diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/Documentation/SubmittingPatches 830-ivtv/Documentation/SubmittingPatches --- 000-virgin/Documentation/SubmittingPatches Tue Aug 5 19:59:11 2003 +++ 830-ivtv/Documentation/SubmittingPatches Thu Jan 8 08:54:03 2004 @@ -239,7 +239,7 @@ Let the compiler optimize away the "no-o Simple example, of poor code: - dev = init_etherdev (NULL, 0); + dev = alloc_etherdev (sizeof(struct funky_private)); if (!dev) return -ENODEV; #ifdef CONFIG_NET_FUNKINESS @@ -254,7 +254,7 @@ Cleaned-up example: #endif (in the code itself) - dev = init_etherdev (NULL, 0); + dev = alloc_etherdev (sizeof(struct funky_private)); if (!dev) return -ENODEV; init_funky_net(dev); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/Documentation/filesystems/proc.txt 830-ivtv/Documentation/filesystems/proc.txt --- 000-virgin/Documentation/filesystems/proc.txt Mon Nov 17 18:28:07 2003 +++ 830-ivtv/Documentation/filesystems/proc.txt Thu Jan 8 10:20:43 2004 @@ -38,6 +38,7 @@ Table of Contents 2.8 /proc/sys/net/ipv4 - IPV4 settings 2.9 Appletalk 2.10 IPX + 2.11 /proc/sys/sched - scheduler tunables ------------------------------------------------------------------------------ Preface @@ -1804,6 +1805,104 @@ IPX. The /proc/net/ipx_route table holds a list of IPX routes. For each route it gives the destination network, the router node (or Directly) and the network address of the router (or Connected) for internal networks. + +2.11 /proc/sys/sched - scheduler tunables +----------------------------------------- + +Useful knobs for tuning the scheduler live in /proc/sys/sched. + +child_penalty +------------- + +Percentage of the parent's sleep_avg that children inherit. sleep_avg is +a running average of the time a process spends sleeping. Tasks with high +sleep_avg values are considered interactive and given a higher dynamic +priority and a larger timeslice. You typically want this some value just +under 100. + +exit_weight +----------- + +When a CPU hog task exits, its parent's sleep_avg is reduced by a factor of +exit_weight against the exiting task's sleep_avg. + +interactive_delta +----------------- + +If a task is "interactive" it is reinserted into the active array after it +has expired its timeslice, instead of being inserted into the expired array. +How "interactive" a task must be in order to be deemed interactive is a +function of its nice value. This interactive limit is scaled linearly by nice +value and is offset by the interactive_delta. + +max_sleep_avg +------------- + +max_sleep_avg is the largest value (in ms) stored for a task's running sleep +average. The larger this value, the longer a task needs to sleep to be +considered interactive (maximum interactive bonus is a function of +max_sleep_avg). + +max_timeslice +------------- + +Maximum timeslice, in milliseconds. This is the value given to tasks of the +highest dynamic priority. + +min_timeslice +------------- + +Minimum timeslice, in milliseconds. This is the value given to tasks of the +lowest dynamic priority. Every task gets at least this slice of the processor +per array switch. + +parent_penalty +-------------- + +Percentage of the parent's sleep_avg that it retains across a fork(). +sleep_avg is a running average of the time a process spends sleeping. Tasks +with high sleep_avg values are considered interactive and given a higher +dynamic priority and a larger timeslice. Normally, this value is 100 and thus +task's retain their sleep_avg on fork. If you want to punish interactive +tasks for forking, set this below 100. + +prio_bonus_ratio +---------------- + +Middle percentage of the priority range that tasks can receive as a dynamic +priority. The default value of 25% ensures that nice values at the +extremes are still enforced. For example, nice +19 interactive tasks will +never be able to preempt a nice 0 CPU hog. Setting this higher will increase +the size of the priority range the tasks can receive as a bonus. Setting +this lower will decrease this range, making the interactivity bonus less +apparent and user nice values more applicable. + +starvation_limit +---------------- + +Sufficiently interactive tasks are reinserted into the active array when they +run out of timeslice. Normally, tasks are inserted into the expired array. +Reinserting interactive tasks into the active array allows them to remain +runnable, which is important to interactive performance. This could starve +expired tasks, however, since the interactive task could prevent the array +switch. To prevent starving the tasks on the expired array for too long. the +starvation_limit is the longest (in ms) we will let the expired array starve +at the expense of reinserting interactive tasks back into active. Higher +values here give more preferance to running interactive tasks, at the expense +of expired tasks. Lower values provide more fair scheduling behavior, at the +expense of interactivity. The units are in milliseconds. + +idle_node_rebalance_ratio +------------------------- + +On NUMA machines, we normally rebalance within nodes, but we also rebalance +globally every N idle rebalance ticks, where N = idle_node_rebalance_ratio. + +busy_node_rebalance_ratio +------------------------- + +On NUMA machines, we normally rebalance within nodes, but we also rebalance +globally every N busy rebalance ticks, where N = busy_node_rebalance_ratio. ------------------------------------------------------------------------------ Summary diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/Documentation/i386/kgdb/andthen 830-ivtv/Documentation/i386/kgdb/andthen --- 000-virgin/Documentation/i386/kgdb/andthen Wed Dec 31 16:00:00 1969 +++ 830-ivtv/Documentation/i386/kgdb/andthen Thu Jan 8 09:30:15 2004 @@ -0,0 +1,100 @@ + +define set_andthen + set var $thp=0 + set var $thp=(struct kgdb_and_then_struct *)&kgdb_data[0] + set var $at_size = (sizeof kgdb_data)/(sizeof *$thp) + set var $at_oc=kgdb_and_then_count + set var $at_cc=$at_oc +end + +define andthen_next + set var $at_cc=$arg0 +end + +define andthen + andthen_set_edge + if ($at_cc >= $at_oc) + printf "Outside window. Window size is %d\n",($at_oc-$at_low) + else + printf "%d: ",$at_cc + output *($thp+($at_cc++ % $at_size )) + printf "\n" + end +end +define andthen_set_edge + set var $at_oc=kgdb_and_then_count + set var $at_low = $at_oc - $at_size + if ($at_low < 0 ) + set var $at_low = 0 + end + if (( $at_cc > $at_oc) || ($at_cc < $at_low)) + printf "Count outside of window, setting count to " + if ($at_cc >= $at_oc) + set var $at_cc = $at_oc + else + set var $at_cc = $at_low + end + printf "%d\n",$at_cc + end +end + +define beforethat + andthen_set_edge + if ($at_cc <= $at_low) + printf "Outside window. Window size is %d\n",($at_oc-$at_low) + else + printf "%d: ",$at_cc-1 + output *($thp+(--$at_cc % $at_size )) + printf "\n" + end +end + +document andthen_next + andthen_next + . sets the number of the event to display next. If this event + . is not in the event pool, either andthen or beforethat will + . correct it to the nearest event pool edge. The event pool + . ends at the last event recorded and begins + . prior to that. If beforethat is used next, it will display + . event -1. +. + andthen commands are: set_andthen, andthen_next, andthen and beforethat +end + + +document andthen + andthen +. displays the next event in the list. sets up to display +. the oldest saved event first. +. (optional) count of the event to display. +. note the number of events saved is specified at configure time. +. if events are saved between calls to andthen the index will change +. but the displayed event will be the next one (unless the event buffer +. is overrun). +. +. andthen commands are: set_andthen, andthen_next, andthen and beforethat +end + +document set_andthen + set_andthen +. sets up to use the and commands. +. if you have defined your own struct, use the above and +. then enter the following: +. p $thp=(struct kgdb_and_then_structX *)&kgdb_data[0] +. where is the name of your structure. +. +. andthen commands are: set_andthen, andthen_next, andthen and beforethat +end + +document beforethat + beforethat +. displays the next prior event in the list. sets up to +. display the last occuring event first. +. +. note the number of events saved is specified at configure time. +. if events are saved between calls to beforethat the index will change +. but the displayed event will be the next one (unless the event buffer +. is overrun). +. +. andthen commands are: set_andthen, andthen_next, andthen and beforethat +end diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/Documentation/i386/kgdb/debug-nmi.txt 830-ivtv/Documentation/i386/kgdb/debug-nmi.txt --- 000-virgin/Documentation/i386/kgdb/debug-nmi.txt Wed Dec 31 16:00:00 1969 +++ 830-ivtv/Documentation/i386/kgdb/debug-nmi.txt Thu Jan 8 09:30:15 2004 @@ -0,0 +1,37 @@ +Subject: Debugging with NMI +Date: Mon, 12 Jul 1999 11:28:31 -0500 +From: David Grothe +Organization: Gcom, Inc +To: David Grothe + +Kernel hackers: + +Maybe this is old hat, but it is new to me -- + +On an ISA bus machine, if you short out the A1 and B1 pins of an ISA +slot you will generate an NMI to the CPU. This interrupts even a +machine that is hung in a loop with interrupts disabled. Used in +conjunction with kgdb < +ftp://ftp.gcom.com/pub/linux/src/kgdb-2.3.35/kgdb-2.3.35.tgz > you can +gain debugger control of a machine that is hung in the kernel! Even +without kgdb the kernel will print a stack trace so you can find out +where it was hung. + +The A1/B1 pins are directly opposite one another and the farthest pins +towards the bracket end of the ISA bus socket. You can stick a paper +clip or multi-meter probe between them to short them out. + +I had a spare ISA bus to PC104 bus adapter around. The PC104 end of the +board consists of two rows of wire wrap pins. So I wired a push button +between the A1/B1 pins and now have an ISA board that I can stick into +any ISA bus slot for debugger entry. + +Microsoft has a circuit diagram of a PCI card at +http://www.microsoft.com/hwdev/DEBUGGING/DMPSW.HTM. If you want to +build one you will have to mail them and ask for the PAL equations. +Nobody makes one comercially. + +[THIS TIP COMES WITH NO WARRANTY WHATSOEVER. It works for me, but if +your machine catches fire, it is your problem, not mine.] + +-- Dave (the kgdb guy) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/Documentation/i386/kgdb/gdb-globals.txt 830-ivtv/Documentation/i386/kgdb/gdb-globals.txt --- 000-virgin/Documentation/i386/kgdb/gdb-globals.txt Wed Dec 31 16:00:00 1969 +++ 830-ivtv/Documentation/i386/kgdb/gdb-globals.txt Thu Jan 8 09:30:15 2004 @@ -0,0 +1,71 @@ +Sender: akale@veritas.com +Date: Fri, 23 Jun 2000 19:26:35 +0530 +From: "Amit S. Kale" +Organization: Veritas Software (India) +To: Dave Grothe , linux-kernel@vger.rutgers.edu +CC: David Milburn , + "Edouard G. Parmelan" , + ezannoni@cygnus.com, Keith Owens +Subject: Re: Module debugging using kgdb + +Dave Grothe wrote: +> +> Amit: +> +> There is a 2.4.0 version of kgdb on our ftp site: +> ftp://ftp.gcom.com/pub/linux/src/kgdb. I mirrored your version of gdb +> and loadmodule.sh there. +> +> Have a look at the README file and see if I go it right. If not, send +> me some corrections and I will update it. +> +> Does your version of gdb solve the global variable problem? + +Yes. +Thanks to Elena Zanoni, gdb (developement version) can now calculate +correctly addresses of dynamically loaded object files. I have not been +following gdb developement for sometime and am not sure when symbol +address calculation fix is going to appear in a gdb stable version. + +Elena, any idea when the fix will make it to a prebuilt gdb from a +redhat release? + +For the time being I have built a gdb developement version. It can be +used for module debugging with loadmodule.sh script. + +The problem with calculating of module addresses with previous versions +of gdb was as follows: +gdb did not use base address of a section while calculating address of +a symbol in the section in an object file loaded via 'add-symbol-file'. +It used address of .text segment instead. Due to this addresses of +symbols in .data, .bss etc. (e.g. global variables) were calculated incorrectly. + +Above mentioned fix allow gdb to use base address of a segment while +calculating address of a symbol in it. It adds a parameter '-s' to +'add-symbol-file' command for specifying base address of a segment. + +loadmodule.sh script works as follows. + +1. Copy a module file to target machine. +2. Load the module on the target machine using insmod with -m parameter. +insmod produces a module load map which contains base addresses of all +sections in the module and addresses of symbols in the module file. +3. Find all sections and their base addresses in the module from +the module map. +4. Generate a script that loads the module file. The script uses +'add-symbol-file' and specifies address of text segment followed by +addresses of all segments in the module. + +Here is an example gdb script produced by loadmodule.sh script. + +add-symbol-file foo 0xd082c060 -s .text.lock 0xd08cbfb5 +-s .fixup 0xd08cfbdf -s .rodata 0xd08cfde0 -s __ex_table 0xd08e3b38 +-s .data 0xd08e3d00 -s .bss 0xd08ec8c0 -s __ksymtab 0xd08ee838 + +With this command gdb can calculate addresses of symbols in ANY segment +in a module file. + +Regards. +-- +Amit Kale +Veritas Software ( http://www.veritas.com ) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/Documentation/i386/kgdb/gdbinit 830-ivtv/Documentation/i386/kgdb/gdbinit --- 000-virgin/Documentation/i386/kgdb/gdbinit Wed Dec 31 16:00:00 1969 +++ 830-ivtv/Documentation/i386/kgdb/gdbinit Thu Jan 8 09:30:15 2004 @@ -0,0 +1,14 @@ +shell echo -e "\003" >/dev/ttyS0 +set remotebaud 38400 +target remote /dev/ttyS0 +define si +stepi +printf "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", $eax, $ebx, $ecx, $edx +printf "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n", $esi, $edi, $ebp, $esp +x/i $eip +end +define ni +nexti +printf "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", $eax, $ebx, $ecx, $edx +printf "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n", $esi, $edi, $ebp, $esp +x/i $eip diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/Documentation/i386/kgdb/gdbinit-modules 830-ivtv/Documentation/i386/kgdb/gdbinit-modules --- 000-virgin/Documentation/i386/kgdb/gdbinit-modules Wed Dec 31 16:00:00 1969 +++ 830-ivtv/Documentation/i386/kgdb/gdbinit-modules Thu Jan 8 09:30:15 2004 @@ -0,0 +1,146 @@ +# +# Usefull GDB user-command to debug Linux Kernel Modules with gdbstub. +# +# This don't work for Linux-2.0 or older. +# +# Author Edouard G. Parmelan +# +# +# Fri Apr 30 20:33:29 CEST 1999 +# First public release. +# +# Major cleanup after experiment Linux-2.0 kernel without success. +# Symbols of a module are not in the correct order, I can't explain +# why :( +# +# Fri Mar 19 15:41:40 CET 1999 +# Initial version. +# +# Thu Jan 6 16:29:03 CST 2000 +# A little fixing by Dave Grothe +# +# Mon Jun 19 09:33:13 CDT 2000 +# Alignment changes from Edouard Parmelan +# +# The basic idea is to find where insmod load the module and inform +# GDB to load the symbol table of the module with the GDB command +# ``add-symbol-file
''. +# +# The Linux kernel holds the list of all loaded modules in module_list, +# this list end with &kernel_module (exactly with module->next == NULL, +# but the last module is not a real module). +# +# Insmod allocates the struct module before the object file. Since +# Linux-2.1, this structure contain his size. The real address of +# the object file is then (char*)module + module->size_of_struct. +# +# You can use three user functions ``mod-list'', ``mod-print-symbols'' +# and ``add-module-symbols''. +# +# mod-list list all loaded modules with the format: +# +# +# As soon as you have found the address of your module, you can +# print its exported symbols (mod-print-symbols) or inform GDB to add +# symbols from your module file (mod-add-symbols). +# +# The argument that you give to mod-print-symbols or mod-add-symbols +# is the from the mod-list command. +# +# When using the mod-add-symbols command you must also give the full +# pathname of the modules object code file. +# +# The command mod-add-lis is an example of how to make this easier. +# You can edit this macro to contain the path name of your own +# favorite module and then use it as a shorthand to load it. You +# still need the module-address, however. +# +# The internal function ``mod-validate'' set the GDB variable $mod +# as a ``struct module*'' if the kernel known the module otherwise +# $mod is set to NULL. This ensure to not add symbols for a wrong +# address. +# +# Have a nice hacking day ! +# +# +define mod-list + set $mod = (struct module*)module_list + # the last module is the kernel, ignore it + while $mod != &kernel_module + printf "%p\t%s\n", (long)$mod, ($mod)->name + set $mod = $mod->next + end +end +document mod-list +List all modules in the form: +Use the as the argument for the other +mod-commands: mod-print-symbols, mod-add-symbols. +end + +define mod-validate + set $mod = (struct module*)module_list + while ($mod != $arg0) && ($mod != &kernel_module) + set $mod = $mod->next + end + if $mod == &kernel_module + set $mod = 0 + printf "%p is not a module\n", $arg0 + end +end +document mod-validate +mod-validate +Internal user-command used to validate the module parameter. +If is a real loaded module, set $mod to it otherwise set $mod to 0. +end + + +define mod-print-symbols + mod-validate $arg0 + if $mod != 0 + set $i = 0 + while $i < $mod->nsyms + set $sym = $mod->syms[$i] + printf "%p\t%s\n", $sym->value, $sym->name + set $i = $i + 1 + end + end +end +document mod-print-symbols +mod-print-symbols +Print all exported symbols of the module. see mod-list +end + + +define mod-add-symbols-align + mod-validate $arg0 + if $mod != 0 + set $mod_base = ($mod->size_of_struct + (long)$mod) + if ($arg2 != 0) && (($mod_base & ($arg2 - 1)) != 0) + set $mod_base = ($mod_base | ($arg2 - 1)) + 1 + end + add-symbol-file $arg1 $mod_base + end +end +document mod-add-symbols-align +mod-add-symbols-align +Load the symbols table of the module from the object file where +first section aligment is . +To retreive alignment, use `objdump -h '. +end + +define mod-add-symbols + mod-add-symbols-align $arg0 $arg1 sizeof(long) +end +document mod-add-symbols +mod-add-symbols +Load the symbols table of the module from the object file. +Default alignment is 4. See mod-add-symbols-align. +end + +define mod-add-lis + mod-add-symbols-align $arg0 /usr/src/LiS/streams.o 16 +end +document mod-add-lis +mod-add-lis +Does mod-add-symbols /usr/src/LiS/streams.o +end diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/Documentation/i386/kgdb/gdbinit.hw 830-ivtv/Documentation/i386/kgdb/gdbinit.hw --- 000-virgin/Documentation/i386/kgdb/gdbinit.hw Wed Dec 31 16:00:00 1969 +++ 830-ivtv/Documentation/i386/kgdb/gdbinit.hw Thu Jan 8 09:30:15 2004 @@ -0,0 +1,117 @@ + +#Using ia-32 hardware breakpoints. +# +#4 hardware breakpoints are available in ia-32 processors. These breakpoints +#do not need code modification. They are set using debug registers. +# +#Each hardware breakpoint can be of one of the +#three types: execution, write, access. +#1. An Execution breakpoint is triggered when code at the breakpoint address is +#executed. +#2. A write breakpoint ( aka watchpoints ) is triggered when memory location +#at the breakpoint address is written. +#3. An access breakpoint is triggered when memory location at the breakpoint +#address is either read or written. +# +#As hardware breakpoints are available in limited number, use software +#breakpoints ( br command in gdb ) instead of execution hardware breakpoints. +# +#Length of an access or a write breakpoint defines length of the datatype to +#be watched. Length is 1 for char, 2 short , 3 int. +# +#For placing execution, write and access breakpoints, use commands +#hwebrk, hwwbrk, hwabrk +#To remove a breakpoint use hwrmbrk command. +# +#These commands take following types of arguments. For arguments associated +#with each command, use help command. +#1. breakpointno: 0 to 3 +#2. length: 1 to 3 +#3. address: Memory location in hex ( without 0x ) e.g c015e9bc +# +#Use the command exinfo to find which hardware breakpoint occured. + +#hwebrk breakpointno address +define hwebrk + maintenance packet Y$arg0,0,0,$arg1 +end +document hwebrk + hwebrk
+ Places a hardware execution breakpoint + = 0 - 3 +
= Hex digits without leading "0x". +end + +#hwwbrk breakpointno length address +define hwwbrk + maintenance packet Y$arg0,1,$arg1,$arg2 +end +document hwwbrk + hwwbrk
+ Places a hardware write breakpoint + = 0 - 3 + = 1 (1 byte), 2 (2 byte), 3 (4 byte) +
= Hex digits without leading "0x". +end + +#hwabrk breakpointno length address +define hwabrk + maintenance packet Y$arg0,1,$arg1,$arg2 +end +document hwabrk + hwabrk
+ Places a hardware access breakpoint + = 0 - 3 + = 1 (1 byte), 2 (2 byte), 3 (4 byte) +
= Hex digits without leading "0x". +end + +#hwrmbrk breakpointno +define hwrmbrk + maintenance packet y$arg0 +end +document hwrmbrk + hwrmbrk + = 0 - 3 + Removes a hardware breakpoint +end + +define reboot + maintenance packet r +end +#exinfo +define exinfo + maintenance packet qE +end +document exinfo + exinfo + Gives information about a breakpoint. +end +define get_th + p $th=(struct thread_info *)((int)$esp & ~8191) +end +document get_th + get_tu + Gets and prints the current thread_info pointer, Defines th to be it. +end +define get_cu + p $cu=((struct thread_info *)((int)$esp & ~8191))->task +end +document get_cu + get_cu + Gets and print the "current" value. Defines $cu to be it. +end +define int_off + set var $flags=$eflags + set $eflags=$eflags&~0x200 + end +define int_on + set var $eflags|=$flags&0x200 + end +document int_off + saves the current interrupt state and clears the processor interrupt + flag. Use int_on to restore the saved flag. +end +document int_on + Restores the interrupt flag saved by int_off. +end diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/Documentation/i386/kgdb/kgdb.txt 830-ivtv/Documentation/i386/kgdb/kgdb.txt --- 000-virgin/Documentation/i386/kgdb/kgdb.txt Wed Dec 31 16:00:00 1969 +++ 830-ivtv/Documentation/i386/kgdb/kgdb.txt Thu Jan 8 09:30:15 2004 @@ -0,0 +1,775 @@ +Last edit: <20030806.1637.12> +This file has information specific to the i386 kgdb option. Other +platforms with the kgdb option may behave in a similar fashion. + +New features: +============ +20030806.1557.37 +This version was made against the 2.6.0-test2 kernel. We have made the +following changes: + +- The getthread() code in the stub calls find_task_by_pid(). It fails + if we are early in the bring up such that the pid arrays have yet to + be allocated. We have added a line to kernel/pid.c to make + "kgdb_pid_init_done" true once the arrays are allocated. This way the + getthread() code knows not to call. This is only used by the thread + debugging stuff and threads will not yet exist at this point in the + boot. + +- For some reason, gdb was not asking for a new thread list when the + "info thread" command was given. We changed to the newer version of + the thread info command and gdb now seems to ask when needed. Result, + we now get all threads in the thread list. + +- We now respond to the ThreadExtraInfo request from gdb with the thread + name from task_struct .comm. This then appears in the thread list. + Thoughts on additional options for this are welcome. Things such as + "has BKL" and "Preempted" come to mind. I think we could have a flag + word that could enable different bits of info here. + +- We now honor, sort of, the C and S commands. These are continue and + single set after delivering a signal. We ignore the signal and do the + requested action. This only happens when we told gdb that a signal + was the reason for entry, which is only done on memory faults. The + result is that you can now continue into the Oops. + +- We changed the -g to -gdwarf-2. This seems to be the same as -ggdb, + but it is more exact on what language to use. + +- We added two dwarf2 include files and a bit of code at the end of + entry.S. This does not yet work, so it is disabled. Still we want to + keep track of the code and "maybe" someone out there can fix it. + +- Randy Dunlap sent some fix ups for this file which are now merged. + +- Hugh Dickins sent a fix to a bit of code in traps.c that prevents a + compiler warning if CONFIG_KGDB is off (now who would do that :). + +- Andrew Morton sent a fix for the serial driver which is now merged. + +- Andrew also sent a change to the stub around the cpu managment code + which is also merged. + +- Andrew also sent a patch to make "f" as well as "g" work as SysRq + commands to enter kgdb, merged. + +- If CONFIG_KGDB and CONFIG_DEBUG_SPINLOCKS are both set we added a + "who" field to the spinlock data struct. This is filled with + "current" when ever the spinlock suceeds. Useful if you want to know + who has the lock. + +_ And last, but not least, we fixed the "get_cu" macro to properly get + the current value of "current". + +New features: +============ +20030505.1827.27 +We are starting to align with the sourceforge version, at least in +commands. To this end, the boot command string to start kgdb at +boot time has been changed from "kgdb" to "gdb". + +Andrew Morton sent a couple of patches which are now included as follows: +1.) We now return a flag to the interrupt handler. +2.) We no longer use smp_num_cpus (a conflict with the lock meter). +3.) And from William Lee Irwin III code to make + sure high-mem is set up before we attempt to register our interrupt + handler. +We now include asm/kgdb.h from config.h so you will most likely never +have to include it. It also 'NULLS' the kgdb macros you might have in +your code when CONFIG_KGDB is not defined. This allows you to just +turn off CONFIG_KGDB to turn off all the kgdb_ts() calls and such. +This include is conditioned on the machine being an x86 so as to not +mess with other archs. + +20020801.1129.03 +This is currently the version for the 2.4.18 (and beyond?) kernel. + +We have several new "features" beginning with this version: + +1.) Kgdb now syncs the "other" CPUs with a cross-CPU NMI. No more + waiting and it will pull that guy out of an IRQ off spin lock :) + +2.) We doctored up the code that tells where a task is waiting and + included it so that the "info thread" command will show a bit more + than "schedule()". Try it... + +3.) Added the ability to call a function from gdb. All the standard gdb + issues apply, i.e. if you hit a breakpoint in the function, you are + not allowed to call another (gdb limitation, not kgdb). To help + this capability we added a memory allocation function. Gdb does not + return this memory (it is used for strings that you pass to that function + you are calling from gdb) so we fixed up a way to allow you to + manually return the memory (see below). + +4.) Kgdb time stamps (kgdb_ts()) are enhanced to expand what was the + interrupt flag to now also include the preemption count and the + "in_interrupt" info. The flag is now called "with_pif" to indicate + the order, preempt_count, in_interrupt, flag. The preempt_count is + shifted left by 4 bits so you can read the count in hex by dropping + the low order digit. In_interrupt is in bit 1, and the flag is in + bit 0. + +5.) The command: "p kgdb_info" is now expanded and prints something + like: +(gdb) p kgdb_info +$2 = {used_malloc = 0, called_from = 0xc0107506, entry_tsc = 67468627259, + errcode = 0, vector = 3, print_debug_info = 0, hold_on_sstep = 1, + cpus_waiting = {{task = 0xc027a000, pid = 32768, hold = 0, + regs = 0xc027bf84}, {task = 0x0, pid = 0, hold = 0, regs = 0x0}}} + + Things to note here: a.) used_malloc is the amount of memory that + has been malloc'ed to do calls from gdb. You can reclaim this + memory like this: "p kgdb_info.used_malloc=0" Cool, huh? b.) + cpus_waiting is now "sized" by the number of CPUs you enter at + configure time in the kgdb configure section. This is NOT used + anywhere else in the system, but it is "nice" here. c.) The task's + "pid" is now in the structure. This is the pid you will need to use + to decode to the thread id to get gdb to look at that thread. + Remember that the "info thread" command prints a list of threads + wherein it numbers each thread with its reference number followed + by the thread's pid. Note that the per-CPU idle threads actually + have pids of 0 (yes, there is more than one pid 0 in an SMP system). + To avoid confusion, kgdb numbers these threads with numbers beyond + the MAX_PID. That is why you see 32768 and above. + +6.) A subtle change, we now provide the complete register set for tasks + that are active on the other CPUs. This allows better trace back on + those tasks. + + And, let's mention what we could not fix. Back-trace from all but the + thread that we trapped will, most likely, have a bogus entry in it. + The problem is that gdb does not recognize the entry code for + functions that use "current" near (at all?) the entry. The compiler + is putting the "current" decode as the first two instructions of the + function where gdb expects to find %ebp changing code. Back trace + also has trouble with interrupt frames. I am talking with Daniel + Jacobowitz about some way to fix this, but don't hold your breath. + +20011220.0050.35 +Major enhancement with this version is the ability to hold one or more +CPUs in an SMP system while allowing the others to continue. Also, by +default only the current CPU is enabled on single-step commands (please +note that gdb issues single-step commands at times other than when you +use the si command). + +Another change is to collect some useful information in +a global structure called "kgdb_info". You should be able to just: + +p kgdb_info + +although I have seen cases where the first time this is done gdb just +prints the first member but prints the whole structure if you then enter +CR (carriage return or enter). This also works: + +p *&kgdb_info + +Here is a sample: +(gdb) p kgdb_info +$4 = {called_from = 0xc010732c, entry_tsc = 32804123790856, errcode = 0, + vector = 3, print_debug_info = 0} + +"Called_from" is the return address from the current entry into kgdb. +Sometimes it is useful to know why you are in kgdb, for example, was +it an NMI or a real breakpoint? The simple way to interrogate this +return address is: + +l *0xc010732c + +which will print the surrounding few lines of source code. + +"Entry_tsc" is the CPU TSC on entry to kgdb (useful to compare to the +kgdb_ts entries). + +"errcode" and "vector" are other entry parameters which may be helpful on +some traps. + +"print_debug_info" is the internal debugging kgdb print enable flag. Yes, +you can modify it. + +In SMP systems kgdb_info also includes the "cpus_waiting" structure and +"hold_on_step": + +(gdb) p kgdb_info +$7 = {called_from = 0xc0112739, entry_tsc = 1034936624074, errcode = 0, + vector = 2, print_debug_info = 0, hold_on_sstep = 1, cpus_waiting = {{ + task = 0x0, hold = 0, regs = 0x0}, {task = 0xc71b8000, hold = 0, + regs = 0xc71b9f70}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0, + hold = 0, regs = 0x0}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0, + hold = 0, regs = 0x0}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0, + hold = 0, regs = 0x0}}} + +"Cpus_waiting" has an entry for each CPU other than the current one that +has been stopped. Each entry contains the task_struct address for that +CPU, the address of the regs for that task and a hold flag. All these +have the proper typing so that, for example: + +p *kgdb_info.cpus_waiting[1].regs + +will print the registers for CPU 1. + +"Hold_on_sstep" is a new feature with this version and comes up set or +true. What this means is that whenever kgdb is asked to single-step all +other CPUs are held (i.e. not allowed to execute). The flag applies to +all but the current CPU and, again, can be changed: + +p kgdb_info.hold_on_sstep=0 + +restores the old behavior of letting all CPUs run during single-stepping. + +Likewise, each CPU has a "hold" flag, which if set, locks that CPU out +of execution. Note that this has some risk in cases where the CPUs need +to communicate with each other. If kgdb finds no CPU available on exit, +it will push a message thru gdb and stay in kgdb. Note that it is legal +to hold the current CPU as long as at least one CPU can execute. + +20010621.1117.09 +This version implements an event queue. Events are signaled by calling +a function in the kgdb stub and may be examined from gdb. See EVENTS +below for details. This version also tightens up the interrupt and SMP +handling to not allow interrupts on the way to kgdb from a breakpoint +trap. It is fine to allow these interrupts for user code, but not +system debugging. + +Version +======= + +This version of the kgdb package was developed and tested on +kernel version 2.4.16. It will not install on any earlier kernels. +It is possible that it will continue to work on later versions +of 2.4 and then versions of 2.5 (I hope). + + +Debugging Setup +=============== + +Designate one machine as the "development" machine. This is the +machine on which you run your compiles and which has your source +code for the kernel. Designate a second machine as the "target" +machine. This is the machine that will run your experimental +kernel. + +The two machines will be connected together via a serial line out +one or the other of the COM ports of the PC. You will need the +appropriate modem eliminator (null modem) cable(s) for this. + +Decide on which tty port you want the machines to communicate, then +connect them up back-to-back using the null modem cable. COM1 is +/dev/ttyS0 and COM2 is /dev/ttyS1. You should test this connection +with the two machines prior to trying to debug a kernel. Once you +have it working, on the TARGET machine, enter: + +setserial /dev/ttyS0 (or what ever tty you are using) + +and record the port address and the IRQ number. + +On the DEVELOPMENT machine you need to apply the patch for the kgdb +hooks. You have probably already done that if you are reading this +file. + +On your DEVELOPMENT machine, go to your kernel source directory and do +"make Xconfig" where X is one of "x", "menu", or "". If you are +configuring in the standard serial driver, it must not be a module. +Either yes or no is ok, but making the serial driver a module means it +will initialize after kgdb has set up the UART interrupt code and may +cause a failure of the control-C option discussed below. The configure +question for the serial driver is under the "Character devices" heading +and is: + +"Standard/generic (8250/16550 and compatible UARTs) serial support" + +Go down to the kernel debugging menu item and open it up. Enable the +kernel kgdb stub code by selecting that item. You can also choose to +turn on the "-ggdb -O1" compile options. The -ggdb causes the compiler +to put more debug info (like local symbols) in the object file. On the +i386 -g and -ggdb are the same so this option just reduces to "O1". The +-O1 reduces the optimization level. This may be helpful in some cases, +be aware, however, that this may also mask the problem you are looking +for. + +The baud rate. Default is 115200. What ever you choose be sure that +the host machine is set to the same speed. I recommend the default. + +The port. This is the I/O address of the serial UART that you should +have gotten using setserial as described above. The standard COM1 port +(3f8) using IRQ 4 is default. COM2 is 2f8 which by convention uses IRQ +3. + +The port IRQ (see above). + +Stack overflow test. This option makes a minor change in the trap, +system call and interrupt code to detect stack overflow and transfer +control to kgdb if it happens. (Some platforms have this in the +baseline code, but the i386 does not.) + +You can also configure the system to recognize the boot option +"console=kgdb" which if given will cause all console output during +booting to be put thru gdb as well as other consoles. This option +requires that gdb and kgdb be connected prior to sending console output +so, if they are not, a breakpoint is executed to force the connection. +This will happen before any kernel output (it is going thru gdb, right), +and will stall the boot until the connection is made. + +You can also configure in a patch to SysRq to enable the kGdb SysRq. +This request generates a breakpoint. Since the serial port IRQ line is +set up after any serial drivers, it is possible that this command will +work when the control-C will not. + +Save and exit the Xconfig program. Then do "make clean" , "make dep" +and "make bzImage" (or whatever target you want to make). This gets the +kernel compiled with the "-g" option set -- necessary for debugging. + +You have just built the kernel on your DEVELOPMENT machine that you +intend to run on your TARGET machine. + +To install this new kernel, use the following installation procedure. +Remember, you are on the DEVELOPMENT machine patching the kernel source +for the kernel that you intend to run on the TARGET machine. + +Copy this kernel to your target machine using your usual procedures. I +usually arrange to copy development: +/usr/src/linux/arch/i386/boot/bzImage to /vmlinuz on the TARGET machine +via a LAN based NFS access. That is, I run the cp command on the target +and copy from the development machine via the LAN. Run Lilo (see "man +lilo" for details on how to set this up) on the new kernel on the target +machine so that it will boot! Then boot the kernel on the target +machine. + +On the DEVELOPMENT machine, create a file called .gdbinit in the +directory /usr/src/linux. An example .gdbinit file looks like this: + +shell echo -e "\003" >/dev/ttyS0 +set remotebaud 38400 (or what ever speed you have chosen) +target remote /dev/ttyS0 + + +Change the "echo" and "target" definition so that it specifies the tty +port that you intend to use. Change the "remotebaud" definition to +match the data rate that you are going to use for the com line. + +You are now ready to try it out. + +Boot your target machine with "kgdb" in the boot command i.e. something +like: + +lilo> test kgdb + +or if you also want console output thru gdb: + +lilo> test kgdb console=kgdb + +You should see the lilo message saying it has loaded the kernel and then +all output stops. The kgdb stub is trying to connect with gdb. Start +gdb something like this: + + +On your DEVELOPMENT machine, cd /usr/src/linux and enter "gdb vmlinux". +When gdb gets the symbols loaded it will read your .gdbinit file and, if +everything is working correctly, you should see gdb print out a few +lines indicating that a breakpoint has been taken. It will actually +show a line of code in the target kernel inside the kgdb activation +code. + +The gdb interaction should look something like this: + + linux-dev:/usr/src/linux# gdb vmlinux + GDB is free software and you are welcome to distribute copies of it + under certain conditions; type "show copying" to see the conditions. + There is absolutely no warranty for GDB; type "show warranty" for details. + GDB 4.15.1 (i486-slackware-linux), + Copyright 1995 Free Software Foundation, Inc... + breakpoint () at i386-stub.c:750 + 750 } + (gdb) + +You can now use whatever gdb commands you like to set breakpoints. +Enter "continue" to start your target machine executing again. At this +point the target system will run at full speed until it encounters +your breakpoint or gets a segment violation in the kernel, or whatever. + +If you have the kgdb console enabled when you continue, gdb will print +out all the console messages. + +The above example caused a breakpoint relatively early in the boot +process. For the i386 kgdb it is possible to code a break instruction +as the first C-language point in init/main.c, i.e. as the first instruction +in start_kernel(). This could be done as follows: + +#include + breakpoint(); + +This breakpoint() is really a function that sets up the breakpoint and +single-step hardware trap cells and then executes a breakpoint. Any +early hard coded breakpoint will need to use this function. Once the +trap cells are set up they need not be set again, but doing it again +does not hurt anything, so you don't need to be concerned about which +breakpoint is hit first. Once the trap cells are set up (and the kernel +sets them up in due course even if breakpoint() is never called) the +macro: + +BREAKPOINT; + +will generate an inline breakpoint. This may be more useful as it stops +the processor at the instruction instead of in a function a step removed +from the location of interest. In either case must be +included to define both breakpoint() and BREAKPOINT. + +Triggering kgdbstub at other times +================================== + +Often you don't need to enter the debugger until much later in the boot +or even after the machine has been running for some time. Once the +kernel is booted and interrupts are on, you can force the system to +enter the debugger by sending a control-C to the debug port. This is +what the first line of the recommended .gdbinit file does. This allows +you to start gdb any time after the system is up as well as when the +system is already at a breakpoint. (In the case where the system is +already at a breakpoint the control-C is not needed, however, it will +be ignored by the target so no harm is done. Also note the the echo +command assumes that the port speed is already set. This will be true +once gdb has connected, but it is best to set the port speed before you +run gdb.) + +Another simple way to do this is to put the following file in you ~/bin +directory: + +#!/bin/bash +echo -e "\003" > /dev/ttyS0 + +Here, the ttyS0 should be replaced with what ever port you are using. +The "\003" is control-C. Once you are connected with gdb, you can enter +control-C at the command prompt. + +An alternative way to get control to the debugger is to enable the kGdb +SysRq command. Then you would enter Alt-SysRq-g (all three keys at the +same time, but push them down in the order given). To refresh your +memory of the available SysRq commands try Alt-SysRq-=. Actually any +undefined command could replace the "=", but I like to KNOW that what I +am pushing will never be defined. + +Debugging hints +=============== + +You can break into the target machine at any time from the development +machine by typing ^C (see above paragraph). If the target machine has +interrupts enabled this will stop it in the kernel and enter the +debugger. + +There is unfortunately no way of breaking into the kernel if it is +in a loop with interrupts disabled, so if this happens to you then +you need to place exploratory breakpoints or printk's into the kernel +to find out where it is looping. The exploratory breakpoints can be +entered either thru gdb or hard coded into the source. This is very +handy if you do something like: + +if () BREAKPOINT; + + +There is a copy of an e-mail in the Documentation/i386/kgdb/ directory +(debug-nmi.txt) which describes how to create an NMI on an ISA bus +machine using a paper clip. I have a sophisticated version of this made +by wiring a push button switch into a PC104/ISA bus adapter card. The +adapter card nicely furnishes wire wrap pins for all the ISA bus +signals. + +When you are done debugging the kernel on the target machine it is a +good idea to leave it in a running state. This makes reboots faster, +bypassing the fsck. So do a gdb "continue" as the last gdb command if +this is possible. To terminate gdb itself on the development machine +and leave the target machine running, first clear all breakpoints and +continue, then type ^Z to suspend gdb and then kill it with "kill %1" or +something similar. + +If gdbstub Does Not Work +======================== + +If it doesn't work, you will have to troubleshoot it. Do the easy +things first like double checking your cabling and data rates. You +might try some non-kernel based programs to see if the back-to-back +connection works properly. Just something simple like cat /etc/hosts +>/dev/ttyS0 on one machine and cat /dev/ttyS0 on the other will tell you +if you can send data from one machine to the other. Make sure it works +in both directions. There is no point in tearing out your hair in the +kernel if the line doesn't work. + +All of the real action takes place in the file +/usr/src/linux/arch/i386/kernel/kgdb_stub.c. That is the code on the target +machine that interacts with gdb on the development machine. In gdb you can +turn on a debug switch with the following command: + + set remotedebug + +This will print out the protocol messages that gdb is exchanging with +the target machine. + +Another place to look is /usr/src/arch/i386/lib/kgdb_serial.c. This is +the code that talks to the serial port on the target side. There might +be a problem there. In particular there is a section of this code that +tests the UART which will tell you what UART you have if you define +"PRNT" (just remove "_off" from the #define PRNT_off). To view this +report you will need to boot the system without any beakpoints. This +allows the kernel to run to the point where it calls kgdb to set up +interrupts. At this time kgdb will test the UART and print out the type +it finds. (You need to wait so that the printks are actually being +printed. Early in the boot they are cached, waiting for the console to +be enabled. Also, if kgdb is entered thru a breakpoint it is possible +to cause a dead lock by calling printk when the console is locked. The +stub thus avoids doing printks from breakpoints, especially in the +serial code.) At this time, if the UART fails to do the expected thing, +kgdb will print out (using printk) information on what failed. (These +messages will be buried in all the other boot up messages. Look for +lines that start with "gdb_hook_interrupt:". You may want to use dmesg +once the system is up to view the log. If this fails or if you still +don't connect, review your answers for the port address. Use: + +setserial /dev/ttyS0 + +to get the current port and IRQ information. This command will also +tell you what the system found for the UART type. The stub recognizes +the following UART types: + +16450, 16550, and 16550A + +If you are really desperate you can use printk debugging in the +kgdbstub code in the target kernel until you get it working. In particular, +there is a global variable in /usr/src/linux/arch/i386/kernel/kgdb_stub.c +named "remote_debug". Compile your kernel with this set to 1, rather +than 0 and the debug stub will print out lots of stuff as it does +what it does. Likewise there are debug printks in the kgdb_serial.c +code that can be turned on with simple changes in the macro defines. + + +Debugging Loadable Modules +========================== + +This technique comes courtesy of Edouard Parmelan + + +When you run gdb, enter the command + +source gdbinit-modules + +This will read in a file of gdb macros that was installed in your +kernel source directory when kgdb was installed. This file implements +the following commands: + +mod-list + Lists the loaded modules in the form + +mod-print-symbols + Prints all the symbols in the indicated module. + +mod-add-symbols + Loads the symbols from the object file and associates them + with the indicated module. + +After you have loaded the module that you want to debug, use the command +mod-list to find the of your module. Then use that +address in the mod-add-symbols command to load your module's symbols. +From that point onward you can debug your module as if it were a part +of the kernel. + +The file gdbinit-modules also contains a command named mod-add-lis as +an example of how to construct a command of your own to load your +favorite module. The idea is to "can" the pathname of the module +in the command so you don't have to type so much. + +Threads +======= + +Each process in a target machine is seen as a gdb thread. gdb thread +related commands (info threads, thread n) can be used. + +ia-32 hardware breakpoints +========================== + +kgdb stub contains support for hardware breakpoints using debugging features +of ia-32(x86) processors. These breakpoints do not need code modification. +They use debugging registers. 4 hardware breakpoints are available in ia-32 +processors. + +Each hardware breakpoint can be of one of the following three types. + +1. Execution breakpoint - An Execution breakpoint is triggered when code + at the breakpoint address is executed. + + As limited number of hardware breakpoints are available, it is + advisable to use software breakpoints ( break command ) instead + of execution hardware breakpoints, unless modification of code + is to be avoided. + +2. Write breakpoint - A write breakpoint is triggered when memory + location at the breakpoint address is written. + + A write or can be placed for data of variable length. Length of + a write breakpoint indicates length of the datatype to be + watched. Length is 1 for 1 byte data , 2 for 2 byte data, 3 for + 4 byte data. + +3. Access breakpoint - An access breakpoint is triggered when memory + location at the breakpoint address is either read or written. + + Access breakpoints also have lengths similar to write breakpoints. + +IO breakpoints in ia-32 are not supported. + +Since gdb stub at present does not use the protocol used by gdb for hardware +breakpoints, hardware breakpoints are accessed through gdb macros. gdb macros +for hardware breakpoints are described below. + +hwebrk - Places an execution breakpoint + hwebrk breakpointno address +hwwbrk - Places a write breakpoint + hwwbrk breakpointno length address +hwabrk - Places an access breakpoint + hwabrk breakpointno length address +hwrmbrk - Removes a breakpoint + hwrmbrk breakpointno +exinfo - Tells whether a software or hardware breakpoint has occurred. + Prints number of the hardware breakpoint if a hardware breakpoint has + occurred. + +Arguments required by these commands are as follows +breakpointno - 0 to 3 +length - 1 to 3 +address - Memory location in hex digits ( without 0x ) e.g c015e9bc + +SMP support +========== + +When a breakpoint occurs or user issues a break ( Ctrl + C ) to gdb +client, all the processors are forced to enter the debugger. Current +thread corresponds to the thread running on the processor where +breakpoint occurred. Threads running on other processor(s) appear +similar to other non-running threads in the 'info threads' output. +Within the kgdb stub there is a structure "waiting_cpus" in which kgdb +records the values of "current" and "regs" for each CPU other than the +one that hit the breakpoint. "current" is a pointer to the task +structure for the task that CPU is running, while "regs" points to the +saved registers for the task. This structure can be examined with the +gdb "p" command. + +ia-32 hardware debugging registers on all processors are set to same +values. Hence any hardware breakpoints may occur on any processor. + +gdb troubleshooting +=================== + +1. gdb hangs +Kill it. restart gdb. Connect to target machine. + +2. gdb cannot connect to target machine (after killing a gdb and +restarting another) If the target machine was not inside debugger when +you killed gdb, gdb cannot connect because the target machine won't +respond. In this case echo "Ctrl+C"(ASCII 3) to the serial line. +e.g. echo -e "\003" > /dev/ttyS1 +This forces that target machine into the debugger, after which you +can connect. + +3. gdb cannot connect even after echoing Ctrl+C into serial line +Try changing serial line settings min to 1 and time to 0 +e.g. stty min 1 time 0 < /dev/ttyS1 +Try echoing again + +Check serial line speed and set it to correct value if required +e.g. stty ispeed 115200 ospeed 115200 < /dev/ttyS1 + +EVENTS +====== + +Ever want to know the order of things happening? Which CPU did what and +when? How did the spinlock get the way it is? Then events are for +you. Events are defined by calls to an event collection interface and +saved for later examination. In this case, kgdb events are saved by a +very fast bit of code in kgdb which is fully SMP and interrupt protected +and they are examined by using gdb to display them. Kgdb keeps only +the last N events, where N must be a power of two and is defined at +configure time. + + +Events are signaled to kgdb by calling: + +kgdb_ts(data0,data1) + +For each call kgdb records each call in an array along with other info. +Here is the array definition: + +struct kgdb_and_then_struct { +#ifdef CONFIG_SMP + int on_cpu; +#endif + long long at_time; + int from_ln; + char * in_src; + void *from; + int with_if; + int data0; + int data1; +}; + +For SMP machines the CPU is recorded, for all machines the TSC is +recorded (gets a time stamp) as well as the line number and source file +the call was made from. The address of the (from), the "if" (interrupt +flag) and the two data items are also recorded. The macro kgdb_ts casts +the types to int, so you can put any 32-bit values here. There is a +configure option to select the number of events you want to keep. A +nice number might be 128, but you can keep up to 1024 if you want. The +number must be a power of two. An "andthen" macro library is provided +for gdb to help you look at these events. It is also possible to define +a different structure for the event storage and cast the data to this +structure. For example the following structure is defined in kgdb: + +struct kgdb_and_then_struct2 { +#ifdef CONFIG_SMP + int on_cpu; +#endif + long long at_time; + int from_ln; + char * in_src; + void *from; + int with_if; + struct task_struct *t1; + struct task_struct *t2; +}; + +If you use this for display, the data elements will be displayed as +pointers to task_struct entries. You may want to define your own +structure to use in casting. You should only change the last two items +and you must keep the structure size the same. Kgdb will handle these +as 32-bit ints, but within that constraint you can define a structure to +cast to any 32-bit quantity. This need only be available to gdb and is +only used for casting in the display code. + +Final Items +=========== + +I picked up this code from Amit S. Kale and enhanced it. + +If you make some really cool modification to this stuff, or if you +fix a bug, please let me know. + +George Anzinger + + +Amit S. Kale + + +(First kgdb by David Grothe ) + +(modified by Tigran Aivazian ) + Putting gdbstub into the kernel config menu. + +(modified by Scott Foehner ) + Hooks for entering gdbstub at boot time. + +(modified by Amit S. Kale ) + Threads, ia-32 hw debugging, mp support, console support, + nmi watchdog handling. + +(modified by George Anzinger ) + Extended threads to include the idle threads. + Enhancements to allow breakpoint() at first C code. + Use of module_init() and __setup() to automate the configure. + Enhanced the cpu "collection" code to work in early bring-up. + Added ability to call functions from gdb + Print info thread stuff without going back to schedule() + Now collect the "other" cpus with an IPI/ NMI. diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/Documentation/i386/kgdb/kgdbeth.txt 830-ivtv/Documentation/i386/kgdb/kgdbeth.txt --- 000-virgin/Documentation/i386/kgdb/kgdbeth.txt Wed Dec 31 16:00:00 1969 +++ 830-ivtv/Documentation/i386/kgdb/kgdbeth.txt Thu Jan 8 09:30:18 2004 @@ -0,0 +1,92 @@ +KGDB over ethernet +================== + +Authors +------- + +Robert Walsh (2.6 port) +wangdi (2.6 port) +Matt Mackall (netpoll api) +San Mehat (original 2.4 code) + + +Introduction +------------ + +KGDB supports debugging over ethernet (kgdboe) via polling of a given +network interface. Most cards should be supported automatically. +Debugging facilities are available as soon as the network driver and +kgdboe have initialized. Unfortunately, this is too late in the boot +process for debugging some issues, but works quite well for many +others. This should not interfere with normal network usage and +doesn't require a dedicated NIC. + +Terminology +----------- + +This document uses the following terms: + + TARGET: the machine being debugged. + HOST: the machine running gdb. + + +Usage +----- + +You need to use the following command-line option on the TARGET kernel: + + kgdboe=[tgt-port]@/[dev],[host-port]@/[host-macaddr] + + where + tgt-port source for UDP packets (defaults to 6443) + tgt-ip source IP to use (interface address) + dev network interface (eth0) + host-port HOST UDP port (6442) (not really used) + host-ip IP address for HOST machine + host-macaddr ethernet MAC address for HOST (ff:ff:ff:ff:ff:ff) + + examples: + + kgdboe=7000@192.168.0.1/eth1,7001@192.168.0.2/00:05:3C:04:47:5D + this machine is 192.168.0.1 on eth1 + remote machine is 192.168.0.2 with MAC address 00:05:3C:04:47:5D + listen for gdb packets on port 7000 + send unsolicited gdb packets to port 7001 + + kgdboe=@192.168.0.1/,@192.168.0.2/ + this machine is 192.168.0.1 on default interface eth0 + remote machine is 192.168.0.2, use default broadcast MAC address + listen for gdb packets on default port 6443 + send unsolicited gdb packets to port 6442 + +Only packets originating from the configured HOST IP address will be +accepted by the debugger. + +On the HOST side, run gdb as normal and use a remote UDP host as the +target: + + % gdb ./vmlinux + GNU gdb Red Hat Linux (5.3post-0.20021129.18rh) + Copyright 2003 Free Software Foundation, Inc. + GDB is free software, covered by the GNU General Public License, and you are + welcome to change it and/or distribute copies of it under certain conditions. + Type "show copying" to see the conditions. + There is absolutely no warranty for GDB. Type "show warranty" for details. + This GDB was configured as "i386-redhat-linux-gnu"... + (gdb) target remote udp:HOSTNAME:6443 + +You can now continue as if you were debugging over a serial line. + +Limitations +----------- + +The current release of this code is exclusive of using kgdb on a +serial interface, so you must boot without the kgdboe option to use +serial debugging. Trying to debug the network driver while using it +will prove interesting. + +Bug reports +----------- + +Send bug reports to Robert Walsh and Matt +Mackall . diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/Documentation/i386/kgdb/loadmodule.sh 830-ivtv/Documentation/i386/kgdb/loadmodule.sh --- 000-virgin/Documentation/i386/kgdb/loadmodule.sh Wed Dec 31 16:00:00 1969 +++ 830-ivtv/Documentation/i386/kgdb/loadmodule.sh Thu Jan 8 09:30:15 2004 @@ -0,0 +1,78 @@ +#/bin/sh +# This script loads a module on a target machine and generates a gdb script. +# source generated gdb script to load the module file at appropriate addresses +# in gdb. +# +# Usage: +# Loading the module on target machine and generating gdb script) +# [foo]$ loadmodule.sh +# +# Loading the module file into gdb +# (gdb) source +# +# Modify following variables according to your setup. +# TESTMACHINE - Name of the target machine +# GDBSCRIPTS - The directory where a gdb script will be generated +# +# Author: Amit S. Kale (akale@veritas.com). +# +# If you run into problems, please check files pointed to by following +# variables. +# ERRFILE - /tmp/.errs contains stderr output of insmod +# MAPFILE - /tmp/.map contains stdout output of insmod +# GDBSCRIPT - $GDBSCRIPTS/load gdb script. + +TESTMACHINE=foo +GDBSCRIPTS=/home/bar + +if [ $# -lt 1 ] ; then { + echo Usage: $0 modulefile + exit +} ; fi + +MODULEFILE=$1 +MODULEFILEBASENAME=`basename $1` + +if [ $MODULEFILE = $MODULEFILEBASENAME ] ; then { + MODULEFILE=`pwd`/$MODULEFILE +} fi + +ERRFILE=/tmp/$MODULEFILEBASENAME.errs +MAPFILE=/tmp/$MODULEFILEBASENAME.map +GDBSCRIPT=$GDBSCRIPTS/load$MODULEFILEBASENAME + +function findaddr() { + local ADDR=0x$(echo "$SEGMENTS" | \ + grep "$1" | sed 's/^[^ ]*[ ]*[^ ]*[ ]*//' | \ + sed 's/[ ]*[^ ]*$//') + echo $ADDR +} + +function checkerrs() { + if [ "`cat $ERRFILE`" != "" ] ; then { + cat $ERRFILE + exit + } fi +} + +#load the module +echo Copying $MODULEFILE to $TESTMACHINE +rcp $MODULEFILE root@${TESTMACHINE}: + +echo Loading module $MODULEFILE +rsh -l root $TESTMACHINE /sbin/insmod -m ./`basename $MODULEFILE` \ + > $MAPFILE 2> $ERRFILE +checkerrs + +SEGMENTS=`head -n 11 $MAPFILE | tail -n 10` +TEXTADDR=$(findaddr "\\.text[^.]") +LOADSTRING="add-symbol-file $MODULEFILE $TEXTADDR" +SEGADDRS=`echo "$SEGMENTS" | awk '//{ + if ($1 != ".text" && $1 != ".this" && + $1 != ".kstrtab" && $1 != ".kmodtab") { + print " -s " $1 " 0x" $3 " " + } +}'` +LOADSTRING="$LOADSTRING $SEGADDRS" +echo Generating script $GDBSCRIPT +echo $LOADSTRING > $GDBSCRIPT diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/Documentation/networking/8139too.txt 830-ivtv/Documentation/networking/8139too.txt --- 000-virgin/Documentation/networking/8139too.txt Tue Sep 2 09:55:40 2003 +++ 830-ivtv/Documentation/networking/8139too.txt Wed Dec 31 16:00:00 1969 @@ -1,449 +0,0 @@ - - "8139too" Fast Ethernet driver for Linux - RTL-8139, -8129, and -8130 10/100 Fast Ethernet adapters - - Copyright 2000,2001 Jeff Garzik - - http://sourceforge.net/projects/gkernel/ - - - Architectures supported (all PCI platforms): - x86, Alpha AXP, PowerPC, Sparc64 - - Kernel versions supported: 2.4.x - - - -Disclaimer ----------- - -DO NOT CONTACT DONALD BECKER FOR SUPPORT OF THIS DRIVER, his driver is -completely different and maintained independently of the 8139too code base. - - - -Requirements ------------- -Kernel 2.4.3 or later. -A Fast Ethernet adapter containing an RTL8139-based chip. - - - -Introduction ------------- - -The "8139too" Fast Ethernet driver for Linux 2.4.0 is a substantial -modification of the experimental rtl8139 driver from Donald Becker, -some versions of which appeared in 2.2.x and 2.3.x kernels. The -RTL-8139 is a very low-cost Fast Ethernet chip, which makes it very -popular. - -The step from 2.2.x to 2.4.x kernels brings many new features to Linux -device drivers. Features for MMIO resources, a standard hot-plug API, -and other interfaces are now becoming requirements, as drivers move -off the x86 platform. With that in mind, I have begun updating the -RTL-8139 driver to current 2.3.x (2.4) kernel standards and APIs, and -fixing the problems that users have been encountering. - - - -Features of 8139too -------------------- -[note - this list intended for people familiar with kernel drivers] - -** 100% MMIO, for full speed operation. All users (so far) have -reported performance increases over their existing RTL drivers. - -** Multi-platform support: x86, Alpha, PPC, ... - -** Use proper SMP spinlocking, fixing SMP interrupt bugs, making the -driver portable to non-x86 SMP platforms in the process. - -** Use new PCI driver API for seamless, low-maintenance hot-plug support - -** Several bugs fixes from original rtl8139 1.08r (October 5, 1999), -including the very common "transmit timeout" problem. - -* Use new resource allocation API, required for hot-plug support -* Use new register read/write macros -* initcall support (module_init/exit) -* vastly improved debug tracing support -* code formatting in many places for readability -* use new init_etherdev() facilities - -...and probably some other less important changes which I forgot. - - - -Installation ------------- - -OPTION 1: Build inside kernel tree (into kernel image, or as module) - - (overwrite 8139too driver in kernel tree with different version) - 1) cp 8139too.c $my_source_tree/drivers/net/8139too.c - -OPTION 2: Build outside kernel tree - - Use the included Makefile. - - - -Tested Adapters ---------------- -AOpen ALN-325C -AT-2500TX 10/100 PCI Fast Ethernet Network Adapter Card -D-Link DFE-530TX -Cnet CNF401 'SinglePoint' 10/100 Base-TX -Genius GF 100TXR4 Fast Ethernet 10/100M PCI Network Card -KTI KF-230TX -KTI KF-230TX/2 -Lantech FastNet TX -Ovislink Fast Ethernet -Planet ENW-9504 (V.4) 10/100 -SDT Jeoun Fast PCI-TX -SMC EZNET 10/100 -UNEX NexNIC ND012C - -(please add your adapter model to this list) - - - -Status of Platform Support --------------------------- - -(see errata below for details) - -x86: tested, stable -Alpha AXP: tested, stable -PowerPC: tested, unstable -Sparc64: not tested - - - -Special Thanks --------------- -The following people contributed invaluable testing time, feedback -and/or patches during the development of this driver. Thanks to all -of them. - -Donald Becker, Alan Cox, Richard Stallman, Linus Torvalds - inspiration - -Alan Cox, Gerard Roudier - insight on posted MMIO writes - -Martin Mares - code review - -Tigran Aivazian - testing, code review, and a bug fix - -Chmouel Boudjnah, Alexander Dietrich, Oleg Drokin, -James Fidell, Taso Hatzi, Peter K - intrepid test team - -And thanks to every supporter free software. - -(see top of 8139too.c for further credits and kudos) - - - -Submitting Bug Reports ----------------------- -Obtain and compile the modified rtl8139-diag source code from the -8139too driver Web site, http://sourceforge.net/projects/gkernel/ -This diagnostics programs, originally from Donald Becker, has been -modified to display all registers on your RTL8139 chip, not just the -first 0x80. - -If possible, send the output of a working and broken driver with - rtl8139-diag -mmaaavvveefN > my-output-file.txt - -Send "lspci -vvv" or "cat /proc/pci" output for PCI information. - - - -Known Bugs / Errata / To-Do ---------------------------- -The following issues are known, and are actively being pursued. Patches -to resolve these issues is welcome. If a problem occurs which is not in -the list, please report it. That's why we do beta releases, after all... - - - -1) Work with Donald to merge fixes and updates into his driver. - -2) ETHTOOL_SSET support - -3) PPC platform has stability problems. (XXX: verify this is still true) - -4) Sparc64 platform not tested at all. - -8) Much improved command line / module parameter setup. (patches and -suggestions welcome) (WIP) - -9) Better documentation. (patches welcome) - -12) 10base-T support flaky or slow (todo: verify this is still true) - - - - -Change History --------------- - -Version 0.9.26 - August 9, 2002 - -* Fix MII ioctl phy id corruption. -* Fix big-endian multicast bug. -* Support register dumps via ethtool. -* Fix several uses of 'len' after potential skb free, in dev->hard_start_xmit -* Replace several "magic numbers" with their proper representation - constants in linux/mii.h. -* Support ethtool media interface via generic kernel MII API -* Export NIC-specific statistics via ethtool. -* Proper support for RTL8139 rev K. (can be disabled via - compile-time conditional) -* Add PCI ids for new 8139 boards. -* Use ethernet crc via generic linux/crc32.h kernel API. -* Better RX reset. Old rx-reset method still available via - a compile-time conditional. -* Only account specific RX errors if rx_status is !OK - - -Version 0.9.22 - November 8, 2001 - -* Additional retries before aborting Tx -* Do not write other TxConfig bits when writing clear-abort bit. -* Ack TxErr intr status after each Tx abort, too. -* Fix oops in interface restart - - -Version 0.9.21 - November 1, 2001 - -* Disable early Rx, it hurts performance and creates races. -* Remove DPRINTK macro function tracing. -* Better interrupt sharing behavior. -* Acknowledge PCI errors. -* Remove early-Rx acknowledgement, unnecessary -* Remove code for uncommon case where Tx packets are - properly aligned, and do not need to be copied. - Tx packets are now always copied into a static DMA buffer, - which is allocated at interface open. -* Fix problems with kernel thread exit. - - -Version 0.9.20 - October 18, 2001 - -* Print out notice when 8139C+ chip is detected -* Add id for D-Link DFE690TXD pcmcia cardbus card (Gert Dewit) - - -Version 0.9.19 - October 9, 2001 - -* Eliminate buffer copy for unaligned Tx's (manfred) -* Better RX error recovery (manfred) -* Wake-On-LAN and ETHTOOL_GSET support (Kalle Niemitalo) -* Fix assertion in PIO mode (various) - - -Version 0.9.18 - July 6, 2001 - -* Fix race leading to crashes on some machines. -* Minimize race leading to low performance. -* Correct interrupt acknowledgement to cover all three - relevant Rx events. -* Add ethtool driver info support. -* Collect additional driver-internal statistics. -* Add descriptions for module parameters. -* Support new SIOCxMIIxxx ioctls added in kernel 2.4.6. -* Multicast filter big endian fix. -* Support new PCI PM API added in kernel 2.4.6. - - -Version 0.9.17 - May 7, 2001 - -* Fix chipset wakeup bug which prevent media connection for 8139B -* Print out "media is unconnected..." instead of - "partner ability 0000" - - -Version 0.9.16 - April 14, 2001 - -* Complete MMIO audit, disable read-after-every-write -* Update Rx interrupt handling -* Enable Early Rx thresholds, highly recommended to reduce - Rx FIFO overflow -* Make 8129 support conditional -* Support for new 2.4.3 kernel APIs -* More correct PIO/MMIO PCI BAR region size checking -* Add check for totally dead/missing hardware -* Disable media timer code to "set full duplex" -* s/spin_lock_irq/spin_lock_irqsave/ -* Only set AcceptMulticast if more than one mc address -* Only set rx_mode if changed, in set_rx_mode -* Only suspend/resume if interface is up -* Always print out version upon module load, even if no devices found - - -Version 0.9.15 - February 20, 2001 - -* Call pci_enable_device to wake up/assign resource to device, - before actually using it. -* Support wacky clone PCI ids (report from Norival Toniato Junior) -* Text spelling corrections -* Make sure tp->phys[] is signed -* Always wake queue after hw restart, in tx_timeout -* Record time of last received packet - - -Version 0.9.14 - January 11, 2001 - -* Merge some changes from Becker version 1.13: - * Add DFE 538TX PCI id - * MII read/write functions updated - * Cfg93[45]6 lock/unlock fix - * RTL-8129 (MII) support -* Clean up spinlocking - - -Version 0.9.13 - December, 2000 - -* Clear blocked signals, avoid buffer overrun setting current->comm -* Remove bogus PCI BAR length assertions -* Remove unused 'debug' module parameter - - -Version 0.9.12 - November 23, 2000 - -* Kill major Tx stop/wake queue race -* Use SET_MODULE_OWNER and fix module unload race -* Fix cable length ("Twister") tuning -* Proper media[] array length checking -* Replace timer with kernel thread for twister tuning state machine - and media checking. Fixes mdio_xxx locking, now mdio_xxx is always - protected by rtnl_lock semaphore. -* Correct some sledgehammer a.k.a. overzealous spin-locks -* Performance: Eliminate atomic_t for Tx counters, we don't need it -* Performance: Don't copy Tx buffer if the rare case occurs where it - is aligned perfectly for us. -* Eliminate needless casting of dev->priv -* PIO mode selection and Twister tuning are now CONFIG_xxx options - (though purposefully not in net/Config.in... yet) - - -Version 0.9.11 - October 28, 2000 - -* Do not fail when PIO and MMIO region lengths do not match. - (They don't on some CardBus models, at least) -* Sanity check Rx packet status and size (Tobias) -* When handling a Tx timeout, disable Tx ASAP if not already. -* Do not inline Tx interrupt handler (better register usage) -* Handle dirty_tx signed integer wrap -* Do not abort Rx processing on lack of memory, keep going - until the current Rx ring is completely handling. (Tobias) -* Clean up rtl8139_close -* Whitespace correction for dev_kfree_skb_irq call - - -Version 0.9.10 - September 12, 2000 - -* Never wrap an Rx packet (faster Rx interrupt handling) -* Clear all TxAborted conditions (bug fix) -* Correct copyright -* More credits -* Update NWay doc URL -* Clean up commonly used ifdef switches -* Reorg info displayed at bootup/modprobe time -* Remove some unneeded spinlocks -* Misc cosmetic code cleanup -* Always print interrupt status for abnormal interrupts -* Use RealTek-recommended FIFO and DMA burst settings (1024 bytes) - - -Version 0.9.9 - September 9, 2000 - -* Fix oops-able bug in Rx ring wrap calculation (David Ford) -* Use PIO instead of MMIO when USE_IO_OPS is defined -* Move Rx error handling out of Rx interrupt handler, resulting in - tighter Rx interrupt processing - - -Version 0.9.8 - September 7, 2000 - -* Propagate request_irq error value (andrew morton) -* Correct potential oops bug in PCI DMA unmap code -* Fix bugs related to counting/discounting of 32-bit CRC in each Rx packet -* Fix 16/32-bit bug in interrupt status check -* Timer cleanups (andrew morton) - - -Version 0.9.7 - June 11, 2000 - -* Fix support for older chips (RTL8139 early chips should now work again) - - -Version 0.9.6 - May 30, 2000 - -* Fix 4-extra-bytes bug - (thanks to Markus Westergren, via Santiago Garcia Mantinan) -* Yet more improved chip recognition - - -Version 0.9.5 - May 17, 2000 - -* Improved chip version recognition -* Continue banging away at receiver hang problem -* Use spin_lock_irq in another spot -* Don't print anything on pci_enable_device, it does so for us -* Disable buggy NWay code -* Define TxConfig bitmasks - - -Version 0.9.4.1 - April 27, 2000 - third public beta release - -* Replace several "magic numbers" with symbolic constants -* Differentiate between board-specific info and chip-specific info - (allows for easier support of specific boards or chips) -* Move some of the transmit side outside of the spinlock - by using atomic variables. Use spin_lock_irq instead of - spin_lock_irq{save,restore} in select places, for better performance. -* New module option "media" for forcing media selection. Functions the - same as "options" in other drivers, and will soon be renamed - 'options' to be homogeneous. -* New power management wake-up code -* Slightly more verbose chip id messages in kernel log -* Add/correct chip register constant list -* New chipset wake up (open) logic -* No longer locks CONFIGx updates -* Do not set Interfame Gap (IFG) bits in TxConfig -* Better Rx reset logic in case of Rx FIFO Overflow -* For chips which support it, enable bit to automatically clear Rx - FIFO overflow -* No longer enable and disable interrupts in interrupt handler - (technique borrowed from BSD driver, appears to have problems - with some chips) -* H/W spinlock now protects ioctl -* Chipset-dependent RxConfig settings - - -Version 0.9.3.3.2 - Feb 22, 2000 - second public beta release - -* Begin integration of Daniel Kobras' MMIO flush patch (disabled for now) -* Softnet logic updates to fix bugs and improve performance -* Dynamic sizing of I/O resources (0x80 for older chips, 0xFF for newer ones) -* Remove bogus SiS entries from PCI probe table -* Add support for cards - "Delta Electronics 8139 10/100BaseTX" - "Addtron Technolgy 8139 10/100BaseTX" -* Fix major bug with rx ring buffer size (also present in rtl8139.c 1.08r) -* PCI DMA mapping by Dave Miller -* Complete rewrite of SMP locking logic -* Hotplug support -* Call rtl8139_hw_start from rtl8139_open, and remove duplicated code - from rtl8139_open -* Reset NWay registers to sane defaults on rtl8139_open/hw_start -* Miscellaneous code cleanup - - -Version 0.7.0 - Feb 7, 2000 - first public beta release -* Initial public version, derived from Donald Becker's rtl8139.c v1.08r - -[EOF] - diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/Documentation/networking/bonding.txt 830-ivtv/Documentation/networking/bonding.txt --- 000-virgin/Documentation/networking/bonding.txt Mon Nov 17 18:28:29 2003 +++ 830-ivtv/Documentation/networking/bonding.txt Thu Jan 8 08:54:03 2004 @@ -21,7 +21,7 @@ userspace tools, please follow the links Table of Contents ================= - + Installation Bond Configuration Module Parameters @@ -66,7 +66,7 @@ of the -I option on the ifenslave compil /usr/include/linux. To install ifenslave.c, do: - # gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave + # gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave # cp ifenslave /sbin/ifenslave @@ -74,10 +74,10 @@ Bond Configuration ================== You will need to add at least the following line to /etc/modules.conf -so the bonding driver will automatically load when the bond0 interface is -configured. Refer to the modules.conf manual page for specific modules.conf -syntax details. The Module Parameters section of this document describes each -bonding driver parameter. +so the bonding driver will automatically load when the bond0 interface is +configured. Refer to the modules.conf manual page for specific modules.conf +syntax details. The Module Parameters section of this document describes each +bonding driver parameter. alias bond0 bonding @@ -113,7 +113,7 @@ bonding interface (bond1), use MASTER=bo network interface be a slave of bond1. Restart the networking subsystem or just bring up the bonding device if your -administration tools allow it. Otherwise, reboot. On Red Hat distros you can +administration tools allow it. Otherwise, reboot. On Red Hat distros you can issue `ifup bond0' or `/etc/rc.d/init.d/network restart'. If the administration tools of your distribution do not support @@ -128,30 +128,30 @@ manually configure the bonding device wi (use appropriate values for your network above) -You can then create a script containing these commands and place it in the +You can then create a script containing these commands and place it in the appropriate rc directory. If you specifically need all network drivers loaded before the bonding driver, -adding the following line to modules.conf will cause the network driver for +adding the following line to modules.conf will cause the network driver for eth0 and eth1 to be loaded before the bonding driver. probeall bond0 eth0 eth1 bonding -Be careful not to reference bond0 itself at the end of the line, or modprobe +Be careful not to reference bond0 itself at the end of the line, or modprobe will die in an endless recursive loop. -To have device characteristics (such as MTU size) propagate to slave devices, -set the bond characteristics before enslaving the device. The characteristics +To have device characteristics (such as MTU size) propagate to slave devices, +set the bond characteristics before enslaving the device. The characteristics are propagated during the enslave process. -If running SNMP agents, the bonding driver should be loaded before any network -drivers participating in a bond. This requirement is due to the the interface -index (ipAdEntIfIndex) being associated to the first interface found with a -given IP address. That is, there is only one ipAdEntIfIndex for each IP -address. For example, if eth0 and eth1 are slaves of bond0 and the driver for -eth0 is loaded before the bonding driver, the interface for the IP address -will be associated with the eth0 interface. This configuration is shown below, -the IP address 192.168.1.1 has an interface index of 2 which indexes to eth0 +If running SNMP agents, the bonding driver should be loaded before any network +drivers participating in a bond. This requirement is due to the the interface +index (ipAdEntIfIndex) being associated to the first interface found with a +given IP address. That is, there is only one ipAdEntIfIndex for each IP +address. For example, if eth0 and eth1 are slaves of bond0 and the driver for +eth0 is loaded before the bonding driver, the interface for the IP address +will be associated with the eth0 interface. This configuration is shown below, +the IP address 192.168.1.1 has an interface index of 2 which indexes to eth0 in the ifDescr table (ifDescr.2). interfaces.ifTable.ifEntry.ifDescr.1 = lo @@ -189,10 +189,10 @@ functions such as Interface_Scan_Next wi Module Parameters ================= -Optional parameters for the bonding driver can be supplied as command line -arguments to the insmod command. Typically, these parameters are specified in -the file /etc/modules.conf (see the manual page for modules.conf). The -available bonding driver parameters are listed below. If a parameter is not +Optional parameters for the bonding driver can be supplied as command line +arguments to the insmod command. Typically, these parameters are specified in +the file /etc/modules.conf (see the manual page for modules.conf). The +available bonding driver parameters are listed below. If a parameter is not specified the default value is used. When initially configuring a bond, it is recommended "tail -f /var/log/messages" be run in a separate window to watch for bonding driver error messages. @@ -202,19 +202,19 @@ parameters be specified, otherwise serio during link failures. arp_interval - - Specifies the ARP monitoring frequency in milli-seconds. - If ARP monitoring is used in a load-balancing mode (mode 0 or 2), the - switch should be configured in a mode that evenly distributes packets - across all links - such as round-robin. If the switch is configured to - distribute the packets in an XOR fashion, all replies from the ARP - targets will be received on the same link which could cause the other + + Specifies the ARP monitoring frequency in milli-seconds. + If ARP monitoring is used in a load-balancing mode (mode 0 or 2), the + switch should be configured in a mode that evenly distributes packets + across all links - such as round-robin. If the switch is configured to + distribute the packets in an XOR fashion, all replies from the ARP + targets will be received on the same link which could cause the other team members to fail. ARP monitoring should not be used in conjunction - with miimon. A value of 0 disables ARP monitoring. The default value + with miimon. A value of 0 disables ARP monitoring. The default value is 0. - + arp_ip_target - + Specifies the ip addresses to use when arp_interval is > 0. These are the targets of the ARP request sent to determine the health of the link to the targets. Specify these values in ddd.ddd.ddd.ddd @@ -223,8 +223,8 @@ arp_ip_target maximum number of targets that can be specified is set at 16. downdelay - - Specifies the delay time in milli-seconds to disable a link after a + + Specifies the delay time in milli-seconds to disable a link after a link failure has been detected. This should be a multiple of miimon value, otherwise the value will be rounded. The default value is 0. @@ -247,7 +247,7 @@ max_bonds and bond2 will be created. The default value is 1. miimon - + Specifies the frequency in milli-seconds that MII link monitoring will occur. A value of zero disables MII link monitoring. A value of 100 is a good starting point. See High Availability section for @@ -258,7 +258,7 @@ mode Specifies one of the bonding policies. The default is round-robin (balance-rr). Possible values are (you can use either the text or numeric option): - + balance-rr or 0 Round-robin policy: Transmit in a sequential order @@ -273,7 +273,7 @@ mode externally visible on only one port (network adapter) to avoid confusing the switch. This mode provides fault tolerance. - + balance-xor or 2 XOR policy: Transmit based on [(source MAC address @@ -293,7 +293,7 @@ mode groups that share the same speed and duplex settings. Transmits and receives on all slaves in the active aggregator. - + Pre-requisites: 1. Ethtool support in the base drivers for retrieving the @@ -317,7 +317,7 @@ mode Ethtool support in the base drivers for retrieving the speed of each slave. - balance-alb or 6 + balance-alb or 6 Adaptive load balancing: includes balance-tlb + receive load balancing (rlb) for IPV4 traffic and does not require @@ -327,7 +327,7 @@ mode overwrites the src hw address with the unique hw address of one of the slaves in the bond such that different clients use different hw addresses for the server. - + Receive traffic from connections created by the server is also balanced. When the server sends an ARP Request the bonding driver copies and saves the client's IP information @@ -363,25 +363,11 @@ mode 2. Base driver support for setting the hw address of a device also when it is open. This is required so that there will always be one slave in the team using the bond hw - address (the current_slave) while having a unique hw - address for each slave in the bond. If the current_slave - fails it's hw address is swapped with the new current_slave + address (the curr_active_slave) while having a unique hw + address for each slave in the bond. If the curr_active_slave + fails it's hw address is swapped with the new curr_active_slave that was chosen. -multicast - - Option specifying the mode of operation for multicast support. - Possible values are: - - disabled or 0 - Disabled (no multicast support) - - active or 1 - Enabled on active slave only, useful in active-backup mode - - all or 2 - Enabled on all slaves, this is the default - primary A string (eth0, eth2, etc) to equate to a primary device. If this @@ -397,11 +383,11 @@ primary primary is only valid in active-backup mode. updelay - - Specifies the delay time in milli-seconds to enable a link after a + + Specifies the delay time in milli-seconds to enable a link after a link up status has been detected. This should be a multiple of miimon value, otherwise the value will be rounded. The default value is 0. - + use_carrier Specifies whether or not miimon should use MII or ETHTOOL @@ -529,20 +515,20 @@ Verifying Bond Configuration ---------------------------- The bonding driver information files reside in the /proc/net/bonding directory. -Sample contents of /proc/net/bonding/bond0 after the driver is loaded with +Sample contents of /proc/net/bonding/bond0 after the driver is loaded with parameters of mode=0 and miimon=1000 is shown below. - + Bonding Mode: load balancing (round-robin) Currently Active Slave: eth0 MII Status: up MII Polling Interval (ms): 1000 Up Delay (ms): 0 Down Delay (ms): 0 - + Slave Interface: eth1 MII Status: up Link Failure Count: 1 - + Slave Interface: eth0 MII Status: up Link Failure Count: 1 @@ -550,34 +536,34 @@ parameters of mode=0 and miimon=1000 is 2) Network verification ----------------------- The network configuration can be verified using the ifconfig command. In -the example below, the bond0 interface is the master (MASTER) while eth0 and -eth1 are slaves (SLAVE). Notice all slaves of bond0 have the same MAC address +the example below, the bond0 interface is the master (MASTER) while eth0 and +eth1 are slaves (SLAVE). Notice all slaves of bond0 have the same MAC address (HWaddr) as bond0 for all modes except TLB and ALB that require a unique MAC address for each slave. [root]# /sbin/ifconfig -bond0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 +bond0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 inet addr:XXX.XXX.XXX.YYY Bcast:XXX.XXX.XXX.255 Mask:255.255.252.0 UP BROADCAST RUNNING MASTER MULTICAST MTU:1500 Metric:1 RX packets:7224794 errors:0 dropped:0 overruns:0 frame:0 TX packets:3286647 errors:1 dropped:0 overruns:1 carrier:0 - collisions:0 txqueuelen:0 + collisions:0 txqueuelen:0 -eth0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 +eth0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 inet addr:XXX.XXX.XXX.YYY Bcast:XXX.XXX.XXX.255 Mask:255.255.252.0 UP BROADCAST RUNNING SLAVE MULTICAST MTU:1500 Metric:1 RX packets:3573025 errors:0 dropped:0 overruns:0 frame:0 TX packets:1643167 errors:1 dropped:0 overruns:1 carrier:0 - collisions:0 txqueuelen:100 - Interrupt:10 Base address:0x1080 + collisions:0 txqueuelen:100 + Interrupt:10 Base address:0x1080 -eth1 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 +eth1 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 inet addr:XXX.XXX.XXX.YYY Bcast:XXX.XXX.XXX.255 Mask:255.255.252.0 UP BROADCAST RUNNING SLAVE MULTICAST MTU:1500 Metric:1 RX packets:3651769 errors:0 dropped:0 overruns:0 frame:0 TX packets:1643480 errors:0 dropped:0 overruns:0 carrier:0 - collisions:0 txqueuelen:100 - Interrupt:9 Base address:0x1400 + collisions:0 txqueuelen:100 + Interrupt:9 Base address:0x1400 Frequently Asked Questions @@ -605,9 +591,9 @@ Frequently Asked Questions 5. What happens when a slave link dies? - If your ethernet cards support MII or ETHTOOL link status monitoring - and the MII monitoring has been enabled in the driver (see description - of module parameters), there will be no adverse consequences. This + If your ethernet cards support MII or ETHTOOL link status monitoring + and the MII monitoring has been enabled in the driver (see description + of module parameters), there will be no adverse consequences. This release of the bonding driver knows how to get the MII information and enables or disables its slaves according to their link status. See section on High Availability for additional information. @@ -622,8 +608,8 @@ Frequently Asked Questions slave. If neither mii_monitor and arp_interval is configured, the bonding - driver will not handle this situation very well. The driver will - continue to send packets but some packets will be lost. Retransmits + driver will not handle this situation very well. The driver will + continue to send packets but some packets will be lost. Retransmits will cause serious degradation of performance (in the case when one of two slave links fails, 50% packets will be lost, which is a serious problem for both TCP and UDP). @@ -636,9 +622,9 @@ Frequently Asked Questions 7. Which switches/systems does it work with? - In round-robin and XOR mode, it works with systems that support + In round-robin and XOR mode, it works with systems that support trunking: - + * Many Cisco switches and routers (look for EtherChannel support). * SunTrunking software. * Alteon AceDirector switches / WebOS (use Trunks). @@ -646,7 +632,7 @@ Frequently Asked Questions models (450) can define trunks between ports on different physical units. * Linux bonding, of course ! - + In 802.3ad mode, it works with with systems that support IEEE 802.3ad Dynamic Link Aggregation: @@ -667,21 +653,21 @@ Frequently Asked Questions is then passed to all following slaves and remains persistent (even if the the first slave is removed) until the bonding device is brought down or reconfigured. - + If you wish to change the MAC address, you can set it with ifconfig: # ifconfig bond0 hw ether 00:11:22:33:44:55 The MAC address can be also changed by bringing down/up the device and then changing its slaves (or their order): - + # ifconfig bond0 down ; modprobe -r bonding # ifconfig bond0 .... up # ifenslave bond0 eth... This method will automatically take the address from the next slave that will be added. - + To restore your slaves' MAC addresses, you need to detach them from the bond (`ifenslave -d bond0 eth0'), set them down (`ifconfig eth0 down'), unload the drivers (`rmmod 3c59x', for @@ -729,27 +715,27 @@ High Availability ================= To implement high availability using the bonding driver, the driver needs to be -compiled as a module, because currently it is the only way to pass parameters +compiled as a module, because currently it is the only way to pass parameters to the driver. This may change in the future. -High availability is achieved by using MII or ETHTOOL status reporting. You -need to verify that all your interfaces support MII or ETHTOOL link status -reporting. On Linux kernel 2.2.17, all the 100 Mbps capable drivers and -yellowfin gigabit driver support MII. To determine if ETHTOOL link reporting -is available for interface eth0, type "ethtool eth0" and the "Link detected:" -line should contain the correct link status. If your system has an interface -that does not support MII or ETHTOOL status reporting, a failure of its link -will not be detected! A message indicating MII and ETHTOOL is not supported by -a network driver is logged when the bonding driver is loaded with a non-zero +High availability is achieved by using MII or ETHTOOL status reporting. You +need to verify that all your interfaces support MII or ETHTOOL link status +reporting. On Linux kernel 2.2.17, all the 100 Mbps capable drivers and +yellowfin gigabit driver support MII. To determine if ETHTOOL link reporting +is available for interface eth0, type "ethtool eth0" and the "Link detected:" +line should contain the correct link status. If your system has an interface +that does not support MII or ETHTOOL status reporting, a failure of its link +will not be detected! A message indicating MII and ETHTOOL is not supported by +a network driver is logged when the bonding driver is loaded with a non-zero miimon value. The bonding driver can regularly check all its slaves links using the ETHTOOL -IOCTL (ETHTOOL_GLINK command) or by checking the MII status registers. The -check interval is specified by the module argument "miimon" (MII monitoring). -It takes an integer that represents the checking time in milliseconds. It -should not come to close to (1000/HZ) (10 milli-seconds on i386) because it -may then reduce the system interactivity. A value of 100 seems to be a good -starting point. It means that a dead link will be detected at most 100 +IOCTL (ETHTOOL_GLINK command) or by checking the MII status registers. The +check interval is specified by the module argument "miimon" (MII monitoring). +It takes an integer that represents the checking time in milliseconds. It +should not come to close to (1000/HZ) (10 milli-seconds on i386) because it +may then reduce the system interactivity. A value of 100 seems to be a good +starting point. It means that a dead link will be detected at most 100 milli-seconds after it goes down. Example: @@ -761,7 +747,7 @@ Or, put the following lines in /etc/modu alias bond0 bonding options bond0 miimon=100 -There are currently two policies for high availability. They are dependent on +There are currently two policies for high availability. They are dependent on whether: a) hosts are connected to a single host or switch that support trunking @@ -811,7 +797,7 @@ Example 2 : host to switch at twice the # ifenslave bond0 eth0 eth1 -2) High Availability on two or more switches (or a single switch without +2) High Availability on two or more switches (or a single switch without trunking support) --------------------------------------------------------------------------- This mode is more problematic because it relies on the fact that there @@ -870,10 +856,10 @@ by another external mechanism, it is goo connected to one switch and host2's to the other. Such system will survive a failure of a single host, cable, or switch. The worst thing that may happen in the case of a switch failure is that half of the hosts will be temporarily -unreachable until the other switch expires its tables. +unreachable until the other switch expires its tables. Example 2: Using multiple ethernet cards connected to a switch to configure - NIC failover (switch is not required to support trunking). + NIC failover (switch is not required to support trunking). +----------+ +----------+ @@ -957,7 +943,7 @@ The main limitations are : servers, but may be useful when the front switches send multicast information on their links (e.g. VRRP), or even health-check the servers. Use the arp_interval/arp_ip_target parameters to count incoming/outgoing - frames. + frames. @@ -973,13 +959,12 @@ Donald Becker's Ethernet Drivers and dia You will also find a lot of information regarding Ethernet, NWay, MII, etc. at www.scyld.com. -For new versions of the driver, patches for older kernels and the updated -userspace tools, take a look at Willy Tarreau's site : +Patches for 2.2 kernels are at Willy Tarreau's site : - http://wtarreau.free.fr/pub/bonding/ - - http://www-miaif.lip6.fr/willy/pub/bonding/ + - http://www-miaif.lip6.fr/~tarreau/pub/bonding/ To get latest informations about Linux Kernel development, please consult the Linux Kernel Mailing List Archives at : - http://boudicca.tux.org/hypermail/linux-kernel/latest/ + http://www.ussg.iu.edu/hypermail/linux/kernel/ -- END -- diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/Documentation/networking/ifenslave.c 830-ivtv/Documentation/networking/ifenslave.c --- 000-virgin/Documentation/networking/ifenslave.c Mon Nov 17 18:28:29 2003 +++ 830-ivtv/Documentation/networking/ifenslave.c Thu Jan 8 08:54:03 2004 @@ -4,8 +4,6 @@ * This program controls the Linux implementation of running multiple * network interfaces in parallel. * - * Usage: ifenslave [-v] master-interface < slave-interface [metric ] > ... - * * Author: Donald Becker * Copyright 1994-1996 Donald Becker * @@ -90,24 +88,30 @@ * - For opt_c: slave should not be set to the master's setting * while it is running. It was already set during enslave. To * simplify things, it is now handeled separately. + * + * - 2003/09/24 - Shmulik Hen + * - Code cleanup and style changes + * set version to 1.1.0 */ -#define APP_VERSION "1.0.12" -#define APP_RELDATE "June 30, 2003" +#define APP_VERSION "1.1.0" +#define APP_RELDATE "Septemer 24, 2003" #define APP_NAME "ifenslave" static char *version = -APP_NAME ".c:v" APP_VERSION " (" APP_RELDATE ") " "\nDonald Becker (becker@cesdis.gsfc.nasa.gov).\n" -"detach support added on 2000/10/02 by Willy Tarreau (willy at meta-x.org).\n" -"2.4 kernel support added on 2001/02/16 by Chad N. Tindel (ctindel at ieee dot org.\n"; +APP_NAME ".c:v" APP_VERSION " (" APP_RELDATE ")\n" +"o Donald Becker (becker@cesdis.gsfc.nasa.gov).\n" +"o Detach support added on 2000/10/02 by Willy Tarreau (willy at meta-x.org).\n" +"o 2.4 kernel support added on 2001/02/16 by Chad N. Tindel\n" +" (ctindel at ieee dot org).\n"; static const char *usage_msg = -"Usage: ifenslave [-adfrvVh] < [metric ] > ...\n" -" ifenslave -c master-interface slave-if\n"; +"Usage: ifenslave [-f] [...]\n" +" ifenslave -d [...]\n" +" ifenslave -c \n" +" ifenslave --help\n"; -static const char *howto_msg = -"Usage: ifenslave [-adfrvVh] < [metric ] > ...\n" -" ifenslave -c master-interface slave-if\n" +static const char *help_msg = "\n" " To create a bond device, simply follow these three steps :\n" " - ensure that the required drivers are properly loaded :\n" @@ -115,18 +119,32 @@ static const char *howto_msg = " - assign an IP address to the bond device :\n" " # ifconfig bond0 netmask broadcast \n" " - attach all the interfaces you need to the bond device :\n" -" # ifenslave bond0 eth0 eth1 eth2\n" +" # ifenslave [{-f|--force}] bond0 eth0 [eth1 [eth2]...]\n" " If bond0 didn't have a MAC address, it will take eth0's. Then, all\n" " interfaces attached AFTER this assignment will get the same MAC addr.\n" -"\n" -" To detach a dead interface without setting the bond device down :\n" -" # ifenslave -d bond0 eth1\n" +" (except for ALB/TLB modes)\n" "\n" " To set the bond device down and automatically release all the slaves :\n" " # ifconfig bond0 down\n" "\n" +" To detach a dead interface without setting the bond device down :\n" +" # ifenslave {-d|--detach} bond0 eth0 [eth1 [eth2]...]\n" +"\n" " To change active slave :\n" -" # ifenslave -c bond0 eth0\n" +" # ifenslave {-c|--change-active} bond0 eth0\n" +"\n" +" To show master interface info\n" +" # ifenslave bond0\n" +"\n" +" To show all interfaces info\n" +" # ifenslave {-a|--all-interfaces}\n" +"\n" +" To be more verbose\n" +" # ifenslave {-v|--verbose} ...\n" +"\n" +" # ifenslave {-u|--usage} Show usage\n" +" # ifenslave {-V|--version} Show version\n" +" # ifenslave {-h|--help} This message\n" "\n"; #include @@ -153,476 +171,332 @@ typedef __uint8_t u8; /* ditto */ #include struct option longopts[] = { - /* { name has_arg *flag val } */ - {"all-interfaces", 0, 0, 'a'}, /* Show all interfaces. */ - {"force", 0, 0, 'f'}, /* Force the operation. */ - {"help", 0, 0, '?'}, /* Give help */ - {"howto", 0, 0, 'h'}, /* Give some more help */ - {"receive-slave", 0, 0, 'r'}, /* Make a receive-only slave. */ - {"verbose", 0, 0, 'v'}, /* Report each action taken. */ - {"version", 0, 0, 'V'}, /* Emit version information. */ - {"detach", 0, 0, 'd'}, /* Detach a slave interface. */ - {"change-active", 0, 0, 'c'}, /* Change the active slave. */ - { 0, 0, 0, 0 } + /* { name has_arg *flag val } */ + {"all-interfaces", 0, 0, 'a'}, /* Show all interfaces. */ + {"change-active", 0, 0, 'c'}, /* Change the active slave. */ + {"detach", 0, 0, 'd'}, /* Detach a slave interface. */ + {"force", 0, 0, 'f'}, /* Force the operation. */ + {"help", 0, 0, 'h'}, /* Give help */ + {"usage", 0, 0, 'u'}, /* Give usage */ + {"verbose", 0, 0, 'v'}, /* Report each action taken. */ + {"version", 0, 0, 'V'}, /* Emit version information. */ + { 0, 0, 0, 0} }; /* Command-line flags. */ unsigned int -opt_a = 0, /* Show-all-interfaces flag. */ -opt_f = 0, /* Force the operation. */ -opt_r = 0, /* Set up a Rx-only slave. */ -opt_d = 0, /* detach a slave interface. */ -opt_c = 0, /* change-active-slave flag. */ -verbose = 0, /* Verbose flag. */ -opt_version = 0, -opt_howto = 0; -int skfd = -1; /* AF_INET socket for ioctl() calls. */ +opt_a = 0, /* Show-all-interfaces flag. */ +opt_c = 0, /* Change-active-slave flag. */ +opt_d = 0, /* Detach a slave interface. */ +opt_f = 0, /* Force the operation. */ +opt_h = 0, /* Help */ +opt_u = 0, /* Usage */ +opt_v = 0, /* Verbose flag. */ +opt_V = 0; /* Version */ + +int skfd = -1; /* AF_INET socket for ioctl() calls.*/ +int abi_ver = 0; /* userland - kernel ABI version */ +int hwaddr_set = 0; /* Master's hwaddr is set */ +int saved_errno; + +struct ifreq master_mtu, master_flags, master_hwaddr; +struct ifreq slave_mtu, slave_flags, slave_hwaddr; + +struct dev_ifr { + struct ifreq *req_ifr; + char *req_name; + int req_type; +}; + +struct dev_ifr master_ifra[] = { + {&master_mtu, "SIOCGIFMTU", SIOCGIFMTU}, + {&master_flags, "SIOCGIFFLAGS", SIOCGIFFLAGS}, + {&master_hwaddr, "SIOCGIFHWADDR", SIOCGIFHWADDR}, + {NULL, "", 0} +}; + +struct dev_ifr slave_ifra[] = { + {&slave_mtu, "SIOCGIFMTU", SIOCGIFMTU}, + {&slave_flags, "SIOCGIFFLAGS", SIOCGIFFLAGS}, + {&slave_hwaddr, "SIOCGIFHWADDR", SIOCGIFHWADDR}, + {NULL, "", 0} +}; static void if_print(char *ifname); -static int get_abi_ver(char *master_ifname); +static int get_drv_info(char *master_ifname); +static int get_if_settings(char *ifname, struct dev_ifr ifra[]); +static int get_slave_flags(char *slave_ifname); +static int set_master_hwaddr(char *master_ifname, struct sockaddr *hwaddr); +static int set_slave_hwaddr(char *slave_ifname, struct sockaddr *hwaddr); +static int set_slave_mtu(char *slave_ifname, int mtu); +static int set_if_flags(char *ifname, short flags); +static int set_if_up(char *ifname, short flags); +static int set_if_down(char *ifname, short flags); +static int clear_if_addr(char *ifname); +static int set_if_addr(char *master_ifname, char *slave_ifname); +static int change_active(char *master_ifname, char *slave_ifname); +static int enslave(char *master_ifname, char *slave_ifname); +static int release(char *master_ifname, char *slave_ifname); +#define v_print(fmt, args...) \ + if (opt_v) \ + fprintf(stderr, fmt, ## args ) -int -main(int argc, char **argv) +int main(int argc, char *argv[]) { - struct ifreq ifr2, if_hwaddr, if_ipaddr, if_metric, if_mtu, if_dstaddr; - struct ifreq if_netmask, if_brdaddr, if_flags; - int rv, goterr = 0; - int c, errflag = 0; - sa_family_t master_family; char **spp, *master_ifname, *slave_ifname; - int hwaddr_notset; - int abi_ver = 0; + int c, i, rv; + int res = 0; + int exclusive = 0; - while ((c = getopt_long(argc, argv, "acdfrvV?h", longopts, 0)) != EOF) + while ((c = getopt_long(argc, argv, "acdfhuvV", longopts, 0)) != EOF) { switch (c) { - case 'a': opt_a++; break; - case 'f': opt_f++; break; - case 'r': opt_r++; break; - case 'd': opt_d++; break; - case 'c': opt_c++; break; - case 'v': verbose++; break; - case 'V': opt_version++; break; - case 'h': opt_howto++; break; - case '?': errflag++; - } + case 'a': opt_a++; exclusive++; break; + case 'c': opt_c++; exclusive++; break; + case 'd': opt_d++; exclusive++; break; + case 'f': opt_f++; exclusive++; break; + case 'h': opt_h++; exclusive++; break; + case 'u': opt_u++; exclusive++; break; + case 'v': opt_v++; break; + case 'V': opt_V++; exclusive++; break; - /* option check */ - if (opt_c) - if(opt_a || opt_f || opt_r || opt_d || verbose || opt_version || - opt_howto || errflag ) { + case '?': fprintf(stderr, usage_msg); - return 2; + res = 2; + goto out; } + } - if (errflag) { + /* options check */ + if (exclusive > 1) { fprintf(stderr, usage_msg); - return 2; + res = 2; + goto out; } - if (opt_howto) { - fprintf(stderr, howto_msg); - return 0; + if (opt_v || opt_V) { + printf(version); + if (opt_V) { + res = 0; + goto out; + } } - if (verbose || opt_version) { - printf(version); - if (opt_version) - exit(0); + if (opt_u) { + printf(usage_msg); + res = 0; + goto out; } - /* Open a basic socket. */ - if ((skfd = socket(AF_INET, SOCK_DGRAM,0)) < 0) { - perror("socket"); - exit(-1); + if (opt_h) { + printf(usage_msg); + printf(help_msg); + res = 0; + goto out; } - if (verbose) - fprintf(stderr, "DEBUG: argc=%d, optind=%d and argv[optind] is %s.\n", - argc, optind, argv[optind]); + /* Open a basic socket */ + if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("socket"); + res = 1; + goto out; + } - /* No remaining args means show all interfaces. */ - if (optind == argc) { - if_print((char *)NULL); - (void) close(skfd); - exit(0); + if (opt_a) { + if (optind == argc) { + /* No remaining args */ + /* show all interfaces */ + if_print((char *)NULL); + goto out; + } else { + /* Just show usage */ + fprintf(stderr, usage_msg); + res = 2; + goto out; + } } - /* Copy the interface name. */ + /* Copy the interface name */ spp = argv + optind; master_ifname = *spp++; - slave_ifname = *spp++; - /* Check command line. */ - if (opt_c) { - char **tempp = spp; - if ((master_ifname == NULL)||(slave_ifname == NULL)||(*tempp++ != NULL)) { - fprintf(stderr, usage_msg); - (void) close(skfd); - return 2; - } + if (master_ifname == NULL) { + fprintf(stderr, usage_msg); + res = 2; + goto out; } - /* A single args means show the configuration for this interface. */ - if (slave_ifname == NULL) { - if_print(master_ifname); - (void) close(skfd); - exit(0); + /* exchange abi version with bonding module */ + res = get_drv_info(master_ifname); + if (res) { + fprintf(stderr, + "Master '%s': Error: handshake with driver failed. " + "Aborting\n", + master_ifname); + goto out; } - /* exchange abi version with bonding driver */ - abi_ver = get_abi_ver(master_ifname); - if (abi_ver < 0) { - (void) close(skfd); - exit(1); - } - - /* Get the vitals from the master interface. */ - { - struct ifreq *ifra[7] = { &if_ipaddr, &if_mtu, &if_dstaddr, - &if_brdaddr, &if_netmask, &if_flags, - &if_hwaddr }; - const char *req_name[7] = { - "IP address", "MTU", "destination address", - "broadcast address", "netmask", "status flags", - "hardware address" }; - const int ioctl_req_type[7] = { - SIOCGIFADDR, SIOCGIFMTU, SIOCGIFDSTADDR, - SIOCGIFBRDADDR, SIOCGIFNETMASK, SIOCGIFFLAGS, - SIOCGIFHWADDR }; - int i; - - for (i = 0; i < 7; i++) { - strncpy(ifra[i]->ifr_name, master_ifname, IFNAMSIZ); - if (ioctl(skfd, ioctl_req_type[i], ifra[i]) < 0) { - fprintf(stderr, - "Something broke getting the master's %s: %s.\n", - req_name[i], strerror(errno)); - } - } - - /* check if master is up; if not then fail any operation */ - if (!(if_flags.ifr_flags & IFF_UP)) { - fprintf(stderr, "Illegal operation; the specified master interface '%s' is not up.\n", master_ifname); - (void) close(skfd); - exit (1); - } + slave_ifname = *spp++; - hwaddr_notset = 1; /* assume master's address not set yet */ - for (i = 0; hwaddr_notset && (i < 6); i++) { - hwaddr_notset &= ((unsigned char *)if_hwaddr.ifr_hwaddr.sa_data)[i] == 0; + if (slave_ifname == NULL) { + if (opt_d || opt_c) { + fprintf(stderr, usage_msg); + res = 2; + goto out; } - /* The family '1' is ARPHRD_ETHER for ethernet. */ - if (if_hwaddr.ifr_hwaddr.sa_family != 1 && !opt_f) { - fprintf(stderr, "The specified master interface '%s' is not" - " ethernet-like.\n This program is designed to work" - " with ethernet-like network interfaces.\n" - " Use the '-f' option to force the operation.\n", - master_ifname); - (void) close(skfd); - exit (1); - } - master_family = if_hwaddr.ifr_hwaddr.sa_family; - if (verbose) { - unsigned char *hwaddr = (unsigned char *)if_hwaddr.ifr_hwaddr.sa_data; - printf("The current hardware address (SIOCGIFHWADDR) of %s is type %d " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", master_ifname, - if_hwaddr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1], - hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); - } + /* A single arg means show the + * configuration for this interface + */ + if_print(master_ifname); + goto out; } + res = get_if_settings(master_ifname, master_ifra); + if (res) { + /* Probably a good reason not to go on */ + fprintf(stderr, + "Master '%s': Error: get settings failed: %s. " + "Aborting\n", + master_ifname, strerror(res)); + goto out; + } - /* do this when enslaving interfaces */ - do { - if (opt_d) { /* detach a slave interface from the master */ - strncpy(if_flags.ifr_name, master_ifname, IFNAMSIZ); - strncpy(if_flags.ifr_slave, slave_ifname, IFNAMSIZ); - if ((ioctl(skfd, SIOCBONDRELEASE, &if_flags) < 0) && - (ioctl(skfd, BOND_RELEASE_OLD, &if_flags) < 0)) { - fprintf(stderr, "SIOCBONDRELEASE: cannot detach %s from %s. errno=%s.\n", - slave_ifname, master_ifname, strerror(errno)); - } - else if (abi_ver < 1) { - /* The driver is using an old ABI, so we'll set the interface - * down to avoid any conflicts due to same IP/MAC - */ - strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ); - if (ioctl(skfd, SIOCGIFFLAGS, &ifr2) < 0) { - int saved_errno = errno; - fprintf(stderr, "SIOCGIFFLAGS on %s failed: %s\n", slave_ifname, - strerror(saved_errno)); - } - else { - ifr2.ifr_flags &= ~(IFF_UP | IFF_RUNNING); - if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { - int saved_errno = errno; - fprintf(stderr, "Shutting down interface %s failed: %s\n", - slave_ifname, strerror(saved_errno)); - } - } - } - } else if (opt_c) { /* change primary slave */ - strncpy(if_flags.ifr_name, master_ifname, IFNAMSIZ); - strncpy(if_flags.ifr_slave, slave_ifname, IFNAMSIZ); - if ((ioctl(skfd, SIOCBONDCHANGEACTIVE, &if_flags) < 0) && - (ioctl(skfd, BOND_CHANGE_ACTIVE_OLD, &if_flags) < 0)) { - fprintf(stderr, "SIOCBONDCHANGEACTIVE: %s.\n", strerror(errno)); - } - } else { /* attach a slave interface to the master */ - - strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ); - if (ioctl(skfd, SIOCGIFFLAGS, &ifr2) < 0) { - int saved_errno = errno; - fprintf(stderr, "SIOCGIFFLAGS on %s failed: %s\n", slave_ifname, - strerror(saved_errno)); - (void) close(skfd); - return 1; - } - - if ((ifr2.ifr_flags & IFF_SLAVE) && !opt_r) { - fprintf(stderr, "%s is already a slave\n", slave_ifname); - (void) close(skfd); - return 1; - } - - /* if hwaddr_notset, assign the slave hw address to the master */ - if (hwaddr_notset) { - /* assign the slave hw address to the - * master since it currently does not - * have one; otherwise, slaves may - * have different hw addresses in - * active-backup mode as seen when enslaving - * using "ifenslave bond0 eth0 eth1" because - * hwaddr_notset is set outside this loop. - * TODO: put this and the "else" portion in - * a function. - */ - /* get the slaves MAC address */ - strncpy(if_hwaddr.ifr_name, slave_ifname, - IFNAMSIZ); - rv = ioctl(skfd, SIOCGIFHWADDR, &if_hwaddr); - if (-1 == rv) { - fprintf(stderr, "Could not get MAC " - "address of %s: %s\n", - slave_ifname, - strerror(errno)); - strncpy(if_hwaddr.ifr_name, - master_ifname, IFNAMSIZ); - goterr = 1; - } - - if (!goterr) { - if (abi_ver < 1) { - /* In ABI versions older than 1, the - * master's set_mac routine couldn't - * work if it was up, because it - * used the default ethernet set_mac - * function. - */ - /* bring master down */ - if_flags.ifr_flags &= ~IFF_UP; - if (ioctl(skfd, SIOCSIFFLAGS, - &if_flags) < 0) { - goterr = 1; - fprintf(stderr, - "Shutting down " - "interface %s failed: " - "%s\n", - master_ifname, - strerror(errno)); - } - } - - strncpy(if_hwaddr.ifr_name, - master_ifname, IFNAMSIZ); - if (ioctl(skfd, SIOCSIFHWADDR, - &if_hwaddr) < 0) { - fprintf(stderr, - "Could not set MAC " - "address of %s: %s\n", - master_ifname, - strerror(errno)); - goterr=1; - } else { - hwaddr_notset = 0; - } - - if (abi_ver < 1) { - /* bring master back up */ - if_flags.ifr_flags |= IFF_UP; - if (ioctl(skfd, SIOCSIFFLAGS, - &if_flags) < 0) { - fprintf(stderr, - "Bringing up interface " - "%s failed: %s\n", - master_ifname, - strerror(errno)); - } - } - } - } else if (abi_ver < 1) { /* if (hwaddr_notset) */ - - /* The driver is using an old ABI, so we'll set the interface - * down and assign the master's hwaddr to it - */ - if (ifr2.ifr_flags & IFF_UP) { - ifr2.ifr_flags &= ~IFF_UP; - if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { - int saved_errno = errno; - fprintf(stderr, "Shutting down interface %s failed: %s\n", - slave_ifname, strerror(saved_errno)); - } - } - - strncpy(if_hwaddr.ifr_name, slave_ifname, IFNAMSIZ); - if (ioctl(skfd, SIOCSIFHWADDR, &if_hwaddr) < 0) { - int saved_errno = errno; - fprintf(stderr, "SIOCSIFHWADDR on %s failed: %s\n", if_hwaddr.ifr_name, - strerror(saved_errno)); - if (saved_errno == EBUSY) - fprintf(stderr, " The slave device %s is busy: it must be" - " idle before running this command.\n", slave_ifname); - else if (saved_errno == EOPNOTSUPP) - fprintf(stderr, " The slave device you specified does not support" - " setting the MAC address.\n Your kernel likely does not" - " support slave devices.\n"); - else if (saved_errno == EINVAL) - fprintf(stderr, " The slave device's address type does not match" - " the master's address type.\n"); - } else { - if (verbose) { - unsigned char *hwaddr = if_hwaddr.ifr_hwaddr.sa_data; - printf("Slave's (%s) hardware address set to " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", slave_ifname, - hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); - } - } - } + /* check if master is indeed a master; + * if not then fail any operation + */ + if (!(master_flags.ifr_flags & IFF_MASTER)) { + fprintf(stderr, + "Illegal operation; the specified interface '%s' " + "is not a master. Aborting\n", + master_ifname); + res = 1; + goto out; + } - if (*spp && !strcmp(*spp, "metric")) { - if (*++spp == NULL) { - fprintf(stderr, usage_msg); - (void) close(skfd); - exit(2); - } - if_metric.ifr_metric = atoi(*spp); - strncpy(if_metric.ifr_name, slave_ifname, IFNAMSIZ); - if (ioctl(skfd, SIOCSIFMETRIC, &if_metric) < 0) { - fprintf(stderr, "SIOCSIFMETRIC on %s: %s\n", slave_ifname, - strerror(errno)); - goterr = 1; - } - spp++; - } + /* check if master is up; if not then fail any operation */ + if (!(master_flags.ifr_flags & IFF_UP)) { + fprintf(stderr, + "Illegal operation; the specified master interface " + "'%s' is not up.\n", + master_ifname); + res = 1; + goto out; + } - if (strncpy(if_ipaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFADDR, &if_ipaddr) < 0) { - fprintf(stderr, - "Something broke setting the slave's address: %s.\n", - strerror(errno)); - } else { - if (verbose) { - unsigned char *ipaddr = if_ipaddr.ifr_addr.sa_data; - printf("Set the slave's (%s) IP address to %d.%d.%d.%d.\n", - slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); - } - } + /* Only for enslaving */ + if (!opt_c && !opt_d) { + sa_family_t master_family = master_hwaddr.ifr_hwaddr.sa_family; + unsigned char *hwaddr = + (unsigned char *)master_hwaddr.ifr_hwaddr.sa_data; - if (strncpy(if_mtu.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFMTU, &if_mtu) < 0) { - fprintf(stderr, "Something broke setting the slave MTU: %s.\n", - strerror(errno)); - } else { - if (verbose) - printf("Set the slave's (%s) MTU to %d.\n", slave_ifname, if_mtu.ifr_mtu); - } + /* The family '1' is ARPHRD_ETHER for ethernet. */ + if (master_family != 1 && !opt_f) { + fprintf(stderr, + "Illegal operation: The specified master " + "interface '%s' is not ethernet-like.\n " + "This program is designed to work with " + "ethernet-like network interfaces.\n " + "Use the '-f' option to force the " + "operation.\n", + master_ifname); + res = 1; + goto out; + } - if (strncpy(if_dstaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFDSTADDR, &if_dstaddr) < 0) { - fprintf(stderr, "Error setting the slave (%s) with SIOCSIFDSTADDR: %s.\n", - slave_ifname, strerror(errno)); - } else { - if (verbose) { - unsigned char *ipaddr = if_dstaddr.ifr_dstaddr.sa_data; - printf("Set the slave's (%s) destination address to %d.%d.%d.%d.\n", - slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); - } + /* Check master's hw addr */ + for (i = 0; i < 6; i++) { + if (hwaddr[i] != 0) { + hwaddr_set = 1; + break; } + } - if (strncpy(if_brdaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFBRDADDR, &if_brdaddr) < 0) { - fprintf(stderr, - "Something broke setting the slave (%s) broadcast address: %s.\n", - slave_ifname, strerror(errno)); - } else { - if (verbose) { - unsigned char *ipaddr = if_brdaddr.ifr_broadaddr.sa_data; - printf("Set the slave's (%s) broadcast address to %d.%d.%d.%d.\n", - slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); - } - } + if (hwaddr_set) { + v_print("current hardware address of master '%s' " + "is %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " + "type %d\n", + master_ifname, + hwaddr[0], hwaddr[1], + hwaddr[2], hwaddr[3], + hwaddr[4], hwaddr[5], + master_family); + } + } - if (strncpy(if_netmask.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFNETMASK, &if_netmask) < 0) { - fprintf(stderr, - "Something broke setting the slave (%s) netmask: %s.\n", - slave_ifname, strerror(errno)); - } else { - if (verbose) { - unsigned char *ipaddr = if_netmask.ifr_netmask.sa_data; - printf("Set the slave's (%s) netmask to %d.%d.%d.%d.\n", - slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); + /* Accepts only one slave */ + if (opt_c) { + /* change active slave */ + res = get_slave_flags(slave_ifname); + if (res) { + fprintf(stderr, + "Slave '%s': Error: get flags failed. " + "Aborting\n", + slave_ifname); + goto out; + } + res = change_active(master_ifname, slave_ifname); + if (res) { + fprintf(stderr, + "Master '%s', Slave '%s': Error: " + "Change active failed\n", + master_ifname, slave_ifname); + } + } else { + /* Accept multiple slaves */ + do { + if (opt_d) { + /* detach a slave interface from the master */ + rv = get_slave_flags(slave_ifname); + if (rv) { + /* Can't work with this slave. */ + /* remember the error and skip it*/ + fprintf(stderr, + "Slave '%s': Error: get flags " + "failed. Skipping\n", + slave_ifname); + res = rv; + continue; } - } - - if (abi_ver < 1) { - - /* The driver is using an old ABI, so we'll set the interface - * up before enslaving it - */ - ifr2.ifr_flags |= IFF_UP; - if ((ifr2.ifr_flags &= ~(IFF_SLAVE | IFF_MASTER)) == 0 - || strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { - fprintf(stderr, - "Something broke setting the slave (%s) flags: %s.\n", - slave_ifname, strerror(errno)); - } else { - if (verbose) - printf("Set the slave's (%s) flags %4.4x.\n", - slave_ifname, if_flags.ifr_flags); + rv = release(master_ifname, slave_ifname); + if (rv) { + fprintf(stderr, + "Master '%s', Slave '%s': Error: " + "Release failed\n", + master_ifname, slave_ifname); + res = rv; } } else { - /* the bonding module takes care of setting the slave's mac address - * and opening its interface - */ - if (ifr2.ifr_flags & IFF_UP) { /* the interface will need to be down */ - ifr2.ifr_flags &= ~IFF_UP; - if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { - int saved_errno = errno; - fprintf(stderr, "Shutting down interface %s failed: %s\n", - slave_ifname, strerror(saved_errno)); - } + /* attach a slave interface to the master */ + rv = get_if_settings(slave_ifname, slave_ifra); + if (rv) { + /* Can't work with this slave. */ + /* remember the error and skip it*/ + fprintf(stderr, + "Slave '%s': Error: get " + "settings failed: %s. " + "Skipping\n", + slave_ifname, strerror(rv)); + res = rv; + continue; } - } - - /* Do the real thing */ - if (!opt_r) { - strncpy(if_flags.ifr_name, master_ifname, IFNAMSIZ); - strncpy(if_flags.ifr_slave, slave_ifname, IFNAMSIZ); - if ((ioctl(skfd, SIOCBONDENSLAVE, &if_flags) < 0) && - (ioctl(skfd, BOND_ENSLAVE_OLD, &if_flags) < 0)) { - fprintf(stderr, "SIOCBONDENSLAVE: %s.\n", strerror(errno)); + rv = enslave(master_ifname, slave_ifname); + if (rv) { + fprintf(stderr, + "Master '%s', Slave '%s': Error: " + "Enslave failed\n", + master_ifname, slave_ifname); + res = rv; } } - } - } while ( (slave_ifname = *spp++) != NULL); + } while ((slave_ifname = *spp++) != NULL); + } - /* Close the socket. */ - (void) close(skfd); +out: + if (skfd >= 0) { + close(skfd); + } - return(goterr); + return res; } static short mif_flags; @@ -631,35 +505,34 @@ static short mif_flags; static int if_getconfig(char *ifname) { struct ifreq ifr; - int metric, mtu; /* Parameters of the master interface. */ + int metric, mtu; /* Parameters of the master interface. */ struct sockaddr dstaddr, broadaddr, netmask; + unsigned char *hwaddr; strcpy(ifr.ifr_name, ifname); if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) return -1; mif_flags = ifr.ifr_flags; printf("The result of SIOCGIFFLAGS on %s is %x.\n", - ifname, ifr.ifr_flags); + ifname, ifr.ifr_flags); strcpy(ifr.ifr_name, ifname); if (ioctl(skfd, SIOCGIFADDR, &ifr) < 0) return -1; printf("The result of SIOCGIFADDR is %2.2x.%2.2x.%2.2x.%2.2x.\n", - ifr.ifr_addr.sa_data[0], ifr.ifr_addr.sa_data[1], - ifr.ifr_addr.sa_data[2], ifr.ifr_addr.sa_data[3]); + ifr.ifr_addr.sa_data[0], ifr.ifr_addr.sa_data[1], + ifr.ifr_addr.sa_data[2], ifr.ifr_addr.sa_data[3]); strcpy(ifr.ifr_name, ifname); if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) return -1; - { - /* Gotta convert from 'char' to unsigned for printf(). */ - unsigned char *hwaddr = (unsigned char *)ifr.ifr_hwaddr.sa_data; - printf("The result of SIOCGIFHWADDR is type %d " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", - ifr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1], - hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); - } + /* Gotta convert from 'char' to unsigned for printf(). */ + hwaddr = (unsigned char *)ifr.ifr_hwaddr.sa_data; + printf("The result of SIOCGIFHWADDR is type %d " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", + ifr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1], + hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); strcpy(ifr.ifr_name, ifname); if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0) { @@ -691,7 +564,7 @@ static int if_getconfig(char *ifname) } else netmask = ifr.ifr_netmask; - return(0); + return 0; } static void if_print(char *ifname) @@ -705,15 +578,16 @@ static void if_print(char *ifname) ifc.ifc_len = sizeof(buff); ifc.ifc_buf = buff; if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) { - fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno)); + perror("SIOCGIFCONF failed"); return; } ifr = ifc.ifc_req; for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) { if (if_getconfig(ifr->ifr_name) < 0) { - fprintf(stderr, "%s: unknown interface.\n", - ifr->ifr_name); + fprintf(stderr, + "%s: unknown interface.\n", + ifr->ifr_name); continue; } @@ -721,16 +595,18 @@ static void if_print(char *ifname) /*ife_print(&ife);*/ } } else { - if (if_getconfig(ifname) < 0) - fprintf(stderr, "%s: unknown interface.\n", ifname); + if (if_getconfig(ifname) < 0) { + fprintf(stderr, + "%s: unknown interface.\n", ifname); + } } } -static int get_abi_ver(char *master_ifname) +static int get_drv_info(char *master_ifname) { struct ifreq ifr; struct ethtool_drvinfo info; - int abi_ver = 0; + char *endptr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); @@ -739,24 +615,487 @@ static int get_abi_ver(char *master_ifna info.cmd = ETHTOOL_GDRVINFO; strncpy(info.driver, "ifenslave", 32); snprintf(info.fw_version, 32, "%d", BOND_ABI_VERSION); - if (ioctl(skfd, SIOCETHTOOL, &ifr) >= 0) { - char *endptr; - abi_ver = strtoul(info.fw_version, &endptr, 0); - if (*endptr) { - fprintf(stderr, "Error: got invalid string as an ABI " - "version from the bonding module\n"); - return -1; + if (ioctl(skfd, SIOCETHTOOL, &ifr) < 0) { + if (errno == EOPNOTSUPP) { + goto out; } + + saved_errno = errno; + v_print("Master '%s': Error: get bonding info failed %s\n", + master_ifname, strerror(saved_errno)); + return 1; } - if (verbose) { - printf("ABI ver is %d\n", abi_ver); + abi_ver = strtoul(info.fw_version, &endptr, 0); + if (*endptr) { + v_print("Master '%s': Error: got invalid string as an ABI " + "version from the bonding module\n", + master_ifname); + return 1; } - return abi_ver; + +out: + v_print("ABI ver is %d\n", abi_ver); + + return 0; } +static int change_active(char *master_ifname, char *slave_ifname) +{ + struct ifreq ifr; + int res = 0; + if (!(slave_flags.ifr_flags & IFF_SLAVE)) { + fprintf(stderr, + "Illegal operation: The specified slave interface " + "'%s' is not a slave\n", + slave_ifname); + return 1; + } + + strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); + strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ); + if ((ioctl(skfd, SIOCBONDCHANGEACTIVE, &ifr) < 0) && + (ioctl(skfd, BOND_CHANGE_ACTIVE_OLD, &ifr) < 0)) { + saved_errno = errno; + v_print("Master '%s': Error: SIOCBONDCHANGEACTIVE failed: " + "%s\n", + master_ifname, strerror(saved_errno)); + res = 1; + } + + return res; +} + +static int enslave(char *master_ifname, char *slave_ifname) +{ + struct ifreq ifr; + int res = 0; + + if (slave_flags.ifr_flags & IFF_SLAVE) { + fprintf(stderr, + "Illegal operation: The specified slave interface " + "'%s' is already a slave\n", + slave_ifname); + return 1; + } + + res = set_if_down(slave_ifname, slave_flags.ifr_flags); + if (res) { + fprintf(stderr, + "Slave '%s': Error: bring interface down failed\n", + slave_ifname); + return res; + } + + if (abi_ver < 2) { + /* Older bonding versions would panic if the slave has no IP + * address, so get the IP setting from the master. + */ + res = set_if_addr(master_ifname, slave_ifname); + if (res) { + fprintf(stderr, + "Slave '%s': Error: set address failed\n", + slave_ifname); + return res; + } + } else { + res = clear_if_addr(slave_ifname); + if (res) { + fprintf(stderr, + "Slave '%s': Error: clear address failed\n", + slave_ifname); + return res; + } + } + + if (master_mtu.ifr_mtu != slave_mtu.ifr_mtu) { + res = set_slave_mtu(slave_ifname, master_mtu.ifr_mtu); + if (res) { + fprintf(stderr, + "Slave '%s': Error: set MTU failed\n", + slave_ifname); + return res; + } + } + + if (hwaddr_set) { + /* Master already has an hwaddr + * so set it's hwaddr to the slave + */ + if (abi_ver < 1) { + /* The driver is using an old ABI, so + * the application sets the slave's + * hwaddr + */ + res = set_slave_hwaddr(slave_ifname, + &(master_hwaddr.ifr_hwaddr)); + if (res) { + fprintf(stderr, + "Slave '%s': Error: set hw address " + "failed\n", + slave_ifname); + goto undo_mtu; + } + + /* For old ABI the application needs to bring the + * slave back up + */ + res = set_if_up(slave_ifname, slave_flags.ifr_flags); + if (res) { + fprintf(stderr, + "Slave '%s': Error: bring interface " + "down failed\n", + slave_ifname); + goto undo_slave_mac; + } + } + /* The driver is using a new ABI, + * so the driver takes care of setting + * the slave's hwaddr and bringing + * it up again + */ + } else { + /* No hwaddr for master yet, so + * set the slave's hwaddr to it + */ + if (abi_ver < 1) { + /* For old ABI, the master needs to be + * down before setting it's hwaddr + */ + res = set_if_down(master_ifname, master_flags.ifr_flags); + if (res) { + fprintf(stderr, + "Master '%s': Error: bring interface " + "down failed\n", + master_ifname); + goto undo_mtu; + } + } + + res = set_master_hwaddr(master_ifname, + &(slave_hwaddr.ifr_hwaddr)); + if (res) { + fprintf(stderr, + "Master '%s': Error: set hw address " + "failed\n", + master_ifname); + goto undo_mtu; + } + + if (abi_ver < 1) { + /* For old ABI, bring the master + * back up + */ + res = set_if_up(master_ifname, master_flags.ifr_flags); + if (res) { + fprintf(stderr, + "Master '%s': Error: bring interface " + "up failed\n", + master_ifname); + goto undo_master_mac; + } + } + + hwaddr_set = 1; + } + + /* Do the real thing */ + strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); + strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ); + if ((ioctl(skfd, SIOCBONDENSLAVE, &ifr) < 0) && + (ioctl(skfd, BOND_ENSLAVE_OLD, &ifr) < 0)) { + saved_errno = errno; + v_print("Master '%s': Error: SIOCBONDENSLAVE failed: %s\n", + master_ifname, strerror(saved_errno)); + res = 1; + } + + if (res) { + goto undo_master_mac; + } + + return 0; + +/* rollback (best effort) */ +undo_master_mac: + set_master_hwaddr(master_ifname, &(master_hwaddr.ifr_hwaddr)); + hwaddr_set = 0; + goto undo_mtu; +undo_slave_mac: + set_slave_hwaddr(slave_ifname, &(slave_hwaddr.ifr_hwaddr)); +undo_mtu: + set_slave_mtu(slave_ifname, slave_mtu.ifr_mtu); + return res; +} + +static int release(char *master_ifname, char *slave_ifname) +{ + struct ifreq ifr; + int res = 0; + + if (!(slave_flags.ifr_flags & IFF_SLAVE)) { + fprintf(stderr, + "Illegal operation: The specified slave interface " + "'%s' is not a slave\n", + slave_ifname); + return 1; + } + + strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); + strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ); + if ((ioctl(skfd, SIOCBONDRELEASE, &ifr) < 0) && + (ioctl(skfd, BOND_RELEASE_OLD, &ifr) < 0)) { + saved_errno = errno; + v_print("Master '%s': Error: SIOCBONDRELEASE failed: %s\n", + master_ifname, strerror(saved_errno)); + return 1; + } else if (abi_ver < 1) { + /* The driver is using an old ABI, so we'll set the interface + * down to avoid any conflicts due to same MAC/IP + */ + res = set_if_down(slave_ifname, slave_flags.ifr_flags); + if (res) { + fprintf(stderr, + "Slave '%s': Error: bring interface " + "down failed\n", + slave_ifname); + } + } + + /* set to default mtu */ + set_slave_mtu(slave_ifname, 1500); + + return res; +} + +static int get_if_settings(char *ifname, struct dev_ifr ifra[]) +{ + int i; + int res = 0; + + for (i = 0; ifra[i].req_ifr; i++) { + strncpy(ifra[i].req_ifr->ifr_name, ifname, IFNAMSIZ); + res = ioctl(skfd, ifra[i].req_type, ifra[i].req_ifr); + if (res < 0) { + saved_errno = errno; + v_print("Interface '%s': Error: %s failed: %s\n", + ifname, ifra[i].req_name, + strerror(saved_errno)); + + return saved_errno; + } + } + + return 0; +} + +static int get_slave_flags(char *slave_ifname) +{ + int res = 0; + + strncpy(slave_flags.ifr_name, slave_ifname, IFNAMSIZ); + res = ioctl(skfd, SIOCGIFFLAGS, &slave_flags); + if (res < 0) { + saved_errno = errno; + v_print("Slave '%s': Error: SIOCGIFFLAGS failed: %s\n", + slave_ifname, strerror(saved_errno)); + } else { + v_print("Slave %s: flags %04X.\n", + slave_ifname, slave_flags.ifr_flags); + } + + return res; +} + +static int set_master_hwaddr(char *master_ifname, struct sockaddr *hwaddr) +{ + unsigned char *addr = (unsigned char *)hwaddr->sa_data; + struct ifreq ifr; + int res = 0; + + strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); + memcpy(&(ifr.ifr_hwaddr), hwaddr, sizeof(struct sockaddr)); + res = ioctl(skfd, SIOCSIFHWADDR, &ifr); + if (res < 0) { + saved_errno = errno; + v_print("Master '%s': Error: SIOCSIFHWADDR failed: %s\n", + master_ifname, strerror(saved_errno)); + return res; + } else { + v_print("Master '%s': hardware address set to " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", + master_ifname, addr[0], addr[1], addr[2], + addr[3], addr[4], addr[5]); + } + + return res; +} + +static int set_slave_hwaddr(char *slave_ifname, struct sockaddr *hwaddr) +{ + unsigned char *addr = (unsigned char *)hwaddr->sa_data; + struct ifreq ifr; + int res = 0; + + strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ); + memcpy(&(ifr.ifr_hwaddr), hwaddr, sizeof(struct sockaddr)); + res = ioctl(skfd, SIOCSIFHWADDR, &ifr); + if (res < 0) { + saved_errno = errno; + + v_print("Slave '%s': Error: SIOCSIFHWADDR failed: %s\n", + slave_ifname, strerror(saved_errno)); + + if (saved_errno == EBUSY) { + v_print(" The device is busy: it must be idle " + "before running this command.\n"); + } else if (saved_errno == EOPNOTSUPP) { + v_print(" The device does not support setting " + "the MAC address.\n" + " Your kernel likely does not support slave " + "devices.\n"); + } else if (saved_errno == EINVAL) { + v_print(" The device's address type does not match " + "the master's address type.\n"); + } + return res; + } else { + v_print("Slave '%s': hardware address set to " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", + slave_ifname, addr[0], addr[1], addr[2], + addr[3], addr[4], addr[5]); + } + + return res; +} + +static int set_slave_mtu(char *slave_ifname, int mtu) +{ + struct ifreq ifr; + int res = 0; + + ifr.ifr_mtu = mtu; + strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ); + + res = ioctl(skfd, SIOCSIFMTU, &ifr); + if (res < 0) { + saved_errno = errno; + v_print("Slave '%s': Error: SIOCSIFMTU failed: %s\n", + slave_ifname, strerror(saved_errno)); + } else { + v_print("Slave '%s': MTU set to %d.\n", slave_ifname, mtu); + } + + return res; +} + +static int set_if_flags(char *ifname, short flags) +{ + struct ifreq ifr; + int res = 0; + + ifr.ifr_flags = flags; + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + + res = ioctl(skfd, SIOCSIFFLAGS, &ifr); + if (res < 0) { + saved_errno = errno; + v_print("Interface '%s': Error: SIOCSIFFLAGS failed: %s\n", + ifname, strerror(saved_errno)); + } else { + v_print("Interface '%s': flags set to %04X.\n", ifname, flags); + } + + return res; +} + +static int set_if_up(char *ifname, short flags) +{ + return set_if_flags(ifname, flags | IFF_UP); +} + +static int set_if_down(char *ifname, short flags) +{ + return set_if_flags(ifname, flags & ~IFF_UP); +} + +static int clear_if_addr(char *ifname) +{ + struct ifreq ifr; + int res = 0; + + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + ifr.ifr_addr.sa_family = AF_INET; + memset(ifr.ifr_addr.sa_data, 0, sizeof(ifr.ifr_addr.sa_data)); + + res = ioctl(skfd, SIOCSIFADDR, &ifr); + if (res < 0) { + saved_errno = errno; + v_print("Interface '%s': Error: SIOCSIFADDR failed: %s\n", + ifname, strerror(saved_errno)); + } else { + v_print("Interface '%s': address cleared\n", ifname); + } + + return res; +} + +static int set_if_addr(char *master_ifname, char *slave_ifname) +{ + struct ifreq ifr; + int res; + unsigned char *ipaddr; + int i; + struct { + char *req_name; + char *desc; + int g_ioctl; + int s_ioctl; + } ifra[] = { + {"IFADDR", "addr", SIOCGIFADDR, SIOCSIFADDR}, + {"DSTADDR", "destination addr", SIOCGIFDSTADDR, SIOCSIFDSTADDR}, + {"BRDADDR", "broadcast addr", SIOCGIFBRDADDR, SIOCSIFBRDADDR}, + {"NETMASK", "netmask", SIOCGIFNETMASK, SIOCSIFNETMASK}, + {NULL, NULL, 0, 0}, + }; + + for (i = 0; ifra[i].req_name; i++) { + strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); + res = ioctl(skfd, ifra[i].g_ioctl, &ifr); + if (res < 0) { + int saved_errno = errno; + + v_print("Interface '%s': Error: SIOCG%s failed: %s\n", + master_ifname, ifra[i].req_name, + strerror(saved_errno)); + + ifr.ifr_addr.sa_family = AF_INET; + memset(ifr.ifr_addr.sa_data, 0, + sizeof(ifr.ifr_addr.sa_data)); + } + + strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ); + res = ioctl(skfd, ifra[i].s_ioctl, &ifr); + if (res < 0) { + int saved_errno = errno; + + v_print("Interface '%s': Error: SIOCS%s failed: %s\n", + slave_ifname, ifra[i].req_name, + strerror(saved_errno)); + + return res; + } + + ipaddr = ifr.ifr_addr.sa_data; + v_print("Interface '%s': set IP %s to %d.%d.%d.%d\n", + slave_ifname, ifra[i].desc, + ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); + } + + return 0; +} /* * Local variables: @@ -768,3 +1107,4 @@ static int get_abi_ver(char *master_ifna * compile-command: "gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave" * End: */ + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/Documentation/networking/netconsole.txt 830-ivtv/Documentation/networking/netconsole.txt --- 000-virgin/Documentation/networking/netconsole.txt Wed Dec 31 16:00:00 1969 +++ 830-ivtv/Documentation/networking/netconsole.txt Thu Jan 8 08:54:03 2004 @@ -0,0 +1,57 @@ + +started by Ingo Molnar , 2001.09.17 +2.6 port and netpoll api by Matt Mackall , Sep 9 2003 + +Please send bug reports to Matt Mackall + +This module logs kernel printk messages over UDP allowing debugging of +problem where disk logging fails and serial consoles are impractical. + +It can be used either built-in or as a module. As a built-in, +netconsole initializes immediately after NIC cards and will bring up +the specified interface as soon as possible. While this doesn't allow +capture of early kernel panics, it does capture most of the boot +process. + +It takes a string configuration parameter "netconsole" in the +following format: + + netconsole=[src-port]@[src-ip]/[],[tgt-port]@/[tgt-macaddr] + + where + src-port source for UDP packets (defaults to 6665) + src-ip source IP to use (interface address) + dev network interface (eth0) + tgt-port port for logging agent (6666) + tgt-ip IP address for logging agent + tgt-macaddr ethernet MAC address for logging agent (broadcast) + +Examples: + + linux netconsole=4444@10.0.0.1/eth1,9353@10.0.0.2/12:34:56:78:9a:bc + + or + + insmod netconsole netconsole=@/,@10.0.0.2/ + +Built-in netconsole starts immediately after the TCP stack is +initialized and attempts to bring up the supplied dev at the supplied +address. + +The remote host can run either 'netcat -u -l -p ' or syslogd. + +WARNING: the default target ethernet setting uses the broadcast +ethernet address to send packets, which can cause increased load on +other systems on the same ethernet segment. + +NOTE: the network device (eth1 in the above case) can run any kind +of other network traffic, netconsole is not intrusive. Netconsole +might cause slight delays in other traffic if the volume of kernel +messages is high, but should have no other impact. + +Netconsole was designed to be as instantaneous as possible, to +enable the logging of even the most critical kernel bugs. It works +from IRQ contexts as well, and does not enable interrupts while +sending packets. Due to these unique needs, configuration can not +be more automatic, and some fundamental limitations will remain: +only IP networks, UDP packets and ethernet devices are supported. diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/Documentation/networking/sk98lin.txt 830-ivtv/Documentation/networking/sk98lin.txt --- 000-virgin/Documentation/networking/sk98lin.txt Mon Nov 17 18:28:29 2003 +++ 830-ivtv/Documentation/networking/sk98lin.txt Thu Jan 8 08:54:03 2004 @@ -2,9 +2,9 @@ All rights reserved =========================================================================== -sk98lin.txt created 23-Sep-2003 +sk98lin.txt created 15-Dec-2003 -Readme File for sk98lin v6.18 +Readme File for sk98lin v6.21 Marvell Yukon/SysKonnect SK-98xx Gigabit Ethernet Adapter family driver for LINUX This file contains @@ -466,7 +466,7 @@ The Marvell Yukon/SysKonnect Linux drive Link Aggregation according to IEEE standards 802.1, 802.1q, and 802.3ad. These features are only available after installation of open source modules available on the Internet: -For VLAN go to: http://scry.wanfear.com/~greear/vlan.html +For VLAN go to: http://www.candelatech.com/~greear/vlan.html For Link Aggregation go to: http://www.st.rim.or.jp/~yumo NOTE: SysKonnect GmbH does not offer any support for these open source diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/Documentation/scsi-changer.txt 830-ivtv/Documentation/scsi-changer.txt --- 000-virgin/Documentation/scsi-changer.txt Wed Dec 31 16:00:00 1969 +++ 830-ivtv/Documentation/scsi-changer.txt Thu Jan 8 11:16:54 2004 @@ -0,0 +1,184 @@ + +README for the SCSI media changer driver +======================================== + +This is a driver for SCSI Medium Changer devices, which are listed +with "Type: Medium Changer" in /proc/scsi/scsi. + +This is for *real* Jukeboxes. It is *not* supported to work with +common small CD-ROM changers, neither one-lun-per-slot SCSI changers +nor IDE drives. + +Userland tools available from: http://bytesex.org/changer.html + + +General Information +------------------- + +First some words about how changers work: A changer has 2 (possibly +more) SCSI ID's. One for the changer device which controls the robot, +and one for the device which actually reads and writes the data. The +later may be anything, a MOD, a CD-ROM, a tape or whatever. For the +changer device this is a "don't care", he *only* shuffles around the +media, nothing else. + + +The SCSI changer model is complex, compared to - for example - IDE-CD +changers. But it allows to handle nearly all possible cases. It knows +4 different types of changer elements: + + media transport - this one shuffles around the media, i.e. the + transport arm. Also known as "picker". + storage - a slot which can hold a media. + import/export - the same as above, but is accessable from outside, + i.e. there the operator (you !) can use this to + fill in and remove media from the changer. + Sometimes named "mailslot". + data transfer - this is the device which reads/writes, i.e. the + CD-ROM / Tape / whatever drive. + +None of these is limited to one: A huge Jukebox could have slots for +123 CD-ROM's, 5 CD-ROM readers (and therefore 6 SCSI ID's: the changer +and each CD-ROM) and 2 transport arms. No problem to handle. + + +How it is implemented +--------------------- + +I implemented the driver as character device driver with a NetBSD-like +ioctl interface. Just grabbed NetBSD's header file and one of the +other linux SCSI device drivers as starting point. The interface +should be source code compatible with NetBSD. So if there is any +software (anybody knows ???) which supports a BSDish changer driver, +it should work with this driver too. + +Over time a few more ioctls where added, volume tag support for example +wasn't covered by the NetBSD ioctl API. + + +Current State +------------- + +Support for more than one transport arm is not implemented yet (and +nobody asked for it so far...). + +I test and use the driver myself with a 35 slot cdrom jukebox from +Grundig. I got some reports telling it works ok with tape autoloaders +(Exabyte, HP and DEC). Some People use this driver with amanda. It +works fine with small (11 slots) and a huge (4 MOs, 88 slots) +magneto-optical Jukebox. Probably with lots of other changers too, most +(but not all :-) people mail me only if it does *not* work... + +I don't have any device lists, neither black-list nor white-list. Thus +it is quite useless to ask me whenever a specific device is supported or +not. In theory every changer device which supports the SCSI-2 media +changer command set should work out-of-the-box with this driver. If it +doesn't, it is a bug. Either within the driver or within the firmware +of the changer device. + + +Using it +-------- + +This is a character device with major number is 86, so use +"mknod /dev/sch0 c 86 0" to create the special file for the driver. + +If the module finds the changer, it prints some messages about the +device [ try "dmesg" if you don't see anything ] and should show up in +/proc/devices. If not.... some changers use ID ? / LUN 0 for the +device and ID ? / LUN 1 for the robot mechanism. But Linux does *not* +look for LUN's other than 0 as default, becauce there are to many +broken devices. So you can try: + + 1) echo "scsi add-single-device 0 0 ID 1" > /proc/scsi/scsi + (replace ID with the SCSI-ID of the device) + 2) boot the kernel with "max_scsi_luns=1" on the command line + (append="max_scsi_luns=1" in lilo.conf should do the trick) + + +Trouble? +-------- + +If you insmod the driver with "insmod debug=1", it will be verbose and +prints a lot of stuff to the syslog. Compiling the kernel with +CONFIG_SCSI_CONSTANTS=y improves the quality of the error messages alot +because the kernel will translate the error codes into human-readable +strings then. + +You can display these messages with the dmesg command (or check the +logfiles). If you email me some question becauce of a problem with the +driver, please include these messages. + + +Insmod options +-------------- + +debug=0/1 + Enable debug messages (see above, default: 0). + +verbose=0/1 + Be verbose (default: 1). + +init=0/1 + Send INITIALIZE ELEMENT STATUS command to the changer + at insmod time (default: 1). + +check_busy=0/1 + When moving media from/to data transfer elements, check + whenever the device is busy and refuse to move if so + (default: 1). + +timeout_init= + timeout for the INITIALIZE ELEMENT STATUS command + (default: 3600). + +timeout_move= + timeout for all other commands (default: 120). + +dt_id=,,... +dt_lun=,,... + These two allow to specify the SCSI ID and LUN for the data + transfer elements. You likely don't need this as the jukebox + should provide this information. But some devices don't ... + +vendor_firsts= +vendor_counts= +vendor_labels= + These insmod options can be used to tell the driver that there + are some vendor-specific element types. Grundig for example + does this. Some jukeboxes have a printer to label fresh burned + CDs, which is addressed as element 0xc000 (type 5). To tell the + driver about this vendor-specific element, use this: + $ insmod ch \ + vendor_firsts=0xc000 \ + vendor_counts=1 \ + vendor_labels=printer + All three insmod options accept up to four comma-separated + values, this way you can configure the element types 5-8. + You likely need the SCSI specs for the device in question to + find the correct values as they are not covered by the SCSI-2 + standard. + + +Credits +------- + +I wrote this driver using the famous mailing-patches-around-the-world +method. With (more or less) help from: + + Daniel Moehwald + Dane Jasper + R. Scott Bailey + Jonathan Corbet + +Special thanks go to + Martin Kuehne +for a old, second-hand (but full functional) cdrom jukebox which I use +to develop/test driver and tools now. + +Have fun, + + Gerd + +-- +Gerd Knorr diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/Documentation/sound/alsa/ALSA-Configuration.txt 830-ivtv/Documentation/sound/alsa/ALSA-Configuration.txt --- 000-virgin/Documentation/sound/alsa/ALSA-Configuration.txt Mon Nov 17 18:28:29 2003 +++ 830-ivtv/Documentation/sound/alsa/ALSA-Configuration.txt Thu Jan 8 10:26:49 2004 @@ -55,9 +55,10 @@ Module parameters major - major # for sound driver - default is 116 cards_limit - - specifies card limit # (1-8) - - good for kmod support if you do not want to search - for soundcards which are not installed in your system + - specifies card limit # for auto-loading (1-8) + - default is 1 + - for auto-loading more than 1 card, specify this option + together with snd-card-X aliases. device_mode - specifies permission mask for dynamic sound device filesystem (available only when DEVFS is enabled) @@ -173,8 +174,7 @@ Module parameters Module for soundcards based on Avance Logic ALS4000 PCI chip. joystick_port - port # for legacy joystick support. - default: 0x200 for the 1st card. - 0 = disabled + 0 = disabled (default), 1 = auto-detect Module supports up to 8 cards, autoprobe and PnP. @@ -199,6 +199,8 @@ Module parameters Module for soundcards based on Aztech AZF3328 PCI chip. + joystick - Enable joystick (default off) + Module supports up to 8 cards. Module snd-cmi8330 @@ -221,10 +223,11 @@ Module parameters Module for C-Media CMI8338 and 8738 PCI soundcards. - mpu_port - 0x300 (default),0x310,0x320,0x330, -1 (diable) - fm_port - 0x388 (default), -1 (disable) + mpu_port - 0x300,0x310,0x320,0x330, 0 = disable (default) + fm_port - 0x388 (default), 0 = disable (default) soft_ac3 - Sofware-conversion of raw SPDIF packets (model 033 only) (default = 1) + joystick - Enable joystick (default off) Module supports autoprobe and multiple chips (max 8). @@ -377,6 +380,8 @@ Module parameters * SoundBlaster PCI 64 * SoundBlaster PCI 128 + joystick - Enable joystick (default off) + Module supports up to 8 cards and autoprobe. Module snd-ens1371 @@ -387,6 +392,9 @@ Module parameters * SoundBlaster PCI 128 * SoundBlaster Vibra PCI + joystick_port - port # for joystick (0x200,0x208,0x210,0x218), + 0 = disable (default), 1 = auto-detect + Module supports up to 8 cards and autoprobe. Module snd-es968 @@ -451,6 +459,7 @@ Module parameters use_pm - support the power-management (0 = off, 1 = on, 2 = auto (default)) enable_mpu - enable MPU401 (0 = off, 1 = on, 2 = auto (default)) + joystick - enable joystick (default off) Module supports up to 8 cards and autoprobe. @@ -581,7 +590,7 @@ Module parameters * ALi m5455 ac97_clock - AC'97 codec clock base (0 = auto-detect) - joystick_port - Joystick port # (0 = disabled, 0x200) + joystick - Enable joystick (default off) mpu_port - MPU401 port # (0 = disabled, 0x330,0x300) Module supports autoprobe and multiple bus-master chips (max 8). @@ -991,10 +1000,11 @@ Module parameters mpu_port - 0x300,0x310,0x320,0x330, otherwise obtain BIOS setup [VIA686A/686B only] + joystick - Enable joystick (default off) [VIA686A/686B only] ac97_clock - AC'97 codec clock base (default 48000Hz) dxs_support - support DXS channels, 0 = auto (defalut), 1 = enable, 2 = disable, - 3 = 48k only + 3 = 48k only, 4 = no VRA [VIA8233/C,8235 only] Module supports autoprobe and multiple bus-master chips (max 8). @@ -1008,13 +1018,20 @@ Module parameters Note: VIA8233/5 (not VIA8233A) can support DXS (direct sound) channels as the first PCM. On these channels, up to 4 streams can be played at the same time. - As default (dxs_support = 0), 48k fixed rate is chosen since - the output is often noisy except for 48k on some mother - boards due to the bug of BIOS. + As default (dxs_support = 0), 48k fixed rate is chosen + except for the known devices since the output is often + noisy except for 48k on some mother boards due to the + bug of BIOS. Please try once dxs_support=1 and if it works on other - sample rates, please let us know the PCI subsystem - vendor/device id's (output of "lspci -nv"). - If it doesn't work, use dxs_support=3 or dxs_support=2. + sample rates (e.g. 44.1kHz of mp3 playback), please let us + know the PCI subsystem vendor/device id's (output of + "lspci -nv"). + If it doesn't work, try dxs_support=4. If it still doesn't + work and the default setting is ok, dxs_support=3 is the + right choice. If the default setting doesn't work at all, + try dxs_support=2 to disable the DXS channels. + In any cases, please let us know the result and the + subsystem vendor/device ids. Note: for the MPU401 on VIA823x, use snd-mpu401 driver additonally. The mpu_port option is for VIA686 chips only. @@ -1060,6 +1077,7 @@ Module parameters irq_mask - IRQ bitmask, specifies the available IRQs as bits (default = 0xffff, all available) irq_list - List of available interrupts (default = -1, not specified) + 4 numbers must be given (if specified). ibl - Capture IBL size. (default = 0, minimum size) Module supports up to 8 cards. The module is compiled only when @@ -1076,6 +1094,8 @@ Module parameters About capture IBL, see the description of snd-vx222 module. + Note: the driver is build only when CONFIG_ISA is set. + Module snd-vxp440 ----------------- @@ -1083,6 +1103,7 @@ Module parameters irq_mask - IRQ bitmask, specifies the available IRQs as bits irq_list - List of available interrupts (default = -1, not specified) + 4 numbers must be given (if specified). ibl - Capture IBL size. (default = 0, minimum size) Module supports up to 8 cards. The module is compiled only when @@ -1099,17 +1120,23 @@ Module parameters About capture IBL, see the description of snd-vx222 module. + Note: the driver is build only when CONFIG_ISA is set. + Module snd-ymfpci ----------------- Module for Yamaha PCI chips (YMF72x, YMF74x & YMF75x). - mpu_port - 0x300,0x330,0x332,0x334, -1 (disable) by default - fm_port - 0x388,0x398,0x3a0,0x3a8, -1 (disable) by default - rear_switch - enable shared rear/line-in switch (bool) + mpu_port - 0x300,0x330,0x332,0x334, 0 (disable) by default, + 1 (auto-detect for YMF744/754 only) + fm_port - 0x388,0x398,0x3a0,0x3a8, 0 (disable) by default + 1 (auto-detect for YMF744/754 only) + joystick_port - 0x201,0x202,0x204,0x205, 0 (disable) by default, + 1 (auto-detect) + rear_switch - enable shared rear/line-in switch (bool) Module supports autoprobe and multiple chips (max 8). - + The power-management is supported. @@ -1126,160 +1153,49 @@ When the kernel is configured without IS will be not built in. -modprobe/kmod support -===================== - -The modprobe program must know which modules are used for the -device major numbers. -Native ALSA devices have got default number 116. Thus a line like -'alias char-major-116 snd' must be added to /etc/modules.conf. If you have -compiled the ALSA driver with the OSS/Free emulation code, then you -will need to add lines as explained below: - -The ALSA driver uses soundcore multiplexer for 2.2+ kernels and OSS compatible -devices. You should add line like 'alias char-major-14 soundcore'. - -Example with OSS/Free emulation turned on: - ------ /etc/modules.conf +Module Autoloading Support +========================== -# ALSA portion -alias char-major-116 snd -# OSS/Free portion -alias char-major-14 soundcore - ------ /etc/modules.conf +The ALSA drivers can be loaded automatically on demand by defining +module aliases. The string 'snd-card-%1' is requested for ALSA native +devices where %i is soundcard number from zero to seven. + +To auto-load an ALSA driver for OSS services, define the string +'sound-slot-%i' where %i means the slot number for OSS, which +corresponds to the card index of ALSA. Usually, define this +as the the same card module. + +An example configuration for a single emu10k1 card is like below: +----- /etc/modprobe.conf +alias snd-card-0 snd-emu10k1 +alias sound-slot-0 snd-emu10k1 +----- /etc/modprobe.conf + +The available number of auto-loaded soundcards depends on the module +option "cards_limit" of snd module. As default it's set to 1. +To enable the auto-loading of multiple cards, specify the number of +soundcards in that option. + +When multiple cards are available, it'd better to specify the index +number for each card via module option, too, so that the order of +cards is kept consistent. -After the main multiplexer is loaded, its code requests top-level soundcard -module. String 'snd-card-%i' is requested for native devices where %i is -soundcard number from zero to seven. String 'sound-slot-%i' is requested -for native devices where %i is slot number (for ALSA owner this means soundcard -number). - ------ /etc/modules.conf +An example configuration for two soundcards is like below: +----- /etc/modprobe.conf # ALSA portion +options snd cards_limit=2 alias snd-card-0 snd-interwave alias snd-card-1 snd-ens1371 +options snd-interwave index=0 +options snd-ens1371 index=1 # OSS/Free portion -alias sound-slot-0 snd-card-0 -alias sound-slot-1 snd-card-1 - ------ /etc/modules.conf - -We are finished at this point with the configuration for ALSA native devices, -but you may also need autoloading for ALSA's add-on OSS/Free emulation -modules. At this time only one module does not depend on any others, thus -must be loaded separately - snd-pcm-oss. String 'sound-service-%i-%i' -is requested for OSS/Free service where first %i means slot number -(e.g. card number) and second %i means service number. - ------ /etc/modules.conf - -# OSS/Free portion - card #1 -alias sound-service-0-0 snd-mixer-oss -alias sound-service-0-1 snd-seq-oss -alias sound-service-0-3 snd-pcm-oss -alias sound-service-0-8 snd-seq-oss -alias sound-service-0-12 snd-pcm-oss -# OSS/Free portion - card #2 -alias sound-service-1-0 snd-mixer-oss -alias sound-service-1-3 snd-pcm-oss -alias sound-service-1-12 snd-pcm-oss - ------ /etc/modules.conf - -A complete example for Gravis UltraSound PnP soundcard: - ------ /etc/modules.conf - -# ISA PnP support (don't use IRQs 9,10,11,12,13) -options isapnp isapnp_reserve_irq=9,10,11,12,13 - -# ALSA native device support -alias char-major-116 snd -options snd major=116 cards_limit=1 -alias snd-card-0 snd-interwave -options snd-interwave index=0 id="GusPnP" - -# OSS/Free setup -alias char-major-14 soundcore -alias sound-slot-0 snd-card-0 -alias sound-service-0-0 snd-mixer-oss -alias sound-service-0-1 snd-seq-oss -alias sound-service-0-3 snd-pcm-oss -alias sound-service-0-8 snd-seq-oss -alias sound-service-0-12 snd-pcm-oss - ------ - -A complete example if you want to use more soundcards in one machine -(the configuration below is for Sound Blaster 16 and Gravis UltraSound Classic): - ------ /etc/modules.conf - -# ISA PnP support (don't use IRQs 9,10,11,12,13) -# it's only an example to reserve some IRQs for another hardware -options isapnp isapnp_reserve_irq=9,10,11,12,13 - -# ALSA native device support -alias char-major-116 snd -options snd major=116 cards_limit=2 -alias snd-card-0 snd-gusclassic -alias snd-card-1 snd-sb16 -options snd-gusclassic index=0 id="Gus" \ - port=0x220 irq=5 dma1=6 dma2=7 -options snd-sb16 index=1 id="SB16" - -# OSS/Free setup -alias char-major-14 soundcore -alias sound-slot-0 snd-card-0 -alias sound-service-0-0 snd-mixer-oss -alias sound-service-0-1 snd-seq-oss -alias sound-service-0-3 snd-pcm-oss -alias sound-service-0-8 snd-seq-oss -alias sound-service-0-12 snd-pcm-oss -alias sound-slot-1 snd-card-1 -alias sound-service-1-0 snd-mixer-oss -alias sound-service-1-3 snd-pcm-oss -alias sound-service-1-12 snd-pcm-oss - ------ - -A complete example, two Gravis UltraSound Classic soundcards are installed -in the system: - ------ /etc/modules.conf - -# ALSA native device support -alias char-major-116 snd -options snd major=116 cards_limit=2 -alias snd-card-0 snd-gusclassic -alias snd-card-1 snd-gusclassic -options snd-gusclassic index=0,1 id="Gus1","Gus2" \ - port=0x220,0x240 irq=5,7 dma1=1,5 dma2=3,6 - -# OSS/Free setup -alias char-major-14 soundcore -alias sound-slot-0 snd-card-0 -alias sound-service-0-0 snd-mixer-oss -alias sound-service-0-1 snd-seq-oss -alias sound-service-0-3 snd-pcm-oss -alias sound-service-0-8 snd-seq-oss -alias sound-service-0-12 snd-pcm-oss -alias sound-slot-1 snd-card-1 -alias sound-service-1-0 snd-mixer-oss -alias sound-service-1-3 snd-pcm-oss -alias sound-service-1-12 snd-pcm-oss - ------ - -If you want to autoclean your modules, you should put below line to your -/etc/crontab: - -*/10 * * * * root /sbin/modprobe -rs snd-card-0 snd-card-1; /sbin/rmmod -as +alias sound-slot-0 snd-interwave +alias sound-slot-1 snd-ens1371 +----- /etc/moprobe.conf -You may also want to extend the soundcard list to follow your requirements. +In this example, the interwave card is always loaded as the first card +(index 0) and ens1371 as the second (index 1). ALSA PCM devices to OSS devices mapping diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl 830-ivtv/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl --- 000-virgin/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl Thu Jan 8 08:35:18 2004 +++ 830-ivtv/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl Thu Jan 8 10:26:49 2004 @@ -341,10 +341,6 @@ drivers will be on pci directory, because its API is identical with the standard PCI cards. - - - At this moment, only VX-pocket driver exists. -
@@ -1299,7 +1295,7 @@ printk(KERN_ERR "error to set 28bit mask DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x0fffffff); + pci_set_consistent_dma_mask(pci, 0x0fffffff); chip = snd_magic_kcalloc(mychip_t, 0, GFP_KERNEL); if (chip == NULL) @@ -1417,7 +1413,7 @@ printk(KERN_ERR "error to set 28bit mask DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x0fffffff); + pci_set_consistent_dma_mask(pci, 0x0fffffff); ]]> @@ -3982,13 +3978,18 @@ struct _snd_pcm_runtime { static int snd_mychip_ac97(mychip_t *chip) { + ac97_bus_t bus, *pbus; ac97_t ac97; + int err; + memset(&bus, 0, sizeof(bus)); + bus.write = snd_mychip_ac97_write; + bus.read = snd_mychip_ac97_read; + if ((err = snd_ac97_bus(chip->card, &bus, &pbus)) < 0) + return err; memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_mychip_ac97_write; - ac97.read = snd_mychip_ac97_read; ac97.private_data = chip; - return snd_ac97_mixer(card, &ac97, &chip->ac97); + return snd_ac97_mixer(pbus, &ac97, &chip->ac97); } ]]> @@ -4000,9 +4001,29 @@ struct _snd_pcm_runtime {
Constructor - For creating an ac97 instance, call - snd_ac97_mixer() with an ac97_t - record, in which the callbacks and the private_data is set. + For creating an ac97 instance, first call snd_ac97_bus + with ac97_bus_t record including callback functions. + + + + + + + + The bus record is shared among all belonging ac97 instances. + + + + And then call snd_ac97_mixer() with an ac97_t + record together with the bus pointer created above. @@ -4011,16 +4032,16 @@ struct _snd_pcm_runtime { int err; memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_mychip_ac97_write; - ac97.read = snd_mychip_ac97_read; ac97.private_data = chip; - snd_ac97_mixer(card, &ac97, &chip->ac97); + snd_ac97_mixer(bus, &ac97, &chip->ac97); ]]> where chip->ac97 is the pointer of a newly created ac97_t instance. + In this case, the chip pointer is set as the private data, so that + the read/write callback functions can refer to this chip instance. This instance is not necessarily stored in the chip record. When you need to change the register values from the driver, or need the suspend/resume of ac97 codecs, keep this @@ -4094,14 +4115,11 @@ struct _snd_pcm_runtime { The wait callback is used for a certain wait at the standard initialization of the codec. If the chip requires the extra wait-time, define this callback. - This callback is always non-atomic, because it's never called - in the resume mode. The init callback is used for - additional initialization of the codec. This callback is called - after the reset, and should be atomic in the resume mode. + additional initialization of the codec.
@@ -4674,10 +4692,7 @@ struct _snd_pcm_runtime { - Note that you have to pre-allocate to use this function - (i.e. you cannot use this function for - - a scatter-gather buffer). + Note that you have to pre-allocate to use this function.
@@ -4905,6 +4920,8 @@ struct _snd_pcm_runtime { When a SG-handler is used, you need to set snd_pcm_sgbuf_ops_page as the page callback. + (See + page callback section.) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/Documentation/sound/alsa/Joystick.txt 830-ivtv/Documentation/sound/alsa/Joystick.txt --- 000-virgin/Documentation/sound/alsa/Joystick.txt Wed Dec 31 16:00:00 1969 +++ 830-ivtv/Documentation/sound/alsa/Joystick.txt Thu Jan 8 10:26:49 2004 @@ -0,0 +1,87 @@ +Analog Joystick Support on ALSA Drivers +======================================= + Oct. 14, 2003 + Takashi Iwai + +General +------- + +First of all, you need to enable GAMEPORT support on Linux kernel for +using a joystick with the ALSA driver. For the details of gameport +support, refer to Documentation/input/joystick.txt. + +The joystick support of ALSA drivers is different between ISA and PCI +cards. In the case of ISA (PnP) cards, it's usually handled by the +independent module (ns558). Meanwhile, the ALSA PCI drivers have the +built-in gameport support. Hence, when the ALSA PCI driver is built +in the kernel, CONFIG_GAMEPORT must be 'y', too. Otherwise, the +gameport support on that card will be (silently) disabled. + +Some adapter modules probe the physical connection of the device at +the load time. It'd be safer to plug in the joystick device before +loading the module. + + +PCI Cards +--------- + +For PCI cards, the joystick is enabled when the appropriate module +option is specified. Some drivers don't need options, and the +joystick support is always enabled. In the former ALSA version, there +was a dynamic control API for the joystick activation. It was +changed, however, to the static module options because of the system +stability and the resource management. + +The following PCI drivers support the joystick natively. + + Driver Module Option Available Values + --------------------------------------------------------------------------- + als4000 joystick_port 0 = disable (default), 1 = auto-detect, + manual: any address (e.g. 0x200) + au88x0 N/A N/A + azf3328 joystick 0 = disable, 1 = enable, -1 = auto (default) + ens1370 joystick 0 = disable (default), 1 = enable + ens1371 joystick_port 0 = disable (default), 1 = auto-detect, + manual: 0x200, 0x208, 0x210, 0x218 + cmipci joystick 0 = disable (default), 1 = enable + cs4281 N/A N/A + cs46xx N/A N/A + es1938 N/A N/A + es1968 joystick 0 = disable (default), 1 = enable + intel8x0(*1)joystick 0 = disable (default), 1 = enable + sonicvibes N/A N/A + trident N/A N/A + via82xx(*2) joystick 0 = disable (default), 1 = enable + ymfpci joystick_port 0 = disable (default), 1 = auto-detect, + manual: 0x201, 0x202, 0x204, 0x205(*3) + --------------------------------------------------------------------------- + + *1) not all chips support joystick + *2) VIA686A/B only + *3) With YMF744/754 chips, the port address can be chosen arbitrarily + +The following drivers don't support gameport natively, but there are +additional modules. Load the corresponding module to add the gameport +support. + + Driver Additional Module + ----------------------------- + emu10k1 emu10k1-gp + fm801 fm801-gp + ----------------------------- + +Note: the "pcigame" and "cs461x" modules are for the OSS drivers only. + These ALSA drivers (cs46xx, trident and au88x0) have the + built-in gameport support. + +As mentioned above, ALSA PCI drivers have the built-in gameport +support, so you don't have to load ns558 module. Just load "joydev" +and the appropriate adapter module (e.g. "analog"). + + +ISA Cards +--------- + +ALSA ISA drivers don't have the built-in gameport support. +Instead, you need to load "ns558" module in addition to "joydev" and +the adapter module (e.g. "analog"). diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/Documentation/video4linux/bttv/CARDLIST 830-ivtv/Documentation/video4linux/bttv/CARDLIST --- 000-virgin/Documentation/video4linux/bttv/CARDLIST Fri May 30 19:01:58 2003 +++ 830-ivtv/Documentation/video4linux/bttv/CARDLIST Thu Jan 8 11:17:30 2004 @@ -1,141 +1,115 @@ -bttv.o - card=0 - *** UNKNOWN/GENERIC *** - card=1 - MIRO PCTV - card=2 - Hauppauge (bt848) - card=3 - STB, Gateway P/N 6000699 (bt848) - card=4 - Intel Create and Share PCI/ Smart Video Recorder III - card=5 - Diamond DTV2000 - card=6 - AVerMedia TVPhone - card=7 - MATRIX-Vision MV-Delta - card=8 - Lifeview FlyVideo II (Bt848) LR26 - card=9 - IMS/IXmicro TurboTV - card=10 - Hauppauge (bt878) - card=11 - MIRO PCTV pro - card=12 - ADS Technologies Channel Surfer TV (bt848) - card=13 - AVerMedia TVCapture 98 - card=14 - Aimslab Video Highway Xtreme (VHX) - card=15 - Zoltrix TV-Max - card=16 - Prolink Pixelview PlayTV (bt878) - card=17 - Leadtek WinView 601 - card=18 - AVEC Intercapture - card=19 - Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only) - card=20 - CEI Raffles Card - card=21 - Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50 - card=22 - Askey CPH050/ Phoebe Tv Master + FM - card=23 - Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878 - card=24 - Askey CPH05X/06X (bt878) [many vendors] - card=25 - Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar - card=26 - Hauppauge WinCam newer (bt878) - card=27 - Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50 - card=28 - Terratec TerraTV+ Version 1.1 (bt878) - card=29 - Imagenation PXC200 - card=30 - Lifeview FlyVideo 98 LR50 - card=31 - Formac iProTV - card=32 - Intel Create and Share PCI/ Smart Video Recorder III - card=33 - Terratec TerraTValue Version Bt878 - card=34 - Leadtek WinFast 2000/ WinFast 2000 XP - card=35 - Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II - card=36 - Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner - card=37 - Prolink PixelView PlayTV pro - card=38 - Askey CPH06X TView99 - card=39 - Pinnacle PCTV Studio/Rave - card=40 - STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100 - card=41 - AVerMedia TVPhone 98 - card=42 - ProVideo PV951 - card=43 - Little OnAir TV - card=44 - Sigma TVII-FM - card=45 - MATRIX-Vision MV-Delta 2 - card=46 - Zoltrix Genie TV/FM - card=47 - Terratec TV/Radio+ - card=48 - Askey CPH03x/ Dynalink Magic TView - card=49 - IODATA GV-BCTV3/PCI - card=50 - Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP - card=51 - Eagle Wireless Capricorn2 (bt878A) - card=52 - Pinnacle PCTV Studio Pro - card=53 - Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS - card=54 - Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90] - card=55 - Askey CPH031/ BESTBUY Easy TV - card=56 - Lifeview FlyVideo 98FM LR50 - card=57 - GrandTec 'Grand Video Capture' (Bt848) - card=58 - Askey CPH060/ Phoebe TV Master Only (No FM) - card=59 - Askey CPH03x TV Capturer - card=60 - Modular Technology MM100PCTV - card=61 - AG Electronics GMV1 - card=62 - Askey CPH061/ BESTBUY Easy TV (bt878) - card=63 - ATI TV-Wonder - card=64 - ATI TV-Wonder VE - card=65 - Lifeview FlyVideo 2000S LR90 - card=66 - Terratec TValueRadio - card=67 - IODATA GV-BCTV4/PCI - card=68 - 3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA) - card=69 - Active Imaging AIMMS - card=70 - Prolink Pixelview PV-BT878P+ (Rev.4C,8E) - card=71 - Lifeview FlyVideo 98EZ (capture only) LR51 - card=72 - Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM) - card=73 - Sensoray 311 - card=74 - RemoteVision MX (RV605) - card=75 - Powercolor MTV878/ MTV878R/ MTV878F - card=76 - Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP) - card=77 - GrandTec Multi Capture Card (Bt878) - card=78 - Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF - card=79 - DSP Design TCVIDEO - card=80 - Hauppauge WinTV PVR - card=81 - GV-BCTV5/PCI - card=82 - Osprey 100/150 (878) - card=83 - Osprey 100/150 (848) - card=84 - Osprey 101 (848) - card=85 - Osprey 101/151 - card=86 - Osprey 101/151 w/ svid - card=87 - Osprey 200/201/250/251 - card=88 - Osprey 200/250 - card=89 - Osprey 210/220 - card=90 - Osprey 500 - card=91 - Osprey 540 - card=92 - Osprey 2000 - card=93 - IDS Eagle - card=94 - Pinnacle PCTV Sat - card=95 - Formac ProTV II - card=96 - MachTV - card=97 - Euresys Picolo - -tuner.o - type=0 - Temic PAL (4002 FH5) - type=1 - Philips PAL_I (FI1246 and compatibles) - type=2 - Philips NTSC (FI1236,FM1236 and compatibles) - type=3 - Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF) - type=4 - NoTuner - type=5 - Philips PAL_BG (FI1216 and compatibles) - type=6 - Temic NTSC (4032 FY5) - type=7 - Temic PAL_I (4062 FY5) - type=8 - Temic NTSC (4036 FY5) - type=9 - Alps HSBH1 - type=10 - Alps TSBE1 - type=11 - Alps TSBB5 - type=12 - Alps TSBE5 - type=13 - Alps TSBC5 - type=14 - Temic PAL_BG (4006FH5) - type=15 - Alps TSCH6 - type=16 - Temic PAL_DK (4016 FY5) - type=17 - Philips NTSC_M (MK2) - type=18 - Temic PAL_I (4066 FY5) - type=19 - Temic PAL* auto (4006 FN5) - type=20 - Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5) - type=21 - Temic NTSC (4039 FR5) - type=22 - Temic PAL/SECAM multi (4046 FM5) - type=23 - Philips PAL_DK (FI1256 and compatibles) - type=24 - Philips PAL/SECAM multi (FQ1216ME) - type=25 - LG PAL_I+FM (TAPC-I001D) - type=26 - LG PAL_I (TAPC-I701D) - type=27 - LG NTSC+FM (TPI8NSR01F) - type=28 - LG PAL_BG+FM (TPI8PSB01D) - type=29 - LG PAL_BG (TPI8PSB11D) - type=30 - Temic PAL* auto + FM (4009 FN5) - type=31 - SHARP NTSC_JP (2U5JF5540) - type=32 - Samsung PAL TCPM9091PD27 - type=33 - MT2032 universal - type=34 - Temic PAL_BG (4106 FH5) - type=35 - Temic PAL_DK/SECAM_L (4012 FY5) - type=36 - Temic NTSC (4136 FY5) - type=37 - LG PAL (newer TAPC series) - type=38 - Philips PAL/SECAM multi (FM1216ME MK3) - type=39 - LG NTSC (newer TAPC series) +card=0 - *** UNKNOWN/GENERIC *** +card=1 - MIRO PCTV +card=2 - Hauppauge (bt848) +card=3 - STB, Gateway P/N 6000699 (bt848) +card=4 - Intel Create and Share PCI/ Smart Video Recorder III +card=5 - Diamond DTV2000 +card=6 - AVerMedia TVPhone +card=7 - MATRIX-Vision MV-Delta +card=8 - Lifeview FlyVideo II (Bt848) LR26 / MAXI TV Video PCI2 LR26 +card=9 - IMS/IXmicro TurboTV +card=10 - Hauppauge (bt878) +card=11 - MIRO PCTV pro +card=12 - ADS Technologies Channel Surfer TV (bt848) +card=13 - AVerMedia TVCapture 98 +card=14 - Aimslab Video Highway Xtreme (VHX) +card=15 - Zoltrix TV-Max +card=16 - Prolink Pixelview PlayTV (bt878) +card=17 - Leadtek WinView 601 +card=18 - AVEC Intercapture +card=19 - Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only) +card=20 - CEI Raffles Card +card=21 - Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50 +card=22 - Askey CPH050/ Phoebe Tv Master + FM +card=23 - Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878 +card=24 - Askey CPH05X/06X (bt878) [many vendors] +card=25 - Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar +card=26 - Hauppauge WinCam newer (bt878) +card=27 - Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50 +card=28 - Terratec TerraTV+ Version 1.1 (bt878) +card=29 - Imagenation PXC200 +card=30 - Lifeview FlyVideo 98 LR50 +card=31 - Formac iProTV, Formac ProTV I (bt848) +card=32 - Intel Create and Share PCI/ Smart Video Recorder III +card=33 - Terratec TerraTValue Version Bt878 +card=34 - Leadtek WinFast 2000/ WinFast 2000 XP +card=35 - Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II +card=36 - Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner +card=37 - Prolink PixelView PlayTV pro +card=38 - Askey CPH06X TView99 +card=39 - Pinnacle PCTV Studio/Rave +card=40 - STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100 +card=41 - AVerMedia TVPhone 98 +card=42 - ProVideo PV951 +card=43 - Little OnAir TV +card=44 - Sigma TVII-FM +card=45 - MATRIX-Vision MV-Delta 2 +card=46 - Zoltrix Genie TV/FM +card=47 - Terratec TV/Radio+ +card=48 - Askey CPH03x/ Dynalink Magic TView +card=49 - IODATA GV-BCTV3/PCI +card=50 - Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP +card=51 - Eagle Wireless Capricorn2 (bt878A) +card=52 - Pinnacle PCTV Studio Pro +card=53 - Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS +card=54 - Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90] +card=55 - Askey CPH031/ BESTBUY Easy TV +card=56 - Lifeview FlyVideo 98FM LR50 +card=57 - GrandTec 'Grand Video Capture' (Bt848) +card=58 - Askey CPH060/ Phoebe TV Master Only (No FM) +card=59 - Askey CPH03x TV Capturer +card=60 - Modular Technology MM100PCTV +card=61 - AG Electronics GMV1 +card=62 - Askey CPH061/ BESTBUY Easy TV (bt878) +card=63 - ATI TV-Wonder +card=64 - ATI TV-Wonder VE +card=65 - Lifeview FlyVideo 2000S LR90 +card=66 - Terratec TValueRadio +card=67 - IODATA GV-BCTV4/PCI +card=68 - 3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA) +card=69 - Active Imaging AIMMS +card=70 - Prolink Pixelview PV-BT878P+ (Rev.4C,8E) +card=71 - Lifeview FlyVideo 98EZ (capture only) LR51 +card=72 - Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM) +card=73 - Sensoray 311 +card=74 - RemoteVision MX (RV605) +card=75 - Powercolor MTV878/ MTV878R/ MTV878F +card=76 - Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP) +card=77 - GrandTec Multi Capture Card (Bt878) +card=78 - Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF +card=79 - DSP Design TCVIDEO +card=80 - Hauppauge WinTV PVR +card=81 - IODATA GV-BCTV5/PCI +card=82 - Osprey 100/150 (878) +card=83 - Osprey 100/150 (848) +card=84 - Osprey 101 (848) +card=85 - Osprey 101/151 +card=86 - Osprey 101/151 w/ svid +card=87 - Osprey 200/201/250/251 +card=88 - Osprey 200/250 +card=89 - Osprey 210/220 +card=90 - Osprey 500 +card=91 - Osprey 540 +card=92 - Osprey 2000 +card=93 - IDS Eagle +card=94 - Pinnacle PCTV Sat +card=95 - Formac ProTV II (bt878) +card=96 - MachTV +card=97 - Euresys Picolo +card=98 - ProVideo PV150 +card=99 - AD-TVK503 +card=100 - Hercules Smart TV Stereo +card=101 - Pace TV & Radio Card +card=102 - IVC-200 +card=103 - Grand X-Guard / Trust 814PCI +card=104 - Nebula Electronics DigiTV +card=105 - ProVideo PV143 +card=106 - PHYTEC VD-009-X1 MiniDIN (bt878) +card=107 - PHYTEC VD-009-X1 Combi (bt878) +card=108 - PHYTEC VD-009 MiniDIN (bt878) +card=109 - PHYTEC VD-009 Combi (bt878) +card=110 - IVC-100 +card=111 - IVC-120G +card=112 - pcHDTV HD-2000 TV +card=113 - Twinhan DST + clones +card=114 - Winfast VC100 diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/Documentation/video4linux/bttv/Insmod-options 830-ivtv/Documentation/video4linux/bttv/Insmod-options --- 000-virgin/Documentation/video4linux/bttv/Insmod-options Sun Nov 17 20:29:24 2002 +++ 830-ivtv/Documentation/video4linux/bttv/Insmod-options Thu Jan 8 11:17:30 2004 @@ -1,4 +1,10 @@ +Note: "modinfo " prints various informations about a kernel +module, among them a complete and up-to-date list of insmod options. +This list tends to be outdated because it is updated manually ... + +========================================================================== + bttv.o the bt848/878 (grabber chip) driver diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/Documentation/video4linux/bttv/README 830-ivtv/Documentation/video4linux/bttv/README --- 000-virgin/Documentation/video4linux/bttv/README Sun Nov 17 20:29:21 2002 +++ 830-ivtv/Documentation/video4linux/bttv/README Thu Jan 8 11:17:30 2004 @@ -1,88 +1,37 @@ -IMPORTANT: Don't send me mails with images attached unless I ask you -to do so. Mails with images attached will go to /dev/null unseen. - - -Release notes for bttv-0.7.x -============================ - -This version is based on Ralphs 0.6.4 release. There are alot of -changes. Bugfixes, merged patches from other people, merged fixes -from the kernel version, port to the new i2c stack, removed support -for 2.0.x, code cleanups, ... - -To compile this bttv version, you'll the new i2c stack. Kernels -newer than 2.3.34 have this already included. If you have a older -kernel, download it from: - http://www2.lm-sensors.nu/~lm78/download.html +Release notes for bttv +====================== You'll need at least these config options for bttv: -CONFIG_I2C=m -CONFIG_I2C_ALGOBIT=m -CONFIG_VIDEO_DEV=m + CONFIG_I2C=m + CONFIG_I2C_ALGOBIT=m + CONFIG_VIDEO_DEV=m The latest bttv version is available from http://bytesex.org/bttv/ -You'll find Ralphs original (mostly outdated) documentation in the -ralphs-doc subdirectory. - - -Compile bttv ------------- - -If you are compiling the kernel version, just say 'm' if you are asked -for bttv. I /strongly/ recommend to compile bttv as module, because -there are some insmod options for configuring the driver. Starting -with 0.7.49 the most important ones are available as kernel args too. - -If you downloaded the separate bttv bundle: You need configured kernel -sources to compile the bttv driver. The driver uses some Makefile -magic to compile the modules with your kernel's configuration -(wrt. module-versions, SMP, ...). If you already have compiled the -kernel at least once, you probably don't have do worry about this. If -not, go to /usr/src/linux and run at least "make config". Even -better, compile your own kernel, you'll never become a real hacker -else ;-) -Note that you have to turn on video4linux support (CONFIG_VIDEO_DEV) -in the kernel to get the videodev.o module which is required by bttv. - Make bttv work with your card ----------------------------- -Setup your /etc/modules.conf file and let kmod load the modules. -See also: +Just try "modprobe bttv" and see if that works. -Modules.conf: some sample entries for /etc/modules.conf -Insmod-options: list of all insmod options available for bttv and - the helper modules. -MAKEDEV: a script to create the special files for v4l -CARDLIST: List of all supported cards -Cards: more detailed descriptions of known TV cards: - OEM name variants, used i2c chips, ... - also includes non-bttv cards. - -Loading just the bttv modules isn't enouth for most cards. The -drivers for the i2c tuner/sound chips must also be loaded. bttv tries -to load them automagically by calling request_module() now, but this -obviously works only with kmod enabled. +If it doesn't bttv likely could not autodetect your card and needs some +insmod options. The most important insmod option for bttv is "card=n" +to select the correct card type. If you get video but no sound you've +very likely specified the wrong (or no) card type. A list of supported +cards is in CARDLIST.bttv If bttv takes very long to load (happens sometimes with the cheap cards which have no tuner), try adding this to your modules.conf: options i2c-algo-bit bit_test=1 -The most important insmod option for bttv is "card=n" to select the -correct card type in case the autodetection does'nt work. If you get -video but no sound you've very likely specified the wrong (or no) -card type. A list of supported cards is in CARDLIST. - For the WinTV/PVR you need one firmware file from the driver CD: hcwamc.rbf. The file is in the pvr45xxx.exe archive (self-extracting zip file, unzip can unpack it). Put it into the /etc/pvr directory or use the firm_altera= insmod option to point the driver to the location of the file. -If your card isn't listed in CARDLIST or if you have trouble making +If your card isn't listed in CARDLIST.bttv or if you have trouble making audio work, you should read the Sound-FAQ. @@ -103,14 +52,6 @@ ID and therefore can't be autodetected. in bttv-cards.c (in case you are intrested or want to mail patches with updates). -Old driver versions used to have a heuristic which could identify some -bt848-based cards. It worked for Hauppauge and Miro cards in most -cases (simply because these where the first cards available on the -market), but misdetected other bt848 cards. That code is gone now for -exactly this reason, the misdetection confused lots of people. If you -have a old Hauppauge or Miro card, you'll have to load the driver with -card=1 or card=2 these days. - Still doesn't work? ------------------- @@ -146,4 +87,4 @@ Have fun with bttv, Gerd -- -Gerd Knorr +Gerd Knorr diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/Documentation/video4linux/bttv/Specs 830-ivtv/Documentation/video4linux/bttv/Specs --- 000-virgin/Documentation/video4linux/bttv/Specs Sun Nov 17 20:29:47 2002 +++ 830-ivtv/Documentation/video4linux/bttv/Specs Thu Jan 8 11:17:30 2004 @@ -1,3 +0,0 @@ -Philips http://www.Semiconductors.COM/pip/ -Conexant http://www.conexant.com/techinfo/default.asp -Micronas http://www.micronas.de/pages/product_documentation/index.html diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/MAINTAINERS 830-ivtv/MAINTAINERS --- 000-virgin/MAINTAINERS Thu Jan 8 08:35:19 2004 +++ 830-ivtv/MAINTAINERS Thu Jan 8 10:26:46 2004 @@ -1158,12 +1158,27 @@ W: http://sf.net/projects/kernel-janitor W: http://developer.osdl.org/rddunlap/kj-patches/ S: Maintained +KGDB FOR I386 PLATFORM +P: George Anzinger +M: george@mvista.com +L: linux-net@vger.kernel.org +S: Supported + KERNEL NFSD P: Neil Brown M: neilb@cse.unsw.edu.au L: nfs@lists.sourceforge.net W: http://nfs.sourceforge.net/ W: http://www.cse.unsw.edu.au/~neilb/patches/linux-devel/ +S: Maintained + +KEXEC +P: Eric Biederman +M: ebiederm@xmission.com +M: ebiederman@lnxi.com +W: http://www.xmission.com/~ebiederm/files/kexec/ +L: linux-kernel@vger.kernel.org +L: fastboot@osdl.org S: Maintained LANMEDIA WAN CARD DRIVER diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/Makefile 830-ivtv/Makefile --- 000-virgin/Makefile Thu Jan 8 08:35:19 2004 +++ 830-ivtv/Makefile Thu Jan 8 10:21:27 2004 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 1 -EXTRAVERSION =-rc3 +EXTRAVERSION =-rc3-mjb1 # *DOCUMENTATION* # To see a list of typical targets execute "make help" @@ -66,6 +66,8 @@ endif # # The O= assigment takes precedence over the KBUILD_OUTPUT environment variable. +GCOV_FLAGS = -fprofile-arcs -ftest-coverage + # KBUILD_SRC is set on invocation of make in OBJ directory # KBUILD_SRC is not intended to be used by the regular user (for now) @@ -287,6 +289,8 @@ export VERSION PATCHLEVEL SUBLEVEL EXTRA export CPPFLAGS NOSTDINC_FLAGS OBJCOPYFLAGS LDFLAGS export CFLAGS CFLAGS_KERNEL CFLAGS_MODULE export AFLAGS AFLAGS_KERNEL AFLAGS_MODULE +export CFLAGS_NOGCOV + export MODVERDIR := .tmp_versions @@ -441,6 +445,10 @@ ifndef CONFIG_FRAME_POINTER CFLAGS += -fomit-frame-pointer endif +ifeq ($(CONFIG_MCOUNT),y) +CFLAGS += -pg +endif + ifdef CONFIG_DEBUG_INFO CFLAGS += -g endif @@ -668,6 +676,11 @@ depend dep: # --------------------------------------------------------------------------- # Modules +CFLAGS_NOGCOV := $(CFLAGS) +ifdef CONFIG_GCOV_ALL +CFLAGS += $(GCOV_FLAGS) +endif + ifdef CONFIG_MODULES # By default, build modules as well @@ -790,6 +803,7 @@ clean: archclean $(clean-dirs) $(call cmd,rmclean) @find . $(RCS_FIND_IGNORE) \ \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \ + -o -name '*.bb' -o -name '*.bbg' -o -name '*.da' \ -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \) \ -type f -print | xargs rm -f diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/Kconfig 830-ivtv/arch/i386/Kconfig --- 000-virgin/arch/i386/Kconfig Thu Jan 8 08:35:20 2004 +++ 830-ivtv/arch/i386/Kconfig Thu Jan 8 10:26:46 2004 @@ -402,6 +402,54 @@ config X86_OOSTORE depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 default y +config X86_4G + bool "4 GB kernel-space and 4 GB user-space virtual memory support" + help + This option is only useful for systems that have more than 1 GB + of RAM. + + The default kernel VM layout leaves 1 GB of virtual memory for + kernel-space mappings, and 3 GB of VM for user-space applications. + This option ups both the kernel-space VM and the user-space VM to + 4 GB. + + The cost of this option is additional TLB flushes done at + system-entry points that transition from user-mode into kernel-mode. + I.e. system calls and page faults, and IRQs that interrupt user-mode + code. There's also additional overhead to kernel operations that copy + memory to/from user-space. The overhead from this is hard to tell and + depends on the workload - it can be anything from no visible overhead + to 20-30% overhead. A good rule of thumb is to count with a runtime + overhead of 20%. + + The upside is the much increased kernel-space VM, which more than + quadruples the maximum amount of RAM supported. Kernels compiled with + this option boot on 64GB of RAM and still have more than 3.1 GB of + 'lowmem' left. Another bonus is that highmem IO bouncing decreases, + if used with drivers that still use bounce-buffers. + + There's also a 33% increase in user-space VM size - database + applications might see a boost from this. + + But the cost of the TLB flushes and the runtime overhead has to be + weighed against the bonuses offered by the larger VM spaces. The + dividing line depends on the actual workload - there might be 4 GB + systems that benefit from this option. Systems with less than 4 GB + of RAM will rarely see a benefit from this option - but it's not + out of question, the exact circumstances have to be considered. + +config X86_SWITCH_PAGETABLES + def_bool X86_4G + +config X86_4G_VM_LAYOUT + def_bool X86_4G + +config X86_UACCESS_INDIRECT + def_bool X86_4G + +config X86_HIGH_ENTRY + def_bool X86_4G + config HPET_TIMER bool "HPET Timer Support" help @@ -458,17 +506,17 @@ config NR_CPUS This is purely to save memory - each supported CPU adds approximately eight kilobytes to the kernel image. -config PREEMPT - bool "Preemptible Kernel" - help - This option reduces the latency of the kernel when reacting to - real-time or interactive events by allowing a low priority process to - be preempted even if it is in kernel mode executing a system call. - This allows applications to run more reliably even when the system is - under load. - - Say Y here if you are building a kernel for a desktop, embedded - or real-time system. Say N if you are unsure. +# config PREEMPT +# bool "Preemptible Kernel" +# help +# This option reduces the latency of the kernel when reacting to +# real-time or interactive events by allowing a low priority process to +# be preempted even if it is in kernel mode executing a system call. +# This allows applications to run more reliably even when the system is +# under load. +# +# Say Y here if you are building a kernel for a desktop, embedded +# or real-time system. Say N if you are unsure. config X86_UP_APIC bool "Local APIC support on uniprocessors" if !SMP @@ -687,6 +735,44 @@ config HIGHMEM64G endchoice +choice + help + On i386, a process can only virtually address 4GB of memory. This + lets you select how much of that virtual space you would like to + devoted to userspace, and how much to the kernel. + + Some userspace programs would like to address as much as possible and + have few demands of the kernel other than it get out of the way. These + users may opt to use the 3.5GB option to give their userspace program + as much room as possible. Due to alignment issues imposed by PAE, + the "3.5GB" option is unavailable if "64GB" high memory support is + enabled. + + Other users (especially those who use PAE) may be running out of + ZONE_NORMAL memory. Those users may benefit from increasing the + kernel's virtual address space size by taking it away from userspace, + which may not need all of its space. An indicator that this is + happening is when /proc/Meminfo's "LowFree:" is a small percentage of + "LowTotal:" while "HighFree:" is very large. + + If unsure, say "3GB" + prompt "User address space size" + default 1GB + +config 05GB + bool "3.5 GB" + depends on !HIGHMEM64G + +config 1GB + bool "3 GB" + +config 2GB + bool "2 GB" + +config 3GB + bool "1 GB" +endchoice + config HIGHMEM bool depends on HIGHMEM64G || HIGHMEM4G @@ -808,6 +894,33 @@ config EFI anything about EFI). However, even with this option, the resultant kernel should continue to boot on existing non-EFI platforms. +choice + help + This is unrelated to your processor's speed. This variable alters + how often the system is asked to generate timer interrupts. A larger + value can lead to a more responsive system, but also causes extra + overhead from the increased number of context switches. + + If in doubt, leave it at the default of 1000. + + prompt "Kernel HZ" + default 1000HZ + +config 100HZ + bool "100 Hz" + +config 1000HZ + bool "1000 Hz" +endchoice + +config IRQBALANCE + bool "Enable kernel irq balancing" + depends on SMP + default y + help + The defalut yes will allow the kernel to do irq load balancing. + Saying no will keep the kernel from doing irq load balancing. + config HAVE_DEC_LOCK bool depends on (SMP || PREEMPT) && X86_CMPXCHG @@ -820,6 +933,23 @@ config BOOT_IOREMAP depends on (((X86_SUMMIT || X86_GENERICARCH) && NUMA) || (X86 && EFI)) default y +config KEXEC + bool "kexec system call (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + kexec is a system call that implements the ability to shutdown your + current kernel, and to start another kernel. It is like a reboot + but it is indepedent of the system firmware. And like a reboot + you can start any kernel with it, not just Linux. + + The name comes from the similiarity to the exec system call. + + It is an ongoing process to be certain the hardware in a machine + is properly shutdown, so do not be surprised if this code does not + initially work for you. It may help to enable device hotplugging + support. As of this writing the exact hardware interface is + strongly in flux, so no good recommendation can be made. + endmenu @@ -1167,6 +1297,36 @@ source "fs/Kconfig" source "arch/i386/oprofile/Kconfig" +menu "GCOV coverage profiling" + +config GCOV_PROFILE + bool "GCOV coverage profiling" + ---help--- + Provide infrastructure for coverage support for the kernel. This + will not compile the kernel by default with the necessary flags. + To obtain coverage information for the entire kernel, one should + enable the subsequent option (Profile entire kernel). If only + particular files or directories of the kernel are desired, then + one must provide the following compile options for such targets: + "-fprofile-arcs -ftest-coverage" in the CFLAGS. To obtain + access to the coverage data one must insmod the gcov-proc kernel + module. + +config GCOV_ALL + bool "GCOV_ALL" + depends on GCOV_PROFILE + ---help--- + If you say Y here, it will compile the entire kernel with coverage + option enabled. + +config GCOV_PROC + tristate "gcov-proc module" + depends on GCOV_PROFILE && PROC_FS + ---help--- + This is the gcov-proc module that exposes gcov data through the + /proc filesystem + +endmenu menu "Kernel hacking" @@ -1213,6 +1373,26 @@ config MAGIC_SYSRQ keys are documented in . Don't say Y unless you really know what this hack does. +config X86_EARLY_PRINTK + bool "Early console support" + default n + depends on DEBUG_KERNEL + help + Write kernel log output directly into the VGA buffer or serial port. + This is useful for kernel debugging when your machine crashes very + early before the console code is initialized. For normal operation + it is not recommended because it looks ugly and doesn't cooperate + with klogd/syslogd or the X server.You should normally N here, + unless you want to debug such a crash. + + Syntax: earlyprintk=vga + earlyprintk=serial[,ttySn[,baudrate]] + Append ,keep to not disable it when the real console takes over. + Only vga or serial at a time, not both. + Currently only ttyS0 and ttyS1 are supported. + Interaction with the standard serial driver is not very good. + The VGA output is eventually overwritten by the real console. + config DEBUG_SPINLOCK bool "Spinlock debugging" depends on DEBUG_KERNEL @@ -1230,6 +1410,15 @@ config DEBUG_PAGEALLOC This results in a large slowdown, but helps to find certain types of memory corruptions. +config SPINLINE + bool "Spinlock inlining" + depends on DEBUG_KERNEL + help + This will change spinlocks from out of line to inline, making them + account cost to the callers in readprofile, rather than the lock + itself (as ".text.lock.filename"). This can be helpful for finding + the callers of locks. + config DEBUG_HIGHMEM bool "Highmem debugging" depends on DEBUG_KERNEL && HIGHMEM @@ -1246,20 +1435,230 @@ config DEBUG_INFO Say Y here only if you plan to use gdb to debug the kernel. If you don't debug the kernel, you can say N. +config LOCKMETER + bool "Kernel lock metering" + depends on SMP + help + Say Y to enable kernel lock metering, which adds overhead to SMP locks, + but allows you to see various statistics using the lockstat command. + config DEBUG_SPINLOCK_SLEEP bool "Sleep-inside-spinlock checking" help If you say Y here, various routines which may sleep will become very noisy if they are called with a spinlock held. +config KGDB + bool "Include kgdb kernel debugger" + depends on DEBUG_KERNEL + help + If you say Y here, the system will be compiled with the debug + option (-g) and a debugging stub will be included in the + kernel. This stub communicates with gdb on another (host) + computer via a serial port. The host computer should have + access to the kernel binary file (vmlinux) and a serial port + that is connected to the target machine. Gdb can be made to + configure the serial port or you can use stty and setserial to + do this. See the 'target' command in gdb. This option also + configures in the ability to request a breakpoint early in the + boot process. To request the breakpoint just include 'kgdb' + as a boot option when booting the target machine. The system + will then break as soon as it looks at the boot options. This + option also installs a breakpoint in panic and sends any + kernel faults to the debugger. For more information see the + Documentation/i386/kgdb.txt file. + +choice + depends on KGDB + prompt "Debug serial port BAUD" + default KGDB_115200BAUD + help + Gdb and the kernel stub need to agree on the baud rate to be + used. Some systems (x86 family at this writing) allow this to + be configured. + +config KGDB_9600BAUD + bool "9600" + +config KGDB_19200BAUD + bool "19200" + +config KGDB_38400BAUD + bool "38400" + +config KGDB_57600BAUD + bool "57600" + +config KGDB_115200BAUD + bool "115200" +endchoice + +config KGDB_PORT + hex "hex I/O port address of the debug serial port" + depends on KGDB + default 3f8 + help + Some systems (x86 family at this writing) allow the port + address to be configured. The number entered is assumed to be + hex, don't put 0x in front of it. The standard address are: + COM1 3f8 , irq 4 and COM2 2f8 irq 3. Setserial /dev/ttySx + will tell you what you have. It is good to test the serial + connection with a live system before trying to debug. + +config KGDB_IRQ + int "IRQ of the debug serial port" + depends on KGDB + default 4 + help + This is the irq for the debug port. If everything is working + correctly and the kernel has interrupts on a control C to the + port should cause a break into the kernel debug stub. + +config DEBUG_INFO + bool + depends on KGDB + default y + +config KGDB_MORE + bool "Add any additional compile options" + depends on KGDB + default n + help + Saying yes here turns on the ability to enter additional + compile options. + + +config KGDB_OPTIONS + depends on KGDB_MORE + string "Additional compile arguments" + default "-O1" + help + This option allows you enter additional compile options for + the whole kernel compile. Each platform will have a default + that seems right for it. For example on PPC "-ggdb -O1", and + for i386 "-O1". Note that by configuring KGDB "-g" is already + turned on. In addition, on i386 platforms + "-fomit-frame-pointer" is deleted from the standard compile + options. + +config NO_KGDB_CPUS + int "Number of CPUs" + depends on KGDB && SMP + default NR_CPUS + help + + This option sets the number of cpus for kgdb ONLY. It is used + to prune some internal structures so they look "nice" when + displayed with gdb. This is to overcome possibly larger + numbers that may have been entered above. Enter the real + number to get nice clean kgdb_info displays. + +config KGDB_TS + bool "Enable kgdb time stamp macros?" + depends on KGDB + default n + help + Kgdb event macros allow you to instrument your code with calls + to the kgdb event recording function. The event log may be + examined with gdb at a break point. Turning on this + capability also allows you to choose how many events to + keep. Kgdb always keeps the lastest events. + +choice + depends on KGDB_TS + prompt "Max number of time stamps to save?" + default KGDB_TS_128 + +config KGDB_TS_64 + bool "64" + +config KGDB_TS_128 + bool "128" + +config KGDB_TS_256 + bool "256" + +config KGDB_TS_512 + bool "512" + +config KGDB_TS_1024 + bool "1024" + +endchoice + +config STACK_OVERFLOW_TEST + bool "Turn on kernel stack overflow testing?" + depends on KGDB + default n + help + This option enables code in the front line interrupt handlers + to check for kernel stack overflow on interrupts and system + calls. This is part of the kgdb code on x86 systems. + +config KGDB_CONSOLE + bool "Enable serial console thru kgdb port" + depends on KGDB + default n + help + This option enables the command line "console=kgdb" option. + When the system is booted with this option in the command line + all kernel printk output is sent to gdb (as well as to other + consoles). For this to work gdb must be connected. For this + reason, this command line option will generate a breakpoint if + gdb has not yet connected. After the gdb continue command is + given all pent up console output will be printed by gdb on the + host machine. Neither this option, nor KGDB require the + serial driver to be configured. + +config KGDB_SYSRQ + bool "Turn on SysRq 'G' command to do a break?" + depends on KGDB + default y + help + This option includes an option in the SysRq code that allows + you to enter SysRq G which generates a breakpoint to the KGDB + stub. This will work if the keyboard is alive and can + interrupt the system. Because of constraints on when the + serial port interrupt can be enabled, this code may allow you + to interrupt the system before the serial port control C is + available. Just say yes here. + config FRAME_POINTER bool "Compile the kernel with frame pointers" + default KGDB help If you say Y here the resulting kernel image will be slightly larger and slower, but it will give very useful debugging information. If you don't debug the kernel, you can say N, but we may not be able to solve problems without frame pointers. +config MAGIC_SYSRQ + bool + depends on KGDB_SYSRQ + default y + +config SCHEDSTATS + bool "Collect scheduler statistics" + depends on PROC_FS + default y + help + If you say Y here, additional code will be inserted into the + scheduler and related routines to collect statistics about + scheduler behavior and provide them in /proc/schedstat. These + stats may be useful for both tuning and debugging the scheduler + If you aren't debugging the scheduler or trying to tune a specific + application, you can say N to avoid the very slight overhead + this adds. + +config MMAP_TOPDOWN + bool "Top-down vma allocation" + help + Say Y here to have the kernel change its vma allocation policy + to allocate vma's from the top of the address space down, and + to shove the stack low so as to conserve virtualspace. This is + risky because various apps, including a number of versions of + ld.so, depend on the kernel's bottom-up behavior. + config X86_EXTRA_IRQS bool depends on X86_LOCAL_APIC || X86_VOYAGER @@ -1274,6 +1673,14 @@ config X86_MPPARSE bool depends on X86_LOCAL_APIC && !X86_VISWS default y + +config MCOUNT + bool "Generate function call graph" + depends on FRAME_POINTER + help + This option instruments the kernel to generate a deterministic + function call graph. Answering Y here will make your kernel run + ???% slower. endmenu diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/Makefile 830-ivtv/arch/i386/Makefile --- 000-virgin/arch/i386/Makefile Mon Nov 17 18:28:32 2003 +++ 830-ivtv/arch/i386/Makefile Thu Jan 8 10:20:38 2004 @@ -84,6 +84,9 @@ mcore-$(CONFIG_X86_ES7000) := mach-es700 # default subarch .h files mflags-y += -Iinclude/asm-i386/mach-default +mflags-$(CONFIG_KGDB) += -gdwarf-2 +mflags-$(CONFIG_KGDB_MORE) += $(shell echo $(CONFIG_KGDB_OPTIONS) | sed -e 's/"//g') + head-y := arch/i386/kernel/head.o arch/i386/kernel/init_task.o libs-y += arch/i386/lib/ @@ -98,6 +101,7 @@ drivers-$(CONFIG_PM) += arch/i386/powe CFLAGS += $(mflags-y) AFLAGS += $(mflags-y) +AFLAGS_vmlinux.lds.o += -include $(TOPDIR)/include/asm-i386/page.h boot := arch/i386/boot diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/boot/compressed/Makefile 830-ivtv/arch/i386/boot/compressed/Makefile --- 000-virgin/arch/i386/boot/compressed/Makefile Mon Mar 17 21:43:38 2003 +++ 830-ivtv/arch/i386/boot/compressed/Makefile Thu Jan 8 10:21:27 2004 @@ -7,7 +7,19 @@ targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o EXTRA_AFLAGS := -traditional +CFLAGS := $(CFLAGS_NOGCOV) LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup_32 + +ifeq ($(CONFIG_MCOUNT),y) +quiet_cmd_nopg = CC $@ + cmd_nopg = $(CC) $(subst -pg,,$(CFLAGS)) -c $(src)/$(*F).c -o $@ + +$(obj)/misc.o: alwayscc + $(call cmd,nopg) + +alwayscc: + $(Q)rm -f $(obj)/misc.o +endif $(obj)/vmlinux: $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE $(call if_changed,ld) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/boot/setup.S 830-ivtv/arch/i386/boot/setup.S --- 000-virgin/arch/i386/boot/setup.S Mon Nov 17 18:28:32 2003 +++ 830-ivtv/arch/i386/boot/setup.S Thu Jan 8 09:30:57 2004 @@ -162,7 +162,7 @@ cmd_line_ptr: .long 0 # (Header versio # can be located anywhere in # low memory 0x10000 or higher. -ramdisk_max: .long MAXMEM-1 # (Header version 0x0203 or later) +ramdisk_max: .long __MAXMEM-1 # (Header version 0x0203 or later) # The highest safe address for # the contents of an initrd diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/defconfig 830-ivtv/arch/i386/defconfig --- 000-virgin/arch/i386/defconfig Mon Nov 17 18:28:08 2003 +++ 830-ivtv/arch/i386/defconfig Thu Jan 8 10:26:46 2004 @@ -83,6 +83,7 @@ CONFIG_X86_USE_PPRO_CHECKSUM=y CONFIG_SMP=y CONFIG_NR_CPUS=8 CONFIG_PREEMPT=y +CONFIG_KEXEC=y CONFIG_X86_LOCAL_APIC=y CONFIG_X86_IO_APIC=y CONFIG_X86_TSC=y diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/Makefile 830-ivtv/arch/i386/kernel/Makefile --- 000-virgin/arch/i386/kernel/Makefile Thu Jan 8 08:35:20 2004 +++ 830-ivtv/arch/i386/kernel/Makefile Thu Jan 8 10:26:46 2004 @@ -7,13 +7,14 @@ extra-y := head.o init_task.o vmlinux.ld obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \ pci-dma.o i386_ksyms.o i387.o dmi_scan.o bootflag.o \ - doublefault.o + doublefault.o entry_trampoline.o obj-y += cpu/ obj-y += timers/ obj-$(CONFIG_ACPI_BOOT) += acpi/ obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o obj-$(CONFIG_MCA) += mca.o +obj-$(CONFIG_KGDB) += kgdb_stub.o obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_MICROCODE) += microcode.o @@ -23,6 +24,7 @@ obj-$(CONFIG_X86_TRAMPOLINE) += trampoli obj-$(CONFIG_X86_MPPARSE) += mpparse.o obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o obj-$(CONFIG_X86_IO_APIC) += io_apic.o +obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o obj-$(CONFIG_X86_NUMAQ) += numaq.o obj-$(CONFIG_X86_SUMMIT_NUMA) += summit.o obj-$(CONFIG_EDD) += edd.o diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/apic.c 830-ivtv/arch/i386/kernel/apic.c --- 000-virgin/arch/i386/kernel/apic.c Mon Nov 17 18:29:41 2003 +++ 830-ivtv/arch/i386/kernel/apic.c Thu Jan 8 10:26:46 2004 @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -183,6 +184,39 @@ void disconnect_bsp_APIC(void) outb(0x70, 0x22); outb(0x00, 0x23); } +#ifdef CONFIG_KEXEC + else { + /* Go back to Virtual Wire compatibility mode */ + unsigned long value; + + /* For the spurious interrupt use vector F, and enable it */ + value = apic_read(APIC_SPIV); + value &= ~APIC_VECTOR_MASK; + value |= APIC_SPIV_APIC_ENABLED; + value |= 0xf; + apic_write_around(APIC_SPIV, value); + + /* For LVT0 make it edge triggered, active high, external and enabled */ + value = apic_read(APIC_LVT0); + value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING | + APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR | + APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED ); + value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING; + value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_EXINT); + apic_write_around(APIC_LVT0, value); + + /* For LVT1 make it edge triggered, active high, nmi and enabled */ + value = apic_read(APIC_LVT1); + value &= ~( + APIC_MODE_MASK | APIC_SEND_PENDING | + APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR | + APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED); + value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING; + value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_NMI); + apic_write_around(APIC_LVT1, value); + } +#endif /* CONFIG_KEXEC */ + } void disable_local_APIC(void) @@ -1028,7 +1062,7 @@ int setup_profiling_timer(unsigned int m * multiplier is 1 and it can be changed by writing the new multiplier * value into /proc/profile. */ - +extern void calc_load_cpu(int cpu); inline void smp_local_timer_interrupt(struct pt_regs * regs) { int cpu = smp_processor_id(); @@ -1056,6 +1090,7 @@ inline void smp_local_timer_interrupt(st #ifdef CONFIG_SMP update_process_times(user_mode(regs)); + calc_load_cpu(cpu); #endif } @@ -1156,6 +1191,28 @@ asmlinkage void smp_error_interrupt(void printk (KERN_INFO "APIC error on CPU%d: %02lx(%02lx)\n", smp_processor_id(), v , v1); irq_exit(); +} + +void stop_apics(void) +{ + /* By resetting the APIC's we disable the nmi watchdog */ +#if CONFIG_SMP + /* + * Stop all CPUs and turn off local APICs and the IO-APIC, so + * other OSs see a clean IRQ state. + */ + smp_send_stop(); +#else + if (cpu_has_apic) { + local_irq_disable(); + disable_local_APIC(); + local_irq_enable(); + } +#endif +#if defined(CONFIG_X86_IO_APIC) + disable_IO_APIC(); +#endif + disconnect_bsp_APIC(); } /* diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/asm-offsets.c 830-ivtv/arch/i386/kernel/asm-offsets.c --- 000-virgin/arch/i386/kernel/asm-offsets.c Sat May 10 18:34:33 2003 +++ 830-ivtv/arch/i386/kernel/asm-offsets.c Thu Jan 8 09:30:57 2004 @@ -4,9 +4,11 @@ * to extract and format the required data. */ +#include #include #include #include "sigframe.h" +#include #define DEFINE(sym, val) \ asm volatile("\n->" #sym " %0 " #val : : "i" (val)) @@ -28,4 +30,17 @@ void foo(void) DEFINE(RT_SIGFRAME_sigcontext, offsetof (struct rt_sigframe, uc.uc_mcontext)); + DEFINE(TI_task, offsetof (struct thread_info, task)); + DEFINE(TI_exec_domain, offsetof (struct thread_info, exec_domain)); + DEFINE(TI_flags, offsetof (struct thread_info, flags)); + DEFINE(TI_preempt_count, offsetof (struct thread_info, preempt_count)); + DEFINE(TI_addr_limit, offsetof (struct thread_info, addr_limit)); + DEFINE(TI_real_stack, offsetof (struct thread_info, real_stack)); + DEFINE(TI_virtual_stack, offsetof (struct thread_info, virtual_stack)); + DEFINE(TI_user_pgd, offsetof (struct thread_info, user_pgd)); + + DEFINE(FIX_ENTRY_TRAMPOLINE_0_addr, __fix_to_virt(FIX_ENTRY_TRAMPOLINE_0)); + DEFINE(FIX_VSYSCALL_addr, __fix_to_virt(FIX_VSYSCALL)); + DEFINE(PAGE_SIZE_asm, PAGE_SIZE); + DEFINE(task_thread_db7, offsetof (struct task_struct, thread.debugreg[7])); } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/cpu/common.c 830-ivtv/arch/i386/kernel/cpu/common.c --- 000-virgin/arch/i386/kernel/cpu/common.c Thu Jan 8 08:35:20 2004 +++ 830-ivtv/arch/i386/kernel/cpu/common.c Thu Jan 8 09:30:57 2004 @@ -514,11 +514,15 @@ void __init cpu_init (void) set_tss_desc(cpu,t); cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff; load_TR_desc(); - load_LDT(&init_mm.context); + if (cpu) + load_LDT(&init_mm.context); /* Set up doublefault TSS pointer in the GDT */ __set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss); cpu_gdt_table[cpu][GDT_ENTRY_DOUBLEFAULT_TSS].b &= 0xfffffdff; + + if (cpu) + trap_init_virtual_GDT(); /* Clear %fs and %gs. */ asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs"); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/cpu/intel.c 830-ivtv/arch/i386/kernel/cpu/intel.c --- 000-virgin/arch/i386/kernel/cpu/intel.c Mon Dec 8 09:55:50 2003 +++ 830-ivtv/arch/i386/kernel/cpu/intel.c Thu Jan 8 10:26:37 2004 @@ -8,11 +8,10 @@ #include #include #include +#include #include "cpu.h" -extern int trap_init_f00f_bug(void); - #ifdef CONFIG_X86_INTEL_USERCOPY /* * Alignment at which movsl is preferred for bulk memory copies. @@ -157,7 +156,7 @@ static void __init init_intel(struct cpu c->f00f_bug = 1; if ( !f00f_workaround_enabled ) { - trap_init_f00f_bug(); + trap_init_virtual_IDT(); printk(KERN_NOTICE "Intel Pentium with F0 0F bug - workaround enabled.\n"); f00f_workaround_enabled = 1; } @@ -240,6 +239,12 @@ static void __init init_intel(struct cpu /* SEP CPUID bug: Pentium Pro reports SEP but doesn't have it until model 3 mask 3 */ if ((c->x86<<8 | c->x86_model<<4 | c->x86_mask) < 0x633) clear_bit(X86_FEATURE_SEP, c->x86_capability); + /* + * FIXME: SEP is disabled for 4G/4G for now: + */ +#ifdef CONFIG_X86_HIGH_ENTRY + clear_bit(X86_FEATURE_SEP, c->x86_capability); +#endif /* Names for the Pentium II/Celeron processors detectable only by also checking the cache size. diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/dmi_scan.c 830-ivtv/arch/i386/kernel/dmi_scan.c --- 000-virgin/arch/i386/kernel/dmi_scan.c Mon Nov 17 18:29:21 2003 +++ 830-ivtv/arch/i386/kernel/dmi_scan.c Thu Jan 8 10:26:46 2004 @@ -222,31 +222,6 @@ static __init int set_bios_reboot(struct return 0; } -/* - * Some machines require the "reboot=s" commandline option, this quirk makes that automatic. - */ -static __init int set_smp_reboot(struct dmi_blacklist *d) -{ -#ifdef CONFIG_SMP - extern int reboot_smp; - if (reboot_smp == 0) - { - reboot_smp = 1; - printk(KERN_INFO "%s series board detected. Selecting SMP-method for reboots.\n", d->ident); - } -#endif - return 0; -} - -/* - * Some machines require the "reboot=b,s" commandline option, this quirk makes that automatic. - */ -static __init int set_smp_bios_reboot(struct dmi_blacklist *d) -{ - set_smp_reboot(d); - set_bios_reboot(d); - return 0; -} /* * Some bioses have a broken protected mode poweroff and need to use realmode @@ -581,7 +556,7 @@ static __initdata struct dmi_blacklist d MATCH(DMI_BIOS_VERSION, "4.60 PGMA"), MATCH(DMI_BIOS_DATE, "134526184"), NO_MATCH } }, - { set_smp_bios_reboot, "Dell PowerEdge 1300", { /* Handle problems with rebooting on Dell 1300's */ + { set_bios_reboot, "Dell PowerEdge 1300", { /* Handle problems with rebooting on Dell 1300's */ MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"), NO_MATCH, NO_MATCH diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/doublefault.c 830-ivtv/arch/i386/kernel/doublefault.c --- 000-virgin/arch/i386/kernel/doublefault.c Tue Sep 2 09:55:41 2003 +++ 830-ivtv/arch/i386/kernel/doublefault.c Thu Jan 8 09:30:57 2004 @@ -7,12 +7,13 @@ #include #include #include +#include #define DOUBLEFAULT_STACKSIZE (1024) static unsigned long doublefault_stack[DOUBLEFAULT_STACKSIZE]; #define STACK_START (unsigned long)(doublefault_stack+DOUBLEFAULT_STACKSIZE) -#define ptr_ok(x) ((x) > 0xc0000000 && (x) < 0xc1000000) +#define ptr_ok(x) (((x) > __PAGE_OFFSET && (x) < (__PAGE_OFFSET + 0x01000000)) || ((x) >= FIXADDR_START)) static void doublefault_fn(void) { @@ -38,8 +39,8 @@ static void doublefault_fn(void) printk("eax = %08lx, ebx = %08lx, ecx = %08lx, edx = %08lx\n", t->eax, t->ebx, t->ecx, t->edx); - printk("esi = %08lx, edi = %08lx\n", - t->esi, t->edi); + printk("esi = %08lx, edi = %08lx, ebp = %08lx\n", + t->esi, t->edi, t->ebp); } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/entry.S 830-ivtv/arch/i386/kernel/entry.S --- 000-virgin/arch/i386/kernel/entry.S Mon Dec 8 09:55:50 2003 +++ 830-ivtv/arch/i386/kernel/entry.S Thu Jan 8 10:26:46 2004 @@ -43,11 +43,25 @@ #include #include #include +#include #include #include +#include #include #include #include "irq_vectors.h" + /* We do not recover from a stack overflow, but at least + * we know it happened and should be able to track it down. + */ +#ifdef CONFIG_STACK_OVERFLOW_TEST +#define STACK_OVERFLOW_TEST \ + testl $7680,%esp; \ + jnz 10f; \ + call stack_overflow; \ +10: +#else +#define STACK_OVERFLOW_TEST +#endif #define nr_syscalls ((syscall_table_size)/4) @@ -87,7 +101,102 @@ TSS_ESP0_OFFSET = (4 - 0x200) #define resume_kernel restore_all #endif -#define SAVE_ALL \ +#ifdef CONFIG_X86_HIGH_ENTRY + +#ifdef CONFIG_X86_SWITCH_PAGETABLES + +#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP) +/* + * If task is preempted in __SWITCH_KERNELSPACE, and moved to another cpu, + * __switch_to repoints %esp to the appropriate virtual stack; but %ebp is + * left stale, so we must check whether to repeat the real stack calculation. + */ +#define repeat_if_esp_changed \ + xorl %esp, %ebp; \ + testl $0xffffe000, %ebp; \ + jnz 0b +#else +#define repeat_if_esp_changed +#endif + +/* clobbers ebx, edx and ebp */ + +#define __SWITCH_KERNELSPACE \ + cmpl $0xff000000, %esp; \ + jb 1f; \ + \ + /* \ + * switch pagetables and load the real stack, \ + * keep the stack offset: \ + */ \ + \ + movl $swapper_pg_dir-__PAGE_OFFSET, %edx; \ + \ + /* GET_THREAD_INFO(%ebp) intermixed */ \ +0: \ + movl %esp, %ebp; \ + movl %esp, %ebx; \ + andl $0xffffe000, %ebp; \ + andl $0x00001fff, %ebx; \ + orl TI_real_stack(%ebp), %ebx; \ + repeat_if_esp_changed; \ + \ + movl %edx, %cr3; \ + movl %ebx, %esp; \ +1: + +#endif + + +#define __SWITCH_USERSPACE \ + /* interrupted any of the user return paths? */ \ + \ + movl EIP(%esp), %eax; \ + \ + cmpl $int80_ret_start_marker, %eax; \ + jb 33f; /* nope - continue with sysexit check */\ + cmpl $int80_ret_end_marker, %eax; \ + jb 22f; /* yes - switch to virtual stack */ \ +33: \ + cmpl $sysexit_ret_start_marker, %eax; \ + jb 44f; /* nope - continue with user check */ \ + cmpl $sysexit_ret_end_marker, %eax; \ + jb 22f; /* yes - switch to virtual stack */ \ + /* return to userspace? */ \ +44: \ + movl EFLAGS(%esp),%ecx; \ + movb CS(%esp),%cl; \ + testl $(VM_MASK | 3),%ecx; \ + jz 2f; \ +22: \ + /* \ + * switch to the virtual stack, then switch to \ + * the userspace pagetables. \ + */ \ + \ + GET_THREAD_INFO(%ebp); \ + movl TI_virtual_stack(%ebp), %edx; \ + movl TI_user_pgd(%ebp), %ecx; \ + \ + movl %esp, %ebx; \ + andl $0x1fff, %ebx; \ + orl %ebx, %edx; \ +int80_ret_start_marker: \ + movl %edx, %esp; \ + movl %ecx, %cr3; \ + \ + __RESTORE_ALL; \ +int80_ret_end_marker: \ +2: + +#else /* !CONFIG_X86_HIGH_ENTRY */ + +#define __SWITCH_KERNELSPACE +#define __SWITCH_USERSPACE + +#endif + +#define __SAVE_ALL \ cld; \ pushl %es; \ pushl %ds; \ @@ -102,7 +211,7 @@ TSS_ESP0_OFFSET = (4 - 0x200) movl %edx, %ds; \ movl %edx, %es; -#define RESTORE_INT_REGS \ +#define __RESTORE_INT_REGS \ popl %ebx; \ popl %ecx; \ popl %edx; \ @@ -111,29 +220,28 @@ TSS_ESP0_OFFSET = (4 - 0x200) popl %ebp; \ popl %eax -#define RESTORE_REGS \ - RESTORE_INT_REGS; \ -1: popl %ds; \ -2: popl %es; \ +#define __RESTORE_REGS \ + __RESTORE_INT_REGS; \ +111: popl %ds; \ +222: popl %es; \ .section .fixup,"ax"; \ -3: movl $0,(%esp); \ - jmp 1b; \ -4: movl $0,(%esp); \ - jmp 2b; \ +444: movl $0,(%esp); \ + jmp 111b; \ +555: movl $0,(%esp); \ + jmp 222b; \ .previous; \ .section __ex_table,"a";\ .align 4; \ - .long 1b,3b; \ - .long 2b,4b; \ + .long 111b,444b;\ + .long 222b,555b;\ .previous - -#define RESTORE_ALL \ - RESTORE_REGS \ +#define __RESTORE_ALL \ + __RESTORE_REGS \ addl $4, %esp; \ -1: iret; \ +333: iret; \ .section .fixup,"ax"; \ -2: sti; \ +666: sti; \ movl $(__USER_DS), %edx; \ movl %edx, %ds; \ movl %edx, %es; \ @@ -142,10 +250,19 @@ TSS_ESP0_OFFSET = (4 - 0x200) .previous; \ .section __ex_table,"a";\ .align 4; \ - .long 1b,2b; \ + .long 333b,666b;\ .previous +#define SAVE_ALL \ + __SAVE_ALL; \ + __SWITCH_KERNELSPACE; \ + STACK_OVERFLOW_TEST; + +#define RESTORE_ALL \ + __SWITCH_USERSPACE; \ + __RESTORE_ALL; +.section .entry.text,"ax" ENTRY(lcall7) pushfl # We get a different stack layout with call @@ -163,7 +280,7 @@ do_lcall: movl %edx,EIP(%ebp) # Now we move them to their "normal" places movl %ecx,CS(%ebp) # andl $-8192, %ebp # GET_THREAD_INFO - movl TI_EXEC_DOMAIN(%ebp), %edx # Get the execution domain + movl TI_exec_domain(%ebp), %edx # Get the execution domain call *4(%edx) # Call the lcall7 handler for the domain addl $4, %esp popl %eax @@ -208,7 +325,7 @@ ENTRY(resume_userspace) cli # make sure we don't miss an interrupt # setting need_resched or sigpending # between sampling and the iret - movl TI_FLAGS(%ebp), %ecx + movl TI_flags(%ebp), %ecx andl $_TIF_WORK_MASK, %ecx # is there any work to be done on # int/exception return? jne work_pending @@ -216,18 +333,18 @@ ENTRY(resume_userspace) #ifdef CONFIG_PREEMPT ENTRY(resume_kernel) - cmpl $0,TI_PRE_COUNT(%ebp) # non-zero preempt_count ? + cmpl $0,TI_preempt_count(%ebp) # non-zero preempt_count ? jnz restore_all need_resched: - movl TI_FLAGS(%ebp), %ecx # need_resched set ? + movl TI_flags(%ebp), %ecx # need_resched set ? testb $_TIF_NEED_RESCHED, %cl jz restore_all testl $IF_MASK,EFLAGS(%esp) # interrupts off (exception path) ? jz restore_all - movl $PREEMPT_ACTIVE,TI_PRE_COUNT(%ebp) + movl $PREEMPT_ACTIVE,TI_preempt_count(%ebp) sti call schedule - movl $0,TI_PRE_COUNT(%ebp) + movl $0,TI_preempt_count(%ebp) cli jmp need_resched #endif @@ -246,37 +363,50 @@ sysenter_past_esp: pushl $(__USER_CS) pushl $SYSENTER_RETURN -/* - * Load the potential sixth argument from user stack. - * Careful about security. - */ - cmpl $__PAGE_OFFSET-3,%ebp - jae syscall_fault -1: movl (%ebp),%ebp -.section __ex_table,"a" - .align 4 - .long 1b,syscall_fault -.previous - pushl %eax SAVE_ALL GET_THREAD_INFO(%ebp) cmpl $(nr_syscalls), %eax jae syscall_badsys - testb $_TIF_SYSCALL_TRACE,TI_FLAGS(%ebp) + testb $_TIF_SYSCALL_TRACE,TI_flags(%ebp) jnz syscall_trace_entry call *sys_call_table(,%eax,4) movl %eax,EAX(%esp) cli - movl TI_FLAGS(%ebp), %ecx + movl TI_flags(%ebp), %ecx testw $_TIF_ALLWORK_MASK, %cx jne syscall_exit_work + +#ifdef CONFIG_X86_SWITCH_PAGETABLES + + GET_THREAD_INFO(%ebp) + movl TI_virtual_stack(%ebp), %edx + movl TI_user_pgd(%ebp), %ecx + movl %esp, %ebx + andl $0x1fff, %ebx + orl %ebx, %edx +sysexit_ret_start_marker: + movl %edx, %esp + movl %ecx, %cr3 +#endif + /* + * only ebx is not restored by the userspace sysenter vsyscall + * code, it assumes it to be callee-saved. + */ + movl EBX(%esp), %ebx + /* if something modifies registers it must also disable sysexit */ + movl EIP(%esp), %edx movl OLDESP(%esp), %ecx + sti sysexit +#ifdef CONFIG_X86_SWITCH_PAGETABLES +sysexit_ret_end_marker: + nop +#endif # system call handler stub @@ -287,7 +417,7 @@ ENTRY(system_call) cmpl $(nr_syscalls), %eax jae syscall_badsys # system call tracing in operation - testb $_TIF_SYSCALL_TRACE,TI_FLAGS(%ebp) + testb $_TIF_SYSCALL_TRACE,TI_flags(%ebp) jnz syscall_trace_entry syscall_call: call *sys_call_table(,%eax,4) @@ -296,10 +426,23 @@ syscall_exit: cli # make sure we don't miss an interrupt # setting need_resched or sigpending # between sampling and the iret - movl TI_FLAGS(%ebp), %ecx + movl TI_flags(%ebp), %ecx testw $_TIF_ALLWORK_MASK, %cx # current->work jne syscall_exit_work restore_all: +#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS + movl EFLAGS(%esp), %eax # mix EFLAGS and CS + movb CS(%esp), %al + testl $(VM_MASK | 3), %eax + jz resume_kernelX # returning to kernel or vm86-space + + cmpl $0,TI_preempt_count(%ebp) # non-zero preempt_count ? + jz resume_kernelX + + int $3 + +resume_kernelX: +#endif RESTORE_ALL # perform work that needs to be done immediately before resumption @@ -312,7 +455,7 @@ work_resched: cli # make sure we don't miss an interrupt # setting need_resched or sigpending # between sampling and the iret - movl TI_FLAGS(%ebp), %ecx + movl TI_flags(%ebp), %ecx andl $_TIF_WORK_MASK, %ecx # is there any work to be done other # than syscall tracing? jz restore_all @@ -327,6 +470,22 @@ work_notifysig: # deal with pending s # vm86-space xorl %edx, %edx call do_notify_resume + +#if CONFIG_X86_HIGH_ENTRY + /* + * Reload db7 if necessary: + */ + movl TI_flags(%ebp), %ecx + testb $_TIF_DB7, %cl + jnz work_db7 + + jmp restore_all + +work_db7: + movl TI_task(%ebp), %edx; + movl task_thread_db7(%edx), %edx; + movl %edx, %db7; +#endif jmp restore_all ALIGN @@ -382,7 +541,7 @@ syscall_badsys: */ .data ENTRY(interrupt) -.text +.previous vector=0 ENTRY(irq_entries_start) @@ -392,7 +551,7 @@ ENTRY(irq_entries_start) jmp common_interrupt .data .long 1b -.text +.previous vector=vector+1 .endr @@ -433,12 +592,17 @@ error_code: movl ES(%esp), %edi # get the function address movl %eax, ORIG_EAX(%esp) movl %ecx, ES(%esp) - movl %esp, %edx pushl %esi # push the error code - pushl %edx # push the pt_regs pointer movl $(__USER_DS), %edx movl %edx, %ds movl %edx, %es + +/* clobbers edx, ebx and ebp */ + __SWITCH_KERNELSPACE + + leal 4(%esp), %edx # prepare pt_regs + pushl %edx # push pt_regs + call *%edi addl $8, %esp jmp ret_from_exception @@ -529,7 +693,7 @@ nmi_stack_correct: pushl %edx call do_nmi addl $8, %esp - RESTORE_ALL + jmp restore_all nmi_stack_fixup: FIX_STACK(12,nmi_stack_correct, 1) @@ -606,6 +770,8 @@ ENTRY(spurious_interrupt_bug) pushl $do_spurious_interrupt_bug jmp error_code +.previous + .data ENTRY(sys_call_table) .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ @@ -831,7 +997,7 @@ ENTRY(sys_call_table) .long sys_getdents64 /* 220 */ .long sys_fcntl64 .long sys_ni_syscall /* reserved for TUX */ - .long sys_ni_syscall + .long sys_mbind .long sys_gettid .long sys_readahead /* 225 */ .long sys_setxattr @@ -882,5 +1048,6 @@ ENTRY(sys_call_table) .long sys_utimes .long sys_fadvise64_64 .long sys_ni_syscall /* sys_vserver */ + .long sys_kexec_load syscall_table_size=(.-sys_call_table) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/entry_trampoline.c 830-ivtv/arch/i386/kernel/entry_trampoline.c --- 000-virgin/arch/i386/kernel/entry_trampoline.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/arch/i386/kernel/entry_trampoline.c Thu Jan 8 09:30:57 2004 @@ -0,0 +1,75 @@ +/* + * linux/arch/i386/kernel/entry_trampoline.c + * + * (C) Copyright 2003 Ingo Molnar + * + * This file contains the needed support code for 4GB userspace + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern char __entry_tramp_start, __entry_tramp_end, __start___entry_text; + +void __init init_entry_mappings(void) +{ +#ifdef CONFIG_X86_HIGH_ENTRY + void *tramp; + + /* + * We need a high IDT and GDT for the 4G/4G split: + */ + trap_init_virtual_IDT(); + + __set_fixmap(FIX_ENTRY_TRAMPOLINE_0, __pa((unsigned long)&__entry_tramp_start), PAGE_KERNEL); + __set_fixmap(FIX_ENTRY_TRAMPOLINE_1, __pa((unsigned long)&__entry_tramp_start) + PAGE_SIZE, PAGE_KERNEL); + tramp = (void *)fix_to_virt(FIX_ENTRY_TRAMPOLINE_0); + + printk("mapped 4G/4G trampoline to %p.\n", tramp); + BUG_ON((void *)&__start___entry_text != tramp); + /* + * Virtual kernel stack: + */ + BUG_ON(__kmap_atomic_vaddr(KM_VSTACK0) & 8191); + BUG_ON(sizeof(struct desc_struct)*NR_CPUS*GDT_ENTRIES > 2*PAGE_SIZE); + BUG_ON((unsigned int)&__entry_tramp_end - (unsigned int)&__entry_tramp_start > 2*PAGE_SIZE); + + /* + * set up the initial thread's virtual stack related + * fields: + */ + current->thread.stack_page0 = virt_to_page((char *)current->thread_info); + current->thread.stack_page1 = virt_to_page((char *)current->thread_info + PAGE_SIZE); + current->thread_info->virtual_stack = (void *)__kmap_atomic_vaddr(KM_VSTACK0); + + __kunmap_atomic_type(KM_VSTACK0); + __kunmap_atomic_type(KM_VSTACK1); + __kmap_atomic(current->thread.stack_page0, KM_VSTACK0); + __kmap_atomic(current->thread.stack_page1, KM_VSTACK1); + +#endif + printk("current: %p\n", current); + printk("current->thread_info: %p\n", current->thread_info); + current->thread_info->real_stack = (void *)current->thread_info; + current->thread_info->user_pgd = NULL; + current->thread.esp0 = (unsigned long)current->thread_info->real_stack + THREAD_SIZE; +} + + + +void __init entry_trampoline_setup(void) +{ + /* + * old IRQ entries set up by the boot code will still hang + * around - they are a sign of hw trouble anyway, now they'll + * produce a double fault message. + */ + trap_init_virtual_GDT(); +} diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/head.S 830-ivtv/arch/i386/kernel/head.S --- 000-virgin/arch/i386/kernel/head.S Tue Sep 2 09:55:42 2003 +++ 830-ivtv/arch/i386/kernel/head.S Thu Jan 8 10:21:17 2004 @@ -16,6 +16,7 @@ #include #include #include +#include #define OLD_CL_MAGIC_ADDR 0x90020 #define OLD_CL_MAGIC 0xA33F @@ -330,7 +331,7 @@ ENTRY(stack_start) /* This is the default interrupt "handler" :-) */ int_msg: - .asciz "Unknown interrupt\n" + .asciz "Unknown interrupt or fault at EIP %p %p %p\n" ALIGN ignore_int: cld @@ -342,9 +343,17 @@ ignore_int: movl $(__KERNEL_DS),%eax movl %eax,%ds movl %eax,%es + pushl 16(%esp) + pushl 24(%esp) + pushl 32(%esp) + pushl 40(%esp) pushl $int_msg call printk popl %eax + popl %eax + popl %eax + popl %eax + popl %eax popl %ds popl %es popl %edx @@ -377,23 +386,27 @@ cpu_gdt_descr: .fill NR_CPUS-1,8,0 # space for the other GDT descriptors /* - * This is initialized to create an identity-mapping at 0-8M (for bootup - * purposes) and another mapping of the 0-8M area at virtual address + * This is initialized to create an identity-mapping at 0-16M (for bootup + * purposes) and another mapping of the 0-16M area at virtual address * PAGE_OFFSET. */ .org 0x1000 ENTRY(swapper_pg_dir) .long 0x00102007 .long 0x00103007 - .fill BOOT_USER_PGD_PTRS-2,4,0 - /* default: 766 entries */ + .long 0x00104007 + .long 0x00105007 + .fill BOOT_USER_PGD_PTRS-4,4,0 + /* default: 764 entries */ .long 0x00102007 .long 0x00103007 - /* default: 254 entries */ - .fill BOOT_KERNEL_PGD_PTRS-2,4,0 + .long 0x00104007 + .long 0x00105007 + /* default: 252 entries */ + .fill BOOT_KERNEL_PGD_PTRS-4,4,0 /* - * The page tables are initialized to only 8MB here - the final page + * The page tables are initialized to only 16MB here - the final page * tables are set up later depending on memory size. */ .org 0x2000 @@ -402,15 +415,21 @@ ENTRY(pg0) .org 0x3000 ENTRY(pg1) +.org 0x4000 +ENTRY(pg2) + +.org 0x5000 +ENTRY(pg3) + /* * empty_zero_page must immediately follow the page tables ! (The * initialization loop counts until empty_zero_page) */ -.org 0x4000 +.org 0x6000 ENTRY(empty_zero_page) -.org 0x5000 +.org 0x7000 /* * Real beginning of normal "text" segment @@ -419,12 +438,12 @@ ENTRY(stext) ENTRY(_stext) /* - * This starts the data section. Note that the above is all - * in the text section because it has alignment requirements - * that we cannot fulfill any other way. + * This starts the data section. */ .data +.align PAGE_SIZE_asm + /* * The Global Descriptor Table contains 28 quadwords, per-CPU. */ @@ -439,7 +458,9 @@ ENTRY(boot_gdt_table) .quad 0x00cf9a000000ffff /* kernel 4GB code at 0x00000000 */ .quad 0x00cf92000000ffff /* kernel 4GB data at 0x00000000 */ #endif - .align L1_CACHE_BYTES + +.align PAGE_SIZE_asm + ENTRY(cpu_gdt_table) .quad 0x0000000000000000 /* NULL descriptor */ .quad 0x0000000000000000 /* 0x0b reserved */ @@ -485,5 +506,26 @@ ENTRY(cpu_gdt_table) #ifdef CONFIG_SMP .fill (NR_CPUS-1)*GDT_ENTRIES,8,0 /* other CPU's GDT */ +#endif + +#ifdef CONFIG_GCOV_PROFILE +/* + * The .ctors-section contains a list of pointers to constructor + * functions which are used to initialize gcov structures. + * + * Because there is no NULL at the end of the constructor list + * in the kernel we need the addresses of both the constructor + * as well as the destructor list which are supposed to be + * adjacent. + */ + +.section ".ctors","aw" +.globl __CTOR_LIST__ +.type __CTOR_LIST__,@object +__CTOR_LIST__: +.section ".dtors","aw" +.globl __DTOR_LIST__ +.type __DTOR_LIST__,@object +__DTOR_LIST__: #endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/i386_ksyms.c 830-ivtv/arch/i386/kernel/i386_ksyms.c --- 000-virgin/arch/i386/kernel/i386_ksyms.c Mon Nov 17 18:29:21 2003 +++ 830-ivtv/arch/i386/kernel/i386_ksyms.c Thu Jan 8 10:21:27 2004 @@ -98,7 +98,6 @@ EXPORT_SYMBOL_NOVERS(__down_failed_inter EXPORT_SYMBOL_NOVERS(__down_failed_trylock); EXPORT_SYMBOL_NOVERS(__up_wakeup); /* Networking helper routines. */ -EXPORT_SYMBOL(csum_partial_copy_generic); /* Delay loops */ EXPORT_SYMBOL(__ndelay); EXPORT_SYMBOL(__udelay); @@ -112,13 +111,17 @@ EXPORT_SYMBOL_NOVERS(__get_user_4); EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strstr); +#if !defined(CONFIG_X86_UACCESS_INDIRECT) EXPORT_SYMBOL(strncpy_from_user); -EXPORT_SYMBOL(__strncpy_from_user); +EXPORT_SYMBOL(__direct_strncpy_from_user); EXPORT_SYMBOL(clear_user); EXPORT_SYMBOL(__clear_user); EXPORT_SYMBOL(__copy_from_user_ll); EXPORT_SYMBOL(__copy_to_user_ll); EXPORT_SYMBOL(strnlen_user); +#else /* CONFIG_X86_UACCESS_INDIRECT */ +EXPORT_SYMBOL(direct_csum_partial_copy_generic); +#endif EXPORT_SYMBOL(dma_alloc_coherent); EXPORT_SYMBOL(dma_free_coherent); @@ -185,6 +188,11 @@ extern void * memset(void *,int,__kernel extern void * memcpy(void *,const void *,__kernel_size_t); EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL_NOVERS(memset); + +#ifdef CONFIG_MCOUNT +extern void mcount(void); +EXPORT_SYMBOL_NOVERS(mcount); +#endif #ifdef CONFIG_HAVE_DEC_LOCK EXPORT_SYMBOL(atomic_dec_and_lock); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/i387.c 830-ivtv/arch/i386/kernel/i387.c --- 000-virgin/arch/i386/kernel/i387.c Mon Nov 17 18:29:21 2003 +++ 830-ivtv/arch/i386/kernel/i387.c Thu Jan 8 09:30:58 2004 @@ -218,6 +218,7 @@ void set_fpu_mxcsr( struct task_struct * static int convert_fxsr_to_user( struct _fpstate __user *buf, struct i387_fxsave_struct *fxsave ) { + struct _fpreg tmp[8]; /* 80 bytes scratch area */ unsigned long env[7]; struct _fpreg __user *to; struct _fpxreg *from; @@ -234,23 +235,25 @@ static int convert_fxsr_to_user( struct if ( __copy_to_user( buf, env, 7 * sizeof(unsigned long) ) ) return 1; - to = &buf->_st[0]; + to = tmp; from = (struct _fpxreg *) &fxsave->st_space[0]; for ( i = 0 ; i < 8 ; i++, to++, from++ ) { unsigned long *t = (unsigned long *)to; unsigned long *f = (unsigned long *)from; - if (__put_user(*f, t) || - __put_user(*(f + 1), t + 1) || - __put_user(from->exponent, &to->exponent)) - return 1; + *t = *f; + *(t + 1) = *(f+1); + to->exponent = from->exponent; } + if (copy_to_user(buf->_st, tmp, sizeof(struct _fpreg [8]))) + return 1; return 0; } static int convert_fxsr_from_user( struct i387_fxsave_struct *fxsave, struct _fpstate __user *buf ) { + struct _fpreg tmp[8]; /* 80 bytes scratch area */ unsigned long env[7]; struct _fpxreg *to; struct _fpreg __user *from; @@ -258,6 +261,8 @@ static int convert_fxsr_from_user( struc if ( __copy_from_user( env, buf, 7 * sizeof(long) ) ) return 1; + if (copy_from_user(tmp, buf->_st, sizeof(struct _fpreg [8]))) + return 1; fxsave->cwd = (unsigned short)(env[0] & 0xffff); fxsave->swd = (unsigned short)(env[1] & 0xffff); @@ -269,15 +274,14 @@ static int convert_fxsr_from_user( struc fxsave->fos = env[6]; to = (struct _fpxreg *) &fxsave->st_space[0]; - from = &buf->_st[0]; + from = tmp; for ( i = 0 ; i < 8 ; i++, to++, from++ ) { unsigned long *t = (unsigned long *)to; unsigned long *f = (unsigned long *)from; - if (__get_user(*t, f) || - __get_user(*(t + 1), f + 1) || - __get_user(to->exponent, &from->exponent)) - return 1; + *t = *f; + *(t + 1) = *(f + 1); + to->exponent = from->exponent; } return 0; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/i8259.c 830-ivtv/arch/i386/kernel/i8259.c --- 000-virgin/arch/i386/kernel/i8259.c Thu Jan 8 08:35:20 2004 +++ 830-ivtv/arch/i386/kernel/i8259.c Thu Jan 8 10:26:46 2004 @@ -244,9 +244,21 @@ static int i8259A_resume(struct sys_devi return 0; } +static int i8259A_shutdown(struct sys_device *dev) +{ + /* Put the i8259A into a quiescent state that + * the kernel initialization code can get it + * out of. + */ + outb(0xff, 0x21); /* mask all of 8259A-1 */ + outb(0xff, 0xA1); /* mask all of 8259A-1 */ + return 0; +} + static struct sysdev_class i8259_sysdev_class = { set_kset_name("i8259"), .resume = i8259A_resume, + .shutdown = i8259A_shutdown, }; static struct sys_device device_i8259A = { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/init_task.c 830-ivtv/arch/i386/kernel/init_task.c --- 000-virgin/arch/i386/kernel/init_task.c Mon Nov 17 18:29:21 2003 +++ 830-ivtv/arch/i386/kernel/init_task.c Thu Jan 8 09:30:58 2004 @@ -26,7 +26,7 @@ EXPORT_SYMBOL(init_mm); */ union thread_union init_thread_union __attribute__((__section__(".data.init_task"))) = - { INIT_THREAD_INFO(init_task) }; + { INIT_THREAD_INFO(init_task, init_thread_union) }; /* * Initial task structure. @@ -44,5 +44,5 @@ EXPORT_SYMBOL(init_task); * section. Since TSS's are completely CPU-local, we want them * on exact cacheline boundaries, to eliminate cacheline ping-pong. */ -struct tss_struct init_tss[NR_CPUS] __cacheline_aligned = { [0 ... NR_CPUS-1] = INIT_TSS }; +struct tss_struct init_tss[NR_CPUS] __attribute__((__section__(".data.tss"))) = { [0 ... NR_CPUS-1] = INIT_TSS }; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/io_apic.c 830-ivtv/arch/i386/kernel/io_apic.c --- 000-virgin/arch/i386/kernel/io_apic.c Thu Jan 8 08:35:20 2004 +++ 830-ivtv/arch/i386/kernel/io_apic.c Thu Jan 8 10:26:46 2004 @@ -280,7 +280,7 @@ static void set_ioapic_affinity_irq(unsi spin_unlock_irqrestore(&ioapic_lock, flags); } -#if defined(CONFIG_SMP) +#if defined(CONFIG_IRQBALANCE) # include /* kernel_thread() */ # include /* kstat */ # include /* kmalloc() */ @@ -401,7 +401,7 @@ static void do_irq_balance(void) unsigned long max_cpu_irq = 0, min_cpu_irq = (~0); unsigned long move_this_load = 0; int max_loaded = 0, min_loaded = 0; - unsigned long useful_load_threshold = balanced_irq_interval + 10; + unsigned long useful_load_threshold = balanced_irq_interval / 10; int selected_irq; int tmp_loaded, first_attempt = 1; unsigned long tmp_cpu_irq; @@ -689,9 +689,11 @@ static inline void move_irq(int irq) __initcall(balanced_irq_init); -#else /* !SMP */ +#else /* !CONFIG_IRQBALANCE */ static inline void move_irq(int irq) { } +#endif /* CONFIG_IRQBALANCE */ +#ifndef CONFIG_SMP void send_IPI_self(int vector) { unsigned int cfg; @@ -706,7 +708,7 @@ void send_IPI_self(int vector) */ apic_write_around(APIC_ICR, cfg); } -#endif /* defined(CONFIG_SMP) */ +#endif /* !CONFIG_SMP */ /* @@ -1629,8 +1631,6 @@ void disable_IO_APIC(void) * Clear the IO-APIC before rebooting: */ clear_IO_APIC(); - - disconnect_bsp_APIC(); } /* diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/irq.c 830-ivtv/arch/i386/kernel/irq.c --- 000-virgin/arch/i386/kernel/irq.c Thu Jan 8 08:35:20 2004 +++ 830-ivtv/arch/i386/kernel/irq.c Thu Jan 8 09:30:18 2004 @@ -508,6 +508,8 @@ out: irq_exit(); + kgdb_process_breakpoint(); + return 1; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/kgdb_stub.c 830-ivtv/arch/i386/kernel/kgdb_stub.c --- 000-virgin/arch/i386/kernel/kgdb_stub.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/arch/i386/kernel/kgdb_stub.c Thu Jan 8 09:30:18 2004 @@ -0,0 +1,2457 @@ +/* + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +/* + * Copyright (c) 2000 VERITAS Software Corporation. + * + */ +/**************************************************************************** + * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ + * + * Module name: remcom.c $ + * Revision: 1.34 $ + * Date: 91/03/09 12:29:49 $ + * Contributor: Lake Stevens Instrument Division$ + * + * Description: low level support for gdb debugger. $ + * + * Considerations: only works on target hardware $ + * + * Written by: Glenn Engel $ + * Updated by: David Grothe + * Updated by: Robert Walsh + * Updated by: wangdi + * ModuleState: Experimental $ + * + * NOTES: See Below $ + * + * Modified for 386 by Jim Kingdon, Cygnus Support. + * Compatibility with 2.1.xx kernel by David Grothe + * + * Changes to allow auto initilization. All that is needed is that it + * be linked with the kernel and a break point (int 3) be executed. + * The header file defines BREAKPOINT to allow one to do + * this. It should also be possible, once the interrupt system is up, to + * call putDebugChar("+"). Once this is done, the remote debugger should + * get our attention by sending a ^C in a packet. George Anzinger + * + * Integrated into 2.2.5 kernel by Tigran Aivazian + * Added thread support, support for multiple processors, + * support for ia-32(x86) hardware debugging. + * Amit S. Kale ( akale@veritas.com ) + * + * Modified to support debugging over ethernet by Robert Walsh + * and wangdi , based on + * code by San Mehat. + * + * + * To enable debugger support, two things need to happen. One, a + * call to set_debug_traps() is necessary in order to allow any breakpoints + * or error conditions to be properly intercepted and reported to gdb. + * Two, a breakpoint needs to be generated to begin communication. This + * is most easily accomplished by a call to breakpoint(). Breakpoint() + * simulates a breakpoint by executing an int 3. + * + ************* + * + * The following gdb commands are supported: + * + * command function Return value + * + * g return the value of the CPU registers hex data or ENN + * G set the value of the CPU registers OK or ENN + * + * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN + * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN + * + * c Resume at current address SNN ( signal NN) + * cAA..AA Continue at address AA..AA SNN + * + * s Step one instruction SNN + * sAA..AA Step one instruction from AA..AA SNN + * + * k kill + * + * ? What was the last sigval ? SNN (signal NN) + * + * All commands and responses are sent with a packet which includes a + * checksum. A packet consists of + * + * $#. + * + * where + * :: + * :: < two hex digits computed as modulo 256 sum of > + * + * When a packet is received, it is first acknowledged with either '+' or '-'. + * '+' indicates a successful transfer. '-' indicates a failed transfer. + * + * Example: + * + * Host: Reply: + * $m0,10#2a +$00010203040506070809101112131415#42 + * + ****************************************************************************/ +#define KGDB_VERSION "<20030915.1651.33>" +#include +#include +#include /* for strcpy */ +#include +#include +#include +#include +#include /* for linux pt_regs struct */ +#include +#include +#include +#include +#include +#include +#include +#include + +/************************************************************************ + * + * external low-level support routines + */ +typedef void (*Function) (void); /* pointer to a function */ + +/* Thread reference */ +typedef unsigned char threadref[8]; + +extern int tty_putDebugChar(int); /* write a single character */ +extern int tty_getDebugChar(void); /* read and return a single char */ +extern void tty_flushDebugChar(void); /* flush pending characters */ +extern int eth_putDebugChar(int); /* write a single character */ +extern int eth_getDebugChar(void); /* read and return a single char */ +extern void eth_flushDebugChar(void); /* flush pending characters */ + +/************************************************************************/ +/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/ +/* at least NUMREGBYTES*2 are needed for register packets */ +/* Longer buffer is needed to list all threads */ +#define BUFMAX 400 + +char *kgdb_version = KGDB_VERSION; + +/* debug > 0 prints ill-formed commands in valid packets & checksum errors */ +int debug_regs = 0; /* set to non-zero to print registers */ + +/* filled in by an external module */ +char *gdb_module_offsets; + +static const char hexchars[] = "0123456789abcdef"; + +/* Number of bytes of registers. */ +#define NUMREGBYTES 64 +/* + * Note that this register image is in a different order than + * the register image that Linux produces at interrupt time. + * + * Linux's register image is defined by struct pt_regs in ptrace.h. + * Just why GDB uses a different order is a historical mystery. + */ +enum regnames { _EAX, /* 0 */ + _ECX, /* 1 */ + _EDX, /* 2 */ + _EBX, /* 3 */ + _ESP, /* 4 */ + _EBP, /* 5 */ + _ESI, /* 6 */ + _EDI, /* 7 */ + _PC /* 8 also known as eip */ , + _PS /* 9 also known as eflags */ , + _CS, /* 10 */ + _SS, /* 11 */ + _DS, /* 12 */ + _ES, /* 13 */ + _FS, /* 14 */ + _GS /* 15 */ +}; + +/*************************** ASSEMBLY CODE MACROS *************************/ +/* + * Put the error code here just in case the user cares. + * Likewise, the vector number here (since GDB only gets the signal + * number through the usual means, and that's not very specific). + * The called_from is the return address so he can tell how we entered kgdb. + * This will allow him to seperate out the various possible entries. + */ +#define REMOTE_DEBUG 0 /* set != to turn on printing (also available in info) */ + +#define PID_MAX PID_MAX_DEFAULT + +#ifdef CONFIG_SMP +void smp_send_nmi_allbutself(void); +#define IF_SMP(x) x +#undef MAX_NO_CPUS +#ifndef CONFIG_NO_KGDB_CPUS +#define CONFIG_NO_KGDB_CPUS 2 +#endif +#if CONFIG_NO_KGDB_CPUS > NR_CPUS +#define MAX_NO_CPUS NR_CPUS +#else +#define MAX_NO_CPUS CONFIG_NO_KGDB_CPUS +#endif +#define hold_init hold_on_sstep: 1, +#define MAX_CPU_MASK (unsigned long)((1LL << MAX_NO_CPUS) - 1LL) +#define NUM_CPUS num_online_cpus() +#else +#define IF_SMP(x) +#define hold_init +#undef MAX_NO_CPUS +#define MAX_NO_CPUS 1 +#define NUM_CPUS 1 +#endif +#define NOCPU (struct task_struct *)0xbad1fbad +/* *INDENT-OFF* */ +struct kgdb_info { + int used_malloc; + void *called_from; + long long entry_tsc; + int errcode; + int vector; + int print_debug_info; +#ifdef CONFIG_SMP + int hold_on_sstep; + struct { + volatile struct task_struct *task; + int pid; + int hold; + struct pt_regs *regs; + } cpus_waiting[MAX_NO_CPUS]; +#endif +} kgdb_info = {hold_init print_debug_info:REMOTE_DEBUG, vector:-1}; + +/* *INDENT-ON* */ + +#define used_m kgdb_info.used_malloc +/* + * This is little area we set aside to contain the stack we + * need to build to allow gdb to call functions. We use one + * per cpu to avoid locking issues. We will do all this work + * with interrupts off so that should take care of the protection + * issues. + */ +#define LOOKASIDE_SIZE 200 /* should be more than enough */ +#define MALLOC_MAX 200 /* Max malloc size */ +struct { + unsigned int esp; + int array[LOOKASIDE_SIZE]; +} fn_call_lookaside[MAX_NO_CPUS]; + +static int trap_cpu; +static unsigned int OLD_esp; + +#define END_OF_LOOKASIDE &fn_call_lookaside[trap_cpu].array[LOOKASIDE_SIZE] +#define IF_BIT 0x200 +#define TF_BIT 0x100 + +#define MALLOC_ROUND 8-1 + +static char malloc_array[MALLOC_MAX]; +IF_SMP(static void to_gdb(const char *mess)); +void * +malloc(int size) +{ + + if (size <= (MALLOC_MAX - used_m)) { + int old_used = used_m; + used_m += ((size + MALLOC_ROUND) & (~MALLOC_ROUND)); + return &malloc_array[old_used]; + } else { + return NULL; + } +} + +/* + * I/O dispatch functions... + * Based upon kgdboe, either call the ethernet + * handler or the serial one.. + */ +void +putDebugChar(int c) +{ + if (!kgdboe) { + tty_putDebugChar(c); + } else { + eth_putDebugChar(c); + } +} + +int +getDebugChar(void) +{ + if (!kgdboe) { + return tty_getDebugChar(); + } else { + return eth_getDebugChar(); + } +} + +void +flushDebugChar(void) +{ + if (!kgdboe) { + tty_flushDebugChar(); + } else { + eth_flushDebugChar(); + } +} + +/* + * Gdb calls functions by pushing agruments, including a return address + * on the stack and the adjusting EIP to point to the function. The + * whole assumption in GDB is that we are on a different stack than the + * one the "user" i.e. code that hit the break point, is on. This, of + * course is not true in the kernel. Thus various dodges are needed to + * do the call without directly messing with EIP (which we can not change + * as it is just a location and not a register. To adjust it would then + * require that we move every thing below EIP up or down as needed. This + * will not work as we may well have stack relative pointer on the stack + * (such as the pointer to regs, for example). + + * So here is what we do: + * We detect gdb attempting to store into the stack area and instead, store + * into the fn_call_lookaside.array at the same relative location as if it + * were the area ESP pointed at. We also trap ESP modifications + * and uses these to adjust fn_call_lookaside.esp. On entry + * fn_call_lookaside.esp will be set to point at the last entry in + * fn_call_lookaside.array. This allows us to check if it has changed, and + * if so, on exit, we add the registers we will use to do the move and a + * trap/ interrupt return exit sequence. We then adjust the eflags in the + * regs array (remember we now have a copy in the fn_call_lookaside.array) to + * kill the interrupt bit, AND we change EIP to point at our set up stub. + * As part of the register set up we preset the registers to point at the + * begining and end of the fn_call_lookaside.array, so all the stub needs to + * do is move words from the array to the stack until ESP= the desired value + * then do the rti. This will then transfer to the desired function with + * all the correct registers. Nifty huh? + */ +extern asmlinkage void fn_call_stub(void); +extern asmlinkage void fn_rtn_stub(void); +/* *INDENT-OFF* */ +__asm__("fn_rtn_stub:\n\t" + "movl %eax,%esp\n\t" + "fn_call_stub:\n\t" + "1:\n\t" + "addl $-4,%ebx\n\t" + "movl (%ebx), %eax\n\t" + "pushl %eax\n\t" + "cmpl %esp,%ecx\n\t" + "jne 1b\n\t" + "popl %eax\n\t" + "popl %ebx\n\t" + "popl %ecx\n\t" + "iret \n\t"); +/* *INDENT-ON* */ +#define gdb_i386vector kgdb_info.vector +#define gdb_i386errcode kgdb_info.errcode +#define waiting_cpus kgdb_info.cpus_waiting +#define remote_debug kgdb_info.print_debug_info +#define hold_cpu(cpu) kgdb_info.cpus_waiting[cpu].hold +/* gdb locks */ + +#ifdef CONFIG_SMP +static int in_kgdb_called; +static spinlock_t waitlocks[MAX_NO_CPUS] = + {[0 ... MAX_NO_CPUS - 1] = SPIN_LOCK_UNLOCKED }; +/* + * The following array has the thread pointer of each of the "other" + * cpus. We make it global so it can be seen by gdb. + */ +volatile int in_kgdb_entry_log[MAX_NO_CPUS]; +volatile struct pt_regs *in_kgdb_here_log[MAX_NO_CPUS]; +/* +static spinlock_t continuelocks[MAX_NO_CPUS]; +*/ +spinlock_t kgdb_spinlock = SPIN_LOCK_UNLOCKED; +/* waiters on our spinlock plus us */ +static atomic_t spinlock_waiters = ATOMIC_INIT(1); +static int spinlock_count = 0; +static int spinlock_cpu = 0; +/* + * Note we use nested spin locks to account for the case where a break + * point is encountered when calling a function by user direction from + * kgdb. Also there is the memory exception recursion to account for. + * Well, yes, but this lets other cpus thru too. Lets add a + * cpu id to the lock. + */ +#define KGDB_SPIN_LOCK(x) if( spinlock_count == 0 || \ + spinlock_cpu != smp_processor_id()){\ + atomic_inc(&spinlock_waiters); \ + while (! spin_trylock(x)) {\ + in_kgdb(®s);\ + }\ + atomic_dec(&spinlock_waiters); \ + spinlock_count = 1; \ + spinlock_cpu = smp_processor_id(); \ + }else{ \ + spinlock_count++; \ + } +#define KGDB_SPIN_UNLOCK(x) if( --spinlock_count == 0) spin_unlock(x) +#else +unsigned kgdb_spinlock = 0; +#define KGDB_SPIN_LOCK(x) --*x +#define KGDB_SPIN_UNLOCK(x) ++*x +#endif + +int +hex(char ch) +{ + if ((ch >= 'a') && (ch <= 'f')) + return (ch - 'a' + 10); + if ((ch >= '0') && (ch <= '9')) + return (ch - '0'); + if ((ch >= 'A') && (ch <= 'F')) + return (ch - 'A' + 10); + return (-1); +} + +/* scan for the sequence $# */ +void +getpacket(char *buffer) +{ + unsigned char checksum; + unsigned char xmitcsum; + int i; + int count; + char ch; + + do { + /* wait around for the start character, ignore all other characters */ + while ((ch = (getDebugChar() & 0x7f)) != '$') ; + checksum = 0; + xmitcsum = -1; + + count = 0; + + /* now, read until a # or end of buffer is found */ + while (count < BUFMAX) { + ch = getDebugChar() & 0x7f; + if (ch == '#') + break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + buffer[count] = 0; + + if (ch == '#') { + xmitcsum = hex(getDebugChar() & 0x7f) << 4; + xmitcsum += hex(getDebugChar() & 0x7f); + if ((remote_debug) && (checksum != xmitcsum)) { + printk + ("bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n", + checksum, xmitcsum, buffer); + } + + if (checksum != xmitcsum) + putDebugChar('-'); /* failed checksum */ + else { + putDebugChar('+'); /* successful transfer */ + /* if a sequence char is present, reply the sequence ID */ + if (buffer[2] == ':') { + putDebugChar(buffer[0]); + putDebugChar(buffer[1]); + /* remove sequence chars from buffer */ + count = strlen(buffer); + for (i = 3; i <= count; i++) + buffer[i - 3] = buffer[i]; + } + } + } + } while (checksum != xmitcsum); + + if (remote_debug) + printk("R:%s\n", buffer); + flushDebugChar(); +} + +/* send the packet in buffer. */ + +void +putpacket(char *buffer) +{ + unsigned char checksum; + int count; + char ch; + + /* $#. */ + + if (!kgdboe) { + do { + if (remote_debug) + printk("T:%s\n", buffer); + putDebugChar('$'); + checksum = 0; + count = 0; + + while ((ch = buffer[count])) { + putDebugChar(ch); + checksum += ch; + count += 1; + } + + putDebugChar('#'); + putDebugChar(hexchars[checksum >> 4]); + putDebugChar(hexchars[checksum % 16]); + flushDebugChar(); + + } while ((getDebugChar() & 0x7f) != '+'); + } else { + /* + * For udp, we can not transfer too much bytes once. + * We only transfer MAX_SEND_COUNT size bytes each time + */ + +#define MAX_SEND_COUNT 30 + + int send_count = 0, i = 0; + char send_buf[MAX_SEND_COUNT]; + + do { + if (remote_debug) + printk("T:%s\n", buffer); + putDebugChar('$'); + checksum = 0; + count = 0; + send_count = 0; + while ((ch = buffer[count])) { + if (send_count >= MAX_SEND_COUNT) { + for(i = 0; i < MAX_SEND_COUNT; i++) { + putDebugChar(send_buf[i]); + } + flushDebugChar(); + send_count = 0; + } else { + send_buf[send_count] = ch; + checksum += ch; + count ++; + send_count++; + } + } + for(i = 0; i < send_count; i++) + putDebugChar(send_buf[i]); + putDebugChar('#'); + putDebugChar(hexchars[checksum >> 4]); + putDebugChar(hexchars[checksum % 16]); + flushDebugChar(); + } while ((getDebugChar() & 0x7f) != '+'); + } +} + +static char remcomInBuffer[BUFMAX]; +static char remcomOutBuffer[BUFMAX]; +static short error; + +void +debug_error(char *format, char *parm) +{ + if (remote_debug) + printk(format, parm); +} + +static void +print_regs(struct pt_regs *regs) +{ + printk("EAX=%08lx ", regs->eax); + printk("EBX=%08lx ", regs->ebx); + printk("ECX=%08lx ", regs->ecx); + printk("EDX=%08lx ", regs->edx); + printk("\n"); + printk("ESI=%08lx ", regs->esi); + printk("EDI=%08lx ", regs->edi); + printk("EBP=%08lx ", regs->ebp); + printk("ESP=%08lx ", (long) ®s->esp); + printk("\n"); + printk(" DS=%08x ", regs->xds); + printk(" ES=%08x ", regs->xes); + printk(" SS=%08x ", __KERNEL_DS); + printk(" FL=%08lx ", regs->eflags); + printk("\n"); + printk(" CS=%08x ", regs->xcs); + printk(" IP=%08lx ", regs->eip); +#if 0 + printk(" FS=%08x ", regs->fs); + printk(" GS=%08x ", regs->gs); +#endif + printk("\n"); + +} /* print_regs */ + +#define NEW_esp fn_call_lookaside[trap_cpu].esp + +static void +regs_to_gdb_regs(int *gdb_regs, struct pt_regs *regs) +{ + gdb_regs[_EAX] = regs->eax; + gdb_regs[_EBX] = regs->ebx; + gdb_regs[_ECX] = regs->ecx; + gdb_regs[_EDX] = regs->edx; + gdb_regs[_ESI] = regs->esi; + gdb_regs[_EDI] = regs->edi; + gdb_regs[_EBP] = regs->ebp; + gdb_regs[_DS] = regs->xds; + gdb_regs[_ES] = regs->xes; + gdb_regs[_PS] = regs->eflags; + gdb_regs[_CS] = regs->xcs; + gdb_regs[_PC] = regs->eip; + /* Note, as we are a debugging the kernel, we will always + * trap in kernel code, this means no priviledge change, + * and so the pt_regs structure is not completely valid. In a non + * privilege change trap, only EFLAGS, CS and EIP are put on the stack, + * SS and ESP are not stacked, this means that the last 2 elements of + * pt_regs is not valid (they would normally refer to the user stack) + * also, using regs+1 is no good because you end up will a value that is + * 2 longs (8) too high. This used to cause stepping over functions + * to fail, so my fix is to use the address of regs->esp, which + * should point at the end of the stack frame. Note I have ignored + * completely exceptions that cause an error code to be stacked, such + * as double fault. Stuart Hughes, Zentropix. + * original code: gdb_regs[_ESP] = (int) (regs + 1) ; + + * this is now done on entry and moved to OLD_esp (as well as NEW_esp). + */ + gdb_regs[_ESP] = NEW_esp; + gdb_regs[_SS] = __KERNEL_DS; + gdb_regs[_FS] = 0xFFFF; + gdb_regs[_GS] = 0xFFFF; +} /* regs_to_gdb_regs */ + +static void +gdb_regs_to_regs(int *gdb_regs, struct pt_regs *regs) +{ + regs->eax = gdb_regs[_EAX]; + regs->ebx = gdb_regs[_EBX]; + regs->ecx = gdb_regs[_ECX]; + regs->edx = gdb_regs[_EDX]; + regs->esi = gdb_regs[_ESI]; + regs->edi = gdb_regs[_EDI]; + regs->ebp = gdb_regs[_EBP]; + regs->xds = gdb_regs[_DS]; + regs->xes = gdb_regs[_ES]; + regs->eflags = gdb_regs[_PS]; + regs->xcs = gdb_regs[_CS]; + regs->eip = gdb_regs[_PC]; + NEW_esp = gdb_regs[_ESP]; /* keep the value */ +#if 0 /* can't change these */ + regs->esp = gdb_regs[_ESP]; + regs->xss = gdb_regs[_SS]; + regs->fs = gdb_regs[_FS]; + regs->gs = gdb_regs[_GS]; +#endif + +} /* gdb_regs_to_regs */ +extern void scheduling_functions_start_here(void); +extern void scheduling_functions_end_here(void); +#define first_sched ((unsigned long) scheduling_functions_start_here) +#define last_sched ((unsigned long) scheduling_functions_end_here) + +int thread_list = 0; + +void +get_gdb_regs(struct task_struct *p, struct pt_regs *regs, int *gdb_regs) +{ + unsigned long stack_page; + int count = 0; + IF_SMP(int i); + if (!p || p == current) { + regs_to_gdb_regs(gdb_regs, regs); + return; + } +#ifdef CONFIG_SMP + for (i = 0; i < MAX_NO_CPUS; i++) { + if (p == kgdb_info.cpus_waiting[i].task) { + regs_to_gdb_regs(gdb_regs, + kgdb_info.cpus_waiting[i].regs); + gdb_regs[_ESP] = + (int) &kgdb_info.cpus_waiting[i].regs->esp; + + return; + } + } +#endif + memset(gdb_regs, 0, NUMREGBYTES); + gdb_regs[_ESP] = p->thread.esp; + gdb_regs[_PC] = p->thread.eip; + gdb_regs[_EBP] = *(int *) gdb_regs[_ESP]; + gdb_regs[_EDI] = *(int *) (gdb_regs[_ESP] + 4); + gdb_regs[_ESI] = *(int *) (gdb_regs[_ESP] + 8); + +/* + * This code is to give a more informative notion of where a process + * is waiting. It is used only when the user asks for a thread info + * list. If he then switches to the thread, s/he will find the task + * is in schedule, but a back trace should show the same info we come + * up with. This code was shamelessly purloined from process.c. It was + * then enhanced to provide more registers than simply the program + * counter. + */ + + if (!thread_list) { + return; + } + + if (p->state == TASK_RUNNING) + return; + stack_page = (unsigned long) p->thread_info; + if (gdb_regs[_ESP] < stack_page || gdb_regs[_ESP] > 8188 + stack_page) + return; + /* include/asm-i386/system.h:switch_to() pushes ebp last. */ + do { + if (gdb_regs[_EBP] < stack_page || + gdb_regs[_EBP] > 8184 + stack_page) + return; + gdb_regs[_PC] = *(unsigned long *) (gdb_regs[_EBP] + 4); + gdb_regs[_ESP] = gdb_regs[_EBP] + 8; + gdb_regs[_EBP] = *(unsigned long *) gdb_regs[_EBP]; + if (gdb_regs[_PC] < first_sched || gdb_regs[_PC] >= last_sched) + return; + } while (count++ < 16); + return; +} + +/* Indicate to caller of mem2hex or hex2mem that there has been an + error. */ +static volatile int mem_err = 0; +static volatile int mem_err_expected = 0; +static volatile int mem_err_cnt = 0; +static int garbage_loc = -1; + +int +get_char(char *addr) +{ + return *addr; +} + +void +set_char(char *addr, int val, int may_fault) +{ + /* + * This code traps references to the area mapped to the kernel + * stack as given by the regs and, instead, stores to the + * fn_call_lookaside[cpu].array + */ + if (may_fault && + (unsigned int) addr < OLD_esp && + ((unsigned int) addr > (OLD_esp - (unsigned int) LOOKASIDE_SIZE))) { + addr = (char *) END_OF_LOOKASIDE - ((char *) OLD_esp - addr); + } + *addr = val; +} + +/* convert the memory pointed to by mem into hex, placing result in buf */ +/* return a pointer to the last char put in buf (null) */ +/* If MAY_FAULT is non-zero, then we should set mem_err in response to + a fault; if zero treat a fault like any other fault in the stub. */ +char * +mem2hex(char *mem, char *buf, int count, int may_fault) +{ + int i; + unsigned char ch; + + if (may_fault) { + mem_err_expected = 1; + mem_err = 0; + } + for (i = 0; i < count; i++) { + /* printk("%lx = ", mem) ; */ + + ch = get_char(mem++); + + /* printk("%02x\n", ch & 0xFF) ; */ + if (may_fault && mem_err) { + if (remote_debug) + printk("Mem fault fetching from addr %lx\n", + (long) (mem - 1)); + *buf = 0; /* truncate buffer */ + return (buf); + } + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch % 16]; + } + *buf = 0; + if (may_fault) + mem_err_expected = 0; + return (buf); +} + +/* convert the hex array pointed to by buf into binary to be placed in mem */ +/* return a pointer to the character AFTER the last byte written */ +/* NOTE: We use the may fault flag to also indicate if the write is to + * the registers (0) or "other" memory (!=0) + */ +char * +hex2mem(char *buf, char *mem, int count, int may_fault) +{ + int i; + unsigned char ch; + + if (may_fault) { + mem_err_expected = 1; + mem_err = 0; + } + for (i = 0; i < count; i++) { + ch = hex(*buf++) << 4; + ch = ch + hex(*buf++); + set_char(mem++, ch, may_fault); + + if (may_fault && mem_err) { + if (remote_debug) + printk("Mem fault storing to addr %lx\n", + (long) (mem - 1)); + return (mem); + } + } + if (may_fault) + mem_err_expected = 0; + return (mem); +} + +/**********************************************/ +/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */ +/* RETURN NUMBER OF CHARS PROCESSED */ +/**********************************************/ +int +hexToInt(char **ptr, int *intValue) +{ + int numChars = 0; + int hexValue; + + *intValue = 0; + + while (**ptr) { + hexValue = hex(**ptr); + if (hexValue >= 0) { + *intValue = (*intValue << 4) | hexValue; + numChars++; + } else + break; + + (*ptr)++; + } + + return (numChars); +} + +#define stubhex(h) hex(h) +#ifdef old_thread_list + +static int +stub_unpack_int(char *buff, int fieldlength) +{ + int nibble; + int retval = 0; + + while (fieldlength) { + nibble = stubhex(*buff++); + retval |= nibble; + fieldlength--; + if (fieldlength) + retval = retval << 4; + } + return retval; +} +#endif +static char * +pack_hex_byte(char *pkt, int byte) +{ + *pkt++ = hexchars[(byte >> 4) & 0xf]; + *pkt++ = hexchars[(byte & 0xf)]; + return pkt; +} + +#define BUF_THREAD_ID_SIZE 16 + +static char * +pack_threadid(char *pkt, threadref * id) +{ + char *limit; + unsigned char *altid; + + altid = (unsigned char *) id; + limit = pkt + BUF_THREAD_ID_SIZE; + while (pkt < limit) + pkt = pack_hex_byte(pkt, *altid++); + return pkt; +} + +#ifdef old_thread_list +static char * +unpack_byte(char *buf, int *value) +{ + *value = stub_unpack_int(buf, 2); + return buf + 2; +} + +static char * +unpack_threadid(char *inbuf, threadref * id) +{ + char *altref; + char *limit = inbuf + BUF_THREAD_ID_SIZE; + int x, y; + + altref = (char *) id; + + while (inbuf < limit) { + x = stubhex(*inbuf++); + y = stubhex(*inbuf++); + *altref++ = (x << 4) | y; + } + return inbuf; +} +#endif +void +int_to_threadref(threadref * id, int value) +{ + unsigned char *scan; + + scan = (unsigned char *) id; + { + int i = 4; + while (i--) + *scan++ = 0; + } + *scan++ = (value >> 24) & 0xff; + *scan++ = (value >> 16) & 0xff; + *scan++ = (value >> 8) & 0xff; + *scan++ = (value & 0xff); +} +int +int_to_hex_v(unsigned char * id, int value) +{ + unsigned char *start = id; + int shift; + int ch; + + for (shift = 28; shift >= 0; shift -= 4) { + if ((ch = (value >> shift) & 0xf) || (id != start)) { + *id = hexchars[ch]; + id++; + } + } + if (id == start) + *id++ = '0'; + return id - start; +} +#ifdef old_thread_list + +static int +threadref_to_int(threadref * ref) +{ + int i, value = 0; + unsigned char *scan; + + scan = (char *) ref; + scan += 4; + i = 4; + while (i-- > 0) + value = (value << 8) | ((*scan++) & 0xff); + return value; +} +#endif +static int +cmp_str(char *s1, char *s2, int count) +{ + while (count--) { + if (*s1++ != *s2++) + return 0; + } + return 1; +} + +#if 1 /* this is a hold over from 2.4 where O(1) was "sometimes" */ +extern struct task_struct *kgdb_get_idle(int cpu); +#define idle_task(cpu) kgdb_get_idle(cpu) +#else +#define idle_task(cpu) init_tasks[cpu] +#endif + +extern int kgdb_pid_init_done; + +struct task_struct * +getthread(int pid) +{ + struct task_struct *thread; + if (pid >= PID_MAX && pid <= (PID_MAX + MAX_NO_CPUS)) { + + return idle_task(pid - PID_MAX); + } else { + /* + * find_task_by_pid is relatively safe all the time + * Other pid functions require lock downs which imply + * that we may be interrupting them (as we get here + * in the middle of most any lock down). + * Still we don't want to call until the table exists! + */ + if (kgdb_pid_init_done){ + thread = find_task_by_pid(pid); + if (thread) { + return thread; + } + } + } + return NULL; +} +/* *INDENT-OFF* */ +struct hw_breakpoint { + unsigned enabled; + unsigned type; + unsigned len; + unsigned addr; +} breakinfo[4] = { {enabled:0}, + {enabled:0}, + {enabled:0}, + {enabled:0}}; +/* *INDENT-ON* */ +unsigned hw_breakpoint_status; +void +correct_hw_break(void) +{ + int breakno; + int correctit; + int breakbit; + unsigned dr7; + + asm volatile ("movl %%db7, %0\n":"=r" (dr7) + :); + /* *INDENT-OFF* */ + do { + unsigned addr0, addr1, addr2, addr3; + asm volatile ("movl %%db0, %0\n" + "movl %%db1, %1\n" + "movl %%db2, %2\n" + "movl %%db3, %3\n" + :"=r" (addr0), "=r"(addr1), + "=r"(addr2), "=r"(addr3) + :); + } while (0); + /* *INDENT-ON* */ + correctit = 0; + for (breakno = 0; breakno < 3; breakno++) { + breakbit = 2 << (breakno << 1); + if (!(dr7 & breakbit) && breakinfo[breakno].enabled) { + correctit = 1; + dr7 |= breakbit; + dr7 &= ~(0xf0000 << (breakno << 2)); + dr7 |= (((breakinfo[breakno].len << 2) | + breakinfo[breakno].type) << 16) << + (breakno << 2); + switch (breakno) { + case 0: + asm volatile ("movl %0, %%dr0\n"::"r" + (breakinfo[breakno].addr)); + break; + + case 1: + asm volatile ("movl %0, %%dr1\n"::"r" + (breakinfo[breakno].addr)); + break; + + case 2: + asm volatile ("movl %0, %%dr2\n"::"r" + (breakinfo[breakno].addr)); + break; + + case 3: + asm volatile ("movl %0, %%dr3\n"::"r" + (breakinfo[breakno].addr)); + break; + } + } else if ((dr7 & breakbit) && !breakinfo[breakno].enabled) { + correctit = 1; + dr7 &= ~breakbit; + dr7 &= ~(0xf0000 << (breakno << 2)); + } + } + if (correctit) { + asm volatile ("movl %0, %%db7\n"::"r" (dr7)); + } +} + +int +remove_hw_break(unsigned breakno) +{ + if (!breakinfo[breakno].enabled) { + return -1; + } + breakinfo[breakno].enabled = 0; + return 0; +} + +int +set_hw_break(unsigned breakno, unsigned type, unsigned len, unsigned addr) +{ + if (breakinfo[breakno].enabled) { + return -1; + } + breakinfo[breakno].enabled = 1; + breakinfo[breakno].type = type; + breakinfo[breakno].len = len; + breakinfo[breakno].addr = addr; + return 0; +} + +#ifdef CONFIG_SMP +static int in_kgdb_console = 0; + +int +in_kgdb(struct pt_regs *regs) +{ + unsigned flags; + int cpu = smp_processor_id(); + in_kgdb_called = 1; + if (!spin_is_locked(&kgdb_spinlock)) { + if (in_kgdb_here_log[cpu] || /* we are holding this cpu */ + in_kgdb_console) { /* or we are doing slow i/o */ + return 1; + } + return 0; + } + + /* As I see it the only reason not to let all cpus spin on + * the same spin_lock is to allow selected ones to proceed. + * This would be a good thing, so we leave it this way. + * Maybe someday.... Done ! + + * in_kgdb() is called from an NMI so we don't pretend + * to have any resources, like printk() for example. + */ + + kgdb_local_irq_save(flags); /* only local here, to avoid hanging */ + /* + * log arival of this cpu + * The NMI keeps on ticking. Protect against recurring more + * than once, and ignor the cpu that has the kgdb lock + */ + in_kgdb_entry_log[cpu]++; + in_kgdb_here_log[cpu] = regs; + if (cpu == spinlock_cpu || waiting_cpus[cpu].task) + goto exit_in_kgdb; + + /* + * For protection of the initilization of the spin locks by kgdb + * it locks the kgdb spinlock before it gets the wait locks set + * up. We wait here for the wait lock to be taken. If the + * kgdb lock goes away first?? Well, it could be a slow exit + * sequence where the wait lock is removed prior to the kgdb lock + * so if kgdb gets unlocked, we just exit. + */ + + while (spin_is_locked(&kgdb_spinlock) && + !spin_is_locked(waitlocks + cpu)) ; + if (!spin_is_locked(&kgdb_spinlock)) + goto exit_in_kgdb; + + waiting_cpus[cpu].task = current; + waiting_cpus[cpu].pid = (current->pid) ? : (PID_MAX + cpu); + waiting_cpus[cpu].regs = regs; + + spin_unlock_wait(waitlocks + cpu); + + /* + * log departure of this cpu + */ + waiting_cpus[cpu].task = 0; + waiting_cpus[cpu].pid = 0; + waiting_cpus[cpu].regs = 0; + correct_hw_break(); + exit_in_kgdb: + in_kgdb_here_log[cpu] = 0; + kgdb_local_irq_restore(flags); + return 1; + /* + spin_unlock(continuelocks + smp_processor_id()); + */ +} + +void +smp__in_kgdb(struct pt_regs regs) +{ + ack_APIC_irq(); + in_kgdb(®s); +} +#else +int +in_kgdb(struct pt_regs *regs) +{ + return (kgdb_spinlock); +} +#endif + +void +printexceptioninfo(int exceptionNo, int errorcode, char *buffer) +{ + unsigned dr6; + int i; + switch (exceptionNo) { + case 1: /* debug exception */ + break; + case 3: /* breakpoint */ + sprintf(buffer, "Software breakpoint"); + return; + default: + sprintf(buffer, "Details not available"); + return; + } + asm volatile ("movl %%db6, %0\n":"=r" (dr6) + :); + if (dr6 & 0x4000) { + sprintf(buffer, "Single step"); + return; + } + for (i = 0; i < 4; ++i) { + if (dr6 & (1 << i)) { + sprintf(buffer, "Hardware breakpoint %d", i); + return; + } + } + sprintf(buffer, "Unknown trap"); + return; +} + +/* + * This function does all command procesing for interfacing to gdb. + * + * NOTE: The INT nn instruction leaves the state of the interrupt + * enable flag UNCHANGED. That means that when this routine + * is entered via a breakpoint (INT 3) instruction from code + * that has interrupts enabled, then interrupts will STILL BE + * enabled when this routine is entered. The first thing that + * we do here is disable interrupts so as to prevent recursive + * entries and bothersome serial interrupts while we are + * trying to run the serial port in polled mode. + * + * For kernel version 2.1.xx the kgdb_cli() actually gets a spin lock so + * it is always necessary to do a restore_flags before returning + * so as to let go of that lock. + */ +int +kgdb_handle_exception(int exceptionVector, + int signo, int err_code, struct pt_regs *linux_regs) +{ + struct task_struct *usethread = NULL; + struct task_struct *thread_list_start = 0, *thread = NULL; + int addr, length; + int breakno, breaktype; + char *ptr; + int newPC; + threadref thref; + int threadid; + int thread_min = PID_MAX + MAX_NO_CPUS; +#ifdef old_thread_list + int maxthreads; +#endif + int nothreads; + unsigned long flags; + int gdb_regs[NUMREGBYTES / 4]; + int dr6; + IF_SMP(int entry_state = 0); /* 0, ok, 1, no nmi, 2 sync failed */ +#define NO_NMI 1 +#define NO_SYNC 2 +#define regs (*linux_regs) +#define NUMREGS NUMREGBYTES/4 + /* + * If the entry is not from the kernel then return to the Linux + * trap handler and let it process the interrupt normally. + */ + if ((linux_regs->eflags & VM_MASK) || (3 & linux_regs->xcs)) { + printk("ignoring non-kernel exception\n"); + print_regs(®s); + return (0); + } + /* + * If we're using eth mode, set the 'mode' in the netdevice. + */ + + if (kgdboe) + netpoll_set_trap(1); + + kgdb_local_irq_save(flags); + + /* Get kgdb spinlock */ + + KGDB_SPIN_LOCK(&kgdb_spinlock); + rdtscll(kgdb_info.entry_tsc); + /* + * We depend on this spinlock and the NMI watch dog to control the + * other cpus. They will arrive at "in_kgdb()" as a result of the + * NMI and will wait there for the following spin locks to be + * released. + */ +#ifdef CONFIG_SMP + +#if 0 + if (cpu_callout_map & ~MAX_CPU_MASK) { + printk("kgdb : too many cpus, possibly not mapped" + " in contiguous space, change MAX_NO_CPUS" + " in kgdb_stub and make new kernel.\n" + " cpu_callout_map is %lx\n", cpu_callout_map); + goto exit_just_unlock; + } +#endif + if (spinlock_count == 1) { + int time, end_time, dum; + int i; + int cpu_logged_in[MAX_NO_CPUS] = {[0 ... MAX_NO_CPUS - 1] = (0) + }; + if (remote_debug) { + printk("kgdb : cpu %d entry, syncing others\n", + smp_processor_id()); + } + for (i = 0; i < MAX_NO_CPUS; i++) { + /* + * Use trylock as we may already hold the lock if + * we are holding the cpu. Net result is all + * locked. + */ + spin_trylock(&waitlocks[i]); + } + for (i = 0; i < MAX_NO_CPUS; i++) + cpu_logged_in[i] = 0; + /* + * Wait for their arrival. We know the watch dog is active if + * in_kgdb() has ever been called, as it is always called on a + * watchdog tick. + */ + rdtsc(dum, time); + end_time = time + 2; /* Note: we use the High order bits! */ + i = 1; + if (num_online_cpus() > 1) { + int me_in_kgdb = in_kgdb_entry_log[smp_processor_id()]; + smp_send_nmi_allbutself(); + + while (i < num_online_cpus() && time != end_time) { + int j; + for (j = 0; j < MAX_NO_CPUS; j++) { + if (waiting_cpus[j].task && + waiting_cpus[j].task != NOCPU && + !cpu_logged_in[j]) { + i++; + cpu_logged_in[j] = 1; + if (remote_debug) { + printk + ("kgdb : cpu %d arrived at kgdb\n", + j); + } + break; + } else if (!waiting_cpus[j].task && + !cpu_online(j)) { + waiting_cpus[j].task = NOCPU; + cpu_logged_in[j] = 1; + waiting_cpus[j].hold = 1; + break; + } + if (!waiting_cpus[j].task && + in_kgdb_here_log[j]) { + + int wait = 100000; + while (wait--) ; + if (!waiting_cpus[j].task && + in_kgdb_here_log[j]) { + printk + ("kgdb : cpu %d stall" + " in in_kgdb\n", + j); + i++; + cpu_logged_in[j] = 1; + waiting_cpus[j].task = + (struct task_struct + *) 1; + } + } + } + + if (in_kgdb_entry_log[smp_processor_id()] > + (me_in_kgdb + 10)) { + break; + } + + rdtsc(dum, time); + } + if (i < num_online_cpus()) { + printk + ("kgdb : time out, proceeding without sync\n"); +#if 0 + printk("kgdb : Waiting_cpus: 0 = %d, 1 = %d\n", + waiting_cpus[0].task != 0, + waiting_cpus[1].task != 0); + printk("kgdb : Cpu_logged in: 0 = %d, 1 = %d\n", + cpu_logged_in[0], cpu_logged_in[1]); + printk + ("kgdb : in_kgdb_here_log in: 0 = %d, 1 = %d\n", + in_kgdb_here_log[0] != 0, + in_kgdb_here_log[1] != 0); +#endif + entry_state = NO_SYNC; + } else { +#if 0 + int ent = + in_kgdb_entry_log[smp_processor_id()] - + me_in_kgdb; + printk("kgdb : sync after %d entries\n", ent); +#endif + } + } else { + if (remote_debug) { + printk + ("kgdb : %d cpus, but watchdog not active\n" + "proceeding without locking down other cpus\n", + num_online_cpus()); + entry_state = NO_NMI; + } + } + } +#endif + + if (remote_debug) { + unsigned long *lp = (unsigned long *) &linux_regs; + + printk("handle_exception(exceptionVector=%d, " + "signo=%d, err_code=%d, linux_regs=%p)\n", + exceptionVector, signo, err_code, linux_regs); + if (debug_regs) { + print_regs(®s); + printk("Stk: %8lx %8lx %8lx %8lx" + " %8lx %8lx %8lx %8lx\n", + lp[0], lp[1], lp[2], lp[3], + lp[4], lp[5], lp[6], lp[7]); + printk(" %8lx %8lx %8lx %8lx" + " %8lx %8lx %8lx %8lx\n", + lp[8], lp[9], lp[10], lp[11], + lp[12], lp[13], lp[14], lp[15]); + printk(" %8lx %8lx %8lx %8lx " + "%8lx %8lx %8lx %8lx\n", + lp[16], lp[17], lp[18], lp[19], + lp[20], lp[21], lp[22], lp[23]); + printk(" %8lx %8lx %8lx %8lx " + "%8lx %8lx %8lx %8lx\n", + lp[24], lp[25], lp[26], lp[27], + lp[28], lp[29], lp[30], lp[31]); + } + } + + /* Disable hardware debugging while we are in kgdb */ + /* Get the debug register status register */ +/* *INDENT-OFF* */ + __asm__("movl %0,%%db7" + : /* no output */ + :"r"(0)); + + asm volatile ("movl %%db6, %0\n" + :"=r" (hw_breakpoint_status) + :); + +/* *INDENT-ON* */ + switch (exceptionVector) { + case 0: /* divide error */ + case 1: /* debug exception */ + case 2: /* NMI */ + case 3: /* breakpoint */ + case 4: /* overflow */ + case 5: /* bounds check */ + case 6: /* invalid opcode */ + case 7: /* device not available */ + case 8: /* double fault (errcode) */ + case 10: /* invalid TSS (errcode) */ + case 12: /* stack fault (errcode) */ + case 16: /* floating point error */ + case 17: /* alignment check (errcode) */ + default: /* any undocumented */ + break; + case 11: /* segment not present (errcode) */ + case 13: /* general protection (errcode) */ + case 14: /* page fault (special errcode) */ + case 19: /* cache flush denied */ + if (mem_err_expected) { + /* + * This fault occured because of the + * get_char or set_char routines. These + * two routines use either eax of edx to + * indirectly reference the location in + * memory that they are working with. + * For a page fault, when we return the + * instruction will be retried, so we + * have to make sure that these + * registers point to valid memory. + */ + mem_err = 1; /* set mem error flag */ + mem_err_expected = 0; + mem_err_cnt++; /* helps in debugging */ + /* make valid address */ + regs.eax = (long) &garbage_loc; + /* make valid address */ + regs.edx = (long) &garbage_loc; + if (remote_debug) + printk("Return after memory error: " + "mem_err_cnt=%d\n", mem_err_cnt); + if (debug_regs) + print_regs(®s); + goto exit_kgdb; + } + break; + } + if (remote_debug) + printk("kgdb : entered kgdb on cpu %d\n", smp_processor_id()); + + gdb_i386vector = exceptionVector; + gdb_i386errcode = err_code; + kgdb_info.called_from = __builtin_return_address(0); +#ifdef CONFIG_SMP + /* + * OK, we can now communicate, lets tell gdb about the sync. + * but only if we had a problem. + */ + switch (entry_state) { + case NO_NMI: + to_gdb("NMI not active, other cpus not stopped\n"); + break; + case NO_SYNC: + to_gdb("Some cpus not stopped, see 'kgdb_info' for details\n"); + default:; + } + +#endif +/* + * Set up the gdb function call area. + */ + trap_cpu = smp_processor_id(); + OLD_esp = NEW_esp = (int) (&linux_regs->esp); + + IF_SMP(once_again:) + /* reply to host that an exception has occurred */ + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[signo >> 4]; + remcomOutBuffer[2] = hexchars[signo % 16]; + remcomOutBuffer[3] = 0; + + putpacket(remcomOutBuffer); + + while (1 == 1) { + error = 0; + remcomOutBuffer[0] = 0; + getpacket(remcomInBuffer); + switch (remcomInBuffer[0]) { + case '?': + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[signo >> 4]; + remcomOutBuffer[2] = hexchars[signo % 16]; + remcomOutBuffer[3] = 0; + break; + case 'd': + remote_debug = !(remote_debug); /* toggle debug flag */ + printk("Remote debug %s\n", + remote_debug ? "on" : "off"); + break; + case 'g': /* return the value of the CPU registers */ + get_gdb_regs(usethread, ®s, gdb_regs); + mem2hex((char *) gdb_regs, + remcomOutBuffer, NUMREGBYTES, 0); + break; + case 'G': /* set the value of the CPU registers - return OK */ + hex2mem(&remcomInBuffer[1], + (char *) gdb_regs, NUMREGBYTES, 0); + if (!usethread || usethread == current) { + gdb_regs_to_regs(gdb_regs, ®s); + strcpy(remcomOutBuffer, "OK"); + } else { + strcpy(remcomOutBuffer, "E00"); + } + break; + + case 'P':{ /* set the value of a single CPU register - + return OK */ + /* + * For some reason, gdb wants to talk about psudo + * registers (greater than 15). These may have + * meaning for ptrace, but for us it is safe to + * ignor them. We do this by dumping them into + * _GS which we also ignor, but do have memory for. + */ + int regno; + + ptr = &remcomInBuffer[1]; + regs_to_gdb_regs(gdb_regs, ®s); + if ((!usethread || usethread == current) && + hexToInt(&ptr, ®no) && + *ptr++ == '=' && (regno >= 0)) { + regno = + (regno >= NUMREGS ? _GS : regno); + hex2mem(ptr, (char *) &gdb_regs[regno], + 4, 0); + gdb_regs_to_regs(gdb_regs, ®s); + strcpy(remcomOutBuffer, "OK"); + break; + } + strcpy(remcomOutBuffer, "E01"); + break; + } + + /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + case 'm': + /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ + ptr = &remcomInBuffer[1]; + if (hexToInt(&ptr, &addr) && + (*(ptr++) == ',') && (hexToInt(&ptr, &length))) { + ptr = 0; + /* + * hex doubles the byte count + */ + if (length > (BUFMAX / 2)) + length = BUFMAX / 2; + mem2hex((char *) addr, + remcomOutBuffer, length, 1); + if (mem_err) { + strcpy(remcomOutBuffer, "E03"); + debug_error("memory fault\n", NULL); + } + } + + if (ptr) { + strcpy(remcomOutBuffer, "E01"); + debug_error + ("malformed read memory command: %s\n", + remcomInBuffer); + } + break; + + /* MAA..AA,LLLL: + Write LLLL bytes at address AA.AA return OK */ + case 'M': + /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ + ptr = &remcomInBuffer[1]; + if (hexToInt(&ptr, &addr) && + (*(ptr++) == ',') && + (hexToInt(&ptr, &length)) && (*(ptr++) == ':')) { + hex2mem(ptr, (char *) addr, length, 1); + + if (mem_err) { + strcpy(remcomOutBuffer, "E03"); + debug_error("memory fault\n", NULL); + } else { + strcpy(remcomOutBuffer, "OK"); + } + + ptr = 0; + } + if (ptr) { + strcpy(remcomOutBuffer, "E02"); + debug_error + ("malformed write memory command: %s\n", + remcomInBuffer); + } + break; + case 'S': + remcomInBuffer[0] = 's'; + case 'C': + /* Csig;AA..AA where ;AA..AA is optional + * continue with signal + * Since signals are meaning less to us, delete that + * part and then fall into the 'c' code. + */ + ptr = &remcomInBuffer[1]; + length = 2; + while (*ptr && *ptr != ';') { + length++; + ptr++; + } + if (*ptr) { + do { + ptr++; + *(ptr - length++) = *ptr; + } while (*ptr); + } else { + remcomInBuffer[1] = 0; + } + + /* cAA..AA Continue at address AA..AA(optional) */ + /* sAA..AA Step one instruction from AA..AA(optional) */ + /* D detach, reply OK and then continue */ + case 'c': + case 's': + case 'D': + + /* try to read optional parameter, + pc unchanged if no parm */ + ptr = &remcomInBuffer[1]; + if (hexToInt(&ptr, &addr)) { + if (remote_debug) + printk("Changing EIP to 0x%x\n", addr); + + regs.eip = addr; + } + + newPC = regs.eip; + + /* clear the trace bit */ + regs.eflags &= 0xfffffeff; + + /* set the trace bit if we're stepping */ + if (remcomInBuffer[0] == 's') + regs.eflags |= 0x100; + + /* detach is a friendly version of continue. Note that + debugging is still enabled (e.g hit control C) + */ + if (remcomInBuffer[0] == 'D') { + strcpy(remcomOutBuffer, "OK"); + putpacket(remcomOutBuffer); + } + + if (remote_debug) { + printk("Resuming execution\n"); + print_regs(®s); + } + asm volatile ("movl %%db6, %0\n":"=r" (dr6) + :); + if (!(dr6 & 0x4000)) { + for (breakno = 0; breakno < 4; ++breakno) { + if (dr6 & (1 << breakno) && + (breakinfo[breakno].type == 0)) { + /* Set restore flag */ + regs.eflags |= 0x10000; + break; + } + } + } + + if (kgdboe) + netpoll_set_trap(0); + + correct_hw_break(); + asm volatile ("movl %0, %%db6\n"::"r" (0)); + goto exit_kgdb; + + /* kill the program */ + case 'k': /* do nothing */ + break; + + /* query */ + case 'q': + nothreads = 0; + switch (remcomInBuffer[1]) { + case 'f': + threadid = 1; + thread_list = 2; + thread_list_start = (usethread ? : current); + case 's': + if (!cmp_str(&remcomInBuffer[2], + "ThreadInfo", 10)) + break; + + remcomOutBuffer[nothreads++] = 'm'; + for (; threadid < PID_MAX + MAX_NO_CPUS; + threadid++) { + thread = getthread(threadid); + if (thread) { + nothreads += int_to_hex_v( + &remcomOutBuffer[ + nothreads], + threadid); + if (thread_min > threadid) + thread_min = threadid; + remcomOutBuffer[ + nothreads] = ','; + nothreads++; + if (nothreads > BUFMAX - 10) + break; + } + } + if (remcomOutBuffer[nothreads - 1] == 'm') { + remcomOutBuffer[nothreads - 1] = 'l'; + } else { + nothreads--; + } + remcomOutBuffer[nothreads] = 0; + break; + +#ifdef old_thread_list /* Old thread info request */ + case 'L': + /* List threads */ + thread_list = 2; + thread_list_start = (usethread ? : current); + unpack_byte(remcomInBuffer + 3, &maxthreads); + unpack_threadid(remcomInBuffer + 5, &thref); + do { + int buf_thread_limit = + (BUFMAX - 22) / BUF_THREAD_ID_SIZE; + if (maxthreads > buf_thread_limit) { + maxthreads = buf_thread_limit; + } + } while (0); + remcomOutBuffer[0] = 'q'; + remcomOutBuffer[1] = 'M'; + remcomOutBuffer[4] = '0'; + pack_threadid(remcomOutBuffer + 5, &thref); + + threadid = threadref_to_int(&thref); + for (nothreads = 0; + nothreads < maxthreads && + threadid < PID_MAX + MAX_NO_CPUS; + threadid++) { + thread = getthread(threadid); + if (thread) { + int_to_threadref(&thref, + threadid); + pack_threadid(remcomOutBuffer + + 21 + + nothreads * 16, + &thref); + nothreads++; + if (thread_min > threadid) + thread_min = threadid; + } + } + + if (threadid == PID_MAX + MAX_NO_CPUS) { + remcomOutBuffer[4] = '1'; + } + pack_hex_byte(remcomOutBuffer + 2, nothreads); + remcomOutBuffer[21 + nothreads * 16] = '\0'; + break; +#endif + case 'C': + /* Current thread id */ + remcomOutBuffer[0] = 'Q'; + remcomOutBuffer[1] = 'C'; + threadid = current->pid; + if (!threadid) { + /* + * idle thread + */ + for (threadid = PID_MAX; + threadid < PID_MAX + MAX_NO_CPUS; + threadid++) { + if (current == + idle_task(threadid - + PID_MAX)) + break; + } + } + int_to_threadref(&thref, threadid); + pack_threadid(remcomOutBuffer + 2, &thref); + remcomOutBuffer[18] = '\0'; + break; + + case 'E': + /* Print exception info */ + printexceptioninfo(exceptionVector, + err_code, remcomOutBuffer); + break; + case 'T':{ + char * nptr; + /* Thread extra info */ + if (!cmp_str(&remcomInBuffer[2], + "hreadExtraInfo,", 15)) { + break; + } + ptr = &remcomInBuffer[17]; + hexToInt(&ptr, &threadid); + thread = getthread(threadid); + nptr = &thread->comm[0]; + length = 0; + ptr = &remcomOutBuffer[0]; + do { + length++; + ptr = pack_hex_byte(ptr, *nptr++); + } while (*nptr && length < 16); + /* + * would like that 16 to be the size of + * task_struct.comm but don't know the + * syntax.. + */ + *ptr = 0; + } + } + break; + + /* task related */ + case 'H': + switch (remcomInBuffer[1]) { + case 'g': + ptr = &remcomInBuffer[2]; + hexToInt(&ptr, &threadid); + thread = getthread(threadid); + if (!thread) { + remcomOutBuffer[0] = 'E'; + remcomOutBuffer[1] = '\0'; + break; + } + /* + * Just in case I forget what this is all about, + * the "thread info" command to gdb causes it + * to ask for a thread list. It then switches + * to each thread and asks for the registers. + * For this (and only this) usage, we want to + * fudge the registers of tasks not on the run + * list (i.e. waiting) to show the routine that + * called schedule. Also, gdb, is a minimalist + * in that if the current thread is the last + * it will not re-read the info when done. + * This means that in this case we must show + * the real registers. So here is how we do it: + * Each entry we keep track of the min + * thread in the list (the last that gdb will) + * get info for. We also keep track of the + * starting thread. + * "thread_list" is cleared when switching back + * to the min thread if it is was current, or + * if it was not current, thread_list is set + * to 1. When the switch to current comes, + * if thread_list is 1, clear it, else do + * nothing. + */ + usethread = thread; + if ((thread_list == 1) && + (thread == thread_list_start)) { + thread_list = 0; + } + if (thread_list && (threadid == thread_min)) { + if (thread == thread_list_start) { + thread_list = 0; + } else { + thread_list = 1; + } + } + /* follow through */ + case 'c': + remcomOutBuffer[0] = 'O'; + remcomOutBuffer[1] = 'K'; + remcomOutBuffer[2] = '\0'; + break; + } + break; + + /* Query thread status */ + case 'T': + ptr = &remcomInBuffer[1]; + hexToInt(&ptr, &threadid); + thread = getthread(threadid); + if (thread) { + remcomOutBuffer[0] = 'O'; + remcomOutBuffer[1] = 'K'; + remcomOutBuffer[2] = '\0'; + if (thread_min > threadid) + thread_min = threadid; + } else { + remcomOutBuffer[0] = 'E'; + remcomOutBuffer[1] = '\0'; + } + break; + + case 'Y': /* set up a hardware breakpoint */ + ptr = &remcomInBuffer[1]; + hexToInt(&ptr, &breakno); + ptr++; + hexToInt(&ptr, &breaktype); + ptr++; + hexToInt(&ptr, &length); + ptr++; + hexToInt(&ptr, &addr); + if (set_hw_break(breakno & 0x3, + breaktype & 0x3, + length & 0x3, addr) == 0) { + strcpy(remcomOutBuffer, "OK"); + } else { + strcpy(remcomOutBuffer, "ERROR"); + } + break; + + /* Remove hardware breakpoint */ + case 'y': + ptr = &remcomInBuffer[1]; + hexToInt(&ptr, &breakno); + if (remove_hw_break(breakno & 0x3) == 0) { + strcpy(remcomOutBuffer, "OK"); + } else { + strcpy(remcomOutBuffer, "ERROR"); + } + break; + + case 'r': /* reboot */ + strcpy(remcomOutBuffer, "OK"); + putpacket(remcomOutBuffer); + /*to_gdb("Rebooting\n"); */ + /* triplefault no return from here */ + { + static long no_idt[2]; + __asm__ __volatile__("lidt %0"::"m"(no_idt[0])); + BREAKPOINT; + } + + } /* switch */ + + /* reply to the request */ + putpacket(remcomOutBuffer); + } /* while(1==1) */ + /* + * reached by goto only. + */ + exit_kgdb: + /* + * Here is where we set up to trap a gdb function call. NEW_esp + * will be changed if we are trying to do this. We handle both + * adding and subtracting, thus allowing gdb to put grung on + * the stack which it removes later. + */ + if (NEW_esp != OLD_esp) { + int *ptr = END_OF_LOOKASIDE; + if (NEW_esp < OLD_esp) + ptr -= (OLD_esp - NEW_esp) / sizeof (int); + *--ptr = linux_regs->eflags; + *--ptr = linux_regs->xcs; + *--ptr = linux_regs->eip; + *--ptr = linux_regs->ecx; + *--ptr = linux_regs->ebx; + *--ptr = linux_regs->eax; + linux_regs->ecx = NEW_esp - (sizeof (int) * 6); + linux_regs->ebx = (unsigned int) END_OF_LOOKASIDE; + if (NEW_esp < OLD_esp) { + linux_regs->eip = (unsigned int) fn_call_stub; + } else { + linux_regs->eip = (unsigned int) fn_rtn_stub; + linux_regs->eax = NEW_esp; + } + linux_regs->eflags &= ~(IF_BIT | TF_BIT); + } +#ifdef CONFIG_SMP + /* + * Release gdb wait locks + * Sanity check time. Must have at least one cpu to run. Also single + * step must not be done if the current cpu is on hold. + */ + if (spinlock_count == 1) { + int ss_hold = (regs.eflags & 0x100) && kgdb_info.hold_on_sstep; + int cpu_avail = 0; + int i; + + for (i = 0; i < MAX_NO_CPUS; i++) { + if (!cpu_online(i)) + break; + if (!hold_cpu(i)) { + cpu_avail = 1; + } + } + /* + * Early in the bring up there will be NO cpus on line... + */ + if (!cpu_avail && !cpus_empty(cpu_online_map)) { + to_gdb("No cpus unblocked, see 'kgdb_info.hold_cpu'\n"); + goto once_again; + } + if (hold_cpu(smp_processor_id()) && (regs.eflags & 0x100)) { + to_gdb + ("Current cpu must be unblocked to single step\n"); + goto once_again; + } + if (!(ss_hold)) { + int i; + for (i = 0; i < MAX_NO_CPUS; i++) { + if (!hold_cpu(i)) { + spin_unlock(&waitlocks[i]); + } + } + } else { + spin_unlock(&waitlocks[smp_processor_id()]); + } + /* Release kgdb spinlock */ + KGDB_SPIN_UNLOCK(&kgdb_spinlock); + /* + * If this cpu is on hold, this is where we + * do it. Note, the NMI will pull us out of here, + * but will return as the above lock is not held. + * We will stay here till another cpu releases the lock for us. + */ + spin_unlock_wait(waitlocks + smp_processor_id()); + kgdb_local_irq_restore(flags); + return (0); + } +#if 0 +exit_just_unlock: +#endif +#endif + /* Release kgdb spinlock */ + KGDB_SPIN_UNLOCK(&kgdb_spinlock); + kgdb_local_irq_restore(flags); + return (0); +} + +/* this function is used to set up exception handlers for tracing and + * breakpoints. + * This function is not needed as the above line does all that is needed. + * We leave it for backward compatitability... + */ +void +set_debug_traps(void) +{ + /* + * linux_debug_hook is defined in traps.c. We store a pointer + * to our own exception handler into it. + + * But really folks, every hear of labeled common, an old Fortran + * concept. Lots of folks can reference it and it is define if + * anyone does. Only one can initialize it at link time. We do + * this with the hook. See the statement above. No need for any + * executable code and it is ready as soon as the kernel is + * loaded. Very desirable in kernel debugging. + + linux_debug_hook = handle_exception ; + */ + + /* In case GDB is started before us, ack any packets (presumably + "$?#xx") sitting there. + putDebugChar ('+'); + + initialized = 1; + */ +} + +/* This function will generate a breakpoint exception. It is used at the + beginning of a program to sync up with a debugger and can be used + otherwise as a quick means to stop program execution and "break" into + the debugger. */ +/* But really, just use the BREAKPOINT macro. We will handle the int stuff + */ + +#ifdef later +/* + * possibly we should not go thru the traps.c code at all? Someday. + */ +void +do_kgdb_int3(struct pt_regs *regs, long error_code) +{ + kgdb_handle_exception(3, 5, error_code, regs); + return; +} +#endif +#undef regs +#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS +asmlinkage void +bad_sys_call_exit(int stuff) +{ + struct pt_regs *regs = (struct pt_regs *) &stuff; + printk("Sys call %d return with %x preempt_count\n", + (int) regs->orig_eax, preempt_count()); +} +#endif +#ifdef CONFIG_STACK_OVERFLOW_TEST +#include +asmlinkage void +stack_overflow(void) +{ +#ifdef BREAKPOINT + BREAKPOINT; +#else + printk("Kernel stack overflow, looping forever\n"); +#endif + while (1) { + } +} +#endif + +#if defined(CONFIG_SMP) || defined(CONFIG_KGDB_CONSOLE) +char gdbconbuf[BUFMAX]; + +static void +kgdb_gdb_message(const char *s, unsigned count) +{ + int i; + int wcount; + char *bufptr; + /* + * This takes care of NMI while spining out chars to gdb + */ + IF_SMP(in_kgdb_console = 1); + gdbconbuf[0] = 'O'; + bufptr = gdbconbuf + 1; + while (count > 0) { + if ((count << 1) > (BUFMAX - 2)) { + wcount = (BUFMAX - 2) >> 1; + } else { + wcount = count; + } + count -= wcount; + for (i = 0; i < wcount; i++) { + bufptr = pack_hex_byte(bufptr, s[i]); + } + *bufptr = '\0'; + s += wcount; + + putpacket(gdbconbuf); + + } + IF_SMP(in_kgdb_console = 0); +} +#endif +#ifdef CONFIG_SMP +static void +to_gdb(const char *s) +{ + int count = 0; + while (s[count] && (count++ < BUFMAX)) ; + kgdb_gdb_message(s, count); +} +#endif +#ifdef CONFIG_KGDB_CONSOLE +#include +#include +#include +#include +#include + +void +kgdb_console_write(struct console *co, const char *s, unsigned count) +{ + + if (gdb_i386vector == -1) { + /* + * We have not yet talked to gdb. What to do... + * lets break, on continue we can do the write. + * But first tell him whats up. Uh, well no can do, + * as this IS the console. Oh well... + * We do need to wait or the messages will be lost. + * Other option would be to tell the above code to + * ignore this breakpoint and do an auto return, + * but that might confuse gdb. Also this happens + * early enough in boot up that we don't have the traps + * set up yet, so... + */ + breakpoint(); + } + kgdb_gdb_message(s, count); +} + +/* + * ------------------------------------------------------------ + * Serial KGDB driver + * ------------------------------------------------------------ + */ + +static struct console kgdbcons = { + name:"kgdb", + write:kgdb_console_write, +#ifdef CONFIG_KGDB_USER_CONSOLE + device:kgdb_console_device, +#endif + flags:CON_PRINTBUFFER | CON_ENABLED, + index:-1, +}; + +/* + * The trick here is that this file gets linked before printk.o + * That means we get to peer at the console info in the command + * line before it does. If we are up, we register, otherwise, + * do nothing. By returning 0, we allow printk to look also. + */ +static int kgdb_console_enabled; + +int __init +kgdb_console_init(char *str) +{ + if ((strncmp(str, "kgdb", 4) == 0) || (strncmp(str, "gdb", 3) == 0)) { + register_console(&kgdbcons); + kgdb_console_enabled = 1; + } + return 0; /* let others look at the string */ +} + +__setup("console=", kgdb_console_init); + +#ifdef CONFIG_KGDB_USER_CONSOLE +static kdev_t kgdb_console_device(struct console *c); +/* This stuff sort of works, but it knocks out telnet devices + * we are leaving it here in case we (or you) find time to figure it out + * better.. + */ + +/* + * We need a real char device as well for when the console is opened for user + * space activities. + */ + +static int +kgdb_consdev_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static ssize_t +kgdb_consdev_write(struct file *file, const char *buf, + size_t count, loff_t * ppos) +{ + int size, ret = 0; + static char kbuf[128]; + static DECLARE_MUTEX(sem); + + /* We are not reentrant... */ + if (down_interruptible(&sem)) + return -ERESTARTSYS; + + while (count > 0) { + /* need to copy the data from user space */ + size = count; + if (size > sizeof (kbuf)) + size = sizeof (kbuf); + if (copy_from_user(kbuf, buf, size)) { + ret = -EFAULT; + break;; + } + kgdb_console_write(&kgdbcons, kbuf, size); + count -= size; + ret += size; + buf += size; + } + + up(&sem); + + return ret; +} + +struct file_operations kgdb_consdev_fops = { + open:kgdb_consdev_open, + write:kgdb_consdev_write +}; +static kdev_t +kgdb_console_device(struct console *c) +{ + return MKDEV(TTYAUX_MAJOR, 1); +} + +/* + * This routine gets called from the serial stub in the i386/lib + * This is so it is done late in bring up (just before the console open). + */ +void +kgdb_console_finit(void) +{ + if (kgdb_console_enabled) { + char *cptr = cdevname(MKDEV(TTYAUX_MAJOR, 1)); + char *cp = cptr; + while (*cptr && *cptr != '(') + cptr++; + *cptr = 0; + unregister_chrdev(TTYAUX_MAJOR, cp); + register_chrdev(TTYAUX_MAJOR, "kgdb", &kgdb_consdev_fops); + } +} +#endif +#endif +#ifdef CONFIG_KGDB_TS +#include /* time stamp code */ +#include /* in_interrupt */ +#ifdef CONFIG_KGDB_TS_64 +#define DATA_POINTS 64 +#endif +#ifdef CONFIG_KGDB_TS_128 +#define DATA_POINTS 128 +#endif +#ifdef CONFIG_KGDB_TS_256 +#define DATA_POINTS 256 +#endif +#ifdef CONFIG_KGDB_TS_512 +#define DATA_POINTS 512 +#endif +#ifdef CONFIG_KGDB_TS_1024 +#define DATA_POINTS 1024 +#endif +#ifndef DATA_POINTS +#define DATA_POINTS 128 /* must be a power of two */ +#endif +#define INDEX_MASK (DATA_POINTS - 1) +#if (INDEX_MASK & DATA_POINTS) +#error "CONFIG_KGDB_TS_COUNT must be a power of 2" +#endif +struct kgdb_and_then_struct { +#ifdef CONFIG_SMP + int on_cpu; +#endif + struct task_struct *task; + long long at_time; + int from_ln; + char *in_src; + void *from; + int *with_shpf; + int data0; + int data1; +}; +struct kgdb_and_then_struct2 { +#ifdef CONFIG_SMP + int on_cpu; +#endif + struct task_struct *task; + long long at_time; + int from_ln; + char *in_src; + void *from; + int *with_shpf; + struct task_struct *t1; + struct task_struct *t2; +}; +struct kgdb_and_then_struct kgdb_data[DATA_POINTS]; + +struct kgdb_and_then_struct *kgdb_and_then = &kgdb_data[0]; +int kgdb_and_then_count; + +void +kgdb_tstamp(int line, char *source, int data0, int data1) +{ + static spinlock_t ts_spin = SPIN_LOCK_UNLOCKED; + int flags; + kgdb_local_irq_save(flags); + spin_lock(&ts_spin); + rdtscll(kgdb_and_then->at_time); +#ifdef CONFIG_SMP + kgdb_and_then->on_cpu = smp_processor_id(); +#endif + kgdb_and_then->task = current; + kgdb_and_then->from_ln = line; + kgdb_and_then->in_src = source; + kgdb_and_then->from = __builtin_return_address(0); + kgdb_and_then->with_shpf = (int *) (((flags & IF_BIT) >> 9) | + (preempt_count() << 8)); + kgdb_and_then->data0 = data0; + kgdb_and_then->data1 = data1; + kgdb_and_then = &kgdb_data[++kgdb_and_then_count & INDEX_MASK]; + spin_unlock(&ts_spin); + kgdb_local_irq_restore(flags); +#ifdef CONFIG_PREEMPT + +#endif + return; +} +#endif +typedef int gdb_debug_hook(int exceptionVector, + int signo, int err_code, struct pt_regs *linux_regs); +gdb_debug_hook *linux_debug_hook = &kgdb_handle_exception; /* histerical reasons... */ + +static int kgdb_need_breakpoint[NR_CPUS]; + +void kgdb_schedule_breakpoint(void) +{ + kgdb_need_breakpoint[smp_processor_id()] = 1; +} + +void kgdb_process_breakpoint(void) +{ + /* + * Handle a breakpoint queued from inside network driver code + * to avoid reentrancy issues + */ + if (kgdb_need_breakpoint[smp_processor_id()]) { + kgdb_need_breakpoint[smp_processor_id()] = 0; + BREAKPOINT; + } +} + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/ldt.c 830-ivtv/arch/i386/kernel/ldt.c --- 000-virgin/arch/i386/kernel/ldt.c Tue Sep 2 09:55:42 2003 +++ 830-ivtv/arch/i386/kernel/ldt.c Thu Jan 8 09:30:58 2004 @@ -2,7 +2,7 @@ * linux/kernel/ldt.c * * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds - * Copyright (C) 1999 Ingo Molnar + * Copyright (C) 1999, 2003 Ingo Molnar */ #include @@ -18,6 +18,8 @@ #include #include #include +#include +#include #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */ static void flush_ldt(void *null) @@ -29,34 +31,31 @@ static void flush_ldt(void *null) static int alloc_ldt(mm_context_t *pc, int mincount, int reload) { - void *oldldt; - void *newldt; - int oldsize; + int oldsize, newsize, i; if (mincount <= pc->size) return 0; + /* + * LDT got larger - reallocate if necessary. + */ oldsize = pc->size; mincount = (mincount+511)&(~511); - if (mincount*LDT_ENTRY_SIZE > PAGE_SIZE) - newldt = vmalloc(mincount*LDT_ENTRY_SIZE); - else - newldt = kmalloc(mincount*LDT_ENTRY_SIZE, GFP_KERNEL); - - if (!newldt) - return -ENOMEM; - - if (oldsize) - memcpy(newldt, pc->ldt, oldsize*LDT_ENTRY_SIZE); - oldldt = pc->ldt; - memset(newldt+oldsize*LDT_ENTRY_SIZE, 0, (mincount-oldsize)*LDT_ENTRY_SIZE); - pc->ldt = newldt; - wmb(); + newsize = mincount*LDT_ENTRY_SIZE; + for (i = 0; i < newsize; i += PAGE_SIZE) { + int nr = i/PAGE_SIZE; + BUG_ON(i >= 64*1024); + if (!pc->ldt_pages[nr]) { + pc->ldt_pages[nr] = alloc_page(GFP_HIGHUSER); + if (!pc->ldt_pages[nr]) + return -ENOMEM; + clear_highpage(pc->ldt_pages[nr]); + } + } pc->size = mincount; - wmb(); - if (reload) { #ifdef CONFIG_SMP cpumask_t mask; + preempt_disable(); load_LDT(pc); mask = cpumask_of_cpu(smp_processor_id()); @@ -67,21 +66,20 @@ static int alloc_ldt(mm_context_t *pc, i load_LDT(pc); #endif } - if (oldsize) { - if (oldsize*LDT_ENTRY_SIZE > PAGE_SIZE) - vfree(oldldt); - else - kfree(oldldt); - } return 0; } static inline int copy_ldt(mm_context_t *new, mm_context_t *old) { - int err = alloc_ldt(new, old->size, 0); - if (err < 0) + int i, err, size = old->size, nr_pages = (size*LDT_ENTRY_SIZE + PAGE_SIZE-1)/PAGE_SIZE; + + err = alloc_ldt(new, size, 0); + if (err < 0) { + new->size = 0; return err; - memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE); + } + for (i = 0; i < nr_pages; i++) + copy_user_highpage(new->ldt_pages[i], old->ldt_pages[i], 0); return 0; } @@ -96,6 +94,7 @@ int init_new_context(struct task_struct init_MUTEX(&mm->context.sem); mm->context.size = 0; + memset(mm->context.ldt_pages, 0, sizeof(struct page *) * MAX_LDT_PAGES); old_mm = current->mm; if (old_mm && old_mm->context.size > 0) { down(&old_mm->context.sem); @@ -107,23 +106,21 @@ int init_new_context(struct task_struct /* * No need to lock the MM as we are the last user + * Do not touch the ldt register, we are already + * in the next thread. */ void destroy_context(struct mm_struct *mm) { - if (mm->context.size) { - if (mm == current->active_mm) - clear_LDT(); - if (mm->context.size*LDT_ENTRY_SIZE > PAGE_SIZE) - vfree(mm->context.ldt); - else - kfree(mm->context.ldt); - mm->context.size = 0; - } + int i, nr_pages = (mm->context.size*LDT_ENTRY_SIZE + PAGE_SIZE-1) / PAGE_SIZE; + + for (i = 0; i < nr_pages; i++) + __free_page(mm->context.ldt_pages[i]); + mm->context.size = 0; } static int read_ldt(void __user * ptr, unsigned long bytecount) { - int err; + int err, i; unsigned long size; struct mm_struct * mm = current->mm; @@ -138,8 +135,25 @@ static int read_ldt(void __user * ptr, u size = bytecount; err = 0; - if (copy_to_user(ptr, mm->context.ldt, size)) - err = -EFAULT; + /* + * This is necessary just in case we got here straight from a + * context-switch where the ptes were set but no tlb flush + * was done yet. We rather avoid doing a TLB flush in the + * context-switch path and do it here instead. + */ + __flush_tlb_global(); + + for (i = 0; i < size; i += PAGE_SIZE) { + int nr = i / PAGE_SIZE, bytes; + char *kaddr = kmap(mm->context.ldt_pages[nr]); + + bytes = size - i; + if (bytes > PAGE_SIZE) + bytes = PAGE_SIZE; + if (copy_to_user(ptr + i, kaddr, size - i)) + err = -EFAULT; + kunmap(mm->context.ldt_pages[nr]); + } up(&mm->context.sem); if (err < 0) return err; @@ -158,7 +172,7 @@ static int read_default_ldt(void __user err = 0; address = &default_ldt[0]; - size = 5*sizeof(struct desc_struct); + size = 5*LDT_ENTRY_SIZE; if (size > bytecount) size = bytecount; @@ -200,7 +214,15 @@ static int write_ldt(void __user * ptr, goto out_unlock; } - lp = (__u32 *) ((ldt_info.entry_number << 3) + (char *) mm->context.ldt); + /* + * No rescheduling allowed from this point to the install. + * + * We do a TLB flush for the same reason as in the read_ldt() path. + */ + preempt_disable(); + __flush_tlb_global(); + lp = (__u32 *) ((ldt_info.entry_number << 3) + + (char *) __kmap_atomic_vaddr(KM_LDT_PAGE0)); /* Allow LDTs to be cleared by the user. */ if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { @@ -221,6 +243,7 @@ install: *lp = entry_1; *(lp+1) = entry_2; error = 0; + preempt_enable(); out_unlock: up(&mm->context.sem); @@ -247,4 +270,27 @@ asmlinkage int sys_modify_ldt(int func, break; } return ret; +} + +/* + * load one particular LDT into the current CPU + */ +void load_LDT_nolock(mm_context_t *pc, int cpu) +{ + struct page **pages = pc->ldt_pages; + int count = pc->size; + int nr_pages, i; + + if (likely(!count)) { + pages = &default_ldt_page; + count = 5; + } + nr_pages = (count*LDT_ENTRY_SIZE + PAGE_SIZE-1) / PAGE_SIZE; + + for (i = 0; i < nr_pages; i++) { + __kunmap_atomic_type(KM_LDT_PAGE0 - i); + __kmap_atomic(pages[i], KM_LDT_PAGE0 - i); + } + set_ldt_desc(cpu, (void *)__kmap_atomic_vaddr(KM_LDT_PAGE0), count); + load_LDT_desc(); } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/machine_kexec.c 830-ivtv/arch/i386/kernel/machine_kexec.c --- 000-virgin/arch/i386/kernel/machine_kexec.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/arch/i386/kernel/machine_kexec.c Thu Jan 8 10:26:46 2004 @@ -0,0 +1,122 @@ +/* + * machine_kexec.c - handle transition of Linux booting another kernel + * Copyright (C) 2002-2003 Eric Biederman + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static void set_idt(void *newidt, __u16 limit) +{ + unsigned char curidt[6]; + + /* ia32 supports unaliged loads & stores */ + (*(__u16 *)(curidt)) = limit; + (*(__u32 *)(curidt +2)) = (unsigned long)(newidt); + + __asm__ __volatile__ ( + "lidt %0\n" + : "=m" (curidt) + ); +}; + + +static void set_gdt(void *newgdt, __u16 limit) +{ + unsigned char curgdt[6]; + + /* ia32 supports unaligned loads & stores */ + (*(__u16 *)(curgdt)) = limit; + (*(__u32 *)(curgdt +2)) = (unsigned long)(newgdt); + + __asm__ __volatile__ ( + "lgdt %0\n" + : "=m" (curgdt) + ); +}; + +static void load_segments(void) +{ +#define __STR(X) #X +#define STR(X) __STR(X) + + __asm__ __volatile__ ( + "\tljmp $"STR(__KERNEL_CS)",$1f\n" + "\t1:\n" + "\tmovl $"STR(__KERNEL_DS)",%eax\n" + "\tmovl %eax,%ds\n" + "\tmovl %eax,%es\n" + "\tmovl %eax,%fs\n" + "\tmovl %eax,%gs\n" + "\tmovl %eax,%ss\n" + ); +#undef STR +#undef __STR +} + +typedef void (*relocate_new_kernel_t)( + unsigned long indirection_page, unsigned long reboot_code_buffer, + unsigned long start_address, unsigned int has_pae); + +const extern unsigned char relocate_new_kernel[]; +extern void relocate_new_kernel_end(void); +const extern unsigned int relocate_new_kernel_size; +extern void use_mm(struct mm_struct *mm); + +/* + * Do not allocate memory (or fail in any way) in machine_kexec(). + * We are past the point of no return, committed to rebooting now. + */ +void machine_kexec(struct kimage *image) +{ + unsigned long indirection_page; + unsigned long reboot_code_buffer; + relocate_new_kernel_t rnk; + + /* switch to an mm where the reboot_code_buffer is identity mapped */ + use_mm(&init_mm); + stop_apics(); + + /* Interrupts aren't acceptable while we reboot */ + local_irq_disable(); + reboot_code_buffer = page_to_pfn(image->reboot_code_pages) << PAGE_SHIFT; + indirection_page = image->head & PAGE_MASK; + + /* copy it out */ + memcpy((void *)reboot_code_buffer, relocate_new_kernel, relocate_new_kernel_size); + + /* The segment registers are funny things, they are + * automatically loaded from a table, in memory wherever you + * set them to a specific selector, but this table is never + * accessed again you set the segment to a different selector. + * + * The more common model is are caches where the behide + * the scenes work is done, but is also dropped at arbitrary + * times. + * + * I take advantage of this here by force loading the + * segments, before I zap the gdt with an invalid value. + */ + load_segments(); + /* The gdt & idt are now invalid. + * If you want to load them you must set up your own idt & gdt. + */ + set_gdt(phys_to_virt(0),0); + set_idt(phys_to_virt(0),0); + + /* now call it */ + rnk = (relocate_new_kernel_t) reboot_code_buffer; + (*rnk)(indirection_page, reboot_code_buffer, image->start, cpu_has_pae); +} diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/mpparse.c 830-ivtv/arch/i386/kernel/mpparse.c --- 000-virgin/arch/i386/kernel/mpparse.c Thu Jan 8 08:35:20 2004 +++ 830-ivtv/arch/i386/kernel/mpparse.c Thu Jan 8 09:30:58 2004 @@ -668,7 +668,7 @@ void __init get_smp_config (void) * Read the physical hardware table. Anything here will * override the defaults. */ - if (!smp_read_mpc((void *)mpf->mpf_physptr)) { + if (!smp_read_mpc((void *)phys_to_virt(mpf->mpf_physptr))) { smp_found_config = 0; printk(KERN_ERR "BIOS bug, MP table errors detected!...\n"); printk(KERN_ERR "... disabling SMP support. (tell your hw vendor)\n"); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/nmi.c 830-ivtv/arch/i386/kernel/nmi.c --- 000-virgin/arch/i386/kernel/nmi.c Wed Aug 13 20:24:18 2003 +++ 830-ivtv/arch/i386/kernel/nmi.c Thu Jan 8 09:30:15 2004 @@ -31,7 +31,16 @@ #include #include +#ifdef CONFIG_KGDB +#include +#ifdef CONFIG_SMP +unsigned int nmi_watchdog = NMI_IO_APIC; +#else +unsigned int nmi_watchdog = NMI_LOCAL_APIC; +#endif +#else unsigned int nmi_watchdog = NMI_NONE; +#endif static unsigned int nmi_hz = HZ; unsigned int nmi_perfctr_msr; /* the MSR to reset in NMI handler */ extern void show_registers(struct pt_regs *regs); @@ -408,6 +417,9 @@ void touch_nmi_watchdog (void) for (i = 0; i < NR_CPUS; i++) alert_counter[i] = 0; } +#ifdef CONFIG_KGDB +int tune_watchdog = 5*HZ; +#endif void nmi_watchdog_tick (struct pt_regs * regs) { @@ -421,12 +433,24 @@ void nmi_watchdog_tick (struct pt_regs * sum = irq_stat[cpu].apic_timer_irqs; +#ifdef CONFIG_KGDB + if (! in_kgdb(regs) && last_irq_sums[cpu] == sum ) { + +#else if (last_irq_sums[cpu] == sum) { +#endif /* * Ayiee, looks like this CPU is stuck ... * wait a few IRQs (5 seconds) before doing the oops ... */ alert_counter[cpu]++; +#ifdef CONFIG_KGDB + if (alert_counter[cpu] == tune_watchdog) { + kgdb_handle_exception(2, SIGPWR, 0, regs); + last_irq_sums[cpu] = sum; + alert_counter[cpu] = 0; + } +#endif if (alert_counter[cpu] == 5*nmi_hz) { spin_lock(&nmi_print_lock); /* diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/numaq.c 830-ivtv/arch/i386/kernel/numaq.c --- 000-virgin/arch/i386/kernel/numaq.c Mon Nov 17 18:28:33 2003 +++ 830-ivtv/arch/i386/kernel/numaq.c Thu Jan 8 10:21:30 2004 @@ -42,6 +42,10 @@ extern long node_start_pfn[], node_end_p * function also increments numnodes with the number of nodes (quads) * present. */ +extern unsigned long max_pages_per_node; +extern int limit_mem_per_node; + +#define node_size_pages(n) (node_end_pfn[n] - node_start_pfn[n]) static void __init smp_dump_qct(void) { int node; @@ -60,6 +64,8 @@ static void __init smp_dump_qct(void) eq->hi_shrd_mem_start - eq->priv_mem_size); node_end_pfn[node] = MB_TO_PAGES( eq->hi_shrd_mem_start + eq->hi_shrd_mem_size); + if (node_size_pages(node) > max_pages_per_node) + node_end_pfn[node] = node_start_pfn[node] + max_pages_per_node; } } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/process.c 830-ivtv/arch/i386/kernel/process.c --- 000-virgin/arch/i386/kernel/process.c Thu Jan 8 08:35:21 2004 +++ 830-ivtv/arch/i386/kernel/process.c Thu Jan 8 09:30:58 2004 @@ -47,6 +47,7 @@ #include #include #include +#include #ifdef CONFIG_MATH_EMULATION #include #endif @@ -302,6 +303,9 @@ void flush_thread(void) struct task_struct *tsk = current; memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8); +#ifdef CONFIG_X86_HIGH_ENTRY + clear_thread_flag(TIF_DB7); +#endif memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array)); /* * Forget coprocessor state.. @@ -315,9 +319,8 @@ void release_thread(struct task_struct * if (dead_task->mm) { // temporary debugging check if (dead_task->mm->context.size) { - printk("WARNING: dead process %8s still has LDT? <%p/%d>\n", + printk("WARNING: dead process %8s still has LDT? <%d>\n", dead_task->comm, - dead_task->mm->context.ldt, dead_task->mm->context.size); BUG(); } @@ -352,7 +355,17 @@ int copy_thread(int nr, unsigned long cl p->thread.esp = (unsigned long) childregs; p->thread.esp0 = (unsigned long) (childregs+1); + /* + * get the two stack pages, for the virtual stack. + * + * IMPORTANT: this code relies on the fact that the task + * structure is an 8K aligned piece of physical memory. + */ + p->thread.stack_page0 = virt_to_page((unsigned long)p->thread_info); + p->thread.stack_page1 = virt_to_page((unsigned long)p->thread_info + PAGE_SIZE); + p->thread.eip = (unsigned long) ret_from_fork; + p->thread_info->real_stack = p->thread_info; savesegment(fs,p->thread.fs); savesegment(gs,p->thread.gs); @@ -504,10 +517,41 @@ struct task_struct * __switch_to(struct __unlazy_fpu(prev_p); +#ifdef CONFIG_X86_HIGH_ENTRY + /* + * Set the ptes of the virtual stack. (NOTE: a one-page TLB flush is + * needed because otherwise NMIs could interrupt the + * user-return code with a virtual stack and stale TLBs.) + */ + __kunmap_atomic_type(KM_VSTACK0); + __kunmap_atomic_type(KM_VSTACK1); + __kmap_atomic(next->stack_page0, KM_VSTACK0); + __kmap_atomic(next->stack_page1, KM_VSTACK1); + + /* + * NOTE: here we rely on the task being the stack as well + */ + next_p->thread_info->virtual_stack = + (void *)__kmap_atomic_vaddr(KM_VSTACK0); + +#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP) + /* + * If next was preempted on entry from userspace to kernel, + * and now it's on a different cpu, we need to adjust %esp. + * This assumes that entry.S does not copy %esp while on the + * virtual stack (with interrupts enabled): which is so, + * except within __SWITCH_KERNELSPACE itself. + */ + if (unlikely(next->esp >= TASK_SIZE)) { + next->esp &= THREAD_SIZE - 1; + next->esp |= (unsigned long) next_p->thread_info->virtual_stack; + } +#endif +#endif /* * Reload esp0, LDT and the page table pointer: */ - load_esp0(tss, next); + load_virtual_esp0(tss, next_p); /* * Load the per-thread Thread-Local Storage descriptor. diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/reboot.c 830-ivtv/arch/i386/kernel/reboot.c --- 000-virgin/arch/i386/kernel/reboot.c Thu Jan 8 08:35:21 2004 +++ 830-ivtv/arch/i386/kernel/reboot.c Thu Jan 8 10:26:46 2004 @@ -22,8 +22,7 @@ static int reboot_mode; int reboot_thru_bios; #ifdef CONFIG_SMP -int reboot_smp = 0; -static int reboot_cpu = -1; +int reboot_cpu = -1; /* specifies the internal linux cpu id, not the apicid */ /* shamelessly grabbed from lib/vsprintf.c for readability */ #define is_digit(c) ((c) >= '0' && (c) <= '9') #endif @@ -45,7 +44,6 @@ static int __init reboot_setup(char *str break; #ifdef CONFIG_SMP case 's': /* "smp" reboot by executing reset on BSP or other CPU*/ - reboot_smp = 1; if (is_digit(*(str+1))) { reboot_cpu = (int) (*(str+1) - '0'); if (is_digit(*(str+2))) @@ -155,12 +153,11 @@ void machine_real_restart(unsigned char CMOS_WRITE(0x00, 0x8f); spin_unlock_irqrestore(&rtc_lock, flags); - /* Remap the kernel at virtual address zero, as well as offset zero - from the kernel segment. This assumes the kernel segment starts at - virtual address PAGE_OFFSET. */ - - memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, - sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS); + /* + * Remap the first 16 MB of RAM (which includes the kernel image) + * at virtual address zero: + */ + setup_identity_mappings(swapper_pg_dir, 0, 16*1024*1024); /* * Use `swapper_pg_dir' as our page directory. @@ -219,50 +216,7 @@ void machine_real_restart(unsigned char void machine_restart(char * __unused) { -#ifdef CONFIG_SMP - int cpuid; - - cpuid = GET_APIC_ID(apic_read(APIC_ID)); - - if (reboot_smp) { - - /* check to see if reboot_cpu is valid - if its not, default to the BSP */ - if ((reboot_cpu == -1) || - (reboot_cpu > (NR_CPUS -1)) || - !physid_isset(cpuid, phys_cpu_present_map)) - reboot_cpu = boot_cpu_physical_apicid; - - reboot_smp = 0; /* use this as a flag to only go through this once*/ - /* re-run this function on the other CPUs - it will fall though this section since we have - cleared reboot_smp, and do the reboot if it is the - correct CPU, otherwise it halts. */ - if (reboot_cpu != cpuid) - smp_call_function((void *)machine_restart , NULL, 1, 0); - } - - /* if reboot_cpu is still -1, then we want a tradional reboot, - and if we are not running on the reboot_cpu,, halt */ - if ((reboot_cpu != -1) && (cpuid != reboot_cpu)) { - for (;;) - __asm__ __volatile__ ("hlt"); - } - /* - * Stop all CPUs and turn off local APICs and the IO-APIC, so - * other OSs see a clean IRQ state. - */ - smp_send_stop(); -#elif defined(CONFIG_X86_LOCAL_APIC) - if (cpu_has_apic) { - local_irq_disable(); - disable_local_APIC(); - local_irq_enable(); - } -#endif -#ifdef CONFIG_X86_IO_APIC - disable_IO_APIC(); -#endif + stop_apics(); if (!reboot_thru_bios) { if (efi_enabled) { @@ -289,12 +243,14 @@ EXPORT_SYMBOL(machine_restart); void machine_halt(void) { + stop_apics(); } EXPORT_SYMBOL(machine_halt); void machine_power_off(void) { + stop_apics(); if (efi_enabled) efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, 0); if (pm_power_off) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/relocate_kernel.S 830-ivtv/arch/i386/kernel/relocate_kernel.S --- 000-virgin/arch/i386/kernel/relocate_kernel.S Wed Dec 31 16:00:00 1969 +++ 830-ivtv/arch/i386/kernel/relocate_kernel.S Thu Jan 8 10:26:46 2004 @@ -0,0 +1,118 @@ +/* + * relocate_kernel.S - put the kernel image in place to boot + * Copyright (C) 2002-2003 Eric Biederman + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include + + /* + * Must be relocatable PIC code callable as a C function, that once + * it starts can not use the previous processes stack. + */ + .globl relocate_new_kernel +relocate_new_kernel: + /* read the arguments and say goodbye to the stack */ + movl 4(%esp), %ebx /* indirection_page */ + movl 8(%esp), %ebp /* reboot_code_buffer */ + movl 12(%esp), %edx /* start address */ + movl 16(%esp), %ecx /* cpu_has_pae */ + + /* zero out flags, and disable interrupts */ + pushl $0 + popfl + + /* set a new stack at the bottom of our page... */ + lea 4096(%ebp), %esp + + /* store the parameters back on the stack */ + pushl %edx /* store the start address */ + + /* Set cr0 to a known state: + * 31 0 == Paging disabled + * 18 0 == Alignment check disabled + * 16 0 == Write protect disabled + * 3 0 == No task switch + * 2 0 == Don't do FP software emulation. + * 0 1 == Proctected mode enabled + */ + movl %cr0, %eax + andl $~((1<<31)|(1<<18)|(1<<16)|(1<<3)|(1<<2)), %eax + orl $(1<<0), %eax + movl %eax, %cr0 + + /* clear cr4 if applicable */ + testl %ecx, %ecx + jz 1f + /* Set cr4 to a known state: + * Setting everything to zero seems safe. + */ + movl %cr4, %eax + andl $0, %eax + movl %eax, %cr4 + + jmp 1f +1: + + /* Flush the TLB (needed?) */ + xorl %eax, %eax + movl %eax, %cr3 + + /* Do the copies */ + cld +0: /* top, read another word for the indirection page */ + movl %ebx, %ecx + movl (%ebx), %ecx + addl $4, %ebx + testl $0x1, %ecx /* is it a destination page */ + jz 1f + movl %ecx, %edi + andl $0xfffff000, %edi + jmp 0b +1: + testl $0x2, %ecx /* is it an indirection page */ + jz 1f + movl %ecx, %ebx + andl $0xfffff000, %ebx + jmp 0b +1: + testl $0x4, %ecx /* is it the done indicator */ + jz 1f + jmp 2f +1: + testl $0x8, %ecx /* is it the source indicator */ + jz 0b /* Ignore it otherwise */ + movl %ecx, %esi /* For every source page do a copy */ + andl $0xfffff000, %esi + + movl $1024, %ecx + rep ; movsl + jmp 0b + +2: + + /* To be certain of avoiding problems with self-modifying code + * I need to execute a serializing instruction here. + * So I flush the TLB, it's handy, and not processor dependent. + */ + xorl %eax, %eax + movl %eax, %cr3 + + /* set all of the registers to known values */ + /* leave %esp alone */ + + xorl %eax, %eax + xorl %ebx, %ebx + xorl %ecx, %ecx + xorl %edx, %edx + xorl %esi, %esi + xorl %edi, %edi + xorl %ebp, %ebp + ret +relocate_new_kernel_end: + + .globl relocate_new_kernel_size +relocate_new_kernel_size: + .long relocate_new_kernel_end - relocate_new_kernel diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/setup.c 830-ivtv/arch/i386/kernel/setup.c --- 000-virgin/arch/i386/kernel/setup.c Thu Jan 8 08:35:21 2004 +++ 830-ivtv/arch/i386/kernel/setup.c Thu Jan 8 10:21:30 2004 @@ -145,7 +145,7 @@ static void __init probe_roms(void) probe_extension_roms(roms); } -static void __init limit_regions(unsigned long long size) +void __init limit_regions(unsigned long long size) { unsigned long long current_addr = 0; int i; @@ -474,6 +474,7 @@ static void __init setup_memory_region(v print_memory_map(who); } /* setup_memory_region */ +unsigned long max_pages_per_node = 0xFFFFFFFF; static void __init parse_cmdline_early (char ** cmdline_p) { @@ -516,6 +517,14 @@ static void __init parse_cmdline_early ( limit_regions(mem_size); userdef=1; } + } + + if (c == ' ' && !memcmp(from, "memnode=", 8)) { + unsigned long long node_size_bytes; + if (to != command_line) + to--; + node_size_bytes = memparse(from+8, &from); + max_pages_per_node = node_size_bytes >> PAGE_SHIFT; } if (c == ' ' && !memcmp(from, "memmap=", 7)) { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/signal.c 830-ivtv/arch/i386/kernel/signal.c --- 000-virgin/arch/i386/kernel/signal.c Mon Dec 8 09:55:50 2003 +++ 830-ivtv/arch/i386/kernel/signal.c Thu Jan 8 09:30:58 2004 @@ -128,28 +128,29 @@ sys_sigaltstack(const stack_t __user *us */ static int -restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *peax) +restore_sigcontext(struct pt_regs *regs, + struct sigcontext __user *__sc, int *peax) { - unsigned int err = 0; + struct sigcontext scratch; /* 88 bytes of scratch area */ /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; -#define COPY(x) err |= __get_user(regs->x, &sc->x) + if (copy_from_user(&scratch, __sc, sizeof(scratch))) + return -EFAULT; + +#define COPY(x) regs->x = scratch.x #define COPY_SEG(seg) \ - { unsigned short tmp; \ - err |= __get_user(tmp, &sc->seg); \ + { unsigned short tmp = scratch.seg; \ regs->x##seg = tmp; } #define COPY_SEG_STRICT(seg) \ - { unsigned short tmp; \ - err |= __get_user(tmp, &sc->seg); \ + { unsigned short tmp = scratch.seg; \ regs->x##seg = tmp|3; } #define GET_SEG(seg) \ - { unsigned short tmp; \ - err |= __get_user(tmp, &sc->seg); \ + { unsigned short tmp = scratch.seg; \ loadsegment(seg,tmp); } GET_SEG(gs); @@ -168,27 +169,23 @@ restore_sigcontext(struct pt_regs *regs, COPY_SEG_STRICT(ss); { - unsigned int tmpflags; - err |= __get_user(tmpflags, &sc->eflags); + unsigned int tmpflags = scratch.eflags; regs->eflags = (regs->eflags & ~0x40DD5) | (tmpflags & 0x40DD5); regs->orig_eax = -1; /* disable syscall checks */ } { - struct _fpstate __user * buf; - err |= __get_user(buf, &sc->fpstate); + struct _fpstate * buf = scratch.fpstate; if (buf) { if (verify_area(VERIFY_READ, buf, sizeof(*buf))) - goto badframe; - err |= restore_i387(buf); + return -EFAULT; + if (restore_i387(buf)) + return -EFAULT; } } - err |= __get_user(*peax, &sc->eax); - return err; - -badframe: - return 1; + *peax = scratch.eax; + return 0; } asmlinkage int sys_sigreturn(unsigned long __unused) @@ -266,46 +263,47 @@ badframe: */ static int -setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate, +setup_sigcontext(struct sigcontext __user *__sc, struct _fpstate __user *fpstate, struct pt_regs *regs, unsigned long mask) { - int tmp, err = 0; + struct sigcontext sc; /* 88 bytes of scratch area */ + int tmp; tmp = 0; __asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp)); - err |= __put_user(tmp, (unsigned int *)&sc->gs); + *(unsigned int *)&sc.gs = tmp; __asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp)); - err |= __put_user(tmp, (unsigned int *)&sc->fs); - - err |= __put_user(regs->xes, (unsigned int *)&sc->es); - err |= __put_user(regs->xds, (unsigned int *)&sc->ds); - err |= __put_user(regs->edi, &sc->edi); - err |= __put_user(regs->esi, &sc->esi); - err |= __put_user(regs->ebp, &sc->ebp); - err |= __put_user(regs->esp, &sc->esp); - err |= __put_user(regs->ebx, &sc->ebx); - err |= __put_user(regs->edx, &sc->edx); - err |= __put_user(regs->ecx, &sc->ecx); - err |= __put_user(regs->eax, &sc->eax); - err |= __put_user(current->thread.trap_no, &sc->trapno); - err |= __put_user(current->thread.error_code, &sc->err); - err |= __put_user(regs->eip, &sc->eip); - err |= __put_user(regs->xcs, (unsigned int *)&sc->cs); - err |= __put_user(regs->eflags, &sc->eflags); - err |= __put_user(regs->esp, &sc->esp_at_signal); - err |= __put_user(regs->xss, (unsigned int *)&sc->ss); + *(unsigned int *)&sc.fs = tmp; + *(unsigned int *)&sc.es = regs->xes; + *(unsigned int *)&sc.ds = regs->xds; + sc.edi = regs->edi; + sc.esi = regs->esi; + sc.ebp = regs->ebp; + sc.esp = regs->esp; + sc.ebx = regs->ebx; + sc.edx = regs->edx; + sc.ecx = regs->ecx; + sc.eax = regs->eax; + sc.trapno = current->thread.trap_no; + sc.err = current->thread.error_code; + sc.eip = regs->eip; + *(unsigned int *)&sc.cs = regs->xcs; + sc.eflags = regs->eflags; + sc.esp_at_signal = regs->esp; + *(unsigned int *)&sc.ss = regs->xss; tmp = save_i387(fpstate); if (tmp < 0) - err = 1; - else - err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate); + return 1; + sc.fpstate = tmp ? fpstate : NULL; /* non-iBCS2 extensions.. */ - err |= __put_user(mask, &sc->oldmask); - err |= __put_user(current->thread.cr2, &sc->cr2); + sc.oldmask = mask; + sc.cr2 = current->thread.cr2; - return err; + if (copy_to_user(__sc, &sc, sizeof(sc))) + return 1; + return 0; } /* @@ -443,7 +441,7 @@ static void setup_rt_frame(int sig, stru /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(0, &frame->uc.uc_link); - err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); + err |= __put_user(current->sas_ss_sp, (unsigned long *)&frame->uc.uc_stack.ss_sp); err |= __put_user(sas_ss_flags(regs->esp), &frame->uc.uc_stack.ss_flags); err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/smp.c 830-ivtv/arch/i386/kernel/smp.c --- 000-virgin/arch/i386/kernel/smp.c Tue Sep 2 09:55:42 2003 +++ 830-ivtv/arch/i386/kernel/smp.c Thu Jan 8 10:26:46 2004 @@ -327,10 +327,12 @@ asmlinkage void smp_invalidate_interrupt if (flush_mm == cpu_tlbstate[cpu].active_mm) { if (cpu_tlbstate[cpu].state == TLBSTATE_OK) { +#ifndef CONFIG_X86_SWITCH_PAGETABLES if (flush_va == FLUSH_ALL) local_flush_tlb(); else __flush_tlb_one(flush_va); +#endif } else leave_mm(cpu); } @@ -396,21 +398,6 @@ static void flush_tlb_others(cpumask_t c spin_unlock(&tlbstate_lock); } -void flush_tlb_current_task(void) -{ - struct mm_struct *mm = current->mm; - cpumask_t cpu_mask; - - preempt_disable(); - cpu_mask = mm->cpu_vm_mask; - cpu_clear(smp_processor_id(), cpu_mask); - - local_flush_tlb(); - if (!cpus_empty(cpu_mask)) - flush_tlb_others(cpu_mask, mm, FLUSH_ALL); - preempt_enable(); -} - void flush_tlb_mm (struct mm_struct * mm) { cpumask_t cpu_mask; @@ -442,7 +429,10 @@ void flush_tlb_page(struct vm_area_struc if (current->active_mm == mm) { if(current->mm) - __flush_tlb_one(va); +#ifndef CONFIG_X86_SWITCH_PAGETABLES + __flush_tlb_one(va) +#endif + ; else leave_mm(smp_processor_id()); } @@ -466,7 +456,17 @@ void flush_tlb_all(void) { on_each_cpu(do_flush_tlb_all, 0, 1, 1); } - +#ifdef CONFIG_KGDB +/* + * By using the NMI code instead of a vector we just sneak thru the + * word generator coming out with just what we want. AND it does + * not matter if clustered_apic_mode is set or not. + */ +void smp_send_nmi_allbutself(void) +{ + send_IPI_allbutself(APIC_DM_NMI); +} +#endif /* * this function sends a 'reschedule' IPI to another CPU. * it goes straight through and wastes no time serializing @@ -564,6 +564,30 @@ static void stop_this_cpu (void * dummy) void smp_send_stop(void) { + extern int reboot_cpu; + int reboot_cpu_id; + + /* The boot cpu is always logical cpu 0 */ + reboot_cpu_id = 0; + + /* See if there has been give a command line override. + */ + if ((reboot_cpu != -1) && !(reboot_cpu >= NR_CPUS) && + test_bit(reboot_cpu, &cpu_online_map)) { + reboot_cpu_id = reboot_cpu; + } + + /* Make certain the the cpu I'm rebooting on is online */ + if (!test_bit(reboot_cpu_id, &cpu_online_map)) { + reboot_cpu_id = smp_processor_id(); + } + + /* Make certain I only run on the appropriate processor */ + set_cpus_allowed(current, 1 << reboot_cpu_id); + + /* O.K. Now that I'm on the appropriate processor, stop + * all of the others. + */ smp_call_function(stop_this_cpu, NULL, 1, 0); local_irq_disable(); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/smpboot.c 830-ivtv/arch/i386/kernel/smpboot.c --- 000-virgin/arch/i386/kernel/smpboot.c Mon Nov 17 18:29:21 2003 +++ 830-ivtv/arch/i386/kernel/smpboot.c Thu Jan 8 10:27:05 2004 @@ -946,6 +946,7 @@ static void __init smp_boot_cpus(unsigne printk("CPU%d: ", 0); print_cpu_info(&cpu_data[0]); + boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID)); boot_cpu_logical_apicid = logical_smp_processor_id(); current_thread_info()->cpu = 0; @@ -1006,8 +1007,6 @@ static void __init smp_boot_cpus(unsigne setup_local_APIC(); map_cpu_to_logical_apicid(); - if (GET_APIC_ID(apic_read(APIC_ID)) != boot_cpu_physical_apicid) - BUG(); setup_portio_remap(); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/srat.c 830-ivtv/arch/i386/kernel/srat.c --- 000-virgin/arch/i386/kernel/srat.c Mon Nov 17 18:28:33 2003 +++ 830-ivtv/arch/i386/kernel/srat.c Thu Jan 8 10:21:30 2004 @@ -53,6 +53,10 @@ struct node_memory_chunk_s { }; static struct node_memory_chunk_s node_memory_chunk[MAXCHUNKS]; +#define chunk_start(i) (node_memory_chunk[i].start_pfn) +#define chunk_end(i) (node_memory_chunk[i].end_pfn) +#define chunk_size(i) (chunk_end(i)-chunk_start(i)) + static int num_memory_chunks; /* total number of memory chunks */ static int zholes_size_init; static unsigned long zholes_size[MAX_NUMNODES * MAX_NR_ZONES]; @@ -198,6 +202,9 @@ static void __init initialize_physnode_m } } +extern unsigned long max_pages_per_node; +extern int limit_mem_per_node; + /* Parse the ACPI Static Resource Affinity Table */ static int __init acpi20_parse_srat(struct acpi_table_srat *sratp) { @@ -281,23 +288,27 @@ static int __init acpi20_parse_srat(stru node_memory_chunk[j].start_pfn, node_memory_chunk[j].end_pfn); } - + /*calculate node_start_pfn/node_end_pfn arrays*/ for (nid = 0; nid < numnodes; nid++) { - int been_here_before = 0; + unsigned long node_present_pages = 0; + node_start_pfn[nid] = -1; for (j = 0; j < num_memory_chunks; j++){ - if (node_memory_chunk[j].nid == nid) { - if (been_here_before == 0) { - node_start_pfn[nid] = node_memory_chunk[j].start_pfn; - node_end_pfn[nid] = node_memory_chunk[j].end_pfn; - been_here_before = 1; - } else { /* We've found another chunk of memory for the node */ - if (node_start_pfn[nid] < node_memory_chunk[j].start_pfn) { - node_end_pfn[nid] = node_memory_chunk[j].end_pfn; - } - } - } + unsigned long proposed_size; + + if (node_memory_chunk[j].nid != nid) + continue; + + proposed_size = node_present_pages + chunk_size(j); + if (proposed_size > max_pages_per_node) + chunk_end(j) = chunk_start(j) + + max_pages_per_node - node_present_pages; + node_present_pages += chunk_size(j); + + if (node_start_pfn[nid] == -1) + node_start_pfn[nid] = chunk_start(j); + node_end_pfn[nid] = chunk_end(j); } } return 1; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/sysenter.c 830-ivtv/arch/i386/kernel/sysenter.c --- 000-virgin/arch/i386/kernel/sysenter.c Wed Aug 13 20:24:18 2003 +++ 830-ivtv/arch/i386/kernel/sysenter.c Thu Jan 8 09:30:58 2004 @@ -18,13 +18,18 @@ #include #include #include +#include extern asmlinkage void sysenter_entry(void); void enable_sep_cpu(void *info) { int cpu = get_cpu(); +#ifdef CONFIG_X86_HIGH_ENTRY + struct tss_struct *tss = (struct tss_struct *) __fix_to_virt(FIX_TSS_0) + cpu; +#else struct tss_struct *tss = init_tss + cpu; +#endif tss->ss1 = __KERNEL_CS; tss->esp1 = sizeof(struct tss_struct) + (unsigned long) tss; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/traps.c 830-ivtv/arch/i386/kernel/traps.c --- 000-virgin/arch/i386/kernel/traps.c Mon Nov 17 18:29:41 2003 +++ 830-ivtv/arch/i386/kernel/traps.c Thu Jan 8 10:22:35 2004 @@ -54,12 +54,8 @@ #include "mach_traps.h" -asmlinkage int system_call(void); -asmlinkage void lcall7(void); -asmlinkage void lcall27(void); - -struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, - { 0, 0 }, { 0, 0 } }; +struct desc_struct default_ldt[] __attribute__((__section__(".data.default_ldt"))) = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }; +struct page *default_ldt_page; /* Do we ignore FPU interrupts ? */ char ignore_fpu_irq = 0; @@ -91,19 +87,97 @@ asmlinkage void alignment_check(void); asmlinkage void spurious_interrupt_bug(void); asmlinkage void machine_check(void); -static int kstack_depth_to_print = 24; +#ifdef CONFIG_KGDB +extern void sysenter_entry(void); +#include +#include +extern void int3(void); +extern void debug(void); +void set_intr_gate(unsigned int n, void *addr); +static void set_intr_usr_gate(unsigned int n, void *addr); +/* + * Should be able to call this breakpoint() very early in + * bring up. Just hard code the call where needed. + * The breakpoint() code is here because set_?_gate() functions + * are local (static) to trap.c. They need be done only once, + * but it does not hurt to do them over. + */ +void breakpoint(void) +{ + init_entry_mappings(); + set_intr_usr_gate(3,&int3); /* disable ints on trap */ + set_intr_gate(1,&debug); + set_intr_gate(14,&page_fault); -void show_trace(struct task_struct *task, unsigned long * stack) + BREAKPOINT; +} +#define CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after) \ + { \ + if (!user_mode(regs) ) \ + { \ + kgdb_handle_exception(trapnr, signr, error_code, regs); \ + after; \ + } else if ((trapnr == 3) && (regs->eflags &0x200)) local_irq_enable(); \ + } +#else +#define CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after) +#endif + + +#define STACK_PRINT_DEPTH 32 + +#ifdef CONFIG_FRAME_POINTER +#define valid_stack_ptr(task, p) \ + ((p > (unsigned long)task->thread_info) && \ + (p < (unsigned long)task->thread_info+4096)) + +void show_stack_frame(unsigned long start, unsigned long end) +{ + int i; + + printk(" "); + for (i = start; i < end; i += 4) { + if ((i - start) && ((i - start)%24 == 0)) + printk("\n "); + printk("%08lx ", *(unsigned long *) i); + } + printk("\n"); +} + +void show_trace_fp(struct task_struct *task, unsigned long * stack) +{ + unsigned long addr, ebp; + + if (!task) + task = current; + + if (task == current) { + /* Grab ebp right from our regs */ + asm ("movl %%ebp, %0" : "=r" (ebp) : ); + } else { + /* ebp is the last reg pushed by switch_to */ + ebp = *(unsigned long *) task->thread.esp; + } + + show_stack_frame((unsigned long) stack, ebp+4); + while (valid_stack_ptr(task, ebp)) { + addr = *(unsigned long *) (ebp + 4); + printk(" [<%08lx>] ", addr); + print_symbol("%s\n", addr); + + /* Show the stack frame starting with args */ + show_stack_frame(ebp + 8, (*(unsigned long *) ebp) + 4); + ebp = *(unsigned long *) ebp; + } +} +#else +void show_trace_guess(unsigned long * stack) { unsigned long addr; if (!stack) stack = (unsigned long*)&stack; - printk("Call Trace:"); -#ifdef CONFIG_KALLSYMS - printk("\n"); -#endif while (!kstack_end(stack)) { addr = *stack++; if (kernel_text_address(addr)) { @@ -111,6 +185,20 @@ void show_trace(struct task_struct *task print_symbol("%s\n", addr); } } +} +#endif + +void show_trace(struct task_struct *task, unsigned long * stack) +{ + printk("Call Trace:"); +#ifdef CONFIG_KALLSYMS + printk("\n"); +#endif +#ifdef CONFIG_FRAME_POINTER + show_trace_fp(task, stack); +#else + show_trace_guess(stack); +#endif printk("\n"); } @@ -126,8 +214,10 @@ void show_trace_task(struct task_struct void show_stack(struct task_struct *task, unsigned long *esp) { +#ifndef CONFIG_FRAME_POINTER unsigned long *stack; int i; +#endif if (esp == NULL) { if (task) @@ -136,8 +226,9 @@ void show_stack(struct task_struct *task esp = (unsigned long *)&esp; } +#ifndef CONFIG_FRAME_POINTER stack = esp; - for(i = 0; i < kstack_depth_to_print; i++) { + for(i = 0; i < STACK_PRINT_DEPTH; i++) { if (kstack_end(stack)) break; if (i && ((i % 8) == 0)) @@ -145,6 +236,7 @@ void show_stack(struct task_struct *task printk("%08lx ", *stack++); } printk("\n"); +#endif show_trace(task, esp); } @@ -175,8 +267,9 @@ void show_registers(struct pt_regs *regs ss = regs->xss & 0xffff; } print_modules(); - printk("CPU: %d\nEIP: %04x:[<%08lx>] %s\nEFLAGS: %08lx\n", - smp_processor_id(), 0xffff & regs->xcs, regs->eip, print_tainted(), regs->eflags); + printk("CPU: %d\nEIP: %04x:[<%08lx>] %s VLI\nEFLAGS: %08lx\n", + smp_processor_id(), 0xffff & regs->xcs, + regs->eip, print_tainted(), regs->eflags); print_symbol("EIP is at %s\n", regs->eip); printk("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n", @@ -192,23 +285,27 @@ void show_registers(struct pt_regs *regs * time of the fault.. */ if (in_kernel) { + u8 *eip; printk("\nStack: "); show_stack(NULL, (unsigned long*)esp); printk("Code: "); - if(regs->eip < PAGE_OFFSET) - goto bad; - for(i=0;i<20;i++) - { - unsigned char c; - if(__get_user(c, &((unsigned char*)regs->eip)[i])) { -bad: + eip = (u8 *)regs->eip - 43; + for (i = 0; i < 64; i++, eip++) { + unsigned char c = 0xff; + + if ((user_mode(regs) && get_user(c, eip)) || + (!user_mode(regs) && __direct_get_user(c, eip))) { + printk(" Bad EIP value."); break; } - printk("%02x ", c); + if (eip == (u8 *)regs->eip) + printk("<%02x> ", c); + else + printk("%02x ", c); } } printk("\n"); @@ -261,6 +358,15 @@ void die(const char * str, struct pt_reg bust_spinlocks(1); handle_BUG(regs); printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); +#ifdef CONFIG_KGDB + /* This is about the only place we want to go to kgdb even if in + * user mode. But we must go in via a trap so within kgdb we will + * always be in kernel mode. + */ + if (user_mode(regs)) + BREAKPOINT; +#endif + CHK_REMOTE_DEBUG(0,SIGTRAP,err,regs,) show_registers(regs); bust_spinlocks(0); spin_unlock_irq(&die_lock); @@ -330,6 +436,7 @@ static inline void do_trap(int trapnr, i #define DO_ERROR(trapnr, signr, str, name) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ + CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,)\ do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \ } @@ -347,7 +454,9 @@ asmlinkage void do_##name(struct pt_regs #define DO_VM86_ERROR(trapnr, signr, str, name) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ + CHK_REMOTE_DEBUG(trapnr, signr, error_code,regs, return)\ do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \ + return; \ } #define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ @@ -394,8 +503,10 @@ gp_in_vm86: return; gp_in_kernel: - if (!fixup_exception(regs)) + if (!fixup_exception(regs)){ + CHK_REMOTE_DEBUG(13,SIGSEGV,error_code,regs,) die("general protection fault", regs, error_code); + } } static void mem_parity_error(unsigned char reason, struct pt_regs * regs) @@ -534,10 +645,18 @@ asmlinkage void do_debug(struct pt_regs if (regs->eflags & X86_EFLAGS_IF) local_irq_enable(); - /* Mask out spurious debug traps due to lazy DR7 setting */ + /* + * Mask out spurious debug traps due to lazy DR7 setting or + * due to 4G/4G kernel mode: + */ if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { if (!tsk->thread.debugreg[7]) goto clear_dr7; + if (!user_mode(regs)) { + // restore upon return-to-userspace: + set_thread_flag(TIF_DB7); + goto clear_dr7; + } } if (regs->eflags & VM_MASK) @@ -557,8 +676,18 @@ asmlinkage void do_debug(struct pt_regs * allowing programs to debug themselves without the ptrace() * interface. */ +#ifdef CONFIG_KGDB + /* + * I think this is the only "real" case of a TF in the kernel + * that really belongs to user space. Others are + * "Ours all ours!" + */ + if (((regs->xcs & 3) == 0) && ((void *)regs->eip == sysenter_entry)) + goto clear_TF_reenable; +#else if ((regs->xcs & 3) == 0) goto clear_TF_reenable; +#endif if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE) goto clear_TF; } @@ -570,6 +699,17 @@ asmlinkage void do_debug(struct pt_regs info.si_errno = 0; info.si_code = TRAP_BRKPT; +#ifdef CONFIG_KGDB + /* + * If this is a kernel mode trap, we need to reset db7 to allow us + * to continue sanely ALSO skip the signal delivery + */ + if ((regs->xcs & 3) == 0) + goto clear_dr7; + + /* if not kernel, allow ints but only if they were on */ + if ( regs->eflags & 0x200) local_irq_enable(); +#endif /* If this is a kernel mode trap, save the user PC on entry to * the kernel, that's what the debugger can make sense of. */ @@ -584,6 +724,7 @@ clear_dr7: __asm__("movl %0,%%db7" : /* no output */ : "r" (0)); + CHK_REMOTE_DEBUG(1,SIGTRAP,error_code,regs,) return; debug_vm86: @@ -779,19 +920,53 @@ asmlinkage void math_emulate(long arg) #endif /* CONFIG_MATH_EMULATION */ -#ifdef CONFIG_X86_F00F_BUG -void __init trap_init_f00f_bug(void) +void __init trap_init_virtual_IDT(void) { - __set_fixmap(FIX_F00F_IDT, __pa(&idt_table), PAGE_KERNEL_RO); - /* - * Update the IDT descriptor and reload the IDT so that - * it uses the read-only mapped virtual address. + * "idt" is magic - it overlaps the idt_descr + * variable so that updating idt will automatically + * update the idt descriptor.. */ - idt_descr.address = fix_to_virt(FIX_F00F_IDT); + __set_fixmap(FIX_IDT, __pa(&idt_table), PAGE_KERNEL_RO); + idt_descr.address = __fix_to_virt(FIX_IDT); + __asm__ __volatile__("lidt %0" : : "m" (idt_descr)); } + +void __init trap_init_virtual_GDT(void) +{ + int cpu = smp_processor_id(); + struct Xgt_desc_struct *gdt_desc = cpu_gdt_descr + cpu; + struct Xgt_desc_struct tmp_desc = {0, 0}; + struct tss_struct * t; + + __asm__ __volatile__("sgdt %0": "=m" (tmp_desc): :"memory"); + +#ifdef CONFIG_X86_HIGH_ENTRY + if (!cpu) { + __set_fixmap(FIX_GDT_0, __pa(cpu_gdt_table), PAGE_KERNEL); + __set_fixmap(FIX_GDT_1, __pa(cpu_gdt_table) + PAGE_SIZE, PAGE_KERNEL); + __set_fixmap(FIX_TSS_0, __pa(init_tss), PAGE_KERNEL); + __set_fixmap(FIX_TSS_1, __pa(init_tss) + 1*PAGE_SIZE, PAGE_KERNEL); + __set_fixmap(FIX_TSS_2, __pa(init_tss) + 2*PAGE_SIZE, PAGE_KERNEL); + __set_fixmap(FIX_TSS_3, __pa(init_tss) + 3*PAGE_SIZE, PAGE_KERNEL); + } + + gdt_desc->address = __fix_to_virt(FIX_GDT_0) + sizeof(cpu_gdt_table[0]) * cpu; +#else + gdt_desc->address = (unsigned long)cpu_gdt_table[cpu]; +#endif + __asm__ __volatile__("lgdt %0": "=m" (*gdt_desc)); + +#ifdef CONFIG_X86_HIGH_ENTRY + t = (struct tss_struct *) __fix_to_virt(FIX_TSS_0) + cpu; +#else + t = init_tss + cpu; #endif + set_tss_desc(cpu, t); + cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff; + load_TR_desc(); +} #define _set_gate(gate_addr,type,dpl,addr,seg) \ do { \ @@ -818,20 +993,26 @@ void set_intr_gate(unsigned int n, void _set_gate(idt_table+n,14,0,addr,__KERNEL_CS); } -static void __init set_trap_gate(unsigned int n, void *addr) +void __init set_trap_gate(unsigned int n, void *addr) { _set_gate(idt_table+n,15,0,addr,__KERNEL_CS); } -static void __init set_system_gate(unsigned int n, void *addr) +void __init set_system_gate(unsigned int n, void *addr) { _set_gate(idt_table+n,15,3,addr,__KERNEL_CS); } -static void __init set_call_gate(void *a, void *addr) +void __init set_call_gate(void *a, void *addr) { _set_gate(a,12,3,addr,__KERNEL_CS); } +#ifdef CONFIG_KGDB +void set_intr_usr_gate(unsigned int n, void *addr) +{ + _set_gate(idt_table+n,14,3,addr,__KERNEL_CS); +} +#endif static void __init set_task_gate(unsigned int n, unsigned int gdt_entry) { @@ -850,11 +1031,16 @@ void __init trap_init(void) #ifdef CONFIG_X86_LOCAL_APIC init_apic_mappings(); #endif + init_entry_mappings(); set_trap_gate(0,÷_error); set_intr_gate(1,&debug); set_intr_gate(2,&nmi); +#ifndef CONFIG_KGDB set_system_gate(3,&int3); /* int3-5 can be called from all */ +#else + set_intr_usr_gate(3,&int3); /* int3-5 can be called from all */ +#endif set_system_gate(4,&overflow); set_system_gate(5,&bounds); set_trap_gate(6,&invalid_op); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/vm86.c 830-ivtv/arch/i386/kernel/vm86.c --- 000-virgin/arch/i386/kernel/vm86.c Thu Jan 8 08:35:21 2004 +++ 830-ivtv/arch/i386/kernel/vm86.c Thu Jan 8 09:30:58 2004 @@ -125,7 +125,7 @@ struct pt_regs * save_v86_state(struct k tss = init_tss + get_cpu(); current->thread.esp0 = current->thread.saved_esp0; current->thread.sysenter_cs = __KERNEL_CS; - load_esp0(tss, ¤t->thread); + load_virtual_esp0(tss, current); current->thread.saved_esp0 = 0; put_cpu(); @@ -305,7 +305,7 @@ static void do_sys_vm86(struct kernel_vm tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0; if (cpu_has_sep) tsk->thread.sysenter_cs = 0; - load_esp0(tss, &tsk->thread); + load_virtual_esp0(tss, tsk); put_cpu(); tsk->thread.screen_bitmap = info->screen_bitmap; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/vmlinux.lds.S 830-ivtv/arch/i386/kernel/vmlinux.lds.S --- 000-virgin/arch/i386/kernel/vmlinux.lds.S Tue Sep 2 09:55:42 2003 +++ 830-ivtv/arch/i386/kernel/vmlinux.lds.S Thu Jan 8 09:30:58 2004 @@ -3,6 +3,9 @@ */ #include +#include +#include +#include OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) @@ -10,7 +13,7 @@ ENTRY(startup_32) jiffies = jiffies_64; SECTIONS { - . = 0xC0000000 + 0x100000; + . = __PAGE_OFFSET + 0x100000; /* read-only */ _text = .; /* Text and read-only data */ .text : { @@ -19,6 +22,19 @@ SECTIONS *(.gnu.warning) } = 0x9090 +#ifdef CONFIG_X86_4G + . = ALIGN(PAGE_SIZE_asm); + __entry_tramp_start = .; + . = FIX_ENTRY_TRAMPOLINE_0_addr; + __start___entry_text = .; + .entry.text : AT (__entry_tramp_start) { *(.entry.text) } + __entry_tramp_end = __entry_tramp_start + SIZEOF(.entry.text); + . = __entry_tramp_end; + . = ALIGN(PAGE_SIZE_asm); +#else + .entry.text : { *(.entry.text) } +#endif + _etext = .; /* End of text section */ . = ALIGN(16); /* Exception table */ @@ -34,15 +50,12 @@ SECTIONS CONSTRUCTORS } - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE_asm); __nosave_begin = .; .data_nosave : { *(.data.nosave) } - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE_asm); __nosave_end = .; - . = ALIGN(4096); - .data.page_aligned : { *(.data.idt) } - . = ALIGN(32); .data.cacheline_aligned : { *(.data.cacheline_aligned) } @@ -52,7 +65,7 @@ SECTIONS .data.init_task : { *(.data.init_task) } /* will be freed after init */ - . = ALIGN(4096); /* Init code and data */ + . = ALIGN(PAGE_SIZE_asm); /* Init code and data */ __init_begin = .; .init.text : { _sinittext = .; @@ -91,7 +104,7 @@ SECTIONS from .altinstructions and .eh_frame */ .exit.text : { *(.exit.text) } .exit.data : { *(.exit.data) } - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE_asm); __initramfs_start = .; .init.ramfs : { *(.init.ramfs) } __initramfs_end = .; @@ -99,10 +112,22 @@ SECTIONS __per_cpu_start = .; .data.percpu : { *(.data.percpu) } __per_cpu_end = .; - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE_asm); __init_end = .; /* freed after init ends here */ - + + . = ALIGN(PAGE_SIZE_asm); + .data.page_aligned_tss : { *(.data.tss) } + + . = ALIGN(PAGE_SIZE_asm); + .data.page_aligned_default_ldt : { *(.data.default_ldt) } + + . = ALIGN(PAGE_SIZE_asm); + .data.page_aligned_idt : { *(.data.idt) } + + . = ALIGN(PAGE_SIZE_asm); + .data.page_aligned_gdt : { *(.data.gdt) } + __bss_start = .; /* BSS */ .bss : { *(.bss) } __bss_stop = .; @@ -122,4 +147,6 @@ SECTIONS .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } .comment 0 : { *(.comment) } + + } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/vsyscall-sysenter.S 830-ivtv/arch/i386/kernel/vsyscall-sysenter.S --- 000-virgin/arch/i386/kernel/vsyscall-sysenter.S Sat May 10 18:34:33 2003 +++ 830-ivtv/arch/i386/kernel/vsyscall-sysenter.S Thu Jan 8 09:30:58 2004 @@ -7,6 +7,11 @@ .type __kernel_vsyscall,@function __kernel_vsyscall: .LSTART_vsyscall: + cmpl $192, %eax + jne 1f + int $0x80 + ret +1: push %ecx .Lpush_ecx: push %edx diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/kernel/vsyscall.lds 830-ivtv/arch/i386/kernel/vsyscall.lds --- 000-virgin/arch/i386/kernel/vsyscall.lds Sat May 10 18:34:33 2003 +++ 830-ivtv/arch/i386/kernel/vsyscall.lds Thu Jan 8 09:30:58 2004 @@ -5,7 +5,7 @@ */ /* This must match . */ -VSYSCALL_BASE = 0xffffe000; +VSYSCALL_BASE = 0xffffd000; SECTIONS { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/lib/Makefile 830-ivtv/arch/i386/lib/Makefile --- 000-virgin/arch/i386/lib/Makefile Sat Jun 14 18:37:24 2003 +++ 830-ivtv/arch/i386/lib/Makefile Thu Jan 8 10:21:27 2004 @@ -9,4 +9,6 @@ lib-y = checksum.o delay.o \ lib-$(CONFIG_X86_USE_3DNOW) += mmx.o lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o +lib-$(CONFIG_KGDB) += kgdb_serial.o lib-$(CONFIG_DEBUG_IOVIRT) += iodebug.o +lib-$(CONFIG_MCOUNT) += mcount.o diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/lib/checksum.S 830-ivtv/arch/i386/lib/checksum.S --- 000-virgin/arch/i386/lib/checksum.S Sun Nov 17 20:29:29 2002 +++ 830-ivtv/arch/i386/lib/checksum.S Thu Jan 8 09:30:58 2004 @@ -280,14 +280,14 @@ unsigned int csum_partial_copy_generic ( .previous .align 4 -.globl csum_partial_copy_generic +.globl direct_csum_partial_copy_generic #ifndef CONFIG_X86_USE_PPRO_CHECKSUM #define ARGBASE 16 #define FP 12 -csum_partial_copy_generic: +direct_csum_partial_copy_generic: subl $4,%esp pushl %edi pushl %esi @@ -422,7 +422,7 @@ DST( movb %cl, (%edi) ) #define ARGBASE 12 -csum_partial_copy_generic: +direct_csum_partial_copy_generic: pushl %ebx pushl %edi pushl %esi diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/lib/dec_and_lock.c 830-ivtv/arch/i386/lib/dec_and_lock.c --- 000-virgin/arch/i386/lib/dec_and_lock.c Sun Nov 17 20:29:28 2002 +++ 830-ivtv/arch/i386/lib/dec_and_lock.c Thu Jan 8 09:30:50 2004 @@ -10,6 +10,7 @@ #include #include +#ifndef ATOMIC_DEC_AND_LOCK int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) { int counter; @@ -38,3 +39,5 @@ slow_path: spin_unlock(lock); return 0; } +#endif + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/lib/getuser.S 830-ivtv/arch/i386/lib/getuser.S --- 000-virgin/arch/i386/lib/getuser.S Sun Nov 17 20:29:20 2002 +++ 830-ivtv/arch/i386/lib/getuser.S Thu Jan 8 09:30:58 2004 @@ -9,6 +9,7 @@ * return value. */ #include +#include /* @@ -28,7 +29,7 @@ .globl __get_user_1 __get_user_1: GET_THREAD_INFO(%edx) - cmpl TI_ADDR_LIMIT(%edx),%eax + cmpl TI_addr_limit(%edx),%eax jae bad_get_user 1: movzbl (%eax),%edx xorl %eax,%eax @@ -40,7 +41,7 @@ __get_user_2: addl $1,%eax jc bad_get_user GET_THREAD_INFO(%edx) - cmpl TI_ADDR_LIMIT(%edx),%eax + cmpl TI_addr_limit(%edx),%eax jae bad_get_user 2: movzwl -1(%eax),%edx xorl %eax,%eax @@ -52,7 +53,7 @@ __get_user_4: addl $3,%eax jc bad_get_user GET_THREAD_INFO(%edx) - cmpl TI_ADDR_LIMIT(%edx),%eax + cmpl TI_addr_limit(%edx),%eax jae bad_get_user 3: movl -3(%eax),%edx xorl %eax,%eax diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/lib/kgdb_serial.c 830-ivtv/arch/i386/lib/kgdb_serial.c --- 000-virgin/arch/i386/lib/kgdb_serial.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/arch/i386/lib/kgdb_serial.c Thu Jan 8 09:30:18 2004 @@ -0,0 +1,499 @@ +/* + * Serial interface GDB stub + * + * Written (hacked together) by David Grothe (dave@gcom.com) + * Modified to allow invokation early in boot see also + * kgdb.h for instructions by George Anzinger(george@mvista.com) + * Modified to handle debugging over ethernet by Robert Walsh + * and wangdi , based on + * code by San Mehat. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_KGDB_USER_CONSOLE +extern void kgdb_console_finit(void); +#endif +#define PRNT_off +#define TEST_EXISTANCE +#ifdef PRNT +#define dbprintk(s) printk s +#else +#define dbprintk(s) +#endif +#define TEST_INTERRUPT_off +#ifdef TEST_INTERRUPT +#define intprintk(s) printk s +#else +#define intprintk(s) +#endif + +#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT) + +#define GDB_BUF_SIZE 512 /* power of 2, please */ + +static char gdb_buf[GDB_BUF_SIZE]; +static int gdb_buf_in_inx; +static atomic_t gdb_buf_in_cnt; +static int gdb_buf_out_inx; + +struct async_struct *gdb_async_info; +static int gdb_async_irq; + +#define outb_px(a,b) outb_p(b,a) + +static void program_uart(struct async_struct *info); +static void write_char(struct async_struct *info, int chr); +/* + * Get a byte from the hardware data buffer and return it + */ +static int +read_data_bfr(struct async_struct *info) +{ + char it = inb_p(info->port + UART_LSR); + + if (it & UART_LSR_DR) + return (inb_p(info->port + UART_RX)); + /* + * If we have a framing error assume somebody messed with + * our uart. Reprogram it and send '-' both ways... + */ + if (it & 0xc) { + program_uart(info); + write_char(info, '-'); + return ('-'); + } + return (-1); + +} /* read_data_bfr */ + +/* + * Get a char if available, return -1 if nothing available. + * Empty the receive buffer first, then look at the interface hardware. + + * Locking here is a bit of a problem. We MUST not lock out communication + * if we are trying to talk to gdb about a kgdb entry. ON the other hand + * we can loose chars in the console pass thru if we don't lock. It is also + * possible that we could hold the lock or be waiting for it when kgdb + * NEEDS to talk. Since kgdb locks down the world, it does not need locks. + * We do, of course have possible issues with interrupting a uart operation, + * but we will just depend on the uart status to help keep that straight. + + */ +static spinlock_t uart_interrupt_lock = SPIN_LOCK_UNLOCKED; +#ifdef CONFIG_SMP +extern spinlock_t kgdb_spinlock; +#endif + +static int +read_char(struct async_struct *info) +{ + int chr; + unsigned long flags; + local_irq_save(flags); +#ifdef CONFIG_SMP + if (!spin_is_locked(&kgdb_spinlock)) { + spin_lock(&uart_interrupt_lock); + } +#endif + if (atomic_read(&gdb_buf_in_cnt) != 0) { /* intr routine has q'd chars */ + chr = gdb_buf[gdb_buf_out_inx++]; + gdb_buf_out_inx &= (GDB_BUF_SIZE - 1); + atomic_dec(&gdb_buf_in_cnt); + } else { + chr = read_data_bfr(info); + } +#ifdef CONFIG_SMP + if (!spin_is_locked(&kgdb_spinlock)) { + spin_unlock(&uart_interrupt_lock); + } +#endif + local_irq_restore(flags); + return (chr); +} + +/* + * Wait until the interface can accept a char, then write it. + */ +static void +write_char(struct async_struct *info, int chr) +{ + while (!(inb_p(info->port + UART_LSR) & UART_LSR_THRE)) ; + + outb_p(chr, info->port + UART_TX); + +} /* write_char */ + +/* + * Mostly we don't need a spinlock, but since the console goes + * thru here with interrutps on, well, we need to catch those + * chars. + */ +/* + * This is the receiver interrupt routine for the GDB stub. + * It will receive a limited number of characters of input + * from the gdb host machine and save them up in a buffer. + * + * When the gdb stub routine tty_getDebugChar() is called it + * draws characters out of the buffer until it is empty and + * then reads directly from the serial port. + * + * We do not attempt to write chars from the interrupt routine + * since the stubs do all of that via tty_putDebugChar() which + * writes one byte after waiting for the interface to become + * ready. + * + * The debug stubs like to run with interrupts disabled since, + * after all, they run as a consequence of a breakpoint in + * the kernel. + * + * Perhaps someone who knows more about the tty driver than I + * care to learn can make this work for any low level serial + * driver. + */ +static irqreturn_t +gdb_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct async_struct *info; + unsigned long flags; + + info = gdb_async_info; + if (!info || !info->tty || irq != gdb_async_irq) + return IRQ_NONE; + + local_irq_save(flags); + spin_lock(&uart_interrupt_lock); + do { + int chr = read_data_bfr(info); + intprintk(("Debug char on int: %x hex\n", chr)); + if (chr < 0) + continue; + + if (chr == 3) { /* Ctrl-C means remote interrupt */ + BREAKPOINT; + continue; + } + + if (atomic_read(&gdb_buf_in_cnt) >= GDB_BUF_SIZE) { + /* buffer overflow tosses early char */ + read_char(info); + } + gdb_buf[gdb_buf_in_inx++] = chr; + gdb_buf_in_inx &= (GDB_BUF_SIZE - 1); + } while (inb_p(info->port + UART_IIR) & UART_IIR_RDI); + spin_unlock(&uart_interrupt_lock); + local_irq_restore(flags); + return IRQ_HANDLED; +} /* gdb_interrupt */ + +/* + * Just a NULL routine for testing. + */ +void +gdb_null(void) +{ +} /* gdb_null */ + +/* These structure are filled in with values defined in asm/kgdb_local.h + */ +static struct serial_state state = SB_STATE; +static struct async_struct local_info = SB_INFO; +static int ok_to_enable_ints = 0; +static void kgdb_enable_ints_now(void); + +extern char *kgdb_version; +/* + * Hook an IRQ for KGDB. + * + * This routine is called from tty_putDebugChar, below. + */ +static int ints_disabled = 1; +int +gdb_hook_interrupt(struct async_struct *info, int verb) +{ + struct serial_state *state = info->state; + unsigned long flags; + int port; +#ifdef TEST_EXISTANCE + int scratch, scratch2; +#endif + + /* The above fails if memory managment is not set up yet. + * Rather than fail the set up, just keep track of the fact + * and pick up the interrupt thing later. + */ + gdb_async_info = info; + port = gdb_async_info->port; + gdb_async_irq = state->irq; + if (verb) { + printk("kgdb %s : port =%x, IRQ=%d, divisor =%d\n", + kgdb_version, + port, + gdb_async_irq, gdb_async_info->state->custom_divisor); + } + local_irq_save(flags); +#ifdef TEST_EXISTANCE + /* Existance test */ + /* Should not need all this, but just in case.... */ + + scratch = inb_p(port + UART_IER); + outb_px(port + UART_IER, 0); + outb_px(0xff, 0x080); + scratch2 = inb_p(port + UART_IER); + outb_px(port + UART_IER, scratch); + if (scratch2) { + printk + ("gdb_hook_interrupt: Could not clear IER, not a UART!\n"); + local_irq_restore(flags); + return 1; /* We failed; there's nothing here */ + } + scratch2 = inb_p(port + UART_LCR); + outb_px(port + UART_LCR, 0xBF); /* set up for StarTech test */ + outb_px(port + UART_EFR, 0); /* EFR is the same as FCR */ + outb_px(port + UART_LCR, 0); + outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO); + scratch = inb_p(port + UART_IIR) >> 6; + if (scratch == 1) { + printk("gdb_hook_interrupt: Undefined UART type!" + " Not a UART! \n"); + local_irq_restore(flags); + return 1; + } else { + dbprintk(("gdb_hook_interrupt: UART type " + "is %d where 0=16450, 2=16550 3=16550A\n", scratch)); + } + scratch = inb_p(port + UART_MCR); + outb_px(port + UART_MCR, UART_MCR_LOOP | scratch); + outb_px(port + UART_MCR, UART_MCR_LOOP | 0x0A); + scratch2 = inb_p(port + UART_MSR) & 0xF0; + outb_px(port + UART_MCR, scratch); + if (scratch2 != 0x90) { + printk("gdb_hook_interrupt: " + "Loop back test failed! Not a UART!\n"); + local_irq_restore(flags); + return scratch2 + 1000; /* force 0 to fail */ + } +#endif /* test existance */ + program_uart(info); + local_irq_restore(flags); + + return (0); + +} /* gdb_hook_interrupt */ + +static void +program_uart(struct async_struct *info) +{ + int port = info->port; + + (void) inb_p(port + UART_RX); + outb_px(port + UART_IER, 0); + + (void) inb_p(port + UART_RX); /* serial driver comments say */ + (void) inb_p(port + UART_IIR); /* this clears the interrupt regs */ + (void) inb_p(port + UART_MSR); + outb_px(port + UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB); + outb_px(port + UART_DLL, info->state->custom_divisor & 0xff); /* LS */ + outb_px(port + UART_DLM, info->state->custom_divisor >> 8); /* MS */ + outb_px(port + UART_MCR, info->MCR); + + outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1 | UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR); /* set fcr */ + outb_px(port + UART_LCR, UART_LCR_WLEN8); /* reset DLAB */ + outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1); /* set fcr */ + if (!ints_disabled) { + intprintk(("KGDB: Sending %d to port %x offset %d\n", + gdb_async_info->IER, + (int) gdb_async_info->port, UART_IER)); + outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER); + } + return; +} + +/* + * tty_getDebugChar + * + * This is a GDB stub routine. It waits for a character from the + * serial interface and then returns it. If there is no serial + * interface connection then it returns a bogus value which will + * almost certainly cause the system to hang. In the + */ +int kgdb_in_isr = 0; +int kgdb_in_lsr = 0; +extern spinlock_t kgdb_spinlock; + +/* Caller takes needed protections */ + +int +tty_getDebugChar(void) +{ + volatile int chr, dum, time, end_time; + + dbprintk(("tty_getDebugChar(port %x): ", gdb_async_info->port)); + + if (gdb_async_info == NULL) { + gdb_hook_interrupt(&local_info, 0); + } + /* + * This trick says if we wait a very long time and get + * no char, return the -1 and let the upper level deal + * with it. + */ + rdtsc(dum, time); + end_time = time + 2; + while (((chr = read_char(gdb_async_info)) == -1) && + (end_time - time) > 0) { + rdtsc(dum, time); + }; + /* + * This covers our butts if some other code messes with + * our uart, hay, it happens :o) + */ + if (chr == -1) + program_uart(gdb_async_info); + + dbprintk(("%c\n", chr > ' ' && chr < 0x7F ? chr : ' ')); + return (chr); + +} /* tty_getDebugChar */ + +static int count = 3; +static spinlock_t one_at_atime = SPIN_LOCK_UNLOCKED; + +static int __init +kgdb_enable_ints(void) +{ + if (kgdboe) { + return 0; + } + if (gdb_async_info == NULL) { + gdb_hook_interrupt(&local_info, 1); + } + ok_to_enable_ints = 1; + kgdb_enable_ints_now(); +#ifdef CONFIG_KGDB_USER_CONSOLE + kgdb_console_finit(); +#endif + return 0; +} + +#ifdef CONFIG_SERIAL_8250 +void shutdown_for_kgdb(struct async_struct *gdb_async_info); +#endif + +#ifdef CONFIG_DISCONTIGMEM +static inline int kgdb_mem_init_done(void) +{ + return highmem_start_page != NULL; +} +#else +static inline int kgdb_mem_init_done(void) +{ + return max_mapnr != 0; +} +#endif + +static void +kgdb_enable_ints_now(void) +{ + if (!spin_trylock(&one_at_atime)) + return; + if (!ints_disabled) + goto exit; + if (kgdb_mem_init_done() && + ints_disabled) { /* don't try till mem init */ +#ifdef CONFIG_SERIAL_8250 + /* + * The ifdef here allows the system to be configured + * without the serial driver. + * Don't make it a module, however, it will steal the port + */ + shutdown_for_kgdb(gdb_async_info); +#endif + ints_disabled = request_irq(gdb_async_info->state->irq, + gdb_interrupt, + IRQ_T(gdb_async_info), + "KGDB-stub", NULL); + intprintk(("KGDB: request_irq returned %d\n", ints_disabled)); + } + if (!ints_disabled) { + intprintk(("KGDB: Sending %d to port %x offset %d\n", + gdb_async_info->IER, + (int) gdb_async_info->port, UART_IER)); + outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER); + } + exit: + spin_unlock(&one_at_atime); +} + +/* + * tty_putDebugChar + * + * This is a GDB stub routine. It waits until the interface is ready + * to transmit a char and then sends it. If there is no serial + * interface connection then it simply returns to its caller, having + * pretended to send the char. Caller takes needed protections. + */ +void +tty_putDebugChar(int chr) +{ + dbprintk(("tty_putDebugChar(port %x): chr=%02x '%c', ints_on=%d\n", + gdb_async_info->port, + chr, + chr > ' ' && chr < 0x7F ? chr : ' ', ints_disabled ? 0 : 1)); + + if (gdb_async_info == NULL) { + gdb_hook_interrupt(&local_info, 0); + } + + write_char(gdb_async_info, chr); /* this routine will wait */ + count = (chr == '#') ? 0 : count + 1; + if ((count == 2)) { /* try to enable after */ + if (ints_disabled & ok_to_enable_ints) + kgdb_enable_ints_now(); /* try to enable after */ + + /* We do this a lot because, well we really want to get these + * interrupts. The serial driver will clear these bits when it + * initializes the chip. Every thing else it does is ok, + * but this. + */ + if (!ints_disabled) { + outb_px(gdb_async_info->port + UART_IER, + gdb_async_info->IER); + } + } + +} /* tty_putDebugChar */ + +/* + * This does nothing for the serial port, since it doesn't buffer. + */ + +void tty_flushDebugChar(void) +{ +} + +module_init(kgdb_enable_ints); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/lib/mcount.S 830-ivtv/arch/i386/lib/mcount.S --- 000-virgin/arch/i386/lib/mcount.S Wed Dec 31 16:00:00 1969 +++ 830-ivtv/arch/i386/lib/mcount.S Thu Jan 8 10:21:27 2004 @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2000 SGI + * + * Written by Dimitris Michailidis dimitris@sgi.com + * + * This file implements mcount(), which is used to collect profiling data. + * We provide several variants to accomodate different types of callers at + * the lowest possible overhead. + */ + +#include +#include + +#define MCOUNT_HEAD \ + pushl %ecx /* We must protect the arguments of FASTCALLs */; \ + movl mcount_hook, %ecx; \ + testl %ecx, %ecx; \ + jz 1f; \ + pushl %eax; \ + pushl %edx; \ + movl 12(%esp), %edx /* mcount()'s parent */ + +#define MCOUNT_TAIL \ + call *%ecx; \ + popl %edx; \ + popl %eax; \ +1: popl %ecx + +/* + * This is the main variant and is called by C code. GCC's -pg option + * automatically instruments every C function with a call to this. + */ +ENTRY(mcount) +#if defined(CONFIG_MCOUNT) + MCOUNT_HEAD +#ifdef CONFIG_FRAME_POINTER + movl 4(%ebp), %eax /* mcount()'s parent's parent */ +#endif + MCOUNT_TAIL +#endif + ret diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/lib/usercopy.c 830-ivtv/arch/i386/lib/usercopy.c --- 000-virgin/arch/i386/lib/usercopy.c Thu Jan 8 08:35:21 2004 +++ 830-ivtv/arch/i386/lib/usercopy.c Thu Jan 8 09:30:58 2004 @@ -76,7 +76,7 @@ do { \ * and returns @count. */ long -__strncpy_from_user(char *dst, const char __user *src, long count) +__direct_strncpy_from_user(char *dst, const char __user *src, long count) { long res; __do_strncpy_from_user(dst, src, count, res); @@ -102,7 +102,7 @@ __strncpy_from_user(char *dst, const cha * and returns @count. */ long -strncpy_from_user(char *dst, const char __user *src, long count) +direct_strncpy_from_user(char *dst, const char __user *src, long count) { long res = -EFAULT; if (access_ok(VERIFY_READ, src, 1)) @@ -147,7 +147,7 @@ do { \ * On success, this will be zero. */ unsigned long -clear_user(void __user *to, unsigned long n) +direct_clear_user(void __user *to, unsigned long n) { might_sleep(); if (access_ok(VERIFY_WRITE, to, n)) @@ -167,7 +167,7 @@ clear_user(void __user *to, unsigned lon * On success, this will be zero. */ unsigned long -__clear_user(void __user *to, unsigned long n) +__direct_clear_user(void __user *to, unsigned long n) { __do_clear_user(to, n); return n; @@ -184,7 +184,7 @@ __clear_user(void __user *to, unsigned l * On exception, returns 0. * If the string is too long, returns a value greater than @n. */ -long strnlen_user(const char __user *s, long n) +long direct_strnlen_user(const char __user *s, long n) { unsigned long mask = -__addr_ok(s); unsigned long res, tmp; @@ -575,3 +575,4 @@ unsigned long __copy_from_user_ll(void * n = __copy_user_zeroing_intel(to, (const void *) from, n); return n; } + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/math-emu/fpu_system.h 830-ivtv/arch/i386/math-emu/fpu_system.h --- 000-virgin/arch/i386/math-emu/fpu_system.h Sun Nov 17 20:29:30 2002 +++ 830-ivtv/arch/i386/math-emu/fpu_system.h Thu Jan 8 09:30:58 2004 @@ -15,6 +15,7 @@ #include #include #include +#include /* This sets the pointer FPU_info to point to the argument part of the stack frame of math_emulate() */ @@ -22,7 +23,7 @@ /* s is always from a cpu register, and the cpu does bounds checking * during register load --> no further bounds checks needed */ -#define LDT_DESCRIPTOR(s) (((struct desc_struct *)current->mm->context.ldt)[(s) >> 3]) +#define LDT_DESCRIPTOR(s) (((struct desc_struct *)__kmap_atomic_vaddr(KM_LDT_PAGE0))[(s) >> 3]) #define SEG_D_SIZE(x) ((x).b & (3 << 21)) #define SEG_G_BIT(x) ((x).b & (1 << 23)) #define SEG_GRANULARITY(x) (((x).b & (1 << 23)) ? 4096 : 1) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/mm/extable.c 830-ivtv/arch/i386/mm/extable.c --- 000-virgin/arch/i386/mm/extable.c Mon Jan 13 21:09:20 2003 +++ 830-ivtv/arch/i386/mm/extable.c Thu Jan 8 09:30:58 2004 @@ -6,6 +6,52 @@ #include #include #include +#include + +extern struct exception_table_entry __start___ex_table[]; +extern struct exception_table_entry __stop___ex_table[]; + +/* + * The exception table needs to be sorted because we use the macros + * which put things into the exception table in a variety of sections + * as well as the init section and the main kernel text section. + */ +static inline void +sort_ex_table(struct exception_table_entry *start, + struct exception_table_entry *finish) +{ + struct exception_table_entry el, *p, *q; + + /* insertion sort */ + for (p = start + 1; p < finish; ++p) { + /* start .. p-1 is sorted */ + if (p[0].insn < p[-1].insn) { + /* move element p down to its right place */ + el = *p; + q = p; + do { + /* el comes before q[-1], move q[-1] up one */ + q[0] = q[-1]; + --q; + } while (q > start && el.insn < q[-1].insn); + *q = el; + } + } +} + +void fixup_sort_exception_table(void) +{ + struct exception_table_entry *p; + + /* + * Fix up the trampoline exception addresses: + */ + for (p = __start___ex_table; p < __stop___ex_table; p++) { + p->insn = (unsigned long)(void *)p->insn; + p->fixup = (unsigned long)(void *)p->fixup; + } + sort_ex_table(__start___ex_table, __stop___ex_table); +} /* Simple binary search */ const struct exception_table_entry * @@ -15,13 +61,15 @@ search_extable(const struct exception_ta { while (first <= last) { const struct exception_table_entry *mid; - long diff; mid = (last - first) / 2 + first; - diff = mid->insn - value; - if (diff == 0) + /* + * careful, the distance between entries can be + * larger than 2GB: + */ + if (mid->insn == value) return mid; - else if (diff < 0) + else if (mid->insn < value) first = mid+1; else last = mid-1; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/mm/fault.c 830-ivtv/arch/i386/mm/fault.c --- 000-virgin/arch/i386/mm/fault.c Wed Dec 24 18:16:46 2003 +++ 830-ivtv/arch/i386/mm/fault.c Thu Jan 8 09:30:58 2004 @@ -27,6 +27,7 @@ #include #include #include +#include extern void die(const char *,struct pt_regs *,long); @@ -104,8 +105,17 @@ static inline unsigned long get_segment_ if (seg & (1<<2)) { /* Must lock the LDT while reading it. */ down(¤t->mm->context.sem); +#if 1 + /* horrible hack for 4/4 disabled kernels. + I'm not quite sure what the TLB flush is good for, + it's mindlessly copied from the read_ldt code */ + __flush_tlb_global(); + desc = kmap(current->mm->context.ldt_pages[(seg&~7)/PAGE_SIZE]); + desc = (void *)desc + ((seg & ~7) % PAGE_SIZE); +#else desc = current->mm->context.ldt; desc = (void *)desc + (seg & ~7); +#endif } else { /* Must disable preemption while reading the GDT. */ desc = (u32 *)&cpu_gdt_table[get_cpu()]; @@ -118,6 +128,9 @@ static inline unsigned long get_segment_ (desc[1] & 0xff000000); if (seg & (1<<2)) { +#if 1 + kunmap((void *)((unsigned long)desc & PAGE_MASK)); +#endif up(¤t->mm->context.sem); } else put_cpu(); @@ -243,6 +256,19 @@ asmlinkage void do_page_fault(struct pt_ * (error_code & 4) == 0, and that the fault was not a * protection error (error_code & 1) == 0. */ +#ifdef CONFIG_X86_4G + /* + * On 4/4 all kernels faults are either bugs, vmalloc or prefetch + */ + if (unlikely((regs->xcs & 3) == 0)) { + if (error_code & 3) + goto bad_area_nosemaphore; + + /* If it's vm86 fall through */ + if (!(regs->eflags & VM_MASK)) + goto vmalloc_fault; + } +#else if (unlikely(address >= TASK_SIZE)) { if (!(error_code & 5)) goto vmalloc_fault; @@ -252,6 +278,7 @@ asmlinkage void do_page_fault(struct pt_ */ goto bad_area_nosemaphore; } +#endif mm = tsk->mm; @@ -403,6 +430,12 @@ no_context: * Oops. The kernel tried to access some bad page. We'll have to * terminate things with extreme prejudice. */ +#ifdef CONFIG_KGDB + if (!user_mode(regs)){ + kgdb_handle_exception(14,SIGBUS, error_code, regs); + return; + } +#endif bust_spinlocks(1); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/mm/hugetlbpage.c 830-ivtv/arch/i386/mm/hugetlbpage.c --- 000-virgin/arch/i386/mm/hugetlbpage.c Thu Jan 8 08:35:21 2004 +++ 830-ivtv/arch/i386/mm/hugetlbpage.c Thu Jan 8 10:21:12 2004 @@ -61,6 +61,27 @@ static struct page *alloc_fresh_huge_pag static void free_huge_page(struct page *page); +#ifdef CONFIG_NUMA + +static inline void huge_inc_rss(struct mm_struct *mm, struct page *page) +{ + mm->rss += (HPAGE_SIZE / PAGE_SIZE); + mm->pernode_rss[page_to_nid(page)] += (HPAGE_SIZE / PAGE_SIZE); +} + +static inline void huge_dec_rss(struct mm_struct *mm, struct page *page) +{ + mm->rss -= (HPAGE_SIZE / PAGE_SIZE); + mm->pernode_rss[page_to_nid(page)] -= (HPAGE_SIZE / PAGE_SIZE); +} + +#else /* !CONFIG_NUMA */ + +#define huge_inc_rss(mm, page) ((mm)->rss += (HPAGE_SIZE / PAGE_SIZE)) +#define huge_dec_rss(mm, page) ((mm)->rss -= (HPAGE_SIZE / PAGE_SIZE)) + +#endif /* CONFIG_NUMA */ + static struct page *alloc_hugetlb_page(void) { int i; @@ -105,7 +126,7 @@ static void set_huge_pte(struct mm_struc { pte_t entry; - mm->rss += (HPAGE_SIZE / PAGE_SIZE); + huge_inc_rss(mm, page); if (write_access) { entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))); @@ -145,7 +166,7 @@ int copy_hugetlb_page_range(struct mm_st ptepage = pte_page(entry); get_page(ptepage); set_pte(dst_pte, entry); - dst->rss += (HPAGE_SIZE / PAGE_SIZE); + huge_inc_rss(dst, ptepage); addr += HPAGE_SIZE; } return 0; @@ -314,8 +335,8 @@ void unmap_hugepage_range(struct vm_area page = pte_page(*pte); huge_page_release(page); pte_clear(pte); + huge_dec_rss(mm, page); } - mm->rss -= (end - start) >> PAGE_SHIFT; flush_tlb_range(vma, start, end); } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/mm/init.c 830-ivtv/arch/i386/mm/init.c --- 000-virgin/arch/i386/mm/init.c Thu Jan 8 08:35:21 2004 +++ 830-ivtv/arch/i386/mm/init.c Thu Jan 8 09:30:59 2004 @@ -40,125 +40,13 @@ #include #include #include +#include DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); unsigned long highstart_pfn, highend_pfn; static int do_test_wp_bit(void); -/* - * Creates a middle page table and puts a pointer to it in the - * given global directory entry. This only returns the gd entry - * in non-PAE compilation mode, since the middle layer is folded. - */ -static pmd_t * __init one_md_table_init(pgd_t *pgd) -{ - pmd_t *pmd_table; - -#ifdef CONFIG_X86_PAE - pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); - set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT)); - if (pmd_table != pmd_offset(pgd, 0)) - BUG(); -#else - pmd_table = pmd_offset(pgd, 0); -#endif - - return pmd_table; -} - -/* - * Create a page table and place a pointer to it in a middle page - * directory entry. - */ -static pte_t * __init one_page_table_init(pmd_t *pmd) -{ - if (pmd_none(*pmd)) { - pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); - set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE)); - if (page_table != pte_offset_kernel(pmd, 0)) - BUG(); - - return page_table; - } - - return pte_offset_kernel(pmd, 0); -} - -/* - * This function initializes a certain range of kernel virtual memory - * with new bootmem page tables, everywhere page tables are missing in - * the given range. - */ - -/* - * NOTE: The pagetables are allocated contiguous on the physical space - * so we can cache the place of the first one and move around without - * checking the pgd every time. - */ -static void __init page_table_range_init (unsigned long start, unsigned long end, pgd_t *pgd_base) -{ - pgd_t *pgd; - pmd_t *pmd; - int pgd_idx, pmd_idx; - unsigned long vaddr; - - vaddr = start; - pgd_idx = pgd_index(vaddr); - pmd_idx = pmd_index(vaddr); - pgd = pgd_base + pgd_idx; - - for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd++, pgd_idx++) { - if (pgd_none(*pgd)) - one_md_table_init(pgd); - - pmd = pmd_offset(pgd, vaddr); - for (; (pmd_idx < PTRS_PER_PMD) && (vaddr != end); pmd++, pmd_idx++) { - if (pmd_none(*pmd)) - one_page_table_init(pmd); - - vaddr += PMD_SIZE; - } - pmd_idx = 0; - } -} - -/* - * This maps the physical memory to kernel virtual address space, a total - * of max_low_pfn pages, by creating page tables starting from address - * PAGE_OFFSET. - */ -static void __init kernel_physical_mapping_init(pgd_t *pgd_base) -{ - unsigned long pfn; - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - int pgd_idx, pmd_idx, pte_ofs; - - pgd_idx = pgd_index(PAGE_OFFSET); - pgd = pgd_base + pgd_idx; - pfn = 0; - - for (; pgd_idx < PTRS_PER_PGD; pgd++, pgd_idx++) { - pmd = one_md_table_init(pgd); - if (pfn >= max_low_pfn) - continue; - for (pmd_idx = 0; pmd_idx < PTRS_PER_PMD && pfn < max_low_pfn; pmd++, pmd_idx++) { - /* Map with big pages if possible, otherwise create normal page tables. */ - if (cpu_has_pse) { - set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE)); - pfn += PTRS_PER_PTE; - } else { - pte = one_page_table_init(pmd); - - for (pte_ofs = 0; pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, pte_ofs++) - set_pte(pte, pfn_pte(pfn, PAGE_KERNEL)); - } - } - } -} - static inline int page_kills_ppro(unsigned long pagenr) { if (pagenr >= 0x70000 && pagenr <= 0x7003F) @@ -206,11 +94,8 @@ static inline int page_is_ram(unsigned l return 0; } -#ifdef CONFIG_HIGHMEM pte_t *kmap_pte; -pgprot_t kmap_prot; -EXPORT_SYMBOL(kmap_prot); EXPORT_SYMBOL(kmap_pte); #define kmap_get_fixmap_pte(vaddr) \ @@ -218,29 +103,7 @@ EXPORT_SYMBOL(kmap_pte); void __init kmap_init(void) { - unsigned long kmap_vstart; - - /* cache the first kmap pte */ - kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN); - kmap_pte = kmap_get_fixmap_pte(kmap_vstart); - - kmap_prot = PAGE_KERNEL; -} - -void __init permanent_kmaps_init(pgd_t *pgd_base) -{ - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - unsigned long vaddr; - - vaddr = PKMAP_BASE; - page_table_range_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base); - - pgd = swapper_pg_dir + pgd_index(vaddr); - pmd = pmd_offset(pgd, vaddr); - pte = pte_offset_kernel(pmd, vaddr); - pkmap_page_table = pte; + kmap_pte = kmap_get_fixmap_pte(__fix_to_virt(FIX_KMAP_BEGIN)); } void __init one_highpage_init(struct page *page, int pfn, int bad_ppro) @@ -255,6 +118,8 @@ void __init one_highpage_init(struct pag SetPageReserved(page); } +#ifdef CONFIG_HIGHMEM + #ifndef CONFIG_DISCONTIGMEM void __init set_highmem_pages_init(int bad_ppro) { @@ -266,12 +131,9 @@ void __init set_highmem_pages_init(int b #else extern void set_highmem_pages_init(int); #endif /* !CONFIG_DISCONTIGMEM */ - #else -#define kmap_init() do { } while (0) -#define permanent_kmaps_init(pgd_base) do { } while (0) -#define set_highmem_pages_init(bad_ppro) do { } while (0) -#endif /* CONFIG_HIGHMEM */ +# define set_highmem_pages_init(bad_ppro) do { } while (0) +#endif unsigned long __PAGE_KERNEL = _PAGE_KERNEL; @@ -281,30 +143,125 @@ unsigned long __PAGE_KERNEL = _PAGE_KERN extern void __init remap_numa_kva(void); #endif -static void __init pagetable_init (void) +static __init void prepare_pagetables(pgd_t *pgd_base, unsigned long address) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + pgd = pgd_base + pgd_index(address); + pmd = pmd_offset(pgd, address); + if (!pmd_present(*pmd)) { + pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); + set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))); + } +} + +static void __init fixrange_init (unsigned long start, unsigned long end, pgd_t *pgd_base) { unsigned long vaddr; - pgd_t *pgd_base = swapper_pg_dir; + for (vaddr = start; vaddr != end; vaddr += PAGE_SIZE) + prepare_pagetables(pgd_base, vaddr); +} + +void setup_identity_mappings(pgd_t *pgd_base, unsigned long start, unsigned long end) +{ + unsigned long vaddr; + pgd_t *pgd; + int i, j, k; + pmd_t *pmd; + pte_t *pte, *pte_base; + + pgd = pgd_base; + + for (i = 0; i < PTRS_PER_PGD; pgd++, i++) { + vaddr = i*PGDIR_SIZE; + if (end && (vaddr >= end)) + break; + pmd = pmd_offset(pgd, 0); + for (j = 0; j < PTRS_PER_PMD; pmd++, j++) { + vaddr = i*PGDIR_SIZE + j*PMD_SIZE; + if (end && (vaddr >= end)) + break; + if (vaddr < start) + continue; + if (cpu_has_pse) { + unsigned long __pe; + + set_in_cr4(X86_CR4_PSE); + boot_cpu_data.wp_works_ok = 1; + __pe = _KERNPG_TABLE + _PAGE_PSE + vaddr - start; + /* Make it "global" too if supported */ + if (cpu_has_pge) { + set_in_cr4(X86_CR4_PGE); +#if !defined(CONFIG_X86_SWITCH_PAGETABLES) + __pe += _PAGE_GLOBAL; + __PAGE_KERNEL |= _PAGE_GLOBAL; +#endif + } + set_pmd(pmd, __pmd(__pe)); + continue; + } + if (!pmd_present(*pmd)) + pte_base = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); + else + pte_base = (pte_t *) page_address(pmd_page(*pmd)); + pte = pte_base; + for (k = 0; k < PTRS_PER_PTE; pte++, k++) { + vaddr = i*PGDIR_SIZE + j*PMD_SIZE + k*PAGE_SIZE; + if (end && (vaddr >= end)) + break; + if (vaddr < start) + continue; + *pte = mk_pte_phys(vaddr-start, PAGE_KERNEL); + } + set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte_base))); + } + } +} + +static void __init pagetable_init (void) +{ + unsigned long vaddr, end; + pgd_t *pgd_base; #ifdef CONFIG_X86_PAE int i; - /* Init entries of the first-level page table to the zero page */ - for (i = 0; i < PTRS_PER_PGD; i++) - set_pgd(pgd_base + i, __pgd(__pa(empty_zero_page) | _PAGE_PRESENT)); #endif - /* Enable PSE if available */ - if (cpu_has_pse) { - set_in_cr4(X86_CR4_PSE); - } + /* + * This can be zero as well - no problem, in that case we exit + * the loops anyway due to the PTRS_PER_* conditions. + */ + end = (unsigned long)__va(max_low_pfn*PAGE_SIZE); - /* Enable PGE if available */ - if (cpu_has_pge) { - set_in_cr4(X86_CR4_PGE); - __PAGE_KERNEL |= _PAGE_GLOBAL; + pgd_base = swapper_pg_dir; +#ifdef CONFIG_X86_PAE + /* + * It causes too many problems if there's no proper pmd set up + * for all 4 entries of the PGD - so we allocate all of them. + * PAE systems will not miss this extra 4-8K anyway ... + */ + for (i = 0; i < PTRS_PER_PGD; i++) { + pmd_t *pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); + set_pgd(pgd_base + i, __pgd(__pa(pmd) + 0x1)); } +#endif + /* + * Set up lowmem-sized identity mappings at PAGE_OFFSET: + */ + setup_identity_mappings(pgd_base, PAGE_OFFSET, end); - kernel_physical_mapping_init(pgd_base); + /* + * Add flat-mode identity-mappings - SMP needs it when + * starting up on an AP from real-mode. (In the non-PAE + * case we already have these mappings through head.S.) + * All user-space mappings are explicitly cleared after + * SMP startup. + */ +#if CONFIG_SMP && CONFIG_X86_PAE + setup_identity_mappings(pgd_base, 0, 16*1024*1024); +#endif remap_numa_kva(); /* @@ -312,38 +269,64 @@ static void __init pagetable_init (void) * created - mappings will be set by set_fixmap(): */ vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK; - page_table_range_init(vaddr, 0, pgd_base); + fixrange_init(vaddr, 0, pgd_base); - permanent_kmaps_init(pgd_base); +#if CONFIG_HIGHMEM + { + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; -#ifdef CONFIG_X86_PAE - /* - * Add low memory identity-mappings - SMP needs it when - * starting up on an AP from real-mode. In the non-PAE - * case we already have these mappings through head.S. - * All user-space mappings are explicitly cleared after - * SMP startup. - */ - pgd_base[0] = pgd_base[USER_PTRS_PER_PGD]; + /* + * Permanent kmaps: + */ + vaddr = PKMAP_BASE; + fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base); + + pgd = swapper_pg_dir + pgd_index(vaddr); + pmd = pmd_offset(pgd, vaddr); + pte = pte_offset_kernel(pmd, vaddr); + pkmap_page_table = pte; + } #endif } -void zap_low_mappings (void) +/* + * Clear kernel pagetables in a PMD_SIZE-aligned range. + */ +static void clear_mappings(pgd_t *pgd_base, unsigned long start, unsigned long end) { - int i; + unsigned long vaddr; + pgd_t *pgd; + pmd_t *pmd; + int i, j; + + pgd = pgd_base; + + for (i = 0; i < PTRS_PER_PGD; pgd++, i++) { + vaddr = i*PGDIR_SIZE; + if (end && (vaddr >= end)) + break; + pmd = pmd_offset(pgd, 0); + for (j = 0; j < PTRS_PER_PMD; pmd++, j++) { + vaddr = i*PGDIR_SIZE + j*PMD_SIZE; + if (end && (vaddr >= end)) + break; + if (vaddr < start) + continue; + pmd_clear(pmd); + } + } + flush_tlb_all(); +} + +void __init zap_low_mappings(void) +{ + printk("zapping low mappings.\n"); /* * Zap initial low-memory mappings. - * - * Note that "pgd_clear()" doesn't do it for - * us, because pgd_clear() is a no-op on i386. */ - for (i = 0; i < USER_PTRS_PER_PGD; i++) -#ifdef CONFIG_X86_PAE - set_pgd(swapper_pg_dir+i, __pgd(1 + __pa(empty_zero_page))); -#else - set_pgd(swapper_pg_dir+i, __pgd(0)); -#endif - flush_tlb_all(); + clear_mappings(swapper_pg_dir, 0, 16*1024*1024); } #ifndef CONFIG_DISCONTIGMEM @@ -441,6 +424,7 @@ extern void set_max_mapnr_init(void); #endif /* !CONFIG_DISCONTIGMEM */ static struct kcore_list kcore_mem, kcore_vmalloc; +extern void fixup_sort_exception_table(void); void __init mem_init(void) { @@ -449,6 +433,8 @@ void __init mem_init(void) int tmp; int bad_ppro; + fixup_sort_exception_table(); + #ifndef CONFIG_DISCONTIGMEM if (!mem_map) BUG(); @@ -524,13 +510,18 @@ void __init mem_init(void) #ifndef CONFIG_SMP zap_low_mappings(); #endif + entry_trampoline_setup(); + default_ldt_page = virt_to_page(default_ldt); + load_LDT(&init_mm.context); } -kmem_cache_t *pgd_cache; -kmem_cache_t *pmd_cache; +kmem_cache_t *pgd_cache, *pmd_cache, *kpmd_cache; void __init pgtable_cache_init(void) { + void (*ctor)(void *, kmem_cache_t *, unsigned long); + void (*dtor)(void *, kmem_cache_t *, unsigned long); + if (PTRS_PER_PMD > 1) { pmd_cache = kmem_cache_create("pmd", PTRS_PER_PMD*sizeof(pmd_t), @@ -540,13 +531,36 @@ void __init pgtable_cache_init(void) NULL); if (!pmd_cache) panic("pgtable_cache_init(): cannot create pmd cache"); + + if (TASK_SIZE > PAGE_OFFSET) { + kpmd_cache = kmem_cache_create("kpmd", + PTRS_PER_PMD*sizeof(pmd_t), + 0, + SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN, + kpmd_ctor, + NULL); + if (!kpmd_cache) + panic("pgtable_cache_init(): " + "cannot create kpmd cache"); + } } + + if (PTRS_PER_PMD == 1 || TASK_SIZE <= PAGE_OFFSET) + ctor = pgd_ctor; + else + ctor = NULL; + + if (PTRS_PER_PMD == 1 && TASK_SIZE <= PAGE_OFFSET) + dtor = pgd_dtor; + else + dtor = NULL; + pgd_cache = kmem_cache_create("pgd", PTRS_PER_PGD*sizeof(pgd_t), 0, SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN, - pgd_ctor, - PTRS_PER_PMD == 1 ? pgd_dtor : NULL); + ctor, + dtor); if (!pgd_cache) panic("pgtable_cache_init(): Cannot create pgd cache"); } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/i386/mm/pgtable.c 830-ivtv/arch/i386/mm/pgtable.c --- 000-virgin/arch/i386/mm/pgtable.c Wed Aug 13 20:24:18 2003 +++ 830-ivtv/arch/i386/mm/pgtable.c Thu Jan 8 10:22:24 2004 @@ -21,6 +21,7 @@ #include #include #include +#include void show_mem(void) { @@ -157,11 +158,20 @@ void pmd_ctor(void *pmd, kmem_cache_t *c memset(pmd, 0, PTRS_PER_PMD*sizeof(pmd_t)); } +void kpmd_ctor(void *__pmd, kmem_cache_t *cache, unsigned long flags) +{ + pmd_t *kpmd, *pmd; + kpmd = pmd_offset(&swapper_pg_dir[PTRS_PER_PGD-1], + (PTRS_PER_PMD - NR_SHARED_PMDS)*PMD_SIZE); + pmd = (pmd_t *)__pmd + (PTRS_PER_PMD - NR_SHARED_PMDS); + + memset(__pmd, 0, (PTRS_PER_PMD - NR_SHARED_PMDS)*sizeof(pmd_t)); + memcpy(pmd, kpmd, NR_SHARED_PMDS*sizeof(pmd_t)); +} + /* - * List of all pgd's needed for non-PAE so it can invalidate entries - * in both cached and uncached pgd's; not needed for PAE since the - * kernel pmd is shared. If PAE were not to share the pmd a similar - * tactic would be needed. This is essentially codepath-based locking + * List of all pgd's needed so it can invalidate entries in both cached + * and uncached pgd's. This is essentially codepath-based locking * against pageattr.c; it is the unique case in which a valid change * of kernel pagetables can't be lazily synchronized by vmalloc faults. * vmalloc faults work because attached pagetables are never freed. @@ -170,30 +180,60 @@ void pmd_ctor(void *pmd, kmem_cache_t *c * could be used. The locking scheme was chosen on the basis of * manfred's recommendations and having no core impact whatsoever. * -- wli + * + * The entire issue goes away when XKVA is configured. */ spinlock_t pgd_lock = SPIN_LOCK_UNLOCKED; LIST_HEAD(pgd_list); -void pgd_ctor(void *pgd, kmem_cache_t *cache, unsigned long unused) +/* + * This is not that hard to figure out. + * (a) PTRS_PER_PMD == 1 means non-PAE. + * (b) PTRS_PER_PMD > 1 means PAE. + * (c) TASK_SIZE > PAGE_OFFSET means XKVA. + * (d) TASK_SIZE <= PAGE_OFFSET means non-XKVA. + * + * Do *NOT* back out the preconstruction like the patch I'm cleaning + * up after this very instant did, or at all, for that matter. + * This is never called when PTRS_PER_PMD > 1 && TASK_SIZE > PAGE_OFFSET. + * -- wli + */ +void pgd_ctor(void *__pgd, kmem_cache_t *cache, unsigned long unused) { + pgd_t *pgd = (pgd_t *)__pgd; unsigned long flags; - if (PTRS_PER_PMD == 1) - spin_lock_irqsave(&pgd_lock, flags); + if (PTRS_PER_PMD == 1) { + if (TASK_SIZE <= PAGE_OFFSET) + spin_lock_irqsave(&pgd_lock, flags); + else + memcpy(&pgd[PTRS_PER_PGD - NR_SHARED_PMDS], + &swapper_pg_dir[PTRS_PER_PGD - NR_SHARED_PMDS], + NR_SHARED_PMDS * sizeof(pgd_t)); + } - memcpy((pgd_t *)pgd + USER_PTRS_PER_PGD, - swapper_pg_dir + USER_PTRS_PER_PGD, - (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); + if (TASK_SIZE <= PAGE_OFFSET) + memcpy(pgd + USER_PTRS_PER_PGD, + swapper_pg_dir + USER_PTRS_PER_PGD, + (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); if (PTRS_PER_PMD > 1) return; - list_add(&virt_to_page(pgd)->lru, &pgd_list); - spin_unlock_irqrestore(&pgd_lock, flags); - memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t)); + if (TASK_SIZE > PAGE_OFFSET) + memset(pgd, 0, (PTRS_PER_PGD - NR_SHARED_PMDS)*sizeof(pgd_t)); + else { + list_add(&virt_to_page(pgd)->lru, &pgd_list); + spin_unlock_irqrestore(&pgd_lock, flags); + memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t)); + } } -/* never called when PTRS_PER_PMD > 1 */ +/* + * Never called when PTRS_PER_PMD > 1 || TASK_SIZE > PAGE_OFFSET + * for with PAE we would list_del() multiple times, and for non-PAE + * with XKVA all the AGP pgd shootdown code is unnecessary. + */ void pgd_dtor(void *pgd, kmem_cache_t *cache, unsigned long unused) { unsigned long flags; /* can be called from interrupt context */ @@ -203,6 +243,12 @@ void pgd_dtor(void *pgd, kmem_cache_t *c spin_unlock_irqrestore(&pgd_lock, flags); } +/* + * See the comments above pgd_ctor() wrt. preconstruction. + * Do *NOT* memcpy() here. If you do, you back out important + * anti- cache pollution code. + * + */ pgd_t *pgd_alloc(struct mm_struct *mm) { int i; @@ -211,15 +257,33 @@ pgd_t *pgd_alloc(struct mm_struct *mm) if (PTRS_PER_PMD == 1 || !pgd) return pgd; + /* + * In the 4G userspace case alias the top 16 MB virtual + * memory range into the user mappings as well (these + * include the trampoline and CPU data structures). + */ for (i = 0; i < USER_PTRS_PER_PGD; ++i) { - pmd_t *pmd = kmem_cache_alloc(pmd_cache, GFP_KERNEL); + kmem_cache_t *cache; + pmd_t *pmd; + + if (TASK_SIZE > PAGE_OFFSET && i == USER_PTRS_PER_PGD - 1) + cache = kpmd_cache; + else + cache = pmd_cache; + + pmd = kmem_cache_alloc(cache, GFP_KERNEL); if (!pmd) goto out_oom; set_pgd(&pgd[i], __pgd(1 + __pa((u64)((u32)pmd)))); } - return pgd; + return pgd; out_oom: + /* + * we don't have to handle the kpmd_cache here, since it's the + * last allocation, and has either nothing to free or when it + * succeeds the whole operation succeeds. + */ for (i--; i >= 0; i--) kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1)); kmem_cache_free(pgd_cache, pgd); @@ -230,10 +294,85 @@ void pgd_free(pgd_t *pgd) { int i; - /* in the PAE case user pgd entries are overwritten before usage */ - if (PTRS_PER_PMD > 1) - for (i = 0; i < USER_PTRS_PER_PGD; ++i) - kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1)); /* in the non-PAE case, clear_page_tables() clears user pgd entries */ + if (PTRS_PER_PMD == 1) + goto out_free; + + /* in the PAE case user pgd entries are overwritten before usage */ + for (i = 0; i < USER_PTRS_PER_PGD; ++i) { + kmem_cache_t *cache; + pmd_t *pmd = __va(pgd_val(pgd[i]) - 1); + + /* + * only userspace pmd's are cleared for us + * by mm/memory.c; it's a slab cache invariant + * that we must separate the kernel pmd slab + * all times, else we'll have bad pmd's. + */ + if (TASK_SIZE > PAGE_OFFSET && i == USER_PTRS_PER_PGD - 1) + cache = kpmd_cache; + else + cache = pmd_cache; + + kmem_cache_free(cache, pmd); + } +out_free: kmem_cache_free(pgd_cache, pgd); +} + +#define GLIBC_BUFFER (32*1024*1024) + +/* + * This is total crap; it needs to use the free area cache to mitigate + * catastrophic O(n) search with many vmas. + */ +unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, + unsigned long len, unsigned long pgoff, + unsigned long flags) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma, *prev; + + len = PAGE_ALIGN(len); + addr = PAGE_ALIGN(addr); + + if (len > TASK_SIZE) + return -ENOMEM; + + if (addr) { + struct vm_area_struct *vma; + vma = find_vma(mm, addr); + if (TASK_SIZE - len >= addr && + (!vma || addr + len <= vma->vm_start)) + goto out; + } + + if (!mm->mmap) { + if (len > TASK_SIZE - GLIBC_BUFFER) + addr = TASK_SIZE - len; + else + addr = TASK_SIZE - GLIBC_BUFFER - len; + goto out; + } + + addr = -ENOMEM; + for (prev = NULL, vma = mm->mmap; vma; prev = vma, vma = vma->vm_next) { + unsigned long lo, hi; + lo = prev ? prev->vm_end : 0; + hi = vma->vm_start; + if (hi - lo >= len && (addr == -ENOMEM || addr < hi - len)) + addr = hi - len; + } + /* + * We're at the last one; let's try the top, but only if nothing + * else can be found (to respect GLIBC_BUFFER). + */ + if (prev && TASK_SIZE - prev->vm_end >= len) { + if (TASK_SIZE - GLIBC_BUFFER - prev->vm_end >= len) + addr = TASK_SIZE - GLIBC_BUFFER - len; + else if (addr == -ENOMEM) + addr = TASK_SIZE - len; + } +out: + return addr; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/ia64/Kconfig 830-ivtv/arch/ia64/Kconfig --- 000-virgin/arch/ia64/Kconfig Thu Jan 8 08:35:21 2004 +++ 830-ivtv/arch/ia64/Kconfig Thu Jan 8 10:26:35 2004 @@ -667,6 +667,14 @@ config DEBUG_INFO Say Y here only if you plan to use gdb to debug the kernel. If you don't debug the kernel, you can say N. +config LOCKMETER + bool "Kernel lock metering" + depends on SMP + help + Say Y to enable kernel lock metering, which adds overhead to SMP + locks, but allows you to see various statistics using the + lockstat command. + endmenu source "security/Kconfig" diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/ppc/Kconfig 830-ivtv/arch/ppc/Kconfig --- 000-virgin/arch/ppc/Kconfig Mon Nov 17 18:29:23 2003 +++ 830-ivtv/arch/ppc/Kconfig Thu Jan 8 10:21:36 2004 @@ -1288,6 +1288,36 @@ source "drivers/usb/Kconfig" source "lib/Kconfig" +menu "GCOV coverage profiling" + +config GCOV_PROFILE + bool "GCOV coverage profiling" + ---help--- + Provide infrastructure for coverage support for the kernel. This + will not compile the kernel by default with the necessary flags. + To obtain coverage information for the entire kernel, one should + enable the subsequent option (Profile entire kernel). If only + particular files or directories of the kernel are desired, then + one must provide the following compile options for such targets: + "-fprofile-arcs -ftest-coverage" in the CFLAGS. To obtain + access to the coverage data one must insmod the gcov-prof kernel + module. + +config GCOV_ALL + bool "GCOV_ALL" + depends on GCOV_PROFILE + ---help--- + If you say Y here, it will compile the entire kernel with coverage + option enabled. + +config GCOV_PROC + tristate "gcov-proc module" + depends on GCOV_PROFILE && PROC_FS + ---help--- + This is the gcov-proc module that exposes gcov data through the + /proc filesystem + +endmenu menu "Kernel hacking" @@ -1394,6 +1424,19 @@ config DEBUG_INFO debug the kernel. If you don't debug the kernel, you can say N. +config SCHEDSTATS + bool "Collect scheduler statistics" + depends on PROC_FS + default y + help + If you say Y here, additional code will be inserted into the + scheduler and related routines to collect statistics about + scheduler behavior and provide them in /proc/schedstat. These + stats may be useful for both tuning and debugging the scheduler + If you aren't debugging the scheduler or trying to tune a specific + application, you can say N to avoid the very slight overhead + this adds. + config BOOTX_TEXT bool "Support for early boot text console (BootX or OpenFirmware only)" depends PPC_OF diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/ppc/boot/openfirmware/common.c 830-ivtv/arch/ppc/boot/openfirmware/common.c --- 000-virgin/arch/ppc/boot/openfirmware/common.c Sun Nov 17 20:29:52 2002 +++ 830-ivtv/arch/ppc/boot/openfirmware/common.c Thu Jan 8 10:21:17 2004 @@ -30,6 +30,10 @@ struct memchunk { static struct memchunk *freechunks; +#ifdef CONFIG_GCOV_PROFILE +void __bb_init_func (void *ptr /* struct bb *blocks */) { } +#endif + static void *zalloc(void *x, unsigned items, unsigned size) { void *p; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/ppc/boot/prep/misc.c 830-ivtv/arch/ppc/boot/prep/misc.c --- 000-virgin/arch/ppc/boot/prep/misc.c Thu Jan 9 19:15:57 2003 +++ 830-ivtv/arch/ppc/boot/prep/misc.c Thu Jan 8 10:21:17 2004 @@ -71,6 +71,10 @@ extern unsigned long serial_init(int cha extern void serial_fixups(void); extern unsigned long get_mem_size(void); +#ifdef CONFIG_GCOV_PROFILE +void __bb_init_func (void *ptr /* struct bb *blocks */) { } +#endif + void writel(unsigned int val, unsigned int address) { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/ppc/kernel/Makefile 830-ivtv/arch/ppc/kernel/Makefile --- 000-virgin/arch/ppc/kernel/Makefile Mon Nov 17 18:28:37 2003 +++ 830-ivtv/arch/ppc/kernel/Makefile Thu Jan 8 10:21:17 2004 @@ -18,8 +18,8 @@ extra-$(CONFIG_6xx) += idle_6xx.o extra-$(CONFIG_POWER4) += idle_power4.o extra-y += vmlinux.lds.s -obj-y := entry.o traps.o irq.o idle.o time.o misc.o \ - process.o signal.o ptrace.o align.o \ +obj-y := entry.o ptrace.o traps.o irq.o idle.o time.o misc.o \ + process.o signal.o align.o \ semaphore.o syscalls.o setup.o \ cputable.o ppc_htab.o obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/ppc/kernel/entry.S 830-ivtv/arch/ppc/kernel/entry.S --- 000-virgin/arch/ppc/kernel/entry.S Mon Dec 8 09:55:51 2003 +++ 830-ivtv/arch/ppc/kernel/entry.S Thu Jan 8 10:21:17 2004 @@ -106,10 +106,26 @@ transfer_to_handler: mfspr r11,SPRN_HID0 mtcr r11 BEGIN_FTR_SECTION +#ifdef CONFIG_GCOV_PROFILE + bt- 8,near1_power_save_6xx_restore /* Check DOZE */ + b skip1_power_save_6xx_restore +near1_power_save_6xx_restore: + b power_save_6xx_restore +skip1_power_save_6xx_restore: +#else bt- 8,power_save_6xx_restore /* Check DOZE */ +#endif END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE) BEGIN_FTR_SECTION +#ifdef CONFIG_GCOV_PROFILE + bt- 9,near2_power_save_6xx_restore /* Check NAP */ + b skip2_power_save_6xx_restore +near2_power_save_6xx_restore: + b power_save_6xx_restore +skip2_power_save_6xx_restore: +#else bt- 9,power_save_6xx_restore /* Check NAP */ +#endif END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP) #endif /* CONFIG_6xx */ .globl transfer_to_handler_cont diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/ppc/kernel/head.S 830-ivtv/arch/ppc/kernel/head.S --- 000-virgin/arch/ppc/kernel/head.S Mon Nov 17 18:29:41 2003 +++ 830-ivtv/arch/ppc/kernel/head.S Thu Jan 8 10:21:17 2004 @@ -1755,3 +1755,25 @@ intercept_table: */ abatron_pteptrs: .space 8 + +#ifdef CONFIG_GCOV_PROFILE +/* + * The .ctors-section contains a list of pointers to constructor + * functions which are used to initialize gcov structures. + * + * Because there is no NULL at the end of the constructor list + * in the kernel we need the addresses of both the constructor + * as well as the destructor list which are supposed to be + * adjacent. + */ + +.section ".ctors","aw" +.globl __CTOR_LIST__ +.type __CTOR_LIST__,@object +__CTOR_LIST__: +.section ".dtors","aw" +.globl __DTOR_LIST__ +.type __DTOR_LIST__,@object +__DTOR_LIST__: +#endif + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/ppc/syslib/prom_init.c 830-ivtv/arch/ppc/syslib/prom_init.c --- 000-virgin/arch/ppc/syslib/prom_init.c Mon Nov 17 18:28:40 2003 +++ 830-ivtv/arch/ppc/syslib/prom_init.c Thu Jan 8 10:21:17 2004 @@ -737,7 +737,11 @@ prom_instantiate_rtas(void) * Actually OF has bugs so we just arbitrarily * use memory at the 6MB point. */ +#ifdef CONFIG_GCOV_PROFILE + rtas_data = 0x990000; +#else rtas_data = 6 << 20; +#endif prom_print(" at "); prom_print_hex(rtas_data); } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/ppc64/Kconfig 830-ivtv/arch/ppc64/Kconfig --- 000-virgin/arch/ppc64/Kconfig Mon Nov 17 18:28:40 2003 +++ 830-ivtv/arch/ppc64/Kconfig Thu Jan 8 10:21:36 2004 @@ -323,6 +323,37 @@ config VIOPATH source "arch/ppc64/oprofile/Kconfig" +menu "GCOV coverage profiling" + +config GCOV_PROFILE + bool "GCOV coverage profiling" + ---help--- + Provide infrastructure for coverage support for the kernel. This + will not compile the kernel by default with the necessary flags. + To obtain coverage information for the entire kernel, one should + enable the subsequent option (Profile entire kernel). If only + particular files or directories of the kernel are desired, then + one must provide the following compile options for such targets: + "-fprofile-arcs -ftest-coverage" in the CFLAGS. To obtain + access to the coverage data one must insmod the gcov-prof kernel + module. + +config GCOV_ALL + bool "GCOV_ALL" + depends on GCOV_PROFILE + ---help--- + If you say Y here, it will compile the entire kernel with coverage + option enabled. + +config GCOV_PROC + tristate "gcov-proc module" + depends on GCOV_PROFILE && PROC_FS + ---help--- + This is the gcov-proc module that exposes gcov data through the + /proc filesystem + +endmenu + menu "Kernel hacking" config DEBUG_KERNEL @@ -376,7 +407,28 @@ config DEBUG_INFO debugging info resulting in a larger kernel image. Say Y here only if you plan to use gdb to debug the kernel. If you don't debug the kernel, you can say N. + +config SCHEDSTATS + bool "Collect scheduler statistics" + depends on PROC_FS + default y + help + If you say Y here, additional code will be inserted into the + scheduler and related routines to collect statistics about + scheduler behavior and provide them in /proc/schedstat. These + stats may be useful for both tuning and debugging the scheduler + If you aren't debugging the scheduler or trying to tune a specific + application, you can say N to avoid the very slight overhead + this adds. +config MCOUNT + bool "Generate function call graph" + depends on DEBUG_KERNEL + help + This option instruments the kernel to generate a deterministic + function call graph. Answering Y here will make your kernel run + 1-2% slower. + endmenu source "security/Kconfig" diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/ppc64/kernel/Makefile 830-ivtv/arch/ppc64/kernel/Makefile --- 000-virgin/arch/ppc64/kernel/Makefile Tue Sep 2 09:55:43 2003 +++ 830-ivtv/arch/ppc64/kernel/Makefile Thu Jan 8 10:21:27 2004 @@ -5,6 +5,17 @@ EXTRA_CFLAGS += -mno-minimal-toc extra-y := head.o vmlinux.lds.s +ifeq ($(CONFIG_MCOUNT),y) +quiet_cmd_nopg = CC $@ + cmd_nopg = $(CC) $(subst -pg,,$(CFLAGS)) -c $(src)/$(*F).c -o $@ + +$(obj)/stab.o: alwayscc + $(call cmd,nopg) + +alwayscc: + $(Q)rm -f $(obj)/stab.o +endif + obj-y := setup.o entry.o traps.o irq.o idle.o \ time.o process.o signal.o syscalls.o misc.o ptrace.o \ align.o semaphore.o bitops.o stab.o htab.o pacaData.o \ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/ppc64/kernel/head.S 830-ivtv/arch/ppc64/kernel/head.S --- 000-virgin/arch/ppc64/kernel/head.S Mon Nov 17 18:29:41 2003 +++ 830-ivtv/arch/ppc64/kernel/head.S Thu Jan 8 10:21:18 2004 @@ -1924,3 +1924,24 @@ stab_array: .globl cmd_line cmd_line: .space 512 + +#ifdef CONFIG_GCOV_PROFILE +/* + * The .ctors-section contains a list of pointers to constructor + * functions which are used to initialize gcov structures. + * + * Because there is no NULL at the end of the constructor list + * in the kernel we need the addresses of both the constructor + * as well as the destructor list which are supposed to be + * adjacent. + */ + +.section ".ctors","aw" +.globl __CTOR_LIST__ +.type __CTOR_LIST__,@object +__CTOR_LIST__: +.section ".dtors","aw" +.globl __DTOR_LIST__ +.type __DTOR_LIST__,@object +__DTOR_LIST__: +#endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/ppc64/kernel/irq.c 830-ivtv/arch/ppc64/kernel/irq.c --- 000-virgin/arch/ppc64/kernel/irq.c Thu Jan 8 08:35:25 2004 +++ 830-ivtv/arch/ppc64/kernel/irq.c Thu Jan 8 09:30:44 2004 @@ -300,7 +300,7 @@ void enable_irq(unsigned int irq) spin_lock_irqsave(&desc->lock, flags); switch (desc->depth) { case 1: { - unsigned int status = desc->status & ~(IRQ_DISABLED | IRQ_INPROGRESS); + unsigned int status = desc->status & ~IRQ_DISABLED; desc->status = status; if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { desc->status = status | IRQ_REPLAY; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/ppc64/kernel/misc.S 830-ivtv/arch/ppc64/kernel/misc.S --- 000-virgin/arch/ppc64/kernel/misc.S Mon Nov 17 18:29:41 2003 +++ 830-ivtv/arch/ppc64/kernel/misc.S Thu Jan 8 09:30:38 2004 @@ -843,15 +843,15 @@ _GLOBAL(sys_call_table32) .llong .sys_ni_syscall .llong .sys_ni_syscall .llong .sys_ni_syscall - .llong .sys_ni_syscall /* 245 */ - .llong .sys_ni_syscall - .llong .sys_ni_syscall - .llong .sys_ni_syscall - .llong .sys_ni_syscall + .llong .compat_clock_settime /* 245 */ + .llong .compat_clock_gettime + .llong .compat_clock_getres + .llong .compat_clock_nanosleep + .llong .sys_ni_syscall /* 249 swapcontext */ .llong .sys32_tgkill /* 250 */ .llong .sys32_utimes - .llong .sys_statfs64 - .llong .sys_fstatfs64 + .llong .compat_statfs64 + .llong .compat_fstatfs64 .balign 8 _GLOBAL(sys_call_table) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/ppc64/kernel/time.c 830-ivtv/arch/ppc64/kernel/time.c --- 000-virgin/arch/ppc64/kernel/time.c Mon Nov 17 18:29:23 2003 +++ 830-ivtv/arch/ppc64/kernel/time.c Thu Jan 8 09:30:33 2004 @@ -91,6 +91,9 @@ unsigned tb_to_us; unsigned long processor_freq; spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; +unsigned long tb_to_ns_scale; +unsigned long tb_to_ns_shift; + struct gettimeofday_struct do_gtod; extern unsigned long wall_jiffies; @@ -313,11 +316,13 @@ int timer_interrupt(struct pt_regs * reg /* * Scheduler clock - returns current time in nanosec units. * - * This is wrong, but my CPUs run at 1GHz, so nyer nyer. + * Note: mulhdu(a, b) (multiply high double unsigned) returns + * the high 64 bits of a * b, i.e. (a * b) >> 64, where a and b + * are 64-bit unsigned numbers. */ unsigned long long sched_clock(void) { - return get_tb(); + return mulhdu(get_tb(), tb_to_ns_scale) << tb_to_ns_shift; } /* @@ -473,8 +478,29 @@ void __init time_init(void) /* This function is only called on the boot processor */ unsigned long flags; struct rtc_time tm; + struct div_result res; + unsigned long scale, shift; ppc_md.calibrate_decr(); + + /* + * Compute scale factor for sched_clock. + * The calibrate_decr() function has set tb_ticks_per_sec, + * which is the timebase frequency. + * We compute 1e9 * 2^64 / tb_ticks_per_sec and interpret + * the 128-bit result as a 64.64 fixed-point number. + * We then shift that number right until it is less than 1.0, + * giving us the scale factor and shift count to use in + * sched_clock(). + */ + div128_by_32(1000000000, 0, tb_ticks_per_sec, &res); + scale = res.result_low; + for (shift = 0; res.result_high != 0; ++shift) { + scale = (scale >> 1) | (res.result_high << 63); + res.result_high >>= 1; + } + tb_to_ns_scale = scale; + tb_to_ns_shift = shift; #ifdef CONFIG_PPC_ISERIES if (!piranha_simulator) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/ppc64/lib/Makefile 830-ivtv/arch/ppc64/lib/Makefile --- 000-virgin/arch/ppc64/lib/Makefile Sat Jun 14 18:37:25 2003 +++ 830-ivtv/arch/ppc64/lib/Makefile Thu Jan 8 10:21:27 2004 @@ -4,3 +4,4 @@ lib-y := checksum.o dec_and_lock.o string.o strcase.o lib-y += copypage.o memcpy.o copyuser.o +lib-$(CONFIG_MCOUNT) += mcount.o diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/ppc64/lib/mcount.S 830-ivtv/arch/ppc64/lib/mcount.S --- 000-virgin/arch/ppc64/lib/mcount.S Wed Dec 31 16:00:00 1969 +++ 830-ivtv/arch/ppc64/lib/mcount.S Thu Jan 8 10:21:27 2004 @@ -0,0 +1,61 @@ +/* + * Written by Adam Litke (agl@us.ibm.com) + * + * This file implements mcount(), which is used to collect profiling data. + * + */ + +#include +#include +#include + +/* + * This is called by C code in all files compiled with -pg + */ + +_GLOBAL(_mcount) + /* Store parameter regs on stack */ + std r3, -16(r1) + std r4, -24(r1) + std r5, -32(r1) + std r6, -40(r1) + std r7, -48(r1) + std r8, -56(r1) + std r9, -64(r1) + std r10, -72(r1) + + /* Set up new stack frame */ + mflr r0 + std r0, 16(r1) + mfcr r0 + std r0, 8(r1) + stdu r1, -184(r1) + + /* If relocation is off skip mcount_entry */ + std r14, -8(r1) + mfmsr r14 + andi. r14, r14, MSR_IR + cmpldi r14, 0 + ld r14, -8(r1) + beq 1f + + /* Call mcount_entry */ + bl .mcount_entry + ori 0,0,0 + +1: + /* Put everything back */ + addi r1, r1, 184 + ld r0, 16(r1) + mtlr r0 + ld r0, 8(r1) + mtcr r0 + ld r3, -16(r1) + ld r4, -24(r1) + ld r5, -32(r1) + ld r6, -40(r1) + ld r7, -48(r1) + ld r8, -56(r1) + ld r9, -64(r1) + ld r10, -72(r1) + blr diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/ppc64/mm/numa.c 830-ivtv/arch/ppc64/mm/numa.c --- 000-virgin/arch/ppc64/mm/numa.c Mon Nov 17 18:29:41 2003 +++ 830-ivtv/arch/ppc64/mm/numa.c Thu Jan 8 09:30:41 2004 @@ -108,7 +108,7 @@ static int __init parse_numa_properties( for (memory = find_type_devices("memory"); memory; memory = memory->next) { - int *tmp1, *tmp2; + unsigned int *tmp1, *tmp2; unsigned long i; unsigned long start = 0; unsigned long size = 0; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/sparc64/Kconfig 830-ivtv/arch/sparc64/Kconfig --- 000-virgin/arch/sparc64/Kconfig Thu Jan 8 08:35:27 2004 +++ 830-ivtv/arch/sparc64/Kconfig Thu Jan 8 09:30:50 2004 @@ -710,12 +710,19 @@ config STACK_DEBUG depends on DEBUG_KERNEL bool "Stack Overflow Detection Support" +config LOCKMETER + bool "Kernel lock metering" + depends on SMP && !PREEMPT + help + Say Y to enable kernel lock metering, which adds overhead to SMP locks, + but allows you to see various statistics using the lockstat command. + # We have a custom atomic_dec_and_lock() implementation but it's not # compatible with spinlock debugging so we need to fall back on # the generic version in that case. config HAVE_DEC_LOCK bool - depends on SMP && !DEBUG_SPINLOCK + depends on SMP && !DEBUG_SPINLOCK && !LOCKMETER default y config MCOUNT diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/sparc64/lib/rwlock.S 830-ivtv/arch/sparc64/lib/rwlock.S --- 000-virgin/arch/sparc64/lib/rwlock.S Mon Dec 8 09:55:51 2003 +++ 830-ivtv/arch/sparc64/lib/rwlock.S Thu Jan 8 09:30:50 2004 @@ -85,5 +85,20 @@ __write_trylock_succeed: __write_trylock_fail: retl mov 0, %o0 + + .globl __read_trylock +__read_trylock: /* %o0 = lock_ptr */ + ldsw [%o0], %g5 + brlz,pn %g5, 100f + add %g5, 1, %g7 + cas [%o0], %g5, %g7 + cmp %g5, %g7 + bne,pn %icc, __read_trylock + membar #StoreLoad | #StoreStore + retl + mov 1, %o0 +100: retl + mov 0, %o0 + rwlock_impl_end: diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/x86_64/Kconfig 830-ivtv/arch/x86_64/Kconfig --- 000-virgin/arch/x86_64/Kconfig Thu Jan 8 08:35:27 2004 +++ 830-ivtv/arch/x86_64/Kconfig Thu Jan 8 10:21:36 2004 @@ -68,6 +68,9 @@ config HPET_TIMER If unsure, say Y. +config HPET_EMULATE_RTC + def_bool HPET_TIMER && RTC=y + config GENERIC_ISA_DMA bool default y @@ -335,6 +338,26 @@ config PCI_DIRECT # the drivers/pci/msi.c code needs to be fixed first before enabling config PCI_USE_VECTOR + bool "Vector-based interrupt indexing" + depends on X86_LOCAL_APIC && NOTWORKING + default n + help + This replaces the current existing IRQ-based index interrupt scheme + with the vector-base index scheme. The advantages of vector base + over IRQ base are listed below: + 1) Support MSI implementation. + 2) Support future IOxAPIC hotplug + + Note that this enables MSI, Message Signaled Interrupt, on all + MSI capable device functions detected if users also install the + MSI patch. Message Signal Interrupt enables an MSI-capable + hardware device to send an inbound Memory Write on its PCI bus + instead of asserting IRQ signal on device IRQ pin. + + If you don't know what to do here, say N. + +# the drivers/pci/msi.c code needs to be fixed first before enabling +config PCI_USE_VECTOR bool default n @@ -443,6 +466,37 @@ source "drivers/usb/Kconfig" source "arch/x86_64/oprofile/Kconfig" +menu "GCOV coverage profiling" + +config GCOV_PROFILE + bool "GCOV coverage profiling" + ---help--- + Provide infrastructure for coverage support for the kernel. This + will not compile the kernel by default with the necessary flags. + To obtain coverage information for the entire kernel, one should + enable the subsequent option (Profile entire kernel). If only + particular files or directories of the kernel are desired, then + one must provide the following compile options for such targets: + "-fprofile-arcs -ftest-coverage" in the CFLAGS. To obtain + access to the coverage data one must insmod the gcov-prof kernel + module. + +config GCOV_ALL + bool "GCOV_ALL" + depends on GCOV_PROFILE + ---help--- + If you say Y here, it will compile the entire kernel with coverage + option enabled. + +config GCOV_PROC + tristate "gcov-proc module" + depends on GCOV_PROFILE && PROC_FS + ---help--- + This is the gcov-proc module that exposes gcov data through the + /proc filesystem + +endmenu + menu "Kernel hacking" config DEBUG_KERNEL @@ -505,7 +559,20 @@ config DEBUG_INFO debugging info resulting in a larger kernel image. Say Y here only if you plan to use gdb to debug the kernel. If you don't debug the kernel, you can say N. - + +config SCHEDSTATS + bool "Collect scheduler statistics" + depends on PROC_FS + default y + help + If you say Y here, additional code will be inserted into the + scheduler and related routines to collect statistics about + scheduler behavior and provide them in /proc/schedstat. These + stats may be useful for both tuning and debugging the scheduler + If you aren't debugging the scheduler or trying to tune a specific + application, you can say N to avoid the very slight overhead + this adds. + config FRAME_POINTER bool "Compile the kernel with frame pointers" help diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/x86_64/boot/compressed/head.S 830-ivtv/arch/x86_64/boot/compressed/head.S --- 000-virgin/arch/x86_64/boot/compressed/head.S Sun Nov 17 20:29:56 2002 +++ 830-ivtv/arch/x86_64/boot/compressed/head.S Thu Jan 8 09:30:15 2004 @@ -26,6 +26,7 @@ .code32 .text +#define IN_BOOTLOADER #include #include diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/x86_64/boot/compressed/misc.c 830-ivtv/arch/x86_64/boot/compressed/misc.c --- 000-virgin/arch/x86_64/boot/compressed/misc.c Mon Nov 17 18:28:43 2003 +++ 830-ivtv/arch/x86_64/boot/compressed/misc.c Thu Jan 8 09:30:15 2004 @@ -9,6 +9,7 @@ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 */ +#define IN_BOOTLOADER #include "miscsetup.h" #include diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/x86_64/ia32/ia32_signal.c 830-ivtv/arch/x86_64/ia32/ia32_signal.c --- 000-virgin/arch/x86_64/ia32/ia32_signal.c Thu Jan 8 08:35:28 2004 +++ 830-ivtv/arch/x86_64/ia32/ia32_signal.c Thu Jan 8 10:20:07 2004 @@ -44,10 +44,10 @@ asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); void signal_fault(struct pt_regs *regs, void *frame, char *where); -static int ia32_copy_siginfo_to_user(siginfo_t32 *to, siginfo_t *from) +int ia32_copy_siginfo_to_user(siginfo_t32 __user *to, siginfo_t *from) { int err; - if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t32))) return -EFAULT; /* If you change siginfo_t structure, please make sure that @@ -55,21 +55,17 @@ static int ia32_copy_siginfo_to_user(sig It should never copy any pad contained in the structure to avoid security leaks, but must copy the generic 3 ints plus the relevant union member. */ - - if (from->si_code < 0) { err = __put_user(from->si_signo, &to->si_signo); err |= __put_user(from->si_errno, &to->si_errno); err |= __put_user(from->si_code, &to->si_code); - err |= __put_user(from->_sifields._rt._pid, &to->_sifields._rt._pid); - err |= __put_user(from->_sifields._rt._uid, &to->_sifields._rt._uid); - err |= __put_user((u32)(u64)from->_sifields._rt._sigval.sival_ptr, - &to->_sifields._rt._sigval.sival_ptr); - } else { - err = __put_user(from->si_signo, &to->si_signo); - err |= __put_user(from->si_errno, &to->si_errno); - err |= __put_user(from->si_code, &to->si_code); - /* First 32bits of unions are always present. */ + + if (from->si_code < 0) { err |= __put_user(from->si_pid, &to->si_pid); + err |= __put_user(from->si_uid, &to->si_uid); + err |= __put_user((u32)(u64)from->si_ptr, &to->si_ptr); + } else { + /* First 32bits of unions are always present: + * si_pid === si_band === si_tid === si_addr(LS half) */ switch (from->si_code >> 16) { case __SI_FAULT >> 16: break; @@ -78,15 +74,36 @@ static int ia32_copy_siginfo_to_user(sig err |= __put_user(from->si_stime, &to->si_stime); err |= __put_user(from->si_status, &to->si_status); default: + case __SI_KILL >> 16: err |= __put_user(from->si_uid, &to->si_uid); break; case __SI_POLL >> 16: - err |= __put_user(from->si_band, &to->si_band); err |= __put_user(from->si_fd, &to->si_fd); break; + case __SI_TIMER >> 16: + err |= __put_user(from->si_overrun, &to->si_overrun); + err |= __put_user((u32)(u64)from->si_ptr, &to->si_ptr); + break; /* case __SI_RT: This is not generated by the kernel as of now. */ } } + return err; +} + +int ia32_copy_siginfo_from_user(siginfo_t *to, siginfo_t32 __user *from) +{ + int err; + if (!access_ok (VERIFY_READ, from, sizeof(siginfo_t32))) + return -EFAULT; + + err = __get_user(to->si_signo, &from->si_signo); + err |= __get_user(to->si_errno, &from->si_errno); + err |= __get_user(to->si_code, &from->si_code); + + err |= __get_user(to->si_pid, &from->si_pid); + err |= __get_user(to->si_uid, &from->si_uid); + err |= __get_user((u32)(u64)to->si_ptr, &from->si_ptr); + return err; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/x86_64/ia32/sys_ia32.c 830-ivtv/arch/x86_64/ia32/sys_ia32.c --- 000-virgin/arch/x86_64/ia32/sys_ia32.c Thu Jan 8 08:35:28 2004 +++ 830-ivtv/arch/x86_64/ia32/sys_ia32.c Thu Jan 8 10:20:07 2004 @@ -1022,84 +1022,6 @@ sys32_rt_sigpending(compat_sigset_t *set return ret; } -siginfo_t32 * -siginfo64to32(siginfo_t32 *d, siginfo_t *s) -{ - memset (d, 0, sizeof(siginfo_t32)); - d->si_signo = s->si_signo; - d->si_errno = s->si_errno; - d->si_code = s->si_code; - if (s->si_signo >= SIGRTMIN) { - d->si_pid = s->si_pid; - d->si_uid = s->si_uid; - memcpy(&d->si_int, &s->si_int, - sizeof(siginfo_t) - offsetof(siginfo_t,si_int)); - } else switch (s->si_signo) { - /* XXX: What about POSIX1.b timers */ - case SIGCHLD: - d->si_pid = s->si_pid; - d->si_status = s->si_status; - d->si_utime = s->si_utime; - d->si_stime = s->si_stime; - break; - case SIGSEGV: - case SIGBUS: - case SIGFPE: - case SIGILL: - d->si_addr = (long)(s->si_addr); -// d->si_trapno = s->si_trapno; - break; - case SIGPOLL: - d->si_band = s->si_band; - d->si_fd = s->si_fd; - break; - default: - d->si_pid = s->si_pid; - d->si_uid = s->si_uid; - break; - } - return d; -} - -siginfo_t * -siginfo32to64(siginfo_t *d, siginfo_t32 *s) -{ - d->si_signo = s->si_signo; - d->si_errno = s->si_errno; - d->si_code = s->si_code; - if (s->si_signo >= SIGRTMIN) { - d->si_pid = s->si_pid; - d->si_uid = s->si_uid; - memcpy(&d->si_int, - &s->si_int, - sizeof(siginfo_t) - offsetof(siginfo_t, si_int)); - } else switch (s->si_signo) { - /* XXX: What about POSIX1.b timers */ - case SIGCHLD: - d->si_pid = s->si_pid; - d->si_status = s->si_status; - d->si_utime = s->si_utime; - d->si_stime = s->si_stime; - break; - case SIGSEGV: - case SIGBUS: - case SIGFPE: - case SIGILL: - d->si_addr = (void *)A(s->si_addr); -// d->si_trapno = s->si_trapno; - break; - case SIGPOLL: - d->si_band = s->si_band; - d->si_fd = s->si_fd; - break; - default: - d->si_pid = s->si_pid; - d->si_uid = s->si_uid; - break; - } - return d; -} - extern asmlinkage long sys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo, const struct timespec *uts, size_t sigsetsize); @@ -1114,7 +1036,6 @@ sys32_rt_sigtimedwait(compat_sigset_t *u int ret; mm_segment_t old_fs = get_fs(); siginfo_t info; - siginfo_t32 info32; if (copy_from_user (&s32, uthese, sizeof(compat_sigset_t))) return -EFAULT; @@ -1126,13 +1047,18 @@ sys32_rt_sigtimedwait(compat_sigset_t *u } if (uts && get_compat_timespec(&t, uts)) return -EFAULT; + if (uinfo) { + /* stop data leak to user space in case of structure fill mismatch + * between sys_rt_sigtimedwait & ia32_copy_siginfo_to_user. + */ + memset(&info, 0, sizeof(info)); + } set_fs (KERNEL_DS); ret = sys_rt_sigtimedwait(&s, uinfo ? &info : NULL, uts ? &t : NULL, sigsetsize); set_fs (old_fs); if (ret >= 0 && uinfo) { - if (copy_to_user (uinfo, siginfo64to32(&info32, &info), - sizeof(siginfo_t32))) + if (ia32_copy_siginfo_to_user(uinfo, &info)) return -EFAULT; } return ret; @@ -1145,14 +1071,11 @@ asmlinkage long sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 *uinfo) { siginfo_t info; - siginfo_t32 info32; int ret; mm_segment_t old_fs = get_fs(); - if (copy_from_user (&info32, uinfo, sizeof(siginfo_t32))) + if (ia32_copy_siginfo_from_user(&info, uinfo)) return -EFAULT; - /* XXX: Is this correct? */ - siginfo32to64(&info, &info32); set_fs (KERNEL_DS); ret = sys_rt_sigqueueinfo(pid, sig, &info); set_fs (old_fs); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/x86_64/kernel/acpi/sleep.c 830-ivtv/arch/x86_64/kernel/acpi/sleep.c --- 000-virgin/arch/x86_64/kernel/acpi/sleep.c Tue Apr 8 14:38:15 2003 +++ 830-ivtv/arch/x86_64/kernel/acpi/sleep.c Thu Jan 8 10:20:07 2004 @@ -56,6 +56,7 @@ /* address in low memory of the wakeup routine. */ unsigned long acpi_wakeup_address = 0; +unsigned long acpi_video_flags; extern char wakeup_start, wakeup_end; extern unsigned long FASTCALL(acpi_copy_wakeup_routine(unsigned long)); @@ -115,6 +116,22 @@ void __init acpi_reserve_bootmem(void) printk(KERN_CRIT "ACPI: Wakeup code way too big, will crash on attempt to suspend\n"); printk(KERN_DEBUG "ACPI: have wakeup address 0x%8.8lx\n", acpi_wakeup_address); } + +static int __init acpi_sleep_setup(char *str) +{ + while ((str != NULL) && (*str != '\0')) { + if (strncmp(str, "s3_bios", 7) == 0) + acpi_video_flags = 1; + if (strncmp(str, "s3_mode", 7) == 0) + acpi_video_flags |= 2; + str = strchr(str, ','); + if (str != NULL) + str += strspn(str, ", \t"); + } + return 1; +} + +__setup("acpi_sleep=", acpi_sleep_setup); #endif /*CONFIG_ACPI_SLEEP*/ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/x86_64/kernel/acpi/wakeup.S 830-ivtv/arch/x86_64/kernel/acpi/wakeup.S --- 000-virgin/arch/x86_64/kernel/acpi/wakeup.S Wed Jul 2 21:59:08 2003 +++ 830-ivtv/arch/x86_64/kernel/acpi/wakeup.S Thu Jan 8 10:20:07 2004 @@ -41,7 +41,19 @@ wakeup_code: cmpl $0x12345678, %eax jne bogus_real_magic + testl $1, video_flags - wakeup_code + jz 1f lcall $0xc000,$3 + movw %cs, %ax + movw %ax, %ds # Bios might have played with that + movw %ax, %ss +1: + + testl $2, video_flags - wakeup_code + jz 1f + mov video_mode - wakeup_code, %ax + call mode_seta +1: movw $0xb800, %ax movw %ax,%fs @@ -250,6 +262,7 @@ real_save_gdt: .word 0 .quad 0 real_magic: .quad 0 video_mode: .quad 0 +video_flags: .quad 0 bogus_real_magic: movb $0xba,%al ; outb %al,$0x80 @@ -382,8 +395,10 @@ ENTRY(acpi_copy_wakeup_routine) movl %eax, saved_efer movl %edx, saved_efer2 -# movq saved_videomode, %rdx # FIXME: videomode - movq %rdx, video_mode - wakeup_start (,%rdi) + movl saved_video_mode, %edx + movl %edx, video_mode - wakeup_start (,%rdi) + movl acpi_video_flags, %edx + movl %edx, video_flags - wakeup_start (,%rdi) movq $0x12345678, real_magic - wakeup_start (,%rdi) movq $0x123456789abcdef0, %rdx movq %rdx, saved_magic diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/x86_64/kernel/head.S 830-ivtv/arch/x86_64/kernel/head.S --- 000-virgin/arch/x86_64/kernel/head.S Thu Jan 8 08:35:28 2004 +++ 830-ivtv/arch/x86_64/kernel/head.S Thu Jan 8 10:21:18 2004 @@ -372,3 +372,23 @@ ENTRY(idt_table) .quad 0 .endr +#ifdef CONFIG_GCOV_PROFILE +/* + * The .ctors-section contains a list of pointers to constructor + * functions which are used to initialize gcov structures. + * + * Because there is no NULL at the end of the constructor list + * in the kernel we need the addresses of both the constructor + * as well as the destructor list which are supposed to be + * adjacent. + */ + +.section ".ctors","aw" +.globl __CTOR_LIST__ +.type __CTOR_LIST__,@object +__CTOR_LIST__: +.section ".dtors","aw" +.globl __DTOR_LIST__ +.type __DTOR_LIST__,@object +__DTOR_LIST__: +#endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/x86_64/kernel/pci-dma.c 830-ivtv/arch/x86_64/kernel/pci-dma.c --- 000-virgin/arch/x86_64/kernel/pci-dma.c Tue Sep 2 09:55:44 2003 +++ 830-ivtv/arch/x86_64/kernel/pci-dma.c Thu Jan 8 10:20:07 2004 @@ -35,6 +35,7 @@ int pci_map_sg(struct pci_dev *hwdev, st BUG_ON(!s->page); s->dma_address = pci_map_page(hwdev, s->page, s->offset, s->length, direction); + s->dma_length = s->length; } return nents; } @@ -53,7 +54,7 @@ void pci_unmap_sg(struct pci_dev *dev, s struct scatterlist *s = &sg[i]; BUG_ON(s->page == NULL); BUG_ON(s->dma_address == 0); - pci_unmap_single(dev, s->dma_address, s->length, dir); + pci_unmap_single(dev, s->dma_address, s->dma_length, dir); } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/x86_64/kernel/pci-gart.c 830-ivtv/arch/x86_64/kernel/pci-gart.c --- 000-virgin/arch/x86_64/kernel/pci-gart.c Thu Jan 8 08:35:28 2004 +++ 830-ivtv/arch/x86_64/kernel/pci-gart.c Thu Jan 8 10:20:07 2004 @@ -382,10 +382,12 @@ static int pci_map_sg_nonforce(struct pc if (i > 0) pci_unmap_sg(dev, sg, i, dir); nents = 0; + sg[0].dma_length = 0; break; } } s->dma_address = addr; + s->dma_length = s->length; } flush_gart(dev); return nents; @@ -412,8 +414,9 @@ static int __pci_map_cont(struct scatter *sout = *s; sout->dma_address = iommu_bus_base; sout->dma_address += iommu_page*PAGE_SIZE + s->offset; + sout->dma_length = s->length; } else { - sout->length += s->length; + sout->dma_length += s->length; } addr = phys_addr; @@ -436,6 +439,7 @@ static inline int pci_map_cont(struct sc if (!need) { BUG_ON(stopat - start != 1); *sout = sg[start]; + sout->dma_length = sg[start].length; return 0; } return __pci_map_cont(sg, start, stopat, sout, pages); @@ -453,8 +457,6 @@ int pci_map_sg(struct pci_dev *dev, stru unsigned long pages = 0; int need = 0, nextneed; - unsigned long size = 0; - BUG_ON(dir == PCI_DMA_NONE); if (nents == 0) return 0; @@ -466,7 +468,6 @@ int pci_map_sg(struct pci_dev *dev, stru s->dma_address = addr; BUG_ON(s->length == 0); - size += s->length; nextneed = need_iommu(dev, addr, s->length); /* Handle the previous not yet processed entries */ @@ -493,7 +494,7 @@ int pci_map_sg(struct pci_dev *dev, stru out++; flush_gart(dev); if (out < nents) - sg[out].length = 0; + sg[out].dma_length = 0; return out; error: @@ -540,9 +541,9 @@ void pci_unmap_sg(struct pci_dev *dev, s int i; for (i = 0; i < nents; i++) { struct scatterlist *s = &sg[i]; - if (!s->length) + if (!s->dma_length || !s->length) break; - pci_unmap_single(dev, s->dma_address, s->length, dir); + pci_unmap_single(dev, s->dma_address, s->dma_length, dir); } } @@ -800,7 +801,8 @@ fs_initcall(pci_iommu_init); merge Do SG merging. Implies force (experimental) nomerge Don't do SG merging. forcesac For SAC mode for masks <40bits (experimental) - fullflush Flush IOMMU on each allocation (for testing) + fullflush Flush IOMMU on each allocation (default) + nofullflush Don't use IOMMU fullflush */ __init int iommu_setup(char *opt) { @@ -838,6 +840,8 @@ __init int iommu_setup(char *opt) iommu_sac_force = 1; if (!memcmp(p, "fullflush", 9)) iommu_fullflush = 1; + if (!memcmp(p, "nofullflush", 11)) + iommu_fullflush = 0; #ifdef CONFIG_IOMMU_LEAK if (!memcmp(p,"leak", 4)) { leak_trace = 1; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/x86_64/kernel/process.c 830-ivtv/arch/x86_64/kernel/process.c --- 000-virgin/arch/x86_64/kernel/process.c Thu Jan 8 08:35:28 2004 +++ 830-ivtv/arch/x86_64/kernel/process.c Thu Jan 8 10:20:07 2004 @@ -166,6 +166,8 @@ void idle_warning(void) printk(KERN_ERR "******* Disabling USB legacy in the BIOS may also help.\n"); } +EXPORT_SYMBOL(idle_warning); + /* Prints also some state that isn't saved in the pt_regs */ void __show_regs(struct pt_regs * regs) { @@ -439,7 +441,6 @@ struct task_struct *__switch_to(struct t write_pda(oldrsp, next->userrsp); write_pda(pcurrent, next_p); write_pda(kernelstack, (unsigned long)next_p->thread_info + THREAD_SIZE - PDA_STACKOFFSET); - /* * Now maybe reload the debug registers diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/arch/x86_64/kernel/time.c 830-ivtv/arch/x86_64/kernel/time.c --- 000-virgin/arch/x86_64/kernel/time.c Thu Jan 8 08:35:28 2004 +++ 830-ivtv/arch/x86_64/kernel/time.c Thu Jan 8 10:20:07 2004 @@ -10,6 +10,7 @@ * Copyright (c) 1998 Andrea Arcangeli * Copyright (c) 2002 Vojtech Pavlik * Copyright (c) 2003 Andi Kleen + * RTC support code taken from arch/i386/kernel/timers/time_hpet.c * */ @@ -28,6 +29,7 @@ #include #include #include +#include #include #ifdef CONFIG_X86_LOCAL_APIC #include @@ -627,10 +629,10 @@ static int hpet_init(void) * and period also hpet_tick. */ - hpet_writel(HPET_T0_ENABLE | HPET_T0_PERIODIC | HPET_T0_SETVAL | - HPET_T0_32BIT, HPET_T0_CFG); - hpet_writel(hpet_tick, HPET_T0_CMP); + hpet_writel(HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL | + HPET_TN_32BIT, HPET_T0_CFG); hpet_writel(hpet_tick, HPET_T0_CMP); + hpet_writel(hpet_tick, HPET_T0_CMP); /* AK: why twice? */ /* * Go! @@ -733,3 +735,229 @@ void __init time_init_smp(void) } __setup("report_lost_ticks", time_setup); + +#ifdef CONFIG_HPET_EMULATE_RTC +/* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET + * is enabled, we support RTC interrupt functionality in software. + * RTC has 3 kinds of interrupts: + * 1) Update Interrupt - generate an interrupt, every sec, when RTC clock + * is updated + * 2) Alarm Interrupt - generate an interrupt at a specific time of day + * 3) Periodic Interrupt - generate periodic interrupt, with frequencies + * 2Hz-8192Hz (2Hz-64Hz for non-root user) (all freqs in powers of 2) + * (1) and (2) above are implemented using polling at a frequency of + * 64 Hz. The exact frequency is a tradeoff between accuracy and interrupt + * overhead. (DEFAULT_RTC_INT_FREQ) + * For (3), we use interrupts at 64Hz or user specified periodic + * frequency, whichever is higher. + */ +#include +#include + +extern irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs); + +#define DEFAULT_RTC_INT_FREQ 64 +#define RTC_NUM_INTS 1 + +static unsigned long UIE_on; +static unsigned long prev_update_sec; + +static unsigned long AIE_on; +static struct rtc_time alarm_time; + +static unsigned long PIE_on; +static unsigned long PIE_freq = DEFAULT_RTC_INT_FREQ; +static unsigned long PIE_count; + +static unsigned long hpet_rtc_int_freq; /* RTC interrupt frequency */ + +int is_hpet_enabled(void) +{ + return vxtime.hpet_address != 0; +} + +/* + * Timer 1 for RTC, we do not use periodic interrupt feature, + * even if HPET supports periodic interrupts on Timer 1. + * The reason being, to set up a periodic interrupt in HPET, we need to + * stop the main counter. And if we do that everytime someone diables/enables + * RTC, we will have adverse effect on main kernel timer running on Timer 0. + * So, for the time being, simulate the periodic interrupt in software. + * + * hpet_rtc_timer_init() is called for the first time and during subsequent + * interuppts reinit happens through hpet_rtc_timer_reinit(). + */ +int hpet_rtc_timer_init(void) +{ + unsigned int cfg, cnt; + unsigned long flags; + + if (!is_hpet_enabled()) + return 0; + /* + * Set the counter 1 and enable the interrupts. + */ + if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ)) + hpet_rtc_int_freq = PIE_freq; + else + hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ; + + local_irq_save(flags); + cnt = hpet_readl(HPET_COUNTER); + cnt += ((hpet_tick*HZ)/hpet_rtc_int_freq); + hpet_writel(cnt, HPET_T1_CMP); + local_irq_restore(flags); + + cfg = hpet_readl(HPET_T1_CFG); + cfg |= HPET_TN_ENABLE | HPET_TN_SETVAL | HPET_TN_32BIT; + hpet_writel(cfg, HPET_T1_CFG); + + return 1; +} + +static void hpet_rtc_timer_reinit(void) +{ + unsigned int cfg, cnt; + + if (!(PIE_on | AIE_on | UIE_on)) + return; + + if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ)) + hpet_rtc_int_freq = PIE_freq; + else + hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ; + + /* It is more accurate to use the comparator value than current count.*/ + cnt = hpet_readl(HPET_T1_CMP); + cnt += hpet_tick*HZ/hpet_rtc_int_freq; + hpet_writel(cnt, HPET_T1_CMP); + + cfg = hpet_readl(HPET_T1_CFG); + cfg |= HPET_TN_ENABLE | HPET_TN_SETVAL | HPET_TN_32BIT; + hpet_writel(cfg, HPET_T1_CFG); + + return; +} + +/* + * The functions below are called from rtc driver. + * Return 0 if HPET is not being used. + * Otherwise do the necessary changes and return 1. + */ +int hpet_mask_rtc_irq_bit(unsigned long bit_mask) +{ + if (!is_hpet_enabled()) + return 0; + + if (bit_mask & RTC_UIE) + UIE_on = 0; + if (bit_mask & RTC_PIE) + PIE_on = 0; + if (bit_mask & RTC_AIE) + AIE_on = 0; + + return 1; +} + +int hpet_set_rtc_irq_bit(unsigned long bit_mask) +{ + int timer_init_reqd = 0; + + if (!is_hpet_enabled()) + return 0; + + if (!(PIE_on | AIE_on | UIE_on)) + timer_init_reqd = 1; + + if (bit_mask & RTC_UIE) { + UIE_on = 1; + } + if (bit_mask & RTC_PIE) { + PIE_on = 1; + PIE_count = 0; + } + if (bit_mask & RTC_AIE) { + AIE_on = 1; + } + + if (timer_init_reqd) + hpet_rtc_timer_init(); + + return 1; +} + +int hpet_set_alarm_time(unsigned char hrs, unsigned char min, unsigned char sec) +{ + if (!is_hpet_enabled()) + return 0; + + alarm_time.tm_hour = hrs; + alarm_time.tm_min = min; + alarm_time.tm_sec = sec; + + return 1; +} + +int hpet_set_periodic_freq(unsigned long freq) +{ + if (!is_hpet_enabled()) + return 0; + + PIE_freq = freq; + PIE_count = 0; + + return 1; +} + +int hpet_rtc_dropped_irq(void) +{ + if (!is_hpet_enabled()) + return 0; + + return 1; +} + +irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct rtc_time curr_time; + unsigned long rtc_int_flag = 0; + int call_rtc_interrupt = 0; + + hpet_rtc_timer_reinit(); + + if (UIE_on | AIE_on) { + rtc_get_rtc_time(&curr_time); + } + if (UIE_on) { + if (curr_time.tm_sec != prev_update_sec) { + /* Set update int info, call real rtc int routine */ + call_rtc_interrupt = 1; + rtc_int_flag = RTC_UF; + prev_update_sec = curr_time.tm_sec; + } + } + if (PIE_on) { + PIE_count++; + if (PIE_count >= hpet_rtc_int_freq/PIE_freq) { + /* Set periodic int info, call real rtc int routine */ + call_rtc_interrupt = 1; + rtc_int_flag |= RTC_PF; + PIE_count = 0; + } + } + if (AIE_on) { + if ((curr_time.tm_sec == alarm_time.tm_sec) && + (curr_time.tm_min == alarm_time.tm_min) && + (curr_time.tm_hour == alarm_time.tm_hour)) { + /* Set alarm int info, call real rtc int routine */ + call_rtc_interrupt = 1; + rtc_int_flag |= RTC_AF; + } + } + if (call_rtc_interrupt) { + rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8)); + rtc_interrupt(rtc_int_flag, dev_id, regs); + } + return IRQ_HANDLED; +} +#endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/Makefile 830-ivtv/drivers/Makefile --- 000-virgin/drivers/Makefile Mon Nov 17 18:28:10 2003 +++ 830-ivtv/drivers/Makefile Thu Jan 8 10:21:18 2004 @@ -49,3 +49,4 @@ obj-$(CONFIG_ISDN_BOOL) += isdn/ obj-$(CONFIG_MCA) += mca/ obj-$(CONFIG_EISA) += eisa/ obj-$(CONFIG_CPU_FREQ) += cpufreq/ +obj-$(CONFIG_GCOV_PROC) += gcov/ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/block/paride/Kconfig 830-ivtv/drivers/block/paride/Kconfig --- 000-virgin/drivers/block/paride/Kconfig Thu Feb 13 11:08:06 2003 +++ 830-ivtv/drivers/block/paride/Kconfig Thu Jan 8 10:20:07 2004 @@ -130,7 +130,7 @@ config PARIDE_BPCK config PARIDE_BPCK6 tristate "MicroSolutions backpack (Series 6) protocol" - depends on PARIDE + depends on PARIDE && !64BIT ---help--- This option enables support for the Micro Solutions BACKPACK parallel port Series 6 IDE protocol. (Most BACKPACK drives made diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/block/scsi_ioctl.c 830-ivtv/drivers/block/scsi_ioctl.c --- 000-virgin/drivers/block/scsi_ioctl.c Wed Dec 24 18:16:46 2003 +++ 830-ivtv/drivers/block/scsi_ioctl.c Thu Jan 8 09:30:59 2004 @@ -312,7 +312,7 @@ static int sg_scsi_ioctl(request_queue_t return -EFAULT; if (in_len > PAGE_SIZE || out_len > PAGE_SIZE) return -EINVAL; - if (get_user(opcode, sic->data)) + if (get_user(opcode, (int *)sic->data)) return -EFAULT; bytes = max(in_len, out_len); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/char/agp/amd64-agp.c 830-ivtv/drivers/char/agp/amd64-agp.c --- 000-virgin/drivers/char/agp/amd64-agp.c Thu Jan 8 08:35:30 2004 +++ 830-ivtv/drivers/char/agp/amd64-agp.c Thu Jan 8 10:20:07 2004 @@ -16,11 +16,7 @@ #include "agp.h" /* Will need to be increased if AMD64 ever goes >8-way. */ -#ifdef CONFIG_SMP #define MAX_HAMMER_GARTS 8 -#else -#define MAX_HAMMER_GARTS 1 -#endif /* PTE bits. */ #define GPTE_VALID 1 @@ -35,6 +31,14 @@ #define INVGART (1<<0) #define GARTPTEERR (1<<1) +/* NVIDIA K8 registers */ +#define NVIDIA_X86_64_0_APBASE 0x10 +#define NVIDIA_X86_64_1_APBASE1 0x50 +#define NVIDIA_X86_64_1_APLIMIT1 0x54 +#define NVIDIA_X86_64_1_APSIZE 0xa8 +#define NVIDIA_X86_64_1_APBASE2 0xd8 +#define NVIDIA_X86_64_1_APLIMIT2 0xdc + static int nr_garts; static struct pci_dev * hammers[MAX_HAMMER_GARTS]; @@ -346,6 +350,10 @@ static __devinit int cache_nbs (struct p /* cache pci_devs of northbridges. */ while ((loop_dev = pci_find_device(PCI_VENDOR_ID_AMD, 0x1103, loop_dev)) != NULL) { + if (i == MAX_HAMMER_GARTS) { + printk(KERN_ERR PFX "Too many northbridges for AGP\n"); + return -1; + } if (fix_northbridge(loop_dev, pdev, cap_ptr) < 0) { printk(KERN_ERR PFX "No usable aperture found.\n"); #ifdef __x86_64__ @@ -355,29 +363,111 @@ static __devinit int cache_nbs (struct p return -1; } hammers[i++] = loop_dev; + } nr_garts = i; -#ifdef CONFIG_SMP - if (i > MAX_HAMMER_GARTS) { - printk(KERN_ERR PFX "Too many northbridges for AGP\n"); - return -1; + return i == 0 ? -1 : 0; +} + +/* Handle AMD 8151 quirks */ +static void __devinit amd8151_init(struct pci_dev *pdev, struct agp_bridge_data *bridge) + +{ + char *revstring; + u8 rev_id; + + pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id); + switch (rev_id) { + case 0x01: revstring="A0"; break; + case 0x02: revstring="A1"; break; + case 0x11: revstring="B0"; break; + case 0x12: revstring="B1"; break; + case 0x13: revstring="B2"; break; + default: revstring="??"; break; } -#else - /* Uniprocessor case, return after finding first bridge. - (There may be more, but in UP, we don't care). */ - return 0; -#endif + + printk (KERN_INFO PFX "Detected AMD 8151 AGP Bridge rev %s\n", revstring); + + /* + * Work around errata. + * Chips before B2 stepping incorrectly reporting v3.5 + */ + if (rev_id < 0x13) { + printk (KERN_INFO PFX "Correcting AGP revision (reports 3.5, is really 3.0)\n"); + bridge->major_version = 3; + bridge->minor_version = 0; } +} - return i == 0 ? -1 : 0; +static struct aper_size_info_32 nforce3_sizes[5] = +{ + {512, 131072, 7, 0x00000000 }, + {256, 65536, 6, 0x00000008 }, + {128, 32768, 5, 0x0000000C }, + {64, 16384, 4, 0x0000000E }, + {32, 8192, 3, 0x0000000F } +}; + +/* Handle shadow device of the Nvidia NForce3 */ +/* CHECK-ME original 2.4 version set up some IORRs. Check if that is needed. */ +static int __devinit nforce3_agp_init(struct pci_dev *pdev) +{ + u32 tmp, apbase, apbar, aplimit; + struct pci_dev *dev1; + int i; + unsigned size = amd64_fetch_size(); + + printk(KERN_INFO PFX "Setting up Nforce3 AGP.\n"); + + dev1 = pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(11, 0)); + if (dev1 == NULL) { + printk(KERN_INFO PFX "agpgart: Detected an NVIDIA " + "nForce3 chipset, but could not find " + "the secondary device.\n"); + return -ENODEV; + } + + for (i = 0; i < ARRAY_SIZE(nforce3_sizes); i++) + if (nforce3_sizes[i].size == size) + break; + + if (i == ARRAY_SIZE(nforce3_sizes)) { + printk(KERN_INFO PFX "No NForce3 size found for %d\n", size); + return -ENODEV; + } + + pci_read_config_dword(dev1, NVIDIA_X86_64_1_APSIZE, &tmp); + tmp &= ~(0xf); + tmp |= nforce3_sizes[i].size_value; + pci_write_config_dword(dev1, NVIDIA_X86_64_1_APSIZE, tmp); + + /* shadow x86-64 registers into NVIDIA registers */ + pci_read_config_dword (hammers[0], AMD64_GARTAPERTUREBASE, &apbase); + + /* if x86-64 aperture base is beyond 4G, exit here */ + if ( (apbase & 0x7fff) >> (32 - 25) ) + return -ENODEV; + + apbase = (apbase & 0x7fff) << 25; + + pci_read_config_dword(pdev, NVIDIA_X86_64_0_APBASE, &apbar); + apbar &= ~PCI_BASE_ADDRESS_MEM_MASK; + apbar |= apbase; + pci_write_config_dword(pdev, NVIDIA_X86_64_0_APBASE, apbar); + + aplimit = apbase + (size * 1024 * 1024) - 1; + pci_write_config_dword(dev1, NVIDIA_X86_64_1_APBASE1, apbase); + pci_write_config_dword(dev1, NVIDIA_X86_64_1_APLIMIT1, aplimit); + pci_write_config_dword(dev1, NVIDIA_X86_64_1_APBASE2, apbase); + pci_write_config_dword(dev1, NVIDIA_X86_64_1_APLIMIT2, aplimit); + + return 0; } static int __devinit agp_amd64_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct agp_bridge_data *bridge; - u8 rev_id; u8 cap_ptr; - char *revstring=NULL; cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); if (!cap_ptr) @@ -391,32 +481,7 @@ static int __devinit agp_amd64_probe(str if (pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == PCI_DEVICE_ID_AMD_8151_0) { - - pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id); - switch (rev_id) { - case 0x01: revstring="A0"; - break; - case 0x02: revstring="A1"; - break; - case 0x11: revstring="B0"; - break; - case 0x12: revstring="B1"; - break; - case 0x13: revstring="B2"; - break; - default: revstring="??"; - break; - } - printk (KERN_INFO PFX "Detected AMD 8151 AGP Bridge rev %s\n", revstring); - /* - * Work around errata. - * Chips before B2 stepping incorrectly reporting v3.5 - */ - if (rev_id < 0x13) { - printk (KERN_INFO PFX "Correcting AGP revision (reports 3.5, is really 3.0)\n"); - bridge->major_version = 3; - bridge->minor_version = 0; - } + amd8151_init(pdev, bridge); } else { printk(KERN_INFO PFX "Detected AGP bridge %x\n", pdev->devfn); @@ -434,6 +499,14 @@ static int __devinit agp_amd64_probe(str return -ENODEV; } + if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) { + int ret = nforce3_agp_init(pdev); + if (ret) { + agp_put_bridge(bridge); + return ret; + } + } + pci_set_drvdata(pdev, bridge); return agp_add_bridge(bridge); } @@ -478,8 +551,25 @@ static struct pci_device_id agp_amd64_pc { .class = (PCI_CLASS_BRIDGE_HOST << 8), .class_mask = ~0, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_755, + .vendor = PCI_VENDOR_ID_VIA, + .device = PCI_DEVICE_ID_VIA_8380_0, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + /* NForce3 */ + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_NFORCE3, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_NFORCE3S, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/char/drm/Kconfig 830-ivtv/drivers/char/drm/Kconfig --- 000-virgin/drivers/char/drm/Kconfig Mon Nov 17 18:28:44 2003 +++ 830-ivtv/drivers/char/drm/Kconfig Thu Jan 8 10:20:07 2004 @@ -64,10 +64,9 @@ config DRM_I830 module will be called i830. AGP support is required for this driver to work. - config DRM_MGA tristate "Matrox g200/g400" - depends on DRM && AGP + depends on DRM && AGP && (!X86_64 || BROKEN) help Choose this option if you have a Matrox G200, G400 or G450 graphics card. If M is selected, the module will be called mga. AGP diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/char/keyboard.c 830-ivtv/drivers/char/keyboard.c --- 000-virgin/drivers/char/keyboard.c Thu Jan 8 08:35:30 2004 +++ 830-ivtv/drivers/char/keyboard.c Thu Jan 8 09:30:15 2004 @@ -1059,6 +1059,9 @@ void kbd_keycode(unsigned int keycode, i } if (sysrq_down && down && !rep) { handle_sysrq(kbd_sysrq_xlate[keycode], regs, tty); +#ifdef CONFIG_KGDB_SYSRQ + sysrq_down = 0; /* in case we miss the "up" event */ +#endif return; } #endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/char/pcmcia/synclink_cs.c 830-ivtv/drivers/char/pcmcia/synclink_cs.c --- 000-virgin/drivers/char/pcmcia/synclink_cs.c Mon Nov 17 18:29:41 2003 +++ 830-ivtv/drivers/char/pcmcia/synclink_cs.c Thu Jan 8 08:54:03 2004 @@ -244,7 +244,6 @@ typedef struct _mgslpc_info { char netname[10]; struct net_device *netdev; struct net_device_stats netstats; - struct net_device netdevice; #endif } MGSLPC_INFO; @@ -4206,35 +4205,46 @@ void tx_timeout(unsigned long context) #ifdef CONFIG_SYNCLINK_SYNCPPP /* syncppp net device routines */ + +static void mgslpc_setup(struct net_device *dev) +{ + dev->open = mgslpc_sppp_open; + dev->stop = mgslpc_sppp_close; + dev->hard_start_xmit = mgslpc_sppp_tx; + dev->do_ioctl = mgslpc_sppp_ioctl; + dev->get_stats = mgslpc_net_stats; + dev->tx_timeout = mgslpc_sppp_tx_timeout; + dev->watchdog_timeo = 10*HZ; +} void mgslpc_sppp_init(MGSLPC_INFO *info) { struct net_device *d; sprintf(info->netname,"mgslp%d",info->line); + + d = alloc_netdev(0, info->netname, mgslpc_setup); + if (!d) { + printk(KERN_WARNING "%s: alloc_netdev failed.\n", + info->netname); + return; + } info->if_ptr = &info->pppdev; - info->netdev = info->pppdev.dev = &info->netdevice; + info->netdev = info->pppdev.dev = d; sppp_attach(&info->pppdev); - d = info->netdev; - strcpy(d->name,info->netname); d->base_addr = info->io_base; d->irq = info->irq_level; d->priv = info; - d->init = NULL; - d->open = mgslpc_sppp_open; - d->stop = mgslpc_sppp_close; - d->hard_start_xmit = mgslpc_sppp_tx; - d->do_ioctl = mgslpc_sppp_ioctl; - d->get_stats = mgslpc_net_stats; - d->tx_timeout = mgslpc_sppp_tx_timeout; - d->watchdog_timeo = 10*HZ; if (register_netdev(d)) { printk(KERN_WARNING "%s: register_netdev failed.\n", d->name); sppp_detach(info->netdev); + info->netdev = NULL; + info->pppdev.dev = NULL; + free_netdev(d); return; } @@ -4246,8 +4256,11 @@ void mgslpc_sppp_delete(MGSLPC_INFO *inf { if (debug_level >= DEBUG_LEVEL_INFO) printk("mgslpc_sppp_delete(%s)\n",info->netname); - sppp_detach(info->netdev); unregister_netdev(info->netdev); + sppp_detach(info->netdev); + free_netdev(info->netdev); + info->netdev = NULL; + info->pppdev.dev = NULL; } int mgslpc_sppp_open(struct net_device *d) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/char/synclink.c 830-ivtv/drivers/char/synclink.c --- 000-virgin/drivers/char/synclink.c Mon Nov 17 18:29:41 2003 +++ 830-ivtv/drivers/char/synclink.c Thu Jan 8 08:54:04 2004 @@ -327,7 +327,6 @@ struct mgsl_struct { char netname[10]; struct net_device *netdev; struct net_device_stats netstats; - struct net_device netdevice; #endif }; @@ -737,8 +736,8 @@ int mgsl_ioctl_common(struct mgsl_struct #ifdef CONFIG_SYNCLINK_SYNCPPP /* SPPP/HDLC stuff */ -void mgsl_sppp_init(struct mgsl_struct *info); -void mgsl_sppp_delete(struct mgsl_struct *info); +static void mgsl_sppp_init(struct mgsl_struct *info); +static void mgsl_sppp_delete(struct mgsl_struct *info); int mgsl_sppp_open(struct net_device *d); int mgsl_sppp_close(struct net_device *d); void mgsl_sppp_tx_timeout(struct net_device *d); @@ -7820,36 +7819,45 @@ int usc_loopmode_send_active( struct mgs #ifdef CONFIG_SYNCLINK_SYNCPPP /* syncppp net device routines */ +static void mgsl_setup(struct net_device *dev) +{ + dev->open = mgsl_sppp_open; + dev->stop = mgsl_sppp_close; + dev->hard_start_xmit = mgsl_sppp_tx; + dev->do_ioctl = mgsl_sppp_ioctl; + dev->get_stats = mgsl_net_stats; + dev->tx_timeout = mgsl_sppp_tx_timeout; + dev->watchdog_timeo = 10*HZ; +} -void mgsl_sppp_init(struct mgsl_struct *info) +static void mgsl_sppp_init(struct mgsl_struct *info) { struct net_device *d; sprintf(info->netname,"mgsl%d",info->line); + d = alloc_netdev(0, info->netname, mgsl_setup); + if (!d) { + printk(KERN_WARNING "%s: alloc_netdev failed.\n", + info->netname); + return; + } + info->if_ptr = &info->pppdev; - info->netdev = info->pppdev.dev = &info->netdevice; + info->netdev = info->pppdev.dev = d; sppp_attach(&info->pppdev); - d = info->netdev; - strcpy(d->name,info->netname); d->base_addr = info->io_base; d->irq = info->irq_level; d->dma = info->dma_level; d->priv = info; - d->init = NULL; - d->open = mgsl_sppp_open; - d->stop = mgsl_sppp_close; - d->hard_start_xmit = mgsl_sppp_tx; - d->do_ioctl = mgsl_sppp_ioctl; - d->get_stats = mgsl_net_stats; - d->tx_timeout = mgsl_sppp_tx_timeout; - d->watchdog_timeo = 10*HZ; if (register_netdev(d)) { printk(KERN_WARNING "%s: register_netdev failed.\n", d->name); sppp_detach(info->netdev); + info->netdev = NULL; + free_netdev(d); return; } @@ -7861,8 +7869,11 @@ void mgsl_sppp_delete(struct mgsl_struct { if (debug_level >= DEBUG_LEVEL_INFO) printk("mgsl_sppp_delete(%s)\n",info->netname); - sppp_detach(info->netdev); unregister_netdev(info->netdev); + sppp_detach(info->netdev); + free_netdev(info->netdev); + info->netdev = NULL; + info->pppdev.dev = NULL; } int mgsl_sppp_open(struct net_device *d) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/char/synclinkmp.c 830-ivtv/drivers/char/synclinkmp.c --- 000-virgin/drivers/char/synclinkmp.c Mon Nov 17 18:29:41 2003 +++ 830-ivtv/drivers/char/synclinkmp.c Thu Jan 8 08:54:04 2004 @@ -289,7 +289,6 @@ typedef struct _synclinkmp_info { char netname[10]; struct net_device *netdev; struct net_device_stats netstats; - struct net_device netdevice; #endif } SLMP_INFO; @@ -1627,35 +1626,44 @@ static void set_break(struct tty_struct /* syncppp support and callbacks */ +static void cb_setup(struct net_device *dev) +{ + dev->open = sppp_cb_open; + dev->stop = sppp_cb_close; + dev->hard_start_xmit = sppp_cb_tx; + dev->do_ioctl = sppp_cb_ioctl; + dev->get_stats = sppp_cb_net_stats; + dev->tx_timeout = sppp_cb_tx_timeout; + dev->watchdog_timeo = 10*HZ; +} + static void sppp_init(SLMP_INFO *info) { struct net_device *d; sprintf(info->netname,"mgslm%dp%d",info->adapter_num,info->port_num); + d = alloc_netdev(0, info->netname, cb_setup); + if (!d) { + printk(KERN_WARNING "%s: alloc_netdev failed.\n", + info->netname); + return; + } + info->if_ptr = &info->pppdev; - info->netdev = info->pppdev.dev = &info->netdevice; + info->netdev = info->pppdev.dev = d; sppp_attach(&info->pppdev); - d = info->netdev; - strcpy(d->name,info->netname); - d->base_addr = 0; d->irq = info->irq_level; - d->dma = 0; d->priv = info; - d->init = NULL; - d->open = sppp_cb_open; - d->stop = sppp_cb_close; - d->hard_start_xmit = sppp_cb_tx; - d->do_ioctl = sppp_cb_ioctl; - d->get_stats = sppp_cb_net_stats; - d->tx_timeout = sppp_cb_tx_timeout; - d->watchdog_timeo = 10*HZ; if (register_netdev(d)) { printk(KERN_WARNING "%s: register_netdev failed.\n", d->name); sppp_detach(info->netdev); + info->netdev = NULL; + info->pppdev.dev = NULL; + free_netdev(d); return; } @@ -1667,8 +1675,11 @@ static void sppp_delete(SLMP_INFO *info) { if (debug_level >= DEBUG_LEVEL_INFO) printk("sppp_delete(%s)\n",info->netname); - sppp_detach(info->netdev); unregister_netdev(info->netdev); + sppp_detach(info->netdev); + free_netdev(info->netdev); + info->netdev = NULL; + info->pppdev.dev = NULL; } static int sppp_cb_open(struct net_device *d) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/char/sysrq.c 830-ivtv/drivers/char/sysrq.c --- 000-virgin/drivers/char/sysrq.c Mon Nov 17 18:28:46 2003 +++ 830-ivtv/drivers/char/sysrq.c Thu Jan 8 09:30:15 2004 @@ -35,6 +35,25 @@ #include #include +#ifdef CONFIG_KGDB_SYSRQ + +#define GDB_OP &kgdb_op +static void kgdb_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty) +{ + printk("kgdb sysrq\n"); + breakpoint(); +} + +static struct sysrq_key_op kgdb_op = { + .handler = kgdb_sysrq, + .help_msg = "kGdb|Fgdb", + .action_msg = "Debug breakpoint\n", +}; + +#else +#define GDB_OP NULL +#endif + extern void reset_vc(unsigned int); @@ -238,8 +257,8 @@ static struct sysrq_key_op *sysrq_key_ta /* c */ NULL, /* d */ NULL, /* e */ &sysrq_term_op, -/* f */ NULL, -/* g */ NULL, +/* f */ GDB_OP, +/* g */ GDB_OP, /* h */ NULL, /* i */ &sysrq_kill_op, /* j */ NULL, diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/char/tty_io.c 830-ivtv/drivers/char/tty_io.c --- 000-virgin/drivers/char/tty_io.c Mon Nov 17 18:29:48 2003 +++ 830-ivtv/drivers/char/tty_io.c Thu Jan 8 11:17:33 2004 @@ -1829,6 +1829,21 @@ int tty_ioctl(struct inode * inode, stru case TIOCMBIC: case TIOCMBIS: return tty_tiocmset(tty, file, cmd, arg); + /* + * Without the real device to which /dev/console is connected, + * blogd can not work. + * blogd spawns a pty/tty pair, + * set /dev/console to the tty of that pair (ioctl TIOCCONS), + * then reads in all input from the current /dev/console, + * buffer or write the readed data to /var/log/boot.msg + * _and_ to the original real device. + */ + case TIOCGDEV: + { + unsigned int ret = old_encode_dev(tty_devnum(real_tty)); + return put_user(ret, (unsigned int*) arg); + } + } if (tty->driver->ioctl) { int retval = (tty->driver->ioctl)(tty, file, cmd, arg); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/gcov/Makefile 830-ivtv/drivers/gcov/Makefile --- 000-virgin/drivers/gcov/Makefile Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/gcov/Makefile Thu Jan 8 10:21:18 2004 @@ -0,0 +1,8 @@ +# +# Makefile for GCOV profiling kernel module +# + +obj-$(CONFIG_GCOV_PROC) += gcov-proc.o + +$(obj)/gcov-proc.o: $(obj)/gcov-proc.c + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/gcov/gcov-proc.c 830-ivtv/drivers/gcov/gcov-proc.c --- 000-virgin/drivers/gcov/gcov-proc.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/gcov/gcov-proc.c Thu Jan 8 10:21:18 2004 @@ -0,0 +1,713 @@ +/* + * This kernel module provides access to coverage data produced by + * an instrumented kernel via an entry in the proc file system + * at /proc/gcov/. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (c) International Business Machines Corp., 2002 + * + * Author: Hubertus Franke + * Rajan Ravindran + * + * Bugfixes by Peter.Oberparleiter@de.ibm.com: + * Changes by Paul Larson + * Automatically detect gcc version for gcov_type + * + */ + +#include +#include +#include + +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +#define GCOV_PROF_PROC "gcov" + +static DECLARE_MUTEX_LOCKED(gcov_lock); +#define DOWN() down(&gcov_lock); +#define UP() up(&gcov_lock); +#define PAD8(x) ((x + 7) & ~7) + +//#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,4)) +//static inline struct proc_dir_entry *PDE(const struct inode *inode) +//{ +// return ((struct proc_dir_entry *) inode->u.generic_ip); +//} +//#endif + +/* ################################################################### + # NOTICE ########################################################## + ################################################################### + + GCOV_TYPE defines the count type used by the instrumentation code. + Kernels compiled with a gcc version prior to 3.1 should use LONG, + otherwise LONG LONG. */ + +#if __GNUC__ >= 3 && __GNUC_MINOR__ >= 1 +typedef long long gcov_type; +#else +typedef long gcov_type; +#endif + + +struct bb +{ + long zero_word; + const char *filename; + gcov_type *counts; + long ncounts; + struct bb *next; + const unsigned long *addresses; + + /* Older GCC's did not emit these fields. */ + long nwords; + const char **functions; + const long *line_nums; + const char **filenames; + char *flags; +}; + +extern struct bb *bb_head; +static struct file_operations proc_gcov_operations; +extern char *gcov_kernelpath; +extern void (*gcov_callback)(int cmd, struct bb *); +extern void do_global_ctors(char *, char *, struct module *, int); + +static int create_bb_links = 1; +static int kernel_path_len; + +int debug = 0; +#define PPRINTK(x) do { if (debug) { printk x ; } } while (0) + +struct gcov_ftree_node +{ + int isdir; /* directory or file */ + char *fname; /* only the name within the hierachy */ + struct gcov_ftree_node *sibling; /* sibling of tree */ + struct gcov_ftree_node *files; /* children of tree */ + struct gcov_ftree_node *parent; /* parent of current gcov_ftree_node */ + struct proc_dir_entry *proc[4]; + struct bb *bb; + /* below only valid for leaf nodes == files */ + unsigned long offset; /* offset in global file */ + struct gcov_ftree_node *next; /* next leave node */ +}; + +static struct proc_dir_entry *proc_vmlinux = NULL; +static struct gcov_ftree_node *leave_nodes = NULL; +static struct gcov_ftree_node *dumpall_cached_node = NULL; +static struct gcov_ftree_node tree_root = + { 1, GCOV_PROF_PROC, NULL, NULL, NULL, + { NULL, NULL, NULL, NULL} , NULL, 0,NULL }; +static char *endings[3] = { ".bb", ".bbg", ".c" }; + + +/* Calculate the header size of an entry in the vmlinux-tracefile which + contains the collection of trace data of all instrumented kernel objects. + + An entry header is defined as: + 0: length of filename of the respective .da file padded to 8 bytes + 8: filename padded to 8 bytes + + */ + +static inline unsigned long +hdr_ofs (struct gcov_ftree_node *tptr) +{ + return 8 + PAD8(strlen (tptr->bb->filename) + 1); +} + + +/* Calculate the total size of an entry in the vmlinux-tracefile. + An entry consists of the header, an 8 byte word for the number + of counts in this entry and the actual array of 8 byte counts. */ + +static inline unsigned long +dump_size(struct gcov_ftree_node *tptr) +{ + return (hdr_ofs(tptr) + (tptr->bb->ncounts+1)*8); +} + + +/* Store a portable representation of VALUE in DEST using BYTES*8-1 bits. + Return a non-zero value if VALUE requires more than BYTES*8-1 bits + to store (this is adapted code from gcc/gcov-io.h). */ + +static int +store_gcov_type (gcov_type value, void *buf, int offset, int len) +{ + const size_t bytes = 8; + char dest[10]; + int upper_bit = (value < 0 ? 128 : 0); + size_t i; + + if (value < 0) { + gcov_type oldvalue = value; + value = -value; + if (oldvalue != -value) + return 1; + } + + for(i = 0 ; + i < (sizeof (value) < bytes ? sizeof (value) : bytes) ; + i++) { + dest[i] = value & (i == (bytes - 1) ? 127 : 255); + value = value / 256; + } + + if (value && value != -1) + return 1; + + for(; i < bytes ; i++) + dest[i] = 0; + dest[bytes - 1] |= upper_bit; + copy_to_user(buf,&dest[offset],len); + return 0; +} + + +/* Create a directory entry in the proc file system and fill in + the respective fields in the provided tree node. Return a + non-zero value on error. */ + +int +create_dir_proc (struct gcov_ftree_node *bt, char *fname) +{ + bt->proc[0] = proc_mkdir(fname, bt->parent->proc[0]); + bt->proc[1] = bt->proc[2] = bt->proc[3] = NULL; + return (bt->proc[0] == NULL); +} + + +/* Replace file ending in with . Return a new + string containing the new filename or NULL on error. */ + +static +char* replace_ending (const char *fname,char *end, char *newend) +{ + char *newfname; + char *cptr = strstr(fname,end); + int len; + if (cptr == NULL) + return NULL; + len = cptr - fname; + newfname = (char*)kmalloc(len+strlen(newend)+1,GFP_KERNEL); + if (newfname == NULL) + return NULL; + memcpy(newfname,fname,len); + strcpy(newfname+len,newend); + return newfname; +} + + +/* Create a file entry in the proc file system and update the respective + fields on the tree node. Optionally try to create links to the + source, .bb and .bbg files. Return a non-zero value on error. */ + +int +create_file_proc (struct gcov_ftree_node *bt, struct bb *bptr, char *fname, + const char *fullname) +{ + bt->proc[0] = create_proc_entry(fname, S_IWUSR | S_IRUGO, + bt->parent->proc[0]); + if (!bt->proc[0]) { + PPRINTK(("error creating file proc <%s>\n", fname)); + return 1; + } + + bt->proc[0]->proc_fops = &proc_gcov_operations; + bt->proc[0]->size = 8 + (8 * bptr->ncounts); + + if (create_bb_links) { + int i; + for (i=0;i<3;i++) { + char *newfname; + char *newfullname; + newfname = replace_ending(fname,".da",endings[i]); + newfullname = replace_ending(fullname,".da",endings[i]); + if ((newfname) && (newfullname)) { + bt->proc[i+1] = proc_symlink(newfname,bt->parent->proc[0],newfullname); + } + if (newfname) kfree(newfname); + if (newfullname) kfree(newfullname); + } + } else { + bt->proc[1] = bt->proc[2] = bt->proc[3] = NULL; + } + return 0; +} + + +/* Recursively check and if necessary create the file specified by + and all its path components, both in the proc file-system as + well as in the internal tree structure. */ + +void +check_proc_fs(const char *fullname, struct gcov_ftree_node *parent, + char *name, struct bb *bbptr) +{ + char dirname[128]; + char *localname = name; + char *tname; + int isdir; + struct gcov_ftree_node *tptr; + + tname = strstr(name, "/"); + if ((isdir = (tname != NULL))) { + memcpy(dirname,name,tname-name); + dirname[tname-name] = '\0'; + localname = dirname; + } + + /* search the list of files in gcov_ftree_node and + * see whether file already exists in this directory level */ + for ( tptr = parent->files ; tptr ; tptr = tptr->sibling) { + if (!strcmp(tptr->fname,localname)) + break; + } + if (!tptr) { + /* no entry yet */ + tptr = (struct gcov_ftree_node*) + kmalloc(sizeof(struct gcov_ftree_node),GFP_KERNEL); + tptr->parent = parent; + + if (!isdir) { + if (create_file_proc(tptr, bbptr, localname,fullname)) { + kfree(tptr); + return; + } + tptr->bb = bbptr; + tptr->proc[0]->data = tptr; + tptr->next = leave_nodes; + leave_nodes = tptr; + } else { + int len = strlen(dirname)+1; + localname = (char*)kmalloc(len,GFP_KERNEL); + strncpy(localname,dirname,len); + if (create_dir_proc(tptr,localname)) { + kfree(tptr); + kfree(localname); + return; + } + tptr->bb = NULL; + tptr->proc[0]->data = NULL; + tptr->next = NULL; + } + tptr->isdir = isdir; + tptr->fname = localname; + tptr->files = NULL; + tptr->sibling = parent->files; + parent->files = tptr; + } + if (isdir) + check_proc_fs(fullname,tptr,tname+1,bbptr); +} + + +/* Read out tracefile data to user space. Return the number of bytes + read. */ + +static ssize_t +read_gcov(struct file *file, char *buf, + size_t count, loff_t *ppos) +{ + unsigned long p = *ppos; + ssize_t read; + gcov_type ncnt; + struct bb *bbptr; + gcov_type slen; + gcov_type *wptr; + struct gcov_ftree_node *treeptr; + struct proc_dir_entry * de; + int dumpall; + unsigned int hdrofs; + unsigned long poffs; + + DOWN(); + + read = 0; + hdrofs = 0; + poffs = 0; + de = PDE(file->f_dentry->d_inode); + + /* Check whether this is a request to /proc/gcov/vmlinux in + which case we should dump the complete tracefile. */ + dumpall = (de == proc_vmlinux); + + + /* Have treeptr point to the tree node to be dumped. */ + + if (!dumpall) + treeptr = (struct gcov_ftree_node*) (de ? de->data : NULL); + else { + /* dumpall_cached_node will speed up things in case + of a sequential read. */ + if (dumpall_cached_node && (p >= dumpall_cached_node->offset)) { + treeptr = dumpall_cached_node; + } + else + treeptr = leave_nodes; + + /* Search the tree node that covers the requested + tracefile offset. */ + while (treeptr) { + struct gcov_ftree_node *next = treeptr->next; + if ((next == NULL) || (p < next->offset)) { + hdrofs = hdr_ofs(treeptr); + poffs = treeptr->offset; + break; + } + treeptr = next; + } + dumpall_cached_node = treeptr; + } + + bbptr = treeptr ? treeptr->bb : NULL; + + if (bbptr == NULL) + goto out; + + ncnt = (gcov_type) bbptr->ncounts; + p -= poffs; + + do { + if (p < hdrofs) { + /* User wants to read parts of the header. */ + + slen = PAD8(strlen(treeptr->bb->filename)+1); + + if (p >= 8) { + /* Read filename */ + if (slen > (gcov_type) count) slen = count; + copy_to_user (buf, &treeptr->bb->filename[p-8], + slen); + count-=slen;buf+= slen;read+=slen;p+=slen; + continue; + } + wptr = &slen; + } + else if (p < (hdrofs + 8)) { + /* User wants to read the number of counts in this + entry. */ + + wptr = &ncnt; + } + else if (p < (hdrofs) + (unsigned long) (ncnt+1)*8) { + /* User wants to read actual counters */ + + wptr = &bbptr->counts[((p-hdrofs)/8)-1]; + } + else + break; + + /* do we have to write partial word */ + + if ((count < 8) || (p & 0x7)) { + /* partial write */ + unsigned long offset = p & 0x7; + unsigned long length = (count+offset)<8?count:(8-offset); + + store_gcov_type(*wptr,buf, offset, length); + buf+=length;p+=length;count-=length;read+=length; + break; + } else { + store_gcov_type(*wptr,buf, 0, 8); + buf+=8;p+=8;count-=8;read+=8; + } + } while (count > 0); + *ppos = p + poffs; +out: + UP(); + return read; +} + + +/* A write to any of our proc file-system entries is interpreted + as a request to reset the data from that node. */ + +static ssize_t +write_gcov(struct file * file, const char * buf, + size_t count, loff_t *ppos) +{ + struct bb *ptr; + struct proc_dir_entry * de; + int resetall, i; + struct gcov_ftree_node *tptr; + + DOWN(); + + de = PDE(file->f_dentry->d_inode); + + if (de == NULL) { + count = 0; + goto out; + } + + /* Check for a write to /proc/gcov/vmlinux */ + resetall = (de == proc_vmlinux); + + if (resetall) { + /* Reset all nodes */ + for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next) + { + int i; + if (ptr->counts == NULL) continue; + for (i = 0; i < ptr->ncounts; i++) + ptr->counts[i]=0; + } + } else { + /* Reset a single node */ + tptr = (struct gcov_ftree_node*)(de->data); + if (tptr == NULL) + goto out; + ptr = tptr->bb; + if (ptr->ncounts != 0) { + for (i = 0; i < ptr->ncounts; i++) + ptr->counts[i]=0; + } + } +out: + UP(); + return count; +} + + +/* This struct identifies the functions to be used for proc file-system + interaction. */ + +static struct file_operations proc_gcov_operations = { + read: read_gcov, + write: write_gcov +}; + + +/* Recursively remove a node and all its children from the internal + data tree and from the proc file-system. */ + +void +cleanup_node(struct gcov_ftree_node *node, int delname, int del_in_parent) +{ + struct gcov_ftree_node *next,*tptr; + struct proc_dir_entry *par_proc; + + PPRINTK(("parent n:%p p:%p f:%p s:%p <%s>\n", node, + node->parent, node->files, node->sibling, node->fname)); + if ((tptr = node->parent)) { + if (del_in_parent) { + /* Remove node from parent's list of children */ + struct gcov_ftree_node *cptr,*prev_cptr; + for ( prev_cptr = NULL, cptr = tptr->files; cptr && (cptr != node); + prev_cptr = cptr, cptr = cptr->sibling); + if (prev_cptr == NULL) + tptr->files = cptr->sibling; + else + prev_cptr->sibling = cptr->sibling; + } + par_proc = (struct proc_dir_entry*)(tptr->proc[0]); + } else + par_proc = &proc_root; + + if (node->isdir) { + /* In case of a directory, clean up all child nodes. */ + next = node->files; + node->files = NULL; + for (tptr = next ; tptr; ) { + next = tptr->sibling; + cleanup_node(tptr,1,0); + tptr = next; + } + remove_proc_entry(node->fname, par_proc); + if (delname) kfree(node->fname); + } else { + /* Remove file entry and optional links. */ + remove_proc_entry(node->fname, par_proc); + if (create_bb_links) { + int i; + for (i=0;i<3;i++) { + char *newfname; + if (node->proc[i+1] == NULL) continue; + newfname = replace_ending(node->fname,".da",endings[i]); + if (newfname) { + PPRINTK(("remove_proc_entry <%s>\n", node->fname)); + remove_proc_entry(newfname, par_proc); + kfree(newfname); + } + } + } + } + /* free the data */ + if (node != &tree_root) + kfree(node); +} + + +/* Create a tree node for the given bb struct and initiate the + creation of a corresponding proc file-system entry. */ + +static void +create_node_tree(struct bb *bbptr) +{ + const char *tmp; + const char *filename = bbptr->filename; + char *modname; + int len; + + PPRINTK(("kernelpath <%s> <%s>\n", gcov_kernelpath, filename)); + + /* Check whether this is a file located in the kernel source + directory. */ + if (!strncmp (filename, gcov_kernelpath, kernel_path_len)) + { + /* Remove kernel path and create relative proc-file-system + entry. */ + tmp = filename + kernel_path_len+1; + if (*tmp == '0') return; + check_proc_fs(filename, &tree_root, (char*)tmp, bbptr); + } + else { + /* Insert entry to module sub-directory. */ + len = strlen(filename); + modname = (char *)kmalloc (len + 7, GFP_KERNEL); + strcpy(modname, "module"); + strcat (modname, filename); + check_proc_fs(filename, &tree_root, modname, bbptr); + } +} + + +/* This function will be used as gcov_callback, i.e. it is + called from constructor and destructor code of all instrumented + object files. It updates the local tree structure and the proc + file-system entries. */ + +static void +gcov_cleanup(int cmd, struct bb *bbptr) +{ + unsigned long offset = 0; + struct gcov_ftree_node *tptr; + struct gcov_ftree_node *parent; + struct gcov_ftree_node *prev_cptr; + + DOWN(); + switch (cmd) { + case 0: + /* remove leave node */ + prev_cptr = NULL; + for (tptr = leave_nodes; tptr ; prev_cptr = tptr, tptr = tptr->next) { + if (tptr->bb == bbptr) break; + } + if (!tptr) { + PPRINTK(("Can't find module in /proc/gcov\n")); + UP(); + return; + } + if (prev_cptr) + prev_cptr->next = tptr->next; + else + leave_nodes = tptr->next; + dumpall_cached_node = NULL; + + + /* Find highest level node without further siblings */ + + parent = tptr->parent; + do { + if (parent->files->sibling != NULL) break; + tptr = parent; + parent = parent->parent; + } while (parent); + cleanup_node(tptr,0,1); + + /* Update the offsets at which a certain node can + be found in the tracefile. */ + for (tptr = leave_nodes; tptr; tptr = tptr->next) { + tptr->offset = offset; + offset += dump_size(tptr); + } + break; + + case 1: + /* insert node */ + create_node_tree(bbptr); + + /* Update the offsets at which a certain node can + be found in the tracefile. */ + for (tptr = leave_nodes; tptr; tptr = tptr->next) { + tptr->offset = offset; + offset += dump_size(tptr); + } + + break; + } + UP(); +} + + +/* Initialize the data structure by calling the constructor code + of all instrumented object files and creating the proc + file-system entries. */ + +int +init_module(void) +{ + struct bb *bbptr; + unsigned long offset = 0; + struct gcov_ftree_node *tptr; + + PPRINTK(("init module <%s>\n\n", GCOV_PROF_PROC)); + + do_global_ctors(NULL, NULL, NULL, 0); + + tree_root.proc[0] = proc_mkdir(GCOV_PROF_PROC, 0); + kernel_path_len = strlen(gcov_kernelpath); + + for (bbptr = bb_head; bbptr ; bbptr = bbptr->next) { + create_node_tree(bbptr); + } + + /* Fill in the offset at which a certain node can + be found in the tracefile. */ + for (tptr = leave_nodes; tptr; tptr = tptr->next) { + tptr->offset = offset; + offset += dump_size(tptr); + } + + proc_vmlinux = create_proc_entry("vmlinux",S_IWUSR | S_IRUGO, + tree_root.proc[0]); + if (proc_vmlinux) + proc_vmlinux->proc_fops = &proc_gcov_operations; + + gcov_callback = gcov_cleanup; + UP(); + return 0; +} + + +void +cleanup_module(void) +{ + PPRINTK(("remove module <%s>\n\n", GCOV_PROF_PROC)); + gcov_callback = NULL; + DOWN(); + cleanup_node(&tree_root,0,0); +} + +//module_init(gcov_init_module); +//module_exit(gcov_cleanup_module); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/ieee1394/eth1394.c 830-ivtv/drivers/ieee1394/eth1394.c --- 000-virgin/drivers/ieee1394/eth1394.c Thu Jan 8 08:35:32 2004 +++ 830-ivtv/drivers/ieee1394/eth1394.c Thu Jan 8 08:54:04 2004 @@ -375,8 +375,8 @@ static void ether1394_reset_priv (struct } } -/* This function is called by register_netdev */ -static int ether1394_init_dev (struct net_device *dev) +/* This function is called right before register_netdev */ +static void ether1394_init_dev (struct net_device *dev) { /* Our functions */ dev->open = ether1394_open; @@ -403,8 +403,6 @@ static int ether1394_init_dev (struct ne dev->type = ARPHRD_IEEE1394; ether1394_reset_priv (dev, 1); - - return 0; } /* @@ -437,8 +435,6 @@ static void ether1394_add_host (struct h SET_MODULE_OWNER(dev); - dev->init = ether1394_init_dev; - priv = (struct eth1394_priv *)dev->priv; spin_lock_init(&priv->lock); @@ -459,6 +455,8 @@ static void ether1394_add_host (struct h goto out; } + ether1394_init_dev(dev); + if (register_netdev (dev)) { ETH1394_PRINT (KERN_ERR, dev->name, "Error registering network driver\n"); goto out; @@ -483,7 +481,7 @@ static void ether1394_add_host (struct h out: if (dev != NULL) - kfree(dev); + free_netdev(dev); if (hi) hpsb_destroy_hostinfo(ð1394_highlevel, host); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/Kconfig 830-ivtv/drivers/media/Kconfig --- 000-virgin/drivers/media/Kconfig Mon Nov 17 18:29:28 2003 +++ 830-ivtv/drivers/media/Kconfig Thu Jan 8 11:17:36 2004 @@ -34,19 +34,25 @@ source "drivers/media/common/Kconfig" config VIDEO_TUNER tristate - default y if VIDEO_BT848=y || VIDEO_SAA7134=y || VIDEO_MXB=y - default m if VIDEO_BT848=m || VIDEO_SAA7134=m || VIDEO_MXB=m + default y if VIDEO_BT848=y || VIDEO_SAA7134=y || VIDEO_MXB=y || VIDEO_IVTV=y + default m if VIDEO_BT848=m || VIDEO_SAA7134=m || VIDEO_MXB=m || VIDEO_IVTV=m depends on VIDEO_DEV config VIDEO_BUF tristate - default y if VIDEO_BT848=y || VIDEO_SAA7134=y || VIDEO_SAA7146=y - default m if VIDEO_BT848=m || VIDEO_SAA7134=m || VIDEO_SAA7146=m + default y if VIDEO_BT848=y || VIDEO_SAA7134=y || VIDEO_SAA7146=y || VIDEO_IVTV=y + default m if VIDEO_BT848=m || VIDEO_SAA7134=m || VIDEO_SAA7146=m || VIDEO_IVTV=m depends on VIDEO_DEV config VIDEO_BTCX tristate default VIDEO_BT848 + depends on VIDEO_DEV + +config VIDEO_IR + tristate + default y if VIDEO_BT848=y || VIDEO_SAA7134=y + default m if VIDEO_BT848=m || VIDEO_SAA7134=m depends on VIDEO_DEV endmenu diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/common/Makefile 830-ivtv/drivers/media/common/Makefile --- 000-virgin/drivers/media/common/Makefile Mon Nov 17 18:29:28 2003 +++ 830-ivtv/drivers/media/common/Makefile Thu Jan 8 11:17:15 2004 @@ -3,4 +3,4 @@ saa7146_vv-objs := saa7146_vv_ksyms.o sa obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o obj-$(CONFIG_VIDEO_SAA7146_VV) += saa7146_vv.o - +obj-$(CONFIG_VIDEO_IR) += ir-common.o diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/common/ir-common.c 830-ivtv/drivers/media/common/ir-common.c --- 000-virgin/drivers/media/common/ir-common.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/media/common/ir-common.c Thu Jan 8 11:17:15 2004 @@ -0,0 +1,218 @@ +/* + * some common structs and functions to handle infrared remotes via + * input layer ... + * + * (c) 2003 Gerd Knorr [SuSE Labs] + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include + +/* -------------------------------------------------------------------------- */ + +MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); +MODULE_LICENSE("GPL"); + +static int repeat = 1; +MODULE_PARM(repeat,"i"); +MODULE_PARM_DESC(repeat,"auto-repeat for IR keys (default: on)"); + +static int debug = 0; /* debug level (0,1,2) */ +MODULE_PARM(debug,"i"); + +#define dprintk(level, fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG fmt , ## arg) + +/* -------------------------------------------------------------------------- */ + +/* generic RC5 keytable */ +/* see http://users.pandora.be/nenya/electronics/rc5/codes00.htm */ +IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE] = { + [ 0x00 ] = KEY_KP0, // 0 + [ 0x01 ] = KEY_KP1, // 1 + [ 0x02 ] = KEY_KP2, // 2 + [ 0x03 ] = KEY_KP3, // 3 + [ 0x04 ] = KEY_KP4, // 4 + [ 0x05 ] = KEY_KP5, // 5 + [ 0x06 ] = KEY_KP6, // 6 + [ 0x07 ] = KEY_KP7, // 7 + [ 0x08 ] = KEY_KP8, // 8 + [ 0x09 ] = KEY_KP9, // 9 + + [ 0x0b ] = KEY_CHANNEL, // channel / program (japan: 11) + [ 0x0c ] = KEY_POWER, // standby + [ 0x0d ] = KEY_MUTE, // mute / demute + [ 0x0f ] = KEY_TV, // display + [ 0x10 ] = KEY_VOLUMEUP, // volume + + [ 0x11 ] = KEY_VOLUMEDOWN, // volume - + [ 0x12 ] = KEY_BRIGHTNESSUP, // brightness + + [ 0x13 ] = KEY_BRIGHTNESSDOWN, // brightness - + [ 0x1e ] = KEY_SEARCH, // search + + [ 0x20 ] = KEY_CHANNELUP, // channel / program + + [ 0x21 ] = KEY_CHANNELDOWN, // channel / program - + [ 0x22 ] = KEY_CHANNEL, // alt / channel + [ 0x23 ] = KEY_LANGUAGE, // 1st / 2nd language + [ 0x26 ] = KEY_SLEEP, // sleeptimer + [ 0x2e ] = KEY_MENU, // 2nd controls (USA: menu) + [ 0x30 ] = KEY_PAUSE, // pause + [ 0x32 ] = KEY_REWIND, // rewind + [ 0x33 ] = KEY_GOTO, // go to + [ 0x35 ] = KEY_PLAY, // play + [ 0x36 ] = KEY_STOP, // stop + [ 0x37 ] = KEY_RECORD, // recording + +#if 0 /* FIXME */ + [ 0x0a ] = KEY_RESERVED, // 1/2/3 digits (japan: 10) + [ 0x0e ] = KEY_RESERVED, // P.P. (personal preference) + [ 0x14 ] = KEY_RESERVED, // colour saturation + + [ 0x15 ] = KEY_RESERVED, // colour saturation - + [ 0x16 ] = KEY_RESERVED, // bass + + [ 0x17 ] = KEY_RESERVED, // bass - + [ 0x18 ] = KEY_RESERVED, // treble + + [ 0x19 ] = KEY_RESERVED, // treble - + [ 0x1a ] = KEY_RESERVED, // balance right + [ 0x1b ] = KEY_RESERVED, // balance left + [ 0x1c ] = KEY_RESERVED, // contrast + + [ 0x1d ] = KEY_RESERVED, // contrast - + [ 0x1f ] = KEY_RESERVED, // tint/hue + + [ 0x24 ] = KEY_RESERVED, // spacial stereo on/off + [ 0x25 ] = KEY_RESERVED, // mono / stereo (USA) + [ 0x27 ] = KEY_RESERVED, // tint / hue - + [ 0x28 ] = KEY_RESERVED, // RF switch/PIP select + [ 0x29 ] = KEY_RESERVED, // vote + [ 0x2a ] = KEY_RESERVED, // timed page/channel clck + [ 0x2b ] = KEY_RESERVED, // increment (USA) + [ 0x2c ] = KEY_RESERVED, // decrement (USA) + [ 0x2d ] = KEY_RESERVED, // + [ 0x2f ] = KEY_RESERVED, // PIP shift + [ 0x31 ] = KEY_RESERVED, // erase + [ 0x34 ] = KEY_RESERVED, // wind + [ 0x38 ] = KEY_RESERVED, // external 1 + [ 0x39 ] = KEY_RESERVED, // external 2 + [ 0x3a ] = KEY_RESERVED, // PIP display mode + [ 0x3b ] = KEY_RESERVED, // view data mode / advance + [ 0x3c ] = KEY_RESERVED, // teletext submode (Japan: 12) + [ 0x3d ] = KEY_RESERVED, // system standby + [ 0x3e ] = KEY_RESERVED, // crispener on/off + [ 0x3f ] = KEY_RESERVED, // system select +#endif +}; +EXPORT_SYMBOL_GPL(ir_codes_rc5_tv); + +/* empty keytable, can be used as placeholder for not-yet created keytables */ +IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE] = { + [ 42 ] = KEY_COFFEE, +}; +EXPORT_SYMBOL_GPL(ir_codes_empty); + +/* -------------------------------------------------------------------------- */ + +static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir) +{ + if (KEY_RESERVED == ir->keycode) { + printk(KERN_INFO "%s: unknown key: key=0x%02x raw=0x%02x down=%d\n", + dev->name,ir->ir_key,ir->ir_raw,ir->keypressed); + return; + } + dprintk(1,"%s: key event code=%d down=%d\n", + dev->name,ir->keycode,ir->keypressed); + input_report_key(dev,ir->keycode,ir->keypressed); + input_sync(dev); +} + +/* -------------------------------------------------------------------------- */ + +void ir_input_init(struct input_dev *dev, struct ir_input_state *ir, + int ir_type, IR_KEYTAB_TYPE *ir_codes) +{ + int i; + + ir->ir_type = ir_type; + if (ir_codes) + memcpy(ir->ir_codes, ir_codes, sizeof(ir->ir_codes)); + + init_input_dev(dev); + dev->keycode = ir->ir_codes; + dev->keycodesize = sizeof(IR_KEYTAB_TYPE); + dev->keycodemax = IR_KEYTAB_SIZE; + for (i = 0; i < IR_KEYTAB_SIZE; i++) + set_bit(ir->ir_codes[i], dev->keybit); + clear_bit(0, dev->keybit); + + set_bit(EV_KEY, dev->evbit); + if (repeat) + set_bit(EV_REP, dev->evbit); +} + +void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir) +{ + if (ir->keypressed) { + ir->keypressed = 0; + ir_input_key_event(dev,ir); + } +} + +void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir, + u32 ir_key, u32 ir_raw) +{ + u32 keycode = IR_KEYCODE(ir->ir_codes, ir_key); + + if (ir->keypressed && ir->keycode != keycode) { + ir->keypressed = 0; + ir_input_key_event(dev,ir); + } + if (!ir->keypressed) { + ir->ir_key = ir_key; + ir->ir_raw = ir_raw; + ir->keycode = keycode; + ir->keypressed = 1; + ir_input_key_event(dev,ir); + } +#if 0 + /* maybe do something like this ??? */ + input_event(a, EV_IR, ir->ir_type, ir->ir_raw); +#endif +} + +u32 ir_extract_bits(u32 data, u32 mask) +{ + int mbit, vbit; + u32 value; + + value = 0; + vbit = 0; + for (mbit = 0; mbit < 32; mbit++) { + if (!(mask & ((u32)1 << mbit))) + continue; + if (data & ((u32)1 << mbit)) + value |= (1 << vbit); + vbit++; + } + return value; +} + +EXPORT_SYMBOL_GPL(ir_input_init); +EXPORT_SYMBOL_GPL(ir_input_nokey); +EXPORT_SYMBOL_GPL(ir_input_keydown); +EXPORT_SYMBOL_GPL(ir_extract_bits); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/Kconfig 830-ivtv/drivers/media/video/Kconfig --- 000-virgin/drivers/media/video/Kconfig Mon Nov 17 18:29:29 2003 +++ 830-ivtv/drivers/media/video/Kconfig Thu Jan 8 11:17:36 2004 @@ -18,17 +18,25 @@ config VIDEO_BT848 If you say Y or M here, you need to say Y or M to "I2C support" and "I2C bit-banging interfaces" in the character device section. - To compile this driver as a module, choose M here: the - module will be called bttv. + Saying M here will compile this driver as a module (bttv). + +config VIDEO_IVTV + tristate "IVTV Video For Linux" + depends on VIDEO_DEV && PCI && I2C_ALGOBIT && SOUND + ---help--- + Support for Hauppauge WinTv PVR 250 and 350 boards. + + If you say Y or M here, you need to say Y or M to "I2C support" and + "I2C bit-banging interfaces" in the character device section. + + Saying M here will compile this driver as a module (ivtv). config VIDEO_PMS tristate "Mediavision Pro Movie Studio Video For Linux" depends on VIDEO_DEV && ISA help - Say Y if you have such a thing. - - To compile this driver as a module, choose M here: the - module will be called pms. + Say Y if you have such a thing. Saying M here will compile this + driver as a module (pms). config VIDEO_PLANB tristate "PlanB Video-In on PowerMac" diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/Makefile 830-ivtv/drivers/media/video/Makefile --- 000-virgin/drivers/media/video/Makefile Tue Sep 2 09:55:45 2003 +++ 830-ivtv/drivers/media/video/Makefile Thu Jan 8 11:17:36 2004 @@ -3,16 +3,21 @@ # bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \ - bttv-risc.o bttv-vbi.o + bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o zoran-objs := zr36120.o zr36120_i2c.o zr36120_mem.o zr36067-objs := zoran_procfs.o zoran_device.o \ zoran_driver.o zoran_card.o +ivtv-objs := ivtv-driver.o ivtv-i2c.o ivtv-api.o + obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \ - tda7432.o tda9875.o + tda7432.o tda9875.o ir-kbd-i2c.o ir-kbd-gpio.o obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o + +obj-$(CONFIG_VIDEO_IVTV) += msp3400.o saa7115.o tveeprom.o ivtv.o \ + saa7127.o #ivtv-fb.o obj-$(CONFIG_VIDEO_ZR36120) += zoran.o obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/bt832.c 830-ivtv/drivers/media/video/bt832.c --- 000-virgin/drivers/media/video/bt832.c Mon Dec 8 09:55:51 2003 +++ 830-ivtv/drivers/media/video/bt832.c Thu Jan 8 11:17:09 2004 @@ -31,8 +31,8 @@ #include #include -#include "id.h" -#include "audiochip.h" +#include +#include #include "bttv.h" #include "bt832.h" @@ -168,8 +168,7 @@ int bt832_init(struct i2c_client *i2c_cl -static int bt832_attach(struct i2c_adapter *adap, int addr, - unsigned short flags, int kind) +static int bt832_attach(struct i2c_adapter *adap, int addr, int kind) { struct bt832 *t; @@ -184,7 +183,7 @@ static int bt832_attach(struct i2c_adapt return -ENOMEM; memset(t,0,sizeof(*t)); t->client = client_template; - t->client.data = t; + i2c_set_clientdata(&t->client, t); i2c_attach_client(&t->client); if(! bt832_init(&t->client)) { @@ -197,14 +196,19 @@ static int bt832_attach(struct i2c_adapt static int bt832_probe(struct i2c_adapter *adap) { +#ifdef I2C_ADAP_CLASS_TV_ANALOG if (adap->class & I2C_ADAP_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, bt832_attach); +#else + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, bt832_attach); +#endif return 0; } static int bt832_detach(struct i2c_client *client) { - struct bt832 *t = (struct bt832*)client->data; + struct bt832 *t = i2c_get_clientdata(client); printk("bt832: detach.\n"); i2c_detach_client(client); @@ -215,7 +219,7 @@ static int bt832_detach(struct i2c_clien static int bt832_command(struct i2c_client *client, unsigned int cmd, void *arg) { - struct bt832 *t = (struct bt832*)client->data; + struct bt832 *t = i2c_get_clientdata(client); printk("bt832: command %x\n",cmd); @@ -249,9 +253,9 @@ static struct i2c_driver driver = { }; static struct i2c_client client_template = { - .name = "bt832", - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, + I2C_DEVNAME("bt832"), + .flags = I2C_CLIENT_ALLOW_USE, + .driver = &driver, }; @@ -269,3 +273,10 @@ static void bt832_cleanup_module(void) module_init(bt832_init_module); module_exit(bt832_cleanup_module); +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/bt848.h 830-ivtv/drivers/media/video/bt848.h --- 000-virgin/drivers/media/video/bt848.h Mon Nov 17 18:29:29 2003 +++ 830-ivtv/drivers/media/video/bt848.h Thu Jan 8 11:17:21 2004 @@ -158,6 +158,9 @@ #define BT848_ADC_C_SLEEP (1<<1) #define BT848_ADC_CRUSH (1<<0) +#define BT848_WC_UP 0x044 +#define BT848_WC_DOWN 0x078 + #define BT848_E_VTC 0x06C #define BT848_O_VTC 0x0EC #define BT848_VTC_HSFMT (1<<7) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/bttv-cards.c 830-ivtv/drivers/media/video/bttv-cards.c --- 000-virgin/drivers/media/video/bttv-cards.c Mon Dec 8 09:55:51 2003 +++ 830-ivtv/drivers/media/video/bttv-cards.c Thu Jan 8 11:17:21 2004 @@ -53,6 +53,8 @@ static void winview_audio(struct bttv *b static void lt9415_audio(struct bttv *btv, struct video_audio *v, int set); static void avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, int set); +static void avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v, + int set); static void terratv_audio(struct bttv *btv, struct video_audio *v, int set); static void gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set); static void winfast2000_audio(struct bttv *btv, struct video_audio *v, int set); @@ -64,6 +66,7 @@ static void rv605_muxsel(struct bttv *bt static void eagle_muxsel(struct bttv *btv, unsigned int input); static void xguard_muxsel(struct bttv *btv, unsigned int input); static void ivc120_muxsel(struct bttv *btv, unsigned int input); +static void gvc1100_muxsel(struct bttv *btv, unsigned int input); static int terratec_active_radio_upgrade(struct bttv *btv); static int tea5757_read(struct bttv *btv); @@ -77,10 +80,11 @@ static unsigned int vsfx=0; static unsigned int latency = UNSET; unsigned int no_overlay=-1; -static unsigned int card[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET}; -static unsigned int pll[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET}; -static unsigned int tuner[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET}; -static unsigned int svhs[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET}; +static unsigned int card[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET }; +static unsigned int pll[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET }; +static unsigned int tuner[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET }; +static unsigned int svhs[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET }; +static unsigned int remote[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET }; #ifdef MODULE static unsigned int autoload = 1; #else @@ -108,6 +112,10 @@ MODULE_PARM(tuner,"1-" __stringify(BTTV_ MODULE_PARM_DESC(tuner,"specify installed tuner type"); MODULE_PARM(autoload,"i"); MODULE_PARM_DESC(autoload,"automatically load i2c modules like tuner.o, default is 1 (yes)"); + +MODULE_PARM(svhs,"1-" __stringify(BTTV_MAX) "i"); +MODULE_PARM(remote,"1-" __stringify(BTTV_MAX) "i"); + MODULE_PARM(gpiomask,"i"); MODULE_PARM(audioall,"i"); MODULE_PARM(audiomux,"1-5i"); @@ -155,12 +163,13 @@ static struct CARD { { 0x00031002, BTTV_ATI_TVWONDERVE,"ATI TV Wonder/VE" }, { 0x6606107d, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" }, - { 0x6607107d, BTTV_WINFAST2000, "Leadtek WinFast VC 100" }, + { 0x6607107d, BTTV_WINFASTVC100, "Leadtek WinFast VC 100" }, { 0x263610b4, BTTV_STB2, "STB TV PCI FM, Gateway P/N 6000704" }, { 0x264510b4, BTTV_STB2, "STB TV PCI FM, Gateway P/N 6000704" }, { 0x402010fc, BTTV_GVBCTV3PCI, "I-O Data Co. GV-BCTV3/PCI" }, { 0x405010fc, BTTV_GVBCTV4PCI, "I-O Data Co. GV-BCTV4/PCI" }, { 0x407010fc, BTTV_GVBCTV5PCI, "I-O Data Co. GV-BCTV5/PCI" }, + { 0xd01810fc, BTTV_GVBCTV3PCI, "I-O Data Co. GV-BCTV3/PCI" }, { 0x001211bd, BTTV_PINNACLE, "Pinnacle PCTV" }, { 0x001c11bd, BTTV_PINNACLESAT, "Pinnacle PCTV Sat" }, @@ -175,16 +184,15 @@ static struct CARD { { 0x3002144f, BTTV_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH05x" }, { 0x3005144f, BTTV_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH061/06L (T1/LC)" }, { 0x5000144f, BTTV_MAGICTVIEW061, "Askey CPH050" }, - + { 0x300014ff, BTTV_MAGICTVIEW061, "TView 99 (CPH061)" }, + { 0x300214ff, BTTV_PHOEBE_TVMAS, "Phoebe TV Master (CPH060)" }, + { 0x00011461, BTTV_AVPHONE98, "AVerMedia TVPhone98" }, { 0x00021461, BTTV_AVERMEDIA98, "AVermedia TVCapture 98" }, { 0x00031461, BTTV_AVPHONE98, "AVerMedia TVPhone98" }, { 0x00041461, BTTV_AVERMEDIA98, "AVerMedia TVCapture 98" }, { 0x03001461, BTTV_AVERMEDIA98, "VDOMATE TV TUNER CARD" }, - { 0x300014ff, BTTV_MAGICTVIEW061, "TView 99 (CPH061)" }, - { 0x300214ff, BTTV_PHOEBE_TVMAS, "Phoebe TV Master (CPH060)" }, - { 0x1117153b, BTTV_TERRATVALUE, "Terratec TValue (Philips PAL B/G)" }, { 0x1118153b, BTTV_TERRATVALUE, "Terratec TValue (Temic PAL B/G)" }, { 0x1119153b, BTTV_TERRATVALUE, "Terratec TValue (Philips PAL I)" }, @@ -253,16 +261,24 @@ static struct CARD { { 0x18501851, BTTV_CHRONOS_VS2, "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" }, { 0x18511851, BTTV_FLYVIDEO98EZ, "FlyVideo 98EZ (LR51)/ CyberMail AV" }, { 0x18521852, BTTV_TYPHOON_TVIEW, "FlyVideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" }, + { 0x41a0a051, BTTV_FLYVIDEO_98FM, "Lifeview FlyVideo 98 LR50 Rev Q" }, { 0x10b42636, BTTV_HAUPPAUGE878, "STB ???" }, { 0x217d6606, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" }, + { 0xfff6f6ff, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" }, { 0x03116000, BTTV_SENSORAY311, "Sensoray 311" }, { 0x00790e11, BTTV_WINDVR, "Canopus WinDVR PCI" }, { 0xa0fca1a0, BTTV_ZOLTRIX, "Face to Face Tvmax" }, - { 0x01010071, BTTV_NEBULA_DIGITV, "Nebula Electronics DigiTV" }, + { 0x20007063, BTTV_PC_HDTV, "pcHDTV HD-2000 TV"}, + { 0x82b2aa6a, BTTV_SIMUS_GVC1100, "SIMUS GVC1100" }, // likely broken, vendor id doesn't match the other magic views ... //{ 0xa0fca04f, BTTV_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, + // DVB cards (using pci function .1 for mpeg data xfer) + { 0x01010071, BTTV_NEBULA_DIGITV, "Nebula Electronics DigiTV" }, + { 0x002611bd, BTTV_TWINHAN_DST, "Pinnacle PCTV SAT CI" }, + { 0x00011822, BTTV_TWINHAN_DST, "Twinhan VisionPlus DVB-T" }, + { 0, -1, NULL } }; @@ -352,6 +368,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .tuner_type = -1, .audio_hook = avermedia_tvphone_audio, + .has_remote = 1, },{ .name = "MATRIX-Vision MV-Delta", .video_inputs = 5, @@ -438,6 +455,7 @@ struct tvcard bttv_tvcards[] = { .msp34xx_alt = 1, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_PAL, + .audio_hook = avermedia_tv_stereo_audio, },{ .name = "Aimslab Video Highway Xtreme (VHX)", .video_inputs = 3, @@ -471,7 +489,13 @@ struct tvcard bttv_tvcards[] = { .svhs = 2, .gpiomask = 0x01fe00, .muxsel = { 2, 3, 1, 1}, +#if 0 + // old .audiomux = { 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 }, +#else + // 2003-10-20 by "Anton A. Arapov" + .audiomux = { 0x001e00, 0, 0x018000, 0x014000, 0x002000, 0 }, +#endif .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = -1, @@ -733,6 +757,7 @@ struct tvcard bttv_tvcards[] = { .has_radio = 1, .tuner_type = 5, // default for now, gpio reads BFFF06 for Pal bg+dk .audio_hook = winfast2000_audio, + .has_remote = 1, },{ .name = "Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II", .video_inputs = 4, @@ -1248,6 +1273,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = 25, + .has_remote = 1, /* GPIO wiring: GPIO0: U4.A0 (hef4052bt) GPIO1: U4.A1 @@ -1283,6 +1309,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = 5, .audio_hook = pvbt878p9b_audio, // Note: not all cards have stereo .has_radio = 1, // Note: not all cards have radio + .has_remote = 1, /* GPIO wiring: GPIO0: A0 hef4052 GPIO1: A1 hef4052 @@ -1751,7 +1778,8 @@ struct tvcard bttv_tvcards[] = { .no_tda7432 = 1, .pll = PLL_28, .tuner_type = -1, - .no_video = 1, + .has_dvb = 1, + .no_gpioirq = 1, },{ /* Jorge Boncompte - DTI2 */ .name = "ProVideo PV143", @@ -1850,6 +1878,62 @@ struct tvcard bttv_tvcards[] = { 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 }, .muxsel_hook = ivc120_muxsel, .pll = PLL_28, +},{ + + /* ---- card 0x70 ---------------------------------- */ + .name = "pcHDTV HD-2000 TV", + .video_inputs = 4, + .audio_inputs = 1, + .tuner = 0, + .svhs = 2, + .muxsel = { 2, 3, 1, 0}, + .tuner_type = TUNER_PHILIPS_ATSC, +},{ + .name = "Twinhan DST + clones", + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, + .tuner_type = TUNER_ABSENT, + .no_video = 1, + .has_dvb = 1, +},{ + .name = "Winfast VC100", + .video_inputs = 3, + .audio_inputs = 0, + .svhs = 1, + .tuner = -1, // no tuner + .muxsel = { 3, 1, 1, 3}, // Vid In, SVid In, Vid over SVid in connector + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, + .tuner_type = TUNER_ABSENT, + .no_video = 1, + .pll = PLL_28, +},{ + .name = "Teppro TEV-560/InterVision IV-560", + .video_inputs = 3, + .audio_inputs = 1, + .tuner = 0, + .svhs = 2, + .gpiomask = 3, + .muxsel = { 2, 3, 1, 1}, + .audiomux = { 1, 1, 1, 1, 0}, + .needs_tvaudio = 1, + .tuner_type = TUNER_PHILIPS_PAL, + .pll = PLL_35, +},{ + + /* ---- card 0x74 ---------------------------------- */ + .name = "SIMUS GVC1100", + .video_inputs = 4, + .audio_inputs = 0, + .tuner = -1, + .svhs = -1, + .tuner_type = -1, + .pll = PLL_28, + .muxsel = { 2, 2, 2, 2}, + .gpiomask = 0x3F, + .muxsel_hook = gvc1100_muxsel, }}; const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); @@ -1868,9 +1952,9 @@ void __devinit bttv_idcard(struct bttv * unsigned short tmp; /* read PCI subsystem ID */ - pci_read_config_word(btv->dev, PCI_SUBSYSTEM_ID, &tmp); + pci_read_config_word(btv->c.pci, PCI_SUBSYSTEM_ID, &tmp); btv->cardid = tmp << 16; - pci_read_config_word(btv->dev, PCI_SUBSYSTEM_VENDOR_ID, &tmp); + pci_read_config_word(btv->c.pci, PCI_SUBSYSTEM_VENDOR_ID, &tmp); btv->cardid |= tmp; if (0 != btv->cardid && 0xffffffff != btv->cardid) { @@ -1883,14 +1967,14 @@ void __devinit bttv_idcard(struct bttv * /* found it */ printk(KERN_INFO "bttv%d: detected: %s [card=%d], " "PCI subsystem ID is %04x:%04x\n", - btv->nr,cards[type].name,cards[type].cardnr, + btv->c.nr,cards[type].name,cards[type].cardnr, btv->cardid & 0xffff, (btv->cardid >> 16) & 0xffff); - btv->type = cards[type].cardnr; + btv->c.type = cards[type].cardnr; } else { /* 404 */ printk(KERN_INFO "bttv%d: subsystem: %04x:%04x (UNKNOWN)\n", - btv->nr, btv->cardid & 0xffff, + btv->c.nr, btv->cardid & 0xffff, (btv->cardid >> 16) & 0xffff); printk(KERN_DEBUG "please mail id, board name and " "the correct card= insmod option to kraxel@bytesex.org\n"); @@ -1898,13 +1982,13 @@ void __devinit bttv_idcard(struct bttv * } /* let the user override the autodetected type */ - if (card[btv->nr] < bttv_num_tvcards) - btv->type=card[btv->nr]; + if (card[btv->c.nr] < bttv_num_tvcards) + btv->c.type=card[btv->c.nr]; /* print which card config we are using */ - printk(KERN_INFO "bttv%d: using: %s [card=%d,%s]\n",btv->nr, - bttv_tvcards[btv->type].name, btv->type, - card[btv->nr] < bttv_num_tvcards + printk(KERN_INFO "bttv%d: using: %s [card=%d,%s]\n",btv->c.nr, + bttv_tvcards[btv->c.type].name, btv->c.type, + card[btv->c.nr] < bttv_num_tvcards ? "insmod option" : "autodetected"); /* overwrite gpio stuff ?? */ @@ -1914,20 +1998,20 @@ void __devinit bttv_idcard(struct bttv * if (UNSET != audiomux[0]) { gpiobits = 0; for (i = 0; i < 5; i++) { - bttv_tvcards[btv->type].audiomux[i] = audiomux[i]; + bttv_tvcards[btv->c.type].audiomux[i] = audiomux[i]; gpiobits |= audiomux[i]; } } else { gpiobits = audioall; for (i = 0; i < 5; i++) { - bttv_tvcards[btv->type].audiomux[i] = audioall; + bttv_tvcards[btv->c.type].audiomux[i] = audioall; } } - bttv_tvcards[btv->type].gpiomask = (UNSET != gpiomask) ? gpiomask : gpiobits; + bttv_tvcards[btv->c.type].gpiomask = (UNSET != gpiomask) ? gpiomask : gpiobits; printk(KERN_INFO "bttv%d: gpio config override: mask=0x%x, mux=", - btv->nr,bttv_tvcards[btv->type].gpiomask); + btv->c.nr,bttv_tvcards[btv->c.type].gpiomask); for (i = 0; i < 5; i++) { - printk("%s0x%x", i ? "," : "", bttv_tvcards[btv->type].audiomux[i]); + printk("%s0x%x", i ? "," : "", bttv_tvcards[btv->c.type].audiomux[i]); } printk("\n"); } @@ -1941,7 +2025,7 @@ void identify_by_eeprom(struct bttv *btv { int type = -1; - if (0 == strncmp(eeprom_data,"GET.MM20xPCTV",13)) + if (0 == strncmp(eeprom_data,"GET MM20xPCTV",13)) type = BTTV_MODTEC_205; else if (0 == strncmp(eeprom_data+20,"Picolo",7)) type = BTTV_EURESYS_PICOLO; @@ -1949,22 +2033,22 @@ void identify_by_eeprom(struct bttv *btv type = BTTV_HAUPPAUGE; /* old bt848 */ if (-1 != type) { - btv->type = type; + btv->c.type = type; printk("bttv%d: detected by eeprom: %s [card=%d]\n", - btv->nr, bttv_tvcards[btv->type].name, btv->type); + btv->c.nr, bttv_tvcards[btv->c.type].name, btv->c.type); } } static void flyvideo_gpio(struct bttv *btv) { - int gpio,outbits,has_remote,has_radio,is_capture_only,is_lr90,has_tda9820_tda9821; + int gpio,has_remote,has_radio,is_capture_only,is_lr90,has_tda9820_tda9821; int tuner=-1,ttype; - - outbits = btread(BT848_GPIO_OUT_EN); - btwrite(0x00, BT848_GPIO_OUT_EN); + + gpio_inout(0xffffff, 0); udelay(8); // without this we would see the 0x1800 mask - gpio=btread(BT848_GPIO_DATA); - btwrite(outbits, BT848_GPIO_OUT_EN); + gpio = gpio_read(); + /* FIXME: must restore OUR_EN ??? */ + // all cards provide GPIO info, some have an additional eeprom // LR50: GPIO coding can be found lower right CP1 .. CP9 // CP9=GPIO23 .. CP1=GPIO15; when OPEN, the corresponding GPIO reads 1. @@ -1989,7 +2073,7 @@ static void flyvideo_gpio(struct bttv *b case 0xC: tuner=3; // Philips SECAM(+PAL) FQ1216ME or FI1216MF break; default: - printk(KERN_INFO "bttv%d: FlyVideo_gpio: unknown tuner type.\n", btv->nr); + printk(KERN_INFO "bttv%d: FlyVideo_gpio: unknown tuner type.\n", btv->c.nr); } has_remote = gpio & 0x800000; @@ -2005,9 +2089,9 @@ static void flyvideo_gpio(struct bttv *b tuner=4; // No tuner present printk(KERN_INFO "bttv%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n", - btv->nr, has_radio? "yes":"no ", has_remote? "yes":"no ", tuner, gpio); + btv->c.nr, has_radio? "yes":"no ", has_remote? "yes":"no ", tuner, gpio); printk(KERN_INFO "bttv%d: FlyVideo LR90=%s tda9821/tda9820=%s capture_only=%s\n", - btv->nr, is_lr90?"yes":"no ", has_tda9820_tda9821?"yes":"no ", + btv->c.nr, is_lr90?"yes":"no ", has_tda9820_tda9821?"yes":"no ", is_capture_only?"yes":"no "); if(tuner!= -1) // only set if known tuner autodetected, else let insmod option through @@ -2031,8 +2115,8 @@ static void miro_pinnacle_gpio(struct bt int id,msp,gpio; char *info; - btwrite(0,BT848_GPIO_OUT_EN); - gpio = btread(BT848_GPIO_DATA); + gpio_inout(0xffffff, 0); + gpio = gpio_read(); id = ((gpio>>10) & 63) -1; msp = bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx"); if (id < 32) { @@ -2051,14 +2135,14 @@ static void miro_pinnacle_gpio(struct bt btv->has_radio = 0; } if (-1 != msp) { - if (btv->type == BTTV_MIRO) - btv->type = BTTV_MIROPRO; - if (btv->type == BTTV_PINNACLE) - btv->type = BTTV_PINNACLEPRO; + if (btv->c.type == BTTV_MIRO) + btv->c.type = BTTV_MIROPRO; + if (btv->c.type == BTTV_PINNACLE) + btv->c.type = BTTV_PINNACLEPRO; } printk(KERN_INFO "bttv%d: miro: id=%d tuner=%d radio=%s stereo=%s\n", - btv->nr, id+1, btv->tuner_type, + btv->c.nr, id+1, btv->tuner_type, !btv->has_radio ? "no" : (btv->has_matchbox ? "matchbox" : "fmtuner"), (-1 == msp) ? "no" : "yes"); @@ -2092,10 +2176,10 @@ static void miro_pinnacle_gpio(struct bt break; } if (-1 != msp) - btv->type = BTTV_PINNACLEPRO; + btv->c.type = BTTV_PINNACLEPRO; printk(KERN_INFO "bttv%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n", - btv->nr, id, info, btv->has_radio ? "yes" : "no"); + btv->c.nr, id, info, btv->has_radio ? "yes" : "no"); btv->tuner_type = 33; btv->pinnacle_id = id; } @@ -2106,16 +2190,14 @@ static void miro_pinnacle_gpio(struct bt static void init_ids_eagle(struct bttv *btv) { - btwrite(0xFFFF37, BT848_GPIO_OUT_EN); - btwrite(0x000000, BT848_GPIO_REG_INP); - - btwrite(0x200020, BT848_GPIO_DATA); + gpio_inout(0xffffff,0xFFFF37); + gpio_write(0x200020); /* flash strobe inverter ?! */ - btwrite(0x200024, BT848_GPIO_DATA); + gpio_write(0x200024); /* switch sync drive off */ - btor(LM1882_SYNC_DRIVE, BT848_GPIO_DATA); + gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE); /* set BT848 muxel to 2 */ btaor((2)<<5, ~(2<<5), BT848_IFORM); @@ -2127,8 +2209,7 @@ static void init_ids_eagle(struct bttv * static void eagle_muxsel(struct bttv *btv, unsigned int input) { btaor((2)<<5, ~(3<<5), BT848_IFORM); - btaor((bttv_tvcards[btv->type].muxsel[input&7]&3), - ~3, BT848_GPIO_DATA); + gpio_bits(3,bttv_tvcards[btv->c.type].muxsel[input&7]); #if 0 /* svhs */ @@ -2147,7 +2228,13 @@ static void eagle_muxsel(struct bttv *bt #endif /* switch sync drive off */ - btor(LM1882_SYNC_DRIVE, BT848_GPIO_DATA); + gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE); +} + +static void gvc1100_muxsel(struct bttv *btv, unsigned int input) +{ + static const int masks[] = {0x30, 0x01, 0x12, 0x23}; + gpio_write(masks[input%4]); } /* ----------------------------------------------------------------------- */ @@ -2167,7 +2254,7 @@ void bttv_reset_audio(struct bttv *btv) return; if (bttv_debug) - printk("bttv%d: BT878A ARESET\n",btv->nr); + printk("bttv%d: BT878A ARESET\n",btv->c.nr); btwrite((1<<7), 0x058); udelay(10); btwrite( 0, 0x058); @@ -2176,7 +2263,7 @@ void bttv_reset_audio(struct bttv *btv) /* initialization part one -- before registering i2c bus */ void __devinit bttv_init_card1(struct bttv *btv) { - switch (btv->type) { + switch (btv->c.type) { case BTTV_HAUPPAUGE: case BTTV_HAUPPAUGE878: boot_msp34xx(btv,5); @@ -2198,12 +2285,12 @@ void __devinit bttv_init_card2(struct bt { btv->tuner_type = -1; - if (BTTV_UNKNOWN == btv->type) { + if (BTTV_UNKNOWN == btv->c.type) { bttv_readee(btv,eeprom_data,0xa0); identify_by_eeprom(btv,eeprom_data); } - switch (btv->type) { + switch (btv->c.type) { case BTTV_MIRO: case BTTV_MIROPRO: case BTTV_PINNACLE: @@ -2255,7 +2342,7 @@ void __devinit bttv_init_card2(struct bt case BTTV_MAGICTVIEW061: if (btv->cardid == 0x3002144f) { btv->has_radio=1; - printk("bttv%d: radio detected by subsystem id (CPH05x)\n",btv->nr); + printk("bttv%d: radio detected by subsystem id (CPH05x)\n",btv->c.nr); } break; case BTTV_STB2: @@ -2292,16 +2379,16 @@ void __devinit bttv_init_card2(struct bt /* pll configuration */ if (!(btv->id==848 && btv->revision==0x11)) { /* defaults from card list */ - if (PLL_28 == bttv_tvcards[btv->type].pll) { + if (PLL_28 == bttv_tvcards[btv->c.type].pll) { btv->pll.pll_ifreq=28636363; btv->pll.pll_crystal=BT848_IFORM_XT0; } - if (PLL_35 == bttv_tvcards[btv->type].pll) { + if (PLL_35 == bttv_tvcards[btv->c.type].pll) { btv->pll.pll_ifreq=35468950; btv->pll.pll_crystal=BT848_IFORM_XT1; } /* insmod options can override */ - switch (pll[btv->nr]) { + switch (pll[btv->c.nr]) { case 0: /* none */ btv->pll.pll_crystal = 0; btv->pll.pll_ifreq = 0; @@ -2324,27 +2411,33 @@ void __devinit bttv_init_card2(struct bt btv->pll.pll_current = -1; /* tuner configuration (from card list / autodetect / insmod option) */ - if (UNSET != bttv_tvcards[btv->type].tuner_type) + if (UNSET != bttv_tvcards[btv->c.type].tuner_type) if(UNSET == btv->tuner_type) - btv->tuner_type = bttv_tvcards[btv->type].tuner_type; - if (UNSET != tuner[btv->nr]) - btv->tuner_type = tuner[btv->nr]; - printk("bttv%d: using tuner=%d\n",btv->nr,btv->tuner_type); + btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type; + if (UNSET != tuner[btv->c.nr]) + btv->tuner_type = tuner[btv->c.nr]; + printk("bttv%d: using tuner=%d\n",btv->c.nr,btv->tuner_type); if (btv->pinnacle_id != UNSET) bttv_call_i2c_clients(btv,AUDC_CONFIG_PINNACLE, &btv->pinnacle_id); if (btv->tuner_type != UNSET) bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); - btv->svhs = bttv_tvcards[btv->type].svhs; - if (svhs[btv->nr] != UNSET) - btv->svhs = svhs[btv->nr]; + btv->svhs = bttv_tvcards[btv->c.type].svhs; + if (svhs[btv->c.nr] != UNSET) + btv->svhs = svhs[btv->c.nr]; + if (remote[btv->c.nr] != UNSET) + btv->has_remote = remote[btv->c.nr]; - if (bttv_tvcards[btv->type].has_radio) + if (bttv_tvcards[btv->c.type].has_radio) btv->has_radio=1; - if (bttv_tvcards[btv->type].audio_hook) - btv->audio_hook=bttv_tvcards[btv->type].audio_hook; + if (bttv_tvcards[btv->c.type].has_remote) + btv->has_remote=1; + if (bttv_tvcards[btv->c.type].no_gpioirq) + btv->gpioirq=0; + if (bttv_tvcards[btv->c.type].audio_hook) + btv->audio_hook=bttv_tvcards[btv->c.type].audio_hook; - if (bttv_tvcards[btv->type].digital_mode == DIGITAL_MODE_CAMERA) { + if (bttv_tvcards[btv->c.type].digital_mode == DIGITAL_MODE_CAMERA) { /* detect Bt832 chip for quartzsight digital camera */ if ((bttv_I2CRead(btv, I2C_BT832_ALT1, "Bt832") >=0) || (bttv_I2CRead(btv, I2C_BT832_ALT2, "Bt832") >=0)) @@ -2352,31 +2445,31 @@ void __devinit bttv_init_card2(struct bt } /* try to detect audio/fader chips */ - if (!bttv_tvcards[btv->type].no_msp34xx && + if (!bttv_tvcards[btv->c.type].no_msp34xx && bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx") >=0) { if (autoload) request_module("msp3400"); } - if (bttv_tvcards[btv->type].msp34xx_alt && + if (bttv_tvcards[btv->c.type].msp34xx_alt && bttv_I2CRead(btv, I2C_MSP3400_ALT, "MSP34xx (alternate address)") >=0) { if (autoload) request_module("msp3400"); } - if (!bttv_tvcards[btv->type].no_tda9875 && + if (!bttv_tvcards[btv->c.type].no_tda9875 && bttv_I2CRead(btv, I2C_TDA9875, "TDA9875") >=0) { if (autoload) request_module("tda9875"); } - if (!bttv_tvcards[btv->type].no_tda7432 && + if (!bttv_tvcards[btv->c.type].no_tda7432 && bttv_I2CRead(btv, I2C_TDA7432, "TDA7432") >=0) { if (autoload) request_module("tda7432"); } - if (bttv_tvcards[btv->type].needs_tvaudio) { + if (bttv_tvcards[btv->c.type].needs_tvaudio) { if (autoload) request_module("tvaudio"); } @@ -2460,11 +2553,15 @@ static void modtec_eeprom(struct bttv *b { if( strncmp(&(eeprom_data[0x1e]),"Temic 4066 FY5",14) ==0) { btv->tuner_type=TUNER_TEMIC_4066FY5_PAL_I; - printk("bttv Modtec: Tuner autodetected %s\n", - &eeprom_data[0x1e]); + printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n", + btv->c.nr,&eeprom_data[0x1e]); + } else if (strncmp(&(eeprom_data[0x1e]),"Alps TSBB5",10) ==0) { + btv->tuner_type=TUNER_ALPS_TSBB5_PAL_I; + printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n", + btv->c.nr,&eeprom_data[0x1e]); } else { - printk("bttv Modtec: Unknown TunerString:%s\n", - &eeprom_data[0x1e]); + printk("bttv%d: Modtec: Unknown TunerString: %s\n", + btv->c.nr,&eeprom_data[0x1e]); } } @@ -2474,7 +2571,7 @@ static void __devinit hauppauge_eeprom(s if (eeprom_data[0] != 0x84 || eeprom_data[2] != 0) printk(KERN_WARNING "bttv%d: Hauppauge eeprom: invalid\n", - btv->nr); + btv->c.nr); /* Block 2 starts after len+3 bytes header */ blk2 = eeprom_data[1] + 3; @@ -2492,7 +2589,7 @@ static void __devinit hauppauge_eeprom(s if (bttv_verbose) printk(KERN_INFO "bttv%d: Hauppauge eeprom: model=%d, " "tuner=%s (%d), radio=%s\n", - btv->nr, model, hauppauge_tuner[tuner].name, + btv->c.nr, model, hauppauge_tuner[tuner].name, btv->tuner_type, radio ? "yes" : "no"); } @@ -2516,7 +2613,7 @@ static int terratec_active_radio_upgrade tea5757_write(btv, 5 * freq + 0x358); // write 0x1ed8 if (0x1ed8 == tea5757_read(btv)) { printk("bttv%d: Terratec Active Radio Upgrade found.\n", - btv->nr); + btv->c.nr); btv->has_radio = 1; btv->has_matchbox = 1; } else { @@ -2547,36 +2644,35 @@ static int __devinit pvr_altera_load(str u32 n; u8 bits; int i; - - btwrite(BTTV_ALT_DATA|BTTV_ALT_DCLK|BTTV_ALT_NCONFIG, - BT848_GPIO_OUT_EN); - btwrite(0,BT848_GPIO_DATA); + + gpio_inout(0xffffff,BTTV_ALT_DATA|BTTV_ALT_DCLK|BTTV_ALT_NCONFIG); + gpio_write(0); udelay(PVR_GPIO_DELAY); - btwrite(BTTV_ALT_NCONFIG,BT848_GPIO_DATA); + gpio_write(BTTV_ALT_NCONFIG); udelay(PVR_GPIO_DELAY); for (n = 0; n < microlen; n++) { bits = micro[n]; for ( i = 0 ; i < 8 ; i++ ) { - btand(~BTTV_ALT_DCLK,BT848_GPIO_DATA); - if (bits & 0x01) - btor(BTTV_ALT_DATA,BT848_GPIO_DATA); + gpio_bits(BTTV_ALT_DCLK,0); + if (bits & 0x01) + gpio_bits(BTTV_ALT_DATA,BTTV_ALT_DATA); else - btand(~BTTV_ALT_DATA,BT848_GPIO_DATA); - btor(BTTV_ALT_DCLK,BT848_GPIO_DATA); + gpio_bits(BTTV_ALT_DATA,0); + gpio_bits(BTTV_ALT_DCLK,BTTV_ALT_DCLK); bits >>= 1; } } - btand(~BTTV_ALT_DCLK,BT848_GPIO_DATA); + gpio_bits(BTTV_ALT_DCLK,0); udelay(PVR_GPIO_DELAY); /* begin Altera init loop (Not necessary,but doesn't hurt) */ for (i = 0 ; i < 30 ; i++) { - btand(~BTTV_ALT_DCLK,BT848_GPIO_DATA); - btor(BTTV_ALT_DCLK,BT848_GPIO_DATA); + gpio_bits(BTTV_ALT_DCLK,0); + gpio_bits(BTTV_ALT_DCLK,BTTV_ALT_DCLK); } - btand(~BTTV_ALT_DCLK,BT848_GPIO_DATA); + gpio_bits(BTTV_ALT_DCLK,0); return 0; } @@ -2599,15 +2695,15 @@ int __devinit pvr_boot(struct bttv *btv) microlen = mod_firmware_load(firm_altera, (char**) µ); if (!microlen) { printk(KERN_WARNING "bttv%d: altera firmware not found [%s]\n", - btv->nr, firm_altera); + btv->c.nr, firm_altera); return -1; } printk(KERN_INFO "bttv%d: uploading altera firmware [%s] ...\n", - btv->nr, firm_altera); + btv->c.nr, firm_altera); result = pvr_altera_load(btv, micro, microlen); printk(KERN_INFO "bttv%d: ... upload %s\n", - btv->nr, (result < 0) ? "failed" : "ok"); + btv->c.nr, (result < 0) ? "failed" : "ok"); vfree(micro); return result; } @@ -2619,15 +2715,15 @@ int __devinit pvr_boot(struct bttv *btv) const struct firmware *fw_entry; int rc; - rc = request_firmware(&fw_entry, "hcwamc.rbf", &btv->dev->dev); + rc = request_firmware(&fw_entry, "hcwamc.rbf", &btv->c.pci->dev); if (rc != 0) { printk(KERN_WARNING "bttv%d: no altera firmware [via hotplug]\n", - btv->nr); + btv->c.nr); return rc; } rc = pvr_altera_load(btv, fw_entry->data, fw_entry->size); printk(KERN_INFO "bttv%d: altera firmware upload %s\n", - btv->nr, (rc < 0) ? "failed" : "ok"); + btv->c.nr, (rc < 0) ? "failed" : "ok"); release_firmware(fw_entry); return rc; } @@ -2642,7 +2738,7 @@ static void __devinit osprey_eeprom(stru unsigned char *ee = eeprom_data; unsigned long serial = 0; - if (btv->type == 0) { + if (btv->c.type == 0) { /* this might be an antique... check for MMAC label in eeprom */ if ((ee[0]=='M') && (ee[1]=='M') && (ee[2]=='A') && (ee[3]=='C')) { unsigned char checksum = 0; @@ -2650,7 +2746,7 @@ static void __devinit osprey_eeprom(stru checksum += ee[i]; if (checksum != ee[21]) return; - btv->type = BTTV_OSPREY1x0_848; + btv->c.type = BTTV_OSPREY1x0_848; for (i = 12; i < 21; i++) serial *= 10, serial += ee[i] - '0'; } @@ -2679,49 +2775,49 @@ static void __devinit osprey_eeprom(stru /* 848 based */ case 0x0004: - btv->type = BTTV_OSPREY1x0_848; + btv->c.type = BTTV_OSPREY1x0_848; break; case 0x0005: - btv->type = BTTV_OSPREY101_848; + btv->c.type = BTTV_OSPREY101_848; break; /* 878 based */ case 0x0012: case 0x0013: - btv->type = BTTV_OSPREY1x0; + btv->c.type = BTTV_OSPREY1x0; break; case 0x0014: case 0x0015: - btv->type = BTTV_OSPREY1x1; + btv->c.type = BTTV_OSPREY1x1; break; case 0x0016: case 0x0017: case 0x0020: - btv->type = BTTV_OSPREY1x1_SVID; + btv->c.type = BTTV_OSPREY1x1_SVID; break; case 0x0018: case 0x0019: case 0x001E: case 0x001F: - btv->type = BTTV_OSPREY2xx; + btv->c.type = BTTV_OSPREY2xx; break; case 0x001A: case 0x001B: - btv->type = BTTV_OSPREY2x0_SVID; + btv->c.type = BTTV_OSPREY2x0_SVID; break; case 0x0040: - btv->type = BTTV_OSPREY500; + btv->c.type = BTTV_OSPREY500; break; case 0x0050: case 0x0056: - btv->type = BTTV_OSPREY540; + btv->c.type = BTTV_OSPREY540; /* bttv_osprey_540_init(btv); */ break; case 0x0060: case 0x0070: - btv->type = BTTV_OSPREY2x0; + btv->c.type = BTTV_OSPREY2x0; //enable output on select control lines - btwrite(0x000303, BT848_GPIO_OUT_EN); + gpio_inout(0xffffff,0x000303); break; default: /* unknown...leave generic, but get serial # */ @@ -2734,7 +2830,7 @@ static void __devinit osprey_eeprom(stru } printk(KERN_INFO "bttv%d: osprey eeprom: card=%d name=%s serial=%ld\n", - btv->nr, btv->type, bttv_tvcards[btv->type].name,serial); + btv->c.nr, btv->c.type, bttv_tvcards[btv->c.type].name,serial); } /* ----------------------------------------------------------------------- */ @@ -2779,7 +2875,7 @@ static void __devinit avermedia_eeprom(s tuner = tuner_1_table[tuner_format]; printk(KERN_INFO "bttv%d: Avermedia eeprom[0x%02x%02x]: tuner=", - btv->nr,eeprom_data[0x41],eeprom_data[0x42]); + btv->c.nr,eeprom_data[0x41],eeprom_data[0x42]); if(tuner) { btv->tuner_type=tuner; printk("%d",tuner); @@ -2805,8 +2901,8 @@ void bttv_tda9880_setnorm(struct bttv *b dprintk("bttv_tda9880_setnorm to PAL\n"); } // set GPIO according - btaor(bttv_tvcards[btv->type].audiomux[btv->audio], - ~bttv_tvcards[btv->type].gpiomask, BT848_GPIO_DATA); + gpio_bits(bttv_tvcards[btv->c.type].gpiomask, + bttv_tvcards[btv->c.type].audiomux[btv->audio]); } @@ -2821,23 +2917,23 @@ static void __devinit boot_msp34xx(struc { int mask = (1 << pin); - btaor(mask, ~mask, BT848_GPIO_OUT_EN); - btaor(0, ~mask, BT848_GPIO_DATA); + gpio_inout(mask,mask); + gpio_bits(mask,0); udelay(2500); - btaor(mask, ~mask, BT848_GPIO_DATA); + gpio_bits(mask,mask); + if (bttv_gpio) bttv_gpio_tracking(btv,"msp34xx"); - if (bttv_verbose) printk(KERN_INFO "bttv%d: Hauppauge/Voodoo msp34xx: reset line " - "init [%d]\n", btv->nr, pin); + "init [%d]\n", btv->c.nr, pin); } static void __devinit boot_bt832(struct bttv *btv) { - int outbits,databits,resetbit=0; + int resetbit=0; - switch (btv->type) { + switch (btv->c.type) { case BTTV_PXELVWPLTVPAK: resetbit = 0x400000; break; @@ -2851,18 +2947,14 @@ static void __devinit boot_bt832(struct request_module("bt832"); bttv_call_i2c_clients(btv, BT832_HEXDUMP, NULL); - printk("bttv%d: Reset Bt832 [line=0x%x]\n",btv->nr,resetbit); - btwrite(0, BT848_GPIO_DATA); - outbits = btread(BT848_GPIO_OUT_EN); - databits= btread(BT848_GPIO_DATA); - btwrite(resetbit, BT848_GPIO_OUT_EN); + printk("bttv%d: Reset Bt832 [line=0x%x]\n",btv->c.nr,resetbit); + gpio_write(0); + gpio_inout(resetbit, resetbit); udelay(5); - btwrite(resetbit, BT848_GPIO_DATA); + gpio_bits(resetbit, resetbit); udelay(5); - btwrite(0, BT848_GPIO_DATA); + gpio_bits(resetbit, 0); udelay(5); - btwrite(outbits, BT848_GPIO_OUT_EN); - btwrite(databits, BT848_GPIO_DATA); // bt832 on pixelview changes from i2c 0x8a to 0x88 after // being reset as above. So we must follow by this: @@ -2885,13 +2977,13 @@ static void __devinit init_PXC200(struct u32 val; /* Initialise GPIO-connevted stuff */ - btwrite(1<<13,BT848_GPIO_OUT_EN); /* Reset pin only */ - btwrite(0,BT848_GPIO_DATA); + gpio_bits(0xffffff, (1<<13)); + gpio_write(0); udelay(3); - btwrite(1<<13,BT848_GPIO_DATA); + gpio_write(1<<13); /* GPIO inputs are pulled up, so no need to drive * reset pin any longer */ - btwrite(0,BT848_GPIO_OUT_EN); + gpio_bits(0xffffff, 0); if (bttv_gpio) bttv_gpio_tracking(btv,"pxc200"); @@ -2926,10 +3018,10 @@ static void __devinit init_PXC200(struct * device same as above for the reset line, but not the same * value sent to the GPIO-connected stuff * which one is the good one? */ - btwrite( (1<<2), BT848_GPIO_OUT_EN); /* only the reset pin */ - btwrite(0, BT848_GPIO_DATA); + gpio_inout(0xffffff,(1<<2)); + gpio_write(0); udelay(10); - btwrite(1<<2, BT848_GPIO_DATA); + gpio_write(1<<2); for (i = 0; i < ARRAY_SIZE(vals); i++) { tmp=bttv_I2CWrite(btv,0x1E,0,vals[i],1); @@ -2956,17 +3048,16 @@ static void __devinit init_PXC200(struct void bus_low(struct bttv *btv, int bit) { if (btv->mbox_ior) { - btor(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, - BT848_GPIO_DATA); + gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, + btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); udelay(5); } - btand(~(bit), BT848_GPIO_DATA); + gpio_bits(bit,0); udelay(5); if (btv->mbox_ior) { - btand(~(btv->mbox_iow | btv->mbox_csel), - BT848_GPIO_DATA); + gpio_bits(btv->mbox_iow | btv->mbox_csel, 0); udelay(5); } } @@ -2974,17 +3065,16 @@ void bus_low(struct bttv *btv, int bit) void bus_high(struct bttv *btv, int bit) { if (btv->mbox_ior) { - btor(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, - BT848_GPIO_DATA); + gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, + btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); udelay(5); } - btor((bit), BT848_GPIO_DATA); + gpio_bits(bit,bit); udelay(5); if (btv->mbox_ior) { - btand(~(btv->mbox_iow | btv->mbox_csel), - BT848_GPIO_DATA); + gpio_bits(btv->mbox_iow | btv->mbox_csel, 0); udelay(5); } } @@ -2992,15 +3082,14 @@ void bus_high(struct bttv *btv, int bit) int bus_in(struct bttv *btv, int bit) { if (btv->mbox_ior) { - btor(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, - BT848_GPIO_DATA); + gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, + btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); udelay(5); - btand(~(btv->mbox_ior | btv->mbox_csel), - BT848_GPIO_DATA); + gpio_bits(btv->mbox_iow | btv->mbox_csel, 0); udelay(5); } - return btread(BT848_GPIO_DATA) & (bit); + return gpio_read() & (bit); } /* TEA5757 register bits */ @@ -3038,12 +3127,11 @@ static int tea5757_read(struct bttv *btv int i; /* better safe than sorry */ - btaor((btv->mbox_clk | btv->mbox_we), - ~btv->mbox_mask, BT848_GPIO_OUT_EN); + gpio_inout(btv->mbox_mask, btv->mbox_clk | btv->mbox_we); if (btv->mbox_ior) { - btor(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, - BT848_GPIO_DATA); + gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, + btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); udelay(5); } @@ -3060,11 +3148,11 @@ static int tea5757_read(struct bttv *btv while (bus_in(btv,btv->mbox_data) && time_before(jiffies, timeout)) schedule(); if (bus_in(btv,btv->mbox_data)) { - printk(KERN_WARNING "bttv%d: tea5757: read timeout\n",btv->nr); + printk(KERN_WARNING "bttv%d: tea5757: read timeout\n",btv->c.nr); return -1; } - dprintk("bttv%d: tea5757:",btv->nr); + dprintk("bttv%d: tea5757:",btv->c.nr); for(i = 0; i < 24; i++) { udelay(5); @@ -3076,7 +3164,7 @@ static int tea5757_read(struct bttv *btv value |= (bus_in(btv,btv->mbox_data) == 0)?0:1; /* MSB first */ dprintk("%c", (bus_in(btv,btv->mbox_most) == 0)?'S':'M'); } - dprintk("\nbttv%d: tea5757: read 0x%X\n", btv->nr, value); + dprintk("\nbttv%d: tea5757: read 0x%X\n", btv->c.nr, value); return value; } @@ -3085,18 +3173,17 @@ static int tea5757_write(struct bttv *bt int i; int reg = value; - btaor(btv->mbox_clk | btv->mbox_we | btv->mbox_data, - ~btv->mbox_mask, BT848_GPIO_OUT_EN); + gpio_inout(btv->mbox_mask, btv->mbox_clk | btv->mbox_we | btv->mbox_data); if (btv->mbox_ior) { - btor(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, - BT848_GPIO_DATA); + gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, + btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); udelay(5); } if (bttv_gpio) bttv_gpio_tracking(btv,"tea5757 write"); - dprintk("bttv%d: tea5757: write 0x%X\n", btv->nr, value); + dprintk("bttv%d: tea5757: write 0x%X\n", btv->c.nr, value); bus_low(btv,btv->mbox_clk); bus_high(btv,btv->mbox_we); for(i = 0; i < 25; i++) @@ -3122,7 +3209,7 @@ void tea5757_set_freq(struct bttv *btv, #if 0 /* breaks Miro PCTV */ value = tea5757_read(btv); - dprintk("bttv%d: tea5757 readback=0x%x\n",btv->nr,value); + dprintk("bttv%d: tea5757 readback=0x%x\n",btv->c.nr,value); #endif } @@ -3148,7 +3235,7 @@ void winview_audio(struct bttv *btv, str /* tens */ bits_out |= (PT2254_DBS_IN_10>>(vol/5)); bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL; - data = btread(BT848_GPIO_DATA); + data = gpio_read(); data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA| WINVIEW_PT2254_STROBE); for (loops = 17; loops >= 0 ; loops--) { @@ -3156,20 +3243,20 @@ void winview_audio(struct bttv *btv, str data |= WINVIEW_PT2254_DATA; else data &= ~WINVIEW_PT2254_DATA; - btwrite(data, BT848_GPIO_DATA); + gpio_write(data); udelay(5); data |= WINVIEW_PT2254_CLK; - btwrite(data, BT848_GPIO_DATA); + gpio_write(data); udelay(5); data &= ~WINVIEW_PT2254_CLK; - btwrite(data, BT848_GPIO_DATA); + gpio_write(data); } data |= WINVIEW_PT2254_STROBE; data &= ~WINVIEW_PT2254_DATA; - btwrite(data, BT848_GPIO_DATA); + gpio_write(data); udelay(10); data &= ~WINVIEW_PT2254_STROBE; - btwrite(data, BT848_GPIO_DATA); + gpio_write(data); } /* ----------------------------------------------------------------------- */ @@ -3182,7 +3269,7 @@ gvbctv3pci_audio(struct bttv *btv, struc unsigned int con = 0; if (set) { - btor(0x300, BT848_GPIO_OUT_EN); + gpio_inout(0x300, 0x300); if (v->mode & VIDEO_SOUND_LANG1) con = 0x000; if (v->mode & VIDEO_SOUND_LANG2) @@ -3191,7 +3278,7 @@ gvbctv3pci_audio(struct bttv *btv, struc con = 0x200; // if (v->mode & VIDEO_SOUND_MONO) // con = 0x100; - btaor(con, ~0x300, BT848_GPIO_DATA); + gpio_bits(0x300, con); } else { v->mode = VIDEO_SOUND_STEREO | VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; @@ -3217,12 +3304,12 @@ avermedia_tvphone_audio(struct bttv *btv int val = 0; if (set) { - if (v->mode & VIDEO_SOUND_LANG1) /* SAP */ + if (v->mode & VIDEO_SOUND_LANG2) /* SAP */ val = 0x02; if (v->mode & VIDEO_SOUND_STEREO) val = 0x01; if (val) { - btaor(val, ~0x03, BT848_GPIO_DATA); + gpio_bits(0x03,val); if (bttv_gpio) bttv_gpio_tracking(btv,"avermedia"); } @@ -3233,13 +3320,33 @@ avermedia_tvphone_audio(struct bttv *btv } } +static void +avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v, int set) +{ + int val = 0; + + if (set) { + if (v->mode & VIDEO_SOUND_LANG2) /* SAP */ + val = 0x01; + if (v->mode & VIDEO_SOUND_STEREO) /* STEREO */ + val = 0x02; + btaor(val, ~0x03, BT848_GPIO_DATA); + if (bttv_gpio) + bttv_gpio_tracking(btv,"avermedia"); + } else { + v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + return; + } +} + /* Lifetec 9415 handling */ static void lt9415_audio(struct bttv *btv, struct video_audio *v, int set) { int val = 0; - if (btread(BT848_GPIO_DATA) & 0x4000) { + if (gpio_read() & 0x4000) { v->mode = VIDEO_SOUND_MONO; return; } @@ -3252,7 +3359,7 @@ lt9415_audio(struct bttv *btv, struct vi if ((v->mode & VIDEO_SOUND_LANG1) || (v->mode & VIDEO_SOUND_MONO)) val = 0; - btaor(val, ~0x0880, BT848_GPIO_DATA); + gpio_bits(0x0880, val); if (bttv_gpio) bttv_gpio_tracking(btv,"lt9415"); } else { @@ -3270,12 +3377,12 @@ terratv_audio(struct bttv *btv, struct v unsigned int con = 0; if (set) { - btor(0x180000, BT848_GPIO_OUT_EN); + gpio_inout(0x180000,0x180000); if (v->mode & VIDEO_SOUND_LANG2) con = 0x080000; if (v->mode & VIDEO_SOUND_STEREO) con = 0x180000; - btaor(con, ~0x180000, BT848_GPIO_DATA); + gpio_bits(0x180000, con); if (bttv_gpio) bttv_gpio_tracking(btv,"terratv"); } else { @@ -3300,7 +3407,7 @@ winfast2000_audio(struct bttv *btv, stru if (v->mode & VIDEO_SOUND_STEREO) /* Stereo */ val = 0x020000; if (val) { - btaor(val, ~0x430000, BT848_GPIO_DATA); + gpio_bits(0x430000, val); if (bttv_gpio) bttv_gpio_tracking(btv,"winfast2000"); } @@ -3340,7 +3447,7 @@ pvbt878p9b_audio(struct bttv *btv, struc val = 0x02; } if (val) { - btaor(val, ~0x03, BT848_GPIO_DATA); + gpio_bits(0x03,val); if (bttv_gpio) bttv_gpio_tracking(btv,"pvbt878p9b"); } @@ -3376,7 +3483,7 @@ fv2000s_audio(struct bttv *btv, struct v val = 0x1080; //-dk-???: 0x0880, 0x0080, 0x1800 ... } if (val != 0xffff) { - btaor(val, ~0x1800, BT848_GPIO_DATA); + gpio_bits(0x1800, val); if (bttv_gpio) bttv_gpio_tracking(btv,"fv2000s"); } @@ -3405,7 +3512,7 @@ windvr_audio(struct bttv *btv, struct vi if (v->mode & VIDEO_SOUND_STEREO) val = 0; if (val) { - btaor(val, ~0x140000, BT848_GPIO_DATA); + gpio_bits(0x140000, val); if (bttv_gpio) bttv_gpio_tracking(btv,"windvr"); } @@ -3437,7 +3544,7 @@ adtvk503_audio(struct bttv *btv, struct if (v->mode & VIDEO_SOUND_MONO) con = 0x00060000; if (con != 0xffffff) { - btaor(con, ~0x1e0000, BT848_GPIO_DATA); + gpio_bits(0x1e0000,con); if (bttv_gpio) bttv_gpio_tracking(btv, "adtvk503"); } @@ -3474,16 +3581,16 @@ adtvk503_audio(struct bttv *btv, struct static void rv605_muxsel(struct bttv *btv, unsigned int input) { /* reset all conections */ - btaor(0x200,~0x200, BT848_GPIO_DATA); + gpio_bits(0x200,0x200); mdelay(1); - btaor(0x000,~0x200, BT848_GPIO_DATA); + gpio_bits(0x200,0x000); mdelay(1); /* create a new conection */ - btaor(0x080,~0x480, BT848_GPIO_DATA); - btaor(0x480,~0x480, BT848_GPIO_DATA); + gpio_bits(0x480,0x080); + gpio_bits(0x480,0x480); mdelay(1); - btaor(0x080,~0x480, BT848_GPIO_DATA); + gpio_bits(0x480,0x080); mdelay(1); } @@ -3513,7 +3620,7 @@ static void xguard_muxsel(struct bttv *b ENB1, ENB1|IN01, ENB1|IN11, ENB1|IN01|IN11, ENA1, ENA1|IN01, ENA1|IN11, ENA1|IN01|IN11, }; - btwrite(masks[input%16], BT848_GPIO_DATA); + gpio_write(masks[input%16]); } /* @@ -3555,7 +3662,7 @@ static void ivc120_muxsel(struct bttv *b int matrix = input / 4; dprintk("bttv%d: ivc120_muxsel: Input - %02d | TDA - %02d | In - %02d\n", - btv->nr, input, matrix, key); + btv->c.nr, input, matrix, key); // Handles the input selection on the TDA8540's bttv_I2CWrite(btv, I2C_TDA8540_ALT3, 0x00, @@ -3641,12 +3748,12 @@ int __devinit bttv_handle_chipset(struct if (bttv_verbose) { if (triton1) - printk(KERN_INFO "bttv%d: enabling ETBF (430FX/VP3 compatibilty)\n",btv->nr); + printk(KERN_INFO "bttv%d: enabling ETBF (430FX/VP3 compatibilty)\n",btv->c.nr); if (vsfx && btv->id >= 878) - printk(KERN_INFO "bttv%d: enabling VSFX\n",btv->nr); + printk(KERN_INFO "bttv%d: enabling VSFX\n",btv->c.nr); if (UNSET != latency) printk(KERN_INFO "bttv%d: setting pci timer to %d\n", - btv->nr,latency); + btv->c.nr,latency); } if (btv->id < 878) { @@ -3655,15 +3762,15 @@ int __devinit bttv_handle_chipset(struct btv->triton1 = BT848_INT_ETBF; } else { /* bt878 has a bit in the pci config space for it */ - pci_read_config_byte(btv->dev, BT878_DEVCTRL, &command); + pci_read_config_byte(btv->c.pci, BT878_DEVCTRL, &command); if (triton1) command |= BT878_EN_TBFX; if (vsfx) command |= BT878_EN_VSFX; - pci_write_config_byte(btv->dev, BT878_DEVCTRL, command); + pci_write_config_byte(btv->c.pci, BT878_DEVCTRL, command); } if (UNSET != latency) - pci_write_config_byte(btv->dev, PCI_LATENCY_TIMER, latency); + pci_write_config_byte(btv->c.pci, PCI_LATENCY_TIMER, latency); return 0; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/bttv-driver.c 830-ivtv/drivers/media/video/bttv-driver.c --- 000-virgin/drivers/media/video/bttv-driver.c Mon Nov 17 18:29:48 2003 +++ 830-ivtv/drivers/media/video/bttv-driver.c Thu Jan 8 11:17:21 2004 @@ -68,11 +68,12 @@ static unsigned int lumafilter = 0; static unsigned int automute = 1; static unsigned int chroma_agc = 0; static unsigned int adc_crush = 1; +static unsigned int whitecrush_upper = 0xCF; +static unsigned int whitecrush_lower = 0x7F; static unsigned int vcr_hack = 0; static unsigned int irq_iswitch = 0; /* API features (turn on/off stuff for testing) */ -static unsigned int sloppy = 0; static unsigned int v4l2 = 1; @@ -108,12 +109,15 @@ MODULE_PARM(chroma_agc,"i"); MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)"); MODULE_PARM(adc_crush,"i"); MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)"); +MODULE_PARM(whitecrush_upper,"i"); +MODULE_PARM_DESC(whitecrush_upper,"sets the white crush upper value, default is 207"); +MODULE_PARM(whitecrush_lower,"i"); +MODULE_PARM_DESC(whitecrush_lower,"sets the white crush lower value, default is 127"); MODULE_PARM(vcr_hack,"i"); MODULE_PARM_DESC(vcr_hack,"enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)"); MODULE_PARM(irq_iswitch,"i"); MODULE_PARM_DESC(irq_iswitch,"switch inputs in irq handler"); -MODULE_PARM(sloppy,"i"); MODULE_PARM(v4l2,"i"); MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards"); @@ -133,7 +137,7 @@ static ssize_t show_card(struct class_de { struct video_device *vfd = to_video_device(cd); struct bttv *btv = dev_get_drvdata(vfd->dev); - return sprintf(buf, "%d\n", btv ? btv->type : UNSET); + return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET); } static CLASS_DEVICE_ATTR(card, S_IRUGO, show_card, NULL); @@ -479,7 +483,9 @@ const unsigned int BTTV_FORMATS = ARRAY_ #define V4L2_CID_PRIVATE_LUMAFILTER (V4L2_CID_PRIVATE_BASE + 3) #define V4L2_CID_PRIVATE_AGC_CRUSH (V4L2_CID_PRIVATE_BASE + 4) #define V4L2_CID_PRIVATE_VCR_HACK (V4L2_CID_PRIVATE_BASE + 5) -#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 6) +#define V4L2_CID_PRIVATE_WHITECRUSH_UPPER (V4L2_CID_PRIVATE_BASE + 6) +#define V4L2_CID_PRIVATE_WHITECRUSH_LOWER (V4L2_CID_PRIVATE_BASE + 7) +#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 8) static const struct v4l2_queryctrl no_ctl = { .name = "42", @@ -597,7 +603,24 @@ static const struct v4l2_queryctrl bttv_ .minimum = 0, .maximum = 1, .type = V4L2_CTRL_TYPE_BOOLEAN, + },{ + .id = V4L2_CID_PRIVATE_WHITECRUSH_UPPER, + .name = "whitecrush upper", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 0xCF, + .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_PRIVATE_WHITECRUSH_LOWER, + .name = "whitecrush lower", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 0x7F, + .type = V4L2_CTRL_TYPE_INTEGER, } + }; const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls); @@ -695,7 +718,7 @@ static void set_pll(struct bttv *btv) return; if (btv->pll.pll_ofreq == btv->pll.pll_current) { - dprintk("bttv%d: PLL: no change required\n",btv->nr); + dprintk("bttv%d: PLL: no change required\n",btv->c.nr); return; } @@ -704,22 +727,22 @@ static void set_pll(struct bttv *btv) if (btv->pll.pll_current == 0) return; vprintk(KERN_INFO "bttv%d: PLL can sleep, using XTAL (%d).\n", - btv->nr,btv->pll.pll_ifreq); + btv->c.nr,btv->pll.pll_ifreq); btwrite(0x00,BT848_TGCTRL); btwrite(0x00,BT848_PLL_XCI); btv->pll.pll_current = 0; return; } - vprintk(KERN_INFO "bttv%d: PLL: %d => %d ",btv->nr, + vprintk(KERN_INFO "bttv%d: PLL: %d => %d ",btv->c.nr, btv->pll.pll_ifreq, btv->pll.pll_ofreq); set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq); for (i=0; i<10; i++) { /* Let other people run while the PLL stabilizes */ vprintk("."); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/10); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/50); if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) { btwrite(0,BT848_DSTATUS); @@ -742,9 +765,9 @@ void bt848A_set_timing(struct bttv *btv) int table_idx = bttv_tvnorms[btv->tvnorm].sram; int fsc = bttv_tvnorms[btv->tvnorm].Fsc; - if (UNSET == bttv_tvcards[btv->type].muxsel[btv->input]) { + if (UNSET == bttv_tvcards[btv->c.type].muxsel[btv->input]) { dprintk("bttv%d: load digital timing table (table_idx=%d)\n", - btv->nr,table_idx); + btv->c.nr,table_idx); /* timing change...reset timing generator address */ btwrite(0x00, BT848_TGCTRL); @@ -828,13 +851,13 @@ video_mux(struct bttv *btv, unsigned int { int mux,mask2; - if (input >= bttv_tvcards[btv->type].video_inputs) + if (input >= bttv_tvcards[btv->c.type].video_inputs) return -EINVAL; /* needed by RemoteVideo MX */ - mask2 = bttv_tvcards[btv->type].gpiomask2; + mask2 = bttv_tvcards[btv->c.type].gpiomask2; if (mask2) - btaor(mask2,~mask2,BT848_GPIO_OUT_EN); + gpio_inout(mask2,mask2); if (input == btv->svhs) { btor(BT848_CONTROL_COMP, BT848_E_CONTROL); @@ -843,14 +866,14 @@ video_mux(struct bttv *btv, unsigned int btand(~BT848_CONTROL_COMP, BT848_E_CONTROL); btand(~BT848_CONTROL_COMP, BT848_O_CONTROL); } - mux = bttv_tvcards[btv->type].muxsel[input] & 3; + mux = bttv_tvcards[btv->c.type].muxsel[input] & 3; btaor(mux<<5, ~(3<<5), BT848_IFORM); dprintk(KERN_DEBUG "bttv%d: video mux: input=%d mux=%d\n", - btv->nr,input,mux); + btv->c.nr,input,mux); /* card specific hook */ - if(bttv_tvcards[btv->type].muxsel_hook) - bttv_tvcards[btv->type].muxsel_hook (btv, input); + if(bttv_tvcards[btv->c.type].muxsel_hook) + bttv_tvcards[btv->c.type].muxsel_hook (btv, input); return 0; } @@ -863,9 +886,9 @@ static int audio_mux(struct bttv *btv, int mode) { int val,mux,i2c_mux,signal; - - btaor(bttv_tvcards[btv->type].gpiomask, - ~bttv_tvcards[btv->type].gpiomask,BT848_GPIO_OUT_EN); + + gpio_inout(bttv_tvcards[btv->c.type].gpiomask, + bttv_tvcards[btv->c.type].gpiomask); signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC; switch (mode) { @@ -887,12 +910,12 @@ audio_mux(struct bttv *btv, int mode) mux = AUDIO_OFF; #if 0 printk("bttv%d: amux: mode=%d audio=%d signal=%s mux=%d/%d irq=%s\n", - btv->nr, mode, btv->audio, signal ? "yes" : "no", + btv->c.nr, mode, btv->audio, signal ? "yes" : "no", mux, i2c_mux, in_interrupt() ? "yes" : "no"); #endif - val = bttv_tvcards[btv->type].audiomux[mux]; - btaor(val,~bttv_tvcards[btv->type].gpiomask, BT848_GPIO_DATA); + val = bttv_tvcards[btv->c.type].audiomux[mux]; + gpio_bits(bttv_tvcards[btv->c.type].gpiomask,val); if (bttv_gpio) bttv_gpio_tracking(btv,audio_modes[mux]); if (!in_interrupt()) @@ -909,7 +932,7 @@ i2c_vidiocschan(struct bttv *btv) c.norm = btv->tvnorm; c.channel = btv->input; bttv_call_i2c_clients(btv,VIDIOCSCHAN,&c); - if (btv->type == BTTV_VOODOOTV_FM) + if (btv->c.type == BTTV_VOODOOTV_FM) bttv_tda9880_setnorm(btv,c.norm); } @@ -932,7 +955,7 @@ set_tvnorm(struct bttv *btv, unsigned in btwrite(1, BT848_VBI_PACK_DEL); bt848A_set_timing(btv); - switch (btv->type) { + switch (btv->c.type) { case BTTV_VOODOOTV_FM: bttv_tda9880_setnorm(btv,norm); break; @@ -963,7 +986,7 @@ set_input(struct bttv *btv, unsigned int } else { video_mux(btv,input); } - audio_mux(btv,(input == bttv_tvcards[btv->type].tuner ? + audio_mux(btv,(input == bttv_tvcards[btv->c.type].tuner ? AUDIO_TUNER : AUDIO_EXTERN)); set_tvnorm(btv,btv->tvnorm); } @@ -972,7 +995,14 @@ static void init_bt848(struct bttv *btv) { int val; - btwrite(0, BT848_SRESET); + if (bttv_tvcards[btv->c.type].no_video) { + /* very basic init only */ + btwrite(0xfffffUL, BT848_INT_STAT); + btwrite(BT848_INT_I2CDONE, + BT848_INT_MASK); + return; + } + btwrite(0x00, BT848_CAP_CTL); btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL); btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM); @@ -995,6 +1025,9 @@ static void init_bt848(struct bttv *btv) btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0), BT848_ADC); + btwrite(whitecrush_upper, BT848_WC_UP); + btwrite(whitecrush_lower, BT848_WC_DOWN); + if (btv->opt_lumafilter) { btwrite(0, BT848_E_CONTROL); btwrite(0, BT848_O_CONTROL); @@ -1006,11 +1039,12 @@ static void init_bt848(struct bttv *btv) /* interrupt */ btwrite(0xfffffUL, BT848_INT_STAT); btwrite((btv->triton1) | - BT848_INT_GPINT | + (btv->gpioirq ? BT848_INT_GPINT : 0) | BT848_INT_SCERR | (fdsr ? BT848_INT_FDSR : 0) | BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES| - BT848_INT_FMTCHG|BT848_INT_HLOCK, + BT848_INT_FMTCHG|BT848_INT_HLOCK| + BT848_INT_I2CDONE, BT848_INT_MASK); } @@ -1019,7 +1053,7 @@ extern void bttv_reinit_bt848(struct btt unsigned long flags; if (bttv_verbose) - printk(KERN_INFO "bttv%d: reset, reinitialize\n",btv->nr); + printk(KERN_INFO "bttv%d: reset, reinitialize\n",btv->c.nr); spin_lock_irqsave(&btv->s_lock,flags); btv->errors=0; bttv_set_dma(btv,0,0); @@ -1094,6 +1128,12 @@ static int get_control(struct bttv *btv, case V4L2_CID_PRIVATE_VCR_HACK: c->value = btv->opt_vcr_hack; break; + case V4L2_CID_PRIVATE_WHITECRUSH_UPPER: + c->value = btv->opt_whitecrush_upper; + break; + case V4L2_CID_PRIVATE_WHITECRUSH_LOWER: + c->value = btv->opt_whitecrush_lower; + break; default: return -EINVAL; } @@ -1182,6 +1222,14 @@ static int set_control(struct bttv *btv, case V4L2_CID_PRIVATE_VCR_HACK: btv->opt_vcr_hack = c->value; break; + case V4L2_CID_PRIVATE_WHITECRUSH_UPPER: + btv->opt_whitecrush_upper = c->value; + btwrite(c->value, BT848_WC_UP); + break; + case V4L2_CID_PRIVATE_WHITECRUSH_LOWER: + btv->opt_whitecrush_lower = c->value; + btwrite(c->value, BT848_WC_DOWN); + break; default: return -EINVAL; } @@ -1201,7 +1249,7 @@ void bttv_gpio_tracking(struct bttv *btv outbits = btread(BT848_GPIO_OUT_EN); data = btread(BT848_GPIO_DATA); printk(KERN_DEBUG "bttv%d: gpio: en=%08x, out=%08x in=%08x [%s]\n", - btv->nr,outbits,data & outbits, data & ~outbits, comment); + btv->c.nr,outbits,data & outbits, data & ~outbits, comment); } void bttv_field_count(struct bttv *btv) @@ -1325,7 +1373,7 @@ static int bttv_prepare_buffer(struct bt /* alloc risc memory */ if (STATE_NEEDS_INIT == buf->vb.state) { redo_dma_risc = 1; - if (0 != (rc = videobuf_iolock(btv->dev,&buf->vb,&btv->fbuf))) + if (0 != (rc = videobuf_iolock(btv->c.pci,&buf->vb,&btv->fbuf))) goto fail; } @@ -1428,7 +1476,7 @@ int bttv_common_ioctls(struct bttv *btv, { struct video_tuner *v = arg; - if (UNSET == bttv_tvcards[btv->type].tuner) + if (UNSET == bttv_tvcards[btv->c.type].tuner) return -EINVAL; if (v->tuner) /* Only tuner 0 */ return -EINVAL; @@ -1462,13 +1510,13 @@ int bttv_common_ioctls(struct bttv *btv, struct video_channel *v = arg; unsigned int channel = v->channel; - if (channel >= bttv_tvcards[btv->type].video_inputs) + if (channel >= bttv_tvcards[btv->c.type].video_inputs) return -EINVAL; v->tuners=0; v->flags = VIDEO_VC_AUDIO; v->type = VIDEO_TYPE_CAMERA; v->norm = btv->tvnorm; - if (channel == bttv_tvcards[btv->type].tuner) { + if (channel == bttv_tvcards[btv->c.type].tuner) { strcpy(v->name,"Television"); v->flags|=VIDEO_VC_TUNER; v->type=VIDEO_TYPE_TV; @@ -1485,7 +1533,7 @@ int bttv_common_ioctls(struct bttv *btv, struct video_channel *v = arg; unsigned int channel = v->channel; - if (channel >= bttv_tvcards[btv->type].video_inputs) + if (channel >= bttv_tvcards[btv->c.type].video_inputs) return -EINVAL; if (v->norm >= BTTV_TVNORMS) return -EINVAL; @@ -1528,7 +1576,7 @@ int bttv_common_ioctls(struct bttv *btv, struct video_audio *v = arg; unsigned int audio = v->audio; - if (audio >= bttv_tvcards[btv->type].audio_inputs) + if (audio >= bttv_tvcards[btv->c.type].audio_inputs) return -EINVAL; down(&btv->lock); @@ -1596,13 +1644,13 @@ int bttv_common_ioctls(struct bttv *btv, unsigned int n; n = i->index; - if (n >= bttv_tvcards[btv->type].video_inputs) + if (n >= bttv_tvcards[btv->c.type].video_inputs) return -EINVAL; memset(i,0,sizeof(*i)); i->index = n; i->type = V4L2_INPUT_TYPE_CAMERA; i->audioset = 1; - if (i->index == bttv_tvcards[btv->type].tuner) { + if (i->index == bttv_tvcards[btv->c.type].tuner) { sprintf(i->name, "Television"); i->type = V4L2_INPUT_TYPE_TUNER; i->tuner = 0; @@ -1632,7 +1680,7 @@ int bttv_common_ioctls(struct bttv *btv, { unsigned int *i = arg; - if (*i > bttv_tvcards[btv->type].video_inputs) + if (*i > bttv_tvcards[btv->c.type].video_inputs) return -EINVAL; down(&btv->lock); set_input(btv,*i); @@ -1645,7 +1693,7 @@ int bttv_common_ioctls(struct bttv *btv, { struct v4l2_tuner *t = arg; - if (UNSET == bttv_tvcards[btv->type].tuner) + if (UNSET == bttv_tvcards[btv->c.type].tuner) return -EINVAL; if (0 != t->index) return -EINVAL; @@ -1683,7 +1731,7 @@ int bttv_common_ioctls(struct bttv *btv, { struct v4l2_tuner *t = arg; - if (UNSET == bttv_tvcards[btv->type].tuner) + if (UNSET == bttv_tvcards[btv->c.type].tuner) return -EINVAL; if (0 != t->index) return -EINVAL; @@ -2061,16 +2109,16 @@ static int bttv_do_ioctl(struct inode *i switch (_IOC_TYPE(cmd)) { case 'v': printk("bttv%d: ioctl 0x%x (v4l1, VIDIOC%s)\n", - btv->nr, cmd, (_IOC_NR(cmd) < V4L1_IOCTLS) ? + btv->c.nr, cmd, (_IOC_NR(cmd) < V4L1_IOCTLS) ? v4l1_ioctls[_IOC_NR(cmd)] : "???"); break; case 'V': printk("bttv%d: ioctl 0x%x (v4l2, %s)\n", - btv->nr, cmd, v4l2_ioctl_names[_IOC_NR(cmd)]); + btv->c.nr, cmd, v4l2_ioctl_names[_IOC_NR(cmd)]); break; default: printk("bttv%d: ioctl 0x%x (???)\n", - btv->nr, cmd); + btv->c.nr, cmd); } } if (btv->errors) @@ -2110,8 +2158,8 @@ static int bttv_do_ioctl(struct inode *i VID_TYPE_OVERLAY| VID_TYPE_CLIPPING| VID_TYPE_SCALES; - cap->channels = bttv_tvcards[btv->type].video_inputs; - cap->audios = bttv_tvcards[btv->type].audio_inputs; + cap->channels = bttv_tvcards[btv->c.type].video_inputs; + cap->audios = bttv_tvcards[btv->c.type].audio_inputs; cap->maxwidth = bttv_tvnorms[btv->tvnorm].swidth; cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight; cap->minwidth = 48; @@ -2144,7 +2192,7 @@ static int bttv_do_ioctl(struct inode *i if (NULL == fmt) return -EINVAL; down(&fh->cap.lock); - if (fmt->depth != pic->depth && !sloppy) { + if (fmt->depth != pic->depth) { retval = -EINVAL; goto fh_unlock_and_return; } @@ -2228,43 +2276,35 @@ static int bttv_do_ioctl(struct inode *i fbuf->height * fbuf->bytesperline; down(&fh->cap.lock); retval = -EINVAL; - if (sloppy) { - /* also set the default palette -- for backward - compatibility with older versions */ - switch (fbuf->depth) { - case 8: - fmt = format_by_palette(VIDEO_PALETTE_HI240); - break; - case 16: - fmt = format_by_palette(VIDEO_PALETTE_RGB565); - break; - case 24: - fmt = format_by_palette(VIDEO_PALETTE_RGB24); - break; - case 32: - fmt = format_by_palette(VIDEO_PALETTE_RGB32); - break; - case 15: - fbuf->depth = 16; - fmt = format_by_palette(VIDEO_PALETTE_RGB555); - break; - default: - fmt = NULL; - break; - } - if (NULL == fmt) - goto fh_unlock_and_return; - fh->ovfmt = fmt; - fh->fmt = fmt; - btv->init.ovfmt = fmt; - btv->init.fmt = fmt; - } else { - if (15 == fbuf->depth) - fbuf->depth = 16; - if (fbuf->depth != 8 && fbuf->depth != 16 && - fbuf->depth != 24 && fbuf->depth != 32) - goto fh_unlock_and_return; + + switch (fbuf->depth) { + case 8: + fmt = format_by_palette(VIDEO_PALETTE_HI240); + break; + case 16: + fmt = format_by_palette(VIDEO_PALETTE_RGB565); + break; + case 24: + fmt = format_by_palette(VIDEO_PALETTE_RGB24); + break; + case 32: + fmt = format_by_palette(VIDEO_PALETTE_RGB32); + break; + case 15: + fbuf->depth = 16; + fmt = format_by_palette(VIDEO_PALETTE_RGB555); + break; + default: + fmt = NULL; + break; } + if (NULL == fmt) + goto fh_unlock_and_return; + + fh->ovfmt = fmt; + fh->fmt = fmt; + btv->init.ovfmt = fmt; + btv->init.fmt = fmt; btv->fbuf.base = fbuf->base; btv->fbuf.fmt.width = fbuf->width; btv->fbuf.fmt.height = fbuf->height; @@ -2287,7 +2327,7 @@ static int bttv_do_ioctl(struct inode *i if (NULL == btv->fbuf.base) return -EINVAL; if (!fh->ov.setup_ok) { - dprintk("bttv%d: overlay: !setup_ok\n",btv->nr); + dprintk("bttv%d: overlay: !setup_ok\n",btv->c.nr); return -EINVAL; } } @@ -2383,7 +2423,7 @@ static int bttv_do_ioctl(struct inode *i retval = -EIO; /* fall through */ case STATE_DONE: - videobuf_dma_pci_sync(btv->dev,&buf->vb.dma); + videobuf_dma_pci_sync(btv->c.pci,&buf->vb.dma); bttv_dma_free(btv,buf); break; default: @@ -2464,7 +2504,7 @@ static int bttv_do_ioctl(struct inode *i return -EINVAL; strcpy(cap->driver,"bttv"); strlcpy(cap->card,btv->video_dev->name,sizeof(cap->card)); - sprintf(cap->bus_info,"PCI:%s",pci_name(btv->dev)); + sprintf(cap->bus_info,"PCI:%s",pci_name(btv->c.pci)); cap->version = BTTV_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | @@ -2768,7 +2808,7 @@ static ssize_t bttv_read(struct file *fi if (fh->btv->errors) bttv_reinit_bt848(fh->btv); dprintk("bttv%d: read count=%d type=%s\n", - fh->btv->nr,(int)count,v4l2_type_names[fh->type]); + fh->btv->c.nr,(int)count,v4l2_type_names[fh->type]); switch (fh->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: @@ -2849,12 +2889,14 @@ static int bttv_open(struct inode *inode dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor); for (i = 0; i < bttv_num; i++) { - if (bttvs[i].video_dev->minor == minor) { + if (bttvs[i].video_dev && + bttvs[i].video_dev->minor == minor) { btv = &bttvs[i]; type = V4L2_BUF_TYPE_VIDEO_CAPTURE; break; } - if (bttvs[i].vbi_dev->minor == minor) { + if (bttvs[i].vbi_dev && + bttvs[i].vbi_dev->minor == minor) { btv = &bttvs[i]; type = V4L2_BUF_TYPE_VBI_CAPTURE; break; @@ -2864,7 +2906,7 @@ static int bttv_open(struct inode *inode return -ENODEV; dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n", - btv->nr,v4l2_type_names[type]); + btv->c.nr,v4l2_type_names[type]); /* allocate per filehandle data */ fh = kmalloc(sizeof(*fh),GFP_KERNEL); @@ -2879,12 +2921,12 @@ static int bttv_open(struct inode *inode #endif videobuf_queue_init(&fh->cap, &bttv_video_qops, - btv->dev, &btv->s_lock, + btv->c.pci, &btv->s_lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, sizeof(struct bttv_buffer)); videobuf_queue_init(&fh->vbi, &bttv_vbi_qops, - btv->dev, &btv->s_lock, + btv->c.pci, &btv->s_lock, V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_FIELD_SEQ_TB, sizeof(struct bttv_buffer)); @@ -2942,7 +2984,7 @@ bttv_mmap(struct file *file, struct vm_a struct bttv_fh *fh = file->private_data; dprintk("bttv%d: mmap type=%s 0x%lx+%ld\n", - fh->btv->nr, v4l2_type_names[fh->type], + fh->btv->c.nr, v4l2_type_names[fh->type], vma->vm_start, vma->vm_end - vma->vm_start); return videobuf_mmap_mapper(vma,bttv_queue(fh)); } @@ -2998,7 +3040,7 @@ static int radio_open(struct inode *inod if (NULL == btv) return -ENODEV; - dprintk("bttv%d: open called (radio)\n",btv->nr); + dprintk("bttv%d: open called (radio)\n",btv->c.nr); down(&btv->lock); if (btv->radio_user) { up(&btv->lock); @@ -3196,7 +3238,7 @@ bttv_irq_next_set(struct bttv *btv, stru dprintk("bttv%d: next set: top=%p bottom=%p vbi=%p " "[screen=%p,irq=%d,%d]\n", - btv->nr,set->top, set->bottom, set->vbi, + btv->c.nr,set->top, set->bottom, set->vbi, btv->screen,set->irqflags,set->topirq); return 0; } @@ -3218,7 +3260,7 @@ bttv_irq_wakeup_set(struct bttv *btv, st if (wakeup->top == wakeup->bottom) { if (NULL != wakeup->top && curr->top != wakeup->top) { if (irq_debug > 1) - printk("bttv%d: wakeup: both=%p\n",btv->nr,wakeup->top); + printk("bttv%d: wakeup: both=%p\n",btv->c.nr,wakeup->top); wakeup->top->vb.ts = ts; wakeup->top->vb.field_count = btv->field_count; wakeup->top->vb.state = state; @@ -3227,7 +3269,7 @@ bttv_irq_wakeup_set(struct bttv *btv, st } else { if (NULL != wakeup->top && curr->top != wakeup->top) { if (irq_debug > 1) - printk("bttv%d: wakeup: top=%p\n",btv->nr,wakeup->top); + printk("bttv%d: wakeup: top=%p\n",btv->c.nr,wakeup->top); wakeup->top->vb.ts = ts; wakeup->top->vb.field_count = btv->field_count; wakeup->top->vb.state = state; @@ -3235,7 +3277,7 @@ bttv_irq_wakeup_set(struct bttv *btv, st } if (NULL != wakeup->bottom && curr->bottom != wakeup->bottom) { if (irq_debug > 1) - printk("bttv%d: wakeup: bottom=%p\n",btv->nr,wakeup->bottom); + printk("bttv%d: wakeup: bottom=%p\n",btv->c.nr,wakeup->bottom); wakeup->bottom->vb.ts = ts; wakeup->bottom->vb.field_count = btv->field_count; wakeup->bottom->vb.state = state; @@ -3249,15 +3291,16 @@ static void bttv_irq_timeout(unsigned lo struct bttv *btv = (struct bttv *)data; struct bttv_buffer_set old,new; struct bttv_buffer *item; + unsigned long flags; if (bttv_verbose) { printk(KERN_INFO "bttv%d: timeout: risc=%08x, ", - btv->nr,btread(BT848_RISC_COUNT)); + btv->c.nr,btread(BT848_RISC_COUNT)); bttv_print_irqbits(btread(BT848_INT_STAT),0); printk("\n"); } - spin_lock(&btv->s_lock); + spin_lock_irqsave(&btv->s_lock,flags); /* deactivate stuff */ memset(&new,0,sizeof(new)); @@ -3284,7 +3327,7 @@ static void bttv_irq_timeout(unsigned lo } btv->errors++; - spin_unlock(&btv->s_lock); + spin_unlock_irqrestore(&btv->s_lock,flags); } static void @@ -3321,8 +3364,11 @@ bttv_irq_switch_fields(struct bttv *btv) rc = btread(BT848_RISC_COUNT); if (rc < btv->main.dma || rc > btv->main.dma + 0x100) { if (1 /* irq_debug */) - printk("bttv%d: skipped frame. no signal? high irq latency?\n", - btv->nr); + printk("bttv%d: skipped frame. no signal? high irq latency? " + "[main=%lx,o_vbi=%lx,rc=%lx]\n", btv->c.nr, + (unsigned long)btv->main.dma, + (unsigned long)btv->main.cpu[RISC_SLOT_O_VBI+1], + (unsigned long)rc); spin_unlock(&btv->s_lock); return; } @@ -3369,7 +3415,7 @@ static irqreturn_t bttv_irq(int irq, voi if (irq_debug) { printk(KERN_DEBUG "bttv%d: irq loop=%d fc=%d " "riscs=%x, riscc=%08x, ", - btv->nr, count, btv->field_count, + btv->c.nr, count, btv->field_count, stat>>28, btread(BT848_RISC_COUNT)); bttv_print_irqbits(stat,astat); if (stat & BT848_INT_HLOCK) @@ -3388,11 +3434,13 @@ static irqreturn_t bttv_irq(int irq, voi btv->field_count++; if (astat & BT848_INT_GPINT) { -#ifdef CONFIG_VIDEO_IR - if (btv->remote) - bttv_input_irq(btv); -#endif wake_up(&btv->gpioq); + bttv_gpio_irq(&btv->c); + } + + if (astat & BT848_INT_I2CDONE) { + btv->i2c_done = stat; + wake_up(&btv->i2c_queue); } if ((astat & BT848_INT_RISCI) && (stat & (2<<28))) @@ -3405,7 +3453,7 @@ static irqreturn_t bttv_irq(int irq, voi audio_mux(btv, -1); if (astat & (BT848_INT_SCERR|BT848_INT_OCERR)) { - printk(KERN_INFO "bttv%d: %s%s @ %08x,",btv->nr, + printk(KERN_INFO "bttv%d: %s%s @ %08x,",btv->c.nr, (astat & BT848_INT_SCERR) ? "SCERR" : "", (astat & BT848_INT_OCERR) ? "OCERR" : "", btread(BT848_RISC_COUNT)); @@ -3416,7 +3464,7 @@ static irqreturn_t bttv_irq(int irq, voi } if (fdsr && astat & BT848_INT_FDSR) { printk(KERN_INFO "bttv%d: FDSR @ %08x\n", - btv->nr,btread(BT848_RISC_COUNT)); + btv->c.nr,btread(BT848_RISC_COUNT)); if (bttv_debug) bttv_print_riscaddr(btv); } @@ -3425,7 +3473,7 @@ static irqreturn_t bttv_irq(int irq, voi if (count > 4) { btwrite(0, BT848_INT_MASK); printk(KERN_ERR - "bttv%d: IRQ lockup, cleared int mask [", btv->nr); + "bttv%d: IRQ lockup, cleared int mask [", btv->c.nr); bttv_print_irqbits(stat,astat); printk("]\n"); } @@ -3448,11 +3496,11 @@ static struct video_device *vdev_init(st return NULL; *vfd = *template; vfd->minor = -1; - vfd->dev = &btv->dev->dev; + vfd->dev = &btv->c.pci->dev; vfd->release = video_device_release; snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)", btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "", - type, bttv_tvcards[btv->type].name); + type, bttv_tvcards[btv->c.type].name); return vfd; } @@ -3491,7 +3539,7 @@ static int __devinit bttv_register_video if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0) goto err; printk(KERN_INFO "bttv%d: registered device video%d\n", - btv->nr,btv->video_dev->minor & 0x1f); + btv->c.nr,btv->video_dev->minor & 0x1f); video_device_create_file(btv->video_dev, &class_device_attr_card); /* vbi */ @@ -3501,7 +3549,7 @@ static int __devinit bttv_register_video if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0) goto err; printk(KERN_INFO "bttv%d: registered device vbi%d\n", - btv->nr,btv->vbi_dev->minor & 0x1f); + btv->c.nr,btv->vbi_dev->minor & 0x1f); if (!btv->has_radio) return 0; @@ -3512,7 +3560,7 @@ static int __devinit bttv_register_video if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0) goto err; printk(KERN_INFO "bttv%d: registered device radio%d\n", - btv->nr,btv->radio_dev->minor & 0x1f); + btv->c.nr,btv->radio_dev->minor & 0x1f); /* all done */ return 0; @@ -3548,14 +3596,17 @@ static int __devinit bttv_probe(struct p printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num); btv=&bttvs[bttv_num]; memset(btv,0,sizeof(*btv)); - btv->nr = bttv_num; - sprintf(btv->name,"bttv%d",btv->nr); + btv->c.nr = bttv_num; + sprintf(btv->c.name,"bttv%d",btv->c.nr); /* initialize structs / fill in defaults */ init_MUTEX(&btv->lock); init_MUTEX(&btv->reslock); - btv->s_lock = SPIN_LOCK_UNLOCKED; + btv->s_lock = SPIN_LOCK_UNLOCKED; + btv->gpio_lock = SPIN_LOCK_UNLOCKED; init_waitqueue_head(&btv->gpioq); + init_waitqueue_head(&btv->i2c_queue); + INIT_LIST_HEAD(&btv->c.subs); INIT_LIST_HEAD(&btv->capture); INIT_LIST_HEAD(&btv->vcapture); #ifdef VIDIOC_G_PRIORITY @@ -3570,33 +3621,34 @@ static int __devinit bttv_probe(struct p btv->tuner_type = UNSET; btv->pinnacle_id = UNSET; btv->new_input = UNSET; - btv->has_radio=radio[btv->nr]; + btv->gpioirq = 1; + btv->has_radio=radio[btv->c.nr]; /* pci stuff (init, get irq/mmio, ... */ - btv->dev = dev; + btv->c.pci = dev; btv->id = dev->device; if (pci_enable_device(dev)) { printk(KERN_WARNING "bttv%d: Can't enable device.\n", - btv->nr); + btv->c.nr); return -EIO; } if (pci_set_dma_mask(dev, 0xffffffff)) { printk(KERN_WARNING "bttv%d: No suitable DMA available.\n", - btv->nr); + btv->c.nr); return -EIO; } if (!request_mem_region(pci_resource_start(dev,0), pci_resource_len(dev,0), - btv->name)) { + btv->c.name)) { printk(KERN_WARNING "bttv%d: can't request iomem (0x%lx).\n", - btv->nr, pci_resource_start(dev,0)); + btv->c.nr, pci_resource_start(dev,0)); return -EBUSY; } pci_set_master(dev); pci_set_command(dev); pci_set_drvdata(dev,btv); if (!pci_dma_supported(dev,0xffffffff)) { - printk("bttv%d: Oops: no 32bit PCI DMA ???\n", btv->nr); + printk("bttv%d: Oops: no 32bit PCI DMA ???\n", btv->c.nr); result = -EIO; goto fail1; } @@ -3606,12 +3658,12 @@ static int __devinit bttv_probe(struct p printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ", bttv_num,btv->id, btv->revision, pci_name(dev)); printk("irq: %d, latency: %d, mmio: 0x%lx\n", - btv->dev->irq, lat, pci_resource_start(dev,0)); + btv->c.pci->irq, lat, pci_resource_start(dev,0)); schedule(); btv->bt848_mmio=ioremap(pci_resource_start(dev,0), 0x1000); if (NULL == ioremap(pci_resource_start(dev,0), 0x1000)) { - printk("bttv%d: ioremap() failed\n", btv->nr); + printk("bttv%d: ioremap() failed\n", btv->c.nr); result = -EIO; goto fail1; } @@ -3621,11 +3673,11 @@ static int __devinit bttv_probe(struct p /* disable irqs, register irq handler */ btwrite(0, BT848_INT_MASK); - result = request_irq(btv->dev->irq, bttv_irq, - SA_SHIRQ | SA_INTERRUPT,btv->name,(void *)btv); + result = request_irq(btv->c.pci->irq, bttv_irq, + SA_SHIRQ | SA_INTERRUPT,btv->c.name,(void *)btv); if (result < 0) { printk(KERN_ERR "bttv%d: can't get IRQ %d\n", - bttv_num,btv->dev->irq); + bttv_num,btv->c.pci->irq); goto fail1; } @@ -3641,6 +3693,8 @@ static int __devinit bttv_probe(struct p btv->opt_chroma_agc = chroma_agc; btv->opt_adc_crush = adc_crush; btv->opt_vcr_hack = vcr_hack; + btv->opt_whitecrush_upper = whitecrush_upper; + btv->opt_whitecrush_lower = whitecrush_lower; /* fill struct bttv with some useful defaults */ btv->init.btv = btv; @@ -3657,31 +3711,26 @@ static int __devinit bttv_probe(struct p bttv_gpio_tracking(btv,"pre-init"); bttv_risc_init_main(btv); - if (!bttv_tvcards[btv->type].no_video) - init_bt848(btv); + init_bt848(btv); /* gpio */ btwrite(0x00, BT848_GPIO_REG_INP); btwrite(0x00, BT848_GPIO_OUT_EN); - if (bttv_gpio) + if (bttv_verbose) bttv_gpio_tracking(btv,"init"); /* needs to be done before i2c is registered */ bttv_init_card1(btv); - /* register i2c */ + /* register i2c + gpio */ init_bttv_i2c(btv); /* some card-specific stuff (needs working i2c) */ bttv_init_card2(btv); /* register video4linux + input */ - if (!bttv_tvcards[btv->type].no_video) { + if (!bttv_tvcards[btv->c.type].no_video) { bttv_register_video(btv); -#ifdef CONFIG_VIDEO_IR - bttv_input_init(btv); -#endif - bt848_bright(btv,32768); bt848_contrast(btv,32768); bt848_hue(btv,32768); @@ -3690,18 +3739,24 @@ static int __devinit bttv_probe(struct p set_input(btv,0); } + /* add subdevices */ + if (btv->has_remote) + bttv_sub_add_device(&btv->c, "remote"); + if (bttv_tvcards[btv->c.type].has_dvb) + bttv_sub_add_device(&btv->c, "dvb"); + /* everything is fine */ bttv_num++; return 0; fail2: - free_irq(btv->dev->irq,btv); + free_irq(btv->c.pci->irq,btv); fail1: if (btv->bt848_mmio) iounmap(btv->bt848_mmio); - release_mem_region(pci_resource_start(btv->dev,0), - pci_resource_len(btv->dev,0)); + release_mem_region(pci_resource_start(btv->c.pci,0), + pci_resource_len(btv->c.pci,0)); pci_set_drvdata(dev,NULL); return result; } @@ -3711,7 +3766,7 @@ static void __devexit bttv_remove(struct struct bttv *btv = pci_get_drvdata(pci_dev); if (bttv_verbose) - printk("bttv%d: unloading\n",btv->nr); + printk("bttv%d: unloading\n",btv->c.nr); /* shutdown everything (DMA+IRQs) */ btand(~15, BT848_GPIO_DMA_CTL); @@ -3724,29 +3779,92 @@ static void __devexit bttv_remove(struct /* tell gpio modules we are leaving ... */ btv->shutdown=1; wake_up(&btv->gpioq); - + bttv_sub_del_devices(&btv->c); + /* unregister i2c_bus + input */ fini_bttv_i2c(btv); -#ifdef CONFIG_VIDEO_IR - bttv_input_fini(btv); -#endif /* unregister video4linux */ bttv_unregister_video(btv); /* free allocated memory */ - btcx_riscmem_free(btv->dev,&btv->main); + btcx_riscmem_free(btv->c.pci,&btv->main); /* free ressources */ - free_irq(btv->dev->irq,btv); + free_irq(btv->c.pci->irq,btv); iounmap(btv->bt848_mmio); - release_mem_region(pci_resource_start(btv->dev,0), - pci_resource_len(btv->dev,0)); + release_mem_region(pci_resource_start(btv->c.pci,0), + pci_resource_len(btv->c.pci,0)); pci_set_drvdata(pci_dev, NULL); return; } +static int bttv_suspend(struct pci_dev *pci_dev, u32 state) +{ + struct bttv *btv = pci_get_drvdata(pci_dev); + struct bttv_buffer_set idle; + unsigned long flags; + + printk("bttv%d: suspend %d\n", btv->c.nr, state); + + /* stop dma + irqs */ + spin_lock_irqsave(&btv->s_lock,flags); + memset(&idle, 0, sizeof(idle)); + btv->state.set = btv->curr; + btv->curr = idle; + bttv_buffer_set_activate(btv, &idle); + bttv_set_dma(btv, 0, 0); + btwrite(0, BT848_INT_MASK); + spin_unlock_irqrestore(&btv->s_lock,flags); + + /* save bt878 state */ + btv->state.gpio_enable = btread(BT848_GPIO_OUT_EN); + btv->state.gpio_data = gpio_read(); + + /* save pci state */ + pci_save_state(pci_dev, btv->state.pci_cfg); + if (0 != pci_set_power_state(pci_dev, state)) { + pci_disable_device(pci_dev); + btv->state.disabled = 1; + } + return 0; +} + +static int bttv_resume(struct pci_dev *pci_dev) +{ + struct bttv *btv = pci_get_drvdata(pci_dev); + unsigned long flags; + + printk("bttv%d: resume\n", btv->c.nr); + + /* restore pci state */ + if (btv->state.disabled) { + pci_enable_device(pci_dev); + btv->state.disabled = 0; + } + pci_set_power_state(pci_dev, 0); + pci_restore_state(pci_dev, btv->state.pci_cfg); + + /* restore bt878 state */ + bttv_reinit_bt848(btv); + gpio_inout(0xffffff, btv->state.gpio_enable); + gpio_write(btv->state.gpio_data); + + bt848_bright(btv, btv->bright); + bt848_hue(btv, btv->hue); + bt848_contrast(btv, btv->contrast); + bt848_sat(btv, btv->saturation); + + /* restart dma */ + spin_lock_irqsave(&btv->s_lock,flags); + btv->curr = btv->state.set; + bttv_buffer_set_activate(btv, &btv->curr); + bttv_set_dma(btv, 0, btv->curr.irqflags); + spin_unlock_irqrestore(&btv->s_lock,flags); + return 0; +} + static struct pci_device_id bttv_pci_tbl[] = { {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, @@ -3766,6 +3884,9 @@ static struct pci_driver bttv_pci_driver .id_table = bttv_pci_tbl, .probe = bttv_probe, .remove = __devexit_p(bttv_remove), + + .suspend = bttv_suspend, + .resume = bttv_resume, }; static int bttv_init_module(void) @@ -3777,6 +3898,10 @@ static int bttv_init_module(void) (BTTV_VERSION_CODE >> 16) & 0xff, (BTTV_VERSION_CODE >> 8) & 0xff, BTTV_VERSION_CODE & 0xff); +#ifdef SNAPSHOT + printk(KERN_INFO "bttv: snapshot date %04d-%02d-%02d\n", + SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); +#endif if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME) gbuffers = 2; if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF) @@ -3788,6 +3913,7 @@ static int bttv_init_module(void) bttv_check_chipset(); + bus_register(&bttv_sub_bus_type); rc = pci_module_init(&bttv_pci_driver); if (-ENODEV == rc) { /* plenty of people trying to use bttv for the cx2388x ... */ @@ -3800,6 +3926,7 @@ static int bttv_init_module(void) static void bttv_cleanup_module(void) { pci_unregister_driver(&bttv_pci_driver); + bus_unregister(&bttv_sub_bus_type); return; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/bttv-gpio.c 830-ivtv/drivers/media/video/bttv-gpio.c --- 000-virgin/drivers/media/video/bttv-gpio.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/media/video/bttv-gpio.c Thu Jan 8 11:17:21 2004 @@ -0,0 +1,183 @@ +/* + bttv-gpio.c -- gpio sub drivers + + sysfs-based sub driver interface for bttv + mainly intented for gpio access + + + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + & Marcus Metzler (mocm@thp.uni-koeln.de) + (c) 1999-2003 Gerd Knorr + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include + +#include "bttvp.h" + +/* ----------------------------------------------------------------------- */ +/* internal: the bttv "bus" */ + +static int bttv_sub_bus_match(struct device *dev, struct device_driver *drv) +{ + struct bttv_sub_driver *sub = to_bttv_sub_drv(drv); + int len = strlen(sub->wanted); + + if (0 == strncmp(dev->bus_id, sub->wanted, len)) + return 1; + return 0; +} + +struct bus_type bttv_sub_bus_type = { + .name = "bttv-sub", + .match = &bttv_sub_bus_match, +}; +EXPORT_SYMBOL(bttv_sub_bus_type); + +static void release_sub_device(struct device *dev) +{ + struct bttv_sub_device *sub = to_bttv_sub_dev(dev); + kfree(sub); +} + +int bttv_sub_add_device(struct bttv_core *core, char *name) +{ + struct bttv_sub_device *sub; + + sub = kmalloc(sizeof(*sub),GFP_KERNEL); + if (NULL == sub) + return -ENOMEM; + memset(sub,0,sizeof(*sub)); + + sub->core = core; + sub->dev.parent = &core->pci->dev; + sub->dev.bus = &bttv_sub_bus_type; + sub->dev.release = release_sub_device; + snprintf(sub->dev.bus_id,sizeof(sub->dev.bus_id),"%s%d", + name, core->nr); + + printk("bttv%d: add subdevice \"%s\"\n", core->nr, sub->dev.bus_id); + list_add_tail(&sub->list,&core->subs); + device_register(&sub->dev); + return 0; +} + +int bttv_sub_del_devices(struct bttv_core *core) +{ + struct bttv_sub_device *sub; + struct list_head *item,*save; + + list_for_each_safe(item,save,&core->subs) { + sub = list_entry(item,struct bttv_sub_device,list); + device_unregister(&sub->dev); + } + return 0; +} + +void bttv_gpio_irq(struct bttv_core *core) +{ + struct bttv_sub_driver *drv; + struct bttv_sub_device *dev; + struct list_head *item; + + list_for_each(item,&core->subs) { + dev = list_entry(item,struct bttv_sub_device,list); + drv = to_bttv_sub_drv(dev->dev.driver); + if (drv && drv->gpio_irq) + drv->gpio_irq(dev); + } +} + +/* ----------------------------------------------------------------------- */ +/* external: sub-driver register/unregister */ + +int bttv_sub_register(struct bttv_sub_driver *sub, char *wanted) +{ + sub->drv.bus = &bttv_sub_bus_type; + snprintf(sub->wanted,sizeof(sub->wanted),"%s",wanted); + driver_register(&sub->drv); + return 0; +} +EXPORT_SYMBOL(bttv_sub_register); + +int bttv_sub_unregister(struct bttv_sub_driver *sub) +{ + driver_unregister(&sub->drv); + return 0; +} +EXPORT_SYMBOL(bttv_sub_unregister); + +/* ----------------------------------------------------------------------- */ +/* external: gpio access functions */ + +void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits) +{ + struct bttv *btv = container_of(core, struct bttv, c); + unsigned long flags; + u32 data; + + spin_lock_irqsave(&btv->gpio_lock,flags); + data = btread(BT848_GPIO_OUT_EN); + data = data & ~mask; + data = data | (mask & outbits); + btwrite(data,BT848_GPIO_OUT_EN); + spin_unlock_irqrestore(&btv->gpio_lock,flags); +} +EXPORT_SYMBOL(bttv_gpio_inout); + +u32 bttv_gpio_read(struct bttv_core *core) +{ + struct bttv *btv = container_of(core, struct bttv, c); + u32 value; + + value = btread(BT848_GPIO_DATA); + return value; +} +EXPORT_SYMBOL(bttv_gpio_read); + +void bttv_gpio_write(struct bttv_core *core, u32 value) +{ + struct bttv *btv = container_of(core, struct bttv, c); + + btwrite(value,BT848_GPIO_DATA); +} +EXPORT_SYMBOL(bttv_gpio_write); + +void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits) +{ + struct bttv *btv = container_of(core, struct bttv, c); + unsigned long flags; + u32 data; + + spin_lock_irqsave(&btv->gpio_lock,flags); + data = btread(BT848_GPIO_DATA); + data = data & ~mask; + data = data | (mask & bits); + btwrite(data,BT848_GPIO_DATA); + spin_unlock_irqrestore(&btv->gpio_lock,flags); +} +EXPORT_SYMBOL(bttv_gpio_bits); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/bttv-i2c.c 830-ivtv/drivers/media/video/bttv-i2c.c --- 000-virgin/drivers/media/video/bttv-i2c.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/media/video/bttv-i2c.c Thu Jan 8 11:17:21 2004 @@ -0,0 +1,471 @@ +/* + bttv-i2c.c -- all the i2c code is here + + bttv - Bt848 frame grabber driver + + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + & Marcus Metzler (mocm@thp.uni-koeln.de) + (c) 1999-2003 Gerd Knorr + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include + +#include "bttvp.h" + +static struct i2c_algo_bit_data bttv_i2c_algo_bit_template; +static struct i2c_adapter bttv_i2c_adap_sw_template; +static struct i2c_adapter bttv_i2c_adap_hw_template; +static struct i2c_client bttv_i2c_client_template; + +#ifndef I2C_PEC +static void bttv_inc_use(struct i2c_adapter *adap); +static void bttv_dec_use(struct i2c_adapter *adap); +#endif +static int attach_inform(struct i2c_client *client); + +static int i2c_debug = 0; +static int i2c_hw = 0; +MODULE_PARM(i2c_debug,"i"); +MODULE_PARM(i2c_hw,"i"); + +/* ----------------------------------------------------------------------- */ +/* I2C functions - bitbanging adapter (software i2c) */ + +void bttv_bit_setscl(void *data, int state) +{ + struct bttv *btv = (struct bttv*)data; + + if (state) + btv->i2c_state |= 0x02; + else + btv->i2c_state &= ~0x02; + btwrite(btv->i2c_state, BT848_I2C); + btread(BT848_I2C); +} + +void bttv_bit_setsda(void *data, int state) +{ + struct bttv *btv = (struct bttv*)data; + + if (state) + btv->i2c_state |= 0x01; + else + btv->i2c_state &= ~0x01; + btwrite(btv->i2c_state, BT848_I2C); + btread(BT848_I2C); +} + +static int bttv_bit_getscl(void *data) +{ + struct bttv *btv = (struct bttv*)data; + int state; + + state = btread(BT848_I2C) & 0x02 ? 1 : 0; + return state; +} + +static int bttv_bit_getsda(void *data) +{ + struct bttv *btv = (struct bttv*)data; + int state; + + state = btread(BT848_I2C) & 0x01; + return state; +} + +static struct i2c_algo_bit_data bttv_i2c_algo_bit_template = { + .setsda = bttv_bit_setsda, + .setscl = bttv_bit_setscl, + .getsda = bttv_bit_getsda, + .getscl = bttv_bit_getscl, + .udelay = 16, + .mdelay = 10, + .timeout = 200, +}; + +static struct i2c_adapter bttv_i2c_adap_sw_template = { +#ifdef I2C_PEC + .owner = THIS_MODULE, +#else + .inc_use = bttv_inc_use, + .dec_use = bttv_dec_use, +#endif +#ifdef I2C_ADAP_CLASS_TV_ANALOG + .class = I2C_ADAP_CLASS_TV_ANALOG, +#endif + I2C_DEVNAME("bt848"), + .id = I2C_HW_B_BT848, + .client_register = attach_inform, +}; + +/* ----------------------------------------------------------------------- */ +/* I2C functions - hardware i2c */ + +static int algo_control(struct i2c_adapter *adapter, + unsigned int cmd, unsigned long arg) +{ + return 0; +} + +static u32 functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_EMUL; +} + +static int +bttv_i2c_wait_done(struct bttv *btv) +{ + DECLARE_WAITQUEUE(wait, current); + int rc = 0; + + add_wait_queue(&btv->i2c_queue, &wait); + set_current_state(TASK_INTERRUPTIBLE); + if (0 == btv->i2c_done) + schedule_timeout(HZ/50+1); + set_current_state(TASK_RUNNING); + remove_wait_queue(&btv->i2c_queue, &wait); + + if (0 == btv->i2c_done) + /* timeout */ + rc = -EIO; + if (btv->i2c_done & BT848_INT_RACK) + rc = 1; + btv->i2c_done = 0; + return rc; +} + +#define I2C_HW (BT878_I2C_MODE | BT848_I2C_SYNC |\ + BT848_I2C_SCL | BT848_I2C_SDA) + +static int +bttv_i2c_sendbytes(struct bttv *btv, const struct i2c_msg *msg, int last) +{ + u32 xmit; + int retval,cnt; + + /* sanity checks */ + if (0 == msg->len) + return -EINVAL; + + /* start, address + first byte */ + xmit = (msg->addr << 25) | (msg->buf[0] << 16) | I2C_HW; + if (msg->len > 1 || !last) + xmit |= BT878_I2C_NOSTOP; + btwrite(xmit, BT848_I2C); + retval = bttv_i2c_wait_done(btv); + if (retval < 0) + goto err; + if (retval == 0) + goto eio; + if (i2c_debug) { + printk(" addr << 1, msg->buf[0]); + if (!(xmit & BT878_I2C_NOSTOP)) + printk(" >\n"); + } + + for (cnt = 1; cnt < msg->len; cnt++ ) { + /* following bytes */ + xmit = (msg->buf[cnt] << 24) | I2C_HW | BT878_I2C_NOSTART; + if (cnt < msg->len-1 || !last) + xmit |= BT878_I2C_NOSTOP; + btwrite(xmit, BT848_I2C); + retval = bttv_i2c_wait_done(btv); + if (retval < 0) + goto err; + if (retval == 0) + goto eio; + if (i2c_debug) { + printk(" %02x", msg->buf[cnt]); + if (!(xmit & BT878_I2C_NOSTOP)) + printk(" >\n"); + } + } + return msg->len; + + eio: + retval = -EIO; + err: + if (i2c_debug) + printk(" ERR: %d\n",retval); + return retval; +} + +static int +bttv_i2c_readbytes(struct bttv *btv, const struct i2c_msg *msg, int last) +{ + u32 xmit; + u32 cnt; + int retval; + + for(cnt = 0; cnt < msg->len; cnt++) { + xmit = (msg->addr << 25) | (1 << 24) | I2C_HW; + if (cnt < msg->len-1) + xmit |= BT848_I2C_W3B; + if (cnt < msg->len-1 || !last) + xmit |= BT878_I2C_NOSTOP; + if (cnt) + xmit |= BT878_I2C_NOSTART; + btwrite(xmit, BT848_I2C); + retval = bttv_i2c_wait_done(btv); + if (retval < 0) + goto err; + if (retval == 0) + goto eio; + msg->buf[cnt] = ((u32)btread(BT848_I2C) >> 8) & 0xff; + if (i2c_debug) { + if (!(xmit & BT878_I2C_NOSTART)) + printk(" addr << 1) +1); + printk(" =%02x", msg->buf[cnt]); + if (!(xmit & BT878_I2C_NOSTOP)) + printk(" >\n"); + } + } + return msg->len; + + eio: + retval = -EIO; + err: + if (i2c_debug) + printk(" ERR: %d\n",retval); + return retval; +} + +int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) +{ + struct bttv *btv = i2c_get_adapdata(i2c_adap); + int retval = 0; + int i; + + if (i2c_debug) + printk("bt-i2c:"); + btwrite(BT848_INT_I2CDONE|BT848_INT_RACK, BT848_INT_STAT); + for (i = 0 ; i < num; i++) { + if (msgs[i].flags & I2C_M_RD) { + /* read */ + retval = bttv_i2c_readbytes(btv, &msgs[i], i+1 == num); + if (retval < 0) + goto err; + } else { + /* write */ + retval = bttv_i2c_sendbytes(btv, &msgs[i], i+1 == num); + if (retval < 0) + goto err; + } + } + return num; + + err: + return retval; +} + +static struct i2c_algorithm bttv_algo = { + .name = "bt878", + .id = I2C_ALGO_BIT | I2C_HW_B_BT848 /* FIXME */, + .master_xfer = bttv_i2c_xfer, + .algo_control = algo_control, + .functionality = functionality, +}; + +static struct i2c_adapter bttv_i2c_adap_hw_template = { +#ifdef I2C_PEC + .owner = THIS_MODULE, +#else + .inc_use = bttv_inc_use, + .dec_use = bttv_dec_use, +#endif +#ifdef I2C_ADAP_CLASS_TV_ANALOG + .class = I2C_ADAP_CLASS_TV_ANALOG, +#endif + I2C_DEVNAME("bt878"), + .id = I2C_ALGO_BIT | I2C_HW_B_BT848 /* FIXME */, + .algo = &bttv_algo, + .client_register = attach_inform, +}; + +/* ----------------------------------------------------------------------- */ +/* I2C functions - common stuff */ + +#ifndef I2C_PEC +static void bttv_inc_use(struct i2c_adapter *adap) +{ + MOD_INC_USE_COUNT; +} + +static void bttv_dec_use(struct i2c_adapter *adap) +{ + MOD_DEC_USE_COUNT; +} +#endif + +static int attach_inform(struct i2c_client *client) +{ + struct bttv *btv = i2c_get_adapdata(client->adapter); + + if (btv->tuner_type != UNSET) + bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); + if (btv->pinnacle_id != UNSET) + bttv_call_i2c_clients(btv,AUDC_CONFIG_PINNACLE, + &btv->pinnacle_id); + + if (bttv_debug) + printk("bttv%d: i2c attach [client=%s]\n", + btv->c.nr, i2c_clientname(client)); + return 0; +} + +void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg) +{ + if (0 != btv->i2c_rc) + return; + i2c_clients_command(&btv->c.i2c_adap, cmd, arg); +} + +void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg) +{ + if (card >= bttv_num) + return; + bttv_call_i2c_clients(&bttvs[card], cmd, arg); +} + +static struct i2c_client bttv_i2c_client_template = { + I2C_DEVNAME("bttv internal"), + .id = -1, +}; + + +/* read I2C */ +int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for) +{ + unsigned char buffer = 0; + + if (0 != btv->i2c_rc) + return -1; + if (bttv_verbose && NULL != probe_for) + printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ", + btv->c.nr,probe_for,addr); + btv->i2c_client.addr = addr >> 1; + if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) { + if (NULL != probe_for) { + if (bttv_verbose) + printk("not found\n"); + } else + printk(KERN_WARNING "bttv%d: i2c read 0x%x: error\n", + btv->c.nr,addr); + return -1; + } + if (bttv_verbose && NULL != probe_for) + printk("found\n"); + return buffer; +} + +/* write I2C */ +int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, + unsigned char b2, int both) +{ + unsigned char buffer[2]; + int bytes = both ? 2 : 1; + + if (0 != btv->i2c_rc) + return -1; + btv->i2c_client.addr = addr >> 1; + buffer[0] = b1; + buffer[1] = b2; + if (bytes != i2c_master_send(&btv->i2c_client, buffer, bytes)) + return -1; + return 0; +} + +/* read EEPROM content */ +void __devinit bttv_readee(struct bttv *btv, unsigned char *eedata, int addr) +{ + int i; + + if (bttv_I2CWrite(btv, addr, 0, -1, 0)<0) { + printk(KERN_WARNING "bttv: readee error\n"); + return; + } + btv->i2c_client.addr = addr >> 1; + for (i=0; i<256; i+=16) { + if (16 != i2c_master_recv(&btv->i2c_client,eedata+i,16)) { + printk(KERN_WARNING "bttv: readee error\n"); + break; + } + } +} + +/* init + register i2c algo-bit adapter */ +int __devinit init_bttv_i2c(struct bttv *btv) +{ + int use_hw = (btv->id == 878) && i2c_hw; + + memcpy(&btv->i2c_client, &bttv_i2c_client_template, + sizeof(bttv_i2c_client_template)); + + if (use_hw) { + /* bt878 */ + memcpy(&btv->c.i2c_adap, &bttv_i2c_adap_hw_template, + sizeof(bttv_i2c_adap_hw_template)); + } else { + /* bt848 */ + memcpy(&btv->c.i2c_adap, &bttv_i2c_adap_sw_template, + sizeof(bttv_i2c_adap_sw_template)); + memcpy(&btv->i2c_algo, &bttv_i2c_algo_bit_template, + sizeof(bttv_i2c_algo_bit_template)); + btv->i2c_algo.data = btv; + btv->c.i2c_adap.algo_data = &btv->i2c_algo; + } + + btv->c.i2c_adap.dev.parent = &btv->c.pci->dev; + snprintf(btv->c.i2c_adap.name, sizeof(btv->c.i2c_adap.name), + "bt%d #%d [%s]", btv->id, btv->c.nr, use_hw ? "hw" : "sw"); + + i2c_set_adapdata(&btv->c.i2c_adap, btv); + btv->i2c_client.adapter = &btv->c.i2c_adap; + + if (use_hw) { + btv->i2c_rc = i2c_add_adapter(&btv->c.i2c_adap); + } else { + bttv_bit_setscl(btv,1); + bttv_bit_setsda(btv,1); + btv->i2c_rc = i2c_bit_add_bus(&btv->c.i2c_adap); + } + return btv->i2c_rc; +} + +int __devexit fini_bttv_i2c(struct bttv *btv) +{ + int use_hw = (btv->id == 878) && i2c_hw; + + if (0 != btv->i2c_rc) + return 0; + + if (use_hw) { + return i2c_del_adapter(&btv->c.i2c_adap); + } else { + return i2c_bit_del_bus(&btv->c.i2c_adap); + } +} + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/bttv-if.c 830-ivtv/drivers/media/video/bttv-if.c --- 000-virgin/drivers/media/video/bttv-if.c Mon Dec 8 09:55:51 2003 +++ 830-ivtv/drivers/media/video/bttv-if.c Thu Jan 8 11:17:21 2004 @@ -1,7 +1,7 @@ /* - bttv-if.c -- interfaces to other kernel modules - all the i2c code is here - also the gpio interface exported by bttv (used by lirc) + bttv-if.c -- old gpio interface to other kernel modules + don't use in new code, will go away in 2.7 + have a look at bttv-gpio.c instead. bttv - Bt848 frame grabber driver @@ -28,22 +28,10 @@ #include #include #include - #include #include "bttvp.h" -static struct i2c_algo_bit_data bttv_i2c_algo_bit_template; -static struct i2c_adapter bttv_i2c_adap_sw_template; -static struct i2c_adapter bttv_i2c_adap_hw_template; -static struct i2c_client bttv_i2c_client_template; - -#ifndef I2C_PEC -static void bttv_inc_use(struct i2c_adapter *adap); -static void bttv_dec_use(struct i2c_adapter *adap); -#endif -static int attach_inform(struct i2c_client *client); - EXPORT_SYMBOL(bttv_get_cardinfo); EXPORT_SYMBOL(bttv_get_pcidev); EXPORT_SYMBOL(bttv_get_id); @@ -53,11 +41,6 @@ EXPORT_SYMBOL(bttv_write_gpio); EXPORT_SYMBOL(bttv_get_gpio_queue); EXPORT_SYMBOL(bttv_i2c_call); -static int i2c_debug = 0; -static int i2c_hw = 0; -MODULE_PARM(i2c_debug,"i"); -MODULE_PARM(i2c_hw,"i"); - /* ----------------------------------------------------------------------- */ /* Exported functions - for other modules which want to access the */ /* gpio ports (IR for example) */ @@ -68,7 +51,7 @@ int bttv_get_cardinfo(unsigned int card, if (card >= bttv_num) { return -1; } - *type = bttvs[card].type; + *type = bttvs[card].c.type; *cardid = bttvs[card].cardid; return 0; } @@ -77,7 +60,7 @@ struct pci_dev* bttv_get_pcidev(unsigned { if (card >= bttv_num) return NULL; - return bttvs[card].dev; + return bttvs[card].c.pci; } int bttv_get_id(unsigned int card) @@ -86,7 +69,7 @@ int bttv_get_id(unsigned int card) if (card >= bttv_num) { return -1; } - return bttvs[card].type; + return bttvs[card].c.type; } @@ -99,7 +82,7 @@ int bttv_gpio_enable(unsigned int card, } btv = &bttvs[card]; - btaor(data, ~mask, BT848_GPIO_OUT_EN); + gpio_inout(mask,data); if (bttv_gpio) bttv_gpio_tracking(btv,"extern enable"); return 0; @@ -121,7 +104,7 @@ int bttv_read_gpio(unsigned int card, un /* prior setting BT848_GPIO_REG_INP is (probably) not needed because we set direct input on init */ - *data = btread(BT848_GPIO_DATA); + *data = gpio_read(); return 0; } @@ -137,7 +120,7 @@ int bttv_write_gpio(unsigned int card, u /* prior setting BT848_GPIO_REG_INP is (probably) not needed because direct input is set on init */ - btaor(data & mask, ~mask, BT848_GPIO_DATA); + gpio_bits(mask,data); if (bttv_gpio) bttv_gpio_tracking(btv,"extern write"); return 0; @@ -156,418 +139,6 @@ wait_queue_head_t* bttv_get_gpio_queue(u return NULL; } return &btv->gpioq; -} - - -/* ----------------------------------------------------------------------- */ -/* I2C functions - bitbanging adapter (software i2c) */ - -void bttv_bit_setscl(void *data, int state) -{ - struct bttv *btv = (struct bttv*)data; - - if (state) - btv->i2c_state |= 0x02; - else - btv->i2c_state &= ~0x02; - btwrite(btv->i2c_state, BT848_I2C); - btread(BT848_I2C); -} - -void bttv_bit_setsda(void *data, int state) -{ - struct bttv *btv = (struct bttv*)data; - - if (state) - btv->i2c_state |= 0x01; - else - btv->i2c_state &= ~0x01; - btwrite(btv->i2c_state, BT848_I2C); - btread(BT848_I2C); -} - -static int bttv_bit_getscl(void *data) -{ - struct bttv *btv = (struct bttv*)data; - int state; - - state = btread(BT848_I2C) & 0x02 ? 1 : 0; - return state; -} - -static int bttv_bit_getsda(void *data) -{ - struct bttv *btv = (struct bttv*)data; - int state; - - state = btread(BT848_I2C) & 0x01; - return state; -} - -static struct i2c_algo_bit_data bttv_i2c_algo_bit_template = { - .setsda = bttv_bit_setsda, - .setscl = bttv_bit_setscl, - .getsda = bttv_bit_getsda, - .getscl = bttv_bit_getscl, - .udelay = 16, - .mdelay = 10, - .timeout = 200, -}; - -static struct i2c_adapter bttv_i2c_adap_sw_template = { -#ifdef I2C_PEC - .owner = THIS_MODULE, -#else - .inc_use = bttv_inc_use, - .dec_use = bttv_dec_use, -#endif -#ifdef I2C_ADAP_CLASS_TV_ANALOG - .class = I2C_ADAP_CLASS_TV_ANALOG, -#endif - I2C_DEVNAME("bt848"), - .id = I2C_HW_B_BT848, - .client_register = attach_inform, -}; - -/* ----------------------------------------------------------------------- */ -/* I2C functions - hardware i2c */ - -static int algo_control(struct i2c_adapter *adapter, - unsigned int cmd, unsigned long arg) -{ - return 0; -} - -static u32 functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_SMBUS_EMUL; -} - -static int -bttv_i2c_wait_done(struct bttv *btv) -{ - u32 stat; - unsigned long timeout; - - timeout = jiffies + HZ/100 + 1; /* 10ms */ - for (;;) { - stat = btread(BT848_INT_STAT); - if (stat & BT848_INT_I2CDONE) - break; - if (time_after(jiffies,timeout)) - return -EIO; - udelay(10); - } - btwrite(BT848_INT_I2CDONE|BT848_INT_RACK, BT848_INT_STAT); - return ((stat & BT848_INT_RACK) ? 1 : 0); -} - -#define I2C_HW (BT878_I2C_MODE | BT848_I2C_SYNC |\ - BT848_I2C_SCL | BT848_I2C_SDA) - -static int -bttv_i2c_sendbytes(struct bttv *btv, const struct i2c_msg *msg, int last) -{ - u32 xmit; - int retval,cnt; - - /* start, address + first byte */ - xmit = (msg->addr << 25) | (msg->buf[0] << 16) | I2C_HW; - if (msg->len > 1 || !last) - xmit |= BT878_I2C_NOSTOP; - btwrite(xmit, BT848_I2C); - retval = bttv_i2c_wait_done(btv); - if (retval < 0) - goto err; - if (retval == 0) - goto eio; - if (i2c_debug) { - printk(" addr << 1, msg->buf[0]); - if (!(xmit & BT878_I2C_NOSTOP)) - printk(" >\n"); - } - - for (cnt = 1; cnt < msg->len; cnt++ ) { - /* following bytes */ - xmit = (msg->buf[cnt] << 24) | I2C_HW | BT878_I2C_NOSTART; - if (cnt < msg->len-1 || !last) - xmit |= BT878_I2C_NOSTOP; - btwrite(xmit, BT848_I2C); - retval = bttv_i2c_wait_done(btv); - if (retval < 0) - goto err; - if (retval == 0) - goto eio; - if (i2c_debug) { - printk(" %02x", msg->buf[cnt]); - if (!(xmit & BT878_I2C_NOSTOP)) - printk(" >\n"); - } - } - return msg->len; - - eio: - retval = -EIO; - err: - if (i2c_debug) - printk(" ERR: %d\n",retval); - return retval; -} - -static int -bttv_i2c_readbytes(struct bttv *btv, const struct i2c_msg *msg, int last) -{ - u32 xmit; - u32 cnt; - int retval; - - for(cnt = 0; cnt < msg->len; cnt++) { - xmit = (msg->addr << 25) | (1 << 24) | I2C_HW; - if (cnt < msg->len-1) - xmit |= BT848_I2C_W3B; - if (cnt < msg->len-1 || !last) - xmit |= BT878_I2C_NOSTOP; - if (cnt) - xmit |= BT878_I2C_NOSTART; - btwrite(xmit, BT848_I2C); - retval = bttv_i2c_wait_done(btv); - if (retval < 0) - goto err; - if (retval == 0) - goto eio; - msg->buf[cnt] = ((u32)btread(BT848_I2C) >> 8) & 0xff; - if (i2c_debug) { - if (!(xmit & BT878_I2C_NOSTART)) - printk(" addr << 1) +1); - printk(" =%02x", msg->buf[cnt]); - if (!(xmit & BT878_I2C_NOSTOP)) - printk(" >\n"); - } - } - return msg->len; - - eio: - retval = -EIO; - err: - if (i2c_debug) - printk(" ERR: %d\n",retval); - return retval; -} - -int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) -{ - struct bttv *btv = i2c_get_adapdata(i2c_adap); - int retval = 0; - int i; - - if (i2c_debug) - printk("bt-i2c:"); - btwrite(BT848_INT_I2CDONE|BT848_INT_RACK, BT848_INT_STAT); - for (i = 0 ; i < num; i++) { - if (msgs[i].flags & I2C_M_RD) { - /* read */ - retval = bttv_i2c_readbytes(btv, &msgs[i], i+1 == num); - if (retval < 0) - goto err; - } else { - /* write */ - retval = bttv_i2c_sendbytes(btv, &msgs[i], i+1 == num); - if (retval < 0) - goto err; - } - } - return num; - - err: - return retval; -} - -static struct i2c_algorithm bttv_algo = { - .name = "bt878", - .id = I2C_ALGO_BIT | I2C_HW_B_BT848 /* FIXME */, - .master_xfer = bttv_i2c_xfer, - .algo_control = algo_control, - .functionality = functionality, -}; - -static struct i2c_adapter bttv_i2c_adap_hw_template = { -#ifdef I2C_PEC - .owner = THIS_MODULE, -#else - .inc_use = bttv_inc_use, - .dec_use = bttv_dec_use, -#endif -#ifdef I2C_ADAP_CLASS_TV_ANALOG - .class = I2C_ADAP_CLASS_TV_ANALOG, -#endif - I2C_DEVNAME("bt878"), - .id = I2C_ALGO_BIT | I2C_HW_B_BT848 /* FIXME */, - .algo = &bttv_algo, - .client_register = attach_inform, -}; - -/* ----------------------------------------------------------------------- */ -/* I2C functions - common stuff */ - -#ifndef I2C_PEC -static void bttv_inc_use(struct i2c_adapter *adap) -{ - MOD_INC_USE_COUNT; -} - -static void bttv_dec_use(struct i2c_adapter *adap) -{ - MOD_DEC_USE_COUNT; -} -#endif - -static int attach_inform(struct i2c_client *client) -{ - struct bttv *btv = i2c_get_adapdata(client->adapter); - - if (btv->tuner_type != UNSET) - bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); - if (btv->pinnacle_id != UNSET) - bttv_call_i2c_clients(btv,AUDC_CONFIG_PINNACLE, - &btv->pinnacle_id); - - if (bttv_debug) - printk("bttv%d: i2c attach [client=%s]\n", - btv->nr, i2c_clientname(client)); - return 0; -} - -void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg) -{ - if (0 != btv->i2c_rc) - return; - i2c_clients_command(&btv->i2c_adap, cmd, arg); -} - -void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg) -{ - if (card >= bttv_num) - return; - bttv_call_i2c_clients(&bttvs[card], cmd, arg); -} - -static struct i2c_client bttv_i2c_client_template = { - I2C_DEVNAME("bttv internal"), - .id = -1, -}; - - -/* read I2C */ -int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for) -{ - unsigned char buffer = 0; - - if (0 != btv->i2c_rc) - return -1; - if (bttv_verbose && NULL != probe_for) - printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ", - btv->nr,probe_for,addr); - btv->i2c_client.addr = addr >> 1; - if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) { - if (NULL != probe_for) { - if (bttv_verbose) - printk("not found\n"); - } else - printk(KERN_WARNING "bttv%d: i2c read 0x%x: error\n", - btv->nr,addr); - return -1; - } - if (bttv_verbose && NULL != probe_for) - printk("found\n"); - return buffer; -} - -/* write I2C */ -int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, - unsigned char b2, int both) -{ - unsigned char buffer[2]; - int bytes = both ? 2 : 1; - - if (0 != btv->i2c_rc) - return -1; - btv->i2c_client.addr = addr >> 1; - buffer[0] = b1; - buffer[1] = b2; - if (bytes != i2c_master_send(&btv->i2c_client, buffer, bytes)) - return -1; - return 0; -} - -/* read EEPROM content */ -void __devinit bttv_readee(struct bttv *btv, unsigned char *eedata, int addr) -{ - int i; - - if (bttv_I2CWrite(btv, addr, 0, -1, 0)<0) { - printk(KERN_WARNING "bttv: readee error\n"); - return; - } - btv->i2c_client.addr = addr >> 1; - for (i=0; i<256; i+=16) { - if (16 != i2c_master_recv(&btv->i2c_client,eedata+i,16)) { - printk(KERN_WARNING "bttv: readee error\n"); - break; - } - } -} - -/* init + register i2c algo-bit adapter */ -int __devinit init_bttv_i2c(struct bttv *btv) -{ - int use_hw = (btv->id == 878) && i2c_hw; - - memcpy(&btv->i2c_client, &bttv_i2c_client_template, - sizeof(bttv_i2c_client_template)); - - if (use_hw) { - /* bt878 */ - memcpy(&btv->i2c_adap, &bttv_i2c_adap_hw_template, - sizeof(bttv_i2c_adap_hw_template)); - } else { - /* bt848 */ - memcpy(&btv->i2c_adap, &bttv_i2c_adap_sw_template, - sizeof(bttv_i2c_adap_sw_template)); - memcpy(&btv->i2c_algo, &bttv_i2c_algo_bit_template, - sizeof(bttv_i2c_algo_bit_template)); - btv->i2c_algo.data = btv; - btv->i2c_adap.algo_data = &btv->i2c_algo; - } - - btv->i2c_adap.dev.parent = &btv->dev->dev; - snprintf(btv->i2c_adap.name, sizeof(btv->i2c_adap.name), - "bt%d #%d [%s]", btv->id, btv->nr, use_hw ? "hw" : "sw"); - - i2c_set_adapdata(&btv->i2c_adap, btv); - btv->i2c_client.adapter = &btv->i2c_adap; - - if (use_hw) { - btv->i2c_rc = i2c_add_adapter(&btv->i2c_adap); - } else { - bttv_bit_setscl(btv,1); - bttv_bit_setsda(btv,1); - btv->i2c_rc = i2c_bit_add_bus(&btv->i2c_adap); - } - return btv->i2c_rc; -} - -int __devexit fini_bttv_i2c(struct bttv *btv) -{ - int use_hw = (btv->id == 878) && i2c_hw; - - if (0 != btv->i2c_rc) - return 0; - - if (use_hw) { - return i2c_del_adapter(&btv->i2c_adap); - } else { - return i2c_bit_del_bus(&btv->i2c_adap); - } } /* diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/bttv-risc.c 830-ivtv/drivers/media/video/bttv-risc.c --- 000-virgin/drivers/media/video/bttv-risc.c Mon Nov 17 18:29:29 2003 +++ 830-ivtv/drivers/media/video/bttv-risc.c Thu Jan 8 11:17:21 2004 @@ -53,7 +53,7 @@ bttv_risc_packed(struct bttv *btv, struc one write per scan line + sync + jump (all 2 dwords) */ instructions = (bpl * lines) / PAGE_SIZE + lines; instructions += 2; - if ((rc = btcx_riscmem_alloc(btv->dev,risc,instructions*8)) < 0) + if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*8)) < 0) return rc; /* sync instruction */ @@ -100,7 +100,7 @@ bttv_risc_packed(struct bttv *btv, struc } offset += padding; } - dprintk("bttv%d: risc planar: %d sglist elems\n", btv->nr, (int)(sg-sglist)); + dprintk("bttv%d: risc planar: %d sglist elems\n", btv->c.nr, (int)(sg-sglist)); /* save pointer to jmp instruction address */ risc->jmp = rp; @@ -128,7 +128,7 @@ bttv_risc_planar(struct bttv *btv, struc plus sync + jump (2 dwords) */ instructions = (ybpl * ylines * 2) / PAGE_SIZE + ylines; instructions += 2; - if ((rc = btcx_riscmem_alloc(btv->dev,risc,instructions*4*5)) < 0) + if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*4*5)) < 0) return rc; /* sync instruction */ @@ -227,7 +227,7 @@ bttv_risc_overlay(struct bttv *btv, stru instructions = (ov->nclips + 1) * ((skip_even || skip_odd) ? ov->w.height>>1 : ov->w.height); instructions += 2; - if ((rc = btcx_riscmem_alloc(btv->dev,risc,instructions*8)) < 0) { + if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*8)) < 0) { kfree(skips); return rc; } @@ -247,9 +247,6 @@ bttv_risc_overlay(struct bttv *btv, stru if ((btv->opt_vcr_hack) && (line >= (ov->w.height - VCR_HACK_LINES))) continue; - if ((line%2) == 0 && skip_even) - continue; - if ((line%2) == 1 && skip_odd) if ((line%2) == 0 && skip_even) continue; if ((line%2) == 1 && skip_odd) @@ -310,7 +307,7 @@ bttv_calc_geo(struct bttv *btv, struct b int totalwidth = tvnorm->totalwidth; int scaledtwidth = tvnorm->scaledtwidth; - if (bttv_tvcards[btv->type].muxsel[btv->input] < 0) { + if (bttv_tvcards[btv->c.type].muxsel[btv->input] < 0) { swidth = 720; totalwidth = 858; scaledtwidth = 858; @@ -391,7 +388,7 @@ bttv_set_dma(struct bttv *btv, int overr d2printk(KERN_DEBUG "bttv%d: capctl=%x irq=%d top=%08Lx/%08Lx even=%08Lx/%08Lx\n", - btv->nr,capctl,irqflags, + btv->c.nr,capctl,irqflags, btv->curr.vbi ? (unsigned long long)btv->curr.vbi->top.dma : 0, btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0, btv->curr.vbi ? (unsigned long long)btv->curr.vbi->bottom.dma : 0, @@ -429,10 +426,10 @@ bttv_risc_init_main(struct bttv *btv) { int rc; - if ((rc = btcx_riscmem_alloc(btv->dev,&btv->main,PAGE_SIZE)) < 0) + if ((rc = btcx_riscmem_alloc(btv->c.pci,&btv->main,PAGE_SIZE)) < 0) return rc; dprintk(KERN_DEBUG "bttv%d: risc main @ %08Lx\n", - btv->nr,(unsigned long long)btv->main.dma); + btv->c.nr,(unsigned long long)btv->main.dma); btv->main.cpu[0] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC | BT848_FIFO_STATUS_VRE); @@ -472,11 +469,11 @@ bttv_risc_hook(struct bttv *btv, int slo if (NULL == risc) { d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=NULL\n", - btv->nr,risc,slot); + btv->c.nr,risc,slot); btv->main.cpu[slot+1] = cpu_to_le32(next); } else { d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=%08Lx irq=%d\n", - btv->nr,risc,slot,(unsigned long long)risc->dma,irqflags); + btv->c.nr,risc,slot,(unsigned long long)risc->dma,irqflags); cmd = BT848_RISC_JUMP; if (irqflags) { cmd |= BT848_RISC_IRQ; @@ -496,10 +493,10 @@ bttv_dma_free(struct bttv *btv, struct b if (in_interrupt()) BUG(); videobuf_waiton(&buf->vb,0,0); - videobuf_dma_pci_unmap(btv->dev, &buf->vb.dma); + videobuf_dma_pci_unmap(btv->c.pci, &buf->vb.dma); videobuf_dma_free(&buf->vb.dma); - btcx_riscmem_free(btv->dev,&buf->bottom); - btcx_riscmem_free(btv->dev,&buf->top); + btcx_riscmem_free(btv->c.pci,&buf->bottom); + btcx_riscmem_free(btv->c.pci,&buf->top); buf->vb.state = STATE_NEEDS_INIT; } @@ -577,7 +574,7 @@ bttv_buffer_risc(struct bttv *btv, struc dprintk(KERN_DEBUG "bttv%d: buffer field: %s format: %s size: %dx%d\n", - btv->nr, v4l2_field_names[buf->vb.field], + btv->c.nr, v4l2_field_names[buf->vb.field], buf->fmt->name, buf->vb.width, buf->vb.height); /* packed pixel modes */ @@ -731,7 +728,7 @@ bttv_overlay_risc(struct bttv *btv, /* check interleave, bottom+top fields */ dprintk(KERN_DEBUG "bttv%d: overlay fields: %s format: %s size: %dx%d\n", - btv->nr, v4l2_field_names[buf->vb.field], + btv->c.nr, v4l2_field_names[buf->vb.field], fmt->name,ov->w.width,ov->w.height); /* calculate geometry */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/bttv-vbi.c 830-ivtv/drivers/media/video/bttv-vbi.c --- 000-virgin/drivers/media/video/bttv-vbi.c Mon Nov 17 18:29:29 2003 +++ 830-ivtv/drivers/media/video/bttv-vbi.c Thu Jan 8 11:17:21 2004 @@ -44,7 +44,7 @@ MODULE_PARM_DESC(vbi_debug,"vbi code deb # undef dprintk #endif #define dprintk(fmt, arg...) if (vbi_debug) \ - printk(KERN_DEBUG "bttv%d/vbi: " fmt, btv->nr, ## arg) + printk(KERN_DEBUG "bttv%d/vbi: " fmt, btv->c.nr , ## arg) /* ----------------------------------------------------------------------- */ /* vbi risc code + mm */ @@ -87,7 +87,7 @@ static int vbi_buffer_prepare(struct fil return -EINVAL; if (STATE_NEEDS_INIT == buf->vb.state) { - if (0 != (rc = videobuf_iolock(btv->dev, &buf->vb, NULL))) + if (0 != (rc = videobuf_iolock(btv->c.pci, &buf->vb, NULL))) goto fail; if (0 != (rc = vbi_buffer_risc(btv,buf,fh->lines))) goto fail; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/bttv.h 830-ivtv/drivers/media/video/bttv.h --- 000-virgin/drivers/media/video/bttv.h Mon Nov 17 18:29:29 2003 +++ 830-ivtv/drivers/media/video/bttv.h Thu Jan 8 11:17:21 2004 @@ -14,6 +14,7 @@ #define _BTTV_H_ #include +#include /* ---------------------------------------------------------- */ /* exported by bttv-cards.c */ @@ -117,6 +118,10 @@ #define BTTV_PV143 0x69 #define BTTV_IVC100 0x6e #define BTTV_IVC120 0x6f +#define BTTV_PC_HDTV 0x70 +#define BTTV_TWINHAN_DST 0x71 +#define BTTV_WINFASTVC100 0x72 +#define BTTV_SIMUS_GVC1100 0x74 /* i2c address list */ #define I2C_TSA5522 0xc2 @@ -150,6 +155,18 @@ #define DIGITAL_MODE_VIDEO 1 #define DIGITAL_MODE_CAMERA 2 +struct bttv_core { + /* device structs */ + struct pci_dev *pci; + struct i2c_adapter i2c_adap; + struct list_head subs; /* struct bttv_sub_device */ + + /* device config */ + unsigned int nr; /* dev nr (for printk("bttv%d: ..."); */ + unsigned int type; /* card type (pointer into tvcards[]) */ + char name[8]; /* dev name */ +}; + struct bttv; struct tvcard @@ -173,7 +190,10 @@ struct tvcard unsigned int msp34xx_alt:1; /* flag: video pci function is unused */ - unsigned int no_video; + unsigned int no_video:1; + unsigned int has_dvb:1; + unsigned int has_remote:1; + unsigned int no_gpioirq:1; /* other settings */ unsigned int pll; @@ -208,7 +228,9 @@ extern int bttv_handle_chipset(struct bt /* ---------------------------------------------------------- */ /* exported by bttv-if.c */ -/* interface for gpio access by other modules */ + +/* this obsolete -- please use the sysfs-based + interface below for new code */ /* returns card type + card ID (for bt878-based ones) for possible values see lines below beginning with #define BTTV_UNKNOWN @@ -256,7 +278,43 @@ extern wait_queue_head_t* bttv_get_gpio_ extern void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg); -/* i2c */ + +/* ---------------------------------------------------------- */ +/* sysfs/driver-moded based gpio access interface */ + + +struct bttv_sub_device { + struct device dev; + struct bttv_core *core; + struct list_head list; +}; +#define to_bttv_sub_dev(x) container_of((x), struct bttv_sub_device, dev) + +struct bttv_sub_driver { + struct device_driver drv; + char wanted[BUS_ID_SIZE]; + void (*gpio_irq)(struct bttv_sub_device *sub); +}; +#define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv) + +int bttv_sub_register(struct bttv_sub_driver *drv, char *wanted); +int bttv_sub_unregister(struct bttv_sub_driver *drv); + +/* gpio access functions */ +void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits); +u32 bttv_gpio_read(struct bttv_core *core); +void bttv_gpio_write(struct bttv_core *core, u32 value); +void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits); + +#define gpio_inout(mask,bits) bttv_gpio_inout(&btv->c, mask, bits) +#define gpio_read() bttv_gpio_read(&btv->c) +#define gpio_write(value) bttv_gpio_write(&btv->c, value) +#define gpio_bits(mask,bits) bttv_gpio_bits(&btv->c, mask, bits) + + +/* ---------------------------------------------------------- */ +/* i2c */ + extern void bttv_bit_setscl(void *data, int state); extern void bttv_bit_setsda(void *data, int state); extern void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/bttvp.h 830-ivtv/drivers/media/video/bttvp.h --- 000-virgin/drivers/media/video/bttvp.h Mon Nov 17 18:29:29 2003 +++ 830-ivtv/drivers/media/video/bttvp.h Thu Jan 8 11:17:21 2004 @@ -41,13 +41,11 @@ #include #include #include +#include #include "bt848.h" #include "bttv.h" #include "btcx-risc.h" -#ifdef CONFIG_VIDEO_IR -#include "ir-common.h" -#endif #ifdef __KERNEL__ @@ -219,11 +217,14 @@ void bttv_vbi_setlines(struct bttv_fh *f extern struct videobuf_queue_ops bttv_vbi_qops; /* ---------------------------------------------------------- */ -/* bttv-input.c */ +/* bttv-gpio.c */ + + +extern struct bus_type bttv_sub_bus_type; +int bttv_sub_add_device(struct bttv_core *core, char *name); +int bttv_sub_del_devices(struct bttv_core *core); +void bttv_gpio_irq(struct bttv_core *core); -int bttv_input_init(struct bttv *btv); -void bttv_input_fini(struct bttv *btv); -void bttv_input_irq(struct bttv *btv); /* ---------------------------------------------------------- */ /* bttv-driver.c */ @@ -263,7 +264,6 @@ struct bttv_pll_info { unsigned int pll_current; /* Currently programmed ofreq */ }; -#ifdef CONFIG_VIDEO_IR /* for gpio-connected remote control */ struct bttv_input { struct input_dev dev; @@ -273,36 +273,46 @@ struct bttv_input { u32 mask_keycode; u32 mask_keydown; }; -#endif + +struct bttv_suspend_state { + u32 pci_cfg[64 / sizeof(u32)]; + u32 gpio_enable; + u32 gpio_data; + int disabled; + struct bttv_buffer_set set; +}; struct bttv { + struct bttv_core c; + /* pci device config */ - struct pci_dev *dev; unsigned short id; unsigned char revision; unsigned char *bt848_mmio; /* pointer to mmio */ /* card configuration info */ - unsigned int nr; /* dev nr (for printk("bttv%d: ..."); */ - char name[8]; /* dev name */ unsigned int cardid; /* pci subsystem id (bt878 based ones) */ - unsigned int type; /* card type (pointer into tvcards[]) */ unsigned int tuner_type; /* tuner chip type */ unsigned int pinnacle_id; unsigned int svhs; struct bttv_pll_info pll; int triton1; + int gpioirq; - /* gpio interface */ + /* old gpio interface */ wait_queue_head_t gpioq; int shutdown; void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set); - + + /* new gpio interface */ + spinlock_t gpio_lock; + /* i2c layer */ - struct i2c_adapter i2c_adap; struct i2c_algo_bit_data i2c_algo; struct i2c_client i2c_client; int i2c_state, i2c_rc; + int i2c_done; + wait_queue_head_t i2c_queue; /* video4linux (1) */ struct video_device *video_dev; @@ -311,9 +321,7 @@ struct bttv { /* infrared remote */ int has_remote; -#ifdef CONFIG_VIDEO_IR struct bttv_input *remote; -#endif /* locking */ spinlock_t s_lock; @@ -339,6 +347,8 @@ struct bttv { int opt_chroma_agc; int opt_adc_crush; int opt_vcr_hack; + int opt_whitecrush_upper; + int opt_whitecrush_lower; /* radio data/state */ int has_radio; @@ -372,6 +382,7 @@ struct bttv { unsigned long dma_on; struct timer_list timeout; unsigned int errors; + struct bttv_suspend_state state; unsigned int users; struct bttv_fh init; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/ir-kbd-gpio.c 830-ivtv/drivers/media/video/ir-kbd-gpio.c --- 000-virgin/drivers/media/video/ir-kbd-gpio.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/media/video/ir-kbd-gpio.c Thu Jan 8 11:17:24 2004 @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2003 Gerd Knorr + * Copyright (c) 2003 Pavel Machek + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "bttv.h" + +/* ---------------------------------------------------------------------- */ + +static IR_KEYTAB_TYPE ir_codes_avermedia[IR_KEYTAB_SIZE] = { + [ 17 ] = KEY_KP0, + [ 20 ] = KEY_KP1, + [ 12 ] = KEY_KP2, + [ 28 ] = KEY_KP3, + [ 18 ] = KEY_KP4, + [ 10 ] = KEY_KP5, + [ 26 ] = KEY_KP6, + [ 22 ] = KEY_KP7, + [ 14 ] = KEY_KP8, + [ 30 ] = KEY_KP9, + + [ 24 ] = KEY_EJECTCD, // Unmarked on my controller + [ 0 ] = KEY_POWER, + [ 9 ] = BTN_LEFT, // DISPLAY/L + [ 25 ] = BTN_RIGHT, // LOOP/R + [ 5 ] = KEY_MUTE, + [ 19 ] = KEY_RECORD, + [ 11 ] = KEY_PAUSE, + [ 27 ] = KEY_STOP, + [ 15 ] = KEY_VOLUMEDOWN, + [ 31 ] = KEY_VOLUMEUP, + + [ 16 ] = KEY_TUNER, // TV/FM + [ 8 ] = KEY_CD, + [ 4 ] = KEY_VIDEO, + [ 2 ] = KEY_AUDIO, + [ 6 ] = KEY_ZOOM, // full screen + [ 1 ] = KEY_INFO, // preview + [ 21 ] = KEY_SEARCH, // autoscan + [ 13 ] = KEY_STOP, // freeze + [ 29 ] = KEY_RECORD, // capture + [ 3 ] = KEY_PLAY, // unmarked + [ 24 ] = KEY_RED, // unmarked + [ 7 ] = KEY_GREEN, // unmarked + +#if 0 + [ 16 ] = KEY_YELLOW, // unmarked + [ 8 ] = KEY_CHANNELDOWN, + [ 24 ] = KEY_CHANNELUP, + [ 0 ] = KEY_BLUE, // unmarked +#endif +}; + +static IR_KEYTAB_TYPE winfast_codes[IR_KEYTAB_SIZE] = { + [ 5 ] = KEY_KP1, + [ 6 ] = KEY_KP2, + [ 7 ] = KEY_KP3, + [ 9 ] = KEY_KP4, + [ 10 ] = KEY_KP5, + [ 11 ] = KEY_KP6, + [ 13 ] = KEY_KP7, + [ 14 ] = KEY_KP8, + [ 15 ] = KEY_KP9, + [ 18 ] = KEY_KP0, + + [ 0 ] = KEY_POWER, +// [ 27 ] = MTS button + [ 2 ] = KEY_TUNER, // TV/FM + [ 30 ] = KEY_VIDEO, +// [ 22 ] = display button + [ 4 ] = KEY_VOLUMEUP, + [ 8 ] = KEY_VOLUMEDOWN, + [ 12 ] = KEY_CHANNELUP, + [ 16 ] = KEY_CHANNELDOWN, + [ 3 ] = KEY_ZOOM, // fullscreen + [ 31 ] = KEY_SUBTITLE, // closed caption/teletext + [ 32 ] = KEY_SLEEP, +// [ 41 ] = boss key + [ 20 ] = KEY_MUTE, + [ 43 ] = KEY_RED, + [ 44 ] = KEY_GREEN, + [ 45 ] = KEY_YELLOW, + [ 46 ] = KEY_BLUE, + [ 24 ] = KEY_KPPLUS, //fine tune + + [ 25 ] = KEY_KPMINUS, //fine tune - +// [ 42 ] = picture in picture + [ 33 ] = KEY_KPDOT, + [ 19 ] = KEY_KPENTER, +// [ 17 ] = recall + [ 34 ] = KEY_BACK, + [ 35 ] = KEY_PLAYPAUSE, + [ 36 ] = KEY_NEXT, +// [ 37 ] = time shifting + [ 38 ] = KEY_STOP, + [ 39 ] = KEY_RECORD +// [ 40 ] = snapshot +}; + +static IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE] = { + [ 2 ] = KEY_KP0, + [ 1 ] = KEY_KP1, + [ 11 ] = KEY_KP2, + [ 27 ] = KEY_KP3, + [ 5 ] = KEY_KP4, + [ 9 ] = KEY_KP5, + [ 21 ] = KEY_KP6, + [ 6 ] = KEY_KP7, + [ 10 ] = KEY_KP8, + [ 18 ] = KEY_KP9, + + [ 3 ] = KEY_TUNER, // TV/FM + [ 7 ] = KEY_SEARCH, // scan + [ 28 ] = KEY_ZOOM, // full screen + [ 30 ] = KEY_POWER, + [ 23 ] = KEY_VOLUMEDOWN, + [ 31 ] = KEY_VOLUMEUP, + [ 20 ] = KEY_CHANNELDOWN, + [ 22 ] = KEY_CHANNELUP, + [ 24 ] = KEY_MUTE, + + [ 0 ] = KEY_LIST, // source + [ 19 ] = KEY_INFO, // loop + [ 16 ] = KEY_LAST, // +100 + [ 13 ] = KEY_CLEAR, // reset + [ 12 ] = BTN_RIGHT, // fun++ + [ 4 ] = BTN_LEFT, // fun-- + [ 14 ] = KEY_GOTO, // function + [ 15 ] = KEY_STOP, // freeze +}; + +/* ---------------------------------------------------------------------- */ + +struct IR { + struct bttv_sub_device *sub; + struct input_dev input; + struct ir_input_state ir; + char name[32]; + char phys[32]; + u32 mask_keycode; + u32 mask_keydown; + u32 mask_keyup; + + int polling; + u32 last_gpio; + struct work_struct work; + struct timer_list timer; +}; + +static int debug = 0; /* debug level (0,1,2) */ +MODULE_PARM(debug,"i"); + +#define DEVNAME "ir-kbd-gpio" +#define dprintk(fmt, arg...) if (debug) \ + printk(KERN_DEBUG DEVNAME ": " fmt , ## arg) + +static void ir_irq(struct bttv_sub_device *sub); +static int ir_probe(struct device *dev); +static int ir_remove(struct device *dev); + +static struct bttv_sub_driver driver = { + .drv.name = DEVNAME, + .drv.probe = ir_probe, + .drv.remove = ir_remove, + .gpio_irq = ir_irq, +}; + +/* ---------------------------------------------------------------------- */ + +static void ir_handle_key(struct IR *ir) +{ + u32 gpio,data; + + /* read gpio value */ + gpio = bttv_gpio_read(ir->sub->core); + if (ir->polling) { + if (ir->last_gpio == gpio) + return; + ir->last_gpio = gpio; + } + + /* extract data */ + data = ir_extract_bits(gpio, ir->mask_keycode); + dprintk(DEVNAME ": irq gpio=0x%x code=%d | %s%s%s\n", + gpio, data, + ir->polling ? "poll" : "irq", + (gpio & ir->mask_keydown) ? " down" : "", + (gpio & ir->mask_keyup) ? " up" : ""); + + if (ir->mask_keydown) { + /* bit set on keydown */ + if (gpio & ir->mask_keydown) { + ir_input_keydown(&ir->input,&ir->ir,data,data); + } else { + ir_input_nokey(&ir->input,&ir->ir); + } + + } else if (ir->mask_keyup) { + /* bit cleared on keydown */ + if (0 == (gpio & ir->mask_keyup)) { + ir_input_keydown(&ir->input,&ir->ir,data,data); + } else { + ir_input_nokey(&ir->input,&ir->ir); + } + + } else { + /* can't disturgissh keydown/up :-/ */ + ir_input_keydown(&ir->input,&ir->ir,data,data); + ir_input_nokey(&ir->input,&ir->ir); + } +} + +static void ir_irq(struct bttv_sub_device *sub) +{ + struct IR *ir = dev_get_drvdata(&sub->dev); + + if (!ir->polling) + ir_handle_key(ir); +} + +static void ir_timer(unsigned long data) +{ + struct IR *ir = (struct IR*)data; + + schedule_work(&ir->work); +} + +static void ir_work(void *data) +{ + struct IR *ir = data; + unsigned long timeout; + + ir_handle_key(ir); + timeout = jiffies + (ir->polling * HZ / 1000); + mod_timer(&ir->timer, timeout); +} + +/* ---------------------------------------------------------------------- */ + +static int ir_probe(struct device *dev) +{ + struct bttv_sub_device *sub = to_bttv_sub_dev(dev); + struct IR *ir; + IR_KEYTAB_TYPE *ir_codes = NULL; + int ir_type = IR_TYPE_OTHER; + + ir = kmalloc(sizeof(*ir),GFP_KERNEL); + if (NULL == ir) + return -ENOMEM; + memset(ir,0,sizeof(*ir)); + + /* detect & configure */ + switch (sub->core->type) { + case BTTV_AVERMEDIA: + case BTTV_AVPHONE98: + ir_codes = ir_codes_avermedia; + ir->mask_keycode = 0xf80000; + ir->mask_keydown = 0x010000; + break; + case BTTV_WINFAST2000: + ir_codes = winfast_codes; + ir->mask_keycode = 0x8f8; + break; + case BTTV_PV_BT878P_9B: + case BTTV_PV_BT878P_PLUS: + ir_codes = ir_codes_pixelview; + ir->mask_keycode = 0x001f00; + ir->mask_keyup = 0x008000; + ir->polling = 50; // ms + break; + } + if (NULL == ir_codes) { + kfree(ir); + return -ENODEV; + } + + /* init hardware-specific stuff */ + bttv_gpio_inout(sub->core, ir->mask_keycode | ir->mask_keydown, 0); + ir->sub = sub; + + /* init input device */ + snprintf(ir->name, sizeof(ir->name), "bttv IR (card=%d)", + sub->core->type); + snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", + pci_name(sub->core->pci)); + + ir_input_init(&ir->input, &ir->ir, ir_type, ir_codes); + ir->input.name = ir->name; + ir->input.phys = ir->phys; + ir->input.id.bustype = BUS_PCI; + ir->input.id.version = 1; + if (sub->core->pci->subsystem_vendor) { + ir->input.id.vendor = sub->core->pci->subsystem_vendor; + ir->input.id.product = sub->core->pci->subsystem_device; + } else { + ir->input.id.vendor = sub->core->pci->vendor; + ir->input.id.product = sub->core->pci->device; + } + + if (ir->polling) { + INIT_WORK(&ir->work, ir_work, ir); + init_timer(&ir->timer); + ir->timer.function = ir_timer; + ir->timer.data = (unsigned long)ir; + schedule_work(&ir->work); + } + + /* all done */ + dev_set_drvdata(dev,ir); + input_register_device(&ir->input); + printk(DEVNAME ": %s detected at %s\n",ir->input.name,ir->input.phys); + + return 0; +} + +static int ir_remove(struct device *dev) +{ + struct IR *ir = dev_get_drvdata(dev); + + if (ir->polling) { + del_timer(&ir->timer); + flush_scheduled_work(); + } + + input_unregister_device(&ir->input); + kfree(ir); + return 0; +} + +/* ---------------------------------------------------------------------- */ + +MODULE_AUTHOR("Gerd Knorr, Pavel Machek"); +MODULE_DESCRIPTION("input driver for bt8x8 gpio IR remote controls"); +MODULE_LICENSE("GPL"); + +static int ir_init(void) +{ + return bttv_sub_register(&driver, "remote"); +} + +static void ir_fini(void) +{ + bttv_sub_unregister(&driver); +} + +module_init(ir_init); +module_exit(ir_fini); + + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/ir-kbd-i2c.c 830-ivtv/drivers/media/video/ir-kbd-i2c.c --- 000-virgin/drivers/media/video/ir-kbd-i2c.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/media/video/ir-kbd-i2c.c Thu Jan 8 11:17:24 2004 @@ -0,0 +1,372 @@ +/* + * keyboard input driver for i2c IR remote controls + * + * Copyright (c) 2000-2003 Gerd Knorr + * modified for PixelView (BT878P+W/FM) by + * Michal Kochanowicz + * Christoph Bartelmus + * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by + * Ulrich Mueller + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +struct IR; +struct IR { + struct i2c_client c; + struct input_dev input; + struct ir_input_state ir; + + struct work_struct work; + struct timer_list timer; + char phys[32]; + int (*get_key)(struct IR*, u32*, u32*); +}; + +/* ----------------------------------------------------------------------- */ +/* insmod parameters */ + +static int debug = 0; /* debug level (0,1,2) */ +MODULE_PARM(debug,"i"); + +#define DEVNAME "ir-kbd-i2c" +#define dprintk(level, fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG DEVNAME ": " fmt , ## arg) + +/* ----------------------------------------------------------------------- */ + +static inline int reverse(int data, int bits) +{ + int i,c; + + for (c=0,i=0; ic,buf,3)) + return -EIO; + + /* split rc5 data block ... */ + start = (buf[0] >> 6) & 3; + toggle = (buf[0] >> 5) & 1; + dev = buf[0] & 0x1f; + code = (buf[1] >> 2) & 0x3f; + + if (3 != start) + /* no key pressed */ + return 0; + dprintk(1,"ir hauppauge (rc5): s%d t%d dev=%d code=%d\n", + start, toggle, dev, code); + + /* return key */ + *ir_key = code; + *ir_raw = (start << 12) | (toggle << 11) | (dev << 6) | code; + return 1; +} + +static int get_key_pixelview(struct IR *ir, u32 *ir_key, u32 *ir_raw) +{ + unsigned char b; + + /* poll IR chip */ + if (1 != i2c_master_recv(&ir->c,&b,1)) { + dprintk(1,"read error\n"); + return -EIO; + } + *ir_key = b; + *ir_raw = b; + return 1; +} + +static int get_key_pv951(struct IR *ir, u32 *ir_key, u32 *ir_raw) +{ + unsigned char b; + + /* poll IR chip */ + if (1 != i2c_master_recv(&ir->c,&b,1)) { + dprintk(1,"read error\n"); + return -EIO; + } + + /* ignore 0xaa */ + if (b==0xaa) + return 0; + dprintk(2,"key %02x\n", b); + + *ir_key = b; + *ir_raw = b; + return 1; +} + +static int get_key_knc1(struct IR *ir, u32 *ir_key, u32 *ir_raw) +{ + unsigned char b; + + /* poll IR chip */ + if (1 != i2c_master_recv(&ir->c,&b,1)) { + dprintk(1,"read error\n"); + return -EIO; + } + + /* it seems that 0xFE indicates that a button is still hold + down, while 0xFF indicates that no button is hold + down. 0xFE sequences are sometimes interrupted by 0xFF */ + + dprintk(2,"key %02x\n", b); + + if (b == 0xFF) + return 0; + + if (b == 0xFE) + /* keep old data */ + return 1; + + *ir_key = b; + *ir_raw = b; + return 1; +} + +/* ----------------------------------------------------------------------- */ + +static void ir_key_poll(struct IR *ir) +{ + u32 ir_key, ir_raw; + int rc; + + dprintk(2,"ir_poll_key\n"); + rc = ir->get_key(ir, &ir_key, &ir_raw); + if (rc < 0) { + dprintk(2,"error\n"); + return; + } + + if (0 == rc) { + ir_input_nokey(&ir->input,&ir->ir); + } else { + ir_input_keydown(&ir->input,&ir->ir, ir_key, ir_raw); + } +} + +static void ir_timer(unsigned long data) +{ + struct IR *ir = (struct IR*)data; + schedule_work(&ir->work); +} + +static void ir_work(void *data) +{ + struct IR *ir = data; + ir_key_poll(ir); + mod_timer(&ir->timer, jiffies+HZ/10); +} + +/* ----------------------------------------------------------------------- */ + +static int ir_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind); +static int ir_detach(struct i2c_client *client); +static int ir_probe(struct i2c_adapter *adap); + +static struct i2c_driver driver = { + .name = "ir remote kbd driver", + .id = I2C_DRIVERID_EXP3, /* FIXME */ + .flags = I2C_DF_NOTIFY, + .attach_adapter = ir_probe, + .detach_client = ir_detach, +}; + +static struct i2c_client client_template = +{ + I2C_DEVNAME("unset"), + .driver = &driver +}; + +static int ir_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind) +{ + IR_KEYTAB_TYPE *ir_codes = NULL; + char *name; + int ir_type; + struct IR *ir; + + if (NULL == (ir = kmalloc(sizeof(struct IR),GFP_KERNEL))) + return -ENOMEM; + memset(ir,0,sizeof(*ir)); + ir->c = client_template; + + i2c_set_clientdata(&ir->c, ir); + ir->c.adapter = adap; + ir->c.addr = addr; + + switch(addr) { + case 0x64: + name = "Pixelview"; + ir->get_key = get_key_pixelview; + ir_type = IR_TYPE_OTHER; + ir_codes = ir_codes_empty; + break; + case 0x4b: + name = "PV951"; + ir->get_key = get_key_pv951; + ir_type = IR_TYPE_OTHER; + ir_codes = ir_codes_empty; + break; + case 0x18: + case 0x1a: + name = "Hauppauge"; + ir->get_key = get_key_haup; + ir_type = IR_TYPE_RC5; + ir_codes = ir_codes_rc5_tv; + break; + case 0x30: + name = "KNC One"; + ir->get_key = get_key_knc1; + ir_type = IR_TYPE_OTHER; + ir_codes = ir_codes_empty; + break; + default: + /* shouldn't happen */ + printk(DEVNAME ": Huh? unknown i2c address (0x%02x)?\n",addr); + kfree(ir); + return -1; + } + + /* register i2c device */ + i2c_attach_client(&ir->c); + snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (%s)", name); + snprintf(ir->phys, sizeof(ir->phys), "%s/%s/ir0", + ir->c.adapter->dev.bus_id, + ir->c.dev.bus_id); + + /* init + register input device */ + ir_input_init(&ir->input,&ir->ir,ir_type,ir_codes); + ir->input.id.bustype = BUS_I2C; + ir->input.name = ir->c.name; + ir->input.phys = ir->phys; + input_register_device(&ir->input); + printk(DEVNAME ": %s detected at %s\n",ir->input.name,ir->input.phys); + + /* start polling via eventd */ + INIT_WORK(&ir->work, ir_work, ir); + init_timer(&ir->timer); + ir->timer.function = ir_timer; + ir->timer.data = (unsigned long)ir; + schedule_work(&ir->work); + + return 0; +} + +static int ir_detach(struct i2c_client *client) +{ + struct IR *ir = i2c_get_clientdata(client); + + /* kill outstanding polls */ + del_timer(&ir->timer); + flush_scheduled_work(); + + /* unregister devices */ + input_unregister_device(&ir->input); + i2c_detach_client(&ir->c); + + /* free memory */ + kfree(ir); + return 0; +} + +static int ir_probe(struct i2c_adapter *adap) +{ + + /* The external IR receiver is at i2c address 0x34 (0x35 for + reads). Future Hauppauge cards will have an internal + receiver at 0x30 (0x31 for reads). In theory, both can be + fitted, and Hauppauge suggest an external overrides an + internal. + + That's why we probe 0x1a (~0x34) first. CB + */ + + static const int probe[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1}; + struct i2c_client c; char buf; int i,rc; + + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) { + memset(&c,0,sizeof(c)); + c.adapter = adap; + for (i = 0; -1 != probe[i]; i++) { + c.addr = probe[i]; + rc = i2c_master_recv(&c,&buf,1); + dprintk(1,"probe 0x%02x @ %s: %s\n", + probe[i], adap->name, + (1 == rc) ? "yes" : "no"); + if (1 == rc) { + ir_attach(adap,probe[i],0,0); + break; + } + } + } + return 0; +} + +/* ----------------------------------------------------------------------- */ + +MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, Ulrich Mueller"); +MODULE_DESCRIPTION("input driver for i2c IR remote controls"); +MODULE_LICENSE("GPL"); + +static int ir_init(void) +{ + i2c_add_driver(&driver); + return 0; +} + +static void ir_fini(void) +{ + i2c_del_driver(&driver); +} + +module_init(ir_init); +module_exit(ir_fini); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/ivtv-api.c 830-ivtv/drivers/media/video/ivtv-api.c --- 000-virgin/drivers/media/video/ivtv-api.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/media/video/ivtv-api.c Thu Jan 8 11:17:36 2004 @@ -0,0 +1,2715 @@ +/* License: GPL + * Author: Kevin Thayer + * + * This file will hold API related functions, both internal (firmware api) + * and external (v4l2, etc) + * + */ + +#include "ivtv.h" + +/* FIXME need to find a good value */ +#define V4L2_PIX_FMT_CMP_MPG2 77777 +#define IVTV_V4L2_MAX_MINOR 15 + +static int ivtv_v4l2_init(struct video_device *v); +static int ivtv_v4l2_close(struct inode *inode, struct file *filp); +static int ivtv_v4l2_open(struct inode *inode, struct file *filp); +static int ivtv_v4l2_read(struct file *filp, char *buf, size_t count, + loff_t *pos); +static ssize_t ivtv_v4l2_write(struct file *filp, const char *buf, size_t count, + loff_t *pos); +static int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +static int ivtv_v4l2_pre_init(struct ivtv *itv); + +struct file_operations ivtv_v4l2_fops = { + read: ivtv_v4l2_read, + write: ivtv_v4l2_write, + open: ivtv_v4l2_open, + ioctl: ivtv_v4l2_ioctl, + release: ivtv_v4l2_close, + poll: ivtv_poll, + owner: THIS_MODULE, +}; + +/* FIXME Static variables for the various card types go here */ + +struct video_device tmk_v4l2dev = { /*values that work with the author's card */ +.owner = THIS_MODULE, +.name = "Vanilla iTVC15 card", +.type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_OVERLAY| + VID_TYPE_CLIPPING|VID_TYPE_SCALES, +.fops = &ivtv_v4l2_fops, +.hardware = 0, +.minor = -1, +}; + + +/* some tuner table values can change, so allocate this dynamically when you use it*/ +struct v4l2_tuner tmk_tuners[2] = { + { + .index = 0, + .name = "ivtv TV Tuner", + .type = V4L2_TUNER_ANALOG_TV, + .capability = (V4L2_TUNER_CAP_NORM|V4L2_TUNER_CAP_STEREO), + .rxsubchans = (V4L2_TUNER_SUB_STEREO), + .audmode = V4L2_TUNER_MODE_STEREO, + .signal = 0, + .afc = 0, + .reserved = {0,0,0,0} + },{ + .index = 1, + .name = "ivtv Radio", + .type = V4L2_TUNER_RADIO, + .capability = (V4L2_TUNER_CAP_STEREO), + .rxsubchans = 0, + .audmode = V4L2_TUNER_MODE_STEREO, + .signal = 0, + .afc = 0, + .reserved = {0,0,0,0} + } +}; + +struct v4l2_standard tmk_standards[3] = { + { + .index = 0, + .id = V4L2_STD_NTSC, + .name = "NTSC", + .frameperiod = { .numerator = 1001, + .denominator= 30000}, + .framelines = 525, + .reserved = {0,0,0,0} + },{ + .index = 1, + .id = V4L2_STD_PAL, + .name = "PAL", + .frameperiod = { .numerator = 1, + .denominator= 25}, + .framelines = 625, + .reserved = {0,0,0,0} + },{ + .index = 2, + .id = V4L2_STD_SECAM, + .name = "SECAM", + .frameperiod = { .numerator = 1, + .denominator= 25}, + .framelines = 625, + .reserved = {0,0,0,0} + } +}; + +struct v4l2_input tmk_inputs[10] = { /*values that work with the author's card */ + { + .index = 0, + .name = "Composite 0", + .type = V4L2_INPUT_TYPE_CAMERA, + .audioset = 1, + .tuner = 0, + .status = 0, + },{ + .index = 1, + .name = "Composite 1", + .type = V4L2_INPUT_TYPE_CAMERA, + .audioset = 1, + .tuner = 0, + .status = 0, + },{ + .index = 2, + .name = "Composite 2", + .type = V4L2_INPUT_TYPE_CAMERA, + .audioset = 1, + .tuner = 0, + .status = 0, + },{ + .index = 3, + .name = "Composite 3", + .type = V4L2_INPUT_TYPE_CAMERA, + .audioset = 1, + .tuner = 0, + .status = 0, + },{ + .index = 4, + .name = "Tuner 0", + .type = V4L2_INPUT_TYPE_TUNER, + .audioset = 0, + .tuner = 0, + .status = 0, + },{ + .index = 5, + .name = "Composite 4", + .type = V4L2_INPUT_TYPE_CAMERA, + .audioset = 1, + .tuner = 0, + .status = 0, + },{ + .index = 6, + .name = "S-Video 0", + .type = V4L2_INPUT_TYPE_CAMERA, + .audioset = 1, + .tuner = 0, + .status = 0, + },{ + .index = 7, + .name = "S-Video 1", + .type = V4L2_INPUT_TYPE_CAMERA, + .audioset = 1, + .tuner = 0, + .status = 0, + },{ + .index = 8, + .name = "S-Video 2", + .type = V4L2_INPUT_TYPE_CAMERA, + .audioset = 1, + .tuner = 0, + .status = 0, + },{ + .index = 9, + .name = "S-Video 3", + .type = V4L2_INPUT_TYPE_CAMERA, + .audioset = 1, + .tuner = 0, + .status = 0, + } +}; + +//FIXME capability and mode might be wrong +struct v4l2_audio tmk_audio_inputs[2] = { + {0,"Tuner Audio In",0,0,}, + {1,"Audio Line In", 0,0,}, +}; + +int tmk_audio_mapping[] = { + 0,3, /* Input 0 is msp input 3 */ + 1,1, /* input 1 is msp input 1 */ + 0,0 /* you're at end of list! */ +}; + +struct v4l2_queryctrl ivtv_ctrl_menu_freq = { + .id = V4L2_CID_IVTV_FREQ, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Frequency", + .minimum = 0, + .maximum = 2, + .step = 1, + .default_value = 2, + .flags = 0, + .reserved = {0,0} +}; + +struct v4l2_querymenu ivtv_ctrl_query_freq[] = { + /* ID, Index, Name, Reserved */ + {V4L2_CID_IVTV_FREQ, 0, "32kHz", 0 }, + {V4L2_CID_IVTV_FREQ, 1, "44.1kHz", 0 }, + {V4L2_CID_IVTV_FREQ, 2, "48kHz", 0 } +}; + +u32 ivtv_audio_tbl_freq[] = { + /* setting */ + 0x2 /* 32kHz binary 10 */, + 0x0 /* 44.1kHz binary 00 */, + 0x1 /* 48kHz binary 01 */ +}; + +u32 ivtv_audio_mask_freq = 0x3; + +struct v4l2_queryctrl ivtv_ctrl_menu_enc = { + .id = V4L2_CID_IVTV_ENC, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Encoding", + .minimum = 0, + .maximum = 2, + .step = 1, + .default_value = 1, + .flags = 0, + .reserved = {0,0} +}; + +struct v4l2_querymenu ivtv_ctrl_query_enc[] = { + /* ID, Index, Name, Reserved */ + {V4L2_CID_IVTV_ENC, 0, "Layer 1", 0}, + {V4L2_CID_IVTV_ENC, 1, "Layer 2", 0}, + {V4L2_CID_IVTV_ENC, 2, "Layer 3(?)", 0} +}; + +u32 ivtv_audio_tbl_enc[] = { + /* setting */ + 0x1 << 2 /* Layer 1 binary 0100 */, + 0x2 << 2 /* Layer 2 binary 1000 */, + 0x3 << 2 /* Layer 3(?) binary 1100 */ +}; + +u32 ivtv_audio_mask_enc = 0xC; + +struct v4l2_queryctrl ivtv_ctrl_menu_bitrate = { + .id = V4L2_CID_IVTV_BITRATE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Audio Bitrate", + .minimum = 0, + .maximum = 14, + .step = 1, + .default_value = 14, + .flags = 0, + .reserved = {0,0} +}; + +struct v4l2_querymenu ivtv_ctrl_query_bitrate[] = { + /* ID, Index, Name, Reserved */ + {V4L2_CID_IVTV_BITRATE, 0, "[L1/L2] Free fmt", 0}, + {V4L2_CID_IVTV_BITRATE, 1, "[L1/L2] 32k/32k", 0}, + {V4L2_CID_IVTV_BITRATE, 2, "[L1/L2] 64k/48k", 0}, + {V4L2_CID_IVTV_BITRATE, 3, "[L1/L2] 96k/56k", 0}, + {V4L2_CID_IVTV_BITRATE, 4, "[L1/L2] 128k/64k", 0}, + {V4L2_CID_IVTV_BITRATE, 5, "[L1/L2] 160k/80k", 0}, + {V4L2_CID_IVTV_BITRATE, 6, "[L1/L2] 192k/96k", 0}, + {V4L2_CID_IVTV_BITRATE, 7, "[L1/L2] 224k/112k", 0}, + {V4L2_CID_IVTV_BITRATE, 8, "[L1/L2] 256k/128k", 0}, + {V4L2_CID_IVTV_BITRATE, 9, "[L1/L2] 288k/160k", 0}, + {V4L2_CID_IVTV_BITRATE, 10, "[L1/L2] 320k/192k", 0}, + {V4L2_CID_IVTV_BITRATE, 11, "[L1/L2] 352k/224k", 0}, + {V4L2_CID_IVTV_BITRATE, 12, "[L1/L2] 384k/256k", 0}, + {V4L2_CID_IVTV_BITRATE, 13, "[L1/L2] 416k/320k", 0}, + {V4L2_CID_IVTV_BITRATE, 14, "[L1/L2] 448k/384k", 0}, +}; + +u32 ivtv_audio_tbl_bitrate[] = { + /* setting */ + 0x0 << 4 /* [L1/L2] Free fmt binary 0000 */, + 0x1 << 4 /* [L1/L2] 32k/32k, binary 0001 */, + 0x2 << 4 /* [L1/L2] 64k/48k, binary 0010 */, + 0x3 << 4 /* [L1/L2] 96k/56k, binary 0011 */, + 0x4 << 4 /* [L1/L2] 128k/64k, binary 0100 */, + 0x5 << 4 /* [L1/L2] 160k/80k, binary 0101 */, + 0x6 << 4 /* [L1/L2] 192k/96k, binary 0110 */, + 0x7 << 4 /* [L1/L2] 224k/112k, binary 0111 */, + 0x8 << 4 /* [L1/L2] 256k/128k, binary 1000 */, + 0x9 << 4 /* [L1/L2] 288k/160k, binary 1001 */, + 0xA << 4 /* [L1/L2] 320k/192k, binary 1010 */, + 0xB << 4 /* [L1/L2] 352k/224k, binary 1011 */, + 0xC << 4 /* [L1/L2] 384k/256k, binary 1100 */, + 0xD << 4 /* [L1/L2] 416k/320k, binary 1101 */, + 0xE << 4 /* [L1/L2] 448k/384k, binary 1110 */ +}; + +u32 ivtv_audio_mask_bitrate = 0xF0; + + +struct v4l2_queryctrl ivtv_ctrl_menu_mono = { + .id = V4L2_CID_IVTV_MONO, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Mono/Stereo", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + .flags = 0, + .reserved = {0,0} +}; + +struct v4l2_querymenu ivtv_ctrl_query_mono[] = { + /* ID, Index, Name, Reserved */ + {V4L2_CID_IVTV_MONO, 0, "Stereo", 0}, + {V4L2_CID_IVTV_MONO, 1, "JointStereo", 0}, + {V4L2_CID_IVTV_MONO, 2, "Dual", 0}, + {V4L2_CID_IVTV_MONO, 3, "Mono", 0} +}; + +u32 ivtv_audio_tbl_mono[] = { + /* setting */ + 0x0 << 8 /* Stereo, binary 00 */, + 0x1 << 8 /* JointStereo, binary 01 */, + 0x2 << 8 /* Dual, binary 10 */, + 0x3 << 8 /* Mono, binary 11 */ +}; + +u32 ivtv_audio_mask_mono = 0x300; + +struct v4l2_queryctrl ivtv_ctrl_menu_joint = { + .id = V4L2_CID_IVTV_JOINT, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Joint extension", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + .flags = 0, + .reserved = {0,0} +}; + +struct v4l2_querymenu ivtv_ctrl_query_joint[] = { + /* ID, Index, Name, Reserved */ + {V4L2_CID_IVTV_JOINT, 0, "Subbands 4-31/bound=4", 0}, + {V4L2_CID_IVTV_JOINT, 1, "Subbands 8-31/bound=8", 0}, + {V4L2_CID_IVTV_JOINT, 2, "Subbands 12-31/bound=12", 0}, + {V4L2_CID_IVTV_JOINT, 3, "Subbands 16-31/bound=16", 0} +}; + +u32 ivtv_audio_tbl_joint[] = { + /* setting */ + 0x0 << 10 /* Subbands 4-31/bound=4, binary 00 */, + 0x1 << 10 /* Subbands 8-31/bound=8, binary 01 */, + 0x2 << 10 /* Subbands 12-31/bound=12, binary 10 */, + 0x3 << 10 /* Subbands 16-31/bound=16, binary 11 */ +}; + +u32 ivtv_audio_mask_joint = 0xc00; + +struct v4l2_queryctrl ivtv_ctrl_menu_emphasis = { + .id = V4L2_CID_IVTV_EMPHASIS, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Emphasis", + .minimum = 0, + .maximum = 2, + .step = 1, + .default_value = 0, + .flags = 0, + .reserved = {0,0} +}; + +struct v4l2_querymenu ivtv_ctrl_query_emphasis[] = { + /* ID, Index, Name, Reserved */ + {V4L2_CID_IVTV_EMPHASIS, 0, "None", 0}, + {V4L2_CID_IVTV_EMPHASIS, 1, "50/15uS", 0}, + {V4L2_CID_IVTV_EMPHASIS, 2, "CCITT J.17", 0} +}; + +u32 ivtv_audio_tbl_emphasis[] = { + /* setting */ + 0x0 << 12 /* None, binary 00 */, + 0x1 << 12 /* 50/15uS, binary 01 */, + 0x3 << 12 /* CCITT J.17, binary 11 */ +}; + +u32 ivtv_audio_mask_emphasis = 0x3000; + +struct v4l2_queryctrl ivtv_ctrl_menu_crc = { + .id = V4L2_CID_IVTV_CRC, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Audio CRC", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + .reserved = {0,0} +}; + +struct v4l2_querymenu ivtv_ctrl_query_crc[] = { + /* ID, Index, Name, Reserved */ + {V4L2_CID_IVTV_CRC, 0, "off", 0}, + {V4L2_CID_IVTV_CRC, 1, "on", 0} +}; + +u32 ivtv_audio_tbl_crc[] = { + /* setting */ + 0x0 << 14 /* off, binary 0 */, + 0x1 << 14 /* on, binary 1 */ +}; + +u32 ivtv_audio_mask_crc = 0x4000; + +struct v4l2_queryctrl ivtv_ctrl_menu_copyright = { + .id = V4L2_CID_IVTV_COPYRIGHT, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Copyright", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + .reserved = {0,0} +}; + +struct v4l2_querymenu ivtv_ctrl_query_copyright[] = { + /* ID, Index, Name, Reserved */ + {V4L2_CID_IVTV_COPYRIGHT, 0, "off", 0}, + {V4L2_CID_IVTV_COPYRIGHT, 1, "on", 0} +}; + +u32 ivtv_audio_tbl_copyright[] = { + /* setting */ + 0x0 << 15 /* off, binary 0 */, + 0x1 << 15 /* on, binary 1 */ +}; + +u32 ivtv_audio_mask_copyright = 0x8000; + +struct v4l2_queryctrl ivtv_ctrl_menu_generation = { + .id = V4L2_CID_IVTV_GEN, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Generation", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + .reserved = {0,0} +}; + +struct v4l2_querymenu ivtv_ctrl_query_generation[] = { + /* ID, Index, Name, Reserved */ + {V4L2_CID_IVTV_GEN, 0, "copy", 0}, + {V4L2_CID_IVTV_GEN, 1, "original", 0} +}; + +u32 ivtv_audio_tbl_generation[] = { + /* setting */ + 0x0 << 16 /* copy, binary 0 */, + 0x1 << 16 /* original, binary 1 */ +}; + +u32 ivtv_audio_mask_generation = 0x10000; + + +/* 3 stream types: mpeg, yuv, passthru */ +struct ivtv_v4l2_stream tmk_mpg_stream = { +/*MPEG*/ + .s_flags = 0, + .id = -1, + .v4l_reg_type = VFL_TYPE_GRABBER, + .format = { + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .fmt = { + .pix = { + .width = 720, + .height = 480, + .field = V4L2_FIELD_INTERLACED, + .sizeimage = (128*1024), + } + }, + }, + .controlcount = 0, + .controls = NULL +}; + +struct ivtv_v4l2_stream tmk_yuv_stream = { +/*YUV*/ + .s_flags = 0, + .id = -1, + .v4l_reg_type = VFL_TYPE_GRABBER, + .format = { + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .fmt = { + .pix = { + .width = 720, + .height = 480, + .field = V4L2_FIELD_INTERLACED, + .sizeimage = (720*720), + } + }, + }, + .controlcount = 0, + .controls = NULL +}; + +//FIXME these settings are way wrong +struct ivtv_v4l2_stream tmk_vbi_stream = { + .s_flags = 0, + .id = -1, + .v4l_reg_type = VFL_TYPE_VBI, + .format = { + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .fmt = { + .pix = { + .width = 720, + .height = 480, + .field = V4L2_FIELD_INTERLACED, + .sizeimage = (128*1024), + } + }, + }, + .controlcount = 0, + .controls = NULL +}; + +struct ivtv_v4l2_stream dec_mpg_stream = { +/*Decoder MPG*/ + .s_flags = 0, + .id = -1, + .v4l_reg_type = VFL_TYPE_GRABBER, + .format = { + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT, + .fmt = { + .pix = { + .width = 720, + .height = 480, + .field = V4L2_FIELD_INTERLACED, + .sizeimage = (128*1024), + } + }, + }, + .controlcount = 0, + .controls = NULL +}; + +struct ivtv_v4l2_stream dec_yuv_stream = { +/*Decoder YUV*/ + .s_flags = 0, + .id = -1, + .v4l_reg_type = VFL_TYPE_GRABBER, + .format = { + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT, + .fmt = { + .pix = { + .width = 720, + .height = 480, + .field = V4L2_FIELD_INTERLACED, + .sizeimage = (720*720), + } + }, + }, + .controlcount = 0, + .controls = NULL +}; + +/* Initialize v4l2 variables and register v4l2 device */ +int ivtv_v4l2_setup(struct ivtv *itv) { + int x, cont, retval; + + IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 setup\n"); + + /* Set owner for auto usage-incrementing and such */ + //SET_MODULE_OWNER(&ivtv_v4l2_fops); + + //switch based on card type + // and fill in appropriate v4l2 device + switch (itv->card_type) { + case IVTV_350_V1: + IVTV_DEBUG(IVTV_DEBUG_INFO,"Configuring 350rev1 card\n"); + itv->v4l2.streamcount = IVTV_350_V1_STREAMS; + /* Disable dec yuv buffers if requested */ + if (itv->options.dec_yuv_buffers == 0) itv->v4l2.streamcount--; + /* FIXME wrong values */ + itv->v4l2.capabilities = (V4L2_CAP_VIDEO_CAPTURE|V4L2_CAP_TUNER| + V4L2_CAP_AUDIO|V4L2_CAP_READWRITE| + V4L2_CAP_VIDEO_OUTPUT); + break; + case IVTV_250_V2: + IVTV_DEBUG(IVTV_DEBUG_INFO,"Configuring 250rev2 card\n"); + itv->v4l2.streamcount = IVTV_250_V2_STREAMS; + /* FIXME wrong values */ + itv->v4l2.capabilities = (V4L2_CAP_VIDEO_CAPTURE|V4L2_CAP_TUNER| + V4L2_CAP_AUDIO|V4L2_CAP_READWRITE); + break; + case IVTV_250_V1: + IVTV_DEBUG(IVTV_DEBUG_INFO,"Configuring 250rev1 card\n"); + default: /* shouldn't happen, treat like V1 */ + itv->v4l2.streamcount = IVTV_250_V1_STREAMS; + itv->v4l2.capabilities = (V4L2_CAP_VIDEO_CAPTURE|V4L2_CAP_TUNER| + V4L2_CAP_AUDIO|V4L2_CAP_READWRITE); + + break; + } + + /* Initial settings */ + itv->v4l2.codec.bitrate_mode = 0; + itv->v4l2.codec.bitrate = 8000000; + itv->v4l2.codec.bitrate_peak = 16000000; + itv->v4l2.codec.stream_type = IVTV_STREAM_PS; + itv->v4l2.codec.bframes = 3; + itv->v4l2.codec.gop_closure = 0; + itv->v4l2.codec.dnr_mode = 0; + itv->v4l2.codec.dnr_type = 0; + itv->v4l2.codec.dnr_spatial = 0; + itv->v4l2.codec.dnr_temporal = 0; + itv->v4l2.codec.aspect = 2; + + itv->dec_options.hide_last_frame= 1; + itv->dec_options.pts_low = 0; + itv->dec_options.pts_hi = 0; + itv->dec_options.gop_offset = 0; + itv->dec_options.mute_frames = 0; + + /* Ctrls */ + itv->dec_options.speed.mute = 1; + itv->dec_options.speed.aud_mute = 0; + itv->dec_options.speed.smooth = 1; + itv->dec_options.speed.fr_mask = 2; + itv->dec_options.speed.fr_field = 1; + itv->dec_options.decbuffers = 1; + itv->dec_options.prebuffer = 1; + + /* Allocate streams */ + itv->v4l2.streams = (struct ivtv_v4l2_stream *) + kmalloc((itv->v4l2.streamcount * + sizeof(struct ivtv_v4l2_stream)), + GFP_KERNEL); + if (NULL == itv->v4l2.streams) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "Couldn't allocate v4l2 streams\n"); + retval = -ENOMEM; + goto ivtv_stream_fail; + } + + /* pre-init */ + retval = ivtv_v4l2_pre_init(itv); + if (retval < 0) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "Error in pre-init\n"); + goto ivtv_pre_init_fail; + } + + /* Fill in streams with some defaults */ + /* FIXME assumes 3 streams, hardcoding */ + memcpy(&itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_MPG], &tmk_mpg_stream, + sizeof(struct ivtv_v4l2_stream)); + + memcpy(&itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_YUV], &tmk_yuv_stream, + sizeof(struct ivtv_v4l2_stream)); + + memcpy(&itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_VBI], &tmk_vbi_stream, + sizeof(struct ivtv_v4l2_stream)); + + /* Set some card-specific per-stream stuff here */ + switch (itv->card_type) { + case IVTV_350_V1: + memcpy(&itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_MPG], &dec_mpg_stream, + sizeof(struct ivtv_v4l2_stream)); + + if (itv->options.dec_yuv_buffers !=0) { + memcpy(&itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_YUV], &dec_yuv_stream, + sizeof(struct ivtv_v4l2_stream)); + } + break; + case IVTV_250_V2: + break; + case IVTV_250_V1: + default: /* shouldn't happen, treat like V1 */ + break; + } + + for (x=0; x < itv->v4l2.streamcount ; x++) { + init_waitqueue_head(&itv->v4l2.streams[x].waitq); + itv->v4l2.streams[x].v4l2dev = video_device_alloc(); + if (NULL == itv->v4l2.streams[x].v4l2dev) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "Couldn't allocate v4l2 video_device\n"); + retval = -ENOMEM; + goto ivtv_videodev_fail; + } + + memcpy(itv->v4l2.streams[x].v4l2dev, + &tmk_v4l2dev, sizeof(struct video_device)); + itv->v4l2.streams[x].v4l2dev->priv = itv; + itv->v4l2.streams[x].ubytes = 0; + itv->v4l2.streams[x].free_q.vdev = itv->v4l2.streams[x].v4l2dev; + itv->v4l2.streams[x].full_q.vdev = itv->v4l2.streams[x].v4l2dev; + itv->v4l2.streams[x].dma_q.vdev = itv->v4l2.streams[x].v4l2dev; + INIT_LIST_HEAD(&itv->v4l2.streams[x].free_q.list); + INIT_LIST_HEAD(&itv->v4l2.streams[x].full_q.list); + INIT_LIST_HEAD(&itv->v4l2.streams[x].dma_q.list); + + retval = ivtv_init_queue(itv, &itv->v4l2.streams[x].full_q, 0, + itv->v4l2.streams[x].format.type); + if (retval < 0) { + IVTV_DEBUG(IVTV_DEBUG_ERR,"Error on init_queue 1\n"); + goto ivtv_initq_fail; + } + retval = ivtv_init_queue(itv, &itv->v4l2.streams[x].dma_q, 0, + itv->v4l2.streams[x].format.type); + if (retval < 0) { + IVTV_DEBUG(IVTV_DEBUG_ERR,"Error on init_queue 2\n"); + goto ivtv_initq_fail; + } + + itv->v4l2.streams[x].v4l2dev->dev = &itv->dev->dev; + itv->v4l2.streams[x].v4l2dev->release = video_device_release; + } + + /* Some streams have specific values */ + x = ivtv_init_queue(itv, + &itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_MPG].free_q, + mpg_buffers, + itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_MPG].format.type); + x = ivtv_init_queue(itv, + &itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_YUV].free_q, + yuv_buffers, + itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_YUV].format.type); + x = ivtv_init_queue(itv, + &itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_VBI].free_q, + vbi_buffers, + itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_VBI].format.type); + + /* set default minors */ + itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_MPG].v4l2dev->minor = itv->num; + itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_YUV].v4l2dev->minor = + itv->num + IVTV_V4L2_YUV_OFFSET; + //vbi will get offset by v4l, so no offset needed by us + itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_VBI].v4l2dev->minor = itv->num; + + /* Set any card-specific per-stream stuff here */ + switch (itv->card_type) { + case IVTV_350_V1: + /* allocate buffers for decoder */ + x = ivtv_init_queue(itv, + &itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_MPG] + .free_q, dec_mpg_buffers, + itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_MPG].format.type); + + itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_MPG].v4l2dev->minor = + itv->num + IVTV_V4L2_DEC_OFFSET; + + if (itv->options.dec_yuv_buffers != 0) { + x = ivtv_init_queue(itv, + &itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_YUV] + .free_q, dec_yuv_buffers, + itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_YUV].format.type); + + itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_YUV].v4l2dev->minor = + itv->num + IVTV_V4L2_YUV_OFFSET + IVTV_V4L2_DEC_OFFSET; + } + + /* Set poll for decoder parts */ + itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_MPG].v4l2dev->fops->poll = ivtv_dec_poll; + if (itv->options.dec_yuv_buffers) + itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_YUV].v4l2dev->fops->poll = ivtv_dec_poll; + + break; + case IVTV_250_V2: + break; + case IVTV_250_V1: + default: /* shouldn't happen, treat like V1 */ + break; + } + + /* allocate minor, register, loop until works or out of range */ + for (x=0;x < itv->v4l2.streamcount; x++) { + cont = 0; + do { + if(video_register_device(itv->v4l2.streams[x].v4l2dev, + itv->v4l2.streams[x].v4l_reg_type, + itv->v4l2.streams[x].v4l2dev->minor)) { + IVTV_DEBUG(IVTV_DEBUG_ERR, + "Device or minor %d not accepted\n", + itv->v4l2.streams[x].v4l2dev->minor); + itv->v4l2.streams[x].v4l2dev->minor++; + } else { + IVTV_DEBUG(IVTV_DEBUG_ERR, + "Registered v4l2 device, minor %d\n", + itv->v4l2.streams[x].v4l2dev->minor); + cont = 1; + ivtv_v4l2_init(itv->v4l2.streams[x].v4l2dev); + } + } while ((0 == cont) && + (itv->v4l2.streams[x].v4l2dev->minor<=IVTV_V4L2_MAX_MINOR)); + if (0 == cont) { + IVTV_DEBUG(IVTV_DEBUG_ERR,"Couldn't register v4l2 device!\n"); + /* invalidate so we don't try to unload the device */ + itv->v4l2.streams[x].v4l2dev->minor = -1; + return -ENODEV; + } + } + + return 0; + +ivtv_pre_init_fail: + /* needs lots of queue cleanup here -axboe */ +ivtv_videodev_fail: + for (x = 0; x < itv->v4l2.streamcount; x++) + if (itv->v4l2.streams[x].v4l2dev != NULL) + video_device_release(itv->v4l2.streams[x].v4l2dev); +ivtv_initq_fail: + kfree(itv->v4l2.streams); +ivtv_stream_fail: + return retval; +} + +/* After setting the audio.active param, call this to + * get the right input.. think of it as a resolver */ +int ivtv_set_audio(struct ivtv *itv, int *map) { + int input,msp_input; + struct msp_matrix mspm; + + do { + input = *(map++); + msp_input = *(map++); + if (input == itv->v4l2.audio.active) { + IVTV_DEBUG(IVTV_DEBUG_INFO, + "Setting audio to input %d\n", msp_input); + mspm.input = msp_input; + mspm.output = itv->v4l2.audio_output; + + ivtv_call_i2c_client(itv, + IVTV_MSP3400_I2C_ADDR, + MSP_SET_MATRIX, + &mspm); + return 0; + } + } while ((msp_input !=0) || (input != 0)); + + IVTV_DEBUG(IVTV_DEBUG_ERR,"Invalid audio input, shouldn't happen!\n"); + + return -EINVAL; +} + +u32 ivtv_pause_encoder(struct ivtv *itv, int cmd) { + u32 data[16], result=0; + int x; + + data[0] = 0; /* 0 = pause, 1 = unpause */ + if (cmd) data[0] = 1; + + x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_PAUSE_ENCODER, + &result,1, &data[0]); + return result; +} + + +/* Called if v4l2 registration is successful. Set video mode here, at least + * that is required on PAL cards */ +int ivtv_v4l2_init(struct video_device *v) { + struct ivtv *ivtv = v->priv; + u32 data[IVTV_MBOX_MAX_DATA], result; + int x; + + /* + * only set it on minor 0 + */ + if (v->minor != 0) + return 0; + + memset(data, 0, sizeof(data)); + /* set display standard */ + if (ivtv_pal) + data[0] = 1; + else + data[0] = 0; + + x = ivtv_api(ivtv->dec_mbox, &ivtv->dec_msem, IVTV_API_DEC_DISP_STANDARD, + &result, 1, &data[0]); + + return 0; +} + + +/* Called before v4l2 registration */ +int ivtv_v4l2_pre_init(struct ivtv *itv) { + int x, temp, retval = -1; + + IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 init\n"); + //Allocate based on card type + // allocate capabilities and such based on device type + + /* FIXME too much hardcoding? */ + //inputs + itv->v4l2.input.active = 4; + itv->v4l2.input.count = 10; + itv->v4l2.input.table.input = tmk_inputs; + + itv->v4l2.audio_output = 1; + + //audio inputs + itv->v4l2.audio.active = 0; + itv->v4l2.audio.count = 2; + itv->v4l2.audio.table.audio = tmk_audio_inputs; + + //outputs .. none yet (no real 350 support anyways) + itv->v4l2.output.active = 0; + itv->v4l2.output.count = 0; + itv->v4l2.output.table.output = NULL; + + + //standards (NTSC, PAL, SECAM) + if (ivtv_pal) + itv->v4l2.standard.active = 1; + else + itv->v4l2.standard.active = 0; + itv->v4l2.standard.count = 3; + itv->v4l2.standard.table.std = tmk_standards; + + if (itv->v4l2.standard.active == 0) { + itv->v4l2.codec.framespergop = 15; // NTSC + itv->v4l2.codec.framerate = 0; // NTSC 30fps + } else { + itv->v4l2.codec.framespergop = 12; // PAL + itv->v4l2.codec.framerate = 1; // PAL 25fps + + /* set pal height in stream defaults */ + tmk_mpg_stream.format.fmt.pix.height = 576; + tmk_yuv_stream.format.fmt.pix.height = 576; + tmk_vbi_stream.format.fmt.pix.height = 576; + dec_mpg_stream.format.fmt.pix.height = 576; + dec_yuv_stream.format.fmt.pix.height = 576; + } + + //tuner + itv->v4l2.tuner.active = 0; + if (itv->card_type == IVTV_350_V1) { + itv->v4l2.tuner.count = 2; + } else { + itv->v4l2.tuner.count = 1; + } + + itv->v4l2.tuner.table.tuner = (struct v4l2_tuner *) + kmalloc((itv->v4l2.tuner.count * + sizeof(struct v4l2_tuner)), + GFP_KERNEL); + + if (itv->v4l2.tuner.table.tuner == NULL) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "Couldn't allocate v4l2 tuner\n"); + return -ENOMEM; + } + + memcpy(itv->v4l2.tuner.table.tuner, &tmk_tuners[0], + (itv->v4l2.tuner.count * sizeof(struct v4l2_tuner))); + + /* Setup audio */ + /* V4L2_CID_IVTV_FREQ */ + itv->v4l2.audio_meta[0].ctrl = &ivtv_ctrl_menu_freq; + itv->v4l2.audio_meta[0].menu = ivtv_ctrl_query_freq; + itv->v4l2.audio_meta[0].mask = ivtv_audio_mask_freq; + itv->v4l2.audio_meta[0].setting = ivtv_ctrl_menu_freq.default_value; + itv->v4l2.audio_meta[0].table = &ivtv_audio_tbl_freq[0]; + + /* V4L2_CID_IVTV_ENC*/ + itv->v4l2.audio_meta[1].ctrl = &ivtv_ctrl_menu_enc; + itv->v4l2.audio_meta[1].menu = ivtv_ctrl_query_enc; + itv->v4l2.audio_meta[1].mask = ivtv_audio_mask_enc; + itv->v4l2.audio_meta[1].setting = ivtv_ctrl_menu_enc.default_value; + itv->v4l2.audio_meta[1].table = &ivtv_audio_tbl_enc[0]; + + /* V4L2_CID_IVTV_BITRATE*/ + itv->v4l2.audio_meta[2].ctrl = &ivtv_ctrl_menu_bitrate; + itv->v4l2.audio_meta[2].menu = ivtv_ctrl_query_bitrate; + itv->v4l2.audio_meta[2].mask = ivtv_audio_mask_bitrate; + itv->v4l2.audio_meta[2].setting = ivtv_ctrl_menu_bitrate.default_value; + itv->v4l2.audio_meta[2].table = &ivtv_audio_tbl_bitrate[0]; + + /* V4L2_CID_IVTV_MONO*/ + itv->v4l2.audio_meta[3].ctrl = &ivtv_ctrl_menu_mono; + itv->v4l2.audio_meta[3].menu = ivtv_ctrl_query_mono; + itv->v4l2.audio_meta[3].mask = ivtv_audio_mask_mono; + itv->v4l2.audio_meta[3].setting = ivtv_ctrl_menu_mono.default_value; + itv->v4l2.audio_meta[3].table = &ivtv_audio_tbl_mono[0]; + + /* V4L2_CID_IVTV_JOINT*/ + itv->v4l2.audio_meta[4].ctrl = &ivtv_ctrl_menu_joint; + itv->v4l2.audio_meta[4].menu = ivtv_ctrl_query_joint; + itv->v4l2.audio_meta[4].mask = ivtv_audio_mask_joint; + itv->v4l2.audio_meta[4].setting = ivtv_ctrl_menu_joint.default_value; + itv->v4l2.audio_meta[4].table = &ivtv_audio_tbl_joint[0]; + + /* V4L2_CID_IVTV_EMPHASIS*/ + itv->v4l2.audio_meta[5].ctrl = &ivtv_ctrl_menu_emphasis; + itv->v4l2.audio_meta[5].menu = ivtv_ctrl_query_emphasis; + itv->v4l2.audio_meta[5].mask = ivtv_audio_mask_emphasis; + itv->v4l2.audio_meta[5].setting = ivtv_ctrl_menu_emphasis.default_value; + itv->v4l2.audio_meta[5].table = &ivtv_audio_tbl_emphasis[0]; + + /* V4L2_CID_IVTV_CRC*/ + itv->v4l2.audio_meta[6].ctrl = &ivtv_ctrl_menu_crc; + itv->v4l2.audio_meta[6].menu = ivtv_ctrl_query_crc; + itv->v4l2.audio_meta[6].mask = ivtv_audio_mask_crc; + itv->v4l2.audio_meta[6].setting = ivtv_ctrl_menu_crc.default_value; + itv->v4l2.audio_meta[6].table = &ivtv_audio_tbl_crc[0]; + + /* V4L2_CID_IVTV_COPYRIGHT*/ + itv->v4l2.audio_meta[7].ctrl = &ivtv_ctrl_menu_copyright; + itv->v4l2.audio_meta[7].menu = ivtv_ctrl_query_copyright; + itv->v4l2.audio_meta[7].mask = ivtv_audio_mask_copyright; + itv->v4l2.audio_meta[7].setting = ivtv_ctrl_menu_copyright.default_value; + itv->v4l2.audio_meta[7].table = &ivtv_audio_tbl_copyright[0]; + + /* V4L2_CID_IVTV_GEN*/ + itv->v4l2.audio_meta[8].ctrl = &ivtv_ctrl_menu_generation; + itv->v4l2.audio_meta[8].menu = ivtv_ctrl_query_generation; + itv->v4l2.audio_meta[8].mask = ivtv_audio_mask_generation; + itv->v4l2.audio_meta[8].setting = ivtv_ctrl_menu_generation.default_value; + itv->v4l2.audio_meta[8].table = &ivtv_audio_tbl_generation[0]; + + itv->v4l2.codec.audio_bitmap = 0; + for (x = 0; x < IVTV_V4L2_AUDIO_MENUCOUNT; x++) { + temp = itv->v4l2.audio_meta[x].setting; + itv->v4l2.codec.audio_bitmap |= + itv->v4l2.audio_meta[x].table[temp]; + } + + retval = ivtv_set_audio(itv,tmk_audio_mapping); + if (retval) { + kfree(itv->v4l2.tuner.table.tuner); + return retval; + } + + //FIXME Setup components here? tuner channel etc + return 0; +} + +int ivtv_start_v4l2_stream (struct ivtv_open_id *id) { + struct ivtv *itv = id->itv; + u32 data[IVTV_MBOX_MAX_DATA], result; + int x,vsize,vsync,hsize; + int type,subtype; + unsigned int dig; + + /* sem_lock must be held */ + IVTV_ASSERT(ivtv_sem_count(&itv->sem_lock) <= 0); + + IVTV_DEBUG(IVTV_DEBUG_INFO,"ivtv start v4l2 stream\n"); + + /* NTSC/PAL switching */ + vsize = itv->v4l2.streams[0].format.fmt.pix.height; + vsync = (int) itv->v4l2.streams[0].format.fmt.pix.height/2; + hsize = itv->v4l2.streams[0].format.fmt.pix.width; + + type = id->type; + + switch (type) { + case 2: /* VBI, may be the wrong value */ + subtype = 4; + case 4: /* Radio, probably not applicable */ + subtype = 2; + break; + default: + subtype = 3; + break; + } + + /* clear queues */ + ivtv_move_queue(itv, &itv->v4l2.streams[id->type].full_q, + &itv->v4l2.streams[id->type].free_q); + ivtv_move_queue(itv, &itv->v4l2.streams[id->type].dma_q, + &itv->v4l2.streams[id->type].free_q); + + IVTV_DEBUG(IVTV_DEBUG_INFO, "fullq size %d\n", + itv->v4l2.streams[id->type].full_q.elements); + IVTV_DEBUG(IVTV_DEBUG_INFO, "freeq size %d\n", + itv->v4l2.streams[id->type].free_q.elements); + IVTV_DEBUG(IVTV_DEBUG_INFO, "dmaq size %d\n", + itv->v4l2.streams[id->type].dma_q.elements); + + /*assign dma block len*/ + /* FIXME this needs a flag */ + data[0] = 1; /* num bytes in block*/ + data[1] = 1; /* use info from sg instead */ + x = ivtv_api(itv->enc_mbox, &itv->enc_msem, + IVTV_API_ASSIGN_DMA_BLOCKLEN, &result, 2, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 1. Code %d\n",x); + + /*assign program index info */ + /* FIXME need more info on this call */ + data[0] = 0; /*Mask 0:Disable */ + data[1] = 0; /*Num_req 0:??/ */ + x = ivtv_api(itv->enc_mbox, &itv->enc_msem, + IVTV_API_ASSIGN_PGM_INDEX_INFO, &result, 2, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 2. Code %d\n",x); + + /*assign stream type */ + data[0] = itv->v4l2.codec.stream_type; + x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_STREAM_TYPE, + &result,1, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 3. Code %d\n",x); + + /*assign output port */ + data[0] = 0; /*0:Memory */ + x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_OUTPUT_PORT, + &result, 1, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 4. Code %d\n",x); + + /*assign framerate */ + data[0] = itv->v4l2.codec.framerate; + x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_FRAMERATE, + &result, 1, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 5. Code %d\n",x); + + /*assign frame size */ + data[0] = vsize; /* height*/ + data[1] = hsize; /* width */ + x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_FRAME_SIZE, + &result, 2, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 6. Code %d\n",x); + + /*assign aspect ratio */ + data[0] = itv->v4l2.codec.aspect; /*mpeg spec sez 2 */ + x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_ASPECT_RATIO, + &result, 1, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 7. Code %d\n",x); + + /*assign bitrates */ + /*FIXME i think these settings are valid for compressed only */ + data[0] = itv->v4l2.codec.bitrate_mode; /*mode */ + data[1] = itv->v4l2.codec.bitrate; /* bps */ + data[2] = itv->v4l2.codec.bitrate_peak / 400; /* peak/400 */ + data[3] = 0; /*??? */ + data[4] = 0x70; /*??? */ + x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_BITRATES, + &result, 5, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 8. Code %d\n",x); + + /*assign gop properties */ + data[0] = itv->v4l2.codec.framespergop; + data[1] = itv->v4l2.codec.bframes; + x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_GOP_PROPERTIES, + &result, 2, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 9. Code %d\n",x); + + /*assign 3 2 pulldown */ + data[0] = itv->v4l2.codec.pulldown; + x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_3_2_PULLDOWN, + &result, 1, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 10. Code %d\n",x); + + /*assign gop closure */ + data[0] = itv->v4l2.codec.gop_closure; + x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_GOP_CLOSURE, + &result, 1, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 11. Code %d\n",x); + + /*assign audio properties */ + data[0] = itv->v4l2.codec.audio_bitmap; + x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_AUDIO_PROPERTIES, + &result, 1, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 12. Code %d\n",x); + + /*assign dnr filter mode */ + data[0] = itv->v4l2.codec.dnr_mode; + data[1] = itv->v4l2.codec.dnr_type; + x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_DNR_FILTER_MODE, + &result, 2, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 13. Code %d\n",x); + + /*assign dnr filter props*/ + data[0] = itv->v4l2.codec.dnr_spatial; + data[1] = itv->v4l2.codec.dnr_temporal; + x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_DNR_FILTER_PROPS, + &result, 2, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 14. Code %d\n",x); + + /*assign coring levels */ + data[0] = 0; /*luma_h */ + data[1] = 255; /*luma_l */ + data[2] = 0; /*chroma_h */ + data[3] = 255; /*chroma_l */ + x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_CORING_LEVELS, + &result, 4, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 15. Code %d\n",x); + + /*assign spatial filter type */ + data[0] = 1; /*luma_t: 1 = horiz_only */ + data[1] = 1; /*chroma_t: 1 = horiz_only */ + x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_SPATIAL_FILTER_TYPE, + &result, 2, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 16. Code %d\n",x); + + /*assign frame drop rate */ + data[0] = 0; + x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_FRAME_DROP_RATE, + &result, 1, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 17. Code %d\n",x); + + /*assign placeholder */ + data[0] = 0; /* type: 0 = Extension/UserData */ + data[1] = 0; /*period */ + data[2] = 0; /*size_t*/ + data[3] = 0; /*arg0 */ + data[4] = 0; /*arg1 */ + data[5] = 0; /*arg2 */ + data[6] = 0; /*arg3 */ + data[7] = 0; /*arg4 */ + data[8] = 0; /*arg5 */ + data[9] = 0; /*arg6 */ + data[10] = 0; /*arg7 */ + data[11] = 0; /*arg8 */ + x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_PLACEHOLDER, + &result, 12, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 18. Code %d\n\n",x); + + /* assign num vsync lines */ + data[0] = vsync; /*??? */ + data[1] = vsync; /* ??? */ + x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_NUM_VSYNC_LINES, + &result, 2, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 20. Code %d\n",x); + + if (atomic_read(&itv->capturing) == 0) { + + itv->trans_id = 0; + itv->first_read = 1; + + /* Clear pending interrupts */ + IVTV_DEBUG(IVTV_DEBUG_INFO, "Clearing Interrupts\n"); + writel((readl(itv->reg_mem + IVTV_REG_IRQSTATUS)&0xC8000000), + (IVTV_REG_IRQSTATUS+itv->reg_mem)); +#if 0 + /* event notification (on) */ + data[0] = 0; /*type: 0 = refresh */ + data[1] = 1; /*on/off: 1 = on */ + data[2] = 0x10000000; /*intr_bit: 0x10000000 = digitizer */ + data[3] = -1; /*mbox_id: -1: none */ + x = ivtv_api(itv->enc_mbox, &itv->enc_msem, + IVTV_API_EVENT_NOTIFICATION, &result, 4, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "startcap error 2. Code %d\n",x); +#endif + + /* Disable digitizer (saa7115) */ + IVTV_DEBUG(IVTV_DEBUG_INFO, "Disabling digitizer\n"); + dig=0; + ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR, + DECODER_ENABLE_OUTPUT,&dig); + + /*initialize input (no args) */ + x = ivtv_api(itv->enc_mbox, &itv->enc_msem, + IVTV_API_INITIALIZE_INPUT, &result, 0, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 19. Code %d\n\n",x); + + /* enable digitizer (saa7115) */ + IVTV_DEBUG(IVTV_DEBUG_INFO, "Enabling digitizer\n"); + dig=1; + ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR, + DECODER_ENABLE_OUTPUT,&dig); + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 100ms\n"); + ivtv_sleep_timeout(HZ/10); + } + + /* FIXME this is for mpg captures only i think */ + clear_bit(IVTV_F_I_EOS, &itv->i_flags); + + /* begin_capture */ + data[0] = type; /*type: 0 = mpeg */ + data[1] = subtype; /*subtype: 3 = video+audio */ + x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_BEGIN_CAPTURE, + &result, 2, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "startcap error 1. Code %d\n",x); + + if (atomic_read(&itv->capturing) == 0) { + /*Clear the following Interrupt mask bits: 0xd8000000 */ + ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE); + IVTV_DEBUG(IVTV_DEBUG_IRQ, "IRQ Mask is now: 0x%08x\n",itv->irqmask); + } + + /*you're live! sit back and await interrupts :)*/ + atomic_inc(&itv->capturing); + return 0; +} + +int ivtv_api_dec_playback_speed(struct ivtv* itv, int fastspeed, int factor, + int forward, int mpeg_frame_type_mask, + int bframes_per_gop, int mute_audio, + int display_fields) { + + u32 data[IVTV_MBOX_MAX_DATA], result; + + data[0] = (fastspeed << 31) | (factor & 0xff); + data[1] = forward; + data[2] = mpeg_frame_type_mask; + data[3] = bframes_per_gop; + data[4] = mute_audio; + data[5] = display_fields; + + ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_PLAYBACK_SPEED, &result, 6, &data[0]); + return result; +} + +int ivtv_start_v4l2_decode (struct ivtv_open_id *id) +{ + struct ivtv *itv = id->itv; + u32 data[IVTV_MBOX_MAX_DATA], result; + int x; + int type; + int standard=0; + + /* sem_lock must be held */ + IVTV_ASSERT(ivtv_sem_count(&itv->sem_lock) <= 0); + + type = id->type; + + if (itv->v4l2.standard.active != 0) { /* if not NTSC */ + standard = 1; /* PAL */ + } + +/* this isn't needed until we use buffers for decoding */ + /* clear queues */ + ivtv_move_queue(itv, &itv->v4l2.streams[id->type].full_q, + &itv->v4l2.streams[id->type].free_q); + ivtv_move_queue(itv, &itv->v4l2.streams[id->type].dma_q, + &itv->v4l2.streams[id->type].free_q); + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Decoder fullq size %d\n", + itv->v4l2.streams[id->type].full_q.elements); + IVTV_DEBUG(IVTV_DEBUG_INFO, "Decoder freeq size %d\n", + itv->v4l2.streams[id->type].free_q.elements); + IVTV_DEBUG(IVTV_DEBUG_INFO, "Decoder dmaq size %d\n", + itv->v4l2.streams[id->type].dma_q.elements); + + if (atomic_read(&itv->decoding) == 0) + { + /* Clear pending interrupts */ + IVTV_DEBUG(IVTV_DEBUG_INFO, "Clearing Interrupts\n"); + writel((readl(itv->reg_mem + IVTV_REG_IRQSTATUS)&0xC8000000), + (IVTV_REG_IRQSTATUS+itv->reg_mem)); + } + + /* set display standard */ + data[0] = standard; /* 0 = NTSC, 1 = PAL */ + x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_DISP_STANDARD, + &result, 1, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN'T SET DISPLAY STD %d\n",x); + + /* set audio mode */ + data[0] = 0; /* Dual mono-mode action: ??? */ + data[1] = 0; /* stereo mode action: 0=stereo, 1=left, 2=right, 3=mono */ + x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_SELECT_AUDIO, + &result, 2, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN'T SET AUDIO MODE %d\n",x); + + /* set decoder source settings */ + data[0] = id->type; /* Data type: 0 = mpeg from host, 1 = yuv from encoder, 2 = yuv_from_host */ + data[1] = 720; /* YUV source width*/ + if (itv->v4l2.standard.active == 1) + data[2] = 576; /* YUV source height*/ + else + data[2] = 480; /* YUV source height*/ + data[3] = itv->v4l2.codec.audio_bitmap; /* Audio settings to use, bitmap. see docs.*/ + x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_DECODE_SOURCE, + &result, 4, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN't INITIALIZE DECODER SOURCE %d\n",x); + +#if 0 + /* select event notification */ + data[0] = 0; /* Event: 0 = audio change between stereo and mono */ + data[1] = 1; /* Enable/Disable: 0 = disabled, 1 = enabled */ + data[2] = 0x00010000; /* Bit: interrupt bit to fire */ + data[3] = -1; /* Mailbox to use: -1 = no mailbox needed */ + x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_EVENT_NOTIFICATION, + &result, 4, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN'T INITIALIZE EVENT NOTIFICATION %d\n",x); +#endif + /* set number of internal decoder buffers */ + data[0] = itv->dec_options.decbuffers; /* 0 = 6 buffers, 1 = 9 buffers */ + x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_DISPLAY_BUFFERS, + &result, 1, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN'T INITIALIZE # OF DISPLAY BUFFERS %d\n",x); + + /* prebufferring*/ + data[0] = itv->dec_options.prebuffer; /* 0 = no prebuffering, 1 = enabled, see docs */ + x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_BUFFER, &result, 1,&data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN't INITIALIZE BUFFER %d\n",x); +#if 0 + /* set stream input port */ + data[0] = 0; /* 0 = memory, 1 = streaming */ + x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_STREAM_INPUT, &result, 1, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN'T INITIALIZE STREAM INPUT %d\n",x); + + /* A/V sync delay */ + data[0] = 0; /* Delay in 90khz ticks. 0 = synced, negative = audio lags, positive = video lags */ + x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_SET_AV_DELAY, &result, 1, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN't INITIALIZE Audio/Vid sync delay %d\n",x); +#endif + + /* start playback */ + data[0] = itv->dec_options.gop_offset; /* frame to start from (in GOP) */ + data[1] = itv->dec_options.mute_frames; /* # of audio frames to mute */ + x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_START_PLAYBACK, &result, 2, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN'T START PLAYBACK %d\n",x); + + if (atomic_read(&itv->decoding) == 0) { + /*Clear the following Interrupt mask bits: 0xd8000000 */ + ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_DECODE); + IVTV_DEBUG(IVTV_DEBUG_IRQ, "IRQ Mask is now: 0x%08x\n",itv->irqmask); + } + + /*you're live! sit back and await interrupts :)*/ + atomic_inc(&itv->decoding); + return 0; +} + +void ivtv_v4l2_cleanup(struct ivtv *itv) { + int x; + + IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 unregister\n"); + + if (atomic_read(&itv->capturing) >= 0) ivtv_stop_all_captures(itv); + if (itv->v4l2.tuner.table.tuner) kfree(itv->v4l2.tuner.table.tuner); + for (x=0; x < itv->v4l2.streamcount; x++) { + /* Catch a possible kernel panic */ + if (itv->v4l2.streams[x].v4l2dev->minor != -1) { + video_unregister_device(itv->v4l2.streams[x].v4l2dev); + } else { + IVTV_DEBUG(IVTV_DEBUG_ERR, + "invalid v4l2 registration on unload\n"); + } + } + if (itv->v4l2.streams) kfree(itv->v4l2.streams); +} + +int ivtv_v4l2_open(struct inode *inode, struct file *filp) { + int x,y=0,minor; + struct ivtv_open_id *item; + struct ivtv *itv=NULL; + + + minor = iminor(inode); + + IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 open on minor %d\n", minor); + + /* Find which card this open was on */ + spin_lock_irq(&ivtv_lock); + for (x=0;xminor); + if (ivtv_cards[x].v4l2.streams[y].v4l2dev->minor == minor) { + itv = ivtv_cards[x].v4l2.streams[y].v4l2dev->priv; + break; + } + } + /* FIXME ugly :( */ + if (itv !=NULL) break; + } + spin_unlock_irq(&ivtv_lock); + + /* FIXME temporary + if (y == 2) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "VBI not supported yet \n"); + return -EINVAL; + } + */ + if (itv != NULL) { + IVTV_DEBUG(IVTV_DEBUG_INFO,"opened card # %d, stream %d\n",x,y); + //allocate memory + item = kmalloc(sizeof(struct ivtv_open_id), GFP_KERNEL); + if (NULL == item) { + IVTV_DEBUG(IVTV_DEBUG_ERR,"nomem on v4l2 open\n"); + return -ENOMEM; + } + item->itv = itv; + item->type = y; + + INIT_LIST_HEAD(&item->list); + + down(&itv->sem_lock); + + item->open_id = item->itv->open_id++; + + list_add_tail (&item->list, &item->itv->client_list); + + up(&itv->sem_lock); + + filp->private_data = item; + + return 0; + } + + /* Couldnt find a device registered on that minor, shouldn't happen! */ + IVTV_DEBUG(IVTV_DEBUG_ERR,"Device on minor %d not found!\n",minor); + + return -ENXIO; +} + + +int ivtv_v4l2_read(struct file *filp, char *buf, size_t count, loff_t *pos) { + struct ivtv_open_id *id = filp->private_data; + struct ivtv *itv = id->itv; + struct ivtv_v4l2_stream *stream; + int ret=0; + + IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 read\n"); + + if (down_interruptible(&itv->sem_lock)) + return -ERESTARTSYS; + stream = &itv->v4l2.streams[id->type]; + + if (!test_bit(IVTV_F_S_CAP, &stream->s_flags) && stream->id == -1) { + set_bit(IVTV_F_S_CAP, &stream->s_flags); + stream->id = id->open_id; + + ret = ivtv_start_v4l2_stream(id); + if (ret) { + stream->id = -1; + IVTV_DEBUG(IVTV_DEBUG_INFO, + "Error in v4l2 stream init\n"); + } + stream->seq = 0; + stream->ubytes = 0; + } else { + if (id->open_id != stream->id) + ret = -EBUSY; + } + + up(&itv->sem_lock); + + if (ret) + return ret; + + ret = ivtv_read(id, buf, count, !(filp->f_flags & O_NONBLOCK)); + + if (ret > 0) + *pos += ret; + + if (ret == 0) { + IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 read returning 0\n"); + } + + return ret; +} + +ssize_t ivtv_v4l2_write(struct file *filp, const char *buf, size_t count, loff_t *pos) +{ + struct ivtv_open_id *id = filp->private_data; + struct ivtv *itv = id->itv; + struct ivtv_v4l2_stream *stream; + int ret=0; + + if ( (id->type != IVTV_DEC_STREAM_TYPE_MPG) && + (id->type != IVTV_DEC_STREAM_TYPE_YUV)) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "Write on read-only interface\n"); + return -EINVAL; + } + + if (down_interruptible(&itv->sem_lock)) + return -ERESTARTSYS; + + // Initialize Decoder + /* FIXME we'll need to make this its own stream type */ + stream = &itv->v4l2.streams[id->type]; + if ((stream->id == -1) && !test_bit(IVTV_F_S_CAP, &stream->s_flags)) { + set_bit(IVTV_F_S_CAP, &stream->s_flags); + stream->id = id->open_id; + ret = ivtv_start_v4l2_decode(id); + } else { + if (id->open_id != stream->id) + ret = -EBUSY; + } + + up(&itv->sem_lock); + + if (ret) + return ret; + + /* do all the work */ + return ivtv_write(id, buf, count, !(filp->f_flags & O_NONBLOCK)); +} + +int ivtv_v4l2_streamoff(struct ivtv_open_id *id) { + + if (down_interruptible(&id->itv->sem_lock)) + return -ERESTARTSYS; + + if (id->open_id != id->itv->v4l2.streams[id->type].id) { + return -EINVAL; + } else { + ivtv_stop_capture(id); + } + + up(&id->itv->sem_lock); + + return 0; +} + +int ivtv_v4l2_close(struct inode *inode, struct file *filp) { + struct ivtv_open_id *id = filp->private_data; + + IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 close\n"); + + if (NULL == id) { + IVTV_DEBUG(IVTV_DEBUG_ERR,"invalid id on v4l2 close\n"); + return -ENODEV; + } + + if (down_interruptible(&id->itv->sem_lock)) + return -ERESTARTSYS; + + if (id->open_id == id->itv->v4l2.streams[id->type].id) { + ivtv_close(id); + clear_bit(IVTV_F_S_CAP, &id->itv->v4l2.streams[id->type].s_flags); + id->itv->v4l2.streams[id->type].id = -1; + } + up(&id->itv->sem_lock); + + list_del(&id->list); + + kfree(id); + + return 0; +} + +int ivtv_change_speed(struct ivtv *itv, struct ivtv_speed speed) { + u32 data[IVTV_MBOX_MAX_DATA], result; + + if ((speed.scale < 0) || (speed.scale > 50)) + return -EINVAL; + + if ((speed.speed < 0) || (speed.speed > 1)) + return -EINVAL; + + data[0] = speed.scale; + + if (speed.smooth) /* smooth ff */ + data[0] |= 0x40000000; + + if (speed.speed) /* fast forward */ + data[0] |= 0x80000000; + + if (speed.direction) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "DEC: Reverse not supported\n"); + return -EINVAL; + } + + data[1] = speed.direction; /* Forward. Reverse not supported */ + + switch (speed.fr_mask) { + case 2: + default: + data[2] |= 4; /* B */ + case 1: + data[2] |= 2; /* P */ + case 0: + data[2] |= 1; /* I */ + break; + } + + data[3] = itv->v4l2.codec.framespergop; + data[4] = speed.aud_mute; /* mute while fast/slow */ + data[5] = speed.fr_field; /* frame or field at a time */ + data[6] = speed.mute; /* # of frames to mute on normal speed resume */ + + if (ivtv_api(itv->dec_mbox, &itv->dec_msem, + IVTV_API_DEC_PLAYBACK_SPEED, &result, 7, &data[0])) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "DEC: error changing speed\n"); + return (int)result; + } + + /* Save speed options if call succeeded */ + memcpy(&itv->dec_options.speed, &speed, sizeof(speed)); + + return 0; +} + +int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) { + + struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; + struct ivtv *itv = id->itv; + + IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl 0x%08x\n", cmd); + + switch (cmd) { +#ifdef SAA7115_REGTEST + /* ioctls to allow direct access to the saa7115 registers for testing */ + case SAA7115_GET_REG: { + struct saa7115_reg_t *saa7115_reg = (struct saa7115_reg_t *)arg; + + ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,SAA7115_GET_REG,saa7115_reg); + break; + } + case SAA7115_SET_REG: { + struct saa7115_reg_t *saa7115_reg = (struct saa7115_reg_t *)arg; + + ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,SAA7115_SET_REG,saa7115_reg); + break; + } +#endif + case IVTV_IOC_ZCOUNT: { + /* Zeroes out usage count so it can be unloaded in case of + * drastic error */ + + IVTV_DEBUG(IVTV_DEBUG_INFO,"ivtv ioctl: ZCOUNT\n"); + + /* disabled due to module code changes ivtv_zero_usage_count(); */ + + break; + } + case IVTV_IOC_GET_FB: { + if (itv->fb_id < 0) + return -EINVAL; + if (copy_to_user((int*)arg, &itv->fb_id, sizeof(itv->fb_id))) + return -EFAULT; + + break; + } + case IVTV_IOC_FWAPI: { + struct ivtv_ioctl_fwapi fwapi; + int x; + + IVTV_DEBUG(IVTV_DEBUG_INFO,"ivtv ioctl: FWAPI\n"); + + if (copy_from_user(&fwapi, (struct ivtv_ioctl_fwapi *) arg, + sizeof(struct ivtv_ioctl_fwapi))) + return -EFAULT; + /* Encoder + x = ivtv_api(itv->enc_mbox, &itv->enc_msem, fwapi.cmd, + &fwapi.result, fwapi.args, &fwapi.data[0]); + */ + + /* Decoder */ + x = ivtv_api(itv->dec_mbox, &itv->dec_msem, fwapi.cmd, + &fwapi.result, fwapi.args, &fwapi.data[0]); + + if (copy_to_user((struct ivtv_ioctl_fwapi *) arg, &fwapi, + sizeof(struct ivtv_ioctl_fwapi))) + return -EFAULT; + + return x; + } + case IVTV_IOC_FRAMESYNC: { + interruptible_sleep_on(&itv->vsync_w); + + if (signal_pending(current)) + return -ERESTARTSYS; + + if (copy_to_user((void*)arg, &itv->dec_timestamp, + sizeof(itv->dec_timestamp))) { + return -EFAULT; + } + + break; + } + case IVTV_IOC_PLAY: { + u32 data[IVTV_MBOX_MAX_DATA], result; + data[0] = 0; /* 0-based frame # to start from (in GOP) */ + data[1] = 0; /* # of audio frames to mute */ + if (ivtv_api(itv->dec_mbox, &itv->dec_msem, + IVTV_API_DEC_START_PLAYBACK, &result, 2, &data[0])) + IVTV_DEBUG(IVTV_DEBUG_ERR, + "DEC: error starting playback\n"); + + break; + + } + case IVTV_IOC_S_START_DECODE: { + struct ivtv_cfg_start_decode sd; + + if (copy_from_user(&sd, (struct ivtv_cfg_start_decode *) arg, + sizeof(sd))) + return -EFAULT; + + if ((sd.gop_offset < 0) || (sd.gop_offset > 15)) + return -EINVAL; + if (sd.muted_audio_frames < 0) + return -EINVAL; + + itv->dec_options.gop_offset = sd.gop_offset; + + itv->dec_options.mute_frames = sd.muted_audio_frames; + break; + } + case IVTV_IOC_STOP_DECODE: + case IVTV_IOC_S_STOP_DECODE: { + struct ivtv_cfg_stop_decode sd; + + if (copy_from_user(&sd, (struct ivtv_cfg_stop_decode *)arg, + sizeof(sd))) + return -EFAULT; + + if ((sd.hide_last < 0) || (sd.hide_last > 1)) + return -EINVAL; + itv->dec_options.hide_last_frame = sd.hide_last; + + itv->dec_options.pts_low = (u32)(sd.pts_stop & 0xFFFFFFFF); + itv->dec_options.pts_hi = (u32)(sd.pts_stop >> 32); + + if (cmd == IVTV_IOC_S_STOP_DECODE) break; + + ivtv_stop_decode(id); + break; + } + case IVTV_IOC_G_SPEED: { + if (copy_to_user((void*)arg, + &itv->dec_options.speed, + sizeof(itv->dec_options.speed))) { + return -EFAULT; + } + + break; + } + case IVTV_IOC_S_SPEED: { + struct ivtv_speed speed; + int ret=0; + + if (copy_from_user(&speed, (struct ivtv_speed*)arg, + sizeof(speed))) + return -EFAULT; + + ret = ivtv_change_speed(itv, speed); + if (ret) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "DEC: error in slow/fast mode\n"); + return ret; + } + + break; + } + case IVTV_IOC_S_SLOW_FAST: { + struct ivtv_slow_fast sf; + struct ivtv_speed speed; + int ret; + + if (copy_from_user(&sf, (struct ivtv_slow_fast *)arg, + sizeof(sf))) + return -EFAULT; + + if ((sf.scale < 0) || (sf.scale > 50)) + return -EINVAL; + if ((sf.speed < 0) || (sf.speed > 1)) + return -EINVAL; + + memcpy(&speed, &itv->dec_options.speed, sizeof(speed)); + speed.scale = sf.scale; + speed.speed = sf.speed; + + ret = ivtv_change_speed(itv, speed); + if (ret) { + IVTV_DEBUG(IVTV_DEBUG_ERR, + "DEC: error in set slow/fast mode\n"); + return ret; + } + + break; + } + case IVTV_IOC_PAUSE: { + u32 data[IVTV_MBOX_MAX_DATA], result; + data[0] = 0; + if (ivtv_api(itv->dec_mbox, &itv->dec_msem, + IVTV_API_DEC_PAUSE_PLAYBACK, &result, 1, &data[0])) { + IVTV_DEBUG(IVTV_DEBUG_ERR, + "DEC: error pausing\n"); + } + + break; + } + case IVTV_IOC_GET_TIMING: { + struct ivtv_ioctl_framesync timing; + int ret; + + if (atomic_read(&itv->decoding) == 0) { + memset(&timing, 0, sizeof(timing)); + } else { + /* if the value pulled 'efficiently' was OK */ + if (&itv->dec_timestamp.scr == 0) { + /* firmware glitch gave us a bad value. + get a good one */ + + ret = ivtv_get_timing_info(itv, &timing); + if (ret) return -EINVAL; + } else { + memcpy(&timing, &itv->dec_timestamp, sizeof(timing)); + } + } + + if (copy_to_user((void*)arg, &timing, sizeof(timing))) { + return -EFAULT; + } + + break; + } + + case VIDIOC_QUERYMENU: { + struct v4l2_querymenu *qmenu = (struct v4l2_querymenu *)arg; + + if (qmenu->id >= V4L2_CID_PRIVATE_BASE) { + int off = qmenu->id - V4L2_CID_PRIVATE_BASE; + if (off < IVTV_V4L2_AUDIO_MENUCOUNT) { + u32 i = qmenu->index; + if ((i >= itv->v4l2.audio_meta[off].ctrl->minimum) && + (i <= itv->v4l2.audio_meta[off].ctrl->maximum)) { + memcpy(qmenu, + &itv->v4l2.audio_meta[off].menu[i], + sizeof(struct v4l2_querymenu)); + } else { + IVTV_DEBUG(IVTV_DEBUG_ERR, + "qmenu: invalid index\n"); + return -EINVAL; + } + } else { + IVTV_DEBUG(IVTV_DEBUG_ERR, + "qmenu: id out of range\n"); + return -EINVAL; + } + + } + + break; + } + + case VIDIOC_QUERYCTRL: { + struct v4l2_queryctrl *qctrl = (struct v4l2_queryctrl *)arg; + + if (qctrl->id >= V4L2_CID_PRIVATE_BASE) { + int off = qctrl->id - V4L2_CID_PRIVATE_BASE; + if (off < IVTV_V4L2_AUDIO_MENUCOUNT) { + memcpy(qctrl,itv->v4l2.audio_meta[off].ctrl, + sizeof(struct v4l2_queryctrl)); + } else { + switch (qctrl->id) { + case V4L2_CID_IVTV_DEC_SMOOTH_FF: + qctrl->type = V4L2_CTRL_TYPE_BOOLEAN; + strncpy(qctrl->name, "Smooth Slow/FF", 32); + qctrl->minimum = 0; + qctrl->maximum = 1; + qctrl->default_value = 1; + qctrl->flags = 0; + qctrl->reserved[0] = 0; + qctrl->reserved[1] = 0; + break; + case V4L2_CID_IVTV_DEC_FR_MASK: + qctrl->type = V4L2_CTRL_TYPE_INTEGER; + strncpy(qctrl->name, "Frame Mask", 32); + qctrl->minimum = 0; + qctrl->maximum = 2; + qctrl->default_value = 2; + qctrl->flags = 0; + qctrl->reserved[0] = 0; + qctrl->reserved[1] = 0; + break; + case V4L2_CID_IVTV_DEC_SP_MUTE: + qctrl->type = V4L2_CTRL_TYPE_BOOLEAN; + strncpy(qctrl->name, + "Mute during slow/fast", 32); + qctrl->minimum = 0; + qctrl->maximum = 1; + qctrl->default_value = 1; + qctrl->flags = 0; + qctrl->reserved[0] = 0; + qctrl->reserved[1] = 0; + break; + case V4L2_CID_IVTV_DEC_FR_FIELD: + qctrl->type = V4L2_CTRL_TYPE_BOOLEAN; + strncpy(qctrl->name, + "Toggle frame/field", 32); + qctrl->minimum = 0; + qctrl->maximum = 1; + qctrl->default_value = 1; + qctrl->flags = 0; + qctrl->reserved[0] = 0; + qctrl->reserved[1] = 0; + break; + case V4L2_CID_IVTV_DEC_AUD_SKIP: + qctrl->type = V4L2_CTRL_TYPE_INTEGER; + strncpy(qctrl->name, "Mute audio frames",32); + qctrl->minimum = 0; + qctrl->maximum = 15; + qctrl->default_value = 0; + qctrl->flags = 0; + qctrl->reserved[0] = 0; + qctrl->reserved[1] = 0; + break; + case V4L2_CID_IVTV_DEC_NUM_BUFFERS: + qctrl->type = V4L2_CTRL_TYPE_BOOLEAN; + strncpy(qctrl->name, + "Number of decoder buffers", 32); + qctrl->minimum = 0; + qctrl->maximum = 1; + qctrl->default_value = 1; + qctrl->flags = 0; + qctrl->reserved[0] = 0; + qctrl->reserved[1] = 1; + break; + case V4L2_CID_IVTV_DEC_PREBUFFER: + qctrl->type = V4L2_CTRL_TYPE_BOOLEAN; + strncpy(qctrl->name, + "Decoder prebuffer", 32); + qctrl->minimum = 0; + qctrl->maximum = 1; + qctrl->default_value = 1; + qctrl->flags = 0; + qctrl->reserved[0] = 0; + qctrl->reserved[1] = 1; + break; + default: + IVTV_DEBUG(IVTV_DEBUG_ERR, + "qctrl: invalid control\n"); + return -EINVAL; + break; + } + } + + break; + } + + switch (qctrl->id) { + case V4L2_CID_BRIGHTNESS: + qctrl->type = V4L2_CTRL_TYPE_INTEGER; + strncpy(qctrl->name, "Brightness", 32); + qctrl->minimum = 0; + qctrl->maximum = 255; + qctrl->step = 0; + qctrl->default_value = 128; + qctrl->flags = 0; + qctrl->reserved[0] = 0; + qctrl->reserved[1] = 0; + break; + case V4L2_CID_HUE: + qctrl->type = V4L2_CTRL_TYPE_INTEGER; + strncpy(qctrl->name, "Hue", 32); + qctrl->minimum = -128; + qctrl->maximum = 127; + qctrl->step = 0; + qctrl->default_value = 0; + qctrl->flags = 0; + qctrl->reserved[0] = 0; + qctrl->reserved[1] = 0; + break; + case V4L2_CID_SATURATION: + qctrl->type = V4L2_CTRL_TYPE_INTEGER; + strncpy(qctrl->name, "Saturation", 32); + qctrl->minimum = 0; + qctrl->maximum = 127; + qctrl->step = 0; + qctrl->default_value = 64; + qctrl->flags = 0; + qctrl->reserved[0] = 0; + qctrl->reserved[1] = 0; + break; + case V4L2_CID_CONTRAST: + qctrl->type = V4L2_CTRL_TYPE_INTEGER; + strncpy(qctrl->name, "Contrast", 32); + qctrl->minimum = 0; + qctrl->maximum = 127; + qctrl->step = 0; + qctrl->default_value = 64; + qctrl->flags = 0; + qctrl->reserved[0] = 0; + qctrl->reserved[1] = 0; + break; + case V4L2_CID_AUDIO_VOLUME: + qctrl->type = V4L2_CTRL_TYPE_INTEGER; + strncpy(qctrl->name, "Volume", 32); + qctrl->minimum = 0; + qctrl->maximum = 65535; + qctrl->step = 0; + qctrl->default_value = 65535; + qctrl->flags = 0; + qctrl->reserved[0] = 0; + qctrl->reserved[1] = 0; + break; + case V4L2_CID_AUDIO_MUTE: + qctrl->type = V4L2_CTRL_TYPE_INTEGER; + strncpy(qctrl->name, "Mute", 32); + qctrl->minimum = 0; + qctrl->maximum = 1; + qctrl->step = 0; + qctrl->default_value = 1; + qctrl->flags = 0; + qctrl->reserved[0] = 0; + qctrl->reserved[1] = 0; + break; + default: + IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: invalid control\n"); + return -EINVAL; + } + break; + } + case VIDIOC_S_CTRL: { + struct v4l2_control *vctrl = (struct v4l2_control *)arg; + + IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: set control\n"); + + if (vctrl->id >= V4L2_CID_PRIVATE_BASE) { + int off = vctrl->id - V4L2_CID_PRIVATE_BASE; + s32 v = vctrl->value; + if (off < IVTV_V4L2_AUDIO_MENUCOUNT) { + if ((v<=itv->v4l2.audio_meta[off].ctrl->maximum) && + (v>=itv->v4l2.audio_meta[off].ctrl->minimum)) { + itv->v4l2.audio_meta[off].setting = v; + /* presumably value has changed. + * we should update the bitmap */ + itv->v4l2.codec.audio_bitmap &= + ~itv->v4l2.audio_meta[off].mask; + itv->v4l2.codec.audio_bitmap |= + itv->v4l2.audio_meta[off].table[v]; + + /* Also upade the digitizer setting */ + if (0 == off) { /* audio input bitrate */ + int vrate = (int)v; + /* FIXME not obvious how this works + * (see ivtv_ctrl_query_freq[]) */ + ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_SET_AUDIO,&vrate); + } + } else { + IVTV_DEBUG(IVTV_DEBUG_ERR, + "ctrl: value out of range\n"); + return -ERANGE; + } + } else { + switch (vctrl->id) { + case V4L2_CID_IVTV_DEC_SMOOTH_FF: + if ((v < 0) || (v > 1)) return -ERANGE; + itv->dec_options.speed.smooth = vctrl->value; + break; + case V4L2_CID_IVTV_DEC_FR_MASK: + if ((v < 0) || (v > 2)) return -ERANGE; + itv->dec_options.speed.fr_mask=vctrl->value; + break; + case V4L2_CID_IVTV_DEC_SP_MUTE: + if ((v < 0) || (v > 1)) return -ERANGE; + itv->dec_options.speed.aud_mute=vctrl->value; + break; + case V4L2_CID_IVTV_DEC_FR_FIELD: + if ((v < 0) || (v > 1)) return -ERANGE; + itv->dec_options.speed.fr_field=vctrl->value; + break; + case V4L2_CID_IVTV_DEC_AUD_SKIP: + if ((v < 0) || (v > 15)) return -ERANGE; + itv->dec_options.mute_frames = vctrl->value; + break; + case V4L2_CID_IVTV_DEC_NUM_BUFFERS: + if ((v < 0) || (v > 1)) return -ERANGE; + itv->dec_options.decbuffers = vctrl->value; + break; + case V4L2_CID_IVTV_DEC_PREBUFFER: + if ((v < 0) || (v > 1)) return -ERANGE; + itv->dec_options.prebuffer = vctrl->value; + break; + default: + IVTV_DEBUG(IVTV_DEBUG_ERR, + "ctrl: invalid control\n"); + return -EINVAL; + } + } + + break; + } + + switch (vctrl->id) { + case V4L2_CID_BRIGHTNESS: { + struct saa7114 pic; + + if (vctrl->value < 0 || vctrl->value > 255) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "ctrl: invalid brightness value: %d\n", vctrl->value); + return -EINVAL; + } + ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_GET_PICTURE,&pic); + pic.bright = vctrl->value; + ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_SET_PICTURE,&pic); + break; + } + case V4L2_CID_HUE: { + struct saa7114 pic; + + if (vctrl->value < -128 || vctrl->value > 127) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "ctrl: invalid hue value: %d\n", vctrl->value); + return -EINVAL; + } + ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_GET_PICTURE,&pic); + pic.hue = vctrl->value; + ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_SET_PICTURE,&pic); + break; + } + case V4L2_CID_SATURATION: { + struct saa7114 pic; + + if (vctrl->value < 0 || vctrl->value > 127) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "ctrl: invalid saturation value: %d\n", vctrl->value); + return -EINVAL; + } + ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_GET_PICTURE,&pic); + pic.sat = vctrl->value; + ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_SET_PICTURE,&pic); + break; + } + case V4L2_CID_CONTRAST: { + struct saa7114 pic; + + if (vctrl->value < 0 || vctrl->value > 127) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "ctrl: invalid contrast value: %d\n", vctrl->value); + return -EINVAL; + } + ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_GET_PICTURE,&pic); + pic.contrast = vctrl->value; + ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_SET_PICTURE,&pic); + break; + } + case V4L2_CID_AUDIO_VOLUME: { + struct video_audio va; + + if (vctrl->value > 65535 || vctrl->value < 0) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "ctrl: invalid value for volume: %d", vctrl->value); + return -EINVAL; + } + ivtv_call_i2c_client(itv,IVTV_MSP3400_I2C_ADDR,VIDIOCGAUDIO,&va); + va.volume = vctrl->value; + ivtv_call_i2c_client(itv,IVTV_MSP3400_I2C_ADDR,VIDIOCSAUDIO,&va); + break; + } + case V4L2_CID_AUDIO_MUTE: { + struct video_audio va; + ivtv_call_i2c_client(itv,IVTV_MSP3400_I2C_ADDR,VIDIOCGAUDIO,&va); + if (vctrl->value) + va.flags |= VIDEO_AUDIO_MUTE; + else + va.flags = (va.flags & ~(VIDEO_AUDIO_MUTE)); + ivtv_call_i2c_client(itv,IVTV_MSP3400_I2C_ADDR,VIDIOCSAUDIO,&va); + break; + } + default: + IVTV_DEBUG(IVTV_DEBUG_ERR, "ctrl: invalid control\n"); + return -EINVAL; + } + + break; + } + case VIDIOC_G_CTRL: { + struct v4l2_control *vctrl = (struct v4l2_control *)arg; + + IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: get control\n"); + + if (vctrl->id >= V4L2_CID_PRIVATE_BASE) { + int off = vctrl->id - V4L2_CID_PRIVATE_BASE; + if (off < IVTV_V4L2_AUDIO_MENUCOUNT) { + vctrl->value =itv->v4l2.audio_meta[off].setting; + } else { + switch (vctrl->id) { + case V4L2_CID_IVTV_DEC_SMOOTH_FF: + vctrl->value = itv->dec_options.speed.smooth; + break; + case V4L2_CID_IVTV_DEC_FR_MASK: + vctrl->value= itv->dec_options.speed.fr_mask; + break; + case V4L2_CID_IVTV_DEC_SP_MUTE: + vctrl->value=itv->dec_options.speed.aud_mute; + break; + case V4L2_CID_IVTV_DEC_FR_FIELD: + vctrl->value=itv->dec_options.speed.fr_field; + break; + case V4L2_CID_IVTV_DEC_AUD_SKIP: + vctrl->value = itv->dec_options.mute_frames; + break; + case V4L2_CID_IVTV_DEC_NUM_BUFFERS: + vctrl->value = itv->dec_options.decbuffers; + break; + case V4L2_CID_IVTV_DEC_PREBUFFER: + vctrl->value = itv->dec_options.prebuffer; + break; + default: + IVTV_DEBUG(IVTV_DEBUG_ERR, + "ctrl: invalid control\n"); + return -EINVAL; + } + } + + break; + } + + switch (vctrl->id) { + case V4L2_CID_BRIGHTNESS: { + struct saa7114 pic; + ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_GET_PICTURE,&pic); + vctrl->value = pic.bright; + break; + } + case V4L2_CID_HUE: { + struct saa7114 pic; + ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_GET_PICTURE,&pic); + vctrl->value = pic.hue; + break; + } + case V4L2_CID_SATURATION: { + struct saa7114 pic; + ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_GET_PICTURE,&pic); + vctrl->value = pic.sat; + break; + } + case V4L2_CID_CONTRAST: { + struct saa7114 pic; + ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_GET_PICTURE,&pic); + vctrl->value = pic.contrast; + break; + } + case V4L2_CID_AUDIO_VOLUME: { + struct video_audio va; + ivtv_call_i2c_client(itv,IVTV_MSP3400_I2C_ADDR,VIDIOCGAUDIO,&va); + vctrl->value = va.volume; + break; + } + case V4L2_CID_AUDIO_MUTE: { + struct video_audio va; + ivtv_call_i2c_client(itv,IVTV_MSP3400_I2C_ADDR,VIDIOCGAUDIO,&va); + vctrl->value = (va.flags & VIDEO_AUDIO_MUTE); + break; + } + default: + IVTV_DEBUG(IVTV_DEBUG_ERR, "ctrl: invalid control\n"); + return -EINVAL; + } + break; + } + case VIDIOC_QUERYCAP: { + struct v4l2_capability *vcap = (struct v4l2_capability *)arg; + + IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: querycap\n"); + + /* driver name */ + strcpy(vcap->driver,IVTV_DRIVER_NAME); + + /* card type */ + strcpy(vcap->card,id->itv->v4l2.streams[id->type].v4l2dev->name); + + /* bus info.. card # will do */ + sprintf(vcap->bus_info, "%d", itv->num); + + /* version */ + vcap->version = IVTV_DRIVER_VERSION; + + /* capabilities */ + vcap->capabilities = itv->v4l2.capabilities; + + /* reserved.. must set to 0! */ + vcap->reserved[0] = vcap->reserved[1] = vcap->reserved[2] = + vcap->reserved[3] = 0; + break; + } + case VIDIOC_ENUMINPUT: { + struct v4l2_input *vin = (struct v4l2_input *)arg; + + IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: enuminput\n"); + + if ((vin->index < 0) || (vin->index >= itv->v4l2.input.count)) + return -EINVAL; + + /* set it to defaults from our table */ + memcpy(vin, + &itv->v4l2.input.table.input[vin->index], + sizeof(struct v4l2_input)); + + /* set the standard to whatever our overall standard is */ + vin->std = tmk_standards[itv->v4l2.standard.active].id; + vin->status = 0; /*FIXME status isn't always ok... */ + + break; + } + + case VIDIOC_G_FMT: { + struct v4l2_format *vfmt = (struct v4l2_format *)arg; + + IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: get format\n"); + + /* FIXME switch on stream type */ + memcpy (vfmt, &itv->v4l2.streams[0].format, sizeof(struct v4l2_format)); + break; + } + case VIDIOC_S_FMT: { + struct v4l2_format *vfmt = (struct v4l2_format *)arg; + struct video_window wind; + + IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: set format\n"); + + /* FIXME only sets resolution for now */ + wind.width = vfmt->fmt.pix.width; + wind.height = vfmt->fmt.pix.height; + ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR, + DECODER_SET_SIZE,&wind); + + /* FIXME switch on stream type, bounds checking */ + memcpy (&itv->v4l2.streams[0].format, vfmt, sizeof(struct v4l2_format)); + /* Adjust res in YUV also */ + itv->v4l2.streams[1].format.fmt.pix.height = vfmt->fmt.pix.height; + itv->v4l2.streams[1].format.fmt.pix.width = vfmt->fmt.pix.width; + + break; + } + case VIDIOC_G_INPUT: { + int *inp = (int *)arg; + + IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: get input\n"); + + *inp = itv->v4l2.input.active; + break; + } + case VIDIOC_S_INPUT: { + int a_in,inp = *(int *)arg; + struct msp_matrix mspm; + + IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: set input\n"); + + if ((inp < 0) || (inp >= itv->v4l2.input.count)) return -EINVAL; + + if (inp == itv->v4l2.input.active) { + IVTV_DEBUG(IVTV_DEBUG_INFO, "Input unchanged\n"); + } else { + IVTV_DEBUG(IVTV_DEBUG_INFO, "Changing input from %d to %d\n", + itv->v4l2.input.active, inp); + + itv->v4l2.input.active = inp; + itv->v4l2.audio.active = + itv->v4l2.input.table.input[inp].audioset; + + /* Mute sound to avoid pop */ + mspm.input = 8; + mspm.output = itv->v4l2.audio_output; + ivtv_call_i2c_client(itv,IVTV_MSP3400_I2C_ADDR + ,MSP_SET_MATRIX,&mspm); + + if (0 != ivtv_pause_encoder(itv, 0)) + IVTV_DEBUG(IVTV_DEBUG_ERR, + "Input: Error pausing stream\n"); + + ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR, + DECODER_SET_INPUT,&inp); + + /* Pause to let sound calm down */ + ivtv_sleep_timeout(HZ/33); + + if (0 != ivtv_pause_encoder(itv, 1)) + IVTV_DEBUG(IVTV_DEBUG_ERR, + "Input: Error unpausing stream\n"); + + /* FIXME Needs to be card-specific */ + a_in = ivtv_set_audio(itv,tmk_audio_mapping); + if (a_in < 0) return a_in; + } + break; + } + case VIDIOC_G_FREQUENCY: { + struct v4l2_frequency *vf=(struct v4l2_frequency *)arg; + + IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: get frequency\n"); + + if ((vf->tuner < 0) || (vf->tuner >= itv->v4l2.tuner.count)) + return -EINVAL; + vf->frequency = itv->v4l2.freq.frequency; + break; + } + case VIDIOC_S_FREQUENCY: { + struct v4l2_frequency *vf=(struct v4l2_frequency *)arg; + struct msp_matrix mspm; + + IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: set frequency\n"); + + if ((vf->tuner < 0) || (vf->tuner >= itv->v4l2.tuner.count)) + return -EINVAL; + itv->v4l2.freq.frequency = vf->frequency; + + /* Mute sound to avoid pop */ + mspm.input = 8; + mspm.output = itv->v4l2.audio_output; + ivtv_call_i2c_client(itv,IVTV_MSP3400_I2C_ADDR,MSP_SET_MATRIX,&mspm); + + if (0 != ivtv_pause_encoder(itv, 0)) + IVTV_DEBUG(IVTV_DEBUG_ERR, "Freq: Error pausing stream\n"); + + /* Set frequency */ + ivtv_call_i2c_client(itv,IVTV_TUNER_I2C_ADDR, + VIDIOCSFREQ,&itv->v4l2.freq.frequency); + + /* Pause to let sound calm down */ + ivtv_sleep_timeout(HZ/33); + + if (0 != ivtv_pause_encoder(itv, 1)) + IVTV_DEBUG(IVTV_DEBUG_ERR, "Freq: Error unpausing stream\n"); + + /* Unmute */ + ivtv_set_audio(itv,tmk_audio_mapping); + + break; + } + case VIDIOC_ENUMSTD: { + struct v4l2_standard *vs=(struct v4l2_standard *)arg; + + IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: enum standard\n"); + + if ((vs->index < 0) || (vs->index >= itv->v4l2.standard.count)) + return -EINVAL; + + memcpy(vs, &itv->v4l2.standard.table.std[vs->index], + sizeof(struct v4l2_standard)); + + break; + } + case VIDIOC_G_STD: { + v4l2_std_id *vs=(v4l2_std_id *)arg; + + IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: get standard\n"); + + *vs = itv->v4l2.standard.table.std[itv->v4l2.standard.active].id; + break; + } + case VIDIOC_S_STD: { + v4l2_std_id *vs=(v4l2_std_id *)arg; + struct video_channel v; + int x; + + IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: set standard\n"); + + for (x = 0; x < itv->v4l2.standard.count; x++) { + if (itv->v4l2.standard.table.std[x].id & *vs) { + IVTV_DEBUG(IVTV_DEBUG_INFO, + "Switching standard to %s.\n", + itv->v4l2.standard.table.std[x].name); + itv->v4l2.standard.active = x; + /* fixme set standard here */ + switch (itv->v4l2.standard.active) { + case 0: /* NTSC */ + v.norm = VIDEO_MODE_NTSC; + break; + case 1: /* PAL */ + v.norm = VIDEO_MODE_PAL; + break; + case 2: /* SECAM */ + v.norm = VIDEO_MODE_SECAM; + break; + default: + break; + } + + /* Tuner */ + ivtv_call_i2c_client(itv, + IVTV_TUNER_I2C_ADDR, + VIDIOCSCHAN,&v); + /* Tuner Audio */ + ivtv_call_i2c_client(itv, + IVTV_MSP3400_I2C_ADDR, + VIDIOCSCHAN,&v); + /* Digitizer */ + ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR, + DECODER_SET_NORM,&v.norm); + + if (itv->v4l2.standard.active == 0) { // NTSC + itv->v4l2.codec.framespergop = 15; + itv->v4l2.codec.framerate = 0; + } else { // PAL + itv->v4l2.codec.framespergop = 12; + itv->v4l2.codec.framerate = 1; + } + + return 0; + } + } + return -EINVAL; + } + case VIDIOC_S_TUNER: { /* Setting tuner can only set audio mode */ + struct v4l2_tuner *vt=(struct v4l2_tuner *)arg; + + IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: set tuner\n"); + + if ((vt->index < 0) || (vt->index >= itv->v4l2.tuner.count)) + return -EINVAL; + /* looks like tuner.c doesn't support selection + * fallback to stereo... */ + vt->audmode = V4L2_TUNER_MODE_STEREO; + + break; + } + case VIDIOC_G_TUNER: { + struct v4l2_tuner *vt=(struct v4l2_tuner *)arg; + int sig=0; + + IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: get tuner\n"); + + if ((vt->index < 0) || (vt->index >= itv->v4l2.tuner.count)) + return -EINVAL; + + memcpy(vt, &itv->v4l2.tuner.table.tuner[vt->index], + sizeof(struct v4l2_tuner)); + + + ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR, + DECODER_GET_STATUS,&sig); + + if (sig & DECODER_STATUS_GOOD) { + vt->signal = 65535; /* best possible signal */ + } else { + vt->signal = 0; + } + break; + } + case MSP_SET_MATRIX: { + struct msp_matrix *mspm = (struct msp_matrix *)arg; + + /* FIXME hardcoding! */ + if ((mspm->input < 1) || (mspm->input > 8)) { + IVTV_DEBUG(IVTV_DEBUG_ERR,"Invalid audio input!\n"); + return -EINVAL; + } + if ((mspm->output < 0) || (mspm->output > 3)) { + IVTV_DEBUG(IVTV_DEBUG_ERR,"Invalid audio output!\n"); + return -EINVAL; + } + + itv->v4l2.audio_output = mspm->output; + + IVTV_DEBUG(IVTV_DEBUG_INFO, + "v4l2 ioctl: set matrix in=%d,out=%d\n", + mspm->input, + mspm->output); + + ivtv_call_i2c_client(itv,IVTV_MSP3400_I2C_ADDR,MSP_SET_MATRIX, mspm); + break; + } + case IVTV_IOC_G_CODEC: { + struct ivtv_ioctl_codec *codec=(struct ivtv_ioctl_codec *)arg; + + /* FIXME: bounds check? */ + memcpy(codec, &(itv->v4l2.codec), sizeof(struct ivtv_ioctl_codec)); + break; + } + case IVTV_IOC_S_CODEC: { + struct ivtv_ioctl_codec *codec=(struct ivtv_ioctl_codec *)arg; + + /* FIXME: insert abundant parameter validation here */ + if((codec->bitrate == 0) || (codec->bitrate_peak == 0) || + (codec->bitrate > codec->bitrate_peak) ) { + IVTV_DEBUG(IVTV_DEBUG_ERR,"ivtv ioctl: set " + "bitrate=%u < peak=%u: failed\n", + codec->bitrate, codec->bitrate_peak); + return -EINVAL; + } else { + /* Passed the garbage check */ + memcpy(&(itv->v4l2.codec), codec, + sizeof(struct ivtv_ioctl_codec)); + } + + /* VCD streamtype has some quirks. Handle them here */ + if ((codec->stream_type == IVTV_STREAM_VCD) || + (codec->stream_type == IVTV_STREAM_MPEG1)) { + struct v4l2_format *vfmt = (struct v4l2_format *)arg; + struct video_window wind; + int tmpsize = 480; + + if (itv->v4l2.standard.active == 1) tmpsize = 576; + + IVTV_DEBUG(IVTV_DEBUG_INFO,"ivtv ioctl: mpeg1_stream " + "size %d\n", tmpsize); + + /* so far it looks like you can change width at will * + * but the compressor is unhappy when the height changes * + * to anything other than 240 */ + wind.width = 352; + wind.height = tmpsize; + vfmt->fmt.pix.width = 352; + vfmt->fmt.pix.height = tmpsize / 2; + + ivtv_call_i2c_client(itv, + IVTV_SAA7115_I2C_ADDR,DECODER_SET_SIZE,&wind); + memcpy (&itv->v4l2.streams[0].format, + vfmt, sizeof(struct v4l2_format)); + } + + break; + } + case IVTV_IOCTL_GET_DEBUG_LEVEL: { + int *dbg_level = (int *)arg; + IVTV_DEBUG(IVTV_DEBUG_INFO, "IVTV_IOCTL_GET_DEBUG_LEVEL ivtv_debug = " + "0x%08x\n", ivtv_debug); + if (dbg_level) { + put_user(ivtv_debug, dbg_level); + } else { + printk("ivtv: Error: IVTV_IOCTL_GET_DEBUG_LEVEL called with " + "NULL\n"); + } + break; + } + case IVTV_IOCTL_SET_DEBUG_LEVEL: { + int *dbg_level = (int *)arg; + int old_debug_level = ivtv_debug; + get_user(ivtv_debug, dbg_level); + if (!(ivtv_debug & IVTV_DEBUG_ERR)) ivtv_debug |= IVTV_DEBUG_ERR; + IVTV_DEBUG(IVTV_DEBUG_INFO, + "IVTV_IOCTL_SET_DEBUG_LEVEL ivtv_debug = " + "0x%08x (new) 0x%08x (old)\n", + ivtv_debug, + old_debug_level); + put_user(ivtv_debug, dbg_level); + break; + } + case VIDIOC_STREAMOFF: { + ivtv_v4l2_streamoff(id); + break; + } + + case 0x00005401: /* Handle isatty() calls */ + return -EINVAL; + default: + /* If it got here, it's probably not supported.. */ + IVTV_DEBUG(IVTV_DEBUG_ERR,"ivtv-api.c: unknown ioctl 0x%08x\n", cmd); + return -ENOTTY; + } + return 0; +} diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/ivtv-driver.c 830-ivtv/drivers/media/video/ivtv-driver.c --- 000-virgin/drivers/media/video/ivtv-driver.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/media/video/ivtv-driver.c Thu Jan 8 11:17:36 2004 @@ -0,0 +1,2926 @@ +/* Main Driver file for the ivtv project: + * Driver for the iTVC15 chip. + * Author: Kevin Thayer (nufan_wfk at yahoo.com) + * License: GPL + * http://www.sourceforge.net/projects/ivtv/ + */ + +#define __KERNEL_SYSCALLS__ +#include "ivtv.h" + +// Version info +#define IVTV_VERSION_NUMBER(name) name##_version_int +#define IVTV_VERSION_STRING(name) name##_version_string +#define IVTV_VERSION_COMMENT(name) name##_comment_string + +#define IVTV_DEFINE_VERSION_INTERNAL(name, major, minor, patchlevel, comment) \ +unsigned int IVTV_VERSION_NUMBER(name) = ((major << 16) | (minor << 8) | (patchlevel)); \ +const char * const IVTV_VERSION_STRING(name) = #major"."#minor"."#patchlevel;\ +const char * const IVTV_VERSION_COMMENT(name) = comment; + +#define IVTV_VERSION_MAJOR(name) (0xFF & (IVTV_VERSION_NUMBER(name) >> 16)) +#define IVTV_VERSION_MINOR(name) (0xFF & (IVTV_VERSION_NUMBER(name) >> 8)) +#define IVTV_VERSION_PATCHLEVEL(name) (0xFF & (IVTV_VERSION_NUMBER(name))) + +#define IVTV_DEFINE_VERSION(name, major, minor, patchlevel, comment) IVTV_DEFINE_VERSION_INTERNAL(name, major, minor, patchlevel, comment) + +IVTV_DEFINE_VERSION(ivtv_rev, + IVTV_DRIVER_VERSION_MAJOR, + IVTV_DRIVER_VERSION_MINOR, + IVTV_DRIVER_VERSION_PATCHLEVEL, + "pre"); + +/* mini header */ + +/* var to keep track of the number of array elements in use */ +int ivtv_cards_active = 0; + +/* Master variable for all ivtv info */ +struct ivtv ivtv_cards[IVTV_MAX_CARDS]; + +/* for the global data */ +spinlock_t ivtv_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; + +/* add your revision and whatnot here */ +static struct pci_device_id ivtv_pci_tbl[] __devinitdata = { + {PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV15, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV16, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0,} +}; + +static void ivtv_irq_dec_vsync(struct ivtv* itv); +static irqreturn_t ivtv_irq_handler(int irq, void *dev_id, struct pt_regs *regs); +static void ivtv_DMA_done(struct ivtv *itv); +static void ivtv_sched_DMA(struct ivtv *itv); +static void ivtv_dec_DMA_done(struct ivtv *itv); +static void ivtv_dec_sched_DMA(struct ivtv *itv); + +static u32 ivtv_firm_search_id[]= {0x12345678,0x34567812,0x56781234,0x78123456}; + +/* Parameter declarations */ +static int num_devices = IVTV_DEFAULT_NUM_CARDS; +int yuv_buffers = IVTV_DEFAULT_YUV_BUFFERS; +int mpg_buffers = IVTV_DEFAULT_MPG_BUFFERS; +int vbi_buffers = IVTV_DEFAULT_VBI_BUFFERS; +int dec_mpg_buffers = IVTV_DEFAULT_DEC_MPG_BUFFERS; +int dec_yuv_buffers = IVTV_DEFAULT_DEC_YUV_BUFFERS; +static int dec_mpg_qlen = IVTV_DEFAULT_DEC_MPG_QLEN; +static int dec_yuv_qlen = IVTV_DEFAULT_DEC_YUV_QLEN; +#ifdef YUV_FIXUP +static int yuv_fixup; +#endif + +int ivtv_pal = 0; + + +/* low debugging by default */ +#if 0 +int debug = ( IVTV_DEBUG_ERR | IVTV_DEBUG_INFO | IVTV_DEBUG_API + | IVTV_DEBUG_DMA | IVTV_DEBUG_IOCTL | IVTV_DEBUG_I2C + | IVTV_DEBUG_IRQ ); +#endif +int ivtv_debug = IVTV_DEBUG_ERR; + +/* tuner.h tuner type for ivtv card */ +int tuner = -1; + +int errno; + +#define EXPAND_TO_STRING_INTERNAL(arg) #arg +#define EXPAND_TO_STRING(arg) EXPAND_TO_STRING_INTERNAL(arg) + +#ifdef YUV_FIXUP +MODULE_PARM(yuv_fixup, "i"); +MODULE_PARM_DESC(yuv_fixup, + "\nToggles conversion of Hauppauge Macroblock NV12 to NV12\n"); +#endif + +MODULE_PARM(tuner, "i"); +MODULE_PARM_DESC(tuner, "\nTuner type selection, see tuner.h for values"); + +MODULE_PARM(yuv_buffers, "i"); +MODULE_PARM_DESC(yuv_buffers, + "\nNumber of 32K buffers for copying YUV.\n" + "Default: " EXPAND_TO_STRING(IVTV_DEFAULT_YUV_BUFFERS) ", " + "Min: " EXPAND_TO_STRING(IVTV_MIN_YUV_BUFFERS) " " + "Max: " EXPAND_TO_STRING(IVTV_MAX_YUV_BUFFERS)); + +MODULE_PARM(mpg_buffers, "i"); +MODULE_PARM_DESC(mpg_buffers, + "\nNumber of 32K buffers for copying mpg.\n" + "Default: " EXPAND_TO_STRING(IVTV_DEFAULT_MPG_BUFFERS) ", " + "Min: " EXPAND_TO_STRING(IVTV_MIN_MPG_BUFFERS) " " + "Max: " EXPAND_TO_STRING(IVTV_MAX_MPG_BUFFERS)); + +MODULE_PARM(vbi_buffers, "i"); +MODULE_PARM_DESC(vbi_buffers, + "\nNumber of 32K buffers for copying VBI.\n" + "Default: " EXPAND_TO_STRING(IVTV_DEFAULT_VBI_BUFFERS) ", " + "Min: " EXPAND_TO_STRING(IVTV_MIN_VBI_BUFFERS) " " + "Max: " EXPAND_TO_STRING(IVTV_MAX_VBI_BUFFERS)); + +MODULE_PARM(num_devices, "i"); +MODULE_PARM_DESC(num_devices, "\nNumber of supported devices (1-9).\n" + "Default: " EXPAND_TO_STRING(IVTV_DEFAULT_NUM_CARDS)); + +MODULE_PARM(dec_mpg_buffers, "i"); +MODULE_PARM_DESC(dec_mpg_buffers, + "\nNumber of 32K buffers for decoding MPG.\n" + "Default: " EXPAND_TO_STRING(IVTV_DEFAULT_DEC_MPG_BUFFERS) ", " + "Min: " EXPAND_TO_STRING(IVTV_MIN_DEC_MPG_BUFFERS) " " + "Max: " EXPAND_TO_STRING(IVTV_MAX_DEC_MPG_BUFFERS)); + +MODULE_PARM(dec_yuv_buffers, "i"); +MODULE_PARM_DESC(dec_yuv_buffers, + "\nNumber of 32K buffers for decoding YUV.\n" + "Default: " EXPAND_TO_STRING(IVTV_DEFAULT_DEC_YUV_BUFFERS) ", " + "Min: " EXPAND_TO_STRING(IVTV_MIN_DEC_YUV_BUFFERS) " " + "Max: " EXPAND_TO_STRING(IVTV_MAX_DEC_YUV_BUFFERS) ", " + "0 to disable"); + +MODULE_PARM(dec_mpg_qlen, "i"); +MODULE_PARM_DESC(dec_mpg_qlen, + "\nNumber of 32K buffers to queue before dispatching to decoder\n" + "Default: " EXPAND_TO_STRING(IVTV_DEFAULT_DEC_MPG_QLEN) ", " + "Min: " EXPAND_TO_STRING(IVTV_MIN_DEC_MPG_QLEN) " " + "Max: "); + +MODULE_PARM(dec_yuv_qlen, "i"); +MODULE_PARM_DESC(dec_yuv_qlen, + "\nNumber of 32K buffers to queue before dispatching to decoder\n" + "Default: " EXPAND_TO_STRING(IVTV_DEFAULT_DEC_YUV_QLEN) ", " + "Min: " EXPAND_TO_STRING(IVTV_MIN_DEC_YUV_QLEN) " " + "Max: "); + +MODULE_PARM(ivtv_debug, "i"); +MODULE_PARM_DESC(ivtv_debug, "\nDebug level (bitmask), default, errors only\n" + "(debug=127 gives full debuging)"); + +MODULE_PARM(ivtv_pal, "i"); +MODULE_PARM_DESC(ivtv_pal, "\nUse PAL as default video mode instead of NTSC"); + +MODULE_AUTHOR("Kevin Thayer"); +MODULE_DESCRIPTION("Alpha iTVC15 driver"); +MODULE_SUPPORTED_DEVICE("iTVC15/16 mpg2 encoder (aka WinTV PVR 250/350)"); +MODULE_LICENSE("GPL"); + +static int SGarray_size; +static int DSGarray_size; + +void ivtv_sleep_timeout(int timeout) +{ + int sleep = timeout; + + do { + set_current_state(TASK_INTERRUPTIBLE); + sleep = schedule_timeout(sleep); + + } while (sleep && !signal_pending(current)); +} + +/* ceiling function for ints.. */ +int ivtv_ceil(int x, int y) { + int floor = (int)(x/y); + + if ((floor * y) < x) + return floor+1; + return floor; +} + +/* Release ioremapped memory */ +static void ivtv_iounmap(struct ivtv *itv) { + if (itv == NULL) + return ; + + /* Release io memory */ + if (itv->io_mem != NULL) { + IVTV_DEBUG(IVTV_DEBUG_INFO, "releasing iomem\n"); + iounmap(itv->io_mem); + itv->io_mem = NULL ; + } + + /* Release registers memory */ + if (itv->reg_mem != NULL) { + IVTV_DEBUG(IVTV_DEBUG_INFO, "releasing regmem\n"); + iounmap(itv->reg_mem); + itv->reg_mem = NULL ; + } + + /* Release encoder mailboxes */ + if (itv->enc_mbox != NULL) { + IVTV_DEBUG(IVTV_DEBUG_INFO, "releasing encmbox\n"); + iounmap(itv->enc_mbox); + itv->enc_mbox = NULL ; + } + + /* Release decoder mailboxes */ + if (itv->dec_mbox != NULL) { + IVTV_DEBUG(IVTV_DEBUG_INFO, "releasing decmbox\n"); + iounmap(itv->dec_mbox); + itv->dec_mbox = NULL ; + } +} + +/* must only be used as hints, not as a definitive answer. the answer could + * be wrong as soon as we return */ +int ivtv_get_free_elements(struct ivtv *itv, struct ivtv_buffer_list *queue) +{ + unsigned long flags; + int elements; + + spin_lock_irqsave(&itv->lock, flags); + elements = queue->elements; + spin_unlock_irqrestore(&itv->lock, flags); + + return elements; +} + +inline void __ivtv_enq_buf(struct ivtv_buffer_list *queue, + struct ivtv_buffer *buf) { + WARN_ON(!list_empty(&buf->list)); + list_add_tail(&buf->list, &queue->list); + queue->elements++; +} + + +/* Adds buffers to the tail, effectively making a queue */ +int ivtv_enq_buf(struct ivtv *itv, struct ivtv_buffer_list *queue, + struct ivtv_buffer *buf) { + unsigned long flags; + + spin_lock_irqsave(&itv->lock, flags); + __ivtv_enq_buf(queue, buf); + spin_unlock_irqrestore(&itv->lock, flags); + + return 0; +} + +inline void __ivtv_del_buf(struct ivtv_buffer_list *queue, + struct ivtv_buffer *buffer) { + WARN_ON(list_empty(&buffer->list)); + list_del_init(&buffer->list); + queue->elements--; +} + +/* called to remove the buffer returned by _peek_ functions */ +void ivtv_del_buf(struct ivtv *itv, struct ivtv_buffer_list *queue, + struct ivtv_buffer *buffer) { + unsigned long flags; + + spin_lock_irqsave(&itv->lock, flags); + __ivtv_del_buf(queue, buffer); + spin_unlock_irqrestore(&itv->lock, flags); +} + +void ivtv_move_buf(struct ivtv *itv, struct ivtv_buffer_list *from, + struct ivtv_buffer_list *to, struct ivtv_buffer *buffer) +{ + unsigned long flags; + + WARN_ON(list_empty(&buffer->list)); + + spin_lock_irqsave(&itv->lock, flags); + list_move_tail(&buffer->list, &to->list); + from->elements--; + to->elements++; + spin_unlock_irqrestore(&itv->lock, flags); +} + +/* returns first item in queue, doesn't dequeue */ +struct ivtv_buffer *__ivtv_deq_peek_head(struct ivtv_buffer_list *queue) { + + /* make sure list has something to DeQ */ + if (!list_empty(&queue->list)) + return list_entry(queue->list.next, struct ivtv_buffer, list); + + IVTV_DEBUG(IVTV_DEBUG_INFO,"DeQ from empty list\n"); + queue->elements = 0; + return NULL; +} + +struct ivtv_buffer *ivtv_deq_peek_head(struct ivtv *itv, + struct ivtv_buffer_list *queue) { + unsigned long flags; + struct ivtv_buffer *buffer; + + spin_lock_irqsave(&itv->lock, flags); + buffer = __ivtv_deq_peek_head(queue); + spin_unlock_irqrestore(&itv->lock, flags); + + return buffer; +} + +/* removes buffer from the head */ +struct ivtv_buffer *__ivtv_deq_buf(struct ivtv_buffer_list *queue) { + struct ivtv_buffer *buf; + + /* make sure list has something to DeQ */ + if (!list_empty(&queue->list)) { + buf = list_entry(queue->list.next, struct ivtv_buffer, list); + list_del_init(queue->list.next); + queue->elements--; + return buf; + } + + IVTV_DEBUG(IVTV_DEBUG_INFO,"DeQ from empty list!\n"); + queue->elements = 0; + return NULL; +} + +struct ivtv_buffer *ivtv_deq_buf(struct ivtv *itv, + struct ivtv_buffer_list *queue) { + struct ivtv_buffer *buf; + unsigned long flags; + + spin_lock_irqsave(&itv->lock, flags); + buf = __ivtv_deq_buf(queue); + spin_unlock_irqrestore(&itv->lock, flags); + + return buf; +} + +struct ivtv_buffer *ivtv_init_buffer(int gfp_mask) { + struct ivtv_buffer *ibuf; + + ibuf = kmalloc(sizeof(struct ivtv_buffer), gfp_mask); + if (ibuf == NULL) { + IVTV_DEBUG(IVTV_DEBUG_ERR,"No mem on ibuf alloc!\n"); + return NULL; + } + + (void *)ibuf->buffer.m.userptr = kmalloc(IVTV_DMA_BUF_SIZE, gfp_mask); + if ((void *)ibuf->buffer.m.userptr == NULL) { + kfree(ibuf); + IVTV_DEBUG(IVTV_DEBUG_ERR,"No mem on buf alloc!\n"); + return NULL; + } + + INIT_LIST_HEAD(&ibuf->list); + ibuf->buffer.length = IVTV_DMA_BUF_SIZE; + ibuf->buffer.bytesused = 0; + ibuf->readpos = 0; + + return ibuf; +} + +#define IVTV_DMA_UNMAPPED ((u32) -1) + +void ivtv_free_buffer(struct ivtv *itv, struct ivtv_buffer *item) { + if (item->dma_handle != IVTV_DMA_UNMAPPED) + pci_unmap_single(itv->dev, item->dma_handle, IVTV_DMA_BUF_SIZE, PCI_DMA_TODEVICE); + if (item->buffer.m.userptr) { + IVTV_DEBUG(IVTV_DEBUG_INFO,"Freeing buf %d!\n", item->buffer.index); + kfree((void *)item->buffer.m.userptr); + } + kfree(item); +} + +int ivtv_free_queue(struct ivtv_buffer_list *queue) { + struct ivtv_buffer *item; + unsigned long flags; + struct ivtv *itv; + int x; + + if (queue == NULL) { + IVTV_DEBUG(IVTV_DEBUG_ERR,"Free on NULL list!\n"); + return -EINVAL; + } + + spin_lock_irqsave(&ivtv_lock, flags); + + /* FIXME ugly */ + /* verify ivtv before continuing */ + itv = NULL; + for (x = 0; x < ivtv_cards_active; x++) { + if (queue->vdev->priv == &ivtv_cards[x]) { + itv = queue->vdev->priv; + break; + } + } + + spin_unlock_irqrestore(&ivtv_lock, flags); + + if (itv == NULL) + return -ENODEV; + + while ((item = ivtv_deq_buf(itv, queue))) + ivtv_free_buffer(itv, item); + + return 0; +} + +/* NOTE: This returns the # of buffers allocated */ +int ivtv_init_queue(struct ivtv *itv, struct ivtv_buffer_list *queue, + int length, enum v4l2_buf_type type) { + int x; + struct ivtv_buffer *item; + + /* Just in case */ + INIT_LIST_HEAD(&queue->list); + + for (x=0;x < length; x++) { + /* allocate buffer */ + item = ivtv_init_buffer(GFP_KERNEL); + if (item == NULL) { + IVTV_DEBUG(IVTV_DEBUG_ERR,"Buffer alloc failed!\n"); + return x; + } + + /* setup buffer */ + item->buffer.index = x; + item->buffer.type = type; + item->buffer.field = V4L2_FIELD_INTERLACED; + item->buffer.memory = V4L2_MEMORY_MMAP; + + /* enqueue buffer */ + ivtv_enq_buf(itv, queue, item); + } + + return x; +} + +int ivtv_move_queue(struct ivtv *itv, struct ivtv_buffer_list *src, + struct ivtv_buffer_list *dst) { + struct ivtv_buffer *buf; + unsigned long flags; + + spin_lock_irqsave(&itv->lock, flags); + + while ((buf = __ivtv_deq_buf(src))) + __ivtv_enq_buf(dst, buf); + + spin_unlock_irqrestore(&itv->lock, flags); + return 0; +} + +static int load_fw_direct(const char *fn, char *mem) { + int fd; + long l; + mm_segment_t fs = get_fs(); + + set_fs(get_ds()); + + if ( (fd = open(fn, 0, 0)) == -1) { + printk(KERN_INFO "Unable to open '%s'.\n", fn); + l = -EINVAL; + goto out; + } + /* the 2 means SEEK_END */ + l = lseek(fd, 0L, 2); + + if (l <= 0 || l > IVTV_FIRM_IMAGE_SIZE) { + printk(KERN_INFO "Firmware image too large '%s'\n", fn); + l = -ENOMEM; + goto out; + } + + /* the 2 means SEEK_SET */ + lseek(fd, 0L, 0); + + if (read(fd, mem, l) != l){ + printk(KERN_INFO "Failed to read '%s'.\n", fn); + l = -ENOMEM; + } + +out: + close(fd); + set_fs(fs); + + return (int) l; +} + +int ivtv_firmware_copy(struct ivtv *itv) { + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Loading encoder image\n"); + + if (load_fw_direct(IVTV_FIRM_ENC_FILENAME, + (char *)(itv->io_mem + IVTV_ENC_MEM_START)) != + IVTV_FIRM_IMAGE_SIZE) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "failed loading encoder firmware\n"); + return -3; + } + + + if (itv->card_type != IVTV_250_V2) { + IVTV_DEBUG(IVTV_DEBUG_INFO, "Loading decoder firmware\n"); + if (load_fw_direct(IVTV_FIRM_DEC_FILENAME, + (char *)(itv->io_mem + IVTV_DEC_MEM_START)) != + IVTV_FIRM_IMAGE_SIZE) { + IVTV_DEBUG(IVTV_DEBUG_ERR, + "failed loading decoder firmware\n"); + return -1; + } + } + + return 0; +} + + +int ivtv_stop_firmware(struct ivtv *itv) { + u32 data[IVTV_MBOX_MAX_DATA], result; + int x = 0; + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Stopping firmware\n"); + + if (atomic_read(&itv->capturing)) { + x = ivtv_stop_all_captures(itv); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stop_fw error 1. Code %d\n",x); + } + + /*Stop decoder_playback */ + data[0] = 1; /* 0: render last frame, 1: stop NOW! :) */ + data[1] = 0; /* "low 4 bytes of stop index" */ + data[2] = 0; /* 0: stop immedeately */ + x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_STOP_PLAYBACK, + &result, 3, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stop_fw error 2. Code %d\n",x); + + /*halt enc firmware */ + x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ENC_HALT_FW, + &result, 0, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stop_fw error 3. Code %d\n",x); + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 10ms\n"); + ivtv_sleep_timeout(HZ/100); + + /*halt dec firmware */ + if (IVTV_250_V2 != itv->card_type) { + x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_HALT_FW, + &result, 0, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stop_fw error 4. Code %d\n",x); + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 10ms\n"); + ivtv_sleep_timeout(HZ/100); + } + + return 0; +} + +int ivtv_firmware_init(struct ivtv *itv) { + int x; + + /* check that we're not RE-loading firmware */ + /* a sucessful load will have detected HW */ + /* mailboxes. */ + + /* FIXME i dont think this will ever get called */ + if (NULL != itv->enc_mbox) { + IVTV_DEBUG(IVTV_DEBUG_INFO, "readying card for firmware upload\n"); + x = ivtv_stop_firmware(itv); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "Error %d, stopping firmware\n", x); + } + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Stopping VDM\n"); + writel(IVTV_CMD_VDM_STOP, (IVTV_REG_VDM + itv->reg_mem)); + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Stopping AO\n"); + writel(IVTV_CMD_AO_STOP, (IVTV_REG_AO + itv->reg_mem)); + + IVTV_DEBUG(IVTV_DEBUG_INFO, "pinging (?) APU\n"); + writel(IVTV_CMD_APU_PING, (IVTV_REG_APU + itv->reg_mem)); + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Stopping VPU\n"); + if (IVTV_250_V2 == itv->card_type) { + writel(IVTV_CMD_VPU_STOP16, (IVTV_REG_VPU + itv->reg_mem)); + } + else { + writel(IVTV_CMD_VPU_STOP15, (IVTV_REG_VPU + itv->reg_mem)); + } + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Resetting Hw Blocks\n"); + writel(IVTV_CMD_HW_BLOCKS_RST, (IVTV_REG_HW_BLOCKS + itv->reg_mem)); + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Stopping SPU\n"); + writel(IVTV_CMD_SPU_STOP, (IVTV_REG_SPU + itv->reg_mem)); + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 10ms\n"); + ivtv_sleep_timeout(HZ/100); + + IVTV_DEBUG(IVTV_DEBUG_INFO, "init Encoder SDRAM pre-charge\n"); + writel(IVTV_CMD_SDRAM_PRECHARGE_INIT, + (IVTV_REG_ENC_SDRAM_PRECHARGE + itv->reg_mem)); + + IVTV_DEBUG(IVTV_DEBUG_INFO, "init Encoder SDRAM refresh to 1us\n"); + writel(IVTV_CMD_SDRAM_REFRESH_INIT, + (IVTV_REG_ENC_SDRAM_REFRESH + itv->reg_mem)); + + IVTV_DEBUG(IVTV_DEBUG_INFO, "init Decoder SDRAM pre-charge\n"); + writel(IVTV_CMD_SDRAM_PRECHARGE_INIT, + (IVTV_REG_DEC_SDRAM_PRECHARGE + itv->reg_mem)); + + IVTV_DEBUG(IVTV_DEBUG_INFO, "init Decoder SDRAM refresh to 1us\n"); + writel(IVTV_CMD_SDRAM_REFRESH_INIT, + (IVTV_REG_DEC_SDRAM_REFRESH + itv->reg_mem)); + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for %dms (600 recommended)\n",(int)IVTV_SDRAM_SLEEPTIME); + ivtv_sleep_timeout(IVTV_SDRAM_SLEEPTIME); + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Card ready for firmware!\n"); + x = ivtv_firmware_copy(itv); + if (x) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "Error loading firmware!\n"); + return x; + } + + /*I guess this is read-modify-write :)*/ + writel((readl(itv->reg_mem + IVTV_REG_SPU)&IVTV_MASK_SPU_ENABLE), + (IVTV_REG_SPU+itv->reg_mem)); + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 1 sec\n"); + ivtv_sleep_timeout(HZ); + + /*I guess this is read-modify-write :)*/ + if (IVTV_250_V2 == itv->card_type) { + writel((readl(itv->reg_mem + IVTV_REG_VPU)&IVTV_MASK_VPU_ENABLE16), + (IVTV_REG_VPU+itv->reg_mem)); + } + else { + writel((readl(itv->reg_mem + IVTV_REG_VPU)&IVTV_MASK_VPU_ENABLE15), + (IVTV_REG_VPU+itv->reg_mem)); + } + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 1 sec\n"); + ivtv_sleep_timeout(HZ); + + /* FIXME Send Status API commands to encoder and decoder to verify!*/ + + return 0; +} + +int ivtv_find_firmware_mailbox(struct ivtv *itv) { + u32 *searchptr, *result; + int match = 0; + + searchptr = NULL; + result = NULL; + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Searching for encoder mailbox\n"); + searchptr =(u32 *)(IVTV_FIRM_SEARCH_ENCODER_START + itv->io_mem); + + while (searchptr < (u32 *)(IVTV_FIRM_SEARCH_ENCODER_END + itv->io_mem)) { + if (ivtv_firm_search_id[match] == readl(searchptr)) { + (u32)result = (u32)searchptr+4; /* avoid pointer aritmetic */ + match++; + while ((match > 0) && (match < 4)) { + IVTV_DEBUG(IVTV_DEBUG_INFO, "match: 0x%08x at " + "0x%08x. match: %d\n", *result, + (u32)result, match); + if (ivtv_firm_search_id[match] == readl(result)) { + match++; + /* FIXME change to just "result++;" ? */ + (u32)result = (u32)result + 4; + } + else + match = 0; + } + } + else { + IVTV_DEBUG(IVTV_DEBUG_INFO, "."); + } + if ( 4 == match ) { + IVTV_DEBUG(IVTV_DEBUG_INFO, "found encoder mailbox!\n"); + itv->enc_mbox = (struct ivtv_mailbox *) result; + break; + } + (u32)searchptr += IVTV_FIRM_SEARCH_STEP; + } + if (itv->enc_mbox == NULL) IVTV_DEBUG(IVTV_DEBUG_ERR, "Encoder mailbox not found\n"); + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Searching for decoder mailbox\n"); + match = 0; + searchptr = (u32 *)(IVTV_FIRM_SEARCH_DECODER_START + itv->io_mem); + + while (searchptr < (u32 *)(IVTV_FIRM_SEARCH_DECODER_END + itv->io_mem)) { + if (ivtv_firm_search_id[match] == readl(searchptr)) { + (u32)result = (u32)searchptr+4; /* avoid pointer aritmetic */ + match++; + while ((match > 0) && (match < 4)) { + IVTV_DEBUG(IVTV_DEBUG_INFO, "match: 0x%08x at 0x%08x. match: %d\n", + *result, (u32)result, match); + if (ivtv_firm_search_id[match] == readl(result)) { + match++; + /* FIXME change to just "result++;" ? */ + (u32)result = (u32)result + 4; + } + else + match = 0; + } + } + else { + IVTV_DEBUG(IVTV_DEBUG_INFO, "."); + } + if ( 4 == match ) { + IVTV_DEBUG(IVTV_DEBUG_INFO, "found decoder mailbox!\n"); + itv->dec_mbox = (struct ivtv_mailbox *) result; + break; + } + (u32)searchptr += IVTV_FIRM_SEARCH_STEP; + } + if (itv->dec_mbox == 0) IVTV_DEBUG(IVTV_DEBUG_ERR, "Decoder mailbox not found\n"); + + return 0; +} + +int ivtv_get_free_mailbox(struct ivtv_mailbox *mbox) { + int i = 0; + if (NULL == mbox) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "Can't get mailbox from NULL\n"); + return -ENODEV; + } + + /* FIXME hardcoded cause i'm not sure what changing API_BOXES will do */ + //for (i = 0; i < IVTV_MBOX_API_BOXES; i++) { + for (i = 0; i < 2; i++) { + if (mbox[i].flags & IVTV_MBOX_FIRMWARE_DONE) { + switch (mbox[i].cmd) { + case IVTV_API_SCHED_DMA_TO_HOST: + case IVTV_API_DEC_DMA_FROM_HOST: + IVTV_DEBUG(IVTV_DEBUG_API, + "recycled mailbox: %d\n", i); + writel(IVTV_MBOX_IN_USE, &mbox[i].flags); + return i; + break; + default: + IVTV_DEBUG(IVTV_DEBUG_API, + "Mailbox %d in use, skipping\n", i); + break; + } + /* FIXME using 'else' may leak mailboxes in some situations */ + } else if (!test_and_set_bit(0, (void *) &mbox[i].flags)) { + IVTV_DEBUG(IVTV_DEBUG_API, "got free mailbox: %d\n", i); + return i; + } + } + + IVTV_DEBUG(IVTV_DEBUG_ERR, "no free mailboxes!\n"); + IVTV_DEBUG(IVTV_DEBUG_ERR, "mbox 0: 0x%08x, mbox 1 0x%08x!\n", + mbox[0].cmd, mbox[1].cmd); + return -ENODEV; +} + +void ivtv_clear_irq_mask(struct ivtv *itv, unsigned long mask) { + itv->irqmask &= ~mask; + writel(itv->irqmask,(itv->reg_mem + IVTV_REG_IRQMASK)); + /* pci posting */ + readl(itv->reg_mem + IVTV_REG_IRQMASK); +} + +void ivtv_set_irq_mask(struct ivtv *itv, unsigned long mask) { + itv->irqmask |= mask; + writel(itv->irqmask,(itv->reg_mem + IVTV_REG_IRQMASK)); + /* pci posting */ + readl(itv->reg_mem + IVTV_REG_IRQMASK); +} + +/** + * Call ivtv api function using given mailbox, without locking sem. + */ +int __ivtv_api_call(struct ivtv_mailbox *mbox, u32 cmd, int elements, + const u32* data) { + int x; + if (NULL == mbox) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "invalid api mailbox\n"); + return -ENODEV; + } + + /* "if mailbox is available" */ + if ( (mbox->flags & IVTV_MBOX_FIRMWARE_DONE) || + (!test_and_set_bit(0, (void *) &mbox->flags)) ) { + /* I'm too lazy to invert the condition ;) */ + } else { + IVTV_DEBUG(IVTV_DEBUG_INFO, "Mailbox busy (unexpected)\n"); + IVTV_DEBUG(IVTV_DEBUG_INFO, "cmd 0x%08x, m.cmd 0x%08x, fl 0x%08x\n", + cmd, mbox->cmd, mbox->flags); + IVTV_DEBUG(IVTV_DEBUG_INFO, "d0 0x%08x, d1 0x%08x, d2 0x%08x\n", + mbox->data[0], mbox->data[1], + mbox->data[2]); + return -EBUSY; + } + + readl(&mbox->flags); + writel(cmd, &mbox->cmd); + writel(IVTV_API_STD_TIMEOUT, &mbox->timeout); + + for (x = 0; x < IVTV_MBOX_MAX_DATA; x++) { + if (x < elements) { + writel(data[x], &mbox->data[x]); + } else { + writel(0, &mbox->data[x]); + } + } + + writel((IVTV_MBOX_DRIVER_DONE | IVTV_MBOX_IN_USE), &mbox->flags); + readl(&mbox->flags); + + return 0; +} + +/* This one is for stuff that can't sleep.. irq handlers, etc.. */ +int ivtv_api_getresult_nosleep(struct ivtv_mailbox *mbox, u32 *result, u32 data[]) { + u32 readdata; + int count = 0; + + if (NULL == mbox) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "invalid api mailbox\n"); + return -ENODEV; + } + + readdata = readl(&mbox->flags); + + *result = readl(&mbox->retval); + for ( count=0; count < IVTV_MBOX_MAX_DATA; count++) + data[count] = readl(&mbox->data[count]); + + return 0; +} + +int __ivtv_api_getresult(struct ivtv_mailbox *mbox, u32 *result, u32 data[], + int api_timeout) { + u32 readdata; + int count = 0; + + readdata = readl(&mbox->flags); + + while (!(readdata & IVTV_MBOX_FIRMWARE_DONE)) { + IVTV_DEBUG(IVTV_DEBUG_API, + "[%d]result not ready, waiting 10 ms\n", + count); + ivtv_sleep_timeout(HZ/100); + readdata = readl(&mbox->flags); + + if (count++ > api_timeout) { + IVTV_DEBUG(IVTV_DEBUG_ERR, + "%d ms time out waiting for firmware\n", + api_timeout); + return -EBUSY; + } + } + + *result = readl(&mbox->retval); + for ( count=0; count < IVTV_MBOX_MAX_DATA; count++) + data[count] = readl(&mbox->data[count]); + + return 0; +} + +int ivtv_api(struct ivtv_mailbox *mbox, struct semaphore *sem, int cmd, + u32 *result, int args, u32 data[]) { + int x=0, gotsem=0, needsresult=1; + int die=0, api_timeout=100; + struct ivtv_mailbox *local_box; + + IVTV_DEBUG(IVTV_DEBUG_API, "API Call: 0x%08x\n", cmd); + + local_box = mbox; + + /* check args */ + if (args > IVTV_MBOX_MAX_DATA) return -EINVAL; + + switch (cmd) { + case IVTV_API_SCHED_DMA_TO_HOST: + case IVTV_API_DEC_DMA_FROM_HOST: + needsresult = 0; + if (down_trylock(sem)) { /* box 0 was busy */ + gotsem = 0; + local_box = &mbox[1]; + } else { + gotsem = 1; + } + if ((x = __ivtv_api_call(local_box, cmd, args, data))) { + if (local_box == mbox) { + IVTV_DEBUG(IVTV_DEBUG_API, + "Trying alternate mailbox\n"); + x = __ivtv_api_call(&mbox[1],cmd,args,data); + } + } + goto ivtv_api_done; + break; + /* adjust api timeout for these 2 calls */ + case IVTV_API_END_CAPTURE: + case IVTV_API_EVENT_NOTIFICATION: + api_timeout = 1000; + default: + if (down_interruptible(sem)) return -ERESTARTSYS; + gotsem = 1; + break; + } + + /* wait 200ms for mailbox to become free */ + x = __ivtv_api_call(local_box, cmd, args, data); + while ((x == -EBUSY) && (die < 20)) { + die++; + ivtv_sleep_timeout(HZ/100); + x = __ivtv_api_call(local_box, cmd, args, data); + IVTV_DEBUG(IVTV_DEBUG_API, "die: %d\n", die); + } + + if (x == -EBUSY) { + /* dilemma here: + if the command that currently has the mailbox + is lost, then it'll never free up the box, and + we'll lose our only 'general purpose' box forever. + But if it comes back, we run the risk of squishing + something important!. */ + switch (local_box->cmd) { + case IVTV_API_DEC_DMA_FROM_HOST: + /* if we got here, it's because the call to xfer the dma + was finished, and the command that wants to run has + already slept for 20ms. It's probably safe to take over + */ + IVTV_DEBUG(IVTV_DEBUG_API, "Forcibly freeing mailbox\n"); + writel(0x00000000, &mbox->flags); + x = __ivtv_api_call(local_box, cmd, args, data); + break; + default: + /* do nothing */ + break; + } + } + + if (x) { + IVTV_DEBUG(IVTV_DEBUG_API,"Error running command 0x%08x\n", cmd); + goto ivtv_api_done; + } + + if (needsresult) { + x = __ivtv_api_getresult(local_box, result, &data[0], api_timeout); + IVTV_DEBUG(IVTV_DEBUG_API, "retval: 0x%08x\n", *result); + if(x == -EBUSY) + IVTV_DEBUG(IVTV_DEBUG_ERR, "api call 0x%08x\n", cmd); + } + + IVTV_DEBUG(IVTV_DEBUG_API, "Releasing mailbox (before 0x%08x, ", + readl(&mbox->flags)); + writel(0x00000000, &mbox->flags); + IVTV_DEBUG(IVTV_DEBUG_API, "after 0x%08x )\n", readl(&mbox->flags)); + +ivtv_api_done: + if (gotsem) { + up(sem); + } + + return x; +} + +int ivtv_firmware_versions(struct ivtv *itv) { + u32 data[IVTV_MBOX_MAX_DATA], result; + int x; + + /* Encoder */ + IVTV_DEBUG(IVTV_DEBUG_INFO, "Getting encoder firmware rev.\n"); + x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ENC_GETVER, + &result, 0, &data[0]); + if (x) { + IVTV_DEBUG(IVTV_DEBUG_ERR, + "error getting Encoder firmware version\n"); + } + else { + IVTV_DEBUG(IVTV_DEBUG_ERR, + "Encoder revision: 0x%08x\n", data[0]); + } + + if (itv->card_type != IVTV_250_V2) { + /* Decoder */ + IVTV_DEBUG(IVTV_DEBUG_INFO, "Getting decoder firmware rev.\n"); + x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_GETVER, + &result, 0, &data[0]); + if (x) { + IVTV_DEBUG(IVTV_DEBUG_ERR, + "error getting Decoder firmware version\n"); + } + else { + IVTV_DEBUG(IVTV_DEBUG_ERR, + "Decoder revision: 0x%08x\n", data[0]); + } + } + + return 0; +} + + +int ivtv_stop_all_captures(struct ivtv *itv) { + struct ivtv_open_id id; + int x; + id.itv = itv; + + down(&itv->sem_lock); + + for (x = 0; x < itv->v4l2.streamcount;x++) { + if (test_bit(IVTV_F_S_CAP, &itv->v4l2.streams[x].s_flags)) { + id.type=x; + ivtv_stop_capture(&id); + } + } + + up(&itv->sem_lock); + return 0; +} + +int ivtv_stop_capture(struct ivtv_open_id *id) { + struct ivtv *itv=id->itv; + u32 data[IVTV_MBOX_MAX_DATA], result; + DECLARE_WAITQUEUE(wait, current); + int type, subtype, then; + int x; + + /* This function assumes that you are allowed to stop the capture + and that we are actually capturing */ + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Stop Capture\n"); + + /* sem_lock must be held */ + IVTV_ASSERT(ivtv_sem_count(&itv->sem_lock) <= 0); + + type = id->type; + if (type == 1) { + subtype = 3; //FIXME temp + } else { + subtype = 3; + } + +#if 0 + /* only run these if we're shutting down the last cap */ + if (atomic_read(&itv->capturing) - 1 == 0) { + /* event notification (off)*/ + data[0] = 0; /*type: 0 = refresh */ + data[1] = 0; /*on/off: 0 = off */ + data[2] = 0x10000000; /*intr_bit: 0x10000000 = digitizer */ + data[3] = -1; /*mbox_id: -1: none */ + x = ivtv_api(itv->enc_mbox, &itv->enc_msem, + IVTV_API_EVENT_NOTIFICATION, &result, 4, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stopcap error 1. Code %d\n",x); + + } +#endif + + /* end_capture */ + data[0] = 1; /*when: 0 = end of GOP 1 = NOW! */ + data[1] = type; /*type: 0 = mpeg */ + data[2] = subtype; /*subtype: 3 = video+audio */ + x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_END_CAPTURE, + &result, 3, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stopcap error 2. Code %d\n",x); + + then = jiffies; + + add_wait_queue(&itv->v4l2.streams[type].waitq, &wait); + set_current_state(TASK_INTERRUPTIBLE); + do { + /* check if DMA is pending */ + if (!test_bit(IVTV_F_S_DMAP, &itv->v4l2.streams[type].s_flags)) { + break; + } + IVTV_DEBUG(IVTV_DEBUG_INFO, "dma still pending!\n"); + schedule_timeout(HZ/100); + } while ( ((then + HZ) < jiffies) && !signal_pending(current)); + + set_current_state(TASK_RUNNING); + remove_wait_queue(&itv->v4l2.streams[type].waitq, &wait); + + if (test_bit(IVTV_F_S_DMAP, &itv->v4l2.streams[type].s_flags)) { + IVTV_DEBUG(IVTV_DEBUG_ERR, + "giving up waiting for DMA pending clear\n"); + } +/* only needed if we're searching for an EOS.. currently disabled */ +#if 0 + /* only run these if we're shutting down the last cap */ + if (atomic_read(&itv->capturing) - 1 == 0) { + add_wait_queue(&itv->cap_w, &wait); + + set_current_state(TASK_INTERRUPTIBLE); + + /* wait 2s for EOS interrupt */ + while((!test_bit(IVTV_F_I_EOS, &itv->i_flags)) && + (jiffies < then + 2 * HZ)) { + schedule_timeout(HZ); + } + then = jiffies - then; + + if (!test_bit(IVTV_F_I_EOS, &itv->i_flags)) { + IVTV_DEBUG(IVTV_DEBUG_ERR, + "EOS interrupt not received! stopping anyway.\n"); + IVTV_DEBUG(IVTV_DEBUG_ERR, + "waitied %d ms: %d\n", (1000/HZ)*then); + } else { + IVTV_DEBUG(IVTV_DEBUG_ERR, + "EOS took %d ms to occur.\n",(1000/HZ)*then); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&itv->cap_w, &wait); + } +#endif + clear_bit(IVTV_F_S_OVERFLOW, &itv->v4l2.streams[type].s_flags); + clear_bit(IVTV_F_S_CAP, &itv->v4l2.streams[type].s_flags); + + atomic_dec(&itv->capturing); + if (atomic_read(&itv->capturing)) + return 0; + + /*Set the following Interrupt mask bits: 0xd8000000 */ + ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE); + IVTV_DEBUG(IVTV_DEBUG_IRQ, "IRQ Mask is now: 0x%08x\n",itv->irqmask); + + return 0; +} + +int ivtv_stop_decode(struct ivtv_open_id *id) { + struct ivtv *itv=id->itv; + u32 data[IVTV_MBOX_MAX_DATA], result; + int x; + + /* sem_lock must be held */ + IVTV_ASSERT(ivtv_sem_count(&itv->sem_lock) <= 0); + + /* FIXME set 'die' ?? */ + IVTV_DEBUG(IVTV_DEBUG_INFO, "Decoder stop.\n"); + + + /* only run these if we're shutting down the last cap */ + if (atomic_read(&itv->decoding) - 1 == 0) { +#if 0 + /* event notification (off)*/ + data[0] = 0; /* Event: 0 = audio change between stereo and mono */ + data[1] = 0; /* Enable/Disable: 0 = disabled, 1 = enabled */ + data[2] = 0x00010000; /* Bit: interrupt bit to fire */ + data[3] = -1; /* Mailbox to use: -1 = no mailbox needed */ + x = ivtv_api(itv->dec_mbox, &itv->dec_msem, + IVTV_API_DEC_EVENT_NOTIFICATION, &result, 4, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stopDEC error 1. Code %d\n",x); +#endif + + /* end_capture */ + data[0] = itv->dec_options.hide_last_frame; /* 0 = last frame, + 1 = black */ + data[1] = itv->dec_options.pts_low; /* when: pts low */ + data[2] = itv->dec_options.pts_hi; /* when: pts hi */ + x = ivtv_api(itv->dec_mbox, &itv->dec_msem, + IVTV_API_DEC_STOP_PLAYBACK, &result, 3, &data[0]); + if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stopDEC error 2. Code %d\n",x); + } + + /* FIXME turn off relevant irqmask here */ + ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_DECODE); + + /* stop decoder interrupt timeout */ + del_timer_sync(&itv->dec_timeout); + + if (test_and_clear_bit(IVTV_F_S_DMAP, &itv->v4l2.streams[id->type].s_flags)) + IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: clearing dma_pending\n"); + + /* Clean up some possibly loose-ends */ + clear_bit(IVTV_F_I_BUSY, &itv->i_flags); + atomic_dec(&itv->decoding); + wake_up(&itv->dec_master_w); + + return 0; +} + +void ivtv_dec_timeout(unsigned long arg) { + struct ivtv *itv = (struct ivtv *)arg; + + /* FIXME mpg only :/ */ + struct ivtv_v4l2_stream *stream = &itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_MPG]; + unsigned long flags; + + if (!test_bit(IVTV_F_S_DMAP, &stream->s_flags)) + return; + + IVTV_DEBUG(IVTV_DEBUG_ERR, "ivtv_dec_timeout: lost IRQ; resetting...\n"); + spin_lock_irqsave(&itv->lock, flags); + ivtv_dec_DMA_done(itv); + /* kick it off again! */ + set_bit(IVTV_F_I_NEEDS_DATA, &itv->i_flags); + ivtv_dec_sched_DMA(itv); + spin_unlock_irqrestore(&itv->lock, flags); +} + +#if 0 +static void ivtv_show_irq_status(struct ivtv* itv, u32 irqstat, u32 irqmask, u32 dmastat) { + struct ivtv_mailbox* mbox8 = &itv->dec_mbox[8]; + struct ivtv_mailbox* mbox9 = &itv->dec_mbox[9]; + +#if 0 + // Make it less verbose... + if ((irqstat & ~4) == IVTV_IRQ_DEC_VSYNC) + return; +#endif + + printk("ivtv: irqstat [ " + "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s], " + "frame %d, pts %d, scr %d, type %d, offset %08x, max %d, full %d\n", + (irqstat & IVTV_IRQ_ENC_START_CAP) ? "StartCap " : "", + (irqstat & IVTV_IRQ_ENC_EOS) ? "EndOfStream " : "", + (irqstat & IVTV_IRQ_ENC_VBI_CAP) ? "VBICap " : "", + (irqstat & IVTV_IRQ_ENC_VIM_RST) ? "VIMReset " : "", + (irqstat & IVTV_IRQ_ENC_DMA_COMPLETE) ? "EncDMAComplete " : "", + (irqstat & (1<<26)) ? "26 " : "", + (irqstat & IVTV_IRQ_DEC_COPY_PROTECT) ? "CopyProt " : "", + (irqstat & IVTV_IRQ_DEC_AUD_MODE_CHG) ? "AudioMode " : "", + (irqstat & (1<<23)) ? "23 " : "", + (irqstat & IVTV_IRQ_DEC_DATA_REQ) ? "DecDataReq " : "", + (irqstat & IVTV_IRQ_DEC_IFRAME_DONE) ? "IFrameDone " : "", + (irqstat & IVTV_IRQ_DEC_DMA_COMPLETE) ? "DecDMAComplete " : "", + (irqstat & IVTV_IRQ_DEC_VBI_RE_INSERT) ? "VBIReInsert " : "", + (irqstat & IVTV_IRQ_DEC_DMA_ERR) ? "DecDMAError " : "", + (irqstat & (1<<17)) ? "17 " : "", + (irqstat & (1<<16)) ? "16 " : "", + (irqstat & (1<<15)) ? "15 " : "", + (irqstat & (1<<14)) ? "14 " : "", + (irqstat & (1<<13)) ? "13 " : "", + (irqstat & (1<<12)) ? "12 " : "", + (irqstat & (1<<11)) ? "11 " : "", + (irqstat & IVTV_IRQ_DEC_VSYNC) ? "DecVSync " : "", + (irqstat & (1<<9)) ? "9 " : "", + (irqstat & (1<<8)) ? "8 " : "", + (irqstat & (1<<7)) ? "7 " : "", + (irqstat & (1<<6)) ? "6 " : "", + (irqstat & (1<<5)) ? "5 " : "", + (irqstat & (1<<4)) ? "4 " : "", + (irqstat & (1<<3)) ? "3 " : "", + (irqstat & (1<<2)) ? "2 " : "", + (irqstat & (1<<1)) ? "1 " : "", + (irqstat & (1<<0)) ? "0 " : "", + readl(&mbox8->data[0]), + readl(&mbox8->data[1]), + readl(&mbox8->data[3]), + readl(&mbox9->data[0]), + readl(&mbox9->data[1]), + readl(&mbox9->data[2]), + readl(&mbox9->data[3])); +} +#endif + +static irqreturn_t ivtv_irq_handler(int irq, void *dev_id, struct pt_regs *regs) { + + u32 stat = 0; + u32 combo = 0; + struct ivtv *itv=(struct ivtv *)dev_id; + + spin_lock(&itv->lock); + + /* get contents of irq status register*/ + stat = readl(itv->reg_mem + IVTV_REG_IRQSTATUS); + + combo=~itv->irqmask & stat; + + if (0 == combo) { + /* wasn't for us*/ + spin_unlock(&itv->lock); + return IRQ_NONE; + } + + /* + ivtv_show_irq_status(itv, stat, itv->irqmask, + readl(itv->reg_mem + IVTV_REG_DMASTATUS)); + */ + + IVTV_DEBUG(IVTV_DEBUG_IRQ, "======= valid IRQ bits: 0x%08x ======\n", combo); + + writel(combo, (itv->reg_mem + IVTV_REG_IRQSTATUS)); + + if (combo & IVTV_IRQ_ENC_DMA_COMPLETE) { + ivtv_DMA_done(itv); + IVTV_DEBUG(IVTV_DEBUG_IRQ, "Processed DMA-complete\n"); + } + if (combo & IVTV_IRQ_ENC_START_CAP) { + ivtv_sched_DMA(itv); + IVTV_DEBUG(IVTV_DEBUG_IRQ, "Processed enc-startcap\n"); + } + if (combo & IVTV_IRQ_ENC_EOS) { + IVTV_DEBUG(IVTV_DEBUG_IRQ, "Encoder End Of Stream\n"); + set_bit(IVTV_F_I_EOS, &itv->i_flags); + wake_up(&itv->cap_w); + } + if (combo & IVTV_IRQ_ENC_VBI_CAP) { + IVTV_DEBUG(IVTV_DEBUG_IRQ, "deb3\n"); + } + if (combo & IVTV_IRQ_ENC_VIM_RST) { + IVTV_DEBUG(IVTV_DEBUG_IRQ, "VIM Restart\n"); + } + if (combo & IVTV_IRQ_DEC_COPY_PROTECT) { + IVTV_DEBUG(IVTV_DEBUG_IRQ, "deb6\n"); + } + if (combo & IVTV_IRQ_DEC_AUD_MODE_CHG) { + IVTV_DEBUG(IVTV_DEBUG_IRQ, "deb7\n"); + } + if (combo & IVTV_IRQ_DEC_DMA_COMPLETE) { + IVTV_DEBUG(IVTV_DEBUG_IRQ, "Decoder DMA Done\n"); + ivtv_dec_DMA_done(itv); + } + if (combo & IVTV_IRQ_DEC_DATA_REQ) { + IVTV_DEBUG(IVTV_DEBUG_IRQ, "Decoder Data Request\n"); + set_bit(IVTV_F_I_NEEDS_DATA, &itv->i_flags); + ivtv_dec_sched_DMA(itv); + } + if (combo & IVTV_IRQ_DEC_IFRAME_DONE) { + IVTV_DEBUG(IVTV_DEBUG_IRQ, "deb9\n"); + } + if (combo & IVTV_IRQ_DEC_VBI_RE_INSERT) { + IVTV_DEBUG(IVTV_DEBUG_IRQ, "deb11\n"); + } + if (combo & IVTV_IRQ_DEC_DMA_ERR) { + IVTV_DEBUG(IVTV_DEBUG_IRQ, "deb12\n"); + } + if (combo & IVTV_IRQ_DEC_VSYNC) { + ivtv_irq_dec_vsync(itv); + } + /* + stat = readl(itv->reg_mem + IVTV_REG_IRQSTATUS); + IVTV_DEBUG(IVTV_DEBUG_IRQ, "IVTV IRQ STATUS REG AFTER INTERRUPT 0x%08x", stat); + if (combo & ~IVTV_IRQ_DEBUG_KLUGE) { + IVTV_DEBUG(IVTV_DEBUG_ERR, + "unknown irq 0x%08x, mask:0x%08x, combo:0x%08x\n", + stat, itv->irqmask, combo); + } + */ + spin_unlock(&itv->lock); + + return IRQ_HANDLED; +} + +static void ivtv_irq_dec_vsync(struct ivtv* itv) { + u32* data = itv->dec_mbox[IVTV_MBOX_FIELD_DISPLAYED].data; + + u32 newframe = readl(&data[0]); + u64 newpts = ((u64)readl(&data[2]) << 32) | (u64)(readl(&data[1])); + u64 newscr = ((u64)readl(&data[4]) << 32) | (u64)(readl(&data[3])); + + itv->dec_timestamp.pts = newpts; + itv->dec_timestamp.scr = newscr; + if (newframe != itv->dec_timestamp.frame) { + itv->dec_timestamp.frame = newframe; + wake_up(&itv->vsync_w); + } + + IVTV_DEBUG(IVTV_DEBUG_IRQ, "ivtv_irq_dec_vsync: frames %d, pts %ld, scr %ld\n", itv->dec_timestamp.frame, (long int)itv->dec_timestamp.pts, (long int)itv->dec_timestamp.scr); +} + +static void ivtv_show_debug_flags(struct ivtv *itv) +{ + int y; + + printk(KERN_DEBUG "ivtv: i_flags=%lx", itv->i_flags); + for (y=IVTV_DEC_STREAM_TYPE_MPG; y < itv->v4l2.streamcount; y++) + printk(", %d s_sflags=%lx", y, itv->v4l2.streams[y].s_flags); + printk("\n"); +} + +static void ivtv_DMA_done(struct ivtv *itv) { + u32 result; + int y,stmtype=-1; + struct ivtv_v4l2_stream *stream=NULL; + struct ivtv_buffer *buf; + + IVTV_DEBUG(IVTV_DEBUG_INFO, "DMA Done tasklet\n"); + + for (y=0; y < itv->v4l2.streamcount; y++) { + if (test_and_clear_bit(IVTV_F_S_DMAP, &itv->v4l2.streams[y].s_flags)) { + stmtype = y; + break; + } + } + + if (stmtype < 0) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "Got DMA-done, but not expecting one\n"); + ivtv_show_debug_flags(itv); + return; + } + + stream = &itv->v4l2.streams[stmtype]; + + /* check DMA status register */ + result = readl(itv->reg_mem + IVTV_REG_DMASTATUS); + + if (!(result & IVTV_DMA_SUCCESS)) { + if (result & IVTV_DMA_WRITE_ERR) + IVTV_DEBUG(IVTV_DEBUG_ERR, "DMA write error. Result=0x%08x\n", result); + if (result & IVTV_DMA_READ_ERR) + IVTV_DEBUG(IVTV_DEBUG_ERR, "DMA read error. Result=0x%08x\n",result); + return; + } + + /* DMA was fine if we made it this far */ + + /* remove from dma_pending queue */ + while ((buf = __ivtv_deq_buf(&stream->dma_q))) { + IVTV_ASSERT(buf->dma_handle != IVTV_DMA_UNMAPPED); + pci_unmap_single(itv->dev, buf->dma_handle, + IVTV_DMA_BUF_SIZE, PCI_DMA_TODEVICE); + buf->dma_handle = IVTV_DMA_UNMAPPED; + /* byteswap ABCD -> DCBA for MPG data*/ + if (stmtype == 0) { + for (y = 0; y < buf->buffer.bytesused; y += 4) { + swab32s( (u32 *)((u32)buf->buffer.m.userptr + y)); + } + } + /* put in the 'done' queue */ + __ivtv_enq_buf(&stream->full_q, buf); + } + + IVTV_DEBUG(IVTV_DEBUG_INFO, "DMA Done tasklet5\n"); + /*wake up client*/ + wake_up(&stream->waitq); + IVTV_DEBUG(IVTV_DEBUG_INFO, "DMA Done tasklet6\n"); +} + +/* must hold itv->lock */ +static int ivtv_ignore_DMA_req(struct ivtv *itv, u32 type) { + u32 data[IVTV_MBOX_MAX_DATA], result; + int ret = 0; + + data[0] = 0; + data[1] = 0; /* ACK the DMA and continue */ + data[2] = type; // AEW - API docs say type goes here + if (ivtv_api(itv->enc_mbox, &itv->enc_msem, + IVTV_API_SCHED_DMA_TO_HOST, &result, 3, &data[0])) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "error sending DMA info\n"); + ret = -EIO; + } + + if (!ret) + set_bit(IVTV_F_S_DMAP, &itv->v4l2.streams[type].s_flags); + + return ret; +} + + +/* FIXME this function is getting too long. split it up? */ +static void ivtv_sched_DMA(struct ivtv *itv) { + u32 data[IVTV_MBOX_MAX_DATA], result; + u32 type, size, offset; + u32 UVsize=0, UVoffset=0, pts_stamp=0; + struct ivtv_v4l2_stream *st; + int x, bufs_needed; + int uvflag=0; + struct ivtv_buffer *buf; + LIST_HEAD(free_list); + long sequence; + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Sched DMA tasklet\n"); + + /* Get DMA destination and size arguments from card*/ + x = ivtv_api_getresult_nosleep(&itv->enc_mbox[9], &result, &data[0]); + if (x) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "error:%d getting DMA info\n", x); + return; + } + + type = data[0]; + + /* FIXME should check for null on the stream element */ + if (itv->v4l2.streamcount <= type) { + IVTV_DEBUG(IVTV_DEBUG_ERR,"No stream handler for type %d\n", type); + ivtv_ignore_DMA_req(itv, type); + return; + } + + switch (type) { + case 0: /* MPEG */ + offset = data[1]; + size = data[2]; + IVTV_DEBUG(IVTV_DEBUG_INFO, + "DMA/MPG type 0x%08x,size 0x%08x,offset 0x%08x\n", + type, size, offset); + bufs_needed = ivtv_ceil(size, IVTV_DMA_BUF_SIZE); + break; + case 1: /* YUV */ + offset = data[1]; + size = data[2]; + UVoffset = data[3]; + UVsize = data[4]; + pts_stamp = data[6]; + IVTV_DEBUG(IVTV_DEBUG_INFO, + "DMA/YUV type 0x%08x,Ysize 0x%08x,Yoffset 0x%08x," + "UVsize 0x%08x,UVoffset 0x%08x,PTS 0x%08x\n", + type, size, offset, UVsize, UVoffset, pts_stamp); + bufs_needed = ivtv_ceil(size, IVTV_DMA_BUF_SIZE); + bufs_needed += ivtv_ceil(UVsize, IVTV_DMA_BUF_SIZE); + break; + + case 2: /* PCM (audio) */ + offset = data[1]; + size = data[2]; + pts_stamp = data[6]; + IVTV_DEBUG(IVTV_DEBUG_INFO, + "DMA/PCM type 0x%08x,size 0x%08x,offset 0x%08x " + "PTS 0x%08x\n", type, size, offset, pts_stamp); + bufs_needed = ivtv_ceil(size, IVTV_DMA_BUF_SIZE); + ivtv_ignore_DMA_req(itv, type); + return; + case 3: /* VBI */ + offset = data[1]; + size = data[2]; + bufs_needed = ivtv_ceil(size, IVTV_DMA_BUF_SIZE); + IVTV_DEBUG(IVTV_DEBUG_ERR, + "DMA/VBI type 0x%08x, size 0x%08x, offset 0x%08x" + "EXPERIMENTAL\n", type, size, offset); + break; + default: + IVTV_DEBUG(IVTV_DEBUG_ERR, + "DMA/UNKNOWN type 0x%08x, NOT SUPPORTED\n", type); + ivtv_ignore_DMA_req(itv, type); + return; + } + + if (bufs_needed > SGarray_size) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "INTERNAL ERROR: ivtv_sched_DMA_tasklet: " + "bufs_needed = %d but SGarray_size = %d\n", + bufs_needed, SGarray_size); + return; + } + + st = &itv->v4l2.streams[type]; + + /* gather the needed buffers first, so we don't have to bail + * in mid-air. put them on a list on the stack */ + for (x = 0; x < bufs_needed; x++) { + buf = __ivtv_deq_buf(&st->free_q); + if (!buf) + break; + + list_add_tail(&buf->list, &free_list); + } + + /* damn, failed */ + if (x < bufs_needed) { + IVTV_DEBUG(IVTV_DEBUG_INFO, "DMA buffer DeQueue failed! got %d, want %d\n", x + 1, bufs_needed + 1); + IVTV_DEBUG(IVTV_DEBUG_INFO, "SCHED: free_q: %d elements\n", st->free_q.elements); + IVTV_DEBUG(IVTV_DEBUG_INFO, "SCHED: dma_q: %d elements\n", st->dma_q.elements); + IVTV_DEBUG(IVTV_DEBUG_INFO, "SCHED: full_q: %d elements\n", st->full_q.elements); + while (!list_empty(&free_list)) { + buf = list_entry(free_list.next, struct ivtv_buffer, list); + list_del_init(&buf->list); + __ivtv_enq_buf(&st->free_q, buf); + } + /* mark overflow condition, next free will restart dma req */ + set_bit(IVTV_F_S_OVERFLOW, &st->s_flags); + return; + } + + /* increment the sequence # */ + sequence = ++st->seq; + + for (x = 0; x < bufs_needed; x++) { + IVTV_DEBUG(IVTV_DEBUG_INFO, "size: %d 0x%08x\n", size, size); + + if ((size == 0) && (type == 1) && (uvflag == 0)) { /* YUV */ + /* process the UV section */ + offset = UVoffset; + size = UVsize; + uvflag = 1; + } + + /* extract the buffers we procured earlier */ + buf = list_entry(free_list.next, struct ivtv_buffer, list); + list_del_init(&buf->list); + + buf->readpos = 0; + buf->buffer.index = x; + buf->buffer.sequence = sequence; + buf->ts = jiffies; + + if (size < (IVTV_DMA_BUF_SIZE & 0xffffff00)) { + buf->buffer.bytesused = size; + /* bytecount must be multiple of 0x100 (256) */ + itv->SGarray[x].size = + (0xffffff00 & (buf->buffer.bytesused + 0xFF)); + size = 0; + } + else { + buf->buffer.bytesused = IVTV_DMA_BUF_SIZE; + itv->SGarray[x].size = IVTV_DMA_BUF_SIZE; + size -= IVTV_DMA_BUF_SIZE; + } + + itv->SGarray[x].src = offset; + offset += buf->buffer.bytesused; + + /* unfortunately the pci dma api wasn't properly defined + * for handling mapping errors (running out of iommu space, + * for instance). 0 can be a valid bus address. */ + buf->dma_handle = pci_map_single(itv->dev, + (void *)buf->buffer.m.userptr, + buf->buffer.bytesused, + PCI_DMA_FROMDEVICE); + + itv->SGarray[x].dst = buf->dma_handle; + + /* FIXME need to add pts stuff, index, etc. */ + __ivtv_enq_buf(&st->dma_q, buf); + } + + /* This should wrap gracefully */ + /* FIXME obselete? */ + itv->trans_id++; + + itv->SGarray[bufs_needed-1].size |= 0x80000000; + + /*FIXME unlock */ + + data[0] = itv->SG_handle; + /* 3 elements * 4 bytes per element * num_elements */ + data[1] = (3 * 4 * bufs_needed); + data[2] = type; + data[3] = 0x0; + + for (x = 0; x < bufs_needed; x++) + IVTV_DEBUG(IVTV_DEBUG_INFO, "SGarray[%d]: 0x%08x, 0x%08x 0x%08x\n", + x, itv->SGarray[x].src, itv->SGarray[x].dst, itv->SGarray[x].size); + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Sched dma: addr: 0x%08x, array_size 0x%08x," + " type 0x%08x\n", data[0], data[1], data[2]); + + set_bit(IVTV_F_S_DMAP, &st->s_flags); + ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_SCHED_DMA_TO_HOST, + &result, 4, &data[0]); +} + +static void ivtv_sched_DMA_tasklet(unsigned long arg) { + struct ivtv *itv = (struct ivtv *) arg; + unsigned long flags; + + spin_lock_irqsave(&itv->lock, flags); + ivtv_sched_DMA(itv); + spin_unlock_irqrestore(&itv->lock, flags); +} + +/* FIXME this function does way more than it should */ +static int __devinit ivtv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) { + int retval=0; + unsigned char pci_latency; + struct ivtv *itv; + struct video_channel v; + unsigned long freq; + u16 cmd; + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Found card #%d\n", ivtv_cards_active); + + spin_lock_irq(&ivtv_lock); + + /* Make sure we've got a place for this card */ + if (ivtv_cards_active == IVTV_MAX_CARDS) { + IVTV_DEBUG(IVTV_DEBUG_ERR, ":Maximum # of cards already detected (%d).\n", ivtv_cards_active); + spin_unlock_irq(&ivtv_lock); + return -ENOMEM; + } + + itv = &ivtv_cards[ivtv_cards_active]; + itv->dev = dev; + itv->num = ivtv_cards_active; + + ivtv_cards_active++; + + spin_unlock_irq(&ivtv_lock); + + /* always remember what you think the irq mask should be */ + itv->irqmask = 0; + +#ifdef YUV_FIXUP + itv->options.yuv_fixup = yuv_fixup; +#endif + itv->options.dec_yuv_buffers = dec_yuv_buffers; + itv->options.dec_mpg_buffers = mpg_buffers; + itv->options.yuv_buffers = yuv_buffers; + itv->options.mpg_buffers = mpg_buffers; + itv->options.vbi_buffers = vbi_buffers; + itv->options.num_devices = num_devices; + itv->options.dec_mpg_qlen = dec_mpg_qlen; + itv->options.dec_yuv_qlen = dec_yuv_qlen; + + /* Set FrameBuffer-ID to invalid */ + itv->fb_id = -1; + + switch (dev->subsystem_device) { + case IVTV_PCI_ID_250_V2: + case IVTV_PCI_ID_250_V4: + IVTV_DEBUG(IVTV_DEBUG_ERR, "Found an iTVC16 based chip\n"); + itv->card_type = IVTV_250_V2; + break; + case IVTV_PCI_ID_350_V1: + case IVTV_PCI_ID_350_V2: + IVTV_DEBUG(IVTV_DEBUG_ERR, "Found an iTVC15 based chip\n"); + itv->card_type = IVTV_350_V1; + break; + case IVTV_PCI_ID_250_V1: + case IVTV_PCI_ID_250_V3: + IVTV_DEBUG(IVTV_DEBUG_ERR, "Found an iTVC15 based chip\n"); + itv->card_type = IVTV_250_V1; + break; + default: /* Default to 250 v1 style */ + IVTV_DEBUG(IVTV_DEBUG_ERR, "Found an unknown chip, treating it like an iTVC15\n"); + itv->card_type = IVTV_250_V1; + break; + } + + init_MUTEX(&itv->enc_msem); + init_MUTEX(&itv->dec_msem); + init_MUTEX(&itv->sem_lock); + spin_lock_init(&itv->lock); + itv->base_addr=pci_resource_start(dev,0); + itv->enc_mbox = NULL; + itv->dec_mbox = NULL; + itv->io_mem = NULL; + itv->reg_mem = NULL; + itv->i_flags = 0; + atomic_set(&itv->capturing, 0); + atomic_set(&itv->decoding, 0); + itv->user_dma_to_device_state = NULL; + + /* Prepare list for action! */ + INIT_LIST_HEAD(&itv->client_list); + + init_waitqueue_head(&itv->cap_w); + init_waitqueue_head(&itv->vsync_w); + init_waitqueue_head(&itv->dec_master_w); + init_timer(&itv->dec_timeout); + itv->dec_timeout.function = ivtv_dec_timeout; + itv->dec_timeout.data = (unsigned long)itv; + + tasklet_init(&itv->dma_sched_tq, ivtv_sched_DMA_tasklet, (unsigned long) itv); + + IVTV_DEBUG(IVTV_DEBUG_INFO, "base addr: 0x%08x\n", itv->base_addr); + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Enabling pci device\n"); + if (pci_enable_device(dev)) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "Can't enable device %d!\n",itv->num); + retval = -EIO; + goto err; + } + if (pci_set_dma_mask(dev, 0xffffffff)) { + IVTV_DEBUG(IVTV_DEBUG_ERR, KERN_WARNING "No suitable DMA available on card %d.\n", + itv->num); + retval = -EIO; + goto err; + } + if (!request_mem_region(pci_resource_start(dev,0), IVTV_IOREMAP_SIZE, IVTV_DEVNAME )) { + retval = -EIO; + goto err; + } + + /* Check for bus mastering */ + pci_read_config_word(dev, PCI_COMMAND, &cmd); + if (! (cmd & PCI_COMMAND_MASTER)) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "Bus Mastering is not enabled\n"); + retval = -ENXIO; + goto free_mem; + } + else { + IVTV_DEBUG(IVTV_DEBUG_INFO, "Bus Mastering Enabled."); + } + + pci_read_config_byte(dev, PCI_CLASS_REVISION, &itv->card_rev); + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency); + + IVTV_DEBUG(IVTV_DEBUG_INFO, "%d (rev %d) at %02x:%02x.%x, ", + itv->dev->device, itv->card_rev, dev->bus->number, + PCI_SLOT(dev->devfn),PCI_FUNC(dev->devfn)); + IVTV_DEBUG(IVTV_DEBUG_INFO, " irq: %d, latency: %d, memory: 0x%lx\n", + itv->dev->irq, pci_latency, (unsigned long)itv->base_addr); + + /*map io memory*/ + IVTV_DEBUG(IVTV_DEBUG_INFO, "attempting ioremap at 0x%08x len 0x%08x\n", + itv->base_addr, IVTV_ENCDEC_SIZE); + itv->io_mem = ioremap_nocache(itv->base_addr,IVTV_ENCDEC_SIZE); + if (!itv->io_mem) { + IVTV_DEBUG(IVTV_DEBUG_ERR, IVTV_IOREMAP_ERROR); + retval = -ENOMEM; + goto free_mem; + } + + /*map registers memory*/ + IVTV_DEBUG(IVTV_DEBUG_INFO, "attempting ioremap at 0x%08x len 0x%08x\n", + itv->base_addr+IVTV_REG_OFFSET, IVTV_REG_SIZE); + itv->reg_mem = ioremap_nocache(itv->base_addr+IVTV_REG_OFFSET,IVTV_REG_SIZE); + if (!itv->reg_mem) { + IVTV_DEBUG(IVTV_DEBUG_ERR, IVTV_IOREMAP_ERROR); + retval = -ENOMEM; + goto free_io; + } + + IVTV_DEBUG(IVTV_DEBUG_IRQ, "Masking interrupts\n"); + /* clear interrupt mask, effectively disabling interrupts */ + ivtv_set_irq_mask(itv, 0xffffffff); + + retval = request_irq(itv->dev->irq, ivtv_irq_handler, + SA_SHIRQ | SA_INTERRUPT,IVTV_DEVNAME,(void *)itv); + if (retval) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "failed to register irq %d\n", retval); + goto free_io; + } + + /* save itv in the pci struct for later use*/ + pci_set_drvdata(dev,itv); + + /* active i2c */ + itv->i2c_command=(I2C_TIMING); + IVTV_DEBUG(IVTV_DEBUG_INFO, "activating i2c..\n"); + if (init_ivtv_i2c(itv)) { + IVTV_DEBUG(IVTV_DEBUG_INFO, "i2c died! unloading\n"); + goto free_irq; + } + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Active card count: %d.\n", ivtv_cards_active); + + /*write firmware */ + retval = ivtv_firmware_init(itv); + if (retval) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "Error initializing.\n"); + retval = -ENOMEM; + goto free_i2c; + } + + /*search for encoder/decoder mailboxes*/ + IVTV_DEBUG(IVTV_DEBUG_INFO, "About to search for mailboxes\n"); + ivtv_find_firmware_mailbox(itv); + + if ((itv->enc_mbox == NULL) && (itv->dec_mbox ==NULL)) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "Error locating firmware.\n"); + retval = -ENOMEM; + goto free_i2c; + } + + /*releasing unneeded iomapped memory (encoder+decoder)*/ + //iounmap(itv->io_mem); + + /*remapping only needed io memory (mailboxes) */ + itv->enc_mbox = ioremap(itv->base_addr+((u8 *)itv->enc_mbox - (u8 *)itv->io_mem), + IVTV_MBOX_MAX_BOXES * IVTV_MBOX_SIZE); + itv->dec_mbox = ioremap(itv->base_addr+((u8 *)itv->dec_mbox - (u8 *)itv->io_mem), + IVTV_MBOX_MAX_BOXES * IVTV_MBOX_SIZE); + + /* clearing pointers */ + //itv->io_mem = NULL ; + + /*Try and get firmware versions */ + IVTV_DEBUG(IVTV_DEBUG_INFO, "Getting firmware version..\n"); + retval = ivtv_firmware_versions(itv); + if (retval) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "error %d getting version #!\n", retval); + goto free_i2c; + } + + /* Allocate scatter-gather arrays*/ + + //++MTY NASTY little bug!!! If user changes dec_mpg_buffers, + // memory corruption results with the old way! + + /* encoder */ + itv->SGarray = (struct ivtv_SG_element *) + kmalloc(sizeof(struct ivtv_SG_element) * + SGarray_size, + GFP_KERNEL); + if (!(itv->SGarray)) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "Error allocating SGarray[].\n"); + retval = -ENOMEM; + goto free_i2c; + } + + itv->SG_handle = pci_map_single(itv->dev, + (void *)&itv->SGarray[0], + (sizeof(struct ivtv_SG_element) * + SGarray_size), + PCI_DMA_TODEVICE); + + if (itv->card_type == IVTV_350_V1) { + /* decoder */ + itv->DSGarray = (struct ivtv_SG_element *) + kmalloc(sizeof(struct ivtv_SG_element) * + DSGarray_size, GFP_KERNEL); + if (!(itv->DSGarray)) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "Error allocating DSGarray[].\n"); + retval = -ENOMEM; + goto free_sg; + } + + itv->DSG_handle = pci_map_single(itv->dev, + (void *)&itv->DSGarray[0], + (sizeof(struct ivtv_SG_element) * + DSGarray_size), PCI_DMA_TODEVICE); + } + + /* FIXME -temporary- setup tuner */ + IVTV_DEBUG(IVTV_DEBUG_INFO, "Setting Tuner\n"); + + if( tuner > -1 ) { + ivtv_call_i2c_client(itv, + IVTV_TUNER_I2C_ADDR, + TUNER_SET_TYPE, + &tuner ); + } + + /* set the standard */ + if (!ivtv_pal) + v.norm = VIDEO_MODE_NTSC; + else + v.norm = VIDEO_MODE_PAL; + + ivtv_call_i2c_client(itv,IVTV_TUNER_I2C_ADDR, VIDIOCSCHAN,&v); + + if (!ivtv_pal) { + /* set the channel */ + freq = 1076; /* ch. 4 67250*16/1000 */ + ivtv_call_i2c_client(itv,IVTV_TUNER_I2C_ADDR,VIDIOCSFREQ,&freq); + } + + retval = ivtv_v4l2_setup(itv); + if (retval) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "Problem starting v4l2\n"); + goto ivtv_v4l2_fail; + } + + return 0; + +ivtv_v4l2_fail: + pci_unmap_single(itv->dev, + itv->DSG_handle, + (sizeof(struct ivtv_SG_element) * + DSGarray_size), + PCI_DMA_TODEVICE); + kfree(itv->DSGarray); +free_sg: + pci_unmap_single(itv->dev, + itv->SG_handle, + (sizeof(struct ivtv_SG_element) * + SGarray_size), + PCI_DMA_TODEVICE); + kfree(itv->SGarray); +free_i2c: + exit_ivtv_i2c(itv); +free_irq: + free_irq(itv->dev->irq, (void *)itv); +free_io: + ivtv_iounmap(itv); +free_mem: + release_mem_region(pci_resource_start(itv->dev,0), IVTV_IOREMAP_SIZE); +err: + IVTV_DEBUG(IVTV_DEBUG_ERR, "Error %d on init\n", retval); + + spin_lock_irq(&ivtv_lock); + ivtv_cards_active--; + spin_unlock_irq(&ivtv_lock); + return retval; +} + +static void ivtv_remove(struct pci_dev *pci_dev) { + struct ivtv *itv=pci_get_drvdata(pci_dev); + int x = 0; + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Disabling interrupts!\n"); + ivtv_set_irq_mask(itv, 0xffffffff); + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Stopping thread\n"); + atomic_set(&itv->decoding, 0); + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Stopping card parts\n"); + x = ivtv_stop_firmware(itv); + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Freeing buffers\n"); + + for (x = 0; x < itv->v4l2.streamcount; x++) { + IVTV_DEBUG(IVTV_DEBUG_INFO,"Freeing stream %d!\n", x); + ivtv_free_queue(&itv->v4l2.streams[x].free_q); + ivtv_free_queue(&itv->v4l2.streams[x].full_q); + ivtv_free_queue(&itv->v4l2.streams[x].dma_q); + } + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Unregistering v4l devices!\n"); + ivtv_v4l2_cleanup(itv); + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Freeing dma resources\n"); + + pci_unmap_single(itv->dev, itv->SG_handle, + (sizeof(struct ivtv_SG_element) * SGarray_size), + PCI_DMA_TODEVICE); + kfree(itv->SGarray); + + pci_unmap_single(itv->dev, itv->DSG_handle, + (sizeof(struct ivtv_SG_element) * DSGarray_size), + PCI_DMA_TODEVICE); + kfree(itv->DSGarray); + + exit_ivtv_i2c(itv); + + IVTV_DEBUG(IVTV_DEBUG_INFO, "releasing irq\n"); + free_irq(itv->dev->irq, (void *)itv); + + if (itv->dev) { + ivtv_iounmap(itv); + } + + IVTV_DEBUG(IVTV_DEBUG_INFO, "releasing mem\n"); + if (itv) + release_mem_region(pci_resource_start(itv->dev,0), IVTV_IOREMAP_SIZE); + + /* FIXME free v4l2 stuff! */ + /* FIXME am i leaking kernel mem? */ + +} + +/* define a pci_driver for card detection */ +static struct pci_driver ivtv_pci_driver = { + name: "ivtv: iTVC15/16 mpg2 encoder card", + id_table: ivtv_pci_tbl, + probe: ivtv_probe, + remove: ivtv_remove, +}; + +#ifdef YUV_FIXUP +static int ivtv_YUV_fixup(struct ivtv_v4l2_stream *st, int count, + char *ubuf, struct ivtv_buffer *buf) { +/* + * int count = # of bytes to transfer to client + * st->ubytes = # of bytes written this frame + * ubuf = buffer to write to (user's buffer) + * buf = read buffer + * + */ + int src_width=720; /* all known formats have src width of 720 */ + int Hoff, Voff; /* collectors for offsets to read position */ + int width, height; /* resolution of the capture stream */ + int curline; /* vertical line currently being processed */ + int maxline; /* height of combined frame */ + int cur_m_block; /* current horizontal offset of working mblock in this row */ + int maxblock; /* # of macroblocks in a row */ + int Hbytes; /* # of bytes to write to user this time around */ + int retval=0; /* accumulator for total bytes written */ + int start; /* position in buf to read from */ + int buf_start; /* byte offset of first byte in this *buf */ + + height = st->format.fmt.pix.height; + width = st->format.fmt.pix.width; + maxblock = (width + 0xf) >> 4; + maxline = (int)(1.5 * height); /* 1 for Y, .5 for UV */ + /* Offset is always bufsize * buffer index + buf_start = (st->ubytes - buf->readpos); tested/works */ + + buf_start = IVTV_DMA_BUF_SIZE * buf->buffer.index; + + /* FIXME it may not be possible to get YUV width > 720 */ + // if (width > src_width) src_width=width; + + curline = (int) (st->ubytes / width); + + while (curline < maxline) { +// printk(" cl: %d, ml: %d\n", curline, maxline); + Voff = 16 * (curline & 0xf) + /* Voffset within MBlock */ + ((curline & 0xfff0) * src_width); /* Voffset of Mblock */ + + cur_m_block = (st->ubytes - (curline * width)) >> 4; + +/* printk("voff %d, macroVoff %d, Voff %d, cmb %d\n", (16 * (curline & 0xf)), + ((curline & 0xff0) * src_width), Voff, cur_m_block); +*/ + + while ((cur_m_block < maxblock) && (count > 0)) { + Hoff = (cur_m_block * 256) + /* mblock offset within line */ + /* Hoffset within mblock, usually 0 */ + ((st->ubytes - (curline * width)) & 0xf); + Hbytes = 16 - ((st->ubytes - (curline * width)) & 0xf); + + if (Hbytes > count) Hbytes = count; + + start = Hoff + Voff; + + if (copy_to_user((char *)((u32)ubuf + retval), + (u32 *)((u32)buf->buffer.m.userptr + + (start - buf_start)), + Hbytes)) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "copy to user failed\n"); + return -EFAULT; + } + + count -= Hbytes; + retval += Hbytes; + st->ubytes += Hbytes; + + cur_m_block++; + } + + /* if user can't handle anymore data or buffer empty */ + curline++; + if ((count == 0) ) /*|| ((curline * src_width) % IVTV_DMA_BUF_SIZE) == 0)*/ + return retval; + } + + /* FIXME i don't think you should ever get here */ + IVTV_DEBUG(IVTV_DEBUG_ERR, "You've just sailed off the edge of this function\n"); + return retval; +} +#endif + +long ivtv_read(struct ivtv_open_id *id, char *ubuf, size_t count, int block) { + int x, sleepctr, datalen, retval=0, freed=0; + struct ivtv *itv = id->itv; + size_t newcount; + unsigned long tid; + struct ivtv_buffer *buf; + struct ivtv_v4l2_stream *st=&itv->v4l2.streams[id->type]; + DECLARE_WAITQUEUE(wait, current); + + IVTV_DEBUG(IVTV_DEBUG_INFO, " Read stream.. \n"); + + if (atomic_read(&itv->capturing) == 0 && (st->id == -1)) { + IVTV_DEBUG(IVTV_DEBUG_ERR, + "Stream not initialized before read(shouldn't happen)\n"); + return -EIO; + } + + /* FIXME find a way to gracefully exit capture */ + + sleepctr = retval = 0; + buf = NULL; + + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&st->waitq, &wait); + do { + if ((itv->trans_id == 0) && (sleepctr >= IVTV_MAX_DATA_SLEEP)) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "Timeout waiting for data!\n"); + retval = -EIO; + break; + } + + buf = ivtv_deq_peek_head(itv, &st->full_q); + if (buf) { + break; + } else { + + /* Done capturing? */ + if (!test_bit(IVTV_F_S_CAP, &st->s_flags)) { + IVTV_DEBUG(IVTV_DEBUG_INFO, + "No more data to send, returning 0\n"); + set_current_state(TASK_RUNNING); + remove_wait_queue(&st->waitq, &wait); + return 0; + } + } + + if (!block) { + retval = -EAGAIN; + break; + } + + ivtv_sleep_timeout(IVTV_SLEEP_WAIT); + + if (signal_pending(current)) + retval = -ERESTARTSYS; + + sleepctr++; + } while (!retval); + + set_current_state(TASK_RUNNING); + remove_wait_queue(&st->waitq, &wait); + + /* an error (or signal) occured */ + if (retval) { + return retval; + } + + /* Skip the first 4 bytes of mpg streams to help out + * finicky decoders.. but not for iTVC16 */ + if ((id->type == 0) && (itv->first_read == 1) && + (itv->card_type != IVTV_250_V2)) { + for( x = 0; x < buf->buffer.bytesused-4; x++ ) { + unsigned char *p; + itv->first_read = 0; + p = (unsigned char *) buf->buffer.m.userptr + + buf->readpos + x; + if( !p[0] && !p[1] && p[2] == 1 ) { + IVTV_DEBUG(IVTV_DEBUG_INFO, + "Stripping first 4 bytes\n"); + buf->buffer.bytesused -= x; + buf->readpos += x; + break; + } + } + } + + /* data ready */ + /* copy it to the client */ + while ((count > 0) && (buf->buffer.bytesused > 0)) { + newcount = count; + datalen = buf->buffer.bytesused; + + IVTV_DEBUG(IVTV_DEBUG_INFO, "datalen 0x%08x\n", datalen); + + if (newcount > datalen) + newcount = datalen; + +#ifdef YUV_FIXUP + if ((id->type == 1) && (itv->options.yuv_fixup)) { + newcount = ivtv_YUV_fixup(st,newcount,ubuf+retval,buf); + if (newcount < 0) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "Error fixing up YUV!\n"); + return newcount; + } + } else { +#endif + if (copy_to_user((char *)((u32)ubuf+retval), + (u32 *)((u32)buf->buffer.m.userptr + + buf->readpos), newcount)) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "copy to user failed\n"); + return -EFAULT; + } +#ifdef YUV_FIXUP + } +#endif + + buf->readpos += newcount; + retval += newcount; + count -= newcount; + buf->buffer.bytesused -= newcount; + IVTV_DEBUG(IVTV_DEBUG_INFO, + "new datalen 0x%08x\n", buf->buffer.bytesused); + + /* if buffer is empty or we've read the whole frame */ + if ((buf->buffer.bytesused == 0)) { + ivtv_move_buf(itv, &st->full_q, &st->free_q, buf); + freed++; + + buf = ivtv_deq_peek_head(itv, &st->full_q); + if (buf) { + tid = buf->buffer.sequence; + if (buf->buffer.sequence != tid) { + /* end of frame! */ + st->ubytes = 0; + break; + } + } else { + /* user wanted more than we had. Since + * queues are filled in irq time, + * that means end of frame */ + st->ubytes = 0; + break; + } + } + } /* end of while */ + + /* if we put some buffers back in the free queue, kick off dma + * scheduling if card was stopped due to overflow before */ + if (freed && test_and_clear_bit(IVTV_F_S_OVERFLOW, &st->s_flags)) { + spin_lock_irq(&itv->lock); + ivtv_sched_DMA(itv); + spin_unlock_irq(&itv->lock); + } + + /*FIXME unlock */ + if (retval != 0) { + IVTV_DEBUG(IVTV_DEBUG_INFO, "Returning %d\n", retval); + return retval; + } + + /* Shouldn't ever get here */ + return -EIO; +} + +static void ivtv_swap_copy(const char *buf, const char *ubuf, size_t count) { + u32 *src,*dst; + + src=(u32 *)ubuf; + dst=(u32 *)buf; + +#ifdef CONFIG_X86 + while ((u32)src <= (u32)ubuf + count) { /* byteswap while copying */ + __asm__ __volatile__ ("bswap %0" : + "=r" (*dst) : + "0" (*src) ); + src++;dst++; + } +#else + { + int y; + /* Old slow memcpy then swab */ + memcpy((void *)buf,(void *)ubuf,count); + for (y = 0; y < count; y += 4) { + swab32s( (u32 *)((u32)buf + y)); + } + } +#endif +} + +static int ivtv_fill_dec_buffers(struct ivtv_open_id *id, const char *ubuf, + size_t count, int block) { + struct ivtv *itv = id->itv; + struct ivtv_v4l2_stream *stream=&itv->v4l2.streams[id->type]; + struct ivtv_buffer *buf; + int copybytes=0, bytesread=0, retval=0; + + IVTV_DEBUG(IVTV_DEBUG_INFO, "ivtv_fill_dec_buffers, %d bytes\n", count); + + /* Read what the user gives us. queue it for DMA after each buffer + * also enqueue partly-full buffers. */ + + IVTV_DEBUG(IVTV_DEBUG_INFO, + "DEC: free_q: %d elements\n", stream->free_q.elements); + IVTV_DEBUG(IVTV_DEBUG_INFO, + "DEC: dma_q: %d elements\n", stream->dma_q.elements); + IVTV_DEBUG(IVTV_DEBUG_INFO, + "DEC: full_q: %d elements\n", stream->full_q.elements); + + /* FIXME will only do one write. Has underlying code to handle more + * than one, just need loop control logic for it, if it's + * deemed necessary. */ + while (bytesread == 0) { + DECLARE_WAITQUEUE(wait, current); + unsigned long flags; + + buf = NULL; + add_wait_queue(&stream->waitq, &wait); + do { + set_current_state(TASK_INTERRUPTIBLE); + buf = ivtv_deq_peek_head(itv, &stream->free_q); + if (buf) + break; + + if (!block) { + retval = -EAGAIN; + break; + } + + schedule(); + + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + + spin_lock_irqsave(&itv->lock, flags); + ivtv_dec_sched_DMA(id->itv); + spin_unlock_irqrestore(&itv->lock, flags); + } while (!buf); + set_current_state(TASK_RUNNING); + remove_wait_queue(&stream->waitq, &wait); + + if (retval) + return retval; + + /* bytes left to send > free bytes in current buffer */ + if ((count - bytesread) > + (IVTV_DMA_DEC_BUF_SIZE - buf->buffer.bytesused)) { + copybytes = IVTV_DMA_DEC_BUF_SIZE - buf->buffer.bytesused; + } else { + copybytes = count - bytesread; + } + + /* copy data */ + /* FIXME */ + IVTV_DEBUG(IVTV_DEBUG_INFO, "copying %d bytes to 0x%08x" + " (buffer free = %d)\n", + copybytes,(int)(buf->buffer.m.userptr + buf->buffer.bytesused), + (int)(IVTV_DMA_DEC_BUF_SIZE - buf->buffer.bytesused)); + + ivtv_swap_copy((char *)(buf->buffer.m.userptr+buf->buffer.bytesused), + (char *)((u32)ubuf + bytesread),copybytes); + + bytesread += copybytes; + buf->buffer.bytesused += copybytes; + + /* enq buffer when full */ + if (buf->buffer.bytesused == IVTV_DMA_DEC_BUF_SIZE) + ivtv_move_buf(itv,&stream->free_q,&stream->full_q,buf); + } + + return bytesread; +} + +/* + * Schedule host -> hardware DMA of one buffer from the stream (MPEG or YUV) + * with the most recent request for more data, but only if dec->dec_needs_data + * is set. + * + * This code can be called from both interrupt context as well as userspace; + * it does the right things in either case. If called from userspace, it may + * block only when the same call is in progress in interupt context (since + * interrupt context is not allowed to block.) + * + * @returns 0 if the buffer was queued to dma_q and the DMA was initiated. + * + * -EAGAIN if either the full_q queue is empty or the function is + * already in progress in interrupt context. + * + * -ENOSPC if there is no space remaining in the hardware's buffer. + * This should never happen if proper flow control is used. + * + * -EINVAL if the most recent "data needed" interrupt requested an + * unknown stream type (should really never happen!) + * + * -EBUSY if a DMA on the same queue is already in progress (should + * never happen) + * + */ +static void ivtv_dec_sched_DMA(struct ivtv *itv) { + int ret=0, x=0, bytes_written=0, type=0, max=2; + struct ivtv_buffer *buf; + struct ivtv_v4l2_stream *stream=NULL; + u32 data[IVTV_MBOX_MAX_DATA], result; + u32 mem_offset, mem_size, hw_stream_type, buffer_bytes; + + IVTV_DEBUG(IVTV_DEBUG_INFO, "ivtv_dec_sched_DMA\n"); + + /* fancy way of saying "if (ivtv->dec_needs_data == 0)" */ + if (!test_bit(IVTV_F_I_NEEDS_DATA, &itv->i_flags)) { + IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: no data needed\n"); + return; + } + + /* Get Card Mem Dst address from mailbox 10 */ + ret = ivtv_api_getresult_nosleep(&itv->dec_mbox[9], &result, &data[0]); + IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: Mailbox 10: 0x%08x 0x%08x 0x%08x 0x%08x\n", + data[0],data[1],data[2],data[3]); + + hw_stream_type = data[0]; + + switch(hw_stream_type) { + case 0: /* MPG */ + type = IVTV_DEC_STREAM_TYPE_MPG; + IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: mpg data\n"); + break; + case 2: /* YUV */ + type = IVTV_DEC_STREAM_TYPE_YUV; + IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: yuv data\n"); + break; + default: + IVTV_DEBUG(IVTV_DEBUG_ERR, "DEC: unknown stream type %d\n", + data[0]); + max = 0; + return; + } + + stream = &itv->v4l2.streams[type]; + + if (test_bit(IVTV_F_I_BUSY, &itv->i_flags)) { + IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: decoder busy, delaying\n"); + set_bit(IVTV_F_I_NEEDS_DATA, &itv->i_flags); + return; + } + + /* If we got this far, we have data to send and it wants it */ + clear_bit(IVTV_F_I_NEEDS_DATA, &itv->i_flags); + + /* Get card mem addr and size from data array */ + mem_offset = data[1]; + mem_size = data[2]; + buffer_bytes = data[3]; /* # bytes in card's buffer */ + + while ((max > x) && (mem_size > bytes_written)) { /* send a maximum of + 'max' buffers */ + buf = __ivtv_deq_peek_head(&stream->full_q); + if (buf == NULL) { + IVTV_DEBUG(IVTV_DEBUG_INFO, + "DEC: No more buffers to send\n"); + break; + } + +#if 1 + if (mem_size < buf->buffer.bytesused) { + itv->DSGarray[x].size = mem_size; + } else { + itv->DSGarray[x].size = buf->buffer.bytesused; + } +#else + /* just send the whole buffer */ + itv->DSGarray[x].size = buf->buffer.bytesused; +#endif + buf->dma_handle = pci_map_single(itv->dev, + (void *)(buf->buffer.m.userptr + + buf->readpos), + itv->DSGarray[x].size, + PCI_DMA_TODEVICE); + + itv->DSGarray[x].src = buf->dma_handle; + itv->DSGarray[x].dst = (mem_offset + bytes_written + + IVTV_FIRM_SEARCH_DECODER_START); + + buf->readpos += itv->DSGarray[x].size; + bytes_written += itv->DSGarray[x].size; + buf->buffer.bytesused -= itv->DSGarray[x].size; + + IVTV_DEBUG(IVTV_DEBUG_INFO, "1st 32bits of buffer %d are 0x%08x\n", + buf->buffer.index, *(u32 *)buf->buffer.m.userptr); + IVTV_DEBUG(IVTV_DEBUG_INFO, "DSGarray[%d]: 0x%08x, 0x%08x 0x%08x\n", + x, itv->DSGarray[x].src, + itv->DSGarray[x].dst, + itv->DSGarray[x].size); + + /* buffer is empty? */ + if (buf->buffer.bytesused == 0) { + __ivtv_del_buf(&stream->full_q, buf); + __ivtv_enq_buf(&stream->dma_q, buf); + } + x++; + } + + if (x == 0) { /* no full buffers */ + IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: Nothing to send\n"); + set_bit(IVTV_F_I_NEEDS_DATA, &itv->i_flags); + return; + } + + //Set Last Element Bit + itv->DSGarray[x-1].size |= 0x80000000; + + //Schedule DMA XFER + data[0] = itv->DSG_handle; + data[1] = bytes_written; + data[2] = hw_stream_type; + + /* note that we're DMA'ing */ + mod_timer(&itv->dec_timeout, jiffies + DEC_DMA_TIMEOUT); + set_bit(IVTV_F_S_DMAP, &stream->s_flags); + set_bit(IVTV_F_I_BUSY, &itv->i_flags); + + ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_DMA_FROM_HOST, + &result, 3, &data[0]); + + IVTV_DEBUG(IVTV_DEBUG_INFO, + "Sched DEC dma: addr: 0x%08x, array_size 0x%08x, type 0x%08x\n", + data[0], data[1], data[2]); +} + +static void ivtv_dec_DMA_done(struct ivtv *itv) { + struct ivtv_v4l2_stream *stream=NULL; + struct ivtv_buffer *buf; + int y, stmtype=-1, freed=0; + + IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: DMA Done tasklet\n"); + + if (!test_and_clear_bit(IVTV_F_I_BUSY, &itv->i_flags)) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "DMAP not set\n"); + ivtv_show_debug_flags(itv); + return; + } + +#if 0 + del_timer(&itv->dec_timeout); +#else + mod_timer(&itv->dec_timeout, jiffies + DEC_DMA_TIMEOUT); +#endif + + for (y=IVTV_DEC_STREAM_TYPE_MPG; y < itv->v4l2.streamcount; y++) { + if (test_and_clear_bit(IVTV_F_S_DMAP, &itv->v4l2.streams[y].s_flags)) { + stmtype = y; + break; + } + } + + /* Handle OSD DMA */ + if (test_and_clear_bit(IVTV_F_I_OSD_DMA, &itv->i_flags)) { + IVTV_DEBUG(IVTV_DEBUG_INFO, "OSD: DMA Done\n"); + + /* wake all the normal streams, in case they fell asleep */ + for (y=IVTV_DEC_STREAM_TYPE_MPG; y < itv->v4l2.streamcount; y++) { + wake_up(&itv->v4l2.streams[y].waitq); + } + + wake_up(&itv->dec_master_w); + return; + } + + if (stmtype < 0) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "DEC: Got DMA-done, not expecting one\n"); + ivtv_show_debug_flags(itv); + return; + } + + IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: Stream %d dma-done\n", y); + stream = &itv->v4l2.streams[y]; + + while ((buf = __ivtv_deq_buf(&stream->dma_q)) != NULL) { + IVTV_ASSERT(buf->dma_handle != IVTV_DMA_UNMAPPED); + pci_unmap_single(itv->dev, buf->dma_handle, + IVTV_DMA_DEC_BUF_SIZE, PCI_DMA_TODEVICE); + buf->dma_handle = IVTV_DMA_UNMAPPED; + buf->buffer.bytesused = 0; + buf->readpos = 0; + + /* put in the 'done' queue */ + __ivtv_enq_buf(&stream->free_q, buf); + freed++; + } + + /* if we put some buffers back in the free queue, kick off dma + * scheduling if card was stopped due to overflow before */ + if (freed && test_and_clear_bit(IVTV_F_S_OVERFLOW, &stream->s_flags)) + ivtv_sched_DMA(itv); + + /* wake up queue filler */ + wake_up(&stream->waitq); + wake_up(&itv->dec_master_w); +} + +int ivtv_get_timing_info(struct ivtv *itv, struct ivtv_ioctl_framesync *info) { + u32 ret, result, data[IVTV_MBOX_MAX_DATA]; + + int suicidecounter = 0; + + memset(info, 0x00, sizeof(struct ivtv_ioctl_framesync)); + + /* Occasionally, we'll get a wierd, invalid number for + * frames played. fortunately, it sets the SCR timestamp to 0 + * in that case, which it never is otherwise. cool, huh */ + while (info->scr == 0) { /* eliminate bogus values, FIXME ugly */ + ret = ivtv_api(itv->dec_mbox, &itv->dec_msem, + IVTV_API_DEC_TIMING_INFO,&result,0,&data[0]); + if (ret) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "DEC: err sending timing info\n"); + return ret; + } + + info->frame = data[0]; + info->pts = ((u64)data[2] << 32) | (u64)data[1]; + info->scr = ((u64)data[4] << 32) | (u64)data[3]; + + if (suicidecounter++ > 10) { /* endless loops are bad! */ + IVTV_DEBUG(IVTV_DEBUG_ERR,"Timeout getting frames played\n"); + return -1; + } + if (info->scr == 0) + ivtv_sleep_timeout(HZ/50); + } + + return 0; +} + +ssize_t ivtv_write(struct ivtv_open_id *id, const char *ubuf, size_t count, + int block) { + int bytes_written=0, ret=0; + unsigned long flags; + + IVTV_DEBUG(IVTV_DEBUG_INFO, "ivtv_write\n"); + + while (bytes_written < count) { /* completely use up user data + * before returning */ + /* buffer the data - this may block waiting on free buffers */ + ret = ivtv_fill_dec_buffers(id, ubuf + bytes_written, + (count - bytes_written), block); + + /* FIXME temporary hack to make sure non-blocking works */ + /* send it! it'll return right away if no data needed */ + spin_lock_irqsave(&id->itv->lock, flags); + ivtv_dec_sched_DMA(id->itv); + spin_unlock_irqrestore(&id->itv->lock, flags); + + if (ret < 0) { + break; + } else { + bytes_written += ret; + } + } + + IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: returning %d\n", bytes_written); + return bytes_written ? bytes_written : ret; +} + +unsigned int ivtv_dec_poll(struct file *filp, poll_table *wait) { + struct ivtv_open_id *id = filp->private_data; + unsigned int mask = 0; + unsigned long flags; + + /* add stream's waitq to the poll list */ + poll_wait(filp, &id->itv->v4l2.streams[id->type].waitq, wait); + + /* FIXME temporary hack to restart DMA in case the decoder's + been busy for a while and the application is using poll to + see if it can write */ + spin_lock_irqsave(&id->itv->lock, flags); + ivtv_dec_sched_DMA(id->itv); + spin_unlock_irqrestore(&id->itv->lock, flags); + + if (ivtv_deq_peek_head(id->itv, &id->itv->v4l2.streams[id->type].free_q)) + mask |= POLLOUT | POLLWRNORM; /* Writable */ + + IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: dec_poll returning 0x%x\n", mask); + return mask; +} + +unsigned int ivtv_poll(struct file *filp, poll_table *wait) { + struct ivtv_open_id *id = filp->private_data; + unsigned int mask = 0; + + /* add stream's waitq to the poll list */ + poll_wait(filp, &id->itv->v4l2.streams[id->type].waitq, wait); + +#if 0 + if (down_interruptible(&id->itv->sem_lock)) + return -ERESTARTSYS; + + if (ivtv_get_free_elements(id->itv, &id->itv->v4l2.streams[id->type].full_q)) + mask |= POLLIN | POLLRDNORM; /* readable */ + + up(&id->itv->sem_lock); +#else + mask |= POLLIN | POLLRDNORM; +#endif + return mask; +} + +#if 0 +static void ivtv_print_boxes(struct ivtv_mailbox *mbox) { + + int x,y; + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 10ms\n"); + ivtv_sleep_timeout(HZ/100); + + if (NULL == mbox) { + IVTV_DEBUG(IVTV_DEBUG_IOCTL, "Mailboxes not initialized!\n"); + return; + } + + for (x = 0; x <= IVTV_MBOX_MAX_BOXES; x++) { + IVTV_DEBUG(IVTV_DEBUG_IOCTL, "mbox: 0x%08x, # %d\n", (u32)mbox, x); + IVTV_DEBUG(IVTV_DEBUG_IOCTL, "flags: 0x%08x ",(u32)readl(&mbox->flags)); + IVTV_DEBUG(IVTV_DEBUG_IOCTL, "cmd: 0x%08x\n", readl(&mbox->cmd)); + IVTV_DEBUG(IVTV_DEBUG_IOCTL, "result: 0x%08x ", readl(&mbox->retval)); + IVTV_DEBUG(IVTV_DEBUG_IOCTL, "timeout: 0x%08x\n", readl(&mbox->timeout)); + IVTV_DEBUG(IVTV_DEBUG_IOCTL, "Data:\n"); + for (y = 0; y < IVTV_MBOX_MAX_DATA; y++) { + IVTV_DEBUG(IVTV_DEBUG_IOCTL, "[%02d]0x%08x, ", y, readl(&mbox->data[y])); + if (2 == y%3) IVTV_DEBUG(IVTV_DEBUG_IOCTL, "\n"); + } + /*Since mbox has type ptr, this should step it up*/ + /* to the start of the next mbox */ + mbox++; + IVTV_DEBUG(IVTV_DEBUG_IOCTL, "\n"); + } +} +#endif + +void ivtv_flush_queues(struct ivtv_open_id *id) { + struct ivtv *itv = id->itv; + struct ivtv_v4l2_stream *st = &itv->v4l2.streams[id->type]; + struct ivtv_buffer *buf; + + /* move free_q to full_q to clean up partially-filled buffers */ + while ((buf = ivtv_deq_buf(itv, &st->free_q))) + ivtv_enq_buf(itv, &st->full_q, buf); + + while ((buf = ivtv_deq_buf(itv, &itv->v4l2.streams[id->type].full_q))) { + buf->buffer.bytesused=0; + buf->readpos=0; + ivtv_enq_buf(itv, &st->free_q, buf); + } + + while ((buf = ivtv_deq_buf(itv, &itv->v4l2.streams[id->type].dma_q))) { + buf->buffer.bytesused=0; + buf->readpos=0; + ivtv_enq_buf(itv, &st->free_q, buf); + } + + return; +} + +int ivtv_close(struct ivtv_open_id *id) { + struct ivtv *itv=id->itv; + int ret = 0; + + /* sem_lock must be held */ + IVTV_ASSERT(ivtv_sem_count(&itv->sem_lock) <= 0); + + switch (id->type) { + case IVTV_DEC_STREAM_TYPE_MPG: /* decoder streams */ + case IVTV_DEC_STREAM_TYPE_YUV: + if (atomic_read(&itv->decoding)) { + IVTV_DEBUG(IVTV_DEBUG_INFO, + "close stopping decode\n"); + ret = ivtv_stop_decode(id); + } + break; + default: /* encoder streams */ + if (atomic_read(&itv->capturing)) { + IVTV_DEBUG(IVTV_DEBUG_INFO, + "close stopping capture\n"); + ret = ivtv_stop_capture(id); + } + break; + } + + ivtv_flush_queues(id); + return ret; +} + +static int module_start(void) { + int loop_a; + + printk("ivtv: version %s (%s) loading\n", IVTV_VERSION_STRING(ivtv_rev), + IVTV_VERSION_COMMENT(ivtv_rev)); + + memset(&ivtv_cards[0], 0, IVTV_MAX_CARDS * sizeof(struct ivtv)); + + /* Validate parameters */ + if (((yuv_buffers > IVTV_MAX_YUV_BUFFERS) + || (yuv_buffers < IVTV_MIN_YUV_BUFFERS)) + && (yuv_buffers != 0)) { + IVTV_DEBUG(IVTV_DEBUG_ERR, + "Error! yuv_buffers must be between 40 and 500\n"); + IVTV_DEBUG(IVTV_DEBUG_ERR, "Exiting..\n"); + return -1; + } + +#ifdef YUV_FIXUP + if ((yuv_fixup != 0) && (yuv_fixup != 1)) { + IVTV_DEBUG(IVTV_DEBUG_ERR, + "Error! yuv_fixup must be 0 or 1\n"); + IVTV_DEBUG(IVTV_DEBUG_ERR, "Exiting..\n"); + return -1; + } +#endif + if ((dec_mpg_buffers > IVTV_MAX_DEC_MPG_BUFFERS) + || (dec_mpg_buffers < IVTV_MIN_DEC_MPG_BUFFERS)) { + IVTV_DEBUG(IVTV_DEBUG_ERR, + "Error! dec_mpg_buffers must be between 5 and 100\n"); + IVTV_DEBUG(IVTV_DEBUG_ERR, "Exiting..\n"); + return -1; + } + + if (((dec_yuv_buffers > IVTV_MAX_DEC_YUV_BUFFERS) + || (dec_yuv_buffers < IVTV_MIN_DEC_YUV_BUFFERS)) + && (dec_yuv_buffers != 0)) { + IVTV_DEBUG(IVTV_DEBUG_ERR, + "Error! dec_yuv_buffers must be between 17 and 500\n"); + IVTV_DEBUG(IVTV_DEBUG_ERR, "Exiting..\n"); + return -1; + } + + if ((mpg_buffers > IVTV_MAX_MPG_BUFFERS) + || (mpg_buffers < IVTV_MIN_MPG_BUFFERS)) { + IVTV_DEBUG(IVTV_DEBUG_ERR, + "Error! mpg_buffers must be between 15 and 100\n"); + IVTV_DEBUG(IVTV_DEBUG_ERR, "Exiting..\n"); + return -1; + } + + if ((dec_yuv_qlen > dec_yuv_buffers) + || (dec_yuv_qlen < IVTV_MIN_DEC_YUV_QLEN)) { + IVTV_DEBUG(IVTV_DEBUG_ERR, + "Error! dec_yuv_qlen must be between %d and %d\n", + IVTV_MIN_DEC_YUV_QLEN, dec_yuv_buffers); + IVTV_DEBUG(IVTV_DEBUG_ERR, "Exiting..\n"); + return -1; + } + + if ((dec_mpg_qlen > dec_mpg_buffers) + || (dec_mpg_qlen < IVTV_MIN_DEC_MPG_QLEN)) { + IVTV_DEBUG(IVTV_DEBUG_ERR, + "Error! dec_mpg_qlen must be between %d and %d\n", + IVTV_MIN_DEC_MPG_QLEN, dec_mpg_buffers); + IVTV_DEBUG(IVTV_DEBUG_ERR, "Exiting..\n"); + return -1; + } + + if ((vbi_buffers > IVTV_MAX_VBI_BUFFERS) + || (vbi_buffers < IVTV_MIN_VBI_BUFFERS)) { + IVTV_DEBUG(IVTV_DEBUG_ERR, + "Error! vbi_buffers must be between 3 and 100\n"); + IVTV_DEBUG(IVTV_DEBUG_ERR, "Exiting..\n"); + return -1; + } + + if ((num_devices > IVTV_MAX_CARDS) || (num_devices < 1)) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "Error! num_devices must be between 1 and 9 (not working yet)\n"); + IVTV_DEBUG(IVTV_DEBUG_ERR, "Exiting..\n"); + return -1; + } + + if (ivtv_debug < 0) IVTV_DEBUG(IVTV_DEBUG_ERR, "debug value must be >= 0!\n"); + + IVTV_DEBUG(IVTV_DEBUG_INFO, + "Loading, I'll try to detect %d devices!\n", num_devices); + IVTV_DEBUG(IVTV_DEBUG_INFO, + " .. running on kernel %s\n", UTS_RELEASE); + IVTV_DEBUG(IVTV_DEBUG_INFO, + "Setting some variables to invalid for detection\n"); + + for (loop_a = 0; loop_a < IVTV_MAX_CARDS; loop_a++) { + ivtv_cards[loop_a].num = -1; + ivtv_cards[loop_a].dev = NULL; + } + + SGarray_size = (mpg_buffers + yuv_buffers + vbi_buffers) * 2; + DSGarray_size = (dec_mpg_buffers + dec_yuv_buffers) * 2; + + IVTV_DEBUG(IVTV_DEBUG_ERR, "SGarray_size = %d, DSGarray_size = %d\n", + SGarray_size, DSGarray_size); + + IVTV_DEBUG(IVTV_DEBUG_INFO, "Scanning PCI bus..\n"); + if (pci_module_init(&ivtv_pci_driver)) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "Error detecting PCI card\n"); + return -ENODEV; + } + + printk("ivtv: loaded\n"); + return 0; +} + +static void module_cleanup(void) { + + pci_unregister_driver(&ivtv_pci_driver); + IVTV_DEBUG(IVTV_DEBUG_ERR, "You've not seen the last of willy!\n"); +#ifdef AEW_DEBUG + DUMP_BAD_ALLOC_TABLE; +#endif // AEW_DEBUG +} + +module_init(module_start); +module_exit(module_cleanup); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/ivtv-fb.c 830-ivtv/drivers/media/video/ivtv-fb.c --- 000-virgin/drivers/media/video/ivtv-fb.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/media/video/ivtv-fb.c Thu Jan 8 11:17:36 2004 @@ -0,0 +1,1112 @@ +/* + * iTVC15 Framebuffer driver + * + * This module presents the iTVC15 OSD (onscreen display) framebuffer memory + * as a standard Linux /dev/fb style framebuffer device. The framebuffer has + * a 32 bpp packed pixel format with full alpha channel support. Depending + * on the TV standard configured in the ivtv module at load time, resolution + * is fixed at either 720x480 (NTSC) or 720x576 (PAL). + * + * Copyright (c) 2003 Matt T. Yourst + * + * Derived from drivers/video/vesafb.c + * Portions (c) 1998 Gerd Knorr + * + * This file is licensed under the GNU General Public License, version 2. + * + */ + +/* +# +# Instructions for making ivtv-fb work with XFree86: +# Add the following sections and parts thereof to /etc/X11/XF86Config: +# + +# +# NOTE: The monitor section is obtainable by running: +# fbset -fb /dev/fb1 -x +# (or /dev/fbX for whatever framebuffer ivtv-fb is on) +# +Section "Monitor" + Identifier "NTSC Monitor" + HorizSync 30-68 + VertRefresh 50-120 + Mode "720x480" + # D: 34.563 MHz, H: 37.244 kHz, V: 73.897 Hz + DotClock 34.564 + HTimings 720 752 840 928 + VTimings 480 484 488 504 + Flags "-HSync" "-VSync" + EndMode +EndSection + +Section "Device" + Identifier "Hauppauge PVR 350 iTVC15 Framebuffer" + Driver "fbdev" + Option "fbdev" "/dev/fb1" # <-- modify if using another device + BusID "0:10:0" +EndSection + +Section "Screen" + Identifier "TV Screen" + Device "Hauppauge PVR 350 iTVC15 Framebuffer" + Monitor "NTSC Monitor" + DefaultDepth 24 + DefaultFbbpp 32 + Subsection "Display" + Depth 24 + FbBpp 32 + Modes "720x480" + EndSubsection +EndSection + +Section "ServerLayout" + ... + + Screen 0 "Screen 1" # << (your computer monitor) + + # (add the following line) + Screen 1 "TV Screen" RightOf "Screen 1" # << (TV screen) + + ... +EndSection + +# +# Then start X as usual; both your normal (computer) monitor and the +# NTSC or PAL TV monitor should display the default X background. +# +# Note the "RightOf" clause above: if you move the mouse off the right +# side of the computer screen, the pointer should appear on your TV +# screen. Keyboard events will go to windows in either screen. +# +# To start a program (e.g., xterm) on the TV only: +# +# export DISPLAY=:0.1 (i.e., X server #0, screen #1 = TV) +# xterm& +# +# There is also a way to join both the computer monitor and TV into +# one giant virtual screen using the Xinerama extension, but I haven't +# tried it. Doing so may not be such a good idea anyway, as you obviously +# wouldn't want random X windows getting moved over the TV picture. + + +A note on unloading the fb driver: + +If you want to be able to unload the framebuffer driver (and you aren't +already using fbcon), add this to your lilo config: + +video=vc:x-y + +where x is the first fb device to allocate and y is the second. If you +already have a fb driver loaded, fiddle with the numbers so all the consoles +are already allocated. For me, i just set it to 0-0, ie: + +in lilo.conf: + +image=/vmlinuz + label=linux + read-only + append="root=/dev/hda1 video=vc:0-0" + +--OR-- +on bootup, do this +LILO: linux video=vc:0-0 + +according to how i read /usr/src/linux/drivers/video/fbmem.c and +/usr/src/linux/drivers/char/console.c, that should disable the +console hijacks, and allow you to unload the driver. + +-tmk +# +# +# +# +# +# +# +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef CONFIG_MTRR +#include +#endif + +#include "ivtv.h" + +/* + * card parameters + */ + +static int ivtv_fb_card_id; + +/* Card selected as framebuffer for this module instance: */ +static struct ivtv *ivtv_fb; + +/* card */ +static unsigned long video_base; /* physical addr */ +static unsigned long video_rel_base; /* address relative to base of decoder memory */ +static int video_size; +static char *video_vbase; /* mapped */ + +/* mode */ +static int video_width; +static int video_height; +static int video_height_virtual; +static int video_linelength; +static unsigned long shadow_framebuf_offset; +static unsigned long shadow_framebuf_size; + +/* + * ivtv API calls for framebuffer related support + */ + +static inline int ivtv_api_fb_get_framebuffer(struct ivtv *itv, + void **fbbase, int *fblength) +{ + u32 data[IVTV_MBOX_MAX_DATA], result; + int rc; + + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_get_framebuffer\n"); + + rc = ivtv_api(itv->dec_mbox, &itv->dec_msem, + IVTV_API_FB_GET_FRAMEBUFFER, &result, 0, &data[0]); + *fbbase = (void *) data[0]; + *fblength = data[1]; + return rc; +} + +static inline int ivtv_api_fb_get_pixel_format(struct ivtv *itv) +{ + u32 data[IVTV_MBOX_MAX_DATA], result; + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_get_pixel_format\n"); + + ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_FB_GET_PIXEL_FORMAT, + &result, 0, &data[0]); + return data[0]; +} + +static inline int ivtv_api_fb_set_pixel_format(struct ivtv *itv, + int format) +{ + u32 data[IVTV_MBOX_MAX_DATA], result; + data[0] = format; + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_set_pixel_format\n"); + + ivtv_api(itv->dec_mbox, &itv->dec_msem, + IVTV_API_FB_SET_PIXEL_FORMAT, &result, 1, &data[0]); + return result; +} + +static inline int ivtv_api_fb_get_state(struct ivtv *itv) +{ + u32 data[IVTV_MBOX_MAX_DATA], result; + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_get_state\n"); + + ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_FB_GET_STATE, + &result, 0, &data[0]); + return data[0]; +} + +static inline int ivtv_api_fb_set_state(struct ivtv *itv, int enabled) +{ + u32 params[IVTV_MBOX_MAX_DATA], result; + params[0] = enabled; + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_set_state\n"); + + ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_FB_SET_STATE, + &result, 1, ¶ms[0]); + return result; +} + +static inline int ivtv_api_fb_set_framebuffer_window(struct ivtv *itv, + int left, int top, + int width, int height) +{ + u32 data[IVTV_MBOX_MAX_DATA], result; + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_set_framebuffer_window\n"); + data[0] = width; + data[1] = height; + data[2] = left; + data[3] = top; + + ivtv_api(itv->dec_mbox, &itv->dec_msem, + IVTV_API_FB_SET_FRAMEBUFFER_WINDOW, &result, 4, &data[0]); + return result; +} + +static inline int ivtv_api_fb_get_osd_coords(struct ivtv *itv, + struct ivtv_osd_coords *osd) +{ + u32 data[IVTV_MBOX_MAX_DATA], result; + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_get_osd_coords\n"); + + ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_FB_GET_OSD_COORDS, + &result, 0, &data[0]); + + osd->offset = data[0] - video_rel_base; + osd->max_offset = video_size; + osd->pixel_stride = data[1]; + osd->lines = data[2]; + osd->x = data[3]; + osd->y = data[4]; + + return result; +} + +static inline int ivtv_api_fb_set_osd_coords(struct ivtv *itv, + const struct ivtv_osd_coords + *osd) +{ + u32 data[IVTV_MBOX_MAX_DATA], result; + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_set_osd_coords\n"); + data[0] = osd->offset + video_rel_base; + data[1] = osd->pixel_stride; + data[2] = osd->lines; + data[3] = osd->x; + data[4] = osd->y; + + // FIXME maybe wait on vsync? + ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_FB_SET_OSD_COORDS, + &result, 5, &data[0]); + return result; +} + +static inline int ivtv_api_fb_get_screen_coords(struct ivtv *itv, + struct rectangle *r) +{ + u32 data[IVTV_MBOX_MAX_DATA], result; + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_get_screen_coords\n"); + + ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_FB_GET_SCREEN_COORDS, + &result, 0, &data[0]); + + r->x0 = data[0]; + r->y0 = data[1]; + r->x1 = data[2]; + r->y1 = data[3]; + + return result; +} + +static inline int ivtv_api_fb_set_screen_coords(struct ivtv *itv, + const struct rectangle *r) +{ + u32 data[IVTV_MBOX_MAX_DATA], result; + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_set_screen_coords\n"); + data[0] = r->x0; + data[1] = r->y0; + data[2] = r->x1; + data[3] = r->y1; + + ivtv_api(itv->dec_mbox, &itv->dec_msem, + IVTV_API_FB_SET_SCREEN_COORDS, &result, 4, &data[0]); + return result; +} + +static inline int ivtv_api_fb_get_global_alpha(struct ivtv *itv) +{ + u32 data[IVTV_MBOX_MAX_DATA], result; + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_get_global_alpha\n"); + + ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_FB_GET_GLOBAL_ALPHA, + &result, 0, &data[0]); + return data[1]; +} + +static inline int ivtv_api_fb_set_global_alpha(struct ivtv *itv, + int enable_global, + int alpha, int enable_local) +{ + u32 data[IVTV_MBOX_MAX_DATA], result; + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_set_global_alpha\n"); + data[0] = enable_global; + data[1] = alpha; + data[2] = !enable_local; + ivtv_api(itv->dec_mbox, &itv->dec_msem, + IVTV_API_FB_SET_GLOBAL_ALPHA, &result, 3, &data[0]); + return result; +} + +static inline int ivtv_api_fb_get_flicker_state(struct ivtv *itv) +{ + u32 data[IVTV_MBOX_MAX_DATA], result; + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_get_flicker_state\n"); + + ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_FB_GET_FLICKER_STATE, + &result, 0, &data[0]); + return data[0]; +} + +static inline int ivtv_api_fb_set_flicker_state(struct ivtv *itv, + int enabled) +{ + u32 params[IVTV_MBOX_MAX_DATA], result; + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_set_flicker_state\n"); + params[0] = enabled; + + ivtv_api(itv->dec_mbox, &itv->dec_msem, + IVTV_API_FB_SET_FLICKER_STATE, &result, 1, ¶ms[0]); + return result; +} + +static inline int ivtv_api_fb_blt_fill(struct ivtv *itv, int rasterop, + int alpha_mode, int alpha_mask_mode, + int width, int height, int destmask, + u32 destaddr, int deststride, + u32 value) +{ + u32 data[IVTV_MBOX_MAX_DATA], result; + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_blt_fill\n"); + data[0] = rasterop; + data[1] = alpha_mode; + data[2] = alpha_mask_mode; + data[3] = width; + data[4] = height; + data[5] = destmask; + data[6] = destaddr; + data[7] = deststride; + data[8] = value; + + ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_FB_BLT_FILL, &result, + 9, &data[0]); + return result; +} + +static inline int ivtv_api_fb_blt_copy(struct ivtv *itv, int rasterop, + int alpha_mode, int alpha_mask_mode, + int width, int height, int destmask, + u32 destaddr, int deststride, + int sourcestride, int sourceaddr) +{ + u32 data[IVTV_MBOX_MAX_DATA], result; + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_blt_copy: width = %d, height = %d, destaddr = %d, deststride = %d, sourcestride = %d, sourceaddr = %d\n", + width, height, destaddr, deststride, sourcestride, sourceaddr); + + data[0] = rasterop; + data[1] = alpha_mode; + data[2] = alpha_mask_mode; + data[3] = width; + data[4] = height; + data[5] = destmask; + data[6] = destaddr; + data[7] = deststride; + data[8] = sourcestride; + data[9] = sourceaddr; + + ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_FB_BLT_COPY, &result, + 10, &data[0]); + return result; +} + + +MODULE_PARM(ivtv_fb_card_id, "i"); +MODULE_PARM_DESC(ivtv_fb_card_id, + "ID number of ivtv card to use as framebuffer device (0-2)"); + +MODULE_LICENSE("GPL"); + + +/* --------------------------------------------------------------------- */ + +static struct fb_var_screeninfo ivtvfb_defined = { + 0, 0, 0, 0, /* W,H, W, H (virtual) load xres,xres_virtual */ + 0, 0, /* virtual -> visible no offset */ + 32, /* depth -> load bits_per_pixel */ + 0, /* greyscale ? */ + {0, 0, 0}, /* R */ + {0, 0, 0}, /* G */ + {0, 0, 0}, /* B */ + {0, 0, 0}, /* transparency */ + 0, /* standard pixel format */ + FB_ACTIVATE_NOW, + -1, -1, + 0, + 0L, 0L, 0L, 0L, 0L, + 0L, 0L, 0, /* No sync info */ + FB_VMODE_NONINTERLACED, + 0, + {0, 0, 0, 0, 0} +}; + +static struct display disp; +static struct fb_info fb_info; +static union { + u32 cfb32[16]; +} fbcon_cmap; + +#ifdef CONFIG_MTRR +static int mtrr = 1; //++MTY +static unsigned long fb_start_aligned_physaddr; /* video_base rounded down as required by hardware MTRRs */ +static unsigned long fb_end_aligned_physaddr; /* video_base rounded up as required by hardware MTRRs */ +#endif + +static struct display_switch ivtvfb_sw; + +/* --------------------------------------------------------------------- */ + +static int ivtvfb_update_var(int con, struct fb_info *info) +{ + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_update_var\n"); + return 0; +} + +static int ivtvfb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info) +{ + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_get_fix\n"); + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strcpy(fix->id, "iTVC15 TV out"); + + fix->smem_start = video_base; + fix->smem_len = video_size; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->visual = FB_VISUAL_TRUECOLOR; + fix->xpanstep = 0; + fix->ypanstep = 0; + fix->ywrapstep = 0; + fix->line_length = video_linelength; + return 0; +} + +static int ivtvfb_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_get_var\n"); + if (con == -1) + { + memcpy(var, &ivtvfb_defined, sizeof(struct fb_var_screeninfo)); + } + else + { + *var = fb_display[con].var; + } + return 0; +} + +static void ivtvfb_set_disp(int con) +{ + struct fb_fix_screeninfo fix; + struct display *display; + struct display_switch *sw; + + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_set_disp\n"); + if (con >= 0) + display = &fb_display[con]; + else + display = &disp; /* used during initialization */ + + ivtvfb_get_fix(&fix, con, 0); + + memset(display, 0, sizeof(struct display)); + display->screen_base = video_vbase; + display->visual = fix.visual; + display->type = fix.type; + display->type_aux = fix.type_aux; + display->ypanstep = fix.ypanstep; + display->ywrapstep = fix.ywrapstep; + display->line_length = fix.line_length; + display->next_line = fix.line_length; + display->can_soft_blank = 0; + display->inverse = 0; + ivtvfb_get_var(&display->var, -1, &fb_info); + + sw = &fbcon_cfb32; + display->dispsw_data = fbcon_cmap.cfb32; + memcpy(&ivtvfb_sw, sw, sizeof(*sw)); + display->dispsw = &ivtvfb_sw; + display->scrollmode = SCROLL_YREDRAW; + ivtvfb_sw.bmove = fbcon_redraw_bmove; +} + +static int ivtvfb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + int first=0; + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_set_var\n"); + if (con >= 0) first = 1; + + if (var->xres != ivtvfb_defined.xres || + var->yres != ivtvfb_defined.yres || + var->xres_virtual != ivtvfb_defined.xres_virtual || + var->yres_virtual > video_height_virtual || + var->yres_virtual < video_height || + var->xoffset || + var->bits_per_pixel != ivtvfb_defined.bits_per_pixel || + var->nonstd) { + if (first) { + printk(KERN_ERR + "ivtvfb does not support changing the video mode\n"); + first = 0; + } + return -EINVAL; + } + + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST) + return 0; + + if (var->yoffset) + return -EINVAL; + return 0; +} + +/* + * ivtv never uses a colormap: it is always straight RGBA 8:8:8:8... + */ +static int ivtvfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_get_cmap\n"); + return 0; +} + +static int ivtvfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_set_cmap\n"); + return 0; +} + +static int ivtv_fb_blt_copy(struct ivtv *itv, int x, int y, int width, + int height, int source_offset, + int source_stride) +{ + int rc; + unsigned long destaddr = ((y * video_width) + x) * 4; + + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_fb_blt_copy\n"); + source_offset += shadow_framebuf_offset; + + rc = ivtv_api_fb_blt_copy(ivtv_fb, 0xa, 0x1, 0x0, width, height, + 0xffffffff, destaddr, video_width, + source_stride, source_offset); + return rc; +} + +/* + * Returns the physical location of the PTE associated with a given virtual address. + */ +static inline pte_t *virt_to_pte(struct mm_struct *mm, void *addr) +{ + return + pte_offset(pmd_offset + (pgd_offset(mm, (unsigned long) addr), + (unsigned long) addr), (unsigned long) addr); +} + +struct ivtvfb_user_dma_to_device ivtvfb_current_fb_dma; + +// 4MB max buffer size (on IA32 at least: 1024 pages x 4KB/page = 4MB): +#define IVTV_MAX_FB_DMA_PAGES 1024 + +int ivtvfb_alloc_user_dma_to_device(struct ivtvfb_user_dma_to_device *dma) +{ + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_alloc_user_dma_to_device\n"); + dma->page_count = 0; + dma->sglist = kmalloc(sizeof(struct ivtv_SG_element)*IVTV_MAX_FB_DMA_PAGES, + GFP_KERNEL); + if (!dma->sglist) { + printk(KERN_ERR + "ivtvfb: cannot allocate scatter/gather list for %d pages\n", + IVTV_MAX_FB_DMA_PAGES); + return -ENOMEM; + } + + dma->map = kmalloc(sizeof(struct page *) * IVTV_MAX_FB_DMA_PAGES, GFP_KERNEL); + if (!dma->map) { + IVTV_DEBUG_FB(IVTV_DEBUG_ERR, "can't alloc dma page array\n"); + kfree(dma->sglist); + return -ENOMEM; + } + + dma->sg_dma_handle = + pci_map_single(ivtv_fb->dev, (void *) dma->sglist, + (sizeof(struct ivtv_SG_element) * + IVTV_MAX_FB_DMA_PAGES), PCI_DMA_TODEVICE); + + return 0; +} + +//++MTY This is pretty fast - fast enough to do around 30+ frames per second at NTSC 720x480x4 or 27 frames per second at PAL 720x576x4 +int ivtvfb_prep_user_dma_to_device(struct ivtvfb_user_dma_to_device *dma, + unsigned long ivtv_dest_addr, + char *userbuf, int size_in_bytes) +{ + int i, offset; + unsigned long uaddr; + int size_in_pages = (size_in_bytes + (PAGE_SIZE - 1)) >> PAGE_SHIFT; + + IVTV_DEBUG_FB(IVTV_DEBUG_DMA, "ivtvfb_prep_user_dma_to_device, dst: 0x%08x\n", + (unsigned int) ivtv_dest_addr); + + uaddr = ((unsigned long) userbuf & PAGE_MASK); + offset = uaddr & ~PAGE_MASK; + + down_read(¤t->mm->mmap_sem); + size_in_pages = get_user_pages(current, current->mm, uaddr, size_in_pages, 0, 0, dma->map, NULL); + up_read(¤t->mm->mmap_sem); + + if (size_in_pages < 0) { + IVTV_DEBUG_FB(IVTV_DEBUG_ERR, "failed to map user pages\n"); + return size_in_pages; + } + + dma->page_count = size_in_pages; + for (i = 0; i < size_in_pages; i++) { + dma->sglist[i].size = PAGE_SIZE; + dma->sglist[i].src = pci_map_page(ivtv_fb->dev, dma->map[i], 0, offset, PCI_DMA_TODEVICE); + dma->sglist[i].dst = ivtv_dest_addr + i * PAGE_SIZE + offset; + offset = 0; + } + + // Indicate the last element to the hardware, so we get an interrupt on completion... + dma->sglist[size_in_pages - 1].size |= 0x80000000; + +#ifdef IVTVFB_DEBUG_PER_FRAME + printk(KERN_INFO + "ivtvfb: Allocated scatter/gather list of %d bytes (%d pages) at kva 0x%08x = physaddr 0x%08x:\n", + size_in_bytes, size_in_pages, dma->sglist, dma->sg_dma_handle); + for (i = 0; i < size_in_pages; i++) { + printk(KERN_INFO + "ivtvfb: [%d] src 0x%08x -> dest 0x%08x, size 0x%08x bytes\n", + i, dma->sglist[i].src, dma->sglist[i].dst, + dma->sglist[i].size); + } +#endif + + return 0; +} + +int ivtvfb_free_user_dma_to_device(struct ivtvfb_user_dma_to_device *dma) +{ + int i; + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_free_user_dma_to_device\n"); + + for (i = 0; i < dma->page_count; i++) { + pci_unmap_page(ivtv_fb->dev, dma->sglist[i].src, PAGE_SIZE, PCI_DMA_TODEVICE); + page_cache_release(dma->map[i]); + } + kfree(dma->sglist); + kfree(dma->map); + dma->page_count = 0; + return 0; +} + +int ivtvfb_execute_user_dma_to_device(struct ivtvfb_user_dma_to_device + *dma) +{ + u32 data[IVTV_MBOX_MAX_DATA], result; + int rc; + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_execute_user_dma_to_device\n"); + + data[0] = dma->sg_dma_handle; + data[1] = dma->page_count; + data[2] = 0x1; // 0x1 = OSD data + + IVTV_DEBUG_FB(IVTV_DEBUG_DMA, "Schedule FB DMA: physical address 0x%08x, " + "arraysize 0x%08x, type 0x%08x\n", data[0], data[1], data[2]); + + // Enable DMA complete interrupt: + ivtv_clear_irq_mask(ivtv_fb, IVTV_IRQ_DEC_DMA_COMPLETE); + + set_bit(IVTV_F_I_OSD_DMA, &ivtv_fb->i_flags); + + rc = ivtv_api(ivtv_fb->dec_mbox, &ivtv_fb->dec_msem, + IVTV_API_DEC_DMA_FROM_HOST, &result, 3, &data[0]); + + if (rc) { + IVTV_DEBUG_FB(IVTV_DEBUG_ERR, "error sending DMA info\n"); + clear_bit(IVTV_F_I_BUSY, &ivtv_fb->i_flags); + } + + IVTV_DEBUG_FB(IVTV_DEBUG_DMA, "OK, scheduled FB DMA!"); + return 0; +} + +static inline int ivtv_fb_prep_frame(struct ivtv *itv, + unsigned long destaddr, void *srcaddr, + int count) +{ + DECLARE_WAITQUEUE(wait, current); + int rc; + + //if (!srcaddr || verify_area(...)) ... + if ((destaddr + count) > video_size) + return -E2BIG; + + rc = 0; + add_wait_queue(&ivtv_fb->dec_master_w, &wait); + do { + set_current_state(TASK_INTERRUPTIBLE); + /* FIXME mini-race still .. need to port to 'stream' format */ + if (!test_and_set_bit(IVTV_F_I_BUSY, &ivtv_fb->i_flags)) + break; + + schedule(); + + if (signal_pending(current)) + rc = -ERESTARTSYS; + } while (!rc); + set_current_state(TASK_RUNNING); + remove_wait_queue(&ivtv_fb->dec_master_w, &wait); + + if (rc) + goto out_dma_lock; + + destaddr = IVTV_DEC_MEM_START + video_rel_base + destaddr; + + if (0 != (rc = ivtvfb_prep_user_dma_to_device(&ivtvfb_current_fb_dma, destaddr, + (char *) srcaddr, count))) + { + IVTV_DEBUG_FB(IVTV_DEBUG_DMA, "err prep user dma to device=%x\n",rc); + goto out_dma_lock; + } + if (0 != (rc = ivtvfb_execute_user_dma_to_device(&ivtvfb_current_fb_dma))) + { + IVTV_DEBUG_FB(IVTV_DEBUG_DMA, "err exec user dma to device=%x\n",rc); + goto out_dma_lock; + } + + return 0; +out_dma_lock: + clear_bit(IVTV_F_I_BUSY, &ivtv_fb->i_flags); + wake_up(&ivtv_fb->dec_master_w); + return rc; +} + +int ivtv_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg, int con, struct fb_info *info) +{ + + int rc; + + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_fb_ioctl\n"); + switch (cmd) { + case 0x7777:{ + while (MOD_IN_USE) MOD_DEC_USE_COUNT; + MOD_INC_USE_COUNT; + return 0; + } + case IVTVFB_IOCTL_GET_STATE:{ + struct ivtvfb_ioctl_state_info state; + state.status = (ivtv_api_fb_get_state(ivtv_fb) & 0x7); + state.status |= (ivtv_api_fb_get_flicker_state(ivtv_fb) << 3); + state.alpha = ivtv_api_fb_get_global_alpha(ivtv_fb); + IVTV_DEBUG_FB(IVTV_DEBUG_IOCTL, "IVTVFB_IOCTL_GET_STATE: status = %lu, alpha = %lu\n", + state.status, state.alpha); + if (copy_to_user((void *) arg, &state, sizeof(state))) + return -EFAULT; + return 0; + } + case IVTVFB_IOCTL_SET_STATE:{ + struct ivtvfb_ioctl_state_info state; + if (copy_from_user(&state, (void *) arg, sizeof(state))) + return -EFAULT; + IVTV_DEBUG_FB(IVTV_DEBUG_IOCTL, "IVTVFB_IOCTL_SET_STATE: status = %lu, alpha = %lu\n", + state.status, state.alpha); + ivtv_api_fb_set_state(ivtv_fb, + (state.status && IVTVFB_STATUS_ENABLED)); + ivtv_api_fb_set_global_alpha(ivtv_fb, + (state. + status & + IVTVFB_STATUS_GLOBAL_ALPHA) ? 1 : + 0, state.alpha, + (state. + status & + IVTVFB_STATUS_LOCAL_ALPHA) ? 1 : + 0); + ivtv_api_fb_set_flicker_state(ivtv_fb, + (state. + status & + IVTVFB_STATUS_FLICKER_REDUCTION) + ? 1 : 0); + IVTV_DEBUG_FB(IVTV_DEBUG_IOCTL, "new state = %d\n", + ivtv_api_fb_get_state(ivtv_fb)); + IVTV_DEBUG_FB(IVTV_DEBUG_IOCTL, "global alpha now = %d\n", + ivtv_api_fb_get_global_alpha(ivtv_fb)); + return 0; + } + case IVTVFB_IOCTL_PREP_FRAME:{ + struct ivtvfb_ioctl_dma_host_to_ivtv_args args; + if (copy_from_user(&args, (void *) arg, sizeof(args))) + return -EFAULT; + return ivtv_fb_prep_frame(ivtv_fb, args.dest_offset, + args.source, args.count); + } + case IVTVFB_IOCTL_BLT_COPY:{ + struct ivtvfb_ioctl_blt_copy_args args; + if (copy_from_user(&args, (void *) arg, sizeof(args))) + return -EFAULT; + + return ivtv_fb_blt_copy(ivtv_fb, args.x, args.y, args.width, + args.height, args.source_stride, + args.source_offset); + } + case IVTVFB_IOCTL_GET_ACTIVE_BUFFER:{ + struct ivtv_osd_coords bufinfo; + rc = ivtv_api_fb_get_osd_coords(ivtv_fb, &bufinfo); + return copy_to_user((void *) arg, &bufinfo, sizeof(bufinfo)); + } + case IVTVFB_IOCTL_SET_ACTIVE_BUFFER:{ + struct ivtv_osd_coords bufinfo; + if (copy_from_user(&bufinfo, (void *) arg, sizeof(bufinfo))) + return -EFAULT; + return ivtv_api_fb_set_osd_coords(ivtv_fb, &bufinfo); + } + case IVTVFB_IOCTL_GET_FRAME_BUFFER:{ + struct ivtvfb_ioctl_get_frame_buffer getfb; + getfb.mem = (void *)video_vbase; + getfb.bytes = video_size; + getfb.sizex = video_width; + getfb.sizey = video_height; + + return copy_to_user((void *) arg, &getfb, sizeof(getfb)); + } + default: + return -EINVAL; + } + return 0; +} + +static struct fb_ops ivtvfb_ops = { + owner:THIS_MODULE, + fb_get_fix:ivtvfb_get_fix, + fb_get_var:ivtvfb_get_var, + fb_set_var:ivtvfb_set_var, + fb_get_cmap:ivtvfb_get_cmap, + fb_set_cmap:ivtvfb_set_cmap, + fb_ioctl:ivtv_fb_ioctl, + fb_pan_display:NULL, +}; + +/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ + +static void ivtvfb_blank(int blank, struct fb_info *info) +{ + /* Not supported */ +} + +int __init ivtvfb_init(void) +{ + int rc; + u32 fbbase; + u32 fblength; + struct ivtv_osd_coords osd; + struct rectangle rect; + + if ((ivtv_fb_card_id < 0) || (ivtv_fb_card_id >= ivtv_cards_active)) { + printk(KERN_ERR + "Error! ivtv-fb: ivtv_fb_card_id parameter is out of range (valid range: 0-%d)\n", + ivtv_cards_active - 1); + return -1; + } + + ivtv_fb = &ivtv_cards[ivtv_fb_card_id]; + if (!ivtv_fb || (ivtv_fb->card_type != IVTV_350_V1)) { + printk(KERN_ERR + "Error! ivtv-fb: Specified card (id %d) is either not present or does not support TV out (PVR350 only)\n", + ivtv_fb_card_id); + return -1; + } + + printk(KERN_INFO + "ivtv-fb: Framebuffer module loaded (attached to ivtv card id %d)\n", + ivtv_fb_card_id); + + rc = ivtv_api_fb_set_pixel_format(ivtv_fb, 4); // 4 = AlphaRGB 8:8:8:8 + + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "Current pixel format = %d\n", + ivtv_api_fb_get_pixel_format(ivtv_fb)); + + rc = ivtv_api_fb_get_framebuffer(ivtv_fb, (void **) &fbbase, + &fblength); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "Framebuffer is at decoder-relative address 0x%08x and has %d bytes.\n", + fbbase, fblength); + + rc = ivtv_api_fb_get_osd_coords(ivtv_fb, &osd); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "OSD: offset = 0x%08x (max offset = 0x%08x), pixel_stride = %d, lines = %d, x = %d, y = %d\n", + (u32)osd.offset, (u32)osd.max_offset, osd.pixel_stride, osd.lines, osd.x, + osd.y); + + /* setup OSD and screen for PAL */ + if (ivtv_pal) { + osd.lines = 576; + rc = ivtv_api_fb_set_osd_coords(ivtv_fb, &osd); + if (rc) + IVTV_DEBUG_FB(IVTV_DEBUG_ERR, "failed setting PAL osd\n"); + + rect.x0 = 0; + rect.x1 = 720; + rect.y0 = 0; + rect.y1 = 576; + rc = ivtv_api_fb_set_screen_coords(ivtv_fb, &rect); + if (rc) + IVTV_DEBUG_FB(IVTV_DEBUG_ERR, "failed setting PAL screen\n"); + } + + rc = ivtv_api_fb_get_screen_coords(ivtv_fb, &rect); + printk(KERN_INFO "ivtv-fb: screen coords: [%d %d] -> [%d %d]\n", + rect.x0, rect.y0, rect.x1, rect.y1); + + printk(KERN_INFO "ivtv-fb: original global alpha = %d\n", + ivtv_api_fb_get_global_alpha(ivtv_fb)); + + /* + * Normally a 32-bit RGBA framebuffer would be fine, however XFree86's fbdev + * driver doesn't understand the concept of alpha channel and always sets + * bits 24-31 to zero when using a 24bpp-on-32bpp framebuffer device. We fix + * this behavior by enabling the iTVC15's global alpha feature, which causes + * the chip to ignore the per-pixel alpha data and instead use one value (e.g., + * full brightness = 255) for the entire framebuffer. The local alpha is also + * disabled in this step. + * + *++MTY Need to update http://ivtv.sourceforge.net/ivtv/firmware-api.html + * call 0x4b: param[2] says 1 = enable local alpha, when in reality + * it means *disable* local alpha... + * + */ + ivtv_api_fb_set_global_alpha(ivtv_fb, 1, 255, 0); + printk(KERN_INFO "ivtv-fb: new global alpha = %d\n", + ivtv_api_fb_get_global_alpha(ivtv_fb)); + + rc = ivtv_api_fb_set_state(ivtv_fb, 1); // 1 = enabled + printk(KERN_INFO "ivtv-fb: current OSD state = %d\n", + ivtv_api_fb_get_state(ivtv_fb)); + + video_rel_base = fbbase; + video_base = ivtv_fb->base_addr + IVTV_DEC_MEM_START + video_rel_base; + video_width = rect.x1 - rect.x0; + video_height = rect.y1 - rect.y0; + video_linelength = 4 * osd.pixel_stride; + video_size = fblength; + + shadow_framebuf_size = (video_width * video_height * 4); + shadow_framebuf_offset = (video_size - shadow_framebuf_size) & ~3; + + if (!request_mem_region(video_base, video_size, "ivtvfb")) { + printk(KERN_WARNING + "ivtv-fb: warning: cannot reserve video memory at 0x%lx\n", + video_base); + /* We cannot make this fatal. Sometimes this comes from magic spaces our resource handlers simply don't know about */ + } + + video_vbase = ioremap(video_base, video_size); + if (!video_vbase) { + release_mem_region(video_base, video_size); + printk(KERN_ERR + "ivtv-fb: abort, cannot ioremap video memory 0x%x @ 0x%lx\n", + video_size, video_base); + return -EIO; + } + + printk(KERN_INFO + "ivtv-fb: framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", + video_base, video_vbase, video_size / 1024); + printk(KERN_INFO "ivtv-fb: mode is %dx%dx%d, linelength=%d\n", + video_width, video_height, 32, video_linelength); + + ivtvfb_defined.xres = video_width; + ivtvfb_defined.yres = video_height; + ivtvfb_defined.xres_virtual = video_width; + ivtvfb_defined.yres_virtual = video_height; + ivtvfb_defined.bits_per_pixel = 32; + video_height_virtual = ivtvfb_defined.yres_virtual; + + /* some dummy values for timing to make fbset happy */ + ivtvfb_defined.pixclock = 10000000 / video_width * 1000 / video_height; + ivtvfb_defined.left_margin = (video_width / 8) & 0xf8; + ivtvfb_defined.right_margin = 32; + ivtvfb_defined.upper_margin = 16; + ivtvfb_defined.lower_margin = 4; + ivtvfb_defined.hsync_len = (video_width / 8) & 0xf8; + ivtvfb_defined.vsync_len = 4; + + ivtvfb_defined.red.offset = 0; + ivtvfb_defined.red.length = 8; + ivtvfb_defined.green.offset = 8; + ivtvfb_defined.green.length = 8; + ivtvfb_defined.blue.offset = 16; + ivtvfb_defined.blue.length = 8; + ivtvfb_defined.transp.offset = 24; + ivtvfb_defined.transp.length = 8; + +#ifdef CONFIG_MTRR + if (mtrr) { + /* Find the largest power of two that maps the whole buffer */ + int size_shift = 31; + while (!(video_size & (1 << size_shift))) { + size_shift--; + } + size_shift++; + + fb_start_aligned_physaddr = video_base & ~((1 << size_shift) - 1); + fb_end_aligned_physaddr = + (video_base + (1 << size_shift) - 1) & ~((1 << size_shift) - + 1); + if (mtrr_add + (fb_start_aligned_physaddr, + (fb_end_aligned_physaddr - fb_start_aligned_physaddr), + MTRR_TYPE_WRCOMB, 1) < 0) { + printk(KERN_WARNING + "ivtv-fb: warning: mtrr_add() failed to add write combining region 0x%08x-0x%08x\n", + (unsigned int) fb_start_aligned_physaddr, + (unsigned int) fb_end_aligned_physaddr); + } + } +#endif + + strcpy(fb_info.modename, "iTVC15 TV out"); + fb_info.fontname[0] = '\0'; + fb_info.changevar = NULL; + fb_info.node = -1; + fb_info.fbops = &ivtvfb_ops; + fb_info.disp = &disp; + fb_info.switch_con = NULL; //&ivtvfb_switch; (fbcon will ignore it then) + fb_info.updatevar = &ivtvfb_update_var; + fb_info.blank = &ivtvfb_blank; + fb_info.flags = FBINFO_FLAG_DEFAULT; + ivtvfb_set_disp(-1); + + if (register_framebuffer(&fb_info) < 0) + return -EINVAL; + + ivtv_fb->fb_id = GET_FB_IDX(fb_info.node); + + printk(KERN_INFO "fb%d: %s frame buffer device\n", + ivtv_fb->fb_id, fb_info.modename); + + /* Set up DMA and BLT copy structures */ + ivtvfb_alloc_user_dma_to_device(&ivtvfb_current_fb_dma); + ivtv_fb->user_dma_to_device_state = &ivtvfb_current_fb_dma; + return 0; +} + + +static void ivtvfb_cleanup(void) +{ + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "Unloading framebuffer module\n"); + unregister_framebuffer(&fb_info); + iounmap(video_vbase); +#ifdef CONFIG_MTRR + mtrr_del(-1, fb_start_aligned_physaddr, + (fb_end_aligned_physaddr - fb_start_aligned_physaddr)); +#endif + ivtv_fb->user_dma_to_device_state = NULL; + ivtvfb_free_user_dma_to_device(&ivtvfb_current_fb_dma); + ivtv_fb->fb_id = -1; + //release_mem_region(video_base, video_size); +} + +module_init(ivtvfb_init); +module_exit(ivtvfb_cleanup); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/ivtv-i2c.c 830-ivtv/drivers/media/video/ivtv-i2c.c --- 000-virgin/drivers/media/video/ivtv-i2c.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/media/video/ivtv-i2c.c Thu Jan 8 11:17:36 2004 @@ -0,0 +1,211 @@ +#include "ivtv.h" + +/* i2c implementation for iTVC15 chip, ivtv project. + * Author: Kevin Thayer (nufan_wfk at yahoo.com) + * License: GPL + * http://www.sourceforge.net/projects/ivtv/ + */ + + +/* moved here from ivtv.h */ +static int writeregs(struct i2c_client *client, const unsigned char *regs); +static int attach_inform(struct i2c_client *client); +static int detach_inform(struct i2c_client *client); + +int writereg(struct i2c_client *client, + unsigned char reg, unsigned char data) +{ + int ret; + unsigned char msg[] = {0x1f, 0x00}; + + printk("<1>writing reg 0x%02x, data 0x%02x\n", reg,data); + + msg[0]=reg; msg[1]=data; + ret=i2c_master_send(client, msg, 2); + if (ret!=2) + printk("writereg error\n"); + return ret; +} + +static int writeregs(struct i2c_client *client, const unsigned char *regs) +{ + unsigned char reg, data; + + while (*regs!=0x00) { + reg =*(regs++); + data=*(regs++); + if (writereg(client, reg, data)<0) + return -1; + } + return 0; +} + +static struct i2c_adapter ivtv_i2c_adapter_template = { + .owner = THIS_MODULE, + + .id= I2C_HW_B_BT848, /*id?? (algo-bit is OR'd with this)*/ + .class = I2C_ADAP_CLASS_TV_ANALOG, + .algo = NULL, /*set by i2c-algo-bit*/ + .algo_data = NULL, /*filled from template*/ + .client_register = attach_inform, + .client_unregister = detach_inform, + I2C_DEVNAME("ivtv i2c driver"), +}; + +static struct i2c_algo_bit_data ivtv_i2c_algo_template = { + NULL, /*??*/ + ivtv_setsda, /*setsda function*/ + ivtv_setscl, /*"*/ + ivtv_getsda, /*"*/ + ivtv_getscl, /*"*/ + 5, /*udelay or mdelay*/ + 5, /*whatever above isn't*/ + 200 /*timeout*/ +}; + +void ivtv_setscl(void *data, int state) { + struct ivtv *itv = (struct ivtv *)data; + + if (state) + itv->i2c_state |= 0x01; + else + itv->i2c_state &= ~0x01; + + /* write them out */ + /* write bits are inverted */ + writel(~itv->i2c_state,(itv->reg_mem + IVTV_REG_I2C_SETSCL_OFFSET)); +} + +void ivtv_setsda(void *data, int state) { + struct ivtv *itv = (struct ivtv *)data; + + if (state) + itv->i2c_state |= 0x01; + else + itv->i2c_state &= ~0x01; + + /* write them out */ + /* write bits are inverted */ + writel(~itv->i2c_state,(itv->reg_mem + IVTV_REG_I2C_SETSDA_OFFSET)); +} + +int ivtv_getscl(void *data) { + struct ivtv *itv = (struct ivtv *)data; + return readb(itv->reg_mem + IVTV_REG_I2C_GETSCL_OFFSET); +} + +int ivtv_getsda(void *data) { + struct ivtv *itv = (struct ivtv *)data; + return readb(itv->reg_mem + IVTV_REG_I2C_GETSDA_OFFSET); +} + +static struct i2c_client ivtv_i2c_client_template = { + .id = -1, + I2C_DEVNAME("ivtv internal use only") +}; + +static int attach_inform(struct i2c_client *client) { + struct ivtv *itv = (struct ivtv*) i2c_get_adapdata(client->adapter); + int i; + + IVTV_DEBUG(IVTV_DEBUG_I2C, "i2c client attach\n"); + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + if (itv->i2c_clients[i] == NULL) { + itv->i2c_clients[i] = client; + break; + } + } + IVTV_DEBUG(IVTV_DEBUG_I2C, "i2c attach [client=%s,%s]\n", + client->name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed"); + + return 0; +} + +static int detach_inform(struct i2c_client *client) { + struct ivtv *itv = (struct ivtv*) i2c_get_adapdata(client->adapter); + int i; + + IVTV_DEBUG(IVTV_DEBUG_I2C, "i2c client detach\n"); + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + if (itv->i2c_clients[i] == client) { + itv->i2c_clients[i] = NULL; + break; + } + } + IVTV_DEBUG(IVTV_DEBUG_I2C, "i2c detach [client=%s,%s]\n", + client->name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed"); + + return 0; +} + + +void ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg) { + int i; + + IVTV_DEBUG(IVTV_DEBUG_I2C, "call_i2c_client\n"); + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + if (NULL == itv->i2c_clients[i]) + continue; + if (NULL == itv->i2c_clients[i]->driver->command) + continue; + if (addr == itv->i2c_clients[i]->addr) { + itv->i2c_clients[i]->driver->command( + itv->i2c_clients[i],cmd,arg); + return; + } + } + IVTV_DEBUG(IVTV_DEBUG_ERR, "i2c client addr: 0x%02x not found!\n",addr); +} + +int ivtv_i2c_direct(struct ivtv *itv, int addr, const unsigned char *regs) { + int i, ret=0; + + IVTV_DEBUG(IVTV_DEBUG_I2C, "i2c_direct\n"); + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + if (NULL == itv->i2c_clients[i]) + continue; + if (addr == itv->i2c_clients[i]->addr) { + ret = writeregs(itv->i2c_clients[i], regs); + break; + } + } + + if (ret) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "error %d writing reg\n", ret); + return -EIO; + } + + return 0; +} + +/* init + register i2c algo-bit adapter */ +int __devinit init_ivtv_i2c(struct ivtv *itv) { + IVTV_DEBUG(IVTV_DEBUG_I2C, "i2c init\n"); + memcpy(&itv->i2c_adap, &ivtv_i2c_adapter_template, + sizeof(struct i2c_adapter)); + memcpy(&itv->i2c_algo, &ivtv_i2c_algo_template, + sizeof(struct i2c_algo_bit_data)); + memcpy(&itv->i2c_client, &ivtv_i2c_client_template, + sizeof(struct i2c_client)); + + sprintf(itv->i2c_adap.name+strlen(itv->i2c_adap.name), + " #%d", itv->num); + itv->i2c_algo.data = itv; + i2c_set_adapdata(&itv->i2c_adap, itv); + itv->i2c_adap.algo_data = &itv->i2c_algo; + itv->i2c_client.adapter = &itv->i2c_adap; + + IVTV_DEBUG(IVTV_DEBUG_I2C, "setting scl and sda to 1\n"); + ivtv_setscl(itv,1); + ivtv_setsda(itv,1); + + itv->i2c_rc = i2c_bit_add_bus(&itv->i2c_adap); + return itv->i2c_rc; +} + +void __devexit exit_ivtv_i2c(struct ivtv *itv) { + IVTV_DEBUG(IVTV_DEBUG_I2C, "i2c exit\n"); + + i2c_bit_del_bus(&itv->i2c_adap); +} + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/ivtv.h 830-ivtv/drivers/media/video/ivtv.h --- 000-virgin/drivers/media/video/ivtv.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/media/video/ivtv.h Thu Jan 8 11:17:36 2004 @@ -0,0 +1,847 @@ +#ifndef IVTV_H +#define IVTV_H + +/* Header for ivtv project: + * Driver for the iTVC15 chip. + * Author: Kevin Thayer (nufan_wfk at yahoo.com) + * License: GPL + * http://www.sourceforge.net/projects/ivtv/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "msp3400.h" +/* If you don't want to patch to v4l2, grab a copy of + * videodev2.h and put it in the same dir as this file */ +#ifndef HAVE_V4L2 + #define HAVE_V4L2 1 + #include "videodev2.h" +#endif +#include +#include +#include + +#ifndef CONFIG_PCI +# error "This driver requires kernel PCI support." +#endif + +#define IVTV_ENCODER_OFFSET 0x00000000 +#define IVTV_ENCODER_SIZE 0x01000000 + +#define IVTV_DECODER_OFFSET 0x01000000 +#define IVTV_DECODER_SIZE 0x01000000 + +#define IVTV_ENCDEC_SIZE (IVTV_ENCODER_SIZE + IVTV_DECODER_SIZE) + +#define IVTV_REG_OFFSET 0x02000000 +#define IVTV_REG_SIZE 0x00010000 + +#define IVTV_IOREMAP_SIZE (IVTV_ENCDEC_SIZE + IVTV_REG_SIZE) + +#define IVTV_IOREMAP_ERROR "ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h " \ + "or disabling CONFIG_HIMEM4G into the kernel would help" + +/* General */ +#define IVTV_DRIVER_NAME "ivtv" +#define IVTV_DRIVER_VERSION_MAJOR 0 +#define IVTV_DRIVER_VERSION_MINOR 1 +#define IVTV_DRIVER_VERSION_PATCHLEVEL 8 +#define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL) +#define IVTV_MAX_CARDS 9 +#define IVTV_DEFAULT_NUM_CARDS 1 +#define IVTV_MAX_YUV_BUFFERS 500 +#define IVTV_MIN_YUV_BUFFERS 40 +#define IVTV_DEFAULT_YUV_BUFFERS 60 +#define IVTV_MAX_MPG_BUFFERS 100 +#define IVTV_MIN_MPG_BUFFERS 15 +#define IVTV_DEFAULT_MPG_BUFFERS IVTV_MAX_MPG_BUFFERS +#define IVTV_MAX_DEC_YUV_BUFFERS 500 +#define IVTV_MIN_DEC_YUV_BUFFERS 17 +#define IVTV_DEFAULT_DEC_YUV_BUFFERS 0 +#define IVTV_MAX_DEC_MPG_BUFFERS 100 +#define IVTV_MIN_DEC_MPG_BUFFERS 5 +#define IVTV_DEFAULT_DEC_MPG_BUFFERS 8 +#define IVTV_MAX_VBI_BUFFERS 100 +#define IVTV_MIN_VBI_BUFFERS 3 +#define IVTV_DEFAULT_VBI_BUFFERS 10 +#define IVTV_MIN_DEC_MPG_QLEN 0 +#define IVTV_DEFAULT_DEC_MPG_QLEN 2 +#define IVTV_MIN_DEC_YUV_QLEN 0 +#define IVTV_DEFAULT_DEC_YUV_QLEN 0 +#define IVTV_IOCTL_SET_DEBUG_LEVEL _IOWR('@', 98, int *) +#define IVTV_IOCTL_GET_DEBUG_LEVEL _IOR('@', 99, int *) + +#define IVTV_PCI_ID_250_V1 0x4001 /* subsystem id */ +#define IVTV_PCI_ID_250_V2 0x4009 +#define IVTV_PCI_ID_250_V3 0x4801 /* treat like 250_V1 */ +#define IVTV_PCI_ID_250_V4 0x4803 /* treat like 250_V2 */ +#define IVTV_PCI_ID_350_V1 0x4000 +#define IVTV_PCI_ID_350_V2 0x4800 /* treat like 350_V1 */ +#define IVTV_250_V1 0 /* wintv pvr 250, encoder and decoder */ +#define IVTV_250_V2 1 /* pvr 250, encoder only */ +#define IVTV_350_V1 2 /* encoder, decoder, tv-out */ +#define IVTV_250_V1_STREAMS 3 +#define IVTV_250_V2_STREAMS 3 +#define IVTV_350_V1_STREAMS 5 +#define IVTV_V4L2_DEC_OFFSET 16 /* offset from 0 to register dec. v4l2 minors on */ +#define IVTV_V4L2_YUV_OFFSET 32 /* offset from 0 to register yuv v4l2 minors on */ + +#define IVTV_ENC_STREAM_TYPE_MPG 0 +#define IVTV_ENC_STREAM_TYPE_YUV 1 +#define IVTV_ENC_STREAM_TYPE_VBI 2 +#define IVTV_DEC_STREAM_TYPE_MPG 3 +#define IVTV_DEC_STREAM_TYPE_YUV 4 + +#define IVTV_ENC_MEM_START 0x00000000 +#define IVTV_DEC_MEM_START 0x01000000 +#define PCI_VENDOR_ID_ICOMP 0x4444 +#define PCI_DEVICE_ID_IVTV15 0x0803 +#define PCI_DEVICE_ID_IVTV16 0x0016 +#define IVTV_DEVNAME "ivtv: iTVC15/16 mpg2 encoder chip" +#define IVTV_MBOX_MAX_BOXES 20 +#define IVTV_MBOX_API_BOXES 6 +#define IVTV_MBOX_DMA_START 6 +#define IVTV_MBOX_DMA_END 8 +#define IVTV_MBOX_MAX_DATA 16 +#define IVTV_MBOX_DMA 9 +#define IVTV_MBOX_FIELD_DISPLAYED 8 +#define IVTV_MBOX_SIZE 80 +#define IVTV_SAA7115_I2C_ADDR 0x21 +#define IVTV_TUNER_I2C_ADDR 0x61 +#define IVTV_MSP3400_I2C_ADDR 0x40 +#define IVTV_DMA_BUF_SIZE 34560 /* 0x8000 = 32kbytes, 0x20000 = 128kbytes */ +#define IVTV_DMA_DEC_BUF_SIZE 32768 /* 0x8000 = 32kbytes, 0x20000 = 128kbytes */ +//#define IVTV_DMA_BUF_SIZE 65536 /* 0x8000 = 32kbytes, 0x20000 = 128kbytes */ +//#define IVTV_DMA_DEC_BUF_SIZE 65536 /* 0x8000 = 32kbytes, 0x20000 = 128kbytes */ + +#define IVTV_DMA_MAX_XFER 0x00080000 /* 0x8000 = 32kbytes, 0x20000 = 128kbytes */ +#define IVTV_DEC_MIN_BUF 0x00050000 /* want this many bytes+ in decoder buffer */ +#define IVTV_SLEEP_WAIT (HZ/10) /*100 ms*/ +#define IVTV_MAX_DATA_SLEEP 30 +#define DEC_DMA_TIMEOUT (15*HZ/100) /* used to be 100/15 */ + +#define IVTV_DMA_ERR_LIST 0x00000008 +#define IVTV_DMA_ERR_WRITE 0x00000004 +#define IVTV_DMA_ERR_READ 0x00000002 +#define IVTV_DMA_SUCCESS 0x00000001 +#define IVTV_DMA_READ_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_READ) +#define IVTV_DMA_WRITE_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_WRITE) +#define IVTV_DMA_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_WRITE | IVTV_DMA_ERR_READ) + +/* video related */ +#define IVTV_MAX_INPUTS 9 + +/*ioctl's*/ +#define IVTV_CTL_PRINTBOXES 0x00000001 +#define IVTV_CTL_CLEANUP 0x00000002 +#define IVTV_CTL_INIT_VIDCAP 0x00000003 + +/* Registers */ +#define IVTV_REG_DMASTATUS (0x0004 /*| IVTV_REG_OFFSET*/) +#define IVTV_REG_IRQSTATUS (0x0040 /*| IVTV_REG_OFFSET*/) +#define IVTV_REG_IRQMASK (0x0048 /*| IVTV_REG_OFFSET*/) +#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8 /*| IVTV_REG_OFFSET*/) +#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC /*| IVTV_REG_OFFSET*/) +#define IVTV_REG_DEC_SDRAM_REFRESH (0x08F8 /*| IVTV_REG_OFFSET*/) +#define IVTV_REG_DEC_SDRAM_PRECHARGE (0x08FC /*| IVTV_REG_OFFSET*/) +#define IVTV_REG_VDM (0x2800 /*| IVTV_REG_OFFSET*/) +#define IVTV_REG_AO (0x2D00 /*| IVTV_REG_OFFSET*/) +#define IVTV_REG_BYTEFLUSH (0x2D24 /*| IVTV_REG_OFFSET*/) +#define IVTV_REG_SPU (0x9050 /*| IVTV_REG_OFFSET*/) +#define IVTV_REG_HW_BLOCKS (0x9054 /*| IVTV_REG_OFFSET*/) +#define IVTV_REG_VPU (0x9058 /*| IVTV_REG_OFFSET*/) +#define IVTV_REG_APU (0xA064 /*| IVTV_REG_OFFSET*/) + +/* IRQ Masks */ +#define IVTV_IRQ_MASK_DEFAULT 0x00000404 /*stuff to ignore*/ +#define IVTV_IRQ_MASK_CAPTURE 0xFC000400 /*inverse mask, we want the high bits!*/ +#define IVTV_IRQ_MASK_DECODE 0x00FC0400 + +#define IVTV_IRQ_ENC_START_CAP (0x1 << 31) +#define IVTV_IRQ_ENC_EOS (0x1 << 30) +#define IVTV_IRQ_ENC_VBI_CAP (0x1 << 29) +#define IVTV_IRQ_ENC_VIM_RST (0x1 << 28) +#define IVTV_IRQ_ENC_DMA_COMPLETE (0x1 << 27) + +#define IVTV_IRQ_DEC_COPY_PROTECT (0x1 << 25) +#define IVTV_IRQ_DEC_AUD_MODE_CHG (0x1 << 24) +#define IVTV_IRQ_DEC_DATA_REQ (0x1 << 22) +#define IVTV_IRQ_DEC_IFRAME_DONE (0x1 << 21) +#define IVTV_IRQ_DEC_DMA_COMPLETE (0x1 << 20) +#define IVTV_IRQ_DEC_VBI_RE_INSERT (0x1 << 19) +#define IVTV_IRQ_DEC_DMA_ERR (0x1 << 18) +#define IVTV_IRQ_DEC_VSYNC (0x1 << 10) + +#define IVTV_IRQ_DEBUG_KLUGE ( IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_EOS | IVTV_IRQ_ENC_VBI_CAP | IVTV_IRQ_ENC_VIM_RST | IVTV_IRQ_ENC_DMA_COMPLETE | IVTV_IRQ_DEC_COPY_PROTECT | IVTV_IRQ_DEC_AUD_MODE_CHG | IVTV_IRQ_DEC_DATA_REQ | IVTV_IRQ_DEC_IFRAME_DONE | IVTV_IRQ_DEC_DMA_COMPLETE | IVTV_IRQ_DEC_VBI_RE_INSERT | IVTV_IRQ_DEC_DMA_ERR ) + +/* commands */ +#define IVTV_MASK_SPU_ENABLE 0xFFFFFFFE +#define IVTV_MASK_VPU_ENABLE15 0xFFFFFFF6 +#define IVTV_MASK_VPU_ENABLE16 0xFFFFFFFB +#define IVTV_CMD_VDM_STOP 0x00000000 +#define IVTV_CMD_AO_STOP 0x00000005 +#define IVTV_CMD_APU_PING 0x00000000 +#define IVTV_CMD_VPU_STOP15 0xFFFFFFFE +#define IVTV_CMD_VPU_STOP16 0xFFFFFFEE +#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF +#define IVTV_CMD_SPU_STOP 0x00000001 +#define IVTV_CMD_SDRAM_PRECHARGE_INIT 0x0000001A +#define IVTV_CMD_SDRAM_REFRESH_INIT 0x80000640 +#define IVTV_SDRAM_SLEEPTIME (60 * HZ / 100) /* 600ms */ + +/*Used for locating the firmware mailboxes*/ +#define IVTV_FIRM_ENC_FILENAME "/lib/modules/ivtv-fw-enc.bin" +#define IVTV_FIRM_DEC_FILENAME "/lib/modules/ivtv-fw-dec.bin" +#define IVTV_FIRM_IMAGE_SIZE 256*1024 +#define IVTV_FIRM_SEARCH_ENCODER_START IVTV_ENCODER_OFFSET +#define IVTV_FIRM_SEARCH_DECODER_START IVTV_DECODER_OFFSET +#define IVTV_FIRM_SEARCH_ENCODER_END (IVTV_ENCODER_OFFSET + IVTV_ENCODER_SIZE - 1) +#define IVTV_FIRM_SEARCH_DECODER_END (IVTV_DECODER_OFFSET + IVTV_DECODER_SIZE - 1) +#define IVTV_FIRM_SEARCH_STEP 0x00000100 + +/* Firmware mailbox flags*/ +#define IVTV_MBOX_FIRMWARE_DONE 0x00000004 +#define IVTV_MBOX_DRIVER_DONE 0x00000002 +#define IVTV_MBOX_IN_USE 0x00000001 +#define IVTV_MBOX_FREE 0x00000000 + +/*Firmware API commands*/ +#define IVTV_API_ENC_GETVER 0x000000C4 +#define IVTV_API_DEC_GETVER 0x00000011 +#define IVTV_API_ENC_HALT_FW 0x000000C3 +#define IVTV_API_DEC_HALT_FW 0x0000000E +#define IVTV_API_DEC_START_PLAYBACK 0x00000001 +#define IVTV_API_DEC_STOP_PLAYBACK 0x00000002 +#define IVTV_API_DEC_PLAYBACK_SPEED 0x00000003 +#define IVTV_API_DEC_PAUSE_PLAYBACK 0x0000000d +#define IVTV_API_DEC_DMA_BLOCKSIZE 0x00000008 +#define IVTV_API_DEC_DMA_FROM_HOST 0x00000000b +#define IVTV_API_DEC_DISP_STANDARD 0x00000010 +#define IVTV_API_DEC_STREAM_INPUT 0x00000014 +#define IVTV_API_DEC_TIMING_INFO 0x00000015 +#define IVTV_API_DEC_SELECT_AUDIO 0x00000016 +#define IVTV_API_DEC_EVENT_NOTIFICATION 0x00000017 +#define IVTV_API_DEC_DISPLAY_BUFFERS 0x00000018 +#define IVTV_API_DEC_DECODE_SOURCE 0x0000001a +#define IVTV_API_DEC_AUDIO_OUTPUT 0x0000001b +#define IVTV_API_DEC_SET_AV_DELAY 0x0000001c +#define IVTV_API_DEC_BUFFER 0x0000001e +#define IVTV_API_DEC_DMA_STATUS 0x0000000a +#define IVTV_API_DEC_XFER_INFO 0x00000009 +#define IVTV_API_STD_TIMEOUT 0x00010000 /*units??*/ +#define IVTV_API_ASSIGN_DMA_BLOCKLEN 0x000000c9 +#define IVTV_API_ASSIGN_PGM_INDEX_INFO 0x000000c7 +#define IVTV_API_ASSIGN_STREAM_TYPE 0x000000b9 +#define IVTV_API_ASSIGN_OUTPUT_PORT 0x000000bb +#define IVTV_API_ASSIGN_FRAMERATE 0x0000008f +#define IVTV_API_ASSIGN_FRAME_SIZE 0x00000091 +#define IVTV_API_ASSIGN_ASPECT_RATIO 0x00000099 +#define IVTV_API_ASSIGN_BITRATES 0x00000095 +#define IVTV_API_ASSIGN_GOP_PROPERTIES 0x00000097 +#define IVTV_API_ASSIGN_3_2_PULLDOWN 0x000000b1 +#define IVTV_API_ASSIGN_GOP_CLOSURE 0x000000c5 +#define IVTV_API_ASSIGN_AUDIO_PROPERTIES 0x000000bd +#define IVTV_API_ASSIGN_DNR_FILTER_MODE 0x0000009b +#define IVTV_API_ASSIGN_DNR_FILTER_PROPS 0x0000009d +#define IVTV_API_ASSIGN_CORING_LEVELS 0x0000009f +#define IVTV_API_ASSIGN_SPATIAL_FILTER_TYPE 0x000000a1 +#define IVTV_API_ASSIGN_FRAME_DROP_RATE 0x000000d0 +#define IVTV_API_ASSIGN_PLACEHOLDER 0x000000d8 +#define IVTV_API_INITIALIZE_INPUT 0x000000cd +#define IVTV_API_ASSIGN_NUM_VSYNC_LINES 0x000000d6 +#define IVTV_API_BEGIN_CAPTURE 0x00000081 +#define IVTV_API_PAUSE_ENCODER 0x000000d2 +#define IVTV_API_EVENT_NOTIFICATION 0x000000d5 +#define IVTV_API_END_CAPTURE 0x00000082 +#define IVTV_API_SCHED_DMA_TO_HOST 0x000000cc +#define IVTV_API_FB_GET_FRAMEBUFFER 0x00000041 +#define IVTV_API_FB_GET_PIXEL_FORMAT 0x00000042 +#define IVTV_API_FB_SET_PIXEL_FORMAT 0x00000043 +#define IVTV_API_FB_GET_STATE 0x00000044 +#define IVTV_API_FB_SET_STATE 0x00000045 +#define IVTV_API_FB_GET_OSD_COORDS 0x00000046 +#define IVTV_API_FB_SET_OSD_COORDS 0x00000047 +#define IVTV_API_FB_GET_SCREEN_COORDS 0x00000048 +#define IVTV_API_FB_SET_SCREEN_COORDS 0x00000049 +#define IVTV_API_FB_GET_GLOBAL_ALPHA 0x0000004a +#define IVTV_API_FB_SET_GLOBAL_ALPHA 0x0000004b +#define IVTV_API_FB_SET_BLEND_COORDS 0x0000004c +// 0x4d unknown +// 0x4e unknown +#define IVTV_API_FB_GET_FLICKER_STATE 0x0000004f +#define IVTV_API_FB_SET_FLICKER_STATE 0x00000050 +// 0x51 unknown +#define IVTV_API_FB_BLT_COPY 0x00000052 +#define IVTV_API_FB_BLT_FILL 0x00000053 +#define IVTV_API_FB_BLT_TEXT 0x00000054 +// 0x55 unknown +#define IVTV_API_FB_SET_FRAMEBUFFER_WINDOW 0x00000056 +// 0x57 - 0x5f unknown +#define IVTV_API_FB_SET_CHROMA_KEY 0x00000060 +#define IVTV_API_FB_GET_ALPHA_CONTENT_INDEX 0x00000061 +#define IVTV_API_FB_SET_ALPHA_CONTENT_INDEX 0x00000062 + +/* i2c stuff */ +#define I2C_CLIENTS_MAX 16 +#define I2C_TIMING (0x7<<4) +#define IVTV_REG_I2C_SETSCL_OFFSET (0x7000 /*| IVTV_REG_OFFSET*/) +#define IVTV_REG_I2C_SETSDA_OFFSET (0x7004 /*| IVTV_REG_OFFSET*/) +#define IVTV_REG_I2C_GETSCL_OFFSET (0x7008 /*| IVTV_REG_OFFSET*/) +#define IVTV_REG_I2C_GETSDA_OFFSET (0x700c /*| IVTV_REG_OFFSET*/) + +/* debugging */ +#define IVTV_DEBUG_ERR (1 << 0) +#define IVTV_DEBUG_INFO (1 << 1) +#define IVTV_DEBUG_API (1 << 2) +#define IVTV_DEBUG_DMA (1 << 3) +#define IVTV_DEBUG_IOCTL (1 << 4) +#define IVTV_DEBUG_I2C (1 << 5) +#define IVTV_DEBUG_IRQ (1 << 6) +#define IVTV_DEBUG(x,args...) if((x)&ivtv_debug) printk("ivtv: " args); +#define IVTV_DEBUG_FB(x,args...) if((x)&ivtv_debug) printk("ivtv-fb: " args); + +/* Temp saa7115 hack FIXME */ +#define DECODER_SET_SIZE 76598 +#define DECODER_GET_PICTURE 76599 + +/* Values for IVTV_API_DEC_PLAYBACK_SPEED mpeg_frame_type_mask parameter: */ +#define MPEG_FRAME_TYPE_IFRAME 1 +#define MPEG_FRAME_TYPE_IFRAME_PFRAME 3 +#define MPEG_FRAME_TYPE_ALL 7 + +/* External API stuff */ +#define IVTV_IOC_FWAPI 0xFFEE7701 /*just some values i picked for now*/ +#define IVTV_IOC_ZCOUNT 0xFFEE7702 +#define IVTV_IOC_G_CODEC 0xFFEE7703 +#define IVTV_IOC_S_CODEC 0xFFEE7704 + +/* allow direct access to the saa7115 registers for testing */ +#define SAA7115_GET_REG 0xFFEE7705 +#define SAA7115_SET_REG 0xFFEE7706 + + +#define DECODER_SET_AUDIO 0xFFEE7707 +#define DECODER_AUDIO_32_KHZ 0 +#define DECODER_AUDIO_441_KHZ 1 +#define DECODER_AUDIO_48_KHZ 2 + +#define IVTV_IOC_PLAY 0xFFEE7781 +#define IVTV_IOC_PAUSE 0xFFEE7782 +#define IVTV_IOC_FRAMESYNC 0xFFEE7783 +#define IVTV_IOC_GET_TIMING 0xFFEE7784 +#define IVTV_IOC_S_SLOW_FAST 0xFFEE7785 +#define IVTV_IOC_S_START_DECODE 0xFFEE7786 +#define IVTV_IOC_S_STOP_DECODE 0xFFEE7787 +#define IVTV_IOC_S_OSD 0xFFEE7788 +#define IVTV_IOC_GET_FB 0xFFEE7789 + +#define IVTV_IOC_STOP_DECODE _IOW('@', 30, struct ivtv_cfg_stop_decode) +#define IVTV_IOC_G_SPEED _IOR('@', 31, struct ivtv_speed) +#define IVTV_IOC_S_SPEED _IOW('@', 32, struct ivtv_speed) + +/* Framebuffer external API */ +/* NOTE: These must *exactly* match the structures and constants in driver/ivtv.h */ + +struct ivtvfb_ioctl_state_info { + unsigned long status; + unsigned long alpha; +}; + +struct ivtvfb_ioctl_blt_copy_args { + int x, y, width, height, source_offset, source_stride; +}; + +struct ivtvfb_ioctl_dma_host_to_ivtv_args { + void* source; + unsigned long dest_offset; + int count; +}; + +struct ivtvfb_ioctl_get_frame_buffer { + void* mem; + int bytes; + int sizex; + int sizey; +}; + +struct ivtv_osd_coords { + unsigned long offset; + unsigned long max_offset; + int pixel_stride; + int lines; + int x; + int y; +}; + +struct rectangle { + int x0; + int y0; + int x1; + int y1; +}; + +#define IVTVFB_IOCTL_GET_STATE _IOR('@', 1, struct ivtvfb_ioctl_state_info) +#define IVTVFB_IOCTL_SET_STATE _IOW('@', 2, struct ivtvfb_ioctl_state_info) +#define IVTVFB_IOCTL_PREP_FRAME _IOW('@', 3, struct ivtvfb_ioctl_dma_host_to_ivtv_args) +#define IVTVFB_IOCTL_BLT_COPY _IOW('@', 4, struct ivtvfb_ioctl_blt_copy_args) +#define IVTVFB_IOCTL_GET_ACTIVE_BUFFER _IOR('@', 5, struct ivtv_osd_coords) +#define IVTVFB_IOCTL_SET_ACTIVE_BUFFER _IOW('@', 6, struct ivtv_osd_coords) +#define IVTVFB_IOCTL_GET_FRAME_BUFFER _IOR('@', 7, struct ivtvfb_ioctl_get_frame_buffer) + +#define IVTVFB_STATUS_ENABLED (1 << 0) +#define IVTVFB_STATUS_GLOBAL_ALPHA (1 << 1) +#define IVTVFB_STATUS_LOCAL_ALPHA (1 << 2) +#define IVTVFB_STATUS_FLICKER_REDUCTION (1 << 3) + +/* Stream types */ +#define IVTV_STREAM_PS 0 +#define IVTV_STREAM_TS 1 +#define IVTV_STREAM_MPEG1 2 +#define IVTV_STREAM_PES_AV 3 +#define IVTV_STREAM_PES_V 5 +#define IVTV_STREAM_PES_A 7 +#define IVTV_STREAM_DVD 10 +#define IVTV_STREAM_VCD 11 +#define IVTV_STREAM_SVCD 12 +#define IVTV_STREAM_DVD_S1 13 +#define IVTV_STREAM_DVD_S2 14 + +/* Custom v4l controls */ +#ifndef V4L2_CID_PRIVATE_BASE +#define V4L2_CID_PRIVATE_BASE 0x08000000 +#endif + +#define V4L2_CID_IVTV_FREQ (V4L2_CID_PRIVATE_BASE) +#define V4L2_CID_IVTV_ENC (V4L2_CID_PRIVATE_BASE + 1) +#define V4L2_CID_IVTV_BITRATE (V4L2_CID_PRIVATE_BASE + 2) +#define V4L2_CID_IVTV_MONO (V4L2_CID_PRIVATE_BASE + 3) +#define V4L2_CID_IVTV_JOINT (V4L2_CID_PRIVATE_BASE + 4) +#define V4L2_CID_IVTV_EMPHASIS (V4L2_CID_PRIVATE_BASE + 5) +#define V4L2_CID_IVTV_CRC (V4L2_CID_PRIVATE_BASE + 6) +#define V4L2_CID_IVTV_COPYRIGHT (V4L2_CID_PRIVATE_BASE + 7) +#define V4L2_CID_IVTV_GEN (V4L2_CID_PRIVATE_BASE + 8) + +#define IVTV_V4L2_AUDIO_MENUCOUNT 9 /* # of v4l controls */ + +#define IVTV_DEC_PRIVATE_BASE (V4L2_CID_PRIVATE_BASE + IVTV_V4L2_AUDIO_MENUCOUNT) + +#define V4L2_CID_IVTV_DEC_SMOOTH_FF (IVTV_DEC_PRIVATE_BASE + 0) +#define V4L2_CID_IVTV_DEC_FR_MASK (IVTV_DEC_PRIVATE_BASE + 1) +#define V4L2_CID_IVTV_DEC_SP_MUTE (IVTV_DEC_PRIVATE_BASE + 2) +#define V4L2_CID_IVTV_DEC_FR_FIELD (IVTV_DEC_PRIVATE_BASE + 3) +#define V4L2_CID_IVTV_DEC_AUD_SKIP (IVTV_DEC_PRIVATE_BASE + 4) +#define V4L2_CID_IVTV_DEC_NUM_BUFFERS (IVTV_DEC_PRIVATE_BASE + 5) +#define V4L2_CID_IVTV_DEC_PREBUFFER (IVTV_DEC_PRIVATE_BASE + 6) + +#define IVTV_V4L2_DEC_MENUCOUNT 7 + +#ifdef SAA7115_REGTEST +/* allow direct access to the saa7115 registers for testing */ +#define SAA7115_GET_REG 0xFFEE7705 +#define SAA7115_SET_REG 0xFFEE7706 + +struct saa7115_reg_t { + u8 reg; + u8 val; +}; +#endif +struct saa7114 { + int norm; + int input; + int enable; + int bright; + int contrast; + int hue; + int sat; + int playback; +}; + + +struct ivtv_cfg_start_decode { + u32 gop_offset; /*Frames in GOP to skip before starting */ + u32 muted_audio_frames; /* #of audio frames to mute */ +}; + +struct ivtv_cfg_stop_decode { + int hide_last; /* 1 = show black after stop, 0 = show last frame */ + u64 pts_stop; /* PTS to stop at */ +}; + +struct ivtv_speed { + int scale; /* 1-?? (50 for now) */ + int smooth; /* Smooth mode when in slow/fast mode */ + int speed; /* 0 = slow, 1 = fast */ + int direction; /* 0 = forward, 1 = reverse (not supportd */ + int fr_mask; /* 0 = I, 1 = I,P, 2 = I,P,B */ + int b_per_gop; /* frames per GOP (reverse only) */ + int aud_mute; /* Mute audio while in slow/fast mode */ + int fr_field; /* 1 = show every field, 0 = show every frame */ + int mute; /* # of audio frames to mute on playback resume */ +}; + +struct ivtv_slow_fast { + int speed; /* 0 = slow, 1 = fast */ + int scale; /* 1-?? (50 for now) */ +}; + +struct ivtv_ioctl_fwapi { + u32 cmd; + u32 result; + int args; + u32 data[IVTV_MBOX_MAX_DATA]; +}; + +struct ivtv_ioctl_framesync { + u32 frame; + u64 pts; + u64 scr; +}; + +struct ivtv_audio_meta { + struct v4l2_queryctrl *ctrl; + struct v4l2_querymenu *menu; + u32 *table; + u32 mask; + s32 setting; +}; + +/* For use with IVTV_IOC_G_CODEC and IVTV_IOC_S_CODEC */ +struct ivtv_ioctl_codec { + u32 aspect; + u32 audio_bitmap; + u32 bframes; + u32 bitrate_mode; + u32 bitrate; + u32 bitrate_peak; + u32 dnr_mode; + u32 dnr_spatial; + u32 dnr_temporal; + u32 dnr_type; + u32 framerate; + u32 framespergop; + u32 gop_closure; + u32 pulldown; + u32 stream_type; +}; + +extern int ivtv_debug; +extern int ivtv_pal; + +/* Scatter-Gather array element, used in DMA transfers */ +struct ivtv_SG_element { + u32 src; + u32 dst; + u32 size; +}; + +/* ivtv-specific mailbox template */ +struct ivtv_mailbox { + u32 flags; + u32 cmd; + u32 retval; + u32 timeout; + u32 data[IVTV_MBOX_MAX_DATA]; +}; + +struct ivtv_state { + unsigned long freq; /* Current tuned frequency */ + int input; /* Current digitizer input */ + u32 flags;/* tuner, audio */ + u16 type; /* tv or camera */ + u16 norm; /* Current video standard */ + /* more to come! */ +}; + +struct ivtv_buffer { + size_t readpos; + dma_addr_t dma_handle; + struct v4l2_buffer buffer; + struct list_head list; + unsigned long ts; +}; + +struct ivtv_buffer_list { + struct video_device *vdev; /* to get itv from */ + int elements; + struct list_head list; +}; + +struct ivtv_options { + int yuv_fixup; /* Should we re-work YUV to a standard format? */ + int yuv_buffers; /* How many yuv buffers to allocate? */ + int mpg_buffers; /* how many mpg buffers to allocate? */ + int vbi_buffers; /* how many vbi buffers to allocate? */ + int dec_mpg_buffers; /* how many decoder mpg buffers to allocate? */ + int dec_yuv_buffers; /* How many decoder yuv buffers to allocate? */ + int dec_mpg_qlen; /* how many decoder mpg buffers to queue? */ + int dec_yuv_qlen; /* how many decoder yuv buffers to queue? */ + int num_devices; /* how many cards to detect? */ +}; + +struct ivtv_dec_options { + int hide_last_frame; /* 0 = display last frame on stop_decode + * 1 = display black */ + u32 pts_low; /* low bits PTS to stop playback at */ + u32 pts_hi; /* hi bits PTS to stop playback at */ + int gop_offset; /* on start-playback, skip this + * # of frames in the GOP */ + int mute_frames; /* # of audio frames to mute on playback start */ + int decbuffers; /* 0 = 6 buffers, 1 = 9 buffers */ + int prebuffer; /* 0 = no prebuffer, 1 = enabled, see docs */ + struct ivtv_speed speed; +}; + +/* per-stream, s_flags */ +#define IVTV_F_S_DMAP 0 +#define IVTV_F_S_OVERFLOW 1 +#define IVTV_F_S_CAP 2 + +/* per-ivtv, i_flags */ +#define IVTV_F_I_BUSY 0 +#define IVTV_F_I_NEEDS_DATA 1 +#define IVTV_F_I_EOS 2 +#define IVTV_F_I_OSD_DMA 3 + +struct ivtv_v4l2_stream { + int buf_size; /* size of buffers this stream */ + long id; + long seq; + int ubytes; /* bytes written back to user this frame */ + unsigned long s_flags; + int v4l_reg_type; + wait_queue_head_t waitq; + struct video_device *v4l2dev; + struct v4l2_format format; + + // FIXME need to make sure no read() if streaming + struct ivtv_buffer_list free_q; /* unused buffers */ + struct ivtv_buffer_list full_q; /* filled buffers */ + struct ivtv_buffer_list dma_q; /* awaiting dma to fill them */ + /* only updated in interrupt time! */ + + int controlcount; /* Number of elements in controls */ + struct v4l2_control *controls; +}; + +struct ivtv_v4l2_table { + int count; + int active; + union { + struct v4l2_input *input; + struct v4l2_output *output; + struct v4l2_audio *audio; + struct v4l2_tuner *tuner; + struct v4l2_control *control; + struct v4l2_standard *std; + } table; +}; + +struct ivtv_v4l2 { + u32 capabilities; + struct ivtv_v4l2_table input; + int audio_output; + struct ivtv_v4l2_table output; + struct ivtv_v4l2_table audio; + struct ivtv_v4l2_table tuner; + struct ivtv_v4l2_table standard; + struct v4l2_capability capability; + struct v4l2_frequency freq; + int streamcount; /* Number of elements in streams */ + struct ivtv_v4l2_stream *streams; + + /* codec settings */ + struct ivtv_ioctl_codec codec; + struct ivtv_audio_meta audio_meta[IVTV_V4L2_AUDIO_MENUCOUNT]; + + /* FIXME probably should get rid of this */ + wait_queue_head_t waitq; +}; + +struct ivtv_open_id { + int open_id; + int type; + struct ivtv *itv; + struct list_head list; +}; + +struct ivtvfb_user_dma_to_device { + int page_count; + struct ivtv_SG_element* sglist; + struct page **map; + dma_addr_t sg_dma_handle; +}; + + + +/* Stuct to hold info about ivtv cards */ +struct ivtv { + int card_type; /* pvr 250 rev1, 250 rev2, 350 are options so far */ + struct pci_dev *dev; + struct ivtv_options options; + struct ivtv_dec_options dec_options; + int num; /* invalidate during init! */ + int first_read; /* used to clean up stream */ + unsigned long i_flags; + atomic_t capturing; + atomic_t decoding; + struct semaphore sem_lock __cacheline_aligned_in_smp; + spinlock_t lock __cacheline_aligned_in_smp; + + long open_id; /* incremented each time an open occurs + used as unique ID */ + + /* FIXME should use part of v4l2_performace instead */ + unsigned long trans_id; + + struct tasklet_struct dma_sched_tq; + + u32 enc_fw_ver, dec_fw_ver, base_addr; /*is base_addr needed? */ + u32 irqmask; + + struct ivtv_mailbox *enc_mbox, *dec_mbox; + struct semaphore enc_msem __cacheline_aligned_in_smp; + struct semaphore dec_msem __cacheline_aligned_in_smp; + + unsigned char card_rev, *io_mem, *reg_mem; + + wait_queue_head_t cap_w, vsync_w; + + /*FIXME perhaps move these to the v4l2_stream struct */ + struct ivtv_SG_element *SGarray, *DSGarray; + dma_addr_t SG_handle, DSG_handle; + + /* Decoder */ + struct ivtv_ioctl_framesync dec_timestamp; + wait_queue_head_t dec_master_w; + struct timer_list dec_timeout; + + /* Framebuffer DMA support */ + struct ivtvfb_user_dma_to_device* user_dma_to_device_state; + int fb_id; + + /* i2c */ + struct i2c_adapter i2c_adap; + struct i2c_algo_bit_data i2c_algo; + struct i2c_client i2c_client; + int i2c_state, i2c_rc, i2c_command; + struct i2c_client *i2c_clients[I2C_CLIENTS_MAX]; + + /* v4l2 and User settings*/ + struct ivtv_state state; + struct ivtv_v4l2 v4l2; + struct list_head client_list; +}; + +/* Globals */ +extern struct ivtv ivtv_cards[]; +extern int ivtv_cards_active; +extern int dec_yuv_buffers; +extern int dec_mpg_buffers; +extern int yuv_buffers; +extern int mpg_buffers; +extern int vbi_buffers; +extern spinlock_t ivtv_lock; + +/*==============Prototypes==================*/ +/* FIXME some of these proably need fine-tuning + * to avoid warnings + */ + +void ivtv_setscl(void *data, int state); +void ivtv_setsda(void *data, int state); +int ivtv_getscl(void *data); +int ivtv_getsda(void *data); + +void ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg); +int ivtv_i2c_direct(struct ivtv *itv, int addr, const unsigned char *regs); + +void ivtv_inc(struct i2c_adapter *adapter); +void ivtv_dec(struct i2c_adapter *adapter); + +/* init + register i2c algo-bit adapter */ +int __devinit init_ivtv_i2c(struct ivtv *itv); +void __devexit exit_ivtv_i2c(struct ivtv *itv); + +/* end i2c stuff */ + +/* Initialization stuff */ +int ivtv_firmware_copy(struct ivtv *itv); + +/* Unload stuff */ +void ivtv_v4l2_cleanup(struct ivtv *itv); +int ivtv_stop_firmware(struct ivtv *itv); +void ivtv_zero_usage_count(void); + +/* API Related */ +int ivtv_find_firmware_mailbox(struct ivtv *itv); +int ivtv_get_free_mailbox(struct ivtv_mailbox *mbox); +int ivtv_api_call(struct ivtv_mailbox *mbox, u32 cmd, struct semaphore *sem, + int elements, u32 data[]); +int ivtv_api_getresult_nosleep(struct ivtv_mailbox *mbox, u32 *result, u32 data[]); +int ivtv_api_getresult(struct ivtv_mailbox *mbox, struct semaphore *sem, + u32 *result, u32 data[]); +int ivtv_api(struct ivtv_mailbox *mbox, struct semaphore *sem, int cmd, + u32 *result, int args, u32 data[]); +extern int __ivtv_api(struct ivtv_mailbox *mbox, int cmd, + u32 *result, int args, u32 data[]); +int ivtv_v4l2_setup(struct ivtv *itv); + +/* Capture related */ +int ivtv_stop_all_captures(struct ivtv *itv); +int ivtv_stop_capture(struct ivtv_open_id *id); +long ivtv_read(struct ivtv_open_id *id, char *ubuf, size_t count, int block); +int ivtv_get_timing_info(struct ivtv *itv, struct ivtv_ioctl_framesync *info); +ssize_t ivtv_write(struct ivtv_open_id *id, const char *buf, size_t count, + int block); +unsigned int ivtv_poll(struct file *filp, poll_table *wait); +unsigned int ivtv_dec_poll(struct file *filp, poll_table *wait); + /* makes a queue complete with 'length' items */ + /* NOTE: This returns the # of buffers allocated */ +extern int ivtv_init_queue(struct ivtv *itv,struct ivtv_buffer_list *queue, + int length, enum v4l2_buf_type type); + /* moves all items in queue 'src' to queue 'dst' */ +extern int ivtv_move_queue(struct ivtv *itv, struct ivtv_buffer_list *src, + struct ivtv_buffer_list *dst); +extern int ivtv_stop_decode(struct ivtv_open_id *id); + +/* Hardware/IRQ */ +extern void ivtv_set_irq_mask(struct ivtv *itv, unsigned long mask); +extern void ivtv_clear_irq_mask(struct ivtv *itv, unsigned long mask); +extern void ivtv_sleep_timeout(int timeout); + +/* Testing/Debugging */ +extern int ivtv_close(struct ivtv_open_id *id); + +/* debug stuff, to get the locking right */ +#ifndef WARN_ON +#define WARN_ON(condition) do { \ + if (unlikely((condition)!=0)) { \ + printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ + dump_stack(); \ + } \ +} while (0) +#endif + +#define IVTV_ASSERT(x) WARN_ON(!(x)) + +static inline int ivtv_sem_count(struct semaphore *sem) +{ + return atomic_read(&sem->count); +} + +#endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/msp3400.c 830-ivtv/drivers/media/video/msp3400.c --- 000-virgin/drivers/media/video/msp3400.c Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/media/video/msp3400.c Thu Jan 8 11:17:36 2004 @@ -50,10 +50,6 @@ #include #include -/* kernel_thread */ -#define __KERNEL_SYSCALLS__ -#include - #include #include "msp3400.h" @@ -62,6 +58,7 @@ static int debug = 0; /* debug out static int once = 0; /* no continous stereo monitoring */ static int amsound = 0; /* hard-wire AM sound at 6.5 Hz (france), the autoscan seems work well only with FM... */ +static int standard = 1; /* Override auto detect of audio standard, if needed. */ static int simple = -1; /* use short programming (>= msp3410 only) */ static int dolby = 0; @@ -117,6 +114,7 @@ static struct i2c_client *msps[MSP3400_M MODULE_PARM(once,"i"); MODULE_PARM(debug,"i"); MODULE_PARM(simple,"i"); +MODULE_PARM(standard,"i"); MODULE_PARM(amsound,"i"); MODULE_PARM(dolby,"i"); @@ -194,7 +192,7 @@ msp3400c_read(struct i2c_client *client, err++; printk(KERN_WARNING "msp34xx: I/O error #%d (read 0x%02x/0x%02x)\n", err, dev, addr); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ/10); } if (3 == err) { @@ -223,7 +221,7 @@ msp3400c_write(struct i2c_client *client err++; printk(KERN_WARNING "msp34xx: I/O error #%d (write 0x%02x/0x%02x)\n", err, dev, addr); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ/10); } if (3 == err) { @@ -334,16 +332,6 @@ static struct CARRIER_DETECT carrier_det /* ----------------------------------------------------------------------- */ -#define SCART_MASK 0 -#define SCART_IN1 1 -#define SCART_IN2 2 -#define SCART_IN1_DA 3 -#define SCART_IN2_DA 4 -#define SCART_IN3 5 -#define SCART_IN4 6 -#define SCART_MONO 7 -#define SCART_MUTE 8 - static int scarts[3][9] = { /* MASK IN1 IN2 IN1_DA IN2_DA IN3 IN4 MONO MUTE */ { 0x0320, 0x0000, 0x0200, -1, -1, 0x0300, 0x0020, 0x0100, 0x0320 }, @@ -388,7 +376,7 @@ static void msp3400c_setvolume(struct i2 if (!muted) { vol = (left > right) ? left : right; - val = (vol * 0x73 / 65535) << 8; + val = (vol * 0x7F / 65535) << 8; } if (vol > 0) { balance = ((right-left) * 127) / vol; @@ -399,8 +387,10 @@ static void msp3400c_setvolume(struct i2 muted ? "on" : "off", left, right, val>>8, balance); msp3400c_write(client,I2C_MSP3400C_DFP, 0x0000, val); /* loudspeaker */ msp3400c_write(client,I2C_MSP3400C_DFP, 0x0006, val); /* headphones */ - /* scart - on/off only */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0007, val ? 0x4000 : 0); + // scart - on/off only - AEW why? undone NOTE values below + // 40000 are mostly useless, 59343 is a good default (0x73) + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0007, + muted ? 0x1 : (val | 0x1)); msp3400c_write(client,I2C_MSP3400C_DFP, 0x0001, balance << 8); } @@ -477,6 +467,19 @@ static void msp3400c_setmode(struct i2c_ } } +// given a bitmask of VIDEO_SOUND_XXX returns the "best" in the bitmask +static int best_video_sound(int mode) { + int ret_cap = VIDEO_SOUND_MONO; + if (mode & VIDEO_SOUND_STEREO) { + ret_cap = VIDEO_SOUND_STEREO; + } else if (mode & VIDEO_SOUND_LANG1) { + ret_cap = VIDEO_SOUND_LANG1; + } else if (mode & VIDEO_SOUND_LANG2) { + ret_cap = VIDEO_SOUND_LANG2; + } + return ret_cap; +} + /* turn on/off nicam + stereo */ static void msp3400c_setstereo(struct i2c_client *client, int mode) { @@ -551,7 +554,7 @@ static void msp3400c_setstereo(struct i2 } /* switch audio */ - switch (mode) { + switch (best_video_sound(mode)) { case VIDEO_SOUND_STEREO: src = 0x0020 | nicam; #if 0 @@ -775,10 +778,9 @@ static int msp3400c_thread(void *data) struct CARRIER_DETECT *cd; int count, max1,max2,val1,val2, val,this; - lock_kernel(); daemonize("msp3400"); + msp->thread = current; - unlock_kernel(); printk("msp3400: daemon started\n"); if(msp->notify != NULL) @@ -804,7 +806,7 @@ static int msp3400c_thread(void *data) } /* some time for the tuner to sync */ - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ/5); if (signal_pending(current)) goto done; @@ -839,7 +841,7 @@ static int msp3400c_thread(void *data) for (this = 0; this < count; this++) { msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ/10); if (signal_pending(current)) goto done; @@ -876,7 +878,7 @@ static int msp3400c_thread(void *data) for (this = 0; this < count; this++) { msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ/10); if (signal_pending(current)) goto done; @@ -1023,10 +1025,9 @@ static int msp3410d_thread(void *data) struct msp3400c *msp = i2c_get_clientdata(client); int mode,val,i,std; - lock_kernel(); daemonize("msp3410 [auto]"); + msp->thread = current; - unlock_kernel(); printk("msp3410: daemon started\n"); if(msp->notify != NULL) @@ -1052,7 +1053,7 @@ static int msp3410d_thread(void *data) } /* some time for the tuner to sync */ - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ/5); if (signal_pending(current)) goto done; @@ -1076,7 +1077,7 @@ static int msp3410d_thread(void *data) switch (msp->norm) { case VIDEO_MODE_PAL: mode = 0x1003; - std = 1; + std = standard; break; case VIDEO_MODE_NTSC: /* BTSC */ mode = 0x2003; @@ -1084,15 +1085,19 @@ static int msp3410d_thread(void *data) break; case VIDEO_MODE_SECAM: mode = 0x0003; - std = 1; + std = standard; break; case VIDEO_MODE_RADIO: mode = 0x0003; std = 0x0040; break; + case VIDEO_MODE_AUTO: + mode = 0x2003; + std = standard; + break; default: mode = 0x0003; - std = 1; + std = standard; break; } msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, mode); @@ -1113,7 +1118,7 @@ static int msp3410d_thread(void *data) } else { /* triggered autodetect */ for (;;) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ/10); if (signal_pending(current)) goto done; @@ -1204,13 +1209,19 @@ static int msp3410d_thread(void *data) #endif break; case 0x0003: + case 0x0004: + case 0x0005: msp->mode = MSP_MODE_FM_TERRA; msp->stereo = VIDEO_SOUND_MONO; msp->nicam_on = 0; msp->watch_stereo = 1; break; } - + + // AEW a true reset has probably messed with our ACB register + // we need to restore this. + msp3400c_write(client, I2C_MSP3400C_DFP, 0x0013, msp->acb); + /* unmute + restore dfp registers */ msp3400c_setbass(client, msp->bass); msp3400c_settreble(client, msp->treble); @@ -1241,7 +1252,7 @@ static int msp_probe(struct i2c_adapter static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg); static struct i2c_driver driver = { - .owner = THIS_MODULE, + .owner = THIS_MODULE, .name = "i2c msp3400 driver", .id = I2C_DRIVERID_MSP3400, .flags = I2C_DF_NOTIFY, @@ -1252,7 +1263,7 @@ static struct i2c_driver driver = { static struct i2c_client client_template = { - I2C_DEVNAME("(unset)"), + I2C_DEVNAME("(msp3400 internal)"), .flags = I2C_CLIENT_ALLOW_USE, .driver = &driver, }; @@ -1262,7 +1273,7 @@ static int msp_attach(struct i2c_adapter DECLARE_MUTEX_LOCKED(sem); struct msp3400c *msp; struct i2c_client *c; - int i; + int i, rc; client_template.adapter = adap; client_template.addr = addr; @@ -1281,12 +1292,13 @@ static int msp_attach(struct i2c_adapter } memset(msp,0,sizeof(struct msp3400c)); - msp->left = 65535; - msp->right = 65535; + msp->norm = VIDEO_MODE_NTSC; + msp->left = 59343; + msp->right = 59343; msp->bass = 32768; msp->treble = 32768; msp->input = -1; - msp->muted = 1; +// msp->muted = 1; for (i = 0; i < DFP_COUNT; i++) msp->dfp_regs[i] = -1; @@ -1316,7 +1328,7 @@ static int msp_attach(struct i2c_adapter #endif msp3400c_setvolume(c,msp->muted,msp->left,msp->right); - snprintf(c->name, I2C_NAME_SIZE, "MSP34%02d%c-%c%d", + snprintf(c->name, sizeof(c->name), "MSP34%02d%c-%c%d", (msp->rev2>>8)&0xff, (msp->rev1&0xff)+'@', ((msp->rev1>>8)&0xff)+'@', msp->rev2&0x1f); @@ -1345,9 +1357,12 @@ static int msp_attach(struct i2c_adapter /* startup control thread */ msp->notify = &sem; - kernel_thread(msp->simple ? msp3410d_thread : msp3400c_thread, - (void *)c, 0); - down(&sem); + rc = kernel_thread(msp->simple ? msp3410d_thread : msp3400c_thread, + (void *)c, 0); + if (rc < 0) + printk(KERN_WARNING "msp34xx: kernel_thread() failed\n"); + else + down(&sem); msp->notify = NULL; wake_up_interruptible(&msp->wq); @@ -1398,8 +1413,13 @@ static int msp_detach(struct i2c_client static int msp_probe(struct i2c_adapter *adap) { +#ifdef I2C_ADAP_CLASS_TV_ANALOG if (adap->class & I2C_ADAP_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, msp_attach); +#else + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, msp_attach); +#endif return 0; } @@ -1515,7 +1535,7 @@ static int msp_command(struct i2c_client struct video_audio *va = arg; dprintk(KERN_DEBUG "msp34xx: VIDIOCGAUDIO\n"); - va->flags |= VIDEO_AUDIO_VOLUME | + va->flags = VIDEO_AUDIO_VOLUME | VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE | VIDEO_AUDIO_MUTABLE; @@ -1567,6 +1587,7 @@ static int msp_command(struct i2c_client dprintk(KERN_DEBUG "msp34xx: VIDIOCSCHAN\n"); msp->norm = vc->norm; + msp_wake_thread(client); break; } case VIDIOCSFREQ: @@ -1576,7 +1597,14 @@ static int msp_command(struct i2c_client msp_wake_thread(client); break; } + case MSP_SET_MATRIX: + { + struct msp_matrix *mspm = arg; + dprintk(KERN_DEBUG "msp34xx: MSP_SET_MATRIX\n"); + msp3400c_set_scart(client, mspm->input, mspm->output); + break; + } default: /* nothing */ break; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/msp3400.h 830-ivtv/drivers/media/video/msp3400.h --- 000-virgin/drivers/media/video/msp3400.h Sun Nov 17 20:29:54 2002 +++ 830-ivtv/drivers/media/video/msp3400.h Thu Jan 8 11:17:36 2004 @@ -8,7 +8,29 @@ struct msp_dfpreg { int value; }; +struct msp_matrix { + int input; + int output; +}; + #define MSP_SET_DFPREG _IOW('m',15,struct msp_dfpreg) #define MSP_GET_DFPREG _IOW('m',16,struct msp_dfpreg) + +/* ioctl for MSP_SET_MATRIX will have to be registered */ +#define MSP_SET_MATRIX _IOW('m',17,struct msp_matrix) + +#define SCART_MASK 0 +#define SCART_IN1 1 +#define SCART_IN2 2 +#define SCART_IN1_DA 3 +#define SCART_IN2_DA 4 +#define SCART_IN3 5 +#define SCART_IN4 6 +#define SCART_MONO 7 +#define SCART_MUTE 8 + +#define SCART_DSP_IN 0 +#define SCART1_OUT 1 +#define SCART2_OUT 2 #endif /* MSP3400_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/saa7115.c 830-ivtv/drivers/media/video/saa7115.c --- 000-virgin/drivers/media/video/saa7115.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/media/video/saa7115.c Thu Jan 8 11:17:36 2004 @@ -0,0 +1,1106 @@ +/* + * saa7114 - Philips SAA7114H video decoder driver version 0.0.1 + * + * Copyright (C) 2002 Maxim Yevtyushkin + * + * Based on saa7111 driver by Dave Perks + * + * Copyright (C) 1998 Dave Perks + * + * Slight changes for video timing and attachment output by + * Wolfgang Scherr + * + * Changes by Ronald Bultje + * - moved over to linux>=2.4.x i2c protocol (1/1/2003) + * + * Changes by Kevin Thayer + * - changed to saa7115. (2/17/2003) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +MODULE_DESCRIPTION("Philips SAA7115 video decoder driver"); +MODULE_AUTHOR("Kevin Thayer"); +MODULE_LICENSE("GPL"); + +#include +#include + +#ifndef I2C_DRIVERID_SAA7114 +#warning Using temporary hack for missing I2C driver-ID for saa7114 +#define I2C_DRIVERID_SAA7114 I2C_DRIVERID_EXP1 +#endif + +#include + +static int debug = 1; +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug level (0-1)"); + +/* FIXME need to get this properly allocated + * also defined in ivtv.h, so change it there too */ +#define DECODER_SET_SIZE 76598 +#define DECODER_GET_PICTURE 76599 + +/* Need to be able to set the audio bitrates */ +#define DECODER_SET_AUDIO 0xFFEE7707 +#define DECODER_AUDIO_32_KHZ 0 +#define DECODER_AUDIO_441_KHZ 1 +#define DECODER_AUDIO_48_KHZ 2 + +#ifdef SAA7115_REGTEST +/* allow direct access to the saa7115 registers for testing */ +#define SAA7115_GET_REG 0xFFEE7705 +#define SAA7115_SET_REG 0xFFEE7706 + + +struct saa7115_reg_t { + u8 reg; + u8 val; +}; +#endif + +#define dprintk(num, format, args...) \ + do { \ + if (debug >= num) \ + printk(format, ##args); \ + } while (0) + +/* ----------------------------------------------------------------------- */ + +static u8 readreg(struct i2c_client *client, unsigned char reg) { + struct i2c_adapter *adap=client->adapter; + unsigned char mm1[] = {0x1e}; + unsigned char mm2[] = {0x00}; + struct i2c_msg msgs[2]; + + msgs[0].flags=0; + msgs[1].flags=I2C_M_RD; + msgs[0].addr=msgs[1].addr=client->addr; + mm1[0]=reg; + msgs[0].len=1; msgs[1].len=1; + msgs[0].buf=mm1; msgs[1].buf=mm2; + i2c_transfer(adap, msgs, 2); + + return mm2[0]; +} + +struct saa7114 { + int norm; + int input; + int enable; + int bright; + int contrast; + int hue; + int sat; + int playback; + int audio; +}; + +#define I2C_SAA7114 0x42 +#define I2C_SAA7114A 0x40 + +#define I2C_DELAY 10 + + +//#define SAA_7114_NTSC_HSYNC_START (-3) +//#define SAA_7114_NTSC_HSYNC_STOP (-18) + +#define SAA_7114_NTSC_HSYNC_START (-17) +#define SAA_7114_NTSC_HSYNC_STOP (-32) + +//#define SAA_7114_NTSC_HOFFSET (5) +#define SAA_7114_NTSC_HOFFSET (6) +#define SAA_7114_NTSC_VOFFSET (10) +#define SAA_7114_NTSC_WIDTH (720) +#define SAA_7114_NTSC_HEIGHT (480) /* was 250*/ + +#define SAA_7114_SECAM_HSYNC_START (-17) +#define SAA_7114_SECAM_HSYNC_STOP (-32) + +#define SAA_7114_SECAM_HOFFSET (2) +#define SAA_7114_SECAM_VOFFSET (10) +#define SAA_7114_SECAM_WIDTH (720) +#define SAA_7114_SECAM_HEIGHT (300) + +#define SAA_7114_PAL_HSYNC_START (-17) +#define SAA_7114_PAL_HSYNC_STOP (-32) + +#define SAA_7114_PAL_HOFFSET (2) +#define SAA_7114_PAL_VOFFSET (10) +#define SAA_7114_PAL_WIDTH (720) +#define SAA_7114_PAL_HEIGHT (300) + +#define SAA_7114_VERTICAL_CHROMA_OFFSET 0 //0x50504040 +#define SAA_7114_VERTICAL_LUMA_OFFSET 0 + +#define REG_ADDR(x) (((x) << 1) + 1) +#define LOBYTE(x) ((unsigned char)((x) & 0xff)) +#define HIBYTE(x) ((unsigned char)(((x) >> 8) & 0xff)) +#define LOWORD(x) ((unsigned short int)((x) & 0xffff)) +#define HIWORD(x) ((unsigned short int)(((x) >> 16) & 0xffff)) + + +/* ----------------------------------------------------------------------- */ + +static inline int +saa7114_write (struct i2c_client *client, + u8 reg, + u8 value) +{ +// struct saa7114 *decoder = i2c_get_clientdata(client); + return i2c_smbus_write_byte_data(client, reg, value); +} + + +static int writeregs(struct i2c_client *client, const unsigned char *regs) +{ + unsigned char reg, data; + + while (*regs!=0x00) { + reg =*(regs++); + data=*(regs++); + if (saa7114_write(client, reg, data) < 0) + return -1; + } + return 0; +} + +static inline int +saa7114_read (struct i2c_client *client, + u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +/* ----------------------------------------------------------------------- */ + + +static const unsigned char init_saa7115_auto_input[] = { + 0x01, 0x08, //(was 0x48) // 0x08: white peak control enabled, 0x48: white peak control disabled + 0x03, 0x2C, //was 0x20 // 0x20: automatic gain control, 0x2c: user programmable gain + 0x04, 0x90, // analog gain set to 0 + 0x05, 0x90, // analog gain set to 0 + 0x06, 0xEB, // horiz sync begin = -21 + 0x07, 0xE0, // horiz sync stop = -17 + + // done in misc +// 0x09, 0x40, //80 for svideo // 0x40: use luminance comb filter, 0x80: don't use ... + + 0x0A, 0x80, //i2c dump ends up at 96 (was 80) // decoder brightness, 0x80 is itu standard + 0x0B, 0x44, // decoder contrast, 0x44 is itu standard + 0x0C, 0x40, // decoder saturation, 0x40 is itu standard + 0x0D, 0x00, //i2c dump ends up at 04 (was 00) // chrominance hue control + 0x0F, 0x24, //i2c dump says 0x30 (was 0x2A) // chrominance gain control , should be 0x00 for agc, otherwise 0x80+0x24: 0xA4 + 0x10, 0x06, + 0x11, 0x00, + 0x12, 0x9D, //i2c dump says 0x9D (was 0x00) + 0x13, 0x80, //" 0x80 (was 0x00) + 0x14, 0x01, //" 0x01 (was 0x01) + 0x15, 0x04, //" 0x00 (was 0x11) //should also be moved to NTSC/PAL VGATE start + /* moved to NTSC/PAL sections + 0x16, 0x11, //" 0x11 (was 0xFE) // VGATE stop + */ + 0x17, 0x98, //" 0x98 (was 0xD8) //may set to 98 // VGATE MSB and other values + 0x18, 0x40, // raw data gain 0x00 = nominal + 0x19, 0x80, // raw data offset 0x80 = 0 LSB + 0x1A, 0x77, // color killer level control 0x77 = recommended + 0x1B, 0x42, // misc chroma control 0x42 = recommended + 0x1C, 0xA9, // combfilter control 0xA9 = recommended + 0x1D, 0x01, // combfilter control 0x01 = recommended + 0x88, 0xD0, //reset device // set programmed, reset + 0x88, 0xF0, //Set device programmed, all in operational mode // set programmed, active ?programmed should be 0? + 0x00, 0x00 // ? not necessary, version readback register +}; + +/* ============== SAA7715 VIDEO templates ============= */ + +static const unsigned char cfg_saa7115_reset_scaler[] = { + 0x87, 0x00, //Disable I-port output + 0x88, 0x0B, //reset scaler (was 0xD0) // ?should be 0xD0 + 0x88, 0xF0, //activate scaler + 0x87, 0x01, //Enable I-port output // what about high bits? how is ICLK used? + 0x00, 0x00 +}; +static const unsigned char cfg_saa7115_NTSC_fullres_x[] = { + 0xCC, 0xD0, //hsize low (output) //hor output window size = 0x2d0 = 720 + 0xCD, 0x02, //hsize hi (output) + + 0xD0, 0x01, // down scale = 1 + 0xD1, 0x00, // prescale accumulation length = 1 + 0xD2, 0x00, // dc gain and fir prefilter control + 0xD4, 0x80, //Lum Brightness // nominal value = 0x80 + 0xD5, 0x40, //Lum contrast // nominal value = 0x40 + 0xD6, 0x40, //Chroma satur. // nominal value = 0x80 + 0xD8, 0x00, // hor lum scaling 0x0400 = 1 + 0xD9, 0x04, + 0xDA, 0x00, //H-phase offset Luma = 0 + 0xDC, 0x00, // hor chrom scaling 0x0200. must be hor lum scaling /2 + 0xDD, 0x02, //H-scaling incr chroma + 0xDE, 0x00, //H-phase offset chroma // must be offset luma /2 + + 0x00, 0x00 +}; +static const unsigned char cfg_saa7115_NTSC_fullres_y[] = { + 0xCE, 0xFD, //vsize low (output) was FD // ver output window size = 253 ??240 + 0xCF, 0x00, //vsize hi (output) + + 0xE0, 0x00, //V-scaling incr luma low 0x0400 = 1 + 0xE1, 0x04, //" hi + 0xE2, 0x00, //V-scaling incr chroma low // must be same as luma + 0xE3, 0x04, //" hi + 0xE4, 0x01, //V-scaling mode control // no mirroring, higher order accumulation + 0xE8, 0x00, //V-phase offset chroma 00 //?only regs E8 and EC necessary? + 0xE9, 0x00, //V-phase offset chroma 01 + 0xEA, 0x00, //V-phase offset chroma 10 + 0xEB, 0x00, //V-phase offset chroma 11 + 0xEC, 0x00, //V-phase offset luma 00 + 0xED, 0x00, //V-phase offset luma 01 + 0xEE, 0x00, //V-phase offset luma 10 + + 0x00, 0x00 +}; + +static const unsigned char cfg_saa7115_NTSC_video[] = { + 0x80, 0x00, //reset tasks + 0x88, 0x0B, //reset scaler (was 0xD0) + + 0x16, 0x11, //" 0x11 (was 0xFE) //VGATE pulse stop + + 0x08, 0x68, //i2c dump says 0x68 (was 0xB0) NTSC ONLY // 0xBO: auto detection, 0x68 = NTSC + 0x0E, 0x07, //i2c dump says 0x0d (was 0x07) // lots of different stuff... video autodetection is on + + 0xC0, 0x00, //Task Handling Control (was 0x00) + 0xC1, 0x08, //X-port formats/config + 0xC2, 0x00, //Input Ref. signal Def. + 0xC3, 0x80, //I-port config (was 0x80) + 0xC4, 0x02, //hoffset low (input) // 0x0002 is minimum + 0xC5, 0x00, //hoffset hi (input) + 0xC6, 0xD0, //hsize low (input) // 0x02d0 = 720 + 0xC7, 0x02, //hsize hi (input) + 0xC8, 0x14, //voff low was 0x14, changing to 0x0E (14) // 0x0014 = 20 + 0xC9, 0x00, //voff hi + 0xCA, 0xFD, //vsize low (input) was FD // 0x00fd = 253 + 0xCB, 0x00, //vsize hi (input) + + 0xF0, 0xAD, //Set PLL Register. NTSC 525 lines per frame, 27 MHz + 0xF1, 0x05, //low bit with 0xF0, (was 0x05) + 0xF5, 0xAD, //Set pulse generator register + 0xF6, 0x01, + + 0x87, 0x00, //Disable I-port output + 0x88, 0x0B, //reset scaler (was 0xD0) + 0x80, 0x20, //Activate only task "B", continuous mode (was 0xA0) + 0x88, 0xF0, //activate scaler + 0x87, 0x01, //Enable I-port output + 0x00, 0x00 +}; + +static const unsigned char cfg_saa7115_PAL_fullres_x[] = { + 0xCC, 0xD0, //hsize low (output) //720 same as NTSC + 0xCD, 0x02, //hsize hi (output) + + 0xD0, 0x01, + 0xD1, 0x00, + 0xD2, 0x00, + 0xD4, 0x80, //Lum Brightness + 0xD5, 0x40, //Lum contrast + 0xD6, 0x40, //Chroma satur. + 0xD8, 0x00, + 0xD9, 0x04, + 0xDA, 0x00, //H-phase offset Luma + 0xDC, 0x00, + 0xDD, 0x02, //H-scaling incr chroma + 0xDE, 0x00, //H-phase offset chroma + + 0x00, 0x00 +}; +static const unsigned char cfg_saa7115_PAL_fullres_y[] = { + 0xCE, 0x20, //vsize low (output) // 0x0120 = 288 + 0xCF, 0x01, //vsize hi (output) + + 0xE0, 0x00, //V-scaling incr luma low + 0xE1, 0x04, //" hi + 0xE2, 0x00, //V-scaling incr chroma low + 0xE3, 0x04, //" hi + 0xE4, 0x01, //V-scaling mode control + 0xE8, 0x00, //V-phase offset chroma 00 + 0xE9, 0x00, //V-phase offset chroma 01 + 0xEA, 0x00, //V-phase offset chroma 10 + 0xEB, 0x00, //V-phase offset chroma 11 + 0xEC, 0x00, //V-phase offset luma 00 + 0xED, 0x00, //V-phase offset luma 01 + 0xEE, 0x00, //V-phase offset luma 10 + 0xEF, 0x00, //V-phase offset luma 11 + + 0x00, 0x00 +}; + +/* FIXME need to input proper height/width */ +static const unsigned char cfg_saa7115_PAL_video[] = { + 0x80, 0x00, //reset tasks + 0x88, 0x0B, //reset scaler (was 0xD0) + + 0x16, 0x15, //" 0x11 (was 0xFE) + + 0x08, 0x28, //i2c dump says 0x28 (was 0xB0) PAL ONLY // 0x28 = PAL + 0x0E, 0x07, //i2c dump says 0x0d (was 0x07) + + 0xC0, 0x00, //Task Handling Control (was 0x00) + 0xC1, 0x08, //X-port formats/config + 0xC2, 0x00, //Input Ref. signal Def. + 0xC3, 0x80, //I-port config (was 0x80) + 0xC4, 0x00, //hoffset low (input) + 0xC5, 0x00, //hoffset hi (input) + 0xC6, 0xD0, //hsize low (input) // 0x02D0 = 720 + 0xC7, 0x02, //hsize hi (input) + 0xC8, 0x14, //voffset low (input) low was 0x14, changing to 0x0E (14) + 0xC9, 0x00, //voffset hi (input) + 0xCA, 0x20, //vsize low (input) // 288 + 0xCB, 0x01, //vsize hi (input) + + 0xF0, 0xB0, //Set PLL Register. PAL 625 lines per frame, 27 MHz + 0xF1, 0x05, //low bit with 0xF0, (was 0x05) + 0xF5, 0xB0, //Set pulse generator register + 0xF6, 0x01, + + 0x87, 0x00, //Disable I-port output + 0x88, 0x0B, //reset scaler (was 0xD0) + 0x80, 0xA0, //Activate only task "B", continuous mode (was 0xA0) + 0x88, 0xF0, //activate scaler + 0x87, 0x01, //Enable I-port output + 0x00, 0x00 +}; +/* ============== SAA7715 VIDEO templates (end) ======= */ + + +static const unsigned char init_saa7115_misc[] = { + 0x38, 0x03, // audio stuff + 0x39, 0x10, + 0x3A, 0x00, + +// 0x80, 0x00, // set below + 0x81, 0x01, //reg 0x15,0x16 define blanking window + 0x82, 0x00, + 0x83, 0x01, //was 0x01 // I port settings + 0x84, 0x20, + 0x85, 0x21, + 0x86, 0xC5, + 0x87, 0x01, +// 0x88, 0xD0, // unnecessary + +// 0xF0, 0xAD, //this goes in PAL/NTSC video +// 0xF1, 0x05, + 0xF2, 0x50, // crystal clock = 24.576 MHz, target = 27MHz + 0xF3, 0x46, + 0xF4, 0x00, +// 0xF5, 0xAD, //this goes in PAL/NTSC video +// 0xF6, 0x01, + 0xF7, 0x4B, // not the recommended settings! + 0xF8, 0x00, + 0xF9, 0x4B, + 0xFA, 0x00, + 0xFB, 0x4B, +// 0xFC, 0x00, // unused +// 0xFD, 0x00, +// 0xFE, 0x00, + 0xFF, 0x88, // PLL2 lock detection settings: 71 lines 50% phase error + +// 0x88, 0xF0, // unnecessary + +// 0x0D, 0x04, // already set in auto_input +// 0x0C, 0x40, +// 0x0A, 0x96, +// 0x0B, 0x41, +// 0x98, 0x05, // belongs to task A; unnecessary +/* Turn off VBI */ + 0x40, 0x00, + 0x41, 0xFF, + 0x42, 0xFF, + 0x43, 0xFF, + 0x44, 0xFF, + 0x45, 0xFF, + 0x46, 0xFF, + 0x47, 0xFF, + 0x48, 0xFF, + 0x49, 0xFF, + 0x4A, 0xFF, + 0x4B, 0xFF, + 0x4C, 0xFF, + 0x4D, 0xFF, + 0x4E, 0xFF, + 0x4F, 0xFF, + 0x50, 0xFF, + 0x51, 0xFF, + 0x52, 0xFF, + 0x53, 0xFF, + 0x54, 0xFF, + 0x55, 0xFF, + 0x56, 0xFF, + 0x57, 0xFF, + 0x58, 0x00, + 0x59, 0x47, + 0x5A, 0x06, + 0x5B, 0x88, + 0x5D, 0xBF, + 0x5E, 0x35, + + 0x02, 0x84, //input tuner -> input 4, amplifier active + 0x09, 0x53, //chrom trap for tuner // special tuner stuff? + + 0x80, 0x20, //was 0x30 // 0x20 clock from PLL2, 0x30 clock from ICLK + 0x88, 0xD0, + 0x88, 0xF0, + 0x00, 0x00 +}; + +/* ============== SAA7715 AUDIO settings ============= */ +static const unsigned char cfg_saa7115_48_audio[] = { + 0x34, 0xCE, // 48khz + 0x35, 0xFB, // " + 0x36, 0x30, // " + 0x00, 0x00 +}; + +static const unsigned char cfg_saa7115_441_audio[] = { + 0x34, 0xF2, // 44.1khz + 0x35, 0x00, // " + 0x36, 0x2D, // " + 0x00, 0x00 +}; + +static const unsigned char cfg_saa7115_32_audio[] = { + 0x34, 0xDF, // 32.0khz + 0x35, 0xA7, // " + 0x36, 0x20, // " + 0x00, 0x00 +}; + +static const unsigned char cfg_saa7115_NTSC_48_audio[] = { + 0x30, 0xCD, // 48.0khz NTSC + 0x31, 0x20, // " + 0x32, 0x03, // " + 0x00, 0x00 +}; + +static const unsigned char cfg_saa7115_PAL_48_audio[] = { + 0x30, 0x00, // 48.0khz PAL + 0x31, 0xC0, // " + 0x32, 0x03, // " + 0x00, 0x00 +}; + +static const unsigned char cfg_saa7115_NTSC_441_audio[] = { + 0x30, 0xBC, // 44.1khz NTSC + 0x31, 0xDF, // " + 0x32, 0x02, // " + 0x00, 0x00 +}; + +static const unsigned char cfg_saa7115_PAL_441_audio[] = { + 0x30, 0x00, // 44.1khz PAL + 0x31, 0x72, // " + 0x32, 0x03, // " + 0x00, 0x00 +}; + +static const unsigned char cfg_saa7115_NTSC_32_audio[] = { + 0x30, 0xDE, // 32.0khz NTSC + 0x31, 0x15, // " + 0x32, 0x02, // " + 0x00, 0x00 +}; + +static const unsigned char cfg_saa7115_PAL_32_audio[] = { + 0x30, 0x00, // 32.0khz PAL + 0x31, 0x80, // " + 0x32, 0x02, // " + 0x00, 0x00 +}; + +/* ============ SAA7715 AUDIO settings (end) ============= */ + +static int +saa7114_command (struct i2c_client *client, + unsigned int cmd, + void *arg) +{ + struct saa7114 *decoder = i2c_get_clientdata(client); + + switch (cmd) { + + case 0: + //dprintk(1, KERN_INFO "%s: writing init\n", client->dev.name); + //saa7114_write_block(client, init, sizeof(init)); + break; +#ifdef SAA7115_REGTEST + /* ioctls to allow direct access to the saa7115 registers for testing */ + case SAA7115_GET_REG: + { + struct saa7115_reg_t *saa7115_reg = (struct saa7115_reg_t *)arg; + + saa7115_reg->val = saa7114_read(client, saa7115_reg->reg); + break; + } + case SAA7115_SET_REG: + { + struct saa7115_reg_t *saa7115_reg = (struct saa7115_reg_t *)arg; + + saa7114_write(client, saa7115_reg->reg, saa7115_reg->val); + break; + } +#endif + case DECODER_SET_SIZE: + { + /* Used video_window because it has height/width and is + * already defined */ + struct video_window *wind = arg; + int HPSC, HFSC; + int VSCY, Vsrc; + + dprintk(1, KERN_INFO "%s: decoder set size\n", client->name); + + /* FIXME need better bounds checking here */ + if ( (wind->width < 1) || (wind->width > 1440)) + return -EINVAL; + if ( (wind->height < 1) || (wind->height > 960)) + return -EINVAL; + + /* probably have a valid size, let's set it */ +/* Set output width/height */ + /* width */ + saa7114_write (client, 0xCC, (u8)(wind->width & 0xFF)); + saa7114_write (client, 0xCD, (u8)((wind->width >> 8)&0xFF)); + /* height */ + saa7114_write (client, 0xCE, (u8)(wind->height & 0xFF)); + saa7114_write (client, 0xCF, (u8)((wind->height >> 8)&0xFF)); + +/* Scaling settings */ + /* Hprescaler is floor(inres/outres) */ + /* FIXME hardcoding input res */ + if (wind->width != 720) { + HPSC = (int) (720/wind->width); + HFSC = (int) ((1024*720)/(HPSC*wind->width)); + + printk("Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC); + /* FIXME hardcodes to "Task B" + * write H prescaler integer */ + saa7114_write (client, 0xD0, (u8)(HPSC & 0x3F)); + + /* write H fine-scaling (luminance)*/ + saa7114_write (client, 0xD8, (u8)(HFSC & 0xFF)); + saa7114_write (client, 0xD9, (u8)((HFSC >> 8) & 0xFF) ); + /* write H fine-scaling (chrominance) + * must be lum/2, so i'll just bitshift :) */ + saa7114_write (client, 0xDC, (u8)((HFSC >> 1) & 0xFF) ); + saa7114_write (client, 0xDD, (u8)((HFSC >> 9) & 0xFF) ); + } else { + if (decoder->norm != VIDEO_MODE_NTSC) { + printk("Setting full PAL width\n"); + writeregs(client, cfg_saa7115_PAL_fullres_x); + } else { + printk("Setting full NTSC width\n"); + writeregs(client, cfg_saa7115_NTSC_fullres_x); + } + } + + Vsrc = 480; + if (decoder->norm != VIDEO_MODE_NTSC) Vsrc = 576; + + if (wind->height != Vsrc) { + VSCY = (int) ((1024*Vsrc)/wind->height); + printk("Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY); + /* write V fine-scaling (luminance)*/ + saa7114_write (client, 0xE0, (u8)(VSCY & 0xFF)); + saa7114_write (client, 0xE1, (u8)((VSCY >> 8) & 0xFF) ); + /* write V fine-scaling (chrominance)*/ + saa7114_write (client, 0xE2, (u8)(VSCY & 0xFF)); + saa7114_write (client, 0xE3, (u8)((VSCY >> 8) & 0xFF) ); + } else { + if (decoder->norm != VIDEO_MODE_NTSC) { + printk("Setting full PAL height\n"); + writeregs(client, cfg_saa7115_PAL_fullres_y); + } else { + printk("Setting full NTSC height\n"); + writeregs(client, cfg_saa7115_NTSC_fullres_y); + } + } + + writeregs(client, cfg_saa7115_reset_scaler); + break; + } + case DECODER_DUMP: + { + int i; + + dprintk(1, KERN_INFO "%s: decoder dump\n", client->name); + + for (i = 0; i < 32; i += 16) { + int j; + + printk(KERN_DEBUG "%s: %03x", client->name, i); + for (j = 0; j < 16; ++j) { + printk(" %02x", + saa7114_read(client, i + j)); + } + printk("\n"); + } + } + break; + + case DECODER_GET_CAPABILITIES: + { + struct video_decoder_capability *cap = arg; + + dprintk(1, KERN_DEBUG "%s: decoder get capabilities\n", + client->name); + + cap->flags = VIDEO_DECODER_PAL | + VIDEO_DECODER_NTSC | + VIDEO_DECODER_SECAM | + VIDEO_DECODER_AUTO | + VIDEO_DECODER_CCIR; + cap->inputs = 8; + cap->outputs = 1; + } + break; + + case DECODER_SET_AUDIO: + { + int *iarg = arg; + dprintk(1, KERN_DEBUG "%s set audio: 0x%02x\n", client->name, *iarg); + switch (*iarg) { + case DECODER_AUDIO_32_KHZ: + writeregs(client, cfg_saa7115_32_audio); + if (decoder->norm == VIDEO_MODE_NTSC) { + writeregs(client, cfg_saa7115_NTSC_32_audio); + } else { + writeregs(client, cfg_saa7115_PAL_32_audio); + } + break; + case DECODER_AUDIO_441_KHZ: + writeregs(client, cfg_saa7115_441_audio); + if (decoder->norm == VIDEO_MODE_NTSC) { + writeregs(client, cfg_saa7115_NTSC_441_audio); + } else { + writeregs(client, cfg_saa7115_PAL_441_audio); + } + break; + case DECODER_AUDIO_48_KHZ: + writeregs(client, cfg_saa7115_48_audio); + if (decoder->norm == VIDEO_MODE_NTSC) { + writeregs(client, cfg_saa7115_NTSC_48_audio); + } else { + writeregs(client, cfg_saa7115_PAL_48_audio); + } + break; + default: + printk(KERN_DEBUG "%s invalid audio setting 0x%02x\n", client->name, *iarg); + } + + /*FIXME digitizer reset needed? + * if so, uncomment this line */ + //writeregs(client, cfg_saa7115_reset_scaler); + + decoder->audio = *iarg; + + } + break; + case DECODER_GET_STATUS: + { + int *iarg = arg; + int status; + int res; + + status = saa7114_read(client, 0x1f); + + dprintk(1, KERN_DEBUG "%s status: 0x%02x\n", client->name, + status); + res = 0; + if ((status & (1 << 6)) == 0) { + res |= DECODER_STATUS_GOOD; + } + switch (decoder->norm) { + case VIDEO_MODE_NTSC: + res |= DECODER_STATUS_NTSC; + break; + case VIDEO_MODE_PAL: + res |= DECODER_STATUS_PAL; + break; + case VIDEO_MODE_SECAM: + res |= DECODER_STATUS_SECAM; + break; + default: + case VIDEO_MODE_AUTO: + if ((status & (1 << 5)) != 0) { + res |= DECODER_STATUS_NTSC; + } else { + res |= DECODER_STATUS_PAL; + } + break; + } + if ((status & (1 << 0)) != 0) { + res |= DECODER_STATUS_COLOR; + } + *iarg = res; + } + break; + + case DECODER_SET_NORM: + { + u16 *iarg = arg; + + dprintk(1, KERN_DEBUG "%s: decoder set norm ", + client->name); + + switch (*iarg) { + + case VIDEO_MODE_NTSC: + dprintk(1, "NTSC\n"); + writeregs(client, cfg_saa7115_NTSC_video); + break; + + case VIDEO_MODE_PAL: + dprintk(1, "PAL\n"); + writeregs(client, cfg_saa7115_PAL_video); + break; + + case VIDEO_MODE_SECAM: + dprintk(1, "SECAM\n"); + writeregs(client, cfg_saa7115_PAL_video); + break; + + default: + dprintk(1, " Unknown video mode!!!\n"); + return -EINVAL; + + } + + decoder->norm = *iarg; + + /* switch audio mode too! */ + saa7114_command(client, DECODER_SET_AUDIO, &decoder->audio); + + } + break; + + case DECODER_SET_INPUT: + { + int *iarg = arg; + + dprintk(1, KERN_DEBUG "%s: decoder set input (%d)\n", + client->name, *iarg); + /* inputs from 0-9 are available*/ + if (*iarg < 0 || *iarg > 9) { + return -EINVAL; + } + + if (decoder->input != *iarg) { + dprintk(1, KERN_DEBUG "%s: now setting %s input\n", + client->name, + *iarg >= 6 ? "S-Video" : "Composite"); + decoder->input = *iarg; + + /* select mode */ + saa7114_write( + client, + 0x02, + (saa7114_read(client, 0x02) & 0xf0)|decoder->input); + + /* bypass chrominance trap for modes 6..9 */ + saa7114_write(client, 0x09, + (saa7114_read(client,0x09) & 0x7f)| + (decoder->input < 6 ? 0x0 : 0x80)); + } + } + break; + + case DECODER_SET_OUTPUT: + { + int *iarg = arg; + + dprintk(1, KERN_DEBUG "%s: decoder set output\n", + client->name); + + /* not much choice of outputs */ + if (*iarg != 0) { + return -EINVAL; + } + } + break; + + case DECODER_ENABLE_OUTPUT: + { + int *iarg = arg; + int enable = (*iarg != 0); + + dprintk(1, KERN_DEBUG "%s: decoder %s output\n", + client->name, enable ? "enable" : "disable"); + + decoder->playback = !enable; + + if (decoder->enable != enable) { + decoder->enable = enable; + + if (decoder->enable) { + saa7114_write(client,0x87,0x01); + } else { + saa7114_write(client,0x87,0x00); + } + } + } + break; + + case DECODER_GET_PICTURE: + { + struct saa7114 *pic = arg; + + pic->bright = decoder->bright; + pic->contrast = decoder->contrast; + pic->sat = decoder->sat; + pic->hue = decoder->hue; + } + break; + + case DECODER_SET_PICTURE: + { + struct saa7114 *pic = arg; + + dprintk(1, + KERN_DEBUG + "%s: decoder set picture bright=%d contrast=%d saturation=%d hue=%d\n", + client->name, pic->bright, pic->contrast, + pic->sat, pic->hue); + + if (decoder->bright != pic->bright) { + /* We want 0 to 255 */ + if (pic->bright < 0 || pic->bright > 255) { + dprintk(0, KERN_ERR "%s: invalid brightness setting %d", client->name, pic->bright); + return -EINVAL; + } + decoder->bright = pic->bright; + saa7114_write(client, 0x0a, decoder->bright); + } + if (decoder->contrast != pic->contrast) { + /* We want 0 to 127 */ + if (pic->contrast < 0 || pic->contrast > 127) { + dprintk(0, KERN_ERR "%s: invalid contrast setting %d", client->name, pic->contrast); + return -EINVAL; + } + decoder->contrast = pic->contrast; + saa7114_write(client, 0x0b, decoder->contrast); + } + if (decoder->sat != pic->sat) { + /* We want 0 to 127 */ + if (pic->sat < 0 || pic->sat > 127) { + dprintk(0, KERN_ERR "%s: invalid saturation setting %d", client->name, pic->sat); + return -EINVAL; + } + decoder->sat = pic->sat; + saa7114_write(client, 0x0c, decoder->sat); + } + if (decoder->hue != pic->hue) { + /* We want -128 to 127 */ + if (pic->hue < -128 || pic->hue > 127) { + dprintk(0, KERN_ERR "%s: invalid hue setting %d", client->name, pic->hue); + return -EINVAL; + } + decoder->hue = pic->hue; + saa7114_write(client, 0x0d, decoder->hue); + } + } + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + + +/* + * Generic i2c probe + * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' + */ +static unsigned short normal_i2c[] = + { I2C_SAA7114 >> 1, I2C_SAA7114A >> 1, I2C_CLIENT_END }; +static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; + +I2C_CLIENT_INSMOD; + +static int saa7114_i2c_id = 0; +struct i2c_driver i2c_driver_saa7114; + +static int +saa7114_detect_client (struct i2c_adapter *adapter, + int address, + int kind) +{ +// int i, err[30]; +// short int hoff = SAA_7114_NTSC_HOFFSET; +// short int voff = SAA_7114_NTSC_VOFFSET; +// short int w = SAA_7114_NTSC_WIDTH; +// short int h = SAA_7114_NTSC_HEIGHT; + struct i2c_client *client; + struct saa7114 *decoder; + + dprintk(1, + KERN_INFO + "saa7114.c: detecting saa7114 client on address 0x%x\n", + address << 1); + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return 0; + + client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == 0) + return -ENOMEM; + memset(client, 0, sizeof(struct i2c_client)); + client->addr = address; + client->adapter = adapter; + client->driver = &i2c_driver_saa7114; + client->flags = I2C_CLIENT_ALLOW_USE; + client->id = saa7114_i2c_id++; + snprintf(client->name, sizeof(client->name) - 1, "saa7115[%d]", + client->id); + + i2c_set_clientdata(client, decoder = + kmalloc(sizeof(struct saa7114), GFP_KERNEL)); + if (decoder == NULL) { + kfree(client); + return -ENOMEM; + } + memset(decoder, 0, sizeof(struct saa7114)); + decoder->norm = VIDEO_MODE_NTSC; + decoder->input = -1; + decoder->enable = 1; + decoder->bright = 128; + decoder->contrast = 64; + decoder->hue = 0; + decoder->sat = 64; + decoder->playback = 0; // initially capture mode used + decoder->audio = DECODER_AUDIO_48_KHZ; + + dprintk(1, + KERN_INFO + "saa7115.c: writing init values\n"); + + /* init to NTSC/48khz */ + writeregs(client, init_saa7115_auto_input); + writeregs(client, init_saa7115_misc); + writeregs(client, cfg_saa7115_NTSC_fullres_x); + writeregs(client, cfg_saa7115_NTSC_fullres_y); + writeregs(client, cfg_saa7115_NTSC_video); + writeregs(client, cfg_saa7115_48_audio); + writeregs(client, cfg_saa7115_NTSC_48_audio); + writeregs(client, cfg_saa7115_reset_scaler); + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(2*HZ); + + printk("status: (1E) 0x%02x, (1F) 0x%02x\n", + readreg(client, 0x1e), + readreg(client, 0x1f)); + + i2c_attach_client(client); + + return 0; +} + +static int +saa7114_attach_adapter (struct i2c_adapter *adapter) +{ + dprintk(1, + KERN_INFO + "saa7114.c: starting probe for adapter %s (0x%x)\n", + adapter->name, adapter->id); + return i2c_probe(adapter, &addr_data, &saa7114_detect_client); +} + +static int +saa7114_detach_client (struct i2c_client *client) +{ + struct saa7114 *decoder = i2c_get_clientdata(client); + int err; + + err = i2c_detach_client(client); + if (err) { + return err; + } + + kfree(decoder); + kfree(client); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ +struct i2c_driver i2c_driver_saa7114 = { + .owner = THIS_MODULE, + .name = "saa7115", + + .id = I2C_DRIVERID_SAA7114, + .flags = I2C_DF_NOTIFY, + + .attach_adapter = saa7114_attach_adapter, + .detach_client = saa7114_detach_client, + .command = saa7114_command, +}; + +static int saa7114_init_module (void) +{ + i2c_add_driver(&i2c_driver_saa7114); + + return 0; +} + +static void saa7114_exit_module (void) +{ + i2c_del_driver(&i2c_driver_saa7114); +} + +module_init(saa7114_init_module); +module_exit(saa7114_exit_module); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/saa7127.c 830-ivtv/drivers/media/video/saa7127.c --- 000-virgin/drivers/media/video/saa7127.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/media/video/saa7127.c Thu Jan 8 11:17:36 2004 @@ -0,0 +1,912 @@ +/* + * saa7127 - Philips SAA7127 video encoder driver version 0.2 + * + * Copyright (C) 2003 Roy Bulter + * + * Based on SAA7126 video encoder driver by Gillem & Andreas Oberritter + * + * Copyright (C) 2000-2001 Gillem + * Copyright (C) 2002 Andreas Oberritter + * + * Based on Stadis 4:2:2 MPEG-2 Decoder Driver by Nathan Laredo + * + * Copyright (C) 1999 Nathan Laredo + * + * This driver is designed for the Hauppauge 250/350 Linux driver + * designed by the Ivytv Project (ivtv.sf.net) + * + * Copyright (C) 2003 Kevin Thayer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Revision History + * + * + * Revision : 0.1 (09-05-2003) + * Change : First Version + * + * Revision : 0.2 (21-05-2003) + * Change : solved compiler error on line 785(800) + * reg61h variable was not set in saa7127_set_norm function + * + * Revision : 0.3 (21-07-2003) Matt T. Yourst + * Change : Update configuration tables to make NTSC appear correctly; + * Enable alternative outputs (s-video, composite, RGB, etc.) + */ + + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "saa7127.h" + +/* + ********************************************************************** + * Debug Macro's + * + * + ********************************************************************** + */ + +#define CURRENT_MASK 3 +#define NO_MASK 0 +#define INFO_MASK 1 /* 0b0000000000001 */ +#define ERROR_MASK 2 /* 0b0000000000010 */ +#define ENTER_MASK 4 /* 0b0000000000100 */ +#define RETURN_MASK 8 /* 0b0000000001000 */ +#define TRACE1_MASK 16 /* 0b0000000010000 */ +#define TRACE2_MASK 32 /* 0b0000000100000 */ +#define TRACE3_MASK 64 /* 0b0000001000000 */ +#define TRACE4_MASK 128 /* 0b0000010000000 */ +#define TRACE5_MASK 256 /* 0b0000100000000 */ +#define TRACE6_MASK 512 /* 0b0001000000000 */ +#define TRACE7_MASK 1024 /* 0b0010000000000 */ +#define TRACE8_MASK 2048 /* 0b0100000000000 */ +#define TRACE9_MASK 4096 /* 0b1000000000000 */ + + +static int debug_mask = CURRENT_MASK; +static int test_image = 0; +static int pal = 0; +static int enable_output = 0; +static int output_select = SAA7127_OUTPUT_TYPE_SVIDEO; + +#define INFO(format, args...)\ + if ((debug_mask&INFO_MASK) == INFO_MASK)\ + {\ + printk("[%s: INFO]: ", __FILE__);\ + printk(format, ##args);\ + printk("\n");\ + }\ + +#define ERROR(format, args...)\ + if ((debug_mask&ERROR_MASK) == ERROR_MASK)\ + {\ + printk("[%s: %d: ERROR]: ", __FILE__,__LINE__);\ + printk(format, ##args);\ + printk("\n");\ + }\ + + +#ifdef DEBUG + +#define ENTER\ + if ((debug_mask&ENTER_MASK) == ENTER_MASK)\ + {\ + printk("[%s : %s: %d: ENTER]: ",__FILE__,__FUNCTION__,__LINE__);\ + printk("\n");\ + }\ + +#define RETURN(value)\ + if ((debug_mask&RETURN_MASK) == RETURN_MASK)\ + {\ + printk("[%s : %s : %d: RETURN]: ", __FILE__,__FUNCTION__,__LINE__);\ + printk("value: %x",value);\ + printk("\n");\ + }\ + return(value);\ + +static int get_trace_mask(int num) +{ + switch (num) + { + case 1: + return TRACE1_MASK; + break; + case 2: + return TRACE2_MASK; + break; + case 3: + return TRACE3_MASK; + break; + case 4: + return TRACE4_MASK; + break; + case 5: + return TRACE5_MASK; + break; + case 6: + return TRACE6_MASK; + break; + case 7: + return TRACE7_MASK; + break; + case 8: + return TRACE8_MASK; + break; + case 9: + return TRACE9_MASK; + break; + default: + return NO_MASK; + } +} + +#define TRACE(num, format, args...) \ + if ((debug_mask&get_trace_mask(num)) == get_trace_mask(num)) \ + {\ + printk("[%s: %d: TRACE%d] ", __FILE__, __LINE__,num);\ + printk(format, ##args);\ + printk("\n");\ + }\ + +#else + +#define ENTER +#define RETURN(value) return(value); +#define TRACE(num, format, args...) + +#endif /* DEBUG */ + +/* + ********************************************************************** + * + * Array's with configuration parameters for the SAA7127 + * + ********************************************************************** + */ + +struct i2c_reg_value +{ + unsigned char reg; + unsigned char value; +}; + +struct i2c_reg_value saa7127_init_config_common[] = +{ + {SAA7127_REG_WIDESCREEN_CONFIG, 0x0d}, + {SAA7127_REG_WIDESCREEN_ENABLE, 0x00}, + {SAA7127_REG_COPYGEN_0, 0x77}, + {SAA7127_REG_COPYGEN_1, 0x41}, + {SAA7127_REG_COPYGEN_2, 0x00}, // (Macrovision enable/disable) + {SAA7127_REG_OUTPUT_PORT_CONTROL, 0x9e}, + {SAA7127_REG_GAIN_LUMINANCE_RGB, 0x00}, + {SAA7127_REG_GAIN_COLORDIFF_RGB, 0x00}, + {SAA7127_REG_INPUT_PORT_CONTROL_1, 0x80}, // (for color bars) + {SAA7127_REG_LINE_21_ODD_0, 0x77}, + {SAA7127_REG_LINE_21_ODD_1, 0x41}, + {SAA7127_REG_LINE_21_EVEN_0, 0x88}, + {SAA7127_REG_LINE_21_EVEN_1, 0x41}, + {SAA7127_REG_RCV_PORT_CONTROL, 0x12}, + {SAA7127_REG_VTRIG, 0xf9}, + {SAA7127_REG_HTRIG_HI, 0x00}, + {SAA7127_REG_RCV2_OUTPUT_START, 0x41}, + {SAA7127_REG_RCV2_OUTPUT_END, 0xc3}, + {SAA7127_REG_RCV2_OUTPUT_MSBS, 0x00}, + {SAA7127_REG_TTX_REQUEST_H_START, 0x3e}, + {SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH, 0xb8}, + {SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT, 0x03}, + {SAA7127_REG_TTX_ODD_REQ_VERT_START, 0x15}, + {SAA7127_REG_TTX_ODD_REQ_VERT_END, 0x16}, + {SAA7127_REG_TTX_EVEN_REQ_VERT_START, 0x15}, + {SAA7127_REG_TTX_EVEN_REQ_VERT_END, 0x16}, + {SAA7127_REG_FIRST_ACTIVE, 0x1a}, + {SAA7127_REG_LAST_ACTIVE, 0x01}, + {SAA7127_REG_MSB_VERTICAL, 0xc0}, + {SAA7127_REG_DISABLE_TTX_LINE_LO_0, 0x00}, + {SAA7127_REG_DISABLE_TTX_LINE_LO_1, 0x00}, + {0, 0} +}; + +#define SAA7127_NTSC_DAC_CONTROL 0x05 +struct i2c_reg_value saa7127_init_config_ntsc[] = +{ + {SAA7127_REG_BURST_START, 0x19}, + {SAA7127_REG_BURST_END, 0x1d}, + {SAA7127_REG_CHROMA_PHASE, 0x27}, + {SAA7127_REG_GAINU, 0x88}, + {SAA7127_REG_GAINV, 0xc0}, + {SAA7127_REG_BLACK_LEVEL, 0x3f}, + {SAA7127_REG_BLANKING_LEVEL, 0x36}, + {SAA7127_REG_VBI_BLANKING, 0x36}, + {SAA7127_REG_DAC_CONTROL, 0x05}, + {SAA7127_REG_BURST_AMP, 0x4a}, + {SAA7127_REG_SUBC3, 0x1f}, + {SAA7127_REG_SUBC2, 0x7c}, + {SAA7127_REG_SUBC1, 0xf0}, + {SAA7127_REG_SUBC0, 0x21}, + {SAA7127_REG_MULTI, 0x90}, + {SAA7127_REG_CLOSED_CAPTION, 0x14}, + {0, 0} +}; + +#define SAA7127_PAL_DAC_CONTROL 0x02 +struct i2c_reg_value saa7127_init_config_pal[] = +{ + {SAA7127_REG_BURST_START, 0x21}, + {SAA7127_REG_BURST_END, 0x1d}, + {SAA7127_REG_CHROMA_PHASE, 0x3f}, + {SAA7127_REG_GAINU, 0x7d}, + {SAA7127_REG_GAINV, 0xaf}, + {SAA7127_REG_BLACK_LEVEL, 0x23}, + {SAA7127_REG_BLANKING_LEVEL, 0x35}, + {SAA7127_REG_VBI_BLANKING, 0x35}, + {SAA7127_REG_DAC_CONTROL, 0x02}, + {SAA7127_REG_BURST_AMP, 0x2f}, + {SAA7127_REG_SUBC3, 0xcb}, + {SAA7127_REG_SUBC2, 0x8a}, + {SAA7127_REG_SUBC1, 0x09}, + {SAA7127_REG_SUBC0, 0x2a}, + {SAA7127_REG_MULTI, 0xa0}, + {SAA7127_REG_CLOSED_CAPTION, 0x00}, + {0, 0} +}; + +/* + ********************************************************************** + * + * Encoder Struct, holds the configuration state of the encoder + * + ********************************************************************** + */ + +struct saa7127 +{ + enum SAA7127_video_norm norm; + enum SAA7127_input_type input_type; + enum SAA7127_output_type output_type; + enum SAA7127_enable_type enable; + enum SAA7127_wss_enable_type wss_enable; + enum SAA7127_wss_mode_type wss_mode; + u8 reg_2d; + u8 reg_3a; + u8 reg_61; +}; + +/* ----------------------------------------------------------------------- */ + +static int saa7127_read (struct i2c_client *client, + u8 reg) +{ + ENTER; + RETURN (i2c_smbus_read_byte_data(client, reg)); +} + + +/* ----------------------------------------------------------------------- */ + + +static int saa7127_writereg(struct i2c_client *client, u8 reg, u8 val) +{ + ENTER; + if (i2c_smbus_write_byte_data(client, reg, val) < 0) + { + ERROR ("I2C Write Problem"); + return (-1); + } + TRACE(4,"I2C Write to reg: %x, data: %x",reg,val); + RETURN (0); +} + + +/* ----------------------------------------------------------------------- */ + +static int saa7127_write_inittab(struct i2c_client *client, const struct i2c_reg_value *regs) +{ + ENTER; + + while (regs->reg != 0) + { + if (i2c_smbus_write_byte_data(client, regs->reg, regs->value) < 0) + { + ERROR ("I2C Write Problem"); + RETURN (-1); + } + TRACE(4,"I2C Write to reg: %x, data: %x",regs->reg,regs->value); + regs++; + } + RETURN (0); +} + + +/* ----------------------------------------------------------------------- */ + + +static int saa7127_set_wss(struct i2c_client *client) +{ + struct saa7127 *encoder = (struct saa7127 *) i2c_get_clientdata(client); + + ENTER; + switch (encoder->wss_enable) + { + case SAA7127_WSS_DISABLE: + TRACE(3,"Disable Wide Screen Signal"); + saa7127_writereg(client, 0x27, 0x00); + break; + case SAA7127_WSS_ENABLE: + TRACE(3,"Enable Wide Screen Signal"); + saa7127_writereg(client, 0x27, 0x80); + break; + default: + return (-EINVAL); + } + return (0); +} + + + +/* ----------------------------------------------------------------------- */ + + +static int saa7127_set_wss_mode(struct i2c_client *client) +{ + struct saa7127 *encoder = (struct saa7127 *) i2c_get_clientdata(client); + + ENTER; + + switch (encoder->wss_mode) + { + case SAA7127_WSS_MODE_4_3_FULL_FORMAT: + TRACE(3,"Widescreen Mode 4:3 Full Format"); + saa7127_writereg(client, 0x26, 0x08); + break; + case SAA7127_WSS_MODE_BOX_14_9_C: + TRACE(3,"Widescreen Mode Box 14:9 Center"); + saa7127_writereg(client, 0x26, 0x01); + break; + case SAA7127_WSS_MODE_BOX_14_9_TOP: + TRACE(3,"Widescreen Mode Box 14:9 Top"); + saa7127_writereg(client, 0x26, 0x02); + break; + case SAA7127_WSS_MODE_BOX_16_9_C: + TRACE(3,"Widescreen Mode Box 16:9 Center"); + saa7127_writereg(client, 0x26, 0x0b); + break; + case SAA7127_WSS_MODE_BOX_16_9_TOP: + TRACE(3,"Widescreen Mode Box 16:9 Top"); + saa7127_writereg(client, 0x26, 0x04); + break; + case SAA7127_WSS_MODE_SMALL_BOX_16_9_C: + TRACE(3,"Widescreen Mode Small Box 16:9 Center"); + saa7127_writereg(client, 0x26, 0x0d); + break; + case SAA7127_WSS_MODE_4_3_14_9_FULL_FORMAT: + TRACE(3,"Widescreen Mode 14:9 Full Format"); + saa7127_writereg(client, 0x26, 0x0e); + break; + case SAA7127_WSS_MODE_16_9_ANAMORPHIC: + TRACE(3,"Widescreen Mode 16:9 Full Format"); + saa7127_writereg(client, 0x26, 0x07); + break; + default: + RETURN (-EINVAL); + } + RETURN (0); +} + + + +/* ----------------------------------------------------------------------- */ + + +static int saa7127_set_enable (struct i2c_client *client) +{ + struct saa7127 *encoder = (struct saa7127 *) i2c_get_clientdata(client); + + ENTER; + + switch (encoder->enable) + { + case SAA7127_DISABLE: + TRACE(3,"Disable Video Output"); + saa7127_writereg(client, 0x2d, (encoder->reg_2d & 0xf0)); + saa7127_writereg(client, 0x61, (encoder->reg_61 | 0xc0)); + break; + case SAA7127_ENABLE: + TRACE(3,"Enable Video Output"); + saa7127_writereg(client, 0x2d, encoder->reg_2d); + saa7127_writereg(client, 0x61, encoder->reg_61); + break; + default: + RETURN (-EINVAL); + } + +#if 0 + int j; + for (j = 0; j < 128/16; j++) + { + TRACE(3, "saa7127 registers 0x%02x-0x%02x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + j*16, j*16 + 15, + saa7127_read(client, j*16 + 0), + saa7127_read(client, j*16 + 1), + saa7127_read(client, j*16 + 2), + saa7127_read(client, j*16 + 3), + saa7127_read(client, j*16 + 4), + saa7127_read(client, j*16 + 5), + saa7127_read(client, j*16 + 6), + saa7127_read(client, j*16 + 7), + saa7127_read(client, j*16 + 8), + saa7127_read(client, j*16 + 9), + saa7127_read(client, j*16 + 10), + saa7127_read(client, j*16 + 11), + saa7127_read(client, j*16 + 12), + saa7127_read(client, j*16 + 13), + saa7127_read(client, j*16 + 14), + saa7127_read(client, j*16 + 15)); + } +#endif + + RETURN (0); +} + + +/* ----------------------------------------------------------------------- */ + +static int saa7127_set_norm(struct i2c_client *client) +{ + struct saa7127 *encoder = (struct saa7127 *) i2c_get_clientdata(client); + const struct i2c_reg_value *inittab; + + ENTER; + + switch (encoder->norm) + { + case SAA7127_VIDEO_NORM_NTSC: + TRACE(3,"Selecting NTSC video Standard"); + inittab = saa7127_init_config_ntsc; + encoder->reg_61 = SAA7127_NTSC_DAC_CONTROL; + break; + case SAA7127_VIDEO_NORM_PAL: + TRACE(3,"Selecting PAL video Standard"); + inittab = saa7127_init_config_pal; + encoder->reg_61 = SAA7127_PAL_DAC_CONTROL; + break; + default: + RETURN (-EINVAL); + } + + /* Write Table */ + saa7127_write_inittab(client, inittab); + RETURN (0); +} + +/* ----------------------------------------------------------------------- */ + +static int saa7127_set_output_type(struct i2c_client *client) +{ + struct saa7127 *encoder = (struct saa7127 *) i2c_get_clientdata(client); + + ENTER; + + encoder->reg_3a = 0x13; // by default swithch YUV to RGB-matrix on + + switch (encoder->output_type) + { + case SAA7127_OUTPUT_TYPE_RGB: + TRACE(3,"Selecting RGB Output Type"); + encoder->reg_2d = 0x0f; // RGB + CVBS (for sync) + break; + case SAA7127_OUTPUT_TYPE_COMPOSITE: + TRACE(3,"Selecting Composite Output Type"); + encoder->reg_2d = 0x08; // 00001000 CVBS only, RGB DAC's off (high impedance mode) !!! + break; + case SAA7127_OUTPUT_TYPE_SVIDEO: + TRACE(3,"Selecting S-Video Output Type"); + encoder->reg_2d = 0xff; // 11111111 croma -> R, luma -> CVBS + G + B + break; + case SAA7127_OUTPUT_TYPE_YUV_V: + TRACE(3,"Selecting YUV V Output Type"); + encoder->reg_2d = 0x4f; // reg 2D = 01001111, all DAC's on, RGB + VBS + encoder->reg_3a = 0x0b; // reg 3A = 00001011, bypass RGB-matrix + break; + case SAA7127_OUTPUT_TYPE_YUV_C: + TRACE(3,"Selecting YUV C Output Type"); + encoder->reg_2d = 0x0f; // reg 2D = 00001111, all DAC's on, RGB + CVBS + encoder->reg_3a = 0x0b; // reg 3A = 00001011, bypass RGB-matrix + break; + default: + RETURN (-EINVAL); + } + + /* Configure Encoder */ + + saa7127_writereg(client, 0x2d, encoder->reg_2d); + saa7127_writereg(client, 0x3a, (encoder->input_type == SAA7127_INPUT_TYPE_TEST_IMAGE) ? 0x80 : encoder->reg_3a); + + RETURN (0); +} + + +static int saa7127_set_input_type(struct i2c_client *client) +{ + struct saa7127 *encoder = (struct saa7127 *) i2c_get_clientdata(client); + + ENTER; + + switch (encoder->input_type) + { + case SAA7127_INPUT_TYPE_NORMAL: /* avia */ + TRACE(3,"Selecting Normal Encoder Input"); + saa7127_writereg(client, 0x3a, encoder->reg_3a); + break; + case SAA7127_INPUT_TYPE_TEST_IMAGE: /* color bar */ + TRACE(3,"Selecting Colour Bar generator"); + saa7127_writereg(client, 0x3a, 0x80); + break; + default: + RETURN (-EINVAL); + } + + RETURN (0); +} + + +/* ----------------------------------------------------------------------- */ + + +static int saa7127_command (struct i2c_client *client, + unsigned int cmd, + void *parg) +{ + struct saa7127 *encoder = i2c_get_clientdata(client); + unsigned long arg = (unsigned long) parg; + struct video_encoder_capability *cap = parg; + ENTER; + printk("saa7127_command: entered with cmd = %d\n", cmd); + + switch (cmd) + { + case ENCODER_GET_CAPABILITIES: + TRACE(3,"Asking Encoder Capabilities"); + cap->flags = VIDEO_ENCODER_PAL | VIDEO_ENCODER_NTSC; + cap->inputs = 1; + cap->outputs = 1; + break; + + case ENCODER_SET_NORM: + TRACE(3,"Setting Encoder Video Standard"); + switch (arg) + { + case VIDEO_MODE_NTSC: + TRACE(3,"Set NTSC Video Mode"); + encoder->norm = SAA7127_VIDEO_NORM_NTSC; + break; + case VIDEO_MODE_PAL: + TRACE(3,"Set PAL Video Mode"); + encoder->norm = SAA7127_VIDEO_NORM_PAL; + break; + default: + return (-EINVAL); + } + saa7127_set_norm(client); + break; + + case ENCODER_SET_INPUT: + TRACE(3,"Setting Encoder Input"); + switch (arg) + { + case SAA7127_INPUT_NORMAL: /* encoder input selected */ + TRACE(3,"Select Normal input"); + encoder->input_type = SAA7127_INPUT_TYPE_NORMAL; + break; + case SAA7127_INPUT_TESTIMAGE: /* Internal colourbars selected */ + TRACE(3,"Select ColourBar Generator"); + encoder->input_type = SAA7127_INPUT_TYPE_TEST_IMAGE; + break; + default: + RETURN (-EINVAL); + } + saa7127_set_input_type (client); + break; + + case ENCODER_SET_OUTPUT: + TRACE(3,"Setting Encoder Output"); + encoder->output_type = arg; + saa7127_set_output_type(client); + break; + + case ENCODER_ENABLE_OUTPUT: + TRACE(3,"Turn on/off Output"); + switch (arg) + { + case SAA7127_VIDEO_ENABLE: + TRACE (3,"Turn on Video Output"); + encoder->enable=SAA7127_ENABLE; + break; + case SAA7127_VIDEO_DISABLE: + TRACE (3,"Turn off Video Output"); + encoder->enable=SAA7127_DISABLE; + break; + default: + RETURN (-EINVAL); + } + saa7127_set_enable(client); + break; + + default: + RETURN (-EINVAL); + } + RETURN (0); +} + + + +/* ----------------------------------------------------------------------- */ + +/* + * Generic i2c probe + * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' + */ + +static unsigned short normal_i2c[] = { I2C_SAA7127_ADRESS >> 1,I2C_CLIENT_END }; +static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; + +I2C_CLIENT_INSMOD; + +static int saa7127_i2c_id = 0; +struct i2c_driver i2c_driver_saa7127; + + +/* ----------------------------------------------------------------------- */ + + + +static int saa7127_detect_client (struct i2c_adapter *adapter, + int address, + int kind) +{ + struct i2c_client *client; + struct saa7127 *encoder; + int read_result = 0; + + ENTER; + + TRACE(1,"detecting saa7127 client on address 0x%x", address << 1); + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return (0); + + client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == 0) + return (-ENOMEM); + + memset(client, 0, sizeof(struct i2c_client)); + client->addr = address; + client->adapter = adapter; + client->driver = &i2c_driver_saa7127; + client->flags = I2C_CLIENT_ALLOW_USE; + client->id = saa7127_i2c_id++; + snprintf(client->name, sizeof(client->name) - 1, "saa7127[%d]", client->id); + + i2c_set_clientdata(client, encoder = kmalloc(sizeof(struct saa7127), GFP_KERNEL)); + + if (encoder == NULL) + { + kfree(client); + return (-ENOMEM); + } + + memset(encoder, 0, sizeof(struct saa7127)); + + + /* Initialize default values */ + + encoder->output_type = output_select; + encoder->wss_enable = SAA7127_WSS_DISABLE; + encoder->wss_mode = SAA7127_WSS_MODE_4_3_FULL_FORMAT; + + + /* Look if the pal module parameter is set */ + + if (pal == 1) + { + /* Select PAL Video Standard */ + encoder->norm = SAA7127_VIDEO_NORM_PAL; + } + else + { + /* Select NTSC Video Standard, default */ + encoder->norm = SAA7127_VIDEO_NORM_NTSC; + } + + /* Look if the Encoder needs to be enabled */ + + if (enable_output == 1) + { + encoder->enable = SAA7127_ENABLE; + } + else + { + /* for default disable output */ + /* Because the MPEG DECODER is not initialised */ + encoder->enable = SAA7127_DISABLE; + } + + /* The Encoder is does have internal Colourbar generator */ + /* This can be used for debugging, configuration values for the encoder */ + + if (test_image == 1) + { + /* Select ColourBar Generator */ + encoder->input_type = SAA7127_INPUT_TYPE_TEST_IMAGE; + } + else + { + /* Select normal input */ + encoder->input_type = SAA7127_INPUT_TYPE_NORMAL; + } + + + TRACE(2,"writing init values"); + + /* Configure Encoder */ + + printk("saa7127: Configuring encoder..."); + saa7127_write_inittab(client, saa7127_init_config_common); + saa7127_set_norm(client); + saa7127_set_output_type (client); + saa7127_set_wss (client); + saa7127_set_wss_mode (client); + saa7127_set_input_type (client); + saa7127_set_enable (client); + + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(2*HZ); + + read_result = saa7127_read(client, 0x00); + + TRACE(4,"Read status register (00h) : 0x%02x ", read_result); + + i2c_attach_client(client); + + RETURN (0); +} + + +/* ----------------------------------------------------------------------- */ + + +static int saa7127_attach_adapter (struct i2c_adapter *adapter) +{ + + TRACE(2,"starting probe for adapter %s (0x%x)", adapter->dev.name, adapter->id); + return (i2c_probe(adapter, &addr_data, &saa7127_detect_client)); +} + + +/* ----------------------------------------------------------------------- */ + + +static int saa7127_detach_client (struct i2c_client *client) +{ + struct saa7127 *encoder = i2c_get_clientdata(client); + int err; + + /* Turn off TV output */ + + encoder->enable = SAA7127_DISABLE; + saa7127_set_enable (client); + + err = i2c_detach_client(client); + + if (err) + { + return (err); + } + + kfree(encoder); + kfree(client); + return (0); +} + +/* ----------------------------------------------------------------------- */ + + +struct i2c_driver i2c_driver_saa7127 = +{ + .owner = THIS_MODULE, + .name = "saa7127", + .id = I2C_DRIVERID_SAA7127, + .flags = I2C_DF_NOTIFY, + .attach_adapter = saa7127_attach_adapter, + .detach_client = saa7127_detach_client, + .command = saa7127_command, +}; + + +/* ----------------------------------------------------------------------- */ + + +static int saa7127_init (void) +{ + INFO ("SAA7127 video encoder driver loaded"); + TRACE (1,"Driver version: V %s",SAA7127_DRIVER_VERSION); + return (i2c_add_driver(&i2c_driver_saa7127)); +} + + +/* ----------------------------------------------------------------------- */ + + +static void saa7127_exit (void) +{ + + INFO ("SAA7127 video encoder driver unloaded"); + i2c_del_driver(&i2c_driver_saa7127); +} + + + +/* ----------------------------------------------------------------------- */ + + +module_init(saa7127_init); +module_exit(saa7127_exit); + + +MODULE_DESCRIPTION("Philips SAA7127 video encoder driver"); +MODULE_AUTHOR("Roy Bulter"); +MODULE_LICENSE("GPL"); +MODULE_PARM(debug_mask, "i"); +MODULE_PARM(test_image, "i"); +MODULE_PARM(pal, "i"); +MODULE_PARM(enable_output, "i"); +MODULE_PARM(output_select, "i"); +MODULE_PARM_DESC(debug_mask, "debug_mask (0-8192) "); +MODULE_PARM_DESC(test_image, "test_image (0-1) "); +MODULE_PARM_DESC(pal, "pal (0-1) "); +MODULE_PARM_DESC(enable_output, "enable_output (0-1) "); +MODULE_PARM_DESC(output_select, "output_select (0 = composite, 1 = s-video, 2 = rgb, 3 = YUVc, 4 = YUVv)"); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/saa7127.h 830-ivtv/drivers/media/video/saa7127.h --- 000-virgin/drivers/media/video/saa7127.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/media/video/saa7127.h Thu Jan 8 11:17:36 2004 @@ -0,0 +1,154 @@ +#ifndef _SAA7127_H +#define _SAA7127_H + +/* + ********************************************************************** + * + * Define's + * + * + ********************************************************************** + */ + + +#define SAA7127_DRIVER_VERSION "0.3" + + +#ifndef I2C_DRIVERID_SAA7127 + #warning Using temporary hack for missing I2C driver-ID for saa7127 + #define I2C_DRIVERID_SAA7127 I2C_DRIVERID_EXP2 +#endif + + +#define I2C_SAA7127_ADRESS 0x88 + +#define SAA7127_VIDEO_ENABLE 0x01 +#define SAA7127_VIDEO_DISABLE 0x00 + +#define SAA7127_INPUT_TESTIMAGE 0x01 +#define SAA7127_INPUT_NORMAL 0x00 + +/* + * SAA7127 registers + */ + +#define SAA7127_REG_STATUS 0x00 +/* (registers 0x01-0x25 unused.) */ +#define SAA7127_REG_WIDESCREEN_CONFIG 0x26 +#define SAA7127_REG_WIDESCREEN_ENABLE 0x27 +#define SAA7127_REG_BURST_START 0x28 +#define SAA7127_REG_BURST_END 0x29 +#define SAA7127_REG_COPYGEN_0 0x2a +#define SAA7127_REG_COPYGEN_1 0x2b +#define SAA7127_REG_COPYGEN_2 0x2c +#define SAA7127_REG_OUTPUT_PORT_CONTROL 0x2d +/* (registers 0x2e-0x37 unused.) */ +#define SAA7127_REG_GAIN_LUMINANCE_RGB 0x38 +#define SAA7127_REG_GAIN_COLORDIFF_RGB 0x39 +#define SAA7127_REG_INPUT_PORT_CONTROL_1 0x3A +/* (registers 0x3b-0x53 undefined) */ +#define SAA7127_REG_CHROMA_PHASE 0x5A +#define SAA7127_REG_GAINU 0x5B +#define SAA7127_REG_GAINV 0x5C +#define SAA7127_REG_BLACK_LEVEL 0x5D +#define SAA7127_REG_BLANKING_LEVEL 0x5E +#define SAA7127_REG_VBI_BLANKING 0x5F +/* (register 0x60 unused) */ +#define SAA7127_REG_DAC_CONTROL 0x61 +#define SAA7127_REG_BURST_AMP 0x62 +#define SAA7127_REG_SUBC3 0x63 +#define SAA7127_REG_SUBC2 0x64 +#define SAA7127_REG_SUBC1 0x65 +#define SAA7127_REG_SUBC0 0x66 +#define SAA7127_REG_LINE_21_ODD_0 0x67 +#define SAA7127_REG_LINE_21_ODD_1 0x68 +#define SAA7127_REG_LINE_21_EVEN_0 0x69 +#define SAA7127_REG_LINE_21_EVEN_1 0x6A +#define SAA7127_REG_RCV_PORT_CONTROL 0x6B +#define SAA7127_REG_VTRIG 0x6C +#define SAA7127_REG_HTRIG_HI 0x6D +#define SAA7127_REG_MULTI 0x6E +#define SAA7127_REG_CLOSED_CAPTION 0x6F +#define SAA7127_REG_RCV2_OUTPUT_START 0x70 +#define SAA7127_REG_RCV2_OUTPUT_END 0x71 +#define SAA7127_REG_RCV2_OUTPUT_MSBS 0x72 +#define SAA7127_REG_TTX_REQUEST_H_START 0x73 +#define SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH 0x74 +#define SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT 0x75 +#define SAA7127_REG_TTX_ODD_REQ_VERT_START 0x76 +#define SAA7127_REG_TTX_ODD_REQ_VERT_END 0x77 +#define SAA7127_REG_TTX_EVEN_REQ_VERT_START 0x78 +#define SAA7127_REG_TTX_EVEN_REQ_VERT_END 0x79 +#define SAA7127_REG_FIRST_ACTIVE 0x7A +#define SAA7127_REG_LAST_ACTIVE 0x7B +#define SAA7127_REG_MSB_VERTICAL 0x7C +/* (register 0x7d unused) */ +#define SAA7127_REG_DISABLE_TTX_LINE_LO_0 0x7E +#define SAA7127_REG_DISABLE_TTX_LINE_LO_1 0x7F + + + +/* + ********************************************************************** + * + * Enumurations + * + ********************************************************************** + */ + + +/* Enumeration for the Video Standard */ + + +enum SAA7127_video_norm { + SAA7127_VIDEO_NORM_NTSC, + SAA7127_VIDEO_NORM_PAL + }; + + +/* Enumeration for the Supported input types */ + +enum SAA7127_input_type { + SAA7127_INPUT_TYPE_NORMAL, + SAA7127_INPUT_TYPE_TEST_IMAGE + }; + + +/* Enumeration for the Supported Output signal types */ + +enum SAA7127_output_type { + SAA7127_OUTPUT_TYPE_COMPOSITE, + SAA7127_OUTPUT_TYPE_SVIDEO, + SAA7127_OUTPUT_TYPE_RGB, + SAA7127_OUTPUT_TYPE_YUV_C, + SAA7127_OUTPUT_TYPE_YUV_V + }; + +/* Enumeration for the enable/disabeling the output signal */ + +enum SAA7127_enable_type { + SAA7127_DISABLE, + SAA7127_ENABLE + }; +/* Enumeration for the turning on/off the Wide screen signal for Wide screen TV */ + +enum SAA7127_wss_enable_type { + SAA7127_WSS_DISABLE, + SAA7127_WSS_ENABLE + }; + +/* Enumeration for the selecting the different Wide screen mode */ + +enum SAA7127_wss_mode_type { + SAA7127_WSS_MODE_4_3_FULL_FORMAT, /* full format 4:3 */ + SAA7127_WSS_MODE_BOX_14_9_C, /* box 14:9 c */ + SAA7127_WSS_MODE_BOX_14_9_TOP, /* box 14:9 top */ + SAA7127_WSS_MODE_BOX_16_9_C, /* box 16:9 c */ + SAA7127_WSS_MODE_BOX_16_9_TOP, /* box 16:9 top */ + SAA7127_WSS_MODE_SMALL_BOX_16_9_C, /* box > 16:9 c */ + SAA7127_WSS_MODE_4_3_14_9_FULL_FORMAT, /* full format 4:3 with 14:9 c letterbox content */ + SAA7127_WSS_MODE_16_9_ANAMORPHIC /* full format 16:9 (anamorphic) */ + }; + + +#endif // _SAA7127_H diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/saa7134/Makefile 830-ivtv/drivers/media/video/saa7134/Makefile --- 000-virgin/drivers/media/video/saa7134/Makefile Mon Dec 16 21:50:44 2002 +++ 830-ivtv/drivers/media/video/saa7134/Makefile Thu Jan 8 11:17:27 2004 @@ -1,7 +1,7 @@ saa7134-objs := saa7134-cards.o saa7134-core.o saa7134-i2c.o \ saa7134-oss.o saa7134-ts.o saa7134-tvaudio.o \ - saa7134-vbi.o saa7134-video.o + saa7134-vbi.o saa7134-video.o saa7134-input.o obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/saa7134/saa6752hs.c 830-ivtv/drivers/media/video/saa7134/saa6752hs.c --- 000-virgin/drivers/media/video/saa7134/saa6752hs.c Mon Nov 17 18:29:29 2003 +++ 830-ivtv/drivers/media/video/saa7134/saa6752hs.c Thu Jan 8 11:17:27 2004 @@ -168,13 +168,13 @@ static int saa6752hs_chip_command(struct } // wait a bit - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/100); } // delay a bit to let encoder settle - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(5); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/20); // done return status; @@ -230,6 +230,7 @@ static int saa6752hs_set_bitrate(struct static int saa6752hs_init(struct i2c_client* client, struct mpeg_params* params) { unsigned char buf[3]; + void *data; // check the bitrate parameters first if (params != NULL) { @@ -281,12 +282,13 @@ static int saa6752hs_init(struct i2c_cli i2c_master_send(client,buf,3); // setup bitrate settings + data = i2c_get_clientdata(client); if (params) { saa6752hs_set_bitrate(client, params); - memcpy(client->data, params, sizeof(struct mpeg_params)); + memcpy(data, params, sizeof(struct mpeg_params)); } else { // parameters were not supplied. use the previous set - saa6752hs_set_bitrate(client, (struct mpeg_params*) client->data); + saa6752hs_set_bitrate(client, (struct mpeg_params*) data); } // Send SI tables @@ -324,7 +326,7 @@ static int saa6752hs_attach(struct i2c_a if (NULL == (params = kmalloc(sizeof(struct mpeg_params), GFP_KERNEL))) return -ENOMEM; memcpy(params,&mpeg_params_template,sizeof(struct mpeg_params)); - client->data = params; + i2c_set_clientdata(client, params); i2c_attach_client(client); @@ -341,8 +343,11 @@ static int saa6752hs_probe(struct i2c_ad static int saa6752hs_detach(struct i2c_client *client) { + void *data; + + data = i2c_get_clientdata(client); i2c_detach_client(client); - kfree(client->data); + kfree(data); kfree(client); return 0; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/saa7134/saa7134-cards.c 830-ivtv/drivers/media/video/saa7134/saa7134-cards.c --- 000-virgin/drivers/media/video/saa7134/saa7134-cards.c Mon Nov 17 18:29:29 2003 +++ 830-ivtv/drivers/media/video/saa7134/saa7134-cards.c Thu Jan 8 11:17:27 2004 @@ -2,7 +2,7 @@ * device driver for philips saa7134 based TV cards * card-specific stuff. * - * (c) 2001,02 Gerd Knorr [SuSE Labs] + * (c) 2001-03 Gerd Knorr [SuSE Labs] * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -70,6 +70,10 @@ struct saa7134_board saa7134_boards[] = .amux = LINE2, .tv = 1, }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, }, [SAA7134_BOARD_FLYVIDEO3000] = { /* "Marco d'Itri" */ @@ -235,7 +239,7 @@ struct saa7134_board saa7134_boards[] = }, }, [SAA7134_BOARD_TVSTATION_RDS] = { - .name = "KNC One TV-Station RDS", + .name = "KNC One TV-Station RDS / Typhoon TV+Radio 90031", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, .need_tda9887 = 1, @@ -245,11 +249,11 @@ struct saa7134_board saa7134_boards[] = .amux = TV, .tv = 1, },{ - .name = name_comp1, - .vmux = 2, + .name = name_svideo, + .vmux = 8, .amux = LINE1, },{ - .name = name_comp2, + .name = name_comp1, .vmux = 3, .amux = LINE1, }}, @@ -258,6 +262,38 @@ struct saa7134_board saa7134_boards[] = .amux = LINE2, }, }, + [SAA7134_BOARD_TVSTATION_DVR] = { + .name = "KNC One TV-Station DVR", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .need_tda9887 = 1, + .gpiomask = 0x820000, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = LINE2, + .tv = 1, + .gpio = 0x20000, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + .gpio = 0x20000, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + .gpio = 0x20000, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + .gpio = 0x20000, + }, + .i2s_rate = 48000, + .has_ts = 1, + .video_out = CCIR656, + }, [SAA7134_BOARD_CINERGY400] = { .name = "Terratec Cinergy 400 TV", .audio_clock = 0x00200000, @@ -283,7 +319,7 @@ struct saa7134_board saa7134_boards[] = }, [SAA7134_BOARD_MD5044] = { .name = "Medion 5044", - .audio_clock = 0x00200000, + .audio_clock = 0x00187de7, // was: 0x00200000, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, .need_tda9887 = 1, .inputs = {{ @@ -392,32 +428,6 @@ struct saa7134_board saa7134_boards[] = .amux = LINE2, }, }, - [SAA7134_BOARD_TYPHOON_90031] = { - /* Christian Rothl�nder */ - .name = "Typhoon TV+Radio 90031", - .audio_clock = 0x00200000, - //.tuner_type = TUNER_PHILIPS_PAL, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .need_tda9887 = 1, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, [SAA7134_BOARD_ELSA] = { .name = "ELSA EX-VISION 300TV", .audio_clock = 0x00187de7, @@ -450,6 +460,11 @@ struct saa7134_board saa7134_boards[] = .vmux = 8, .amux = TV, .tv = 1, + },{ + .name = name_tv_mono, + .vmux = 8, + .amux = LINE2, + .tv = 1, }}, }, [SAA7134_BOARD_ASUSTeK_TVFM7134] = { @@ -505,6 +520,45 @@ struct saa7134_board saa7134_boards[] = .tv = 1, }}, }, + [SAA7134_BOARD_10MOONSTVMASTER] = { + /* "lilicheng" */ + .name = "10MOONS PCI TV CAPTURE CARD", + .audio_clock = 0x00200000, + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .gpiomask = 0xe000, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = LINE2, + .gpio = 0x0000, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 0, + .amux = LINE2, + .gpio = 0x4000, + },{ + .name = name_comp2, + .vmux = 3, + .amux = LINE2, + .gpio = 0x4000, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + .gpio = 0x4000, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + .gpio = 0x2000, + }, + .mute = { + .name = name_mute, + .amux = LINE2, + .gpio = 0x8000, + }, + }, [SAA7134_BOARD_BMK_MPEX_NOTUNER] = { /* "Andrew de Quincey" */ .name = "BMK MPEX No Tuner", @@ -555,13 +609,105 @@ struct saa7134_board saa7134_boards[] = }}, }, [SAA7134_BOARD_CRONOS_PLUS] = { + /* gpio pins: + 0 .. 3 BASE_ID + 4 .. 7 PROTECT_ID + 8 .. 11 USER_OUT + 12 .. 13 USER_IN + 14 .. 15 VIDIN_SEL */ .name = "Matrox CronosPlus", .tuner_type = TUNER_ABSENT, + .gpiomask = 0xcf00, .inputs = {{ .name = name_comp1, .vmux = 0, + .gpio = 2 << 14, + },{ + .name = name_comp2, + .vmux = 0, + .gpio = 1 << 14, + },{ + .name = name_comp3, + .vmux = 0, + .gpio = 0 << 14, + },{ + .name = name_comp4, + .vmux = 0, + .gpio = 3 << 14, + },{ + .name = name_svideo, + .vmux = 8, + .gpio = 2 << 14, }}, }, + [SAA7134_BOARD_MD2819] = { + .name = "Medion 2819", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .need_tda9887 = 1, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 0, + .amux = LINE2, + },{ + .name = name_comp2, + .vmux = 3, + .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_BMK_MPEX_TUNER] = { + /* "Greg Wickham */ + .name = "BMK MPEX Tuner", + .audio_clock = 0x200000, + .tuner_type = TUNER_PHILIPS_PAL, + .inputs = {{ + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_tv, + .vmux = 3, + .amux = LINE2, + .tv = 1, + }}, + .i2s_rate = 48000, + .has_ts = 1, + .video_out = CCIR656, + }, + [SAA7134_BOARD_ASUSTEK_TVFM7133] = { + .name = "ASUS TV-FM 7133", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1236_MK3, + .need_tda9887 = 1, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + }}, + .radio = { + .name = name_radio, + .amux = LINE1, + }, + }, + }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -648,11 +794,29 @@ struct pci_device_id saa7134_pci_tbl[] = .subdevice = 0x4830, .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = PCI_VENDOR_ID_ASUSTEK, + .subdevice = 0x4843, + .driver_data = SAA7134_BOARD_ASUSTEK_TVFM7133, + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, .subvendor = PCI_VENDOR_ID_PHILIPS, .subdevice = 0xfe01, - .driver_data = SAA7134_BOARD_TYPHOON_90031, + .driver_data = SAA7134_BOARD_TVSTATION_RDS, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x1894, + .subdevice = 0xfe01, + .driver_data = SAA7134_BOARD_TVSTATION_RDS, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x1894, + .subdevice = 0xa006, + .driver_data = SAA7134_BOARD_TVSTATION_DVR, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, @@ -661,6 +825,12 @@ struct pci_device_id saa7134_pci_tbl[] = .driver_data = SAA7134_BOARD_VA1000POWER, },{ .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = PCI_VENDOR_ID_PHILIPS, + .subdevice = 0x2001, + .driver_data = SAA7134_BOARD_10MOONSTVMASTER, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x185b, .subdevice = 0xc100, @@ -672,6 +842,12 @@ struct pci_device_id saa7134_pci_tbl[] = .subdevice = 0x48d0, .driver_data = SAA7134_BOARD_CRONOS_PLUS, },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0xa70b, + .driver_data = SAA7134_BOARD_MD2819, + },{ /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, @@ -777,6 +953,7 @@ int saa7134_board_init(struct saa7134_de dev->has_remote = 1; break; case SAA7134_BOARD_CINERGY400: + case SAA7134_BOARD_CINERGY600: dev->has_remote = 1; break; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/saa7134/saa7134-core.c 830-ivtv/drivers/media/video/saa7134/saa7134-core.c --- 000-virgin/drivers/media/video/saa7134/saa7134-core.c Mon Nov 17 18:29:42 2003 +++ 830-ivtv/drivers/media/video/saa7134/saa7134-core.c Thu Jan 8 11:17:27 2004 @@ -599,12 +599,10 @@ static irqreturn_t saa7134_irq(int irq, if ((report & SAA7134_IRQ_REPORT_DONE_RA3)) saa7134_irq_oss_done(dev,status); -#ifdef CONFIG_VIDEO_IR if ((report & (SAA7134_IRQ_REPORT_GPIO16 | SAA7134_IRQ_REPORT_GPIO18)) && dev->remote) saa7134_input_irq(dev); -#endif }; if (10 == loop) { @@ -636,9 +634,7 @@ static int saa7134_hwinit1(struct saa713 saa7134_vbi_init1(dev); if (card_has_ts(dev)) saa7134_ts_init1(dev); -#ifdef CONFIG_VIDEO_IR saa7134_input_init1(dev); -#endif switch (dev->pci->device) { case PCI_DEVICE_ID_PHILIPS_SAA7134: @@ -714,9 +710,7 @@ static int saa7134_hwfini(struct saa7134 } if (card_has_ts(dev)) saa7134_ts_fini(dev); -#ifdef CONFIG_VIDEO_IR saa7134_input_fini(dev); -#endif saa7134_vbi_fini(dev); saa7134_video_fini(dev); saa7134_tvaudio_fini(dev); @@ -907,7 +901,7 @@ static int __devinit saa7134_initdev(str } /* wait a bit, register i2c bus */ - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ/10); saa7134_i2c_register(dev); @@ -1041,18 +1035,7 @@ static void __devexit saa7134_finidev(st saa_writel(SAA7134_MAIN_CTRL,0); /* shutdown subsystems */ - switch (dev->pci->device) { - case PCI_DEVICE_ID_PHILIPS_SAA7134: - case PCI_DEVICE_ID_PHILIPS_SAA7133: - case PCI_DEVICE_ID_PHILIPS_SAA7135: - saa7134_oss_fini(dev); - break; - } - if (card_has_ts(dev)) - saa7134_ts_fini(dev); - saa7134_vbi_fini(dev); - saa7134_video_fini(dev); - saa7134_tvaudio_fini(dev); + saa7134_hwfini(dev); /* unregister */ saa7134_i2c_unregister(dev); @@ -1099,6 +1082,10 @@ static int saa7134_init(void) (SAA7134_VERSION_CODE >> 16) & 0xff, (SAA7134_VERSION_CODE >> 8) & 0xff, SAA7134_VERSION_CODE & 0xff); +#ifdef SNAPSHOT + printk(KERN_INFO "saa7130/34: snapshot date %04d-%02d-%02d\n", + SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); +#endif return pci_module_init(&saa7134_pci_driver); } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/saa7134/saa7134-input.c 830-ivtv/drivers/media/video/saa7134/saa7134-input.c --- 000-virgin/drivers/media/video/saa7134/saa7134-input.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/media/video/saa7134/saa7134-input.c Thu Jan 8 11:17:27 2004 @@ -0,0 +1,218 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include + +#include "saa7134-reg.h" +#include "saa7134.h" + +/* ---------------------------------------------------------------------- */ + +static IR_KEYTAB_TYPE flyvideo_codes[IR_KEYTAB_SIZE] = { + [ 15 ] = KEY_KP0, + [ 3 ] = KEY_KP1, + [ 4 ] = KEY_KP2, + [ 5 ] = KEY_KP3, + [ 7 ] = KEY_KP4, + [ 8 ] = KEY_KP5, + [ 9 ] = KEY_KP6, + [ 11 ] = KEY_KP7, + [ 12 ] = KEY_KP8, + [ 13 ] = KEY_KP9, + + [ 14 ] = KEY_TUNER, // Air/Cable + [ 17 ] = KEY_VIDEO, // Video + [ 21 ] = KEY_AUDIO, // Audio + [ 0 ] = KEY_POWER, // Pover + [ 2 ] = KEY_ZOOM, // Fullscreen + [ 27 ] = KEY_MUTE, // Mute + [ 20 ] = KEY_VOLUMEUP, + [ 23 ] = KEY_VOLUMEDOWN, + [ 18 ] = KEY_CHANNELUP, // Channel + + [ 19 ] = KEY_CHANNELDOWN, // Channel - + [ 6 ] = KEY_AGAIN, // Recal + [ 16 ] = KEY_KPENTER, // Enter + +#if 1 /* FIXME */ + [ 26 ] = KEY_F22, // Stereo + [ 24 ] = KEY_EDIT, // AV Source +#endif +}; + +static IR_KEYTAB_TYPE cinergy_codes[IR_KEYTAB_SIZE] = { + [ 0 ] = KEY_KP0, + [ 1 ] = KEY_KP1, + [ 2 ] = KEY_KP2, + [ 3 ] = KEY_KP3, + [ 4 ] = KEY_KP4, + [ 5 ] = KEY_KP5, + [ 6 ] = KEY_KP6, + [ 7 ] = KEY_KP7, + [ 8 ] = KEY_KP8, + [ 9 ] = KEY_KP9, + + [ 0x0a ] = KEY_POWER, + [ 0x0b ] = KEY_PROG1, // app + [ 0x0c ] = KEY_ZOOM, // zoom/fullscreen + [ 0x0d ] = KEY_CHANNELUP, // channel + [ 0x0e ] = KEY_CHANNELDOWN, // channel- + [ 0x0f ] = KEY_VOLUMEUP, + [ 0x10 ] = KEY_VOLUMEDOWN, + [ 0x11 ] = KEY_TUNER, // AV + [ 0x12 ] = KEY_NUMLOCK, // -/-- + [ 0x13 ] = KEY_AUDIO, // audio + [ 0x14 ] = KEY_MUTE, + [ 0x15 ] = KEY_UP, + [ 0x16 ] = KEY_DOWN, + [ 0x17 ] = KEY_LEFT, + [ 0x18 ] = KEY_RIGHT, + [ 0x19 ] = BTN_LEFT, + [ 0x1a ] = BTN_RIGHT, + [ 0x1b ] = KEY_WWW, // text + [ 0x1c ] = KEY_REWIND, + [ 0x1d ] = KEY_FORWARD, + [ 0x1e ] = KEY_RECORD, + [ 0x1f ] = KEY_PLAY, + [ 0x20 ] = KEY_PREVIOUSSONG, + [ 0x21 ] = KEY_NEXTSONG, + [ 0x22 ] = KEY_PAUSE, + [ 0x23 ] = KEY_STOP, +}; + +/* ---------------------------------------------------------------------- */ + +static int build_key(struct saa7134_dev *dev) +{ + struct saa7134_ir *ir = dev->remote; + u32 gpio, data; + + /* rising SAA7134_GPIO_GPRESCAN reads the status */ + saa_clearb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN); + saa_setb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN); + gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2); + data = ir_extract_bits(gpio, ir->mask_keycode); + + printk("%s: build_key gpio=0x%x mask=0x%x data=%d\n", + dev->name, gpio, ir->mask_keycode, data); + + if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) || + (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) { + ir_input_keydown(&ir->dev,&ir->ir,data,data); + } else { + ir_input_nokey(&ir->dev,&ir->ir); + } + return 0; +} + +/* ---------------------------------------------------------------------- */ + +void saa7134_input_irq(struct saa7134_dev *dev) +{ + build_key(dev); +} + +int saa7134_input_init1(struct saa7134_dev *dev) +{ + struct saa7134_ir *ir; + IR_KEYTAB_TYPE *ir_codes = NULL; + u32 mask_keycode = 0; + u32 mask_keydown = 0; + u32 mask_keyup = 0; + int ir_type = IR_TYPE_OTHER; + + /* detect & configure */ + if (!dev->has_remote) + return -ENODEV; + switch (dev->board) { + case SAA7134_BOARD_FLYVIDEO2000: + case SAA7134_BOARD_FLYVIDEO3000: + ir_codes = flyvideo_codes; + mask_keycode = 0xEC00000; + mask_keydown = 0x0040000; + break; + case SAA7134_BOARD_CINERGY400: + case SAA7134_BOARD_CINERGY600: + ir_codes = cinergy_codes; + mask_keycode = 0x00003f; + mask_keyup = 0x040000; + break; + } + if (NULL == ir_codes) { + printk("%s: Oops: IR config error [card=%d]\n", + dev->name, dev->board); + return -ENODEV; + } + + ir = kmalloc(sizeof(*ir),GFP_KERNEL); + if (NULL == ir) + return -ENOMEM; + memset(ir,0,sizeof(*ir)); + + /* init hardware-specific stuff */ + ir->mask_keycode = mask_keycode; + ir->mask_keydown = mask_keydown; + ir->mask_keyup = mask_keyup; + + /* init input device */ + snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)", + saa7134_boards[dev->board].name); + snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", + pci_name(dev->pci)); + + ir_input_init(&ir->dev, &ir->ir, ir_type, ir_codes); + ir->dev.name = ir->name; + ir->dev.phys = ir->phys; + ir->dev.id.bustype = BUS_PCI; + ir->dev.id.version = 1; + if (dev->pci->subsystem_vendor) { + ir->dev.id.vendor = dev->pci->subsystem_vendor; + ir->dev.id.product = dev->pci->subsystem_device; + } else { + ir->dev.id.vendor = dev->pci->vendor; + ir->dev.id.product = dev->pci->device; + } + + /* all done */ + dev->remote = ir; + input_register_device(&dev->remote->dev); + printk("%s: registered input device for IR\n",dev->name); + return 0; +} + +void saa7134_input_fini(struct saa7134_dev *dev) +{ + if (NULL == dev->remote) + return; + + input_unregister_device(&dev->remote->dev); + kfree(dev->remote); + dev->remote = NULL; +} + +/* ---------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/saa7134/saa7134-oss.c 830-ivtv/drivers/media/video/saa7134/saa7134-oss.c --- 000-virgin/drivers/media/video/saa7134/saa7134-oss.c Mon Nov 17 18:29:29 2003 +++ 830-ivtv/drivers/media/video/saa7134/saa7134-oss.c Thu Jan 8 11:17:27 2004 @@ -40,7 +40,7 @@ MODULE_PARM(oss_rate,"i"); MODULE_PARM_DESC(oss_rate,"sample rate (valid are: 32000,48000)"); #define dprintk(fmt, arg...) if (oss_debug) \ - printk(KERN_DEBUG "%s/oss: " fmt, dev->name, ## arg) + printk(KERN_DEBUG "%s/oss: " fmt, dev->name , ## arg) /* ------------------------------------------------------------------ */ @@ -295,8 +295,10 @@ static ssize_t dsp_read(struct file *fil break; } up(&dev->oss.lock); - current->state = TASK_INTERRUPTIBLE; - schedule(); + set_current_state(TASK_INTERRUPTIBLE); + if (0 == dev->oss.read_count) + schedule(); + set_current_state(TASK_RUNNING); down(&dev->oss.lock); if (signal_pending(current)) { if (0 == ret) @@ -328,7 +330,6 @@ static ssize_t dsp_read(struct file *fil } up(&dev->oss.lock); remove_wait_queue(&dev->oss.wq, &wait); - current->state = TASK_RUNNING; return ret; } @@ -777,7 +778,7 @@ void saa7134_irq_oss_done(struct saa7134 spin_lock(&dev->slock); if (UNSET == dev->oss.dma_blk) { - dprintk("irq: recording stopped%s\n",""); + dprintk("irq: recording stopped\n"); goto done; } if (0 != (status & 0x0f000000)) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/saa7134/saa7134-ts.c 830-ivtv/drivers/media/video/saa7134/saa7134-ts.c --- 000-virgin/drivers/media/video/saa7134/saa7134-ts.c Mon Nov 17 18:29:29 2003 +++ 830-ivtv/drivers/media/video/saa7134/saa7134-ts.c Thu Jan 8 11:17:27 2004 @@ -45,7 +45,7 @@ MODULE_PARM_DESC(tsbufs,"number of ts bu #define TS_NR_PACKETS 312 #define dprintk(fmt, arg...) if (ts_debug) \ - printk(KERN_DEBUG "%s/ts: " fmt, dev->name, ## arg) + printk(KERN_DEBUG "%s/ts: " fmt, dev->name , ## arg) /* ------------------------------------------------------------------ */ @@ -173,7 +173,7 @@ static void ts_reset_encoder(struct saa7 saa_writeb(SAA7134_SPECIAL_MODE, 0x00); mdelay(10); saa_writeb(SAA7134_SPECIAL_MODE, 0x01); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ/10); } @@ -196,7 +196,7 @@ static int ts_open(struct inode *inode, list_for_each(list,&saa7134_devlist) { h = list_entry(list, struct saa7134_dev, devlist); - if (h->ts_dev->minor == minor) + if (h->ts_dev && h->ts_dev->minor == minor) dev = h; } if (NULL == dev) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/saa7134/saa7134-tvaudio.c 830-ivtv/drivers/media/video/saa7134/saa7134-tvaudio.c --- 000-virgin/drivers/media/video/saa7134/saa7134-tvaudio.c Mon Nov 17 18:29:29 2003 +++ 830-ivtv/drivers/media/video/saa7134/saa7134-tvaudio.c Thu Jan 8 11:17:27 2004 @@ -42,7 +42,7 @@ MODULE_PARM(audio_carrier,"i"); MODULE_PARM_DESC(audio_carrier,"audio carrier location"); #define dprintk(fmt, arg...) if (audio_debug) \ - printk(KERN_DEBUG "%s/audio: " fmt, dev->name, ## arg) + printk(KERN_DEBUG "%s/audio: " fmt, dev->name , ## arg) #define d2printk(fmt, arg...) if (audio_debug > 1) \ printk(KERN_DEBUG "%s/audio: " fmt, dev->name, ## arg) @@ -50,7 +50,7 @@ MODULE_PARM_DESC(audio_carrier,"audio ca dev->name,(SAA7134_##reg),(#reg),saa_readb((SAA7134_##reg))) #define SCAN_INITIAL_DELAY (HZ) -#define SCAN_SAMPLE_DELAY (HZ/10) +#define SCAN_SAMPLE_DELAY (HZ/5) /* ------------------------------------------------------------------ */ /* saa7134 code */ @@ -259,12 +259,14 @@ static void tvaudio_setmode(struct saa71 saa_writeb(SAA7134_DCXO_IDENT_CTRL, 0x00); saa_writeb(SAA7134_FM_DEEMPHASIS, 0x44); saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0xa1); + saa_writeb(SAA7134_NICAM_CONFIG, 0x00); break; case TVAUDIO_NICAM_AM: saa_writeb(SAA7134_DEMODULATOR, 0x12); saa_writeb(SAA7134_DCXO_IDENT_CTRL, 0x00); saa_writeb(SAA7134_FM_DEEMPHASIS, 0x44); saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0xa1); + saa_writeb(SAA7134_NICAM_CONFIG, 0x00); break; case TVAUDIO_FM_SAT_STEREO: /* not implemented (yet) */ @@ -278,7 +280,7 @@ static int tvaudio_sleep(struct saa7134_ DECLARE_WAITQUEUE(wait, current); add_wait_queue(&dev->thread.wq, &wait); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(timeout); remove_wait_queue(&dev->thread.wq, &wait); return dev->thread.scan1 != dev->thread.scan2; @@ -437,7 +439,7 @@ static int tvaudio_thread(void *data) const int *carr_scan; int carr_vals[4]; unsigned int i, audio; - int max1,max2,carrier,rx,mode; + int max1,max2,carrier,rx,mode,lastmode; lock_kernel(); daemonize("%s", dev->name); @@ -535,7 +537,7 @@ static int tvaudio_thread(void *data) if (UNSET == audio) audio = i; tvaudio_setmode(dev,&tvaudio[i],"trying"); - if (tvaudio_sleep(dev,HZ)) + if (tvaudio_sleep(dev,HZ*2)) goto restart; if (-1 != tvaudio_getstereo(dev,&tvaudio[i])) { audio = i; @@ -549,8 +551,9 @@ static int tvaudio_thread(void *data) tvaudio_setstereo(dev,&tvaudio[audio],V4L2_TUNER_MODE_MONO); dev->tvaudio = &tvaudio[audio]; + lastmode = 42; for (;;) { - if (tvaudio_sleep(dev,3*HZ)) + if (tvaudio_sleep(dev,5*HZ)) goto restart; if (dev->thread.exit || signal_pending(current)) break; @@ -560,7 +563,10 @@ static int tvaudio_thread(void *data) } else { mode = dev->thread.mode; } - tvaudio_setstereo(dev,&tvaudio[audio],mode); + if (lastmode != mode) { + tvaudio_setstereo(dev,&tvaudio[audio],mode); + lastmode = mode; + } } } @@ -856,17 +862,12 @@ int saa7134_tvaudio_init2(struct saa7134 /* enable I2S audio output */ if (saa7134_boards[dev->board].i2s_rate) { - int rate = (32000 == saa7134_boards[dev->board].i2s_rate) - ? 0x01 : 0x03; + int i2sform = (32000 == saa7134_boards[dev->board].i2s_rate) ? 0x00 : 0x01; - /* set rate */ - saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, rate); - /* enable I2S output */ - saa_writeb(SAA7134_DSP_OUTPUT_SELECT, 0x80); - saa_writeb(SAA7134_I2S_OUTPUT_SELECT, 0x80); - saa_writeb(SAA7134_I2S_OUTPUT_FORMAT, 0x01); - saa_writeb(SAA7134_I2S_OUTPUT_LEVEL, 0x00); + saa_writeb(SAA7134_I2S_OUTPUT_SELECT, 0x80); + saa_writeb(SAA7134_I2S_OUTPUT_FORMAT, i2sform); + saa_writeb(SAA7134_I2S_OUTPUT_LEVEL, 0x0F); saa_writeb(SAA7134_I2S_AUDIO_OUTPUT, 0x01); } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/saa7134/saa7134-vbi.c 830-ivtv/drivers/media/video/saa7134/saa7134-vbi.c --- 000-virgin/drivers/media/video/saa7134/saa7134-vbi.c Mon Nov 17 18:29:29 2003 +++ 830-ivtv/drivers/media/video/saa7134/saa7134-vbi.c Thu Jan 8 11:17:27 2004 @@ -39,7 +39,7 @@ MODULE_PARM(vbibufs,"i"); MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32"); #define dprintk(fmt, arg...) if (vbi_debug) \ - printk(KERN_DEBUG "%s/vbi: " fmt, dev->name, ## arg) + printk(KERN_DEBUG "%s/vbi: " fmt, dev->name , ## arg) /* ------------------------------------------------------------------ */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/saa7134/saa7134-video.c 830-ivtv/drivers/media/video/saa7134/saa7134-video.c --- 000-virgin/drivers/media/video/saa7134/saa7134-video.c Mon Nov 17 18:29:29 2003 +++ 830-ivtv/drivers/media/video/saa7134/saa7134-video.c Thu Jan 8 11:17:27 2004 @@ -40,7 +40,7 @@ MODULE_PARM(gbuffers,"i"); MODULE_PARM_DESC(gbuffers,"number of capture buffers, range 2-32"); #define dprintk(fmt, arg...) if (video_debug) \ - printk(KERN_DEBUG "%s/video: " fmt, dev->name, ## arg) + printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg) /* ------------------------------------------------------------------ */ /* data structs for video */ @@ -83,6 +83,12 @@ static struct saa7134_format formats[] = .depth = 24, .pm = 0x11, },{ + .name = "24 bpp RGB, be", + .fourcc = V4L2_PIX_FMT_RGB24, + .depth = 24, + .pm = 0x11, + .bswap = 1, + },{ .name = "32 bpp RGB, le", .fourcc = V4L2_PIX_FMT_BGR32, .depth = 32, @@ -125,6 +131,16 @@ static struct saa7134_format formats[] = .planar = 1, .hshift = 1, .vshift = 1, + },{ + .name = "4:2:0 planar, Y-Cb-Cr", + .fourcc = V4L2_PIX_FMT_YVU420, + .depth = 12, + .pm = 0x0a, + .yuv = 1, + .planar = 1, + .uvswap = 1, + .hshift = 1, + .vshift = 1, } }; #define FORMATS ARRAY_SIZE(formats) @@ -788,7 +804,7 @@ static int buffer_activate(struct saa713 struct saa7134_buf *next) { unsigned long base,control,bpl; - unsigned long bpl_uv,lines_uv,base2,base3; /* planar */ + unsigned long bpl_uv,lines_uv,base2,base3,tmp; /* planar */ dprintk("buffer_activate buf=%p\n",buf); buf->vb.state = STATE_ACTIVE; @@ -834,6 +850,8 @@ static int buffer_activate(struct saa713 lines_uv = buf->vb.height >> buf->fmt->vshift; base2 = base + bpl * buf->vb.height; base3 = base2 + bpl_uv * lines_uv; + if (buf->fmt->uvswap) + tmp = base2, base2 = base3, base3 = tmp; dprintk("uv: bpl=%ld lines=%ld base2/3=%ld/%ld\n", bpl_uv,lines_uv,base2,base3); if (V4L2_FIELD_HAS_BOTH(buf->vb.field)) { @@ -1268,7 +1286,7 @@ static int video_release(struct inode *i /* stop video capture */ if (res_check(fh, RESOURCE_VIDEO)) { - videobuf_queue_cancel(file,&fh->cap); + videobuf_streamoff(file,&fh->cap); res_free(dev,fh,RESOURCE_VIDEO); } if (fh->cap.read_buf) { @@ -1697,6 +1715,7 @@ static int video_do_ioctl(struct inode * down(&dev->lock); dev->ctl_freq = f->frequency; saa7134_i2c_call_clients(dev,VIDIOCSFREQ,&dev->ctl_freq); + saa7134_tvaudio_do_scan(dev); up(&dev->lock); return 0; } @@ -2148,8 +2167,8 @@ void saa7134_irq_video_done(struct saa71 spin_lock(&dev->slock); if (dev->video_q.curr) { + dev->video_fieldcount++; field = dev->video_q.curr->vb.field; - if (V4L2_FIELD_HAS_BOTH(field)) { /* make sure we have seen both fields */ if ((status & 0x10) == 0x00) { @@ -2165,6 +2184,7 @@ void saa7134_irq_video_done(struct saa71 if ((status & 0x10) != 0x00) goto done; } + dev->video_q.curr->vb.field_count = dev->video_fieldcount; saa7134_buffer_finish(dev,&dev->video_q,STATE_DONE); } saa7134_buffer_next(dev,&dev->video_q); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/saa7134/saa7134.h 830-ivtv/drivers/media/video/saa7134/saa7134.h --- 000-virgin/drivers/media/video/saa7134/saa7134.h Mon Nov 17 18:29:29 2003 +++ 830-ivtv/drivers/media/video/saa7134/saa7134.h Thu Jan 8 11:17:27 2004 @@ -29,14 +29,11 @@ #include -#ifdef CONFIG_VIDEO_IR -#include "ir-common.h" -#endif - #include #include #include #include +#include #ifndef TRUE # define TRUE (1==1) @@ -116,6 +113,7 @@ struct saa7134_format { unsigned int wswap:1; unsigned int yuv:1; unsigned int planar:1; + unsigned int uvswap:1; }; /* ----------------------------------------------------------- */ @@ -135,7 +133,7 @@ struct saa7134_format { #define SAA7134_BOARD_KWORLD 10 #define SAA7134_BOARD_CINERGY600 11 #define SAA7134_BOARD_MD7134 12 -#define SAA7134_BOARD_TYPHOON_90031 13 +//#define SAA7134_BOARD_TYPHOON_90031 13 /* => 7 */ #define SAA7134_BOARD_ELSA 14 #define SAA7134_BOARD_ELSA_500TV 15 #define SAA7134_BOARD_ASUSTeK_TVFM7134 16 @@ -143,6 +141,11 @@ struct saa7134_format { #define SAA7134_BOARD_BMK_MPEX_NOTUNER 18 #define SAA7134_BOARD_VIDEOMATE_TV 19 #define SAA7134_BOARD_CRONOS_PLUS 20 +#define SAA7134_BOARD_10MOONSTVMASTER 21 +#define SAA7134_BOARD_MD2819 22 +#define SAA7134_BOARD_BMK_MPEX_TUNER 23 +#define SAA7134_BOARD_TVSTATION_DVR 24 +#define SAA7134_BOARD_ASUSTEK_TVFM7133 25 #define SAA7134_INPUT_MAX 8 @@ -242,11 +245,12 @@ struct saa7134_fh { struct saa7134_dev *dev; unsigned int radio; enum v4l2_buf_type type; + unsigned int resources; + /* video overlay */ struct v4l2_window win; struct v4l2_clip clips[8]; unsigned int nclips; - unsigned int resources; /* video capture */ struct saa7134_format *fmt; @@ -298,7 +302,6 @@ struct saa7134_oss { unsigned int read_count; }; -#ifdef CONFIG_VIDEO_IR /* IR input */ struct saa7134_ir { struct input_dev dev; @@ -307,8 +310,8 @@ struct saa7134_ir { char phys[32]; u32 mask_keycode; u32 mask_keydown; + u32 mask_keyup; }; -#endif /* global device status */ struct saa7134_dev { @@ -327,9 +330,7 @@ struct saa7134_dev { /* infrared remote */ int has_remote; -#ifdef CONFIG_VIDEO_IR struct saa7134_ir *remote; -#endif /* pci i/o */ char name[32]; @@ -358,6 +359,7 @@ struct saa7134_dev { struct saa7134_dmaqueue video_q; struct saa7134_dmaqueue ts_q; struct saa7134_dmaqueue vbi_q; + unsigned int video_fieldcount; unsigned int vbi_fieldcount; /* various v4l controls */ @@ -403,9 +405,7 @@ struct saa7134_dev { #define saa_setb(reg,bit) saa_andorb((reg),(bit),(bit)) #define saa_clearb(reg,bit) saa_andorb((reg),(bit),0) -//#define saa_wait(d) { if (need_resched()) schedule(); else udelay(d);} #define saa_wait(d) { udelay(d); } -//#define saa_wait(d) { schedule_timeout(HZ*d/1000 ?:1); } /* ----------------------------------------------------------- */ /* saa7134-core.c */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/tda7432.c 830-ivtv/drivers/media/video/tda7432.c --- 000-virgin/drivers/media/video/tda7432.c Fri May 30 19:02:10 2003 +++ 830-ivtv/drivers/media/video/tda7432.c Thu Jan 8 11:17:12 2004 @@ -338,8 +338,13 @@ static int tda7432_attach(struct i2c_ada static int tda7432_probe(struct i2c_adapter *adap) { +#ifdef I2C_ADAP_CLASS_TV_ANALOG if (adap->class & I2C_ADAP_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, tda7432_attach); +#else + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, tda7432_attach); +#endif return 0; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/tda9875.c 830-ivtv/drivers/media/video/tda9875.c --- 000-virgin/drivers/media/video/tda9875.c Fri May 30 19:02:10 2003 +++ 830-ivtv/drivers/media/video/tda9875.c Thu Jan 8 11:17:12 2004 @@ -272,8 +272,13 @@ static int tda9875_attach(struct i2c_ada static int tda9875_probe(struct i2c_adapter *adap) { +#ifdef I2C_ADAP_CLASS_TV_ANALOG if (adap->class & I2C_ADAP_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, tda9875_attach); +#else + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, tda9875_attach); +#endif return 0; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/tda9887.c 830-ivtv/drivers/media/video/tda9887.c --- 000-virgin/drivers/media/video/tda9887.c Wed Aug 13 20:24:24 2003 +++ 830-ivtv/drivers/media/video/tda9887.c Thu Jan 8 11:17:12 2004 @@ -366,8 +366,18 @@ static int tda9887_attach(struct i2c_ada static int tda9887_probe(struct i2c_adapter *adap) { +#ifdef I2C_ADAP_CLASS_TV_ANALOG if (adap->class & I2C_ADAP_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, tda9887_attach); +#else + switch (adap->id) { + case I2C_ALGO_BIT | I2C_HW_B_BT848: + case I2C_ALGO_BIT | I2C_HW_B_RIVA: + case I2C_ALGO_SAA7134: + return i2c_probe(adap, &addr_data, tda9887_attach); + break; + } +#endif return 0; } @@ -439,9 +449,9 @@ static struct i2c_driver driver = { }; static struct i2c_client client_template = { - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, - .name = "tda9887", + I2C_DEVNAME("tda9887"), + .flags = I2C_CLIENT_ALLOW_USE, + .driver = &driver, }; static int tda9887_init_module(void) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/tuner.c 830-ivtv/drivers/media/video/tuner.c --- 000-virgin/drivers/media/video/tuner.c Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/media/video/tuner.c Thu Jan 8 11:17:18 2004 @@ -45,18 +45,21 @@ MODULE_LICENSE("GPL"); static int this_adap; #define dprintk if (debug) printk -struct tuner -{ +struct tuner { unsigned int type; /* chip type */ unsigned int freq; /* keep track of the current settings */ unsigned int std; unsigned int radio; unsigned int mode; /* current norm for multi-norm tuners */ + unsigned int input; // only for MT2032 unsigned int xogc; unsigned int radio_if2; + + void (*tv_freq)(struct i2c_client *c, unsigned int freq); + void (*radio_freq)(struct i2c_client *c, unsigned int freq); }; static struct i2c_driver driver; @@ -207,7 +210,7 @@ static struct tunertype tuners[] = { { "Samsung PAL TCPM9091PD27", Samsung, PAL, /* from sourceforge v3tv */ 16*169,16*464,0xA0,0x90,0x30,0x8e,623}, - { "MT2032 universal", Microtune,PAL|NTSC, + { "MT20xx universal", Microtune,PAL|NTSC, 0,0,0,0,0,0,0}, { "Temic PAL_BG (4106 FH5)", TEMIC, PAL, 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, @@ -225,6 +228,12 @@ static struct tunertype tuners[] = { { "HITACHI V7-J180AT", HITACHI, NTSC, 16*170.00, 16*450.00, 0x01,0x02,0x00,0x8e,940 }, + { "Philips PAL_MK (FI1216 MK)", Philips, PAL, + 16*140.25,16*463.25,0x01,0xc2,0xcf,0x8e,623}, + { "Philips 1236D ATSC/NTSC daul in",Philips,ATSC, + 16*157.25,16*454.00,0xa0,0x90,0x30,0x8e,732}, + { "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", Philips, NTSC, + 16*160.00,16*442.00,0x01,0x02,0x04,0x8}, }; #define TUNERS ARRAY_SIZE(tuners) @@ -279,86 +288,19 @@ static int tuner_mode (struct i2c_client } #endif -// Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001 -static int mt2032_init(struct i2c_client *c) -{ - unsigned char buf[21]; - int ret,xogc,xok=0; - struct tuner *t = i2c_get_clientdata(c); - - buf[0]=0; - ret=i2c_master_send(c,buf,1); - i2c_master_recv(c,buf,21); - - printk("MT2032: Companycode=%02x%02x Part=%02x Revision=%02x\n", - buf[0x11],buf[0x12],buf[0x13],buf[0x14]); - - if(debug) { - int i; - printk("MT2032 hexdump:\n"); - for(i=0;i<21;i++) { - printk(" %02x",buf[i]); - if(((i+1)%8)==0) printk(" "); - if(((i+1)%16)==0) printk("\n "); - } - printk("\n "); - } - // Look for MT2032 id: - // part= 0x04(MT2032), 0x06(MT2030), 0x07(MT2040) - if((buf[0x11] != 0x4d) || (buf[0x12] != 0x54) || (buf[0x13] != 0x04)) { - printk("not a MT2032.\n"); - return 0; - } - - - // Initialize Registers per spec. - buf[1]=2; // Index to register 2 - buf[2]=0xff; - buf[3]=0x0f; - buf[4]=0x1f; - ret=i2c_master_send(c,buf+1,4); - - buf[5]=6; // Index register 6 - buf[6]=0xe4; - buf[7]=0x8f; - buf[8]=0xc3; - buf[9]=0x4e; - buf[10]=0xec; - ret=i2c_master_send(c,buf+5,6); - - buf[12]=13; // Index register 13 - buf[13]=0x32; - ret=i2c_master_send(c,buf+12,2); - - // Adjust XOGC (register 7), wait for XOK - xogc=7; - do { - dprintk("mt2032: xogc = 0x%02x\n",xogc&0x07); - mdelay(10); - buf[0]=0x0e; - i2c_master_send(c,buf,1); - i2c_master_recv(c,buf,1); - xok=buf[0]&0x01; - dprintk("mt2032: xok = 0x%02x\n",xok); - if (xok == 1) break; - - xogc--; - dprintk("mt2032: xogc = 0x%02x\n",xogc&0x07); - if (xogc == 3) { - xogc=4; // min. 4 per spec - break; - } - buf[0]=0x07; - buf[1]=0x88 + xogc; - ret=i2c_master_send(c,buf,2); - if (ret!=2) - printk("mt2032_init failed with %d\n",ret); - } while (xok != 1 ); - t->xogc=xogc; - - return(1); -} +/* ---------------------------------------------------------------------- */ +#define MT2032 0x04 +#define MT2030 0x06 +#define MT2040 0x07 +#define MT2050 0x42 + +static char *microtune_part[] = { + [ MT2030 ] = "MT2030", + [ MT2032 ] = "MT2032", + [ MT2040 ] = "MT2040", + [ MT2050 ] = "MT2050", +}; // IsSpurInBand()? static int mt2032_spurcheck(int f1, int f2, int spectrum_from,int spectrum_to) @@ -583,13 +525,13 @@ static void mt2032_set_if_freq(struct i2 } -static void mt2032_set_tv_freq(struct i2c_client *c, - unsigned int freq, unsigned int norm) +static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq) { + struct tuner *t = i2c_get_clientdata(c); int if2,from,to; // signal bandwidth and picture carrier - if (norm==VIDEO_MODE_NTSC) { + if (t->mode == VIDEO_MODE_NTSC) { from=40750*1000; to=46750*1000; if2=45750*1000; @@ -604,36 +546,231 @@ static void mt2032_set_tv_freq(struct i2 1090*1000*1000, if2, from, to); } +static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq) +{ + struct tuner *t = i2c_get_clientdata(c); + int if2 = t->radio_if2; -// Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz -static void set_tv_freq(struct i2c_client *c, unsigned int freq) + // per Manual for FM tuning: first if center freq. 1085 MHz + mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */, + 1085*1000*1000,if2,if2,if2); +} + +// Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001 +static int mt2032_init(struct i2c_client *c) { - u8 config; - u16 div; - struct tunertype *tun; struct tuner *t = i2c_get_clientdata(c); - unsigned char buffer[4]; - int rc; + unsigned char buf[21]; + int ret,xogc,xok=0; - if (t->type == UNSET) { - printk("tuner: tuner type not set\n"); - return; - } - if (t->type == TUNER_MT2032) { - mt2032_set_tv_freq(c,freq,t->mode); - return; + // Initialize Registers per spec. + buf[1]=2; // Index to register 2 + buf[2]=0xff; + buf[3]=0x0f; + buf[4]=0x1f; + ret=i2c_master_send(c,buf+1,4); + + buf[5]=6; // Index register 6 + buf[6]=0xe4; + buf[7]=0x8f; + buf[8]=0xc3; + buf[9]=0x4e; + buf[10]=0xec; + ret=i2c_master_send(c,buf+5,6); + + buf[12]=13; // Index register 13 + buf[13]=0x32; + ret=i2c_master_send(c,buf+12,2); + + // Adjust XOGC (register 7), wait for XOK + xogc=7; + do { + dprintk("mt2032: xogc = 0x%02x\n",xogc&0x07); + mdelay(10); + buf[0]=0x0e; + i2c_master_send(c,buf,1); + i2c_master_recv(c,buf,1); + xok=buf[0]&0x01; + dprintk("mt2032: xok = 0x%02x\n",xok); + if (xok == 1) break; + + xogc--; + dprintk("mt2032: xogc = 0x%02x\n",xogc&0x07); + if (xogc == 3) { + xogc=4; // min. 4 per spec + break; + } + buf[0]=0x07; + buf[1]=0x88 + xogc; + ret=i2c_master_send(c,buf,2); + if (ret!=2) + printk("mt2032_init failed with %d\n",ret); + } while (xok != 1 ); + t->xogc=xogc; + + t->tv_freq = mt2032_set_tv_freq; + t->radio_freq = mt2032_set_radio_freq; + return(1); +} + +static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned int if2) +{ + unsigned int if1=1218*1000*1000; + unsigned int f_lo1,f_lo2,lo1,lo2,f_lo1_modulo,f_lo2_modulo,num1,num2,div1a,div1b,div2a,div2b; + int ret; + unsigned char buf[6]; + + dprintk("mt2050_set_if_freq freq=%d\n",freq); + + f_lo1=freq+if1; + f_lo1=(f_lo1/1000000)*1000000; + + f_lo2=f_lo1-freq-if2; + f_lo2=(f_lo2/50000)*50000; + + lo1=f_lo1/4000000; + lo2=f_lo2/4000000; + + f_lo1_modulo= f_lo1-(lo1*4000000); + f_lo2_modulo= f_lo2-(lo2*4000000); + + num1=4*f_lo1_modulo/4000000; + num2=4096*(f_lo2_modulo/1000)/4000; + + // todo spurchecks + + div1a=(lo1/12)-1; + div1b=lo1-(div1a+1)*12; + + div2a=(lo2/8)-1; + div2b=lo2-(div2a+1)*8; + + dprintk("lo1 lo2 = %d %d\n", lo1, lo2); + dprintk("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n",num1,num2,div1a,div1b,div2a,div2b); + + + buf[0]=1; + buf[1]= 4*div1b + num1; + if(freq<275*1000*1000) buf[1] = buf[1]|0x80; + + buf[2]=div1a; + buf[3]=32*div2b + num2/256; + buf[4]=num2-(num2/256)*256; + buf[5]=div2a; + if(num2!=0) buf[5]=buf[5]|0x40; + + if(debug) { + int i; + printk("bufs is: "); + for(i=0;i<6;i++) + printk("%x ",buf[i]); + printk("\n"); } + + ret=i2c_master_send(c,buf,6); + if (ret!=6) + printk("mt2050_set_if_freq failed with %d\n",ret); +} - if (freq < tv_range[0]*16 || freq > tv_range[1]*16) { - /* FIXME: better do that chip-specific, but - right now we don't have that in the config - struct and this way is still better than no - check at all */ - printk("tuner: TV freq (%d.%02d) out of range (%d-%d)\n", - freq/16,freq%16*100/16,tv_range[0],tv_range[1]); - return; +static void mt2050_set_tv_freq(struct i2c_client *c, unsigned int freq) +{ + struct tuner *t = i2c_get_clientdata(c); + unsigned int if2; + + if (t->mode == VIDEO_MODE_NTSC) { + if2=45750*1000; + } else { + // Pal + if2=38900*1000; + } + mt2050_set_if_freq(c,freq*62500,if2); +} + +static int mt2050_init(struct i2c_client *c) +{ + struct tuner *t = i2c_get_clientdata(c); + unsigned char buf[1]; + int ret; + + buf[0]=6; + buf[1]=0x10; + ret=i2c_master_send(c,buf,2); // power + + buf[0]=0x0f; + buf[1]=0x0f; + ret=i2c_master_send(c,buf,2); // m1lo + + buf[0]=0x0d; + ret=i2c_master_send(c,buf,1); + i2c_master_recv(c,buf,1); + + dprintk("mt2050: sro is %x\n",buf[0]); + t->tv_freq = mt2050_set_tv_freq; + return 0; +} + +static int microtune_init(struct i2c_client *c) +{ + struct tuner *t = i2c_get_clientdata(c); + char *name; + unsigned char buf[21]; + int company_code; + + buf[0] = 0; + t->tv_freq = NULL; + t->radio_freq = NULL; + name = "unknown"; + + i2c_master_send(c,buf,1); + i2c_master_recv(c,buf,21); + if(debug) { + int i; + printk(KERN_DEBUG "tuner: MT2032 hexdump:\n"); + for(i=0;i<21;i++) { + printk(" %02x",buf[i]); + if(((i+1)%8)==0) printk(" "); + if(((i+1)%16)==0) printk("\n "); + } + printk("\n "); + } + company_code = buf[0x11] << 8 | buf[0x12]; + printk("tuner: microtune: companycode=%04x part=%02x rev=%02x\n", + company_code,buf[0x13],buf[0x14]); + if (company_code != 0x4d54) { + printk("tuner: microtune: unknown companycode\n"); + return 0; } + if (buf[0x13] < ARRAY_SIZE(microtune_part) && + NULL != microtune_part[buf[0x13]]) + name = microtune_part[buf[0x13]]; + switch (buf[0x13]) { + case MT2032: + mt2032_init(c); + break; + case MT2050: + mt2050_init(c); + break; + default: + printk("tuner: microtune %s found, not (yet?) supported, sorry :-/\n", + name); + return 0; + } + printk("tuner: microtune %s found, OK\n",name); + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) +{ + struct tuner *t = i2c_get_clientdata(c); + u8 config; + u16 div; + struct tunertype *tun; + unsigned char buffer[4]; + int rc; + tun=&tuners[t->type]; if (freq < tun->thresh1) config = tun->VHF_L; @@ -700,6 +837,20 @@ static void set_tv_freq(struct i2c_clien break; } break; + + case TUNER_PHILIPS_ATSC: + /* 0x00 -> ATSC antenna input 1 */ + /* 0x01 -> ATSC antenna input 2 */ + /* 0x02 -> NTSC antenna input 1 */ + /* 0x03 -> NTSC antenna input 2 */ + + config &= ~0x03; +#ifdef VIDEO_MODE_ATSC + if (VIDEO_MODE_ATSC != t->mode) + config |= 2; +#endif + /* FIXME: input */ + break; } @@ -737,17 +888,7 @@ static void set_tv_freq(struct i2c_clien } -static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq) -{ - struct tuner *t = i2c_get_clientdata(c); - int if2 = t->radio_if2; - - // per Manual for FM tuning: first if center freq. 1085 MHz - mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */, - 1085*1000*1000,if2,if2,if2); -} - -static void set_radio_freq(struct i2c_client *c, unsigned int freq) +static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) { struct tunertype *tun; struct tuner *t = i2c_get_clientdata(c); @@ -755,22 +896,6 @@ static void set_radio_freq(struct i2c_cl unsigned div; int rc; - if (freq < radio_range[0]*16 || freq > radio_range[1]*16) { - printk("tuner: radio freq (%d.%02d) out of range (%d-%d)\n", - freq/16,freq%16*100/16, - radio_range[0],radio_range[1]); - return; - } - if (t->type == UNSET) { - printk("tuner: tuner type not set\n"); - return; - } - - if (t->type == TUNER_MT2032) { - mt2032_set_radio_freq(c,freq); - return; - } - tun=&tuners[t->type]; div = freq + (int)(16*10.7); buffer[0] = (div>>8) & 0x7f; @@ -778,6 +903,7 @@ static void set_radio_freq(struct i2c_cl buffer[2] = tun->config; switch (t->type) { case TUNER_PHILIPS_FM1216ME_MK3: + case TUNER_PHILIPS_FM1236_MK3: buffer[3] = 0x19; break; default: @@ -794,6 +920,80 @@ static void set_radio_freq(struct i2c_cl /* ---------------------------------------------------------------------- */ +// Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz +static void set_tv_freq(struct i2c_client *c, unsigned int freq) +{ + struct tuner *t = i2c_get_clientdata(c); + + if (t->type == UNSET) { + printk("tuner: tuner type not set\n"); + return; + } + if (NULL == t->tv_freq) { + printk("tuner: Huh? tv_set is NULL?\n"); + return; + } + if (freq < tv_range[0]*16 || freq > tv_range[1]*16) { + /* FIXME: better do that chip-specific, but + right now we don't have that in the config + struct and this way is still better than no + check at all */ + printk("tuner: TV freq (%d.%02d) out of range (%d-%d)\n", + freq/16,freq%16*100/16,tv_range[0],tv_range[1]); + return; + } + t->tv_freq(c,freq); +} + +static void set_radio_freq(struct i2c_client *c, unsigned int freq) +{ + struct tuner *t = i2c_get_clientdata(c); + + if (t->type == UNSET) { + printk("tuner: tuner type not set\n"); + return; + } + if (NULL == t->radio_freq) { + printk("tuner: no radio tuning for this one, sorry.\n"); + return; + } + if (freq < radio_range[0]*16 || freq > radio_range[1]*16) { + printk("tuner: radio freq (%d.%02d) out of range (%d-%d)\n", + freq/16,freq%16*100/16, + radio_range[0],radio_range[1]); + return; + } + t->radio_freq(c,freq); +} + +static void set_type(struct i2c_client *c, unsigned int type) +{ + struct tuner *t = i2c_get_clientdata(c); + + if (t->type != UNSET) { + printk("tuner: type already set (%d)\n",t->type); + return; + } + if (type >= TUNERS) + return; + + t->type = type; + printk("tuner: type set to %d (%s)\n", t->type,tuners[t->type].name); + strlcpy(c->name, tuners[t->type].name, sizeof(c->name)); + + switch (t->type) { + case TUNER_MT2032: + microtune_init(c); + break; + default: + t->tv_freq = default_set_tv_freq; + t->radio_freq = default_set_radio_freq; + break; + } +} + +/* ---------------------------------------------------------------------- */ + static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) { struct tuner *t; @@ -821,15 +1021,12 @@ static int tuner_attach(struct i2c_adapt t->type = UNSET; t->radio_if2 = 10700*1000; // 10.7MHz - FM radio + i2c_attach_client(client); if (type < TUNERS) { - t->type = type; - printk("tuner(bttv): type forced to %d (%s) [insmod]\n",t->type,tuners[t->type].name); - strlcpy(client->name, tuners[t->type].name, I2C_NAME_SIZE); + printk("tuner: type forced to %d (%s) [insmod]\n", + t->type,tuners[t->type].name); + set_type(client,type); } - i2c_attach_client(client); - if (t->type == TUNER_MT2032) - mt2032_init(client); - return 0; } @@ -841,8 +1038,19 @@ static int tuner_probe(struct i2c_adapte } this_adap = 0; +#ifdef I2C_ADAP_CLASS_TV_ANALOG if (adap->class & I2C_ADAP_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, tuner_attach); +#else + switch (adap->id) { + case I2C_ALGO_BIT | I2C_HW_B_BT848: + case I2C_ALGO_BIT | I2C_HW_B_RIVA: + case I2C_ALGO_SAA7134: + case I2C_ALGO_SAA7146: + return i2c_probe(adap, &addr_data, tuner_attach); + break; + } +#endif return 0; } @@ -866,21 +1074,13 @@ tuner_command(struct i2c_client *client, /* --- configuration --- */ case TUNER_SET_TYPE: - if (t->type != UNSET) { - printk("tuner: type already set (%d)\n",t->type); - return 0; - } - if (*iarg >= TUNERS) - return 0; - t->type = *iarg; - printk("tuner: type set to %d (%s)\n", - t->type,tuners[t->type].name); - strlcpy(client->name, tuners[t->type].name, I2C_NAME_SIZE); - if (t->type == TUNER_MT2032) - mt2032_init(client); + set_type(client,*iarg); break; case AUDC_SET_RADIO: - t->radio = 1; + if (!t->radio) { + set_tv_freq(client,400 * 16); + t->radio = 1; + } break; case AUDC_CONFIG_PINNACLE: switch (*iarg) { @@ -913,12 +1113,12 @@ tuner_command(struct i2c_client *client, unsigned long *v = arg; if (t->radio) { - dprintk("tuner: radio freq set to %d.%02d\n", - (*iarg)/16,(*iarg)%16*100/16); + dprintk("tuner: radio freq set to %lu.%02lu\n", + (*v)/16,(*v)%16*100/16); set_radio_freq(client,*v); } else { - dprintk("tuner: tv freq set to %d.%02d\n", - (*iarg)/16,(*iarg)%16*100/16); + dprintk("tuner: tv freq set to %lu.%02lu\n", + (*v)/16,(*v)%16*100/16); set_tv_freq(client,*v); } t->freq = *v; @@ -960,9 +1160,9 @@ static struct i2c_driver driver = { }; static struct i2c_client client_template = { - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, - .name = "(tuner unset)", + I2C_DEVNAME("(tuner unset)"), + .flags = I2C_CLIENT_ALLOW_USE, + .driver = &driver, }; static int tuner_init_module(void) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/tvaudio.c 830-ivtv/drivers/media/video/tvaudio.c --- 000-virgin/drivers/media/video/tvaudio.c Fri May 30 19:02:10 2003 +++ 830-ivtv/drivers/media/video/tvaudio.c Thu Jan 8 11:17:12 2004 @@ -1420,6 +1420,7 @@ static int chip_attach(struct i2c_adapte { struct CHIPSTATE *chip; struct CHIPDESC *desc; + int rc; chip = kmalloc(sizeof(*chip),GFP_KERNEL); if (!chip) @@ -1487,8 +1488,12 @@ static int chip_attach(struct i2c_adapte chip->wt.function = chip_thread_wake; chip->wt.data = (unsigned long)chip; init_waitqueue_head(&chip->wq); - kernel_thread(chip_thread,(void *)chip,0); - down(&sem); + rc = kernel_thread(chip_thread,(void *)chip,0); + if (rc < 0) + printk(KERN_WARNING "%s: kernel_thread() failed\n", + i2c_clientname(&chip->c)); + else + down(&sem); chip->notify = NULL; wake_up_interruptible(&chip->wq); } @@ -1497,8 +1502,17 @@ static int chip_attach(struct i2c_adapte static int chip_probe(struct i2c_adapter *adap) { +#ifdef I2C_ADAP_CLASS_TV_ANALOG if (adap->class & I2C_ADAP_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, chip_attach); +#else + switch (adap->id) { + case I2C_ALGO_BIT | I2C_HW_B_BT848: + case I2C_ALGO_BIT | I2C_HW_B_RIVA: + case I2C_ALGO_SAA7134: + return i2c_probe(adap, &addr_data, chip_attach); + } +#endif return 0; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/tveeprom.c 830-ivtv/drivers/media/video/tveeprom.c --- 000-virgin/drivers/media/video/tveeprom.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/media/video/tveeprom.c Thu Jan 8 11:17:36 2004 @@ -0,0 +1,565 @@ +/* + * tveeprom - eeprom decoder for tvcard configuration eeproms + * + * Data and decoding routines shamelessly borrowed from bttv-cards.c + * eeprom access routine shamelessly borrowed from bttv-if.c + * which are: + + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + & Marcus Metzler (mocm@thp.uni-koeln.de) + (c) 1999-2001 Gerd Knorr + + * Adjustments to fit a more general model and all bugs: + + Copyright (C) 2003 John Klar + + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +MODULE_DESCRIPTION("i2c eeprom decoder driver"); +MODULE_AUTHOR("John Klar"); +MODULE_LICENSE("GPL"); + +#include +#include + +#include + +#ifndef I2C_DRIVERID_TVEEPROM +#warning Using temporary hack for missing I2C driver-ID for tveeprom +#define I2C_DRIVERID_TVEEPROM I2C_DRIVERID_EXP2 +#endif + +static int debug = 1; +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug level (0-2)"); + +#define STRM(array,i) (i < sizeof(array)/sizeof(char*) ? array[i] : "unknown") + +#define dprintk(num, format, args...) \ + do { \ + if (debug >= num) \ + printk(format, ##args); \ + } while (0) + +/* ----------------------------------------------------------------------- */ + +static unsigned char eeprom_buf[256]; + +struct tveeprom { + u32 has_radio; + + u32 tuner_type; + u32 tuner_formats; + + u32 digitizer; + u32 digitizer_formats; + + u32 audio_processor; + /* a_p_fmts? */ + + u32 model; + u32 revision; + u32 serial_number; + char rev_str[5]; +}; + +#define I2C_TVEEPROM 0xA0 +#define I2C_TVEEPROMA 0xA0 + +#define I2C_DELAY 10 + + +#define REG_ADDR(x) (((x) << 1) + 1) +#define LOBYTE(x) ((unsigned char)((x) & 0xff)) +#define HIBYTE(x) ((unsigned char)(((x) >> 8) & 0xff)) +#define LOWORD(x) ((unsigned short int)((x) & 0xffff)) +#define HIWORD(x) ((unsigned short int)(((x) >> 16) & 0xffff)) + +/* ----------------------------------------------------------------------- */ +/* some hauppauge specific stuff */ + +static struct HAUPPAUGE_TUNER_FMT +{ + int id; + char *name; +} +hauppauge_tuner_fmt[] __devinitdata = +{ + { 0x00000000, "unknown1" }, + { 0x00000000, "unknown2" }, + { 0x00000007, "PAL(B/G)" }, + { 0x00001000, "NTSC(M)" }, + { 0x00000010, "PAL(I)" }, + { 0x00400000, "SECAM(L/L´)" }, + { 0x00000e00, "PAL(D/K)" }, + { 0x03000000, "ATSC Digital" }, +}; + +static struct HAUPPAUGE_TUNER +{ + int id; + char *name; +} +hauppauge_tuner[] __devinitdata = +{ + { TUNER_ABSENT, "" }, + { TUNER_ABSENT, "External" }, + { TUNER_ABSENT, "Unspecified" }, + { TUNER_PHILIPS_PAL, "Philips FI1216" }, + { TUNER_PHILIPS_SECAM, "Philips FI1216MF" }, + { TUNER_PHILIPS_NTSC, "Philips FI1236" }, + { TUNER_PHILIPS_PAL_I, "Philips FI1246" }, + { TUNER_PHILIPS_PAL_DK,"Philips FI1256" }, + { TUNER_PHILIPS_PAL, "Philips FI1216 MK2" }, + { TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" }, + { TUNER_PHILIPS_NTSC, "Philips FI1236 MK2" }, + { TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" }, + { TUNER_PHILIPS_PAL_DK,"Philips FI1256 MK2" }, + { TUNER_TEMIC_NTSC, "Temic 4032FY5" }, + { TUNER_TEMIC_PAL, "Temic 4002FH5" }, + { TUNER_TEMIC_PAL_I, "Temic 4062FY5" }, + { TUNER_PHILIPS_PAL, "Philips FR1216 MK2" }, + { TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" }, + { TUNER_PHILIPS_NTSC, "Philips FR1236 MK2" }, + { TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" }, + { TUNER_PHILIPS_PAL_DK,"Philips FR1256 MK2" }, + { TUNER_PHILIPS_PAL, "Philips FM1216" }, + { TUNER_PHILIPS_SECAM, "Philips FM1216MF" }, + { TUNER_PHILIPS_NTSC, "Philips FM1236" }, + { TUNER_PHILIPS_PAL_I, "Philips FM1246" }, + { TUNER_PHILIPS_PAL_DK,"Philips FM1256" }, + { TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" }, + { TUNER_ABSENT, "Samsung TCPN9082D" }, + { TUNER_ABSENT, "Samsung TCPM9092P" }, + { TUNER_TEMIC_4006FH5_PAL, "Temic 4006FH5" }, + { TUNER_ABSENT, "Samsung TCPN9085D" }, + { TUNER_ABSENT, "Samsung TCPB9085P" }, + { TUNER_ABSENT, "Samsung TCPL9091P" }, + { TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" }, + { TUNER_PHILIPS_FQ1216ME, "Philips FQ1216 ME" }, + { TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" }, + { TUNER_ABSENT, "Philips TD1536" }, + { TUNER_ABSENT, "Philips TD1536D" }, + { TUNER_PHILIPS_NTSC, "Philips FMR1236" }, /* mono radio */ + { TUNER_ABSENT, "Philips FI1256MP" }, + { TUNER_ABSENT, "Samsung TCPQ9091P" }, + { TUNER_TEMIC_4006FN5_MULTI_PAL, "Temic 4006FN5" }, + { TUNER_TEMIC_4009FR5_PAL, "Temic 4009FR5" }, + { TUNER_TEMIC_4046FM5, "Temic 4046FM5" }, + { TUNER_TEMIC_4009FN5_MULTI_PAL_FM, "Temic 4009FN5" }, + { TUNER_ABSENT, "Philips TD1536D_FH_44"}, + { TUNER_LG_NTSC_FM, "LG TP18NSR01F"}, + { TUNER_LG_PAL_FM, "LG TP18PSB01D"}, + { TUNER_LG_PAL, "LG TP18PSB11D"}, + { TUNER_LG_PAL_I_FM, "LG TAPC-I001D"}, + { TUNER_LG_PAL_I, "LG TAPC-I701D"} +}; + +static char *sndtype[] = { + "None", "TEA6300", "TEA6320", "TDA9850", "MSP3400C", "MSP3410D", + "MSP3415", "MSP3430", "MSP3438", "CS5331", "MSP3435", "MSP3440", + "MSP3445", "MSP3411", "MSP3416", "MSP3425", + + "Type 0x10","Type 0x11","Type 0x12","Type 0x13", + "Type 0x14","Type 0x15","Type 0x16","Type 0x17", + "Type 0x18","MSP4418","Type 0x1a","MSP4448", + "Type 0x1c","Type 0x1d","Type 0x1e","Type 0x1f", +}; + +static void __devinit hauppauge_eeprom(struct tveeprom *tvee, + unsigned char *eeprom_data) +{ + + /* ---------------------------------------------- + ** The hauppauge eeprom format is tagged + ** + ** if packet[0] == 0x84, then packet[0..1] == length + ** else length = packet[0] & 3f; + ** if packet[0] & f8 == f8, then EOD and packet[1] == checksum + ** + ** In our (ivtv) case we're interested in the following: + ** tuner type: tag [00].05 or [0a].01 (index into hauppauge_tuners) + ** tuner fmts: tag [00].04 or [0a].00 (bitmask index into hauppauge_fmts) + ** radio: tag [00].{last} or [0e].00 (bitmask. bit2=FM) + ** audio proc: tag [02].01 or [05].00 (lower nibble indexes lut?) + + ** Fun info: + ** model: tag [00].07-08 or [06].00-01 + ** revision: tag [00].09-0b or [06].04-06 + ** serial#: tag [01].05-07 or [04].04-06 + + ** # of inputs/outputs ??? + */ + + int i,j,len,done,tag,tuner=0,t_format=0; + char *t_name = NULL, *t_fmt_name = NULL; + + tvee->revision = done = len = 0; + for(i=0; !done && i<256; i+=len) { + + dprintk(2, + KERN_INFO + "tvee: processing pos=%02x (%02x,%02x)\n", + i,eeprom_data[i],eeprom_data[i+1]); + + if(eeprom_data[i] == 0x84) { + len = eeprom_data[i+1] + (eeprom_data[i+2] << 8); + i+=3; + } else + if((eeprom_data[i] & 0xf0) == 0x70) { + if((eeprom_data[i] & 0x08)) { + /* verify checksum! */ + done = 1; + break; + } + len = eeprom_data[i] & 0x07; + ++i; + } else { + printk(KERN_WARNING "Encountered bad packet header [%02x]. " + "Corrupt or not a Hauppauge eeprom.\n",eeprom_data[i]); + return; + } + + dprintk(1, + KERN_INFO + "%3d [%02x] ", + len,eeprom_data[i]); + for(j=1; jhas_radio = eeprom_data[i+len-1]; + tvee->model = + eeprom_data[i+8] + + (eeprom_data[i+9] << 8); + tvee->revision = eeprom_data[i+10] + + (eeprom_data[i+11] << 8) + + (eeprom_data[i+12] << 16); + break; + case 0x01: + tvee->serial_number = + eeprom_data[i+6] + + (eeprom_data[i+7] << 8) + + (eeprom_data[i+8] << 16); + break; + case 0x02: + tvee->audio_processor = eeprom_data[i+2] & 0x0f; + break; + case 0x04: + tvee->serial_number = + eeprom_data[i+5] + + (eeprom_data[i+6] << 8) + + (eeprom_data[i+7] << 16); + break; + case 0x05: + tvee->audio_processor = eeprom_data[i+1] & 0x0f; + break; + case 0x06: + tvee->model = + eeprom_data[i+1] + + (eeprom_data[i+2] << 8); + tvee->revision = eeprom_data[i+5] + + (eeprom_data[i+6] << 8) + + (eeprom_data[i+7] << 16); + break; + case 0x0a: + tuner = eeprom_data[i+2]; + t_format = eeprom_data[i+1]; + break; + case 0x0e: + tvee->has_radio = eeprom_data[i+1]; + break; + default: + printk(KERN_WARNING "Not sure what to do with tag [%02x]\n",tag); + /* dump the rest of the packet? */ + } + + } + + if(!done) { + printk(KERN_WARNING "Ran out of data!\n"); + return; + } + + if(tvee->revision != 0) { + tvee->rev_str[0] = 32 + ((tvee->revision >> 18) & 0x3f); + tvee->rev_str[1] = 32 + ((tvee->revision >> 12) & 0x3f); + tvee->rev_str[2] = 32 + ((tvee->revision >> 6) & 0x3f); + tvee->rev_str[3] = 32 + ( tvee->revision & 0x3f); + tvee->rev_str[4] = 0; + } + + if (tuner < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) { + tvee->tuner_type = hauppauge_tuner[tuner].id; + t_name = hauppauge_tuner[tuner].name; + } else { + t_name = ""; + } + + tvee->tuner_formats = 0; + t_fmt_name = ""; + for(i=0; i<8; i++) { + if( (t_format & (1<tuner_formats |= hauppauge_tuner_fmt[i].id; + /* yuck */ + t_fmt_name = hauppauge_tuner_fmt[i].name; + } + } + +#if 0 + if (t_format < sizeof(hauppauge_tuner_fmt)/sizeof(struct HAUPPAUGE_TUNER_FMT)) { + tvee->tuner_formats = hauppauge_tuner_fmt[t_format].id; + t_fmt_name = hauppauge_tuner_fmt[t_format].name; + } else { + t_fmt_name = ""; + } +#endif + + printk(KERN_INFO "tvee: Hauppauge: model=%d, rev=%s, serial#=%d\n", + tvee->model, + tvee->rev_str, + tvee->serial_number); + printk(KERN_INFO "tvee: tuner=%s (idx=%d, type=%d)\n", + t_name, + tuner, + tvee->tuner_type); + printk(KERN_INFO "tvee: tuner fmt=%s (eeprom=0x%02x, v4l2=0x%08x)\n", + t_fmt_name, + t_format, + tvee->tuner_formats); + + printk(KERN_INFO "tvee: audio_processor=%s (type=%d)\n", + STRM(sndtype,tvee->audio_processor), + tvee->audio_processor); + +} + +/* ----------------------------------------------------------------------- */ + +/* write I2C */ +int tvee_I2CWrite(struct i2c_client *client, + unsigned char b1, + unsigned char b2, int both) +{ + unsigned char buffer[2]; + int bytes = both ? 2 : 1; + + buffer[0] = b1; + buffer[1] = b2; + if (bytes != i2c_master_send(client, buffer, bytes)) + return -1; + return 0; +} + +void __devinit tvee_readee(struct i2c_client *client, + unsigned char *eedata) +{ + int i; + + if (tvee_I2CWrite(client, 0, -1, 0)<0) { + printk(KERN_WARNING "tvee: readee error\n"); + return; + } + + for (i=0; i<256; i+=16) { + if (16 != i2c_master_recv(client,eedata+i,16)) { + printk(KERN_WARNING "tvee: readee error\n"); + break; + } + } +} + +/* ----------------------------------------------------------------------- */ + +static int +tveeprom_command (struct i2c_client *client, + unsigned int cmd, + void *arg) +{ + + struct tveeprom *eeprom = i2c_get_clientdata(client); + u32 *eeprom_props = arg; + + switch (cmd) { + + case 0: + eeprom_props[0] = eeprom->tuner_type; + eeprom_props[1] = eeprom->tuner_formats; + eeprom_props[2] = eeprom->model; + eeprom_props[3] = eeprom->revision; + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* + * Generic i2c probe + * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' + */ +static unsigned short normal_i2c[] = + { I2C_TVEEPROM >> 1, I2C_TVEEPROMA >> 1, I2C_CLIENT_END }; +static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; + +I2C_CLIENT_INSMOD; + +static int tveeprom_i2c_id = 0; +struct i2c_driver i2c_driver_tveeprom; + +static int +tveeprom_detect_client (struct i2c_adapter *adapter, + int address, + int kind) +{ + struct i2c_client *client; + struct tveeprom *eeprom; + + dprintk(1, + KERN_INFO + "tveeprom.c: detecting tveeprom client on address 0x%x\n", + address << 1); + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return 0; + + client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == 0) + return -ENOMEM; + memset(client, 0, sizeof(struct i2c_client)); + client->addr = address; + client->adapter = adapter; + client->driver = &i2c_driver_tveeprom; + client->flags = I2C_CLIENT_ALLOW_USE; + client->id = tveeprom_i2c_id++; + snprintf(client->name, sizeof(client->name) - 1, "tveeprom[%d]", + client->id); + + i2c_set_clientdata(client, eeprom = + kmalloc(sizeof(struct tveeprom), GFP_KERNEL)); + if (eeprom == NULL) { + kfree(client); + return -ENOMEM; + } + memset(eeprom, 0, sizeof(struct tveeprom)); + eeprom->tuner_type = -1; + eeprom->has_radio = 0; + eeprom->model = 0; + + tvee_readee(client,eeprom_buf); + hauppauge_eeprom(eeprom,eeprom_buf); + + return 0; +} + +static int +tveeprom_attach_adapter (struct i2c_adapter *adapter) +{ + if(adapter->id != (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return 0; + dprintk(1, + KERN_INFO + "tveeprom.c: starting probe for adapter %s (0x%x)\n", + adapter->name, adapter->id); + return i2c_probe(adapter, &addr_data, tveeprom_detect_client); +} + +static int +tveeprom_detach_client (struct i2c_client *client) +{ + struct tveeprom *eeprom = i2c_get_clientdata(client); + int err; + + err = i2c_detach_client(client); + if (err) { + return err; + } + + kfree(eeprom); + kfree(client); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ +struct i2c_driver i2c_driver_tveeprom = { + .owner = THIS_MODULE, + .name = "tveeprom", + + .id = I2C_DRIVERID_TVEEPROM, + .flags = I2C_DF_NOTIFY, + + .attach_adapter = tveeprom_attach_adapter, + .detach_client = tveeprom_detach_client, + .command = tveeprom_command, +}; + +static int tveeprom_init (void) +{ + return i2c_add_driver(&i2c_driver_tveeprom); +} + +static void tveeprom_exit (void) +{ + i2c_del_driver(&i2c_driver_tveeprom); +} + +module_init(tveeprom_init); +module_exit(tveeprom_exit); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/tvmixer.c 830-ivtv/drivers/media/video/tvmixer.c --- 000-virgin/drivers/media/video/tvmixer.c Mon Nov 17 18:28:14 2003 +++ 830-ivtv/drivers/media/video/tvmixer.c Thu Jan 8 11:17:12 2004 @@ -190,6 +190,10 @@ static int tvmixer_open(struct inode *in /* lock bttv in memory while the mixer is in use */ file->private_data = mix; +#ifndef I2C_PEC + if (client->adapter->inc_use) + client->adapter->inc_use(client->adapter); +#endif if (client->adapter->owner) try_module_get(client->adapter->owner); return 0; @@ -205,17 +209,27 @@ static int tvmixer_release(struct inode return -ENODEV; } +#ifndef I2C_PEC + if (client->adapter->dec_use) + client->adapter->dec_use(client->adapter); +#endif if (client->adapter->owner) module_put(client->adapter->owner); return 0; } static struct i2c_driver driver = { +#ifdef I2C_PEC .owner = THIS_MODULE, +#endif .name = "tv card mixer driver", .id = I2C_DRIVERID_TVMIXER, +#ifdef I2C_DF_DUMMY + .flags = I2C_DF_DUMMY, +#else .flags = I2C_DF_NOTIFY, .detach_adapter = tvmixer_adapters, +#endif .attach_adapter = tvmixer_adapters, .detach_client = tvmixer_clients, }; @@ -247,8 +261,21 @@ static int tvmixer_clients(struct i2c_cl struct video_audio va; int i,minor; +#ifdef I2C_ADAP_CLASS_TV_ANALOG if (!(client->adapter->class & I2C_ADAP_CLASS_TV_ANALOG)) return -1; +#else + /* TV card ??? */ + switch (client->adapter->id) { + case I2C_ALGO_BIT | I2C_HW_B_BT848: + case I2C_ALGO_BIT | I2C_HW_B_RIVA: + /* ok, have a look ... */ + break; + default: + /* ignore that one */ + return -1; + } +#endif /* unregister ?? */ for (i = 0; i < DEV_MAX; i++) { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/v4l1-compat.c 830-ivtv/drivers/media/video/v4l1-compat.c --- 000-virgin/drivers/media/video/v4l1-compat.c Fri May 30 19:02:10 2003 +++ 830-ivtv/drivers/media/video/v4l1-compat.c Thu Jan 8 11:17:04 2004 @@ -21,7 +21,6 @@ #include -#include #include #include #include @@ -52,7 +51,7 @@ MODULE_DESCRIPTION("v4l(1) compatibility MODULE_LICENSE("GPL"); #define dprintk(fmt, arg...) if (debug) \ - printk(KERN_DEBUG "v4l1-compat: " fmt, ## arg) + printk(KERN_DEBUG "v4l1-compat: " fmt , ## arg) /* * I O C T L T R A N S L A T I O N @@ -80,8 +79,10 @@ get_v4l_control(struct inode { ctrl2.id = qctrl2.id; err = drv(inode, file, VIDIOC_G_CTRL, &ctrl2); - if (err < 0) + if (err < 0) { dprintk("VIDIOC_G_CTRL: %d\n",err); + return 0; + } return ((ctrl2.value - qctrl2.minimum) * 65535 + (qctrl2.maximum - qctrl2.minimum) / 2) / (qctrl2.maximum - qctrl2.minimum); @@ -207,17 +208,10 @@ static int poll_one(struct file *file) { int retval = 1; poll_table *table; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,48) - poll_table wait_table; - - poll_initwait(&wait_table); - table = &wait_table; -#else struct poll_wqueues pwq; poll_initwait(&pwq); table = &pwq.pt; -#endif for (;;) { int mask; set_current_state(TASK_INTERRUPTIBLE); @@ -231,12 +225,8 @@ static int poll_one(struct file *file) } schedule(); } - current->state = TASK_RUNNING; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,48) - poll_freewait(&wait_table); -#else + set_current_state(TASK_RUNNING); poll_freewait(&pwq); -#endif return retval; } @@ -482,6 +472,7 @@ v4l_compat_translate_ioctl(struct inode fmt2->fmt.pix.width = win->width; fmt2->fmt.pix.height = win->height; fmt2->fmt.pix.field = V4L2_FIELD_ANY; + fmt2->fmt.pix.bytesperline = 0; err = drv(inode, file, VIDIOC_S_FMT, fmt2); if (err < 0) dprintk("VIDIOCSWIN / VIDIOC_S_FMT #1: %d\n", @@ -509,6 +500,14 @@ v4l_compat_translate_ioctl(struct inode } case VIDIOCCAPTURE: /* turn on/off preview */ { + int *on = arg; + + if (0 == *on) { + /* dirty hack time. But v4l1 has no STREAMOFF + * equivalent in the API, and this one at + * least comes close ... */ + drv(inode, file, VIDIOC_STREAMOFF, NULL); + } err = drv(inode, file, VIDIOC_OVERLAY, arg); if (err < 0) dprintk("VIDIOCCAPTURE / VIDIOC_PREVIEW: %d\n",err); @@ -719,7 +718,8 @@ v4l_compat_translate_ioctl(struct inode case VIDIOCGFREQ: /* get frequency */ { int *freq = arg; - + + freq2.tuner = 0; err = drv(inode, file, VIDIOC_G_FREQUENCY, &freq2); if (err < 0) dprintk("VIDIOCGFREQ / VIDIOC_G_FREQUENCY: %d\n",err); @@ -731,6 +731,7 @@ v4l_compat_translate_ioctl(struct inode { int *freq = arg; + freq2.tuner = 0; drv(inode, file, VIDIOC_G_FREQUENCY, &freq2); freq2.frequency = *freq; err = drv(inode, file, VIDIOC_S_FREQUENCY, &freq2); @@ -877,6 +878,7 @@ v4l_compat_translate_ioctl(struct inode fmt2->fmt.pix.pixelformat = palette_to_pixelformat(mm->format); fmt2->fmt.pix.field = V4L2_FIELD_ANY; + fmt2->fmt.pix.bytesperline = 0; err = drv(inode, file, VIDIOC_S_FMT, fmt2); if (err < 0) { dprintk("VIDIOCMCAPTURE / VIDIOC_S_FMT: %d\n",err); @@ -895,7 +897,7 @@ v4l_compat_translate_ioctl(struct inode dprintk("VIDIOCMCAPTURE / VIDIOC_QBUF: %d\n",err); break; } - err = drv(inode, file, VIDIOC_STREAMON, &buf2.type); + err = drv(inode, file, VIDIOC_STREAMON, NULL); if (err < 0) dprintk("VIDIOCMCAPTURE / VIDIOC_STREAMON: %d\n",err); break; @@ -989,7 +991,7 @@ v4l_compat_translate_ioctl(struct inode if (fmt2->fmt.vbi.samples_per_line != fmt->samples_per_line || fmt2->fmt.vbi.sampling_rate != fmt->sampling_rate || - fmt2->fmt.vbi.sample_format != V4L2_PIX_FMT_GREY || + VIDEO_PALETTE_RAW != fmt->sample_format || fmt2->fmt.vbi.start[0] != fmt->start[0] || fmt2->fmt.vbi.count[0] != fmt->count[0] || fmt2->fmt.vbi.start[1] != fmt->start[1] || @@ -999,10 +1001,9 @@ v4l_compat_translate_ioctl(struct inode break; } err = drv(inode, file, VIDIOC_S_FMT, fmt2); - if (err < 0) { + if (err < 0) dprintk("VIDIOCSVBIFMT / VIDIOC_S_FMT: %d\n", err); - break; - } + break; } default: diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/v4l2-common.c 830-ivtv/drivers/media/video/v4l2-common.c --- 000-virgin/drivers/media/video/v4l2-common.c Mon Nov 17 18:29:29 2003 +++ 830-ivtv/drivers/media/video/v4l2-common.c Thu Jan 8 11:17:04 2004 @@ -67,6 +67,7 @@ #include #endif + #include MODULE_AUTHOR("Bill Dirks, Justin Schoeman, Gerd Knorr"); @@ -100,9 +101,11 @@ v4l2_video_std_fps(struct v4l2_standard int v4l2_video_std_construct(struct v4l2_standard *vs, int id, char *name) { - memset(vs, 0, sizeof(struct v4l2_standard)); + u32 index = vs->index; - vs->id = id; + memset(vs, 0, sizeof(struct v4l2_standard)); + vs->index = index; + vs->id = id; if (id & (V4L2_STD_NTSC | V4L2_STD_PAL_M)) { vs->frameperiod.numerator = 1001; vs->frameperiod.denominator = 30000; @@ -118,6 +121,66 @@ int v4l2_video_std_construct(struct v4l2 /* ----------------------------------------------------------------- */ +/* priority handling */ + +#define V4L2_PRIO_VALID(val) (val == V4L2_PRIORITY_BACKGROUND || \ + val == V4L2_PRIORITY_INTERACTIVE || \ + val == V4L2_PRIORITY_RECORD) + +int v4l2_prio_init(struct v4l2_prio_state *global) +{ + memset(global,0,sizeof(*global)); + return 0; +} + +int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local, + enum v4l2_priority new) +{ + if (!V4L2_PRIO_VALID(new)) + return -EINVAL; + if (*local == new) + return 0; + + atomic_inc(&global->prios[new]); + if (V4L2_PRIO_VALID(*local)) + atomic_dec(&global->prios[*local]); + *local = new; + return 0; +} + +int v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local) +{ + return v4l2_prio_change(global,local,V4L2_PRIORITY_DEFAULT); +} + +int v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority *local) +{ + if (V4L2_PRIO_VALID(*local)) + atomic_dec(&global->prios[*local]); + return 0; +} + +enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global) +{ + if (atomic_read(&global->prios[V4L2_PRIORITY_RECORD]) > 0) + return V4L2_PRIORITY_RECORD; + if (atomic_read(&global->prios[V4L2_PRIORITY_INTERACTIVE]) > 0) + return V4L2_PRIORITY_INTERACTIVE; + if (atomic_read(&global->prios[V4L2_PRIORITY_BACKGROUND]) > 0) + return V4L2_PRIORITY_BACKGROUND; + return V4L2_PRIORITY_UNSET; +} + +int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local) +{ + if (*local < v4l2_prio_max(global)) + return -EBUSY; + return 0; +} + + +/* ----------------------------------------------------------------- */ +/* some arrays for pretty-printing debug messages */ char *v4l2_field_names[] = { [V4L2_FIELD_ANY] = "any", @@ -198,6 +261,13 @@ char *v4l2_ioctl_names[256] = { EXPORT_SYMBOL(v4l2_video_std_fps); EXPORT_SYMBOL(v4l2_video_std_construct); + +EXPORT_SYMBOL(v4l2_prio_init); +EXPORT_SYMBOL(v4l2_prio_change); +EXPORT_SYMBOL(v4l2_prio_open); +EXPORT_SYMBOL(v4l2_prio_close); +EXPORT_SYMBOL(v4l2_prio_max); +EXPORT_SYMBOL(v4l2_prio_check); EXPORT_SYMBOL(v4l2_field_names); EXPORT_SYMBOL(v4l2_type_names); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/video-buf.c 830-ivtv/drivers/media/video/video-buf.c --- 000-virgin/drivers/media/video/video-buf.c Thu Jan 8 08:35:37 2004 +++ 830-ivtv/drivers/media/video/video-buf.c Thu Jan 8 11:17:06 2004 @@ -41,7 +41,7 @@ MODULE_LICENSE("GPL"); MODULE_PARM(debug,"i"); #define dprintk(level, fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "vbuf: " fmt, ## arg) + printk(KERN_DEBUG "vbuf: " fmt , ## arg) struct scatterlist* videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages) @@ -236,8 +236,8 @@ int videobuf_dma_pci_map(struct pci_dev dma->sglist = kmalloc(sizeof(struct scatterlist), GFP_KERNEL); if (NULL != dma->sglist) { dma->sglen = 1; - sg_dma_address(&dma->sglist[0]) = dma->bus_addr & ~PAGE_MASK; - dma->sglist[0].offset = dma->bus_addr & PAGE_MASK; + sg_dma_address(&dma->sglist[0]) = dma->bus_addr & PAGE_MASK; + dma->sglist[0].offset = dma->bus_addr & ~PAGE_MASK; sg_dma_len(&dma->sglist[0]) = dma->nr_pages * PAGE_SIZE; } } @@ -325,8 +325,8 @@ int videobuf_waiton(struct videobuf_buff retval = -EAGAIN; break; } - set_current_state(intr ? TASK_INTERRUPTIBLE : - TASK_UNINTERRUPTIBLE); + set_current_state(intr ? TASK_INTERRUPTIBLE + : TASK_UNINTERRUPTIBLE); if (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) schedule(); set_current_state(TASK_RUNNING); @@ -969,8 +969,10 @@ ssize_t videobuf_read_stream(struct file retval += bytes; q->read_off += bytes; } else { - /* some error -- skip buffer */ + /* some error */ q->read_off = q->read_buf->size; + if (0 == retval) + retval = -EIO; } /* requeue buffer when done with copying */ @@ -982,6 +984,8 @@ ssize_t videobuf_read_stream(struct file spin_unlock_irqrestore(q->irqlock,flags); q->read_buf = NULL; } + if (retval < 0) + break; } done: diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/media/video/videodev.c 830-ivtv/drivers/media/video/videodev.c --- 000-virgin/drivers/media/video/videodev.c Mon Nov 17 18:29:29 2003 +++ 830-ivtv/drivers/media/video/videodev.c Thu Jan 8 11:16:57 2004 @@ -140,6 +140,30 @@ static int video_open(struct inode *inod /* * helper function -- handles userspace copying for ioctl arguments */ + +static unsigned int +video_fix_command(unsigned int cmd) +{ + switch (cmd) { + case VIDIOC_OVERLAY_OLD: + cmd = VIDIOC_OVERLAY; + break; + case VIDIOC_S_PARM_OLD: + cmd = VIDIOC_S_PARM; + break; + case VIDIOC_S_CTRL_OLD: + cmd = VIDIOC_S_CTRL; + break; + case VIDIOC_G_AUDIO_OLD: + cmd = VIDIOC_G_AUDIO; + break; + case VIDIOC_G_AUDOUT_OLD: + cmd = VIDIOC_G_AUDOUT; + break; + } + return cmd; +} + int video_usercopy(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg, @@ -151,12 +175,14 @@ video_usercopy(struct inode *inode, stru void *parg = NULL; int err = -EINVAL; + cmd = video_fix_command(cmd); + /* Copy arguments into temp kernel buffer */ switch (_IOC_DIR(cmd)) { case _IOC_NONE: parg = (void *)arg; break; - case _IOC_READ: /* some v4l ioctls are marked wrong ... */ + case _IOC_READ: case _IOC_WRITE: case (_IOC_WRITE | _IOC_READ): if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { @@ -170,8 +196,9 @@ video_usercopy(struct inode *inode, stru } err = -EFAULT; - if (copy_from_user(parg, (void *)arg, _IOC_SIZE(cmd))) - goto out; + if (_IOC_DIR(cmd) & _IOC_WRITE) + if (copy_from_user(parg, (void *)arg, _IOC_SIZE(cmd))) + goto out; break; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/3c501.c 830-ivtv/drivers/net/3c501.c --- 000-virgin/drivers/net/3c501.c Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/3c501.c Thu Jan 8 08:54:04 2004 @@ -136,17 +136,14 @@ static const char version[] = #include "3c501.h" -/* A zero-terminated list of I/O addresses to be probed. - The 3c501 can be at many locations, but here are the popular ones. */ -static unsigned int netcard_portlist[] __initdata = { - 0x280, 0x300, 0 -}; - - /* * The boilerplate probe code. */ +static int io=0x280; +static int irq=5; +static int mem_start; + /** * el1_probe: - probe for a 3c501 * @dev: The device structure passed in to probe. @@ -160,23 +157,47 @@ static unsigned int netcard_portlist[] _ * probe and failing to find anything. */ -int __init el1_probe(struct net_device *dev) +struct net_device * __init el1_probe(int unit) { - int i; - int base_addr = dev->base_addr; + struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); + static unsigned ports[] = { 0x280, 0x300, 0}; + unsigned *port; + int err = 0; + + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + irq = dev->irq; + mem_start = dev->mem_start & 7; + } SET_MODULE_OWNER(dev); - if (base_addr > 0x1ff) /* Check a single specified location. */ - return el1_probe1(dev, base_addr); - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; - - for (i = 0; netcard_portlist[i]; i++) - if (el1_probe1(dev, netcard_portlist[i]) == 0) - return 0; - - return -ENODEV; + if (io > 0x1ff) { /* Check a single specified location. */ + err = el1_probe1(dev, io); + } else if (io != 0) { + err = -ENXIO; /* Don't probe at all. */ + } else { + for (port = ports; *port && el1_probe1(dev, *port); port++) + ; + if (!*port) + err = -ENODEV; + } + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + release_region(dev->base_addr, EL1_IO_EXTENT); +out: + free_netdev(dev); + return ERR_PTR(err); } /** @@ -240,6 +261,8 @@ static int __init el1_probe1(struct net_ * high. */ + dev->irq = irq; + if (dev->irq < 2) { unsigned long irq_mask; @@ -267,8 +290,8 @@ static int __init el1_probe1(struct net_ dev->base_addr = ioaddr; memcpy(dev->dev_addr, station_addr, ETH_ALEN); - if (dev->mem_start & 0xf) - el_debug = dev->mem_start & 0x7; + if (mem_start & 0xf) + el_debug = mem_start & 0x7; if (autoirq) dev->irq = autoirq; @@ -282,17 +305,7 @@ static int __init el1_probe1(struct net_ if (el_debug) printk(KERN_DEBUG "%s", version); - /* - * Initialize the device structure. - */ - - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == NULL) { - release_region(ioaddr, EL1_IO_EXTENT); - return -ENOMEM; - } memset(dev->priv, 0, sizeof(struct net_local)); - lp=dev->priv; spin_lock_init(&lp->lock); @@ -308,13 +321,6 @@ static int __init el1_probe1(struct net_ dev->get_stats = &el1_get_stats; dev->set_multicast_list = &set_multicast_list; dev->ethtool_ops = &netdev_ethtool_ops; - - /* - * Setup the generic properties - */ - - ether_setup(dev); - return 0; } @@ -884,14 +890,8 @@ static struct ethtool_ops netdev_ethtool #ifdef MODULE -static struct net_device dev_3c501 = { - .init = el1_probe, - .base_addr = 0x280, - .irq = 5, -}; +static struct net_device *dev_3c501; -static int io=0x280; -static int irq=5; MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); MODULE_PARM_DESC(io, "EtherLink I/O base address"); @@ -911,10 +911,9 @@ MODULE_PARM_DESC(irq, "EtherLink IRQ num int init_module(void) { - dev_3c501.irq=irq; - dev_3c501.base_addr=io; - if (register_netdev(&dev_3c501) != 0) - return -EIO; + dev_3c501 = el1_probe(-1); + if (IS_ERR(dev_3c501)) + return PTR_ERR(dev_3c501); return 0; } @@ -927,19 +926,10 @@ int init_module(void) void cleanup_module(void) { - unregister_netdev(&dev_3c501); - - /* - * Free up the private structure, or leak memory :-) - */ - - kfree(dev_3c501.priv); - dev_3c501.priv = NULL; /* gets re-allocated by el1_probe1 */ - - /* - * If we don't do this, we can't re-insmod it later. - */ - release_region(dev_3c501.base_addr, EL1_IO_EXTENT); + struct net_device *dev = dev_3c501; + unregister_netdev(dev); + release_region(dev->base_addr, EL1_IO_EXTENT); + free_netdev(dev); } #endif /* MODULE */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/3c501.h 830-ivtv/drivers/net/3c501.h --- 000-virgin/drivers/net/3c501.h Mon Nov 17 18:28:14 2003 +++ 830-ivtv/drivers/net/3c501.h Thu Jan 8 08:54:04 2004 @@ -3,7 +3,6 @@ * Index to functions. */ -int el1_probe(struct net_device *dev); static int el1_probe1(struct net_device *dev, int ioaddr); static int el_open(struct net_device *dev); static void el_timeout(struct net_device *dev); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/3c503.c 830-ivtv/drivers/net/3c503.c --- 000-virgin/drivers/net/3c503.c Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/3c503.c Thu Jan 8 08:54:04 2004 @@ -60,7 +60,6 @@ static const char version[] = #include "3c503.h" #define WRD_COUNT 4 -int el2_probe(struct net_device *dev); static int el2_pio_probe(struct net_device *dev); static int el2_probe1(struct net_device *dev, int ioaddr); @@ -90,11 +89,11 @@ static struct ethtool_ops netdev_ethtool If the ethercard isn't found there is an optional probe for ethercard jumpered to programmed-I/O mode. */ -int __init -el2_probe(struct net_device *dev) +static int __init do_el2_probe(struct net_device *dev) { int *addr, addrs[] = { 0xddffe, 0xd9ffe, 0xcdffe, 0xc9ffe, 0}; int base_addr = dev->base_addr; + int irq = dev->irq; SET_MODULE_OWNER(dev); @@ -104,16 +103,13 @@ el2_probe(struct net_device *dev) return -ENXIO; for (addr = addrs; *addr; addr++) { - int i; - unsigned int base_bits = isa_readb(*addr); - /* Find first set bit. */ - for(i = 7; i >= 0; i--, base_bits >>= 1) - if (base_bits & 0x1) - break; - if (base_bits != 1) + unsigned base_bits = isa_readb(*addr); + int i = ffs(base_bits) - 1; + if (i == -1 || base_bits != (1 << i)) continue; if (el2_probe1(dev, netcard_portlist[i]) == 0) return 0; + dev->irq = irq; } #if ! defined(no_probe_nonshared_memory) return el2_pio_probe(dev); @@ -128,20 +124,54 @@ static int __init el2_pio_probe(struct net_device *dev) { int i; - int base_addr = dev ? dev->base_addr : 0; + int base_addr = dev->base_addr; + int irq = dev->irq; if (base_addr > 0x1ff) /* Check a single specified location. */ return el2_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ return -ENXIO; - for (i = 0; netcard_portlist[i]; i++) + for (i = 0; netcard_portlist[i]; i++) { if (el2_probe1(dev, netcard_portlist[i]) == 0) return 0; + dev->irq = irq; + } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + /* NB: el2_close() handles free_irq */ + release_region(dev->base_addr, EL2_IO_EXTENT); +} + +struct net_device * __init el2_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_el2_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + /* Probe for the Etherlink II card at I/O port base IOADDR, returning non-zero on success. If found, set the station address and memory parameters in DEVICE. */ @@ -152,15 +182,19 @@ el2_probe1(struct net_device *dev, int i static unsigned version_printed; unsigned long vendor_id; - /* FIXME: code reads ioaddr + 0x400, we request ioaddr + 16 */ if (!request_region(ioaddr, EL2_IO_EXTENT, dev->name)) return -EBUSY; + if (!request_region(ioaddr + 0x400, 8, dev->name)) { + retval = -EBUSY; + goto out; + } + /* Reset and/or avoid any lurking NE2000 */ if (inb(ioaddr + 0x408) == 0xff) { mdelay(1); retval = -ENODEV; - goto out; + goto out1; } /* We verify that it's a 3C503 board by checking the first three octets @@ -171,7 +205,7 @@ el2_probe1(struct net_device *dev, int i if ( (iobase_reg & (iobase_reg - 1)) || (membase_reg & (membase_reg - 1))) { retval = -ENODEV; - goto out; + goto out1; } saved_406 = inb_p(ioaddr + 0x406); outb_p(ECNTRL_RESET|ECNTRL_THIN, ioaddr + 0x406); /* Reset it... */ @@ -184,19 +218,13 @@ el2_probe1(struct net_device *dev, int i /* Restore the register we frobbed. */ outb(saved_406, ioaddr + 0x406); retval = -ENODEV; - goto out; + goto out1; } if (ei_debug && version_printed++ == 0) printk(version); dev->base_addr = ioaddr; - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk ("3c503: unable to allocate memory for dev->priv.\n"); - retval = -ENOMEM; - goto out; - } printk("%s: 3c503 at i/o base %#3x, node ", dev->name, ioaddr); @@ -322,7 +350,10 @@ el2_probe1(struct net_device *dev, int i printk("\n%s: %s, %dkB RAM, using programmed I/O (REJUMPER for SHARED MEMORY).\n", dev->name, ei_status.name, (wordlength+1)<<3); } + release_region(ioaddr + 0x400, 8); return 0; +out1: + release_region(ioaddr + 0x400, 8); out: release_region(ioaddr, EL2_IO_EXTENT); return retval; @@ -633,7 +664,7 @@ static struct ethtool_ops netdev_ethtool #ifdef MODULE #define MAX_EL2_CARDS 4 /* Max number of EL2 cards per module */ -static struct net_device dev_el2[MAX_EL2_CARDS]; +static struct net_device *dev_el2[MAX_EL2_CARDS]; static int io[MAX_EL2_CARDS]; static int irq[MAX_EL2_CARDS]; static int xcvr[MAX_EL2_CARDS]; /* choose int. or ext. xcvr */ @@ -651,28 +682,34 @@ ISA device autoprobes on a running machi int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_EL2_CARDS; this_dev++) { - struct net_device *dev = &dev_el2[this_dev]; - dev->irq = irq[this_dev]; - dev->base_addr = io[this_dev]; - dev->mem_end = xcvr[this_dev]; /* low 4bits = xcvr sel. */ - dev->init = el2_probe; if (io[this_dev] == 0) { if (this_dev != 0) break; /* only autoprobe 1st one */ printk(KERN_NOTICE "3c503.c: Presently autoprobing (not recommended) for a single card.\n"); } - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "3c503.c: No 3c503 card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) { /* Got at least one. */ - return 0; + dev = alloc_ei_netdev(); + if (!dev) + break; + dev->irq = irq[this_dev]; + dev->base_addr = io[this_dev]; + dev->mem_end = xcvr[this_dev]; /* low 4bits = xcvr sel. */ + if (do_el2_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_el2[found++] = dev; + continue; } - return -ENXIO; + cleanup_card(dev); } - found++; + free_netdev(dev); + printk(KERN_WARNING "3c503.c: No 3c503 card found (i/o = 0x%x).\n", io[this_dev]); + break; } - return 0; + if (found) + return 0; + return -ENXIO; } void @@ -681,13 +718,11 @@ cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < MAX_EL2_CARDS; this_dev++) { - struct net_device *dev = &dev_el2[this_dev]; - if (dev->priv != NULL) { - void *priv = dev->priv; - /* NB: el2_close() handles free_irq */ - release_region(dev->base_addr, EL2_IO_EXTENT); + struct net_device *dev = dev_el2[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(priv); + cleanup_card(dev); + free_netdev(dev); } } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/3c505.c 830-ivtv/drivers/net/3c505.c --- 000-virgin/drivers/net/3c505.c Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/3c505.c Thu Jan 8 08:54:04 2004 @@ -1293,42 +1293,6 @@ static void elp_set_mc_list(struct net_d } } -/****************************************************** - * - * initialise Etherlink Plus board - * - ******************************************************/ - -static inline void elp_init(struct net_device *dev) -{ - elp_device *adapter = dev->priv; - - /* - * set ptrs to various functions - */ - dev->open = elp_open; /* local */ - dev->stop = elp_close; /* local */ - dev->get_stats = elp_get_stats; /* local */ - dev->hard_start_xmit = elp_start_xmit; /* local */ - dev->tx_timeout = elp_timeout; /* local */ - dev->watchdog_timeo = 10*HZ; - dev->set_multicast_list = elp_set_mc_list; /* local */ - dev->ethtool_ops = &netdev_ethtool_ops; /* local */ - - /* Setup the generic properties */ - ether_setup(dev); - - /* - * setup ptr to adapter specific information - */ - memset(&(adapter->stats), 0, sizeof(struct net_device_stats)); - - /* - * memory information - */ - dev->mem_start = dev->mem_end = 0; -} - /************************************************************ * * A couple of tests to see if there's 3C505 or not @@ -1442,12 +1406,13 @@ static int __init elp_autodetect(struct * work at all if it was in a weird state). */ -int __init elplus_probe(struct net_device *dev) +static int __init elplus_setup(struct net_device *dev) { - elp_device *adapter; + elp_device *adapter = dev->priv; int i, tries, tries1, okay; unsigned long timeout; unsigned long cookie = 0; + int err = -ENODEV; SET_MODULE_OWNER(dev); @@ -1456,17 +1421,8 @@ int __init elplus_probe(struct net_devic */ dev->base_addr = elp_autodetect(dev); - if (!(dev->base_addr)) - return -ENODEV; - - /* - * setup ptr to adapter specific information - */ - adapter = (elp_device *) (dev->priv = kmalloc(sizeof(elp_device), GFP_KERNEL)); - if (adapter == NULL) { - printk(KERN_ERR "%s: out of memory\n", dev->name); + if (!dev->base_addr) return -ENODEV; - } adapter->send_pcb_semaphore = 0; @@ -1544,8 +1500,7 @@ int __init elplus_probe(struct net_devic outb_control(adapter->hcr_val & ~(FLSH | ATTN), dev); } printk(KERN_ERR "%s: failed to initialise 3c505\n", dev->name); - release_region(dev->base_addr, ELP_IO_EXTENT); - return -ENODEV; + goto out; okay: if (dev->irq) { /* Is there a preset IRQ? */ @@ -1560,14 +1515,14 @@ int __init elplus_probe(struct net_devic case 0: printk(KERN_ERR "%s: IRQ probe failed: check 3c505 jumpers.\n", dev->name); - return -ENODEV; + goto out; case 1: case 6: case 8: case 13: printk(KERN_ERR "%s: Impossible IRQ %d reported by probe_irq_off().\n", dev->name, dev->irq); - return -ENODEV; + goto out; } /* * Now we have the IRQ number so we can disable the interrupts from @@ -1636,16 +1591,48 @@ int __init elplus_probe(struct net_devic printk(KERN_ERR "%s: adapter configuration failed\n", dev->name); } - /* - * initialise the device - */ - elp_init(dev); + dev->open = elp_open; /* local */ + dev->stop = elp_close; /* local */ + dev->get_stats = elp_get_stats; /* local */ + dev->hard_start_xmit = elp_start_xmit; /* local */ + dev->tx_timeout = elp_timeout; /* local */ + dev->watchdog_timeo = 10*HZ; + dev->set_multicast_list = elp_set_mc_list; /* local */ + dev->ethtool_ops = &netdev_ethtool_ops; /* local */ + + memset(&(adapter->stats), 0, sizeof(struct net_device_stats)); + dev->mem_start = dev->mem_end = 0; + + err = register_netdev(dev); + if (err) + goto out; return 0; +out: + release_region(dev->base_addr, ELP_IO_EXTENT); + return err; +} + +struct net_device * __init elplus_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(sizeof(elp_device)); + int err; + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = elplus_setup(dev); + if (err) { + free_netdev(dev); + return ERR_PTR(err); + } + return dev; } #ifdef MODULE -static struct net_device dev_3c505[ELP_MAX_CARDS]; +static struct net_device *dev_3c505[ELP_MAX_CARDS]; static int io[ELP_MAX_CARDS]; static int irq[ELP_MAX_CARDS]; static int dma[ELP_MAX_CARDS]; @@ -1661,10 +1648,12 @@ int init_module(void) int this_dev, found = 0; for (this_dev = 0; this_dev < ELP_MAX_CARDS; this_dev++) { - struct net_device *dev = &dev_3c505[this_dev]; + struct net_device *dev = alloc_etherdev(sizeof(elp_device)); + if (!dev) + break; + dev->irq = irq[this_dev]; dev->base_addr = io[this_dev]; - dev->init = elplus_probe; if (dma[this_dev]) { dev->dma = dma[this_dev]; } else { @@ -1672,16 +1661,22 @@ int init_module(void) printk(KERN_WARNING "3c505.c: warning, using default DMA channel,\n"); } if (io[this_dev] == 0) { - if (this_dev) break; + if (this_dev) { + free_netdev(dev); + break; + } printk(KERN_NOTICE "3c505.c: module autoprobe not recommended, give io=xx.\n"); } - if (register_netdev(dev) != 0) { + if (elplus_setup(dev) != 0) { printk(KERN_WARNING "3c505.c: Failed to register card at 0x%x.\n", io[this_dev]); - if (found != 0) return 0; - return -ENXIO; + free_netdev(dev); + break; } + dev_3c505[this_dev] = dev; found++; } + if (!found) + return -ENODEV; return 0; } @@ -1690,12 +1685,11 @@ void cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < ELP_MAX_CARDS; this_dev++) { - struct net_device *dev = &dev_3c505[this_dev]; - if (dev->priv != NULL) { + struct net_device *dev = dev_3c505[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(dev->priv); - dev->priv = NULL; release_region(dev->base_addr, ELP_IO_EXTENT); + free_netdev(dev); } } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/3c507.c 830-ivtv/drivers/net/3c507.c --- 000-virgin/drivers/net/3c507.c Mon Nov 17 18:28:14 2003 +++ 830-ivtv/drivers/net/3c507.c Thu Jan 8 08:54:04 2004 @@ -74,10 +74,6 @@ static unsigned int net_debug = NET_DEBU #define debug net_debug -/* A zero-terminated list of common I/O addresses to be probed. */ -static unsigned int netcard_portlist[] __initdata = - { 0x300, 0x320, 0x340, 0x280, 0}; - /* Details of the i82586. @@ -286,8 +282,6 @@ static unsigned short init_words[] = { /* Index to functions, as function prototypes. */ -extern int el16_probe(struct net_device *dev); /* Called from Space.c */ - static int el16_probe1(struct net_device *dev, int ioaddr); static int el16_open(struct net_device *dev); static int el16_send_packet(struct sk_buff *skb, struct net_device *dev); @@ -301,6 +295,10 @@ static void hardware_send_packet(struct static void init_82586_mem(struct net_device *dev); static struct ethtool_ops netdev_ethtool_ops; +static int io = 0x300; +static int irq; +static int mem_start; + /* Check for a network adaptor of this type, and return '0' iff one exists. If dev->base_addr == 0, probe all likely locations. @@ -309,23 +307,50 @@ static struct ethtool_ops netdev_ethtool device and return success. */ -int __init el16_probe(struct net_device *dev) +struct net_device * __init el16_probe(int unit) { - int base_addr = dev->base_addr; - int i; + struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); + static unsigned ports[] = { 0x300, 0x320, 0x340, 0x280, 0}; + unsigned *port; + int err = -ENODEV; + + if (!dev) + return ERR_PTR(-ENODEV); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + irq = dev->irq; + mem_start = dev->mem_start & 15; + } SET_MODULE_OWNER(dev); - if (base_addr > 0x1ff) /* Check a single specified location. */ - return el16_probe1(dev, base_addr); - else if (base_addr != 0) - return -ENXIO; /* Don't probe at all. */ - - for (i = 0; netcard_portlist[i]; i++) - if (el16_probe1(dev, netcard_portlist[i]) == 0) - return 0; + if (io > 0x1ff) /* Check a single specified location. */ + err = el16_probe1(dev, io); + else if (io != 0) + err = -ENXIO; /* Don't probe at all. */ + else { + for (port = ports; *port; port++) { + err = el16_probe1(dev, *port); + if (!err) + break; + } + } - return -ENODEV; + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + free_irq(dev->irq, dev); + release_region(dev->base_addr, EL16_IO_EXTENT); +out: + free_netdev(dev); + return ERR_PTR(err); } static int __init el16_probe1(struct net_device *dev, int ioaddr) @@ -383,8 +408,8 @@ static int __init el16_probe1(struct net printk(" %02x", dev->dev_addr[i]); } - if ((dev->mem_start & 0xf) > 0) - net_debug = dev->mem_start & 7; + if (mem_start) + net_debug = mem_start & 7; #ifdef MEM_BASE dev->mem_start = MEM_BASE; @@ -416,27 +441,18 @@ static int __init el16_probe1(struct net if (net_debug) printk(version); - /* Initialize the device structure. */ - lp = dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == NULL) { - retval = -ENOMEM; - goto out; - } - memset(dev->priv, 0, sizeof(struct net_local)); + lp = dev->priv; + memset(lp, 0, sizeof(*lp)); spin_lock_init(&lp->lock); - dev->open = el16_open; - dev->stop = el16_close; + dev->open = el16_open; + dev->stop = el16_close; dev->hard_start_xmit = el16_send_packet; dev->get_stats = el16_get_stats; dev->tx_timeout = el16_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; dev->ethtool_ops = &netdev_ethtool_ops; - - ether_setup(dev); /* Generic ethernet behaviour */ - - dev->flags&=~IFF_MULTICAST; /* Multicast doesn't work */ - + dev->flags &= ~IFF_MULTICAST; /* Multicast doesn't work */ return 0; out: release_region(ioaddr, EL16_IO_EXTENT); @@ -899,9 +915,7 @@ static struct ethtool_ops netdev_ethtool }; #ifdef MODULE -static struct net_device dev_3c507; -static int io = 0x300; -static int irq; +static struct net_device *dev_3c507; MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); MODULE_PARM_DESC(io, "EtherLink16 I/O base address"); @@ -911,26 +925,18 @@ int init_module(void) { if (io == 0) printk("3c507: You should not use auto-probing with insmod!\n"); - dev_3c507.base_addr = io; - dev_3c507.irq = irq; - dev_3c507.init = el16_probe; - if (register_netdev(&dev_3c507) != 0) { - printk("3c507: register_netdev() returned non-zero.\n"); - return -EIO; - } - return 0; + dev_3c507 = el16_probe(-1); + return IS_ERR(dev_3c507) ? PTR_ERR(dev_3c507) : 0; } void cleanup_module(void) { - unregister_netdev(&dev_3c507); - kfree(dev_3c507.priv); - dev_3c507.priv = NULL; - - /* If we don't do this, we can't re-insmod it later. */ - free_irq(dev_3c507.irq, &dev_3c507); - release_region(dev_3c507.base_addr, EL16_IO_EXTENT); + struct net_device *dev = dev_3c507; + unregister_netdev(dev); + free_irq(dev->irq, dev); + release_region(dev->base_addr, EL16_IO_EXTENT); + free_netdev(dev); } #endif /* MODULE */ MODULE_LICENSE("GPL"); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/3c515.c 830-ivtv/drivers/net/3c515.c --- 000-virgin/drivers/net/3c515.c Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/3c515.c Thu Jan 8 08:54:04 2004 @@ -307,7 +307,8 @@ struct boom_tx_desc { struct corkscrew_private { const char *product_name; - struct net_device *next_module; + struct list_head list; + struct net_device *our_dev; /* The Rx and Tx rings are here to keep them quad-word-aligned. */ struct boom_rx_desc rx_ring[RX_RING_SIZE]; struct boom_tx_desc tx_ring[TX_RING_SIZE]; @@ -329,6 +330,7 @@ struct corkscrew_private { full_bus_master_tx:1, full_bus_master_rx:1, /* Boomerang */ tx_full:1; spinlock_t lock; + struct device *dev; }; /* The action to take with a media selection timer tick. @@ -367,17 +369,12 @@ static struct isapnp_device_id corkscrew MODULE_DEVICE_TABLE(isapnp, corkscrew_isapnp_adapters); -static int corkscrew_isapnp_phys_addr[3]; - static int nopnp; #endif /* __ISAPNP__ */ -static int corkscrew_scan(struct net_device *dev); -static struct net_device *corkscrew_found_device(struct net_device *dev, - int ioaddr, int irq, - int product_index, - int options); -static int corkscrew_probe1(struct net_device *dev); +static struct net_device *corkscrew_scan(int unit); +static void corkscrew_setup(struct net_device *dev, int ioaddr, + struct pnp_dev *idev, int card_number); static int corkscrew_open(struct net_device *dev); static void corkscrew_timer(unsigned long arg); static int corkscrew_start_xmit(struct sk_buff *skb, @@ -413,47 +410,99 @@ static int options[MAX_UNITS] = { -1, -1 #ifdef MODULE static int debug = -1; /* A list of all installed Vortex devices, for removing the driver module. */ -static struct net_device *root_corkscrew_dev; +/* we will need locking (and refcounting) if we ever use it for more */ +static LIST_HEAD(root_corkscrew_dev); int init_module(void) { - int cards_found; - + int found = 0; if (debug >= 0) corkscrew_debug = debug; if (corkscrew_debug) printk(version); - - root_corkscrew_dev = NULL; - cards_found = corkscrew_scan(NULL); - return cards_found ? 0 : -ENODEV; + while (corkscrew_scan(-1)) + found++; + return found ? 0 : -ENODEV; } #else -int tc515_probe(struct net_device *dev) +struct net_device *tc515_probe(int unit) { - int cards_found = 0; + struct net_device *dev = corkscrew_scan(unit); + static int printed; - SET_MODULE_OWNER(dev); - - cards_found = corkscrew_scan(dev); + if (!dev) + return ERR_PTR(-ENODEV); - if (corkscrew_debug > 0 && cards_found) + if (corkscrew_debug > 0 && !printed) { + printed = 1; printk(version); + } - return cards_found ? 0 : -ENODEV; + return dev; } #endif /* not MODULE */ -static int corkscrew_scan(struct net_device *dev) +static int check_device(unsigned ioaddr) +{ + int timer; + + if (!request_region(ioaddr, CORKSCREW_TOTAL_SIZE, "3c515")) + return 0; + /* Check the resource configuration for a matching ioaddr. */ + if ((inw(ioaddr + 0x2002) & 0x1f0) != (ioaddr & 0x1f0)) { + release_region(ioaddr, CORKSCREW_TOTAL_SIZE); + return 0; + } + /* Verify by reading the device ID from the EEPROM. */ + outw(EEPROM_Read + 7, ioaddr + Wn0EepromCmd); + /* Pause for at least 162 us. for the read to take place. */ + for (timer = 4; timer >= 0; timer--) { + udelay(162); + if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) == 0) + break; + } + if (inw(ioaddr + Wn0EepromData) != 0x6d50) { + release_region(ioaddr, CORKSCREW_TOTAL_SIZE); + return 0; + } + return 1; +} + +static void cleanup_card(struct net_device *dev) +{ + struct corkscrew_private *vp = (struct corkscrew_private *) dev->priv; + list_del_init(&vp->list); + if (dev->dma) + free_dma(dev->dma); + outw(TotalReset, dev->base_addr + EL3_CMD); + release_region(dev->base_addr, CORKSCREW_TOTAL_SIZE); + if (vp->dev) + pnp_device_detach(to_pnp_dev(vp->dev)); +} + +static struct net_device *corkscrew_scan(int unit) { - int cards_found = 0; + struct net_device *dev; + static int cards_found = 0; static int ioaddr; + int err; #ifdef __ISAPNP__ short i; static int pnp_cards; #endif + dev = alloc_etherdev(sizeof(struct corkscrew_private)); + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } + + SET_MODULE_OWNER(dev); + #ifdef __ISAPNP__ if(nopnp == 1) goto no_pnp; @@ -470,7 +519,7 @@ static int corkscrew_scan(struct net_dev if (pnp_activate_dev(idev) < 0) { printk("pnp activate failed (out of resources?)\n"); pnp_device_detach(idev); - return -ENOMEM; + continue; } if (!pnp_port_valid(idev, 0) || !pnp_irq_valid(idev, 0)) { pnp_device_detach(idev); @@ -478,40 +527,22 @@ static int corkscrew_scan(struct net_dev } ioaddr = pnp_port_start(idev, 0); irq = pnp_irq(idev, 0); - if(corkscrew_debug) - printk ("ISAPNP reports %s at i/o 0x%x, irq %d\n", - (char*) corkscrew_isapnp_adapters[i].driver_data, ioaddr, irq); - - if ((inw(ioaddr + 0x2002) & 0x1f0) != (ioaddr & 0x1f0)) { + if (!check_device(ioaddr)) { pnp_device_detach(idev); continue; } - /* Verify by reading the device ID from the EEPROM. */ - { - int timer; - outw(EEPROM_Read + 7, ioaddr + Wn0EepromCmd); - /* Pause for at least 162 us. for the read to take place. */ - for (timer = 4; timer >= 0; timer--) { - udelay(162); - if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) - == 0) - break; - } - if (inw(ioaddr + Wn0EepromData) != 0x6d50) { - pnp_device_detach(idev); - continue; - } - } + if(corkscrew_debug) + printk ("ISAPNP reports %s at i/o 0x%x, irq %d\n", + (char*) corkscrew_isapnp_adapters[i].driver_data, ioaddr, irq); printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n", inl(ioaddr + 0x2002), inw(ioaddr + 0x2000)); /* irq = inw(ioaddr + 0x2002) & 15; */ /* Use the irq from isapnp */ - corkscrew_isapnp_phys_addr[pnp_cards] = ioaddr; - corkscrew_found_device(dev, ioaddr, irq, CORKSCREW_ID, dev - && dev->mem_start ? dev-> - mem_start : options[cards_found]); - dev = 0; + corkscrew_setup(dev, ioaddr, idev, cards_found++); pnp_cards++; - cards_found++; + err = register_netdev(dev); + if (!err) + return dev; + cleanup_card(dev); } } no_pnp: @@ -519,122 +550,64 @@ no_pnp: /* Check all locations on the ISA bus -- evil! */ for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20) { - int irq; -#ifdef __ISAPNP__ - /* Make sure this was not already picked up by isapnp */ - if(ioaddr == corkscrew_isapnp_phys_addr[0]) continue; - if(ioaddr == corkscrew_isapnp_phys_addr[1]) continue; - if(ioaddr == corkscrew_isapnp_phys_addr[2]) continue; -#endif /* __ISAPNP__ */ - if (check_region(ioaddr, CORKSCREW_TOTAL_SIZE)) - continue; - /* Check the resource configuration for a matching ioaddr. */ - if ((inw(ioaddr + 0x2002) & 0x1f0) != (ioaddr & 0x1f0)) + if (!check_device(ioaddr)) continue; - /* Verify by reading the device ID from the EEPROM. */ - { - int timer; - outw(EEPROM_Read + 7, ioaddr + Wn0EepromCmd); - /* Pause for at least 162 us. for the read to take place. */ - for (timer = 4; timer >= 0; timer--) { - udelay(162); - if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) - == 0) - break; - } - if (inw(ioaddr + Wn0EepromData) != 0x6d50) - continue; - } + printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n", inl(ioaddr + 0x2002), inw(ioaddr + 0x2000)); - irq = inw(ioaddr + 0x2002) & 15; - corkscrew_found_device(dev, ioaddr, irq, CORKSCREW_ID, - dev && dev->mem_start ? dev->mem_start : - (cards_found >= MAX_UNITS ? -1 : - options[cards_found])); - dev = 0; - cards_found++; + corkscrew_setup(dev, ioaddr, NULL, cards_found++); + err = register_netdev(dev); + if (!err) + return dev; + cleanup_card(dev); } - if (corkscrew_debug) - printk(KERN_INFO "%d 3c515 cards found.\n", cards_found); - return cards_found; + free_netdev(dev); + return NULL; } -static struct net_device *corkscrew_found_device(struct net_device *dev, - int ioaddr, int irq, - int product_index, - int options) +static void corkscrew_setup(struct net_device *dev, int ioaddr, + struct pnp_dev *idev, int card_number) { - struct corkscrew_private *vp; - -#ifdef MODULE - /* Allocate and fill new device structure. */ - int dev_size = sizeof(struct net_device) + sizeof(struct corkscrew_private) + 15; /* Pad for alignment */ + struct corkscrew_private *vp = (struct corkscrew_private *) dev->priv; + unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */ + int i; + int irq; - dev = (struct net_device *) kmalloc(dev_size, GFP_KERNEL); - if (!dev) - return NULL; - memset(dev, 0, dev_size); - /* Align the Rx and Tx ring entries. */ - dev->priv = (void *) (((long) dev + sizeof(struct net_device) + 15) & ~15); - vp = (struct corkscrew_private *) dev->priv; - dev->base_addr = ioaddr; - dev->irq = irq; - dev->dma = (product_index == CORKSCREW_ID ? inw(ioaddr + 0x2000) & 7 : 0); - dev->init = corkscrew_probe1; - vp->product_name = "3c515"; - vp->options = options; - if (options >= 0) { - vp->media_override = ((options & 7) == 2) ? 0 : options & 7; - vp->full_duplex = (options & 8) ? 1 : 0; - vp->bus_master = (options & 16) ? 1 : 0; + if (idev) { + irq = pnp_irq(idev, 0); + vp->dev = &idev->dev; } else { - vp->media_override = 7; - vp->full_duplex = 0; - vp->bus_master = 0; + irq = inw(ioaddr + 0x2002) & 15; } - ether_setup(dev); - vp->next_module = root_corkscrew_dev; - root_corkscrew_dev = dev; - SET_MODULE_OWNER(dev); - if (register_netdev(dev) != 0) { - kfree(dev); - return NULL; - } -#else /* not a MODULE */ - /* Caution: quad-word alignment required for rings! */ - dev->priv = kmalloc(sizeof(struct corkscrew_private), GFP_KERNEL); - if (!dev->priv) - return NULL; - memset(dev->priv, 0, sizeof(struct corkscrew_private)); - dev = init_etherdev(dev, sizeof(struct corkscrew_private)); + dev->base_addr = ioaddr; dev->irq = irq; - dev->dma = (product_index == CORKSCREW_ID ? inw(ioaddr + 0x2000) & 7 : 0); - vp = (struct corkscrew_private *) dev->priv; + dev->dma = inw(ioaddr + 0x2000) & 7; vp->product_name = "3c515"; - vp->options = options; - if (options >= 0) { - vp->media_override = ((options & 7) == 2) ? 0 : options & 7; - vp->full_duplex = (options & 8) ? 1 : 0; - vp->bus_master = (options & 16) ? 1 : 0; + vp->options = dev->mem_start; + vp->our_dev = dev; + + if (!vp->options) { + if (card_number >= MAX_UNITS) + vp->options = -1; + else + vp->options = options[card_number]; + } + + if (vp->options >= 0) { + vp->media_override = vp->options & 7; + if (vp->media_override == 2) + vp->media_override = 0; + vp->full_duplex = (vp->options & 8) ? 1 : 0; + vp->bus_master = (vp->options & 16) ? 1 : 0; } else { vp->media_override = 7; vp->full_duplex = 0; vp->bus_master = 0; } - - corkscrew_probe1(dev); -#endif /* MODULE */ - return dev; -} - -static int corkscrew_probe1(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - struct corkscrew_private *vp = (struct corkscrew_private *) dev->priv; - unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */ - int i; +#ifdef MODULE + list_add(&vp->list, &root_corkscrew_dev); +#endif printk(KERN_INFO "%s: 3Com %s at %#3x,", dev->name, vp->product_name, ioaddr); @@ -706,9 +679,6 @@ static int corkscrew_probe1(struct net_d /* vp->full_bus_master_rx = 0; */ vp->full_bus_master_rx = (vp->capabilities & 0x20) ? 1 : 0; - /* We do a request_region() to register /proc/ioports info. */ - request_region(ioaddr, CORKSCREW_TOTAL_SIZE, vp->product_name); - /* The 3c51x-specific entries in the device structure. */ dev->open = &corkscrew_open; dev->hard_start_xmit = &corkscrew_start_xmit; @@ -718,8 +688,6 @@ static int corkscrew_probe1(struct net_d dev->get_stats = &corkscrew_get_stats; dev->set_multicast_list = &set_rx_mode; dev->ethtool_ops = &netdev_ethtool_ops; - - return 0; } @@ -1607,20 +1575,16 @@ static struct ethtool_ops netdev_ethtool #ifdef MODULE void cleanup_module(void) { - struct net_device *next_dev; - - while (root_corkscrew_dev) { - next_dev = - ((struct corkscrew_private *) root_corkscrew_dev-> - priv)->next_module; - if (root_corkscrew_dev->dma) - free_dma(root_corkscrew_dev->dma); - unregister_netdev(root_corkscrew_dev); - outw(TotalReset, root_corkscrew_dev->base_addr + EL3_CMD); - release_region(root_corkscrew_dev->base_addr, - CORKSCREW_TOTAL_SIZE); - free_netdev(root_corkscrew_dev); - root_corkscrew_dev = next_dev; + while (!list_empty(&root_corkscrew_dev)) { + struct net_device *dev; + struct corkscrew_private *vp; + + vp = list_entry(root_corkscrew_dev.next, + struct corkscrew_private, list); + dev = vp->our_dev; + unregister_netdev(dev); + cleanup_card(dev); + free_netdev(dev); } } #endif /* MODULE */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/3c523.c 830-ivtv/drivers/net/3c523.c --- 000-virgin/drivers/net/3c523.c Mon Nov 17 18:29:30 2003 +++ 830-ivtv/drivers/net/3c523.c Thu Jan 8 08:54:04 2004 @@ -410,7 +410,7 @@ static int elmc_getinfo(char *buf, int s /*****************************************************************/ -int __init elmc_probe(struct net_device *dev) +static int __init do_elmc_probe(struct net_device *dev) { static int slot; int base_addr = dev->base_addr; @@ -420,7 +420,7 @@ int __init elmc_probe(struct net_device int i = 0; unsigned int size = 0; int retval; - struct priv *pr; + struct priv *pr = dev->priv; SET_MODULE_OWNER(dev); if (MCA_bus == 0) { @@ -455,10 +455,9 @@ int __init elmc_probe(struct net_device } /* we didn't find any 3c523 in the slots we checked for */ - if (slot == MCA_NOTFOUND) { - retval = ((base_addr || irq) ? -ENXIO : -ENODEV); - goto err_out; - } + if (slot == MCA_NOTFOUND) + return ((base_addr || irq) ? -ENXIO : -ENODEV); + mca_set_adapter_name(slot, "3Com 3c523 Etherlink/MC"); mca_set_adapter_procfn(slot, (MCA_ProcFn) elmc_getinfo, dev); @@ -497,13 +496,7 @@ int __init elmc_probe(struct net_device break; } - pr = dev->priv = kmalloc(sizeof(struct priv), GFP_KERNEL); - if (dev->priv == NULL) { - retval = -ENOMEM; - goto err_out; - } memset(pr, 0, sizeof(struct priv)); - pr->slot = slot; printk(KERN_INFO "%s: 3Com 3c523 Rev 0x%x at %#lx\n", dev->name, (int) revision, @@ -530,8 +523,6 @@ int __init elmc_probe(struct net_device if (!check586(dev, dev->mem_start, size)) { printk(KERN_ERR "%s: memprobe, Can't find memory at 0x%lx!\n", dev->name, dev->mem_start); - kfree(dev->priv); - dev->priv = NULL; retval = -ENODEV; goto err_out; } @@ -573,8 +564,6 @@ int __init elmc_probe(struct net_device #endif dev->ethtool_ops = &netdev_ethtool_ops; - ether_setup(dev); - /* note that we haven't actually requested the IRQ from the kernel. That gets done in elmc_open(). I'm not sure that's such a good idea, but it works, so I'll go with it. */ @@ -585,9 +574,41 @@ int __init elmc_probe(struct net_device return 0; err_out: + mca_set_adapter_procfn(slot, NULL, NULL); release_region(dev->base_addr, ELMC_IO_EXTENT); return retval; } + +static void cleanup_card(struct net_device *dev) +{ + mca_set_adapter_procfn(((struct priv *) (dev->priv))->slot, NULL, NULL); + release_region(dev->base_addr, ELMC_IO_EXTENT); +} + +struct net_device * __init elmc_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct priv)); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_elmc_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} /********************************************** * init the chip (elmc-interrupt should be disabled?!) @@ -1245,7 +1266,7 @@ static struct ethtool_ops netdev_ethtool /* Increase if needed ;) */ #define MAX_3C523_CARDS 4 -static struct net_device dev_elmc[MAX_3C523_CARDS]; +static struct net_device *dev_elmc[MAX_3C523_CARDS]; static int irq[MAX_3C523_CARDS]; static int io[MAX_3C523_CARDS]; MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_3C523_CARDS) "i"); @@ -1258,16 +1279,24 @@ int init_module(void) int this_dev,found = 0; /* Loop until we either can't find any more cards, or we have MAX_3C523_CARDS */ - for(this_dev=0; this_devirq=irq[this_dev]; dev->base_addr=io[this_dev]; - dev->init=elmc_probe; - if(register_netdev(dev)!=0) { - if(io[this_dev]==0) break; - printk(KERN_WARNING "3c523.c: No 3c523 card found at io=%#x\n",io[this_dev]); - } else found++; + if (do_elmc_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_elmc[this_dev] = dev; + found++; + continue; + } + cleanup_card(dev); + } + free_netdev(dev); + if (io[this_dev]==0) + break; + printk(KERN_WARNING "3c523.c: No 3c523 card found at io=%#x\n",io[this_dev]); } if(found==0) { @@ -1279,31 +1308,12 @@ int init_module(void) void cleanup_module(void) { int this_dev; - for(this_dev=0; this_devpriv) { - /* shutdown interrupts on the card */ - elmc_id_reset586(); - if (dev->irq != 0) { - /* this should be done by close, but if we failed to - initialize properly something may have gotten hosed. */ - free_irq(dev->irq, dev); - dev->irq = 0; - } - if (dev->base_addr != 0) { - release_region(dev->base_addr, ELMC_IO_EXTENT); - dev->base_addr = 0; - } - irq[this_dev] = 0; - io[this_dev] = 0; + for (this_dev=0; this_devpriv))->slot, - NULL, NULL); - - kfree(dev->priv); - dev->priv = NULL; + cleanup_card(dev); + free_netdev(dev); } } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/3c527.c 830-ivtv/drivers/net/3c527.c --- 000-virgin/drivers/net/3c527.c Mon Dec 8 09:55:51 2003 +++ 830-ivtv/drivers/net/3c527.c Thu Jan 8 08:54:04 2004 @@ -1,9 +1,10 @@ -/* 3c527.c: 3Com Etherlink/MC32 driver for Linux 2.4 +/* 3c527.c: 3Com Etherlink/MC32 driver for Linux 2.4 and 2.6. * * (c) Copyright 1998 Red Hat Software Inc * Written by Alan Cox. * Further debugging by Carl Drougge. - * Modified by Richard Procter (rnp@netlink.co.nz) + * Initial SMP support by Felipe W Damasio + * Heavily modified by Richard Procter * * Based on skeleton.c written 1993-94 by Donald Becker and ne2.c * (for the MCA stuff) written by Wim Dumon. @@ -17,11 +18,11 @@ */ #define DRV_NAME "3c527" -#define DRV_VERSION "0.6a" -#define DRV_RELDATE "2001/11/17" +#define DRV_VERSION "0.7-SMP" +#define DRV_RELDATE "2003/09/21" static const char *version = -DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Richard Proctor (rnp@netlink.co.nz)\n"; +DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Richard Procter \n"; /** * DOC: Traps for the unwary @@ -100,7 +101,9 @@ DRV_NAME ".c:v" DRV_VERSION " " DRV_RELD #include #include #include +#include +#include #include #include #include @@ -143,19 +146,19 @@ static unsigned int mc32_debug = NET_DEB static const int WORKAROUND_82586=1; /* Pointers to buffers and their on-card records */ - struct mc32_ring_desc { volatile struct skb_header *p; struct sk_buff *skb; }; - /* Information that needs to be kept for each board. */ struct mc32_local { - struct net_device_stats net_stats; int slot; + + u32 base; + struct net_device_stats net_stats; volatile struct mc32_mailbox *rx_box; volatile struct mc32_mailbox *tx_box; volatile struct mc32_mailbox *exec_box; @@ -165,22 +168,23 @@ struct mc32_local u16 tx_len; /* Transmit list count */ u16 rx_len; /* Receive list count */ - u32 base; - u16 exec_pending; - u16 mc_reload_wait; /* a multicast load request is pending */ + u16 xceiver_desired_state; /* HALTED or RUNNING */ + u16 cmd_nonblocking; /* Thread is uninterested in command result */ + u16 mc_reload_wait; /* A multicast load request is pending */ u32 mc_list_valid; /* True when the mclist is set */ - u16 xceiver_state; /* Current transceiver state. bitmapped */ - u16 desired_state; /* The state we want the transceiver to be in */ - atomic_t tx_count; /* buffers left */ - wait_queue_head_t event; struct mc32_ring_desc tx_ring[TX_RING_LEN]; /* Host Transmit ring */ struct mc32_ring_desc rx_ring[RX_RING_LEN]; /* Host Receive ring */ + atomic_t tx_count; /* buffers left */ + atomic_t tx_ring_head; /* index to tx en-queue end */ u16 tx_ring_tail; /* index to tx de-queue end */ - u16 tx_ring_head; /* index to tx en-queue end */ u16 rx_ring_tail; /* index to rx de-queue end */ + + struct semaphore cmd_mutex; /* Serialises issuing of execute commands */ + struct completion execution_cmd; /* Card has completed an execute command */ + struct completion xceiver_cmd; /* Card has completed a tx or rx command */ }; /* The station (ethernet) address prefix, used for a sanity check. */ @@ -208,8 +212,6 @@ static inline u16 next_tx(u16 tx) { retu /* Index to functions, as function prototypes. */ -extern int mc32_probe(struct net_device *dev); - static int mc32_probe1(struct net_device *dev, int ioaddr); static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len); static int mc32_open(struct net_device *dev); @@ -222,9 +224,19 @@ static void mc32_set_multicast_list(stru static void mc32_reset_multicast_list(struct net_device *dev); static struct ethtool_ops netdev_ethtool_ops; +static void cleanup_card(struct net_device *dev) +{ + struct mc32_local *lp=dev->priv; + unsigned slot = lp->slot; + mca_mark_as_unused(slot); + mca_set_adapter_name(slot, NULL); + free_irq(dev->irq, dev); + release_region(dev->base_addr, MC32_IO_EXTENT); +} + /** * mc32_probe - Search for supported boards - * @dev: device to probe + * @unit: interface number to use * * Because MCA bus is a real bus and we can scan for cards we could do a * single scan for all boards here. Right now we use the passed in device @@ -232,11 +244,18 @@ static struct ethtool_ops netdev_ethtool * in particular. */ -int __init mc32_probe(struct net_device *dev) +struct net_device *__init mc32_probe(int unit) { + struct net_device *dev = alloc_etherdev(sizeof(struct mc32_local)); static int current_mca_slot = -1; int i; - int adapter_found = 0; + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) + sprintf(dev->name, "eth%d", unit); SET_MODULE_OWNER(dev); @@ -247,22 +266,28 @@ int __init mc32_probe(struct net_device Autodetecting MCA cards is extremely simple. Just search for the card. */ - for(i = 0; (mc32_adapters[i].name != NULL) && !adapter_found; i++) { + for(i = 0; (mc32_adapters[i].name != NULL); i++) { current_mca_slot = mca_find_unused_adapter(mc32_adapters[i].id, 0); - if((current_mca_slot != MCA_NOTFOUND) && !adapter_found) { + if(current_mca_slot != MCA_NOTFOUND) { if(!mc32_probe1(dev, current_mca_slot)) { mca_set_adapter_name(current_mca_slot, mc32_adapters[i].name); mca_mark_as_used(current_mca_slot); - return 0; + err = register_netdev(dev); + if (err) { + cleanup_card(dev); + free_netdev(dev); + dev = ERR_PTR(err); + } + return dev; } } } - return -ENODEV; + return ERR_PTR(-ENODEV); } /** @@ -282,7 +307,7 @@ static int __init mc32_probe1(struct net int i, err; u8 POS; u32 base; - struct mc32_local *lp; + struct mc32_local *lp = dev->priv; static u16 mca_io_bases[]={ 0x7280,0x7290, 0x7680,0x7690, @@ -409,24 +434,14 @@ static int __init mc32_probe1(struct net * Grab the IRQ */ - i = request_irq(dev->irq, &mc32_interrupt, SA_SHIRQ, dev->name, dev); - if (i) { + err = request_irq(dev->irq, &mc32_interrupt, SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev); + if (err) { release_region(dev->base_addr, MC32_IO_EXTENT); printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq); - return i; + goto err_exit_ports; } - - /* Initialize the device structure. */ - dev->priv = kmalloc(sizeof(struct mc32_local), GFP_KERNEL); - if (dev->priv == NULL) - { - err = -ENOMEM; - goto err_exit_irq; - } - - memset(dev->priv, 0, sizeof(struct mc32_local)); - lp = dev->priv; + memset(lp, 0, sizeof(struct mc32_local)); lp->slot = slot; i=0; @@ -440,7 +455,7 @@ static int __init mc32_probe1(struct net { printk(KERN_ERR "%s: failed to boot adapter.\n", dev->name); err = -ENODEV; - goto err_exit_free; + goto err_exit_irq; } udelay(1000); if(inb(dev->base_addr+2)&(1<<5)) @@ -455,7 +470,7 @@ static int __init mc32_probe1(struct net else printk(KERN_ERR "%s: unknown failure %d.\n", dev->name, base); err = -ENODEV; - goto err_exit_free; + goto err_exit_irq; } base=0; @@ -471,7 +486,7 @@ static int __init mc32_probe1(struct net { printk(KERN_ERR "%s: mailbox read fail (%d).\n", dev->name, i); err = -ENODEV; - goto err_exit_free; + goto err_exit_irq; } } @@ -498,7 +513,9 @@ static int __init mc32_probe1(struct net lp->tx_len = lp->exec_box->data[9]; /* Transmit list count */ lp->rx_len = lp->exec_box->data[11]; /* Receive list count */ - init_waitqueue_head(&lp->event); + init_MUTEX_LOCKED(&lp->cmd_mutex); + init_completion(&lp->execution_cmd); + init_completion(&lp->xceiver_cmd); printk("%s: Firmware Rev %d. %d RX buffers, %d TX buffers. Base of 0x%08X.\n", dev->name, lp->exec_box->data[12], lp->rx_len, lp->tx_len, lp->base); @@ -511,20 +528,12 @@ static int __init mc32_probe1(struct net dev->tx_timeout = mc32_timeout; dev->watchdog_timeo = HZ*5; /* Board does all the work */ dev->ethtool_ops = &netdev_ethtool_ops; - - lp->xceiver_state = HALTED; - - lp->tx_ring_tail=lp->tx_ring_head=0; - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - return 0; -err_exit_free: - kfree(dev->priv); err_exit_irq: free_irq(dev->irq, dev); +err_exit_ports: release_region(dev->base_addr, MC32_IO_EXTENT); return err; } @@ -539,7 +548,7 @@ err_exit_irq: * status of any pending commands and takes very little time at all. */ -static void mc32_ready_poll(struct net_device *dev) +static inline void mc32_ready_poll(struct net_device *dev) { int ioaddr = dev->base_addr; while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); @@ -554,31 +563,38 @@ static void mc32_ready_poll(struct net_d * @len: Length of the data block * * Send a command from interrupt state. If there is a command - * currently being executed then we return an error of -1. It simply - * isn't viable to wait around as commands may be slow. Providing we - * get in, we busy wait for the board to become ready to accept the - * command and issue it. We do not wait for the command to complete - * --- the card will interrupt us when it's done. + * currently being executed then we return an error of -1. It + * simply isn't viable to wait around as commands may be + * slow. This can theoretically be starved on SMP, but it's hard + * to see a realistic situation. We do not wait for the command + * to complete --- we rely on the interrupt handler to tidy up + * after us. */ static int mc32_command_nowait(struct net_device *dev, u16 cmd, void *data, int len) { struct mc32_local *lp = (struct mc32_local *)dev->priv; int ioaddr = dev->base_addr; + int ret = -1; - if(lp->exec_pending) - return -1; - - lp->exec_pending=3; - lp->exec_box->mbox=0; - lp->exec_box->mbox=cmd; - memcpy((void *)lp->exec_box->data, data, len); - barrier(); /* the memcpy forgot the volatile so be sure */ + if (down_trylock(&lp->cmd_mutex) == 0) + { + lp->cmd_nonblocking=1; + lp->exec_box->mbox=0; + lp->exec_box->mbox=cmd; + memcpy((void *)lp->exec_box->data, data, len); + barrier(); /* the memcpy forgot the volatile so be sure */ + + /* Send the command */ + mc32_ready_poll(dev); + outb(1<<6, ioaddr+HOST_CMD); - /* Send the command */ - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - outb(1<<6, ioaddr+HOST_CMD); - return 0; + ret = 0; + + /* Interrupt handler will signal mutex on completion */ + } + + return ret; } @@ -592,76 +608,47 @@ static int mc32_command_nowait(struct ne * Sends exec commands in a user context. This permits us to wait around * for the replies and also to wait for the command buffer to complete * from a previous command before we execute our command. After our - * command completes we will complete any pending multicast reload + * command completes we will attempt any pending multicast reload * we blocked off by hogging the exec buffer. * * You feed the card a command, you wait, it interrupts you get a * reply. All well and good. The complication arises because you use * commands for filter list changes which come in at bh level from things * like IPV6 group stuff. - * - * We have a simple state machine - * - * 0 - nothing issued - * - * 1 - command issued, wait reply - * - * 2 - reply waiting - reader then goes to state 0 - * - * 3 - command issued, trash reply. In which case the irq - * takes it back to state 0 - * */ static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len) { struct mc32_local *lp = (struct mc32_local *)dev->priv; int ioaddr = dev->base_addr; - unsigned long flags; int ret = 0; + down(&lp->cmd_mutex); + /* - * Wait for a command - */ - - save_flags(flags); - cli(); - - while(lp->exec_pending) - sleep_on(&lp->event); - - /* - * Issue mine + * My Turn */ - lp->exec_pending=1; - - restore_flags(flags); - + lp->cmd_nonblocking=0; lp->exec_box->mbox=0; lp->exec_box->mbox=cmd; memcpy((void *)lp->exec_box->data, data, len); barrier(); /* the memcpy forgot the volatile so be sure */ - /* Send the command */ - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - outb(1<<6, ioaddr+HOST_CMD); + mc32_ready_poll(dev); + outb(1<<6, ioaddr+HOST_CMD); - save_flags(flags); - cli(); - - while(lp->exec_pending!=2) - sleep_on(&lp->event); - lp->exec_pending=0; - restore_flags(flags); + wait_for_completion(&lp->execution_cmd); if(lp->exec_box->mbox&(1<<13)) ret = -1; + up(&lp->cmd_mutex); + /* - * A multicast set got blocked - do it now - */ - + * A multicast set got blocked - try it now + */ + if(lp->mc_reload_wait) { mc32_reset_multicast_list(dev); @@ -678,11 +665,9 @@ static int mc32_command(struct net_devic * This may be called from the interrupt state, where it is used * to restart the rx ring if the card runs out of rx buffers. * - * First, we check if it's ok to start the transceiver. We then show - * the card where to start in the rx ring and issue the - * commands to start reception and transmission. We don't wait - * around for these to complete. - */ + * We must first check if it's ok to (re)start the transceiver. See + * mc32_close for details. + */ static void mc32_start_transceiver(struct net_device *dev) { @@ -690,24 +675,20 @@ static void mc32_start_transceiver(struc int ioaddr = dev->base_addr; /* Ignore RX overflow on device closure */ - if (lp->desired_state==HALTED) + if (lp->xceiver_desired_state==HALTED) return; + /* Give the card the offset to the post-EOL-bit RX descriptor */ mc32_ready_poll(dev); - - lp->tx_box->mbox=0; lp->rx_box->mbox=0; - - /* Give the card the offset to the post-EOL-bit RX descriptor */ lp->rx_box->data[0]=lp->rx_ring[prev_rx(lp->rx_ring_tail)].p->next; - outb(HOST_CMD_START_RX, ioaddr+HOST_CMD); mc32_ready_poll(dev); + lp->tx_box->mbox=0; outb(HOST_CMD_RESTRT_TX, ioaddr+HOST_CMD); /* card ignores this on RX restart */ /* We are not interrupted on start completion */ - lp->xceiver_state=RUNNING; } @@ -727,25 +708,17 @@ static void mc32_halt_transceiver(struct { struct mc32_local *lp = (struct mc32_local *)dev->priv; int ioaddr = dev->base_addr; - unsigned long flags; mc32_ready_poll(dev); - - lp->tx_box->mbox=0; lp->rx_box->mbox=0; - outb(HOST_CMD_SUSPND_RX, ioaddr+HOST_CMD); + wait_for_completion(&lp->xceiver_cmd); + mc32_ready_poll(dev); + lp->tx_box->mbox=0; outb(HOST_CMD_SUSPND_TX, ioaddr+HOST_CMD); - - save_flags(flags); - cli(); - - while(lp->xceiver_state!=HALTED) - sleep_on(&lp->event); - - restore_flags(flags); -} + wait_for_completion(&lp->xceiver_cmd); +} /** @@ -756,7 +729,7 @@ static void mc32_halt_transceiver(struct * the point where mc32_start_transceiver() can be called. * * The card sets up the receive ring for us. We are required to use the - * ring it provides although we can change the size of the ring. + * ring it provides, although the size of the ring is configurable. * * We allocate an sk_buff for each ring entry in turn and * initalise its house-keeping info. At the same time, we read @@ -777,7 +750,7 @@ static int mc32_load_rx_ring(struct net_ rx_base=lp->rx_chain; - for(i=0;irx_ring[i].skb=alloc_skb(1532, GFP_KERNEL); skb_reserve(lp->rx_ring[i].skb, 18); @@ -814,21 +787,19 @@ static int mc32_load_rx_ring(struct net_ * * Free the buffer for each ring slot. This may be called * before mc32_load_rx_ring(), eg. on error in mc32_open(). + * Requires rx skb pointers to point to a valid skb, or NULL. */ static void mc32_flush_rx_ring(struct net_device *dev) { struct mc32_local *lp = (struct mc32_local *)dev->priv; - - struct sk_buff *skb; int i; for(i=0; i < RX_RING_LEN; i++) { - skb = lp->rx_ring[i].skb; - if (skb!=NULL) { - kfree_skb(skb); - skb=NULL; + if (lp->rx_ring[i].skb) { + dev_kfree_skb(lp->rx_ring[i].skb); + lp->rx_ring[i].skb = NULL; } lp->rx_ring[i].p=NULL; } @@ -860,7 +831,7 @@ static void mc32_load_tx_ring(struct net tx_base=lp->tx_box->data[0]; - for(i=0;itx_len;i++) + for(i=0 ; ibase+tx_base); lp->tx_ring[i].p=p; @@ -869,11 +840,12 @@ static void mc32_load_tx_ring(struct net tx_base=p->next; } - /* -1 so that tx_ring_head cannot "lap" tx_ring_tail, */ - /* which would be bad news for mc32_tx_ring as cur. implemented */ + /* -1 so that tx_ring_head cannot "lap" tx_ring_tail */ + /* see mc32_tx_ring */ atomic_set(&lp->tx_count, TX_RING_LEN-1); - lp->tx_ring_head=lp->tx_ring_tail=0; + atomic_set(&lp->tx_ring_head, 0); + lp->tx_ring_tail=0; } @@ -881,47 +853,29 @@ static void mc32_load_tx_ring(struct net * mc32_flush_tx_ring - free transmit ring * @lp: Local data of 3c527 to flush the tx ring of * - * We have to consider two cases here. We want to free the pending - * buffers only. If the ring buffer head is past the start then the - * ring segment we wish to free wraps through zero. The tx ring - * house-keeping variables are then reset. + * If the ring is non-empty, zip over the it, freeing any + * allocated skb_buffs. The tx ring house-keeping variables are + * then reset. Requires rx skb pointers to point to a valid skb, + * or NULL. */ static void mc32_flush_tx_ring(struct net_device *dev) { struct mc32_local *lp = (struct mc32_local *)dev->priv; - - if(lp->tx_ring_tail!=lp->tx_ring_head) + int i; + + for (i=0; i < TX_RING_LEN; i++) { - int i; - if(lp->tx_ring_tail < lp->tx_ring_head) + if (lp->tx_ring[i].skb) { - for(i=lp->tx_ring_tail;itx_ring_head;i++) - { - dev_kfree_skb(lp->tx_ring[i].skb); - lp->tx_ring[i].skb=NULL; - lp->tx_ring[i].p=NULL; - } - } - else - { - for(i=lp->tx_ring_tail; itx_ring[i].skb); - lp->tx_ring[i].skb=NULL; - lp->tx_ring[i].p=NULL; - } - for(i=0; itx_ring_head; i++) - { - dev_kfree_skb(lp->tx_ring[i].skb); - lp->tx_ring[i].skb=NULL; - lp->tx_ring[i].p=NULL; - } + dev_kfree_skb(lp->tx_ring[i].skb); + lp->tx_ring[i].skb = NULL; } } - + atomic_set(&lp->tx_count, 0); - lp->tx_ring_tail=lp->tx_ring_head=0; + atomic_set(&lp->tx_ring_head, 0); + lp->tx_ring_tail=0; } @@ -958,6 +912,12 @@ static int mc32_open(struct net_device * regs|=HOST_CTRL_INTE; outb(regs, ioaddr+HOST_CTRL); + /* + * Allow ourselves to issue commands + */ + + up(&lp->cmd_mutex); + /* * Send the indications on command @@ -1010,7 +970,7 @@ static int mc32_open(struct net_device * return -ENOBUFS; } - lp->desired_state = RUNNING; + lp->xceiver_desired_state = RUNNING; /* And finally, set the ball rolling... */ mc32_start_transceiver(dev); @@ -1047,61 +1007,64 @@ static void mc32_timeout(struct net_devi * Transmit a buffer. This normally means throwing the buffer onto * the transmit queue as the queue is quite large. If the queue is * full then we set tx_busy and return. Once the interrupt handler - * gets messages telling it to reclaim transmit queue entries we will + * gets messages telling it to reclaim transmit queue entries, we will * clear tx_busy and the kernel will start calling this again. * - * We use cli rather than spinlocks. Since I have no access to an SMP - * MCA machine I don't plan to change it. It is probably the top - * performance hit for this driver on SMP however. + * We do not disable interrupts or acquire any locks; this can + * run concurrently with mc32_tx_ring(), and the function itself + * is serialised at a higher layer. However, similarly for the + * card itself, we must ensure that we update tx_ring_head only + * after we've established a valid packet on the tx ring (and + * before we let the card "see" it, to prevent it racing with the + * irq handler). + * */ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev) { struct mc32_local *lp = (struct mc32_local *)dev->priv; - unsigned long flags; - + u32 head = atomic_read(&lp->tx_ring_head); + volatile struct skb_header *p, *np; netif_stop_queue(dev); - save_flags(flags); - cli(); - - if(atomic_read(&lp->tx_count)==0) - { - restore_flags(flags); + if(atomic_read(&lp->tx_count)==0) { return 1; } + skb = skb_padto(skb, ETH_ZLEN); + if (skb == NULL) { + netif_wake_queue(dev); + return 0; + } + atomic_dec(&lp->tx_count); /* P is the last sending/sent buffer as a pointer */ - p=lp->tx_ring[lp->tx_ring_head].p; + p=lp->tx_ring[head].p; - lp->tx_ring_head=next_tx(lp->tx_ring_head); + head = next_tx(head); /* NP is the buffer we will be loading */ - np=lp->tx_ring[lp->tx_ring_head].p; - - if (skb->len < ETH_ZLEN) { - skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) - goto out; - } - + np=lp->tx_ring[head].p; + /* We will need this to flush the buffer out */ - lp->tx_ring[lp->tx_ring_head].skb = skb; - - np->length = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; - + lp->tx_ring[head].skb=skb; + + np->length = unlikely(skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; np->data = isa_virt_to_bus(skb->data); np->status = 0; np->control = CONTROL_EOP | CONTROL_EOL; wmb(); - p->control &= ~CONTROL_EOL; /* Clear EOL on p */ -out: - restore_flags(flags); + /* + * The new frame has been setup; we can now + * let the interrupt handler and card "see" it + */ + + atomic_set(&lp->tx_ring_head, head); + p->control &= ~CONTROL_EOL; netif_wake_queue(dev); return 0; @@ -1182,10 +1145,11 @@ static void mc32_rx_ring(struct net_devi { struct mc32_local *lp=dev->priv; volatile struct skb_header *p; - u16 rx_ring_tail = lp->rx_ring_tail; - u16 rx_old_tail = rx_ring_tail; - + u16 rx_ring_tail; + u16 rx_old_tail; int x=0; + + rx_old_tail = rx_ring_tail = lp->rx_ring_tail; do { @@ -1275,9 +1239,14 @@ static void mc32_tx_ring(struct net_devi struct mc32_local *lp=(struct mc32_local *)dev->priv; volatile struct skb_header *np; - /* NB: lp->tx_count=TX_RING_LEN-1 so that tx_ring_head cannot "lap" tail here */ + /* + * We rely on head==tail to mean 'queue empty'. + * This is why lp->tx_count=TX_RING_LEN-1: in order to prevent + * tx_ring_head wrapping to tail and confusing a 'queue empty' + * condition with 'queue full' + */ - while (lp->tx_ring_tail != lp->tx_ring_head) + while (lp->tx_ring_tail != atomic_read(&lp->tx_ring_head)) { u16 t; @@ -1388,8 +1357,7 @@ static irqreturn_t mc32_interrupt(int ir break; case 3: /* Halt */ case 4: /* Abort */ - lp->xceiver_state |= TX_HALTED; - wake_up(&lp->event); + complete(&lp->xceiver_cmd); break; default: printk("%s: strange tx ack %d\n", dev->name, status&7); @@ -1404,8 +1372,7 @@ static irqreturn_t mc32_interrupt(int ir break; case 3: /* Halt */ case 4: /* Abort */ - lp->xceiver_state |= RX_HALTED; - wake_up(&lp->event); + complete(&lp->xceiver_cmd); break; case 6: /* Out of RX buffers stat */ @@ -1421,26 +1388,17 @@ static irqreturn_t mc32_interrupt(int ir status>>=3; if(status&1) { - - /* 0=no 1=yes 2=replied, get cmd, 3 = wait reply & dump it */ - - if(lp->exec_pending!=3) { - lp->exec_pending=2; - wake_up(&lp->event); - } - else - { - lp->exec_pending=0; - - /* A new multicast set may have been - blocked while the old one was - running. If so, do it now. */ + /* + * No thread is waiting: we need to tidy + * up ourself. + */ + if (lp->cmd_nonblocking) { + up(&lp->cmd_mutex); if (lp->mc_reload_wait) mc32_reset_multicast_list(dev); - else - wake_up(&lp->event); } + else complete(&lp->execution_cmd); } if(status&2) { @@ -1493,12 +1451,12 @@ static irqreturn_t mc32_interrupt(int ir static int mc32_close(struct net_device *dev) { struct mc32_local *lp = (struct mc32_local *)dev->priv; - int ioaddr = dev->base_addr; + u8 regs; u16 one=1; - lp->desired_state = HALTED; + lp->xceiver_desired_state = HALTED; netif_stop_queue(dev); /* @@ -1511,11 +1469,10 @@ static int mc32_close(struct net_device mc32_halt_transceiver(dev); - /* Catch any waiting commands */ + /* Ensure we issue no more commands beyond this point */ + + down(&lp->cmd_mutex); - while(lp->exec_pending==1) - sleep_on(&lp->event); - /* Ok the card is now stopping */ regs=inb(ioaddr+HOST_CTRL); @@ -1542,12 +1499,9 @@ static int mc32_close(struct net_device static struct net_device_stats *mc32_get_stats(struct net_device *dev) { - struct mc32_local *lp; + struct mc32_local *lp = (struct mc32_local *)dev->priv; mc32_update_stats(dev); - - lp = (struct mc32_local *)dev->priv; - return &lp->net_stats; } @@ -1684,7 +1638,7 @@ static struct ethtool_ops netdev_ethtool #ifdef MODULE -static struct net_device this_device; +static struct net_device *this_device; /** * init_module - entry point @@ -1696,12 +1650,9 @@ static struct net_device this_device; int init_module(void) { - int result; - - this_device.init = mc32_probe; - if ((result = register_netdev(&this_device)) != 0) - return result; - + this_device = mc32_probe(-1); + if (IS_ERR(this_device)) + return PTR_ERR(this_device); return 0; } @@ -1718,24 +1669,9 @@ int init_module(void) void cleanup_module(void) { - int slot; - - unregister_netdev(&this_device); - - /* - * If we don't do this, we can't re-insmod it later. - */ - - if (this_device.priv) - { - struct mc32_local *lp=this_device.priv; - slot = lp->slot; - mca_mark_as_unused(slot); - mca_set_adapter_name(slot, NULL); - kfree(this_device.priv); - } - free_irq(this_device.irq, &this_device); - release_region(this_device.base_addr, MC32_IO_EXTENT); + unregister_netdev(this_device); + cleanup_card(this_device); + free_netdev(this_device); } #endif /* MODULE */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/3c527.h 830-ivtv/drivers/net/3c527.h --- 000-virgin/drivers/net/3c527.h Sun Nov 17 20:29:22 2002 +++ 830-ivtv/drivers/net/3c527.h Thu Jan 8 08:54:04 2004 @@ -27,10 +27,8 @@ #define HOST_RAMPAGE 8 -#define RX_HALTED (1<<0) -#define TX_HALTED (1<<1) -#define HALTED (RX_HALTED | TX_HALTED) -#define RUNNING 0 +#define HALTED 0 +#define RUNNING 1 struct mc32_mailbox { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/3c59x.c 830-ivtv/drivers/net/3c59x.c --- 000-virgin/drivers/net/3c59x.c Mon Nov 17 18:28:14 2003 +++ 830-ivtv/drivers/net/3c59x.c Thu Jan 8 08:54:06 2004 @@ -920,6 +920,18 @@ static struct net_device *compaq_net_dev static int vortex_cards_found; +#ifdef CONFIG_NET_POLL_CONTROLLER +static void poll_vortex(struct net_device *dev) +{ + struct vortex_private *vp = (struct vortex_private *)dev->priv; + unsigned long flags; + local_save_flags(flags); + local_irq_disable(); + (vp->full_bus_master_rx ? boomerang_interrupt:vortex_interrupt)(dev->irq,dev,NULL); + local_irq_restore(flags); +} +#endif + #ifdef CONFIG_PM static int vortex_suspend (struct pci_dev *pdev, u32 state) @@ -1450,6 +1462,9 @@ static int __devinit vortex_probe1(struc dev->set_multicast_list = set_rx_mode; dev->tx_timeout = vortex_tx_timeout; dev->watchdog_timeo = (watchdog * HZ) / 1000; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = poll_vortex; +#endif if (pdev) { vp->pm_state_valid = 1; pci_save_state(VORTEX_PCI(vp), vp->power_state); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/68360enet.c 830-ivtv/drivers/net/68360enet.c --- 000-virgin/drivers/net/68360enet.c Sat May 10 18:34:40 2003 +++ 830-ivtv/drivers/net/68360enet.c Wed Dec 31 16:00:00 1969 @@ -1,951 +0,0 @@ -/* - * Ethernet driver for Motorola MPC8xx. - * Copyright (c) 2000 Michael Leslie - * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) - * - * I copied the basic skeleton from the lance driver, because I did not - * know how to write the Linux driver, but I did know how the LANCE worked. - * - * This version of the driver is somewhat selectable for the different - * processor/board combinations. It works for the boards I know about - * now, and should be easily modified to include others. Some of the - * configuration information is contained in "commproc.h" and the - * remainder is here. - * - * Buffer descriptors are kept in the CPM dual port RAM, and the frame - * buffers are in the host memory. - * - * Right now, I am very watseful with the buffers. I allocate memory - * pages and then divide them into 2K frame buffers. This way I know I - * have buffers large enough to hold one frame within one buffer descriptor. - * Once I get this working, I will use 64 or 128 byte CPM buffers, which - * will be much more memory efficient and will easily handle lots of - * small packets. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -/* #include */ -/* #include */ -/* #include */ -#include -/* #include */ -#include - - -/* - * Theory of Operation - * - * The MPC8xx CPM performs the Ethernet processing on SCC1. It can use - * an aribtrary number of buffers on byte boundaries, but must have at - * least two receive buffers to prevent constant overrun conditions. - * - * The buffer descriptors are allocated from the CPM dual port memory - * with the data buffers allocated from host memory, just like all other - * serial communication protocols. The host memory buffers are allocated - * from the free page pool, and then divided into smaller receive and - * transmit buffers. The size of the buffers should be a power of two, - * since that nicely divides the page. This creates a ring buffer - * structure similar to the LANCE and other controllers. - * - * Like the LANCE driver: - * The driver runs as two independent, single-threaded flows of control. One - * is the send-packet routine, which enforces single-threaded use by the - * cep->tx_busy flag. The other thread is the interrupt handler, which is - * single threaded by the hardware and other software. - * - * The send packet thread has partial control over the Tx ring and the - * 'cep->tx_busy' flag. It sets the tx_busy flag whenever it's queuing a Tx - * packet. If the next queue slot is empty, it clears the tx_busy flag when - * finished otherwise it sets the 'lp->tx_full' flag. - * - * The MBX has a control register external to the MPC8xx that has some - * control of the Ethernet interface. Information is in the manual for - * your board. - * - * The RPX boards have an external control/status register. Consult the - * programming documents for details unique to your board. - * - * For the TQM8xx(L) modules, there is no control register interface. - * All functions are directly controlled using I/O pins. See commproc.h. - */ - - -/* The transmitter timeout - */ -#define TX_TIMEOUT (2*HZ) - -/* The number of Tx and Rx buffers. These are allocated statically here. - * We don't need to allocate pages for the transmitter. We just use - * the skbuffer directly. - */ -#ifdef CONFIG_ENET_BIG_BUFFERS -#define RX_RING_SIZE 64 -#define TX_RING_SIZE 64 /* Must be power of two */ -#define TX_RING_MOD_MASK 63 /* for this to work */ -#else -#define RX_RING_SIZE 8 -#define TX_RING_SIZE 8 /* Must be power of two */ -#define TX_RING_MOD_MASK 7 /* for this to work */ -#endif - -#define CPM_ENET_RX_FRSIZE 2048 /* overkill left over from ppc page-based allocation */ -static char rx_buf_pool[RX_RING_SIZE * CPM_ENET_RX_FRSIZE]; - - -/* The CPM stores dest/src/type, data, and checksum for receive packets. - */ -#define PKT_MAXBUF_SIZE 1518 -#define PKT_MINBUF_SIZE 64 -#define PKT_MAXBLR_SIZE 1520 - -/* The CPM buffer descriptors track the ring buffers. The rx_bd_base and - * tx_bd_base always point to the base of the buffer descriptors. The - * cur_rx and cur_tx point to the currently available buffer. - * The dirty_tx tracks the current buffer that is being sent by the - * controller. The cur_tx and dirty_tx are equal under both completely - * empty and completely full conditions. The empty/ready indicator in - * the buffer descriptor determines the actual condition. - */ -struct scc_enet_private { - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct sk_buff* tx_skbuff[TX_RING_SIZE]; - ushort skb_cur; - ushort skb_dirty; - - /* CPM dual port RAM relative addresses. - */ - QUICC_BD *rx_bd_base; /* Address of Rx and Tx buffers. */ - QUICC_BD *tx_bd_base; - QUICC_BD *cur_rx, *cur_tx; /* The next free ring entry */ - QUICC_BD *dirty_tx; /* The ring entries to be free()ed. */ - volatile struct scc_regs *sccp; - /* struct net_device_stats stats; */ - struct net_device_stats stats; - uint tx_full; - /* spinlock_t lock; */ - volatile unsigned int lock; -}; - - - -static int scc_enet_open(struct net_device *dev); -static int scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev); -static int scc_enet_rx(struct net_device *dev); -static irqreturn_t scc_enet_interrupt(int vec, void *dev_id, struct pt_regs *fp); -static int scc_enet_close(struct net_device *dev); -/* static struct net_device_stats *scc_enet_get_stats(struct net_device *dev); */ -static struct net_device_stats *scc_enet_get_stats(struct net_device *dev); -static void set_multicast_list(struct net_device *dev); - -/* Get this from various configuration locations (depends on board). -*/ -/*static ushort my_enet_addr[] = { 0x0800, 0x3e26, 0x1559 };*/ - -/* Typically, 860(T) boards use SCC1 for Ethernet, and other 8xx boards - * use SCC2. This is easily extended if necessary. - */ - -#define CONFIG_SCC1_ENET /* by default */ - -#ifdef CONFIG_SCC1_ENET -#define CPM_CR_ENET CPM_CR_CH_SCC1 -#define PROFF_ENET PROFF_SCC1 -#define SCC_ENET 0 -#define CPMVEC_ENET CPMVEC_SCC1 -#endif - -#ifdef CONFIG_SCC2_ENET -#define CPM_CR_ENET CPM_CR_CH_SCC2 -#define PROFF_ENET PROFF_SCC2 -#define SCC_ENET 1 /* Index, not number! */ -#define CPMVEC_ENET CPMVEC_SCC2 -#endif - -static int -scc_enet_open(struct net_device *dev) -{ - - /* I should reset the ring buffers here, but I don't yet know - * a simple way to do that. - * mleslie: That's no biggie. Worth doing, too. - */ - - /* netif_start_queue(dev); */ - return 0; /* Always succeed */ -} - - -static int -scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct scc_enet_private *cep = (struct scc_enet_private *)dev->priv; - volatile QUICC_BD *bdp; - - /* Fill in a Tx ring entry */ - bdp = cep->cur_tx; - -#ifndef final_version - if (bdp->status & BD_ENET_TX_READY) { - /* Ooops. All transmit buffers are full. Bail out. - * This should not happen, since cep->tx_busy should be set. - */ - printk("%s: tx queue full!.\n", dev->name); - return 1; - } -#endif - - /* Clear all of the status flags. - */ - bdp->status &= ~BD_ENET_TX_STATS; - - /* If the frame is short, tell CPM to pad it. - */ - if (skb->len <= ETH_ZLEN) - bdp->status |= BD_ENET_TX_PAD; - else - bdp->status &= ~BD_ENET_TX_PAD; - - /* Set buffer length and buffer pointer. - */ - bdp->length = skb->len; - /* bdp->buf = __pa(skb->data); */ - bdp->buf = skb->data; - - /* Save skb pointer. - */ - cep->tx_skbuff[cep->skb_cur] = skb; - - /* cep->stats.tx_bytes += skb->len; */ /* TODO: It would really be nice... */ - - cep->skb_cur = (cep->skb_cur+1) & TX_RING_MOD_MASK; - - - /* Push the data cache so the CPM does not get stale memory - * data. - */ -/* flush_dcache_range((unsigned long)(skb->data), */ -/* (unsigned long)(skb->data + skb->len)); */ - - /* spin_lock_irq(&cep->lock); */ /* TODO: SPINLOCK */ - local_irq_disable(); - if (cep->lock > 0) { - printk ("scc_enet_start_xmit() lock == %d\n", cep->lock); - } else { - cep->lock++; - } - - /* Send it on its way. Tell CPM its ready, interrupt when done, - * its the last BD of the frame, and to put the CRC on the end. - */ - bdp->status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR | BD_ENET_TX_LAST | BD_ENET_TX_TC); - - dev->trans_start = jiffies; - - /* If this was the last BD in the ring, start at the beginning again. - */ - if (bdp->status & BD_ENET_TX_WRAP) - bdp = cep->tx_bd_base; - else - bdp++; - - if (bdp->status & BD_ENET_TX_READY) { - /* netif_stop_queue(dev); */ - cep->tx_full = 1; - } - - cep->cur_tx = (QUICC_BD *)bdp; - - /* spin_unlock_irq(&cep->lock); */ /* TODO: SPINLOCK */ - cep->lock--; - sti(); - - return 0; -} - -#if 0 -static void -scc_enet_timeout(struct net_device *dev) -{ - struct scc_enet_private *cep = (struct scc_enet_private *)dev->priv; - - printk("%s: transmit timed out.\n", dev->name); - cep->stats.tx_errors++; -#ifndef final_version - { - int i; - QUICC_BD *bdp; - printk(" Ring data dump: cur_tx %p%s cur_rx %p.\n", - cep->cur_tx, cep->tx_full ? " (full)" : "", - cep->cur_rx); - bdp = cep->tx_bd_base; - for (i = 0 ; i < TX_RING_SIZE; i++, bdp++) - printk("%04x %04x %08x\n", - bdp->status, - bdp->length, - (int)(bdp->buf)); - bdp = cep->rx_bd_base; - for (i = 0 ; i < RX_RING_SIZE; i++, bdp++) - printk("%04x %04x %08x\n", - bdp->status, - bdp->length, - (int)(bdp->buf)); - } -#endif -/* if (!cep->tx_full) */ -/* netif_wake_queue(dev); */ -} -#endif - -/* The interrupt handler. - * This is called from the CPM handler, not the MPC core interrupt. - */ -static irqreturn_t scc_enet_interrupt(int vec, void *dev_id, struct pt_regs *fp) -{ - struct net_device *dev = (struct net_device *)dev_id; - volatile struct scc_enet_private *cep; - volatile QUICC_BD *bdp; - ushort int_events; - int must_restart; - - cep = (struct scc_enet_private *)dev->priv; - - /* Get the interrupt events that caused us to be here. - */ - int_events = cep->sccp->scc_scce; - cep->sccp->scc_scce = int_events; - must_restart = 0; - - /* Handle receive event in its own function. - */ - if (int_events & SCCE_ENET_RXF) - scc_enet_rx(dev_id); - - /* Check for a transmit error. The manual is a little unclear - * about this, so the debug code until I get it figured out. It - * appears that if TXE is set, then TXB is not set. However, - * if carrier sense is lost during frame transmission, the TXE - * bit is set, "and continues the buffer transmission normally." - * I don't know if "normally" implies TXB is set when the buffer - * descriptor is closed.....trial and error :-). - */ - - /* Transmit OK, or non-fatal error. Update the buffer descriptors. - */ - if (int_events & (SCCE_ENET_TXE | SCCE_ENET_TXB)) { - /* spin_lock(&cep->lock); */ /* TODO: SPINLOCK */ - /* local_irq_disable(); */ - if (cep->lock > 0) { - printk ("scc_enet_interrupt() lock == %d\n", cep->lock); - } else { - cep->lock++; - } - - bdp = cep->dirty_tx; - while ((bdp->status&BD_ENET_TX_READY)==0) { - if ((bdp==cep->cur_tx) && (cep->tx_full == 0)) - break; - - if (bdp->status & BD_ENET_TX_HB) /* No heartbeat */ - cep->stats.tx_heartbeat_errors++; - if (bdp->status & BD_ENET_TX_LC) /* Late collision */ - cep->stats.tx_window_errors++; - if (bdp->status & BD_ENET_TX_RL) /* Retrans limit */ - cep->stats.tx_aborted_errors++; - if (bdp->status & BD_ENET_TX_UN) /* Underrun */ - cep->stats.tx_fifo_errors++; - if (bdp->status & BD_ENET_TX_CSL) /* Carrier lost */ - cep->stats.tx_carrier_errors++; - - - /* No heartbeat or Lost carrier are not really bad errors. - * The others require a restart transmit command. - */ - if (bdp->status & - (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) { - must_restart = 1; - cep->stats.tx_errors++; - } - - cep->stats.tx_packets++; - - /* Deferred means some collisions occurred during transmit, - * but we eventually sent the packet OK. - */ - if (bdp->status & BD_ENET_TX_DEF) - cep->stats.collisions++; - - /* Free the sk buffer associated with this last transmit. - */ - /* dev_kfree_skb_irq(cep->tx_skbuff[cep->skb_dirty]); */ - dev_kfree_skb (cep->tx_skbuff[cep->skb_dirty]); - cep->skb_dirty = (cep->skb_dirty + 1) & TX_RING_MOD_MASK; - - /* Update pointer to next buffer descriptor to be transmitted. - */ - if (bdp->status & BD_ENET_TX_WRAP) - bdp = cep->tx_bd_base; - else - bdp++; - - /* I don't know if we can be held off from processing these - * interrupts for more than one frame time. I really hope - * not. In such a case, we would now want to check the - * currently available BD (cur_tx) and determine if any - * buffers between the dirty_tx and cur_tx have also been - * sent. We would want to process anything in between that - * does not have BD_ENET_TX_READY set. - */ - - /* Since we have freed up a buffer, the ring is no longer - * full. - */ - if (cep->tx_full) { - cep->tx_full = 0; -/* if (netif_queue_stopped(dev)) */ -/* netif_wake_queue(dev); */ - } - - cep->dirty_tx = (QUICC_BD *)bdp; - } - - if (must_restart) { - volatile QUICC *cp; - - /* Some transmit errors cause the transmitter to shut - * down. We now issue a restart transmit. Since the - * errors close the BD and update the pointers, the restart - * _should_ pick up without having to reset any of our - * pointers either. - */ - cp = pquicc; - cp->cp_cr = - mk_cr_cmd(CPM_CR_ENET, CPM_CR_RESTART_TX) | CPM_CR_FLG; - while (cp->cp_cr & CPM_CR_FLG); - } - /* spin_unlock(&cep->lock); */ /* TODO: SPINLOCK */ - /* sti(); */ - cep->lock--; - } - - /* Check for receive busy, i.e. packets coming but no place to - * put them. This "can't happen" because the receive interrupt - * is tossing previous frames. - */ - if (int_events & SCCE_ENET_BSY) { - cep->stats.rx_dropped++; - printk("CPM ENET: BSY can't happen.\n"); - } - - return IRQ_HANDLED; -} - -/* During a receive, the cur_rx points to the current incoming buffer. - * When we update through the ring, if the next incoming buffer has - * not been given to the system, we just set the empty indicator, - * effectively tossing the packet. - */ -static int -scc_enet_rx(struct net_device *dev) -{ - struct scc_enet_private *cep; - volatile QUICC_BD *bdp; - struct sk_buff *skb; - ushort pkt_len; - - cep = (struct scc_enet_private *)dev->priv; - - /* First, grab all of the stats for the incoming packet. - * These get messed up if we get called due to a busy condition. - */ - bdp = cep->cur_rx; - - for (;;) { - if (bdp->status & BD_ENET_RX_EMPTY) - break; - -#ifndef final_version - /* Since we have allocated space to hold a complete frame, both - * the first and last indicators should be set. - */ - if ((bdp->status & (BD_ENET_RX_FIRST | BD_ENET_RX_LAST)) != - (BD_ENET_RX_FIRST | BD_ENET_RX_LAST)) - printk("CPM ENET: rcv is not first+last\n"); -#endif - - /* Frame too long or too short. - */ - if (bdp->status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) - cep->stats.rx_length_errors++; - if (bdp->status & BD_ENET_RX_NO) /* Frame alignment */ - cep->stats.rx_frame_errors++; - if (bdp->status & BD_ENET_RX_CR) /* CRC Error */ - cep->stats.rx_crc_errors++; - if (bdp->status & BD_ENET_RX_OV) /* FIFO overrun */ - cep->stats.rx_crc_errors++; - - /* Report late collisions as a frame error. - * On this error, the BD is closed, but we don't know what we - * have in the buffer. So, just drop this frame on the floor. - */ - if (bdp->status & BD_ENET_RX_CL) { - cep->stats.rx_frame_errors++; - } - else { - - /* Process the incoming frame. - */ - cep->stats.rx_packets++; - pkt_len = bdp->length; - /* cep->stats.rx_bytes += pkt_len; */ /* TODO: It would really be nice... */ - - /* This does 16 byte alignment, much more than we need. - * The packet length includes FCS, but we don't want to - * include that when passing upstream as it messes up - * bridging applications. - */ - skb = dev_alloc_skb(pkt_len-4); - - if (skb == NULL) { - printk("%s: Memory squeeze, dropping packet.\n", dev->name); - cep->stats.rx_dropped++; - } - else { - skb->dev = dev; - skb_put(skb,pkt_len-4); /* Make room */ - eth_copy_and_sum(skb, (unsigned char *)bdp->buf, pkt_len-4, 0); - skb->protocol=eth_type_trans(skb,dev); - netif_rx(skb); - } - } - - /* Clear the status flags for this buffer. - */ - bdp->status &= ~BD_ENET_RX_STATS; - - /* Mark the buffer empty. - */ - bdp->status |= BD_ENET_RX_EMPTY; - - /* Update BD pointer to next entry. - */ - if (bdp->status & BD_ENET_RX_WRAP) - bdp = cep->rx_bd_base; - else - bdp++; - - } - cep->cur_rx = (QUICC_BD *)bdp; - - return 0; -} - -static int -scc_enet_close(struct net_device *dev) -{ - /* Don't know what to do yet. - */ - /* netif_stop_queue(dev); */ - - return 0; -} - -/* static struct net_device_stats *scc_enet_get_stats(struct net_device *dev) */ -static struct net_device_stats *scc_enet_get_stats(struct net_device *dev) -{ - struct scc_enet_private *cep = (struct scc_enet_private *)dev->priv; - - return &cep->stats; -} - -/* Set or clear the multicast filter for this adaptor. - * Skeleton taken from sunlance driver. - * The CPM Ethernet implementation allows Multicast as well as individual - * MAC address filtering. Some of the drivers check to make sure it is - * a group multicast address, and discard those that are not. I guess I - * will do the same for now, but just remove the test if you want - * individual filtering as well (do the upper net layers want or support - * this kind of feature?). - */ - -static void set_multicast_list(struct net_device *dev) -{ - struct scc_enet_private *cep; - struct dev_mc_list *dmi; - u_char *mcptr, *tdptr; - volatile scc_enet_t *ep; - int i, j; - volatile QUICC *cp = pquicc; - - cep = (struct scc_enet_private *)dev->priv; - - /* Get pointer to SCC area in parameter RAM. - */ - ep = (scc_enet_t *)dev->base_addr; - - if (dev->flags&IFF_PROMISC) { - - /* Log any net taps. */ - printk("%s: Promiscuous mode enabled.\n", dev->name); - cep->sccp->scc_psmr |= ETHER_PRO; - } else { - - cep->sccp->scc_psmr &= ~ETHER_PRO; - - if (dev->flags & IFF_ALLMULTI) { - /* Catch all multicast addresses, so set the - * filter to all 1's. - */ - ep->sen_gaddr1 = 0xffff; - ep->sen_gaddr2 = 0xffff; - ep->sen_gaddr3 = 0xffff; - ep->sen_gaddr4 = 0xffff; - } - else { - /* Clear filter and add the addresses in the list. - */ - ep->sen_gaddr1 = 0; - ep->sen_gaddr2 = 0; - ep->sen_gaddr3 = 0; - ep->sen_gaddr4 = 0; - - dmi = dev->mc_list; - - for (i=0; imc_count; i++) { - - /* Only support group multicast for now. - */ - if (!(dmi->dmi_addr[0] & 1)) - continue; - - /* The address in dmi_addr is LSB first, - * and taddr is MSB first. We have to - * copy bytes MSB first from dmi_addr. - */ - mcptr = (u_char *)dmi->dmi_addr + 5; - tdptr = (u_char *)&ep->sen_taddrh; - for (j=0; j<6; j++) - *tdptr++ = *mcptr--; - - /* Ask CPM to run CRC and set bit in - * filter mask. - */ - cp->cp_cr = mk_cr_cmd(CPM_CR_ENET, CPM_CR_SET_GADDR) | CPM_CR_FLG; - /* this delay is necessary here -- Cort */ - udelay(10); - while (cp->cp_cr & CPM_CR_FLG); - } - } - } -} - - -/* Initialize the CPM Ethernet on SCC. - */ -int scc_enet_init(void) -{ - struct net_device *dev; - struct scc_enet_private *cep; - int i, j; - unsigned char *eap; - /* unsigned long mem_addr; */ - /* pte_t *pte; */ - /* bd_t *bd; */ /* `board tag' used by ppc - TODO: integrate uC bootloader vars */ - volatile QUICC_BD *bdp; - volatile QUICC *cp; - volatile struct scc_regs *sccp; - volatile struct ethernet_pram *ep; - /* volatile immap_t *immap; */ - - cp = pquicc; /* Get pointer to Communication Processor */ - - /* immap = (immap_t *)IMAP_ADDR; */ /* and to internal registers */ - - /* bd = (bd_t *)__res; */ - - /* Allocate some private information. - */ - cep = (struct scc_enet_private *)kmalloc(sizeof(*cep), GFP_KERNEL); - memset(cep, 0, sizeof(*cep)); - /* __clear_user(cep,sizeof(*cep)); */ - /* spin_lock_init(&cep->lock); */ /* TODO: SPINLOCK */ - - /* Create an Ethernet device instance. - */ - dev = init_etherdev(0, 0); - - /* Get pointer to SCC area in parameter RAM. - */ - /* ep = (ethernet_pram *)(&cp->cp_dparam[PROFF_ENET]); */ - ep = &pquicc->pram[SCC_ENET].enet_scc; - - /* And another to the SCC register area. - */ - sccp = &pquicc->scc_regs[SCC_ENET]; - cep->sccp = sccp; /* Keep the pointer handy */ - - /* Disable receive and transmit in case EPPC-Bug started it. - */ - sccp->scc_gsmr.w.low &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); - - /* Set up 360 pins for SCC interface to ethernet transceiver. - * Pin mappings (PA_xx and PC_xx) are defined in commproc.h - */ - - /* Configure port A pins for Txd and Rxd. - */ - pquicc->pio_papar |= (PA_ENET_RXD | PA_ENET_TXD); - pquicc->pio_padir &= ~(PA_ENET_RXD | PA_ENET_TXD); - pquicc->pio_paodr &= ~PA_ENET_TXD; - - /* Configure port C pins to enable CLSN and RENA. - */ - pquicc->pio_pcpar &= ~(PC_ENET_CLSN | PC_ENET_RENA); - pquicc->pio_pcdir &= ~(PC_ENET_CLSN | PC_ENET_RENA); - pquicc->pio_pcso |= (PC_ENET_CLSN | PC_ENET_RENA); - - /* Configure port A for TCLK and RCLK. - */ - pquicc->pio_papar |= (PA_ENET_TCLK | PA_ENET_RCLK); - pquicc->pio_padir &= ~(PA_ENET_TCLK | PA_ENET_RCLK); - - /* Configure Serial Interface clock routing. - * First, clear all SCC bits to zero, then set the ones we want. - */ - pquicc->si_sicr &= ~SICR_ENET_MASK; - pquicc->si_sicr |= SICR_ENET_CLKRT; - - - /* Allocate space for the buffer descriptors in the DP ram. - * These are relative offsets in the DP ram address space. - * Initialize base addresses for the buffer descriptors. - */ - i = m360_cpm_dpalloc(sizeof(QUICC_BD) * RX_RING_SIZE); - ep->rbase = i; - cep->rx_bd_base = (QUICC_BD *)((uint)pquicc + i); - - i = m360_cpm_dpalloc(sizeof(QUICC_BD) * TX_RING_SIZE); - ep->tbase = i; - cep->tx_bd_base = (QUICC_BD *)((uint)pquicc + i); - - cep->dirty_tx = cep->cur_tx = cep->tx_bd_base; - cep->cur_rx = cep->rx_bd_base; - - /* Issue init Rx BD command for SCC. - * Manual says to perform an Init Rx parameters here. We have - * to perform both Rx and Tx because the SCC may have been - * already running. [In uCquicc's case, I don't think that is so - mles] - * In addition, we have to do it later because we don't yet have - * all of the BD control/status set properly. - cp->cp_cpcr = mk_cr_cmd(CPM_CR_ENET, CPM_CR_INIT_RX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); - */ - - /* Initialize function code registers for big-endian. - */ - ep->rfcr = (SCC_EB | SCC_FC_DMA); - ep->tfcr = (SCC_EB | SCC_FC_DMA); - - /* Set maximum bytes per receive buffer. - * This appears to be an Ethernet frame size, not the buffer - * fragment size. It must be a multiple of four. - */ - ep->mrblr = PKT_MAXBLR_SIZE; - - /* Set CRC preset and mask. - */ - ep->c_pres = 0xffffffff; - ep->c_mask = 0xdebb20e3; /* see 360UM p. 7-247 */ - - ep->crcec = 0; /* CRC Error counter */ - ep->alec = 0; /* alignment error counter */ - ep->disfc = 0; /* discard frame counter */ - - ep->pads = 0x8888; /* Tx short frame pad character */ - ep->ret_lim = 0x000f; /* Retry limit threshold */ - - ep->mflr = PKT_MAXBUF_SIZE; /* maximum frame length register */ - ep->minflr = PKT_MINBUF_SIZE; /* minimum frame length register */ - - ep->maxd1 = PKT_MAXBLR_SIZE; /* maximum DMA1 length */ - ep->maxd2 = PKT_MAXBLR_SIZE; /* maximum DMA2 length */ - - /* Clear hash tables, group and individual. - */ - ep->gaddr1 = ep->gaddr2 = ep->gaddr3 = ep->gaddr4 = 0; - ep->iaddr1 = ep->iaddr2 = ep->iaddr3 = ep->iaddr4 = 0; - - /* Set Ethernet station address. - * - * The uCbootloader provides a hook to the kernel to retrieve - * stuff like the MAC address. This is retrieved in config_BSP() - */ -#if defined (CONFIG_UCQUICC) - { - extern unsigned char *scc1_hwaddr; - - eap = (char *)ep->paddr.b; - for (i=5; i>=0; i--) - *eap++ = dev->dev_addr[i] = scc1_hwaddr[i]; - } -#endif - - -/* #ifndef CONFIG_MBX */ -/* eap = (unsigned char *)&(ep->paddrh); */ - -/* for (i=5; i>=0; i--) */ -/* *eap++ = dev->dev_addr[i] = bd->bi_enetaddr[i]; */ -/* #else */ -/* for (i=5; i>=0; i--) */ -/* dev->dev_addr[i] = *eap++; */ -/* #endif */ - - ep->p_per = 0; /* 'cause the book says so */ - ep->taddr_l = 0; /* temp address (LSB) */ - ep->taddr_m = 0; - ep->taddr_h = 0; /* temp address (MSB) */ - - /* Now allocate the host memory pages and initialize the - * buffer descriptors. - */ - /* initialize rx buffer descriptors */ - bdp = cep->tx_bd_base; - for (j=0; j<(TX_RING_SIZE-1); j++) { - bdp->buf = 0; - bdp->status = 0; - bdp++; - } - bdp->buf = 0; - bdp->status = BD_SC_WRAP; - - - /* initialize rx buffer descriptors */ - bdp = cep->rx_bd_base; - for (j=0; j<(RX_RING_SIZE-1); j++) { - bdp->buf = &rx_buf_pool[j * CPM_ENET_RX_FRSIZE]; - bdp->status = BD_SC_EMPTY | BD_SC_INTRPT; - bdp++; - } - bdp->buf = &rx_buf_pool[j * CPM_ENET_RX_FRSIZE]; - bdp->status = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT; - - - - /* Let's re-initialize the channel now. We have to do it later - * than the manual describes because we have just now finished - * the BD initialization. - */ - cp->cp_cr = mk_cr_cmd(CPM_CR_ENET, CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cr & CPM_CR_FLG); - - cep->skb_cur = cep->skb_dirty = 0; - - sccp->scc_scce = 0xffff; /* Clear any pending events */ - - /* Enable interrupts for transmit error, complete frame - * received, and any transmit buffer we have also set the - * interrupt flag. - */ - sccp->scc_sccm = (SCCE_ENET_TXE | SCCE_ENET_RXF | SCCE_ENET_TXB); - - /* Install our interrupt handler. - */ - /* cpm_install_handler(CPMVEC_ENET, scc_enet_interrupt, dev); */ - request_irq(CPMVEC_ENET, scc_enet_interrupt, - IRQ_FLG_LOCK, dev->name, (void *)dev); - - /* Set GSMR_H to enable all normal operating modes. - * Set GSMR_L to enable Ethernet to MC68160. - */ - sccp->scc_gsmr.w.high = 0; - sccp->scc_gsmr.w.low = (SCC_GSMRL_TCI | SCC_GSMRL_TPL_48 | - SCC_GSMRL_TPP_10 | SCC_GSMRL_MODE_ENET); - - /* Set sync/delimiters. - */ - sccp->scc_dsr = 0xd555; - - /* Set processing mode. Use Ethernet CRC, catch broadcast, and - * start frame search 22 bit times after RENA. - */ - sccp->scc_psmr = (SCC_PMSR_ENCRC /* Ethernet CRC mode */ - /* | SCC_PSMR_HBC */ /* Enable heartbeat */ - /* | SCC_PMSR_PRO */ /* Promiscuous mode */ - /* | SCC_PMSR_FDE */ /* Full duplex enable */ - | ETHER_NIB_22); - /* sccp->scc_psmr = (SCC_PMSR_PRO | ETHER_CRC_32 | ETHER_NIB_22); */ - - - /* It is now OK to enable the Ethernet transmitter. - * Unfortunately, there are board implementation differences here. - */ -#if defined(CONFIG_UCQUICC) -/* immap->im_ioport.iop_pcpar |= PC_ENET_TENA; */ -/* immap->im_ioport.iop_pcdir &= ~PC_ENET_TENA; */ - cp->pio_pcpar |= PC_ENET_TENA; /* t_en */ - cp->pio_pcdir &= ~PC_ENET_TENA; - - cp->pip_pbpar &= ~(0x00000200); /* power up ethernet transceiver */ - cp->pip_pbdir |= (0x00000200); - cp->pip_pbdat |= (0x00000200); -#endif - - - dev->base_addr = (unsigned long)ep; - dev->priv = cep; -#if 0 - dev->name = "CPM_ENET"; -#endif - - /* The CPM Ethernet specific entries in the device structure. */ - dev->open = scc_enet_open; - dev->hard_start_xmit = scc_enet_start_xmit; - /* dev->tx_timeout = scc_enet_timeout; */ - /* dev->watchdog_timeo = TX_TIMEOUT; */ - dev->stop = scc_enet_close; - dev->get_stats = scc_enet_get_stats; - dev->set_multicast_list = set_multicast_list; - - /* And last, enable the transmit and receive processing. - */ - sccp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); - - printk("%s: CPM ENET Version 0.3, ", dev->name); - for (i=0; i<5; i++) - printk("%02x:", dev->dev_addr[i]); - printk("%02x\n", dev->dev_addr[5]); - - return 0; -} - - - -int m68360_enet_probe(struct device *dev) -{ - return(scc_enet_init ()); -} - - -/* - * Local variables: - * c-indent-level: 4 - * c-basic-offset: 4 - * tab-width: 4 - * End: - */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/8139too.c 830-ivtv/drivers/net/8139too.c --- 000-virgin/drivers/net/8139too.c Thu Jan 8 08:35:37 2004 +++ 830-ivtv/drivers/net/8139too.c Thu Jan 8 08:54:06 2004 @@ -92,7 +92,7 @@ */ #define DRV_NAME "8139too" -#define DRV_VERSION "0.9.26" +#define DRV_VERSION "0.9.27" #include @@ -117,17 +117,17 @@ #define RTL8139_DRIVER_NAME DRV_NAME " Fast Ethernet driver " DRV_VERSION #define PFX DRV_NAME ": " +/* Default Message level */ +#define RTL8139_DEF_MSG_ENABLE (NETIF_MSG_DRV | \ + NETIF_MSG_PROBE | \ + NETIF_MSG_LINK) + /* enable PIO instead of MMIO, if CONFIG_8139TOO_PIO is selected */ #ifdef CONFIG_8139TOO_PIO #define USE_IO_OPS 1 #endif -/* use a 16K rx ring buffer instead of the default 32K */ -#ifdef CONFIG_SH_DREAMCAST -#define USE_BUF16K 1 -#endif - /* define to 1 to enable copious debugging info */ #undef RTL8139_DEBUG @@ -146,9 +146,9 @@ # define assert(expr) do {} while (0) #else # define assert(expr) \ - if(!(expr)) { \ - printk( "Assertion failed! %s,%s,%s,line=%d\n", \ - #expr,__FILE__,__FUNCTION__,__LINE__); \ + if(unlikely(!(expr))) { \ + printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \ + #expr,__FILE__,__FUNCTION__,__LINE__); \ } #endif @@ -159,9 +159,6 @@ static int media[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 20; - /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). The RTL chips use a 64 element hash table based on the Ethernet CRC. */ static int multicast_filter_limit = 32; @@ -169,16 +166,16 @@ static int multicast_filter_limit = 32; /* bitmapped message enable number */ static int debug = -1; -/* Size of the in-memory receive ring. */ -#ifdef USE_BUF16K -#define RX_BUF_LEN_IDX 1 /* 0==8K, 1==16K, 2==32K, 3==64K */ -#else -#define RX_BUF_LEN_IDX 2 /* 0==8K, 1==16K, 2==32K, 3==64K */ -#endif -#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX) +/* Ring size is now a config option */ +#define RX_BUF_LEN (8192 << CONFIG_8139_RXBUF_IDX) #define RX_BUF_PAD 16 #define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */ + +#if RX_BUF_LEN == 65536 +#define RX_BUF_TOT_LEN RX_BUF_LEN +#else #define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD) +#endif /* Number of Tx descriptor registers. */ #define NUM_TX_DESC 4 @@ -251,6 +248,10 @@ static struct pci_device_id rtl8139_pci_ {0x11db, 0x1234, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, {0x1432, 0x9130, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, {0x02ac, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, + {0x018a, 0x0106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, + {0x126c, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, + {0x1743, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, + {0x021b, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, #ifdef CONFIG_SH_SECUREEDGE5410 /* Bogus 8139 silicon reports 8129 without external PROM :-( */ @@ -450,7 +451,7 @@ enum RxConfigBits { RxCfgRcv32K = (1 << 12), RxCfgRcv64K = (1 << 11) | (1 << 12), - /* Disable packet wrap at end of Rx buffer */ + /* Disable packet wrap at end of Rx buffer. (not possible with 64k) */ RxNoWrap = (1 << 7), }; @@ -560,6 +561,7 @@ struct rtl8139_private { int drv_flags; struct pci_dev *pci_dev; u32 pci_state[16]; + u32 msg_enable; struct net_device_stats stats; unsigned char *rx_ring; unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */ @@ -574,6 +576,7 @@ struct rtl8139_private { char twistie, twist_row, twist_col; /* Twister tune state. */ unsigned int default_port:4; /* Last dev->if_port value. */ spinlock_t lock; + spinlock_t rx_lock; chip_t chipset; pid_t thr_pid; wait_queue_head_t thr_wait; @@ -590,13 +593,11 @@ MODULE_DESCRIPTION ("RealTek RTL-8139 Fa MODULE_LICENSE("GPL"); MODULE_PARM (multicast_filter_limit, "i"); -MODULE_PARM (max_interrupt_work, "i"); MODULE_PARM (media, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM (full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM (debug, "i"); MODULE_PARM_DESC (debug, "8139too bitmapped message enable number"); MODULE_PARM_DESC (multicast_filter_limit, "8139too maximum number of filtered multicast addresses"); -MODULE_PARM_DESC (max_interrupt_work, "8139too maximum events handled per interrupt"); MODULE_PARM_DESC (media, "8139too: Bits 4+9: force full duplex, bit 5: 100Mbps"); MODULE_PARM_DESC (full_duplex, "8139too: Force full duplex for board(s) (1)"); @@ -610,6 +611,10 @@ static void rtl8139_tx_timeout (struct n static void rtl8139_init_ring (struct net_device *dev); static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev); +static int rtl8139_poll(struct net_device *dev, int *budget); +#ifdef CONFIG_NET_POLL_CONTROLLER +static void rtl8139_poll_controller(struct net_device *dev); +#endif static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance, struct pt_regs *regs); static int rtl8139_close (struct net_device *dev); @@ -682,16 +687,32 @@ static const u16 rtl8139_intr_mask = PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK; -#ifdef USE_BUF16K +static const u16 rtl8139_norx_intr_mask = + PCIErr | PCSTimeout | RxUnderrun | + TxErr | TxOK | RxErr ; + +#if CONFIG_8139_RXBUF_IDX == 0 +static const unsigned int rtl8139_rx_config = + RxCfgRcv8K | RxNoWrap | + (RX_FIFO_THRESH << RxCfgFIFOShift) | + (RX_DMA_BURST << RxCfgDMAShift); +#elif CONFIG_8139_RXBUF_IDX == 1 static const unsigned int rtl8139_rx_config = RxCfgRcv16K | RxNoWrap | (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift); -#else +#elif CONFIG_8139_RXBUF_IDX == 2 static const unsigned int rtl8139_rx_config = RxCfgRcv32K | RxNoWrap | (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift); +#elif CONFIG_8139_RXBUF_IDX == 3 +static const unsigned int rtl8139_rx_config = + RxCfgRcv64K | + (RX_FIFO_THRESH << RxCfgFIFOShift) | + (RX_DMA_BURST << RxCfgDMAShift); +#else +#error "Invalid configuration for 8139_RXBUF_IDX" #endif static const unsigned int rtl8139_tx_config = @@ -868,9 +889,7 @@ static int __devinit rtl8139_init_board match: DPRINTK ("chipset id (%d) == index %d, '%s'\n", - tmp, - tp->chipset, - rtl_chip_info[tp->chipset].name); + version, i, rtl_chip_info[i].name); if (tp->chipset >= CH_8139B) { u8 new_tmp8 = tmp8 = RTL_R8 (Config1); @@ -964,6 +983,8 @@ static int __devinit rtl8139_init_one (s /* The Rtl8139-specific entries in the device structure. */ dev->open = rtl8139_open; dev->hard_start_xmit = rtl8139_start_xmit; + dev->poll = rtl8139_poll; + dev->weight = 64; dev->stop = rtl8139_close; dev->get_stats = rtl8139_get_stats; dev->set_multicast_list = rtl8139_set_rx_mode; @@ -971,6 +992,9 @@ static int __devinit rtl8139_init_one (s dev->ethtool_ops = &rtl8139_ethtool_ops; dev->tx_timeout = rtl8139_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = rtl8139_poll_controller; +#endif /* note: the hardware is not capable of sg/csum/highdma, however * through the use of skb_copy_and_csum_dev we enable these @@ -986,7 +1010,10 @@ static int __devinit rtl8139_init_one (s /* note: tp->chipset set in rtl8139_init_board */ tp->drv_flags = board_info[ent->driver_data].hw_flags; tp->mmio_addr = ioaddr; + tp->msg_enable = + (debug < 0 ? RTL8139_DEF_MSG_ENABLE : ((1 << debug) - 1)); spin_lock_init (&tp->lock); + spin_lock_init (&tp->rx_lock); init_waitqueue_head (&tp->thr_wait); init_completion (&tp->thr_exited); tp->mii.dev = dev; @@ -1288,9 +1315,7 @@ static int rtl8139_open (struct net_devi { struct rtl8139_private *tp = dev->priv; int retval; -#ifdef RTL8139_DEBUG void *ioaddr = tp->mmio_addr; -#endif retval = request_irq (dev->irq, rtl8139_interrupt, SA_SHIRQ, dev->name, dev); if (retval) @@ -1319,8 +1344,10 @@ static int rtl8139_open (struct net_devi rtl8139_init_ring (dev); rtl8139_hw_start (dev); + netif_start_queue (dev); - DPRINTK ("%s: rtl8139_open() ioaddr %#lx IRQ %d" + if (netif_msg_ifup(tp)) + printk(KERN_DEBUG "%s: rtl8139_open() ioaddr %#lx IRQ %d" " GP Pins %2.2x %s-duplex.\n", dev->name, pci_resource_start (tp->pci_dev, 1), dev->irq, RTL_R8 (MediaStatus), @@ -1337,7 +1364,7 @@ static void rtl_check_media (struct net_ struct rtl8139_private *tp = dev->priv; if (tp->phys[0] >= 0) { - mii_check_media(&tp->mii, 1, init_media); + mii_check_media(&tp->mii, netif_msg_link(tp), init_media); } } @@ -1407,8 +1434,6 @@ static void rtl8139_hw_start (struct net /* Enable all known interrupts by setting the interrupt mask. */ RTL_W16 (IntrMask, rtl8139_intr_mask); - - netif_start_queue (dev); } @@ -1631,7 +1656,7 @@ static inline void rtl8139_start_thread( } } -static void rtl8139_tx_clear (struct rtl8139_private *tp) +static inline void rtl8139_tx_clear (struct rtl8139_private *tp) { tp->cur_tx = 0; tp->dirty_tx = 0; @@ -1661,6 +1686,7 @@ static void rtl8139_tx_timeout (struct n if (tmp8 & CmdTxEnb) RTL_W8 (ChipCmd, CmdRxEnb); + spin_lock(&tp->rx_lock); /* Disable interrupts by clearing the interrupt mask. */ RTL_W16 (IntrMask, 0x0000); @@ -1679,9 +1705,12 @@ static void rtl8139_tx_timeout (struct n spin_unlock_irqrestore (&tp->lock, flags); /* ...and finally, reset everything */ - rtl8139_hw_start (dev); - - netif_wake_queue (dev); + if (netif_running(dev)) { + rtl8139_hw_start (dev); + netif_wake_queue (dev); + } + spin_unlock(&tp->rx_lock); + } @@ -1695,6 +1724,7 @@ static int rtl8139_start_xmit (struct sk /* Calculate the next Tx descriptor entry. */ entry = tp->cur_tx % NUM_TX_DESC; + /* Note: the chip doesn't have auto-pad! */ if (likely(len < TX_BUF_SIZE)) { if (len < ETH_ZLEN) memset(tp->tx_buf[entry], 0, ETH_ZLEN); @@ -1706,7 +1736,6 @@ static int rtl8139_start_xmit (struct sk return 0; } - /* Note: the chip doesn't have auto-pad! */ spin_lock_irq(&tp->lock); RTL_W32_F (TxStatus0 + (entry * sizeof (u32)), tp->tx_flag | max(len, (unsigned int)ETH_ZLEN)); @@ -1720,8 +1749,9 @@ static int rtl8139_start_xmit (struct sk netif_stop_queue (dev); spin_unlock_irq(&tp->lock); - DPRINTK ("%s: Queued Tx packet size %u to slot %d.\n", - dev->name, len, entry); + if (netif_msg_tx_queued(tp)) + printk (KERN_DEBUG "%s: Queued Tx packet size %u to slot %d.\n", + dev->name, len, entry); return 0; } @@ -1751,8 +1781,9 @@ static void rtl8139_tx_interrupt (struct /* Note: TxCarrierLost is always asserted at 100mbps. */ if (txstatus & (TxOutOfWindow | TxAborted)) { /* There was an major error, log it. */ - DPRINTK ("%s: Transmit error, Tx status %8.8x.\n", - dev->name, txstatus); + if (netif_msg_tx_err(tp)) + printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", + dev->name, txstatus); tp->stats.tx_errors++; if (txstatus & TxAborted) { tp->stats.tx_aborted_errors++; @@ -1792,8 +1823,7 @@ static void rtl8139_tx_interrupt (struct if (tp->dirty_tx != dirty_tx) { tp->dirty_tx = dirty_tx; mb(); - if (netif_queue_stopped (dev)) - netif_wake_queue (dev); + netif_wake_queue (dev); } } @@ -1807,8 +1837,9 @@ static void rtl8139_rx_err (u32 rx_statu int tmp_work; #endif - DPRINTK ("%s: Ethernet frame had errors, status %8.8x.\n", - dev->name, rx_status); + if (netif_msg_rx_err (tp)) + printk(KERN_DEBUG "%s: Ethernet frame had errors, status %8.8x.\n", + dev->name, rx_status); tp->stats.rx_errors++; if (!(rx_status & RxStatusOK)) { if (rx_status & RxTooLong) { @@ -1880,30 +1911,41 @@ static void rtl8139_rx_err (u32 rx_statu #endif } -static void rtl8139_rx_interrupt (struct net_device *dev, - struct rtl8139_private *tp, void *ioaddr) -{ - unsigned char *rx_ring; - u16 cur_rx; - - assert (dev != NULL); - assert (tp != NULL); - assert (ioaddr != NULL); +#if CONFIG_8139_RXBUF_IDX == 3 +static __inline__ void wrap_copy(struct sk_buff *skb, const unsigned char *ring, + u32 offset, unsigned int size) +{ + u32 left = RX_BUF_LEN - offset; + + if (size > left) { + memcpy(skb->data, ring + offset, left); + memcpy(skb->data+left, ring, size - left); + } else + memcpy(skb->data, ring + offset, size); +} +#endif - rx_ring = tp->rx_ring; - cur_rx = tp->cur_rx; +static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp, + int budget) +{ + void *ioaddr = tp->mmio_addr; + int received = 0; + unsigned char *rx_ring = tp->rx_ring; + unsigned int cur_rx = tp->cur_rx; DPRINTK ("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x," " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx, RTL_R16 (RxBufAddr), RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd)); - while ((RTL_R8 (ChipCmd) & RxBufEmpty) == 0) { - int ring_offset = cur_rx % RX_BUF_LEN; + while (netif_running(dev) && received < budget + && (RTL_R8 (ChipCmd) & RxBufEmpty) == 0) { + u32 ring_offset = cur_rx % RX_BUF_LEN; u32 rx_status; unsigned int rx_size; unsigned int pkt_size; struct sk_buff *skb; + u16 status; rmb(); @@ -1912,8 +1954,9 @@ static void rtl8139_rx_interrupt (struct rx_size = rx_status >> 16; pkt_size = rx_size - 4; - DPRINTK ("%s: rtl8139_rx() status %4.4x, size %4.4x," - " cur %4.4x.\n", dev->name, rx_status, + if (netif_msg_rx_status(tp)) + printk(KERN_DEBUG "%s: rtl8139_rx() status %4.4x, size %4.4x," + " cur %4.4x.\n", dev->name, rx_status, rx_size, cur_rx); #if RTL8139_DEBUG > 2 { @@ -1930,9 +1973,9 @@ static void rtl8139_rx_interrupt (struct * Theoretically, this should never happen * since EarlyRx is disabled. */ - if (rx_size == 0xfff0) { + if (unlikely(rx_size == 0xfff0)) { tp->xstats.early_rx++; - break; + goto done; } /* If Rx err or invalid rx_size/rx_status received @@ -1940,55 +1983,69 @@ static void rtl8139_rx_interrupt (struct * Rx process gets reset, so we abort any further * Rx processing. */ - if ((rx_size > (MAX_ETH_FRAME_SIZE+4)) || - (rx_size < 8) || - (!(rx_status & RxStatusOK))) { + if (unlikely((rx_size > (MAX_ETH_FRAME_SIZE+4)) || + (rx_size < 8) || + (!(rx_status & RxStatusOK)))) { rtl8139_rx_err (rx_status, dev, tp, ioaddr); - return; + return -1; } /* Malloc up new buffer, compatible with net-2e. */ /* Omit the four octet CRC from the length. */ - /* TODO: consider allocating skb's outside of - * interrupt context, both to speed interrupt processing, - * and also to reduce the chances of having to - * drop packets here under memory pressure. - */ - skb = dev_alloc_skb (pkt_size + 2); - if (skb) { + if (likely(skb)) { skb->dev = dev; skb_reserve (skb, 2); /* 16 byte align the IP fields. */ - +#if CONFIG_8139_RXBUF_IDX == 3 + wrap_copy(skb, rx_ring, ring_offset+4, pkt_size); +#else eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0); +#endif skb_put (skb, pkt_size); skb->protocol = eth_type_trans (skb, dev); - netif_rx (skb); + dev->last_rx = jiffies; tp->stats.rx_bytes += pkt_size; tp->stats.rx_packets++; + + netif_receive_skb (skb); } else { - printk (KERN_WARNING - "%s: Memory squeeze, dropping packet.\n", - dev->name); + if (net_ratelimit()) + printk (KERN_WARNING + "%s: Memory squeeze, dropping packet.\n", + dev->name); tp->stats.rx_dropped++; } + received++; cur_rx = (cur_rx + rx_size + 4 + 3) & ~3; - RTL_W16 (RxBufPtr, cur_rx - 16); + RTL_W16 (RxBufPtr, (u16) (cur_rx - 16)); - if (RTL_R16 (IntrStatus) & RxAckBits) + /* Clear out errors and receive interrupts */ + status = RTL_R16 (IntrStatus) & RxAckBits; + if (likely(status != 0)) { + if (unlikely(status & (RxFIFOOver | RxOverflow))) { + tp->stats.rx_errors++; + if (status & RxFIFOOver) + tp->stats.rx_fifo_errors++; + } RTL_W16_F (IntrStatus, RxAckBits); + } } + done: + +#if RTL8139_DEBUG > 1 DPRINTK ("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x," " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx, RTL_R16 (RxBufAddr), RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd)); +#endif tp->cur_rx = cur_rx; + return received; } @@ -2014,14 +2071,12 @@ static void rtl8139_weird_interrupt (str status &= ~RxUnderrun; } - /* XXX along with rtl8139_rx_err, are we double-counting errors? */ - if (status & - (RxUnderrun | RxOverflow | RxErr | RxFIFOOver)) + if (status & (RxUnderrun | RxErr)) tp->stats.rx_errors++; if (status & PCSTimeout) tp->stats.rx_length_errors++; - if (status & (RxUnderrun | RxFIFOOver)) + if (status & RxUnderrun) tp->stats.rx_fifo_errors++; if (status & PCIErr) { u16 pci_cmd_status; @@ -2033,6 +2088,39 @@ static void rtl8139_weird_interrupt (str } } +static int rtl8139_poll(struct net_device *dev, int *budget) +{ + struct rtl8139_private *tp = dev->priv; + void *ioaddr = tp->mmio_addr; + int orig_budget = min(*budget, dev->quota); + int done = 1; + + spin_lock(&tp->rx_lock); + if (likely(RTL_R16(IntrStatus) & RxAckBits)) { + int work_done; + + work_done = rtl8139_rx(dev, tp, orig_budget); + if (likely(work_done > 0)) { + *budget -= work_done; + dev->quota -= work_done; + done = (work_done < orig_budget); + } + } + + if (done) { + /* + * Order is important since data can get interrupted + * again when we think we are done. + */ + local_irq_disable(); + RTL_W16_F(IntrMask, rtl8139_intr_mask); + __netif_rx_complete(dev); + local_irq_enable(); + } + spin_unlock(&tp->rx_lock); + + return !done; +} /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ @@ -2041,68 +2129,59 @@ static irqreturn_t rtl8139_interrupt (in { struct net_device *dev = (struct net_device *) dev_instance; struct rtl8139_private *tp = dev->priv; - int boguscnt = max_interrupt_work; void *ioaddr = tp->mmio_addr; - int ackstat, status; + u16 status, ackstat; int link_changed = 0; /* avoid bogus "uninit" warning */ int handled = 0; spin_lock (&tp->lock); + status = RTL_R16 (IntrStatus); - do { - status = RTL_R16 (IntrStatus); + /* shared irq? */ + if (unlikely((status & rtl8139_intr_mask) == 0)) + goto out; - /* h/w no longer present (hotplug?) or major error, bail */ - if (status == 0xFFFF) - break; + handled = 1; - if ((status & - (PCIErr | PCSTimeout | RxUnderrun | RxOverflow | - RxFIFOOver | TxErr | TxOK | RxErr | RxOK)) == 0) - break; + /* h/w no longer present (hotplug?) or major error, bail */ + if (unlikely(status == 0xFFFF)) + goto out; - handled = 1; + /* close possible race's with dev_close */ + if (unlikely(!netif_running(dev))) { + RTL_W16 (IntrMask, 0); + goto out; + } - /* Acknowledge all of the current interrupt sources ASAP, but - an first get an additional status bit from CSCR. */ - if (status & RxUnderrun) - link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit; + /* Acknowledge all of the current interrupt sources ASAP, but + an first get an additional status bit from CSCR. */ + if (unlikely(status & RxUnderrun)) + link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit; - /* The chip takes special action when we clear RxAckBits, - * so we clear them later in rtl8139_rx_interrupt - */ - ackstat = status & ~(RxAckBits | TxErr); + ackstat = status & ~(RxAckBits | TxErr); + if (ackstat) RTL_W16 (IntrStatus, ackstat); - DPRINTK ("%s: interrupt status=%#4.4x ackstat=%#4.4x new intstat=%#4.4x.\n", - dev->name, status, ackstat, RTL_R16 (IntrStatus)); - - if (netif_running (dev) && (status & RxAckBits)) - rtl8139_rx_interrupt (dev, tp, ioaddr); - - /* Check uncommon events with one test. */ - if (status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow | - RxFIFOOver | RxErr)) - rtl8139_weird_interrupt (dev, tp, ioaddr, - status, link_changed); - - if (netif_running (dev) && (status & (TxOK | TxErr))) { - rtl8139_tx_interrupt (dev, tp, ioaddr); - if (status & TxErr) - RTL_W16 (IntrStatus, TxErr); + /* Receive packets are processed by poll routine. + If not running start it now. */ + if (status & RxAckBits){ + if (netif_rx_schedule_prep(dev)) { + RTL_W16_F (IntrMask, rtl8139_norx_intr_mask); + __netif_rx_schedule (dev); } - - boguscnt--; - } while (boguscnt > 0); - - if (boguscnt <= 0) { - printk (KERN_WARNING "%s: Too much work at interrupt, " - "IntrStatus=0x%4.4x.\n", dev->name, status); - - /* Clear all interrupt sources. */ - RTL_W16 (IntrStatus, 0xffff); } + /* Check uncommon events with one test. */ + if (unlikely(status & (PCIErr | PCSTimeout | RxUnderrun | RxErr))) + rtl8139_weird_interrupt (dev, tp, ioaddr, + status, link_changed); + + if (status & (TxOK | TxErr)) { + rtl8139_tx_interrupt (dev, tp, ioaddr); + if (status & TxErr) + RTL_W16 (IntrStatus, TxErr); + } + out: spin_unlock (&tp->lock); DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n", @@ -2110,6 +2189,18 @@ static irqreturn_t rtl8139_interrupt (in return IRQ_RETVAL(handled); } +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling receive - used by netconsole and other diagnostic tools + * to allow network i/o with interrupts disabled. + */ +static void rtl8139_poll_controller(struct net_device *dev) +{ + disable_irq(dev->irq); + rtl8139_interrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif static int rtl8139_close (struct net_device *dev) { @@ -2130,8 +2221,9 @@ static int rtl8139_close (struct net_dev } wait_for_completion (&tp->thr_exited); } - - DPRINTK ("%s: Shutting down ethercard, status was 0x%4.4x.\n", + + if (netif_msg_ifdown(tp)) + printk(KERN_DEBUG "%s: Shutting down ethercard, status was 0x%4.4x.\n", dev->name, RTL_R16 (IntrStatus)); spin_lock_irqsave (&tp->lock, flags); @@ -2289,12 +2381,14 @@ static u32 rtl8139_get_link(struct net_d static u32 rtl8139_get_msglevel(struct net_device *dev) { - return debug; + struct rtl8139_private *np = dev->priv; + return np->msg_enable; } static void rtl8139_set_msglevel(struct net_device *dev, u32 datum) { - debug = datum; + struct rtl8139_private *np = dev->priv; + np->msg_enable = datum; } /* TODO: we are too slack to do reg dumping for pio, for now */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/82596.c 830-ivtv/drivers/net/82596.c --- 000-virgin/drivers/net/82596.c Wed Aug 13 20:24:24 2003 +++ 830-ivtv/drivers/net/82596.c Thu Jan 8 08:54:06 2004 @@ -1129,21 +1129,40 @@ static void print_eth(unsigned char *add printk(" %02X%02X, %s\n", add[12], add[13], str); } -int __init i82596_probe(struct net_device *dev) +static int io = 0x300; +static int irq = 10; + +struct net_device * __init i82596_probe(int unit) { + struct net_device *dev; int i; struct i596_private *lp; char eth_addr[8]; static int probed; + int err; if (probed) - return -ENODEV; + return ERR_PTR(-ENODEV); probed++; + + dev = alloc_etherdev(0); + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } else { + dev->base_addr = io; + dev->irq = irq; + } + #ifdef ENABLE_MVME16x_NET if (MACH_IS_MVME16x) { if (mvme16x_config & MVME16x_CONFIG_NO_ETHERNET) { printk(KERN_NOTICE "Ethernet probe disabled - chip not present\n"); - return -ENODEV; + err = -ENODEV; + goto out; } memcpy(eth_addr, (void *) 0xfffc1f2c, 6); /* YUCK! Get addr from NOVRAM */ dev->base_addr = MVME_I596_BASE; @@ -1174,7 +1193,8 @@ int __init i82596_probe(struct net_devic if (!request_region(ioaddr, I596_TOTAL_SIZE, dev->name)) { printk(KERN_ERR "82596: IO address 0x%04x in use\n", ioaddr); - return -EBUSY; + err = -EBUSY; + goto out; } for (i = 0; i < 8; i++) { @@ -1190,8 +1210,8 @@ int __init i82596_probe(struct net_devic if ((checksum % 0x100) || (memcmp(eth_addr, "\x00\x00\x49", 3) != 0)) { - release_region(ioaddr, I596_TOTAL_SIZE); - return -ENODEV; + err = -ENODEV; + goto out1; } dev->base_addr = ioaddr; @@ -1200,13 +1220,10 @@ int __init i82596_probe(struct net_devic #endif dev->mem_start = (int)__get_free_pages(GFP_ATOMIC, 0); if (!dev->mem_start) { -#ifdef ENABLE_APRICOT - release_region(dev->base_addr, I596_TOTAL_SIZE); -#endif - return -ENOMEM; + err = -ENOMEM; + goto out1; } - ether_setup(dev); DEB(DEB_PROBE,printk(KERN_INFO "%s: 82596 at %#3lx,", dev->name, dev->base_addr)); for (i = 0; i < 6; i++) @@ -1244,7 +1261,26 @@ int __init i82596_probe(struct net_devic lp->scb.rfd = I596_NULL; lp->lock = SPIN_LOCK_UNLOCKED; - return 0; + err = register_netdev(dev); + if (err) + goto out2; + return dev; +out2: +#ifdef __mc68000__ + /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING, + * XXX which may be invalid (CONFIG_060_WRITETHROUGH) + */ + kernel_set_cachemode((void *)(dev->mem_start), 4096, + IOMAP_FULL_CACHING); +#endif + free_page ((u32)(dev->mem_start)); +out1: +#ifdef ENABLE_APRICOT + release_region(dev->base_addr, I596_TOTAL_SIZE); +#endif +out: + free_netdev(dev); + return ERR_PTR(err); } static irqreturn_t i596_interrupt(int irq, void *dev_id, struct pt_regs *regs) @@ -1532,11 +1568,9 @@ static void set_multicast_list(struct ne } #ifdef MODULE -static struct net_device dev_82596 = { .init = i82596_probe }; +static struct net_device *dev_82596; #ifdef ENABLE_APRICOT -static int io = 0x300; -static int irq = 10; MODULE_PARM(irq, "i"); MODULE_PARM_DESC(irq, "Apricot IRQ number"); #endif @@ -1547,34 +1581,31 @@ static int debug = -1; int init_module(void) { -#ifdef ENABLE_APRICOT - dev_82596.base_addr = io; - dev_82596.irq = irq; -#endif if (debug >= 0) i596_debug = debug; - if (register_netdev(&dev_82596) != 0) - return -EIO; + dev_82596 = i82596_probe(-1); + if (IS_ERR(dev_82596)) + return PTR_ERR(dev_82596); return 0; } void cleanup_module(void) { - unregister_netdev(&dev_82596); + unregister_netdev(dev_82596); #ifdef __mc68000__ /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING, * XXX which may be invalid (CONFIG_060_WRITETHROUGH) */ - kernel_set_cachemode((void *)(dev_82596.mem_start), 4096, + kernel_set_cachemode((void *)(dev_82596->mem_start), 4096, IOMAP_FULL_CACHING); #endif - free_page ((u32)(dev_82596.mem_start)); - dev_82596.priv = NULL; + free_page ((u32)(dev_82596->mem_start)); #ifdef ENABLE_APRICOT /* If we don't do this, we can't re-insmod it later. */ - release_region(dev_82596.base_addr, I596_TOTAL_SIZE); + release_region(dev_82596->base_addr, I596_TOTAL_SIZE); #endif + free_netdev(dev_82596); } #endif /* MODULE */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/8390.c 830-ivtv/drivers/net/8390.c --- 000-virgin/drivers/net/8390.c Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/8390.c Thu Jan 8 08:54:06 2004 @@ -157,15 +157,8 @@ static void do_set_multicast_list(struct int ei_open(struct net_device *dev) { unsigned long flags; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); - /* This can't happen unless somebody forgot to call ethdev_init(). */ - if (ei_local == NULL) - { - printk(KERN_EMERG "%s: ei_open passed a non-existent device!\n", dev->name); - return -ENXIO; - } - /* The card I/O part of the driver (e.g. 3c503) can hook a Tx timeout wrapper that does e.g. media check & then calls ei_tx_timeout. */ if (dev->tx_timeout == NULL) @@ -196,7 +189,7 @@ int ei_open(struct net_device *dev) */ int ei_close(struct net_device *dev) { - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned long flags; /* @@ -221,7 +214,7 @@ int ei_close(struct net_device *dev) void ei_tx_timeout(struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); int txsr, isr, tickssofar = jiffies - dev->trans_start; unsigned long flags; @@ -267,7 +260,7 @@ void ei_tx_timeout(struct net_device *de static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); int length, send_length, output_page; unsigned long flags; char scratch[ETH_ZLEN]; @@ -435,7 +428,7 @@ irqreturn_t ei_interrupt(int irq, void * } e8390_base = dev->base_addr; - ei_local = (struct ei_device *) dev->priv; + ei_local = (struct ei_device *) netdev_priv(dev); /* * Protect the irq test too. @@ -540,7 +533,7 @@ irqreturn_t ei_interrupt(int irq, void * static void ei_tx_err(struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned char txsr = inb_p(e8390_base+EN0_TSR); unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU); @@ -583,7 +576,7 @@ static void ei_tx_err(struct net_device static void ei_tx_intr(struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); int status = inb(e8390_base + EN0_TSR); outb_p(ENISR_TX, e8390_base + EN0_ISR); /* Ack intr. */ @@ -675,7 +668,7 @@ static void ei_tx_intr(struct net_device static void ei_receive(struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned char rxing_page, this_frame, next_frame; unsigned short current_offset; int rx_pkt_count = 0; @@ -813,7 +806,7 @@ static void ei_rx_overrun(struct net_dev { long e8390_base = dev->base_addr; unsigned char was_txing, must_resend = 0; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); /* * Record whether a Tx was in progress and then issue the @@ -881,7 +874,7 @@ static void ei_rx_overrun(struct net_dev static struct net_device_stats *get_stats(struct net_device *dev) { long ioaddr = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned long flags; /* If the card is stopped, just return the present stats. */ @@ -936,7 +929,7 @@ static void do_set_multicast_list(struct { long e8390_base = dev->base_addr; int i; - struct ei_device *ei_local = (struct ei_device*)dev->priv; + struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev); if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) { @@ -990,53 +983,34 @@ static void do_set_multicast_list(struct static void set_multicast_list(struct net_device *dev) { unsigned long flags; - struct ei_device *ei_local = (struct ei_device*)dev->priv; + struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev); spin_lock_irqsave(&ei_local->page_lock, flags); do_set_multicast_list(dev); spin_unlock_irqrestore(&ei_local->page_lock, flags); } -static inline void ei_device_init(struct ei_device *ei_local) -{ - spin_lock_init(&ei_local->page_lock); -} - /** - * ethdev_init - init rest of 8390 device struct + * ethdev_setup - init rest of 8390 device struct * @dev: network device structure to init * * Initialize the rest of the 8390 device structure. Do NOT __init * this, as it is used by 8390 based modular drivers too. */ -int ethdev_init(struct net_device *dev) +static void ethdev_setup(struct net_device *dev) { + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); if (ei_debug > 1) printk(version); - if (dev->priv == NULL) - { - dev->priv = kmalloc(sizeof(struct ei_device), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct ei_device)); - ei_device_init(dev->priv); - } - dev->hard_start_xmit = &ei_start_xmit; dev->get_stats = get_stats; dev->set_multicast_list = &set_multicast_list; ether_setup(dev); - - return 0; -} -/* wrapper to make alloc_netdev happy; probably should just cast... */ -static void __ethdev_init(struct net_device *dev) -{ - ethdev_init(dev); + spin_lock_init(&ei_local->page_lock); } /** @@ -1044,15 +1018,10 @@ static void __ethdev_init(struct net_dev * * Allocate 8390-specific net_device. */ -struct net_device *alloc_ei_netdev(void) +struct net_device *__alloc_ei_netdev(int size) { - struct net_device *dev; - - dev = alloc_netdev(sizeof(struct ei_device), "eth%d", __ethdev_init); - if (dev) - ei_device_init(dev->priv); - - return dev; + return alloc_netdev(sizeof(struct ei_device) + size, "eth%d", + ethdev_setup); } @@ -1072,7 +1041,7 @@ struct net_device *alloc_ei_netdev(void) void NS8390_init(struct net_device *dev, int startp) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); int i; int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS | (ei_local->bigendian ? ENDCFG_BOS : 0)) @@ -1136,7 +1105,7 @@ static void NS8390_trigger_send(struct n int start_page) { long e8390_base = dev->base_addr; - struct ei_device *ei_local __attribute((unused)) = (struct ei_device *) dev->priv; + struct ei_device *ei_local __attribute((unused)) = (struct ei_device *) netdev_priv(dev); outb_p(E8390_NODMA+E8390_PAGE0, e8390_base+E8390_CMD); @@ -1156,9 +1125,8 @@ EXPORT_SYMBOL(ei_open); EXPORT_SYMBOL(ei_close); EXPORT_SYMBOL(ei_interrupt); EXPORT_SYMBOL(ei_tx_timeout); -EXPORT_SYMBOL(ethdev_init); EXPORT_SYMBOL(NS8390_init); -EXPORT_SYMBOL(alloc_ei_netdev); +EXPORT_SYMBOL(__alloc_ei_netdev); #if defined(MODULE) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/8390.h 830-ivtv/drivers/net/8390.h --- 000-virgin/drivers/net/8390.h Mon Nov 17 18:28:14 2003 +++ 830-ivtv/drivers/net/8390.h Thu Jan 8 08:54:06 2004 @@ -39,12 +39,15 @@ extern int ei_debug; #define ei_debug 1 #endif -extern int ethdev_init(struct net_device *dev); extern void NS8390_init(struct net_device *dev, int startp); extern int ei_open(struct net_device *dev); extern int ei_close(struct net_device *dev); extern irqreturn_t ei_interrupt(int irq, void *dev_id, struct pt_regs *regs); -extern struct net_device *alloc_ei_netdev(void); +extern struct net_device *__alloc_ei_netdev(int size); +static inline struct net_device *alloc_ei_netdev(void) +{ + return __alloc_ei_netdev(0); +} /* You have one of these per-board */ struct ei_device { @@ -84,7 +87,7 @@ struct ei_device { /* The maximum time waited (in jiffies) before assuming a Tx failed. (20ms) */ #define TX_TIMEOUT (20*HZ/100) -#define ei_status (*(struct ei_device *)(dev->priv)) +#define ei_status (*(struct ei_device *)netdev_priv(dev)) /* Some generic ethernet register configurations. */ #define E8390_TX_IRQ_MASK 0xa /* For register EN0_ISR */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/Kconfig 830-ivtv/drivers/net/Kconfig --- 000-virgin/drivers/net/Kconfig Mon Nov 17 18:29:42 2003 +++ 830-ivtv/drivers/net/Kconfig Thu Jan 8 08:54:07 2004 @@ -657,7 +657,7 @@ config ELMC config ELMC_II tristate "3c527 \"EtherLink/MC 32\" support (EXPERIMENTAL)" - depends on NET_VENDOR_3COM && MCA && EXPERIMENTAL && BROKEN_ON_SMP + depends on NET_VENDOR_3COM && MCA && MCA_LEGACY help If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from @@ -1283,6 +1283,19 @@ config B44 . The module will be called b44. +config FORCEDETH + tristate "Reverse Engineered nForce Ethernet support (EXPERIMENTAL)" + depends on NET_PCI && PCI && EXPERIMENTAL + help + If you have a network (Ethernet) controller of this type, say Y and + read the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here and read + . The module will be + called forcedeth. + + config CS89x0 tristate "CS89x0 support" depends on NET_PCI && ISA @@ -1341,8 +1354,9 @@ config EEPRO100_PIO say N. config E100 - tristate "EtherExpressPro/100 support (e100, Alternate Intel driver)" + tristate "Intel(R) PRO/100+ support" depends on NET_PCI && PCI + select MII ---help--- This driver supports Intel(R) PRO/100 family of adapters, which includes: @@ -1415,6 +1429,10 @@ config E100 . The module will be called e100. +config E100_NAPI + bool "Use Rx Polling (NAPI)" + depends on E100 + config LNE390 tristate "Mylex EISA LNE390A/B support (EXPERIMENTAL)" depends on NET_PCI && EISA && EXPERIMENTAL @@ -1564,6 +1582,24 @@ config 8139_OLD_RX_RESET experience problems, you can enable this option to restore the old RX-reset behavior. If unsure, say N. +config 8139_RXBUF_IDX + int "Receive ring size (0 => 8K, 1 => 16K, 2 => 32K, 3 => 64K)" + depends on 8139TOO + range 0 3 + default 1 if EMBEDDED || SH_DREAMCAST + default 2 + help + The 8139too driver has a fixed area of memory for receiving data. + The default value is adequate for most systems. The 64KB + ring size has hardware issues that may cause problems. + Values: + 0 => 8 KB + 1 => 16 KB embedded systems + 2 => 32 KB default for most systems + 3 => 64 KB + If unsure, use the default 2. + + config SIS900 tristate "SiS 900/7016 PCI Fast Ethernet Adapter support" depends on NET_PCI && PCI @@ -1957,9 +1993,11 @@ config SK98LIN - EG1032 v2 Instant Gigabit Network Adapter - EG1064 v2 Instant Gigabit Network Adapter - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Abit) + - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Albatron) - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Asus) - Marvell 88E8001 Gigabit LOM Ethernet Adapter (ECS) - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Epox) + - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Foxconn) - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Gigabyte) - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Iwill) - Marvell RDK-8001 Adapter @@ -2005,8 +2043,10 @@ config SK98LIN Questions concerning this driver may be addressed to: linux@syskonnect.de - To compile this driver as a module, choose M here: the module - will be called sk98lin. This is recommended. + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. This is recommended. + The module will be called sk98lin. This is recommended. config TIGON3 tristate "Broadcom Tigon3 support" @@ -2440,6 +2480,13 @@ config SHAPER To compile this driver as a module, choose M here: the module will be called shaper. If unsure, say N. + +config NETCONSOLE + tristate "Network console logging support (EXPERIMENTAL)" + depends on NETDEVICES && EXPERIMENTAL + ---help--- + If you want to log kernel messages over the network, enable this. + See Documentation/networking/netconsole.txt for details. source "drivers/net/wan/Kconfig" diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/Makefile 830-ivtv/drivers/net/Makefile --- 000-virgin/drivers/net/Makefile Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/Makefile Thu Jan 8 09:30:18 2004 @@ -8,7 +8,6 @@ ifeq ($(CONFIG_ISDN_PPP),y) obj-$(CONFIG_ISDN) += slhc.o endif -obj-$(CONFIG_E100) += e100/ obj-$(CONFIG_E1000) += e1000/ obj-$(CONFIG_IXGB) += ixgb/ obj-$(CONFIG_BONDING) += bonding/ @@ -39,6 +38,7 @@ obj-$(CONFIG_TYPHOON) += typhoon.o obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o obj-$(CONFIG_PCNET32) += pcnet32.o obj-$(CONFIG_EEPRO100) += eepro100.o +obj-$(CONFIG_E100) += e100.o obj-$(CONFIG_TLAN) += tlan.o obj-$(CONFIG_EPIC100) += epic100.o obj-$(CONFIG_SIS190) += sis190.o @@ -95,6 +95,7 @@ obj-$(CONFIG_LNE390) += lne390.o 8390.o obj-$(CONFIG_NE3210) += ne3210.o 8390.o obj-$(CONFIG_NET_SB1250_MAC) += sb1250-mac.o obj-$(CONFIG_B44) += b44.o +obj-$(CONFIG_FORCEDETH) += forcedeth.o obj-$(CONFIG_PPP) += ppp_generic.o slhc.o obj-$(CONFIG_PPP_ASYNC) += ppp_async.o @@ -111,7 +112,6 @@ endif obj-$(CONFIG_DUMMY) += dummy.o obj-$(CONFIG_DE600) += de600.o obj-$(CONFIG_DE620) += de620.o -obj-$(CONFIG_AT1500) += lance.o obj-$(CONFIG_LANCE) += lance.o obj-$(CONFIG_SUN3_82586) += sun3_82586.o obj-$(CONFIG_SUN3LANCE) += sun3lance.o @@ -188,3 +188,6 @@ obj-$(CONFIG_NET_TULIP) += tulip/ obj-$(CONFIG_HAMRADIO) += hamradio/ obj-$(CONFIG_IRDA) += irda/ +# Must come after all NICs that might use them +obj-$(CONFIG_NETCONSOLE) += netconsole.o +obj-$(CONFIG_KGDB) += kgdb_eth.o diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/Space.c 830-ivtv/drivers/net/Space.c --- 000-virgin/drivers/net/Space.c Thu Jan 8 08:35:37 2004 +++ 830-ivtv/drivers/net/Space.c Thu Jan 8 09:28:25 2004 @@ -40,63 +40,62 @@ ethernet adaptor have the name "eth[0123...]". */ -extern int ne2_probe(struct net_device *dev); -extern int hp100_probe(struct net_device *dev); -extern int ultra_probe(struct net_device *dev); -extern int ultra32_probe(struct net_device *dev); -extern int wd_probe(struct net_device *dev); -extern int el2_probe(struct net_device *dev); -extern int ne_probe(struct net_device *dev); -extern int hp_probe(struct net_device *dev); -extern int hp_plus_probe(struct net_device *dev); -extern int express_probe(struct net_device *); -extern int eepro_probe(struct net_device *); -extern int at1500_probe(struct net_device *); -extern int at1700_probe(struct net_device *); -extern int fmv18x_probe(struct net_device *); -extern int eth16i_probe(struct net_device *); -extern int i82596_probe(struct net_device *); -extern int ewrk3_probe(struct net_device *); -extern int el1_probe(struct net_device *); -extern int wavelan_probe(struct net_device *); -extern int arlan_probe(struct net_device *); -extern int el16_probe(struct net_device *); -extern int elmc_probe(struct net_device *); -extern int skmca_probe(struct net_device *); -extern int elplus_probe(struct net_device *); -extern int ac3200_probe(struct net_device *); -extern int es_probe(struct net_device *); -extern int lne390_probe(struct net_device *); -extern int e2100_probe(struct net_device *); -extern int ni5010_probe(struct net_device *); -extern int ni52_probe(struct net_device *); -extern int ni65_probe(struct net_device *); -extern int sonic_probe(struct net_device *); -extern int SK_init(struct net_device *); -extern int seeq8005_probe(struct net_device *); -extern int smc_init( struct net_device * ); -extern int atarilance_probe(struct net_device *); -extern int sun3lance_probe(struct net_device *); -extern int sun3_82586_probe(struct net_device *); -extern int apne_probe(struct net_device *); -extern int bionet_probe(struct net_device *); -extern int pamsnet_probe(struct net_device *); -extern int cs89x0_probe(struct net_device *dev); -extern int hplance_probe(struct net_device *dev); -extern int bagetlance_probe(struct net_device *); -extern int mvme147lance_probe(struct net_device *dev); -extern int tc515_probe(struct net_device *dev); -extern int lance_probe(struct net_device *dev); -extern int mace_probe(struct net_device *dev); -extern int macsonic_probe(struct net_device *dev); -extern int mac8390_probe(struct net_device *dev); -extern int mac89x0_probe(struct net_device *dev); -extern int mc32_probe(struct net_device *dev); +extern struct net_device *ne2_probe(int unit); +extern struct net_device *hp100_probe(int unit); +extern struct net_device *ultra_probe(int unit); +extern struct net_device *ultra32_probe(int unit); +extern struct net_device *wd_probe(int unit); +extern struct net_device *el2_probe(int unit); +extern struct net_device *ne_probe(int unit); +extern struct net_device *hp_probe(int unit); +extern struct net_device *hp_plus_probe(int unit); +extern struct net_device *express_probe(int unit); +extern struct net_device *eepro_probe(int unit); +extern struct net_device *at1700_probe(int unit); +extern struct net_device *fmv18x_probe(int unit); +extern struct net_device *eth16i_probe(int unit); +extern struct net_device *i82596_probe(int unit); +extern struct net_device *ewrk3_probe(int unit); +extern struct net_device *el1_probe(int unit); +extern struct net_device *wavelan_probe(int unit); +extern struct net_device *arlan_probe(int unit); +extern struct net_device *el16_probe(int unit); +extern struct net_device *elmc_probe(int unit); +extern struct net_device *skmca_probe(int unit); +extern struct net_device *elplus_probe(int unit); +extern struct net_device *ac3200_probe(int unit); +extern struct net_device *es_probe(int unit); +extern struct net_device *lne390_probe(int unit); +extern struct net_device *e2100_probe(int unit); +extern struct net_device *ni5010_probe(int unit); +extern struct net_device *ni52_probe(int unit); +extern struct net_device *ni65_probe(int unit); +extern struct net_device *sonic_probe(int unit); +extern struct net_device *SK_init(int unit); +extern struct net_device *seeq8005_probe(int unit); +extern struct net_device *smc_init(int unit); +extern struct net_device *atarilance_probe(int unit); +extern struct net_device *sun3lance_probe(int unit); +extern struct net_device *sun3_82586_probe(int unit); +extern struct net_device *apne_probe(int unit); +extern struct net_device *bionet_probe(int unit); +extern struct net_device *pamsnet_probe(int unit); +extern struct net_device *cs89x0_probe(int unit); +extern struct net_device *hplance_probe(int unit); +extern struct net_device *bagetlance_probe(int unit); +extern struct net_device *mvme147lance_probe(int unit); +extern struct net_device *tc515_probe(int unit); +extern struct net_device *lance_probe(int unit); +extern struct net_device *mace_probe(int unit); +extern struct net_device *macsonic_probe(int unit); +extern struct net_device *mac8390_probe(int unit); +extern struct net_device *mac89x0_probe(int unit); +extern struct net_device *mc32_probe(int unit); extern struct net_device *cops_probe(int unit); extern struct net_device *ltpc_probe(void); /* Detachable devices ("pocket adaptors") */ -extern int de620_probe(struct net_device *); +extern struct net_device *de620_probe(int unit); /* Fibre Channel adapters */ extern int iph5526_probe(struct net_device *dev); @@ -104,33 +103,22 @@ extern int iph5526_probe(struct net_devi /* SBNI adapters */ extern int sbni_probe(int unit); -struct devprobe -{ - int (*probe)(struct net_device *dev); +struct devprobe2 { + struct net_device *(*probe)(int unit); int status; /* non-zero if autoprobe has failed */ }; -/* - * probe_list walks a list of probe functions and calls each so long - * as a non-zero ioaddr is given, or as long as it hasn't already failed - * to find a card in the past (as recorded by "status") when asked to - * autoprobe (i.e. a probe that fails to find a card when autoprobing - * will not be asked to autoprobe again). It exits when a card is found. - */ -static int __init probe_list(struct net_device *dev, struct devprobe *plist) +static int __init probe_list2(int unit, struct devprobe2 *p, int autoprobe) { - struct devprobe *p = plist; - unsigned long base_addr = dev->base_addr; - - while (p->probe != NULL) { - if (base_addr && p->probe(dev) == 0) /* probe given addr */ + struct net_device *dev; + for (; p->probe; p++) { + if (autoprobe && p->status) + continue; + dev = p->probe(unit); + if (!IS_ERR(dev)) return 0; - else if (p->status == 0) { /* has autoprobe failed yet? */ - p->status = p->probe(dev); /* no, try autoprobe */ - if (p->status == 0) - return 0; - } - p++; + if (autoprobe) + p->status = PTR_ERR(dev); } return -ENODEV; } @@ -141,7 +129,8 @@ static int __init probe_list(struct net_ * drivers that probe for EISA cards (in the ISA group). These are the * legacy EISA only driver probes, and also the legacy PCI probes */ -static struct devprobe eisa_probes[] __initdata = { + +static struct devprobe2 eisa_probes[] __initdata = { #ifdef CONFIG_ULTRA32 {ultra32_probe, 0}, #endif @@ -157,8 +146,7 @@ static struct devprobe eisa_probes[] __i {NULL, 0}, }; - -static struct devprobe mca_probes[] __initdata = { +static struct devprobe2 mca_probes[] __initdata = { #ifdef CONFIG_NE2_MCA {ne2_probe, 0}, #endif @@ -178,7 +166,7 @@ static struct devprobe mca_probes[] __in * ISA probes that touch addresses < 0x400 (including those that also * look for EISA/PCI/MCA cards in addition to ISA cards). */ -static struct devprobe isa_probes[] __initdata = { +static struct devprobe2 isa_probes[] __initdata = { #ifdef CONFIG_HP100 /* ISA, EISA & PCI */ {hp100_probe, 0}, #endif @@ -215,9 +203,6 @@ static struct devprobe isa_probes[] __in #ifdef CONFIG_SEEQ8005 {seeq8005_probe, 0}, #endif -#ifdef CONFIG_AT1500 - {at1500_probe, 0}, -#endif #ifdef CONFIG_CS89x0 {cs89x0_probe, 0}, #endif @@ -272,14 +257,14 @@ static struct devprobe isa_probes[] __in {NULL, 0}, }; -static struct devprobe parport_probes[] __initdata = { +static struct devprobe2 parport_probes[] __initdata = { #ifdef CONFIG_DE620 /* D-Link DE-620 adapter */ {de620_probe, 0}, #endif {NULL, 0}, }; -static struct devprobe m68k_probes[] __initdata = { +static struct devprobe2 m68k_probes[] __initdata = { #ifdef CONFIG_ATARILANCE /* Lance-based Atari ethernet boards */ {atarilance_probe, 0}, #endif @@ -319,7 +304,7 @@ static struct devprobe m68k_probes[] __i {NULL, 0}, }; -static struct devprobe mips_probes[] __initdata = { +static struct devprobe2 mips_probes[] __initdata = { #ifdef CONFIG_MIPS_JAZZ_SONIC {sonic_probe, 0}, #endif @@ -334,83 +319,65 @@ static struct devprobe mips_probes[] __i * per bus interface. This drives the legacy devices only for now. */ -static int __init ethif_probe(int unit) +static void __init ethif_probe2(int unit) { - struct net_device *dev; - int err = -ENODEV; + unsigned long base_addr = netdev_boot_base("eth", unit); - dev = alloc_etherdev(0); - if (!dev) - return -ENOMEM; - - sprintf(dev->name, "eth%d", unit); - netdev_boot_setup_check(dev); - - /* - * Backwards compatibility - historically an I/O base of 1 was - * used to indicate not to probe for this ethN interface - */ - if (__dev_get_by_name(dev->name) || dev->base_addr == 1) { - free_netdev(dev); - return -ENXIO; - } - - /* - * The arch specific probes are 1st so that any on-board ethernet - * will be probed before other ISA/EISA/MCA/PCI bus cards. - */ - if (probe_list(dev, m68k_probes) == 0 || - probe_list(dev, mips_probes) == 0 || - probe_list(dev, eisa_probes) == 0 || - probe_list(dev, mca_probes) == 0 || - probe_list(dev, isa_probes) == 0 || - probe_list(dev, parport_probes) == 0) - err = register_netdev(dev); - - if (err) - free_netdev(dev); - return err; + if (base_addr == 1) + return; + (void)( probe_list2(unit, m68k_probes, base_addr == 0) && + probe_list2(unit, mips_probes, base_addr == 0) && + probe_list2(unit, eisa_probes, base_addr == 0) && + probe_list2(unit, mca_probes, base_addr == 0) && + probe_list2(unit, isa_probes, base_addr == 0) && + probe_list2(unit, parport_probes, base_addr == 0)); } #ifdef CONFIG_TR /* Token-ring device probe */ -extern int ibmtr_probe(struct net_device *); -extern int sk_isa_probe(struct net_device *); -extern int proteon_probe(struct net_device *); -extern int smctr_probe(struct net_device *); +extern int ibmtr_probe_card(struct net_device *); +extern struct net_device *sk_isa_probe(int unit); +extern struct net_device *proteon_probe(int unit); +extern struct net_device *smctr_probe(int unit); + +static struct devprobe2 tr_probes2[] __initdata = { +#ifdef CONFIG_SKISA + {sk_isa_probe, 0}, +#endif +#ifdef CONFIG_PROTEON + {proteon_probe, 0}, +#endif +#ifdef CONFIG_SMCTR + {smctr_probe, 0}, +#endif + {NULL, 0}, +}; static __init int trif_probe(int unit) { - struct net_device *dev; int err = -ENODEV; - - dev = alloc_trdev(0); +#ifdef CONFIG_IBMTR + struct net_device *dev = alloc_trdev(0); if (!dev) return -ENOMEM; sprintf(dev->name, "tr%d", unit); netdev_boot_setup_check(dev); - if ( -#ifdef CONFIG_IBMTR - ibmtr_probe(dev) == 0 || -#endif -#ifdef CONFIG_SKISA - sk_isa_probe(dev) == 0 || -#endif -#ifdef CONFIG_PROTEON - proteon_probe(dev) == 0 || -#endif -#ifdef CONFIG_SMCTR - smctr_probe(dev) == 0 || -#endif - 0 ) - err = register_netdev(dev); - + err = ibmtr_probe_card(dev); if (err) free_netdev(dev); +#endif return err; +} + +static void __init trif_probe2(int unit) +{ + unsigned long base_addr = netdev_boot_base("tr", unit); + if (base_addr == 1) + return; + probe_list2(unit, tr_probes2, base_addr == 0); } #endif @@ -437,10 +404,11 @@ static int __init net_olddevs_init(void) #endif #ifdef CONFIG_TR for (num = 0; num < 8; ++num) - trif_probe(num); + if (!trif_probe(num)) + trif_probe2(num); #endif for (num = 0; num < 8; ++num) - ethif_probe(num); + ethif_probe2(num); #ifdef CONFIG_COPS cops_probe(0); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/a2065.c 830-ivtv/drivers/net/a2065.c --- 000-virgin/drivers/net/a2065.c Tue Sep 2 09:55:46 2003 +++ 830-ivtv/drivers/net/a2065.c Thu Jan 8 08:54:09 2004 @@ -737,7 +737,7 @@ static int __init a2065_probe(void) continue; } - dev = init_etherdev(NULL, sizeof(struct lance_private)); + dev = alloc_etherdev(sizeof(struct lance_private)); if (dev == NULL) { release_resource(r1); @@ -791,17 +791,22 @@ static int __init a2065_probe(void) dev->set_multicast_list = &lance_set_multicast; dev->dma = 0; -#ifdef MODULE - priv->next_module = root_a2065_dev; - root_a2065_dev = priv; -#endif - ether_setup(dev); init_timer(&priv->multicast_timer); priv->multicast_timer.data = (unsigned long) dev; priv->multicast_timer.function = (void (*)(unsigned long)) &lance_set_multicast; - res = 0; + res = register_netdev(dev); + if (res) { + release_resource(r1); + release_resource(r2); + free_netdev(dev); + break; + } +#ifdef MODULE + priv->next_module = root_a2065_dev; + root_a2065_dev = priv; +#endif } return res; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/ac3200.c 830-ivtv/drivers/net/ac3200.c --- 000-virgin/drivers/net/ac3200.c Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/ac3200.c Thu Jan 8 08:54:09 2004 @@ -75,7 +75,6 @@ static const char *port_name[4] = { "10b #define AC_START_PG 0x00 /* First page of 8390 TX buffer */ #define AC_STOP_PG 0x80 /* Last page +1 of the 8390 RX ring */ -int ac3200_probe(struct net_device *dev); static int ac_probe1(int ioaddr, struct net_device *dev); static int ac_open(struct net_device *dev); @@ -96,9 +95,11 @@ static int ac_close_card(struct net_devi or the unique value in the station address PROM. */ -int __init ac3200_probe(struct net_device *dev) +static int __init do_ac3200_probe(struct net_device *dev) { unsigned short ioaddr = dev->base_addr; + int irq = dev->irq; + int mem_start = dev->mem_start; SET_MODULE_OWNER(dev); @@ -110,13 +111,50 @@ int __init ac3200_probe(struct net_devic if ( ! EISA_bus) return -ENXIO; - for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) + for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) { if (ac_probe1(ioaddr, dev) == 0) return 0; + dev->irq = irq; + dev->mem_start = mem_start; + } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + /* Someday free_irq may be in ac_close_card() */ + free_irq(dev->irq, dev); + release_region(dev->base_addr, AC_IO_EXTENT); + if (ei_status.reg0) + iounmap((void *)dev->mem_start); +} + +struct net_device * __init ac3200_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_ac3200_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init ac_probe1(int ioaddr, struct net_device *dev) { int i, retval; @@ -156,13 +194,6 @@ static int __init ac_probe1(int ioaddr, } #endif - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk (", unable to allocate memory for dev->priv.\n"); - retval = -ENOMEM; - goto out; - } - /* Assign and allocate the interrupt now. */ if (dev->irq == 0) { dev->irq = config2irq(inb(ioaddr + AC_CONFIG)); @@ -210,7 +241,7 @@ static int __init ac_probe1(int ioaddr, printk(KERN_CRIT "ac3200.c: or to an address above 0x%lx.\n", virt_to_phys(high_memory)); printk(KERN_CRIT "ac3200.c: Driver NOT installed.\n"); retval = -EINVAL; - goto out2; + goto out1; } dev->mem_start = (unsigned long)ioremap(dev->mem_start, AC_STOP_PG*0x100); if (dev->mem_start == 0) { @@ -218,7 +249,7 @@ static int __init ac_probe1(int ioaddr, printk(KERN_ERR "ac3200.c: Try using EISA SCU to set memory below 1MB.\n"); printk(KERN_ERR "ac3200.c: Driver NOT installed.\n"); retval = -EINVAL; - goto out2; + goto out1; } ei_status.reg0 = 1; /* Use as remap flag */ printk("ac3200.c: remapped %dkB card memory to virtual address %#lx\n", @@ -247,11 +278,8 @@ static int __init ac_probe1(int ioaddr, dev->stop = &ac_close_card; NS8390_init(dev, 0); return 0; -out2: - free_irq(dev->irq, dev); out1: - kfree(dev->priv); - dev->priv = NULL; + free_irq(dev->irq, dev); out: release_region(ioaddr, AC_IO_EXTENT); return retval; @@ -338,7 +366,7 @@ static int ac_close_card(struct net_devi #ifdef MODULE #define MAX_AC32_CARDS 4 /* Max number of AC32 cards per module */ -static struct net_device dev_ac32[MAX_AC32_CARDS]; +static struct net_device *dev_ac32[MAX_AC32_CARDS]; static int io[MAX_AC32_CARDS]; static int irq[MAX_AC32_CARDS]; static int mem[MAX_AC32_CARDS]; @@ -354,26 +382,32 @@ MODULE_LICENSE("GPL"); int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_AC32_CARDS; this_dev++) { - struct net_device *dev = &dev_ac32[this_dev]; + if (io[this_dev] == 0 && this_dev != 0) + break; + dev = alloc_ei_netdev(); + if (!dev) + break; dev->irq = irq[this_dev]; dev->base_addr = io[this_dev]; dev->mem_start = mem[this_dev]; /* Currently ignored by driver */ - dev->init = ac3200_probe; - /* Default is to only install one card. */ - if (io[this_dev] == 0 && this_dev != 0) break; - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "ac3200.c: No ac3200 card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) { /* Got at least one. */ - return 0; + if (do_ac3200_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_ac32[found++] = dev; + continue; } - return -ENXIO; + cleanup_card(dev); } - found++; + free_netdev(dev); + printk(KERN_WARNING "ac3200.c: No ac3200 card found (i/o = 0x%x).\n", io[this_dev]); + break; } - return 0; + if (found) + return 0; + return -ENXIO; } void @@ -382,16 +416,11 @@ cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < MAX_AC32_CARDS; this_dev++) { - struct net_device *dev = &dev_ac32[this_dev]; - if (dev->priv != NULL) { - /* Someday free_irq may be in ac_close_card() */ - free_irq(dev->irq, dev); - release_region(dev->base_addr, AC_IO_EXTENT); - if (ei_status.reg0) - iounmap((void *)dev->mem_start); + struct net_device *dev = dev_ac32[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(dev->priv); - dev->priv = NULL; + cleanup_card(dev); + free_netdev(dev); } } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/amd8111e.c 830-ivtv/drivers/net/amd8111e.c --- 000-virgin/drivers/net/amd8111e.c Mon Nov 17 18:29:42 2003 +++ 830-ivtv/drivers/net/amd8111e.c Thu Jan 8 08:54:09 2004 @@ -1153,6 +1153,17 @@ err_no_interrupt: return IRQ_RETVAL(handled); } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void amd8111e_poll(struct net_device *dev) +{ + unsigned long flags; + local_save_flags(flags); + local_irq_disable(); + amd8111e_interrupt(0, dev, NULL); + local_irq_restore(flags); +} +#endif + /* This function closes the network interface and updates the statistics so that most recent statistics will be available after the interface is down. */ @@ -1884,6 +1895,9 @@ static int __devinit amd8111e_probe_one( dev->irq =pdev->irq; dev->tx_timeout = amd8111e_tx_timeout; dev->watchdog_timeo = AMD8111E_TX_TIMEOUT; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = amd8111e_poll; +#endif #if AMD8111E_VLAN_TAG_USED dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/apne.c 830-ivtv/drivers/net/apne.c --- 000-virgin/drivers/net/apne.c Fri May 30 19:02:11 2003 +++ 830-ivtv/drivers/net/apne.c Thu Jan 8 08:54:09 2004 @@ -72,7 +72,7 @@ #define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ -int apne_probe(struct net_device *dev); +struct net_device * __init apne_probe(int unit); static int apne_probe1(struct net_device *dev, int ioaddr); static int apne_open(struct net_device *dev); @@ -116,28 +116,37 @@ static const char version[] = static int apne_owned; /* signal if card already owned */ -int __init apne_probe(struct net_device *dev) +struct net_device * __init apne_probe(int unit) { + struct net_device *dev; #ifndef MANUAL_CONFIG char tuple[8]; #endif + int err; if (apne_owned) - return -ENODEV; - - SET_MODULE_OWNER(dev); + return ERR_PTR(-ENODEV); if ( !(AMIGAHW_PRESENT(PCMCIA)) ) - return (-ENODEV); + return ERR_PTR(-ENODEV); printk("Looking for PCMCIA ethernet card : "); /* check if a card is inserted */ if (!(PCMCIA_INSERTED)) { printk("NO PCMCIA card inserted\n"); - return (-ENODEV); + return ERR_PTR(-ENODEV); } - + + dev = alloc_ei_netdev(); + if (!dev) + return ERR_PTR(-ENOMEM); + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } + SET_MODULE_OWNER(dev); + /* disable pcmcia irq for readtuple */ pcmcia_disable_irq(); @@ -145,17 +154,41 @@ int __init apne_probe(struct net_device if ((pcmcia_copy_tuple(CISTPL_FUNCID, tuple, 8) < 3) || (tuple[2] != CISTPL_FUNCID_NETWORK)) { printk("not an ethernet card\n"); - return (-ENODEV); + /* XXX: shouldn't we re-enable irq here? */ + free_netdev(dev); + return ERR_PTR(-ENODEV); } #endif printk("ethernet PCMCIA card inserted\n"); - if (init_pcmcia()) - return apne_probe1(dev, IOBASE); - else - return (-ENODEV); + if (!init_pcmcia()) { + /* XXX: shouldn't we re-enable irq here? */ + free_netdev(dev); + return ERR_PTR(-ENODEV); + } + if (!request_region(IOBASE, 0x20, dev->name)) { + free_netdev(dev); + return ERR_PTR(-EBUSY); + } + + err = apne_probe1(dev, IOBASE); + if (err) { + release_region(IOBASE, 0x20); + free_netdev(dev); + return ERR_PTR(err); + } + err = register_netdev(dev); + if (!err) + return dev; + + pcmcia_disable_irq(); + free_irq(IRQ_AMIGA_PORTS, dev); + pcmcia_reset(); + release_region(IOBASE, 0x20); + free_netdev(dev); + return ERR_PTR(err); } static int __init apne_probe1(struct net_device *dev, int ioaddr) @@ -280,13 +313,6 @@ static int __init apne_probe1(struct net i = request_irq(IRQ_AMIGA_PORTS, apne_interrupt, SA_SHIRQ, dev->name, dev); if (i) return i; - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk (" unable to get memory for dev->priv.\n"); - free_irq(IRQ_AMIGA_PORTS, dev); - return -ENOMEM; - } - for(i = 0; i < ETHER_ADDR_LEN; i++) { printk(" %2.2x", SA_prom[i]); dev->dev_addr[i] = SA_prom[i]; @@ -534,32 +560,27 @@ static irqreturn_t apne_interrupt(int ir } #ifdef MODULE -static struct net_device apne_dev; +static struct net_device *apne_dev; int init_module(void) { - int err; - - apne_dev.init = apne_probe; - if ((err = register_netdev(&apne_dev))) { - if (err == -EIO) - printk("No PCMCIA NEx000 ethernet card found.\n"); - return (err); - } - return (0); + apne_dev = apne_probe(-1); + if (IS_ERR(apne_dev)) + return PTR_ERR(apne_dev); + return 0; } void cleanup_module(void) { - unregister_netdev(&apne_dev); + unregister_netdev(apne_dev); pcmcia_disable_irq(); - free_irq(IRQ_AMIGA_PORTS, &apne_dev); + free_irq(IRQ_AMIGA_PORTS, apne_dev); pcmcia_reset(); - apne_owned = 0; + free_netdev(apne_dev); } #endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/appletalk/ipddp.c 830-ivtv/drivers/net/appletalk/ipddp.c --- 000-virgin/drivers/net/appletalk/ipddp.c Sun Nov 17 20:29:22 2002 +++ 830-ivtv/drivers/net/appletalk/ipddp.c Thu Jan 8 08:54:09 2004 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -55,34 +56,24 @@ static struct ipddp_route* ipddp_find_ro static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); -static int __init ipddp_init(struct net_device *dev) +static struct net_device * __init ipddp_init(void) { static unsigned version_printed; + struct net_device *dev; + int err; + + dev = alloc_etherdev(sizeof(struct net_device_stats)); + if (!dev) + return ERR_PTR(-ENOMEM); SET_MODULE_OWNER(dev); + strcpy(dev->name, "ipddp%d"); if (version_printed++ == 0) printk(version); - /* Let the user now what mode we are in */ - if(ipddp_mode == IPDDP_ENCAP) - printk("%s: Appletalk-IP Encap. mode by Bradford W. Johnson \n", - dev->name); - if(ipddp_mode == IPDDP_DECAP) - printk("%s: Appletalk-IP Decap. mode by Jay Schulist \n", - dev->name); - - /* Fill in the device structure with ethernet-generic values. */ - ether_setup(dev); - /* Initalize the device structure. */ dev->hard_start_xmit = ipddp_xmit; - - dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); - if(!dev->priv) - return -ENOMEM; - memset(dev->priv,0,sizeof(struct net_device_stats)); - dev->get_stats = ipddp_get_stats; dev->do_ioctl = ipddp_ioctl; @@ -97,7 +88,21 @@ static int __init ipddp_init(struct net_ */ dev->hard_header_len = 14+8+sizeof(struct ddpehdr)+1; - return 0; + err = register_netdev(dev); + if (err) { + free_netdev(dev); + return ERR_PTR(err); + } + + /* Let the user now what mode we are in */ + if(ipddp_mode == IPDDP_ENCAP) + printk("%s: Appletalk-IP Encap. mode by Bradford W. Johnson \n", + dev->name); + if(ipddp_mode == IPDDP_DECAP) + printk("%s: Appletalk-IP Decap. mode by Jay Schulist \n", + dev->name); + + return dev; } /* @@ -281,23 +286,16 @@ static int ipddp_ioctl(struct net_device } } -static struct net_device dev_ipddp; +static struct net_device *dev_ipddp; MODULE_LICENSE("GPL"); MODULE_PARM(ipddp_mode, "i"); static int __init ipddp_init_module(void) { - int err; - - dev_ipddp.init = ipddp_init; - err=dev_alloc_name(&dev_ipddp, "ipddp%d"); - if(err < 0) - return err; - - if(register_netdev(&dev_ipddp) != 0) - return -EIO; - + dev_ipddp = ipddp_init(); + if (IS_ERR(dev_ipddp)) + return PTR_ERR(dev_ipddp); return 0; } @@ -305,8 +303,8 @@ static void __exit ipddp_cleanup_module( { struct ipddp_route *p; - unregister_netdev(&dev_ipddp); - kfree(dev_ipddp.priv); + unregister_netdev(dev_ipddp); + free_netdev(dev_ipddp); while (ipddp_route_list) { p = ipddp_route_list->next; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/appletalk/ltpc.c 830-ivtv/drivers/net/appletalk/ltpc.c --- 000-virgin/drivers/net/appletalk/ltpc.c Mon Nov 17 18:28:14 2003 +++ 830-ivtv/drivers/net/appletalk/ltpc.c Thu Jan 8 08:54:10 2004 @@ -1213,7 +1213,7 @@ out3: out2: release_region(io, 8); out1: - kfree(dev); + free_netdev(dev); out: return ERR_PTR(err); } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/arcnet/arc-rimi.c 830-ivtv/drivers/net/arcnet/arc-rimi.c --- 000-virgin/drivers/net/arcnet/arc-rimi.c Tue Sep 2 09:55:47 2003 +++ 830-ivtv/drivers/net/arcnet/arc-rimi.c Thu Jan 8 08:54:10 2004 @@ -26,6 +26,7 @@ */ #include #include +#include #include #include #include @@ -85,8 +86,6 @@ static void arcrimi_copy_from_card(struc */ static int __init arcrimi_probe(struct net_device *dev) { - int retval; - BUGLVL(D_NORMAL) printk(VERSION); BUGLVL(D_NORMAL) printk("E-mail me if you actually test the RIM I driver, please!\n"); @@ -114,11 +113,7 @@ static int __init arcrimi_probe(struct n "ID!\n"); return -ENODEV; } - retval = arcrimi_found(dev); - if (retval < 0) { - release_mem_region(dev->mem_start, BUFFER_SIZE); - } - return retval; + return arcrimi_found(dev); } @@ -129,11 +124,13 @@ static int __init arcrimi_probe(struct n static int __init arcrimi_found(struct net_device *dev) { struct arcnet_local *lp; - u_long first_mirror, last_mirror, shmem; + unsigned long first_mirror, last_mirror, shmem; int mirror_size; + int err; /* reserve the irq */ if (request_irq(dev->irq, &arcnet_interrupt, 0, "arcnet (RIM I)", dev)) { + release_mem_region(dev->mem_start, BUFFER_SIZE); BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq); return -ENODEV; } @@ -168,11 +165,7 @@ static int __init arcrimi_found(struct n /* initialize the rest of the device structure. */ - lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); - if (!lp) { - BUGMSG(D_NORMAL, "Can't allocate device data!\n"); - goto err_free_irq; - } + lp = dev->priv; lp->card_name = "RIM I"; lp->hw.command = arcrimi_command; lp->hw.status = arcrimi_status; @@ -181,18 +174,6 @@ static int __init arcrimi_found(struct n lp->hw.owner = THIS_MODULE; lp->hw.copy_to_card = arcrimi_copy_to_card; lp->hw.copy_from_card = arcrimi_copy_from_card; - lp->mem_start = ioremap(dev->mem_start, dev->mem_end - dev->mem_start + 1); - if (!lp->mem_start) { - BUGMSG(D_NORMAL, "Can't remap device memory!\n"); - goto err_free_dev_priv; - } - /* Fill in the fields of the device structure with generic - * values. - */ - arcdev_setup(dev); - - /* get and check the station ID from offset 1 in shmem */ - dev->dev_addr[0] = readb(lp->mem_start + 1); /* * re-reserve the memory region - arcrimi_probe() alloced this reqion @@ -200,25 +181,40 @@ static int __init arcrimi_found(struct n * with the correct size. There is a VERY slim chance this could * fail. */ - release_mem_region(dev->mem_start, BUFFER_SIZE); + release_mem_region(shmem, BUFFER_SIZE); if (!request_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1, "arcnet (90xx)")) { BUGMSG(D_NORMAL, "Card memory already allocated\n"); - goto err_free_dev_priv; + goto err_free_irq; } + lp->mem_start = ioremap(dev->mem_start, dev->mem_end - dev->mem_start + 1); + if (!lp->mem_start) { + BUGMSG(D_NORMAL, "Can't remap device memory!\n"); + goto err_release_mem; + } + + /* get and check the station ID from offset 1 in shmem */ + dev->dev_addr[0] = readb(lp->mem_start + 1); + BUGMSG(D_NORMAL, "ARCnet RIM I: station %02Xh found at IRQ %d, " "ShMem %lXh (%ld*%d bytes).\n", dev->dev_addr[0], dev->irq, dev->mem_start, (dev->mem_end - dev->mem_start + 1) / mirror_size, mirror_size); + err = register_netdev(dev); + if (err) + goto err_unmap; + return 0; - err_free_dev_priv: - kfree(dev->priv); - err_free_irq: +err_unmap: + iounmap(lp->mem_start); +err_release_mem: + release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); +err_free_irq: free_irq(dev->irq, dev); return -EIO; } @@ -294,94 +290,79 @@ static void arcrimi_copy_from_card(struc TIME("memcpy_fromio", count, memcpy_fromio(buf, memaddr, count)); } -#ifdef MODULE +static int node; +static int io; /* use the insmod io= irq= node= options */ +static int irq; +static char device[9]; /* use eg. device=arc1 to change name */ + +module_param(node, int, 0); +module_param(io, int, 0); +module_param(irq, int, 0); +module_param_string(device, device, sizeof(device), 0); +MODULE_LICENSE("GPL"); static struct net_device *my_dev; -/* Module parameters */ - -static int node = 0; -static int io = 0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */ -static int irq = 0; /* or use the insmod io= irq= shmem= options */ -static char *device; /* use eg. device="arc1" to change name */ - -MODULE_PARM(node, "i"); -MODULE_PARM(io, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(device, "s"); -MODULE_LICENSE("GPL"); - -int init_module(void) +static int __init arc_rimi_init(void) { struct net_device *dev; - int err; - dev = dev_alloc(device ? : "arc%d", &err); + dev = alloc_arcdev(device); if (!dev) - return err; + return -ENOMEM; if (node && node != 0xff) dev->dev_addr[0] = node; - dev->base_addr = io; + dev->mem_start = io; dev->irq = irq; if (dev->irq == 2) dev->irq = 9; - if (arcrimi_probe(dev)) + if (arcrimi_probe(dev)) { + free_netdev(dev); return -EIO; + } my_dev = dev; return 0; } -void cleanup_module(void) +static void __exit arc_rimi_exit(void) { struct net_device *dev = my_dev; struct arcnet_local *lp = (struct arcnet_local *) dev->priv; unregister_netdev(dev); - free_irq(dev->irq, dev); iounmap(lp->mem_start); release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); - kfree(dev->priv); + free_irq(dev->irq, dev); free_netdev(dev); } -#else - +#ifndef MODULE static int __init arcrimi_setup(char *s) { - struct net_device *dev; int ints[8]; - s = get_options(s, 8, ints); if (!ints[0]) return 1; - dev = alloc_bootmem(sizeof(struct net_device)); - memset(dev, 0, sizeof(struct net_device)); - dev->init = arcrimi_probe; - switch (ints[0]) { default: /* ERROR */ printk("arcrimi: Too many arguments.\n"); case 3: /* Node ID */ - dev->dev_addr[0] = ints[3]; + node = ints[3]; case 2: /* IRQ */ - dev->irq = ints[2]; + irq = ints[2]; case 1: /* IO address */ - dev->mem_start = ints[1]; + io = ints[1]; } if (*s) - strncpy(dev->name, s, 9); - else - strcpy(dev->name, "arc%d"); - if (register_netdev(dev)) - printk(KERN_ERR "arc-rimi: Cannot register arcnet device\n"); - + snprintf(device, sizeof(device), "%s", s); return 1; } - __setup("arcrimi=", arcrimi_setup); - #endif /* MODULE */ + +module_init(arc_rimi_init) +module_exit(arc_rimi_exit) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/arcnet/arcnet.c 830-ivtv/drivers/net/arcnet/arcnet.c --- 000-virgin/drivers/net/arcnet/arcnet.c Mon Nov 17 18:28:14 2003 +++ 830-ivtv/drivers/net/arcnet/arcnet.c Thu Jan 8 08:54:10 2004 @@ -92,6 +92,7 @@ EXPORT_SYMBOL(arc_proto_null); EXPORT_SYMBOL(arcnet_unregister_proto); EXPORT_SYMBOL(arcnet_debug); EXPORT_SYMBOL(arcdev_setup); +EXPORT_SYMBOL(alloc_arcdev); EXPORT_SYMBOL(arcnet_interrupt); /* Internal function prototypes */ @@ -331,6 +332,11 @@ void arcdev_setup(struct net_device *dev dev->rebuild_header = arcnet_rebuild_header; } +struct net_device *alloc_arcdev(char *name) +{ + return alloc_netdev(sizeof(struct arcnet_local), + name && *name ? name : "arc%d", arcdev_setup); +} /* * Open/initialize the board. This is called sometime after booting when diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/arcnet/com20020-isa.c 830-ivtv/drivers/net/arcnet/com20020-isa.c --- 000-virgin/drivers/net/arcnet/com20020-isa.c Mon Nov 17 18:29:30 2003 +++ 830-ivtv/drivers/net/arcnet/com20020-isa.c Thu Jan 8 08:54:11 2004 @@ -26,6 +26,7 @@ * ********************** */ #include +#include #include #include #include @@ -117,49 +118,41 @@ out: return err; } - -#ifdef MODULE - -static struct net_device *my_dev; - -/* Module parameters */ - static int node = 0; static int io = 0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */ static int irq = 0; /* or use the insmod io= irq= shmem= options */ -static char *device; /* use eg. device="arc1" to change name */ +static char device[9]; /* use eg. device="arc1" to change name */ static int timeout = 3; static int backplane = 0; static int clockp = 0; static int clockm = 0; -MODULE_PARM(node, "i"); -MODULE_PARM(io, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(device, "s"); -MODULE_PARM(timeout, "i"); -MODULE_PARM(backplane, "i"); -MODULE_PARM(clockp, "i"); -MODULE_PARM(clockm, "i"); +module_param(node, int, 0); +module_param(io, int, 0); +module_param(irq, int, 0); +module_param_string(device, device, sizeof(device), 0); +module_param(timeout, int, 0); +module_param(backplane, int, 0); +module_param(clockp, int, 0); +module_param(clockm, int, 0); + MODULE_LICENSE("GPL"); -int init_module(void) +static struct net_device *my_dev; + +static int __init com20020_init(void) { struct net_device *dev; struct arcnet_local *lp; - int err; - dev = dev_alloc(device ? : "arc%d", &err); + dev = alloc_arcdev(device); if (!dev) - return err; - lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); - if (!lp) return -ENOMEM; - memset(lp, 0, sizeof(struct arcnet_local)); if (node && node != 0xff) dev->dev_addr[0] = node; + lp = dev->priv; lp->backplane = backplane; lp->clockp = clockp & 7; lp->clockm = clockm & 3; @@ -172,21 +165,24 @@ int init_module(void) if (dev->irq == 2) dev->irq = 9; - if (com20020isa_probe(dev)) + if (com20020isa_probe(dev)) { + free_netdev(dev); return -EIO; + } my_dev = dev; return 0; } -void cleanup_module(void) +static void __exit com20020_exit(void) { - com20020_remove(my_dev); + unregister_netdev(my_dev); + free_irq(my_dev->irq, my_dev); release_region(my_dev->base_addr, ARCNET_TOTAL_SIZE); + free_netdev(my_dev); } -#else - +#ifndef MODULE static int __init com20020isa_setup(char *s) { struct net_device *dev; @@ -196,37 +192,31 @@ static int __init com20020isa_setup(char s = get_options(s, 8, ints); if (!ints[0]) return 1; - dev = alloc_bootmem(sizeof(struct net_device) + sizeof(struct arcnet_local)); - memset(dev, 0, sizeof(struct net_device) + sizeof(struct arcnet_local)); - lp = dev->priv = (struct arcnet_local *) (dev + 1); - dev->init = com20020isa_probe; switch (ints[0]) { default: /* ERROR */ printk("com90xx: Too many arguments.\n"); case 6: /* Timeout */ - lp->timeout = ints[6]; + timeout = ints[6]; case 5: /* CKP value */ - lp->clockp = ints[5]; + clockp = ints[5]; case 4: /* Backplane flag */ - lp->backplane = ints[4]; + backplane = ints[4]; case 3: /* Node ID */ - dev->dev_addr[0] = ints[3]; + node = ints[3]; case 2: /* IRQ */ - dev->irq = ints[2]; + irq = ints[2]; case 1: /* IO address */ - dev->base_addr = ints[1]; + io = ints[1]; } if (*s) - strncpy(dev->name, s, 9); - else - strcpy(dev->name, "arc%d"); - if (register_netdev(dev)) - printk(KERN_ERR "com20020: Cannot register arcnet device\n"); - + snprintf(device, sizeof(device), "%s", s); return 1; } __setup("com20020=", com20020isa_setup); #endif /* MODULE */ + +module_init(com20020_init) +module_exit(com20020_exit) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/arcnet/com20020-pci.c 830-ivtv/drivers/net/arcnet/com20020-pci.c --- 000-virgin/drivers/net/arcnet/com20020-pci.c Mon Nov 17 18:29:30 2003 +++ 830-ivtv/drivers/net/arcnet/com20020-pci.c Thu Jan 8 08:54:11 2004 @@ -27,6 +27,7 @@ * ********************** */ #include +#include #include #include #include @@ -46,18 +47,18 @@ /* Module parameters */ static int node; -static char *device; /* use eg. device="arc1" to change name */ +static char device[9]; /* use eg. device="arc1" to change name */ static int timeout = 3; static int backplane; static int clockp; static int clockm; -MODULE_PARM(node, "i"); -MODULE_PARM(device, "s"); -MODULE_PARM(timeout, "i"); -MODULE_PARM(backplane, "i"); -MODULE_PARM(clockp, "i"); -MODULE_PARM(clockm, "i"); +module_param(node, int, 0); +module_param_string(device, device, sizeof(device), 0); +module_param(timeout, int, 0); +module_param(backplane, int, 0); +module_param(clockp, int, 0); +module_param(clockm, int, 0); MODULE_LICENSE("GPL"); static int __devinit com20020pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) @@ -68,15 +69,11 @@ static int __devinit com20020pci_probe(s if (pci_enable_device(pdev)) return -EIO; - dev = dev_alloc(device ? : "arc%d", &err); + dev = alloc_arcdev(device); if (!dev) - return err; - lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); - if (!lp) { - err = -ENOMEM; - goto out_dev; - } - memset(lp, 0, sizeof(struct arcnet_local)); + return -ENOMEM; + lp = dev->priv; + pci_set_drvdata(pdev, dev); // SOHARD needs PCI base addr 4 @@ -89,6 +86,13 @@ static int __devinit com20020pci_probe(s ioaddr = pci_resource_start(pdev, 2); } + if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "com20020-pci")) { + BUGMSG(D_INIT, "IO region %xh-%xh already allocated.\n", + ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1); + err = -EBUSY; + goto out_dev; + } + // Dummy access after Reset // ARCNET controller needs this access to detect bustype outb(0x00,ioaddr+1); @@ -105,12 +109,6 @@ static int __devinit com20020pci_probe(s lp->timeout = timeout; lp->hw.owner = THIS_MODULE; - if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "com20020-pci")) { - BUGMSG(D_INIT, "IO region %xh-%xh already allocated.\n", - ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1); - err = -EBUSY; - goto out_priv; - } if (ASTATUS() == 0xFF) { BUGMSG(D_NORMAL, "IO address %Xh was reported by PCI BIOS, " "but seems empty!\n", ioaddr); @@ -129,18 +127,18 @@ static int __devinit com20020pci_probe(s out_port: release_region(ioaddr, ARCNET_TOTAL_SIZE); -out_priv: - kfree(dev->priv); out_dev: - kfree(dev); + free_netdev(dev); return err; } static void __devexit com20020pci_remove(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - com20020_remove(dev); + unregister_netdev(dev); + free_irq(dev->irq, dev); release_region(dev->base_addr, ARCNET_TOTAL_SIZE); + free_netdev(dev); } static struct pci_device_id com20020pci_id_table[] = { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/arcnet/com20020.c 830-ivtv/drivers/net/arcnet/com20020.c --- 000-virgin/drivers/net/arcnet/com20020.c Mon Nov 17 18:29:30 2003 +++ 830-ivtv/drivers/net/arcnet/com20020.c Thu Jan 8 08:54:11 2004 @@ -172,11 +172,6 @@ int com20020_found(struct net_device *de dev->set_multicast_list = com20020_set_mc_list; - /* Fill in the fields of the device structure with generic - * values. - */ - arcdev_setup(dev); - if (!dev->dev_addr[0]) dev->dev_addr[0] = inb(ioaddr + 8); /* FIXME: do this some other way! */ @@ -221,7 +216,7 @@ int com20020_found(struct net_device *de lp->setup >> 1, clockrates[3 - ((lp->setup2 & 0xF0) >> 4) + ((lp->setup & 0x0F) >> 1)]); - if (!dev->init && register_netdev(dev)) { + if (register_netdev(dev)) { free_irq(dev->irq, dev); return -EIO; } @@ -332,19 +327,10 @@ static void com20020_set_mc_list(struct } } -void com20020_remove(struct net_device *dev) -{ - unregister_netdev(dev); - free_irq(dev->irq, dev); - kfree(dev->priv); - free_netdev(dev); -} - #ifdef MODULE EXPORT_SYMBOL(com20020_check); EXPORT_SYMBOL(com20020_found); -EXPORT_SYMBOL(com20020_remove); MODULE_LICENSE("GPL"); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/arcnet/com90io.c 830-ivtv/drivers/net/arcnet/com90io.c --- 000-virgin/drivers/net/arcnet/com90io.c Tue Sep 2 09:55:47 2003 +++ 830-ivtv/drivers/net/arcnet/com90io.c Thu Jan 8 08:54:11 2004 @@ -27,6 +27,7 @@ */ #include #include +#include #include #include #include @@ -234,6 +235,7 @@ static int __init com90io_found(struct n { struct arcnet_local *lp; int ioaddr = dev->base_addr; + int err; /* Reserve the irq */ if (request_irq(dev->irq, &arcnet_interrupt, 0, "arcnet (COM90xx-IO)", dev)) { @@ -246,15 +248,6 @@ static int __init com90io_found(struct n return -EBUSY; } - /* Initialize the rest of the device structure. */ - dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); - if (!dev->priv) { - free_irq(dev->irq, dev); - release_region(dev->base_addr, ARCNET_TOTAL_SIZE); - return -ENOMEM; - } - memset(dev->priv, 0, sizeof(struct arcnet_local)); - lp = (struct arcnet_local *) (dev->priv); lp->card_name = "COM90xx I/O"; lp->hw.command = com90io_command; @@ -265,12 +258,6 @@ static int __init com90io_found(struct n lp->hw.copy_to_card = com90io_copy_to_card; lp->hw.copy_from_card = com90io_copy_from_card; - /* - * Fill in the fields of the device structure with generic - * values. - */ - arcdev_setup(dev); - lp->config = (0x16 | IOMAPflag) & ~ENABLE16flag; SETCONF(); @@ -278,6 +265,14 @@ static int __init com90io_found(struct n dev->dev_addr[0] = get_buffer_byte(dev, 1); + err = register_netdev(dev); + if (err) { + outb((inb(_CONFIG) & ~IOMAPflag), _CONFIG); + free_irq(dev->irq, dev); + release_region(dev->base_addr, ARCNET_TOTAL_SIZE); + return err; + } + BUGMSG(D_NORMAL, "COM90IO: station %02Xh found at %03lXh, IRQ %d.\n", dev->dev_addr[0], dev->base_addr, dev->irq); @@ -361,44 +356,67 @@ static void com90io_copy_from_card(struc TIME("get_whole_buffer", count, get_whole_buffer(dev, bufnum * 512 + offset, count, buf)); } - -#ifdef MODULE - -static struct net_device *my_dev; - -/* Module parameters */ - static int io; /* use the insmod io= irq= shmem= options */ static int irq; -static char *device; /* use eg. device=arc1 to change name */ +static char device[9]; /* use eg. device=arc1 to change name */ -MODULE_PARM(io, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(device, "s"); +module_param(io, int, 0); +module_param(irq, int, 0); +module_param_string(device, device, sizeof(device), 0); MODULE_LICENSE("GPL"); -int init_module(void) +#ifndef MODULE +static int __init com90io_setup(char *s) +{ + int ints[4]; + s = get_options(s, 4, ints); + if (!ints[0]) + return 0; + switch (ints[0]) { + default: /* ERROR */ + printk("com90io: Too many arguments.\n"); + case 2: /* IRQ */ + irq = ints[2]; + case 1: /* IO address */ + io = ints[1]; + } + if (*s) + snprintf(device, sizeof(device), "%s", s); + return 1; +} +__setup("com90io=", com90io_setup); +#endif + +static struct net_device *my_dev; + +static int __init com90io_init(void) { struct net_device *dev; int err; - dev = dev_alloc(device ? : "arc%d", &err); + dev = alloc_arcdev(device); if (!dev) - return err; + return -ENOMEM; + + SET_MODULE_OWNER(dev); dev->base_addr = io; dev->irq = irq; if (dev->irq == 2) dev->irq = 9; - if (com90io_probe(dev)) - return -EIO; + err = com90io_probe(dev); + + if (err) { + free_netdev(dev); + return err; + } my_dev = dev; return 0; } -void cleanup_module(void) +static void __exit com90io_exit(void) { struct net_device *dev = my_dev; int ioaddr = dev->base_addr; @@ -410,42 +428,8 @@ void cleanup_module(void) free_irq(dev->irq, dev); release_region(dev->base_addr, ARCNET_TOTAL_SIZE); - kfree(dev->priv); free_netdev(dev); } -#else - -static int __init com90io_setup(char *s) -{ - struct net_device *dev; - int ints[4]; - - s = get_options(s, 4, ints); - if (!ints[0]) - return 0; - dev = alloc_bootmem(sizeof(struct net_device)); - memset(dev, 0, sizeof(struct net_device)); - dev->init = com90io_probe; - - switch (ints[0]) { - default: /* ERROR */ - printk("com90io: Too many arguments.\n"); - case 2: /* IRQ */ - dev->irq = ints[2]; - case 1: /* IO address */ - dev->base_addr = ints[1]; - } - if (*s) - strncpy(dev->name, s, 9); - else - strcpy(dev->name, "arc%d"); - if (register_netdev(dev)) - printk(KERN_ERR "com90io: Cannot register arcnet device\n"); - - return 1; -} - -__setup("com90io=", com90io_setup); - -#endif /* MODULE */ +module_init(com90io_init) +module_exit(com90io_exit) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/arcnet/com90xx.c 830-ivtv/drivers/net/arcnet/com90xx.c --- 000-virgin/drivers/net/arcnet/com90xx.c Tue Sep 2 09:55:47 2003 +++ 830-ivtv/drivers/net/arcnet/com90xx.c Thu Jan 8 08:54:11 2004 @@ -25,6 +25,7 @@ * ********************** */ #include +#include #include #include #include @@ -52,8 +53,7 @@ /* Internal function declarations */ -static int com90xx_found(struct net_device *dev, int ioaddr, int airq, - u_long shmem); +static int com90xx_found(int ioaddr, int airq, u_long shmem); static void com90xx_command(struct net_device *dev, int command); static int com90xx_status(struct net_device *dev); static void com90xx_setmask(struct net_device *dev, int mask); @@ -98,32 +98,43 @@ static int numcards; static int com90xx_skip_probe __initdata = 0; -static int __init com90xx_probe(struct net_device *dev) +/* Module parameters */ + +static int io; /* use the insmod io= irq= shmem= options */ +static int irq; +static int shmem; +static char device[9]; /* use eg. device=arc1 to change name */ + +module_param(io, int, 0); +module_param(irq, int, 0); +module_param(shmem, int, 0); +module_param_string(device, device, sizeof(device), 0); + +static void __init com90xx_probe(void) { - int count, status, ioaddr, numprint, airq, retval = -ENODEV, - openparen = 0; + int count, status, ioaddr, numprint, airq, openparen = 0; unsigned long airqmask; int ports[(0x3f0 - 0x200) / 16 + 1] = {0}; u_long shmems[(0xFF800 - 0xA0000) / 2048 + 1] = {0}; int numports, numshmems, *port; - u_long *shmem; + u_long *p; - if (!dev && com90xx_skip_probe) - return -ENODEV; + if (!io && !irq && !shmem && !*device && com90xx_skip_probe) + return; BUGLVL(D_NORMAL) printk(VERSION); /* set up the arrays where we'll store the possible probe addresses */ numports = numshmems = 0; - if (dev && dev->base_addr) - ports[numports++] = dev->base_addr; + if (io) + ports[numports++] = io; else for (count = 0x200; count <= 0x3f0; count += 16) ports[numports++] = count; - if (dev && dev->mem_start) - shmems[numshmems++] = dev->mem_start; + if (shmem) + shmems[numshmems++] = shmem; else for (count = 0xA0000; count <= 0xFF800; count += 2048) shmems[numshmems++] = count; @@ -143,22 +154,19 @@ static int __init com90xx_probe(struct n ioaddr = *port; - if (check_region(*port, ARCNET_TOTAL_SIZE)) { + if (!request_region(*port, ARCNET_TOTAL_SIZE, "arcnet (90xx)")) { BUGMSG2(D_INIT_REASONS, "(check_region)\n"); BUGMSG2(D_INIT_REASONS, "S1: "); BUGLVL(D_INIT_REASONS) numprint = 0; - *port = ports[numports - 1]; - numports--; - port--; + *port-- = ports[--numports]; continue; } if (ASTATUS() == 0xFF) { BUGMSG2(D_INIT_REASONS, "(empty)\n"); BUGMSG2(D_INIT_REASONS, "S1: "); BUGLVL(D_INIT_REASONS) numprint = 0; - *port = ports[numports - 1]; - numports--; - port--; + release_region(*port, ARCNET_TOTAL_SIZE); + *port-- = ports[--numports]; continue; } inb(_RESET); /* begin resetting card */ @@ -171,14 +179,14 @@ static int __init com90xx_probe(struct n if (!numports) { BUGMSG2(D_NORMAL, "S1: No ARCnet cards found.\n"); - return -ENODEV; + return; } /* Stage 2: we have now reset any possible ARCnet cards, so we can't * do anything until they finish. If D_INIT, print the list of * cards that are left. */ numprint = -1; - for (port = &ports[0]; port - ports < numports; port++) { + for (port = &ports[0]; port < ports + numports; port++) { numprint++; numprint %= 8; if (!numprint) { @@ -194,8 +202,8 @@ static int __init com90xx_probe(struct n * 0xD1 byte in the right place, or are read-only. */ numprint = -1; - for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) { - u_long ptr = *shmem; + for (p = &shmems[0]; p < shmems + numshmems; p++) { + u_long ptr = *p; numprint++; numprint %= 8; @@ -203,15 +211,13 @@ static int __init com90xx_probe(struct n BUGMSG2(D_INIT, "\n"); BUGMSG2(D_INIT, "S3: "); } - BUGMSG2(D_INIT, "%lXh ", *shmem); + BUGMSG2(D_INIT, "%lXh ", *p); - if (check_mem_region(*shmem, BUFFER_SIZE)) { + if (!request_mem_region(*p, BUFFER_SIZE, "arcnet (90xx)")) { BUGMSG2(D_INIT_REASONS, "(check_mem_region)\n"); BUGMSG2(D_INIT_REASONS, "Stage 3: "); BUGLVL(D_INIT_REASONS) numprint = 0; - *shmem = shmems[numshmems - 1]; - numshmems--; - shmem--; + *p-- = shmems[--numshmems]; continue; } if (isa_readb(ptr) != TESTvalue) { @@ -219,9 +225,8 @@ static int __init com90xx_probe(struct n isa_readb(ptr), TESTvalue); BUGMSG2(D_INIT_REASONS, "S3: "); BUGLVL(D_INIT_REASONS) numprint = 0; - *shmem = shmems[numshmems - 1]; - numshmems--; - shmem--; + release_mem_region(*p, BUFFER_SIZE); + *p-- = shmems[--numshmems]; continue; } /* By writing 0x42 to the TESTvalue location, we also make @@ -233,9 +238,8 @@ static int __init com90xx_probe(struct n if (isa_readb(ptr) != 0x42) { BUGMSG2(D_INIT_REASONS, "(read only)\n"); BUGMSG2(D_INIT_REASONS, "S3: "); - *shmem = shmems[numshmems - 1]; - numshmems--; - shmem--; + release_mem_region(*p, BUFFER_SIZE); + *p-- = shmems[--numshmems]; continue; } BUGMSG2(D_INIT_REASONS, "\n"); @@ -246,20 +250,22 @@ static int __init com90xx_probe(struct n if (!numshmems) { BUGMSG2(D_NORMAL, "S3: No ARCnet cards found.\n"); - return -ENODEV; + for (port = &ports[0]; port < ports + numports; port++) + release_region(*port, ARCNET_TOTAL_SIZE); + return; } /* Stage 4: something of a dummy, to report the shmems that are * still possible after stage 3. */ numprint = -1; - for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) { + for (p = &shmems[0]; p < shmems + numshmems; p++) { numprint++; numprint %= 8; if (!numprint) { BUGMSG2(D_INIT, "\n"); BUGMSG2(D_INIT, "S4: "); } - BUGMSG2(D_INIT, "%lXh ", *shmem); + BUGMSG2(D_INIT, "%lXh ", *p); } BUGMSG2(D_INIT, "\n"); @@ -271,7 +277,8 @@ static int __init com90xx_probe(struct n * after the first one is found. */ numprint = -1; - for (port = &ports[0]; port - ports < numports; port++) { + for (port = &ports[0]; port < ports + numports; port++) { + int found = 0; numprint++; numprint %= 8; if (!numprint) { @@ -288,9 +295,8 @@ static int __init com90xx_probe(struct n BUGMSG2(D_INIT_REASONS, "(status=%Xh)\n", status); BUGMSG2(D_INIT_REASONS, "S5: "); BUGLVL(D_INIT_REASONS) numprint = 0; - *port = ports[numports - 1]; - numports--; - port--; + release_region(*port, ARCNET_TOTAL_SIZE); + *port-- = ports[--numports]; continue; } ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear); @@ -300,15 +306,14 @@ static int __init com90xx_probe(struct n status); BUGMSG2(D_INIT_REASONS, "S5: "); BUGLVL(D_INIT_REASONS) numprint = 0; - *port = ports[numports - 1]; - numports--; - port--; + release_region(*port, ARCNET_TOTAL_SIZE); + *port-- = ports[--numports]; continue; } /* skip this completely if an IRQ was given, because maybe * we're on a machine that locks during autoirq! */ - if (!dev || !dev->irq) { + if (!irq) { /* if we do this, we're sure to get an IRQ since the * card has just reset and the NORXflag is on until * we tell it to start receiving. @@ -323,13 +328,12 @@ static int __init com90xx_probe(struct n BUGMSG2(D_INIT_REASONS, "(airq=%d)\n", airq); BUGMSG2(D_INIT_REASONS, "S5: "); BUGLVL(D_INIT_REASONS) numprint = 0; - *port = ports[numports - 1]; - numports--; - port--; + release_region(*port, ARCNET_TOTAL_SIZE); + *port-- = ports[--numports]; continue; } } else { - airq = dev->irq; + airq = irq; } BUGMSG2(D_INIT, "(%d,", airq); @@ -354,21 +358,20 @@ static int __init com90xx_probe(struct n mdelay(RESETtime); #endif - for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) { - u_long ptr = *shmem; + for (p = &shmems[0]; p < shmems + numshmems; p++) { + u_long ptr = *p; if (isa_readb(ptr) == TESTvalue) { /* found one */ - BUGMSG2(D_INIT, "%lXh)\n", *shmem); + BUGMSG2(D_INIT, "%lXh)\n", *p); openparen = 0; /* register the card */ - retval = com90xx_found(dev, *port, airq, *shmem); + if (com90xx_found(*port, airq, *p) == 0) + found = 1; numprint = -1; /* remove shmem from the list */ - *shmem = shmems[numshmems - 1]; - numshmems--; - + *p = shmems[--numshmems]; break; /* go to the next I/O port */ } else { BUGMSG2(D_INIT_REASONS, "%Xh-", isa_readb(ptr)); @@ -380,44 +383,39 @@ static int __init com90xx_probe(struct n BUGLVL(D_INIT_REASONS) printk("S5: "); BUGLVL(D_INIT_REASONS) numprint = 0; } - *port = ports[numports - 1]; - numports--; - port--; + if (!found) + release_region(*port, ARCNET_TOTAL_SIZE); + *port-- = ports[--numports]; } BUGLVL(D_INIT_REASONS) printk("\n"); /* Now put back TESTvalue on all leftover shmems. */ - for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) - isa_writeb(TESTvalue, *shmem); - - if (retval && dev && !numcards) - BUGMSG2(D_NORMAL, "S5: No ARCnet cards found.\n"); - return retval; + for (p = &shmems[0]; p < shmems + numshmems; p++) { + isa_writeb(TESTvalue, *p); + release_mem_region(*p, BUFFER_SIZE); + } } /* Set up the struct net_device associated with this card. Called after * probing succeeds. */ -static int __init com90xx_found(struct net_device *dev0, int ioaddr, int airq, - u_long shmem) +static int __init com90xx_found(int ioaddr, int airq, u_long shmem) { - struct net_device *dev = dev0; + struct net_device *dev = NULL; struct arcnet_local *lp; u_long first_mirror, last_mirror; - int mirror_size, err; + int mirror_size; - /* allocate struct net_device if we don't have one yet */ - if (!dev && !(dev = dev_alloc("arc%d", &err))) { + /* allocate struct net_device */ + dev = alloc_arcdev(device); + if (!dev) { BUGMSG2(D_NORMAL, "com90xx: Can't allocate device!\n"); - return err; - } - lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); - if (!lp) { - BUGMSG(D_NORMAL, "Can't allocate device data!\n"); - goto err_free_dev; + release_mem_region(shmem, BUFFER_SIZE); + return -ENOMEM; } + lp = dev->priv; /* find the real shared memory start/end points, including mirrors */ /* guess the actual size of one "memory mirror" - the number of @@ -442,8 +440,18 @@ static int __init com90xx_found(struct n dev->mem_start = first_mirror; dev->mem_end = last_mirror + MIRROR_SIZE - 1; + release_mem_region(shmem, BUFFER_SIZE); + if (!request_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1, "arcnet (90xx)")) + goto err_free_dev; + + /* reserve the irq */ + if (request_irq(airq, &arcnet_interrupt, 0, "arcnet (90xx)", dev)) { + BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", airq); + goto err_release_mem; + } + dev->irq = airq; + /* Initialize the rest of the device structure. */ - memset(lp, 0, sizeof(struct arcnet_local)); lp->card_name = "COM90xx"; lp->hw.command = com90xx_command; lp->hw.status = com90xx_status; @@ -455,24 +463,12 @@ static int __init com90xx_found(struct n lp->mem_start = ioremap(dev->mem_start, dev->mem_end - dev->mem_start + 1); if (!lp->mem_start) { BUGMSG(D_NORMAL, "Can't remap device memory!\n"); - goto err_free_dev_priv; + goto err_free_irq; } - /* Fill in the fields of the device structure with generic values. */ - arcdev_setup(dev); /* get and check the station ID from offset 1 in shmem */ dev->dev_addr[0] = readb(lp->mem_start + 1); - /* reserve the irq */ - if (request_irq(airq, &arcnet_interrupt, 0, "arcnet (90xx)", dev)) { - BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", airq); - goto err_unmap; - } - dev->irq = airq; - - /* reserve the I/O and memory regions - guaranteed to work by check_region */ - request_region(ioaddr, ARCNET_TOTAL_SIZE, "arcnet (90xx)"); - request_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1, "arcnet (90xx)"); dev->base_addr = ioaddr; BUGMSG(D_NORMAL, "COM90xx station %02Xh found at %03lXh, IRQ %d, " @@ -481,23 +477,20 @@ static int __init com90xx_found(struct n dev->base_addr, dev->irq, dev->mem_start, (dev->mem_end - dev->mem_start + 1) / mirror_size, mirror_size); - if (!dev0 && register_netdev(dev)) - goto err_release; + if (register_netdev(dev)) + goto err_unmap; cards[numcards++] = dev; return 0; - err_release: +err_unmap: + iounmap(lp->mem_start); +err_free_irq: free_irq(dev->irq, dev); - release_region(dev->base_addr, ARCNET_TOTAL_SIZE); +err_release_mem: release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); - err_unmap: - iounmap(lp->mem_start); - err_free_dev_priv: - kfree(dev->priv); - err_free_dev: - if (!dev0) - kfree(dev); +err_free_dev: + free_netdev(dev); return -EIO; } @@ -587,37 +580,13 @@ static void com90xx_copy_from_card(struc } -/* Module parameters */ - -static int io; /* use the insmod io= irq= shmem= options */ -static int irq; -static int shmem; -static char *device; /* use eg. device=arc1 to change name */ - -MODULE_PARM(io, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(shmem, "i"); -MODULE_PARM(device, "s"); MODULE_LICENSE("GPL"); static int __init com90xx_init(void) { - struct net_device *dev; - int err; - - if (io || irq || shmem || device) { - dev = dev_alloc(device ? : "arc%d", &err); - if (!dev) - return err; - dev->base_addr = io; - dev->irq = irq; - if (dev->irq == 2) - dev->irq = 9; - dev->mem_start = shmem; - com90xx_probe(dev); - } else - com90xx_probe(NULL); - + if (irq == 2) + irq = 9; + com90xx_probe(); if (!numcards) return -EIO; return 0; @@ -638,7 +607,6 @@ static void __exit com90xx_exit(void) iounmap(lp->mem_start); release_region(dev->base_addr, ARCNET_TOTAL_SIZE); release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); - kfree(dev->priv); free_netdev(dev); } } @@ -669,9 +637,7 @@ static int __init com90xx_setup(char *s) } if (*s) - strncpy(device, s, 9); - else - strcpy(device, "arc%d"); + snprintf(device, sizeof(device), "%s", s); return 1; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/ariadne.c 830-ivtv/drivers/net/ariadne.c --- 000-virgin/drivers/net/ariadne.c Tue Sep 2 09:55:47 2003 +++ 830-ivtv/drivers/net/ariadne.c Thu Jan 8 08:54:11 2004 @@ -168,7 +168,7 @@ static int __init ariadne_probe(void) continue; } - dev = init_etherdev(NULL, sizeof(struct ariadne_private)); + dev = alloc_etherdev(sizeof(struct ariadne_private)); if (dev == NULL) { release_resource(r1); @@ -205,11 +205,17 @@ static int __init ariadne_probe(void) dev->get_stats = &ariadne_get_stats; dev->set_multicast_list = &set_multicast_list; + res = register_netdev(dev); + if (res) { + release_resource(r1); + release_resource(r2); + free_netdev(dev); + break; + } #ifdef MODULE priv->next_module = root_ariadne_dev; root_ariadne_dev = priv; #endif - res = 0; } return res; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/arm/am79c961a.c 830-ivtv/drivers/net/arm/am79c961a.c --- 000-virgin/drivers/net/arm/am79c961a.c Wed Aug 13 20:24:24 2003 +++ 830-ivtv/drivers/net/arm/am79c961a.c Thu Jan 8 08:54:11 2004 @@ -722,7 +722,7 @@ static int __init am79c961_init(void) release: release_region(dev->base_addr, 0x18); nodev: - kfree(dev); + free_netdev(dev); out: return ret; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/arm/ether00.c 830-ivtv/drivers/net/arm/ether00.c --- 000-virgin/drivers/net/arm/ether00.c Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/arm/ether00.c Thu Jan 8 08:54:11 2004 @@ -923,8 +923,6 @@ static int ether00_add_device(struct pld result = -ENOMEM; goto out_release; } - memset(dev,0,sizeof(struct net_device)); - memset(dev->priv, 0, sizeof(struct net_priv)); priv = dev->priv; priv->tq_memupdate.routine=ether00_mem_update; @@ -966,7 +964,7 @@ static int ether00_add_device(struct pld out_unmap: iounmap(map_addr); out_kfree: - kfree(dev); + free_netdev(dev); out_release: release_mem_region(dev_info->base_addr, MAC_REG_SIZE); return result; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/arm/ether1.c 830-ivtv/drivers/net/arm/ether1.c --- 000-virgin/drivers/net/arm/ether1.c Mon Dec 8 09:55:51 2003 +++ 830-ivtv/drivers/net/arm/ether1.c Thu Jan 8 08:54:11 2004 @@ -1068,7 +1068,7 @@ ether1_probe(struct expansion_card *ec, release: release_region(dev->base_addr, 16); release_region(dev->base_addr + 0x800, 4096); - kfree(dev); + free_netdev(dev); out: return ret; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/arm/ether3.c 830-ivtv/drivers/net/arm/ether3.c --- 000-virgin/drivers/net/arm/ether3.c Mon Dec 8 09:55:51 2003 +++ 830-ivtv/drivers/net/arm/ether3.c Thu Jan 8 08:54:11 2004 @@ -908,7 +908,7 @@ ether3_probe(struct expansion_card *ec, failed: release_region(dev->base_addr, 128); free: - kfree(dev); + free_netdev(dev); out: return ret; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/arm/etherh.c 830-ivtv/drivers/net/arm/etherh.c --- 000-virgin/drivers/net/arm/etherh.c Mon Dec 8 09:55:51 2003 +++ 830-ivtv/drivers/net/arm/etherh.c Thu Jan 8 08:54:11 2004 @@ -551,15 +551,12 @@ etherh_probe(struct expansion_card *ec, etherh_banner(); - dev = alloc_etherdev(sizeof(struct etherh_priv)); + dev = alloc_ei_netdev(); if (!dev) { ret = -ENOMEM; goto out; } - /* - * alloc_etherdev allocs and zeros dev->priv - */ eh = dev->priv; spin_lock_init(&eh->eidev.page_lock); @@ -622,21 +619,12 @@ etherh_probe(struct expansion_card *ec, goto free; } - if (ethdev_init(dev)) { - ret = -ENODEV; - goto release; - } - /* * If we're in the NIC slot, make sure the IRQ is enabled */ if (dev->irq == 11) etherh_set_ctrl(eh, ETHERH_CP_IE); - /* - * Unfortunately, ethdev_init eventually calls - * ether_setup, which re-writes dev->flags. - */ switch (ec->cid.product) { case PROD_ANT_ETHERM: dev_type = "ANT EtherM"; @@ -705,7 +693,7 @@ etherh_probe(struct expansion_card *ec, release: release_region(dev->base_addr, 16); free: - kfree(dev); + free_netdev(dev); out: return ret; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/at1700.c 830-ivtv/drivers/net/at1700.c --- 000-virgin/drivers/net/at1700.c Mon Nov 17 18:29:30 2003 +++ 830-ivtv/drivers/net/at1700.c Thu Jan 8 08:54:11 2004 @@ -81,12 +81,12 @@ static int fmv18x_probe_list[] __initdat */ #ifndef CONFIG_X86_PC9800 -static int at1700_probe_list[] __initdata = { +static unsigned at1700_probe_list[] __initdata = { 0x260, 0x280, 0x2a0, 0x240, 0x340, 0x320, 0x380, 0x300, 0 }; #else /* CONFIG_X86_PC9800 */ -static int at1700_probe_list[] __initdata = { +static unsigned at1700_probe_list[] __initdata = { 0x1d6, 0x1d8, 0x1da, 0x1d4, 0xd4, 0xd2, 0xd8, 0xd0, 0 }; @@ -196,8 +196,6 @@ struct net_local { /* Index to functions, as function prototypes. */ -extern int at1700_probe(struct net_device *dev); - static int at1700_probe1(struct net_device *dev, int ioaddr); static int read_eeprom(long ioaddr, int location); static int net_open(struct net_device *dev); @@ -232,24 +230,78 @@ static struct at1720_mca_adapters_struct (detachable devices only). */ -int __init at1700_probe(struct net_device *dev) +#ifndef CONFIG_X86_PC9800 +static int io = 0x260; +#else +static int io = 0xd0; +#endif + +static int irq; + +static void cleanup_card(struct net_device *dev) { - int i; - int base_addr = dev->base_addr; +#ifdef CONFIG_MCA + struct net_local *lp = dev->priv; + if (lp->mca_slot) + mca_mark_as_unused(lp->mca_slot); +#endif + free_irq(dev->irq, NULL); +#ifndef CONFIG_X86_PC9800 + release_region(dev->base_addr, AT1700_IO_EXTENT); +#else + { + int i; + for (i = 0; i < 0x2000; i += 0x200) + release_region(dev->base_addr + i, 2); + } +#endif +} + +struct net_device * __init at1700_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); + unsigned *port; + int err = 0; + + if (!dev) + return ERR_PTR(-ENODEV); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + irq = dev->irq; + } else { + dev->base_addr = io; + dev->irq = irq; + } SET_MODULE_OWNER(dev); - if (base_addr > 0x1ff) /* Check a single specified location. */ - return at1700_probe1(dev, base_addr); - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; - - for (i = 0; at1700_probe_list[i]; i++) { - int ioaddr = at1700_probe_list[i]; - if (at1700_probe1(dev, ioaddr) == 0) - return 0; + if (io > 0x1ff) { /* Check a single specified location. */ + err = at1700_probe1(dev, io); + } else if (io != 0) { /* Don't probe at all. */ + err = -ENXIO; + } else { + for (port = at1700_probe_list; *port; port++) { + if (at1700_probe1(dev, *port) == 0) + break; + dev->irq = irq; + } + if (!*port) + err = -ENODEV; } - return -ENODEV; + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); } /* The Fujitsu datasheet suggests that the NIC be probed for by checking its @@ -267,7 +319,7 @@ static int __init at1700_probe1(struct n char at1700_irqmap[8] = {3, 4, 5, 9, 10, 11, 14, 15}; unsigned int i, irq, is_fmv18x = 0, is_at1700 = 0; int slot, ret = -ENODEV; - struct net_local *lp; + struct net_local *lp = dev->priv; #ifndef CONFIG_X86_PC9800 if (!request_region(ioaddr, AT1700_IO_EXTENT, dev->name)) @@ -284,9 +336,10 @@ static int __init at1700_probe1(struct n } #endif - /* Resetting the chip doesn't reset the ISA interface, so don't bother. - That means we have to be careful with the register values we probe for. - */ + /* Resetting the chip doesn't reset the ISA interface, so don't bother. + That means we have to be careful with the register values we probe + for. + */ #ifdef notdef printk("at1700 probe at %#x, eeprom is %4.4x %4.4x %4.4x ctrl %4.4x.\n", ioaddr, read_eeprom(ioaddr, 4), read_eeprom(ioaddr, 5), @@ -331,15 +384,13 @@ static int __init at1700_probe1(struct n break; /* probing for a card at a particular IO/IRQ */ - if (dev && - ((dev->irq && dev->irq != irq) || - (dev->base_addr && dev->base_addr != ioaddr))) { + if ((dev->irq && dev->irq != irq) || + (dev->base_addr && dev->base_addr != ioaddr)) { slot++; /* probing next slot */ continue; } - if (dev) - dev->irq = irq; + dev->irq = irq; /* claim the slot */ mca_set_adapter_name( slot, at1720_mca_adapters[j].name ); @@ -476,13 +527,7 @@ found: if (net_debug) printk(version); - /* Initialize the device structure. */ - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == NULL) { - ret = -ENOMEM; - goto err_out; - } - memset(dev->priv, 0, sizeof(struct net_local)); + memset(lp, 0, sizeof(struct net_local)); dev->open = net_open; dev->stop = net_close; @@ -492,11 +537,7 @@ found: dev->tx_timeout = net_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - lp = (struct net_local *)dev->priv; - lp->lock = SPIN_LOCK_UNLOCKED; - - /* Fill in the fields of 'dev' with ethernet-generic values. */ - ether_setup(dev); + spin_lock_init(&lp->lock); lp->jumpered = is_fmv18x; lp->mca_slot = slot; @@ -505,14 +546,11 @@ found: if (ret) { printk (" AT1700 at %#3x is unusable due to a conflict on" "IRQ %d.\n", ioaddr, irq); - goto err_out_priv; + goto err_out; } return 0; -err_out_priv: - kfree(dev->priv); - dev->priv = NULL; err_out: #ifndef CONFIG_X86_PC9800 release_region(ioaddr, AT1700_IO_EXTENT); @@ -940,14 +978,7 @@ set_rx_mode(struct net_device *dev) } #ifdef MODULE -static struct net_device dev_at1700; -#ifndef CONFIG_X86_PC9800 -static int io = 0x260; -#else -static int io = 0xd0; -#endif - -static int irq; +static struct net_device *dev_at1700; MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); @@ -960,41 +991,18 @@ int init_module(void) { if (io == 0) printk("at1700: You should not use auto-probing with insmod!\n"); - dev_at1700.base_addr = io; - dev_at1700.irq = irq; - dev_at1700.init = at1700_probe; - if (register_netdev(&dev_at1700) != 0) { - printk("at1700: register_netdev() returned non-zero.\n"); - return -EIO; - } + dev_at1700 = at1700_probe(-1); + if (IS_ERR(dev_at1700)) + return PTR_ERR(dev_at1700); return 0; } void cleanup_module(void) { -#ifdef CONFIG_MCA - struct net_local *lp = dev_at1700.priv; - if(lp->mca_slot) - { - mca_mark_as_unused(lp->mca_slot); - } -#endif - unregister_netdev(&dev_at1700); - kfree(dev_at1700.priv); - dev_at1700.priv = NULL; - - /* If we don't do this, we can't re-insmod it later. */ - free_irq(dev_at1700.irq, NULL); -#ifndef CONFIG_X86_PC9800 - release_region(dev_at1700.base_addr, AT1700_IO_EXTENT); -#else - { - int i; - for (i = 0; i < 0x2000; i += 0x200) - release_region(dev_at1700.base_addr + i, 2); - } -#endif + unregister_netdev(dev_at1700); + cleanup_card(dev_at1700); + free_netdev(dev_at1700); } #endif /* MODULE */ MODULE_LICENSE("GPL"); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/atari_bionet.c 830-ivtv/drivers/net/atari_bionet.c --- 000-virgin/drivers/net/atari_bionet.c Fri May 30 19:02:12 2003 +++ 830-ivtv/drivers/net/atari_bionet.c Thu Jan 8 08:54:11 2004 @@ -148,8 +148,6 @@ unsigned char *phys_nic_packet; /* Index to functions, as function prototypes. */ -extern int bionet_probe(struct net_device *dev); - static int bionet_open(struct net_device *dev); static int bionet_send_packet(struct sk_buff *skb, struct net_device *dev); static void bionet_poll_rx(struct net_device *); @@ -321,15 +319,26 @@ end: /* Check for a network adaptor of this type, and return '0' if one exists. */ -int __init -bionet_probe(struct net_device *dev){ +struct net_device * __init bionet_probe(int unit) +{ + struct net_device *dev; unsigned char station_addr[6]; static unsigned version_printed; static int no_more_found; /* avoid "Probing for..." printed 4 times */ int i; + int err; if (!MACH_IS_ATARI || no_more_found) - return -ENODEV; + return ERR_PTR(-ENODEV); + + dev = alloc_etherdev(sizeof(struct net_local)); + if (!dev) + return ERR_PTR(-ENOMEM); + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } + SET_MODULE_OWNER(dev); printk("Probing for BioNet 100 Adapter...\n"); @@ -347,11 +356,10 @@ bionet_probe(struct net_device *dev){ || station_addr[2] != 'O' ) { no_more_found = 1; printk( "No BioNet 100 found.\n" ); - return -ENODEV; + free_netdev(dev); + return ERR_PTR(-ENODEV); } - SET_MODULE_OWNER(dev); - if (bionet_debug > 0 && version_printed++ == 0) printk(version); @@ -369,12 +377,6 @@ bionet_probe(struct net_device *dev){ nic_packet, phys_nic_packet ); } - if (dev->priv == NULL) - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (!dev->priv) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct net_local)); - dev->open = bionet_open; dev->stop = bionet_close; dev->hard_start_xmit = bionet_send_packet; @@ -390,8 +392,11 @@ bionet_probe(struct net_device *dev){ #endif dev->dev_addr[i] = station_addr[i]; } - ether_setup(dev); - return 0; + err = register_netdev(dev); + if (!err) + return dev; + free_netdev(dev); + return ERR_PTR(err); } /* Open/initialize the board. This is called (in the current kernel) @@ -640,25 +645,20 @@ static struct net_device_stats *net_get_ #ifdef MODULE -static struct net_device bio_dev; - -int -init_module(void) { - int err; +static struct net_device *bio_dev; - bio_dev.init = bionet_probe; - if ((err = register_netdev(&bio_dev))) { - if (err == -EEXIST) { - printk("BIONET: devices already present. Module not loaded.\n"); - } - return err; - } +int init_module(void) +{ + bio_dev = bionet_probe(-1); + if (IS_ERR(bio_dev)) + return PTR_ERR(bio_dev); return 0; } -void -cleanup_module(void) { - unregister_netdev(&bio_dev); +void cleanup_module(void) +{ + unregister_netdev(bio_dev); + free_netdev(bio_dev); } #endif /* MODULE */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/atari_pamsnet.c 830-ivtv/drivers/net/atari_pamsnet.c --- 000-virgin/drivers/net/atari_pamsnet.c Tue Aug 5 20:01:51 2003 +++ 830-ivtv/drivers/net/atari_pamsnet.c Thu Jan 8 08:54:11 2004 @@ -110,8 +110,6 @@ static char *version = #undef READ #undef WRITE -extern struct net_device *init_etherdev(struct net_device *dev, int sizeof_private); - /* use 0 for production, 1 for verification, >2 for debug */ #ifndef NET_DEBUG @@ -158,8 +156,6 @@ static int send_1_5 (int lun, unsigned c static int get_status (void); static int calc_received (void *start_address); -extern int pamsnet_probe(struct net_device *dev); - static int pamsnet_open(struct net_device *dev); static int pamsnet_send_packet(struct sk_buff *skb, struct net_device *dev); static void pamsnet_poll_rx(struct net_device *); @@ -562,12 +558,12 @@ bad: /* Check for a network adaptor of this type, and return '0' if one exists. */ -int __init -pamsnet_probe (dev) - struct net_device *dev; +struct net_device * __init pamsnet_probe (int unit) { + struct net_device *dev; int i; HADDR *hwaddr; + int err; unsigned char station_addr[6]; static unsigned version_printed; @@ -575,12 +571,18 @@ pamsnet_probe (dev) static int no_more_found; if (no_more_found) - return -ENODEV; + return ERR_PTR(-ENODEV); + no_more_found = 1; + dev = alloc_etherdev(sizeof(struct net_local)); + if (!dev) + return ERR_PTR(-ENOMEM); + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } SET_MODULE_OWNER(dev); - no_more_found = 1; - printk("Probing for PAM's Net/GK Adapter...\n"); /* Allocate the DMA buffer here since we need it for probing! */ @@ -618,11 +620,12 @@ pamsnet_probe (dev) ENABLE_IRQ(); stdma_release(); - if (lance_target < 0) + if (lance_target < 0) { printk("No PAM's Net/GK found.\n"); + free_netdev(dev); + return ERR_PTR(-ENODEV); + } - if ((dev == NULL) || (lance_target < 0)) - return -ENODEV; if (pamsnet_debug > 0 && version_printed++ == 0) printk(version); @@ -632,12 +635,6 @@ pamsnet_probe (dev) station_addr[3], station_addr[4], station_addr[5]); /* Initialize the device structure. */ - if (dev->priv == NULL) - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (!dev->priv) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct net_local)); - dev->open = pamsnet_open; dev->stop = pamsnet_close; dev->hard_start_xmit = pamsnet_send_packet; @@ -653,9 +650,12 @@ pamsnet_probe (dev) #endif dev->dev_addr[i] = station_addr[i]; } - ether_setup(dev); + err = register_netdev(dev); + if (!err) + return dev; - return(0); + free_netdev(dev); + return ERR_PTR(err); } /* Open/initialize the board. This is called (in the current kernel) @@ -866,25 +866,20 @@ static struct net_device_stats *net_get_ #ifdef MODULE -static struct net_device pam_dev; - -int -init_module(void) { - int err; +static struct net_device *pam_dev; - pam_dev.init = pamsnet_probe; - if ((err = register_netdev(&pam_dev))) { - if (err == -EEXIST) { - printk("PAM's Net/GK: devices already present. Module not loaded.\n"); - } - return err; - } +int init_module(void) +{ + pam_dev = pamsnet_probe(-1); + if (IS_ERR(pam_dev)) + return PTR_ERR(pam_dev); return 0; } -void -cleanup_module(void) { - unregister_netdev(&pam_dev); +void cleanup_module(void) +{ + unregister_netdev(pam_dev); + free_netdev(pam_dev); } #endif /* MODULE */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/atarilance.c 830-ivtv/drivers/net/atarilance.c --- 000-virgin/drivers/net/atarilance.c Sat May 10 18:34:40 2003 +++ 830-ivtv/drivers/net/atarilance.c Thu Jan 8 08:54:11 2004 @@ -371,26 +371,39 @@ static void *slow_memcpy( void *dst, con } -int __init atarilance_probe( struct net_device *dev ) -{ +struct net_device * __init atarilance_probe(int unit) +{ int i; static int found; - - SET_MODULE_OWNER(dev); + struct net_device *dev; + int err = -ENODEV; if (!MACH_IS_ATARI || found) /* Assume there's only one board possible... That seems true, since * the Riebl/PAM board's address cannot be changed. */ - return( ENODEV ); + return ERR_PTR(-ENODEV); + + dev = alloc_etherdev(sizeof(struct lance_private)); + if (!dev) + return ERR_PTR(-ENOMEM); + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } + SET_MODULE_OWNER(dev); for( i = 0; i < N_LANCE_ADDR; ++i ) { if (lance_probe1( dev, &lance_addr_list[i] )) { found = 1; - return( 0 ); + err = register_netdev(dev); + if (!err) + return dev; + free_irq(dev->irq, dev); + break; } } - - return( ENODEV ); + free_netdev(dev); + return ERR_PTR(err); } @@ -511,12 +524,6 @@ static unsigned long __init lance_probe1 return( 0 ); probe_ok: - init_etherdev( dev, sizeof(struct lance_private) ); - if (!dev->priv) { - dev->priv = kmalloc( sizeof(struct lance_private), GFP_KERNEL ); - if (!dev->priv) - return 0; - } lp = (struct lance_private *)dev->priv; MEM = (struct lance_memory *)memaddr; IO = lp->iobase = (struct lance_ioreg *)ioaddr; @@ -1171,26 +1178,21 @@ static int lance_set_mac_address( struct #ifdef MODULE -static struct net_device atarilance_dev; +static struct net_device *atarilance_dev; int init_module(void) - -{ int err; - - atarilance_dev.init = atarilance_probe; - if ((err = register_netdev( &atarilance_dev ))) { - if (err == -EIO) { - printk( "No Atari Lance board found. Module not loaded.\n"); - } - return( err ); - } - return( 0 ); +{ + atarilance_dev = atarilance_probe(-1); + if (IS_ERR(atarilance_dev)) + return PTR_ERR(atarilance_dev); + return 0; } void cleanup_module(void) - { - unregister_netdev( &atarilance_dev ); + unregister_netdev(atarilance_dev); + free_irq(atarilance_dev->irq, atarilance_dev); + free_netdev(atarilance_dev); } #endif /* MODULE */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/atp.c 830-ivtv/drivers/net/atp.c --- 000-virgin/drivers/net/atp.c Tue Sep 2 09:55:47 2003 +++ 830-ivtv/drivers/net/atp.c Thu Jan 8 08:54:11 2004 @@ -195,7 +195,7 @@ static void atp_timed_checker(unsigned l /* Index to functions, as function prototypes. */ -static int atp_probe1(struct net_device *dev, long ioaddr); +static int atp_probe1(long ioaddr); static void get_node_ID(struct net_device *dev); static unsigned short eeprom_op(long ioaddr, unsigned int cmd); static int net_open(struct net_device *dev); @@ -224,13 +224,13 @@ static struct net_device *root_atp_dev; FIXME: we should use the parport layer for this */ -static int __init atp_init(struct net_device *dev) +static int __init atp_init(void) { int *port, ports[] = {0x378, 0x278, 0x3bc, 0}; - int base_addr = dev ? dev->base_addr : io[0]; + int base_addr = io[0]; if (base_addr > 0x1ff) /* Check a single specified location. */ - return atp_probe1(dev, base_addr); + return atp_probe1(base_addr); else if (base_addr == 1) /* Don't probe at all. */ return -ENXIO; @@ -239,17 +239,19 @@ static int __init atp_init(struct net_de outb(0x57, ioaddr + PAR_DATA); if (inb(ioaddr + PAR_DATA) != 0x57) continue; - if (atp_probe1(dev, ioaddr) == 0) + if (atp_probe1(ioaddr) == 0) return 0; } return -ENODEV; } -static int __init atp_probe1(struct net_device *dev, long ioaddr) +static int __init atp_probe1(long ioaddr) { + struct net_device *dev = NULL; struct net_local *lp; int saved_ctrl_reg, status, i; + int res; outb(0xff, ioaddr + PAR_DATA); /* Save the original value of the Control register, in case we guessed @@ -296,7 +298,7 @@ static int __init atp_probe1(struct net_ return -ENODEV; } - dev = init_etherdev(dev, sizeof(struct net_local)); + dev = alloc_etherdev(sizeof(struct net_local)); if (!dev) return -ENOMEM; SET_MODULE_OWNER(dev); @@ -331,24 +333,13 @@ static int __init atp_probe1(struct net_ dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); /* Reset the ethernet hardware and activate the printer pass-through. */ - write_reg_high(ioaddr, CMR1, CMR1h_RESET | CMR1h_MUX); - - /* Initialize the device structure. */ - ether_setup(dev); - if (dev->priv == NULL) - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct net_local)); + write_reg_high(ioaddr, CMR1, CMR1h_RESET | CMR1h_MUX); lp = (struct net_local *)dev->priv; lp->chip_type = RTL8002; lp->addr_mode = CMR2h_Normal; spin_lock_init(&lp->lock); - lp->next_module = root_atp_dev; - root_atp_dev = dev; - /* For the ATP adapter the "if_port" is really the data transfer mode. */ if (xcvr[0]) dev->if_port = xcvr[0]; @@ -366,6 +357,15 @@ static int __init atp_probe1(struct net_ dev->tx_timeout = tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; + res = register_netdev(dev); + if (res) { + free_netdev(dev); + return res; + } + + lp->next_module = root_atp_dev; + root_atp_dev = dev; + return 0; } @@ -933,7 +933,7 @@ static void set_rx_mode_8012(struct net_ static int __init atp_init_module(void) { if (debug) /* Emit version even if no cards detected. */ printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); - return atp_init(NULL); + return atp_init(); } static void __exit atp_cleanup_module(void) { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/au1000_eth.c 830-ivtv/drivers/net/au1000_eth.c --- 000-virgin/drivers/net/au1000_eth.c Tue Sep 2 09:55:47 2003 +++ 830-ivtv/drivers/net/au1000_eth.c Thu Jan 8 08:54:11 2004 @@ -56,7 +56,7 @@ static void *dma_alloc(size_t, dma_addr_ static void dma_free(void *, size_t); static void hard_stop(struct net_device *); static void enable_rx_tx(struct net_device *dev); -static int __init au1000_probe1(struct net_device *, long, int, int); +static int __init au1000_probe1(long, int, int); static int au1000_init(struct net_device *); static int au1000_open(struct net_device *); static int au1000_close(struct net_device *); @@ -644,17 +644,17 @@ static int __init au1000_init_module(voi } // check for valid entries, au1100 only has one entry if (base_addr && irq) { - if (au1000_probe1(NULL, base_addr, irq, i) != 0) { + if (au1000_probe1(base_addr, irq, i) != 0) return -ENODEV; - } } } return 0; } static int __init -au1000_probe1(struct net_device *dev, long ioaddr, int irq, int port_num) +au1000_probe1(long ioaddr, int irq, int port_num) { + struct net_device *dev; static unsigned version_printed = 0; struct au1000_private *aup = NULL; int i, retval = 0; @@ -668,15 +668,16 @@ au1000_probe1(struct net_device *dev, lo if (version_printed++ == 0) printk(version); - if (!dev) - dev = init_etherdev(NULL, sizeof(struct au1000_private)); + retval = -ENOMEM; + dev = alloc_etherdev(sizeof(struct au1000_private)); if (!dev) { - printk (KERN_ERR "au1000 eth: init_etherdev failed\n"); - release_region(ioaddr, MAC_IOSIZE); - return -ENODEV; + printk (KERN_ERR "au1000 eth: alloc_etherdev failed\n"); + goto out; } + SET_MODULE_OWNER(dev); + printk("%s: Au1xxx ethernet found at 0x%lx, irq %d\n", dev->name, ioaddr, irq); @@ -685,10 +686,8 @@ au1000_probe1(struct net_device *dev, lo /* Allocate the data buffers */ aup->vaddr = (u32)dma_alloc(MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS), &aup->dma_addr); - if (!aup->vaddr) { - retval = -ENOMEM; - goto free_region; - } + if (!aup->vaddr) + goto out1; /* aup->mac is the base address of the MAC's registers */ aup->mac = (volatile mac_reg_t *)((unsigned long)ioaddr); @@ -749,10 +748,11 @@ au1000_probe1(struct net_device *dev, lo MAC_EN_RESET2 | MAC_EN_CLOCK_ENABLE; au_sync_delay(2); - if (mii_probe(dev) != 0) { - goto free_region; - } + retval = mii_probe(dev); + if (retval) + goto out2; + retval = -EINVAL; pDBfree = NULL; /* setup the data buffer descriptors and attach a buffer to each one */ pDB = aup->db; @@ -767,13 +767,13 @@ au1000_probe1(struct net_device *dev, lo for (i=0; irx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr; aup->rx_db_inuse[i] = pDB; } for (i=0; itx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr; aup->tx_dma_ring[i]->len = 0; aup->tx_db_inuse[i] = pDB; @@ -792,26 +792,25 @@ au1000_probe1(struct net_device *dev, lo dev->tx_timeout = au1000_tx_timeout; dev->watchdog_timeo = ETH_TX_TIMEOUT; - - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - /* * The boot code uses the ethernet controller, so reset it to start * fresh. au1000_init() expects that the device is in reset state. */ reset_mac(dev); + + retval = register_netdev(dev); + if (retval) + goto out2; return 0; -free_region: +out2: + dma_free(aup->vaddr, MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS)); +out1: + free_netdev(dev); +out: release_region(PHYSADDR(ioaddr), MAC_IOSIZE); - unregister_netdev(dev); - if (aup->vaddr) - dma_free((void *)aup->vaddr, - MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS)); printk(KERN_ERR "%s: au1000_probe1 failed. Returns %d\n", dev->name, retval); - free_netdev(dev); return retval; } @@ -933,15 +932,12 @@ static int au1000_open(struct net_device int retval; struct au1000_private *aup = (struct au1000_private *) dev->priv; - MOD_INC_USE_COUNT; - if (au1000_debug > 4) printk("%s: open: dev=%p\n", dev->name, dev); if ((retval = au1000_init(dev))) { printk(KERN_ERR "%s: error in au1000_init\n", dev->name); free_irq(dev->irq, dev); - MOD_DEC_USE_COUNT; return retval; } netif_start_queue(dev); @@ -950,7 +946,6 @@ static int au1000_open(struct net_device dev->name, dev))) { printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, dev->irq); - MOD_DEC_USE_COUNT; return retval; } @@ -984,8 +979,6 @@ static int au1000_close(struct net_devic spin_unlock_irqrestore(&aup->lock, flags); reset_mac(dev); - kfree(dev); - MOD_DEC_USE_COUNT; return 0; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/bagetlance.c 830-ivtv/drivers/net/bagetlance.c --- 000-virgin/drivers/net/bagetlance.c Sat May 10 18:34:40 2003 +++ 830-ivtv/drivers/net/bagetlance.c Thu Jan 8 08:54:11 2004 @@ -465,30 +465,43 @@ void *slow_memcpy( void *dst, const void } -int __init bagetlance_probe( struct net_device *dev ) - -{ int i; +struct net_device * __init bagetlance_probe(int unit) +{ + struct net_device *dev; + int i; static int found; - - SET_MODULE_OWNER(dev); + int err = -ENODEV; if (found) /* Assume there's only one board possible... That seems true, since * the Riebl/PAM board's address cannot be changed. */ - return( -ENODEV ); + return ERR_PTR(-ENODEV); + + dev = alloc_etherdev(sizeof(struct lance_private)); + if (!dev) + return ERR_PTR(-ENOMEM); + + SET_MODULE_OWNER(dev); for( i = 0; i < N_LANCE_ADDR; ++i ) { if (lance_probe1( dev, &lance_addr_list[i] )) { found = 1; - return( 0 ); + break; } } - - return( -ENODEV ); + if (!found) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + free_irq(dev->irq, dev); +out: + free_netdev(dev); + return ERR_PTR(err); } - - /* Derived from hwreg_present() in vme/config.c: */ static int __init addr_accessible( volatile void *regp, @@ -527,6 +540,7 @@ static int __init lance_probe1( struct n if (!addr_accessible( memaddr, 1, 1 )) goto probe_fail; if ((unsigned long)memaddr >= KSEG2) { + /* FIXME: do we need to undo that on cleanup paths? */ extern int kseg2_alloc_io (unsigned long addr, unsigned long size); if (kseg2_alloc_io((unsigned long)memaddr, BAGET_LANCE_MEM_SIZE)) { printk("bagetlance: unable map lance memory\n"); @@ -580,12 +594,6 @@ static int __init lance_probe1( struct n return( 0 ); probe_ok: - init_etherdev( dev, sizeof(struct lance_private) ); - if (!dev->priv) { - dev->priv = kmalloc( sizeof(struct lance_private), GFP_KERNEL ); - if (!dev->priv) - return 0; - } lp = (struct lance_private *)dev->priv; MEM = (struct lance_memory *)memaddr; IO = lp->iobase = (struct lance_ioreg *)ioaddr; @@ -617,8 +625,9 @@ static int __init lance_probe1( struct n if (lp->cardtype == PAM_CARD || memaddr == (unsigned short *)0xffe00000) { /* PAMs card and Riebl on ST use level 5 autovector */ - request_irq(BAGET_LANCE_IRQ, lance_interrupt, IRQ_TYPE_PRIO, - "PAM/Riebl-ST Ethernet", dev); + if (request_irq(BAGET_LANCE_IRQ, lance_interrupt, IRQ_TYPE_PRIO, + "PAM/Riebl-ST Ethernet", dev)) + goto probe_fail; dev->irq = (unsigned short)BAGET_LANCE_IRQ; } else { @@ -629,10 +638,11 @@ static int __init lance_probe1( struct n unsigned long irq = BAGET_LANCE_IRQ; if (!irq) { printk( "Lance: request for VME interrupt failed\n" ); - return( 0 ); + goto probe_fail; } - request_irq(irq, lance_interrupt, IRQ_TYPE_PRIO, - "Riebl-VME Ethernet", dev); + if (request_irq(irq, lance_interrupt, IRQ_TYPE_PRIO, + "Riebl-VME Ethernet", dev)) + goto probe_fail; dev->irq = irq; } @@ -1331,26 +1341,21 @@ static int lance_set_mac_address( struct #ifdef MODULE -static struct net_device bagetlance_dev; +static struct net_device *bagetlance_dev; int init_module(void) - -{ int err; - - bagetlance_dev.init = bagetlance_probe; - if ((err = register_netdev( &bagetlance_dev ))) { - if (err == -EIO) { - printk( "No Vme Lance board found. Module not loaded.\n"); - } - return( err ); - } - return( 0 ); +{ + bagetlance_dev = bagetlance_probe(-1); + if (IS_ERR(bagetlance_dev)) + return PTR_ERR(bagetlance_dev); + return 0; } void cleanup_module(void) - { - unregister_netdev( &bagetlance_dev ); + unregister_netdev(bagetlance_dev); + free_irq(bagetlance_dev->irq, bagetlance_dev); + free_netdev(bagetlance_dev); } #endif /* MODULE */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/bonding/bond_3ad.c 830-ivtv/drivers/net/bonding/bond_3ad.c --- 000-virgin/drivers/net/bonding/bond_3ad.c Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/bonding/bond_3ad.c Thu Jan 8 08:54:12 2004 @@ -47,8 +47,13 @@ * - Send LACPDU as highest priority packet to further fix the above * problem on very high Tx traffic load where packets may get dropped * by the slave. + * + * 2003/09/24 - Shmulik Hen + * - Code cleanup and style changes */ +//#define BONDING_DEBUG 1 + #include #include #include @@ -119,6 +124,7 @@ static struct mac_addr null_mac_addr = {{0, 0, 0, 0, 0, 0}}; static u16 ad_ticks_per_sec; +static const int ad_delta_in_ticks = (AD_TIMER_INTERVAL * HZ) / 1000; // ================= 3AD api to bonding and kernel code ================== static u16 __get_link_speed(struct port *port); @@ -196,13 +202,11 @@ static inline struct bonding *__get_bond */ static inline struct port *__get_first_port(struct bonding *bond) { - struct slave *slave = bond->next; - - if (slave == (struct slave *)bond) { + if (bond->slave_cnt == 0) { return NULL; } - return &(SLAVE_AD_INFO(slave).port); + return &(SLAVE_AD_INFO(bond->first_slave).port); } /** @@ -218,7 +222,7 @@ static inline struct port *__get_next_po struct slave *slave = port->slave; // If there's no bond for this port, or this is the last slave - if ((bond == NULL) || (slave->next == bond->next)) { + if ((bond == NULL) || (slave->next == bond->first_slave)) { return NULL; } @@ -236,12 +240,12 @@ static inline struct aggregator *__get_f { struct bonding *bond = __get_bond_by_port(port); - // If there's no bond for this port, or this is the last slave - if ((bond == NULL) || (bond->next == (struct slave *)bond)) { + // If there's no bond for this port, or bond has no slaves + if ((bond == NULL) || (bond->slave_cnt == 0)) { return NULL; } - return &(SLAVE_AD_INFO(bond->next).aggregator); + return &(SLAVE_AD_INFO(bond->first_slave).aggregator); } /** @@ -257,7 +261,7 @@ static inline struct aggregator *__get_n struct bonding *bond = bond_get_bond_by_slave(slave); // If there's no bond for this aggregator, or this is the last slave - if ((bond == NULL) || (slave->next == bond->next)) { + if ((bond == NULL) || (slave->next == bond->first_slave)) { return NULL; } @@ -392,7 +396,7 @@ static u16 __get_link_speed(struct port } } - BOND_PRINT_DBG(("Port %d Received link speed %d update from adapter", port->actor_port_number, speed)); + dprintk("Port %d Received link speed %d update from adapter\n", port->actor_port_number, speed); return speed; } @@ -418,12 +422,12 @@ static u8 __get_duplex(struct port *port switch (slave->duplex) { case DUPLEX_FULL: retval=0x1; - BOND_PRINT_DBG(("Port %d Received status full duplex update from adapter", port->actor_port_number)); + dprintk("Port %d Received status full duplex update from adapter\n", port->actor_port_number); break; case DUPLEX_HALF: default: retval=0x0; - BOND_PRINT_DBG(("Port %d Received status NOT full duplex update from adapter", port->actor_port_number)); + dprintk("Port %d Received status NOT full duplex update from adapter\n", port->actor_port_number); break; } } @@ -1059,7 +1063,7 @@ static void ad_mux_machine(struct port * // check if the state machine was changed if (port->sm_mux_state != last_state) { - BOND_PRINT_DBG(("Mux Machine: Port=%d, Last State=%d, Curr State=%d", port->actor_port_number, last_state, port->sm_mux_state)); + dprintk("Mux Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_mux_state); switch (port->sm_mux_state) { case AD_MUX_DETACHED: __detach_bond_from_agg(port); @@ -1158,7 +1162,7 @@ static void ad_rx_machine(struct lacpdu // check if the State machine was changed or new lacpdu arrived if ((port->sm_rx_state != last_state) || (lacpdu)) { - BOND_PRINT_DBG(("Rx Machine: Port=%d, Last State=%d, Curr State=%d", port->actor_port_number, last_state, port->sm_rx_state)); + dprintk("Rx Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_rx_state); switch (port->sm_rx_state) { case AD_RX_INITIALIZE: if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_BITS)) { @@ -1204,7 +1208,7 @@ static void ad_rx_machine(struct lacpdu // detect loopback situation if (!MAC_ADDRESS_COMPARE(&(lacpdu->actor_system), &(port->actor_system))) { // INFO_RECEIVED_LOOPBACK_FRAMES - printk(KERN_ERR "bonding: An illegal loopback occurred on adapter (%s)\n", + printk(KERN_ERR DRV_NAME ": An illegal loopback occurred on adapter (%s)\n", port->slave->dev->name); printk(KERN_ERR "Check the configuration to verify that all Adapters " "are connected to 802.3ad compliant switch ports\n"); @@ -1245,7 +1249,7 @@ static void ad_tx_machine(struct port *p __update_lacpdu_from_port(port); // send the lacpdu if (ad_lacpdu_send(port) >= 0) { - BOND_PRINT_DBG(("Sent LACPDU on port %d", port->actor_port_number)); + dprintk("Sent LACPDU on port %d\n", port->actor_port_number); // mark ntt as false, so it will not be sent again until demanded port->ntt = 0; } @@ -1318,7 +1322,7 @@ static void ad_periodic_machine(struct p // check if the state machine was changed if (port->sm_periodic_state != last_state) { - BOND_PRINT_DBG(("Periodic Machine: Port=%d, Last State=%d, Curr State=%d", port->actor_port_number, last_state, port->sm_periodic_state)); + dprintk("Periodic Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_periodic_state); switch (port->sm_periodic_state) { case AD_NO_PERIODIC: port->sm_periodic_timer_counter = 0; // zero timer @@ -1375,7 +1379,7 @@ static void ad_port_selection_logic(stru port->next_port_in_aggregator=NULL; port->actor_port_aggregator_identifier=0; - BOND_PRINT_DBG(("Port %d left LAG %d", port->actor_port_number, temp_aggregator->aggregator_identifier)); + dprintk("Port %d left LAG %d\n", port->actor_port_number, temp_aggregator->aggregator_identifier); // if the aggregator is empty, clear its parameters, and set it ready to be attached if (!temp_aggregator->lag_ports) { ad_clear_agg(temp_aggregator); @@ -1384,7 +1388,7 @@ static void ad_port_selection_logic(stru } } if (!curr_port) { // meaning: the port was related to an aggregator but was not on the aggregator port list - printk(KERN_WARNING "bonding: Warning: Port %d (on %s) was " + printk(KERN_WARNING DRV_NAME ": Warning: Port %d (on %s) was " "related to aggregator %d but was not on its port list\n", port->actor_port_number, port->slave->dev->name, port->aggregator->aggregator_identifier); @@ -1417,7 +1421,7 @@ static void ad_port_selection_logic(stru port->next_port_in_aggregator=aggregator->lag_ports; port->aggregator->num_of_ports++; aggregator->lag_ports=port; - BOND_PRINT_DBG(("Port %d joined LAG %d(existing LAG)", port->actor_port_number, port->aggregator->aggregator_identifier)); + dprintk("Port %d joined LAG %d(existing LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier); // mark this port as selected port->sm_vars |= AD_PORT_SELECTED; @@ -1454,9 +1458,9 @@ static void ad_port_selection_logic(stru // mark this port as selected port->sm_vars |= AD_PORT_SELECTED; - BOND_PRINT_DBG(("Port %d joined LAG %d(new LAG)", port->actor_port_number, port->aggregator->aggregator_identifier)); + dprintk("Port %d joined LAG %d(new LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier); } else { - printk(KERN_ERR "bonding: Port %d (on %s) did not find a suitable aggregator\n", + printk(KERN_ERR DRV_NAME ": Port %d (on %s) did not find a suitable aggregator\n", port->actor_port_number, port->slave->dev->name); } } @@ -1580,30 +1584,30 @@ static void ad_agg_selection_logic(struc aggregator; aggregator = __get_next_agg(aggregator)) { - BOND_PRINT_DBG(("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d", + dprintk("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d\n", aggregator->aggregator_identifier, aggregator->num_of_ports, aggregator->actor_oper_aggregator_key, aggregator->partner_oper_aggregator_key, - aggregator->is_individual, aggregator->is_active)); + aggregator->is_individual, aggregator->is_active); } // check if any partner replys if (best_aggregator->is_individual) { - printk(KERN_WARNING "bonding: Warning: No 802.3ad response from the link partner " + printk(KERN_WARNING DRV_NAME ": Warning: No 802.3ad response from the link partner " "for any adapters in the bond\n"); } // check if there are more than one aggregator if (num_of_aggs > 1) { - BOND_PRINT_DBG(("Warning: More than one Link Aggregation Group was " - "found in the bond. Only one group will function in the bond")); + dprintk("Warning: More than one Link Aggregation Group was " + "found in the bond. Only one group will function in the bond\n"); } best_aggregator->is_active = 1; - BOND_PRINT_DBG(("LAG %d choosed as the active LAG", best_aggregator->aggregator_identifier)); - BOND_PRINT_DBG(("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d", + dprintk("LAG %d choosed as the active LAG\n", best_aggregator->aggregator_identifier); + dprintk("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d\n", best_aggregator->aggregator_identifier, best_aggregator->num_of_ports, best_aggregator->actor_oper_aggregator_key, best_aggregator->partner_oper_aggregator_key, - best_aggregator->is_individual, best_aggregator->is_active)); + best_aggregator->is_individual, best_aggregator->is_active); // disable the ports that were related to the former active_aggregator if (last_active_aggregator) { @@ -1644,7 +1648,7 @@ static void ad_clear_agg(struct aggregat aggregator->lag_ports = NULL; aggregator->is_active = 0; aggregator->num_of_ports = 0; - BOND_PRINT_DBG(("LAG %d was cleared", aggregator->aggregator_identifier)); + dprintk("LAG %d was cleared\n", aggregator->aggregator_identifier); } } @@ -1729,7 +1733,7 @@ static void ad_initialize_port(struct po static void ad_enable_collecting_distributing(struct port *port) { if (port->aggregator->is_active) { - BOND_PRINT_DBG(("Enabling port %d(LAG %d)", port->actor_port_number, port->aggregator->aggregator_identifier)); + dprintk("Enabling port %d(LAG %d)\n", port->actor_port_number, port->aggregator->aggregator_identifier); __enable_port(port); } } @@ -1742,7 +1746,7 @@ static void ad_enable_collecting_distrib static void ad_disable_collecting_distributing(struct port *port) { if (port->aggregator && MAC_ADDRESS_COMPARE(&(port->aggregator->partner_system), &(null_mac_addr))) { - BOND_PRINT_DBG(("Disabling port %d(LAG %d)", port->actor_port_number, port->aggregator->aggregator_identifier)); + dprintk("Disabling port %d(LAG %d)\n", port->actor_port_number, port->aggregator->aggregator_identifier); __disable_port(port); } } @@ -1780,7 +1784,7 @@ static void ad_marker_info_send(struct p // send the marker information if (ad_marker_send(port, &marker) >= 0) { - BOND_PRINT_DBG(("Sent Marker Information on port %d", port->actor_port_number)); + dprintk("Sent Marker Information on port %d\n", port->actor_port_number); } } #endif @@ -1803,7 +1807,7 @@ static void ad_marker_info_received(stru // send the marker response if (ad_marker_send(port, &marker) >= 0) { - BOND_PRINT_DBG(("Sent Marker Response on port %d", port->actor_port_number)); + dprintk("Sent Marker Response on port %d\n", port->actor_port_number); } } @@ -1890,13 +1894,13 @@ static u16 aggregator_identifier; void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution, int lacp_fast) { // check that the bond is not initialized yet - if (MAC_ADDRESS_COMPARE(&(BOND_AD_INFO(bond).system.sys_mac_addr), &(bond->device->dev_addr))) { + if (MAC_ADDRESS_COMPARE(&(BOND_AD_INFO(bond).system.sys_mac_addr), &(bond->dev->dev_addr))) { aggregator_identifier = 0; BOND_AD_INFO(bond).lacp_fast = lacp_fast; BOND_AD_INFO(bond).system.sys_priority = 0xFFFF; - BOND_AD_INFO(bond).system.sys_mac_addr = *((struct mac_addr *)bond->device->dev_addr); + BOND_AD_INFO(bond).system.sys_mac_addr = *((struct mac_addr *)bond->dev->dev_addr); // initialize how many times this module is called in one second(should be about every 100ms) ad_ticks_per_sec = tick_resolution; @@ -1921,7 +1925,7 @@ int bond_3ad_bind_slave(struct slave *sl struct aggregator *aggregator; if (bond == NULL) { - printk(KERN_CRIT "The slave %s is not attached to its bond\n", slave->dev->name); + printk(KERN_ERR "The slave %s is not attached to its bond\n", slave->dev->name); return -1; } @@ -1964,7 +1968,7 @@ int bond_3ad_bind_slave(struct slave *sl ad_initialize_agg(aggregator); - aggregator->aggregator_mac_address = *((struct mac_addr *)bond->device->dev_addr); + aggregator->aggregator_mac_address = *((struct mac_addr *)bond->dev->dev_addr); aggregator->aggregator_identifier = (++aggregator_identifier); aggregator->slave = slave; aggregator->is_active = 0; @@ -1996,11 +2000,11 @@ void bond_3ad_unbind_slave(struct slave // if slave is null, the whole port is not initialized if (!port->slave) { - printk(KERN_WARNING "bonding: Trying to unbind an uninitialized port on %s\n", slave->dev->name); + printk(KERN_WARNING DRV_NAME ": Trying to unbind an uninitialized port on %s\n", slave->dev->name); return; } - BOND_PRINT_DBG(("Unbinding Link Aggregation Group %d", aggregator->aggregator_identifier)); + dprintk("Unbinding Link Aggregation Group %d\n", aggregator->aggregator_identifier); /* Tell the partner that this port is not suitable for aggregation */ port->actor_oper_port_state &= ~AD_STATE_AGGREGATION; @@ -2024,10 +2028,10 @@ void bond_3ad_unbind_slave(struct slave // if new aggregator found, copy the aggregator's parameters // and connect the related lag_ports to the new aggregator if ((new_aggregator) && ((!new_aggregator->lag_ports) || ((new_aggregator->lag_ports == port) && !new_aggregator->lag_ports->next_port_in_aggregator))) { - BOND_PRINT_DBG(("Some port(s) related to LAG %d - replaceing with LAG %d", aggregator->aggregator_identifier, new_aggregator->aggregator_identifier)); + dprintk("Some port(s) related to LAG %d - replaceing with LAG %d\n", aggregator->aggregator_identifier, new_aggregator->aggregator_identifier); if ((new_aggregator->lag_ports == port) && new_aggregator->is_active) { - printk(KERN_INFO "bonding: Removing an active aggregator\n"); + printk(KERN_INFO DRV_NAME ": Removing an active aggregator\n"); // select new active aggregator select_new_active_agg = 1; } @@ -2057,7 +2061,7 @@ void bond_3ad_unbind_slave(struct slave ad_agg_selection_logic(__get_first_agg(port)); } } else { - printk(KERN_WARNING "bonding: Warning: unbinding aggregator, " + printk(KERN_WARNING DRV_NAME ": Warning: unbinding aggregator, " "and could not find a new aggregator for its ports\n"); } } else { // in case that the only port related to this aggregator is the one we want to remove @@ -2072,7 +2076,7 @@ void bond_3ad_unbind_slave(struct slave } } - BOND_PRINT_DBG(("Unbinding port %d", port->actor_port_number)); + dprintk("Unbinding port %d\n", port->actor_port_number); // find the aggregator that this port is connected to temp_aggregator = __get_first_agg(port); for (; temp_aggregator; temp_aggregator = __get_next_agg(temp_aggregator)) { @@ -2123,13 +2127,13 @@ void bond_3ad_state_machine_handler(stru read_lock(&bond->lock); - //check if there are any slaves - if (bond->next == (struct slave *)bond) { - goto end; + if (bond->kill_timers) { + goto out; } - if ((bond->device->flags & IFF_UP) != IFF_UP) { - goto end; + //check if there are any slaves + if (bond->slave_cnt == 0) { + goto re_arm; } // check if agg_select_timer timer after initialize is timed out @@ -2137,8 +2141,8 @@ void bond_3ad_state_machine_handler(stru // select the active aggregator for the bond if ((port = __get_first_port(bond))) { if (!port->slave) { - printk(KERN_WARNING "bonding: Warning: bond's first port is uninitialized\n"); - goto end; + printk(KERN_WARNING DRV_NAME ": Warning: bond's first port is uninitialized\n"); + goto re_arm; } aggregator = __get_first_agg(port); @@ -2149,8 +2153,8 @@ void bond_3ad_state_machine_handler(stru // for each port run the state machines for (port = __get_first_port(bond); port; port = __get_next_port(port)) { if (!port->slave) { - printk(KERN_WARNING "bonding: Warning: Found an uninitialized port\n"); - goto end; + printk(KERN_WARNING DRV_NAME ": Warning: Found an uninitialized port\n"); + goto re_arm; } ad_rx_machine(NULL, port); @@ -2165,14 +2169,10 @@ void bond_3ad_state_machine_handler(stru } } -end: +re_arm: + mod_timer(&(BOND_AD_INFO(bond).ad_timer), jiffies + ad_delta_in_ticks); +out: read_unlock(&bond->lock); - - - if ((bond->device->flags & IFF_UP) == IFF_UP) { - /* re-arm the timer */ - mod_timer(&(BOND_AD_INFO(bond).ad_timer), jiffies + (AD_TIMER_INTERVAL * HZ / 1000)); - } } /** @@ -2194,14 +2194,14 @@ void bond_3ad_rx_indication(struct lacpd port = &(SLAVE_AD_INFO(slave).port); if (!port->slave) { - printk(KERN_WARNING "bonding: Warning: port of slave %s is uninitialized\n", slave->dev->name); + printk(KERN_WARNING DRV_NAME ": Warning: port of slave %s is uninitialized\n", slave->dev->name); return; } switch (lacpdu->subtype) { case AD_TYPE_LACPDU: __ntohs_lacpdu(lacpdu); - BOND_PRINT_DBG(("Received LACPDU on port %d", port->actor_port_number)); + dprintk("Received LACPDU on port %d\n", port->actor_port_number); ad_rx_machine(lacpdu, port); break; @@ -2210,17 +2210,17 @@ void bond_3ad_rx_indication(struct lacpd switch (((struct marker *)lacpdu)->tlv_type) { case AD_MARKER_INFORMATION_SUBTYPE: - BOND_PRINT_DBG(("Received Marker Information on port %d", port->actor_port_number)); + dprintk("Received Marker Information on port %d\n", port->actor_port_number); ad_marker_info_received((struct marker *)lacpdu, port); break; case AD_MARKER_RESPONSE_SUBTYPE: - BOND_PRINT_DBG(("Received Marker Response on port %d", port->actor_port_number)); + dprintk("Received Marker Response on port %d\n", port->actor_port_number); ad_marker_response_received((struct marker *)lacpdu, port); break; default: - BOND_PRINT_DBG(("Received an unknown Marker subtype on slot %d", port->actor_port_number)); + dprintk("Received an unknown Marker subtype on slot %d\n", port->actor_port_number); } } } @@ -2240,14 +2240,14 @@ void bond_3ad_adapter_speed_changed(stru // if slave is null, the whole port is not initialized if (!port->slave) { - printk(KERN_WARNING "bonding: Warning: speed changed for uninitialized port on %s\n", + printk(KERN_WARNING DRV_NAME ": Warning: speed changed for uninitialized port on %s\n", slave->dev->name); return; } port->actor_admin_port_key &= ~AD_SPEED_KEY_BITS; port->actor_oper_port_key=port->actor_admin_port_key |= (__get_link_speed(port) << 1); - BOND_PRINT_DBG(("Port %d changed speed", port->actor_port_number)); + dprintk("Port %d changed speed\n", port->actor_port_number); // there is no need to reselect a new aggregator, just signal the // state machines to reinitialize port->sm_vars |= AD_PORT_BEGIN; @@ -2267,14 +2267,14 @@ void bond_3ad_adapter_duplex_changed(str // if slave is null, the whole port is not initialized if (!port->slave) { - printk(KERN_WARNING "bonding: Warning: duplex changed for uninitialized port on %s\n", + printk(KERN_WARNING DRV_NAME ": Warning: duplex changed for uninitialized port on %s\n", slave->dev->name); return; } port->actor_admin_port_key &= ~AD_DUPLEX_KEY_BITS; port->actor_oper_port_key=port->actor_admin_port_key |= __get_duplex(port); - BOND_PRINT_DBG(("Port %d changed duplex", port->actor_port_number)); + dprintk("Port %d changed duplex\n", port->actor_port_number); // there is no need to reselect a new aggregator, just signal the // state machines to reinitialize port->sm_vars |= AD_PORT_BEGIN; @@ -2295,10 +2295,8 @@ void bond_3ad_handle_link_change(struct // if slave is null, the whole port is not initialized if (!port->slave) { -#ifdef BONDING_DEBUG - printk(KERN_WARNING "bonding: Warning: link status changed for uninitialized port on %s\n", - slave->dev->name); -#endif + printk(KERN_WARNING DRV_NAME ": Warning: link status changed for uninitialized port on %s\n", + slave->dev->name); return; } @@ -2356,41 +2354,27 @@ int bond_3ad_get_active_agg_info(struct int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) { - slave_t *slave, *start_at; - struct bonding *bond = (struct bonding *) dev->priv; + struct slave *slave, *start_at; + struct bonding *bond = dev->priv; struct ethhdr *data = (struct ethhdr *)skb->data; int slave_agg_no; int slaves_in_agg; int agg_id; + int i; struct ad_info ad_info; - if (!IS_UP(dev)) { /* bond down */ - dev_kfree_skb(skb); - return 0; - } - - if (bond == NULL) { - printk(KERN_CRIT "bonding: Error: bond is NULL on device %s\n", dev->name); - dev_kfree_skb(skb); - return 0; - } - + /* make sure that the slaves list will + * not change during tx + */ read_lock(&bond->lock); - slave = bond->prev; - /* check if bond is empty */ - if ((slave == (struct slave *) bond) || (bond->slave_cnt == 0)) { - printk(KERN_DEBUG "ERROR: bond is empty\n"); - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; + if (!BOND_IS_OK(bond)) { + goto free_out; } if (bond_3ad_get_active_agg_info(bond, &ad_info)) { printk(KERN_DEBUG "ERROR: bond_3ad_get_active_agg_info failed\n"); - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; + goto free_out; } slaves_in_agg = ad_info.ports; @@ -2399,21 +2383,12 @@ int bond_3ad_xmit_xor(struct sk_buff *sk if (slaves_in_agg == 0) { /*the aggregator is empty*/ printk(KERN_DEBUG "ERROR: active aggregator is empty\n"); - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; + goto free_out; } - /* we're at the root, get the first slave */ - if ((slave == NULL) || (slave->dev == NULL)) { - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; - } + slave_agg_no = (data->h_dest[5]^bond->dev->dev_addr[5]) % slaves_in_agg; - slave_agg_no = (data->h_dest[5]^slave->dev->dev_addr[5]) % slaves_in_agg; - while (slave != (slave_t *)bond) { + bond_for_each_slave(bond, slave, i) { struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator; if (agg && (agg->aggregator_identifier == agg_id)) { @@ -2422,37 +2397,18 @@ int bond_3ad_xmit_xor(struct sk_buff *sk break; } } - - slave = slave->prev; - if (slave == NULL) { - printk(KERN_ERR "bonding: Error: slave is NULL\n"); - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; - } } - if (slave == (slave_t *)bond) { - printk(KERN_ERR "bonding: Error: Couldn't find a slave to tx on for aggregator ID %d\n", agg_id); - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; + if (slave_agg_no >= 0) { + printk(KERN_ERR DRV_NAME ": Error: Couldn't find a slave to tx on for aggregator ID %d\n", agg_id); + goto free_out; } start_at = slave; - do { + bond_for_each_slave_from(bond, slave, i, start_at) { int slave_agg_id = 0; - struct aggregator *agg; - - if (slave == NULL) { - printk(KERN_ERR "bonding: Error: slave is NULL\n"); - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; - } - - agg = SLAVE_AD_INFO(slave).port.aggregator; + struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator; if (agg) { slave_agg_id = agg->aggregator_identifier; @@ -2463,20 +2419,24 @@ int bond_3ad_xmit_xor(struct sk_buff *sk skb->dev = slave->dev; skb->priority = 1; dev_queue_xmit(skb); - read_unlock(&bond->lock); - return 0; + + goto out; } - } while ((slave = slave->next) != start_at); + } - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); +out: read_unlock(&bond->lock); return 0; + +free_out: + /* no suitable interface, frame not sent */ + dev_kfree_skb(skb); + goto out; } int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype) { - struct bonding *bond = (struct bonding *)dev->priv; + struct bonding *bond = dev->priv; struct slave *slave = NULL; int ret = NET_RX_DROP; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/bonding/bond_3ad.h 830-ivtv/drivers/net/bonding/bond_3ad.h --- 000-virgin/drivers/net/bonding/bond_3ad.h Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/bonding/bond_3ad.h Thu Jan 8 08:54:13 2004 @@ -28,6 +28,9 @@ * 2003/05/01 - Shmulik Hen * - Renamed bond_3ad_link_status_changed() to * bond_3ad_handle_link_change() for compatibility with TLB. + * + * 2003/09/24 - Shmulik Hen + * - Code cleanup and style changes */ #ifndef __BOND_3AD_H__ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/bonding/bond_alb.c 830-ivtv/drivers/net/bonding/bond_alb.c --- 000-virgin/drivers/net/bonding/bond_alb.c Mon Nov 17 18:29:30 2003 +++ 830-ivtv/drivers/net/bonding/bond_alb.c Thu Jan 8 08:54:13 2004 @@ -28,8 +28,13 @@ * 2003/08/06 - Amir Noam * - Add support for setting bond's MAC address with special * handling required for ALB/TLB. + * + * 2003/09/24 - Shmulik Hen + * - Code cleanup and style changes */ +//#define BONDING_DEBUG 1 + #include #include #include @@ -50,11 +55,11 @@ #define ALB_TIMER_TICKS_PER_SEC 10 /* should be a divisor of HZ */ -#define BOND_TLB_REBALANCE_INTERVAL 10 /* in seconds, periodic re-balancing - * used for division - never set +#define BOND_TLB_REBALANCE_INTERVAL 10 /* In seconds, periodic re-balancing. + * Used for division - never set * to zero !!! */ -#define BOND_ALB_LP_INTERVAL 1 /* in seconds periodic send of +#define BOND_ALB_LP_INTERVAL 1 /* In seconds, periodic send of * learning packets to the switch */ @@ -66,7 +71,7 @@ #define TLB_HASH_TABLE_SIZE 256 /* The size of the clients hash table. * Note that this value MUST NOT be smaller - * because the key hash table BYTE wide ! + * because the key hash table is BYTE wide ! */ @@ -86,12 +91,15 @@ */ #define RLB_PROMISC_TIMEOUT 10*ALB_TIMER_TICKS_PER_SEC +static const u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; +static const int alb_delta_in_ticks = HZ / ALB_TIMER_TICKS_PER_SEC; + #pragma pack(1) struct learning_pkt { u8 mac_dst[ETH_ALEN]; u8 mac_src[ETH_ALEN]; u16 type; - u8 padding[ETH_ZLEN - (2*ETH_ALEN + 2)]; + u8 padding[ETH_ZLEN - ETH_HLEN]; }; struct arp_pkt { @@ -110,13 +118,12 @@ struct arp_pkt { /* Forward declaration */ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]); -static inline u8 -_simple_hash(u8 *hash_start, int hash_size) +static inline u8 _simple_hash(u8 *hash_start, int hash_size) { int i; u8 hash = 0; - for (i=0; iload_history = 1 + entry->tx_bytes / - BOND_TLB_REBALANCE_INTERVAL; + BOND_TLB_REBALANCE_INTERVAL; entry->tx_bytes = 0; } + entry->tx_slave = NULL; entry->next = TLB_NULL_INDEX; entry->prev = TLB_NULL_INDEX; } -static inline void -tlb_init_slave(struct slave *slave) +static inline void tlb_init_slave(struct slave *slave) { - struct tlb_slave_info *slave_info = &(SLAVE_TLB_INFO(slave)); - - slave_info->load = 0; - slave_info->head = TLB_NULL_INDEX; + SLAVE_TLB_INFO(slave).load = 0; + SLAVE_TLB_INFO(slave).head = TLB_NULL_INDEX; } /* Caller must hold bond lock for read */ -static inline void -tlb_clear_slave(struct bonding *bond, struct slave *slave, u8 save_load) +static void tlb_clear_slave(struct bonding *bond, struct slave *slave, int save_load) { - struct tlb_client_info *tx_hash_table = NULL; - u32 index, next_index; + struct tlb_client_info *tx_hash_table; + u32 index; - /* clear slave from tx_hashtbl */ _lock_tx_hashtbl(bond); + + /* clear slave from tx_hashtbl */ tx_hash_table = BOND_ALB_INFO(bond).tx_hashtbl; - if (tx_hash_table) { - index = SLAVE_TLB_INFO(slave).head; - while (index != TLB_NULL_INDEX) { - next_index = tx_hash_table[index].next; - tlb_init_table_entry(bond, index, save_load); - index = next_index; - } + index = SLAVE_TLB_INFO(slave).head; + while (index != TLB_NULL_INDEX) { + u32 next_index = tx_hash_table[index].next; + tlb_init_table_entry(&tx_hash_table[index], save_load); + index = next_index; } + _unlock_tx_hashtbl(bond); tlb_init_slave(slave); } /* Must be called before starting the monitor timer */ -static int -tlb_initialize(struct bonding *bond) +static int tlb_initialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); + int size = TLB_HASH_TABLE_SIZE * sizeof(struct tlb_client_info); int i; - size_t size; - -#if(TLB_HASH_TABLE_SIZE != 256) - /* Key to the hash table is byte wide. Check the size! */ - #error Hash Table size is wrong. -#endif spin_lock_init(&(bond_info->tx_hashtbl_lock)); _lock_tx_hashtbl(bond); - if (bond_info->tx_hashtbl != NULL) { - printk (KERN_ERR "%s: TLB hash table is not NULL\n", - bond->device->name); - _unlock_tx_hashtbl(bond); - return -1; - } - size = TLB_HASH_TABLE_SIZE * sizeof(struct tlb_client_info); bond_info->tx_hashtbl = kmalloc(size, GFP_KERNEL); - if (bond_info->tx_hashtbl == NULL) { - printk (KERN_ERR "%s: Failed to allocate TLB hash table\n", - bond->device->name); + if (!bond_info->tx_hashtbl) { + printk(KERN_ERR DRV_NAME + ": Error: %s: Failed to allocate TLB hash table\n", + bond->dev->name); _unlock_tx_hashtbl(bond); return -1; } memset(bond_info->tx_hashtbl, 0, size); - for (i=0; itx_hashtbl[i], 1); } + _unlock_tx_hashtbl(bond); return 0; } /* Must be called only after all slaves have been released */ -static void -tlb_deinitialize(struct bonding *bond) +static void tlb_deinitialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); _lock_tx_hashtbl(bond); - if (bond_info->tx_hashtbl == NULL) { - _unlock_tx_hashtbl(bond); - return; - } + kfree(bond_info->tx_hashtbl); bond_info->tx_hashtbl = NULL; + _unlock_tx_hashtbl(bond); } /* Caller must hold bond lock for read */ -static struct slave* -tlb_get_least_loaded_slave(struct bonding *bond) +static struct slave *tlb_get_least_loaded_slave(struct bonding *bond) { - struct slave *slave; - struct slave *least_loaded; - s64 curr_gap, max_gap; + struct slave *slave, *least_loaded; + s64 max_gap; + int i, found = 0; /* Find the first enabled slave */ - slave = bond_get_first_slave(bond); - while (slave) { + bond_for_each_slave(bond, slave, i) { if (SLAVE_IS_OK(slave)) { + found = 1; break; } - slave = bond_get_next_slave(bond, slave); } - if (!slave) { + if (!found) { return NULL; } least_loaded = slave; - max_gap = (s64)(slave->speed * 1000000) - - (s64)(SLAVE_TLB_INFO(slave).load * 8); + max_gap = (s64)(slave->speed << 20) - /* Convert to Megabit per sec */ + (s64)(SLAVE_TLB_INFO(slave).load << 3); /* Bytes to bits */ /* Find the slave with the largest gap */ - slave = bond_get_next_slave(bond, slave); - while (slave) { + bond_for_each_slave_from(bond, slave, i, least_loaded) { if (SLAVE_IS_OK(slave)) { - curr_gap = (s64)(slave->speed * 1000000) - - (s64)(SLAVE_TLB_INFO(slave).load * 8); - if (max_gap < curr_gap) { + s64 gap = (s64)(slave->speed << 20) - + (s64)(SLAVE_TLB_INFO(slave).load << 3); + if (max_gap < gap) { least_loaded = slave; - max_gap = curr_gap; + max_gap = gap; } } - slave = bond_get_next_slave(bond, slave); } return least_loaded; } /* Caller must hold bond lock for read */ -struct slave* -tlb_choose_channel(struct bonding *bond, u32 hash_index, u32 skb_len) +struct slave *tlb_choose_channel(struct bonding *bond, u32 hash_index, u32 skb_len) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - struct tlb_client_info *hash_table = NULL; - struct slave *assigned_slave = NULL; + struct tlb_client_info *hash_table; + struct slave *assigned_slave; _lock_tx_hashtbl(bond); hash_table = bond_info->tx_hashtbl; - if (hash_table == NULL) { - printk (KERN_ERR "%s: TLB hash table is NULL\n", - bond->device->name); - _unlock_tx_hashtbl(bond); - return NULL; - } - assigned_slave = hash_table[hash_index].tx_slave; if (!assigned_slave) { assigned_slave = tlb_get_least_loaded_slave(bond); @@ -345,14 +310,12 @@ tlb_choose_channel(struct bonding *bond, } /*********************** rlb specific functions ***************************/ -static inline void -_lock_rx_hashtbl(struct bonding *bond) +static inline void _lock_rx_hashtbl(struct bonding *bond) { spin_lock(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); } -static inline void -_unlock_rx_hashtbl(struct bonding *bond) +static inline void _unlock_rx_hashtbl(struct bonding *bond) { spin_unlock(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); } @@ -360,26 +323,20 @@ _unlock_rx_hashtbl(struct bonding *bond) /* when an ARP REPLY is received from a client update its info * in the rx_hashtbl */ -static void -rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp) +static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp) { - u32 hash_index; - struct rlb_client_info *client_info = NULL; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); + struct rlb_client_info *client_info; + u32 hash_index; _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl == NULL) { - _unlock_rx_hashtbl(bond); - return; - } - hash_index = _simple_hash((u8*)&(arp->ip_src), 4); + hash_index = _simple_hash((u8*)&(arp->ip_src), sizeof(arp->ip_src)); client_info = &(bond_info->rx_hashtbl[hash_index]); if ((client_info->assigned) && (client_info->ip_src == arp->ip_dst) && (client_info->ip_dst == arp->ip_src)) { - /* update the clients MAC address */ memcpy(client_info->mac_dst, arp->mac_src, ETH_ALEN); client_info->ntt = 1; @@ -389,66 +346,60 @@ rlb_update_entry_from_arp(struct bonding _unlock_rx_hashtbl(bond); } -static int -rlb_arp_recv(struct sk_buff *skb, - struct net_device *dev, - struct packet_type* ptype) +static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct packet_type *ptype) { - struct bonding *bond = (struct bonding *)dev->priv; - int ret = NET_RX_DROP; + struct bonding *bond = bond_dev->priv; struct arp_pkt *arp = (struct arp_pkt *)skb->data; + int res = NET_RX_DROP; - if (!(dev->flags & IFF_MASTER)) { + if (!(bond_dev->flags & IFF_MASTER)) { goto out; } if (!arp) { - printk(KERN_ERR "Packet has no ARP data\n"); + dprintk("Packet has no ARP data\n"); goto out; } if (skb->len < sizeof(struct arp_pkt)) { - printk(KERN_ERR "Packet is too small to be an ARP\n"); + dprintk("Packet is too small to be an ARP\n"); goto out; } if (arp->op_code == htons(ARPOP_REPLY)) { /* update rx hash table for this ARP */ rlb_update_entry_from_arp(bond, arp); - BOND_PRINT_DBG(("Server received an ARP Reply from client")); + dprintk("Server received an ARP Reply from client\n"); } - ret = NET_RX_SUCCESS; + res = NET_RX_SUCCESS; out: dev_kfree_skb(skb); - return ret; + return res; } /* Caller must hold bond lock for read */ -static struct slave* -rlb_next_rx_slave(struct bonding *bond) +static struct slave *rlb_next_rx_slave(struct bonding *bond) { - struct slave *rx_slave = NULL, *slave = NULL; - unsigned int i = 0; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); + struct slave *rx_slave, *slave, *start_at; + int i = 0; - slave = bond_info->next_rx_slave; - if (slave == NULL) { - slave = bond->next; + if (bond_info->next_rx_slave) { + start_at = bond_info->next_rx_slave; + } else { + start_at = bond->first_slave; } - /* this loop uses the circular linked list property of the - * slave's list to go through all slaves - */ - for (i = 0; i < bond->slave_cnt; i++, slave = slave->next) { + rx_slave = NULL; + bond_for_each_slave_from(bond, slave, i, start_at) { if (SLAVE_IS_OK(slave)) { if (!rx_slave) { rx_slave = slave; - } - else if (slave->speed > rx_slave->speed) { + } else if (slave->speed > rx_slave->speed) { rx_slave = slave; } } @@ -464,48 +415,41 @@ rlb_next_rx_slave(struct bonding *bond) /* teach the switch the mac of a disabled slave * on the primary for fault tolerance * - * Caller must hold bond->ptrlock for write or bond lock for write + * Caller must hold bond->curr_slave_lock for write or bond lock for write */ -static void -rlb_teach_disabled_mac_on_primary(struct bonding *bond, u8 addr[]) +static void rlb_teach_disabled_mac_on_primary(struct bonding *bond, u8 addr[]) { - if (!bond->current_slave) { + if (!bond->curr_active_slave) { return; } + if (!bond->alb_info.primary_is_promisc) { bond->alb_info.primary_is_promisc = 1; - dev_set_promiscuity(bond->current_slave->dev, 1); + dev_set_promiscuity(bond->curr_active_slave->dev, 1); } + bond->alb_info.rlb_promisc_timeout_counter = 0; - alb_send_learning_packets(bond->current_slave, addr); + alb_send_learning_packets(bond->curr_active_slave, addr); } /* slave being removed should not be active at this point * * Caller must hold bond lock for read */ -static void -rlb_clear_slave(struct bonding *bond, struct slave *slave) +static void rlb_clear_slave(struct bonding *bond, struct slave *slave) { - struct rlb_client_info *rx_hash_table = NULL; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; + struct rlb_client_info *rx_hash_table; u32 index, next_index; /* clear slave from rx_hashtbl */ _lock_rx_hashtbl(bond); - rx_hash_table = bond_info->rx_hashtbl; - - if (rx_hash_table == NULL) { - _unlock_rx_hashtbl(bond); - return; - } + rx_hash_table = bond_info->rx_hashtbl; index = bond_info->rx_hashtbl_head; for (; index != RLB_NULL_INDEX; index = next_index) { next_index = rx_hash_table[index].next; - if (rx_hash_table[index].slave == slave) { struct slave *assigned_slave = rlb_next_rx_slave(bond); @@ -533,23 +477,24 @@ rlb_clear_slave(struct bonding *bond, st _unlock_rx_hashtbl(bond); - write_lock(&bond->ptrlock); - if (slave != bond->current_slave) { + write_lock(&bond->curr_slave_lock); + + if (slave != bond->curr_active_slave) { rlb_teach_disabled_mac_on_primary(bond, slave->dev->dev_addr); } - write_unlock(&bond->ptrlock); + + write_unlock(&bond->curr_slave_lock); } -static void -rlb_update_client(struct rlb_client_info *client_info) +static void rlb_update_client(struct rlb_client_info *client_info) { - int i = 0; + int i; - if (client_info->slave == NULL) { + if (!client_info->slave) { return; } - for (i=0; iip_dst, client_info->slave->dev, @@ -561,20 +506,14 @@ rlb_update_client(struct rlb_client_info } /* sends ARP REPLIES that update the clients that need updating */ -static void -rlb_update_rx_clients(struct bonding *bond) +static void rlb_update_rx_clients(struct bonding *bond) { - u32 hash_index; - struct rlb_client_info *client_info = NULL; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); + struct rlb_client_info *client_info; + u32 hash_index; _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl == NULL) { - _unlock_rx_hashtbl(bond); - return; - } - hash_index = bond_info->rx_hashtbl_head; for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) { client_info = &(bond_info->rx_hashtbl[hash_index]); @@ -595,22 +534,15 @@ rlb_update_rx_clients(struct bonding *bo } /* The slave was assigned a new mac address - update the clients */ -static void -rlb_req_update_slave_clients(struct bonding *bond, struct slave *slave) +static void rlb_req_update_slave_clients(struct bonding *bond, struct slave *slave) { - u32 hash_index; - u8 ntt = 0; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; - struct rlb_client_info* client_info = NULL; + struct rlb_client_info *client_info; + int ntt = 0; + u32 hash_index; _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl == NULL) { - _unlock_rx_hashtbl(bond); - return; - } - hash_index = bond_info->rx_hashtbl_head; for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) { client_info = &(bond_info->rx_hashtbl[hash_index]); @@ -633,37 +565,31 @@ rlb_req_update_slave_clients(struct bond } /* mark all clients using src_ip to be updated */ -static void -rlb_req_update_subnet_clients(struct bonding *bond, u32 src_ip) +static void rlb_req_update_subnet_clients(struct bonding *bond, u32 src_ip) { - u32 hash_index; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; - struct rlb_client_info *client_info = NULL; + struct rlb_client_info *client_info; + u32 hash_index; _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl == NULL) { - _unlock_rx_hashtbl(bond); - return; - } - hash_index = bond_info->rx_hashtbl_head; for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) { client_info = &(bond_info->rx_hashtbl[hash_index]); if (!client_info->slave) { - printk(KERN_ERR "Bonding: Error: found a client with no" - " channel in the client's hash table\n"); + printk(KERN_ERR DRV_NAME + ": Error: found a client with no channel in " + "the client's hash table\n"); continue; } /*update all clients using this src_ip, that are not assigned - * to the team's address (current_slave) and have a known + * to the team's address (curr_active_slave) and have a known * unicast mac address. */ if ((client_info->ip_src == src_ip) && memcmp(client_info->slave->dev->dev_addr, - bond->device->dev_addr, ETH_ALEN) && + bond->dev->dev_addr, ETH_ALEN) && memcmp(client_info->mac_dst, mac_bcast, ETH_ALEN)) { client_info->ntt = 1; bond_info->rx_ntt = 1; @@ -674,30 +600,22 @@ rlb_req_update_subnet_clients(struct bon } /* Caller must hold both bond and ptr locks for read */ -struct slave* -rlb_choose_channel(struct bonding *bond, struct arp_pkt *arp) +struct slave *rlb_choose_channel(struct bonding *bond, struct arp_pkt *arp) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - struct rlb_client_info *client_info = NULL; + struct slave *assigned_slave; + struct rlb_client_info *client_info; u32 hash_index = 0; - struct slave *assigned_slave = NULL; - u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl == NULL) { - _unlock_rx_hashtbl(bond); - return NULL; - } - - hash_index = _simple_hash((u8 *)&arp->ip_dst, 4); + hash_index = _simple_hash((u8 *)&arp->ip_dst, sizeof(arp->ip_src)); client_info = &(bond_info->rx_hashtbl[hash_index]); - if (client_info->assigned == 1) { + if (client_info->assigned) { if ((client_info->ip_src == arp->ip_src) && (client_info->ip_dst == arp->ip_dst)) { /* the entry is already assigned to this client */ - if (memcmp(arp->mac_dst, mac_bcast, ETH_ALEN)) { /* update mac address from arp */ memcpy(client_info->mac_dst, arp->mac_dst, ETH_ALEN); @@ -710,12 +628,12 @@ rlb_choose_channel(struct bonding *bond, } } else { /* the entry is already assigned to some other client, - * move the old client to primary (current_slave) so + * move the old client to primary (curr_active_slave) so * that the new client can be assigned to this entry. */ - if (bond->current_slave && - client_info->slave != bond->current_slave) { - client_info->slave = bond->current_slave; + if (bond->curr_active_slave && + client_info->slave != bond->curr_active_slave) { + client_info->slave = bond->curr_active_slave; rlb_update_client(client_info); } } @@ -736,8 +654,7 @@ rlb_choose_channel(struct bonding *bond, if (memcmp(client_info->mac_dst, mac_bcast, ETH_ALEN)) { client_info->ntt = 1; bond->alb_info.rx_ntt = 1; - } - else { + } else { client_info->ntt = 0; } @@ -760,10 +677,9 @@ rlb_choose_channel(struct bonding *bond, /* chooses (and returns) transmit channel for arp reply * does not choose channel for other arp types since they are - * sent on the current_slave + * sent on the curr_active_slave */ -static struct slave* -rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) +static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) { struct arp_pkt *arp = (struct arp_pkt *)skb->nh.raw; struct slave *tx_slave = NULL; @@ -776,9 +692,8 @@ rlb_arp_xmit(struct sk_buff *skb, struct if (tx_slave) { memcpy(arp->mac_src,tx_slave->dev->dev_addr, ETH_ALEN); } - BOND_PRINT_DBG(("Server sent ARP Reply packet")); + dprintk("Server sent ARP Reply packet\n"); } else if (arp->op_code == __constant_htons(ARPOP_REQUEST)) { - /* Create an entry in the rx_hashtbl for this client as a * place holder. * When the arp reply is received the entry will be updated @@ -797,34 +712,29 @@ rlb_arp_xmit(struct sk_buff *skb, struct * updated with their assigned mac. */ rlb_req_update_subnet_clients(bond, arp->ip_src); - BOND_PRINT_DBG(("Server sent ARP Request packet")); + dprintk("Server sent ARP Request packet\n"); } return tx_slave; } /* Caller must hold bond lock for read */ -static void -rlb_rebalance(struct bonding *bond) +static void rlb_rebalance(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - struct slave *assigned_slave = NULL; + struct slave *assigned_slave; + struct rlb_client_info *client_info; + int ntt; u32 hash_index; - struct rlb_client_info *client_info = NULL; - u8 ntt = 0; _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl == NULL) { - _unlock_rx_hashtbl(bond); - return; - } - + ntt = 0; hash_index = bond_info->rx_hashtbl_head; for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) { client_info = &(bond_info->rx_hashtbl[hash_index]); assigned_slave = rlb_next_rx_slave(bond); - if (assigned_slave && (client_info->slave != assigned_slave)){ + if (assigned_slave && (client_info->slave != assigned_slave)) { client_info->slave = assigned_slave; client_info->ntt = 1; ntt = 1; @@ -839,96 +749,83 @@ rlb_rebalance(struct bonding *bond) } /* Caller must hold rx_hashtbl lock */ -static inline void -rlb_init_table_entry(struct rlb_client_info *entry) +static void rlb_init_table_entry(struct rlb_client_info *entry) { + memset(entry, 0, sizeof(struct rlb_client_info)); entry->next = RLB_NULL_INDEX; entry->prev = RLB_NULL_INDEX; - entry->assigned = 0; - entry->ntt = 0; } -static int -rlb_initialize(struct bonding *bond) +static int rlb_initialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct packet_type *pk_type = &(BOND_ALB_INFO(bond).rlb_pkt_type); + int size = RLB_HASH_TABLE_SIZE * sizeof(struct rlb_client_info); int i; - size_t size; spin_lock_init(&(bond_info->rx_hashtbl_lock)); _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl != NULL) { - printk (KERN_ERR "%s: RLB hash table is not NULL\n", - bond->device->name); - _unlock_rx_hashtbl(bond); - return -1; - } - size = RLB_HASH_TABLE_SIZE * sizeof(struct rlb_client_info); bond_info->rx_hashtbl = kmalloc(size, GFP_KERNEL); - if (bond_info->rx_hashtbl == NULL) { - printk (KERN_ERR "%s: Failed to allocate" - " RLB hash table\n", bond->device->name); + if (!bond_info->rx_hashtbl) { + printk(KERN_ERR DRV_NAME + ": Error: %s: Failed to allocate RLB hash table\n", + bond->dev->name); _unlock_rx_hashtbl(bond); return -1; } bond_info->rx_hashtbl_head = RLB_NULL_INDEX; - for (i=0; irx_hashtbl + i); } - _unlock_rx_hashtbl(bond); - /* register to receive ARPs */ + _unlock_rx_hashtbl(bond); /*initialize packet type*/ pk_type->type = __constant_htons(ETH_P_ARP); - pk_type->dev = bond->device; + pk_type->dev = bond->dev; pk_type->func = rlb_arp_recv; + /* register to receive ARPs */ dev_add_pack(pk_type); return 0; } -static void -rlb_deinitialize(struct bonding *bond) +static void rlb_deinitialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); dev_remove_pack(&(bond_info->rlb_pkt_type)); _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl == NULL) { - _unlock_rx_hashtbl(bond); - return; - } + kfree(bond_info->rx_hashtbl); bond_info->rx_hashtbl = NULL; + _unlock_rx_hashtbl(bond); } /*********************** tlb/rlb shared functions *********************/ -static void -alb_send_learning_packets(struct slave *slave, u8 mac_addr[]) +static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]) { - struct sk_buff *skb = NULL; struct learning_pkt pkt; - char *data = NULL; + int size = sizeof(struct learning_pkt); int i; - unsigned int size = sizeof(struct learning_pkt); memset(&pkt, 0, size); memcpy(pkt.mac_dst, mac_addr, ETH_ALEN); memcpy(pkt.mac_src, mac_addr, ETH_ALEN); pkt.type = __constant_htons(ETH_P_LOOP); - for (i=0; i < MAX_LP_RETRY; i++) { - skb = NULL; + for (i = 0; i < MAX_LP_RETRY; i++) { + struct sk_buff *skb; + char *data; + skb = dev_alloc_skb(size); if (!skb) { return; @@ -936,28 +833,26 @@ alb_send_learning_packets(struct slave * data = skb_put(skb, size); memcpy(data, &pkt, size); + skb->mac.raw = data; skb->nh.raw = data + ETH_HLEN; skb->protocol = pkt.type; skb->priority = TC_PRIO_CONTROL; skb->dev = slave->dev; + dev_queue_xmit(skb); } - } /* hw is a boolean parameter that determines whether we should try and * set the hw address of the device as well as the hw address of the * net_device */ -static int -alb_set_slave_mac_addr(struct slave *slave, u8 addr[], int hw) +static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[], int hw) { - struct net_device *dev = NULL; + struct net_device *dev = slave->dev; struct sockaddr s_addr; - dev = slave->dev; - if (!hw) { memcpy(dev->dev_addr, addr, dev->addr_len); return 0; @@ -968,26 +863,23 @@ alb_set_slave_mac_addr(struct slave *sla memcpy(s_addr.sa_data, addr, dev->addr_len); s_addr.sa_family = dev->type; if (dev->set_mac_address(dev, &s_addr)) { - printk(KERN_DEBUG "bonding: Error: alb_set_slave_mac_addr:" - " dev->set_mac_address of dev %s failed!" - " ALB mode requires that the base driver" - " support setting the hw address also when" - " the network device's interface is open\n", - dev->name); + printk(KERN_ERR DRV_NAME + ": Error: dev->set_mac_address of dev %s failed! ALB " + "mode requires that the base driver support setting " + "the hw address also when the network device's " + "interface is open\n", + dev->name); return -EOPNOTSUPP; } return 0; } -/* Caller must hold bond lock for write or ptrlock for write*/ -static void -alb_swap_mac_addr(struct bonding *bond, - struct slave *slave1, - struct slave *slave2) +/* Caller must hold bond lock for write or curr_slave_lock for write*/ +static void alb_swap_mac_addr(struct bonding *bond, struct slave *slave1, struct slave *slave2) { - u8 tmp_mac_addr[ETH_ALEN]; struct slave *disabled_slave = NULL; - u8 slaves_state_differ; + u8 tmp_mac_addr[ETH_ALEN]; + int slaves_state_differ; slaves_state_differ = (SLAVE_IS_OK(slave1) != SLAVE_IS_OK(slave2)); @@ -1004,8 +896,7 @@ alb_swap_mac_addr(struct bonding *bond, */ rlb_req_update_slave_clients(bond, slave1); } - } - else { + } else { disabled_slave = slave1; } @@ -1017,15 +908,14 @@ alb_swap_mac_addr(struct bonding *bond, */ rlb_req_update_slave_clients(bond, slave2); } - } - else { + } else { disabled_slave = slave2; } if (bond->alb_info.rlb_enabled && slaves_state_differ) { - /* A disabled slave was assigned an active mac addr */ - rlb_teach_disabled_mac_on_primary(bond, - disabled_slave->dev->dev_addr); + /* A disabled slave was assigned an active mac addr */ + rlb_teach_disabled_mac_on_primary(bond, + disabled_slave->dev->dev_addr); } } @@ -1043,10 +933,8 @@ alb_swap_mac_addr(struct bonding *bond, * * Caller must hold bond lock */ -static void -alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *slave) +static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *slave) { - struct slave *tmp_slave; int perm_curr_diff; int perm_bond_diff; @@ -1054,20 +942,23 @@ alb_change_hw_addr_on_detach(struct bond slave->dev->dev_addr, ETH_ALEN); perm_bond_diff = memcmp(slave->perm_hwaddr, - bond->device->dev_addr, + bond->dev->dev_addr, ETH_ALEN); + if (perm_curr_diff && perm_bond_diff) { - tmp_slave = bond_get_first_slave(bond); - while (tmp_slave) { + struct slave *tmp_slave; + int i, found = 0; + + bond_for_each_slave(bond, tmp_slave, i) { if (!memcmp(slave->perm_hwaddr, - tmp_slave->dev->dev_addr, - ETH_ALEN)) { + tmp_slave->dev->dev_addr, + ETH_ALEN)) { + found = 1; break; } - tmp_slave = bond_get_next_slave(bond, tmp_slave); } - if (tmp_slave) { + if (found) { alb_swap_mac_addr(bond, slave, tmp_slave); } } @@ -1098,10 +989,11 @@ alb_change_hw_addr_on_detach(struct bond * caller must hold the bond lock for write since the mac addresses are compared * and may be swapped. */ -static int -alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave) +static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave) { - struct slave *tmp_slave1, *tmp_slave2; + struct slave *tmp_slave1, *tmp_slave2, *free_mac_slave; + struct slave *has_bond_addr = bond->curr_active_slave; + int i, j, found = 0; if (bond->slave_cnt == 0) { /* this is the first slave */ @@ -1112,65 +1004,78 @@ alb_handle_addr_collision_on_attach(stru * check uniqueness of slave's mac address against the other * slaves in the bond. */ - if (memcmp(slave->perm_hwaddr, bond->device->dev_addr, ETH_ALEN)) { - tmp_slave1 = bond_get_first_slave(bond); - for (; tmp_slave1; tmp_slave1 = bond_get_next_slave(bond, tmp_slave1)) { + if (memcmp(slave->perm_hwaddr, bond->dev->dev_addr, ETH_ALEN)) { + bond_for_each_slave(bond, tmp_slave1, i) { if (!memcmp(tmp_slave1->dev->dev_addr, slave->dev->dev_addr, ETH_ALEN)) { + found = 1; break; } } - if (tmp_slave1) { + + if (found) { /* a slave was found that is using the mac address * of the new slave */ - printk(KERN_ERR "bonding: Warning: the hw address " - "of slave %s is not unique - cannot enslave it!" - , slave->dev->name); + printk(KERN_ERR DRV_NAME + ": Error: the hw address of slave %s is not " + "unique - cannot enslave it!", + slave->dev->name); return -EINVAL; } + return 0; } - /* the slave's address is equal to the address of the bond - * search for a spare address in the bond for this slave. + /* The slave's address is equal to the address of the bond. + * Search for a spare address in the bond for this slave. */ - tmp_slave1 = bond_get_first_slave(bond); - for (; tmp_slave1; tmp_slave1 = bond_get_next_slave(bond, tmp_slave1)) { - - tmp_slave2 = bond_get_first_slave(bond); - for (; tmp_slave2; tmp_slave2 = bond_get_next_slave(bond, tmp_slave2)) { + free_mac_slave = NULL; + bond_for_each_slave(bond, tmp_slave1, i) { + found = 0; + bond_for_each_slave(bond, tmp_slave2, j) { if (!memcmp(tmp_slave1->perm_hwaddr, tmp_slave2->dev->dev_addr, ETH_ALEN)) { - + found = 1; break; } } - if (!tmp_slave2) { + if (!found) { /* no slave has tmp_slave1's perm addr * as its curr addr */ + free_mac_slave = tmp_slave1; break; } + + if (!has_bond_addr) { + if (!memcmp(tmp_slave1->dev->dev_addr, + bond->dev->dev_addr, + ETH_ALEN)) { + + has_bond_addr = tmp_slave1; + } + } } - if (tmp_slave1) { - alb_set_slave_mac_addr(slave, tmp_slave1->perm_hwaddr, + if (free_mac_slave) { + alb_set_slave_mac_addr(slave, free_mac_slave->perm_hwaddr, bond->alb_info.rlb_enabled); - printk(KERN_WARNING "bonding: Warning: the hw address " - "of slave %s is in use by the bond; " - "giving it the hw address of %s\n", - slave->dev->name, tmp_slave1->dev->name); - } else { - printk(KERN_CRIT "bonding: Error: the hw address " - "of slave %s is in use by the bond; " - "couldn't find a slave with a free hw " - "address to give it (this should not have " - "happened)\n", slave->dev->name); + printk(KERN_WARNING DRV_NAME + ": Warning: the hw address of slave %s is in use by " + "the bond; giving it the hw address of %s\n", + slave->dev->name, free_mac_slave->dev->name); + + } else if (has_bond_addr) { + printk(KERN_ERR DRV_NAME + ": Error: the hw address of slave %s is in use by the " + "bond; couldn't find a slave with a free hw address to " + "give it (this should not have happened)\n", + slave->dev->name); return -EFAULT; } @@ -1188,37 +1093,36 @@ alb_handle_addr_collision_on_attach(stru * * For each slave, this function sets the interface to the new address and then * changes its dev_addr field to its previous value. - * + * * Unwinding assumes bond's mac address has not yet changed. */ -static inline int -alb_set_mac_address(struct bonding *bond, void *addr) +static int alb_set_mac_address(struct bonding *bond, void *addr) { struct sockaddr sa; - struct slave *slave; + struct slave *slave, *stop_at; char tmp_addr[ETH_ALEN]; - int error; + int res; + int i; if (bond->alb_info.rlb_enabled) { return 0; } - slave = bond_get_first_slave(bond); - for (; slave; slave = bond_get_next_slave(bond, slave)) { + bond_for_each_slave(bond, slave, i) { if (slave->dev->set_mac_address == NULL) { - error = -EOPNOTSUPP; + res = -EOPNOTSUPP; goto unwind; } /* save net_device's current hw address */ memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN); - error = slave->dev->set_mac_address(slave->dev, addr); + res = slave->dev->set_mac_address(slave->dev, addr); /* restore net_device's hw address */ memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN); - if (error) { + if (res) { goto unwind; } } @@ -1226,22 +1130,23 @@ alb_set_mac_address(struct bonding *bond return 0; unwind: - memcpy(sa.sa_data, bond->device->dev_addr, bond->device->addr_len); - sa.sa_family = bond->device->type; - slave = bond_get_first_slave(bond); - for (; slave; slave = bond_get_next_slave(bond, slave)) { + memcpy(sa.sa_data, bond->dev->dev_addr, bond->dev->addr_len); + sa.sa_family = bond->dev->type; + + /* unwind from head to the slave that failed */ + stop_at = slave; + bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) { memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN); slave->dev->set_mac_address(slave->dev, &sa); memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN); } - return error; + return res; } /************************ exported alb funcions ************************/ -int -bond_alb_initialize(struct bonding *bond, int rlb_enabled) +int bond_alb_initialize(struct bonding *bond, int rlb_enabled) { int res; @@ -1263,8 +1168,7 @@ bond_alb_initialize(struct bonding *bond return 0; } -void -bond_alb_deinitialize(struct bonding *bond) +void bond_alb_deinitialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); @@ -1275,49 +1179,38 @@ bond_alb_deinitialize(struct bonding *bo } } -int -bond_alb_xmit(struct sk_buff *skb, struct net_device *dev) +int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) { - struct bonding *bond = (struct bonding *) dev->priv; - struct ethhdr *eth_data = (struct ethhdr *)skb->data; + struct bonding *bond = bond_dev->priv; + struct ethhdr *eth_data = (struct ethhdr *)skb->mac.raw = skb->data; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct slave *tx_slave = NULL; - char do_tx_balance = 1; + static u32 ip_bcast = 0xffffffff; int hash_size = 0; + int do_tx_balance = 1; u32 hash_index = 0; u8 *hash_start = NULL; - u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; - if (!IS_UP(dev)) { /* bond down */ - dev_kfree_skb(skb); - return 0; - } - - /* make sure that the current_slave and the slaves list do + /* make sure that the curr_active_slave and the slaves list do * not change during tx */ read_lock(&bond->lock); + read_lock(&bond->curr_slave_lock); - if (bond->slave_cnt == 0) { - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; + if (!BOND_IS_OK(bond)) { + goto free_out; } - read_lock(&bond->ptrlock); - switch (ntohs(skb->protocol)) { case ETH_P_IP: if ((memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) || - (skb->nh.iph->daddr == 0xffffffff)) { + (skb->nh.iph->daddr == ip_bcast)) { do_tx_balance = 0; break; } hash_start = (char*)&(skb->nh.iph->daddr); - hash_size = 4; + hash_size = sizeof(skb->nh.iph->daddr); break; - case ETH_P_IPV6: if (memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) { do_tx_balance = 0; @@ -1325,9 +1218,8 @@ bond_alb_xmit(struct sk_buff *skb, struc } hash_start = (char*)&(skb->nh.ipv6h->daddr); - hash_size = 16; + hash_size = sizeof(skb->nh.ipv6h->daddr); break; - case ETH_P_IPX: if (ipx_hdr(skb)->ipx_checksum != __constant_htons(IPX_NO_CHECKSUM)) { @@ -1336,8 +1228,7 @@ bond_alb_xmit(struct sk_buff *skb, struc break; } - if (ipx_hdr(skb)->ipx_type != - __constant_htons(IPX_TYPE_NCP)) { + if (ipx_hdr(skb)->ipx_type != IPX_TYPE_NCP) { /* The only protocol worth balancing in * this family since it has an "ARP" like * mechanism @@ -1349,14 +1240,12 @@ bond_alb_xmit(struct sk_buff *skb, struc hash_start = (char*)eth_data->h_dest; hash_size = ETH_ALEN; break; - case ETH_P_ARP: do_tx_balance = 0; if (bond_info->rlb_enabled) { tx_slave = rlb_arp_xmit(skb, bond); } break; - default: do_tx_balance = 0; break; @@ -1369,16 +1258,16 @@ bond_alb_xmit(struct sk_buff *skb, struc if (!tx_slave) { /* unbalanced or unassigned, send through primary */ - tx_slave = bond->current_slave; + tx_slave = bond->curr_active_slave; bond_info->unbalanced_load += skb->len; } if (tx_slave && SLAVE_IS_OK(tx_slave)) { skb->dev = tx_slave->dev; - if (tx_slave != bond->current_slave) { + if (tx_slave != bond->curr_active_slave) { memcpy(eth_data->h_source, - tx_slave->dev->dev_addr, - ETH_ALEN); + tx_slave->dev->dev_addr, + ETH_ALEN); } dev_queue_xmit(skb); } else { @@ -1386,26 +1275,35 @@ bond_alb_xmit(struct sk_buff *skb, struc if (tx_slave) { tlb_clear_slave(bond, tx_slave, 0); } - dev_kfree_skb(skb); + goto free_out; } - read_unlock(&bond->ptrlock); +out: + read_unlock(&bond->curr_slave_lock); read_unlock(&bond->lock); return 0; + +free_out: + dev_kfree_skb(skb); + goto out; } -void -bond_alb_monitor(struct bonding *bond) +void bond_alb_monitor(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - struct slave *slave = NULL; + struct slave *slave; + int i; read_lock(&bond->lock); - if ((bond->slave_cnt == 0) || !(bond->device->flags & IFF_UP)) { + if (bond->kill_timers) { + goto out; + } + + if (bond->slave_cnt == 0) { bond_info->tx_rebalance_counter = 0; bond_info->lp_counter = 0; - goto out; + goto re_arm; } bond_info->tx_rebalance_counter++; @@ -1413,51 +1311,53 @@ bond_alb_monitor(struct bonding *bond) /* send learning packets */ if (bond_info->lp_counter >= BOND_ALB_LP_TICKS) { - /* change of current_slave involves swapping of mac addresses. + /* change of curr_active_slave involves swapping of mac addresses. * in order to avoid this swapping from happening while - * sending the learning packets, the ptrlock must be held for + * sending the learning packets, the curr_slave_lock must be held for * read. */ - read_lock(&bond->ptrlock); - slave = bond_get_first_slave(bond); - while (slave) { + read_lock(&bond->curr_slave_lock); + + bond_for_each_slave(bond, slave, i) { alb_send_learning_packets(slave,slave->dev->dev_addr); - slave = bond_get_next_slave(bond, slave); } - read_unlock(&bond->ptrlock); + + read_unlock(&bond->curr_slave_lock); bond_info->lp_counter = 0; } /* rebalance tx traffic */ if (bond_info->tx_rebalance_counter >= BOND_TLB_REBALANCE_TICKS) { - read_lock(&bond->ptrlock); - slave = bond_get_first_slave(bond); - while (slave) { + + read_lock(&bond->curr_slave_lock); + + bond_for_each_slave(bond, slave, i) { tlb_clear_slave(bond, slave, 1); - if (slave == bond->current_slave) { + if (slave == bond->curr_active_slave) { SLAVE_TLB_INFO(slave).load = bond_info->unbalanced_load / BOND_TLB_REBALANCE_INTERVAL; bond_info->unbalanced_load = 0; } - slave = bond_get_next_slave(bond, slave); } - read_unlock(&bond->ptrlock); + + read_unlock(&bond->curr_slave_lock); + bond_info->tx_rebalance_counter = 0; } /* handle rlb stuff */ if (bond_info->rlb_enabled) { /* the following code changes the promiscuity of the - * the current_slave. It needs to be locked with a + * the curr_active_slave. It needs to be locked with a * write lock to protect from other code that also * sets the promiscuity. */ - write_lock(&bond->ptrlock); + write_lock(&bond->curr_slave_lock); + if (bond_info->primary_is_promisc && - (++bond_info->rlb_promisc_timeout_counter >= - RLB_PROMISC_TIMEOUT)) { + (++bond_info->rlb_promisc_timeout_counter >= RLB_PROMISC_TIMEOUT)) { bond_info->rlb_promisc_timeout_counter = 0; @@ -1465,12 +1365,13 @@ bond_alb_monitor(struct bonding *bond) * because a slave was disabled then * it can now leave promiscuous mode. */ - dev_set_promiscuity(bond->current_slave->dev, -1); + dev_set_promiscuity(bond->curr_active_slave->dev, -1); bond_info->primary_is_promisc = 0; } - write_unlock(&bond->ptrlock); - if (bond_info->rlb_rebalance == 1) { + write_unlock(&bond->curr_slave_lock); + + if (bond_info->rlb_rebalance) { bond_info->rlb_rebalance = 0; rlb_rebalance(bond); } @@ -1490,28 +1391,23 @@ bond_alb_monitor(struct bonding *bond) } } +re_arm: + mod_timer(&(bond_info->alb_timer), jiffies + alb_delta_in_ticks); out: read_unlock(&bond->lock); - - if (bond->device->flags & IFF_UP) { - /* re-arm the timer */ - mod_timer(&(bond_info->alb_timer), - jiffies + (HZ/ALB_TIMER_TICKS_PER_SEC)); - } } -/* assumption: called before the slave is attched to the bond +/* assumption: called before the slave is attached to the bond * and not locked by the bond lock */ -int -bond_alb_init_slave(struct bonding *bond, struct slave *slave) +int bond_alb_init_slave(struct bonding *bond, struct slave *slave) { - int err = 0; + int res; - err = alb_set_slave_mac_addr(slave, slave->perm_hwaddr, + res = alb_set_slave_mac_addr(slave, slave->perm_hwaddr, bond->alb_info.rlb_enabled); - if (err) { - return err; + if (res) { + return res; } /* caller must hold the bond lock for write since the mac addresses @@ -1519,12 +1415,12 @@ bond_alb_init_slave(struct bonding *bond */ write_lock_bh(&bond->lock); - err = alb_handle_addr_collision_on_attach(bond, slave); + res = alb_handle_addr_collision_on_attach(bond, slave); write_unlock_bh(&bond->lock); - if (err) { - return err; + if (res) { + return res; } tlb_init_slave(slave); @@ -1540,8 +1436,7 @@ bond_alb_init_slave(struct bonding *bond } /* Caller must hold bond lock for write */ -void -bond_alb_deinit_slave(struct bonding *bond, struct slave *slave) +void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave) { if (bond->slave_cnt > 1) { alb_change_hw_addr_on_detach(bond, slave); @@ -1556,9 +1451,7 @@ bond_alb_deinit_slave(struct bonding *bo } /* Caller must hold bond lock for read */ -void -bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, - char link) +void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char link) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); @@ -1582,109 +1475,111 @@ bond_alb_handle_link_change(struct bondi } /** - * bond_alb_assign_current_slave - assign new current_slave + * bond_alb_handle_active_change - assign new curr_active_slave * @bond: our bonding struct * @new_slave: new slave to assign * - * Set the bond->current_slave to @new_slave and handle + * Set the bond->curr_active_slave to @new_slave and handle * mac address swapping and promiscuity changes as needed. * - * Caller must hold bond ptrlock for write (or bond lock for write) + * Caller must hold bond curr_slave_lock for write (or bond lock for write) */ -void -bond_alb_assign_current_slave(struct bonding *bond, struct slave *new_slave) +void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave) { - struct slave *swap_slave = bond->current_slave; + struct slave *swap_slave; + int i; - if (bond->current_slave == new_slave) { + if (bond->curr_active_slave == new_slave) { return; } - if (bond->current_slave && bond->alb_info.primary_is_promisc) { - dev_set_promiscuity(bond->current_slave->dev, -1); + if (bond->curr_active_slave && bond->alb_info.primary_is_promisc) { + dev_set_promiscuity(bond->curr_active_slave->dev, -1); bond->alb_info.primary_is_promisc = 0; bond->alb_info.rlb_promisc_timeout_counter = 0; } - bond->current_slave = new_slave; + swap_slave = bond->curr_active_slave; + bond->curr_active_slave = new_slave; if (!new_slave || (bond->slave_cnt == 0)) { return; } - /* set the new current_slave to the bonds mac address - * i.e. swap mac addresses of old current_slave and new current_slave + /* set the new curr_active_slave to the bonds mac address + * i.e. swap mac addresses of old curr_active_slave and new curr_active_slave */ if (!swap_slave) { + struct slave *tmp_slave; /* find slave that is holding the bond's mac address */ - swap_slave = bond_get_first_slave(bond); - while (swap_slave) { - if (!memcmp(swap_slave->dev->dev_addr, - bond->device->dev_addr, ETH_ALEN)) { + bond_for_each_slave(bond, tmp_slave, i) { + if (!memcmp(tmp_slave->dev->dev_addr, + bond->dev->dev_addr, ETH_ALEN)) { + swap_slave = tmp_slave; break; } - swap_slave = bond_get_next_slave(bond, swap_slave); } } - /* current_slave must be set before calling alb_swap_mac_addr */ + /* curr_active_slave must be set before calling alb_swap_mac_addr */ if (swap_slave) { /* swap mac address */ alb_swap_mac_addr(bond, swap_slave, new_slave); } else { /* set the new_slave to the bond mac address */ - alb_set_slave_mac_addr(new_slave, bond->device->dev_addr, + alb_set_slave_mac_addr(new_slave, bond->dev->dev_addr, bond->alb_info.rlb_enabled); /* fasten bond mac on new current slave */ - alb_send_learning_packets(new_slave, bond->device->dev_addr); + alb_send_learning_packets(new_slave, bond->dev->dev_addr); } } -int -bond_alb_set_mac_address(struct net_device *dev, void *addr) +int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr) { - struct bonding *bond = dev->priv; + struct bonding *bond = bond_dev->priv; struct sockaddr *sa = addr; - struct slave *swap_slave = NULL; - int error = 0; + struct slave *slave, *swap_slave; + int res; + int i; if (!is_valid_ether_addr(sa->sa_data)) { return -EADDRNOTAVAIL; } - error = alb_set_mac_address(bond, addr); - if (error) { - return error; + res = alb_set_mac_address(bond, addr); + if (res) { + return res; } - memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); + memcpy(bond_dev->dev_addr, sa->sa_data, bond_dev->addr_len); - /* If there is no current_slave there is nothing else to do. + /* If there is no curr_active_slave there is nothing else to do. * Otherwise we'll need to pass the new address to it and handle * duplications. */ - if (bond->current_slave == NULL) { + if (!bond->curr_active_slave) { return 0; } - swap_slave = bond_get_first_slave(bond); - while (swap_slave) { - if (!memcmp(swap_slave->dev->dev_addr, dev->dev_addr, ETH_ALEN)) { + swap_slave = NULL; + + bond_for_each_slave(bond, slave, i) { + if (!memcmp(slave->dev->dev_addr, bond_dev->dev_addr, ETH_ALEN)) { + swap_slave = slave; break; } - swap_slave = bond_get_next_slave(bond, swap_slave); } if (swap_slave) { - alb_swap_mac_addr(bond, swap_slave, bond->current_slave); + alb_swap_mac_addr(bond, swap_slave, bond->curr_active_slave); } else { - alb_set_slave_mac_addr(bond->current_slave, dev->dev_addr, + alb_set_slave_mac_addr(bond->curr_active_slave, bond_dev->dev_addr, bond->alb_info.rlb_enabled); - alb_send_learning_packets(bond->current_slave, dev->dev_addr); + alb_send_learning_packets(bond->curr_active_slave, bond_dev->dev_addr); if (bond->alb_info.rlb_enabled) { /* inform clients mac address has changed */ - rlb_req_update_slave_clients(bond, bond->current_slave); + rlb_req_update_slave_clients(bond, bond->curr_active_slave); } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/bonding/bond_alb.h 830-ivtv/drivers/net/bonding/bond_alb.h --- 000-virgin/drivers/net/bonding/bond_alb.h Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/bonding/bond_alb.h Thu Jan 8 08:54:13 2004 @@ -24,6 +24,9 @@ * 2003/08/06 - Amir Noam * - Add support for setting bond's MAC address with special * handling required for ALB/TLB. + * + * 2003/09/24 - Shmulik Hen + * - Code cleanup and style changes */ #ifndef __BOND_ALB_H__ @@ -126,10 +129,10 @@ void bond_alb_deinitialize(struct bondin int bond_alb_init_slave(struct bonding *bond, struct slave *slave); void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave); void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char link); -void bond_alb_assign_current_slave(struct bonding *bond, struct slave *new_slave); -int bond_alb_xmit(struct sk_buff *skb, struct net_device *dev); +void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave); +int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev); void bond_alb_monitor(struct bonding *bond); -int bond_alb_set_mac_address(struct net_device *dev, void *addr); +int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr); #endif /* __BOND_ALB_H__ */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/bonding/bond_main.c 830-ivtv/drivers/net/bonding/bond_main.c --- 000-virgin/drivers/net/bonding/bond_main.c Thu Jan 8 08:35:37 2004 +++ 830-ivtv/drivers/net/bonding/bond_main.c Thu Jan 8 08:54:13 2004 @@ -1,7 +1,7 @@ /* * originally based on the dummy device. * - * Copyright 1999, Thomas Davis, tadavis@lbl.gov. + * Copyright 1999, Thomas Davis, tadavis@lbl.gov. * Licensed under the GPL. Based on dummy.c, and eql.c devices. * * bonding.c: an Ethernet Bonding driver @@ -15,9 +15,9 @@ * * How it works: * ifconfig bond0 ipaddress netmask up - * will setup a network device, with an ip address. No mac address - * will be assigned at this time. The hw mac address will come from - * the first slave bonded to the channel. All slaves will then use + * will setup a network device, with an ip address. No mac address + * will be assigned at this time. The hw mac address will come from + * the first slave bonded to the channel. All slaves will then use * this hw mac address. * * ifconfig bond0 down @@ -26,7 +26,7 @@ * ifenslave bond0 eth0 * will attach eth0 to bond0 as a slave. eth0 hw mac address will either * a: be used as initial mac address - * b: if a hw mac address already is there, eth0's hw mac address + * b: if a hw mac address already is there, eth0's hw mac address * will then be set from bond0. * * v0.1 - first working version. @@ -93,14 +93,14 @@ * * 2001/4/5 - Chad N. Tindel * - Ported to 2.4 Kernel - * + * * 2001/5/2 - Jeffrey E. Mast * - When a device is detached from a bond, the slave device is no longer * left thinking that is has a master. * * 2001/5/16 - Jeffrey E. Mast - * - memset did not appropriately initialized the bond rw_locks. Used - * rwlock_init to initialize to unlocked state to prevent deadlock when + * - memset did not appropriately initialized the bond rw_locks. Used + * rwlock_init to initialize to unlocked state to prevent deadlock when * first attempting a lock * - Called SET_MODULE_OWNER for bond device * @@ -119,7 +119,7 @@ * * 2001/6/01 - Chad N. Tindel * - Added /proc support for getting bond and slave information. - * Information is in /proc/net//info. + * Information is in /proc/net//info. * - Changed the locking when calling bond_close to prevent deadlock. * * 2001/8/05 - Janice Girouard @@ -144,8 +144,8 @@ * but only for an up link. * * 2001/9/20 - Chad N. Tindel - * - Add the device field to bonding_t. Previously the net_device - * corresponding to a bond wasn't available from the bonding_t + * - Add the device field to bonding_t. Previously the net_device + * corresponding to a bond wasn't available from the bonding_t * structure. * * 2001/9/25 - Janice Girouard @@ -155,10 +155,10 @@ * - Various memory leak fixes * * 2001/11/5 - Mark Huth - * - Don't take rtnl lock in bond_mii_monitor as it deadlocks under - * certain hotswap conditions. + * - Don't take rtnl lock in bond_mii_monitor as it deadlocks under + * certain hotswap conditions. * Note: this same change may be required in bond_arp_monitor ??? - * - Remove possibility of calling bond_sethwaddr with NULL slave_dev ptr + * - Remove possibility of calling bond_sethwaddr with NULL slave_dev ptr * - Handle hot swap ethernet interface deregistration events to remove * kernel oops following hot swap of enslaved interface * @@ -222,23 +222,23 @@ * - fix deletion of multicast groups after unloading module * * 2002/11/06 - Kameshwara Rayaprolu - * - Changes to prevent panic from closing the device twice; if we close - * the device in bond_release, we must set the original_flags to down + * - Changes to prevent panic from closing the device twice; if we close + * the device in bond_release, we must set the original_flags to down * so it won't be closed again by the network layer. * * 2002/11/07 - Tony Cureington * - Fix arp_target_hw_addr memory leak - * - Created activebackup_arp_monitor function to handle arp monitoring - * in active backup mode - the bond_arp_monitor had several problems... - * such as allowing slaves to tx arps sequentially without any delay + * - Created activebackup_arp_monitor function to handle arp monitoring + * in active backup mode - the bond_arp_monitor had several problems... + * such as allowing slaves to tx arps sequentially without any delay * for a response * - Renamed bond_arp_monitor to loadbalance_arp_monitor and re-wrote * this function to just handle arp monitoring in load-balancing mode; * it is a lot more compact now - * - Changes to ensure one and only one slave transmits in active-backup + * - Changes to ensure one and only one slave transmits in active-backup * mode - * - Robustesize parameters; warn users about bad combinations of - * parameters; also if miimon is specified and a network driver does + * - Robustesize parameters; warn users about bad combinations of + * parameters; also if miimon is specified and a network driver does * not support MII or ETHTOOL, inform the user of this * - Changes to support link_failure_count when in arp monitoring mode * - Fix up/down delay reported in /proc @@ -248,7 +248,7 @@ * * 2002/11/16 - Laurent Deniel * - fix multicast handling in activebackup_arp_monitor - * - remove one unnecessary and confusing current_slave == slave test + * - remove one unnecessary and confusing curr_active_slave == slave test * in activebackup_arp_monitor * * 2002/11/17 - Laurent Deniel @@ -267,7 +267,7 @@ * One change: an invalid choice will cause module load failure, * rather than the previous behavior of just picking one. * - Minor cleanups; got rid of dup ctype stuff, atoi function - * + * * 2003/02/07 - Jay Vosburgh * - Added use_carrier module parameter that causes miimon to * use netif_carrier_ok() test instead of MII/ETHTOOL ioctls. @@ -330,7 +330,7 @@ * new/old ifenslave and new/old bonding. * * 2003/05/01 - Shmulik Hen - * - Fixed bug in bond_release_all(): save old value of current_slave + * - Fixed bug in bond_release_all(): save old value of curr_active_slave * before setting it to NULL. * - Changed driver versioning scheme to include version number instead * of release date (that is already in another field). There are 3 @@ -358,7 +358,7 @@ * * 2003/05/01 - Shmulik Hen * - Added support for Transmit load balancing mode. - * - Concentrate all assignments of current_slave to a single point + * - Concentrate all assignments of curr_active_slave to a single point * so specific modes can take actions when the primary adapter is * changed. * - Take the updelay parameter into consideration during bond_enslave @@ -426,8 +426,36 @@ * - Convert /proc to seq_file interface. * Change /proc/net/bondX/info to /proc/net/bonding/bondX. * Set version to 2.4.1. + * + * 2003/11/20 - Amir Noam + * - Fix /proc creation/destruction. + * + * 2003/12/01 - Shmulik Hen + * - Massive cleanup - Set version to 2.5.0 + * Code changes: + * o Consolidate format of prints and debug prints. + * o Remove bonding_t/slave_t typedefs and consolidate all casts. + * o Remove dead code and unnecessary checks. + * o Consolidate starting/stopping timers. + * o Consolidate handling of primary module param throughout the code. + * o Removed multicast module param support - all settings are done + * according to mode. + * o Slave list iteration - bond is no longer part of the list, + * added cyclic list iteration macros. + * o Consolidate error handling in all xmit functions. + * Style changes: + * o Consolidate function naming and declarations. + * o Consolidate function params and local variables names. + * o Consolidate return values. + * o Consolidate curly braces. + * o Consolidate conditionals format. + * o Change struct member names and types. + * o Chomp trailing spaces, remove empty lines, fix indentations. + * o Re-organize code according to context. */ +//#define BONDING_DEBUG 1 + #include #include #include @@ -452,7 +480,6 @@ #include #include #include - #include #include #include @@ -461,58 +488,72 @@ #include #include #include - -#include #include #include #include #include #include +#include #include "bonding.h" #include "bond_3ad.h" #include "bond_alb.h" -#define DRV_VERSION "2.4.1" -#define DRV_RELDATE "September 15, 2003" -#define DRV_NAME "bonding" -#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" - -static const char *version = -DRV_NAME ".c:v" DRV_VERSION " (" DRV_RELDATE ")\n"; +/*---------------------------- Module parameters ----------------------------*/ /* monitor all links that often (in milliseconds). <=0 disables monitoring */ -#ifndef BOND_LINK_MON_INTERV #define BOND_LINK_MON_INTERV 0 -#endif - -#ifndef BOND_LINK_ARP_INTERV #define BOND_LINK_ARP_INTERV 0 -#endif +#define MAX_ARP_IP_TARGETS 16 -#ifndef MAX_ARP_IP_TARGETS -#define MAX_ARP_IP_TARGETS 16 -#endif +static int max_bonds = BOND_DEFAULT_MAX_BONDS; +static int miimon = BOND_LINK_MON_INTERV; +static int updelay = 0; +static int downdelay = 0; +static int use_carrier = 1; +static char *mode = NULL; +static char *primary = NULL; +static char *lacp_rate = NULL; +static int arp_interval = BOND_LINK_ARP_INTERV; +static char *arp_ip_target[MAX_ARP_IP_TARGETS] = { NULL, }; + +MODULE_PARM(max_bonds, "i"); +MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); +MODULE_PARM(miimon, "i"); +MODULE_PARM_DESC(miimon, "Link check interval in milliseconds"); +MODULE_PARM(updelay, "i"); +MODULE_PARM_DESC(updelay, "Delay before considering link up, in milliseconds"); +MODULE_PARM(downdelay, "i"); +MODULE_PARM_DESC(downdelay, "Delay before considering link down, in milliseconds"); +MODULE_PARM(use_carrier, "i"); +MODULE_PARM_DESC(use_carrier, "Use netif_carrier_ok (vs MII ioctls) in miimon; 0 for off, 1 for on (default)"); +MODULE_PARM(mode, "s"); +MODULE_PARM_DESC(mode, "Mode of operation : 0 for round robin, 1 for active-backup, 2 for xor"); +MODULE_PARM(primary, "s"); +MODULE_PARM_DESC(primary, "Primary network device to use"); +MODULE_PARM(lacp_rate, "s"); +MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner (slow/fast)"); +MODULE_PARM(arp_interval, "i"); +MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds"); +MODULE_PARM(arp_ip_target, "1-" __MODULE_STRING(MAX_ARP_IP_TARGETS) "s"); +MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form"); -#define USES_PRIMARY(mode) \ - (((mode) == BOND_MODE_ACTIVEBACKUP) || \ - ((mode) == BOND_MODE_TLB) || \ - ((mode) == BOND_MODE_ALB)) +/*----------------------------- Global variables ----------------------------*/ -struct bond_parm_tbl { - char *modename; - int mode; -}; +static const char *version = + DRV_DESCRIPTION ": v" DRV_VERSION " (" DRV_RELDATE ")\n"; -static int arp_interval = BOND_LINK_ARP_INTERV; -static char *arp_ip_target[MAX_ARP_IP_TARGETS] = { NULL, }; -static u32 arp_target[MAX_ARP_IP_TARGETS] = { 0, } ; -static int arp_ip_count = 0; -static u32 my_ip = 0; -char *arp_target_hw_addr = NULL; +static LIST_HEAD(bond_dev_list); -static char *primary= NULL; +#ifdef CONFIG_PROC_FS +static struct proc_dir_entry *bond_proc_dir = NULL; +#endif -static int app_abi_ver = 0; +static u32 arp_target[MAX_ARP_IP_TARGETS] = { 0, } ; +static int arp_ip_count = 0; +static u32 my_ip = 0; +static int bond_mode = BOND_MODE_ROUNDROBIN; +static int lacp_fast = 0; +static int app_abi_ver = 0; static int orig_app_abi_ver = -1; /* This is used to save the first ABI version * we receive from the application. Once set, * it won't be changed, and the module will @@ -521,14 +562,16 @@ static int orig_app_abi_ver = -1; /* Thi * another ABI version. */ -static int max_bonds = BOND_DEFAULT_MAX_BONDS; -static int miimon = BOND_LINK_MON_INTERV; -static int use_carrier = 1; -static int bond_mode = BOND_MODE_ROUNDROBIN; -static int updelay = 0; -static int downdelay = 0; +struct bond_parm_tbl { + char *modename; + int mode; +}; -static char *mode = NULL; +static struct bond_parm_tbl bond_lacp_tbl[] = { +{ "slow", AD_LACP_SLOW}, +{ "fast", AD_LACP_FAST}, +{ NULL, -1}, +}; static struct bond_parm_tbl bond_mode_tbl[] = { { "balance-rr", BOND_MODE_ROUNDROBIN}, @@ -541,101 +584,9 @@ static struct bond_parm_tbl bond_mode_tb { NULL, -1}, }; -static int multicast_mode = BOND_MULTICAST_ALL; -static char *multicast = NULL; - -static struct bond_parm_tbl bond_mc_tbl[] = { -{ "disabled", BOND_MULTICAST_DISABLED}, -{ "active", BOND_MULTICAST_ACTIVE}, -{ "all", BOND_MULTICAST_ALL}, -{ NULL, -1}, -}; - -static int lacp_fast = 0; -static char *lacp_rate = NULL; - -static struct bond_parm_tbl bond_lacp_tbl[] = { -{ "slow", AD_LACP_SLOW}, -{ "fast", AD_LACP_FAST}, -{ NULL, -1}, -}; - -static LIST_HEAD(bond_dev_list); -#ifdef CONFIG_PROC_FS -static struct proc_dir_entry *bond_proc_dir = NULL; -#endif - -MODULE_PARM(max_bonds, "i"); -MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); -MODULE_PARM(miimon, "i"); -MODULE_PARM_DESC(miimon, "Link check interval in milliseconds"); -MODULE_PARM(use_carrier, "i"); -MODULE_PARM_DESC(use_carrier, "Use netif_carrier_ok (vs MII ioctls) in miimon; 0 for off, 1 for on (default)"); -MODULE_PARM(mode, "s"); -MODULE_PARM_DESC(mode, "Mode of operation : 0 for round robin, 1 for active-backup, 2 for xor"); -MODULE_PARM(arp_interval, "i"); -MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds"); -MODULE_PARM(arp_ip_target, "1-" __MODULE_STRING(MAX_ARP_IP_TARGETS) "s"); -MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form"); -MODULE_PARM(updelay, "i"); -MODULE_PARM_DESC(updelay, "Delay before considering link up, in milliseconds"); -MODULE_PARM(downdelay, "i"); -MODULE_PARM_DESC(downdelay, "Delay before considering link down, in milliseconds"); -MODULE_PARM(primary, "s"); -MODULE_PARM_DESC(primary, "Primary network device to use"); -MODULE_PARM(multicast, "s"); -MODULE_PARM_DESC(multicast, "Mode for multicast support : 0 for none, 1 for active slave, 2 for all slaves (default)"); -MODULE_PARM(lacp_rate, "s"); -MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner (slow/fast)"); - -static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *dev); -static int bond_xmit_xor(struct sk_buff *skb, struct net_device *dev); -static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *dev); -static struct net_device_stats *bond_get_stats(struct net_device *dev); -static void bond_mii_monitor(struct net_device *dev); -static void loadbalance_arp_monitor(struct net_device *dev); -static void activebackup_arp_monitor(struct net_device *dev); -static void bond_mc_list_destroy(struct bonding *bond); -static void bond_mc_add(bonding_t *bond, void *addr, int alen); -static void bond_mc_delete(bonding_t *bond, void *addr, int alen); -static int bond_mc_list_copy (struct dev_mc_list *src, struct bonding *dst, int gpf_flag); -static inline int dmi_same(struct dev_mc_list *dmi1, struct dev_mc_list *dmi2); -static void bond_set_promiscuity(bonding_t *bond, int inc); -static void bond_set_allmulti(bonding_t *bond, int inc); -static struct dev_mc_list* bond_mc_list_find_dmi(struct dev_mc_list *dmi, struct dev_mc_list *mc_list); -static void bond_mc_update(bonding_t *bond, slave_t *new, slave_t *old); -static int bond_enslave(struct net_device *master, struct net_device *slave); -static int bond_release(struct net_device *master, struct net_device *slave); -static int bond_release_all(struct net_device *master); -static int bond_sethwaddr(struct net_device *master, struct net_device *slave); -static void change_active_interface(struct bonding *bond, struct slave *new); -static void reselect_active_interface(struct bonding *bond); -static struct slave *find_best_interface(struct bonding *bond); - - -/* #define BONDING_DEBUG 1 */ -#ifdef BONDING_DEBUG -#define dprintk(x...) printk(x...) -#else /* BONDING_DEBUG */ -#define dprintk(x...) do {} while (0) -#endif /* BONDING_DEBUG */ - -/* several macros */ - -static void arp_send_all(slave_t *slave) -{ - int i; - - for (i = 0; (idev, - my_ip, arp_target_hw_addr, slave->dev->dev_addr, - arp_target_hw_addr); - } -} - +/*---------------------------- General routines -----------------------------*/ -static const char * -bond_mode_name(void) +static const char *bond_mode_name(void) { switch (bond_mode) { case BOND_MODE_ROUNDROBIN : @@ -657,149 +608,7 @@ bond_mode_name(void) } } -static const char * -multicast_mode_name(void) -{ - switch(multicast_mode) { - case BOND_MULTICAST_DISABLED : - return "disabled"; - case BOND_MULTICAST_ACTIVE : - return "active slave only"; - case BOND_MULTICAST_ALL : - return "all slaves"; - default : - return "unknown"; - } -} - -void bond_set_slave_inactive_flags(slave_t *slave) -{ - slave->state = BOND_STATE_BACKUP; - slave->dev->flags |= IFF_NOARP; -} - -void bond_set_slave_active_flags(slave_t *slave) -{ - slave->state = BOND_STATE_ACTIVE; - slave->dev->flags &= ~IFF_NOARP; -} - -/* - * This function counts and verifies the the number of attached - * slaves, checking the count against the expected value (given that incr - * is either 1 or -1, for add or removal of a slave). Only - * bond_xmit_xor() uses the slave_cnt value, but this is still a good - * consistency check. - */ -static inline void -update_slave_cnt(bonding_t *bond, int incr) -{ - slave_t *slave = NULL; - int expect = bond->slave_cnt + incr; - - bond->slave_cnt = 0; - for (slave = bond->prev; slave != (slave_t*)bond; - slave = slave->prev) { - bond->slave_cnt++; - } - - if (expect != bond->slave_cnt) - BUG(); -} - -/* - * This function detaches the slave from the list . - * WARNING: no check is made to verify if the slave effectively - * belongs to . It returns in case it's needed. - * Nothing is freed on return, structures are just unchained. - * If the bond->current_slave pointer was pointing to , - * it should be changed by the calling function. - * - * bond->lock held for writing by caller. - */ -static slave_t * -bond_detach_slave(bonding_t *bond, slave_t *slave) -{ - if ((bond == NULL) || (slave == NULL) || - ((void *)bond == (void *)slave)) { - printk(KERN_ERR - "bond_detach_slave(): trying to detach " - "slave %p from bond %p\n", bond, slave); - return slave; - } - - if (bond->next == slave) { /* is the slave at the head ? */ - if (bond->prev == slave) { /* is the slave alone ? */ - bond->prev = bond->next = (slave_t *)bond; - } else { /* not alone */ - bond->next = slave->next; - slave->next->prev = (slave_t *)bond; - bond->prev->next = slave->next; - } - } else { - slave->prev->next = slave->next; - if (bond->prev == slave) { /* is this slave the last one ? */ - bond->prev = slave->prev; - } else { - slave->next->prev = slave->prev; - } - } - - update_slave_cnt(bond, -1); - - return slave; -} - -/* - * This function attaches the slave to the list . - * - * bond->lock held for writing by caller. - */ -static void -bond_attach_slave(struct bonding *bond, struct slave *new_slave) -{ - /* - * queue to the end of the slaves list, make the first element its - * successor, the last one its predecessor, and make it the bond's - * predecessor. - * - * Just to clarify, so future bonding driver hackers don't go through - * the same confusion stage I did trying to figure this out, the - * slaves are stored in a double linked circular list, sortof. - * In the ->next direction, the last slave points to the first slave, - * bypassing bond; only the slaves are in the ->next direction. - * In the ->prev direction, however, the first slave points to bond - * and bond points to the last slave. - * - * It looks like a circle with a little bubble hanging off one side - * in the ->prev direction only. - * - * When going through the list once, its best to start at bond->prev - * and go in the ->prev direction, testing for bond. Doing this - * in the ->next direction doesn't work. Trust me, I know this now. - * :) -mts 2002.03.14 - */ - new_slave->prev = bond->prev; - new_slave->prev->next = new_slave; - bond->prev = new_slave; - new_slave->next = bond->next; - - update_slave_cnt(bond, 1); -} - - -/* - * Less bad way to call ioctl from within the kernel; this needs to be - * done some other way to get the call out of interrupt context. - * Needs "ioctl" variable to be supplied by calling context. - */ -#define IOCTL(dev, arg, cmd) ({ \ - int ret; \ - mm_segment_t fs = get_fs(); \ - set_fs(get_ds()); \ - ret = ioctl(dev, arg, cmd); \ - set_fs(fs); \ - ret; }) +/*------------------------------- Link status -------------------------------*/ /* * Get link speed and duplex from the slave's base driver @@ -809,52 +618,63 @@ bond_attach_slave(struct bonding *bond, */ static int bond_update_speed_duplex(struct slave *slave) { - struct net_device *dev = slave->dev; + struct net_device *slave_dev = slave->dev; static int (* ioctl)(struct net_device *, struct ifreq *, int); struct ifreq ifr; struct ethtool_cmd etool; - ioctl = dev->do_ioctl; - if (ioctl) { - etool.cmd = ETHTOOL_GSET; - ifr.ifr_data = (char*)&etool; - if (IOCTL(dev, &ifr, SIOCETHTOOL) == 0) { - slave->speed = etool.speed; - slave->duplex = etool.duplex; - } else { - goto err_out; + /* Fake speed and duplex */ + slave->speed = SPEED_100; + slave->duplex = DUPLEX_FULL; + + if (slave_dev->ethtool_ops) { + u32 res; + + if (!slave_dev->ethtool_ops->get_settings) { + return -1; } - } else { - goto err_out; + + res = slave_dev->ethtool_ops->get_settings(slave_dev, &etool); + if (res < 0) { + return -1; + } + + goto verify; } - switch (slave->speed) { - case SPEED_10: - case SPEED_100: - case SPEED_1000: - break; - default: - goto err_out; + ioctl = slave_dev->do_ioctl; + strncpy(ifr.ifr_name, slave_dev->name, IFNAMSIZ); + etool.cmd = ETHTOOL_GSET; + ifr.ifr_data = (char*)&etool; + if (!ioctl || (IOCTL(slave_dev, &ifr, SIOCETHTOOL) < 0)) { + return -1; + } + +verify: + switch (etool.speed) { + case SPEED_10: + case SPEED_100: + case SPEED_1000: + break; + default: + return -1; } - switch (slave->duplex) { - case DUPLEX_FULL: - case DUPLEX_HALF: - break; - default: - goto err_out; + switch (etool.duplex) { + case DUPLEX_FULL: + case DUPLEX_HALF: + break; + default: + return -1; } - return 0; + slave->speed = etool.speed; + slave->duplex = etool.duplex; -err_out: - /* Fake speed and duplex */ - slave->speed = SPEED_100; - slave->duplex = DUPLEX_FULL; - return -1; + return 0; } -/* +/* * if supports MII link status reporting, check its link status. * * We either do MII/ETHTOOL ioctls, or check netif_carrier_ok(), @@ -870,8 +690,7 @@ err_out: * It'd be nice if there was a good way to tell if a driver supports * netif_carrier, but there really isn't. */ -static int -bond_check_dev_link(struct net_device *dev, int reporting) +static int bond_check_dev_link(struct net_device *slave_dev, int reporting) { static int (* ioctl)(struct net_device *, struct ifreq *, int); struct ifreq ifr; @@ -879,10 +698,10 @@ bond_check_dev_link(struct net_device *d struct ethtool_value etool; if (use_carrier) { - return netif_carrier_ok(dev) ? BMSR_LSTATUS : 0; + return netif_carrier_ok(slave_dev) ? BMSR_LSTATUS : 0; } - ioctl = dev->do_ioctl; + ioctl = slave_dev->do_ioctl; if (ioctl) { /* TODO: set pointer to correct ioctl on a per team member */ /* bases to make this more efficient. that is, once */ @@ -897,477 +716,510 @@ bond_check_dev_link(struct net_device *d */ /* Yes, the mii is overlaid on the ifreq.ifr_ifru */ + strncpy(ifr.ifr_name, slave_dev->name, IFNAMSIZ); mii = (struct mii_ioctl_data *)&ifr.ifr_data; - if (IOCTL(dev, &ifr, SIOCGMIIPHY) == 0) { + if (IOCTL(slave_dev, &ifr, SIOCGMIIPHY) == 0) { mii->reg_num = MII_BMSR; - if (IOCTL(dev, &ifr, SIOCGMIIREG) == 0) { - return mii->val_out & BMSR_LSTATUS; + if (IOCTL(slave_dev, &ifr, SIOCGMIIREG) == 0) { + return (mii->val_out & BMSR_LSTATUS); } } + } + + /* try SIOCETHTOOL ioctl, some drivers cache ETHTOOL_GLINK */ + /* for a period of time so we attempt to get link status */ + /* from it last if the above MII ioctls fail... */ + if (slave_dev->ethtool_ops) { + if (slave_dev->ethtool_ops->get_link) { + u32 link; + + link = slave_dev->ethtool_ops->get_link(slave_dev); + + return link ? BMSR_LSTATUS : 0; + } + } - /* try SIOCETHTOOL ioctl, some drivers cache ETHTOOL_GLINK */ - /* for a period of time so we attempt to get link status */ - /* from it last if the above MII ioctls fail... */ - etool.cmd = ETHTOOL_GLINK; - ifr.ifr_data = (char*)&etool; - if (IOCTL(dev, &ifr, SIOCETHTOOL) == 0) { + if (ioctl) { + strncpy(ifr.ifr_name, slave_dev->name, IFNAMSIZ); + etool.cmd = ETHTOOL_GLINK; + ifr.ifr_data = (char*)&etool; + if (IOCTL(slave_dev, &ifr, SIOCETHTOOL) == 0) { if (etool.data == 1) { return BMSR_LSTATUS; - } else { -#ifdef BONDING_DEBUG - printk(KERN_INFO - ":: SIOCETHTOOL shows link down \n"); -#endif + } else { + dprintk("SIOCETHTOOL shows link down\n"); return 0; - } + } } - } - + /* * If reporting, report that either there's no dev->do_ioctl, * or both SIOCGMIIREG and SIOCETHTOOL failed (meaning that we * cannot report link status). If not reporting, pretend * we're ok. */ - return reporting ? -1 : BMSR_LSTATUS; + return (reporting ? -1 : BMSR_LSTATUS); } -static u16 bond_check_mii_link(bonding_t *bond) -{ - int has_active_interface = 0; - - read_lock_bh(&bond->lock); - read_lock(&bond->ptrlock); - has_active_interface = (bond->current_slave != NULL); - read_unlock(&bond->ptrlock); - read_unlock_bh(&bond->lock); +/*----------------------------- Multicast list ------------------------------*/ - return (has_active_interface ? BMSR_LSTATUS : 0); +/* + * Returns 0 if dmi1 and dmi2 are the same, non-0 otherwise + */ +static inline int bond_is_dmi_same(struct dev_mc_list *dmi1, struct dev_mc_list *dmi2) +{ + return memcmp(dmi1->dmi_addr, dmi2->dmi_addr, dmi1->dmi_addrlen) == 0 && + dmi1->dmi_addrlen == dmi2->dmi_addrlen; } -/* register to receive lacpdus on a bond */ -static void bond_register_lacpdu(struct bonding *bond) +/* + * returns dmi entry if found, NULL otherwise + */ +static struct dev_mc_list *bond_mc_list_find_dmi(struct dev_mc_list *dmi, struct dev_mc_list *mc_list) { - struct packet_type* pk_type = &(BOND_AD_INFO(bond).ad_pkt_type); + struct dev_mc_list *idmi; - /* initialize packet type */ - pk_type->type = PKT_TYPE_LACPDU; - pk_type->dev = bond->device; - pk_type->func = bond_3ad_lacpdu_recv; + for (idmi = mc_list; idmi; idmi = idmi->next) { + if (bond_is_dmi_same(dmi, idmi)) { + return idmi; + } + } - dev_add_pack(pk_type); + return NULL; } -/* unregister to receive lacpdus on a bond */ -static void bond_unregister_lacpdu(struct bonding *bond) +/* + * Push the promiscuity flag down to appropriate slaves + */ +static void bond_set_promiscuity(struct bonding *bond, int inc) { - dev_remove_pack(&(BOND_AD_INFO(bond).ad_pkt_type)); + if (USES_PRIMARY(bond_mode)) { + /* write lock already acquired */ + if (bond->curr_active_slave) { + dev_set_promiscuity(bond->curr_active_slave->dev, inc); + } + } else { + struct slave *slave; + int i; + bond_for_each_slave(bond, slave, i) { + dev_set_promiscuity(slave->dev, inc); + } + } } -static int bond_open(struct net_device *dev) +/* + * Push the allmulti flag down to all slaves + */ +static void bond_set_allmulti(struct bonding *bond, int inc) { - struct bonding *bond = (struct bonding *)(dev->priv); - struct timer_list *timer = &((struct bonding *)(dev->priv))->mii_timer; - struct timer_list *arp_timer = &((struct bonding *)(dev->priv))->arp_timer; - - if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { - struct timer_list *alb_timer = &(BOND_ALB_INFO(bond).alb_timer); - - /* bond_alb_initialize must be called before the timer - * is started. - */ - if (bond_alb_initialize(bond, (bond_mode == BOND_MODE_ALB))) { - /* something went wrong - fail the open operation */ - return -1; + if (USES_PRIMARY(bond_mode)) { + /* write lock already acquired */ + if (bond->curr_active_slave) { + dev_set_allmulti(bond->curr_active_slave->dev, inc); } - - init_timer(alb_timer); - alb_timer->expires = jiffies + 1; - alb_timer->data = (unsigned long)bond; - alb_timer->function = (void *)&bond_alb_monitor; - add_timer(alb_timer); - } - - if (miimon > 0) { /* link check interval, in milliseconds. */ - init_timer(timer); - timer->expires = jiffies + (miimon * HZ / 1000); - timer->data = (unsigned long)dev; - timer->function = (void *)&bond_mii_monitor; - add_timer(timer); - } - - if (arp_interval> 0) { /* arp interval, in milliseconds. */ - init_timer(arp_timer); - arp_timer->expires = jiffies + (arp_interval * HZ / 1000); - arp_timer->data = (unsigned long)dev; - if (bond_mode == BOND_MODE_ACTIVEBACKUP) { - arp_timer->function = (void *)&activebackup_arp_monitor; - } else { - arp_timer->function = (void *)&loadbalance_arp_monitor; + } else { + struct slave *slave; + int i; + bond_for_each_slave(bond, slave, i) { + dev_set_allmulti(slave->dev, inc); } - add_timer(arp_timer); } +} - if (bond_mode == BOND_MODE_8023AD) { - struct timer_list *ad_timer = &(BOND_AD_INFO(bond).ad_timer); - init_timer(ad_timer); - ad_timer->expires = jiffies + (AD_TIMER_INTERVAL * HZ / 1000); - ad_timer->data = (unsigned long)bond; - ad_timer->function = (void *)&bond_3ad_state_machine_handler; - add_timer(ad_timer); - - /* register to receive LACPDUs */ - bond_register_lacpdu(bond); +/* + * Add a Multicast address to slaves + * according to mode + */ +static void bond_mc_add(struct bonding *bond, void *addr, int alen) +{ + if (USES_PRIMARY(bond_mode)) { + /* write lock already acquired */ + if (bond->curr_active_slave) { + dev_mc_add(bond->curr_active_slave->dev, addr, alen, 0); + } + } else { + struct slave *slave; + int i; + bond_for_each_slave(bond, slave, i) { + dev_mc_add(slave->dev, addr, alen, 0); + } } - - return 0; } -static int bond_close(struct net_device *master) +/* + * Remove a multicast address from slave + * according to mode + */ +static void bond_mc_delete(struct bonding *bond, void *addr, int alen) { - bonding_t *bond = (struct bonding *) master->priv; - - write_lock_bh(&bond->lock); - - if (miimon > 0) { /* link check interval, in milliseconds. */ - del_timer(&bond->mii_timer); - } - if (arp_interval> 0) { /* arp interval, in milliseconds. */ - del_timer(&bond->arp_timer); - if (arp_target_hw_addr != NULL) { - kfree(arp_target_hw_addr); - arp_target_hw_addr = NULL; + if (USES_PRIMARY(bond_mode)) { + /* write lock already acquired */ + if (bond->curr_active_slave) { + dev_mc_delete(bond->curr_active_slave->dev, addr, alen, 0); + } + } else { + struct slave *slave; + int i; + bond_for_each_slave(bond, slave, i) { + dev_mc_delete(slave->dev, addr, alen, 0); } } +} - if (bond_mode == BOND_MODE_8023AD) { - del_timer_sync(&(BOND_AD_INFO(bond).ad_timer)); +/* + * Totally destroys the mc_list in bond + */ +static void bond_mc_list_destroy(struct bonding *bond) +{ + struct dev_mc_list *dmi; - /* Unregister the receive of LACPDUs */ - bond_unregister_lacpdu(bond); + dmi = bond->mc_list; + while (dmi) { + bond->mc_list = dmi->next; + kfree(dmi); + dmi = bond->mc_list; } +} - bond_mc_list_destroy (bond); - - write_unlock_bh(&bond->lock); +/* + * Copy all the Multicast addresses from src to the bonding device dst + */ +static int bond_mc_list_copy(struct dev_mc_list *mc_list, struct bonding *bond, int gpf_flag) +{ + struct dev_mc_list *dmi, *new_dmi; - /* Release the bonded slaves */ - bond_release_all(master); + for (dmi = mc_list; dmi; dmi = dmi->next) { + new_dmi = kmalloc(sizeof(struct dev_mc_list), gpf_flag); - if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { - del_timer_sync(&(BOND_ALB_INFO(bond).alb_timer)); + if (!new_dmi) { + /* FIXME: Potential memory leak !!! */ + return -ENOMEM; + } - bond_alb_deinitialize(bond); + new_dmi->next = bond->mc_list; + bond->mc_list = new_dmi; + new_dmi->dmi_addrlen = dmi->dmi_addrlen; + memcpy(new_dmi->dmi_addr, dmi->dmi_addr, dmi->dmi_addrlen); + new_dmi->dmi_users = dmi->dmi_users; + new_dmi->dmi_gusers = dmi->dmi_gusers; } return 0; } -/* +/* * flush all members of flush->mc_list from device dev->mc_list */ -static void bond_mc_list_flush(struct net_device *dev, struct net_device *flush) -{ - struct dev_mc_list *dmi; - - for (dmi = flush->mc_list; dmi != NULL; dmi = dmi->next) - dev_mc_delete(dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); +static void bond_mc_list_flush(struct net_device *bond_dev, struct net_device *slave_dev) +{ + struct dev_mc_list *dmi; + + for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) { + dev_mc_delete(slave_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); + } if (bond_mode == BOND_MODE_8023AD) { /* del lacpdu mc addr from mc list */ u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR; - dev_mc_delete(dev, lacpdu_multicast, ETH_ALEN, 0); + dev_mc_delete(slave_dev, lacpdu_multicast, ETH_ALEN, 0); } } +/*--------------------------- Active slave change ---------------------------*/ + /* - * Totally destroys the mc_list in bond + * Update the mc list and multicast-related flags for the new and + * old active slaves (if any) according to the multicast mode, and + * promiscuous flags unconditionally. */ -static void bond_mc_list_destroy(struct bonding *bond) +static void bond_mc_swap(struct bonding *bond, struct slave *new_active, struct slave *old_active) { struct dev_mc_list *dmi; - dmi = bond->mc_list; - while (dmi) { - bond->mc_list = dmi->next; - kfree(dmi); - dmi = bond->mc_list; - } -} - -/* - * Add a Multicast address to every slave in the bonding group - */ -static void bond_mc_add(bonding_t *bond, void *addr, int alen) -{ - slave_t *slave; - switch (multicast_mode) { - case BOND_MULTICAST_ACTIVE : - /* write lock already acquired */ - if (bond->current_slave != NULL) - dev_mc_add(bond->current_slave->dev, addr, alen, 0); - break; - case BOND_MULTICAST_ALL : - for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev) - dev_mc_add(slave->dev, addr, alen, 0); - break; - case BOND_MULTICAST_DISABLED : - break; + if (!USES_PRIMARY(bond_mode)) { + /* nothing to do - mc list is already up-to-date on + * all slaves + */ + return; } -} -/* - * Remove a multicast address from every slave in the bonding group - */ -static void bond_mc_delete(bonding_t *bond, void *addr, int alen) -{ - slave_t *slave; - switch (multicast_mode) { - case BOND_MULTICAST_ACTIVE : - /* write lock already acquired */ - if (bond->current_slave != NULL) - dev_mc_delete(bond->current_slave->dev, addr, alen, 0); - break; - case BOND_MULTICAST_ALL : - for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev) - dev_mc_delete(slave->dev, addr, alen, 0); - break; - case BOND_MULTICAST_DISABLED : - break; - } -} + if (old_active) { + if (bond->dev->flags & IFF_PROMISC) { + dev_set_promiscuity(old_active->dev, -1); + } -/* - * Copy all the Multicast addresses from src to the bonding device dst - */ -static int bond_mc_list_copy (struct dev_mc_list *src, struct bonding *dst, - int gpf_flag) -{ - struct dev_mc_list *dmi, *new_dmi; + if (bond->dev->flags & IFF_ALLMULTI) { + dev_set_allmulti(old_active->dev, -1); + } - for (dmi = src; dmi != NULL; dmi = dmi->next) { - new_dmi = kmalloc(sizeof(struct dev_mc_list), gpf_flag); + for (dmi = bond->dev->mc_list; dmi; dmi = dmi->next) { + dev_mc_delete(old_active->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); + } + } - if (new_dmi == NULL) { - return -ENOMEM; + if (new_active) { + if (bond->dev->flags & IFF_PROMISC) { + dev_set_promiscuity(new_active->dev, 1); } - new_dmi->next = dst->mc_list; - dst->mc_list = new_dmi; + if (bond->dev->flags & IFF_ALLMULTI) { + dev_set_allmulti(new_active->dev, 1); + } - new_dmi->dmi_addrlen = dmi->dmi_addrlen; - memcpy(new_dmi->dmi_addr, dmi->dmi_addr, dmi->dmi_addrlen); - new_dmi->dmi_users = dmi->dmi_users; - new_dmi->dmi_gusers = dmi->dmi_gusers; - } - return 0; + for (dmi = bond->dev->mc_list; dmi; dmi = dmi->next) { + dev_mc_add(new_active->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); + } + } } -/* - * Returns 0 if dmi1 and dmi2 are the same, non-0 otherwise - */ -static inline int dmi_same(struct dev_mc_list *dmi1, struct dev_mc_list *dmi2) -{ - return memcmp(dmi1->dmi_addr, dmi2->dmi_addr, dmi1->dmi_addrlen) == 0 && - dmi1->dmi_addrlen == dmi2->dmi_addrlen; -} - -/* - * Push the promiscuity flag down to appropriate slaves +/** + * find_best_interface - select the best available slave to be the active one + * @bond: our bonding struct + * + * Warning: Caller must hold curr_slave_lock for writing. */ -static void bond_set_promiscuity(bonding_t *bond, int inc) -{ - slave_t *slave; +static struct slave *bond_find_best_slave(struct bonding *bond) +{ + struct slave *new_active, *old_active; + struct slave *bestslave = NULL; + int mintime; + int i; - if (USES_PRIMARY(bond_mode)) { - if (bond->current_slave) { - dev_set_promiscuity(bond->current_slave->dev, inc); - } + new_active = old_active = bond->curr_active_slave; - } else { - for (slave = bond->prev; slave != (slave_t*)bond; - slave = slave->prev) { - dev_set_promiscuity(slave->dev, inc); + if (!new_active) { /* there were no active slaves left */ + if (bond->slave_cnt > 0) { /* found one slave */ + new_active = bond->first_slave; + } else { + return NULL; /* still no slave, return NULL */ } } -} -/* - * Push the allmulti flag down to all slaves - */ -static void bond_set_allmulti(bonding_t *bond, int inc) -{ - slave_t *slave; - switch (multicast_mode) { - case BOND_MULTICAST_ACTIVE : - /* write lock already acquired */ - if (bond->current_slave != NULL) - dev_set_allmulti(bond->current_slave->dev, inc); - break; - case BOND_MULTICAST_ALL : - for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev) - dev_set_allmulti(slave->dev, inc); - break; - case BOND_MULTICAST_DISABLED : - break; + mintime = updelay; + + /* first try the primary link; if arping, a link must tx/rx traffic + * before it can be considered the curr_active_slave - also, we would skip + * slaves between the curr_active_slave and primary_slave that may be up + * and able to arp + */ + if ((bond->primary_slave) && + (!arp_interval) && + (IS_UP(bond->primary_slave->dev))) { + new_active = bond->primary_slave; } -} -/* - * returns dmi entry if found, NULL otherwise - */ -static struct dev_mc_list* bond_mc_list_find_dmi(struct dev_mc_list *dmi, - struct dev_mc_list *mc_list) -{ - struct dev_mc_list *idmi; + /* remember where to stop iterating over the slaves */ + old_active = new_active; - for (idmi = mc_list; idmi != NULL; idmi = idmi->next) { - if (dmi_same(dmi, idmi)) { - return idmi; + bond_for_each_slave_from(bond, new_active, i, old_active) { + if (IS_UP(new_active->dev)) { + if (new_active->link == BOND_LINK_UP) { + return new_active; + } else if (new_active->link == BOND_LINK_BACK) { + /* link up, but waiting for stabilization */ + if (new_active->delay < mintime) { + mintime = new_active->delay; + bestslave = new_active; + } + } } } - return NULL; -} -static void set_multicast_list(struct net_device *master) + return bestslave; +} + +/** + * change_active_interface - change the active slave into the specified one + * @bond: our bonding struct + * @new: the new slave to make the active one + * + * Set the new slave to the bond's settings and unset them on the old + * curr_active_slave. + * Setting include flags, mc-list, promiscuity, allmulti, etc. + * + * If @new's link state is %BOND_LINK_BACK we'll set it to %BOND_LINK_UP, + * because it is apparently the best available slave we have, even though its + * updelay hasn't timed out yet. + * + * Warning: Caller must hold curr_slave_lock for writing. + */ +static void bond_change_active_slave(struct bonding *bond, struct slave *new_active) { - bonding_t *bond = master->priv; - struct dev_mc_list *dmi; + struct slave *old_active = bond->curr_active_slave; - write_lock_bh(&bond->lock); + if (old_active == new_active) { + return; + } - /* - * Do promisc before checking multicast_mode - */ - if ( (master->flags & IFF_PROMISC) && !(bond->flags & IFF_PROMISC) ) - bond_set_promiscuity(bond, 1); + if (new_active) { + if (new_active->link == BOND_LINK_BACK) { + if (USES_PRIMARY(bond_mode)) { + printk(KERN_INFO DRV_NAME + ": %s: making interface %s the new " + "active one %d ms earlier.\n", + bond->dev->name, new_active->dev->name, + (updelay - new_active->delay) * miimon); + } - if ( !(master->flags & IFF_PROMISC) && (bond->flags & IFF_PROMISC) ) - bond_set_promiscuity(bond, -1); + new_active->delay = 0; + new_active->link = BOND_LINK_UP; + new_active->jiffies = jiffies; - if (multicast_mode == BOND_MULTICAST_DISABLED) { - bond->flags = master->flags; - write_unlock_bh(&bond->lock); - return; + if (bond_mode == BOND_MODE_8023AD) { + bond_3ad_handle_link_change(new_active, BOND_LINK_UP); + } + + if ((bond_mode == BOND_MODE_TLB) || + (bond_mode == BOND_MODE_ALB)) { + bond_alb_handle_link_change(bond, new_active, BOND_LINK_UP); + } + } else { + if (USES_PRIMARY(bond_mode)) { + printk(KERN_INFO DRV_NAME + ": %s: making interface %s the new " + "active one.\n", + bond->dev->name, new_active->dev->name); + } + } } - /* set allmulti flag to slaves */ - if ( (master->flags & IFF_ALLMULTI) && !(bond->flags & IFF_ALLMULTI) ) - bond_set_allmulti(bond, 1); + if (bond_mode == BOND_MODE_ACTIVEBACKUP) { + if (old_active) { + bond_set_slave_inactive_flags(old_active); + } + + if (new_active) { + bond_set_slave_active_flags(new_active); + } + } - if ( !(master->flags & IFF_ALLMULTI) && (bond->flags & IFF_ALLMULTI) ) - bond_set_allmulti(bond, -1); + if (USES_PRIMARY(bond_mode)) { + bond_mc_swap(bond, new_active, old_active); + } - bond->flags = master->flags; + if ((bond_mode == BOND_MODE_TLB) || + (bond_mode == BOND_MODE_ALB)) { + bond_alb_handle_active_change(bond, new_active); + } else { + bond->curr_active_slave = new_active; + } +} - /* looking for addresses to add to slaves' mc list */ - for (dmi = master->mc_list; dmi != NULL; dmi = dmi->next) { - if (bond_mc_list_find_dmi(dmi, bond->mc_list) == NULL) - bond_mc_add(bond, dmi->dmi_addr, dmi->dmi_addrlen); - } +/** + * bond_select_active_slave - select a new active slave, if needed + * @bond: our bonding struct + * + * This functions shoud be called when one of the following occurs: + * - The old curr_active_slave has been released or lost its link. + * - The primary_slave has got its link back. + * - A slave has got its link back and there's no old curr_active_slave. + * + * Warning: Caller must hold curr_slave_lock for writing. + */ +static void bond_select_active_slave(struct bonding *bond) +{ + struct slave *best_slave; - /* looking for addresses to delete from slaves' list */ - for (dmi = bond->mc_list; dmi != NULL; dmi = dmi->next) { - if (bond_mc_list_find_dmi(dmi, master->mc_list) == NULL) - bond_mc_delete(bond, dmi->dmi_addr, dmi->dmi_addrlen); + best_slave = bond_find_best_slave(bond); + if (best_slave != bond->curr_active_slave) { + bond_change_active_slave(bond, best_slave); } +} +/*--------------------------- slave list handling ---------------------------*/ - /* save master's multicast list */ - bond_mc_list_destroy (bond); - bond_mc_list_copy (master->mc_list, bond, GFP_ATOMIC); +/* + * This function attaches the slave to the end of list. + * + * bond->lock held for writing by caller. + */ +static void bond_attach_slave(struct bonding *bond, struct slave *new_slave) +{ + if (bond->first_slave == NULL) { /* attaching the first slave */ + new_slave->next = new_slave; + new_slave->prev = new_slave; + bond->first_slave = new_slave; + } else { + new_slave->next = bond->first_slave; + new_slave->prev = bond->first_slave->prev; + new_slave->next->prev = new_slave; + new_slave->prev->next = new_slave; + } - write_unlock_bh(&bond->lock); + bond->slave_cnt++; } /* - * Update the mc list and multicast-related flags for the new and - * old active slaves (if any) according to the multicast mode, and - * promiscuous flags unconditionally. + * This function detaches the slave from the list. + * WARNING: no check is made to verify if the slave effectively + * belongs to . + * Nothing is freed on return, structures are just unchained. + * If any slave pointer in bond was pointing to , + * it should be changed by the calling function. + * + * bond->lock held for writing by caller. */ -static void bond_mc_update(bonding_t *bond, slave_t *new, slave_t *old) +static void bond_detach_slave(struct bonding *bond, struct slave *slave) { - struct dev_mc_list *dmi; + if (slave->next) { + slave->next->prev = slave->prev; + } - if (USES_PRIMARY(bond_mode)) { - if (bond->device->flags & IFF_PROMISC) { - if (old) - dev_set_promiscuity(old->dev, -1); - if (new) - dev_set_promiscuity(new->dev, 1); - } + if (slave->prev) { + slave->prev->next = slave->next; } - switch(multicast_mode) { - case BOND_MULTICAST_ACTIVE : - if (bond->device->flags & IFF_ALLMULTI) { - if (old) - dev_set_allmulti(old->dev, -1); - if (new) - dev_set_allmulti(new->dev, 1); - } - /* first remove all mc addresses from old slave if any, - and _then_ add them to new active slave */ - if (old) { - for (dmi = bond->device->mc_list; dmi != NULL; dmi = dmi->next) - dev_mc_delete(old->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); - } - if (new) { - for (dmi = bond->device->mc_list; dmi != NULL; dmi = dmi->next) - dev_mc_add(new->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); + if (bond->first_slave == slave) { /* slave is the first slave */ + if (bond->slave_cnt > 1) { /* there are more slave */ + bond->first_slave = slave->next; + } else { + bond->first_slave = NULL; /* slave was the last one */ } - break; - case BOND_MULTICAST_ALL : - /* nothing to do: mc list is already up-to-date on all slaves */ - break; - case BOND_MULTICAST_DISABLED : - break; } + + slave->next = NULL; + slave->prev = NULL; + bond->slave_cnt--; +} + +/*---------------------------------- IOCTL ----------------------------------*/ + +static int bond_sethwaddr(struct net_device *bond_dev, struct net_device *slave_dev) +{ + dprintk("bond_dev=%p\n", bond_dev); + dprintk("slave_dev=%p\n", slave_dev); + dprintk("slave_dev->addr_len=%d\n", slave_dev->addr_len); + memcpy(bond_dev->dev_addr, slave_dev->dev_addr, slave_dev->addr_len); + return 0; } /* enslave device to bond device */ -static int bond_enslave(struct net_device *master_dev, - struct net_device *slave_dev) +static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) { - bonding_t *bond = NULL; - slave_t *new_slave = NULL; - unsigned long rflags = 0; - int err = 0; + struct bonding *bond = bond_dev->priv; + struct slave *new_slave = NULL; struct dev_mc_list *dmi; - struct in_ifaddr **ifap; - struct in_ifaddr *ifa; - int link_reporting; struct sockaddr addr; - - if (master_dev == NULL || slave_dev == NULL) { - return -ENODEV; - } - bond = (struct bonding *) master_dev->priv; + int link_reporting; + int res = 0; if (slave_dev->do_ioctl == NULL) { - printk(KERN_DEBUG - "Warning : no link monitoring support for %s\n", - slave_dev->name); + printk(KERN_WARNING DRV_NAME + ": Warning : no link monitoring support for %s\n", + slave_dev->name); } - /* bond must be initialized by bond_open() before enslaving */ - if (!(master_dev->flags & IFF_UP)) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Error, master_dev is not up\n"); -#endif + if (!(bond_dev->flags & IFF_UP)) { + dprintk("Error, master_dev is not up\n"); return -EPERM; } /* already enslaved */ - if (master_dev->flags & IFF_SLAVE || slave_dev->flags & IFF_SLAVE) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Error, Device was already enslaved\n"); -#endif + if (slave_dev->flags & IFF_SLAVE) { + dprintk("Error, Device was already enslaved\n"); return -EBUSY; } @@ -1376,19 +1228,19 @@ static int bond_enslave(struct net_devic * slave interface to be closed. */ if ((slave_dev->flags & IFF_UP)) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Error, slave_dev is up\n"); -#endif + printk(KERN_ERR DRV_NAME + ": Error: %s is up\n", + slave_dev->name); return -EPERM; } if (slave_dev->set_mac_address == NULL) { - printk(KERN_CRIT - "The slave device you specified does not support" - " setting the MAC address.\n"); - printk(KERN_CRIT - "Your kernel likely does not support slave" - " devices.\n"); + printk(KERN_ERR DRV_NAME + ": Error: The slave device you specified does " + "not support setting the MAC address.\n"); + printk(KERN_ERR + "Your kernel likely does not support slave " + "devices.\n"); return -EOPNOTSUPP; } @@ -1397,26 +1249,29 @@ static int bond_enslave(struct net_devic * slave interface to be open. */ if (!(slave_dev->flags & IFF_UP)) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Error, slave_dev is not running\n"); -#endif + printk(KERN_ERR DRV_NAME + ": Error: %s is not running\n", + slave_dev->name); return -EINVAL; } if ((bond_mode == BOND_MODE_8023AD) || - (bond_mode == BOND_MODE_TLB) || + (bond_mode == BOND_MODE_TLB) || (bond_mode == BOND_MODE_ALB)) { - printk(KERN_ERR - "bonding: Error: to use %s mode, you must " - "upgrade ifenslave.\n", bond_mode_name()); + printk(KERN_ERR DRV_NAME + ": Error: to use %s mode, you must upgrade " + "ifenslave.\n", + bond_mode_name()); return -EOPNOTSUPP; } } - if ((new_slave = kmalloc(sizeof(slave_t), GFP_KERNEL)) == NULL) { + new_slave = kmalloc(sizeof(struct slave), GFP_KERNEL); + if (!new_slave) { return -ENOMEM; } - memset(new_slave, 0, sizeof(slave_t)); + + memset(new_slave, 0, sizeof(struct slave)); /* save slave's original flags before calling * netdev_set_master and dev_open @@ -1430,37 +1285,29 @@ static int bond_enslave(struct net_devic */ memcpy(new_slave->perm_hwaddr, slave_dev->dev_addr, ETH_ALEN); - if (bond->slave_cnt > 0) { - /* set slave to master's mac address - * The application already set the master's - * mac address to that of the first slave - */ - memcpy(addr.sa_data, master_dev->dev_addr, master_dev->addr_len); - addr.sa_family = slave_dev->type; - err = slave_dev->set_mac_address(slave_dev, &addr); - if (err) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Error %d calling set_mac_address\n", err); -#endif - goto err_free; - } + /* set slave to master's mac address + * The application already set the master's + * mac address to that of the first slave + */ + memcpy(addr.sa_data, bond_dev->dev_addr, bond_dev->addr_len); + addr.sa_family = slave_dev->type; + res = slave_dev->set_mac_address(slave_dev, &addr); + if (res) { + dprintk("Error %d calling set_mac_address\n", res); + goto err_free; } /* open the slave since the application closed it */ - err = dev_open(slave_dev); - if (err) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Openning slave %s failed\n", slave_dev->name); -#endif + res = dev_open(slave_dev); + if (res) { + dprintk("Openning slave %s failed\n", slave_dev->name); goto err_restore_mac; } } - err = netdev_set_master(slave_dev, master_dev); - if (err) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Error %d calling netdev_set_master\n", err); -#endif + res = netdev_set_master(slave_dev, bond_dev); + if (res) { + dprintk("Error %d calling netdev_set_master\n", res); if (app_abi_ver < 1) { goto err_free; } else { @@ -1475,32 +1322,32 @@ static int bond_enslave(struct net_devic /* bond_alb_init_slave() must be called before all other stages since * it might fail and we do not want to have to undo everything */ - err = bond_alb_init_slave(bond, new_slave); - if (err) { + res = bond_alb_init_slave(bond, new_slave); + if (res) { goto err_unset_master; } } - /* set promiscuity level to new slave */ - if (master_dev->flags & IFF_PROMISC) { - /* If the mode USES_PRIMARY, then the new slave gets the - * master's promisc (and mc) settings only if it becomes the - * current_slave, and that is taken care of later when calling - * bond_change_active() - */ - if (!USES_PRIMARY(bond_mode)) { - dev_set_promiscuity(slave_dev, 1); + /* If the mode USES_PRIMARY, then the new slave gets the + * master's promisc (and mc) settings only if it becomes the + * curr_active_slave, and that is taken care of later when calling + * bond_change_active() + */ + if (!USES_PRIMARY(bond_mode)) { + /* set promiscuity level to new slave */ + if (bond_dev->flags & IFF_PROMISC) { + dev_set_promiscuity(slave_dev, 1); } - } - - if (multicast_mode == BOND_MULTICAST_ALL) { + /* set allmulti level to new slave */ - if (master_dev->flags & IFF_ALLMULTI) - dev_set_allmulti(slave_dev, 1); - - /* upload master's mc_list to new slave */ - for (dmi = master_dev->mc_list; dmi != NULL; dmi = dmi->next) + if (bond_dev->flags & IFF_ALLMULTI) { + dev_set_allmulti(slave_dev, 1); + } + + /* upload master's mc_list to new slave */ + for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) { dev_mc_add (slave_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); + } } if (bond_mode == BOND_MODE_8023AD) { @@ -1511,15 +1358,16 @@ static int bond_enslave(struct net_devic } write_lock_bh(&bond->lock); - + bond_attach_slave(bond, new_slave); + new_slave->delay = 0; new_slave->link_failure_count = 0; - if (miimon > 0 && !use_carrier) { + if (miimon && !use_carrier) { link_reporting = bond_check_dev_link(slave_dev, 1); - if ((link_reporting == -1) && (arp_interval == 0)) { + if ((link_reporting == -1) && !arp_interval) { /* * miimon is set but a bonded network driver * does not support ETHTOOL/MII and @@ -1528,115 +1376,97 @@ static int bond_enslave(struct net_devic * here (because netif_carrier is always * supported); thus, we don't need to change * the messages for netif_carrier. - */ - printk(KERN_ERR - "bond_enslave(): MII and ETHTOOL support not " - "available for interface %s, and " - "arp_interval/arp_ip_target module parameters " - "not specified, thus bonding will not detect " - "link failures! see bonding.txt for details.\n", - slave_dev->name); + */ + printk(KERN_WARNING DRV_NAME + ": Warning: MII and ETHTOOL support not " + "available for interface %s, and " + "arp_interval/arp_ip_target module parameters " + "not specified, thus bonding will not detect " + "link failures! see bonding.txt for details.\n", + slave_dev->name); } else if (link_reporting == -1) { - /* unable get link status using mii/ethtool */ - printk(KERN_WARNING - "bond_enslave: can't get link status from " + /* unable get link status using mii/ethtool */ + printk(KERN_WARNING DRV_NAME + ": Warning: can't get link status from " "interface %s; the network driver associated " - "with this interface does not support " - "MII or ETHTOOL link status reporting, thus " - "miimon has no effect on this interface.\n", + "with this interface does not support MII or " + "ETHTOOL link status reporting, thus miimon " + "has no effect on this interface.\n", slave_dev->name); } } /* check for initial state */ - if ((miimon <= 0) || + if (!miimon || (bond_check_dev_link(slave_dev, 0) == BMSR_LSTATUS)) { if (updelay) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Initial state of slave_dev is " - "BOND_LINK_BACK\n"); -#endif + dprintk("Initial state of slave_dev is " + "BOND_LINK_BACK\n"); new_slave->link = BOND_LINK_BACK; new_slave->delay = updelay; - } - else { -#ifdef BONDING_DEBUG - printk(KERN_DEBUG "Initial state of slave_dev is " + } else { + dprintk("Initial state of slave_dev is " "BOND_LINK_UP\n"); -#endif new_slave->link = BOND_LINK_UP; } new_slave->jiffies = jiffies; - } - else { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Initial state of slave_dev is " + } else { + dprintk("Initial state of slave_dev is " "BOND_LINK_DOWN\n"); -#endif new_slave->link = BOND_LINK_DOWN; } if (bond_update_speed_duplex(new_slave) && (new_slave->link != BOND_LINK_DOWN)) { - - printk(KERN_WARNING - "bond_enslave(): failed to get speed/duplex from %s, " - "speed forced to 100Mbps, duplex forced to Full.\n", + printk(KERN_WARNING DRV_NAME + ": Warning: failed to get speed/duplex from %s, speed " + "forced to 100Mbps, duplex forced to Full.\n", new_slave->dev->name); + if (bond_mode == BOND_MODE_8023AD) { printk(KERN_WARNING - "Operation of 802.3ad mode requires ETHTOOL support " - "in base driver for proper aggregator selection.\n"); + "Operation of 802.3ad mode requires ETHTOOL " + "support in base driver for proper aggregator " + "selection.\n"); } } - /* if we're in active-backup mode, we need one and only one active - * interface. The backup interfaces will have their NOARP flag set - * because we need them to be completely deaf and not to respond to - * any ARP request on the network to avoid fooling a switch. Thus, - * since we guarantee that current_slave always point to the last - * usable interface, we just have to verify this interface's flag. - */ - if (bond_mode == BOND_MODE_ACTIVEBACKUP) { - if (((bond->current_slave == NULL) - || (bond->current_slave->dev->flags & IFF_NOARP)) - && (new_slave->link != BOND_LINK_DOWN)) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "This is the first active slave\n"); -#endif + if (USES_PRIMARY(bond_mode) && primary) { + /* if there is a primary slave, remember it */ + if (strcmp(primary, new_slave->dev->name) == 0) { + bond->primary_slave = new_slave; + } + } + + switch (bond_mode) { + case BOND_MODE_ACTIVEBACKUP: + /* if we're in active-backup mode, we need one and only one active + * interface. The backup interfaces will have their NOARP flag set + * because we need them to be completely deaf and not to respond to + * any ARP request on the network to avoid fooling a switch. Thus, + * since we guarantee that curr_active_slave always point to the last + * usable interface, we just have to verify this interface's flag. + */ + if (((!bond->curr_active_slave) || + (bond->curr_active_slave->dev->flags & IFF_NOARP)) && + (new_slave->link != BOND_LINK_DOWN)) { + dprintk("This is the first active slave\n"); /* first slave or no active slave yet, and this link is OK, so make this interface the active one */ - change_active_interface(bond, new_slave); - } - else { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "This is just a backup slave\n"); -#endif + bond_change_active_slave(bond, new_slave); + } else { + dprintk("This is just a backup slave\n"); bond_set_slave_inactive_flags(new_slave); } - if (((struct in_device *)slave_dev->ip_ptr) != NULL) { - read_lock_irqsave(&(((struct in_device *)slave_dev->ip_ptr)->lock), rflags); - ifap= &(((struct in_device *)slave_dev->ip_ptr)->ifa_list); - ifa = *ifap; - if (ifa != NULL) - my_ip = ifa->ifa_address; - read_unlock_irqrestore(&(((struct in_device *)slave_dev->ip_ptr)->lock), rflags); - } - - /* if there is a primary slave, remember it */ - if (primary != NULL) { - if (strcmp(primary, new_slave->dev->name) == 0) { - bond->primary_slave = new_slave; - } - } - } else if (bond_mode == BOND_MODE_8023AD) { + break; + case BOND_MODE_8023AD: /* in 802.3ad mode, the internal mechanism * will activate the slaves in the selected * aggregator */ bond_set_slave_inactive_flags(new_slave); /* if this is the first slave */ - if (new_slave == bond->next) { + if (bond->slave_cnt == 1) { SLAVE_AD_INFO(new_slave).id = 1; /* Initialize AD with the number of times that the AD timer is called in 1 second * can be called only after the mac address of the bond is set @@ -1645,40 +1475,37 @@ static int bond_enslave(struct net_devic lacp_fast); } else { SLAVE_AD_INFO(new_slave).id = - SLAVE_AD_INFO(new_slave->prev).id + 1; + SLAVE_AD_INFO(new_slave->prev).id + 1; } bond_3ad_bind_slave(new_slave); - } else if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { + break; + case BOND_MODE_TLB: + case BOND_MODE_ALB: new_slave->state = BOND_STATE_ACTIVE; - if ((bond->current_slave == NULL) && (new_slave->link != BOND_LINK_DOWN)) { + if ((!bond->curr_active_slave) && + (new_slave->link != BOND_LINK_DOWN)) { /* first slave or no active slave yet, and this link * is OK, so make this interface the active one */ - change_active_interface(bond, new_slave); + bond_change_active_slave(bond, new_slave); } + break; + default: + dprintk("This slave is always active in trunk mode\n"); - /* if there is a primary slave, remember it */ - if (primary != NULL) { - if (strcmp(primary, new_slave->dev->name) == 0) { - bond->primary_slave = new_slave; - } - } - } else { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "This slave is always active in trunk mode\n"); -#endif /* always active in trunk mode */ new_slave->state = BOND_STATE_ACTIVE; - /* In trunking mode there is little meaning to current_slave + /* In trunking mode there is little meaning to curr_active_slave * anyway (it holds no special properties of the bond device), * so we can change it without calling change_active_interface() */ - if (bond->current_slave == NULL) - bond->current_slave = new_slave; - } + if (!bond->curr_active_slave) { + bond->curr_active_slave = new_slave; + } + break; + } /* switch(bond_mode) */ write_unlock_bh(&bond->lock); @@ -1692,38 +1519,34 @@ static int bond_enslave(struct net_devic */ int ndx = 0; - for (ndx = 0; ndx < slave_dev->addr_len; ndx++) { -#ifdef BONDING_DEBUG - printk(KERN_DEBUG - "Checking ndx=%d of master_dev->dev_addr\n", ndx); -#endif - if (master_dev->dev_addr[ndx] != 0) { -#ifdef BONDING_DEBUG - printk(KERN_DEBUG - "Found non-zero byte at ndx=%d\n", ndx); -#endif + for (ndx = 0; ndx < bond_dev->addr_len; ndx++) { + dprintk("Checking ndx=%d of bond_dev->dev_addr\n", + ndx); + if (bond_dev->dev_addr[ndx] != 0) { + dprintk("Found non-zero byte at ndx=%d\n", + ndx); break; } } - if (ndx == slave_dev->addr_len) { + + if (ndx == bond_dev->addr_len) { /* * We got all the way through the address and it was * all 0's. */ -#ifdef BONDING_DEBUG - printk(KERN_DEBUG "%s doesn't have a MAC address yet. ", - master_dev->name); - printk(KERN_DEBUG "Going to give assign it from %s.\n", - slave_dev->name); -#endif - bond_sethwaddr(master_dev, slave_dev); + dprintk("%s doesn't have a MAC address yet. \n", + bond_dev->name); + dprintk("Going to give assign it from %s.\n", + slave_dev->name); + bond_sethwaddr(bond_dev, slave_dev); } } - printk (KERN_INFO "%s: enslaving %s as a%s interface with a%s link.\n", - master_dev->name, slave_dev->name, - new_slave->state == BOND_STATE_ACTIVE ? "n active" : " backup", - new_slave->link != BOND_LINK_DOWN ? "n up" : " down"); + printk(KERN_INFO DRV_NAME + ": %s: enslaving %s as a%s interface with a%s link.\n", + bond_dev->name, slave_dev->name, + new_slave->state == BOND_STATE_ACTIVE ? "n active" : " backup", + new_slave->link != BOND_LINK_DOWN ? "n up" : " down"); /* enslave is successful */ return 0; @@ -1742,435 +1565,210 @@ err_restore_mac: err_free: kfree(new_slave); - return err; + return res; } -/* - * This function changes the active slave to slave . - * It returns -EINVAL in the following cases. - * - is not found in the list. - * - There is not active slave now. - * - is already active. - * - The link state of is not BOND_LINK_UP. - * - is not running. - * In these cases, this fuction does nothing. - * In the other cases, currnt_slave pointer is changed and 0 is returned. +/* + * Try to release the slave device from the bond device + * It is legal to access curr_active_slave without a lock because all the function + * is write-locked. + * + * The rules for slave state should be: + * for Active/Backup: + * Active stays on all backups go down + * for Bonded connections: + * The first up interface should be left on and all others downed. */ -static int bond_change_active(struct net_device *master_dev, struct net_device *slave_dev) +static int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) { - bonding_t *bond; - slave_t *slave; - slave_t *oldactive = NULL; - slave_t *newactive = NULL; - int ret = 0; - - if (master_dev == NULL || slave_dev == NULL) { - return -ENODEV; - } + struct bonding *bond = bond_dev->priv; + struct slave *slave, *oldcurrent; + struct sockaddr addr; + int mac_addr_differ; - /* Verify that master_dev is indeed the master of slave_dev */ + /* slave is not a slave or master is not master of this slave */ if (!(slave_dev->flags & IFF_SLAVE) || - (slave_dev->master != master_dev)) { - + (slave_dev->master != bond_dev)) { + printk(KERN_ERR DRV_NAME + ": Error: %s: cannot release %s.\n", + bond_dev->name, slave_dev->name); return -EINVAL; } - bond = (struct bonding *) master_dev->priv; write_lock_bh(&bond->lock); - slave = (slave_t *)bond; - oldactive = bond->current_slave; - - while ((slave = slave->prev) != (slave_t *)bond) { - if(slave_dev == slave->dev) { - newactive = slave; - break; - } - } - - /* - * Changing to the current active: do nothing; return success. - */ - if (newactive && (newactive == oldactive)) { - write_unlock_bh(&bond->lock); - return 0; - } - - if ((newactive != NULL)&& - (oldactive != NULL)&& - (newactive->link == BOND_LINK_UP)&& - IS_UP(newactive->dev)) { - change_active_interface(bond, newactive); - } else { - ret = -EINVAL; - } - write_unlock_bh(&bond->lock); - return ret; -} - -/** - * find_best_interface - select the best available slave to be the active one - * @bond: our bonding struct - * - * Warning: Caller must hold ptrlock for writing. - */ -static struct slave *find_best_interface(struct bonding *bond) -{ - struct slave *newslave, *oldslave; - struct slave *bestslave = NULL; - int mintime; - - newslave = oldslave = bond->current_slave; - if (newslave == NULL) { /* there were no active slaves left */ - if (bond->next != (slave_t *)bond) { /* found one slave */ - newslave = bond->next; - } else { - return NULL; /* still no slave, return NULL */ - } + slave = bond_get_slave_by_dev(bond, slave_dev); + if (!slave) { + /* not a slave of this bond */ + printk(KERN_INFO DRV_NAME + ": %s: %s not enslaved\n", + bond_dev->name, slave_dev->name); + return -EINVAL; } - mintime = updelay; - - /* first try the primary link; if arping, a link must tx/rx traffic - * before it can be considered the current_slave - also, we would skip - * slaves between the current_slave and primary_slave that may be up - * and able to arp - */ - if ((bond->primary_slave != NULL) && (arp_interval == 0)) { - if (IS_UP(bond->primary_slave->dev)) - newslave = bond->primary_slave; + mac_addr_differ = memcmp(bond_dev->dev_addr, + slave->perm_hwaddr, + ETH_ALEN); + if (!mac_addr_differ && (bond->slave_cnt > 1)) { + printk(KERN_WARNING DRV_NAME + ": Warning: the permanent HWaddr of %s " + "- %02X:%02X:%02X:%02X:%02X:%02X - is " + "still in use by %s. Set the HWaddr of " + "%s to a different address to avoid " + "conflicts.\n", + slave_dev->name, + slave->perm_hwaddr[0], + slave->perm_hwaddr[1], + slave->perm_hwaddr[2], + slave->perm_hwaddr[3], + slave->perm_hwaddr[4], + slave->perm_hwaddr[5], + bond_dev->name, + slave_dev->name); } - /* remember where to stop iterating over the slaves */ - oldslave = newslave; - - do { - if (IS_UP(newslave->dev)) { - if (newslave->link == BOND_LINK_UP) { - return newslave; - } - else if (newslave->link == BOND_LINK_BACK) { - /* link up, but waiting for stabilization */ - if (newslave->delay < mintime) { - mintime = newslave->delay; - bestslave = newslave; - } - } - } - } while ((newslave = newslave->next) != oldslave); - - return bestslave; -} - -/** - * change_active_interface - change the active slave into the specified one - * @bond: our bonding struct - * @new: the new slave to make the active one - * - * Set the new slave to the bond's settings and unset them on the old - * current_slave. - * Setting include flags, mc-list, promiscuity, allmulti, etc. - * - * If @new's link state is %BOND_LINK_BACK we'll set it to %BOND_LINK_UP, - * because it is apparently the best available slave we have, even though its - * updelay hasn't timed out yet. - * - * Warning: Caller must hold ptrlock for writing. - */ -static void change_active_interface(struct bonding *bond, struct slave *new) -{ - struct slave *old = bond->current_slave; - - if (old == new) { - return; + /* Inform AD package of unbinding of slave. */ + if (bond_mode == BOND_MODE_8023AD) { + /* must be called before the slave is + * detached from the list + */ + bond_3ad_unbind_slave(slave); } - if (new) { - if (new->link == BOND_LINK_BACK) { - if (USES_PRIMARY(bond_mode)) { - printk (KERN_INFO - "%s: making interface %s the new " - "active one %d ms earlier.\n", - bond->device->name, new->dev->name, - (updelay - new->delay) * miimon); - } + printk(KERN_INFO DRV_NAME + ": %s: releasing %s interface %s\n", + bond_dev->name, + (slave->state == BOND_STATE_ACTIVE) + ? "active" : "backup", + slave_dev->name); - new->delay = 0; - new->link = BOND_LINK_UP; - new->jiffies = jiffies; - - if (bond_mode == BOND_MODE_8023AD) { - bond_3ad_handle_link_change(new, BOND_LINK_UP); - } + oldcurrent = bond->curr_active_slave; - if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { - bond_alb_handle_link_change(bond, new, BOND_LINK_UP); - } - } else { - if (USES_PRIMARY(bond_mode)) { - printk (KERN_INFO - "%s: making interface %s the new active one.\n", - bond->device->name, new->dev->name); - } - } - } + bond->current_arp_slave = NULL; - if (bond_mode == BOND_MODE_ACTIVEBACKUP) { - if (old) { - bond_set_slave_inactive_flags(old); - } + /* release the slave from its bond */ + bond_detach_slave(bond, slave); - if (new) { - bond_set_slave_active_flags(new); - } + if (bond->primary_slave == slave) { + bond->primary_slave = NULL; } - if (USES_PRIMARY(bond_mode)) { - bond_mc_update(bond, new, old); + if (oldcurrent == slave) { + bond_change_active_slave(bond, NULL); } if ((bond_mode == BOND_MODE_TLB) || (bond_mode == BOND_MODE_ALB)) { - bond_alb_assign_current_slave(bond, new); - } else { - bond->current_slave = new; - } -} - -/** - * reselect_active_interface - select a new active slave, if needed - * @bond: our bonding struct - * - * This functions shoud be called when one of the following occurs: - * - The old current_slave has been released or lost its link. - * - The primary_slave has got its link back. - * - A slave has got its link back and there's no old current_slave. - * - * Warning: Caller must hold ptrlock for writing. - */ -static void reselect_active_interface(struct bonding *bond) -{ - struct slave *best_slave; - - best_slave = find_best_interface(bond); - - if (best_slave != bond->current_slave) { - change_active_interface(bond, best_slave); - } -} - -/* - * Try to release the slave device from the bond device - * It is legal to access current_slave without a lock because all the function - * is write-locked. - * - * The rules for slave state should be: - * for Active/Backup: - * Active stays on all backups go down - * for Bonded connections: - * The first up interface should be left on and all others downed. - */ -static int bond_release(struct net_device *master, struct net_device *slave) -{ - bonding_t *bond; - slave_t *our_slave, *old_current; - struct sockaddr addr; - - if (master == NULL || slave == NULL) { - return -ENODEV; - } - - bond = (struct bonding *) master->priv; - - /* master already enslaved, or slave not enslaved, - or no slave for this master */ - if ((master->flags & IFF_SLAVE) || !(slave->flags & IFF_SLAVE)) { - printk (KERN_DEBUG "%s: cannot release %s.\n", master->name, slave->name); - return -EINVAL; + /* Must be called only after the slave has been + * detached from the list and the curr_active_slave + * has been cleared (if our_slave == old_current), + * but before a new active slave is selected. + */ + bond_alb_deinit_slave(bond, slave); } - write_lock_bh(&bond->lock); - bond->current_arp_slave = NULL; - our_slave = (slave_t *)bond; - old_current = bond->current_slave; - while ((our_slave = our_slave->prev) != (slave_t *)bond) { - if (our_slave->dev == slave) { - int mac_addr_differ = memcmp(bond->device->dev_addr, - our_slave->perm_hwaddr, - ETH_ALEN); - if (!mac_addr_differ && (bond->slave_cnt > 1)) { - printk(KERN_WARNING "WARNING: the permanent HWaddr of %s " - "- %02X:%02X:%02X:%02X:%02X:%02X - " - "is still in use by %s. Set the HWaddr " - "of %s to a different address " - "to avoid conflicts.\n", - slave->name, - our_slave->perm_hwaddr[0], - our_slave->perm_hwaddr[1], - our_slave->perm_hwaddr[2], - our_slave->perm_hwaddr[3], - our_slave->perm_hwaddr[4], - our_slave->perm_hwaddr[5], - bond->device->name, - slave->name); - } - - /* Inform AD package of unbinding of slave. */ - if (bond_mode == BOND_MODE_8023AD) { - /* must be called before the slave is - * detached from the list - */ - bond_3ad_unbind_slave(our_slave); - } - - printk (KERN_INFO "%s: releasing %s interface %s\n", - master->name, - (our_slave->state == BOND_STATE_ACTIVE) ? "active" : "backup", - slave->name); - - /* release the slave from its bond */ - bond_detach_slave(bond, our_slave); - - if (bond->primary_slave == our_slave) { - bond->primary_slave = NULL; - } - - if (bond->current_slave == our_slave) { - change_active_interface(bond, NULL); - reselect_active_interface(bond); - } - - if (bond->current_slave == NULL) { - printk(KERN_INFO - "%s: now running without any active interface !\n", - master->name); - } - - if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { - /* must be called only after the slave has been - * detached from the list and the current_slave - * has been replaced (if our_slave == old_current) - */ - bond_alb_deinit_slave(bond, our_slave); - } + if (oldcurrent == slave) { + bond_select_active_slave(bond); - break; + if (!bond->curr_active_slave) { + printk(KERN_INFO DRV_NAME + ": %s: now running without any active " + "interface !\n", + bond_dev->name); } - } + write_unlock_bh(&bond->lock); - - if (our_slave == (slave_t *)bond) { - /* if we get here, it's because the device was not found */ - printk (KERN_INFO "%s: %s not enslaved\n", master->name, slave->name); - return -EINVAL; - } - /* unset promiscuity level from slave */ - if (master->flags & IFF_PROMISC) { - /* If the mode USES_PRIMARY, then we should only remove its - * promisc settings if it was the current_slave, but that was - * already taken care of above when we detached the slave - */ - if (!USES_PRIMARY(bond_mode)) { - dev_set_promiscuity(slave, -1); + /* If the mode USES_PRIMARY, then we should only remove its + * promisc and mc settings if it was the curr_active_slave, but that was + * already taken care of above when we detached the slave + */ + if (!USES_PRIMARY(bond_mode)) { + /* unset promiscuity level from slave */ + if (bond_dev->flags & IFF_PROMISC) { + dev_set_promiscuity(slave_dev, -1); } - } - /* undo settings and restore original values */ - if (multicast_mode == BOND_MULTICAST_ALL) { - /* flush master's mc_list from slave */ - bond_mc_list_flush (slave, master); + /* unset allmulti level from slave */ + if (bond_dev->flags & IFF_ALLMULTI) { + dev_set_allmulti(slave_dev, -1); + } - /* unset allmulti level from slave */ - if (master->flags & IFF_ALLMULTI) - dev_set_allmulti(slave, -1); + /* flush master's mc_list from slave */ + bond_mc_list_flush(bond_dev, slave_dev); } - netdev_set_master(slave, NULL); + netdev_set_master(slave_dev, NULL); /* close slave before restoring its mac address */ - dev_close(slave); + dev_close(slave_dev); if (app_abi_ver >= 1) { /* restore original ("permanent") mac address */ - memcpy(addr.sa_data, our_slave->perm_hwaddr, ETH_ALEN); - addr.sa_family = slave->type; - slave->set_mac_address(slave, &addr); + memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN); + addr.sa_family = slave_dev->type; + slave_dev->set_mac_address(slave_dev, &addr); } /* restore the original state of the * IFF_NOARP flag that might have been * set by bond_set_slave_inactive_flags() */ - if ((our_slave->original_flags & IFF_NOARP) == 0) { - slave->flags &= ~IFF_NOARP; + if ((slave->original_flags & IFF_NOARP) == 0) { + slave_dev->flags &= ~IFF_NOARP; } - kfree(our_slave); + kfree(slave); /* if the last slave was removed, zero the mac address * of the master so it will be set by the application * to the mac address of the first slave */ - if (bond->next == (slave_t*)bond) { - memset(master->dev_addr, 0, master->addr_len); + if (bond->slave_cnt == 0) { + memset(bond_dev->dev_addr, 0, bond_dev->addr_len); } return 0; /* deletion OK */ } -/* +/* * This function releases all slaves. */ -static int bond_release_all(struct net_device *master) +static int bond_release_all(struct net_device *bond_dev) { - bonding_t *bond; - slave_t *our_slave, *old_current; + struct bonding *bond = bond_dev->priv; + struct slave *slave; struct net_device *slave_dev; struct sockaddr addr; - int err = 0; - - if (master == NULL) { - return -ENODEV; - } - - if (master->flags & IFF_SLAVE) { - return -EINVAL; - } - - bond = (struct bonding *) master->priv; write_lock_bh(&bond->lock); - if (bond->next == (struct slave *) bond) { - err = -EINVAL; + + if (bond->slave_cnt == 0) { goto out; } - old_current = bond->current_slave; - change_active_interface(bond, NULL); bond->current_arp_slave = NULL; bond->primary_slave = NULL; + bond_change_active_slave(bond, NULL); - while ((our_slave = bond->prev) != (slave_t *)bond) { + while ((slave = bond->first_slave) != NULL) { /* Inform AD package of unbinding of slave * before slave is detached from the list. */ if (bond_mode == BOND_MODE_8023AD) { - bond_3ad_unbind_slave(our_slave); + bond_3ad_unbind_slave(slave); } - slave_dev = our_slave->dev; - bond_detach_slave(bond, our_slave); + slave_dev = slave->dev; + bond_detach_slave(bond, slave); if ((bond_mode == BOND_MODE_TLB) || (bond_mode == BOND_MODE_ALB)) { /* must be called only after the slave * has been detached from the list */ - bond_alb_deinit_slave(bond, our_slave); + bond_alb_deinit_slave(bond, slave); } /* now that the slave is detached, unlock and perform @@ -2179,20 +1777,23 @@ static int bond_release_all(struct net_d */ write_unlock_bh(&bond->lock); - /* unset promiscuity level from slave */ - if (master->flags & IFF_PROMISC) { - if (!USES_PRIMARY(bond_mode)) { - dev_set_promiscuity(slave_dev, -1); + /* If the mode USES_PRIMARY, then we should only remove its + * promisc and mc settings if it was the curr_active_slave, but that was + * already taken care of above when we detached the slave + */ + if (!USES_PRIMARY(bond_mode)) { + /* unset promiscuity level from slave */ + if (bond_dev->flags & IFF_PROMISC) { + dev_set_promiscuity(slave_dev, -1); + } + + /* unset allmulti level from slave */ + if (bond_dev->flags & IFF_ALLMULTI) { + dev_set_allmulti(slave_dev, -1); } - } - if (multicast_mode == BOND_MULTICAST_ALL) { - /* flush master's mc_list from slave */ - bond_mc_list_flush (slave_dev, master); - - /* unset allmulti level from slave */ - if (master->flags & IFF_ALLMULTI) - dev_set_allmulti(slave_dev, -1); + /* flush master's mc_list from slave */ + bond_mc_list_flush(bond_dev, slave_dev); } netdev_set_master(slave_dev, NULL); @@ -2202,7 +1803,7 @@ static int bond_release_all(struct net_d if (app_abi_ver >= 1) { /* restore original ("permanent") mac address*/ - memcpy(addr.sa_data, our_slave->perm_hwaddr, ETH_ALEN); + memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN); addr.sa_family = slave_dev->type; slave_dev->set_mac_address(slave_dev, &addr); } @@ -2210,11 +1811,11 @@ static int bond_release_all(struct net_d /* restore the original state of the IFF_NOARP flag that might have * been set by bond_set_slave_inactive_flags() */ - if ((our_slave->original_flags & IFF_NOARP) == 0) { + if ((slave->original_flags & IFF_NOARP) == 0) { slave_dev->flags &= ~IFF_NOARP; } - kfree(our_slave); + kfree(slave); /* re-acquire the lock before getting the next slave */ write_lock_bh(&bond->lock); @@ -2224,72 +1825,234 @@ static int bond_release_all(struct net_d * set by the application to the mac address of the * first slave */ - memset(master->dev_addr, 0, master->addr_len); + memset(bond_dev->dev_addr, 0, bond_dev->addr_len); - printk (KERN_INFO "%s: released all slaves\n", master->name); + printk(KERN_INFO DRV_NAME + ": %s: released all slaves\n", + bond_dev->name); out: write_unlock_bh(&bond->lock); - return err; + return 0; +} + +/* + * This function changes the active slave to slave . + * It returns -EINVAL in the following cases. + * - is not found in the list. + * - There is not active slave now. + * - is already active. + * - The link state of is not BOND_LINK_UP. + * - is not running. + * In these cases, this fuction does nothing. + * In the other cases, currnt_slave pointer is changed and 0 is returned. + */ +static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_device *slave_dev) +{ + struct bonding *bond = bond_dev->priv; + struct slave *old_active = NULL; + struct slave *new_active = NULL; + int res = 0; + + /* Verify that master_dev is indeed the master of slave_dev */ + if (!(slave_dev->flags & IFF_SLAVE) || + (slave_dev->master != bond_dev)) { + return -EINVAL; + } + + write_lock_bh(&bond->lock); + + old_active = bond->curr_active_slave; + new_active = bond_get_slave_by_dev(bond, slave_dev); + + /* + * Changing to the current active: do nothing; return success. + */ + if (new_active && (new_active == old_active)) { + write_unlock_bh(&bond->lock); + return 0; + } + + if ((new_active) && + (old_active) && + (new_active->link == BOND_LINK_UP) && + IS_UP(new_active->dev)) { + bond_change_active_slave(bond, new_active); + } else { + res = -EINVAL; + } + + write_unlock_bh(&bond->lock); + + return res; +} + +static int bond_ethtool_ioctl(struct net_device *bond_dev, struct ifreq *ifr) +{ + struct ethtool_drvinfo info; + void *addr = ifr->ifr_data; + uint32_t cmd; + + if (get_user(cmd, (uint32_t *)addr)) { + return -EFAULT; + } + + switch (cmd) { + case ETHTOOL_GDRVINFO: + if (copy_from_user(&info, addr, sizeof(info))) { + return -EFAULT; + } + + if (strcmp(info.driver, "ifenslave") == 0) { + int new_abi_ver; + char *endptr; + + new_abi_ver = simple_strtoul(info.fw_version, + &endptr, 0); + if (*endptr) { + printk(KERN_ERR DRV_NAME + ": Error: got invalid ABI " + "version from application\n"); + + return -EINVAL; + } + + if (orig_app_abi_ver == -1) { + orig_app_abi_ver = new_abi_ver; + } + + app_abi_ver = new_abi_ver; + } + + strncpy(info.driver, DRV_NAME, 32); + strncpy(info.version, DRV_VERSION, 32); + snprintf(info.fw_version, 32, "%d", BOND_ABI_VERSION); + + if (copy_to_user(addr, &info, sizeof(info))) { + return -EFAULT; + } + + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int bond_info_query(struct net_device *bond_dev, struct ifbond *info) +{ + struct bonding *bond = bond_dev->priv; + + info->bond_mode = bond_mode; + info->miimon = miimon; + + read_lock_bh(&bond->lock); + info->num_slaves = bond->slave_cnt; + read_unlock_bh(&bond->lock); + + return 0; +} + +static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *info) +{ + struct bonding *bond = bond_dev->priv; + struct slave *slave; + int i, found = 0; + + if (info->slave_id < 0) { + return -ENODEV; + } + + read_lock_bh(&bond->lock); + + bond_for_each_slave(bond, slave, i) { + if (i == (int)info->slave_id) { + found = 1; + break; + } + } + + read_unlock_bh(&bond->lock); + + if (found) { + strcpy(info->slave_name, slave->dev->name); + info->link = slave->link; + info->state = slave->state; + info->link_failure_count = slave->link_failure_count; + } else { + return -ENODEV; + } + + return 0; } +/*-------------------------------- Monitoring -------------------------------*/ + /* this function is called regularly to monitor each slave's link. */ -static void bond_mii_monitor(struct net_device *master) +static void bond_mii_monitor(struct net_device *bond_dev) { - bonding_t *bond = (struct bonding *) master->priv; - slave_t *slave, *oldcurrent; - int slave_died = 0; + struct bonding *bond = bond_dev->priv; + struct slave *slave, *oldcurrent; int do_failover = 0; + int delta_in_ticks = (miimon * HZ) / 1000; + int i; read_lock(&bond->lock); + if (bond->kill_timers) { + goto out; + } + + if (bond->slave_cnt == 0) { + goto re_arm; + } + /* we will try to read the link status of each of our slaves, and * set their IFF_RUNNING flag appropriately. For each slave not * supporting MII status, we won't do anything so that a user-space * program could monitor the link itself if needed. */ - slave = (slave_t *)bond; - - read_lock(&bond->ptrlock); - oldcurrent = bond->current_slave; - read_unlock(&bond->ptrlock); + read_lock(&bond->curr_slave_lock); + oldcurrent = bond->curr_active_slave; + read_unlock(&bond->curr_slave_lock); - while ((slave = slave->prev) != (slave_t *)bond) { - struct net_device *dev = slave->dev; + bond_for_each_slave(bond, slave, i) { + struct net_device *slave_dev = slave->dev; int link_state; u16 old_speed = slave->speed; u8 old_duplex = slave->duplex; - - link_state = bond_check_dev_link(dev, 0); + + link_state = bond_check_dev_link(slave_dev, 0); switch (slave->link) { case BOND_LINK_UP: /* the link was up */ if (link_state == BMSR_LSTATUS) { /* link stays up, nothing more to do */ break; - } - else { /* link going down */ + } else { /* link going down */ slave->link = BOND_LINK_FAIL; slave->delay = downdelay; + if (slave->link_failure_count < UINT_MAX) { slave->link_failure_count++; } - if (downdelay > 0) { - printk (KERN_INFO - "%s: link status down for %sinterface " - "%s, disabling it in %d ms.\n", - master->name, - IS_UP(dev) - ? ((bond_mode == BOND_MODE_ACTIVEBACKUP) - ? ((slave == oldcurrent) - ? "active " : "backup ") - : "") - : "idle ", - dev->name, - downdelay * miimon); - } + + if (downdelay) { + printk(KERN_INFO DRV_NAME + ": %s: link status down for %s " + "interface %s, disabling it in " + "%d ms.\n", + bond_dev->name, + IS_UP(slave_dev) + ? ((bond_mode == BOND_MODE_ACTIVEBACKUP) + ? ((slave == oldcurrent) + ? "active " : "backup ") + : "") + : "idle ", + slave_dev->name, + downdelay * miimon); + } } /* no break ! fall through the BOND_LINK_FAIL test to ensure proper action to be taken @@ -2300,6 +2063,7 @@ static void bond_mii_monitor(struct net_ if (slave->delay <= 0) { /* link down for too long time */ slave->link = BOND_LINK_DOWN; + /* in active/backup mode, we must * completely disable this interface */ @@ -2308,11 +2072,12 @@ static void bond_mii_monitor(struct net_ bond_set_slave_inactive_flags(slave); } - printk(KERN_INFO - "%s: link status definitely down " - "for interface %s, disabling it", - master->name, - dev->name); + printk(KERN_INFO DRV_NAME + ": %s: link status definitely " + "down for interface %s, " + "disabling it\n", + bond_dev->name, + slave_dev->name); /* notify ad that the link status has changed */ if (bond_mode == BOND_MODE_8023AD) { @@ -2327,8 +2092,6 @@ static void bond_mii_monitor(struct net_ if (slave == oldcurrent) { do_failover = 1; } - - slave_died = 1; } else { slave->delay--; } @@ -2336,12 +2099,12 @@ static void bond_mii_monitor(struct net_ /* link up again */ slave->link = BOND_LINK_UP; slave->jiffies = jiffies; - printk(KERN_INFO - "%s: link status up again after %d ms " - "for interface %s.\n", - master->name, - (downdelay - slave->delay) * miimon, - dev->name); + printk(KERN_INFO DRV_NAME + ": %s: link status up again after %d " + "ms for interface %s.\n", + bond_dev->name, + (downdelay - slave->delay) * miimon, + slave_dev->name); } break; case BOND_LINK_DOWN: /* the link was down */ @@ -2351,16 +2114,17 @@ static void bond_mii_monitor(struct net_ } else { /* link going up */ slave->link = BOND_LINK_BACK; slave->delay = updelay; - - if (updelay > 0) { + + if (updelay) { /* if updelay == 0, no need to advertise about a 0 ms delay */ - printk (KERN_INFO - "%s: link status up for interface" - " %s, enabling it in %d ms.\n", - master->name, - dev->name, - updelay * miimon); + printk(KERN_INFO DRV_NAME + ": %s: link status up for " + "interface %s, enabling it " + "in %d ms.\n", + bond_dev->name, + slave_dev->name, + updelay * miimon); } } /* no break ! fall through the BOND_LINK_BACK state in @@ -2370,12 +2134,13 @@ static void bond_mii_monitor(struct net_ if (link_state != BMSR_LSTATUS) { /* link down again */ slave->link = BOND_LINK_DOWN; - printk(KERN_INFO - "%s: link status down again after %d ms " - "for interface %s.\n", - master->name, - (updelay - slave->delay) * miimon, - dev->name); + + printk(KERN_INFO DRV_NAME + ": %s: link status down again after %d " + "ms for interface %s.\n", + bond_dev->name, + (updelay - slave->delay) * miimon, + slave_dev->name); } else { /* link stays up */ if (slave->delay == 0) { @@ -2386,8 +2151,7 @@ static void bond_mii_monitor(struct net_ if (bond_mode == BOND_MODE_8023AD) { /* prevent it from being the active one */ slave->state = BOND_STATE_BACKUP; - } - else if (bond_mode != BOND_MODE_ACTIVEBACKUP) { + } else if (bond_mode != BOND_MODE_ACTIVEBACKUP) { /* make it immediately active */ slave->state = BOND_STATE_ACTIVE; } else if (slave != bond->primary_slave) { @@ -2395,12 +2159,12 @@ static void bond_mii_monitor(struct net_ slave->state = BOND_STATE_BACKUP; } - printk(KERN_INFO - "%s: link status definitely up " - "for interface %s.\n", - master->name, - dev->name); - + printk(KERN_INFO DRV_NAME + ": %s: link status definitely " + "up for interface %s.\n", + bond_dev->name, + slave_dev->name); + /* notify ad that the link status has changed */ if (bond_mode == BOND_MODE_8023AD) { bond_3ad_handle_link_change(slave, BOND_LINK_UP); @@ -2411,7 +2175,7 @@ static void bond_mii_monitor(struct net_ bond_alb_handle_link_change(bond, slave, BOND_LINK_UP); } - if ((oldcurrent == NULL) || + if ((!oldcurrent) || (slave == bond->primary_slave)) { do_failover = 1; } @@ -2420,7 +2184,12 @@ static void bond_mii_monitor(struct net_ } } break; - } /* end of switch */ + default: + /* Should not happen */ + printk(KERN_ERR "bonding: Error: %s Illegal value (link=%d)\n", + slave->dev->name, slave->link); + goto out; + } /* end of switch (slave->link) */ bond_update_speed_duplex(slave); @@ -2428,112 +2197,110 @@ static void bond_mii_monitor(struct net_ if (old_speed != slave->speed) { bond_3ad_adapter_speed_changed(slave); } + if (old_duplex != slave->duplex) { bond_3ad_adapter_duplex_changed(slave); } } - } /* end of while */ + } /* end of for */ if (do_failover) { - write_lock(&bond->ptrlock); + write_lock(&bond->curr_slave_lock); - reselect_active_interface(bond); - if (oldcurrent && !bond->current_slave) { - printk(KERN_INFO - "%s: now running without any active interface !\n", - master->name); + bond_select_active_slave(bond); + + if (oldcurrent && !bond->curr_active_slave) { + printk(KERN_INFO DRV_NAME + ": %s: now running without any active " + "interface !\n", + bond_dev->name); } - write_unlock(&bond->ptrlock); + write_unlock(&bond->curr_slave_lock); } +re_arm: + mod_timer(&bond->mii_timer, jiffies + delta_in_ticks); +out: read_unlock(&bond->lock); - /* re-arm the timer */ - mod_timer(&bond->mii_timer, jiffies + (miimon * HZ / 1000)); } -/* - * this function is called regularly to monitor each slave's link +static void bond_arp_send_all(struct slave *slave) +{ + int i; + + for (i = 0; (idev, + my_ip, NULL, slave->dev->dev_addr, + NULL); + } +} + +/* + * this function is called regularly to monitor each slave's link * ensuring that traffic is being sent and received when arp monitoring - * is used in load-balancing mode. if the adapter has been dormant, then an - * arp is transmitted to generate traffic. see activebackup_arp_monitor for - * arp monitoring in active backup mode. + * is used in load-balancing mode. if the adapter has been dormant, then an + * arp is transmitted to generate traffic. see activebackup_arp_monitor for + * arp monitoring in active backup mode. */ -static void loadbalance_arp_monitor(struct net_device *master) +static void bond_loadbalance_arp_mon(struct net_device *bond_dev) { - bonding_t *bond; - slave_t *slave, *oldcurrent; - int the_delta_in_ticks = arp_interval * HZ / 1000; - int next_timer = jiffies + (arp_interval * HZ / 1000); + struct bonding *bond = bond_dev->priv; + struct slave *slave, *oldcurrent; int do_failover = 0; + int delta_in_ticks = (arp_interval * HZ) / 1000; + int i; - bond = (struct bonding *) master->priv; - if (master->priv == NULL) { - mod_timer(&bond->arp_timer, next_timer); - return; - } + read_lock(&bond->lock); - /* TODO: investigate why rtnl_shlock_nowait and rtnl_exlock_nowait - * are called below and add comment why they are required... - */ - if ((!IS_UP(master)) || rtnl_shlock_nowait()) { - mod_timer(&bond->arp_timer, next_timer); - return; + if (bond->kill_timers) { + goto out; } - if (rtnl_exlock_nowait()) { - rtnl_shunlock(); - mod_timer(&bond->arp_timer, next_timer); - return; + if (bond->slave_cnt == 0) { + goto re_arm; } - read_lock(&bond->lock); - - read_lock(&bond->ptrlock); - oldcurrent = bond->current_slave; - read_unlock(&bond->ptrlock); + read_lock(&bond->curr_slave_lock); + oldcurrent = bond->curr_active_slave; + read_unlock(&bond->curr_slave_lock); /* see if any of the previous devices are up now (i.e. they have - * xmt and rcv traffic). the current_slave does not come into + * xmt and rcv traffic). the curr_active_slave does not come into * the picture unless it is null. also, slave->jiffies is not needed * here because we send an arp on each slave and give a slave as * long as it needs to get the tx/rx within the delta. * TODO: what about up/down delay in arp mode? it wasn't here before - * so it can wait + * so it can wait */ - slave = (slave_t *)bond; - while ((slave = slave->prev) != (slave_t *)bond) { - - if (slave->link != BOND_LINK_UP) { - - if (((jiffies - slave->dev->trans_start) <= - the_delta_in_ticks) && - ((jiffies - slave->dev->last_rx) <= - the_delta_in_ticks)) { + bond_for_each_slave(bond, slave, i) { + if (slave->link != BOND_LINK_UP) { + if (((jiffies - slave->dev->trans_start) <= delta_in_ticks) && + ((jiffies - slave->dev->last_rx) <= delta_in_ticks)) { slave->link = BOND_LINK_UP; slave->state = BOND_STATE_ACTIVE; /* primary_slave has no meaning in round-robin - * mode. the window of a slave being up and - * current_slave being null after enslaving + * mode. the window of a slave being up and + * curr_active_slave being null after enslaving * is closed. */ - if (oldcurrent == NULL) { - printk(KERN_INFO - "%s: link status definitely up " - "for interface %s, ", - master->name, - slave->dev->name); + if (!oldcurrent) { + printk(KERN_INFO DRV_NAME + ": %s: link status definitely " + "up for interface %s, ", + bond_dev->name, + slave->dev->name); do_failover = 1; } else { - printk(KERN_INFO - "%s: interface %s is now up\n", - master->name, - slave->dev->name); + printk(KERN_INFO DRV_NAME + ": %s: interface %s is now up\n", + bond_dev->name, + slave->dev->name); } - } + } } else { /* slave->link == BOND_LINK_UP */ @@ -2541,224 +2308,233 @@ static void loadbalance_arp_monitor(stru * when the source ip is 0, so don't take the link down * if we don't know our ip yet */ - if (((jiffies - slave->dev->trans_start) >= - (2*the_delta_in_ticks)) || - (((jiffies - slave->dev->last_rx) >= - (2*the_delta_in_ticks)) && my_ip !=0)) { + if (((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) || + (((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) && + my_ip)) { + slave->link = BOND_LINK_DOWN; slave->state = BOND_STATE_BACKUP; + if (slave->link_failure_count < UINT_MAX) { slave->link_failure_count++; } - printk(KERN_INFO - "%s: interface %s is now down.\n", - master->name, + + printk(KERN_INFO DRV_NAME + ": %s: interface %s is now down.\n", + bond_dev->name, slave->dev->name); if (slave == oldcurrent) { do_failover = 1; } } - } + } - /* note: if switch is in round-robin mode, all links + /* note: if switch is in round-robin mode, all links * must tx arp to ensure all links rx an arp - otherwise - * links may oscillate or not come up at all; if switch is - * in something like xor mode, there is nothing we can - * do - all replies will be rx'ed on same link causing slaves + * links may oscillate or not come up at all; if switch is + * in something like xor mode, there is nothing we can + * do - all replies will be rx'ed on same link causing slaves * to be unstable during low/no traffic periods */ if (IS_UP(slave->dev)) { - arp_send_all(slave); + bond_arp_send_all(slave); } } if (do_failover) { - write_lock(&bond->ptrlock); + write_lock(&bond->curr_slave_lock); + + bond_select_active_slave(bond); - reselect_active_interface(bond); - if (oldcurrent && !bond->current_slave) { - printk(KERN_INFO - "%s: now running without any active interface !\n", - master->name); + if (oldcurrent && !bond->curr_active_slave) { + printk(KERN_INFO DRV_NAME + ": %s: now running without any active " + "interface !\n", + bond_dev->name); } - write_unlock(&bond->ptrlock); + write_unlock(&bond->curr_slave_lock); } +re_arm: + mod_timer(&bond->arp_timer, jiffies + delta_in_ticks); +out: read_unlock(&bond->lock); - rtnl_exunlock(); - rtnl_shunlock(); - - /* re-arm the timer */ - mod_timer(&bond->arp_timer, next_timer); } -/* +/* * When using arp monitoring in active-backup mode, this function is * called to determine if any backup slaves have went down or a new * current slave needs to be found. - * The backup slaves never generate traffic, they are considered up by merely - * receiving traffic. If the current slave goes down, each backup slave will - * be given the opportunity to tx/rx an arp before being taken down - this - * prevents all slaves from being taken down due to the current slave not + * The backup slaves never generate traffic, they are considered up by merely + * receiving traffic. If the current slave goes down, each backup slave will + * be given the opportunity to tx/rx an arp before being taken down - this + * prevents all slaves from being taken down due to the current slave not * sending any traffic for the backups to receive. The arps are not necessarily - * necessary, any tx and rx traffic will keep the current slave up. While any - * rx traffic will keep the backup slaves up, the current slave is responsible - * for generating traffic to keep them up regardless of any other traffic they + * necessary, any tx and rx traffic will keep the current slave up. While any + * rx traffic will keep the backup slaves up, the current slave is responsible + * for generating traffic to keep them up regardless of any other traffic they * may have received. * see loadbalance_arp_monitor for arp monitoring in load balancing mode */ -static void activebackup_arp_monitor(struct net_device *master) +static void bond_activebackup_arp_mon(struct net_device *bond_dev) { - bonding_t *bond; - slave_t *slave; - int the_delta_in_ticks = arp_interval * HZ / 1000; - int next_timer = jiffies + (arp_interval * HZ / 1000); - - bond = (struct bonding *) master->priv; - if (master->priv == NULL) { - mod_timer(&bond->arp_timer, next_timer); - return; - } + struct bonding *bond = bond_dev->priv; + struct slave *slave; + int delta_in_ticks = (arp_interval * HZ) / 1000; + int i; - if (!IS_UP(master)) { - mod_timer(&bond->arp_timer, next_timer); - return; + read_lock(&bond->lock); + + if (bond->kill_timers) { + goto out; } - read_lock(&bond->lock); + if (bond->slave_cnt == 0) { + goto re_arm; + } - /* determine if any slave has come up or any backup slave has - * gone down + /* determine if any slave has come up or any backup slave has + * gone down * TODO: what about up/down delay in arp mode? it wasn't here before - * so it can wait + * so it can wait */ - slave = (slave_t *)bond; - while ((slave = slave->prev) != (slave_t *)bond) { - - if (slave->link != BOND_LINK_UP) { - if ((jiffies - slave->dev->last_rx) <= - the_delta_in_ticks) { + bond_for_each_slave(bond, slave, i) { + if (slave->link != BOND_LINK_UP) { + if ((jiffies - slave->dev->last_rx) <= delta_in_ticks) { slave->link = BOND_LINK_UP; - write_lock(&bond->ptrlock); - if ((bond->current_slave == NULL) && - ((jiffies - slave->dev->trans_start) <= - the_delta_in_ticks)) { - change_active_interface(bond, slave); + + write_lock(&bond->curr_slave_lock); + + if ((!bond->curr_active_slave) && + ((jiffies - slave->dev->trans_start) <= delta_in_ticks)) { + bond_change_active_slave(bond, slave); bond->current_arp_slave = NULL; - } else if (bond->current_slave != slave) { - /* this slave has just come up but we + } else if (bond->curr_active_slave != slave) { + /* this slave has just come up but we * already have a current slave; this * can also happen if bond_enslave adds - * a new slave that is up while we are + * a new slave that is up while we are * searching for a new slave */ bond_set_slave_inactive_flags(slave); bond->current_arp_slave = NULL; } - if (slave == bond->current_slave) { - printk(KERN_INFO - "%s: %s is up and now the " - "active interface\n", - master->name, - slave->dev->name); + if (slave == bond->curr_active_slave) { + printk(KERN_INFO DRV_NAME + ": %s: %s is up and now the " + "active interface\n", + bond_dev->name, + slave->dev->name); } else { - printk(KERN_INFO - "%s: backup interface %s is " - "now up\n", - master->name, - slave->dev->name); + printk(KERN_INFO DRV_NAME + ": %s: backup interface %s is " + "now up\n", + bond_dev->name, + slave->dev->name); } - write_unlock(&bond->ptrlock); + write_unlock(&bond->curr_slave_lock); } } else { - read_lock(&bond->ptrlock); - if ((slave != bond->current_slave) && - (bond->current_arp_slave == NULL) && - (((jiffies - slave->dev->last_rx) >= - 3*the_delta_in_ticks) && (my_ip != 0))) { - /* a backup slave has gone down; three times - * the delta allows the current slave to be + read_lock(&bond->curr_slave_lock); + + if ((slave != bond->curr_active_slave) && + (!bond->current_arp_slave) && + (((jiffies - slave->dev->last_rx) >= 3*delta_in_ticks) && + my_ip)) { + /* a backup slave has gone down; three times + * the delta allows the current slave to be * taken out before the backup slave. * note: a non-null current_arp_slave indicates - * the current_slave went down and we are - * searching for a new one; under this - * condition we only take the current_slave - * down - this gives each slave a chance to + * the curr_active_slave went down and we are + * searching for a new one; under this + * condition we only take the curr_active_slave + * down - this gives each slave a chance to * tx/rx traffic before being taken out */ - read_unlock(&bond->ptrlock); + + read_unlock(&bond->curr_slave_lock); + slave->link = BOND_LINK_DOWN; + if (slave->link_failure_count < UINT_MAX) { slave->link_failure_count++; } + bond_set_slave_inactive_flags(slave); - printk(KERN_INFO - "%s: backup interface %s is now down\n", - master->name, - slave->dev->name); + + printk(KERN_INFO DRV_NAME + ": %s: backup interface %s is now down\n", + bond_dev->name, + slave->dev->name); } else { - read_unlock(&bond->ptrlock); + read_unlock(&bond->curr_slave_lock); } } } - read_lock(&bond->ptrlock); - slave = bond->current_slave; - read_unlock(&bond->ptrlock); - - if (slave != NULL) { + read_lock(&bond->curr_slave_lock); + slave = bond->curr_active_slave; + read_unlock(&bond->curr_slave_lock); + if (slave) { /* if we have sent traffic in the past 2*arp_intervals but - * haven't xmit and rx traffic in that time interval, select + * haven't xmit and rx traffic in that time interval, select * a different slave. slave->jiffies is only updated when - * a slave first becomes the current_slave - not necessarily - * after every arp; this ensures the slave has a full 2*delta - * before being taken out. if a primary is being used, check - * if it is up and needs to take over as the current_slave + * a slave first becomes the curr_active_slave - not necessarily + * after every arp; this ensures the slave has a full 2*delta + * before being taken out. if a primary is being used, check + * if it is up and needs to take over as the curr_active_slave */ - if ((((jiffies - slave->dev->trans_start) >= - (2*the_delta_in_ticks)) || - (((jiffies - slave->dev->last_rx) >= - (2*the_delta_in_ticks)) && (my_ip != 0))) && - ((jiffies - slave->jiffies) >= 2*the_delta_in_ticks)) { + if ((((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) || + (((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) && + my_ip)) && + ((jiffies - slave->jiffies) >= 2*delta_in_ticks)) { slave->link = BOND_LINK_DOWN; + if (slave->link_failure_count < UINT_MAX) { slave->link_failure_count++; } - printk(KERN_INFO "%s: link status down for " - "active interface %s, disabling it", - master->name, + + printk(KERN_INFO DRV_NAME + ": %s: link status down for active interface " + "%s, disabling it\n", + bond_dev->name, slave->dev->name); - write_lock(&bond->ptrlock); - reselect_active_interface(bond); - slave = bond->current_slave; - write_unlock(&bond->ptrlock); + + write_lock(&bond->curr_slave_lock); + + bond_select_active_slave(bond); + slave = bond->curr_active_slave; + + write_unlock(&bond->curr_slave_lock); + bond->current_arp_slave = slave; - if (slave != NULL) { + + if (slave) { slave->jiffies = jiffies; } - - } else if ((bond->primary_slave != NULL) && - (bond->primary_slave != slave) && + } else if ((bond->primary_slave) && + (bond->primary_slave != slave) && (bond->primary_slave->link == BOND_LINK_UP)) { - /* at this point, slave is the current_slave */ - printk(KERN_INFO - "%s: changing from interface %s to primary " + /* at this point, slave is the curr_active_slave */ + printk(KERN_INFO DRV_NAME + ": %s: changing from interface %s to primary " "interface %s\n", - master->name, - slave->dev->name, + bond_dev->name, + slave->dev->name, bond->primary_slave->dev->name); - + /* primary is up so switch to it */ - write_lock(&bond->ptrlock); - change_active_interface(bond, bond->primary_slave); - write_unlock(&bond->ptrlock); + write_lock(&bond->curr_slave_lock); + bond_change_active_slave(bond, bond->primary_slave); + write_unlock(&bond->curr_slave_lock); + slave = bond->primary_slave; slave->jiffies = jiffies; } else { @@ -2768,567 +2544,606 @@ static void activebackup_arp_monitor(str /* the current slave must tx an arp to ensure backup slaves * rx traffic */ - if ((slave != NULL) && (my_ip != 0)) { - arp_send_all(slave); + if (slave && my_ip) { + bond_arp_send_all(slave); } } - /* if we don't have a current_slave, search for the next available - * backup slave from the current_arp_slave and make it the candidate - * for becoming the current_slave + /* if we don't have a curr_active_slave, search for the next available + * backup slave from the current_arp_slave and make it the candidate + * for becoming the curr_active_slave */ - if (slave == NULL) { - - if ((bond->current_arp_slave == NULL) || - (bond->current_arp_slave == (slave_t *)bond)) { - bond->current_arp_slave = bond->prev; - } + if (!slave) { + if (!bond->current_arp_slave) { + bond->current_arp_slave = bond->first_slave; + } - if (bond->current_arp_slave != (slave_t *)bond) { + if (bond->current_arp_slave) { bond_set_slave_inactive_flags(bond->current_arp_slave); - slave = bond->current_arp_slave->next; /* search for next candidate */ - do { + bond_for_each_slave_from(bond, slave, i, bond->current_arp_slave) { if (IS_UP(slave->dev)) { slave->link = BOND_LINK_BACK; bond_set_slave_active_flags(slave); - arp_send_all(slave); + bond_arp_send_all(slave); slave->jiffies = jiffies; bond->current_arp_slave = slave; break; } - /* if the link state is up at this point, we - * mark it down - this can happen if we have - * simultaneous link failures and - * reselect_active_interface doesn't make this - * one the current slave so it is still marked + /* if the link state is up at this point, we + * mark it down - this can happen if we have + * simultaneous link failures and + * reselect_active_interface doesn't make this + * one the current slave so it is still marked * up when it is actually down */ if (slave->link == BOND_LINK_UP) { slave->link = BOND_LINK_DOWN; - if (slave->link_failure_count < - UINT_MAX) { + if (slave->link_failure_count < UINT_MAX) { slave->link_failure_count++; } bond_set_slave_inactive_flags(slave); - printk(KERN_INFO - "%s: backup interface " - "%s is now down.\n", - master->name, - slave->dev->name); + + printk(KERN_INFO DRV_NAME + ": %s: backup interface %s is " + "now down.\n", + bond_dev->name, + slave->dev->name); } - } while ((slave = slave->next) != - bond->current_arp_slave->next); + } } } +re_arm: + mod_timer(&bond->arp_timer, jiffies + delta_in_ticks); +out: read_unlock(&bond->lock); - mod_timer(&bond->arp_timer, next_timer); } -static int bond_sethwaddr(struct net_device *master, struct net_device *slave) -{ -#ifdef BONDING_DEBUG - printk(KERN_CRIT "bond_sethwaddr: master=%x\n", (unsigned int)master); - printk(KERN_CRIT "bond_sethwaddr: slave=%x\n", (unsigned int)slave); - printk(KERN_CRIT "bond_sethwaddr: slave->addr_len=%d\n", slave->addr_len); -#endif - memcpy(master->dev_addr, slave->dev_addr, slave->addr_len); - return 0; -} +/*------------------------------ proc/seq_file-------------------------------*/ -static int bond_info_query(struct net_device *master, struct ifbond *info) -{ - bonding_t *bond = (struct bonding *) master->priv; - slave_t *slave; +#ifdef CONFIG_PROC_FS - info->bond_mode = bond_mode; - info->num_slaves = 0; - info->miimon = miimon; +#define SEQ_START_TOKEN ((void *)1) +static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos) +{ + struct bonding *bond = seq->private; + loff_t off = 0; + struct slave *slave; + int i; + + /* make sure the bond won't be taken away */ + read_lock(&dev_base_lock); read_lock_bh(&bond->lock); - for (slave = bond->prev; slave != (slave_t *)bond; slave = slave->prev) { - info->num_slaves++; + + if (*pos == 0) { + return SEQ_START_TOKEN; } - read_unlock_bh(&bond->lock); - return 0; + bond_for_each_slave(bond, slave, i) { + if (++off == *pos) { + return slave; + } + } + + return NULL; } -static int bond_slave_info_query(struct net_device *master, - struct ifslave *info) +static void *bond_info_seq_next(struct seq_file *seq, void *v, loff_t *pos) { - bonding_t *bond = (struct bonding *) master->priv; - slave_t *slave; - int cur_ndx = 0; + struct bonding *bond = seq->private; + struct slave *slave = v; - if (info->slave_id < 0) { - return -ENODEV; + ++*pos; + if (v == SEQ_START_TOKEN) { + return bond->first_slave; } - read_lock_bh(&bond->lock); - for (slave = bond->prev; - slave != (slave_t *)bond && cur_ndx < info->slave_id; - slave = slave->prev) { - cur_ndx++; - } - read_unlock_bh(&bond->lock); + slave = slave->next; - if (slave != (slave_t *)bond) { - strcpy(info->slave_name, slave->dev->name); - info->link = slave->link; - info->state = slave->state; - info->link_failure_count = slave->link_failure_count; - } else { - return -ENODEV; - } + return (slave == bond->first_slave) ? NULL : slave; +} - return 0; +static void bond_info_seq_stop(struct seq_file *seq, void *v) +{ + struct bonding *bond = seq->private; + + read_unlock_bh(&bond->lock); + read_unlock(&dev_base_lock); } -static int bond_ethtool_ioctl(struct net_device *master_dev, struct ifreq *ifr) +static void bond_info_show_master(struct seq_file *seq, struct bonding *bond) { - void *addr = ifr->ifr_data; - uint32_t cmd; + struct slave *curr; - if (get_user(cmd, (uint32_t *) addr)) - return -EFAULT; + read_lock(&bond->curr_slave_lock); + curr = bond->curr_active_slave; + read_unlock(&bond->curr_slave_lock); - switch (cmd) { + seq_printf(seq, "Bonding Mode: %s\n", bond_mode_name()); - case ETHTOOL_GDRVINFO: - { - struct ethtool_drvinfo info; - char *endptr; + if (USES_PRIMARY(bond_mode)) { + if (curr) { + seq_printf(seq, + "Currently Active Slave: %s\n", + curr->dev->name); + } + } - if (copy_from_user(&info, addr, sizeof(info))) - return -EFAULT; + seq_printf(seq, "MII Status: %s\n", (curr) ? "up" : "down"); + seq_printf(seq, "MII Polling Interval (ms): %d\n", miimon); + seq_printf(seq, "Up Delay (ms): %d\n", updelay * miimon); + seq_printf(seq, "Down Delay (ms): %d\n", downdelay * miimon); - if (strcmp(info.driver, "ifenslave") == 0) { - int new_abi_ver; + if (bond_mode == BOND_MODE_8023AD) { + struct ad_info ad_info; - new_abi_ver = simple_strtoul(info.fw_version, - &endptr, 0); - if (*endptr) { - printk(KERN_ERR - "bonding: Error: got invalid ABI" - " version from application\n"); + seq_puts(seq, "\n802.3ad info\n"); - return -EINVAL; - } + if (bond_3ad_get_active_agg_info(bond, &ad_info)) { + seq_printf(seq, "bond %s has no active aggregator\n", + bond->dev->name); + } else { + seq_printf(seq, "Active Aggregator Info:\n"); - if (orig_app_abi_ver == -1) { - orig_app_abi_ver = new_abi_ver; - } + seq_printf(seq, "\tAggregator ID: %d\n", + ad_info.aggregator_id); + seq_printf(seq, "\tNumber of ports: %d\n", + ad_info.ports); + seq_printf(seq, "\tActor Key: %d\n", + ad_info.actor_key); + seq_printf(seq, "\tPartner Key: %d\n", + ad_info.partner_key); + seq_printf(seq, "\tPartner Mac Address: %02x:%02x:%02x:%02x:%02x:%02x\n", + ad_info.partner_system[0], + ad_info.partner_system[1], + ad_info.partner_system[2], + ad_info.partner_system[3], + ad_info.partner_system[4], + ad_info.partner_system[5]); + } + } +} - app_abi_ver = new_abi_ver; - } +static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave) +{ + seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name); + seq_printf(seq, "MII Status: %s\n", + (slave->link == BOND_LINK_UP) ? "up" : "down"); + seq_printf(seq, "Link Failure Count: %d\n", + slave->link_failure_count); - strncpy(info.driver, DRV_NAME, 32); - strncpy(info.version, DRV_VERSION, 32); - snprintf(info.fw_version, 32, "%d", BOND_ABI_VERSION); + if (app_abi_ver >= 1) { + seq_printf(seq, + "Permanent HW addr: %02x:%02x:%02x:%02x:%02x:%02x\n", + slave->perm_hwaddr[0], + slave->perm_hwaddr[1], + slave->perm_hwaddr[2], + slave->perm_hwaddr[3], + slave->perm_hwaddr[4], + slave->perm_hwaddr[5]); + } - if (copy_to_user(addr, &info, sizeof(info))) - return -EFAULT; + if (bond_mode == BOND_MODE_8023AD) { + const struct aggregator *agg + = SLAVE_AD_INFO(slave).port.aggregator; - return 0; + if (agg) { + seq_printf(seq, "Aggregator ID: %d\n", + agg->aggregator_identifier); + } else { + seq_puts(seq, "Aggregator ID: N/A\n"); } - break; - default: - return -EOPNOTSUPP; } } -static int bond_ioctl(struct net_device *master_dev, struct ifreq *ifr, int cmd) +static int bond_info_seq_show(struct seq_file *seq, void *v) { - struct net_device *slave_dev = NULL; - struct ifbond *u_binfo = NULL, k_binfo; - struct ifslave *u_sinfo = NULL, k_sinfo; - struct mii_ioctl_data *mii = NULL; - int prev_abi_ver = orig_app_abi_ver; - int ret = 0; + if (v == SEQ_START_TOKEN) { + seq_printf(seq, "%s\n", version); + bond_info_show_master(seq, seq->private); + } else { + bond_info_show_slave(seq, v); + } -#ifdef BONDING_DEBUG - printk(KERN_INFO "bond_ioctl: master=%s, cmd=%d\n", - master_dev->name, cmd); -#endif + return 0; +} - switch (cmd) { - case SIOCETHTOOL: - return bond_ethtool_ioctl(master_dev, ifr); +static struct seq_operations bond_info_seq_ops = { + .start = bond_info_seq_start, + .next = bond_info_seq_next, + .stop = bond_info_seq_stop, + .show = bond_info_seq_show, +}; - case SIOCGMIIPHY: - mii = (struct mii_ioctl_data *)&ifr->ifr_data; - if (mii == NULL) { - return -EINVAL; - } - mii->phy_id = 0; - /* Fall Through */ - case SIOCGMIIREG: - /* - * We do this again just in case we were called by SIOCGMIIREG - * instead of SIOCGMIIPHY. - */ - mii = (struct mii_ioctl_data *)&ifr->ifr_data; - if (mii == NULL) { - return -EINVAL; - } - if (mii->reg_num == 1) { - mii->val_out = bond_check_mii_link( - (struct bonding *)master_dev->priv); - } - return 0; - case BOND_INFO_QUERY_OLD: - case SIOCBONDINFOQUERY: - u_binfo = (struct ifbond *)ifr->ifr_data; - if (copy_from_user(&k_binfo, u_binfo, sizeof(ifbond))) { - return -EFAULT; - } - ret = bond_info_query(master_dev, &k_binfo); - if (ret == 0) { - if (copy_to_user(u_binfo, &k_binfo, sizeof(ifbond))) { - return -EFAULT; - } +static int bond_info_open(struct inode *inode, struct file *file) +{ + struct seq_file *seq; + struct proc_dir_entry *proc; + int res; + + res = seq_open(file, &bond_info_seq_ops); + if (!res) { + /* recover the pointer buried in proc_dir_entry data */ + seq = file->private_data; + proc = PDE(inode); + seq->private = proc->data; + } + + return res; +} + +static struct file_operations bond_info_fops = { + .owner = THIS_MODULE, + .open = bond_info_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int bond_create_proc_entry(struct bonding *bond) +{ + struct net_device *bond_dev = bond->dev; + + if (bond_proc_dir) { + bond->proc_entry = create_proc_entry(bond_dev->name, + S_IRUGO, + bond_proc_dir); + if (bond->proc_entry == NULL) { + printk(KERN_WARNING DRV_NAME + ": Warning: Cannot create /proc/net/%s/%s\n", + DRV_NAME, bond_dev->name); + } else { + bond->proc_entry->data = bond; + bond->proc_entry->proc_fops = &bond_info_fops; + bond->proc_entry->owner = THIS_MODULE; + memcpy(bond->proc_file_name, bond_dev->name, IFNAMSIZ); } - return ret; - case BOND_SLAVE_INFO_QUERY_OLD: - case SIOCBONDSLAVEINFOQUERY: - u_sinfo = (struct ifslave *)ifr->ifr_data; - if (copy_from_user(&k_sinfo, u_sinfo, sizeof(ifslave))) { - return -EFAULT; + } + + return 0; +} + +static void bond_remove_proc_entry(struct bonding *bond) +{ + if (bond_proc_dir && bond->proc_entry) { + remove_proc_entry(bond->proc_file_name, bond_proc_dir); + memset(bond->proc_file_name, 0, IFNAMSIZ); + bond->proc_entry = NULL; + } +} + +/* Create the bonding directory under /proc/net, if doesn't exist yet. + * Caller must hold rtnl_lock. + */ +static void bond_create_proc_dir(void) +{ + int len = strlen(DRV_NAME); + + for (bond_proc_dir = proc_net->subdir; bond_proc_dir; + bond_proc_dir = bond_proc_dir->next) { + if ((bond_proc_dir->namelen == len) && + !memcmp(bond_proc_dir->name, DRV_NAME, len)) { + break; } - ret = bond_slave_info_query(master_dev, &k_sinfo); - if (ret == 0) { - if (copy_to_user(u_sinfo, &k_sinfo, sizeof(ifslave))) { - return -EFAULT; - } + } + + if (!bond_proc_dir) { + bond_proc_dir = proc_mkdir(DRV_NAME, proc_net); + if (bond_proc_dir) { + bond_proc_dir->owner = THIS_MODULE; + } else { + printk(KERN_WARNING DRV_NAME + ": Warning: cannot create /proc/net/%s\n", + DRV_NAME); } - return ret; } +} - if (!capable(CAP_NET_ADMIN)) { - return -EPERM; +/* Destroy the bonding directory under /proc/net, if empty. + * Caller must hold rtnl_lock. + */ +static void bond_destroy_proc_dir(void) +{ + struct proc_dir_entry *de; + + if (!bond_proc_dir) { + return; } - if (orig_app_abi_ver == -1) { - /* no orig_app_abi_ver was provided yet, so we'll use the - * current one from now on, even if it's 0 - */ - orig_app_abi_ver = app_abi_ver; + /* verify that the /proc dir is empty */ + for (de = bond_proc_dir->subdir; de; de = de->next) { + /* ignore . and .. */ + if (*(de->name) != '.') { + break; + } + } - } else if (orig_app_abi_ver != app_abi_ver) { - printk(KERN_ERR - "bonding: Error: already using ifenslave ABI " - "version %d; to upgrade ifenslave to version %d, " - "you must first reload bonding.\n", - orig_app_abi_ver, app_abi_ver); - return -EINVAL; + if (de) { + if (bond_proc_dir->owner == THIS_MODULE) { + bond_proc_dir->owner = NULL; + } + } else { + remove_proc_entry(DRV_NAME, proc_net); + bond_proc_dir = NULL; } +} +#endif /* CONFIG_PROC_FS */ - slave_dev = dev_get_by_name(ifr->ifr_slave); +/*-------------------------- netdev event handling --------------------------*/ -#ifdef BONDING_DEBUG - printk(KERN_INFO "slave_dev=%x: \n", (unsigned int)slave_dev); - printk(KERN_INFO "slave_dev->name=%s: \n", slave_dev->name); +/* + * Change device name + */ +static int bond_event_changename(struct bonding *bond) +{ +#ifdef CONFIG_PROC_FS + bond_remove_proc_entry(bond); + bond_create_proc_entry(bond); #endif - if (slave_dev == NULL) { - ret = -ENODEV; - } else { - switch (cmd) { - case BOND_ENSLAVE_OLD: - case SIOCBONDENSLAVE: - ret = bond_enslave(master_dev, slave_dev); - break; - case BOND_RELEASE_OLD: - case SIOCBONDRELEASE: - ret = bond_release(master_dev, slave_dev); - break; - case BOND_SETHWADDR_OLD: - case SIOCBONDSETHWADDR: - ret = bond_sethwaddr(master_dev, slave_dev); - break; - case BOND_CHANGE_ACTIVE_OLD: - case SIOCBONDCHANGEACTIVE: - if (USES_PRIMARY(bond_mode)) { - ret = bond_change_active(master_dev, slave_dev); - } - else { - ret = -EINVAL; - } - break; - default: - ret = -EOPNOTSUPP; - } - dev_put(slave_dev); + return NOTIFY_DONE; +} + +static int bond_master_netdev_event(unsigned long event, struct net_device *bond_dev) +{ + struct bonding *event_bond = bond_dev->priv; + + switch (event) { + case NETDEV_CHANGENAME: + return bond_event_changename(event_bond); + case NETDEV_UNREGISTER: + /* + * TODO: remove a bond from the list? + */ + break; + default: + break; } - if (ret < 0) { - /* The ioctl failed, so there's no point in changing the - * orig_app_abi_ver. We'll restore it's value just in case - * we've changed it earlier in this function. + return NOTIFY_DONE; +} + +static int bond_slave_netdev_event(unsigned long event, struct net_device *slave_dev) +{ + struct net_device *bond_dev = slave_dev->master; + + switch (event) { + case NETDEV_UNREGISTER: + if (bond_dev) { + bond_release(bond_dev, slave_dev); + } + break; + case NETDEV_CHANGE: + /* + * TODO: is this what we get if somebody + * sets up a hierarchical bond, then rmmod's + * one of the slave bonding devices? + */ + break; + case NETDEV_DOWN: + /* + * ... Or is it this? + */ + break; + case NETDEV_CHANGEMTU: + /* + * TODO: Should slaves be allowed to + * independently alter their MTU? For + * an active-backup bond, slaves need + * not be the same type of device, so + * MTUs may vary. For other modes, + * slaves arguably should have the + * same MTUs. To do this, we'd need to + * take over the slave's change_mtu + * function for the duration of their + * servitude. + */ + break; + case NETDEV_CHANGENAME: + /* + * TODO: handle changing the primary's name */ - orig_app_abi_ver = prev_abi_ver; + break; + default: + break; } - return ret; -} - -#ifdef CONFIG_NET_FASTROUTE -static int bond_accept_fastpath(struct net_device *dev, struct dst_entry *dst) -{ - return -1; + return NOTIFY_DONE; } -#endif -/* - * in broadcast mode, we send everything to all usable interfaces. +/* + * bond_netdev_event: handle netdev notifier chain events. + * + * This function receives events for the netdev chain. The caller (an + * ioctl handler calling notifier_call_chain) holds the necessary + * locks for us to safely manipulate the slave devices (RTNL lock, + * dev_probe_lock). */ -static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *dev) +static int bond_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) { - slave_t *slave, *start_at; - struct bonding *bond = (struct bonding *) dev->priv; - struct net_device *device_we_should_send_to = 0; + struct net_device *event_dev = (struct net_device *)ptr; - if (!IS_UP(dev)) { /* bond down */ - dev_kfree_skb(skb); - return 0; + dprintk("event_dev: %s, event: %lx\n", + (event_dev ? event_dev->name : "None"), + event); + + if (event_dev->flags & IFF_MASTER) { + dprintk("IFF_MASTER\n"); + return bond_master_netdev_event(event, event_dev); } - read_lock(&bond->lock); - - read_lock(&bond->ptrlock); - slave = start_at = bond->current_slave; - read_unlock(&bond->ptrlock); - - if (slave == NULL) { /* we're at the root, get the first slave */ - /* no suitable interface, frame not sent */ - read_unlock(&bond->lock); - dev_kfree_skb(skb); - return 0; + if (event_dev->flags & IFF_SLAVE) { + dprintk("IFF_SLAVE\n"); + return bond_slave_netdev_event(event, event_dev); } - do { - if (IS_UP(slave->dev) - && (slave->link == BOND_LINK_UP) - && (slave->state == BOND_STATE_ACTIVE)) { - if (device_we_should_send_to) { - struct sk_buff *skb2; - if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) { - printk(KERN_ERR "bond_xmit_broadcast: skb_clone() failed\n"); - continue; - } - - skb2->dev = device_we_should_send_to; - skb2->priority = 1; - dev_queue_xmit(skb2); - } - device_we_should_send_to = slave->dev; - } - } while ((slave = slave->next) != start_at); + return NOTIFY_DONE; +} - if (device_we_should_send_to) { - skb->dev = device_we_should_send_to; - skb->priority = 1; - dev_queue_xmit(skb); - } else - dev_kfree_skb(skb); +static struct notifier_block bond_netdev_notifier = { + .notifier_call = bond_netdev_event, +}; - /* frame sent to all suitable interfaces */ - read_unlock(&bond->lock); - return 0; -} +/*-------------------------- Packet type handling ---------------------------*/ -static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *dev) +/* register to receive lacpdus on a bond */ +static void bond_register_lacpdu(struct bonding *bond) { - slave_t *slave, *start_at; - struct bonding *bond = (struct bonding *) dev->priv; + struct packet_type *pk_type = &(BOND_AD_INFO(bond).ad_pkt_type); - if (!IS_UP(dev)) { /* bond down */ - dev_kfree_skb(skb); - return 0; - } + /* initialize packet type */ + pk_type->type = PKT_TYPE_LACPDU; + pk_type->dev = bond->dev; + pk_type->func = bond_3ad_lacpdu_recv; - read_lock(&bond->lock); + dev_add_pack(pk_type); +} - read_lock(&bond->ptrlock); - slave = start_at = bond->current_slave; - read_unlock(&bond->ptrlock); - - if (slave == NULL) { /* we're at the root, get the first slave */ - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; - } +/* unregister to receive lacpdus on a bond */ +static void bond_unregister_lacpdu(struct bonding *bond) +{ + dev_remove_pack(&(BOND_AD_INFO(bond).ad_pkt_type)); +} - do { - if (IS_UP(slave->dev) - && (slave->link == BOND_LINK_UP) - && (slave->state == BOND_STATE_ACTIVE)) { +/*-------------------------- Device entry points ----------------------------*/ - skb->dev = slave->dev; - skb->priority = 1; - dev_queue_xmit(skb); +static int bond_open(struct net_device *bond_dev) +{ + struct bonding *bond = bond_dev->priv; + struct timer_list *mii_timer = &bond->mii_timer; + struct timer_list *arp_timer = &bond->arp_timer; + + bond->kill_timers = 0; - write_lock(&bond->ptrlock); - bond->current_slave = slave->next; - write_unlock(&bond->ptrlock); + if ((bond_mode == BOND_MODE_TLB) || + (bond_mode == BOND_MODE_ALB)) { + struct timer_list *alb_timer = &(BOND_ALB_INFO(bond).alb_timer); - read_unlock(&bond->lock); - return 0; + /* bond_alb_initialize must be called before the timer + * is started. + */ + if (bond_alb_initialize(bond, (bond_mode == BOND_MODE_ALB))) { + /* something went wrong - fail the open operation */ + return -1; } - } while ((slave = slave->next) != start_at); - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; -} + init_timer(alb_timer); + alb_timer->expires = jiffies + 1; + alb_timer->data = (unsigned long)bond; + alb_timer->function = (void *)&bond_alb_monitor; + add_timer(alb_timer); + } -/* - * in XOR mode, we determine the output device by performing xor on - * the source and destination hw adresses. If this device is not - * enabled, find the next slave following this xor slave. - */ -static int bond_xmit_xor(struct sk_buff *skb, struct net_device *dev) -{ - slave_t *slave, *start_at; - struct bonding *bond = (struct bonding *) dev->priv; - struct ethhdr *data = (struct ethhdr *)skb->data; - int slave_no; + if (miimon) { /* link check interval, in milliseconds. */ + init_timer(mii_timer); + mii_timer->expires = jiffies + 1; + mii_timer->data = (unsigned long)bond_dev; + mii_timer->function = (void *)&bond_mii_monitor; + add_timer(mii_timer); + } - if (!IS_UP(dev)) { /* bond down */ - dev_kfree_skb(skb); - return 0; + if (arp_interval) { /* arp interval, in milliseconds. */ + init_timer(arp_timer); + arp_timer->expires = jiffies + 1; + arp_timer->data = (unsigned long)bond_dev; + if (bond_mode == BOND_MODE_ACTIVEBACKUP) { + arp_timer->function = (void *)&bond_activebackup_arp_mon; + } else { + arp_timer->function = (void *)&bond_loadbalance_arp_mon; + } + add_timer(arp_timer); } - read_lock(&bond->lock); - slave = bond->prev; + if (bond_mode == BOND_MODE_8023AD) { + struct timer_list *ad_timer = &(BOND_AD_INFO(bond).ad_timer); + init_timer(ad_timer); + ad_timer->expires = jiffies + 1; + ad_timer->data = (unsigned long)bond; + ad_timer->function = (void *)&bond_3ad_state_machine_handler; + add_timer(ad_timer); - /* we're at the root, get the first slave */ - if (bond->slave_cnt == 0) { - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; + /* register to receive LACPDUs */ + bond_register_lacpdu(bond); } - slave_no = (data->h_dest[5]^slave->dev->dev_addr[5]) % bond->slave_cnt; + return 0; +} - while ( (slave_no > 0) && (slave != (slave_t *)bond) ) { - slave = slave->prev; - slave_no--; - } - start_at = slave; +static int bond_close(struct net_device *bond_dev) +{ + struct bonding *bond = bond_dev->priv; - do { - if (IS_UP(slave->dev) - && (slave->link == BOND_LINK_UP) - && (slave->state == BOND_STATE_ACTIVE)) { + write_lock_bh(&bond->lock); - skb->dev = slave->dev; - skb->priority = 1; - dev_queue_xmit(skb); + bond_mc_list_destroy(bond); - read_unlock(&bond->lock); - return 0; - } - } while ((slave = slave->next) != start_at); + if (bond_mode == BOND_MODE_8023AD) { + /* Unregister the receive of LACPDUs */ + bond_unregister_lacpdu(bond); + } - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; -} + /* signal timers not to re-arm */ + bond->kill_timers = 1; -/* - * in active-backup mode, we know that bond->current_slave is always valid if - * the bond has a usable interface. - */ -static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *dev) -{ - struct bonding *bond = (struct bonding *) dev->priv; - int ret; + write_unlock_bh(&bond->lock); - if (!IS_UP(dev)) { /* bond down */ - dev_kfree_skb(skb); - return 0; + /* del_timer_sync must run without holding the bond->lock + * because a running timer might be trying to hold it too + */ + + if (miimon) { /* link check interval, in milliseconds. */ + del_timer_sync(&bond->mii_timer); } - /* if we are sending arp packets, try to at least - identify our own ip address */ - if ( (arp_interval > 0) && (my_ip == 0) && - (skb->protocol == __constant_htons(ETH_P_ARP) ) ) { - char *the_ip = (((char *)skb->data)) - + sizeof(struct ethhdr) - + sizeof(struct arphdr) + - ETH_ALEN; - memcpy(&my_ip, the_ip, 4); + if (arp_interval) { /* arp interval, in milliseconds. */ + del_timer_sync(&bond->arp_timer); } - /* if we are sending arp packets and don't know - * the target hw address, save it so we don't need - * to use a broadcast address. - * don't do this if in active backup mode because the slaves must - * receive packets to stay up, and the only ones they receive are - * broadcasts. - */ - if ( (bond_mode != BOND_MODE_ACTIVEBACKUP) && - (arp_ip_count == 1) && - (arp_interval > 0) && (arp_target_hw_addr == NULL) && - (skb->protocol == __constant_htons(ETH_P_IP) ) ) { - struct ethhdr *eth_hdr = - (struct ethhdr *) (((char *)skb->data)); - struct iphdr *ip_hdr = (struct iphdr *)(eth_hdr + 1); - - if (arp_target[0] == ip_hdr->daddr) { - arp_target_hw_addr = kmalloc(ETH_ALEN, GFP_KERNEL); - if (arp_target_hw_addr != NULL) - memcpy(arp_target_hw_addr, eth_hdr->h_dest, ETH_ALEN); - } + switch (bond_mode) { + case BOND_MODE_8023AD: + del_timer_sync(&(BOND_AD_INFO(bond).ad_timer)); + break; + case BOND_MODE_TLB: + case BOND_MODE_ALB: + del_timer_sync(&(BOND_ALB_INFO(bond).alb_timer)); + break; + default: + break; } - read_lock(&bond->lock); + /* Release the bonded slaves */ + bond_release_all(bond_dev); - read_lock(&bond->ptrlock); - if (bond->current_slave != NULL) { /* one usable interface */ - skb->dev = bond->current_slave->dev; - read_unlock(&bond->ptrlock); - skb->priority = 1; - ret = dev_queue_xmit(skb); - read_unlock(&bond->lock); - return 0; - } - else { - read_unlock(&bond->ptrlock); + if ((bond_mode == BOND_MODE_TLB) || + (bond_mode == BOND_MODE_ALB)) { + /* Must be called only after all + * slaves have been released + */ + bond_alb_deinitialize(bond); } - /* no suitable interface, frame not sent */ -#ifdef BONDING_DEBUG - printk(KERN_INFO "There was no suitable interface, so we don't transmit\n"); -#endif - dev_kfree_skb(skb); - read_unlock(&bond->lock); return 0; } -static struct net_device_stats *bond_get_stats(struct net_device *dev) +static struct net_device_stats *bond_get_stats(struct net_device *bond_dev) { - bonding_t *bond = dev->priv; + struct bonding *bond = bond_dev->priv; struct net_device_stats *stats = &(bond->stats), *sstats; - slave_t *slave; + struct slave *slave; + int i; memset(stats, 0, sizeof(struct net_device_stats)); read_lock_bh(&bond->lock); - for (slave = bond->prev; slave != (slave_t *)bond; slave = slave->prev) { + bond_for_each_slave(bond, slave, i) { sstats = slave->dev->get_stats(slave->dev); - + stats->rx_packets += sstats->rx_packets; stats->rx_bytes += sstats->rx_bytes; stats->rx_errors += sstats->rx_errors; @@ -3346,290 +3161,294 @@ static struct net_device_stats *bond_get stats->rx_over_errors += sstats->rx_over_errors; stats->rx_crc_errors += sstats->rx_crc_errors; stats->rx_frame_errors += sstats->rx_frame_errors; - stats->rx_fifo_errors += sstats->rx_fifo_errors; + stats->rx_fifo_errors += sstats->rx_fifo_errors; stats->rx_missed_errors += sstats->rx_missed_errors; - + stats->tx_aborted_errors += sstats->tx_aborted_errors; stats->tx_carrier_errors += sstats->tx_carrier_errors; stats->tx_fifo_errors += sstats->tx_fifo_errors; stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors; stats->tx_window_errors += sstats->tx_window_errors; - } read_unlock_bh(&bond->lock); + return stats; } -#ifdef CONFIG_PROC_FS - -#define SEQ_START_TOKEN ((void *)1) - -static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos) +static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd) { - struct bonding *bond = seq->private; - loff_t off = 0; - struct slave *slave; - - /* make sure the bond won't be taken away */ - read_lock(&dev_base_lock); - read_lock_bh(&bond->lock); - - if (*pos == 0) { - return SEQ_START_TOKEN; - } + struct net_device *slave_dev = NULL; + struct ifbond *u_binfo = NULL, k_binfo; + struct ifslave *u_sinfo = NULL, k_sinfo; + struct mii_ioctl_data *mii = NULL; + int prev_abi_ver = orig_app_abi_ver; + int res = 0; - for (slave = bond->prev; slave != (slave_t *)bond; - slave = slave->prev) { + dprintk("bond_ioctl: master=%s, cmd=%d\n", + bond_dev->name, cmd); - if (++off == *pos) { - return slave; + switch (cmd) { + case SIOCETHTOOL: + return bond_ethtool_ioctl(bond_dev, ifr); + case SIOCGMIIPHY: + mii = (struct mii_ioctl_data *)&ifr->ifr_data; + if (!mii) { + return -EINVAL; + } + mii->phy_id = 0; + /* Fall Through */ + case SIOCGMIIREG: + /* + * We do this again just in case we were called by SIOCGMIIREG + * instead of SIOCGMIIPHY. + */ + mii = (struct mii_ioctl_data *)&ifr->ifr_data; + if (!mii) { + return -EINVAL; } - } - - return NULL; -} - -static void *bond_info_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct bonding *bond = seq->private; - struct slave *slave = v; - - ++*pos; - if (v == SEQ_START_TOKEN) { - slave = bond->prev; - } else { - slave = slave->prev; - } - - return (slave == (struct slave *) bond) ? NULL : slave; -} - -static void bond_info_seq_stop(struct seq_file *seq, void *v) -{ - struct bonding *bond = seq->private; - - read_unlock_bh(&bond->lock); - read_unlock(&dev_base_lock); -} - -static void bond_info_show_master(struct seq_file *seq, struct bonding *bond) -{ - struct slave *curr; - read_lock(&bond->ptrlock); - curr = bond->current_slave; - read_unlock(&bond->ptrlock); + if (mii->reg_num == 1) { + struct bonding *bond = bond_dev->priv; + mii->val_out = 0; + read_lock_bh(&bond->lock); + read_lock(&bond->curr_slave_lock); + if (bond->curr_active_slave) { + mii->val_out = BMSR_LSTATUS; + } + read_unlock(&bond->curr_slave_lock); + read_unlock_bh(&bond->lock); + } - seq_printf(seq, "Bonding Mode: %s\n", bond_mode_name()); + return 0; + case BOND_INFO_QUERY_OLD: + case SIOCBONDINFOQUERY: + u_binfo = (struct ifbond *)ifr->ifr_data; - if (USES_PRIMARY(bond_mode)) { - if (curr) { - seq_printf(seq, - "Currently Active Slave: %s\n", - curr->dev->name); + if (copy_from_user(&k_binfo, u_binfo, sizeof(ifbond))) { + return -EFAULT; } - } - - seq_printf(seq, "MII Status: %s\n", (curr) ? "up" : "down"); - seq_printf(seq, "MII Polling Interval (ms): %d\n", miimon); - seq_printf(seq, "Up Delay (ms): %d\n", updelay * miimon); - seq_printf(seq, "Down Delay (ms): %d\n", downdelay * miimon); - seq_printf(seq, "Multicast Mode: %s\n", multicast_mode_name()); - if (bond_mode == BOND_MODE_8023AD) { - struct ad_info ad_info; + res = bond_info_query(bond_dev, &k_binfo); + if (res == 0) { + if (copy_to_user(u_binfo, &k_binfo, sizeof(ifbond))) { + return -EFAULT; + } + } - seq_puts(seq, "\n802.3ad info\n"); + return res; + case BOND_SLAVE_INFO_QUERY_OLD: + case SIOCBONDSLAVEINFOQUERY: + u_sinfo = (struct ifslave *)ifr->ifr_data; - if (bond_3ad_get_active_agg_info(bond, &ad_info)) { - seq_printf(seq, "bond %s has no active aggregator\n", - bond->device->name); - } else { - seq_printf(seq, "Active Aggregator Info:\n"); + if (copy_from_user(&k_sinfo, u_sinfo, sizeof(ifslave))) { + return -EFAULT; + } - seq_printf(seq, "\tAggregator ID: %d\n", - ad_info.aggregator_id); - seq_printf(seq, "\tNumber of ports: %d\n", - ad_info.ports); - seq_printf(seq, "\tActor Key: %d\n", - ad_info.actor_key); - seq_printf(seq, "\tPartner Key: %d\n", - ad_info.partner_key); - seq_printf(seq, "\tPartner Mac Address: %02x:%02x:%02x:%02x:%02x:%02x\n", - ad_info.partner_system[0], - ad_info.partner_system[1], - ad_info.partner_system[2], - ad_info.partner_system[3], - ad_info.partner_system[4], - ad_info.partner_system[5]); + res = bond_slave_info_query(bond_dev, &k_sinfo); + if (res == 0) { + if (copy_to_user(u_sinfo, &k_sinfo, sizeof(ifslave))) { + return -EFAULT; + } } + + return res; + default: + /* Go on */ + break; } -} -static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave) -{ - seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name); - seq_printf(seq, "MII Status: %s\n", - (slave->link == BOND_LINK_UP) ? "up" : "down"); - seq_printf(seq, "Link Failure Count: %d\n", - slave->link_failure_count); + if (!capable(CAP_NET_ADMIN)) { + return -EPERM; + } - if (app_abi_ver >= 1) { - seq_printf(seq, - "Permanent HW addr: %02x:%02x:%02x:%02x:%02x:%02x\n", - slave->perm_hwaddr[0], - slave->perm_hwaddr[1], - slave->perm_hwaddr[2], - slave->perm_hwaddr[3], - slave->perm_hwaddr[4], - slave->perm_hwaddr[5]); + if (orig_app_abi_ver == -1) { + /* no orig_app_abi_ver was provided yet, so we'll use the + * current one from now on, even if it's 0 + */ + orig_app_abi_ver = app_abi_ver; + + } else if (orig_app_abi_ver != app_abi_ver) { + printk(KERN_ERR DRV_NAME + ": Error: already using ifenslave ABI version %d; to " + "upgrade ifenslave to version %d, you must first " + "reload bonding.\n", + orig_app_abi_ver, app_abi_ver); + return -EINVAL; } - if (bond_mode == BOND_MODE_8023AD) { - const struct aggregator *agg - = SLAVE_AD_INFO(slave).port.aggregator; + slave_dev = dev_get_by_name(ifr->ifr_slave); - if (agg) { - seq_printf(seq, "Aggregator ID: %d\n", - agg->aggregator_identifier); - } else { - seq_puts(seq, "Aggregator ID: N/A\n"); + dprintk("slave_dev=%p: \n", slave_dev); + + if (!slave_dev) { + res = -ENODEV; + } else { + dprintk("slave_dev->name=%s: \n", slave_dev->name); + switch (cmd) { + case BOND_ENSLAVE_OLD: + case SIOCBONDENSLAVE: + res = bond_enslave(bond_dev, slave_dev); + break; + case BOND_RELEASE_OLD: + case SIOCBONDRELEASE: + res = bond_release(bond_dev, slave_dev); + break; + case BOND_SETHWADDR_OLD: + case SIOCBONDSETHWADDR: + res = bond_sethwaddr(bond_dev, slave_dev); + break; + case BOND_CHANGE_ACTIVE_OLD: + case SIOCBONDCHANGEACTIVE: + if (USES_PRIMARY(bond_mode)) { + res = bond_ioctl_change_active(bond_dev, slave_dev); + } else { + res = -EINVAL; + } + break; + default: + res = -EOPNOTSUPP; } + + dev_put(slave_dev); } -} -static int bond_info_seq_show(struct seq_file *seq, void *v) -{ - if (v == SEQ_START_TOKEN) { - seq_printf(seq, "%s\n", version); - bond_info_show_master(seq, seq->private); - } else { - bond_info_show_slave(seq, v); + if (res < 0) { + /* The ioctl failed, so there's no point in changing the + * orig_app_abi_ver. We'll restore it's value just in case + * we've changed it earlier in this function. + */ + orig_app_abi_ver = prev_abi_ver; } - return 0; + return res; } -static struct seq_operations bond_info_seq_ops = { - .start = bond_info_seq_start, - .next = bond_info_seq_next, - .stop = bond_info_seq_stop, - .show = bond_info_seq_show, -}; - -static int bond_info_open(struct inode *inode, struct file *file) +static void bond_set_multicast_list(struct net_device *bond_dev) { - struct seq_file *seq; - struct proc_dir_entry *proc; - int rc; - - rc = seq_open(file, &bond_info_seq_ops); - if (!rc) { - /* recover the pointer buried in proc_dir_entry data */ - seq = file->private_data; - proc = PDE(inode); - seq->private = proc->data; - } - return rc; -} + struct bonding *bond = bond_dev->priv; + struct dev_mc_list *dmi; -static struct file_operations bond_info_fops = { - .owner = THIS_MODULE, - .open = bond_info_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; + write_lock_bh(&bond->lock); -static int bond_create_proc_info(struct bonding *bond) -{ - struct net_device *dev = bond->device; + /* + * Do promisc before checking multicast_mode + */ + if ((bond_dev->flags & IFF_PROMISC) && !(bond->flags & IFF_PROMISC)) { + bond_set_promiscuity(bond, 1); + } - if (bond_proc_dir) { - bond->bond_proc_file = create_proc_entry(dev->name, - S_IRUGO, - bond_proc_dir); - if (bond->bond_proc_file == NULL) { - printk(KERN_WARNING - "%s: Cannot create /proc/net/bonding/%s\n", - dev->name, dev->name); - } else { - bond->bond_proc_file->data = bond; - bond->bond_proc_file->proc_fops = &bond_info_fops; - bond->bond_proc_file->owner = THIS_MODULE; - memcpy(bond->procdir_name, dev->name, IFNAMSIZ); - } + if (!(bond_dev->flags & IFF_PROMISC) && (bond->flags & IFF_PROMISC)) { + bond_set_promiscuity(bond, -1); } - return 0; -} + /* set allmulti flag to slaves */ + if ((bond_dev->flags & IFF_ALLMULTI) && !(bond->flags & IFF_ALLMULTI)) { + bond_set_allmulti(bond, 1); + } -static void bond_destroy_proc_info(struct bonding *bond) -{ - if (bond_proc_dir && bond->bond_proc_file) { - remove_proc_entry(bond->procdir_name, bond_proc_dir); - memset(bond->procdir_name, 0, IFNAMSIZ); - bond->bond_proc_file = NULL; + if (!(bond_dev->flags & IFF_ALLMULTI) && (bond->flags & IFF_ALLMULTI)) { + bond_set_allmulti(bond, -1); } -} -/* Create the bonding directory under /proc/net, if doesn't exist yet. - * Caller must hold rtnl_lock. - */ -static void bond_create_proc_dir(void) -{ - int len = strlen(DRV_NAME); + bond->flags = bond_dev->flags; - for (bond_proc_dir = proc_net->subdir; bond_proc_dir; - bond_proc_dir = bond_proc_dir->next) { - if ((bond_proc_dir->namelen == len) && - !memcmp(bond_proc_dir->name, DRV_NAME, len)) { - break; + /* looking for addresses to add to slaves' mc list */ + for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) { + if (!bond_mc_list_find_dmi(dmi, bond->mc_list)) { + bond_mc_add(bond, dmi->dmi_addr, dmi->dmi_addrlen); } } - if (!bond_proc_dir) { - bond_proc_dir = proc_mkdir(DRV_NAME, proc_net); - if (bond_proc_dir) { - bond_proc_dir->owner = THIS_MODULE; - } else { - printk(KERN_WARNING DRV_NAME - ": Warning: cannot create /proc/net/%s\n", - DRV_NAME); + /* looking for addresses to delete from slaves' list */ + for (dmi = bond->mc_list; dmi; dmi = dmi->next) { + if (!bond_mc_list_find_dmi(dmi, bond_dev->mc_list)) { + bond_mc_delete(bond, dmi->dmi_addr, dmi->dmi_addrlen); } } + + /* save master's multicast list */ + bond_mc_list_destroy(bond); + bond_mc_list_copy(bond_dev->mc_list, bond, GFP_ATOMIC); + + write_unlock_bh(&bond->lock); } -/* Destroy the bonding directory under /proc/net, if empty. - * Caller must hold rtnl_lock. +/* + * Change the MTU of all of a master's slaves to match the master */ -static void bond_destroy_proc_dir(void) +static int bond_change_mtu(struct net_device *bond_dev, int new_mtu) { - struct proc_dir_entry *de; + struct bonding *bond = bond_dev->priv; + struct slave *slave, *stop_at; + int res = 0; + int i; - if (!bond_proc_dir) { - return; - } + dprintk("bond=%p, name=%s, new_mtu=%d\n", bond, + (bond_dev ? bond_dev->name : "None"), new_mtu); - /* verify that the /proc dir is empty */ - for (de = bond_proc_dir->subdir; de; de = de->next) { - /* ignore . and .. */ - if (*(de->name) != '.') { - break; + /* Can't hold bond->lock with bh disabled here since + * some base drivers panic. On the other hand we can't + * hold bond->lock without bh disabled because we'll + * deadlock. The only solution is to rely on the fact + * that we're under rtnl_lock here, and the slaves + * list won't change. This doesn't solve the problem + * of setting the slave's MTU while it is + * transmitting, but the assumption is that the base + * driver can handle that. + * + * TODO: figure out a way to safely iterate the slaves + * list, but without holding a lock around the actual + * call to the base driver. + */ + + bond_for_each_slave(bond, slave, i) { + dprintk("s %p s->p %p c_m %p\n", slave, + slave->prev, slave->dev->change_mtu); + if (slave->dev->change_mtu) { + res = slave->dev->change_mtu(slave->dev, new_mtu); + } else { + slave->dev->mtu = new_mtu; + res = 0; + } + + if (res) { + /* If we failed to set the slave's mtu to the new value + * we must abort the operation even in ACTIVE_BACKUP + * mode, because if we allow the backup slaves to have + * different mtu values than the active slave we'll + * need to change their mtu when doing a failover. That + * means changing their mtu from timer context, which + * is probably not a good idea. + */ + dprintk("err %d %s\n", res, slave->dev->name); + goto unwind; } } - if (de) { - if (bond_proc_dir->owner == THIS_MODULE) { - bond_proc_dir->owner = NULL; + bond_dev->mtu = new_mtu; + + return 0; + +unwind: + /* unwind from head to the slave that failed */ + stop_at = slave; + bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) { + int tmp_res; + + if (slave->dev->change_mtu) { + tmp_res = slave->dev->change_mtu(slave->dev, bond_dev->mtu); + if (tmp_res) { + dprintk("unwind err %d dev %s\n", tmp_res, + slave->dev->name); + } + } else { + slave->dev->mtu = bond_dev->mtu; } - } else { - remove_proc_entry(DRV_NAME, proc_net); - bond_proc_dir = NULL; } + + return res; } -#endif /* CONFIG_PROC_FS */ /* * Change HW address @@ -3638,352 +3457,366 @@ static void bond_destroy_proc_dir(void) * downing the master releases all slaves. We can make bonds full of * bonding devices to test this, however. */ -static inline int -bond_set_mac_address(struct net_device *dev, void *addr) +static int bond_set_mac_address(struct net_device *bond_dev, void *addr) { - struct bonding *bond = dev->priv; + struct bonding *bond = bond_dev->priv; struct sockaddr *sa = addr, tmp_sa; - struct slave *slave; - int error; + struct slave *slave, *stop_at; + int res = 0; + int i; - dprintk(KERN_INFO "bond_set_mac_address %p %s\n", dev, - dev->name); + dprintk("bond=%p, name=%s\n", bond, (bond_dev ? bond_dev->name : "None")); if (!is_valid_ether_addr(sa->sa_data)) { return -EADDRNOTAVAIL; } - for (slave = bond->prev; slave != (struct slave *)bond; - slave = slave->prev) { - dprintk(KERN_INFO "bond_set_mac: slave %p %s\n", slave, - slave->dev->name); + /* Can't hold bond->lock with bh disabled here since + * some base drivers panic. On the other hand we can't + * hold bond->lock without bh disabled because we'll + * deadlock. The only solution is to rely on the fact + * that we're under rtnl_lock here, and the slaves + * list won't change. This doesn't solve the problem + * of setting the slave's hw address while it is + * transmitting, but the assumption is that the base + * driver can handle that. + * + * TODO: figure out a way to safely iterate the slaves + * list, but without holding a lock around the actual + * call to the base driver. + */ + + bond_for_each_slave(bond, slave, i) { + dprintk("slave %p %s\n", slave, slave->dev->name); + if (slave->dev->set_mac_address == NULL) { - error = -EOPNOTSUPP; - dprintk(KERN_INFO "bond_set_mac EOPNOTSUPP %s\n", - slave->dev->name); + res = -EOPNOTSUPP; + dprintk("EOPNOTSUPP %s\n", slave->dev->name); goto unwind; } - error = slave->dev->set_mac_address(slave->dev, addr); - if (error) { - /* TODO: consider downing the slave + res = slave->dev->set_mac_address(slave->dev, addr); + if (res) { + /* TODO: consider downing the slave * and retry ? * User should expect communications * breakage anyway until ARP finish * updating, so... */ - dprintk(KERN_INFO "bond_set_mac err %d %s\n", - error, slave->dev->name); + dprintk("err %d %s\n", res, slave->dev->name); goto unwind; } } /* success */ - memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); + memcpy(bond_dev->dev_addr, sa->sa_data, bond_dev->addr_len); return 0; unwind: - memcpy(tmp_sa.sa_data, dev->dev_addr, dev->addr_len); - tmp_sa.sa_family = dev->type; - - for (slave = slave->next; slave != bond->next; - slave = slave->next) { - int tmp_error; + memcpy(tmp_sa.sa_data, bond_dev->dev_addr, bond_dev->addr_len); + tmp_sa.sa_family = bond_dev->type; - tmp_error = slave->dev->set_mac_address(slave->dev, &tmp_sa); - if (tmp_error) { - dprintk(KERN_INFO "bond_set_mac_address: " - "unwind err %d dev %s\n", - tmp_error, slave->dev->name); + /* unwind from head to the slave that failed */ + stop_at = slave; + bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) { + int tmp_res; + + tmp_res = slave->dev->set_mac_address(slave->dev, &tmp_sa); + if (tmp_res) { + dprintk("unwind err %d dev %s\n", tmp_res, + slave->dev->name); } } - return error; + return res; } -/* - * Change the MTU of all of a master's slaves to match the master - */ -static inline int -bond_change_mtu(struct net_device *dev, int newmtu) +static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev) { - bonding_t *bond = dev->priv; - slave_t *slave; - int error; - - dprintk(KERN_INFO "CM: b %p nm %d\n", bond, newmtu); - for (slave = bond->prev; slave != (slave_t *)bond; - slave = slave->prev) { - dprintk(KERN_INFO "CM: s %p s->p %p c_m %p\n", slave, - slave->prev, slave->dev->change_mtu); - if (slave->dev->change_mtu) { - error = slave->dev->change_mtu(slave->dev, newmtu); - } else { - slave->dev->mtu = newmtu; - error = 0; - } + struct bonding *bond = bond_dev->priv; + struct slave *slave, *start_at; + int i; - if (error) { - /* If we failed to set the slave's mtu to the new value - * we must abort the operation even in ACTIVE_BACKUP - * mode, because if we allow the backup slaves to have - * different mtu values than the active slave we'll - * need to change their mtu when doing a failover. That - * means changing their mtu from timer context, which - * is probably not a good idea. - */ - dprintk(KERN_INFO "bond_change_mtu err %d %s\n", - error, slave->dev->name); - goto unwind; - } + read_lock(&bond->lock); + + if (!BOND_IS_OK(bond)) { + goto free_out; } - dev->mtu = newmtu; - return 0; + read_lock(&bond->curr_slave_lock); + slave = start_at = bond->curr_active_slave; + read_unlock(&bond->curr_slave_lock); + + if (!slave) { + goto free_out; + } + bond_for_each_slave_from(bond, slave, i, start_at) { + if (IS_UP(slave->dev) && + (slave->link == BOND_LINK_UP) && + (slave->state == BOND_STATE_ACTIVE)) { + skb->dev = slave->dev; + skb->priority = 1; + dev_queue_xmit(skb); -unwind: - for (slave = slave->next; slave != bond->next; - slave = slave->next) { + write_lock(&bond->curr_slave_lock); + bond->curr_active_slave = slave->next; + write_unlock(&bond->curr_slave_lock); - if (slave->dev->change_mtu) { - slave->dev->change_mtu(slave->dev, dev->mtu); - } else { - slave->dev->mtu = dev->mtu; + goto out; } } - return error; +out: + read_unlock(&bond->lock); + return 0; + +free_out: + /* no suitable interface, frame not sent */ + dev_kfree_skb(skb); + goto out; } /* - * Change device name + * in active-backup mode, we know that bond->curr_active_slave is always valid if + * the bond has a usable interface. */ -static inline int bond_event_changename(struct bonding *bond) +static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_dev) { -#ifdef CONFIG_PROC_FS - bond_destroy_proc_info(bond); - bond_create_proc_info(bond); -#endif + struct bonding *bond = bond_dev->priv; - return NOTIFY_DONE; + /* if we are sending arp packets, try to at least + identify our own ip address */ + if (arp_interval && !my_ip && + (skb->protocol == __constant_htons(ETH_P_ARP))) { + char *the_ip = (char *)skb->data + + sizeof(struct ethhdr) + + sizeof(struct arphdr) + + ETH_ALEN; + memcpy(&my_ip, the_ip, 4); + } + + read_lock(&bond->lock); + read_lock(&bond->curr_slave_lock); + + if (!BOND_IS_OK(bond)) { + goto free_out; + } + + if (bond->curr_active_slave) { /* one usable interface */ + skb->dev = bond->curr_active_slave->dev; + skb->priority = 1; + dev_queue_xmit(skb); + goto out; + } else { + goto free_out; + } +out: + read_unlock(&bond->curr_slave_lock); + read_unlock(&bond->lock); + return 0; + +free_out: + /* no suitable interface, frame not sent */ + dev_kfree_skb(skb); + goto out; } -static int bond_master_netdev_event(unsigned long event, struct net_device *event_dev) +/* + * in XOR mode, we determine the output device by performing xor on + * the source and destination hw adresses. If this device is not + * enabled, find the next slave following this xor slave. + */ +static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev) { - struct bonding *bond, *event_bond = NULL; + struct bonding *bond = bond_dev->priv; + struct ethhdr *data = (struct ethhdr *)skb->data; + struct slave *slave, *start_at; + int slave_no; + int i; - list_for_each_entry(bond, &bond_dev_list, bond_list) { - if (bond == event_dev->priv) { - event_bond = bond; - break; - } - } + read_lock(&bond->lock); - if (event_bond == NULL) { - return NOTIFY_DONE; + if (!BOND_IS_OK(bond)) { + goto free_out; } - switch (event) { - case NETDEV_CHANGENAME: - return bond_event_changename(event_bond); - case NETDEV_UNREGISTER: - /* - * TODO: remove a bond from the list? - */ - break; - default: - break; + slave_no = (data->h_dest[5]^bond_dev->dev_addr[5]) % bond->slave_cnt; + + bond_for_each_slave(bond, slave, i) { + slave_no--; + if (slave_no < 0) { + break; + } } - return NOTIFY_DONE; -} + start_at = slave; -static int bond_slave_netdev_event(unsigned long event, struct net_device *event_dev) -{ - struct net_device *master = event_dev->master; + bond_for_each_slave_from(bond, slave, i, start_at) { + if (IS_UP(slave->dev) && + (slave->link == BOND_LINK_UP) && + (slave->state == BOND_STATE_ACTIVE)) { + skb->dev = slave->dev; + skb->priority = 1; + dev_queue_xmit(skb); - switch (event) { - case NETDEV_UNREGISTER: - if (master != NULL) { - bond_release(master, event_dev); + goto out; } - break; - case NETDEV_CHANGE: - /* - * TODO: is this what we get if somebody - * sets up a hierarchical bond, then rmmod's - * one of the slave bonding devices? - */ - break; - case NETDEV_DOWN: - /* - * ... Or is it this? - */ - break; - case NETDEV_CHANGEMTU: - /* - * TODO: Should slaves be allowed to - * independently alter their MTU? For - * an active-backup bond, slaves need - * not be the same type of device, so - * MTUs may vary. For other modes, - * slaves arguably should have the - * same MTUs. To do this, we'd need to - * take over the slave's change_mtu - * function for the duration of their - * servitude. - */ - break; - case NETDEV_CHANGENAME: - /* - * TODO: handle changing the primary's name - */ - break; - default: - break; } - return NOTIFY_DONE; +out: + read_unlock(&bond->lock); + return 0; + +free_out: + /* no suitable interface, frame not sent */ + dev_kfree_skb(skb); + goto out; } /* - * bond_netdev_event: handle netdev notifier chain events. - * - * This function receives events for the netdev chain. The caller (an - * ioctl handler calling notifier_call_chain) holds the necessary - * locks for us to safely manipulate the slave devices (RTNL lock, - * dev_probe_lock). + * in broadcast mode, we send everything to all usable interfaces. */ -static int bond_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) +static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev) { - struct net_device *event_dev = (struct net_device *)ptr; - unsigned short flags; - int res = NOTIFY_DONE; + struct bonding *bond = bond_dev->priv; + struct slave *slave, *start_at; + struct net_device *tx_dev = NULL; + int i; - dprintk(KERN_INFO "bond_netdev_event n_b %p ev %lx ptr %p\n", - this, event, ptr); + read_lock(&bond->lock); - flags = event_dev->flags & (IFF_MASTER | IFF_SLAVE); - switch (flags) { - case IFF_MASTER: - res = bond_master_netdev_event(event, event_dev); - break; - case IFF_SLAVE: - res = bond_slave_netdev_event(event, event_dev); - break; - default: - /* A master that is also a slave ? */ - break; + if (!BOND_IS_OK(bond)) { + goto free_out; } - return res; -} + read_lock(&bond->curr_slave_lock); + start_at = bond->curr_active_slave; + read_unlock(&bond->curr_slave_lock); + + if (!start_at) { + goto free_out; + } + + bond_for_each_slave_from(bond, slave, i, start_at) { + if (IS_UP(slave->dev) && + (slave->link == BOND_LINK_UP) && + (slave->state == BOND_STATE_ACTIVE)) { + if (tx_dev) { + struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); + if (!skb2) { + printk(KERN_ERR DRV_NAME + ": Error: bond_xmit_broadcast(): " + "skb_clone() failed\n"); + continue; + } -static struct notifier_block bond_netdev_notifier = { - .notifier_call = bond_netdev_event, -}; + skb2->dev = tx_dev; + skb2->priority = 1; + dev_queue_xmit(skb2); + } + tx_dev = slave->dev; + } + } -/* De-initialize device specific data. - * Caller must hold rtnl_lock. - */ -static inline void bond_deinit(struct net_device *dev) -{ - struct bonding *bond = dev->priv; + if (tx_dev) { + skb->dev = tx_dev; + skb->priority = 1; + dev_queue_xmit(skb); + } else { + goto free_out; + } - list_del(&bond->bond_list); +out: + /* frame sent to all suitable interfaces */ + read_unlock(&bond->lock); + return 0; -#ifdef CONFIG_PROC_FS - bond_destroy_proc_info(bond); -#endif +free_out: + /* no suitable interface, frame not sent */ + dev_kfree_skb(skb); + goto out; } -/* Unregister and free all bond devices. - * Caller must hold rtnl_lock. - */ -static void bond_free_all(void) +#ifdef CONFIG_NET_FASTROUTE +static int bond_accept_fastpath(struct net_device *bond_dev, struct dst_entry *dst) { - struct bonding *bond, *nxt; - - list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) { - struct net_device *dev = bond->device; - - unregister_netdevice(dev); - bond_deinit(dev); - } - -#ifdef CONFIG_PROC_FS - bond_destroy_proc_dir(); -#endif + return -1; } +#endif + +/*------------------------- Device initialization ---------------------------*/ /* * Does not allocate but creates a /proc entry. * Allowed to fail. */ -static int __init bond_init(struct net_device *dev) +static int __init bond_init(struct net_device *bond_dev) { - struct bonding *bond; + struct bonding *bond = bond_dev->priv; int count; -#ifdef BONDING_DEBUG - printk (KERN_INFO "Begin bond_init for %s\n", dev->name); -#endif - bond = dev->priv; + dprintk("Begin bond_init for %s\n", bond_dev->name); /* initialize rwlocks */ rwlock_init(&bond->lock); - rwlock_init(&bond->ptrlock); + rwlock_init(&bond->curr_slave_lock); /* Initialize pointers */ - bond->next = bond->prev = (slave_t *)bond; - bond->current_slave = NULL; + bond->first_slave = NULL; + bond->curr_active_slave = NULL; bond->current_arp_slave = NULL; - bond->device = dev; + bond->primary_slave = NULL; + bond->dev = bond_dev; - /* Initialize the device structure. */ - dev->set_mac_address = bond_set_mac_address; + /* Initialize the device entry points */ + bond_dev->open = bond_open; + bond_dev->stop = bond_close; + bond_dev->get_stats = bond_get_stats; + bond_dev->do_ioctl = bond_do_ioctl; + bond_dev->set_multicast_list = bond_set_multicast_list; + bond_dev->change_mtu = bond_change_mtu; + bond_dev->set_mac_address = bond_set_mac_address; switch (bond_mode) { - case BOND_MODE_ACTIVEBACKUP: - dev->hard_start_xmit = bond_xmit_activebackup; - break; case BOND_MODE_ROUNDROBIN: - dev->hard_start_xmit = bond_xmit_roundrobin; + bond_dev->hard_start_xmit = bond_xmit_roundrobin; + break; + case BOND_MODE_ACTIVEBACKUP: + bond_dev->hard_start_xmit = bond_xmit_activebackup; break; case BOND_MODE_XOR: - dev->hard_start_xmit = bond_xmit_xor; + bond_dev->hard_start_xmit = bond_xmit_xor; break; case BOND_MODE_BROADCAST: - dev->hard_start_xmit = bond_xmit_broadcast; + bond_dev->hard_start_xmit = bond_xmit_broadcast; break; case BOND_MODE_8023AD: - dev->hard_start_xmit = bond_3ad_xmit_xor; + bond_dev->hard_start_xmit = bond_3ad_xmit_xor; /* extern */ break; case BOND_MODE_TLB: case BOND_MODE_ALB: - dev->hard_start_xmit = bond_alb_xmit; - dev->set_mac_address = bond_alb_set_mac_address; + bond_dev->hard_start_xmit = bond_alb_xmit; /* extern */ + bond_dev->set_mac_address = bond_alb_set_mac_address; /* extern */ break; default: - printk(KERN_ERR "Unknown bonding mode %d\n", bond_mode); + printk(KERN_ERR DRV_NAME + ": Error: Unknown bonding mode %d\n", + bond_mode); return -EINVAL; } - dev->get_stats = bond_get_stats; - dev->open = bond_open; - dev->stop = bond_close; - dev->set_multicast_list = set_multicast_list; - dev->do_ioctl = bond_ioctl; - dev->change_mtu = bond_change_mtu; - dev->tx_queue_len = 0; - dev->flags |= IFF_MASTER|IFF_MULTICAST; + bond_dev->destructor = free_netdev; #ifdef CONFIG_NET_FASTROUTE - dev->accept_fastpath = bond_accept_fastpath; + bond_dev->accept_fastpath = bond_accept_fastpath; #endif - printk(KERN_INFO "%s registered with", dev->name); - if (miimon > 0) { + /* Initialize the device options */ + bond_dev->tx_queue_len = 0; + bond_dev->flags |= IFF_MASTER|IFF_MULTICAST; + + printk(KERN_INFO DRV_NAME ": %s registered with", bond_dev->name); + if (miimon) { printk(" MII link monitoring set to %d ms", miimon); updelay /= miimon; downdelay /= miimon; @@ -3992,50 +3825,75 @@ static int __init bond_init(struct net_d } printk(", in %s mode.\n", bond_mode_name()); - printk(KERN_INFO "%s registered with", dev->name); + printk(KERN_INFO DRV_NAME ": %s registered with", bond_dev->name); if (arp_interval > 0) { - printk(" ARP monitoring set to %d ms with %d target(s):", - arp_interval, arp_ip_count); - for (count=0 ; countdestructor = free_netdev; - list_add_tail(&bond->bond_list, &bond_dev_list); return 0; } -/* -static int __init bond_probe(struct net_device *dev) +/* De-initialize device specific data. + * Caller must hold rtnl_lock. + */ +static inline void bond_deinit(struct net_device *bond_dev) { - bond_init(dev); - return 0; + struct bonding *bond = bond_dev->priv; + + list_del(&bond->bond_list); + +#ifdef CONFIG_PROC_FS + bond_remove_proc_entry(bond); +#endif } + +/* Unregister and free all bond devices. + * Caller must hold rtnl_lock. */ +static void bond_free_all(void) +{ + struct bonding *bond, *nxt; + + list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) { + struct net_device *bond_dev = bond->dev; + + unregister_netdevice(bond_dev); + bond_deinit(bond_dev); + } + +#ifdef CONFIG_PROC_FS + bond_destroy_proc_dir(); +#endif +} + +/*------------------------- Module initialization ---------------------------*/ /* * Convert string input module parms. Accept either the * number of the mode or its string name. */ -static inline int -bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl) +static inline int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl) { int i; - for (i = 0; tbl[i].modename != NULL; i++) { + for (i = 0; tbl[i].modename; i++) { if ((isdigit(*mode_arg) && - tbl[i].mode == simple_strtol(mode_arg, NULL, 0)) || - (0 == strncmp(mode_arg, tbl[i].modename, - strlen(tbl[i].modename)))) { + tbl[i].mode == simple_strtol(mode_arg, NULL, 0)) || + (strncmp(mode_arg, tbl[i].modename, + strlen(tbl[i].modename)) == 0)) { return tbl[i].mode; } } @@ -4043,88 +3901,64 @@ bond_parse_parm(char *mode_arg, struct b return -1; } - -static int __init bonding_init(void) +static int bond_check_params(void) { - int no; - int err; - - printk(KERN_INFO "%s", version); - /* * Convert string parameters. */ if (mode) { bond_mode = bond_parse_parm(mode, bond_mode_tbl); if (bond_mode == -1) { - printk(KERN_WARNING - "bonding_init(): Invalid bonding mode \"%s\"\n", + printk(KERN_ERR DRV_NAME + ": Error: Invalid bonding mode \"%s\"\n", mode == NULL ? "NULL" : mode); return -EINVAL; } } - if (USES_PRIMARY(bond_mode)) { - multicast_mode = BOND_MULTICAST_ACTIVE; - } else { - multicast_mode = BOND_MULTICAST_ALL; - } - - if (multicast) { - multicast_mode = bond_parse_parm(multicast, bond_mc_tbl); - if (multicast_mode == -1) { - printk(KERN_WARNING - "bonding_init(): Invalid multicast mode \"%s\"\n", - multicast == NULL ? "NULL" : multicast); - return -EINVAL; - } - } - if (lacp_rate) { if (bond_mode != BOND_MODE_8023AD) { - printk(KERN_WARNING - "lacp_rate param is irrelevant in mode %s\n", + printk(KERN_INFO DRV_NAME + ": lacp_rate param is irrelevant in mode %s\n", bond_mode_name()); } else { lacp_fast = bond_parse_parm(lacp_rate, bond_lacp_tbl); if (lacp_fast == -1) { - printk(KERN_WARNING - "bonding_init(): Invalid lacp rate " - "\"%s\"\n", + printk(KERN_ERR DRV_NAME + ": Error: Invalid lacp rate \"%s\"\n", lacp_rate == NULL ? "NULL" : lacp_rate); - return -EINVAL; } } } if (max_bonds < 1 || max_bonds > INT_MAX) { - printk(KERN_WARNING - "bonding_init(): max_bonds (%d) not in range %d-%d, " - "so it was reset to BOND_DEFAULT_MAX_BONDS (%d)", + printk(KERN_WARNING DRV_NAME + ": Warning: max_bonds (%d) not in range %d-%d, so it " + "was reset to BOND_DEFAULT_MAX_BONDS (%d)", max_bonds, 1, INT_MAX, BOND_DEFAULT_MAX_BONDS); max_bonds = BOND_DEFAULT_MAX_BONDS; } if (miimon < 0) { - printk(KERN_WARNING - "bonding_init(): miimon module parameter (%d), " + printk(KERN_WARNING DRV_NAME + ": Warning: miimon module parameter (%d), " "not in range 0-%d, so it was reset to %d\n", miimon, INT_MAX, BOND_LINK_MON_INTERV); miimon = BOND_LINK_MON_INTERV; } if (updelay < 0) { - printk(KERN_WARNING - "bonding_init(): updelay module parameter (%d), " + printk(KERN_WARNING DRV_NAME + ": Warning: updelay module parameter (%d), " "not in range 0-%d, so it was reset to 0\n", updelay, INT_MAX); updelay = 0; } if (downdelay < 0) { - printk(KERN_WARNING - "bonding_init(): downdelay module parameter (%d), " + printk(KERN_WARNING DRV_NAME + ": Warning: downdelay module parameter (%d), " "not in range 0-%d, so it was reset to 0\n", downdelay, INT_MAX); downdelay = 0; @@ -4132,82 +3966,69 @@ static int __init bonding_init(void) /* reset values for 802.3ad */ if (bond_mode == BOND_MODE_8023AD) { - if (arp_interval != 0) { - printk(KERN_WARNING "bonding_init(): ARP monitoring" - "can't be used simultaneously with 802.3ad, " - "disabling ARP monitoring\n"); + if (arp_interval) { + printk(KERN_WARNING DRV_NAME + ": Warning: ARP monitoring can't be used " + "simultaneously with 802.3ad, disabling ARP " + "monitoring\n"); arp_interval = 0; } - if (miimon == 0) { - printk(KERN_ERR - "bonding_init(): miimon must be specified, " - "otherwise bonding will not detect link failure, " - "speed and duplex which are essential " - "for 802.3ad operation\n"); - printk(KERN_ERR "Forcing miimon to 100msec\n"); + if (miimon) { + printk(KERN_WARNING DRV_NAME + ": Warning: miimon must be specified, " + "otherwise bonding will not detect link " + "failure, speed and duplex which are " + "essential for 802.3ad operation\n"); + printk(KERN_WARNING "Forcing miimon to 100msec\n"); miimon = 100; } - - if (multicast_mode != BOND_MULTICAST_ALL) { - printk(KERN_ERR - "bonding_init(): Multicast mode must " - "be set to ALL for 802.3ad\n"); - printk(KERN_ERR "Forcing Multicast mode to ALL\n"); - multicast_mode = BOND_MULTICAST_ALL; - } } /* reset values for TLB/ALB */ if ((bond_mode == BOND_MODE_TLB) || (bond_mode == BOND_MODE_ALB)) { - if (miimon == 0) { - printk(KERN_ERR - "bonding_init(): miimon must be specified, " - "otherwise bonding will not detect link failure " - "and link speed which are essential " + if (!miimon) { + printk(KERN_WARNING DRV_NAME + ": Warning: miimon must be specified, " + "otherwise bonding will not detect link " + "failure and link speed which are essential " "for TLB/ALB load balancing\n"); - printk(KERN_ERR "Forcing miimon to 100msec\n"); + printk(KERN_WARNING "Forcing miimon to 100msec\n"); miimon = 100; } - - if (multicast_mode != BOND_MULTICAST_ACTIVE) { - printk(KERN_ERR - "bonding_init(): Multicast mode must " - "be set to ACTIVE for TLB/ALB\n"); - printk(KERN_ERR "Forcing Multicast mode to ACTIVE\n"); - multicast_mode = BOND_MULTICAST_ACTIVE; - } } if (bond_mode == BOND_MODE_ALB) { - printk(KERN_INFO - "In ALB mode you might experience client disconnections" - " upon reconnection of a link if the bonding module" - " updelay parameter (%d msec) is incompatible with the" - " forwarding delay time of the switch\n", updelay); + printk(KERN_NOTICE DRV_NAME + ": In ALB mode you might experience client " + "disconnections upon reconnection of a link if the " + "bonding module updelay parameter (%d msec) is " + "incompatible with the forwarding delay time of the " + "switch\n", + updelay); } - if (miimon == 0) { - if ((updelay != 0) || (downdelay != 0)) { + if (!miimon) { + if (updelay || downdelay) { /* just warn the user the up/down delay will have * no effect since miimon is zero... */ - printk(KERN_WARNING - "bonding_init(): miimon module parameter not " - "set and updelay (%d) or downdelay (%d) module " + printk(KERN_WARNING DRV_NAME + ": Warning: miimon module parameter not set " + "and updelay (%d) or downdelay (%d) module " "parameter is set; updelay and downdelay have " "no effect unless miimon is set\n", - updelay, downdelay); + updelay, downdelay); } } else { /* don't allow arp monitoring */ - if (arp_interval != 0) { - printk(KERN_WARNING - "bonding_init(): miimon (%d) and arp_interval " - "(%d) can't be used simultaneously, " - "disabling ARP monitoring\n", - miimon, arp_interval); + if (arp_interval) { + printk(KERN_WARNING DRV_NAME + ": Warning: miimon (%d) and arp_interval (%d) " + "can't be used simultaneously, disabling ARP " + "monitoring\n", + miimon, arp_interval); arp_interval = 0; } @@ -4215,103 +4036,114 @@ static int __init bonding_init(void) /* updelay will be rounded in bond_init() when it * is divided by miimon, we just inform user here */ - printk(KERN_WARNING - "bonding_init(): updelay (%d) is not a multiple " + printk(KERN_WARNING DRV_NAME + ": Warning: updelay (%d) is not a multiple " "of miimon (%d), updelay rounded to %d ms\n", - updelay, miimon, (updelay / miimon) * miimon); + updelay, miimon, (updelay / miimon) * miimon); } if ((downdelay % miimon) != 0) { /* downdelay will be rounded in bond_init() when it * is divided by miimon, we just inform user here */ - printk(KERN_WARNING - "bonding_init(): downdelay (%d) is not a " - "multiple of miimon (%d), downdelay rounded " - "to %d ms\n", - downdelay, miimon, + printk(KERN_WARNING DRV_NAME + ": Warning: downdelay (%d) is not a multiple " + "of miimon (%d), downdelay rounded to %d ms\n", + downdelay, miimon, (downdelay / miimon) * miimon); } } if (arp_interval < 0) { - printk(KERN_WARNING - "bonding_init(): arp_interval module parameter (%d), " - "not in range 0-%d, so it was reset to %d\n", + printk(KERN_WARNING DRV_NAME + ": Warning: arp_interval module parameter (%d) " + ", not in range 0-%d, so it was reset to %d\n", arp_interval, INT_MAX, BOND_LINK_ARP_INTERV); arp_interval = BOND_LINK_ARP_INTERV; } - for (arp_ip_count=0 ; - (arp_ip_count < MAX_ARP_IP_TARGETS) && arp_ip_target[arp_ip_count]; - arp_ip_count++ ) { + for (arp_ip_count = 0; + (arp_ip_count < MAX_ARP_IP_TARGETS) && arp_ip_target[arp_ip_count]; + arp_ip_count++) { /* not complete check, but should be good enough to catch mistakes */ - if (!isdigit(arp_ip_target[arp_ip_count][0])) { - printk(KERN_WARNING - "bonding_init(): bad arp_ip_target module " - "parameter (%s), ARP monitoring will not be " - "performed\n", - arp_ip_target[arp_ip_count]); - arp_interval = 0; - } else { - u32 ip = in_aton(arp_ip_target[arp_ip_count]); + if (!isdigit(arp_ip_target[arp_ip_count][0])) { + printk(KERN_WARNING DRV_NAME + ": Warning: bad arp_ip_target module parameter " + "(%s), ARP monitoring will not be performed\n", + arp_ip_target[arp_ip_count]); + arp_interval = 0; + } else { + u32 ip = in_aton(arp_ip_target[arp_ip_count]); arp_target[arp_ip_count] = ip; } - } - + } - if ( (arp_interval > 0) && (arp_ip_count==0)) { + if (arp_interval && !arp_ip_count) { /* don't allow arping if no arp_ip_target given... */ - printk(KERN_WARNING - "bonding_init(): arp_interval module parameter " - "(%d) specified without providing an arp_ip_target " + printk(KERN_WARNING DRV_NAME + ": Warning: arp_interval module parameter (%d) " + "specified without providing an arp_ip_target " "parameter, arp_interval was reset to 0\n", arp_interval); arp_interval = 0; } - if ((miimon == 0) && (arp_interval == 0)) { + if (!miimon && !arp_interval) { /* miimon and arp_interval not set, we need one so things * work as expected, see bonding.txt for details */ - printk(KERN_ERR - "bonding_init(): either miimon or " - "arp_interval and arp_ip_target module parameters " - "must be specified, otherwise bonding will not detect " - "link failures! see bonding.txt for details.\n"); + printk(KERN_WARNING DRV_NAME + ": Warning: either miimon or arp_interval and " + "arp_ip_target module parameters must be specified, " + "otherwise bonding will not detect link failures! see " + "bonding.txt for details.\n"); } - if ((primary != NULL) && !USES_PRIMARY(bond_mode)) { + if (primary && !USES_PRIMARY(bond_mode)) { /* currently, using a primary only makes sense * in active backup, TLB or ALB modes */ - printk(KERN_WARNING - "bonding_init(): %s primary device specified but has " - "no effect in %s mode\n", + printk(KERN_WARNING DRV_NAME + ": Warning: %s primary device specified but has no " + "effect in %s mode\n", primary, bond_mode_name()); primary = NULL; } + return 0; +} + +static int __init bonding_init(void) +{ + int i; + int res; + + printk(KERN_INFO "%s", version); + + res = bond_check_params(); + if (res) { + return res; + } + rtnl_lock(); #ifdef CONFIG_PROC_FS bond_create_proc_dir(); #endif - err = 0; - for (no = 0; no < max_bonds; no++) { - struct net_device *dev; - - dev = alloc_netdev(sizeof(struct bonding), "", ether_setup); - if (!dev) { - err = -ENOMEM; + for (i = 0; i < max_bonds; i++) { + struct net_device *bond_dev; + + bond_dev = alloc_netdev(sizeof(struct bonding), "", ether_setup); + if (!bond_dev) { + res = -ENOMEM; goto out_err; } - err = dev_alloc_name(dev, "bond%d"); - if (err < 0) { - free_netdev(dev); + res = dev_alloc_name(bond_dev, "bond%d"); + if (res < 0) { + free_netdev(bond_dev); goto out_err; } @@ -4319,18 +4151,18 @@ static int __init bonding_init(void) * /proc files), but before register_netdevice(), because we * need to set function pointers. */ - err = bond_init(dev); - if (err < 0) { - free_netdev(dev); + res = bond_init(bond_dev); + if (res < 0) { + free_netdev(bond_dev); goto out_err; } - SET_MODULE_OWNER(dev); + SET_MODULE_OWNER(bond_dev); - err = register_netdevice(dev); - if (err < 0) { - bond_deinit(dev); - free_netdev(dev); + res = register_netdevice(bond_dev); + if (res < 0) { + bond_deinit(bond_dev); + free_netdev(bond_dev); goto out_err; } } @@ -4346,7 +4178,7 @@ out_err: rtnl_unlock(); - return err; + return res; } static void __exit bonding_exit(void) @@ -4362,6 +4194,8 @@ module_init(bonding_init); module_exit(bonding_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION(DRV_DESCRIPTION ", v" DRV_VERSION); +MODULE_AUTHOR("Thomas Davis, tadavis@lbl.gov and many others"); +MODULE_SUPPORTED_DEVICE("most ethernet devices"); /* * Local variables: @@ -4370,3 +4204,4 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION ", v" * tab-width: 8 * End: */ + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/bonding/bonding.h 830-ivtv/drivers/net/bonding/bonding.h --- 000-virgin/drivers/net/bonding/bonding.h Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/bonding/bonding.h Thu Jan 8 08:54:13 2004 @@ -9,7 +9,7 @@ * * This software may be used and distributed according to the terms * of the GNU Public License, incorporated herein by reference. - * + * * * 2003/03/18 - Amir Noam , * Tsippy Mendelson and @@ -22,159 +22,205 @@ * * 2003/05/01 - Shmulik Hen * - Added support for Transmit load balancing mode. + * + * 2003/09/24 - Shmulik Hen + * - Code cleanup and style changes */ - + #ifndef _LINUX_BONDING_H #define _LINUX_BONDING_H #include #include +#include #include "bond_3ad.h" #include "bond_alb.h" -#ifdef BONDING_DEBUG - -// use this like so: BOND_PRINT_DBG(("foo = %d, bar = %d", foo, bar)); -#define BOND_PRINT_DBG(X) \ -do { \ - printk(KERN_DEBUG "%s (%d)", __FUNCTION__, __LINE__); \ - printk X; \ - printk("\n"); \ -} while(0) +#define DRV_VERSION "2.5.0" +#define DRV_RELDATE "December 1, 2003" +#define DRV_NAME "bonding" +#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" +#ifdef BONDING_DEBUG +#define dprintk(fmt, args...) \ + printk(KERN_DEBUG \ + DRV_NAME ": %s() %d: " fmt, __FUNCTION__, __LINE__ , ## args ) #else -#define BOND_PRINT_DBG(X) +#define dprintk(fmt, args...) #endif /* BONDING_DEBUG */ -#define IS_UP(dev) ((((dev)->flags & (IFF_UP)) == (IFF_UP)) && \ - (netif_running(dev) && netif_carrier_ok(dev))) +#define IS_UP(dev) \ + ((((dev)->flags & IFF_UP) == IFF_UP) && \ + netif_running(dev) && \ + netif_carrier_ok(dev)) + +/* + * Checks whether bond is ready for transmit. + * + * Caller must hold bond->lock + */ +#define BOND_IS_OK(bond) \ + (((bond)->dev->flags & IFF_UP) && \ + netif_running((bond)->dev) && \ + ((bond)->slave_cnt > 0)) -/* Checks whether the dev is ready for transmit. We do not check netif_running - * since a device can be stopped by the driver for short periods of time for - * maintainance. dev_queue_xmit() handles this by queing the packet until the - * the dev is running again. Keeping packets ordering requires sticking the - * same dev as much as possible - */ -#define SLAVE_IS_OK(slave) \ - ((((slave)->dev->flags & (IFF_UP)) == (IFF_UP)) && \ - netif_carrier_ok((slave)->dev) && \ +/* + * Checks whether slave is ready for transmit. + */ +#define SLAVE_IS_OK(slave) \ + (((slave)->dev->flags & IFF_UP) && \ + netif_running((slave)->dev) && \ ((slave)->link == BOND_LINK_UP) && \ ((slave)->state == BOND_STATE_ACTIVE)) -typedef struct slave { +#define USES_PRIMARY(mode) \ + (((mode) == BOND_MODE_ACTIVEBACKUP) || \ + ((mode) == BOND_MODE_TLB) || \ + ((mode) == BOND_MODE_ALB)) + +/* + * Less bad way to call ioctl from within the kernel; this needs to be + * done some other way to get the call out of interrupt context. + * Needs "ioctl" variable to be supplied by calling context. + */ +#define IOCTL(dev, arg, cmd) ({ \ + int res = 0; \ + mm_segment_t fs = get_fs(); \ + set_fs(get_ds()); \ + res = ioctl(dev, arg, cmd); \ + set_fs(fs); \ + res; }) + +/** + * bond_for_each_slave_from - iterate the slaves list from a starting point + * @bond: the bond holding this list. + * @pos: current slave. + * @cnt: counter for max number of moves + * @start: starting point. + * + * Caller must hold bond->lock + */ +#define bond_for_each_slave_from(bond, pos, cnt, start) \ + for (cnt = 0, pos = start; \ + cnt < (bond)->slave_cnt; \ + cnt++, pos = (pos)->next) + +/** + * bond_for_each_slave_from_to - iterate the slaves list from start point to stop point + * @bond: the bond holding this list. + * @pos: current slave. + * @cnt: counter for number max of moves + * @start: start point. + * @stop: stop point. + * + * Caller must hold bond->lock + */ +#define bond_for_each_slave_from_to(bond, pos, cnt, start, stop) \ + for (cnt = 0, pos = start; \ + ((cnt < (bond)->slave_cnt) && (pos != (stop)->next)); \ + cnt++, pos = (pos)->next) + +/** + * bond_for_each_slave - iterate the slaves list from head + * @bond: the bond holding this list. + * @pos: current slave. + * @cnt: counter for max number of moves + * + * Caller must hold bond->lock + */ +#define bond_for_each_slave(bond, pos, cnt) \ + bond_for_each_slave_from(bond, pos, cnt, (bond)->first_slave) + + +struct slave { + struct net_device *dev; /* first - usefull for panic debug */ struct slave *next; struct slave *prev; - struct net_device *dev; - short delay; - unsigned long jiffies; - char link; /* one of BOND_LINK_XXXX */ - char state; /* one of BOND_STATE_XXXX */ - unsigned short original_flags; - u32 link_failure_count; + s16 delay; + u32 jiffies; + s8 link; /* one of BOND_LINK_XXXX */ + s8 state; /* one of BOND_STATE_XXXX */ + u32 original_flags; + u32 link_failure_count; u16 speed; u8 duplex; u8 perm_hwaddr[ETH_ALEN]; struct ad_slave_info ad_info; /* HUGE - better to dynamically alloc */ struct tlb_slave_info tlb_info; -} slave_t; +}; /* * Here are the locking policies for the two bonding locks: * * 1) Get bond->lock when reading/writing slave list. - * 2) Get bond->ptrlock when reading/writing bond->current_slave. + * 2) Get bond->curr_slave_lock when reading/writing bond->curr_active_slave. * (It is unnecessary when the write-lock is put with bond->lock.) - * 3) When we lock with bond->ptrlock, we must lock with bond->lock + * 3) When we lock with bond->curr_slave_lock, we must lock with bond->lock * beforehand. */ -typedef struct bonding { - slave_t *next; - slave_t *prev; - slave_t *current_slave; - slave_t *primary_slave; - slave_t *current_arp_slave; - __s32 slave_cnt; +struct bonding { + struct net_device *dev; /* first - usefull for panic debug */ + struct slave *first_slave; + struct slave *curr_active_slave; + struct slave *current_arp_slave; + struct slave *primary_slave; + s32 slave_cnt; /* never change this value outside the attach/detach wrappers */ rwlock_t lock; - rwlock_t ptrlock; - struct timer_list mii_timer; - struct timer_list arp_timer; - struct net_device_stats stats; + rwlock_t curr_slave_lock; + struct timer_list mii_timer; + struct timer_list arp_timer; + s8 kill_timers; + struct net_device_stats stats; #ifdef CONFIG_PROC_FS - struct proc_dir_entry *bond_proc_file; - char procdir_name[IFNAMSIZ]; + struct proc_dir_entry *proc_entry; + char proc_file_name[IFNAMSIZ]; #endif /* CONFIG_PROC_FS */ - struct list_head bond_list; - struct net_device *device; - struct dev_mc_list *mc_list; - unsigned short flags; - struct ad_bond_info ad_info; - struct alb_bond_info alb_info; -} bonding_t; - -/* Forward declarations */ -void bond_set_slave_active_flags(slave_t *slave); -void bond_set_slave_inactive_flags(slave_t *slave); - -/** - * These functions can be used for iterating the slave list - * (which is circular) - * Caller must hold bond lock for read - */ -extern inline struct slave* -bond_get_first_slave(struct bonding *bond) -{ - /* if there are no slaves return NULL */ - if (bond->next == (slave_t *)bond) { - return NULL; - } - return bond->next; -} - -/** - * Caller must hold bond lock for read - */ -extern inline struct slave* -bond_get_next_slave(struct bonding *bond, struct slave *slave) -{ - /* If we have reached the last slave return NULL */ - if (slave->next == bond->next) { - return NULL; - } - return slave->next; -} + struct list_head bond_list; + struct dev_mc_list *mc_list; + u16 flags; + struct ad_bond_info ad_info; + struct alb_bond_info alb_info; +}; /** * Returns NULL if the net_device does not belong to any of the bond's slaves * * Caller must hold bond lock for read */ -extern inline struct slave* -bond_get_slave_by_dev(struct bonding *bond, struct net_device *slave_dev) +extern inline struct slave *bond_get_slave_by_dev(struct bonding *bond, struct net_device *slave_dev) { - struct slave *our_slave = bond->next; + struct slave *slave = NULL; + int i; - /* check if the list of slaves is empty */ - if (our_slave == (slave_t *)bond) { - return NULL; - } - - for (; our_slave; our_slave = bond_get_next_slave(bond, our_slave)) { - if (our_slave->dev == slave_dev) { + bond_for_each_slave(bond, slave, i) { + if (slave->dev == slave_dev) { break; } } - return our_slave; + + return slave; } -extern inline struct bonding* -bond_get_bond_by_slave(struct slave *slave) +extern inline struct bonding *bond_get_bond_by_slave(struct slave *slave) { if (!slave || !slave->dev->master) { return NULL; } - return (struct bonding *)(slave->dev->master->priv); + return (struct bonding *)slave->dev->master->priv; +} + +extern inline void bond_set_slave_inactive_flags(struct slave *slave) +{ + slave->state = BOND_STATE_BACKUP; + slave->dev->flags |= IFF_NOARP; +} + +extern inline void bond_set_slave_active_flags(struct slave *slave) +{ + slave->state = BOND_STATE_ACTIVE; + slave->dev->flags &= ~IFF_NOARP; } #endif /* _LINUX_BONDING_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/cs89x0.c 830-ivtv/drivers/net/cs89x0.c --- 000-virgin/drivers/net/cs89x0.c Thu Jan 8 08:35:38 2004 +++ 830-ivtv/drivers/net/cs89x0.c Thu Jan 8 08:54:13 2004 @@ -212,9 +212,7 @@ struct net_local { /* Index to functions, as function prototypes. */ -extern int cs89x0_probe(struct net_device *dev); - -static int cs89x0_probe1(struct net_device *dev, int ioaddr); +static int cs89x0_probe1(struct net_device *dev, int ioaddr, int modular); static int net_open(struct net_device *dev); static int net_send_packet(struct sk_buff *skb, struct net_device *dev); static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs *regs); @@ -274,27 +272,51 @@ __setup("cs89x0_media=", media_fn); Return 0 on success. */ -int __init cs89x0_probe(struct net_device *dev) +struct net_device * __init cs89x0_probe(int unit) { - int i; - int base_addr = dev ? dev->base_addr : 0; - - SET_MODULE_OWNER(dev); + struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); + unsigned *port; + int err = 0; + int irq; + int io; + + if (!dev) + return ERR_PTR(-ENODEV); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + irq = dev->irq; if (net_debug) - printk("cs89x0:cs89x0_probe(0x%x)\n", base_addr); + printk("cs89x0:cs89x0_probe(0x%x)\n", io); - if (base_addr > 0x1ff) /* Check a single specified location. */ - return cs89x0_probe1(dev, base_addr); - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; - - for (i = 0; netcard_portlist[i]; i++) { - if (cs89x0_probe1(dev, netcard_portlist[i]) == 0) - return 0; + if (io > 0x1ff) { /* Check a single specified location. */ + err = cs89x0_probe1(dev, io, 0); + } else if (io != 0) { /* Don't probe at all. */ + err = -ENXIO; + } else { + for (port = netcard_portlist; *port; port++) { + if (cs89x0_probe1(dev, *port, 0) == 0) + break; + dev->irq = irq; + } + if (!*port) + err = -ENODEV; } + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + outw(PP_ChipID, dev->base_addr + ADD_PORT); + release_region(dev->base_addr, NETCARD_IO_EXTENT); +out: + free_netdev(dev); printk(KERN_WARNING "cs89x0: no cs8900 or cs8920 detected. Be sure to disable PnP with SETUP\n"); - return -ENODEV; + return ERR_PTR(err); } static int @@ -375,39 +397,34 @@ get_eeprom_cksum(int off, int len, int * */ static int __init -cs89x0_probe1(struct net_device *dev, int ioaddr) +cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) { - struct net_local *lp; + struct net_local *lp = (struct net_local *)dev->priv; static unsigned version_printed; int i; unsigned rev_type = 0; int eeprom_buff[CHKSUM_LEN]; int retval; + SET_MODULE_OWNER(dev); /* Initialize the device structure. */ - if (dev->priv == NULL) { - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == 0) { - retval = -ENOMEM; - goto out; - } - lp = (struct net_local *)dev->priv; + if (!modular) { memset(lp, 0, sizeof(*lp)); spin_lock_init(&lp->lock); -#if !defined(MODULE) && (ALLOW_DMA != 0) +#ifndef MODULE +#if ALLOW_DMA if (g_cs89x0_dma) { lp->use_dma = 1; lp->dma = g_cs89x0_dma; lp->dmasize = 16; /* Could make this an option... */ } #endif -#ifndef MODULE lp->force = g_cs89x0_media__force; #endif } - lp = (struct net_local *)dev->priv; /* Grab the region so we can find another board if autoIRQ fails. */ + /* WTF is going on here? */ if (!request_region(ioaddr & ~3, NETCARD_IO_EXTENT, dev->name)) { printk(KERN_ERR "%s: request_region(0x%x, 0x%x) failed\n", dev->name, ioaddr, NETCARD_IO_EXTENT); @@ -696,9 +713,6 @@ printk("PP_addr=0x%x\n", inw(ioaddr + AD dev->set_multicast_list = set_multicast_list; dev->set_mac_address = set_mac_address; - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - printk("\n"); if (net_debug) printk("cs89x0_probe1() successful\n"); @@ -706,9 +720,6 @@ printk("PP_addr=0x%x\n", inw(ioaddr + AD out2: release_region(ioaddr & ~3, NETCARD_IO_EXTENT); out1: - kfree(dev->priv); - dev->priv = 0; -out: return retval; } @@ -1655,7 +1666,7 @@ static int set_mac_address(struct net_de #ifdef MODULE -static struct net_device dev_cs89x0; +static struct net_device *dev_cs89x0; /* * Support the 'debug' module parm even if we're compiled for non-debug to @@ -1733,6 +1744,7 @@ MODULE_LICENSE("GPL"); int init_module(void) { + struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); struct net_local *lp; int ret = 0; @@ -1741,18 +1753,12 @@ init_module(void) #else debug = 0; #endif - - dev_cs89x0.irq = irq; - dev_cs89x0.base_addr = io; - - dev_cs89x0.init = cs89x0_probe; - dev_cs89x0.priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev_cs89x0.priv == 0) { - printk(KERN_ERR "cs89x0.c: Out of memory.\n"); + if (!dev) return -ENOMEM; - } - memset(dev_cs89x0.priv, 0, sizeof(struct net_local)); - lp = (struct net_local *)dev_cs89x0.priv; + + dev->irq = irq; + dev->base_addr = io; + lp = dev->priv; #if ALLOW_DMA if (use_dma) { @@ -1782,7 +1788,10 @@ init_module(void) printk(KERN_ERR "cs89x0.c: Append io=0xNNN\n"); ret = -EPERM; goto out; - } + } else if (io <= 0x1ff) { + ret = -ENXIO; + goto out; + } #if ALLOW_DMA if (use_dma && dmasize != 16 && dmasize != 64) { @@ -1791,30 +1800,31 @@ init_module(void) goto out; } #endif + ret = cs89x0_probe1(dev, io, 1); + if (ret) + goto out; - if (register_netdev(&dev_cs89x0) != 0) { + if (register_netdev(dev) != 0) { printk(KERN_ERR "cs89x0.c: No card found at 0x%x\n", io); ret = -ENXIO; + outw(PP_ChipID, dev->base_addr + ADD_PORT); + release_region(dev->base_addr, NETCARD_IO_EXTENT); goto out; } + dev_cs89x0 = dev; + return 0; out: - if (ret) - kfree(dev_cs89x0.priv); + free_netdev(dev); return ret; } void cleanup_module(void) { - if (dev_cs89x0.priv != NULL) { - /* Free up the private structure, or leak memory :-) */ - unregister_netdev(&dev_cs89x0); - outw(PP_ChipID, dev_cs89x0.base_addr + ADD_PORT); - kfree(dev_cs89x0.priv); - dev_cs89x0.priv = NULL; /* gets re-allocated by cs89x0_probe1 */ - /* If we don't do this, we can't re-insmod it later. */ - release_region(dev_cs89x0.base_addr, NETCARD_IO_EXTENT); - } + unregister_netdev(dev_cs89x0); + outw(PP_ChipID, dev_cs89x0->base_addr + ADD_PORT); + release_region(dev_cs89x0->base_addr, NETCARD_IO_EXTENT); + free_netdev(dev_cs89x0); } #endif /* MODULE */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/de600.c 830-ivtv/drivers/net/de600.c --- 000-virgin/drivers/net/de600.c Sat May 10 18:34:40 2003 +++ 830-ivtv/drivers/net/de600.c Thu Jan 8 08:54:13 2004 @@ -99,7 +99,7 @@ static volatile int tx_fifo_in; static volatile int tx_fifo_out; static volatile int free_tx_pages = TX_PAGES; static int was_down; -static spinlock_t de600_lock; +static spinlock_t de600_lock = SPIN_LOCK_UNLOCKED; static inline u8 de600_read_status(struct net_device *dev) { @@ -398,20 +398,31 @@ static void de600_rx_intr(struct net_dev */ } -int __init de600_probe(struct net_device *dev) +static struct net_device * __init de600_probe(void) { int i; - static struct net_device_stats de600_netstats; - /*dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);*/ + struct net_device *dev; + int err; + + dev = alloc_etherdev(sizeof(struct net_device_stats)); + if (!dev) + return ERR_PTR(-ENOMEM); SET_MODULE_OWNER(dev); + if (!request_region(DE600_IO, 3, "de600")) { + printk(KERN_WARNING "DE600: port 0x%x busy\n", DE600_IO); + err = -EBUSY; + goto out; + } + printk(KERN_INFO "%s: D-Link DE-600 pocket adapter", dev->name); /* Alpha testers must have the version number to report bugs. */ if (de600_debug > 1) printk(version); /* probe for adapter */ + err = -ENODEV; rx_page = 0; select_nic(); (void)de600_read_status(dev); @@ -419,7 +430,7 @@ int __init de600_probe(struct net_device de600_put_command(STOP_RESET); if (de600_read_status(dev) & 0xf0) { printk(": not at I/O %#3x.\n", DATA_PORT); - return -ENODEV; + goto out1; } /* @@ -444,12 +455,7 @@ int __init de600_probe(struct net_device dev->dev_addr[3] |= 0x70; } else { printk(" not identified in the printer port\n"); - return -ENODEV; - } - - if (!request_region(DE600_IO, 3, "de600")) { - printk(KERN_WARNING "DE600: port 0x%x busy\n", DE600_IO); - return -EBUSY; + goto out1; } printk(", Ethernet Address: %02X", dev->dev_addr[0]); @@ -457,22 +463,27 @@ int __init de600_probe(struct net_device printk(":%02X",dev->dev_addr[i]); printk("\n"); - /* Initialize the device structure. */ - dev->priv = &de600_netstats; - - memset(dev->priv, 0, sizeof(struct net_device_stats)); dev->get_stats = get_stats; dev->open = de600_open; dev->stop = de600_close; dev->hard_start_xmit = &de600_start_xmit; - ether_setup(dev); - dev->flags&=~IFF_MULTICAST; select_prn(); - return 0; + + err = register_netdev(dev); + if (err) + goto out1; + + return dev; + +out1: + release_region(DE600_IO, 3); +out: + free_netdev(dev); + return ERR_PTR(err); } static int adapter_init(struct net_device *dev) @@ -527,21 +538,21 @@ static int adapter_init(struct net_devic return 0; /* OK */ } -static struct net_device de600_dev; +static struct net_device *de600_dev; static int __init de600_init(void) { - spin_lock_init(&de600_lock); - de600_dev.init = de600_probe; - if (register_netdev(&de600_dev) != 0) - return -EIO; + de600_dev = de600_probe(); + if (IS_ERR(de600_dev)) + return PTR_ERR(de600_dev); return 0; } static void __exit de600_exit(void) { - unregister_netdev(&de600_dev); + unregister_netdev(de600_dev); release_region(DE600_IO, 3); + free_netdev(de600_dev); } module_init(de600_init); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/de600.h 830-ivtv/drivers/net/de600.h --- 000-virgin/drivers/net/de600.h Sat May 10 18:34:40 2003 +++ 830-ivtv/drivers/net/de600.h Thu Jan 8 08:54:13 2004 @@ -131,7 +131,6 @@ static void de600_rx_intr(struct net_dev /* Initialization */ static void trigger_interrupt(struct net_device *dev); -int de600_probe(struct net_device *dev); static int adapter_init(struct net_device *dev); /* diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/de620.c 830-ivtv/drivers/net/de620.c --- 000-virgin/drivers/net/de620.c Sat May 10 18:34:40 2003 +++ 830-ivtv/drivers/net/de620.c Thu Jan 8 08:54:13 2004 @@ -226,7 +226,6 @@ static int de620_rx_intr(struct net_devi /* Initialization */ static int adapter_init(struct net_device *); -int de620_probe(struct net_device *); static int read_eeprom(struct net_device *); @@ -814,11 +813,16 @@ static int adapter_init(struct net_devic * * Check if there is a DE-620 connected */ -int __init de620_probe(struct net_device *dev) +struct net_device * __init de620_probe(int unit) { - static struct net_device_stats de620_netstats; - int i; byte checkbyte = 0xa5; + struct net_device *dev; + int err = -ENOMEM; + int i; + + dev = alloc_etherdev(sizeof(struct net_device_stats)); + if (!dev) + goto out; SET_MODULE_OWNER(dev); @@ -831,11 +835,23 @@ int __init de620_probe(struct net_device dev->base_addr = io; dev->irq = irq; + /* allow overriding parameters on command line */ + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } + if (de620_debug) printk(version); printk(KERN_INFO "D-Link DE-620 pocket adapter"); + if (!request_region(dev->base_addr, 3, "de620")) { + printk(" io 0x%3lX, which is busy.\n", dev->base_addr); + err = -EBUSY; + goto out1; + } + /* Initially, configure basic nibble mode, so we can read the EEPROM */ NIC_Cmd = DEF_NIC_CMD; de620_set_register(dev, W_EIP, EIPRegister); @@ -846,12 +862,8 @@ int __init de620_probe(struct net_device if ((checkbyte != 0xa5) || (read_eeprom(dev) != 0)) { printk(" not identified in the printer port\n"); - return -ENODEV; - } - - if (!request_region(dev->base_addr, 3, "de620")) { - printk(KERN_ERR "io 0x%3lX, which is busy.\n", dev->base_addr); - return -EBUSY; + err = -ENODEV; + goto out2; } /* else, got it! */ @@ -870,10 +882,6 @@ int __init de620_probe(struct net_device else printk(" UTP)\n"); - /* Initialize the device structure. */ - dev->priv = &de620_netstats; - - memset(dev->priv, 0, sizeof(struct net_device_stats)); dev->get_stats = get_stats; dev->open = de620_open; dev->stop = de620_close; @@ -884,8 +892,6 @@ int __init de620_probe(struct net_device /* base_addr and irq are already set, see above! */ - ether_setup(dev); - /* dump eeprom */ if (de620_debug) { printk("\nEEPROM contents:\n"); @@ -899,7 +905,17 @@ int __init de620_probe(struct net_device printk("SCR = 0x%02x\n", nic_data.SCR); } - return 0; + err = register_netdev(dev); + if (err) + goto out2; + return dev; + +out2: + release_region(dev->base_addr, 3); +out1: + free_netdev(dev); +out: + return ERR_PTR(err); } /********************************** @@ -994,20 +1010,21 @@ static int __init read_eeprom(struct net * */ #ifdef MODULE -static struct net_device de620_dev; +static struct net_device *de620_dev; int init_module(void) { - de620_dev.init = de620_probe; - if (register_netdev(&de620_dev) != 0) - return -EIO; + de620_dev = de620_probe(-1); + if (IS_ERR(de620_dev)) + return PTR_ERR(de620_dev); return 0; } void cleanup_module(void) { - unregister_netdev(&de620_dev); - release_region(de620_dev.base_addr, 3); + unregister_netdev(de620_dev); + release_region(de620_dev->base_addr, 3); + free_netdev(de620_dev); } #endif /* MODULE */ MODULE_LICENSE("GPL"); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/declance.c 830-ivtv/drivers/net/declance.c --- 000-virgin/drivers/net/declance.c Tue Sep 2 09:55:47 2003 +++ 830-ivtv/drivers/net/declance.c Thu Jan 8 08:54:13 2004 @@ -1039,13 +1039,13 @@ static int __init dec_lance_init(const i if (dec_lance_debug && version_printed++ == 0) printk(version); - dev = init_etherdev(NULL, sizeof(struct lance_private)); + dev = alloc_etherdev(sizeof(struct lance_private)); if (!dev) return -ENOMEM; SET_MODULE_OWNER(dev); /* - * init_etherdev ensures the data structures used by the LANCE + * alloc_etherdev ensures the data structures used by the LANCE * are aligned. */ lp = (struct lance_private *) dev->priv; @@ -1188,9 +1188,6 @@ static int __init dec_lance_init(const i } } - lp->next = root_lance_dev; - root_lance_dev = dev; - /* Copy the ethernet address to the device structure, later to the * lance initialization block so the lance gets it every time it's * (re)initialized. @@ -1239,11 +1236,14 @@ static int __init dec_lance_init(const i init_timer(&lp->multicast_timer); lp->multicast_timer.data = (unsigned long) dev; lp->multicast_timer.function = &lance_set_multicast_retry; - + ret = register_netdev(dev); + if (ret) + goto err_out; + lp->next = root_lance_dev; + root_lance_dev = dev; return 0; err_out: - unregister_netdev(dev); free_netdev(dev); return ret; } @@ -1288,13 +1288,12 @@ static void __exit dec_lance_cleanup(voi while (root_lance_dev) { struct net_device *dev = root_lance_dev; struct lance_private *lp = (struct lance_private *)dev->priv; - + unregister_netdev(dev); #ifdef CONFIG_TC if (lp->slot >= 0) release_tc_card(lp->slot); #endif root_lance_dev = lp->next; - unregister_netdev(dev); free_netdev(dev); } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/defxx.c 830-ivtv/drivers/net/defxx.c --- 000-virgin/drivers/net/defxx.c Mon Nov 17 18:29:42 2003 +++ 830-ivtv/drivers/net/defxx.c Thu Jan 8 08:54:13 2004 @@ -491,7 +491,7 @@ err_out_kfree: err_out_region: release_region(ioaddr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN); err_out: - kfree(dev); + free_netdev(dev); return err; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/depca.c 830-ivtv/drivers/net/depca.c --- 000-virgin/drivers/net/depca.c Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/depca.c Thu Jan 8 08:54:13 2004 @@ -681,8 +681,7 @@ static int __init depca_hw_init (struct lp->sh_mem = ioremap(mem_start, mem_len); if (lp->sh_mem == NULL) { printk(KERN_ERR "depca: cannot remap ISA memory, aborting\n"); - release_mem_region (mem_start, mem_len); - goto out_priv; + goto out1; } lp->mem_start = mem_start; @@ -771,7 +770,7 @@ static int __init depca_hw_init (struct status = -ENXIO; if (!irqnum) { printk(" and failed to detect IRQ line.\n"); - goto out_priv; + goto out2; } else { for (dev->irq = 0, i = 0; (depca_irq[i]) && (!dev->irq); i++) if (irqnum == depca_irq[i]) { @@ -781,7 +780,7 @@ static int __init depca_hw_init (struct if (!dev->irq) { printk(" but incorrect IRQ line detected.\n"); - return -ENXIO; + goto out2; } } } else { @@ -807,11 +806,14 @@ static int __init depca_hw_init (struct device->driver_data = dev; SET_NETDEV_DEV (dev, device); - register_netdev (dev); - return 0; - - out_priv: - + status = register_netdev(dev); + if (status == 0) + return 0; +out2: + iounmap(lp->sh_mem); +out1: + release_mem_region (mem_start, mem_len); +out_priv: return status; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/dummy.c 830-ivtv/drivers/net/dummy.c --- 000-virgin/drivers/net/dummy.c Mon Nov 17 18:28:14 2003 +++ 830-ivtv/drivers/net/dummy.c Thu Jan 8 08:54:13 2004 @@ -96,7 +96,7 @@ static int __init dummy_init_module(void return -ENOMEM; if ((err = register_netdev(dev_dummy))) { - kfree(dev_dummy); + free_netdev(dev_dummy); dev_dummy = NULL; } return err; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/e100/LICENSE 830-ivtv/drivers/net/e100/LICENSE --- 000-virgin/drivers/net/e100/LICENSE Sun Nov 17 20:29:49 2002 +++ 830-ivtv/drivers/net/e100/LICENSE Wed Dec 31 16:00:00 1969 @@ -1,339 +0,0 @@ - -"This software program is licensed subject to the GNU General Public License -(GPL). Version 2, June 1991, available at -" - -GNU General Public License - -Version 2, June 1991 - -Copyright (C) 1989, 1991 Free Software Foundation, Inc. -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - -Everyone is permitted to copy and distribute verbatim copies of this license -document, but changing it is not allowed. - -Preamble - -The licenses for most software are designed to take away your freedom to -share and change it. By contrast, the GNU General Public License is intended -to guarantee your freedom to share and change free software--to make sure -the software is free for all its users. This General Public License applies -to most of the Free Software Foundation's software and to any other program -whose authors commit to using it. (Some other Free Software Foundation -software is covered by the GNU Library General Public License instead.) You -can apply it to your programs, too. - -When we speak of free software, we are referring to freedom, not price. Our -General Public Licenses are designed to make sure that you have the freedom -to distribute copies of free software (and charge for this service if you -wish), that you receive source code or can get it if you want it, that you -can change the software or use pieces of it in new free programs; and that -you know you can do these things. - -To protect your rights, we need to make restrictions that forbid anyone to -deny you these rights or to ask you to surrender the rights. These -restrictions translate to certain responsibilities for you if you distribute -copies of the software, or if you modify it. - -For example, if you distribute copies of such a program, whether gratis or -for a fee, you must give the recipients all the rights that you have. You -must make sure that they, too, receive or can get the source code. And you -must show them these terms so they know their rights. - -We protect your rights with two steps: (1) copyright the software, and (2) -offer you this license which gives you legal permission to copy, distribute -and/or modify the software. - -Also, for each author's protection and ours, we want to make certain that -everyone understands that there is no warranty for this free software. If -the software is modified by someone else and passed on, we want its -recipients to know that what they have is not the original, so that any -problems introduced by others will not reflect on the original authors' -reputations. - -Finally, any free program is threatened constantly by software patents. We -wish to avoid the danger that redistributors of a free program will -individually obtain patent licenses, in effect making the program -proprietary. To prevent this, we have made it clear that any patent must be -licensed for everyone's free use or not licensed at all. - -The precise terms and conditions for copying, distribution and modification -follow. - -TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - -0. This License applies to any program or other work which contains a notice - placed by the copyright holder saying it may be distributed under the - terms of this General Public License. The "Program", below, refers to any - such program or work, and a "work based on the Program" means either the - Program or any derivative work under copyright law: that is to say, a - work containing the Program or a portion of it, either verbatim or with - modifications and/or translated into another language. (Hereinafter, - translation is included without limitation in the term "modification".) - Each licensee is addressed as "you". - - Activities other than copying, distribution and modification are not - covered by this License; they are outside its scope. The act of running - the Program is not restricted, and the output from the Program is covered - only if its contents constitute a work based on the Program (independent - of having been made by running the Program). Whether that is true depends - on what the Program does. - -1. You may copy and distribute verbatim copies of the Program's source code - as you receive it, in any medium, provided that you conspicuously and - appropriately publish on each copy an appropriate copyright notice and - disclaimer of warranty; keep intact all the notices that refer to this - License and to the absence of any warranty; and give any other recipients - of the Program a copy of this License along with the Program. - - You may charge a fee for the physical act of transferring a copy, and you - may at your option offer warranty protection in exchange for a fee. - -2. You may modify your copy or copies of the Program or any portion of it, - thus forming a work based on the Program, and copy and distribute such - modifications or work under the terms of Section 1 above, provided that - you also meet all of these conditions: - - * a) You must cause the modified files to carry prominent notices stating - that you changed the files and the date of any change. - - * b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any part - thereof, to be licensed as a whole at no charge to all third parties - under the terms of this License. - - * c) If the modified program normally reads commands interactively when - run, you must cause it, when started running for such interactive - use in the most ordinary way, to print or display an announcement - including an appropriate copyright notice and a notice that there is - no warranty (or else, saying that you provide a warranty) and that - users may redistribute the program under these conditions, and - telling the user how to view a copy of this License. (Exception: if - the Program itself is interactive but does not normally print such - an announcement, your work based on the Program is not required to - print an announcement.) - - These requirements apply to the modified work as a whole. If identifiable - sections of that work are not derived from the Program, and can be - reasonably considered independent and separate works in themselves, then - this License, and its terms, do not apply to those sections when you - distribute them as separate works. But when you distribute the same - sections as part of a whole which is a work based on the Program, the - distribution of the whole must be on the terms of this License, whose - permissions for other licensees extend to the entire whole, and thus to - each and every part regardless of who wrote it. - - Thus, it is not the intent of this section to claim rights or contest - your rights to work written entirely by you; rather, the intent is to - exercise the right to control the distribution of derivative or - collective works based on the Program. - - In addition, mere aggregation of another work not based on the Program - with the Program (or with a work based on the Program) on a volume of a - storage or distribution medium does not bring the other work under the - scope of this License. - -3. You may copy and distribute the Program (or a work based on it, under - Section 2) in object code or executable form under the terms of Sections - 1 and 2 above provided that you also do one of the following: - - * a) Accompany it with the complete corresponding machine-readable source - code, which must be distributed under the terms of Sections 1 and 2 - above on a medium customarily used for software interchange; or, - - * b) Accompany it with a written offer, valid for at least three years, - to give any third party, for a charge no more than your cost of - physically performing source distribution, a complete machine- - readable copy of the corresponding source code, to be distributed - under the terms of Sections 1 and 2 above on a medium customarily - used for software interchange; or, - - * c) Accompany it with the information you received as to the offer to - distribute corresponding source code. (This alternative is allowed - only for noncommercial distribution and only if you received the - program in object code or executable form with such an offer, in - accord with Subsection b above.) - - The source code for a work means the preferred form of the work for - making modifications to it. For an executable work, complete source code - means all the source code for all modules it contains, plus any - associated interface definition files, plus the scripts used to control - compilation and installation of the executable. However, as a special - exception, the source code distributed need not include anything that is - normally distributed (in either source or binary form) with the major - components (compiler, kernel, and so on) of the operating system on which - the executable runs, unless that component itself accompanies the - executable. - - If distribution of executable or object code is made by offering access - to copy from a designated place, then offering equivalent access to copy - the source code from the same place counts as distribution of the source - code, even though third parties are not compelled to copy the source - along with the object code. - -4. You may not copy, modify, sublicense, or distribute the Program except as - expressly provided under this License. Any attempt otherwise to copy, - modify, sublicense or distribute the Program is void, and will - automatically terminate your rights under this License. However, parties - who have received copies, or rights, from you under this License will not - have their licenses terminated so long as such parties remain in full - compliance. - -5. You are not required to accept this License, since you have not signed - it. However, nothing else grants you permission to modify or distribute - the Program or its derivative works. These actions are prohibited by law - if you do not accept this License. Therefore, by modifying or - distributing the Program (or any work based on the Program), you - indicate your acceptance of this License to do so, and all its terms and - conditions for copying, distributing or modifying the Program or works - based on it. - -6. Each time you redistribute the Program (or any work based on the - Program), the recipient automatically receives a license from the - original licensor to copy, distribute or modify the Program subject to - these terms and conditions. You may not impose any further restrictions - on the recipients' exercise of the rights granted herein. You are not - responsible for enforcing compliance by third parties to this License. - -7. If, as a consequence of a court judgment or allegation of patent - infringement or for any other reason (not limited to patent issues), - conditions are imposed on you (whether by court order, agreement or - otherwise) that contradict the conditions of this License, they do not - excuse you from the conditions of this License. If you cannot distribute - so as to satisfy simultaneously your obligations under this License and - any other pertinent obligations, then as a consequence you may not - distribute the Program at all. For example, if a patent license would - not permit royalty-free redistribution of the Program by all those who - receive copies directly or indirectly through you, then the only way you - could satisfy both it and this License would be to refrain entirely from - distribution of the Program. - - If any portion of this section is held invalid or unenforceable under any - particular circumstance, the balance of the section is intended to apply - and the section as a whole is intended to apply in other circumstances. - - It is not the purpose of this section to induce you to infringe any - patents or other property right claims or to contest validity of any - such claims; this section has the sole purpose of protecting the - integrity of the free software distribution system, which is implemented - by public license practices. Many people have made generous contributions - to the wide range of software distributed through that system in - reliance on consistent application of that system; it is up to the - author/donor to decide if he or she is willing to distribute software - through any other system and a licensee cannot impose that choice. - - This section is intended to make thoroughly clear what is believed to be - a consequence of the rest of this License. - -8. If the distribution and/or use of the Program is restricted in certain - countries either by patents or by copyrighted interfaces, the original - copyright holder who places the Program under this License may add an - explicit geographical distribution limitation excluding those countries, - so that distribution is permitted only in or among countries not thus - excluded. In such case, this License incorporates the limitation as if - written in the body of this License. - -9. The Free Software Foundation may publish revised and/or new versions of - the General Public License from time to time. Such new versions will be - similar in spirit to the present version, but may differ in detail to - address new problems or concerns. - - Each version is given a distinguishing version number. If the Program - specifies a version number of this License which applies to it and "any - later version", you have the option of following the terms and - conditions either of that version or of any later version published by - the Free Software Foundation. If the Program does not specify a version - number of this License, you may choose any version ever published by the - Free Software Foundation. - -10. If you wish to incorporate parts of the Program into other free programs - whose distribution conditions are different, write to the author to ask - for permission. For software which is copyrighted by the Free Software - Foundation, write to the Free Software Foundation; we sometimes make - exceptions for this. Our decision will be guided by the two goals of - preserving the free status of all derivatives of our free software and - of promoting the sharing and reuse of software generally. - - NO WARRANTY - -11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY - FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN - OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES - PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER - EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE - ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH - YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL - NECESSARY SERVICING, REPAIR OR CORRECTION. - -12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING - WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR - REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR - DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL - DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM - (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED - INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF - THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR - OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -END OF TERMS AND CONDITIONS - -How to Apply These Terms to Your New Programs - -If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it free -software which everyone can redistribute and change under these terms. - -To do so, attach the following notices to the program. It is safest to -attach them to the start of each source file to most effectively convey the -exclusion of warranty; and each file should have at least the "copyright" -line and a pointer to where the full notice is found. - -one line to give the program's name and an idea of what it does. -Copyright (C) yyyy name of author - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2 of the License, or (at your option) -any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. - -You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., 59 -Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this when -it starts in an interactive mode: - -Gnomovision version 69, Copyright (C) year name of author Gnomovision comes -with ABSOLUTELY NO WARRANTY; for details type 'show w'. This is free -software, and you are welcome to redistribute it under certain conditions; -type 'show c' for details. - -The hypothetical commands 'show w' and 'show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may be -called something other than 'show w' and 'show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - -Yoyodyne, Inc., hereby disclaims all copyright interest in the program -'Gnomovision' (which makes passes at compilers) written by James Hacker. - -signature of Ty Coon, 1 April 1989 -Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General Public -License instead of this License. diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/e100/Makefile 830-ivtv/drivers/net/e100/Makefile --- 000-virgin/drivers/net/e100/Makefile Thu Feb 13 11:08:08 2003 +++ 830-ivtv/drivers/net/e100/Makefile Wed Dec 31 16:00:00 1969 @@ -1,8 +0,0 @@ -# -# Makefile for the Intel's E100 ethernet driver -# - -obj-$(CONFIG_E100) += e100.o - -e100-objs := e100_main.o e100_config.o e100_phy.o \ - e100_eeprom.o e100_test.o diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/e100/e100.h 830-ivtv/drivers/net/e100/e100.h --- 000-virgin/drivers/net/e100/e100.h Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/e100/e100.h Wed Dec 31 16:00:00 1969 @@ -1,999 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -#ifndef _E100_INC_ -#define _E100_INC_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#define E100_CABLE_UNKNOWN 0 -#define E100_CABLE_OK 1 -#define E100_CABLE_OPEN_NEAR 2 /* Open Circuit Near End */ -#define E100_CABLE_OPEN_FAR 3 /* Open Circuit Far End */ -#define E100_CABLE_SHORT_NEAR 4 /* Short Circuit Near End */ -#define E100_CABLE_SHORT_FAR 5 /* Short Circuit Far End */ - -#define E100_REGS_LEN 2 -/* - * Configure parameters for buffers per controller. - * If the machine this is being used on is a faster machine (i.e. > 150MHz) - * and running on a 10MBS network then more queueing of data occurs. This - * may indicate the some of the numbers below should be adjusted. Here are - * some typical numbers: - * MAX_TCB 64 - * MAX_RFD 64 - * The default numbers give work well on most systems tests so no real - * adjustments really need to take place. Also, if the machine is connected - * to a 100MBS network the numbers described above can be lowered from the - * defaults as considerably less data will be queued. - */ - -#define TX_FRAME_CNT 8 /* consecutive transmit frames per interrupt */ -/* TX_FRAME_CNT must be less than MAX_TCB */ - -#define E100_DEFAULT_TCB 64 -#define E100_MIN_TCB 2*TX_FRAME_CNT + 3 /* make room for at least 2 interrupts */ -#define E100_MAX_TCB 1024 - -#define E100_DEFAULT_RFD 64 -#define E100_MIN_RFD 8 -#define E100_MAX_RFD 1024 - -#define E100_DEFAULT_XSUM true -#define E100_DEFAULT_BER ZLOCK_MAX_ERRORS -#define E100_DEFAULT_SPEED_DUPLEX 0 -#define E100_DEFAULT_FC 0 -#define E100_DEFAULT_IFS true -#define E100_DEFAULT_UCODE true - -#define TX_THRSHLD 8 - -/* IFS parameters */ -#define MIN_NUMBER_OF_TRANSMITS_100 1000 -#define MIN_NUMBER_OF_TRANSMITS_10 100 - -#define E100_MAX_NIC 16 - -#define E100_MAX_SCB_WAIT 100 /* Max udelays in wait_scb */ -#define E100_MAX_CU_IDLE_WAIT 50 /* Max udelays in wait_cus_idle */ - -/* HWI feature related constant */ -#define HWI_REGISTER_GRANULARITY 80 /* register granularity = 80 Cm */ -#define HWI_NEAR_END_BOUNDARY 1000 /* Near end is defined as < 10 meters */ - -/* CPUSAVER_BUNDLE_MAX: Sets the maximum number of frames that will be bundled. - * In some situations, such as the TCP windowing algorithm, it may be - * better to limit the growth of the bundle size than let it go as - * high as it can, because that could cause too much added latency. - * The default is six, because this is the number of packets in the - * default TCP window size. A value of 1 would make CPUSaver indicate - * an interrupt for every frame received. If you do not want to put - * a limit on the bundle size, set this value to xFFFF. - */ -#define E100_DEFAULT_CPUSAVER_BUNDLE_MAX 6 -#define E100_DEFAULT_CPUSAVER_INTERRUPT_DELAY 0x600 -#define E100_DEFAULT_BUNDLE_SMALL_FR false - -/* end of configurables */ - -/* ====================================================================== */ -/* hw */ -/* ====================================================================== */ - -/* timeout for command completion */ -#define E100_CMD_WAIT 100 /* iterations */ - -struct driver_stats { - struct net_device_stats net_stats; - - unsigned long tx_late_col; - unsigned long tx_ok_defrd; - unsigned long tx_one_retry; - unsigned long tx_mt_one_retry; - unsigned long rcv_cdt_frames; - unsigned long xmt_fc_pkts; - unsigned long rcv_fc_pkts; - unsigned long rcv_fc_unsupported; - unsigned long xmt_tco_pkts; - unsigned long rcv_tco_pkts; - unsigned long rx_intr_pkts; -}; - -/* TODO: kill me when we can do C99 */ -#define false (0) -#define true (1) - -/* Changed for 82558 and 82559 enhancements */ -/* defines for 82558/9 flow control CSR values */ -#define DFLT_FC_THLD 0x00 /* Rx FIFO threshold of 0.5KB free */ -#define DFLT_FC_CMD 0x00 /* FC Command in CSR */ - -/* ====================================================================== */ -/* equates */ -/* ====================================================================== */ - -/* - * These are general purpose defines - */ - -/* Bit Mask definitions */ -#define BIT_0 0x0001 -#define BIT_1 0x0002 -#define BIT_2 0x0004 -#define BIT_3 0x0008 -#define BIT_4 0x0010 -#define BIT_5 0x0020 -#define BIT_6 0x0040 -#define BIT_7 0x0080 -#define BIT_8 0x0100 -#define BIT_9 0x0200 -#define BIT_10 0x0400 -#define BIT_11 0x0800 -#define BIT_12 0x1000 -#define BIT_13 0x2000 -#define BIT_14 0x4000 -#define BIT_15 0x8000 -#define BIT_28 0x10000000 - -#define BIT_0_2 0x0007 -#define BIT_0_3 0x000F -#define BIT_0_4 0x001F -#define BIT_0_5 0x003F -#define BIT_0_6 0x007F -#define BIT_0_7 0x00FF -#define BIT_0_8 0x01FF -#define BIT_0_13 0x3FFF -#define BIT_0_15 0xFFFF -#define BIT_1_2 0x0006 -#define BIT_1_3 0x000E -#define BIT_2_5 0x003C -#define BIT_3_4 0x0018 -#define BIT_4_5 0x0030 -#define BIT_4_6 0x0070 -#define BIT_4_7 0x00F0 -#define BIT_5_7 0x00E0 -#define BIT_5_12 0x1FE0 -#define BIT_5_15 0xFFE0 -#define BIT_6_7 0x00c0 -#define BIT_7_11 0x0F80 -#define BIT_8_10 0x0700 -#define BIT_9_13 0x3E00 -#define BIT_12_15 0xF000 -#define BIT_8_15 0xFF00 - -#define BIT_16_20 0x001F0000 -#define BIT_21_25 0x03E00000 -#define BIT_26_27 0x0C000000 - -/* Transmit Threshold related constants */ -#define DEFAULT_TX_PER_UNDERRUN 20000 - -#define MAX_MULTICAST_ADDRS 64 -#define MAX_FILTER 16 - -#define FULL_DUPLEX 2 -#define HALF_DUPLEX 1 - -/* - * These defines are specific to the 82557 - */ - -/* E100 PORT functions -- lower 4 bits */ -#define PORT_SOFTWARE_RESET 0 -#define PORT_SELFTEST 1 -#define PORT_SELECTIVE_RESET 2 -#define PORT_DUMP 3 - -/* SCB Status Word bit definitions */ -/* Interrupt status/ack fields */ -/* ER and FCP interrupts for 82558 masks */ -#define SCB_STATUS_ACK_MASK BIT_8_15 /* Status Mask */ -#define SCB_STATUS_ACK_CX BIT_15 /* CU Completed Action Cmd */ -#define SCB_STATUS_ACK_FR BIT_14 /* RU Received A Frame */ -#define SCB_STATUS_ACK_CNA BIT_13 /* CU Became Inactive (IDLE) */ -#define SCB_STATUS_ACK_RNR BIT_12 /* RU Became Not Ready */ -#define SCB_STATUS_ACK_MDI BIT_11 /* MDI read or write done */ -#define SCB_STATUS_ACK_SWI BIT_10 /* S/W generated interrupt */ -#define SCB_STATUS_ACK_ER BIT_9 /* Early Receive */ -#define SCB_STATUS_ACK_FCP BIT_8 /* Flow Control Pause */ - -/*- CUS Fields */ -#define SCB_CUS_MASK (BIT_6 | BIT_7) /* CUS 2-bit Mask */ -#define SCB_CUS_IDLE 0 /* CU Idle */ -#define SCB_CUS_SUSPEND BIT_6 /* CU Suspended */ -#define SCB_CUS_ACTIVE BIT_7 /* CU Active */ - -/*- RUS Fields */ -#define SCB_RUS_IDLE 0 /* RU Idle */ -#define SCB_RUS_MASK BIT_2_5 /* RUS 3-bit Mask */ -#define SCB_RUS_SUSPEND BIT_2 /* RU Suspended */ -#define SCB_RUS_NO_RESOURCES BIT_3 /* RU Out Of Resources */ -#define SCB_RUS_READY BIT_4 /* RU Ready */ -#define SCB_RUS_SUSP_NO_RBDS (BIT_2 | BIT_5) /* RU No More RBDs */ -#define SCB_RUS_NO_RBDS (BIT_3 | BIT_5) /* RU No More RBDs */ -#define SCB_RUS_READY_NO_RBDS (BIT_4 | BIT_5) /* RU Ready, No RBDs */ - -/* SCB Command Word bit definitions */ -/*- CUC fields */ -/* Changing mask to 4 bits */ -#define SCB_CUC_MASK BIT_4_7 /* CUC 4-bit Mask */ -#define SCB_CUC_NOOP 0 -#define SCB_CUC_START BIT_4 /* CU Start */ -#define SCB_CUC_RESUME BIT_5 /* CU Resume */ -#define SCB_CUC_UNKNOWN BIT_7 /* CU unknown command */ -/* Changed for 82558 enhancements */ -#define SCB_CUC_STATIC_RESUME (BIT_5 | BIT_7) /* 82558/9 Static Resume */ -#define SCB_CUC_DUMP_ADDR BIT_6 /* CU Dump Counters Address */ -#define SCB_CUC_DUMP_STAT (BIT_4 | BIT_6) /* CU Dump stat. counters */ -#define SCB_CUC_LOAD_BASE (BIT_5 | BIT_6) /* Load the CU base */ -/* Below was defined as BIT_4_7 */ -#define SCB_CUC_DUMP_RST_STAT BIT_4_6 /* CU Dump & reset statistics cntrs */ - -/*- RUC fields */ -#define SCB_RUC_MASK BIT_0_2 /* RUC 3-bit Mask */ -#define SCB_RUC_START BIT_0 /* RU Start */ -#define SCB_RUC_RESUME BIT_1 /* RU Resume */ -#define SCB_RUC_ABORT BIT_2 /* RU Abort */ -#define SCB_RUC_LOAD_HDS (BIT_0 | BIT_2) /* Load RFD Header Data Size */ -#define SCB_RUC_LOAD_BASE (BIT_1 | BIT_2) /* Load the RU base */ -#define SCB_RUC_RBD_RESUME BIT_0_2 /* RBD resume */ - -/* Interrupt fields (assuming byte addressing) */ -#define SCB_INT_MASK BIT_0 /* Mask interrupts */ -#define SCB_SOFT_INT BIT_1 /* Generate a S/W interrupt */ -/* Specific Interrupt Mask Bits (upper byte of SCB Command word) */ -#define SCB_FCP_INT_MASK BIT_2 /* Flow Control Pause */ -#define SCB_ER_INT_MASK BIT_3 /* Early Receive */ -#define SCB_RNR_INT_MASK BIT_4 /* RU Not Ready */ -#define SCB_CNA_INT_MASK BIT_5 /* CU Not Active */ -#define SCB_FR_INT_MASK BIT_6 /* Frame Received */ -#define SCB_CX_INT_MASK BIT_7 /* CU eXecution w/ I-bit done */ -#define SCB_BACHELOR_INT_MASK BIT_2_7 /* 82558 interrupt mask bits */ - -#define SCB_GCR2_EEPROM_ACCESS_SEMAPHORE BIT_7 - -/* EEPROM bit definitions */ -/*- EEPROM control register bits */ -#define EEPROM_FLAG_ASF 0x8000 -#define EEPROM_FLAG_GCL 0x4000 - -#define EN_TRNF 0x10 /* Enable turnoff */ -#define EEDO 0x08 /* EEPROM data out */ -#define EEDI 0x04 /* EEPROM data in (set for writing data) */ -#define EECS 0x02 /* EEPROM chip select (1=hi, 0=lo) */ -#define EESK 0x01 /* EEPROM shift clock (1=hi, 0=lo) */ - -/*- EEPROM opcodes */ -#define EEPROM_READ_OPCODE 06 -#define EEPROM_WRITE_OPCODE 05 -#define EEPROM_ERASE_OPCODE 07 -#define EEPROM_EWEN_OPCODE 19 /* Erase/write enable */ -#define EEPROM_EWDS_OPCODE 16 /* Erase/write disable */ - -/*- EEPROM data locations */ -#define EEPROM_NODE_ADDRESS_BYTE_0 0 -#define EEPROM_COMPATIBILITY_WORD 3 -#define EEPROM_PWA_NO 8 -#define EEPROM_ID_WORD 0x0A -#define EEPROM_CONFIG_ASF 0x0D -#define EEPROM_SMBUS_ADDR 0x90 - -#define EEPROM_SUM 0xbaba - -// Zero Locking Algorithm definitions: -#define ZLOCK_ZERO_MASK 0x00F0 -#define ZLOCK_MAX_READS 50 -#define ZLOCK_SET_ZERO 0x2010 -#define ZLOCK_MAX_SLEEP 300 * HZ -#define ZLOCK_MAX_ERRORS 300 - -/* E100 Action Commands */ -#define CB_IA_ADDRESS 1 -#define CB_CONFIGURE 2 -#define CB_MULTICAST 3 -#define CB_TRANSMIT 4 -#define CB_LOAD_MICROCODE 5 -#define CB_LOAD_FILTER 8 -#define CB_MAX_NONTX_CMD 9 -#define CB_IPCB_TRANSMIT 9 - -/* Pre-defined Filter Bits */ -#define CB_FILTER_EL 0x80000000 -#define CB_FILTER_FIX 0x40000000 -#define CB_FILTER_ARP 0x08000000 -#define CB_FILTER_IA_MATCH 0x02000000 - -/* Command Block (CB) Field Definitions */ -/*- CB Command Word */ -#define CB_EL_BIT BIT_15 /* CB EL Bit */ -#define CB_S_BIT BIT_14 /* CB Suspend Bit */ -#define CB_I_BIT BIT_13 /* CB Interrupt Bit */ -#define CB_TX_SF_BIT BIT_3 /* TX CB Flexible Mode */ -#define CB_CMD_MASK BIT_0_3 /* CB 4-bit CMD Mask */ -#define CB_CID_DEFAULT (0x1f << 8) /* CB 5-bit CID (max value) */ - -/*- CB Status Word */ -#define CB_STATUS_MASK BIT_12_15 /* CB Status Mask (4-bits) */ -#define CB_STATUS_COMPLETE BIT_15 /* CB Complete Bit */ -#define CB_STATUS_OK BIT_13 /* CB OK Bit */ -#define CB_STATUS_VLAN BIT_12 /* CB Valn detected Bit */ -#define CB_STATUS_FAIL BIT_11 /* CB Fail (F) Bit */ - -/*misc command bits */ -#define CB_TX_EOF_BIT BIT_15 /* TX CB/TBD EOF Bit */ - -/* Config params */ -#define CB_CFIG_BYTE_COUNT 22 /* 22 config bytes */ -#define CB_CFIG_D102_BYTE_COUNT 10 - -/* Receive Frame Descriptor Fields */ - -/*- RFD Status Bits */ -#define RFD_RECEIVE_COLLISION BIT_0 /* Collision detected on Receive */ -#define RFD_IA_MATCH BIT_1 /* Indv Address Match Bit */ -#define RFD_RX_ERR BIT_4 /* RX_ERR pin on Phy was set */ -#define RFD_FRAME_TOO_SHORT BIT_7 /* Receive Frame Short */ -#define RFD_DMA_OVERRUN BIT_8 /* Receive DMA Overrun */ -#define RFD_NO_RESOURCES BIT_9 /* No Buffer Space */ -#define RFD_ALIGNMENT_ERROR BIT_10 /* Alignment Error */ -#define RFD_CRC_ERROR BIT_11 /* CRC Error */ -#define RFD_STATUS_OK BIT_13 /* RFD OK Bit */ -#define RFD_STATUS_COMPLETE BIT_15 /* RFD Complete Bit */ - -/*- RFD Command Bits*/ -#define RFD_EL_BIT BIT_15 /* RFD EL Bit */ -#define RFD_S_BIT BIT_14 /* RFD Suspend Bit */ -#define RFD_H_BIT BIT_4 /* Header RFD Bit */ -#define RFD_SF_BIT BIT_3 /* RFD Flexible Mode */ - -/*- RFD misc bits*/ -#define RFD_EOF_BIT BIT_15 /* RFD End-Of-Frame Bit */ -#define RFD_F_BIT BIT_14 /* RFD Buffer Fetch Bit */ -#define RFD_ACT_COUNT_MASK BIT_0_13 /* RFD Actual Count Mask */ - -/* Receive Buffer Descriptor Fields*/ -#define RBD_EOF_BIT BIT_15 /* RBD End-Of-Frame Bit */ -#define RBD_F_BIT BIT_14 /* RBD Buffer Fetch Bit */ -#define RBD_ACT_COUNT_MASK BIT_0_13 /* RBD Actual Count Mask */ - -#define SIZE_FIELD_MASK BIT_0_13 /* Size of the associated buffer */ -#define RBD_EL_BIT BIT_15 /* RBD EL Bit */ - -/* Self Test Results*/ -#define CB_SELFTEST_FAIL_BIT BIT_12 -#define CB_SELFTEST_DIAG_BIT BIT_5 -#define CB_SELFTEST_REGISTER_BIT BIT_3 -#define CB_SELFTEST_ROM_BIT BIT_2 - -#define CB_SELFTEST_ERROR_MASK ( \ - CB_SELFTEST_FAIL_BIT | CB_SELFTEST_DIAG_BIT | \ - CB_SELFTEST_REGISTER_BIT | CB_SELFTEST_ROM_BIT) - -/* adapter vendor & device ids */ -#define PCI_OHIO_BOARD 0x10f0 /* subdevice ID, Ohio dual port nic */ - -/* Values for PCI_REV_ID_REGISTER values */ -#define D101A4_REV_ID 4 /* 82558 A4 stepping */ -#define D101B0_REV_ID 5 /* 82558 B0 stepping */ -#define D101MA_REV_ID 8 /* 82559 A0 stepping */ -#define D101S_REV_ID 9 /* 82559S A-step */ -#define D102_REV_ID 12 -#define D102C_REV_ID 13 /* 82550 step C */ -#define D102E_REV_ID 15 - -/* ############Start of 82555 specific defines################## */ - -#define PHY_82555_LED_SWITCH_CONTROL 0x1b /* 82555 led switch control register */ - -/* 82555 led switch control reg. opcodes */ -#define PHY_82555_LED_NORMAL_CONTROL 0 // control back to the 8255X -#define PHY_82555_LED_DRIVER_CONTROL BIT_2 // the driver is in control -#define PHY_82555_LED_OFF BIT_2 // activity LED is off -#define PHY_82555_LED_ON_559 (BIT_0 | BIT_2) // activity LED is on for 559 and later -#define PHY_82555_LED_ON_PRE_559 (BIT_0 | BIT_1 | BIT_2) // activity LED is on for 558 and before - -// Describe the state of the phy led. -// needed for the function : 'e100_blink_timer' -enum led_state_e { - LED_OFF = 0, - LED_ON, -}; - -/* ############End of 82555 specific defines##################### */ - -#define RFD_PARSE_BIT BIT_3 -#define RFD_TCP_PACKET 0x00 -#define RFD_UDP_PACKET 0x01 -#define TCPUDP_CHECKSUM_BIT_VALID BIT_4 -#define TCPUDP_CHECKSUM_VALID BIT_5 -#define CHECKSUM_PROTOCOL_MASK 0x03 - -#define VLAN_SIZE 4 -#define CHKSUM_SIZE 2 -#define RFD_DATA_SIZE (ETH_FRAME_LEN + CHKSUM_SIZE + VLAN_SIZE) - -/* Bits for bdp->flags */ -#define DF_LINK_FC_CAP 0x00000001 /* Link is flow control capable */ -#define DF_CSUM_OFFLOAD 0x00000002 -#define DF_UCODE_LOADED 0x00000004 -#define USE_IPCB 0x00000008 /* set if using ipcb for transmits */ -#define IS_BACHELOR 0x00000010 /* set if 82558 or newer board */ -#define IS_ICH 0x00000020 -#define DF_SPEED_FORCED 0x00000040 /* set if speed is forced */ -#define LED_IS_ON 0x00000080 /* LED is turned ON by the driver */ -#define DF_LINK_FC_TX_ONLY 0x00000100 /* Received PAUSE frames are honored*/ - -typedef struct net_device_stats net_dev_stats_t; - -/* needed macros */ -/* These macros use the bdp pointer. If you use them it better be defined */ -#define PREV_TCB_USED(X) ((X).tail ? (X).tail - 1 : bdp->params.TxDescriptors - 1) -#define NEXT_TCB_TOUSE(X) ((((X) + 1) >= bdp->params.TxDescriptors) ? 0 : (X) + 1) -#define TCB_TO_USE(X) ((X).tail) -#define TCBS_AVAIL(X) (NEXT_TCB_TOUSE( NEXT_TCB_TOUSE((X).tail)) != (X).head) - -#define RFD_POINTER(skb,bdp) ((rfd_t *) (((unsigned char *)((skb)->data))-((bdp)->rfd_size))) -#define SKB_RFD_STATUS(skb,bdp) ((RFD_POINTER((skb),(bdp)))->rfd_header.cb_status) - -/* ====================================================================== */ -/* 82557 */ -/* ====================================================================== */ - -/* Changed for 82558 enhancement */ -typedef struct _d101_scb_ext_t { - u32 scb_rx_dma_cnt; /* Rx DMA byte count */ - u8 scb_early_rx_int; /* Early Rx DMA byte count */ - u8 scb_fc_thld; /* Flow Control threshold */ - u8 scb_fc_xon_xoff; /* Flow Control XON/XOFF values */ - u8 scb_pmdr; /* Power Mgmt. Driver Reg */ -} d101_scb_ext __attribute__ ((__packed__)); - -/* Changed for 82559 enhancement */ -typedef struct _d101m_scb_ext_t { - u32 scb_rx_dma_cnt; /* Rx DMA byte count */ - u8 scb_early_rx_int; /* Early Rx DMA byte count */ - u8 scb_fc_thld; /* Flow Control threshold */ - u8 scb_fc_xon_xoff; /* Flow Control XON/XOFF values */ - u8 scb_pmdr; /* Power Mgmt. Driver Reg */ - u8 scb_gen_ctrl; /* General Control */ - u8 scb_gen_stat; /* General Status */ - u16 scb_reserved; /* Reserved */ - u32 scb_function_event; /* Cardbus Function Event */ - u32 scb_function_event_mask; /* Cardbus Function Mask */ - u32 scb_function_present_state; /* Cardbus Function state */ - u32 scb_force_event; /* Cardbus Force Event */ -} d101m_scb_ext __attribute__ ((__packed__)); - -/* Changed for 82550 enhancement */ -typedef struct _d102_scb_ext_t { - u32 scb_rx_dma_cnt; /* Rx DMA byte count */ - u8 scb_early_rx_int; /* Early Rx DMA byte count */ - u8 scb_fc_thld; /* Flow Control threshold */ - u8 scb_fc_xon_xoff; /* Flow Control XON/XOFF values */ - u8 scb_pmdr; /* Power Mgmt. Driver Reg */ - u8 scb_gen_ctrl; /* General Control */ - u8 scb_gen_stat; /* General Status */ - u8 scb_gen_ctrl2; - u8 scb_reserved; /* Reserved */ - u32 scb_scheduling_reg; - u32 scb_reserved2; - u32 scb_function_event; /* Cardbus Function Event */ - u32 scb_function_event_mask; /* Cardbus Function Mask */ - u32 scb_function_present_state; /* Cardbus Function state */ - u32 scb_force_event; /* Cardbus Force Event */ -} d102_scb_ext __attribute__ ((__packed__)); - -/* - * 82557 status control block. this will be memory mapped & will hang of the - * the bdp, which hangs of the bdp. This is the brain of it. - */ -typedef struct _scb_t { - u16 scb_status; /* SCB Status register */ - u8 scb_cmd_low; /* SCB Command register (low byte) */ - u8 scb_cmd_hi; /* SCB Command register (high byte) */ - u32 scb_gen_ptr; /* SCB General pointer */ - u32 scb_port; /* PORT register */ - u16 scb_flsh_cntrl; /* Flash Control register */ - u16 scb_eprm_cntrl; /* EEPROM control register */ - u32 scb_mdi_cntrl; /* MDI Control Register */ - /* Changed for 82558 enhancement */ - union { - u32 scb_rx_dma_cnt; /* Rx DMA byte count */ - d101_scb_ext d101_scb; /* 82558/9 specific fields */ - d101m_scb_ext d101m_scb; /* 82559 specific fields */ - d102_scb_ext d102_scb; - } scb_ext; -} scb_t __attribute__ ((__packed__)); - -/* Self test - * This is used to dump results of the self test - */ -typedef struct _self_test_t { - u32 st_sign; /* Self Test Signature */ - u32 st_result; /* Self Test Results */ -} self_test_t __attribute__ ((__packed__)); - -/* - * Statistical Counters - */ -/* 82557 counters */ -typedef struct _basic_cntr_t { - u32 xmt_gd_frames; /* Good frames transmitted */ - u32 xmt_max_coll; /* Fatal frames -- had max collisions */ - u32 xmt_late_coll; /* Fatal frames -- had a late coll. */ - u32 xmt_uruns; /* Xmit underruns (fatal or re-transmit) */ - u32 xmt_lost_crs; /* Frames transmitted without CRS */ - u32 xmt_deferred; /* Deferred transmits */ - u32 xmt_sngl_coll; /* Transmits that had 1 and only 1 coll. */ - u32 xmt_mlt_coll; /* Transmits that had multiple coll. */ - u32 xmt_ttl_coll; /* Transmits that had 1+ collisions. */ - u32 rcv_gd_frames; /* Good frames received */ - u32 rcv_crc_errs; /* Aligned frames that had a CRC error */ - u32 rcv_algn_errs; /* Receives that had alignment errors */ - u32 rcv_rsrc_err; /* Good frame dropped cuz no resources */ - u32 rcv_oruns; /* Overrun errors - bus was busy */ - u32 rcv_err_coll; /* Received frms. that encountered coll. */ - u32 rcv_shrt_frames; /* Received frames that were to short */ -} basic_cntr_t; - -/* 82558 extended statistic counters */ -typedef struct _ext_cntr_t { - u32 xmt_fc_frames; - u32 rcv_fc_frames; - u32 rcv_fc_unsupported; -} ext_cntr_t; - -/* 82559 TCO statistic counters */ -typedef struct _tco_cntr_t { - u16 xmt_tco_frames; - u16 rcv_tco_frames; -} tco_cntr_t; - -/* Structures to access thet physical dump area */ -/* Use one of these types, according to the statisitcal counters mode, - to cast the pointer to the physical dump area and access the cmd_complete - DWORD. */ - -/* 557-mode : only basic counters + cmd_complete */ -typedef struct _err_cntr_557_t { - basic_cntr_t basic_stats; - u32 cmd_complete; -} err_cntr_557_t; - -/* 558-mode : basic + extended counters + cmd_complete */ -typedef struct _err_cntr_558_t { - basic_cntr_t basic_stats; - ext_cntr_t extended_stats; - u32 cmd_complete; -} err_cntr_558_t; - -/* 559-mode : basic + extended + TCO counters + cmd_complete */ -typedef struct _err_cntr_559_t { - basic_cntr_t basic_stats; - ext_cntr_t extended_stats; - tco_cntr_t tco_stats; - u32 cmd_complete; -} err_cntr_559_t; - -/* This typedef defines the struct needed to hold the largest number of counters */ -typedef err_cntr_559_t max_counters_t; - -/* Different statistical-counters mode the controller may be in */ -typedef enum _stat_mode_t { - E100_BASIC_STATS = 0, /* 82557 stats : 16 counters / 16 dw */ - E100_EXTENDED_STATS, /* 82558 stats : 19 counters / 19 dw */ - E100_TCO_STATS /* 82559 stats : 21 counters / 20 dw */ -} stat_mode_t; - -/* dump statistical counters complete codes */ -#define DUMP_STAT_COMPLETED 0xA005 -#define DUMP_RST_STAT_COMPLETED 0xA007 - -/* Command Block (CB) Generic Header Structure*/ -typedef struct _cb_header_t { - u16 cb_status; /* Command Block Status */ - u16 cb_cmd; /* Command Block Command */ - u32 cb_lnk_ptr; /* Link To Next CB */ -} cb_header_t __attribute__ ((__packed__)); - -//* Individual Address Command Block (IA_CB)*/ -typedef struct _ia_cb_t { - cb_header_t ia_cb_hdr; - u8 ia_addr[ETH_ALEN]; -} ia_cb_t __attribute__ ((__packed__)); - -/* Configure Command Block (CONFIG_CB)*/ -typedef struct _config_cb_t { - cb_header_t cfg_cbhdr; - u8 cfg_byte[CB_CFIG_BYTE_COUNT + CB_CFIG_D102_BYTE_COUNT]; -} config_cb_t __attribute__ ((__packed__)); - -/* MultiCast Command Block (MULTICAST_CB)*/ -typedef struct _multicast_cb_t { - cb_header_t mc_cbhdr; - u16 mc_count; /* Number of multicast addresses */ - u8 mc_addr[(ETH_ALEN * MAX_MULTICAST_ADDRS)]; -} mltcst_cb_t __attribute__ ((__packed__)); - -#define UCODE_MAX_DWORDS 134 -/* Load Microcode Command Block (LOAD_UCODE_CB)*/ -typedef struct _load_ucode_cb_t { - cb_header_t load_ucode_cbhdr; - u32 ucode_dword[UCODE_MAX_DWORDS]; -} load_ucode_cb_t __attribute__ ((__packed__)); - -/* Load Programmable Filter Data*/ -typedef struct _filter_cb_t { - cb_header_t filter_cb_hdr; - u32 filter_data[MAX_FILTER]; -} filter_cb_t __attribute__ ((__packed__)); - -/* NON_TRANSMIT_CB -- Generic Non-Transmit Command Block - */ -typedef struct _nxmit_cb_t { - union { - config_cb_t config; - ia_cb_t setup; - load_ucode_cb_t load_ucode; - mltcst_cb_t multicast; - filter_cb_t filter; - } ntcb; -} nxmit_cb_t __attribute__ ((__packed__)); - -/*Block for queuing for postponed execution of the non-transmit commands*/ -typedef struct _nxmit_cb_entry_t { - struct list_head list_elem; - nxmit_cb_t *non_tx_cmd; - dma_addr_t dma_addr; - unsigned long expiration_time; -} nxmit_cb_entry_t; - -/* States for postponed non tx commands execution */ -typedef enum _non_tx_cmd_state_t { - E100_NON_TX_IDLE = 0, /* No queued NON-TX commands */ - E100_WAIT_TX_FINISH, /* Wait for completion of the TX activities */ - E100_WAIT_NON_TX_FINISH /* Wait for completion of the non TX command */ -} non_tx_cmd_state_t; - -/* some defines for the ipcb */ -#define IPCB_IP_CHECKSUM_ENABLE BIT_4 -#define IPCB_TCPUDP_CHECKSUM_ENABLE BIT_5 -#define IPCB_TCP_PACKET BIT_6 -#define IPCB_LARGESEND_ENABLE BIT_7 -#define IPCB_HARDWAREPARSING_ENABLE BIT_0 -#define IPCB_INSERTVLAN_ENABLE BIT_1 -#define IPCB_IP_ACTIVATION_DEFAULT IPCB_HARDWAREPARSING_ENABLE - -/* Transmit Buffer Descriptor (TBD)*/ -typedef struct _tbd_t { - u32 tbd_buf_addr; /* Physical Transmit Buffer Address */ - u16 tbd_buf_cnt; /* Actual Count Of Bytes */ - u16 padd; -} tbd_t __attribute__ ((__packed__)); - -/* d102 specific fields */ -typedef struct _tcb_ipcb_t { - u16 schedule_low; - u8 ip_schedule; - u8 ip_activation_high; - u16 vlan; - u8 ip_header_offset; - u8 tcp_header_offset; - union { - u32 sec_rec_phys_addr; - u32 tbd_zero_address; - } tbd_sec_addr; - union { - u16 sec_rec_size; - u16 tbd_zero_size; - } tbd_sec_size; - u16 total_tcp_payload; -} tcb_ipcb_t __attribute__ ((__packed__)); - -#define E100_TBD_ARRAY_SIZE (2+MAX_SKB_FRAGS) - -/* Transmit Command Block (TCB)*/ -struct _tcb_t { - cb_header_t tcb_hdr; - u32 tcb_tbd_ptr; /* TBD address */ - u16 tcb_cnt; /* Data Bytes In TCB past header */ - u8 tcb_thrshld; /* TX Threshold for FIFO Extender */ - u8 tcb_tbd_num; - - union { - tcb_ipcb_t ipcb; /* d102 ipcb fields */ - tbd_t tbd_array[E100_TBD_ARRAY_SIZE]; - } tcbu; - - /* From here onward we can dump anything we want as long as the - * size of the total structure is a multiple of a paragraph - * boundary ( i.e. -16 bit aligned ). - */ - tbd_t *tbd_ptr; - - u32 tcb_tbd_dflt_ptr; /* TBD address for non-segmented packet */ - u32 tcb_tbd_expand_ptr; /* TBD address for segmented packet */ - - struct sk_buff *tcb_skb; /* the associated socket buffer */ - dma_addr_t tcb_phys; /* phys addr of the TCB */ -} __attribute__ ((__packed__)); - -#define _TCB_T_ -typedef struct _tcb_t tcb_t; - -/* Receive Frame Descriptor (RFD) - will be using the simple model*/ -struct _rfd_t { - /* 8255x */ - cb_header_t rfd_header; - u32 rfd_rbd_ptr; /* Receive Buffer Descriptor Addr */ - u16 rfd_act_cnt; /* Number Of Bytes Received */ - u16 rfd_sz; /* Number Of Bytes In RFD */ - /* D102 aka Gamla */ - u16 vlanid; - u8 rcvparserstatus; - u8 reserved; - u16 securitystatus; - u8 checksumstatus; - u8 zerocopystatus; - u8 pad[8]; /* data should be 16 byte aligned */ - u8 data[RFD_DATA_SIZE]; - -} __attribute__ ((__packed__)); - -#define _RFD_T_ -typedef struct _rfd_t rfd_t; - -/* Receive Buffer Descriptor (RBD)*/ -typedef struct _rbd_t { - u16 rbd_act_cnt; /* Number Of Bytes Received */ - u16 rbd_filler; - u32 rbd_lnk_addr; /* Link To Next RBD */ - u32 rbd_rcb_addr; /* Receive Buffer Address */ - u16 rbd_sz; /* Receive Buffer Size */ - u16 rbd_filler1; -} rbd_t __attribute__ ((__packed__)); - -/* - * This structure is used to maintain a FIFO access to a resource that is - * maintained as a circular queue. The resource to be maintained is pointed - * to by the "data" field in the structure below. In this driver the TCBs', - * TBDs' & RFDs' are maintained as a circular queue & are managed thru this - * structure. - */ -typedef struct _buf_pool_t { - unsigned int head; /* index to first used resource */ - unsigned int tail; /* index to last used resource */ - void *data; /* points to resource pool */ -} buf_pool_t; - -/*Rx skb holding structure*/ -struct rx_list_elem { - struct list_head list_elem; - dma_addr_t dma_addr; - struct sk_buff *skb; -}; - -enum next_cu_cmd_e { RESUME_NO_WAIT = 0, RESUME_WAIT, START_WAIT }; -enum zlock_state_e { ZLOCK_INITIAL, ZLOCK_READING, ZLOCK_SLEEPING }; -enum tx_queue_stop_type { LONG_STOP = 0, SHORT_STOP }; - -/* 64 bit aligned size */ -#define E100_SIZE_64A(X) ((sizeof(X) + 7) & ~0x7) - -typedef struct _bd_dma_able_t { - char selftest[E100_SIZE_64A(self_test_t)]; - char stats_counters[E100_SIZE_64A(max_counters_t)]; -} bd_dma_able_t; - -/* bit masks for bool parameters */ -#define PRM_XSUMRX 0x00000001 -#define PRM_UCODE 0x00000002 -#define PRM_FC 0x00000004 -#define PRM_IFS 0x00000008 -#define PRM_BUNDLE_SMALL 0x00000010 - -struct cfg_params { - int e100_speed_duplex; - int RxDescriptors; - int TxDescriptors; - int IntDelay; - int BundleMax; - int ber; - u32 b_params; -}; -struct ethtool_lpbk_data{ - dma_addr_t dma_handle; - tcb_t *tcb; - rfd_t *rfd; - -}; - -struct e100_private { - struct vlan_group *vlgrp; - u32 flags; /* board management flags */ - u32 tx_per_underrun; /* number of good tx frames per underrun */ - unsigned int tx_count; /* count of tx frames, so we can request an interrupt */ - u8 tx_thld; /* stores transmit threshold */ - u16 eeprom_size; - u32 pwa_no; /* PWA: xxxxxx-0xx */ - u8 perm_node_address[ETH_ALEN]; - struct list_head active_rx_list; /* list of rx buffers */ - struct list_head rx_struct_pool; /* pool of rx buffer struct headers */ - u16 rfd_size; /* size of the adapter's RFD struct */ - int skb_req; /* number of skbs neede by the adapter */ - u8 intr_mask; /* mask for interrupt status */ - - void *dma_able; /* dma allocated structs */ - dma_addr_t dma_able_phys; - self_test_t *selftest; /* pointer to self test area */ - dma_addr_t selftest_phys; /* phys addr of selftest */ - max_counters_t *stats_counters; /* pointer to stats table */ - dma_addr_t stat_cnt_phys; /* phys addr of stat counter area */ - - stat_mode_t stat_mode; /* statistics mode: extended, TCO, basic */ - scb_t *scb; /* memory mapped ptr to 82557 scb */ - - tcb_t *last_tcb; /* pointer to last tcb sent */ - buf_pool_t tcb_pool; /* adapter's TCB array */ - dma_addr_t tcb_phys; /* phys addr of start of TCBs */ - - u16 cur_line_speed; - u16 cur_dplx_mode; - - struct net_device *device; - struct pci_dev *pdev; - struct driver_stats drv_stats; - - u8 rev_id; /* adapter PCI revision ID */ - - unsigned int phy_addr; /* address of PHY component */ - unsigned int PhyId; /* ID of PHY component */ - unsigned int PhyState; /* state for the fix squelch algorithm */ - unsigned int PhyDelay; /* delay for the fix squelch algorithm */ - - /* Lock defintions for the driver */ - spinlock_t bd_lock; /* board lock */ - spinlock_t bd_non_tx_lock; /* Non transmit command lock */ - spinlock_t config_lock; /* config block lock */ - spinlock_t mdi_access_lock; /* mdi lock */ - - struct timer_list watchdog_timer; /* watchdog timer id */ - - /* non-tx commands parameters */ - struct timer_list nontx_timer_id; /* non-tx timer id */ - struct list_head non_tx_cmd_list; - non_tx_cmd_state_t non_tx_command_state; - nxmit_cb_entry_t *same_cmd_entry[CB_MAX_NONTX_CMD]; - - enum next_cu_cmd_e next_cu_cmd; - - /* Zero Locking Algorithm data members */ - enum zlock_state_e zlock_state; - u8 zlock_read_data[16]; /* number of times each value 0-15 was read */ - u16 zlock_read_cnt; /* counts number of reads */ - ulong zlock_sleep_cnt; /* keeps track of "sleep" time */ - - u8 config[CB_CFIG_BYTE_COUNT + CB_CFIG_D102_BYTE_COUNT]; - - /* IFS params */ - u8 ifs_state; - u8 ifs_value; - - struct cfg_params params; /* adapter's command line parameters */ - - u32 speed_duplex_caps; /* adapter's speed/duplex capabilities */ - - /* WOL params for ethtool */ - u32 wolsupported; - u32 wolopts; - u16 ip_lbytes; - struct ethtool_lpbk_data loopback; - struct timer_list blink_timer; /* led blink timer id */ - -#ifdef CONFIG_PM - u32 pci_state[16]; -#endif -#ifdef E100_CU_DEBUG - u8 last_cmd; - u8 last_sub_cmd; -#endif -}; - -#define E100_AUTONEG 0 -#define E100_SPEED_10_HALF 1 -#define E100_SPEED_10_FULL 2 -#define E100_SPEED_100_HALF 3 -#define E100_SPEED_100_FULL 4 - -/********* function prototypes *************/ -extern int e100_open(struct net_device *); -extern int e100_close(struct net_device *); -extern void e100_isolate_driver(struct e100_private *bdp); -extern unsigned char e100_hw_init(struct e100_private *); -extern void e100_sw_reset(struct e100_private *bdp, u32 reset_cmd); -extern u8 e100_start_cu(struct e100_private *bdp, tcb_t *tcb); -extern void e100_free_non_tx_cmd(struct e100_private *bdp, - nxmit_cb_entry_t *non_tx_cmd); -extern nxmit_cb_entry_t *e100_alloc_non_tx_cmd(struct e100_private *bdp); -extern unsigned char e100_exec_non_cu_cmd(struct e100_private *bdp, - nxmit_cb_entry_t *cmd); -extern unsigned char e100_selftest(struct e100_private *bdp, u32 *st_timeout, - u32 *st_result); -extern unsigned char e100_get_link_state(struct e100_private *bdp); -extern unsigned char e100_wait_scb(struct e100_private *bdp); - -extern void e100_deisolate_driver(struct e100_private *bdp, u8 full_reset); -extern unsigned char e100_configure_device(struct e100_private *bdp); -#ifdef E100_CU_DEBUG -extern unsigned char e100_cu_unknown_state(struct e100_private *bdp); -#endif - -#define ROM_TEST_FAIL 0x01 -#define REGISTER_TEST_FAIL 0x02 -#define SELF_TEST_FAIL 0x04 -#define TEST_TIMEOUT 0x08 - -enum test_offsets { - test_link, - test_eeprom, - test_self_test, - test_loopback_mac, - test_loopback_phy, - cable_diag, - max_test_res, /* must be last */ -}; - -#endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/e100/e100_config.c 830-ivtv/drivers/net/e100/e100_config.c --- 000-virgin/drivers/net/e100/e100_config.c Thu Jan 8 08:35:38 2004 +++ 830-ivtv/drivers/net/e100/e100_config.c Wed Dec 31 16:00:00 1969 @@ -1,639 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -/********************************************************************** -* * -* INTEL CORPORATION * -* * -* This software is supplied under the terms of the license included * -* above. All use of this driver must be in accordance with the terms * -* of that license. * -* * -* Module Name: e100_config.c * -* * -* Abstract: Functions for configuring the network adapter. * -* * -* Environment: This file is intended to be specific to the Linux * -* operating system. * -* * -**********************************************************************/ -#include "e100_config.h" - -static void e100_config_long_rx(struct e100_private *bdp, unsigned char enable); - -static const u8 def_config[] = { - CB_CFIG_BYTE_COUNT, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x32, 0x07, 0x01, - 0x00, 0x2e, 0x00, 0x60, 0x00, 0xf2, 0xc8, 0x00, - 0x40, 0xf2, 0x80, 0x3f, 0x05 -}; - -/** - * e100_config_init_82557 - config the 82557 adapter - * @bdp: atapter's private data struct - * - * This routine will initialize the 82557 configure block. - * All other init functions will only set values that are - * different from the 82557 default. - */ -void -e100_config_init_82557(struct e100_private *bdp) -{ - /* initialize config block */ - memcpy(bdp->config, def_config, sizeof (def_config)); - bdp->config[0] = CB_CFIG_BYTE_COUNT; /* just in case */ - - e100_config_ifs(bdp); - - /* - * Enable extended statistical counters (82558 and up) and TCO counters - * (82559 and up) and set the statistical counters' mode in bdp - * - * stat. mode | TCO stat. bit (2) | Extended stat. bit (5) - * ------------------------------------------------------------------ - * Basic (557) | 0 | 1 - * ------------------------------------------------------------------ - * Extended (558) | 0 | 0 - * ------------------------------------------------------------------ - * TCO (559) | 1 | 1 - * ------------------------------------------------------------------ - * Reserved | 1 | 0 - * ------------------------------------------------------------------ - */ - bdp->config[6] &= ~CB_CFIG_TCO_STAT; - bdp->config[6] |= CB_CFIG_EXT_STAT_DIS; - bdp->stat_mode = E100_BASIC_STATS; - - /* Setup for MII or 503 operation. The CRS+CDT bit should only be set */ - /* when operating in 503 mode. */ - if (bdp->phy_addr == 32) { - bdp->config[8] &= ~CB_CFIG_503_MII; - bdp->config[15] |= CB_CFIG_CRS_OR_CDT; - } else { - bdp->config[8] |= CB_CFIG_503_MII; - bdp->config[15] &= ~CB_CFIG_CRS_OR_CDT; - } - - e100_config_fc(bdp); - e100_config_force_dplx(bdp); - e100_config_promisc(bdp, false); - e100_config_mulcast_enbl(bdp, false); -} - -static void -e100_config_init_82558(struct e100_private *bdp) -{ - /* MWI enable. This should be turned on only if the adapter is a 82558/9 - * and if the PCI command reg. has enabled the MWI bit. */ - bdp->config[3] |= CB_CFIG_MWI_EN; - - bdp->config[6] &= ~CB_CFIG_EXT_TCB_DIS; - - if (bdp->rev_id >= D101MA_REV_ID) { - /* this is 82559 and up - enable TCO counters */ - bdp->config[6] |= CB_CFIG_TCO_STAT; - bdp->config[6] |= CB_CFIG_EXT_STAT_DIS; - bdp->stat_mode = E100_TCO_STATS; - - if ((bdp->rev_id < D102_REV_ID) && - (bdp->params.b_params & PRM_XSUMRX) && - (bdp->pdev->device != 0x1209)) { - - bdp->flags |= DF_CSUM_OFFLOAD; - bdp->config[9] |= 1; - } - } else { - /* this is 82558 */ - bdp->config[6] &= ~CB_CFIG_TCO_STAT; - bdp->config[6] &= ~CB_CFIG_EXT_STAT_DIS; - bdp->stat_mode = E100_EXTENDED_STATS; - } - - e100_config_long_rx(bdp, true); -} - -static void -e100_config_init_82550(struct e100_private *bdp) -{ - /* The D102 chip allows for 32 config bytes. This value is - * supposed to be in Byte 0. Just add the extra bytes to - * what was already setup in the block. */ - bdp->config[0] += CB_CFIG_D102_BYTE_COUNT; - - /* now we need to enable the extended RFD. When this is - * enabled, the immediated receive data buffer starts at offset - * 32 from the RFD base address, instead of at offset 16. */ - bdp->config[7] |= CB_CFIG_EXTENDED_RFD; - - /* put the chip into D102 receive mode. This is necessary - * for any parsing and offloading features. */ - bdp->config[22] = CB_CFIG_RECEIVE_GAMLA_MODE; - - /* set the flag if checksum offloading was enabled */ - if (bdp->params.b_params & PRM_XSUMRX) { - bdp->flags |= DF_CSUM_OFFLOAD; - } -} - -/* Initialize the adapter's configure block */ -void -e100_config_init(struct e100_private *bdp) -{ - e100_config_init_82557(bdp); - - if (bdp->flags & IS_BACHELOR) - e100_config_init_82558(bdp); - - if (bdp->rev_id >= D102_REV_ID) - e100_config_init_82550(bdp); -} - -/** - * e100_force_config - force a configure command - * @bdp: atapter's private data struct - * - * This routine will force a configure command to the adapter. - * The command will be executed in polled mode as interrupts - * are _disabled_ at this time. - * - * Returns: - * true: if the configure command was successfully issued and completed - * false: otherwise - */ -unsigned char -e100_force_config(struct e100_private *bdp) -{ - spin_lock_bh(&(bdp->config_lock)); - - bdp->config[0] = CB_CFIG_BYTE_COUNT; - if (bdp->rev_id >= D102_REV_ID) { - /* The D102 chip allows for 32 config bytes. This value is - supposed to be in Byte 0. Just add the extra bytes to - what was already setup in the block. */ - bdp->config[0] += CB_CFIG_D102_BYTE_COUNT; - } - - spin_unlock_bh(&(bdp->config_lock)); - - // although we call config outside the lock, there is no - // race condition because config byte count has maximum value - return e100_config(bdp); -} - -/** - * e100_config - issue a configure command - * @bdp: atapter's private data struct - * - * This routine will issue a configure command to the 82557. - * This command will be executed in polled mode as interrupts - * are _disabled_ at this time. - * - * Returns: - * true: if the configure command was successfully issued and completed - * false: otherwise - */ -unsigned char -e100_config(struct e100_private *bdp) -{ - cb_header_t *pntcb_hdr; - unsigned char res = true; - nxmit_cb_entry_t *cmd; - - if (bdp->config[0] == 0) { - goto exit; - } - - if ((cmd = e100_alloc_non_tx_cmd(bdp)) == NULL) { - res = false; - goto exit; - } - - pntcb_hdr = (cb_header_t *) cmd->non_tx_cmd; - pntcb_hdr->cb_cmd = __constant_cpu_to_le16(CB_CONFIGURE); - - spin_lock_bh(&bdp->config_lock); - - if (bdp->config[0] < CB_CFIG_MIN_PARAMS) { - bdp->config[0] = CB_CFIG_MIN_PARAMS; - } - - /* Copy the device's config block to the device's memory */ - memcpy(cmd->non_tx_cmd->ntcb.config.cfg_byte, bdp->config, - bdp->config[0]); - /* reset number of bytes to config next time */ - bdp->config[0] = 0; - - spin_unlock_bh(&bdp->config_lock); - - res = e100_exec_non_cu_cmd(bdp, cmd); - -exit: - if (netif_running(bdp->device)) - netif_wake_queue(bdp->device); - return res; -} - -/** - * e100_config_fc - config flow-control state - * @bdp: adapter's private data struct - * - * This routine will enable or disable flow control support in the adapter's - * config block. Flow control will be enable only if requested using the command - * line option, and if the link is flow-contorl capable (both us and the link - * partner). But, if link partner is capable of autoneg, but not capable of - * flow control, received PAUSE frames are still honored. - */ -void -e100_config_fc(struct e100_private *bdp) -{ - unsigned char enable = false; - /* 82557 doesn't support fc. Don't touch this option */ - if (!(bdp->flags & IS_BACHELOR)) - return; - - /* Enable fc if requested and if the link supports it */ - if ((bdp->params.b_params & PRM_FC) && (bdp->flags & - (DF_LINK_FC_CAP | DF_LINK_FC_TX_ONLY))) { - enable = true; - } - - spin_lock_bh(&(bdp->config_lock)); - - if (enable) { - if (bdp->flags & DF_LINK_FC_TX_ONLY) { - /* If link partner is capable of autoneg, but */ - /* not capable of flow control, Received PAUSE */ - /* frames are still honored, i.e., */ - /* transmitted frames would be paused by */ - /* incoming PAUSE frames */ - bdp->config[16] = DFLT_NO_FC_DELAY_LSB; - bdp->config[17] = DFLT_NO_FC_DELAY_MSB; - bdp->config[19] &= ~(CB_CFIG_FC_RESTOP | CB_CFIG_FC_RESTART); - bdp->config[19] |= CB_CFIG_FC_REJECT; - bdp->config[19] &= ~CB_CFIG_TX_FC_DIS; - } else { - bdp->config[16] = DFLT_FC_DELAY_LSB; - bdp->config[17] = DFLT_FC_DELAY_MSB; - bdp->config[19] |= CB_CFIG_FC_OPTS; - bdp->config[19] &= ~CB_CFIG_TX_FC_DIS; - } - } else { - bdp->config[16] = DFLT_NO_FC_DELAY_LSB; - bdp->config[17] = DFLT_NO_FC_DELAY_MSB; - bdp->config[19] &= ~CB_CFIG_FC_OPTS; - bdp->config[19] |= CB_CFIG_TX_FC_DIS; - } - E100_CONFIG(bdp, 19); - spin_unlock_bh(&(bdp->config_lock)); - - return; -} - -/** - * e100_config_promisc - configure promiscuous mode - * @bdp: atapter's private data struct - * @enable: should we enable this option or not - * - * This routine will enable or disable promiscuous mode - * in the adapter's config block. - */ -void -e100_config_promisc(struct e100_private *bdp, unsigned char enable) -{ - spin_lock_bh(&(bdp->config_lock)); - - /* if in promiscuous mode, save bad frames */ - if (enable) { - - if (!(bdp->config[6] & CB_CFIG_SAVE_BAD_FRAMES)) { - bdp->config[6] |= CB_CFIG_SAVE_BAD_FRAMES; - E100_CONFIG(bdp, 6); - } - - if (bdp->config[7] & (u8) BIT_0) { - bdp->config[7] &= (u8) (~BIT_0); - E100_CONFIG(bdp, 7); - } - - if (!(bdp->config[15] & CB_CFIG_PROMISCUOUS)) { - bdp->config[15] |= CB_CFIG_PROMISCUOUS; - E100_CONFIG(bdp, 15); - } - - } else { /* not in promiscuous mode */ - - if (bdp->config[6] & CB_CFIG_SAVE_BAD_FRAMES) { - bdp->config[6] &= ~CB_CFIG_SAVE_BAD_FRAMES; - E100_CONFIG(bdp, 6); - } - - if (!(bdp->config[7] & (u8) BIT_0)) { - bdp->config[7] |= (u8) (BIT_0); - E100_CONFIG(bdp, 7); - } - - if (bdp->config[15] & CB_CFIG_PROMISCUOUS) { - bdp->config[15] &= ~CB_CFIG_PROMISCUOUS; - E100_CONFIG(bdp, 15); - } - } - - spin_unlock_bh(&(bdp->config_lock)); -} - -/** - * e100_config_mulcast_enbl - configure allmulti mode - * @bdp: atapter's private data struct - * @enable: should we enable this option or not - * - * This routine will enable or disable reception of all multicast packets - * in the adapter's config block. - */ -void -e100_config_mulcast_enbl(struct e100_private *bdp, unsigned char enable) -{ - spin_lock_bh(&(bdp->config_lock)); - - /* this flag is used to enable receiving all multicast packet */ - if (enable) { - if (!(bdp->config[21] & CB_CFIG_MULTICAST_ALL)) { - bdp->config[21] |= CB_CFIG_MULTICAST_ALL; - E100_CONFIG(bdp, 21); - } - - } else { - if (bdp->config[21] & CB_CFIG_MULTICAST_ALL) { - bdp->config[21] &= ~CB_CFIG_MULTICAST_ALL; - E100_CONFIG(bdp, 21); - } - } - - spin_unlock_bh(&(bdp->config_lock)); -} - -/** - * e100_config_ifs - configure the IFS parameter - * @bdp: atapter's private data struct - * - * This routine will configure the adaptive IFS value - * in the adapter's config block. IFS values are only - * relevant in half duplex, so set to 0 in full duplex. - */ -void -e100_config_ifs(struct e100_private *bdp) -{ - u8 value = 0; - - spin_lock_bh(&(bdp->config_lock)); - - /* IFS value is only needed to be specified at half-duplex mode */ - if (bdp->cur_dplx_mode == HALF_DUPLEX) { - value = (u8) bdp->ifs_value; - } - - if (bdp->config[2] != value) { - bdp->config[2] = value; - E100_CONFIG(bdp, 2); - } - - spin_unlock_bh(&(bdp->config_lock)); -} - -/** - * e100_config_force_dplx - configure the forced full duplex mode - * @bdp: atapter's private data struct - * - * This routine will enable or disable force full duplex - * in the adapter's config block. If the PHY is 503, and - * the duplex is full, consider the adapter forced. - */ -void -e100_config_force_dplx(struct e100_private *bdp) -{ - spin_lock_bh(&(bdp->config_lock)); - - /* We must force full duplex on if we are using PHY 0, and we are */ - /* supposed to run in FDX mode. We do this because the e100 has only */ - /* one FDX# input pin, and that pin will be connected to PHY 1. */ - /* Changed the 'if' condition below to fix performance problem * at 10 - * full. The Phy was getting forced to full duplex while the MAC * was - * not, because the cur_dplx_mode was not being set to 2 by SetupPhy. * - * This is how the condition was, initially. * This has been changed so - * that the MAC gets forced to full duplex * simply if the user has - * forced full duplex. * * if (( bdp->phy_addr == 0 ) && ( - * bdp->cur_dplx_mode == 2 )) */ - /* The rest of the fix is in the PhyDetect code. */ - if ((bdp->params.e100_speed_duplex == E100_SPEED_10_FULL) || - (bdp->params.e100_speed_duplex == E100_SPEED_100_FULL) || - ((bdp->phy_addr == 32) && (bdp->cur_dplx_mode == FULL_DUPLEX))) { - if (!(bdp->config[19] & (u8) CB_CFIG_FORCE_FDX)) { - bdp->config[19] |= (u8) CB_CFIG_FORCE_FDX; - E100_CONFIG(bdp, 19); - } - - } else { - if (bdp->config[19] & (u8) CB_CFIG_FORCE_FDX) { - bdp->config[19] &= (u8) (~CB_CFIG_FORCE_FDX); - E100_CONFIG(bdp, 19); - } - } - - spin_unlock_bh(&(bdp->config_lock)); -} - -/** - * e100_config_long_rx - * @bdp: atapter's private data struct - * @enable: should we enable this option or not - * - * This routine will enable or disable reception of larger packets. - * This is needed by VLAN implementations. - */ -static void -e100_config_long_rx(struct e100_private *bdp, unsigned char enable) -{ - if (enable) { - if (!(bdp->config[18] & CB_CFIG_LONG_RX_OK)) { - bdp->config[18] |= CB_CFIG_LONG_RX_OK; - E100_CONFIG(bdp, 18); - } - - } else { - if ((bdp->config[18] & CB_CFIG_LONG_RX_OK)) { - bdp->config[18] &= ~CB_CFIG_LONG_RX_OK; - E100_CONFIG(bdp, 18); - } - } -} - -/** - * e100_config_wol - * @bdp: atapter's private data struct - * - * This sets configuration options for PHY and Magic Packet WoL - */ -void -e100_config_wol(struct e100_private *bdp) -{ - spin_lock_bh(&(bdp->config_lock)); - - if (bdp->wolopts & WAKE_PHY) { - bdp->config[9] |= CB_LINK_STATUS_WOL; - } - else { - /* Disable PHY WoL */ - bdp->config[9] &= ~CB_LINK_STATUS_WOL; - } - - if (bdp->wolopts & WAKE_MAGIC) { - bdp->config[19] &= ~CB_DISABLE_MAGPAK_WAKE; - } - else { - /* Disable Magic Packet WoL */ - bdp->config[19] |= CB_DISABLE_MAGPAK_WAKE; - } - - E100_CONFIG(bdp, 19); - spin_unlock_bh(&(bdp->config_lock)); -} - -void -e100_config_vlan_drop(struct e100_private *bdp, unsigned char enable) -{ - spin_lock_bh(&(bdp->config_lock)); - if (enable) { - if (!(bdp->config[22] & CB_CFIG_VLAN_DROP_ENABLE)) { - bdp->config[22] |= CB_CFIG_VLAN_DROP_ENABLE; - E100_CONFIG(bdp, 22); - } - - } else { - if ((bdp->config[22] & CB_CFIG_VLAN_DROP_ENABLE)) { - bdp->config[22] &= ~CB_CFIG_VLAN_DROP_ENABLE; - E100_CONFIG(bdp, 22); - } - } - spin_unlock_bh(&(bdp->config_lock)); -} - -/** - * e100_config_loopback_mode - * @bdp: atapter's private data struct - * @mode: loopback mode(phy/mac/none) - * - */ -unsigned char -e100_config_loopback_mode(struct e100_private *bdp, u8 mode) -{ - unsigned char bc_changed = false; - u8 config_byte; - - spin_lock_bh(&(bdp->config_lock)); - - switch (mode) { - case NO_LOOPBACK: - config_byte = CB_CFIG_LOOPBACK_NORMAL; - break; - case MAC_LOOPBACK: - config_byte = CB_CFIG_LOOPBACK_INTERNAL; - break; - case PHY_LOOPBACK: - config_byte = CB_CFIG_LOOPBACK_EXTERNAL; - break; - default: - printk(KERN_NOTICE "e100: e100_config_loopback_mode: " - "Invalid argument 'mode': %d\n", mode); - goto exit; - } - - if ((bdp->config[10] & CB_CFIG_LOOPBACK_MODE) != config_byte) { - - bdp->config[10] &= (~CB_CFIG_LOOPBACK_MODE); - bdp->config[10] |= config_byte; - E100_CONFIG(bdp, 10); - bc_changed = true; - } - -exit: - spin_unlock_bh(&(bdp->config_lock)); - return bc_changed; -} -unsigned char -e100_config_tcb_ext_enable(struct e100_private *bdp, unsigned char enable) -{ - unsigned char bc_changed = false; - - spin_lock_bh(&(bdp->config_lock)); - - if (enable) { - if (bdp->config[6] & CB_CFIG_EXT_TCB_DIS) { - - bdp->config[6] &= (~CB_CFIG_EXT_TCB_DIS); - E100_CONFIG(bdp, 6); - bc_changed = true; - } - - } else { - if (!(bdp->config[6] & CB_CFIG_EXT_TCB_DIS)) { - - bdp->config[6] |= CB_CFIG_EXT_TCB_DIS; - E100_CONFIG(bdp, 6); - bc_changed = true; - } - } - spin_unlock_bh(&(bdp->config_lock)); - - return bc_changed; -} -unsigned char -e100_config_dynamic_tbd(struct e100_private *bdp, unsigned char enable) -{ - unsigned char bc_changed = false; - - spin_lock_bh(&(bdp->config_lock)); - - if (enable) { - if (!(bdp->config[7] & CB_CFIG_DYNTBD_EN)) { - - bdp->config[7] |= CB_CFIG_DYNTBD_EN; - E100_CONFIG(bdp, 7); - bc_changed = true; - } - - } else { - if (bdp->config[7] & CB_CFIG_DYNTBD_EN) { - - bdp->config[7] &= (~CB_CFIG_DYNTBD_EN); - E100_CONFIG(bdp, 7); - bc_changed = true; - } - } - spin_unlock_bh(&(bdp->config_lock)); - - return bc_changed; -} - diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/e100/e100_config.h 830-ivtv/drivers/net/e100/e100_config.h --- 000-virgin/drivers/net/e100/e100_config.h Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/e100/e100_config.h Wed Dec 31 16:00:00 1969 @@ -1,168 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -#ifndef _E100_CONFIG_INC_ -#define _E100_CONFIG_INC_ - -#include "e100.h" - -#define E100_CONFIG(bdp, X) ((bdp)->config[0] = max_t(u8, (bdp)->config[0], (X)+1)) - -#define CB_CFIG_MIN_PARAMS 8 - -/* byte 0 bit definitions*/ -#define CB_CFIG_BYTE_COUNT_MASK BIT_0_5 /* Byte count occupies bit 5-0 */ - -/* byte 1 bit definitions*/ -#define CB_CFIG_RXFIFO_LIMIT_MASK BIT_0_4 /* RxFifo limit mask */ -#define CB_CFIG_TXFIFO_LIMIT_MASK BIT_4_7 /* TxFifo limit mask */ - -/* byte 2 bit definitions -- ADAPTIVE_IFS*/ - -/* word 3 bit definitions -- RESERVED*/ -/* Changed for 82558 enhancements */ -/* byte 3 bit definitions */ -#define CB_CFIG_MWI_EN BIT_0 /* Enable MWI on PCI bus */ -#define CB_CFIG_TYPE_EN BIT_1 /* Type Enable */ -#define CB_CFIG_READAL_EN BIT_2 /* Enable Read Align */ -#define CB_CFIG_TERMCL_EN BIT_3 /* Cache line write */ - -/* byte 4 bit definitions*/ -#define CB_CFIG_RX_MIN_DMA_MASK BIT_0_6 /* Rx minimum DMA count mask */ - -/* byte 5 bit definitions*/ -#define CB_CFIG_TX_MIN_DMA_MASK BIT_0_6 /* Tx minimum DMA count mask */ -#define CB_CFIG_DMBC_EN BIT_7 /* Enable Tx/Rx min. DMA counts */ - -/* Changed for 82558 enhancements */ -/* byte 6 bit definitions*/ -#define CB_CFIG_LATE_SCB BIT_0 /* Update SCB After New Tx Start */ -#define CB_CFIG_DIRECT_DMA_DIS BIT_1 /* Direct DMA mode */ -#define CB_CFIG_TNO_INT BIT_2 /* Tx Not OK Interrupt */ -#define CB_CFIG_TCO_STAT BIT_2 /* TCO statistics in 559 and above */ -#define CB_CFIG_CI_INT BIT_3 /* Command Complete Interrupt */ -#define CB_CFIG_EXT_TCB_DIS BIT_4 /* Extended TCB */ -#define CB_CFIG_EXT_STAT_DIS BIT_5 /* Extended Stats */ -#define CB_CFIG_SAVE_BAD_FRAMES BIT_7 /* Save Bad Frames Enabled */ - -/* byte 7 bit definitions*/ -#define CB_CFIG_DISC_SHORT_FRAMES BIT_0 /* Discard Short Frames */ -#define CB_CFIG_DYNTBD_EN BIT_7 /* Enable dynamic TBD */ -/* Enable extended RFD's on D102 */ -#define CB_CFIG_EXTENDED_RFD BIT_5 - -/* byte 8 bit definitions*/ -#define CB_CFIG_503_MII BIT_0 /* 503 vs. MII mode */ - -/* byte 9 bit definitions -- pre-defined all zeros*/ -#define CB_LINK_STATUS_WOL BIT_5 - -/* byte 10 bit definitions*/ -#define CB_CFIG_NO_SRCADR BIT_3 /* No Source Address Insertion */ -#define CB_CFIG_PREAMBLE_LEN BIT_4_5 /* Preamble Length */ -#define CB_CFIG_LOOPBACK_MODE BIT_6_7 /* Loopback Mode */ -#define CB_CFIG_LOOPBACK_NORMAL 0 -#define CB_CFIG_LOOPBACK_INTERNAL BIT_6 -#define CB_CFIG_LOOPBACK_EXTERNAL BIT_6_7 - -/* byte 11 bit definitions*/ -#define CB_CFIG_LINEAR_PRIORITY BIT_0_2 /* Linear Priority */ - -/* byte 12 bit definitions*/ -#define CB_CFIG_LINEAR_PRI_MODE BIT_0 /* Linear Priority mode */ -#define CB_CFIG_IFS_MASK BIT_4_7 /* Interframe Spacing mask */ - -/* byte 13 bit definitions -- pre-defined all zeros*/ - -/* byte 14 bit definitions -- pre-defined 0xf2*/ - -/* byte 15 bit definitions*/ -#define CB_CFIG_PROMISCUOUS BIT_0 /* Promiscuous Mode Enable */ -#define CB_CFIG_BROADCAST_DIS BIT_1 /* Broadcast Mode Disable */ -#define CB_CFIG_CRS_OR_CDT BIT_7 /* CRS Or CDT */ - -/* byte 16 bit definitions -- pre-defined all zeros*/ -#define DFLT_FC_DELAY_LSB 0x1f /* Delay for outgoing Pause frames */ -#define DFLT_NO_FC_DELAY_LSB 0x00 /* no flow control default value */ - -/* byte 17 bit definitions -- pre-defined 0x40*/ -#define DFLT_FC_DELAY_MSB 0x01 /* Delay for outgoing Pause frames */ -#define DFLT_NO_FC_DELAY_MSB 0x40 /* no flow control default value */ - -/* byte 18 bit definitions*/ -#define CB_CFIG_STRIPPING BIT_0 /* Padding Disabled */ -#define CB_CFIG_PADDING BIT_1 /* Padding Disabled */ -#define CB_CFIG_CRC_IN_MEM BIT_2 /* Transfer CRC To Memory */ - -/* byte 19 bit definitions*/ -#define CB_CFIG_TX_ADDR_WAKE BIT_0 /* Address Wakeup */ -#define CB_DISABLE_MAGPAK_WAKE BIT_1 /* Magic Packet Wakeup disable */ -/* Changed TX_FC_EN to TX_FC_DIS because 0 enables, 1 disables. Jul 8, 1999 */ -#define CB_CFIG_TX_FC_DIS BIT_2 /* Tx Flow Control Disable */ -#define CB_CFIG_FC_RESTOP BIT_3 /* Rx Flow Control Restop */ -#define CB_CFIG_FC_RESTART BIT_4 /* Rx Flow Control Restart */ -#define CB_CFIG_FC_REJECT BIT_5 /* Rx Flow Control Restart */ -#define CB_CFIG_FC_OPTS (CB_CFIG_FC_RESTOP | CB_CFIG_FC_RESTART | CB_CFIG_FC_REJECT) - -/* end 82558/9 specifics */ - -#define CB_CFIG_FORCE_FDX BIT_6 /* Force Full Duplex */ -#define CB_CFIG_FDX_ENABLE BIT_7 /* Full Duplex Enabled */ - -/* byte 20 bit definitions*/ -#define CB_CFIG_MULTI_IA BIT_6 /* Multiple IA Addr */ - -/* byte 21 bit definitions*/ -#define CB_CFIG_MULTICAST_ALL BIT_3 /* Multicast All */ - -/* byte 22 bit defines */ -#define CB_CFIG_RECEIVE_GAMLA_MODE BIT_0 /* D102 receive mode */ -#define CB_CFIG_VLAN_DROP_ENABLE BIT_1 /* vlan stripping */ - -#define CB_CFIG_LONG_RX_OK BIT_3 - -#define NO_LOOPBACK 0 -#define MAC_LOOPBACK 0x01 -#define PHY_LOOPBACK 0x02 - -/* function prototypes */ -extern void e100_config_init(struct e100_private *bdp); -extern void e100_config_init_82557(struct e100_private *bdp); -extern unsigned char e100_force_config(struct e100_private *bdp); -extern unsigned char e100_config(struct e100_private *bdp); -extern void e100_config_fc(struct e100_private *bdp); -extern void e100_config_promisc(struct e100_private *bdp, unsigned char enable); -extern void e100_config_brdcast_dsbl(struct e100_private *bdp); -extern void e100_config_mulcast_enbl(struct e100_private *bdp, - unsigned char enable); -extern void e100_config_ifs(struct e100_private *bdp); -extern void e100_config_force_dplx(struct e100_private *bdp); -extern u8 e100_config_loopback_mode(struct e100_private *bdp, u8 mode); -extern u8 e100_config_dynamic_tbd(struct e100_private *bdp, u8 enable); -extern u8 e100_config_tcb_ext_enable(struct e100_private *bdp, u8 enable); -extern void e100_config_vlan_drop(struct e100_private *bdp, unsigned char enable); -#endif /* _E100_CONFIG_INC_ */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/e100/e100_eeprom.c 830-ivtv/drivers/net/e100/e100_eeprom.c --- 000-virgin/drivers/net/e100/e100_eeprom.c Wed Mar 26 22:54:32 2003 +++ 830-ivtv/drivers/net/e100/e100_eeprom.c Wed Dec 31 16:00:00 1969 @@ -1,565 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -/********************************************************************** -* * -* INTEL CORPORATION * -* * -* This software is supplied under the terms of the license included * -* above. All use of this driver must be in accordance with the terms * -* of that license. * -* * -* Module Name: e100_eeprom.c * -* * -* Abstract: This module contains routines to read and write to a * -* serial EEPROM * -* * -* Environment: This file is intended to be specific to the Linux * -* operating system. * -* * -**********************************************************************/ -#include "e100.h" - -#define CSR_EEPROM_CONTROL_FIELD(bdp) ((bdp)->scb->scb_eprm_cntrl) - -#define CSR_GENERAL_CONTROL2_FIELD(bdp) \ - ((bdp)->scb->scb_ext.d102_scb.scb_gen_ctrl2) - -#define EEPROM_STALL_TIME 4 -#define EEPROM_CHECKSUM ((u16) 0xBABA) -#define EEPROM_MAX_WORD_SIZE 256 - -void e100_eeprom_cleanup(struct e100_private *adapter); -u16 e100_eeprom_calculate_chksum(struct e100_private *adapter); -static void e100_eeprom_write_word(struct e100_private *adapter, u16 reg, - u16 data); -void e100_eeprom_write_block(struct e100_private *adapter, u16 start, u16 *data, - u16 size); -u16 e100_eeprom_size(struct e100_private *adapter); -u16 e100_eeprom_read(struct e100_private *adapter, u16 reg); - -static void shift_out_bits(struct e100_private *adapter, u16 data, u16 count); -static u16 shift_in_bits(struct e100_private *adapter); -static void raise_clock(struct e100_private *adapter, u16 *x); -static void lower_clock(struct e100_private *adapter, u16 *x); -static u16 eeprom_wait_cmd_done(struct e100_private *adapter); -static void eeprom_stand_by(struct e100_private *adapter); - -//---------------------------------------------------------------------------------------- -// Procedure: eeprom_set_semaphore -// -// Description: This function set (write 1) Gamla EEPROM semaphore bit (bit 23 word 0x1C in the CSR). -// -// Arguments: -// Adapter - Adapter context -// -// Returns: true if success -// else return false -// -//---------------------------------------------------------------------------------------- - -inline u8 -eeprom_set_semaphore(struct e100_private *adapter) -{ - u16 data = 0; - unsigned long expiration_time = jiffies + HZ / 100 + 1; - - do { - // Get current value of General Control 2 - data = readb(&CSR_GENERAL_CONTROL2_FIELD(adapter)); - - // Set bit 23 word 0x1C in the CSR. - data |= SCB_GCR2_EEPROM_ACCESS_SEMAPHORE; - writeb(data, &CSR_GENERAL_CONTROL2_FIELD(adapter)); - - // Check to see if this bit set or not. - data = readb(&CSR_GENERAL_CONTROL2_FIELD(adapter)); - - if (data & SCB_GCR2_EEPROM_ACCESS_SEMAPHORE) { - return true; - } - - if (time_before(jiffies, expiration_time)) - yield(); - else - return false; - - } while (true); -} - -//---------------------------------------------------------------------------------------- -// Procedure: eeprom_reset_semaphore -// -// Description: This function reset (write 0) Gamla EEPROM semaphore bit -// (bit 23 word 0x1C in the CSR). -// -// Arguments: struct e100_private * adapter - Adapter context -//---------------------------------------------------------------------------------------- - -inline void -eeprom_reset_semaphore(struct e100_private *adapter) -{ - u16 data = 0; - - data = readb(&CSR_GENERAL_CONTROL2_FIELD(adapter)); - data &= ~(SCB_GCR2_EEPROM_ACCESS_SEMAPHORE); - writeb(data, &CSR_GENERAL_CONTROL2_FIELD(adapter)); -} - -//---------------------------------------------------------------------------------------- -// Procedure: e100_eeprom_size -// -// Description: This routine determines the size of the EEPROM. This value should be -// checked for validity - ie. is it too big or too small. The size returned -// is then passed to the read/write functions. -// -// Returns: -// Size of the eeprom, or zero if an error occurred -//---------------------------------------------------------------------------------------- -u16 -e100_eeprom_size(struct e100_private *adapter) -{ - u16 x, size = 1; // must be one to accumulate a product - - // if we've already stored this data, read from memory - if (adapter->eeprom_size) { - return adapter->eeprom_size; - } - // otherwise, read from the eeprom - // Set EEPROM semaphore. - if (adapter->rev_id >= D102_REV_ID) { - if (!eeprom_set_semaphore(adapter)) - return 0; - } - // enable the eeprom by setting EECS. - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - x &= ~(EEDI | EEDO | EESK); - x |= EECS; - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - - // write the read opcode - shift_out_bits(adapter, EEPROM_READ_OPCODE, 3); - - // experiment to discover the size of the eeprom. request register zero - // and wait for the eeprom to tell us it has accepted the entire address. - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - do { - size *= 2; // each bit of address doubles eeprom size - x |= EEDO; // set bit to detect "dummy zero" - x &= ~EEDI; // address consists of all zeros - - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - readw(&(adapter->scb->scb_status)); - udelay(EEPROM_STALL_TIME); - raise_clock(adapter, &x); - lower_clock(adapter, &x); - - // check for "dummy zero" - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - if (size > EEPROM_MAX_WORD_SIZE) { - size = 0; - break; - } - } while (x & EEDO); - - // read in the value requested - (void) shift_in_bits(adapter); - e100_eeprom_cleanup(adapter); - - // Clear EEPROM Semaphore. - if (adapter->rev_id >= D102_REV_ID) { - eeprom_reset_semaphore(adapter); - } - - return size; -} - -//---------------------------------------------------------------------------------------- -// Procedure: eeprom_address_size -// -// Description: determines the number of bits in an address for the eeprom acceptable -// values are 64, 128, and 256 -// Arguments: size of the eeprom -// Returns: bits in an address for that size eeprom -//---------------------------------------------------------------------------------------- - -static inline int -eeprom_address_size(u16 size) -{ - int isize = size; - - return (ffs(isize) - 1); -} - -//---------------------------------------------------------------------------------------- -// Procedure: e100_eeprom_read -// -// Description: This routine serially reads one word out of the EEPROM. -// -// Arguments: -// adapter - our adapter context -// reg - EEPROM word to read. -// -// Returns: -// Contents of EEPROM word (reg). -//---------------------------------------------------------------------------------------- - -u16 -e100_eeprom_read(struct e100_private *adapter, u16 reg) -{ - u16 x, data, bits; - - // Set EEPROM semaphore. - if (adapter->rev_id >= D102_REV_ID) { - if (!eeprom_set_semaphore(adapter)) - return 0; - } - // eeprom size is initialized to zero - if (!adapter->eeprom_size) - adapter->eeprom_size = e100_eeprom_size(adapter); - - bits = eeprom_address_size(adapter->eeprom_size); - - // select EEPROM, reset bits, set EECS - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - - x &= ~(EEDI | EEDO | EESK); - x |= EECS; - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - - // write the read opcode and register number in that order - // The opcode is 3bits in length, reg is 'bits' bits long - shift_out_bits(adapter, EEPROM_READ_OPCODE, 3); - shift_out_bits(adapter, reg, bits); - - // Now read the data (16 bits) in from the selected EEPROM word - data = shift_in_bits(adapter); - - e100_eeprom_cleanup(adapter); - - // Clear EEPROM Semaphore. - if (adapter->rev_id >= D102_REV_ID) { - eeprom_reset_semaphore(adapter); - } - - return data; -} - -//---------------------------------------------------------------------------------------- -// Procedure: shift_out_bits -// -// Description: This routine shifts data bits out to the EEPROM. -// -// Arguments: -// data - data to send to the EEPROM. -// count - number of data bits to shift out. -// -// Returns: (none) -//---------------------------------------------------------------------------------------- - -static void -shift_out_bits(struct e100_private *adapter, u16 data, u16 count) -{ - u16 x, mask; - - mask = 1 << (count - 1); - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - x &= ~(EEDO | EEDI); - - do { - x &= ~EEDI; - if (data & mask) - x |= EEDI; - - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - readw(&(adapter->scb->scb_status)); /* flush command to card */ - udelay(EEPROM_STALL_TIME); - raise_clock(adapter, &x); - lower_clock(adapter, &x); - mask = mask >> 1; - } while (mask); - - x &= ~EEDI; - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); -} - -//---------------------------------------------------------------------------------------- -// Procedure: raise_clock -// -// Description: This routine raises the EEPROM's clock input (EESK) -// -// Arguments: -// x - Ptr to the EEPROM control register's current value -// -// Returns: (none) -//---------------------------------------------------------------------------------------- - -void -raise_clock(struct e100_private *adapter, u16 *x) -{ - *x = *x | EESK; - writew(*x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - readw(&(adapter->scb->scb_status)); /* flush command to card */ - udelay(EEPROM_STALL_TIME); -} - -//---------------------------------------------------------------------------------------- -// Procedure: lower_clock -// -// Description: This routine lower's the EEPROM's clock input (EESK) -// -// Arguments: -// x - Ptr to the EEPROM control register's current value -// -// Returns: (none) -//---------------------------------------------------------------------------------------- - -void -lower_clock(struct e100_private *adapter, u16 *x) -{ - *x = *x & ~EESK; - writew(*x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - readw(&(adapter->scb->scb_status)); /* flush command to card */ - udelay(EEPROM_STALL_TIME); -} - -//---------------------------------------------------------------------------------------- -// Procedure: shift_in_bits -// -// Description: This routine shifts data bits in from the EEPROM. -// -// Arguments: -// -// Returns: -// The contents of that particular EEPROM word -//---------------------------------------------------------------------------------------- - -static u16 -shift_in_bits(struct e100_private *adapter) -{ - u16 x, d, i; - - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - x &= ~(EEDO | EEDI); - d = 0; - - for (i = 0; i < 16; i++) { - d <<= 1; - raise_clock(adapter, &x); - - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - - x &= ~EEDI; - if (x & EEDO) - d |= 1; - - lower_clock(adapter, &x); - } - - return d; -} - -//---------------------------------------------------------------------------------------- -// Procedure: e100_eeprom_cleanup -// -// Description: This routine returns the EEPROM to an idle state -//---------------------------------------------------------------------------------------- - -void -e100_eeprom_cleanup(struct e100_private *adapter) -{ - u16 x; - - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - - x &= ~(EECS | EEDI); - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - - raise_clock(adapter, &x); - lower_clock(adapter, &x); -} - -//********************************************************************************** -// Procedure: e100_eeprom_update_chksum -// -// Description: Calculates the checksum and writes it to the EEProm. -// It calculates the checksum accroding to the formula: -// Checksum = 0xBABA - (sum of first 63 words). -// -//----------------------------------------------------------------------------------- -u16 -e100_eeprom_calculate_chksum(struct e100_private *adapter) -{ - u16 idx, xsum_index, checksum = 0; - - // eeprom size is initialized to zero - if (!adapter->eeprom_size) - adapter->eeprom_size = e100_eeprom_size(adapter); - - xsum_index = adapter->eeprom_size - 1; - for (idx = 0; idx < xsum_index; idx++) - checksum += e100_eeprom_read(adapter, idx); - - checksum = EEPROM_CHECKSUM - checksum; - return checksum; -} - -//---------------------------------------------------------------------------------------- -// Procedure: e100_eeprom_write_word -// -// Description: This routine writes a word to a specific EEPROM location without. -// taking EEPROM semaphore and updating checksum. -// Use e100_eeprom_write_block for the EEPROM update -// Arguments: reg - The EEPROM word that we are going to write to. -// data - The data (word) that we are going to write to the EEPROM. -//---------------------------------------------------------------------------------------- -static void -e100_eeprom_write_word(struct e100_private *adapter, u16 reg, u16 data) -{ - u16 x; - u16 bits; - - bits = eeprom_address_size(adapter->eeprom_size); - - /* select EEPROM, mask off ASIC and reset bits, set EECS */ - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - x &= ~(EEDI | EEDO | EESK); - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - readw(&(adapter->scb->scb_status)); /* flush command to card */ - udelay(EEPROM_STALL_TIME); - x |= EECS; - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - - shift_out_bits(adapter, EEPROM_EWEN_OPCODE, 5); - shift_out_bits(adapter, reg, (u16) (bits - 2)); - if (!eeprom_wait_cmd_done(adapter)) - return; - - /* write the new word to the EEPROM & send the write opcode the EEPORM */ - shift_out_bits(adapter, EEPROM_WRITE_OPCODE, 3); - - /* select which word in the EEPROM that we are writing to */ - shift_out_bits(adapter, reg, bits); - - /* write the data to the selected EEPROM word */ - shift_out_bits(adapter, data, 16); - if (!eeprom_wait_cmd_done(adapter)) - return; - - shift_out_bits(adapter, EEPROM_EWDS_OPCODE, 5); - shift_out_bits(adapter, reg, (u16) (bits - 2)); - if (!eeprom_wait_cmd_done(adapter)) - return; - - e100_eeprom_cleanup(adapter); -} - -//---------------------------------------------------------------------------------------- -// Procedure: e100_eeprom_write_block -// -// Description: This routine writes a block of words starting from specified EEPROM -// location and updates checksum -// Arguments: reg - The EEPROM word that we are going to write to. -// data - The data (word) that we are going to write to the EEPROM. -//---------------------------------------------------------------------------------------- -void -e100_eeprom_write_block(struct e100_private *adapter, u16 start, u16 *data, - u16 size) -{ - u16 checksum; - u16 i; - - if (!adapter->eeprom_size) - adapter->eeprom_size = e100_eeprom_size(adapter); - - // Set EEPROM semaphore. - if (adapter->rev_id >= D102_REV_ID) { - if (!eeprom_set_semaphore(adapter)) - return; - } - - for (i = 0; i < size; i++) { - e100_eeprom_write_word(adapter, start + i, data[i]); - } - //Update checksum - checksum = e100_eeprom_calculate_chksum(adapter); - e100_eeprom_write_word(adapter, (adapter->eeprom_size - 1), checksum); - - // Clear EEPROM Semaphore. - if (adapter->rev_id >= D102_REV_ID) { - eeprom_reset_semaphore(adapter); - } -} - -//---------------------------------------------------------------------------------------- -// Procedure: eeprom_wait_cmd_done -// -// Description: This routine waits for the the EEPROM to finish its command. -// Specifically, it waits for EEDO (data out) to go high. -// Returns: true - If the command finished -// false - If the command never finished (EEDO stayed low) -//---------------------------------------------------------------------------------------- -static u16 -eeprom_wait_cmd_done(struct e100_private *adapter) -{ - u16 x; - unsigned long expiration_time = jiffies + HZ / 100 + 1; - - eeprom_stand_by(adapter); - - do { - rmb(); - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - if (x & EEDO) - return true; - if (time_before(jiffies, expiration_time)) - yield(); - else - return false; - } while (true); -} - -//---------------------------------------------------------------------------------------- -// Procedure: eeprom_stand_by -// -// Description: This routine lowers the EEPROM chip select (EECS) for a few microseconds. -//---------------------------------------------------------------------------------------- -static void -eeprom_stand_by(struct e100_private *adapter) -{ - u16 x; - - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - x &= ~(EECS | EESK); - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - readw(&(adapter->scb->scb_status)); /* flush command to card */ - udelay(EEPROM_STALL_TIME); - x |= EECS; - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - readw(&(adapter->scb->scb_status)); /* flush command to card */ - udelay(EEPROM_STALL_TIME); -} diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/e100/e100_main.c 830-ivtv/drivers/net/e100/e100_main.c --- 000-virgin/drivers/net/e100/e100_main.c Thu Jan 8 08:35:38 2004 +++ 830-ivtv/drivers/net/e100/e100_main.c Wed Dec 31 16:00:00 1969 @@ -1,4343 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -/********************************************************************** -* * -* INTEL CORPORATION * -* * -* This software is supplied under the terms of the license included * -* above. All use of this driver must be in accordance with the terms * -* of that license. * -* * -* Module Name: e100_main.c * -* * -* Abstract: Functions for the driver entry points like load, * -* unload, open and close. All board specific calls made * -* by the network interface section of the driver. * -* * -* Environment: This file is intended to be specific to the Linux * -* operating system. * -* * -**********************************************************************/ - -/* Change Log - * - * 2.3.30 09/21/03 - * o Bug fix (Bugzilla 97908): Loading e100 was causing crash on Itanium2 - * with HP chipset - * o Bug fix (Bugzilla 101583): e100 can't pass traffic with ipv6 - * o Bug fix (Bugzilla 101360): PRO/10+ can't pass traffic - * - * 2.3.27 08/08/03 - * o Bug fix: read skb->len after freeing skb - * [Andrew Morton] akpm@zip.com.au - * o Bug fix: 82557 (with National PHY) timeout during init - * [Adam Kropelin] akropel1@rochester.rr.com - * o Feature add: allow to change Wake On LAN when EEPROM disabled - * - * 2.3.13 05/08/03 - */ - -#include -#include -#include -#include -#include "e100.h" -#include "e100_ucode.h" -#include "e100_config.h" -#include "e100_phy.h" - -extern void e100_force_speed_duplex_to_phy(struct e100_private *bdp); - -static char e100_gstrings_stats[][ETH_GSTRING_LEN] = { - "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", - "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions", - "rx_length_errors", "rx_over_errors", "rx_crc_errors", - "rx_frame_errors", "rx_fifo_errors", "rx_missed_errors", - "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors", - "tx_heartbeat_errors", "tx_window_errors", -}; -#define E100_STATS_LEN sizeof(e100_gstrings_stats) / ETH_GSTRING_LEN - -static int e100_do_ethtool_ioctl(struct net_device *, struct ifreq *); -static void e100_get_speed_duplex_caps(struct e100_private *); -static int e100_ethtool_get_settings(struct net_device *, struct ifreq *); -static int e100_ethtool_set_settings(struct net_device *, struct ifreq *); - -static int e100_ethtool_get_drvinfo(struct net_device *, struct ifreq *); -static int e100_ethtool_eeprom(struct net_device *, struct ifreq *); - -#define E100_EEPROM_MAGIC 0x1234 -static int e100_ethtool_glink(struct net_device *, struct ifreq *); -static int e100_ethtool_gregs(struct net_device *, struct ifreq *); -static int e100_ethtool_nway_rst(struct net_device *, struct ifreq *); -static int e100_ethtool_wol(struct net_device *, struct ifreq *); -#ifdef CONFIG_PM -static unsigned char e100_setup_filter(struct e100_private *bdp); -static void e100_do_wol(struct pci_dev *pcid, struct e100_private *bdp); -#endif -static u16 e100_get_ip_lbytes(struct net_device *dev); -extern void e100_config_wol(struct e100_private *bdp); -extern u32 e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags); -static int e100_ethtool_test(struct net_device *, struct ifreq *); -static int e100_ethtool_gstrings(struct net_device *, struct ifreq *); -static char test_strings[][ETH_GSTRING_LEN] = { - "Link test (on/offline)", - "Eeprom test (on/offline)", - "Self test (offline)", - "Mac loopback (offline)", - "Phy loopback (offline)", - "Cable diagnostic (offline)" -}; - -static int e100_ethtool_led_blink(struct net_device *, struct ifreq *); - -static int e100_mii_ioctl(struct net_device *, struct ifreq *, int); - -static unsigned char e100_delayed_exec_non_cu_cmd(struct e100_private *, - nxmit_cb_entry_t *); -static void e100_free_nontx_list(struct e100_private *); -static void e100_non_tx_background(unsigned long); -static inline void e100_tx_skb_free(struct e100_private *bdp, tcb_t *tcb); -/* Global Data structures and variables */ -char e100_copyright[] = "Copyright (c) 2003 Intel Corporation"; -char e100_driver_version[]="2.3.30-k1"; -const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver"; -char e100_short_driver_name[] = "e100"; -static int e100nics = 0; -static void e100_vlan_rx_register(struct net_device *netdev, struct vlan_group - *grp); -static void e100_vlan_rx_add_vid(struct net_device *netdev, u16 vid); -static void e100_vlan_rx_kill_vid(struct net_device *netdev, u16 vid); - -#ifdef CONFIG_PM -static int e100_notify_reboot(struct notifier_block *, unsigned long event, void *ptr); -static int e100_suspend(struct pci_dev *pcid, u32 state); -static int e100_resume(struct pci_dev *pcid); -static unsigned char e100_asf_enabled(struct e100_private *bdp); -struct notifier_block e100_notifier_reboot = { - .notifier_call = e100_notify_reboot, - .next = NULL, - .priority = 0 -}; -#endif - -/*********************************************************************/ -/*! This is a GCC extension to ANSI C. - * See the item "Labeled Elements in Initializers" in the section - * "Extensions to the C Language Family" of the GCC documentation. - *********************************************************************/ -#define E100_PARAM_INIT { [0 ... E100_MAX_NIC] = -1 } - -/* All parameters are treated the same, as an integer array of values. - * This macro just reduces the need to repeat the same declaration code - * over and over (plus this helps to avoid typo bugs). - */ -#define E100_PARAM(X, S) \ - static const int X[E100_MAX_NIC + 1] = E100_PARAM_INIT; \ - MODULE_PARM(X, "1-" __MODULE_STRING(E100_MAX_NIC) "i"); \ - MODULE_PARM_DESC(X, S); - -/* ====================================================================== */ -static u8 e100_D101M_checksum(struct e100_private *, struct sk_buff *); -static u8 e100_D102_check_checksum(rfd_t *); -static int e100_ioctl(struct net_device *, struct ifreq *, int); -static int e100_change_mtu(struct net_device *, int); -static int e100_xmit_frame(struct sk_buff *, struct net_device *); -static unsigned char e100_init(struct e100_private *); -static int e100_set_mac(struct net_device *, void *); -struct net_device_stats *e100_get_stats(struct net_device *); - -static irqreturn_t e100intr(int, void *, struct pt_regs *); -static void e100_print_brd_conf(struct e100_private *); -static void e100_set_multi(struct net_device *); - -static u8 e100_pci_setup(struct pci_dev *, struct e100_private *); -static u8 e100_sw_init(struct e100_private *); -static void e100_tco_workaround(struct e100_private *); -static unsigned char e100_alloc_space(struct e100_private *); -static void e100_dealloc_space(struct e100_private *); -static int e100_alloc_tcb_pool(struct e100_private *); -static void e100_setup_tcb_pool(tcb_t *, unsigned int, struct e100_private *); -static void e100_free_tcb_pool(struct e100_private *); -static int e100_alloc_rfd_pool(struct e100_private *); -static void e100_free_rfd_pool(struct e100_private *); - -static void e100_rd_eaddr(struct e100_private *); -static void e100_rd_pwa_no(struct e100_private *); -extern u16 e100_eeprom_read(struct e100_private *, u16); -extern void e100_eeprom_write_block(struct e100_private *, u16, u16 *, u16); -extern u16 e100_eeprom_size(struct e100_private *); -u16 e100_eeprom_calculate_chksum(struct e100_private *adapter); - -static unsigned char e100_clr_cntrs(struct e100_private *); -static unsigned char e100_load_microcode(struct e100_private *); -static unsigned char e100_setup_iaaddr(struct e100_private *, u8 *); -static unsigned char e100_update_stats(struct e100_private *bdp); - -static void e100_start_ru(struct e100_private *); -static void e100_dump_stats_cntrs(struct e100_private *); - -static void e100_check_options(int board, struct e100_private *bdp); -static void e100_set_int_option(int *, int, int, int, int, char *); -static void e100_set_bool_option(struct e100_private *bdp, int, u32, int, - char *); -unsigned char e100_wait_exec_cmplx(struct e100_private *, u32, u8, u8); -void e100_exec_cmplx(struct e100_private *, u32, u8); - -/** - * e100_get_rx_struct - retrieve cell to hold skb buff from the pool - * @bdp: atapter's private data struct - * - * Returns the new cell to hold sk_buff or %NULL. - */ -static inline struct rx_list_elem * -e100_get_rx_struct(struct e100_private *bdp) -{ - struct rx_list_elem *rx_struct = NULL; - - if (!list_empty(&(bdp->rx_struct_pool))) { - rx_struct = list_entry(bdp->rx_struct_pool.next, - struct rx_list_elem, list_elem); - list_del(&(rx_struct->list_elem)); - } - - return rx_struct; -} - -/** - * e100_alloc_skb - allocate an skb for the adapter - * @bdp: atapter's private data struct - * - * Allocates skb with enough room for rfd, and data, and reserve non-data space. - * Returns the new cell with sk_buff or %NULL. - */ -static inline struct rx_list_elem * -e100_alloc_skb(struct e100_private *bdp) -{ - struct sk_buff *new_skb; - u32 skb_size = sizeof (rfd_t); - struct rx_list_elem *rx_struct; - - new_skb = (struct sk_buff *) dev_alloc_skb(skb_size); - if (new_skb) { - /* The IP data should be - DWORD aligned. since the ethernet header is 14 bytes long, - we need to reserve 2 extra bytes so that the TCP/IP headers - will be DWORD aligned. */ - skb_reserve(new_skb, 2); - if ((rx_struct = e100_get_rx_struct(bdp)) == NULL) - goto err; - rx_struct->skb = new_skb; - rx_struct->dma_addr = pci_map_single(bdp->pdev, new_skb->data, - sizeof (rfd_t), - PCI_DMA_FROMDEVICE); - if (!rx_struct->dma_addr) - goto err; - skb_reserve(new_skb, bdp->rfd_size); - return rx_struct; - } else { - return NULL; - } - -err: - dev_kfree_skb_irq(new_skb); - return NULL; -} - -/** - * e100_add_skb_to_end - add an skb to the end of our rfd list - * @bdp: atapter's private data struct - * @rx_struct: rx_list_elem with the new skb - * - * Adds a newly allocated skb to the end of our rfd list. - */ -inline void -e100_add_skb_to_end(struct e100_private *bdp, struct rx_list_elem *rx_struct) -{ - rfd_t *rfdn; /* The new rfd */ - rfd_t *rfd; /* The old rfd */ - struct rx_list_elem *rx_struct_last; - - (rx_struct->skb)->dev = bdp->device; - rfdn = RFD_POINTER(rx_struct->skb, bdp); - rfdn->rfd_header.cb_status = 0; - rfdn->rfd_header.cb_cmd = __constant_cpu_to_le16(RFD_EL_BIT); - rfdn->rfd_act_cnt = 0; - rfdn->rfd_sz = __constant_cpu_to_le16(RFD_DATA_SIZE); - - pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr, bdp->rfd_size, - PCI_DMA_TODEVICE); - - if (!list_empty(&(bdp->active_rx_list))) { - rx_struct_last = list_entry(bdp->active_rx_list.prev, - struct rx_list_elem, list_elem); - rfd = RFD_POINTER(rx_struct_last->skb, bdp); - pci_dma_sync_single(bdp->pdev, rx_struct_last->dma_addr, - 4, PCI_DMA_FROMDEVICE); - put_unaligned(cpu_to_le32(rx_struct->dma_addr), - ((u32 *) (&(rfd->rfd_header.cb_lnk_ptr)))); - - pci_dma_sync_single(bdp->pdev, rx_struct_last->dma_addr, - 8, PCI_DMA_TODEVICE); - rfd->rfd_header.cb_cmd &= - __constant_cpu_to_le16((u16) ~RFD_EL_BIT); - - pci_dma_sync_single(bdp->pdev, rx_struct_last->dma_addr, - 4, PCI_DMA_TODEVICE); - } - - list_add_tail(&(rx_struct->list_elem), &(bdp->active_rx_list)); -} - -static inline void -e100_alloc_skbs(struct e100_private *bdp) -{ - for (; bdp->skb_req > 0; bdp->skb_req--) { - struct rx_list_elem *rx_struct; - - if ((rx_struct = e100_alloc_skb(bdp)) == NULL) - return; - - e100_add_skb_to_end(bdp, rx_struct); - } -} - -void e100_tx_srv(struct e100_private *); -u32 e100_rx_srv(struct e100_private *); - -void e100_watchdog(struct net_device *); -void e100_refresh_txthld(struct e100_private *); -void e100_manage_adaptive_ifs(struct e100_private *); -void e100_clear_pools(struct e100_private *); -static void e100_clear_structs(struct net_device *); -static inline tcb_t *e100_prepare_xmit_buff(struct e100_private *, - struct sk_buff *); -static void e100_set_multi_exec(struct net_device *dev); - -MODULE_AUTHOR("Intel Corporation, "); -MODULE_DESCRIPTION("Intel(R) PRO/100 Network Driver"); -MODULE_LICENSE("GPL"); - -E100_PARAM(TxDescriptors, "Number of transmit descriptors"); -E100_PARAM(RxDescriptors, "Number of receive descriptors"); -E100_PARAM(XsumRX, "Disable or enable Receive Checksum offload"); -E100_PARAM(e100_speed_duplex, "Speed and Duplex settings"); -E100_PARAM(ucode, "Disable or enable microcode loading"); -E100_PARAM(ber, "Value for the BER correction algorithm"); -E100_PARAM(flow_control, "Disable or enable Ethernet PAUSE frames processing"); -E100_PARAM(IntDelay, "Value for CPU saver's interrupt delay"); -E100_PARAM(BundleSmallFr, "Disable or enable interrupt bundling of small frames"); -E100_PARAM(BundleMax, "Maximum number for CPU saver's packet bundling"); -E100_PARAM(IFS, "Disable or enable the adaptive IFS algorithm"); - -/** - * e100_exec_cmd - issue a comand - * @bdp: atapter's private data struct - * @scb_cmd_low: the command that is to be issued - * - * This general routine will issue a command to the e100. - */ -static inline void -e100_exec_cmd(struct e100_private *bdp, u8 cmd_low) -{ - writeb(cmd_low, &(bdp->scb->scb_cmd_low)); - readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */ -} - -/** - * e100_wait_scb - wait for SCB to clear - * @bdp: atapter's private data struct - * - * This routine checks to see if the e100 has accepted a command. - * It does so by checking the command field in the SCB, which will - * be zeroed by the e100 upon accepting a command. The loop waits - * for up to 1 millisecond for command acceptance. - * - * Returns: - * true if the SCB cleared within 1 millisecond. - * false if it didn't clear within 1 millisecond - */ -unsigned char -e100_wait_scb(struct e100_private *bdp) -{ - int i; - - /* loop on the scb for a few times */ - for (i = 0; i < 100; i++) { - if (!readb(&bdp->scb->scb_cmd_low)) - return true; - cpu_relax(); - } - - /* it didn't work. do it the slow way using udelay()s */ - for (i = 0; i < E100_MAX_SCB_WAIT; i++) { - if (!readb(&bdp->scb->scb_cmd_low)) - return true; - cpu_relax(); - udelay(1); - } - - return false; -} - -/** - * e100_wait_exec_simple - issue a command - * @bdp: atapter's private data struct - * @scb_cmd_low: the command that is to be issued - * - * This general routine will issue a command to the e100 after waiting for - * the previous command to finish. - * - * Returns: - * true if the command was issued to the chip successfully - * false if the command was not issued to the chip - */ -inline unsigned char -e100_wait_exec_simple(struct e100_private *bdp, u8 scb_cmd_low) -{ - if (!e100_wait_scb(bdp)) { - printk(KERN_DEBUG "e100: %s: e100_wait_exec_simple: failed\n", - bdp->device->name); -#ifdef E100_CU_DEBUG - printk(KERN_ERR "e100: %s: Last command (%x/%x) " - "timeout\n", bdp->device->name, - bdp->last_cmd, bdp->last_sub_cmd); - printk(KERN_ERR "e100: %s: Current simple command (%x) " - "can't be executed\n", - bdp->device->name, scb_cmd_low); -#endif - return false; - } - e100_exec_cmd(bdp, scb_cmd_low); -#ifdef E100_CU_DEBUG - bdp->last_cmd = scb_cmd_low; - bdp->last_sub_cmd = 0; -#endif - return true; -} - -void -e100_exec_cmplx(struct e100_private *bdp, u32 phys_addr, u8 cmd) -{ - writel(phys_addr, &(bdp->scb->scb_gen_ptr)); - readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */ - e100_exec_cmd(bdp, cmd); -} - -unsigned char -e100_wait_exec_cmplx(struct e100_private *bdp, u32 phys_addr, u8 cmd, u8 sub_cmd) -{ - if (!e100_wait_scb(bdp)) { -#ifdef E100_CU_DEBUG - printk(KERN_ERR "e100: %s: Last command (%x/%x) " - "timeout\n", bdp->device->name, - bdp->last_cmd, bdp->last_sub_cmd); - printk(KERN_ERR "e100: %s: Current complex command " - "(%x/%x) can't be executed\n", - bdp->device->name, cmd, sub_cmd); -#endif - return false; - } - e100_exec_cmplx(bdp, phys_addr, cmd); -#ifdef E100_CU_DEBUG - bdp->last_cmd = cmd; - bdp->last_sub_cmd = sub_cmd; -#endif - return true; -} - -inline u8 -e100_wait_cus_idle(struct e100_private *bdp) -{ - int i; - - /* loop on the scb for a few times */ - for (i = 0; i < 100; i++) { - if (((readw(&(bdp->scb->scb_status)) & SCB_CUS_MASK) != - SCB_CUS_ACTIVE)) { - return true; - } - cpu_relax(); - } - - for (i = 0; i < E100_MAX_CU_IDLE_WAIT; i++) { - if (((readw(&(bdp->scb->scb_status)) & SCB_CUS_MASK) != - SCB_CUS_ACTIVE)) { - return true; - } - cpu_relax(); - udelay(1); - } - - return false; -} - -/** - * e100_disable_clear_intr - disable and clear/ack interrupts - * @bdp: atapter's private data struct - * - * This routine disables interrupts at the hardware, by setting - * the M (mask) bit in the adapter's CSR SCB command word. - * It also clear/ack interrupts. - */ -static inline void -e100_disable_clear_intr(struct e100_private *bdp) -{ - u16 intr_status; - /* Disable interrupts on our PCI board by setting the mask bit */ - writeb(SCB_INT_MASK, &bdp->scb->scb_cmd_hi); - intr_status = readw(&bdp->scb->scb_status); - /* ack and clear intrs */ - writew(intr_status, &bdp->scb->scb_status); - readw(&bdp->scb->scb_status); -} - -/** - * e100_set_intr_mask - set interrupts - * @bdp: atapter's private data struct - * - * This routine sets interrupts at the hardware, by resetting - * the M (mask) bit in the adapter's CSR SCB command word - */ -static inline void -e100_set_intr_mask(struct e100_private *bdp) -{ - writeb(bdp->intr_mask, &bdp->scb->scb_cmd_hi); - readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */ -} - -static inline void -e100_trigger_SWI(struct e100_private *bdp) -{ - /* Trigger interrupt on our PCI board by asserting SWI bit */ - writeb(SCB_SOFT_INT, &bdp->scb->scb_cmd_hi); - readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */ -} - -static int -e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent) -{ - static int first_time = true; - struct net_device *dev = NULL; - struct e100_private *bdp = NULL; - int rc = 0; - u16 cal_checksum, read_checksum; - - dev = alloc_etherdev(sizeof (struct e100_private)); - if (dev == NULL) { - printk(KERN_ERR "e100: Not able to alloc etherdev struct\n"); - rc = -ENODEV; - goto out; - } - - SET_MODULE_OWNER(dev); - - if (first_time) { - first_time = false; - printk(KERN_NOTICE "%s - version %s\n", - e100_full_driver_name, e100_driver_version); - printk(KERN_NOTICE "%s\n", e100_copyright); - printk(KERN_NOTICE "\n"); - } - - bdp = dev->priv; - bdp->pdev = pcid; - bdp->device = dev; - - pci_set_drvdata(pcid, dev); - SET_NETDEV_DEV(dev, &pcid->dev); - - bdp->flags = 0; - bdp->ifs_state = 0; - bdp->ifs_value = 0; - bdp->scb = 0; - - init_timer(&bdp->nontx_timer_id); - bdp->nontx_timer_id.data = (unsigned long) bdp; - bdp->nontx_timer_id.function = (void *) &e100_non_tx_background; - INIT_LIST_HEAD(&(bdp->non_tx_cmd_list)); - bdp->non_tx_command_state = E100_NON_TX_IDLE; - - init_timer(&bdp->watchdog_timer); - bdp->watchdog_timer.data = (unsigned long) dev; - bdp->watchdog_timer.function = (void *) &e100_watchdog; - - if ((rc = e100_pci_setup(pcid, bdp)) != 0) { - goto err_dev; - } - - if ((rc = e100_alloc_space(bdp)) != 0) { - goto err_pci; - } - - if (((bdp->pdev->device > 0x1030) - && (bdp->pdev->device < 0x103F)) - || ((bdp->pdev->device >= 0x1050) - && (bdp->pdev->device <= 0x1057)) - || (bdp->pdev->device == 0x2449) - || (bdp->pdev->device == 0x2459) - || (bdp->pdev->device == 0x245D)) { - bdp->rev_id = D101MA_REV_ID; /* workaround for ICH3 */ - bdp->flags |= IS_ICH; - } - - if (bdp->rev_id == 0xff) - bdp->rev_id = 1; - - if ((u8) bdp->rev_id >= D101A4_REV_ID) - bdp->flags |= IS_BACHELOR; - - if ((u8) bdp->rev_id >= D102_REV_ID) { - bdp->flags |= USE_IPCB; - bdp->rfd_size = 32; - } else { - bdp->rfd_size = 16; - } - - dev->vlan_rx_register = e100_vlan_rx_register; - dev->vlan_rx_add_vid = e100_vlan_rx_add_vid; - dev->vlan_rx_kill_vid = e100_vlan_rx_kill_vid; - dev->irq = pcid->irq; - dev->open = &e100_open; - dev->hard_start_xmit = &e100_xmit_frame; - dev->stop = &e100_close; - dev->change_mtu = &e100_change_mtu; - dev->get_stats = &e100_get_stats; - dev->set_multicast_list = &e100_set_multi; - dev->set_mac_address = &e100_set_mac; - dev->do_ioctl = &e100_ioctl; - - if (bdp->flags & USE_IPCB) - dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | - NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - - if ((rc = register_netdev(dev)) != 0) { - goto err_dealloc; - } - - e100_check_options(e100nics, bdp); - - if (!e100_init(bdp)) { - printk(KERN_ERR "e100: Failed to initialize, instance #%d\n", - e100nics); - rc = -ENODEV; - goto err_unregister_netdev; - } - - /* Check if checksum is valid */ - cal_checksum = e100_eeprom_calculate_chksum(bdp); - read_checksum = e100_eeprom_read(bdp, (bdp->eeprom_size - 1)); - if (cal_checksum != read_checksum) { - printk(KERN_ERR "e100: Corrupted EEPROM on instance #%d\n", - e100nics); - rc = -ENODEV; - goto err_unregister_netdev; - } - - e100nics++; - - e100_get_speed_duplex_caps(bdp); - - printk(KERN_NOTICE - "e100: %s: %s\n", - bdp->device->name, "Intel(R) PRO/100 Network Connection"); - e100_print_brd_conf(bdp); - - bdp->wolsupported = 0; - bdp->wolopts = 0; - if (bdp->rev_id >= D101A4_REV_ID) - bdp->wolsupported = WAKE_PHY | WAKE_MAGIC; - if (bdp->rev_id >= D101MA_REV_ID) - bdp->wolsupported |= WAKE_UCAST | WAKE_ARP; - - /* Check if WoL is enabled on EEPROM */ - if (e100_eeprom_read(bdp, EEPROM_ID_WORD) & BIT_5) { - /* Magic Packet WoL is enabled on device by default */ - /* if EEPROM WoL bit is TRUE */ - bdp->wolopts = WAKE_MAGIC; - } - - printk(KERN_NOTICE "\n"); - - goto out; - -err_unregister_netdev: - unregister_netdev(dev); -err_dealloc: - e100_dealloc_space(bdp); -err_pci: - iounmap(bdp->scb); - pci_release_regions(pcid); - pci_disable_device(pcid); -err_dev: - pci_set_drvdata(pcid, NULL); - kfree(dev); -out: - return rc; -} - -/** - * e100_clear_structs - free resources - * @dev: adapter's net_device struct - * - * Free all device specific structs, unmap i/o address, etc. - */ -static void __devexit -e100_clear_structs(struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - - iounmap(bdp->scb); - pci_release_regions(bdp->pdev); - pci_disable_device(bdp->pdev); - - e100_dealloc_space(bdp); - pci_set_drvdata(bdp->pdev, NULL); - free_netdev(dev); -} - -static void __devexit -e100_remove1(struct pci_dev *pcid) -{ - struct net_device *dev; - struct e100_private *bdp; - - if (!(dev = (struct net_device *) pci_get_drvdata(pcid))) - return; - - bdp = dev->priv; - - unregister_netdev(dev); - - e100_sw_reset(bdp, PORT_SELECTIVE_RESET); - - if (bdp->non_tx_command_state != E100_NON_TX_IDLE) { - del_timer_sync(&bdp->nontx_timer_id); - e100_free_nontx_list(bdp); - bdp->non_tx_command_state = E100_NON_TX_IDLE; - } - - e100_clear_structs(dev); - - --e100nics; -} - -static struct pci_device_id e100_id_table[] = { - {0x8086, 0x1229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x2449, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1209, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1031, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1032, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1033, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1034, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1038, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x103A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x103B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x103C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x103D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x103E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1052, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1054, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x2459, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x245D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0,} /* This has to be the last entry*/ -}; -MODULE_DEVICE_TABLE(pci, e100_id_table); - -static struct pci_driver e100_driver = { - .name = "e100", - .id_table = e100_id_table, - .probe = e100_found1, - .remove = __devexit_p(e100_remove1), -#ifdef CONFIG_PM - .suspend = e100_suspend, - .resume = e100_resume, -#endif -}; - -static int __init -e100_init_module(void) -{ - int ret; - ret = pci_module_init(&e100_driver); - - if(ret >= 0) { -#ifdef CONFIG_PM - register_reboot_notifier(&e100_notifier_reboot); -#endif - } - - return ret; -} - -static void __exit -e100_cleanup_module(void) -{ -#ifdef CONFIG_PM - unregister_reboot_notifier(&e100_notifier_reboot); -#endif - - pci_unregister_driver(&e100_driver); -} - -module_init(e100_init_module); -module_exit(e100_cleanup_module); - -/** - * e100_check_options - check command line options - * @board: board number - * @bdp: atapter's private data struct - * - * This routine does range checking on command-line options - */ -void -e100_check_options(int board, struct e100_private *bdp) -{ - if (board >= E100_MAX_NIC) { - printk(KERN_NOTICE - "e100: No configuration available for board #%d\n", - board); - printk(KERN_NOTICE "e100: Using defaults for all values\n"); - board = E100_MAX_NIC; - } - - e100_set_int_option(&(bdp->params.TxDescriptors), TxDescriptors[board], - E100_MIN_TCB, E100_MAX_TCB, E100_DEFAULT_TCB, - "TxDescriptor count"); - - e100_set_int_option(&(bdp->params.RxDescriptors), RxDescriptors[board], - E100_MIN_RFD, E100_MAX_RFD, E100_DEFAULT_RFD, - "RxDescriptor count"); - - e100_set_int_option(&(bdp->params.e100_speed_duplex), - e100_speed_duplex[board], 0, 4, - E100_DEFAULT_SPEED_DUPLEX, "speed/duplex mode"); - - e100_set_int_option(&(bdp->params.ber), ber[board], 0, ZLOCK_MAX_ERRORS, - E100_DEFAULT_BER, "Bit Error Rate count"); - - e100_set_bool_option(bdp, XsumRX[board], PRM_XSUMRX, E100_DEFAULT_XSUM, - "XsumRX value"); - - /* Default ucode value depended on controller revision */ - if (bdp->rev_id >= D101MA_REV_ID) { - e100_set_bool_option(bdp, ucode[board], PRM_UCODE, - E100_DEFAULT_UCODE, "ucode value"); - } else { - e100_set_bool_option(bdp, ucode[board], PRM_UCODE, false, - "ucode value"); - } - - e100_set_bool_option(bdp, flow_control[board], PRM_FC, E100_DEFAULT_FC, - "flow control value"); - - e100_set_bool_option(bdp, IFS[board], PRM_IFS, E100_DEFAULT_IFS, - "IFS value"); - - e100_set_bool_option(bdp, BundleSmallFr[board], PRM_BUNDLE_SMALL, - E100_DEFAULT_BUNDLE_SMALL_FR, - "CPU saver bundle small frames value"); - - e100_set_int_option(&(bdp->params.IntDelay), IntDelay[board], 0x0, - 0xFFFF, E100_DEFAULT_CPUSAVER_INTERRUPT_DELAY, - "CPU saver interrupt delay value"); - - e100_set_int_option(&(bdp->params.BundleMax), BundleMax[board], 0x1, - 0xFFFF, E100_DEFAULT_CPUSAVER_BUNDLE_MAX, - "CPU saver bundle max value"); - -} - -/** - * e100_set_int_option - check and set an integer option - * @option: a pointer to the relevant option field - * @val: the value specified - * @min: the minimum valid value - * @max: the maximum valid value - * @default_val: the default value - * @name: the name of the option - * - * This routine does range checking on a command-line option. - * If the option's value is '-1' use the specified default. - * Otherwise, if the value is invalid, change it to the default. - */ -void -e100_set_int_option(int *option, int val, int min, int max, int default_val, - char *name) -{ - if (val == -1) { /* no value specified. use default */ - *option = default_val; - - } else if ((val < min) || (val > max)) { - printk(KERN_NOTICE - "e100: Invalid %s specified (%i). " - "Valid range is %i-%i\n", - name, val, min, max); - printk(KERN_NOTICE "e100: Using default %s of %i\n", name, - default_val); - *option = default_val; - } else { - printk(KERN_INFO "e100: Using specified %s of %i\n", name, val); - *option = val; - } -} - -/** - * e100_set_bool_option - check and set a boolean option - * @bdp: atapter's private data struct - * @val: the value specified - * @mask: the mask for the relevant option - * @default_val: the default value - * @name: the name of the option - * - * This routine checks a boolean command-line option. - * If the option's value is '-1' use the specified default. - * Otherwise, if the value is invalid (not 0 or 1), - * change it to the default. - */ -void -e100_set_bool_option(struct e100_private *bdp, int val, u32 mask, - int default_val, char *name) -{ - if (val == -1) { - if (default_val) - bdp->params.b_params |= mask; - - } else if ((val != true) && (val != false)) { - printk(KERN_NOTICE - "e100: Invalid %s specified (%i). " - "Valid values are %i/%i\n", - name, val, false, true); - printk(KERN_NOTICE "e100: Using default %s of %i\n", name, - default_val); - - if (default_val) - bdp->params.b_params |= mask; - } else { - printk(KERN_INFO "e100: Using specified %s of %i\n", name, val); - if (val) - bdp->params.b_params |= mask; - } -} - -int -e100_open(struct net_device *dev) -{ - struct e100_private *bdp; - int rc = 0; - - bdp = dev->priv; - - /* setup the tcb pool */ - if (!e100_alloc_tcb_pool(bdp)) { - rc = -ENOMEM; - goto err_exit; - } - bdp->last_tcb = NULL; - - bdp->tcb_pool.head = 0; - bdp->tcb_pool.tail = 1; - - e100_setup_tcb_pool((tcb_t *) bdp->tcb_pool.data, - bdp->params.TxDescriptors, bdp); - - if (!e100_alloc_rfd_pool(bdp)) { - rc = -ENOMEM; - goto err_exit; - } - - if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0)) { - rc = -EAGAIN; - goto err_exit; - } - - if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0)) { - rc = -EAGAIN; - goto err_exit; - } - - mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ)); - - if (dev->flags & IFF_UP) - /* Otherwise process may sleep forever */ - netif_wake_queue(dev); - else - netif_start_queue(dev); - - e100_start_ru(bdp); - if ((rc = request_irq(dev->irq, &e100intr, SA_SHIRQ, - dev->name, dev)) != 0) { - del_timer_sync(&bdp->watchdog_timer); - goto err_exit; - } - bdp->intr_mask = 0; - e100_set_intr_mask(bdp); - - e100_force_config(bdp); - - goto exit; - -err_exit: - e100_clear_pools(bdp); -exit: - return rc; -} - -int -e100_close(struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - - e100_disable_clear_intr(bdp); - free_irq(dev->irq, dev); - bdp->intr_mask = SCB_INT_MASK; - e100_isolate_driver(bdp); - - netif_carrier_off(bdp->device); - bdp->cur_line_speed = 0; - bdp->cur_dplx_mode = 0; - e100_clear_pools(bdp); - - return 0; -} - -static int -e100_change_mtu(struct net_device *dev, int new_mtu) -{ - if ((new_mtu < 68) || (new_mtu > (ETH_DATA_LEN + VLAN_SIZE))) - return -EINVAL; - - dev->mtu = new_mtu; - return 0; -} - -static int -e100_xmit_frame(struct sk_buff *skb, struct net_device *dev) -{ - int rc = 0; - int notify_stop = false; - struct e100_private *bdp = dev->priv; - - if (!spin_trylock(&bdp->bd_non_tx_lock)) { - notify_stop = true; - rc = 1; - goto exit2; - } - - /* tcb list may be empty temporarily during releasing resources */ - if (!TCBS_AVAIL(bdp->tcb_pool) || (bdp->tcb_phys == 0) || - (bdp->non_tx_command_state != E100_NON_TX_IDLE)) { - notify_stop = true; - rc = 1; - goto exit1; - } - - bdp->drv_stats.net_stats.tx_bytes += skb->len; - - e100_prepare_xmit_buff(bdp, skb); - - dev->trans_start = jiffies; - -exit1: - spin_unlock(&bdp->bd_non_tx_lock); -exit2: - if (notify_stop) { - netif_stop_queue(dev); - } - - return rc; -} - -/** - * e100_get_stats - get driver statistics - * @dev: adapter's net_device struct - * - * This routine is called when the OS wants the adapter's stats returned. - * It returns the address of the net_device_stats stucture for the device. - * If the statistics are currently being updated, then they might be incorrect - * for a short while. However, since this cannot actually cause damage, no - * locking is used. - */ -struct net_device_stats * -e100_get_stats(struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - - bdp->drv_stats.net_stats.tx_errors = - bdp->drv_stats.net_stats.tx_carrier_errors + - bdp->drv_stats.net_stats.tx_aborted_errors; - - bdp->drv_stats.net_stats.rx_errors = - bdp->drv_stats.net_stats.rx_crc_errors + - bdp->drv_stats.net_stats.rx_frame_errors + - bdp->drv_stats.net_stats.rx_length_errors + - bdp->drv_stats.rcv_cdt_frames; - - return &(bdp->drv_stats.net_stats); -} - -/** - * e100_set_mac - set the MAC address - * @dev: adapter's net_device struct - * @addr: the new address - * - * This routine sets the ethernet address of the board - * Returns: - * 0 - if successful - * -1 - otherwise - */ -static int -e100_set_mac(struct net_device *dev, void *addr) -{ - struct e100_private *bdp; - int rc = -1; - struct sockaddr *p_sockaddr = (struct sockaddr *) addr; - - if (!is_valid_ether_addr(p_sockaddr->sa_data)) - return -EADDRNOTAVAIL; - bdp = dev->priv; - - if (e100_setup_iaaddr(bdp, (u8 *) (p_sockaddr->sa_data))) { - memcpy(&(dev->dev_addr[0]), p_sockaddr->sa_data, ETH_ALEN); - rc = 0; - } - - return rc; -} - -static void -e100_set_multi_exec(struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - mltcst_cb_t *mcast_buff; - cb_header_t *cb_hdr; - struct dev_mc_list *mc_list; - unsigned int i; - nxmit_cb_entry_t *cmd = e100_alloc_non_tx_cmd(bdp); - - if (cmd != NULL) { - mcast_buff = &((cmd->non_tx_cmd)->ntcb.multicast); - cb_hdr = &((cmd->non_tx_cmd)->ntcb.multicast.mc_cbhdr); - } else { - return; - } - - /* initialize the multi cast command */ - cb_hdr->cb_cmd = __constant_cpu_to_le16(CB_MULTICAST); - - /* now fill in the rest of the multicast command */ - *(u16 *) (&(mcast_buff->mc_count)) = cpu_to_le16(dev->mc_count * 6); - for (i = 0, mc_list = dev->mc_list; - (i < dev->mc_count) && (i < MAX_MULTICAST_ADDRS); - i++, mc_list = mc_list->next) { - /* copy into the command */ - memcpy(&(mcast_buff->mc_addr[i * ETH_ALEN]), - (u8 *) &(mc_list->dmi_addr), ETH_ALEN); - } - - if (!e100_exec_non_cu_cmd(bdp, cmd)) { - printk(KERN_WARNING "e100: %s: Multicast setup failed\n", - dev->name); - } -} - -/** - * e100_set_multi - set multicast status - * @dev: adapter's net_device struct - * - * This routine is called to add or remove multicast addresses, and/or to - * change the adapter's promiscuous state. - */ -static void -e100_set_multi(struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - unsigned char promisc_enbl; - unsigned char mulcast_enbl; - - promisc_enbl = ((dev->flags & IFF_PROMISC) == IFF_PROMISC); - mulcast_enbl = ((dev->flags & IFF_ALLMULTI) || - (dev->mc_count > MAX_MULTICAST_ADDRS)); - - e100_config_promisc(bdp, promisc_enbl); - e100_config_mulcast_enbl(bdp, mulcast_enbl); - - /* reconfigure the chip if something has changed in its config space */ - e100_config(bdp); - - if (promisc_enbl || mulcast_enbl) { - return; /* no need for Multicast Cmd */ - } - - /* get the multicast CB */ - e100_set_multi_exec(dev); -} - -static int -e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - - switch (cmd) { - - case SIOCETHTOOL: - return e100_do_ethtool_ioctl(dev, ifr); - break; - - case SIOCGMIIPHY: /* Get address of MII PHY in use. */ - case SIOCGMIIREG: /* Read MII PHY register. */ - case SIOCSMIIREG: /* Write to MII PHY register. */ - return e100_mii_ioctl(dev, ifr, cmd); - break; - - default: - return -EOPNOTSUPP; - } - return 0; - -} - -/** - * e100init - initialize the adapter - * @bdp: atapter's private data struct - * - * This routine is called when this driver is loaded. This is the initialization - * routine which allocates memory, configures the adapter and determines the - * system resources. - * - * Returns: - * true: if successful - * false: otherwise - */ -static unsigned char -e100_init(struct e100_private *bdp) -{ - u32 st_timeout = 0; - u32 st_result = 0; - e100_sw_init(bdp); - - if (!e100_selftest(bdp, &st_timeout, &st_result)) { - if (st_timeout) { - printk(KERN_ERR "e100: selftest timeout\n"); - } else { - printk(KERN_ERR "e100: selftest failed. Results: %x\n", - st_result); - } - return false; - } - else - printk(KERN_DEBUG "e100: selftest OK.\n"); - - /* read the MAC address from the eprom */ - e100_rd_eaddr(bdp); - if (!is_valid_ether_addr(bdp->device->dev_addr)) { - printk(KERN_ERR "e100: Invalid Ethernet address\n"); - return false; - } - /* read NIC's part number */ - e100_rd_pwa_no(bdp); - - if (!e100_hw_init(bdp)) - return false; - /* Interrupts are enabled after device reset */ - e100_disable_clear_intr(bdp); - - return true; -} - -/** - * e100_sw_init - initialize software structs - * @bdp: atapter's private data struct - * - * This routine initializes all software structures. Sets up the - * circular structures for the RFD's & TCB's. Allocates the per board - * structure for storing adapter information. The CSR is also memory - * mapped in this routine. - * - * Returns : - * true: if S/W was successfully initialized - * false: otherwise - */ -static unsigned char -e100_sw_init(struct e100_private *bdp) -{ - bdp->next_cu_cmd = START_WAIT; // init the next cu state - - /* - * Set the value for # of good xmits per underrun. the value assigned - * here is an intelligent suggested default. Nothing magical about it. - */ - bdp->tx_per_underrun = DEFAULT_TX_PER_UNDERRUN; - - /* get the default transmit threshold value */ - bdp->tx_thld = TX_THRSHLD; - - /* get the EPROM size */ - bdp->eeprom_size = e100_eeprom_size(bdp); - - /* Initialize our spinlocks */ - spin_lock_init(&(bdp->bd_lock)); - spin_lock_init(&(bdp->bd_non_tx_lock)); - spin_lock_init(&(bdp->config_lock)); - spin_lock_init(&(bdp->mdi_access_lock)); - /* Initialize configuration data */ - e100_config_init(bdp); - - return 1; -} - -static void -e100_tco_workaround(struct e100_private *bdp) -{ - int i; - - /* Do software reset */ - e100_sw_reset(bdp, PORT_SOFTWARE_RESET); - - /* Do a dummy LOAD CU BASE command. */ - /* This gets us out of pre-driver to post-driver. */ - e100_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE); - - /* Wait 20 msec for reset to take effect */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 50 + 1); - - /* disable interrupts since they are enabled */ - /* after device reset */ - e100_disable_clear_intr(bdp); - - /* Wait for command to be cleared up to 1 sec */ - for (i=0; i<100; i++) { - if (!readb(&bdp->scb->scb_cmd_low)) - break; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 100 + 1); - } - - /* Wait for TCO request bit in PMDR register to be clear */ - for (i=0; i<50; i++) { - if (!(readb(&bdp->scb->scb_ext.d101m_scb.scb_pmdr) & BIT_1)) - break; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 100 + 1); - } -} - -/** - * e100_hw_init - initialized tthe hardware - * @bdp: atapter's private data struct - * - * This routine performs a reset on the adapter, and configures the adapter. - * This includes configuring the 82557 LAN controller, validating and setting - * the node address, detecting and configuring the Phy chip on the adapter, - * and initializing all of the on chip counters. - * - * Returns: - * true - If the adapter was initialized - * false - If the adapter failed initialization - */ -unsigned char -e100_hw_init(struct e100_private *bdp) -{ - if (!e100_phy_init(bdp)) - goto err; - - e100_sw_reset(bdp, PORT_SELECTIVE_RESET); - - /* Only 82559 or above needs TCO workaround */ - if (bdp->rev_id >= D101MA_REV_ID) - e100_tco_workaround(bdp); - - /* Load the CU BASE (set to 0, because we use linear mode) */ - if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0)) - goto err; - - if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0)) - goto err; - - /* Load interrupt microcode */ - if (e100_load_microcode(bdp)) { - bdp->flags |= DF_UCODE_LOADED; - } - - if ((u8) bdp->rev_id < D101A4_REV_ID) - e100_config_init_82557(bdp); - - if (!e100_config(bdp)) - goto err; - - if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr)) - goto err; - - /* Clear the internal counters */ - if (!e100_clr_cntrs(bdp)) - goto err; - - /* Change for 82558 enhancement */ - /* If 82558/9 and if the user has enabled flow control, set up the - * Flow Control Reg. in the CSR */ - if ((bdp->flags & IS_BACHELOR) - && (bdp->params.b_params & PRM_FC)) { - writeb(DFLT_FC_THLD, &bdp->scb->scb_ext.d101_scb.scb_fc_thld); - writeb(DFLT_FC_CMD, - &bdp->scb->scb_ext.d101_scb.scb_fc_xon_xoff); - } - - return true; -err: - printk(KERN_ERR "e100: hw init failed\n"); - return false; -} - -/** - * e100_setup_tcb_pool - setup TCB circular list - * @head: Pointer to head of the allocated TCBs - * @qlen: Number of elements in the queue - * @bdp: atapter's private data struct - * - * This routine arranges the contigiously allocated TCB's in a circular list. - * Also does the one time initialization of the TCBs. - */ -static void -e100_setup_tcb_pool(tcb_t *head, unsigned int qlen, struct e100_private *bdp) -{ - int ele_no; - tcb_t *pcurr_tcb; /* point to current tcb */ - u32 next_phys; /* the next phys addr */ - u16 txcommand = CB_S_BIT | CB_TX_SF_BIT; - - bdp->tx_count = 0; - if (bdp->flags & USE_IPCB) { - txcommand |= CB_IPCB_TRANSMIT | CB_CID_DEFAULT; - } else if (bdp->flags & IS_BACHELOR) { - txcommand |= CB_TRANSMIT | CB_CID_DEFAULT; - } else { - txcommand |= CB_TRANSMIT; - } - - for (ele_no = 0, next_phys = bdp->tcb_phys, pcurr_tcb = head; - ele_no < qlen; ele_no++, pcurr_tcb++) { - - /* set the phys addr for this TCB, next_phys has not incr. yet */ - pcurr_tcb->tcb_phys = next_phys; - next_phys += sizeof (tcb_t); - - /* set the link to next tcb */ - if (ele_no == (qlen - 1)) - pcurr_tcb->tcb_hdr.cb_lnk_ptr = - cpu_to_le32(bdp->tcb_phys); - else - pcurr_tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(next_phys); - - pcurr_tcb->tcb_hdr.cb_status = 0; - pcurr_tcb->tcb_hdr.cb_cmd = cpu_to_le16(txcommand); - pcurr_tcb->tcb_cnt = 0; - pcurr_tcb->tcb_thrshld = bdp->tx_thld; - if (ele_no < 2) { - pcurr_tcb->tcb_hdr.cb_status = - cpu_to_le16(CB_STATUS_COMPLETE); - } - pcurr_tcb->tcb_tbd_num = 1; - - if (bdp->flags & IS_BACHELOR) { - pcurr_tcb->tcb_tbd_ptr = - __constant_cpu_to_le32(0xFFFFFFFF); - } else { - pcurr_tcb->tcb_tbd_ptr = - cpu_to_le32(pcurr_tcb->tcb_phys + 0x10); - } - - if (bdp->flags & IS_BACHELOR) { - pcurr_tcb->tcb_tbd_expand_ptr = - cpu_to_le32(pcurr_tcb->tcb_phys + 0x20); - } else { - pcurr_tcb->tcb_tbd_expand_ptr = - cpu_to_le32(pcurr_tcb->tcb_phys + 0x10); - } - pcurr_tcb->tcb_tbd_dflt_ptr = pcurr_tcb->tcb_tbd_ptr; - - if (bdp->flags & USE_IPCB) { - pcurr_tcb->tbd_ptr = &(pcurr_tcb->tcbu.tbd_array[1]); - pcurr_tcb->tcbu.ipcb.ip_activation_high = - IPCB_IP_ACTIVATION_DEFAULT; - pcurr_tcb->tcbu.ipcb.vlan = 0; - } else { - pcurr_tcb->tbd_ptr = &(pcurr_tcb->tcbu.tbd_array[0]); - } - - pcurr_tcb->tcb_skb = NULL; - } - - wmb(); -} - -/***************************************************************************/ -/***************************************************************************/ -/* Memory Management Routines */ -/***************************************************************************/ - -/** - * e100_alloc_space - allocate private driver data - * @bdp: atapter's private data struct - * - * This routine allocates memory for the driver. Memory allocated is for the - * selftest and statistics structures. - * - * Returns: - * 0: if the operation was successful - * %-ENOMEM: if memory allocation failed - */ -unsigned char -e100_alloc_space(struct e100_private *bdp) -{ - unsigned long off; - - /* allocate all the dma-able structures in one call: - * selftest results, adapter stats, and non-tx cb commands */ - if (!(bdp->dma_able = - pci_alloc_consistent(bdp->pdev, sizeof (bd_dma_able_t), - &(bdp->dma_able_phys)))) { - goto err; - } - - /* now assign the various pointers into the struct we've just allocated */ - off = offsetof(bd_dma_able_t, selftest); - - bdp->selftest = (self_test_t *) (bdp->dma_able + off); - bdp->selftest_phys = bdp->dma_able_phys + off; - - off = offsetof(bd_dma_able_t, stats_counters); - - bdp->stats_counters = (max_counters_t *) (bdp->dma_able + off); - bdp->stat_cnt_phys = bdp->dma_able_phys + off; - - return 0; - -err: - printk(KERN_ERR - "e100: Failed to allocate memory\n"); - return -ENOMEM; -} - -/** - * e100_alloc_tcb_pool - allocate TCB circular list - * @bdp: atapter's private data struct - * - * This routine allocates memory for the circular list of transmit descriptors. - * - * Returns: - * 0: if allocation has failed. - * 1: Otherwise. - */ -int -e100_alloc_tcb_pool(struct e100_private *bdp) -{ - int stcb = sizeof (tcb_t) * bdp->params.TxDescriptors; - - /* allocate space for the TCBs */ - if (!(bdp->tcb_pool.data = - pci_alloc_consistent(bdp->pdev, stcb, &bdp->tcb_phys))) - return 0; - - memset(bdp->tcb_pool.data, 0x00, stcb); - - return 1; -} - -void -e100_free_tcb_pool(struct e100_private *bdp) -{ - tcb_t *tcb; - int i; - /* Return tx skbs */ - for (i = 0; i < bdp->params.TxDescriptors; i++) { - tcb = bdp->tcb_pool.data; - tcb += bdp->tcb_pool.head; - e100_tx_skb_free(bdp, tcb); - if (NEXT_TCB_TOUSE(bdp->tcb_pool.head) == bdp->tcb_pool.tail) - break; - bdp->tcb_pool.head = NEXT_TCB_TOUSE(bdp->tcb_pool.head); - } - pci_free_consistent(bdp->pdev, - sizeof (tcb_t) * bdp->params.TxDescriptors, - bdp->tcb_pool.data, bdp->tcb_phys); - bdp->tcb_pool.head = 0; - bdp->tcb_pool.tail = 1; - bdp->tcb_phys = 0; -} - -static void -e100_dealloc_space(struct e100_private *bdp) -{ - if (bdp->dma_able) { - pci_free_consistent(bdp->pdev, sizeof (bd_dma_able_t), - bdp->dma_able, bdp->dma_able_phys); - } - - bdp->selftest_phys = 0; - bdp->stat_cnt_phys = 0; - bdp->dma_able_phys = 0; - bdp->dma_able = 0; -} - -static void -e100_free_rfd_pool(struct e100_private *bdp) -{ - struct rx_list_elem *rx_struct; - - while (!list_empty(&(bdp->active_rx_list))) { - - rx_struct = list_entry(bdp->active_rx_list.next, - struct rx_list_elem, list_elem); - list_del(&(rx_struct->list_elem)); - pci_unmap_single(bdp->pdev, rx_struct->dma_addr, - sizeof (rfd_t), PCI_DMA_TODEVICE); - dev_kfree_skb(rx_struct->skb); - kfree(rx_struct); - } - - while (!list_empty(&(bdp->rx_struct_pool))) { - rx_struct = list_entry(bdp->rx_struct_pool.next, - struct rx_list_elem, list_elem); - list_del(&(rx_struct->list_elem)); - kfree(rx_struct); - } -} - -/** - * e100_alloc_rfd_pool - allocate RFDs - * @bdp: atapter's private data struct - * - * Allocates initial pool of skb which holds both rfd and data, - * and return a pointer to the head of the list - */ -static int -e100_alloc_rfd_pool(struct e100_private *bdp) -{ - struct rx_list_elem *rx_struct; - int i; - - INIT_LIST_HEAD(&(bdp->active_rx_list)); - INIT_LIST_HEAD(&(bdp->rx_struct_pool)); - bdp->skb_req = bdp->params.RxDescriptors; - for (i = 0; i < bdp->skb_req; i++) { - rx_struct = kmalloc(sizeof (struct rx_list_elem), GFP_ATOMIC); - list_add(&(rx_struct->list_elem), &(bdp->rx_struct_pool)); - } - e100_alloc_skbs(bdp); - return !list_empty(&(bdp->active_rx_list)); - -} - -void -e100_clear_pools(struct e100_private *bdp) -{ - bdp->last_tcb = NULL; - e100_free_rfd_pool(bdp); - e100_free_tcb_pool(bdp); -} - -/*****************************************************************************/ -/*****************************************************************************/ -/* Run Time Functions */ -/*****************************************************************************/ - -/** - * e100_watchdog - * @dev: adapter's net_device struct - * - * This routine runs every 2 seconds and updates our statitics and link state, - * and refreshs txthld value. - */ -void -e100_watchdog(struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - -#ifdef E100_CU_DEBUG - if (e100_cu_unknown_state(bdp)) { - printk(KERN_ERR "e100: %s: CU unknown state in e100_watchdog\n", - dev->name); - } -#endif - if (!netif_running(dev)) { - return; - } - - /* check if link state has changed */ - if (e100_phy_check(bdp)) { - if (netif_carrier_ok(dev)) { - printk(KERN_ERR - "e100: %s NIC Link is Up %d Mbps %s duplex\n", - bdp->device->name, bdp->cur_line_speed, - (bdp->cur_dplx_mode == HALF_DUPLEX) ? - "Half" : "Full"); - - e100_config_fc(bdp); - e100_config(bdp); - - } else { - printk(KERN_ERR "e100: %s NIC Link is Down\n", - bdp->device->name); - } - } - - // toggle the tx queue according to link status - // this also resolves a race condition between tx & non-cu cmd flows - if (netif_carrier_ok(dev)) { - if (netif_running(dev)) - netif_wake_queue(dev); - } else { - if (netif_running(dev)) - netif_stop_queue(dev); - /* When changing to non-autoneg, device may lose */ - /* link with some switches. e100 will try to */ - /* revover link by sending command to PHY layer */ - if (bdp->params.e100_speed_duplex != E100_AUTONEG) - e100_force_speed_duplex_to_phy(bdp); - } - - rmb(); - - if (e100_update_stats(bdp)) { - - /* Check if a change in the IFS parameter is needed, - and configure the device accordingly */ - if (bdp->params.b_params & PRM_IFS) - e100_manage_adaptive_ifs(bdp); - - /* Now adjust our dynamic tx threshold value */ - e100_refresh_txthld(bdp); - - /* Now if we are on a 557 and we havn't received any frames then we - * should issue a multicast command to reset the RU */ - if (bdp->rev_id < D101A4_REV_ID) { - if (!(bdp->stats_counters->basic_stats.rcv_gd_frames)) { - e100_set_multi(dev); - } - } - } - /* Issue command to dump statistics from device. */ - /* Check for command completion on next watchdog timer. */ - e100_dump_stats_cntrs(bdp); - - wmb(); - - /* relaunch watchdog timer in 2 sec */ - mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ)); - - if (list_empty(&bdp->active_rx_list)) - e100_trigger_SWI(bdp); -} - -/** - * e100_manage_adaptive_ifs - * @bdp: atapter's private data struct - * - * This routine manages the adaptive Inter-Frame Spacing algorithm - * using a state machine. - */ -void -e100_manage_adaptive_ifs(struct e100_private *bdp) -{ - static u16 state_table[9][4] = { // rows are states - {2, 0, 0, 0}, // state0 // column0: next state if increasing - {2, 0, 5, 30}, // state1 // column1: next state if decreasing - {5, 1, 5, 30}, // state2 // column2: IFS value for 100 mbit - {5, 3, 0, 0}, // state3 // column3: IFS value for 10 mbit - {5, 3, 10, 60}, // state4 - {8, 4, 10, 60}, // state5 - {8, 6, 0, 0}, // state6 - {8, 6, 20, 60}, // state7 - {8, 7, 20, 60} // state8 - }; - - u32 transmits = - le32_to_cpu(bdp->stats_counters->basic_stats.xmt_gd_frames); - u32 collisions = - le32_to_cpu(bdp->stats_counters->basic_stats.xmt_ttl_coll); - u32 state = bdp->ifs_state; - u32 old_value = bdp->ifs_value; - int next_col; - u32 min_transmits; - - if (bdp->cur_dplx_mode == FULL_DUPLEX) { - bdp->ifs_state = 0; - bdp->ifs_value = 0; - - } else { /* Half Duplex */ - /* Set speed specific parameters */ - if (bdp->cur_line_speed == 100) { - next_col = 2; - min_transmits = MIN_NUMBER_OF_TRANSMITS_100; - - } else { /* 10 Mbps */ - next_col = 3; - min_transmits = MIN_NUMBER_OF_TRANSMITS_10; - } - - if ((transmits / 32 < collisions) - && (transmits > min_transmits)) { - state = state_table[state][0]; /* increment */ - - } else if (transmits < min_transmits) { - state = state_table[state][1]; /* decrement */ - } - - bdp->ifs_value = state_table[state][next_col]; - bdp->ifs_state = state; - } - - /* If the IFS value has changed, configure the device */ - if (bdp->ifs_value != old_value) { - e100_config_ifs(bdp); - e100_config(bdp); - } -} - -/** - * e100intr - interrupt handler - * @irq: the IRQ number - * @dev_inst: the net_device struct - * @regs: registers (unused) - * - * This routine is the ISR for the e100 board. It services - * the RX & TX queues & starts the RU if it has stopped due - * to no resources. - */ -irqreturn_t -e100intr(int irq, void *dev_inst, struct pt_regs *regs) -{ - struct net_device *dev; - struct e100_private *bdp; - u16 intr_status; - - dev = dev_inst; - bdp = dev->priv; - - intr_status = readw(&bdp->scb->scb_status); - /* If not my interrupt, just return */ - if (!(intr_status & SCB_STATUS_ACK_MASK) || (intr_status == 0xffff)) { - return IRQ_NONE; - } - - /* disable and ack intr */ - e100_disable_clear_intr(bdp); - - /* the device is closed, don't continue or else bad things may happen. */ - if (!netif_running(dev)) { - e100_set_intr_mask(bdp); - return IRQ_NONE; - } - - /* SWI intr (triggered by watchdog) is signal to allocate new skb buffers */ - if (intr_status & SCB_STATUS_ACK_SWI) { - e100_alloc_skbs(bdp); - } - - /* do recv work if any */ - if (intr_status & - (SCB_STATUS_ACK_FR | SCB_STATUS_ACK_RNR | SCB_STATUS_ACK_SWI)) - bdp->drv_stats.rx_intr_pkts += e100_rx_srv(bdp); - - /* clean up after tx'ed packets */ - if (intr_status & (SCB_STATUS_ACK_CNA | SCB_STATUS_ACK_CX)) - e100_tx_srv(bdp); - - e100_set_intr_mask(bdp); - return IRQ_HANDLED; -} - -/** - * e100_tx_skb_free - free TX skbs resources - * @bdp: atapter's private data struct - * @tcb: associated tcb of the freed skb - * - * This routine frees resources of TX skbs. - */ -static inline void -e100_tx_skb_free(struct e100_private *bdp, tcb_t *tcb) -{ - if (tcb->tcb_skb) { - int i; - tbd_t *tbd_arr = tcb->tbd_ptr; - int frags = skb_shinfo(tcb->tcb_skb)->nr_frags; - - for (i = 0; i <= frags; i++, tbd_arr++) { - pci_unmap_single(bdp->pdev, - le32_to_cpu(tbd_arr->tbd_buf_addr), - le16_to_cpu(tbd_arr->tbd_buf_cnt), - PCI_DMA_TODEVICE); - } - dev_kfree_skb_irq(tcb->tcb_skb); - tcb->tcb_skb = NULL; - } -} - -/** - * e100_tx_srv - service TX queues - * @bdp: atapter's private data struct - * - * This routine services the TX queues. It reclaims the TCB's & TBD's & other - * resources used during the transmit of this buffer. It is called from the ISR. - * We don't need a tx_lock since we always access buffers which were already - * prepared. - */ -void -e100_tx_srv(struct e100_private *bdp) -{ - tcb_t *tcb; - int i; - - /* go over at most TxDescriptors buffers */ - for (i = 0; i < bdp->params.TxDescriptors; i++) { - tcb = bdp->tcb_pool.data; - tcb += bdp->tcb_pool.head; - - rmb(); - - /* if the buffer at 'head' is not complete, break */ - if (!(tcb->tcb_hdr.cb_status & - __constant_cpu_to_le16(CB_STATUS_COMPLETE))) - break; - - /* service next buffer, clear the out of resource condition */ - e100_tx_skb_free(bdp, tcb); - - if (netif_running(bdp->device)) - netif_wake_queue(bdp->device); - - /* if we've caught up with 'tail', break */ - if (NEXT_TCB_TOUSE(bdp->tcb_pool.head) == bdp->tcb_pool.tail) { - break; - } - - bdp->tcb_pool.head = NEXT_TCB_TOUSE(bdp->tcb_pool.head); - } -} - -/** - * e100_rx_srv - service RX queue - * @bdp: atapter's private data struct - * @max_number_of_rfds: max number of RFDs to process - * @rx_congestion: flag pointer, to inform the calling function of congestion. - * - * This routine processes the RX interrupt & services the RX queues. - * For each successful RFD, it allocates a new msg block, links that - * into the RFD list, and sends the old msg upstream. - * The new RFD is then put at the end of the free list of RFD's. - * It returns the number of serviced RFDs. - */ -u32 -e100_rx_srv(struct e100_private *bdp) -{ - rfd_t *rfd; /* new rfd, received rfd */ - int i; - u16 rfd_status; - struct sk_buff *skb; - struct net_device *dev; - unsigned int data_sz; - struct rx_list_elem *rx_struct; - u32 rfd_cnt = 0; - - dev = bdp->device; - - /* current design of rx is as following: - * 1. socket buffer (skb) used to pass network packet to upper layer - * 2. all HW host memory structures (like RFDs, RBDs and data buffers) - * are placed in a skb's data room - * 3. when rx process is complete, we change skb internal pointers to exclude - * from data area all unrelated things (RFD, RDB) and to leave - * just rx'ed packet netto - * 4. for each skb passed to upper layer, new one is allocated instead. - * 5. if no skb left, in 2 sec another atempt to allocate skbs will be made - * (watchdog trigger SWI intr and isr should allocate new skbs) - */ - for (i = 0; i < bdp->params.RxDescriptors; i++) { - if (list_empty(&(bdp->active_rx_list))) { - break; - } - - rx_struct = list_entry(bdp->active_rx_list.next, - struct rx_list_elem, list_elem); - skb = rx_struct->skb; - - rfd = RFD_POINTER(skb, bdp); /* locate RFD within skb */ - - // sync only the RFD header - pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr, - bdp->rfd_size, PCI_DMA_FROMDEVICE); - rfd_status = le16_to_cpu(rfd->rfd_header.cb_status); /* get RFD's status */ - if (!(rfd_status & RFD_STATUS_COMPLETE)) /* does not contains data yet - exit */ - break; - - /* to allow manipulation with current skb we need to unlink it */ - list_del(&(rx_struct->list_elem)); - - /* do not free & unmap badly received packet. - * move it to the end of skb list for reuse */ - if (!(rfd_status & RFD_STATUS_OK)) { - e100_add_skb_to_end(bdp, rx_struct); - continue; - } - - data_sz = min_t(u16, (le16_to_cpu(rfd->rfd_act_cnt) & 0x3fff), - (sizeof (rfd_t) - bdp->rfd_size)); - - /* now sync all the data */ - pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr, - (data_sz + bdp->rfd_size), - PCI_DMA_FROMDEVICE); - - pci_unmap_single(bdp->pdev, rx_struct->dma_addr, - sizeof (rfd_t), PCI_DMA_FROMDEVICE); - - list_add(&(rx_struct->list_elem), &(bdp->rx_struct_pool)); - - /* end of dma access to rfd */ - bdp->skb_req++; /* incr number of requested skbs */ - e100_alloc_skbs(bdp); /* and get them */ - - /* set packet size, excluding checksum (2 last bytes) if it is present */ - if ((bdp->flags & DF_CSUM_OFFLOAD) - && (bdp->rev_id < D102_REV_ID)) - skb_put(skb, (int) data_sz - 2); - else - skb_put(skb, (int) data_sz); - - /* set the protocol */ - skb->protocol = eth_type_trans(skb, dev); - - /* set the checksum info */ - if (bdp->flags & DF_CSUM_OFFLOAD) { - if (bdp->rev_id >= D102_REV_ID) { - skb->ip_summed = e100_D102_check_checksum(rfd); - } else { - skb->ip_summed = e100_D101M_checksum(bdp, skb); - } - } else { - skb->ip_summed = CHECKSUM_NONE; - } - - bdp->drv_stats.net_stats.rx_bytes += skb->len; - - if(bdp->vlgrp && (rfd_status & CB_STATUS_VLAN)) { - vlan_hwaccel_rx(skb, bdp->vlgrp, be16_to_cpu(rfd->vlanid)); - } else { - netif_rx(skb); - } - dev->last_rx = jiffies; - - rfd_cnt++; - } /* end of rfd loop */ - - /* restart the RU if it has stopped */ - if ((readw(&bdp->scb->scb_status) & SCB_RUS_MASK) != SCB_RUS_READY) { - e100_start_ru(bdp); - } - - return rfd_cnt; -} - -void -e100_refresh_txthld(struct e100_private *bdp) -{ - basic_cntr_t *pstat = &(bdp->stats_counters->basic_stats); - - /* as long as tx_per_underrun is not 0, we can go about dynamically * - * adjusting the xmit threshold. we stop doing that & resort to defaults - * * once the adjustments become meaningless. the value is adjusted by * - * dumping the error counters & checking the # of xmit underrun errors * - * we've had. */ - if (bdp->tx_per_underrun) { - /* We are going to last values dumped from the dump statistics - * command */ - if (le32_to_cpu(pstat->xmt_gd_frames)) { - if (le32_to_cpu(pstat->xmt_uruns)) { - /* - * if we have had more than one underrun per "DEFAULT # - * OF XMITS ALLOWED PER UNDERRUN" good xmits, raise the - * THRESHOLD. - */ - if ((le32_to_cpu(pstat->xmt_gd_frames) / - le32_to_cpu(pstat->xmt_uruns)) < - bdp->tx_per_underrun) { - bdp->tx_thld += 3; - } - } - - /* - * if we've had less than one underrun per the DEFAULT number of - * of good xmits allowed, lower the THOLD but not less than 0 - */ - if (le32_to_cpu(pstat->xmt_gd_frames) > - bdp->tx_per_underrun) { - bdp->tx_thld--; - - if (bdp->tx_thld < 6) - bdp->tx_thld = 6; - - } - } - - /* end good xmits */ - /* - * * if our adjustments are becoming unresonable, stop adjusting & - * resort * to defaults & pray. A THOLD value > 190 means that the - * adapter will * wait for 190*8=1520 bytes in TX FIFO before it - * starts xmit. Since * MTU is 1514, it doesn't make any sense for - * further increase. */ - if (bdp->tx_thld >= 190) { - bdp->tx_per_underrun = 0; - bdp->tx_thld = 189; - } - } /* end underrun check */ -} - -/** - * e100_prepare_xmit_buff - prepare a buffer for transmission - * @bdp: atapter's private data struct - * @skb: skb to send - * - * This routine prepare a buffer for transmission. It checks - * the message length for the appropiate size. It picks up a - * free tcb from the TCB pool and sets up the corresponding - * TBD's. If the number of fragments are more than the number - * of TBD/TCB it copies all the fragments in a coalesce buffer. - * It returns a pointer to the prepared TCB. - */ -static inline tcb_t * -e100_prepare_xmit_buff(struct e100_private *bdp, struct sk_buff *skb) -{ - tcb_t *tcb, *prev_tcb; - - tcb = bdp->tcb_pool.data; - tcb += TCB_TO_USE(bdp->tcb_pool); - - if (bdp->flags & USE_IPCB) { - tcb->tcbu.ipcb.ip_activation_high = IPCB_IP_ACTIVATION_DEFAULT; - tcb->tcbu.ipcb.ip_schedule &= ~IPCB_TCP_PACKET; - tcb->tcbu.ipcb.ip_schedule &= ~IPCB_TCPUDP_CHECKSUM_ENABLE; - } - - if(bdp->vlgrp && vlan_tx_tag_present(skb)) { - (tcb->tcbu).ipcb.ip_activation_high |= IPCB_INSERTVLAN_ENABLE; - (tcb->tcbu).ipcb.vlan = cpu_to_be16(vlan_tx_tag_get(skb)); - } - - tcb->tcb_hdr.cb_status = 0; - tcb->tcb_thrshld = bdp->tx_thld; - tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_S_BIT); - - /* Set I (Interrupt) bit on every (TX_FRAME_CNT)th packet */ - if (!(++bdp->tx_count % TX_FRAME_CNT)) - tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_I_BIT); - else - /* Clear I bit on other packets */ - tcb->tcb_hdr.cb_cmd &= ~__constant_cpu_to_le16(CB_I_BIT); - - tcb->tcb_skb = skb; - - if (skb->ip_summed == CHECKSUM_HW) { - const struct iphdr *ip = skb->nh.iph; - - if ((ip->protocol == IPPROTO_TCP) || - (ip->protocol == IPPROTO_UDP)) { - - tcb->tcbu.ipcb.ip_activation_high |= - IPCB_HARDWAREPARSING_ENABLE; - tcb->tcbu.ipcb.ip_schedule |= - IPCB_TCPUDP_CHECKSUM_ENABLE; - - if (ip->protocol == IPPROTO_TCP) - tcb->tcbu.ipcb.ip_schedule |= IPCB_TCP_PACKET; - } - } - - if (!skb_shinfo(skb)->nr_frags) { - (tcb->tbd_ptr)->tbd_buf_addr = - cpu_to_le32(pci_map_single(bdp->pdev, skb->data, - skb->len, PCI_DMA_TODEVICE)); - (tcb->tbd_ptr)->tbd_buf_cnt = cpu_to_le16(skb->len); - tcb->tcb_tbd_num = 1; - tcb->tcb_tbd_ptr = tcb->tcb_tbd_dflt_ptr; - } else { - int i; - void *addr; - tbd_t *tbd_arr_ptr = &(tcb->tbd_ptr[1]); - skb_frag_t *frag = &skb_shinfo(skb)->frags[0]; - - (tcb->tbd_ptr)->tbd_buf_addr = - cpu_to_le32(pci_map_single(bdp->pdev, skb->data, - skb_headlen(skb), - PCI_DMA_TODEVICE)); - (tcb->tbd_ptr)->tbd_buf_cnt = - cpu_to_le16(skb_headlen(skb)); - - for (i = 0; i < skb_shinfo(skb)->nr_frags; - i++, tbd_arr_ptr++, frag++) { - - addr = ((void *) page_address(frag->page) + - frag->page_offset); - - tbd_arr_ptr->tbd_buf_addr = - cpu_to_le32(pci_map_single(bdp->pdev, - addr, frag->size, - PCI_DMA_TODEVICE)); - tbd_arr_ptr->tbd_buf_cnt = cpu_to_le16(frag->size); - } - tcb->tcb_tbd_num = skb_shinfo(skb)->nr_frags + 1; - tcb->tcb_tbd_ptr = tcb->tcb_tbd_expand_ptr; - } - - /* clear the S-BIT on the previous tcb */ - prev_tcb = bdp->tcb_pool.data; - prev_tcb += PREV_TCB_USED(bdp->tcb_pool); - prev_tcb->tcb_hdr.cb_cmd &= __constant_cpu_to_le16((u16) ~CB_S_BIT); - - bdp->tcb_pool.tail = NEXT_TCB_TOUSE(bdp->tcb_pool.tail); - - wmb(); - - e100_start_cu(bdp, tcb); - - return tcb; -} - -/* Changed for 82558 enhancement */ -/** - * e100_start_cu - start the adapter's CU - * @bdp: atapter's private data struct - * @tcb: TCB to be transmitted - * - * This routine issues a CU Start or CU Resume command to the 82558/9. - * This routine was added because the prepare_ext_xmit_buff takes advantage - * of the 82558/9's Dynamic TBD chaining feature and has to start the CU as - * soon as the first TBD is ready. - * - * e100_start_cu must be called while holding the tx_lock ! - */ -u8 -e100_start_cu(struct e100_private *bdp, tcb_t *tcb) -{ - unsigned long lock_flag; - u8 ret = true; - - spin_lock_irqsave(&(bdp->bd_lock), lock_flag); - switch (bdp->next_cu_cmd) { - case RESUME_NO_WAIT: - /*last cu command was a CU_RESMUE if this is a 558 or newer we don't need to - * wait for command word to clear, we reach here only if we are bachlor - */ - e100_exec_cmd(bdp, SCB_CUC_RESUME); - break; - - case RESUME_WAIT: - if ((bdp->flags & IS_ICH) && - (bdp->cur_line_speed == 10) && - (bdp->cur_dplx_mode == HALF_DUPLEX)) { - e100_wait_exec_simple(bdp, SCB_CUC_NOOP); - udelay(1); - } - if ((e100_wait_exec_simple(bdp, SCB_CUC_RESUME)) && - (bdp->flags & IS_BACHELOR) && (!(bdp->flags & IS_ICH))) { - bdp->next_cu_cmd = RESUME_NO_WAIT; - } - break; - - case START_WAIT: - // The last command was a non_tx CU command - if (!e100_wait_cus_idle(bdp)) - printk(KERN_DEBUG - "e100: %s: cu_start: timeout waiting for cu\n", - bdp->device->name); - if (!e100_wait_exec_cmplx(bdp, (u32) (tcb->tcb_phys), - SCB_CUC_START, CB_TRANSMIT)) { - printk(KERN_DEBUG - "e100: %s: cu_start: timeout waiting for scb\n", - bdp->device->name); - e100_exec_cmplx(bdp, (u32) (tcb->tcb_phys), - SCB_CUC_START); - ret = false; - } - - bdp->next_cu_cmd = RESUME_WAIT; - - break; - } - - /* save the last tcb */ - bdp->last_tcb = tcb; - - spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag); - return ret; -} - -/* ====================================================================== */ -/* hw */ -/* ====================================================================== */ - -/** - * e100_selftest - perform H/W self test - * @bdp: atapter's private data struct - * @st_timeout: address to return timeout value, if fails - * @st_result: address to return selftest result, if fails - * - * This routine will issue PORT Self-test command to test the e100. - * The self-test will fail if the adapter's master-enable bit is not - * set in the PCI Command Register, or if the adapter is not seated - * in a PCI master-enabled slot. we also disable interrupts when the - * command is completed. - * - * Returns: - * true: if adapter passes self_test - * false: otherwise - */ -unsigned char -e100_selftest(struct e100_private *bdp, u32 *st_timeout, u32 *st_result) -{ - u32 selftest_cmd; - - /* initialize the nic state before running test */ - e100_sw_reset(bdp, PORT_SOFTWARE_RESET); - /* Setup the address of the self_test area */ - selftest_cmd = bdp->selftest_phys; - - /* Setup SELF TEST Command Code in D3 - D0 */ - selftest_cmd |= PORT_SELFTEST; - - /* Initialize the self-test signature and results DWORDS */ - bdp->selftest->st_sign = 0; - bdp->selftest->st_result = 0xffffffff; - - /* Do the port command */ - writel(selftest_cmd, &bdp->scb->scb_port); - readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */ - - /* Wait at least 10 milliseconds for the self-test to complete */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 100 + 1); - - /* disable interrupts since they are enabled */ - /* after device reset during selftest */ - e100_disable_clear_intr(bdp); - - /* if The First Self Test DWORD Still Zero, We've timed out. If the - * second DWORD is not zero then we have an error. */ - if ((bdp->selftest->st_sign == 0) || (bdp->selftest->st_result != 0)) { - - if (st_timeout) - *st_timeout = !(le32_to_cpu(bdp->selftest->st_sign)); - - if (st_result) - *st_result = le32_to_cpu(bdp->selftest->st_result); - - return false; - } - - return true; -} - -/** - * e100_setup_iaaddr - issue IA setup sommand - * @bdp: atapter's private data struct - * @eaddr: new ethernet address - * - * This routine will issue the IA setup command. This command - * will notify the 82557 (e100) of what its individual (node) - * address is. This command will be executed in polled mode. - * - * Returns: - * true: if the IA setup command was successfully issued and completed - * false: otherwise - */ -unsigned char -e100_setup_iaaddr(struct e100_private *bdp, u8 *eaddr) -{ - unsigned int i; - cb_header_t *ntcb_hdr; - unsigned char res; - nxmit_cb_entry_t *cmd; - - if ((cmd = e100_alloc_non_tx_cmd(bdp)) == NULL) { - res = false; - goto exit; - } - - ntcb_hdr = (cb_header_t *) cmd->non_tx_cmd; - ntcb_hdr->cb_cmd = __constant_cpu_to_le16(CB_IA_ADDRESS); - - for (i = 0; i < ETH_ALEN; i++) { - (cmd->non_tx_cmd)->ntcb.setup.ia_addr[i] = eaddr[i]; - } - - res = e100_exec_non_cu_cmd(bdp, cmd); - if (!res) - printk(KERN_WARNING "e100: %s: IA setup failed\n", - bdp->device->name); - -exit: - return res; -} - -/** - * e100_start_ru - start the RU if needed - * @bdp: atapter's private data struct - * - * This routine checks the status of the 82557's receive unit(RU), - * and starts the RU if it was not already active. However, - * before restarting the RU, the driver gives the RU the buffers - * it freed up during the servicing of the ISR. If there are - * no free buffers to give to the RU, (i.e. we have reached a - * no resource condition) the RU will not be started till the - * next ISR. - */ -void -e100_start_ru(struct e100_private *bdp) -{ - struct rx_list_elem *rx_struct = NULL; - int buffer_found = 0; - struct list_head *entry_ptr; - - list_for_each(entry_ptr, &(bdp->active_rx_list)) { - rx_struct = - list_entry(entry_ptr, struct rx_list_elem, list_elem); - pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr, - bdp->rfd_size, PCI_DMA_FROMDEVICE); - if (!((SKB_RFD_STATUS(rx_struct->skb, bdp) & - __constant_cpu_to_le16(RFD_STATUS_COMPLETE)))) { - buffer_found = 1; - break; - } - } - - /* No available buffers */ - if (!buffer_found) { - return; - } - - spin_lock(&bdp->bd_lock); - - if (!e100_wait_exec_cmplx(bdp, rx_struct->dma_addr, SCB_RUC_START, 0)) { - printk(KERN_DEBUG - "e100: %s: start_ru: wait_scb failed\n", - bdp->device->name); - e100_exec_cmplx(bdp, rx_struct->dma_addr, SCB_RUC_START); - } - if (bdp->next_cu_cmd == RESUME_NO_WAIT) { - bdp->next_cu_cmd = RESUME_WAIT; - } - spin_unlock(&bdp->bd_lock); -} - -/** - * e100_cmd_complete_location - * @bdp: atapter's private data struct - * - * This routine returns a pointer to the location of the command-complete - * DWord in the dump statistical counters area, according to the statistical - * counters mode (557 - basic, 558 - extended, or 559 - TCO mode). - * See e100_config_init() for the setting of the statistical counters mode. - */ -static u32 * -e100_cmd_complete_location(struct e100_private *bdp) -{ - u32 *cmd_complete; - max_counters_t *stats = bdp->stats_counters; - - switch (bdp->stat_mode) { - case E100_EXTENDED_STATS: - cmd_complete = - (u32 *) &(((err_cntr_558_t *) (stats))->cmd_complete); - break; - - case E100_TCO_STATS: - cmd_complete = - (u32 *) &(((err_cntr_559_t *) (stats))->cmd_complete); - break; - - case E100_BASIC_STATS: - default: - cmd_complete = - (u32 *) &(((err_cntr_557_t *) (stats))->cmd_complete); - break; - } - - return cmd_complete; -} - -/** - * e100_clr_cntrs - clear statistics counters - * @bdp: atapter's private data struct - * - * This routine will clear the adapter error statistic counters. - * - * Returns: - * true: if successfully cleared stat counters - * false: otherwise - */ -static unsigned char -e100_clr_cntrs(struct e100_private *bdp) -{ - volatile u32 *pcmd_complete; - - /* clear the dump counter complete word */ - pcmd_complete = e100_cmd_complete_location(bdp); - *pcmd_complete = 0; - wmb(); - - if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys, SCB_CUC_DUMP_ADDR, 0)) - return false; - - /* wait 10 microseconds for the command to complete */ - udelay(10); - - if (!e100_wait_exec_simple(bdp, SCB_CUC_DUMP_RST_STAT)) - return false; - - if (bdp->next_cu_cmd == RESUME_NO_WAIT) { - bdp->next_cu_cmd = RESUME_WAIT; - } - - return true; -} - -static unsigned char -e100_update_stats(struct e100_private *bdp) -{ - u32 *pcmd_complete; - basic_cntr_t *pstat = &(bdp->stats_counters->basic_stats); - - // check if last dump command completed - pcmd_complete = e100_cmd_complete_location(bdp); - if (*pcmd_complete != le32_to_cpu(DUMP_RST_STAT_COMPLETED) && - *pcmd_complete != le32_to_cpu(DUMP_STAT_COMPLETED)) { - *pcmd_complete = 0; - return false; - } - - /* increment the statistics */ - bdp->drv_stats.net_stats.rx_packets += - le32_to_cpu(pstat->rcv_gd_frames); - bdp->drv_stats.net_stats.tx_packets += - le32_to_cpu(pstat->xmt_gd_frames); - bdp->drv_stats.net_stats.rx_dropped += le32_to_cpu(pstat->rcv_rsrc_err); - bdp->drv_stats.net_stats.collisions += le32_to_cpu(pstat->xmt_ttl_coll); - bdp->drv_stats.net_stats.rx_length_errors += - le32_to_cpu(pstat->rcv_shrt_frames); - bdp->drv_stats.net_stats.rx_over_errors += - le32_to_cpu(pstat->rcv_rsrc_err); - bdp->drv_stats.net_stats.rx_crc_errors += - le32_to_cpu(pstat->rcv_crc_errs); - bdp->drv_stats.net_stats.rx_frame_errors += - le32_to_cpu(pstat->rcv_algn_errs); - bdp->drv_stats.net_stats.rx_fifo_errors += - le32_to_cpu(pstat->rcv_oruns); - bdp->drv_stats.net_stats.tx_aborted_errors += - le32_to_cpu(pstat->xmt_max_coll); - bdp->drv_stats.net_stats.tx_carrier_errors += - le32_to_cpu(pstat->xmt_lost_crs); - bdp->drv_stats.net_stats.tx_fifo_errors += - le32_to_cpu(pstat->xmt_uruns); - - bdp->drv_stats.tx_late_col += le32_to_cpu(pstat->xmt_late_coll); - bdp->drv_stats.tx_ok_defrd += le32_to_cpu(pstat->xmt_deferred); - bdp->drv_stats.tx_one_retry += le32_to_cpu(pstat->xmt_sngl_coll); - bdp->drv_stats.tx_mt_one_retry += le32_to_cpu(pstat->xmt_mlt_coll); - bdp->drv_stats.rcv_cdt_frames += le32_to_cpu(pstat->rcv_err_coll); - - if (bdp->stat_mode != E100_BASIC_STATS) { - ext_cntr_t *pex_stat = &bdp->stats_counters->extended_stats; - - bdp->drv_stats.xmt_fc_pkts += - le32_to_cpu(pex_stat->xmt_fc_frames); - bdp->drv_stats.rcv_fc_pkts += - le32_to_cpu(pex_stat->rcv_fc_frames); - bdp->drv_stats.rcv_fc_unsupported += - le32_to_cpu(pex_stat->rcv_fc_unsupported); - } - - if (bdp->stat_mode == E100_TCO_STATS) { - tco_cntr_t *ptco_stat = &bdp->stats_counters->tco_stats; - - bdp->drv_stats.xmt_tco_pkts += - le16_to_cpu(ptco_stat->xmt_tco_frames); - bdp->drv_stats.rcv_tco_pkts += - le16_to_cpu(ptco_stat->rcv_tco_frames); - } - - *pcmd_complete = 0; - return true; -} - -/** - * e100_dump_stat_cntrs - * @bdp: atapter's private data struct - * - * This routine will dump the board statistical counters without waiting - * for stat_dump to complete. Any access to this stats should verify the completion - * of the command - */ -void -e100_dump_stats_cntrs(struct e100_private *bdp) -{ - unsigned long lock_flag_bd; - - spin_lock_irqsave(&(bdp->bd_lock), lock_flag_bd); - - /* dump h/w stats counters */ - if (e100_wait_exec_simple(bdp, SCB_CUC_DUMP_RST_STAT)) { - if (bdp->next_cu_cmd == RESUME_NO_WAIT) { - bdp->next_cu_cmd = RESUME_WAIT; - } - } - - spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag_bd); -} - -/** - * e100_exec_non_cu_cmd - * @bdp: atapter's private data struct - * @command: the non-cu command to execute - * - * This routine will submit a command block to be executed, - */ -unsigned char -e100_exec_non_cu_cmd(struct e100_private *bdp, nxmit_cb_entry_t *command) -{ - cb_header_t *ntcb_hdr; - unsigned long lock_flag; - unsigned long expiration_time; - unsigned char rc = true; - u8 sub_cmd; - - ntcb_hdr = (cb_header_t *) command->non_tx_cmd; /* get hdr of non tcb cmd */ - sub_cmd = cpu_to_le16(ntcb_hdr->cb_cmd); - - /* Set the Command Block to be the last command block */ - ntcb_hdr->cb_cmd |= __constant_cpu_to_le16(CB_EL_BIT); - ntcb_hdr->cb_status = 0; - ntcb_hdr->cb_lnk_ptr = 0; - - wmb(); - if (in_interrupt()) - return e100_delayed_exec_non_cu_cmd(bdp, command); - - if (netif_running(bdp->device) && netif_carrier_ok(bdp->device)) - return e100_delayed_exec_non_cu_cmd(bdp, command); - - spin_lock_bh(&(bdp->bd_non_tx_lock)); - - if (bdp->non_tx_command_state != E100_NON_TX_IDLE) { - goto delayed_exec; - } - - if (bdp->last_tcb) { - rmb(); - if ((bdp->last_tcb->tcb_hdr.cb_status & - __constant_cpu_to_le16(CB_STATUS_COMPLETE)) == 0) - goto delayed_exec; - } - - if ((readw(&bdp->scb->scb_status) & SCB_CUS_MASK) == SCB_CUS_ACTIVE) { - goto delayed_exec; - } - - spin_lock_irqsave(&bdp->bd_lock, lock_flag); - - if (!e100_wait_exec_cmplx(bdp, command->dma_addr, SCB_CUC_START, sub_cmd)) { - spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag); - rc = false; - goto exit; - } - - bdp->next_cu_cmd = START_WAIT; - spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag); - - /* now wait for completion of non-cu CB up to 20 msec */ - expiration_time = jiffies + HZ / 50 + 1; - rmb(); - while (!(ntcb_hdr->cb_status & - __constant_cpu_to_le16(CB_STATUS_COMPLETE))) { - - if (time_before(jiffies, expiration_time)) { - spin_unlock_bh(&(bdp->bd_non_tx_lock)); - yield(); - spin_lock_bh(&(bdp->bd_non_tx_lock)); - } else { -#ifdef E100_CU_DEBUG - printk(KERN_ERR "e100: %s: non-TX command (%x) " - "timeout\n", bdp->device->name, sub_cmd); -#endif - rc = false; - goto exit; - } - rmb(); - } - -exit: - e100_free_non_tx_cmd(bdp, command); - - if (netif_running(bdp->device)) - netif_wake_queue(bdp->device); - - spin_unlock_bh(&(bdp->bd_non_tx_lock)); - return rc; - -delayed_exec: - spin_unlock_bh(&(bdp->bd_non_tx_lock)); - return e100_delayed_exec_non_cu_cmd(bdp, command); -} - -/** - * e100_sw_reset - * @bdp: atapter's private data struct - * @reset_cmd: s/w reset or selective reset - * - * This routine will issue a software reset to the adapter. It - * will also disable interrupts, as the are enabled after reset. - */ -void -e100_sw_reset(struct e100_private *bdp, u32 reset_cmd) -{ - /* Do a selective reset first to avoid a potential PCI hang */ - writel(PORT_SELECTIVE_RESET, &bdp->scb->scb_port); - readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */ - - /* wait for the reset to take effect */ - udelay(20); - if (reset_cmd == PORT_SOFTWARE_RESET) { - writel(PORT_SOFTWARE_RESET, &bdp->scb->scb_port); - - /* wait 20 micro seconds for the reset to take effect */ - udelay(20); - } - - /* Mask off our interrupt line -- it is unmasked after reset */ - e100_disable_clear_intr(bdp); -#ifdef E100_CU_DEBUG - bdp->last_cmd = 0; - bdp->last_sub_cmd = 0; -#endif -} - -/** - * e100_load_microcode - Download microsocde to controller. - * @bdp: atapter's private data struct - * - * This routine downloads microcode on to the controller. This - * microcode is available for the 82558/9, 82550. Currently the - * microcode handles interrupt bundling and TCO workaround. - * - * Returns: - * true: if successfull - * false: otherwise - */ -static unsigned char -e100_load_microcode(struct e100_private *bdp) -{ - static struct { - u8 rev_id; - u32 ucode[UCODE_MAX_DWORDS + 1]; - int timer_dword; - int bundle_dword; - int min_size_dword; - } ucode_opts[] = { - { D101A4_REV_ID, - D101_A_RCVBUNDLE_UCODE, - D101_CPUSAVER_TIMER_DWORD, - D101_CPUSAVER_BUNDLE_DWORD, - D101_CPUSAVER_MIN_SIZE_DWORD }, - { D101B0_REV_ID, - D101_B0_RCVBUNDLE_UCODE, - D101_CPUSAVER_TIMER_DWORD, - D101_CPUSAVER_BUNDLE_DWORD, - D101_CPUSAVER_MIN_SIZE_DWORD }, - { D101MA_REV_ID, - D101M_B_RCVBUNDLE_UCODE, - D101M_CPUSAVER_TIMER_DWORD, - D101M_CPUSAVER_BUNDLE_DWORD, - D101M_CPUSAVER_MIN_SIZE_DWORD }, - { D101S_REV_ID, - D101S_RCVBUNDLE_UCODE, - D101S_CPUSAVER_TIMER_DWORD, - D101S_CPUSAVER_BUNDLE_DWORD, - D101S_CPUSAVER_MIN_SIZE_DWORD }, - { D102_REV_ID, - D102_B_RCVBUNDLE_UCODE, - D102_B_CPUSAVER_TIMER_DWORD, - D102_B_CPUSAVER_BUNDLE_DWORD, - D102_B_CPUSAVER_MIN_SIZE_DWORD }, - { D102C_REV_ID, - D102_C_RCVBUNDLE_UCODE, - D102_C_CPUSAVER_TIMER_DWORD, - D102_C_CPUSAVER_BUNDLE_DWORD, - D102_C_CPUSAVER_MIN_SIZE_DWORD }, - { D102E_REV_ID, - D102_E_RCVBUNDLE_UCODE, - D102_E_CPUSAVER_TIMER_DWORD, - D102_E_CPUSAVER_BUNDLE_DWORD, - D102_E_CPUSAVER_MIN_SIZE_DWORD }, - { 0, {0}, 0, 0, 0} - }, *opts; - - opts = ucode_opts; - - /* User turned ucode loading off */ - if (!(bdp->params.b_params & PRM_UCODE)) - return false; - - /* These controllers do not need ucode */ - if (bdp->flags & IS_ICH) - return false; - - /* Search for ucode match against h/w rev_id */ - while (opts->rev_id) { - if (bdp->rev_id == opts->rev_id) { - int i; - u32 *ucode_dword; - load_ucode_cb_t *ucode_cmd_ptr; - nxmit_cb_entry_t *cmd = e100_alloc_non_tx_cmd(bdp); - - if (cmd != NULL) { - ucode_cmd_ptr = - (load_ucode_cb_t *) cmd->non_tx_cmd; - ucode_dword = ucode_cmd_ptr->ucode_dword; - } else { - return false; - } - - memcpy(ucode_dword, opts->ucode, sizeof (opts->ucode)); - - /* Insert user-tunable settings */ - ucode_dword[opts->timer_dword] &= 0xFFFF0000; - ucode_dword[opts->timer_dword] |= - (u16) bdp->params.IntDelay; - ucode_dword[opts->bundle_dword] &= 0xFFFF0000; - ucode_dword[opts->bundle_dword] |= - (u16) bdp->params.BundleMax; - ucode_dword[opts->min_size_dword] &= 0xFFFF0000; - ucode_dword[opts->min_size_dword] |= - (bdp->params.b_params & PRM_BUNDLE_SMALL) ? - 0xFFFF : 0xFF80; - - for (i = 0; i < UCODE_MAX_DWORDS; i++) - cpu_to_le32s(&(ucode_dword[i])); - - ucode_cmd_ptr->load_ucode_cbhdr.cb_cmd = - __constant_cpu_to_le16(CB_LOAD_MICROCODE); - - return e100_exec_non_cu_cmd(bdp, cmd); - } - opts++; - } - - return false; -} - -/***************************************************************************/ -/***************************************************************************/ -/* EEPROM Functions */ -/***************************************************************************/ - -/* Read PWA (printed wired assembly) number */ -void -e100_rd_pwa_no(struct e100_private *bdp) -{ - bdp->pwa_no = e100_eeprom_read(bdp, EEPROM_PWA_NO); - bdp->pwa_no <<= 16; - bdp->pwa_no |= e100_eeprom_read(bdp, EEPROM_PWA_NO + 1); -} - -/* Read the permanent ethernet address from the eprom. */ -void -e100_rd_eaddr(struct e100_private *bdp) -{ - int i; - u16 eeprom_word; - - for (i = 0; i < 6; i += 2) { - eeprom_word = - e100_eeprom_read(bdp, - EEPROM_NODE_ADDRESS_BYTE_0 + (i / 2)); - - bdp->device->dev_addr[i] = - bdp->perm_node_address[i] = (u8) eeprom_word; - bdp->device->dev_addr[i + 1] = - bdp->perm_node_address[i + 1] = (u8) (eeprom_word >> 8); - } -} - -/* Check the D102 RFD flags to see if the checksum passed */ -static unsigned char -e100_D102_check_checksum(rfd_t *rfd) -{ - if (((le16_to_cpu(rfd->rfd_header.cb_status)) & RFD_PARSE_BIT) - && (((rfd->rcvparserstatus & CHECKSUM_PROTOCOL_MASK) == - RFD_TCP_PACKET) - || ((rfd->rcvparserstatus & CHECKSUM_PROTOCOL_MASK) == - RFD_UDP_PACKET)) - && (rfd->checksumstatus & TCPUDP_CHECKSUM_BIT_VALID) - && (rfd->checksumstatus & TCPUDP_CHECKSUM_VALID)) { - return CHECKSUM_UNNECESSARY; - } - return CHECKSUM_NONE; -} - -/** - * e100_D101M_checksum - * @bdp: atapter's private data struct - * @skb: skb received - * - * Sets the skb->csum value from D101 csum found at the end of the Rx frame. The - * D101M sums all words in frame excluding the ethernet II header (14 bytes) so - * in case the packet is ethernet II and the protocol is IP, all is need is to - * assign this value to skb->csum. - */ -static unsigned char -e100_D101M_checksum(struct e100_private *bdp, struct sk_buff *skb) -{ - unsigned short proto = (skb->protocol); - - if (proto == __constant_htons(ETH_P_IP)) { - - skb->csum = get_unaligned((u16 *) (skb->tail)); - return CHECKSUM_HW; - } - return CHECKSUM_NONE; -} - -/***************************************************************************/ -/***************************************************************************/ -/***************************************************************************/ -/***************************************************************************/ -/* Auxilary Functions */ -/***************************************************************************/ - -/* Print the board's configuration */ -void -e100_print_brd_conf(struct e100_private *bdp) -{ - /* Print the string if checksum Offloading was enabled */ - if (bdp->flags & DF_CSUM_OFFLOAD) - printk(KERN_NOTICE " Hardware receive checksums enabled\n"); - else { - if (bdp->rev_id >= D101MA_REV_ID) - printk(KERN_NOTICE " Hardware receive checksums disabled\n"); - } - - if ((bdp->flags & DF_UCODE_LOADED)) - printk(KERN_NOTICE " cpu cycle saver enabled\n"); -} - -/** - * e100_pci_setup - setup the adapter's PCI information - * @pcid: adapter's pci_dev struct - * @bdp: atapter's private data struct - * - * This routine sets up all PCI information for the adapter. It enables the bus - * master bit (some BIOS don't do this), requests memory ans I/O regions, and - * calls ioremap() on the adapter's memory region. - * - * Returns: - * true: if successfull - * false: otherwise - */ -static unsigned char -e100_pci_setup(struct pci_dev *pcid, struct e100_private *bdp) -{ - struct net_device *dev = bdp->device; - int rc = 0; - - if ((rc = pci_enable_device(pcid)) != 0) { - goto err; - } - - /* dev and ven ID have already been checked so it is our device */ - pci_read_config_byte(pcid, PCI_REVISION_ID, (u8 *) &(bdp->rev_id)); - - /* address #0 is a memory region */ - dev->mem_start = pci_resource_start(pcid, 0); - dev->mem_end = dev->mem_start + sizeof (scb_t); - - /* address #1 is a IO region */ - dev->base_addr = pci_resource_start(pcid, 1); - - if ((rc = pci_request_regions(pcid, e100_short_driver_name)) != 0) { - goto err_disable; - } - - pci_enable_wake(pcid, 0, 0); - - /* if Bus Mastering is off, turn it on! */ - pci_set_master(pcid); - - /* address #0 is a memory mapping */ - bdp->scb = (scb_t *) ioremap_nocache(dev->mem_start, sizeof (scb_t)); - - if (!bdp->scb) { - printk(KERN_ERR "e100: %s: Failed to map PCI address 0x%lX\n", - dev->name, pci_resource_start(pcid, 0)); - rc = -ENOMEM; - goto err_region; - } - - return 0; - -err_region: - pci_release_regions(pcid); -err_disable: - pci_disable_device(pcid); -err: - return rc; -} - -void -e100_isolate_driver(struct e100_private *bdp) -{ - - /* Check if interface is up */ - /* NOTE: Can't use netif_running(bdp->device) because */ - /* dev_close clears __LINK_STATE_START before calling */ - /* e100_close (aka dev->stop) */ - if (bdp->device->flags & IFF_UP) { - e100_disable_clear_intr(bdp); - del_timer_sync(&bdp->watchdog_timer); - netif_carrier_off(bdp->device); - netif_stop_queue(bdp->device); - bdp->last_tcb = NULL; - } - e100_sw_reset(bdp, PORT_SELECTIVE_RESET); -} - -static void -e100_tcb_add_C_bit(struct e100_private *bdp) -{ - tcb_t *tcb = (tcb_t *) bdp->tcb_pool.data; - int i; - - for (i = 0; i < bdp->params.TxDescriptors; i++, tcb++) { - tcb->tcb_hdr.cb_status |= cpu_to_le16(CB_STATUS_COMPLETE); - } -} - -/* - * Procedure: e100_configure_device - * - * Description: This routine will configure device - * - * Arguments: - * bdp - Ptr to this card's e100_bdconfig structure - * - * Returns: - * true upon success - * false upon failure - */ -unsigned char -e100_configure_device(struct e100_private *bdp) -{ - /*load CU & RU base */ - if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0)) - return false; - - if (e100_load_microcode(bdp)) - bdp->flags |= DF_UCODE_LOADED; - - if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0)) - return false; - - /* Issue the load dump counters address command */ - if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys, SCB_CUC_DUMP_ADDR, 0)) - return false; - - if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr)) { - printk(KERN_ERR "e100: e100_configure_device: " - "setup iaaddr failed\n"); - return false; - } - - e100_set_multi_exec(bdp->device); - - /* Change for 82558 enhancement */ - /* If 82558/9 and if the user has enabled flow control, set up */ - /* flow Control Reg. in the CSR */ - if ((bdp->flags & IS_BACHELOR) - && (bdp->params.b_params & PRM_FC)) { - writeb(DFLT_FC_THLD, - &bdp->scb->scb_ext.d101_scb.scb_fc_thld); - writeb(DFLT_FC_CMD, - &bdp->scb->scb_ext.d101_scb.scb_fc_xon_xoff); - } - - e100_force_config(bdp); - - return true; -} - -void -e100_deisolate_driver(struct e100_private *bdp, u8 full_reset) -{ - u32 cmd = full_reset ? PORT_SOFTWARE_RESET : PORT_SELECTIVE_RESET; - e100_sw_reset(bdp, cmd); - if (cmd == PORT_SOFTWARE_RESET) { - if (!e100_configure_device(bdp)) - printk(KERN_ERR "e100: e100_deisolate_driver:" - " device configuration failed\n"); - } - - if (netif_running(bdp->device)) { - - bdp->next_cu_cmd = START_WAIT; - bdp->last_tcb = NULL; - - e100_start_ru(bdp); - - /* relaunch watchdog timer in 2 sec */ - mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ)); - - // we must clear tcbs since we may have lost Tx intrrupt - // or have unsent frames on the tcb chain - e100_tcb_add_C_bit(bdp); - e100_tx_srv(bdp); - netif_wake_queue(bdp->device); - e100_set_intr_mask(bdp); - } -} - -static int -e100_do_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr) -{ - struct ethtool_cmd ecmd; - int rc = -EOPNOTSUPP; - - if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd.cmd))) - return -EFAULT; - - switch (ecmd.cmd) { - case ETHTOOL_GSET: - rc = e100_ethtool_get_settings(dev, ifr); - break; - case ETHTOOL_SSET: - rc = e100_ethtool_set_settings(dev, ifr); - break; - case ETHTOOL_GDRVINFO: - rc = e100_ethtool_get_drvinfo(dev, ifr); - break; - case ETHTOOL_GREGS: - rc = e100_ethtool_gregs(dev, ifr); - break; - case ETHTOOL_NWAY_RST: - rc = e100_ethtool_nway_rst(dev, ifr); - break; - case ETHTOOL_GLINK: - rc = e100_ethtool_glink(dev, ifr); - break; - case ETHTOOL_GEEPROM: - case ETHTOOL_SEEPROM: - rc = e100_ethtool_eeprom(dev, ifr); - break; - case ETHTOOL_GSTATS: { - struct { - struct ethtool_stats cmd; - uint64_t data[E100_STATS_LEN]; - } stats = { {ETHTOOL_GSTATS, E100_STATS_LEN} }; - struct e100_private *bdp = dev->priv; - void *addr = ifr->ifr_data; - int i; - - for(i = 0; i < E100_STATS_LEN; i++) - stats.data[i] = - ((unsigned long *)&bdp->drv_stats.net_stats)[i]; - if(copy_to_user(addr, &stats, sizeof(stats))) - return -EFAULT; - return 0; - } - case ETHTOOL_GWOL: - case ETHTOOL_SWOL: - rc = e100_ethtool_wol(dev, ifr); - break; - case ETHTOOL_TEST: - rc = e100_ethtool_test(dev, ifr); - break; - case ETHTOOL_GSTRINGS: - rc = e100_ethtool_gstrings(dev,ifr); - break; - case ETHTOOL_PHYS_ID: - rc = e100_ethtool_led_blink(dev,ifr); - break; -#ifdef ETHTOOL_GRINGPARAM - case ETHTOOL_GRINGPARAM: { - struct ethtool_ringparam ering; - struct e100_private *bdp = dev->priv; - memset((void *) &ering, 0, sizeof(ering)); - ering.rx_max_pending = E100_MAX_RFD; - ering.tx_max_pending = E100_MAX_TCB; - ering.rx_pending = bdp->params.RxDescriptors; - ering.tx_pending = bdp->params.TxDescriptors; - rc = copy_to_user(ifr->ifr_data, &ering, sizeof(ering)) - ? -EFAULT : 0; - return rc; - } -#endif -#ifdef ETHTOOL_SRINGPARAM - case ETHTOOL_SRINGPARAM: { - struct ethtool_ringparam ering; - struct e100_private *bdp = dev->priv; - if (copy_from_user(&ering, ifr->ifr_data, sizeof(ering))) - return -EFAULT; - if (ering.rx_pending > E100_MAX_RFD - || ering.rx_pending < E100_MIN_RFD) - return -EINVAL; - if (ering.tx_pending > E100_MAX_TCB - || ering.tx_pending < E100_MIN_TCB) - return -EINVAL; - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - /* Use new values to open interface */ - bdp->params.RxDescriptors = ering.rx_pending; - bdp->params.TxDescriptors = ering.tx_pending; - e100_hw_init(bdp); - e100_open(dev); - } - else { - bdp->params.RxDescriptors = ering.rx_pending; - bdp->params.TxDescriptors = ering.tx_pending; - } - return 0; - } -#endif -#ifdef ETHTOOL_GPAUSEPARAM - case ETHTOOL_GPAUSEPARAM: { - struct ethtool_pauseparam epause; - struct e100_private *bdp = dev->priv; - memset((void *) &epause, 0, sizeof(epause)); - if ((bdp->flags & IS_BACHELOR) - && (bdp->params.b_params & PRM_FC)) { - epause.autoneg = 1; - if (bdp->flags && DF_LINK_FC_CAP) { - epause.rx_pause = 1; - epause.tx_pause = 1; - } - if (bdp->flags && DF_LINK_FC_TX_ONLY) - epause.tx_pause = 1; - } - rc = copy_to_user(ifr->ifr_data, &epause, sizeof(epause)) - ? -EFAULT : 0; - return rc; - } -#endif -#ifdef ETHTOOL_SPAUSEPARAM - case ETHTOOL_SPAUSEPARAM: { - struct ethtool_pauseparam epause; - struct e100_private *bdp = dev->priv; - if (!(bdp->flags & IS_BACHELOR)) - return -EINVAL; - if (copy_from_user(&epause, ifr->ifr_data, sizeof(epause))) - return -EFAULT; - if (epause.autoneg == 1) - bdp->params.b_params |= PRM_FC; - else - bdp->params.b_params &= ~PRM_FC; - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - e100_hw_init(bdp); - e100_open(dev); - } - return 0; - } -#endif -#ifdef ETHTOOL_GRXCSUM - case ETHTOOL_GRXCSUM: - case ETHTOOL_GTXCSUM: - case ETHTOOL_GSG: - { struct ethtool_value eval; - struct e100_private *bdp = dev->priv; - memset((void *) &eval, 0, sizeof(eval)); - if ((ecmd.cmd == ETHTOOL_GRXCSUM) - && (bdp->params.b_params & PRM_XSUMRX)) - eval.data = 1; - else - eval.data = 0; - rc = copy_to_user(ifr->ifr_data, &eval, sizeof(eval)) - ? -EFAULT : 0; - return rc; - } -#endif -#ifdef ETHTOOL_SRXCSUM - case ETHTOOL_SRXCSUM: - case ETHTOOL_STXCSUM: - case ETHTOOL_SSG: - { struct ethtool_value eval; - struct e100_private *bdp = dev->priv; - if (copy_from_user(&eval, ifr->ifr_data, sizeof(eval))) - return -EFAULT; - if (ecmd.cmd == ETHTOOL_SRXCSUM) { - if (eval.data == 1) { - if (bdp->rev_id >= D101MA_REV_ID) - bdp->params.b_params |= PRM_XSUMRX; - else - return -EINVAL; - } else { - if (bdp->rev_id >= D101MA_REV_ID) - bdp->params.b_params &= ~PRM_XSUMRX; - else - return 0; - } - } else { - if (eval.data == 1) - return -EINVAL; - else - return 0; - } - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - e100_hw_init(bdp); - e100_open(dev); - } - return 0; - } -#endif - default: - break; - } //switch - return rc; -} - -static int -e100_ethtool_get_settings(struct net_device *dev, struct ifreq *ifr) -{ - struct e100_private *bdp; - struct ethtool_cmd ecmd; - u16 advert = 0; - - memset((void *) &ecmd, 0, sizeof (ecmd)); - - bdp = dev->priv; - - ecmd.supported = bdp->speed_duplex_caps; - - ecmd.port = - (bdp->speed_duplex_caps & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE; - ecmd.transceiver = XCVR_INTERNAL; - ecmd.phy_address = bdp->phy_addr; - - if (netif_carrier_ok(bdp->device)) { - ecmd.speed = bdp->cur_line_speed; - ecmd.duplex = - (bdp->cur_dplx_mode == HALF_DUPLEX) ? DUPLEX_HALF : DUPLEX_FULL; - } - else { - ecmd.speed = -1; - ecmd.duplex = -1; - } - - ecmd.advertising = ADVERTISED_TP; - - if (bdp->params.e100_speed_duplex == E100_AUTONEG) { - ecmd.autoneg = AUTONEG_ENABLE; - ecmd.advertising |= ADVERTISED_Autoneg; - } else { - ecmd.autoneg = AUTONEG_DISABLE; - } - - if (bdp->speed_duplex_caps & SUPPORTED_MII) { - e100_mdi_read(bdp, MII_ADVERTISE, bdp->phy_addr, &advert); - - if (advert & ADVERTISE_10HALF) - ecmd.advertising |= ADVERTISED_10baseT_Half; - if (advert & ADVERTISE_10FULL) - ecmd.advertising |= ADVERTISED_10baseT_Full; - if (advert & ADVERTISE_100HALF) - ecmd.advertising |= ADVERTISED_100baseT_Half; - if (advert & ADVERTISE_100FULL) - ecmd.advertising |= ADVERTISED_100baseT_Full; - } else { - ecmd.autoneg = AUTONEG_DISABLE; - ecmd.advertising &= ~ADVERTISED_Autoneg; - } - - if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd))) - return -EFAULT; - - return 0; -} - -static int -e100_ethtool_set_settings(struct net_device *dev, struct ifreq *ifr) -{ - struct e100_private *bdp; - int e100_new_speed_duplex; - int ethtool_new_speed_duplex; - struct ethtool_cmd ecmd; - - bdp = dev->priv; - if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd))) { - return -EFAULT; - } - - if ((ecmd.autoneg == AUTONEG_ENABLE) - && (bdp->speed_duplex_caps & SUPPORTED_Autoneg)) { - bdp->params.e100_speed_duplex = E100_AUTONEG; - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - e100_hw_init(bdp); - e100_open(dev); - } - } else { - if (ecmd.speed == SPEED_10) { - if (ecmd.duplex == DUPLEX_HALF) { - e100_new_speed_duplex = - E100_SPEED_10_HALF; - ethtool_new_speed_duplex = - SUPPORTED_10baseT_Half; - } else { - e100_new_speed_duplex = - E100_SPEED_10_FULL; - ethtool_new_speed_duplex = - SUPPORTED_10baseT_Full; - } - } else { - if (ecmd.duplex == DUPLEX_HALF) { - e100_new_speed_duplex = - E100_SPEED_100_HALF; - ethtool_new_speed_duplex = - SUPPORTED_100baseT_Half; - } else { - e100_new_speed_duplex = - E100_SPEED_100_FULL; - ethtool_new_speed_duplex = - SUPPORTED_100baseT_Full; - } - } - - if (bdp->speed_duplex_caps & ethtool_new_speed_duplex) { - bdp->params.e100_speed_duplex = - e100_new_speed_duplex; - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - e100_hw_init(bdp); - e100_open(dev); - } - } else { - return -EOPNOTSUPP; - } - } - - return 0; -} - -static int -e100_ethtool_glink(struct net_device *dev, struct ifreq *ifr) -{ - struct e100_private *bdp; - struct ethtool_value info; - - memset((void *) &info, 0, sizeof (info)); - - bdp = dev->priv; - info.cmd = ETHTOOL_GLINK; - - /* Consider both PHY link and netif_running */ - info.data = e100_update_link_state(bdp); - - if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) - return -EFAULT; - - return 0; -} - -static int -e100_ethtool_test(struct net_device *dev, struct ifreq *ifr) -{ - struct ethtool_test *info; - int rc = -EFAULT; - - info = kmalloc(sizeof(*info) + max_test_res * sizeof(u64), - GFP_ATOMIC); - - if (!info) - return -ENOMEM; - - memset((void *) info, 0, sizeof(*info) + - max_test_res * sizeof(u64)); - - if (copy_from_user(info, ifr->ifr_data, sizeof(*info))) - goto exit; - - info->flags = e100_run_diag(dev, info->data, info->flags); - - if (!copy_to_user(ifr->ifr_data, info, - sizeof(*info) + max_test_res * sizeof(u64))) - rc = 0; -exit: - kfree(info); - return rc; -} - -static int -e100_ethtool_gregs(struct net_device *dev, struct ifreq *ifr) -{ - struct e100_private *bdp; - u32 regs_buff[E100_REGS_LEN]; - struct ethtool_regs regs = {ETHTOOL_GREGS}; - void *addr = ifr->ifr_data; - u16 mdi_reg; - - bdp = dev->priv; - - if(copy_from_user(®s, addr, sizeof(regs))) - return -EFAULT; - - regs.version = (1 << 24) | bdp->rev_id; - regs_buff[0] = readb(&(bdp->scb->scb_cmd_hi)) << 24 | - readb(&(bdp->scb->scb_cmd_low)) << 16 | - readw(&(bdp->scb->scb_status)); - e100_mdi_read(bdp, MII_NCONFIG, bdp->phy_addr, &mdi_reg); - regs_buff[1] = mdi_reg; - - if(copy_to_user(addr, ®s, sizeof(regs))) - return -EFAULT; - - addr += offsetof(struct ethtool_regs, data); - if(copy_to_user(addr, regs_buff, regs.len)) - return -EFAULT; - - return 0; -} - -static int -e100_ethtool_nway_rst(struct net_device *dev, struct ifreq *ifr) -{ - struct e100_private *bdp; - - bdp = dev->priv; - - if ((bdp->speed_duplex_caps & SUPPORTED_Autoneg) && - (bdp->params.e100_speed_duplex == E100_AUTONEG)) { - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - e100_hw_init(bdp); - e100_open(dev); - } - } else { - return -EFAULT; - } - return 0; -} - -static int -e100_ethtool_get_drvinfo(struct net_device *dev, struct ifreq *ifr) -{ - struct e100_private *bdp; - struct ethtool_drvinfo info; - - memset((void *) &info, 0, sizeof (info)); - - bdp = dev->priv; - - strncpy(info.driver, e100_short_driver_name, sizeof (info.driver) - 1); - strncpy(info.version, e100_driver_version, sizeof (info.version) - 1); - strncpy(info.fw_version, "N/A", - sizeof (info.fw_version) - 1); - strncpy(info.bus_info, pci_name(bdp->pdev), - sizeof (info.bus_info) - 1); - info.n_stats = E100_STATS_LEN; - info.regdump_len = E100_REGS_LEN * sizeof(u32); - info.eedump_len = (bdp->eeprom_size << 1); - info.testinfo_len = max_test_res; - if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) - return -EFAULT; - - return 0; -} - -static int -e100_ethtool_eeprom(struct net_device *dev, struct ifreq *ifr) -{ - struct e100_private *bdp; - struct ethtool_eeprom ecmd; - u16 eeprom_data[256]; - u16 *usr_eeprom_ptr; - u16 first_word, last_word; - int i, max_len; - void *ptr; - u8 *eeprom_data_bytes = (u8 *)eeprom_data; - - bdp = dev->priv; - - if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd))) - return -EFAULT; - - usr_eeprom_ptr = - (u16 *) (ifr->ifr_data + offsetof(struct ethtool_eeprom, data)); - - max_len = bdp->eeprom_size * 2; - - if (ecmd.offset > ecmd.offset + ecmd.len) - return -EINVAL; - - if ((ecmd.offset + ecmd.len) > max_len) - ecmd.len = (max_len - ecmd.offset); - - first_word = ecmd.offset >> 1; - last_word = (ecmd.offset + ecmd.len - 1) >> 1; - - if (first_word >= bdp->eeprom_size) - return -EFAULT; - - if (ecmd.cmd == ETHTOOL_GEEPROM) { - for(i = 0; i <= (last_word - first_word); i++) - eeprom_data[i] = e100_eeprom_read(bdp, first_word + i); - - ecmd.magic = E100_EEPROM_MAGIC; - - if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd))) - return -EFAULT; - - if(ecmd.offset & 1) - eeprom_data_bytes++; - if (copy_to_user(usr_eeprom_ptr, eeprom_data_bytes, ecmd.len)) - return -EFAULT; - } else { - if (ecmd.magic != E100_EEPROM_MAGIC) - return -EFAULT; - - ptr = (void *)eeprom_data; - if(ecmd.offset & 1) { - /* need modification of first changed EEPROM word */ - /* only the second byte of the word is being modified */ - eeprom_data[0] = e100_eeprom_read(bdp, first_word); - ptr++; - } - if((ecmd.offset + ecmd.len) & 1) { - /* need modification of last changed EEPROM word */ - /* only the first byte of the word is being modified */ - eeprom_data[last_word - first_word] = - e100_eeprom_read(bdp, last_word); - } - if(copy_from_user(ptr, usr_eeprom_ptr, ecmd.len)) - return -EFAULT; - - e100_eeprom_write_block(bdp, first_word, eeprom_data, - last_word - first_word + 1); - - if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd))) - return -EFAULT; - } - return 0; -} - -#define E100_BLINK_INTERVAL (HZ/4) -/** - * e100_led_control - * @bdp: atapter's private data struct - * @led_mdi_op: led operation - * - * Software control over adapter's led. The possible operations are: - * TURN LED OFF, TURN LED ON and RETURN LED CONTROL TO HARDWARE. - */ -static void -e100_led_control(struct e100_private *bdp, u16 led_mdi_op) -{ - e100_mdi_write(bdp, PHY_82555_LED_SWITCH_CONTROL, - bdp->phy_addr, led_mdi_op); - -} -/** - * e100_led_blink_callback - * @data: pointer to atapter's private data struct - * - * Blink timer callback function. Toggles ON/OFF led status bit and calls - * led hardware access function. - */ -static void -e100_led_blink_callback(unsigned long data) -{ - struct e100_private *bdp = (struct e100_private *) data; - - if(bdp->flags & LED_IS_ON) { - bdp->flags &= ~LED_IS_ON; - e100_led_control(bdp, PHY_82555_LED_OFF); - } else { - bdp->flags |= LED_IS_ON; - if (bdp->rev_id >= D101MA_REV_ID) - e100_led_control(bdp, PHY_82555_LED_ON_559); - else - e100_led_control(bdp, PHY_82555_LED_ON_PRE_559); - } - - mod_timer(&bdp->blink_timer, jiffies + E100_BLINK_INTERVAL); -} -/** - * e100_ethtool_led_blink - * @dev: pointer to atapter's net_device struct - * @ifr: pointer to ioctl request structure - * - * Blink led ioctl handler. Initialtes blink timer and sleeps until - * blink period expires. Than it kills timer and returns. The led control - * is returned back to hardware when blink timer is killed. - */ -static int -e100_ethtool_led_blink(struct net_device *dev, struct ifreq *ifr) -{ - struct e100_private *bdp; - struct ethtool_value ecmd; - - bdp = dev->priv; - - if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd))) - return -EFAULT; - - if(!bdp->blink_timer.function) { - init_timer(&bdp->blink_timer); - bdp->blink_timer.function = e100_led_blink_callback; - bdp->blink_timer.data = (unsigned long) bdp; - } - - mod_timer(&bdp->blink_timer, jiffies); - - set_current_state(TASK_INTERRUPTIBLE); - - if ((!ecmd.data) || (ecmd.data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))) - ecmd.data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ); - - schedule_timeout(ecmd.data * HZ); - - del_timer_sync(&bdp->blink_timer); - - e100_led_control(bdp, PHY_82555_LED_NORMAL_CONTROL); - - return 0; -} - -static inline int -e100_10BaseT_adapter(struct e100_private *bdp) -{ - return ((bdp->pdev->device == 0x1229) && - (bdp->pdev->subsystem_vendor == 0x8086) && - (bdp->pdev->subsystem_device == 0x0003)); -} - -static void -e100_get_speed_duplex_caps(struct e100_private *bdp) -{ - u16 status; - - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &status); - - bdp->speed_duplex_caps = 0; - - bdp->speed_duplex_caps |= - (status & BMSR_ANEGCAPABLE) ? SUPPORTED_Autoneg : 0; - - bdp->speed_duplex_caps |= - (status & BMSR_10HALF) ? SUPPORTED_10baseT_Half : 0; - - bdp->speed_duplex_caps |= - (status & BMSR_10FULL) ? SUPPORTED_10baseT_Full : 0; - - bdp->speed_duplex_caps |= - (status & BMSR_100HALF) ? SUPPORTED_100baseT_Half : 0; - - bdp->speed_duplex_caps |= - (status & BMSR_100FULL) ? SUPPORTED_100baseT_Full : 0; - - if (IS_NC3133(bdp)) - bdp->speed_duplex_caps = - (SUPPORTED_FIBRE | SUPPORTED_100baseT_Full); - else - bdp->speed_duplex_caps |= SUPPORTED_TP; - - if ((status == 0xFFFF) && e100_10BaseT_adapter(bdp)) { - bdp->speed_duplex_caps = - (SUPPORTED_10baseT_Half | SUPPORTED_TP); - } else { - bdp->speed_duplex_caps |= SUPPORTED_MII; - } - -} - -#ifdef CONFIG_PM -static unsigned char -e100_setup_filter(struct e100_private *bdp) -{ - cb_header_t *ntcb_hdr; - unsigned char res = false; - nxmit_cb_entry_t *cmd; - - if ((cmd = e100_alloc_non_tx_cmd(bdp)) == NULL) { - goto exit; - } - - ntcb_hdr = (cb_header_t *) cmd->non_tx_cmd; - ntcb_hdr->cb_cmd = __constant_cpu_to_le16(CB_LOAD_FILTER); - - /* Set EL and FIX bit */ - (cmd->non_tx_cmd)->ntcb.filter.filter_data[0] = - __constant_cpu_to_le32(CB_FILTER_EL | CB_FILTER_FIX); - - if (bdp->wolopts & WAKE_UCAST) { - (cmd->non_tx_cmd)->ntcb.filter.filter_data[0] |= - __constant_cpu_to_le32(CB_FILTER_IA_MATCH); - } - - if (bdp->wolopts & WAKE_ARP) { - /* Setup ARP bit and lower IP parts */ - /* bdp->ip_lbytes contains 2 lower bytes of IP address in network byte order */ - (cmd->non_tx_cmd)->ntcb.filter.filter_data[0] |= - cpu_to_le32(CB_FILTER_ARP | bdp->ip_lbytes); - } - - res = e100_exec_non_cu_cmd(bdp, cmd); - if (!res) - printk(KERN_WARNING "e100: %s: Filter setup failed\n", - bdp->device->name); - -exit: - return res; - -} - -static void -e100_do_wol(struct pci_dev *pcid, struct e100_private *bdp) -{ - e100_config_wol(bdp); - - if (e100_config(bdp)) { - if (bdp->wolopts & (WAKE_UCAST | WAKE_ARP)) - if (!e100_setup_filter(bdp)) - printk(KERN_ERR - "e100: WOL options failed\n"); - } else { - printk(KERN_ERR "e100: config WOL failed\n"); - } -} -#endif - -static u16 -e100_get_ip_lbytes(struct net_device *dev) -{ - struct in_ifaddr *ifa; - struct in_device *in_dev; - u32 res = 0; - - in_dev = (struct in_device *) dev->ip_ptr; - /* Check if any in_device bound to interface */ - if (in_dev) { - /* Check if any IP address is bound to interface */ - if ((ifa = in_dev->ifa_list) != NULL) { - res = __constant_ntohl(ifa->ifa_address); - res = __constant_htons(res & 0x0000ffff); - } - } - return res; -} - -static int -e100_ethtool_wol(struct net_device *dev, struct ifreq *ifr) -{ - struct e100_private *bdp; - struct ethtool_wolinfo wolinfo; - int res = 0; - - bdp = dev->priv; - - if (copy_from_user(&wolinfo, ifr->ifr_data, sizeof (wolinfo))) { - return -EFAULT; - } - - switch (wolinfo.cmd) { - case ETHTOOL_GWOL: - wolinfo.supported = bdp->wolsupported; - wolinfo.wolopts = bdp->wolopts; - if (copy_to_user(ifr->ifr_data, &wolinfo, sizeof (wolinfo))) - res = -EFAULT; - break; - case ETHTOOL_SWOL: - /* If ALL requests are supported or request is DISABLE wol */ - if (((wolinfo.wolopts & bdp->wolsupported) == wolinfo.wolopts) - || (wolinfo.wolopts == 0)) { - bdp->wolopts = wolinfo.wolopts; - } else { - res = -EOPNOTSUPP; - } - if (wolinfo.wolopts & WAKE_ARP) - bdp->ip_lbytes = e100_get_ip_lbytes(dev); - break; - default: - break; - } - return res; -} - -static int e100_ethtool_gstrings(struct net_device *dev, struct ifreq *ifr) -{ - struct ethtool_gstrings info; - char *strings = NULL; - char *usr_strings; - int i; - - memset((void *) &info, 0, sizeof(info)); - - usr_strings = (u8 *) (ifr->ifr_data + - offsetof(struct ethtool_gstrings, data)); - - if (copy_from_user(&info, ifr->ifr_data, sizeof (info))) - return -EFAULT; - - switch (info.string_set) { - case ETH_SS_TEST: { - int ret = 0; - if (info.len > max_test_res) - info.len = max_test_res; - strings = kmalloc(info.len * ETH_GSTRING_LEN, GFP_ATOMIC); - if (!strings) - return -ENOMEM; - memset(strings, 0, info.len * ETH_GSTRING_LEN); - - for (i = 0; i < info.len; i++) { - sprintf(strings + i * ETH_GSTRING_LEN, "%s", - test_strings[i]); - } - if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) - ret = -EFAULT; - if (copy_to_user(usr_strings, strings, info.len * ETH_GSTRING_LEN)) - ret = -EFAULT; - kfree(strings); - return ret; - } - case ETH_SS_STATS: { - char *strings = NULL; - void *addr = ifr->ifr_data; - info.len = E100_STATS_LEN; - strings = *e100_gstrings_stats; - if(copy_to_user(ifr->ifr_data, &info, sizeof(info))) - return -EFAULT; - addr += offsetof(struct ethtool_gstrings, data); - if(copy_to_user(addr, strings, - info.len * ETH_GSTRING_LEN)) - return -EFAULT; - return 0; - } - default: - return -EOPNOTSUPP; - } -} - -static int -e100_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - struct e100_private *bdp; - struct mii_ioctl_data *data_ptr = - (struct mii_ioctl_data *) &(ifr->ifr_data); - - bdp = dev->priv; - - switch (cmd) { - case SIOCGMIIPHY: - data_ptr->phy_id = bdp->phy_addr & 0x1f; - break; - - case SIOCGMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - e100_mdi_read(bdp, data_ptr->reg_num & 0x1f, bdp->phy_addr, - &(data_ptr->val_out)); - break; - - case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - /* If reg = 0 && change speed/duplex */ - if (data_ptr->reg_num == 0 && - (data_ptr->val_in == (BMCR_ANENABLE | BMCR_ANRESTART) /* restart cmd */ - || data_ptr->val_in == (BMCR_RESET) /* reset cmd */ - || data_ptr->val_in & (BMCR_SPEED100 | BMCR_FULLDPLX) - || data_ptr->val_in == 0)) { - if (data_ptr->val_in == (BMCR_ANENABLE | BMCR_ANRESTART) - || data_ptr->val_in == (BMCR_RESET)) - bdp->params.e100_speed_duplex = E100_AUTONEG; - else if (data_ptr->val_in == (BMCR_SPEED100 | BMCR_FULLDPLX)) - bdp->params.e100_speed_duplex = E100_SPEED_100_FULL; - else if (data_ptr->val_in == (BMCR_SPEED100)) - bdp->params.e100_speed_duplex = E100_SPEED_100_HALF; - else if (data_ptr->val_in == (BMCR_FULLDPLX)) - bdp->params.e100_speed_duplex = E100_SPEED_10_FULL; - else - bdp->params.e100_speed_duplex = E100_SPEED_10_HALF; - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - e100_hw_init(bdp); - e100_open(dev); - } - } - else - /* Only allows changing speed/duplex */ - return -EINVAL; - - break; - - default: - return -EOPNOTSUPP; - } - return 0; -} - -nxmit_cb_entry_t * -e100_alloc_non_tx_cmd(struct e100_private *bdp) -{ - nxmit_cb_entry_t *non_tx_cmd_elem; - - if (!(non_tx_cmd_elem = (nxmit_cb_entry_t *) - kmalloc(sizeof (nxmit_cb_entry_t), GFP_ATOMIC))) { - return NULL; - } - non_tx_cmd_elem->non_tx_cmd = - pci_alloc_consistent(bdp->pdev, sizeof (nxmit_cb_t), - &(non_tx_cmd_elem->dma_addr)); - if (non_tx_cmd_elem->non_tx_cmd == NULL) { - kfree(non_tx_cmd_elem); - return NULL; - } - return non_tx_cmd_elem; -} - -void -e100_free_non_tx_cmd(struct e100_private *bdp, - nxmit_cb_entry_t *non_tx_cmd_elem) -{ - pci_free_consistent(bdp->pdev, sizeof (nxmit_cb_t), - non_tx_cmd_elem->non_tx_cmd, - non_tx_cmd_elem->dma_addr); - kfree(non_tx_cmd_elem); -} - -static void -e100_free_nontx_list(struct e100_private *bdp) -{ - nxmit_cb_entry_t *command; - int i; - - while (!list_empty(&bdp->non_tx_cmd_list)) { - command = list_entry(bdp->non_tx_cmd_list.next, - nxmit_cb_entry_t, list_elem); - list_del(&(command->list_elem)); - e100_free_non_tx_cmd(bdp, command); - } - - for (i = 0; i < CB_MAX_NONTX_CMD; i++) { - bdp->same_cmd_entry[i] = NULL; - } -} - -static unsigned char -e100_delayed_exec_non_cu_cmd(struct e100_private *bdp, - nxmit_cb_entry_t *command) -{ - nxmit_cb_entry_t *same_command; - cb_header_t *ntcb_hdr; - u16 cmd; - - ntcb_hdr = (cb_header_t *) command->non_tx_cmd; - - cmd = CB_CMD_MASK & le16_to_cpu(ntcb_hdr->cb_cmd); - - spin_lock_bh(&(bdp->bd_non_tx_lock)); - - same_command = bdp->same_cmd_entry[cmd]; - - if (same_command != NULL) { - memcpy((void *) (same_command->non_tx_cmd), - (void *) (command->non_tx_cmd), sizeof (nxmit_cb_t)); - e100_free_non_tx_cmd(bdp, command); - } else { - list_add_tail(&(command->list_elem), &(bdp->non_tx_cmd_list)); - bdp->same_cmd_entry[cmd] = command; - } - - if (bdp->non_tx_command_state == E100_NON_TX_IDLE) { - bdp->non_tx_command_state = E100_WAIT_TX_FINISH; - mod_timer(&(bdp->nontx_timer_id), jiffies + 1); - } - - spin_unlock_bh(&(bdp->bd_non_tx_lock)); - return true; -} - -static void -e100_non_tx_background(unsigned long ptr) -{ - struct e100_private *bdp = (struct e100_private *) ptr; - nxmit_cb_entry_t *active_command; - int restart = true; - cb_header_t *non_tx_cmd; - u8 sub_cmd; - - spin_lock_bh(&(bdp->bd_non_tx_lock)); - - switch (bdp->non_tx_command_state) { - case E100_WAIT_TX_FINISH: - if (bdp->last_tcb != NULL) { - rmb(); - if ((bdp->last_tcb->tcb_hdr.cb_status & - __constant_cpu_to_le16(CB_STATUS_COMPLETE)) == 0) - goto exit; - } - if ((readw(&bdp->scb->scb_status) & SCB_CUS_MASK) == - SCB_CUS_ACTIVE) { - goto exit; - } - break; - - case E100_WAIT_NON_TX_FINISH: - active_command = list_entry(bdp->non_tx_cmd_list.next, - nxmit_cb_entry_t, list_elem); - rmb(); - - if (((((cb_header_t *) (active_command->non_tx_cmd))->cb_status - & __constant_cpu_to_le16(CB_STATUS_COMPLETE)) == 0) - && time_before(jiffies, active_command->expiration_time)) { - goto exit; - } else { - non_tx_cmd = (cb_header_t *) active_command->non_tx_cmd; - sub_cmd = CB_CMD_MASK & le16_to_cpu(non_tx_cmd->cb_cmd); -#ifdef E100_CU_DEBUG - if (!(non_tx_cmd->cb_status - & __constant_cpu_to_le16(CB_STATUS_COMPLETE))) - printk(KERN_ERR "e100: %s: Queued " - "command (%x) timeout\n", - bdp->device->name, sub_cmd); -#endif - list_del(&(active_command->list_elem)); - e100_free_non_tx_cmd(bdp, active_command); - } - break; - - default: - break; - } //switch - - if (list_empty(&bdp->non_tx_cmd_list)) { - bdp->non_tx_command_state = E100_NON_TX_IDLE; - spin_lock_irq(&(bdp->bd_lock)); - bdp->next_cu_cmd = START_WAIT; - spin_unlock_irq(&(bdp->bd_lock)); - restart = false; - goto exit; - } else { - u16 cmd_type; - - bdp->non_tx_command_state = E100_WAIT_NON_TX_FINISH; - active_command = list_entry(bdp->non_tx_cmd_list.next, - nxmit_cb_entry_t, list_elem); - sub_cmd = ((cb_header_t *) active_command->non_tx_cmd)->cb_cmd; - spin_lock_irq(&(bdp->bd_lock)); - e100_wait_exec_cmplx(bdp, active_command->dma_addr, - SCB_CUC_START, sub_cmd); - spin_unlock_irq(&(bdp->bd_lock)); - active_command->expiration_time = jiffies + HZ; - cmd_type = CB_CMD_MASK & - le16_to_cpu(((cb_header_t *) - (active_command->non_tx_cmd))->cb_cmd); - bdp->same_cmd_entry[cmd_type] = NULL; - } - -exit: - if (restart) { - mod_timer(&(bdp->nontx_timer_id), jiffies + 1); - } else { - if (netif_running(bdp->device)) - netif_wake_queue(bdp->device); - } - spin_unlock_bh(&(bdp->bd_non_tx_lock)); -} - -static void -e100_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) -{ - struct e100_private *bdp = netdev->priv; - - e100_disable_clear_intr(bdp); - bdp->vlgrp = grp; - - if(grp) { - /* enable VLAN tag insert/strip */ - e100_config_vlan_drop(bdp, true); - - } else { - /* disable VLAN tag insert/strip */ - e100_config_vlan_drop(bdp, false); - } - - e100_config(bdp); - e100_set_intr_mask(bdp); -} - -static void -e100_vlan_rx_add_vid(struct net_device *netdev, u16 vid) -{ - /* We don't do Vlan filtering */ - return; -} - -static void -e100_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) -{ - struct e100_private *bdp = netdev->priv; - - if(bdp->vlgrp) - bdp->vlgrp->vlan_devices[vid] = NULL; - /* We don't do Vlan filtering */ - return; -} - -#ifdef CONFIG_PM -static int -e100_notify_reboot(struct notifier_block *nb, unsigned long event, void *p) -{ - struct pci_dev *pdev = NULL; - - switch(event) { - case SYS_DOWN: - case SYS_HALT: - case SYS_POWER_OFF: - while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { - if(pci_dev_driver(pdev) == &e100_driver) { - /* If net_device struct is allocated? */ - if (pci_get_drvdata(pdev)) - e100_suspend(pdev, 3); - - } - } - } - return NOTIFY_DONE; -} - -static int -e100_suspend(struct pci_dev *pcid, u32 state) -{ - struct net_device *netdev = pci_get_drvdata(pcid); - struct e100_private *bdp = netdev->priv; - - e100_isolate_driver(bdp); - pci_save_state(pcid, bdp->pci_state); - - /* Enable or disable WoL */ - e100_do_wol(pcid, bdp); - - /* If wol is enabled */ - if (bdp->wolopts || e100_asf_enabled(bdp)) { - pci_enable_wake(pcid, 3, 1); /* Enable PME for power state D3 */ - pci_set_power_state(pcid, 3); /* Set power state to D3. */ - } else { - /* Disable bus mastering */ - pci_disable_device(pcid); - pci_set_power_state(pcid, state); - } - return 0; -} - -static int -e100_resume(struct pci_dev *pcid) -{ - struct net_device *netdev = pci_get_drvdata(pcid); - struct e100_private *bdp = netdev->priv; - - pci_set_power_state(pcid, 0); - pci_enable_wake(pcid, 0, 0); /* Clear PME status and disable PME */ - pci_restore_state(pcid, bdp->pci_state); - - /* Also do device full reset because device was in D3 state */ - e100_deisolate_driver(bdp, true); - - return 0; -} - -/** - * e100_asf_enabled - checks if ASF is configured on the current adaper - * by reading registers 0xD and 0x90 in the EEPROM - * @bdp: atapter's private data struct - * - * Returns: true if ASF is enabled - */ -static unsigned char -e100_asf_enabled(struct e100_private *bdp) -{ - u16 asf_reg; - u16 smbus_addr_reg; - if ((bdp->pdev->device >= 0x1050) && (bdp->pdev->device <= 0x1055)) { - asf_reg = e100_eeprom_read(bdp, EEPROM_CONFIG_ASF); - if ((asf_reg & EEPROM_FLAG_ASF) - && !(asf_reg & EEPROM_FLAG_GCL)) { - smbus_addr_reg = - e100_eeprom_read(bdp, EEPROM_SMBUS_ADDR); - if ((smbus_addr_reg & 0xFF) != 0xFE) - return true; - } - } - return false; -} -#endif /* CONFIG_PM */ - -#ifdef E100_CU_DEBUG -unsigned char -e100_cu_unknown_state(struct e100_private *bdp) -{ - u8 scb_cmd_low; - u16 scb_status; - scb_cmd_low = bdp->scb->scb_cmd_low; - scb_status = le16_to_cpu(bdp->scb->scb_status); - /* If CU is active and executing unknown cmd */ - if (scb_status & SCB_CUS_ACTIVE && scb_cmd_low & SCB_CUC_UNKNOWN) - return true; - else - return false; -} -#endif - diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/e100/e100_phy.c 830-ivtv/drivers/net/e100/e100_phy.c --- 000-virgin/drivers/net/e100/e100_phy.c Thu Jan 8 08:35:38 2004 +++ 830-ivtv/drivers/net/e100/e100_phy.c Wed Dec 31 16:00:00 1969 @@ -1,1163 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -#include "e100_phy.h" - -void e100_handle_zlock(struct e100_private *bdp); - -/* - * Procedure: e100_mdi_write - * - * Description: This routine will write a value to the specified MII register - * of an external MDI compliant device (e.g. PHY 100). The - * command will execute in polled mode. - * - * Arguments: - * bdp - Ptr to this card's e100_bdconfig structure - * reg_addr - The MII register that we are writing to - * phy_addr - The MDI address of the Phy component. - * data - The value that we are writing to the MII register. - * - * Returns: - * NOTHING - */ -int -e100_mdi_write(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 data) -{ - int e100_retry; - u32 temp_val; - unsigned int mdi_cntrl; - - spin_lock_bh(&bdp->mdi_access_lock); - temp_val = (((u32) data) | (reg_addr << 16) | - (phy_addr << 21) | (MDI_WRITE << 26)); - writel(temp_val, &bdp->scb->scb_mdi_cntrl); - readw(&bdp->scb->scb_status); - - /* wait 20usec before checking status */ - udelay(20); - - /* poll for the mdi write to complete */ - e100_retry = E100_CMD_WAIT; - while ((!((mdi_cntrl = readl(&bdp->scb->scb_mdi_cntrl)) & MDI_PHY_READY)) && (e100_retry)) { - - udelay(20); - e100_retry--; - } - spin_unlock_bh(&bdp->mdi_access_lock); - if (mdi_cntrl & MDI_PHY_READY) - return 0; - else { - printk(KERN_ERR "e100: MDI write timeout\n"); - return 1; - } -} - -/* - * Procedure: e100_mdi_read - * - * Description: This routine will read a value from the specified MII register - * of an external MDI compliant device (e.g. PHY 100), and return - * it to the calling routine. The command will execute in polled - * mode. - * - * Arguments: - * bdp - Ptr to this card's e100_bdconfig structure - * reg_addr - The MII register that we are reading from - * phy_addr - The MDI address of the Phy component. - * - * Results: - * data - The value that we read from the MII register. - * - * Returns: - * NOTHING - */ -int -e100_mdi_read(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 *data) -{ - int e100_retry; - u32 temp_val; - unsigned int mdi_cntrl; - - spin_lock_bh(&bdp->mdi_access_lock); - /* Issue the read command to the MDI control register. */ - temp_val = ((reg_addr << 16) | (phy_addr << 21) | (MDI_READ << 26)); - writel(temp_val, &bdp->scb->scb_mdi_cntrl); - readw(&bdp->scb->scb_status); - - /* wait 20usec before checking status */ - udelay(20); - - /* poll for the mdi read to complete */ - e100_retry = E100_CMD_WAIT; - while ((!((mdi_cntrl = readl(&bdp->scb->scb_mdi_cntrl)) & MDI_PHY_READY)) && (e100_retry)) { - - udelay(20); - e100_retry--; - } - - spin_unlock_bh(&bdp->mdi_access_lock); - if (mdi_cntrl & MDI_PHY_READY) { - /* return the lower word */ - *data = (u16) mdi_cntrl; - return 0; - } - else { - printk(KERN_ERR "e100: MDI read timeout\n"); - return 1; - } -} - -static unsigned char -e100_phy_valid(struct e100_private *bdp, unsigned int phy_address) -{ - u16 ctrl_reg, stat_reg; - - /* Read the MDI control register */ - e100_mdi_read(bdp, MII_BMCR, phy_address, &ctrl_reg); - - /* Read the status register twice, bacause of sticky bits */ - e100_mdi_read(bdp, MII_BMSR, phy_address, &stat_reg); - e100_mdi_read(bdp, MII_BMSR, phy_address, &stat_reg); - - if ((ctrl_reg == 0xffff) || ((stat_reg == 0) && (ctrl_reg == 0))) - return false; - - return true; -} - -static void -e100_phy_address_detect(struct e100_private *bdp) -{ - unsigned int addr; - unsigned char valid_phy_found = false; - - if (IS_NC3133(bdp)) { - bdp->phy_addr = 0; - return; - } - - if (e100_phy_valid(bdp, PHY_DEFAULT_ADDRESS)) { - bdp->phy_addr = PHY_DEFAULT_ADDRESS; - valid_phy_found = true; - - } else { - for (addr = MIN_PHY_ADDR; addr <= MAX_PHY_ADDR; addr++) { - if (e100_phy_valid(bdp, addr)) { - bdp->phy_addr = addr; - valid_phy_found = true; - break; - } - } - } - - if (!valid_phy_found) { - bdp->phy_addr = PHY_ADDRESS_503; - } -} - -static void -e100_phy_id_detect(struct e100_private *bdp) -{ - u16 low_id_reg, high_id_reg; - - if (bdp->phy_addr == PHY_ADDRESS_503) { - bdp->PhyId = PHY_503; - return; - } - if (!(bdp->flags & IS_ICH)) { - if (bdp->rev_id >= D102_REV_ID) { - bdp->PhyId = PHY_82562ET; - return; - } - } - - /* Read phy id from the MII register */ - e100_mdi_read(bdp, MII_PHYSID1, bdp->phy_addr, &low_id_reg); - e100_mdi_read(bdp, MII_PHYSID2, bdp->phy_addr, &high_id_reg); - - bdp->PhyId = ((unsigned int) low_id_reg | - ((unsigned int) high_id_reg << 16)); -} - -static void -e100_phy_isolate(struct e100_private *bdp) -{ - unsigned int phy_address; - u16 ctrl_reg; - - /* Go over all phy addresses. Deisolate the selected one, and isolate - * all the rest */ - for (phy_address = 0; phy_address <= MAX_PHY_ADDR; phy_address++) { - if (phy_address != bdp->phy_addr) { - e100_mdi_write(bdp, MII_BMCR, phy_address, - BMCR_ISOLATE); - - } else { - e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &ctrl_reg); - ctrl_reg &= ~BMCR_ISOLATE; - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg); - } - - udelay(100); - } -} - -static unsigned char -e100_phy_specific_setup(struct e100_private *bdp) -{ - u16 misc_reg; - - if (bdp->phy_addr == PHY_ADDRESS_503) { - switch (bdp->params.e100_speed_duplex) { - case E100_AUTONEG: - /* The adapter can't autoneg. so set to 10/HALF */ - printk(KERN_INFO - "e100: 503 serial component detected which " - "cannot autonegotiate\n"); - printk(KERN_INFO - "e100: speed/duplex forced to " - "10Mbps / Half duplex\n"); - bdp->params.e100_speed_duplex = E100_SPEED_10_HALF; - break; - - case E100_SPEED_100_HALF: - case E100_SPEED_100_FULL: - printk(KERN_ERR - "e100: 503 serial component detected " - "which does not support 100Mbps\n"); - printk(KERN_ERR - "e100: Change the forced speed/duplex " - "to a supported setting\n"); - return false; - } - - return true; - } - - if (IS_NC3133(bdp)) { - u16 int_reg; - - /* enable 100BASE fiber interface */ - e100_mdi_write(bdp, MDI_NC3133_CONFIG_REG, bdp->phy_addr, - MDI_NC3133_100FX_ENABLE); - - if ((bdp->params.e100_speed_duplex != E100_AUTONEG) && - (bdp->params.e100_speed_duplex != E100_SPEED_100_FULL)) { - /* just inform user about 100 full */ - printk(KERN_ERR "e100: NC3133 NIC can only run " - "at 100Mbps full duplex\n"); - } - - bdp->params.e100_speed_duplex = E100_SPEED_100_FULL; - - /* enable interrupts */ - e100_mdi_read(bdp, MDI_NC3133_INT_ENABLE_REG, - bdp->phy_addr, &int_reg); - int_reg |= MDI_NC3133_INT_ENABLE; - e100_mdi_write(bdp, MDI_NC3133_INT_ENABLE_REG, - bdp->phy_addr, int_reg); - } - - /* Handle the National TX */ - if ((bdp->PhyId & PHY_MODEL_REV_ID_MASK) == PHY_NSC_TX) { - e100_mdi_read(bdp, NSC_CONG_CONTROL_REG, - bdp->phy_addr, &misc_reg); - - misc_reg |= NSC_TX_CONG_TXREADY; - - /* disable the congestion control bit in the National Phy */ - misc_reg &= ~NSC_TX_CONG_ENABLE; - - e100_mdi_write(bdp, NSC_CONG_CONTROL_REG, - bdp->phy_addr, misc_reg); - } - - return true; -} - -/* - * Procedure: e100_phy_fix_squelch - * - * Description: - * Help find link on certain rare scenarios. - * NOTE: This routine must be called once per watchdog, - * and *after* setting the current link state. - * - * Arguments: - * bdp - Ptr to this card's e100_bdconfig structure - * - * Returns: - * NOTHING - */ -static void -e100_phy_fix_squelch(struct e100_private *bdp) -{ - if ((bdp->PhyId != PHY_82555_TX) || (bdp->flags & DF_SPEED_FORCED)) - return; - - if (netif_carrier_ok(bdp->device)) { - switch (bdp->PhyState) { - case 0: - break; - case 1: - e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, 0x0000); - break; - case 2: - e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR, - bdp->phy_addr, 0x3000); - break; - } - bdp->PhyState = 0; - bdp->PhyDelay = 0; - - } else if (!bdp->PhyDelay--) { - switch (bdp->PhyState) { - case 0: - e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, EXTENDED_SQUELCH_BIT); - bdp->PhyState = 1; - break; - case 1: - e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, 0x0000); - e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR, - bdp->phy_addr, 0x2010); - bdp->PhyState = 2; - break; - case 2: - e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR, - bdp->phy_addr, 0x3000); - bdp->PhyState = 0; - break; - } - - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, - BMCR_ANENABLE | BMCR_ANRESTART); - bdp->PhyDelay = 3; - } -} - -/* - * Procedure: e100_fix_polarity - * - * Description: - * Fix for 82555 auto-polarity toggle problem. With a short cable - * connecting an 82555 with an 840A link partner, if the medium is noisy, - * the 82555 sometime thinks that the polarity might be wrong and so - * toggles polarity. This happens repeatedly and results in a high bit - * error rate. - * NOTE: This happens only at 10 Mbps - * - * Arguments: - * bdp - Ptr to this card's e100_bdconfig structure - * - * Returns: - * NOTHING - */ -static void -e100_fix_polarity(struct e100_private *bdp) -{ - u16 status; - u16 errors; - u16 misc_reg; - int speed; - - if ((bdp->PhyId != PHY_82555_TX) && (bdp->PhyId != PHY_82562ET) && - (bdp->PhyId != PHY_82562EM)) - return; - - /* If the user wants auto-polarity disabled, do only that and nothing * - * else. * e100_autopolarity == 0 means disable --- we do just the - * disabling * e100_autopolarity == 1 means enable --- we do nothing at - * all * e100_autopolarity >= 2 means we do the workaround code. */ - /* Change for 82558 enhancement */ - switch (E100_AUTOPOLARITY) { - case 0: - e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, &misc_reg); - e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, bdp->phy_addr, - (u16) (misc_reg | DISABLE_AUTO_POLARITY)); - break; - - case 1: - e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, &misc_reg); - e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, bdp->phy_addr, - (u16) (misc_reg & ~DISABLE_AUTO_POLARITY)); - break; - - case 2: - /* we do this only if link is up */ - if (!netif_carrier_ok(bdp->device)) { - break; - } - - e100_mdi_read(bdp, PHY_82555_CSR, bdp->phy_addr, &status); - speed = (status & PHY_82555_SPEED_BIT) ? 100 : 10; - - /* we need to do this only if speed is 10 */ - if (speed != 10) { - break; - } - - /* see if we have any end of frame errors */ - e100_mdi_read(bdp, PHY_82555_EOF_COUNTER, - bdp->phy_addr, &errors); - - /* if non-zero, wait for 100 ms before reading again */ - if (errors) { - udelay(200); - e100_mdi_read(bdp, PHY_82555_EOF_COUNTER, - bdp->phy_addr, &errors); - - /* if non-zero again, we disable polarity */ - if (errors) { - e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, &misc_reg); - e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, - (u16) (misc_reg | - DISABLE_AUTO_POLARITY)); - } - } - - if (!errors) { - /* it is safe to read the polarity now */ - e100_mdi_read(bdp, PHY_82555_CSR, - bdp->phy_addr, &status); - - /* if polarity is normal, disable polarity */ - if (!(status & PHY_82555_POLARITY_BIT)) { - e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, &misc_reg); - e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, - (u16) (misc_reg | - DISABLE_AUTO_POLARITY)); - } - } - break; - - default: - break; - } -} - -/* - * Procedure: e100_find_speed_duplex - * - * Description: This routine will figure out what line speed and duplex mode - * the PHY is currently using. - * - * Arguments: - * bdp - Ptr to this card's e100_bdconfig structure - * - * Returns: - * NOTHING - */ -static void -e100_find_speed_duplex(struct e100_private *bdp) -{ - unsigned int PhyId; - u16 stat_reg, misc_reg; - u16 ad_reg, lp_ad_reg; - - PhyId = bdp->PhyId & PHY_MODEL_REV_ID_MASK; - - /* First we should check to see if we have link */ - /* If we don't have a link no reason to print a speed and duplex */ - if (!e100_update_link_state(bdp)) { - bdp->cur_line_speed = 0; - bdp->cur_dplx_mode = 0; - return; - } - - /* On the 82559 and later controllers, speed/duplex is part of the * - * SCB. So, we save an mdi_read and get these from the SCB. * */ - if (bdp->rev_id >= D101MA_REV_ID) { - /* Read speed */ - if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_1) - bdp->cur_line_speed = 100; - else - bdp->cur_line_speed = 10; - - /* Read duplex */ - if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_2) - bdp->cur_dplx_mode = FULL_DUPLEX; - else - bdp->cur_dplx_mode = HALF_DUPLEX; - - return; - } - - /* If this is a Phy 100, then read bits 1 and 0 of extended register 0, - * to get the current speed and duplex settings. */ - if ((PhyId == PHY_100_A) || (PhyId == PHY_100_C) || - (PhyId == PHY_82555_TX)) { - - /* Read Phy 100 extended register 0 */ - e100_mdi_read(bdp, EXTENDED_REG_0, bdp->phy_addr, &misc_reg); - - /* Get current speed setting */ - if (misc_reg & PHY_100_ER0_SPEED_INDIC) - bdp->cur_line_speed = 100; - else - bdp->cur_line_speed = 10; - - /* Get current duplex setting -- FDX enabled if bit is set */ - if (misc_reg & PHY_100_ER0_FDX_INDIC) - bdp->cur_dplx_mode = FULL_DUPLEX; - else - bdp->cur_dplx_mode = HALF_DUPLEX; - - return; - } - - /* See if link partner is capable of Auto-Negotiation (bit 0, reg 6) */ - e100_mdi_read(bdp, MII_EXPANSION, bdp->phy_addr, &misc_reg); - - /* See if Auto-Negotiation was complete (bit 5, reg 1) */ - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg); - - /* If a True NWAY connection was made, then we can detect speed/dplx - * by ANDing our adapter's advertised abilities with our link partner's - * advertised ablilities, and then assuming that the highest common - * denominator was chosed by NWAY. */ - if ((misc_reg & EXPANSION_NWAY) && (stat_reg & BMSR_ANEGCOMPLETE)) { - - /* Read our advertisement register */ - e100_mdi_read(bdp, MII_ADVERTISE, bdp->phy_addr, &ad_reg); - - /* Read our link partner's advertisement register */ - e100_mdi_read(bdp, MII_LPA, bdp->phy_addr, &lp_ad_reg); - - /* AND the two advertisement registers together, and get rid - * of any extraneous bits. */ - ad_reg &= (lp_ad_reg & NWAY_LP_ABILITY); - - /* Get speed setting */ - if (ad_reg & - (ADVERTISE_100HALF | ADVERTISE_100FULL | - ADVERTISE_100BASE4)) - - bdp->cur_line_speed = 100; - else - bdp->cur_line_speed = 10; - - /* Get duplex setting -- use priority resolution algorithm */ - if (ad_reg & ADVERTISE_100BASE4) { - bdp->cur_dplx_mode = HALF_DUPLEX; - } else if (ad_reg & ADVERTISE_100FULL) { - bdp->cur_dplx_mode = FULL_DUPLEX; - } else if (ad_reg & ADVERTISE_100HALF) { - bdp->cur_dplx_mode = HALF_DUPLEX; - } else if (ad_reg & ADVERTISE_10FULL) { - bdp->cur_dplx_mode = FULL_DUPLEX; - } else { - bdp->cur_dplx_mode = HALF_DUPLEX; - } - - return; - } - - /* If we are connected to a dumb (non-NWAY) repeater or hub, and the - * line speed was determined automatically by parallel detection, then - * we have no way of knowing exactly what speed the PHY is set to - * unless that PHY has a propietary register which indicates speed in - * this situation. The NSC TX PHY does have such a register. Also, - * since NWAY didn't establish the connection, the duplex setting - * should HALF duplex. */ - bdp->cur_dplx_mode = HALF_DUPLEX; - - if (PhyId == PHY_NSC_TX) { - /* Read register 25 to get the SPEED_10 bit */ - e100_mdi_read(bdp, NSC_SPEED_IND_REG, bdp->phy_addr, &misc_reg); - - /* If bit 6 was set then we're at 10Mbps */ - if (misc_reg & NSC_TX_SPD_INDC_SPEED) - bdp->cur_line_speed = 10; - else - bdp->cur_line_speed = 100; - - } else { - /* If we don't know the line speed, default to 10Mbps */ - bdp->cur_line_speed = 10; - } -} - -/* - * Procedure: e100_force_speed_duplex - * - * Description: This routine forces line speed and duplex mode of the - * adapter based on the values the user has set in e100.c. - * - * Arguments: bdp - Pointer to the e100_private structure for the board - * - * Returns: void - * - */ -void -e100_force_speed_duplex(struct e100_private *bdp) -{ - u16 control; - unsigned long expires; - - bdp->flags |= DF_SPEED_FORCED; - - e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control); - control &= ~BMCR_ANENABLE; - control &= ~BMCR_LOOPBACK; - - switch (bdp->params.e100_speed_duplex) { - case E100_SPEED_10_HALF: - control &= ~BMCR_SPEED100; - control &= ~BMCR_FULLDPLX; - bdp->cur_line_speed = 10; - bdp->cur_dplx_mode = HALF_DUPLEX; - break; - - case E100_SPEED_10_FULL: - control &= ~BMCR_SPEED100; - control |= BMCR_FULLDPLX; - bdp->cur_line_speed = 10; - bdp->cur_dplx_mode = FULL_DUPLEX; - break; - - case E100_SPEED_100_HALF: - control |= BMCR_SPEED100; - control &= ~BMCR_FULLDPLX; - bdp->cur_line_speed = 100; - bdp->cur_dplx_mode = HALF_DUPLEX; - break; - - case E100_SPEED_100_FULL: - control |= BMCR_SPEED100; - control |= BMCR_FULLDPLX; - bdp->cur_line_speed = 100; - bdp->cur_dplx_mode = FULL_DUPLEX; - break; - } - - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, control); - - /* loop must run at least once */ - expires = jiffies + 2 * HZ; - do { - if (e100_update_link_state(bdp) || - time_after(jiffies, expires)) { - break; - } else { - yield(); - } - - } while (true); -} - -void -e100_force_speed_duplex_to_phy(struct e100_private *bdp) -{ - u16 control; - - e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control); - control &= ~BMCR_ANENABLE; - control &= ~BMCR_LOOPBACK; - - switch (bdp->params.e100_speed_duplex) { - case E100_SPEED_10_HALF: - control &= ~BMCR_SPEED100; - control &= ~BMCR_FULLDPLX; - break; - - case E100_SPEED_10_FULL: - control &= ~BMCR_SPEED100; - control |= BMCR_FULLDPLX; - break; - - case E100_SPEED_100_HALF: - control |= BMCR_SPEED100; - control &= ~BMCR_FULLDPLX; - break; - - case E100_SPEED_100_FULL: - control |= BMCR_SPEED100; - control |= BMCR_FULLDPLX; - break; - } - - /* Send speed/duplex command to PHY layer. */ - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, control); -} - -/* - * Procedure: e100_set_fc - * - * Description: Checks the link's capability for flow control. - * - * Arguments: bdp - Pointer to the e100_private structure for the board - * - * Returns: void - * - */ -static void -e100_set_fc(struct e100_private *bdp) -{ - u16 ad_reg; - u16 lp_ad_reg; - u16 exp_reg; - - /* no flow control for 82557, forced links or half duplex */ - if (!netif_carrier_ok(bdp->device) || (bdp->flags & DF_SPEED_FORCED) || - (bdp->cur_dplx_mode == HALF_DUPLEX) || - !(bdp->flags & IS_BACHELOR)) { - - bdp->flags &= ~DF_LINK_FC_CAP; - return; - } - - /* See if link partner is capable of Auto-Negotiation (bit 0, reg 6) */ - e100_mdi_read(bdp, MII_EXPANSION, bdp->phy_addr, &exp_reg); - - if (exp_reg & EXPANSION_NWAY) { - /* Read our advertisement register */ - e100_mdi_read(bdp, MII_ADVERTISE, bdp->phy_addr, &ad_reg); - - /* Read our link partner's advertisement register */ - e100_mdi_read(bdp, MII_LPA, bdp->phy_addr, &lp_ad_reg); - - ad_reg &= lp_ad_reg; /* AND the 2 ad registers */ - - if (ad_reg & NWAY_AD_FC_SUPPORTED) - bdp->flags |= DF_LINK_FC_CAP; - else - /* If link partner is capable of autoneg, but */ - /* not capable of flow control, Received PAUSE */ - /* frames are still honored, i.e., */ - /* transmitted frames would be paused */ - /* by incoming PAUSE frames */ - bdp->flags |= DF_LINK_FC_TX_ONLY; - - } else { - bdp->flags &= ~DF_LINK_FC_CAP; - } -} - -/* - * Procedure: e100_phy_check - * - * Arguments: bdp - Pointer to the e100_private structure for the board - * - * Returns: true if link state was changed - * false otherwise - * - */ -unsigned char -e100_phy_check(struct e100_private *bdp) -{ - unsigned char old_link; - unsigned char changed = false; - - old_link = netif_carrier_ok(bdp->device) ? 1 : 0; - e100_find_speed_duplex(bdp); - - if (!old_link && netif_carrier_ok(bdp->device)) { - e100_set_fc(bdp); - changed = true; - } - - if (old_link && !netif_carrier_ok(bdp->device)) { - /* reset the zero lock state */ - bdp->zlock_state = ZLOCK_INITIAL; - - // set auto lock for phy auto-negotiation on link up - if ((bdp->PhyId & PHY_MODEL_REV_ID_MASK) == PHY_82555_TX) - e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR, - bdp->phy_addr, 0); - changed = true; - } - - e100_phy_fix_squelch(bdp); - e100_handle_zlock(bdp); - - return changed; -} - -/* - * Procedure: e100_auto_neg - * - * Description: This routine will start autonegotiation and wait - * for it to complete - * - * Arguments: - * bdp - pointer to this card's e100_bdconfig structure - * force_restart - defines if autoneg should be restarted even if it - * has been completed before - * Returns: - * NOTHING - */ -static void -e100_auto_neg(struct e100_private *bdp, unsigned char force_restart) -{ - u16 stat_reg; - unsigned long expires; - - bdp->flags &= ~DF_SPEED_FORCED; - - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg); - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg); - - /* if we are capable of performing autoneg then we restart if needed */ - if ((stat_reg != 0xFFFF) && (stat_reg & BMSR_ANEGCAPABLE)) { - - if ((!force_restart) && - (stat_reg & BMSR_ANEGCOMPLETE)) { - goto exit; - } - - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, - BMCR_ANENABLE | BMCR_ANRESTART); - - /* wait for autoneg to complete (up to 3 seconds) */ - expires = jiffies + HZ * 3; - do { - /* now re-read the value. Sticky so read twice */ - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg); - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg); - - if ((stat_reg & BMSR_ANEGCOMPLETE) || - time_after(jiffies, expires) ) { - goto exit; - } else { - yield(); - } - } while (true); - } - -exit: - e100_find_speed_duplex(bdp); -} - -void -e100_phy_set_speed_duplex(struct e100_private *bdp, unsigned char force_restart) -{ - if (bdp->params.e100_speed_duplex == E100_AUTONEG) { - if (bdp->rev_id >= D102_REV_ID) - /* Enable MDI/MDI-X auto switching */ - e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr, - MDI_MDIX_AUTO_SWITCH_ENABLE); - e100_auto_neg(bdp, force_restart); - - } else { - if (bdp->rev_id >= D102_REV_ID) - /* Disable MDI/MDI-X auto switching */ - e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr, - MDI_MDIX_RESET_ALL_MASK); - e100_force_speed_duplex(bdp); - } - - e100_set_fc(bdp); -} - -void -e100_phy_autoneg(struct e100_private *bdp) -{ - u16 ctrl_reg; - - ctrl_reg = BMCR_ANENABLE | BMCR_ANRESTART | BMCR_RESET; - - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg); - - udelay(100); -} - -void -e100_phy_set_loopback(struct e100_private *bdp) -{ - u16 ctrl_reg; - ctrl_reg = BMCR_LOOPBACK; - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg); - udelay(100); -} - -void -e100_phy_reset(struct e100_private *bdp) -{ - u16 ctrl_reg; - ctrl_reg = BMCR_RESET; - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg); - /* ieee 802.3 : The reset process shall be completed */ - /* within 0.5 seconds from the settting of PHY reset bit. */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 2); -} - -unsigned char -e100_phy_init(struct e100_private *bdp) -{ - e100_phy_reset(bdp); - e100_phy_address_detect(bdp); - e100_phy_isolate(bdp); - e100_phy_id_detect(bdp); - - if (!e100_phy_specific_setup(bdp)) - return false; - - bdp->PhyState = 0; - bdp->PhyDelay = 0; - bdp->zlock_state = ZLOCK_INITIAL; - - e100_phy_set_speed_duplex(bdp, false); - e100_fix_polarity(bdp); - - return true; -} - -/* - * Procedure: e100_get_link_state - * - * Description: This routine checks the link status of the adapter - * - * Arguments: bdp - Pointer to the e100_private structure for the board - * - * - * Returns: true - If a link is found - * false - If there is no link - * - */ -unsigned char -e100_get_link_state(struct e100_private *bdp) -{ - unsigned char link = false; - u16 status; - - /* Check link status */ - /* If the controller is a 82559 or later one, link status is available - * from the CSR. This avoids the mdi_read. */ - if (bdp->rev_id >= D101MA_REV_ID) { - if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_0) { - link = true; - } else { - link = false; - } - - } else { - /* Read the status register twice because of sticky bits */ - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &status); - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &status); - - if (status & BMSR_LSTATUS) { - link = true; - } else { - link = false; - } - } - - return link; -} - -/* - * Procedure: e100_update_link_state - * - * Description: This routine updates the link status of the adapter, - * also considering netif_running - * - * Arguments: bdp - Pointer to the e100_private structure for the board - * - * - * Returns: true - If a link is found - * false - If there is no link - * - */ -unsigned char -e100_update_link_state(struct e100_private *bdp) -{ - unsigned char link; - - /* Logical AND PHY link & netif_running */ - link = e100_get_link_state(bdp) && netif_running(bdp->device); - - if (link) { - if (!netif_carrier_ok(bdp->device)) - netif_carrier_on(bdp->device); - } else { - if (netif_carrier_ok(bdp->device)) - netif_carrier_off(bdp->device); - } - - return link; -} - -/**************************************************************************\ - ** - ** PROC NAME: e100_handle_zlock - ** This function manages a state machine that controls - ** the driver's zero locking algorithm. - ** This function is called by e100_watchdog() every ~2 second. - ** States: - ** The current link handling state is stored in - ** bdp->zlock_state, and is one of: - ** ZLOCK_INITIAL, ZLOCK_READING, ZLOCK_SLEEPING - ** Detailed description of the states and the transitions - ** between states is found below. - ** Note that any time the link is down / there is a reset - ** state will be changed outside this function to ZLOCK_INITIAL - ** Algorithm: - ** 1. If link is up & 100 Mbps continue else stay in #1: - ** 2. Set 'auto lock' - ** 3. Read & Store 100 times 'Zero' locked in 1 sec interval - ** 4. If max zero read >= 0xB continue else goto 1 - ** 5. Set most popular 'Zero' read in #3 - ** 6. Sleep 5 minutes - ** 7. Read number of errors, if it is > 300 goto 2 else goto 6 - ** Data Structures (in DRIVER_DATA): - ** zlock_state - current state of the algorithm - ** zlock_read_cnt - counts number of reads (up to 100) - ** zlock_read_data[i] - counts number of times 'Zero' read was i, 0 <= i <= 15 - ** zlock_sleep_cnt - keeps track of "sleep" time (up to 300 secs = 5 minutes) - ** - ** Parameters: DRIVER_DATA *bdp - ** - ** bdp - Pointer to HSM's adapter data space - ** - ** Return Value: NONE - ** - ** See Also: e100_watchdog() - ** - \**************************************************************************/ -void -e100_handle_zlock(struct e100_private *bdp) -{ - u16 pos; - u16 eq_reg; - u16 err_cnt; - u8 mpz; /* Most Popular Zero */ - - switch (bdp->zlock_state) { - case ZLOCK_INITIAL: - - if (((u8) bdp->rev_id <= D102_REV_ID) || - !(bdp->cur_line_speed == 100) || - !netif_carrier_ok(bdp->device)) { - break; - } - - /* initialize hw and sw and start reading */ - e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR, - bdp->phy_addr, 0); - /* reset read counters: */ - bdp->zlock_read_cnt = 0; - for (pos = 0; pos < 16; pos++) - bdp->zlock_read_data[pos] = 0; - /* start reading in the next call back: */ - bdp->zlock_state = ZLOCK_READING; - - /* FALL THROUGH !! */ - - case ZLOCK_READING: - /* state: reading (100 times) zero locked in 1 sec interval - * prev states: ZLOCK_INITIAL - * next states: ZLOCK_INITIAL, ZLOCK_SLEEPING */ - - e100_mdi_read(bdp, PHY_82555_MDI_EQUALIZER_CSR, - bdp->phy_addr, &eq_reg); - pos = (eq_reg & ZLOCK_ZERO_MASK) >> 4; - bdp->zlock_read_data[pos]++; - bdp->zlock_read_cnt++; - - if (bdp->zlock_read_cnt == ZLOCK_MAX_READS) { - /* check if we read a 'Zero' value of 0xB or greater */ - if ((bdp->zlock_read_data[0xB]) || - (bdp->zlock_read_data[0xC]) || - (bdp->zlock_read_data[0xD]) || - (bdp->zlock_read_data[0xE]) || - (bdp->zlock_read_data[0xF])) { - - /* we've read 'Zero' value of 0xB or greater, - * find most popular 'Zero' value and lock it */ - mpz = 0; - /* this loop finds the most popular 'Zero': */ - for (pos = 1; pos < 16; pos++) { - if (bdp->zlock_read_data[pos] > - bdp->zlock_read_data[mpz]) - - mpz = pos; - } - /* now lock the most popular 'Zero': */ - eq_reg = (ZLOCK_SET_ZERO | mpz); - e100_mdi_write(bdp, - PHY_82555_MDI_EQUALIZER_CSR, - bdp->phy_addr, eq_reg); - - /* sleep for 5 minutes: */ - bdp->zlock_sleep_cnt = jiffies; - bdp->zlock_state = ZLOCK_SLEEPING; - /* we will be reading the # of errors after 5 - * minutes, so we need to reset the error - * counters - these registers are self clearing - * on read, so read them */ - e100_mdi_read(bdp, PHY_82555_SYMBOL_ERR, - bdp->phy_addr, &err_cnt); - - } else { - /* we did not read a 'Zero' value of 0xB or - * above. go back to the start */ - bdp->zlock_state = ZLOCK_INITIAL; - } - - } - break; - - case ZLOCK_SLEEPING: - /* state: sleeping for 5 minutes - * prev states: ZLOCK_READING - * next states: ZLOCK_READING, ZLOCK_SLEEPING */ - - /* if 5 minutes have passed: */ - if ((jiffies - bdp->zlock_sleep_cnt) >= ZLOCK_MAX_SLEEP) { - /* read and sum up the number of errors: */ - e100_mdi_read(bdp, PHY_82555_SYMBOL_ERR, - bdp->phy_addr, &err_cnt); - /* if we've more than 300 errors (this number was - * calculated according to the spec max allowed errors - * (80 errors per 1 million frames) for 5 minutes in - * 100 Mbps (or the user specified max BER number) */ - if (err_cnt > bdp->params.ber) { - /* start again in the next callback: */ - bdp->zlock_state = ZLOCK_INITIAL; - } else { - /* we don't have more errors than allowed, - * sleep for 5 minutes */ - bdp->zlock_sleep_cnt = jiffies; - } - } - break; - - default: - break; - } -} diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/e100/e100_phy.h 830-ivtv/drivers/net/e100/e100_phy.h --- 000-virgin/drivers/net/e100/e100_phy.h Wed Mar 26 22:54:32 2003 +++ 830-ivtv/drivers/net/e100/e100_phy.h Wed Dec 31 16:00:00 1969 @@ -1,158 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -#ifndef _E100_PHY_INC_ -#define _E100_PHY_INC_ - -#include "e100.h" - -/* - * Auto-polarity enable/disable - * e100_autopolarity = 0 => disable auto-polarity - * e100_autopolarity = 1 => enable auto-polarity - * e100_autopolarity = 2 => let software determine - */ -#define E100_AUTOPOLARITY 2 - -#define IS_NC3133(bdp) (((bdp)->pdev->subsystem_vendor == 0x0E11) && \ - ((bdp)->pdev->subsystem_device == 0xB0E1)) - -#define PHY_503 0 -#define PHY_100_A 0x000003E0 -#define PHY_100_C 0x035002A8 -#define PHY_NSC_TX 0x5c002000 -#define PHY_82562ET 0x033002A8 -#define PHY_82562EM 0x032002A8 -#define PHY_82562EH 0x017002A8 -#define PHY_82555_TX 0x015002a8 /* added this for 82555 */ -#define PHY_OTHER 0xFFFF -#define MAX_PHY_ADDR 31 -#define MIN_PHY_ADDR 0 - -#define PHY_MODEL_REV_ID_MASK 0xFFF0FFFF - -#define PHY_DEFAULT_ADDRESS 1 -#define PHY_ADDRESS_503 32 - -/* MDI Control register bit definitions */ -#define MDI_PHY_READY BIT_28 /* PHY is ready for next MDI cycle */ - -#define MDI_NC3133_CONFIG_REG 0x19 -#define MDI_NC3133_100FX_ENABLE BIT_2 -#define MDI_NC3133_INT_ENABLE_REG 0x17 -#define MDI_NC3133_INT_ENABLE BIT_1 - -/* MDI Control register opcode definitions */ -#define MDI_WRITE 1 /* Phy Write */ -#define MDI_READ 2 /* Phy read */ - -/* MDI register set*/ -#define AUTO_NEG_NEXT_PAGE_REG 0x07 /* Auto-negotiation next page xmit */ -#define EXTENDED_REG_0 0x10 /* Extended reg 0 (Phy 100 modes) */ -#define EXTENDED_REG_1 0x14 /* Extended reg 1 (Phy 100 error indications) */ -#define NSC_CONG_CONTROL_REG 0x17 /* National (TX) congestion control */ -#define NSC_SPEED_IND_REG 0x19 /* National (TX) speed indication */ - -#define HWI_CONTROL_REG 0x1D /* HWI Control register */ -/* MDI/MDI-X Control Register bit definitions */ -#define MDI_MDIX_RES_TIMER BIT_0_3 /* minimum slot time for resolution timer */ -#define MDI_MDIX_CONFIG_IS_OK BIT_4 /* 1 = resolution algorithm completes OK */ -#define MDI_MDIX_STATUS BIT_5 /* 1 = MDIX (croos over), 0 = MDI (straight through) */ -#define MDI_MDIX_SWITCH BIT_6 /* 1 = Forces to MDIX, 0 = Forces to MDI */ -#define MDI_MDIX_AUTO_SWITCH_ENABLE BIT_7 /* 1 = MDI/MDI-X feature enabled */ -#define MDI_MDIX_CONCT_CONFIG BIT_8 /* Sets the MDI/MDI-X connectivity configuration (test prupose only) */ -#define MDI_MDIX_CONCT_TEST_ENABLE BIT_9 /* 1 = Enables connectivity testing */ -#define MDI_MDIX_RESET_ALL_MASK 0x0000 - -/* HWI Control Register bit definitions */ -#define HWI_TEST_DISTANCE BIT_0_8 /* distance to cable problem */ -#define HWI_TEST_HIGHZ_PROBLEM BIT_9 /* 1 = Open Circuit */ -#define HWI_TEST_LOWZ_PROBLEM BIT_10 /* 1 = Short Circuit */ -#define HWI_TEST_RESERVED (BIT_11 | BIT_12) /* reserved */ -#define HWI_TEST_EXECUTE BIT_13 /* 1 = Execute the HWI test on the PHY */ -#define HWI_TEST_ABILITY BIT_14 /* 1 = test passed */ -#define HWI_TEST_ENABLE BIT_15 /* 1 = Enables the HWI feature */ -#define HWI_RESET_ALL_MASK 0x0000 - -/* ############Start of 82555 specific defines################## */ - -/* Intel 82555 specific registers */ -#define PHY_82555_CSR 0x10 /* 82555 CSR */ -#define PHY_82555_SPECIAL_CONTROL 0x11 /* 82555 special control register */ - -#define PHY_82555_RCV_ERR 0x15 /* 82555 100BaseTx Receive Error - * Frame Counter */ -#define PHY_82555_SYMBOL_ERR 0x16 /* 82555 RCV Symbol Error Counter */ -#define PHY_82555_PREM_EOF_ERR 0x17 /* 82555 100BaseTx RCV Premature End - * of Frame Error Counter */ -#define PHY_82555_EOF_COUNTER 0x18 /* 82555 end of frame error counter */ -#define PHY_82555_MDI_EQUALIZER_CSR 0x1a /* 82555 specific equalizer reg. */ - -/* 82555 CSR bits */ -#define PHY_82555_SPEED_BIT BIT_1 -#define PHY_82555_POLARITY_BIT BIT_8 - -/* 82555 equalizer reg. opcodes */ -#define ENABLE_ZERO_FORCING 0x2010 /* write to ASD conf. reg. 0 */ -#define DISABLE_ZERO_FORCING 0x2000 /* write to ASD conf. reg. 0 */ - -/* 82555 special control reg. opcodes */ -#define DISABLE_AUTO_POLARITY 0x0010 -#define EXTENDED_SQUELCH_BIT BIT_2 - -/* ############End of 82555 specific defines##################### */ - -/* Auto-Negotiation advertisement register bit definitions*/ -#define NWAY_AD_FC_SUPPORTED 0x0400 /* Flow Control supported */ - -/* Auto-Negotiation link partner ability register bit definitions*/ -#define NWAY_LP_ABILITY 0x07e0 /* technologies supported */ - -/* PHY 100 Extended Register 0 bit definitions*/ -#define PHY_100_ER0_FDX_INDIC BIT_0 /* 1 = FDX, 0 = half duplex */ -#define PHY_100_ER0_SPEED_INDIC BIT_1 /* 1 = 100Mbps, 0= 10Mbps */ - -/* National Semiconductor TX phy congestion control register bit definitions*/ -#define NSC_TX_CONG_TXREADY BIT_10 /* Makes TxReady an input */ -#define NSC_TX_CONG_ENABLE BIT_8 /* Enables congestion control */ - -/* National Semiconductor TX phy speed indication register bit definitions*/ -#define NSC_TX_SPD_INDC_SPEED BIT_6 /* 0 = 100Mbps, 1=10Mbps */ - -/************* function prototypes ************/ -extern unsigned char e100_phy_init(struct e100_private *bdp); -extern unsigned char e100_update_link_state(struct e100_private *bdp); -extern unsigned char e100_phy_check(struct e100_private *bdp); -extern void e100_phy_set_speed_duplex(struct e100_private *bdp, - unsigned char force_restart); -extern void e100_phy_autoneg(struct e100_private *bdp); -extern void e100_phy_reset(struct e100_private *bdp); -extern void e100_phy_set_loopback(struct e100_private *bdp); -extern int e100_mdi_write(struct e100_private *, u32, u32, u16); -extern int e100_mdi_read(struct e100_private *, u32, u32, u16 *); - -#endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/e100/e100_test.c 830-ivtv/drivers/net/e100/e100_test.c --- 000-virgin/drivers/net/e100/e100_test.c Fri May 30 19:02:12 2003 +++ 830-ivtv/drivers/net/e100/e100_test.c Wed Dec 31 16:00:00 1969 @@ -1,500 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -#include "e100_phy.h" -#include "e100_config.h" - -extern u16 e100_eeprom_read(struct e100_private *, u16); -extern int e100_wait_exec_cmplx(struct e100_private *, u32,u8, u8); -extern void e100_phy_reset(struct e100_private *bdp); -extern void e100_phy_autoneg(struct e100_private *bdp); -extern void e100_phy_set_loopback(struct e100_private *bdp); -extern void e100_force_speed_duplex(struct e100_private *bdp); - -static u8 e100_diag_selftest(struct net_device *); -static u8 e100_diag_eeprom(struct net_device *); -static u8 e100_diag_loopback(struct net_device *); - -static u8 e100_diag_one_loopback (struct net_device *, u8); -static u8 e100_diag_rcv_loopback_pkt(struct e100_private *); -static void e100_diag_config_loopback(struct e100_private *, u8, u8, u8 *,u8 *); -static u8 e100_diag_loopback_alloc(struct e100_private *); -static void e100_diag_loopback_cu_ru_exec(struct e100_private *); -static u8 e100_diag_check_pkt(u8 *); -static void e100_diag_loopback_free(struct e100_private *); -static int e100_cable_diag(struct e100_private *bdp); - -#define LB_PACKET_SIZE 1500 - -/** - * e100_run_diag - main test execution handler - checks mask of requests and calls the diag routines - * @dev: atapter's net device data struct - * @test_info: array with test request mask also used to store test results - * - * RETURNS: updated flags field of struct ethtool_test - */ -u32 -e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags) -{ - struct e100_private* bdp = dev->priv; - u8 test_result = 0; - - if (!e100_get_link_state(bdp)) { - test_result = ETH_TEST_FL_FAILED; - test_info[test_link] = true; - } - if (!e100_diag_eeprom(dev)) { - test_result = ETH_TEST_FL_FAILED; - test_info[test_eeprom] = true; - } - if (flags & ETH_TEST_FL_OFFLINE) { - u8 fail_mask; - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - } - if (e100_diag_selftest(dev)) { - test_result = ETH_TEST_FL_FAILED; - test_info[test_self_test] = true; - } - - fail_mask = e100_diag_loopback(dev); - if (fail_mask) { - test_result = ETH_TEST_FL_FAILED; - if (fail_mask & PHY_LOOPBACK) - test_info[test_loopback_phy] = true; - if (fail_mask & MAC_LOOPBACK) - test_info[test_loopback_mac] = true; - } - - test_info[cable_diag] = e100_cable_diag(bdp); - /* Need hw init regardless of netif_running */ - e100_hw_init(bdp); - if (netif_running(dev)) { - e100_open(dev); - } - } - else { - test_info[test_self_test] = false; - test_info[test_loopback_phy] = false; - test_info[test_loopback_mac] = false; - test_info[cable_diag] = false; - } - - return flags | test_result; -} - -/** - * e100_diag_selftest - run hardware selftest - * @dev: atapter's net device data struct - */ -static u8 -e100_diag_selftest(struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - u32 st_timeout, st_result; - u8 retval = 0; - - if (!e100_selftest(bdp, &st_timeout, &st_result)) { - if (!st_timeout) { - if (st_result & CB_SELFTEST_REGISTER_BIT) - retval |= REGISTER_TEST_FAIL; - if (st_result & CB_SELFTEST_DIAG_BIT) - retval |= SELF_TEST_FAIL; - if (st_result & CB_SELFTEST_ROM_BIT) - retval |= ROM_TEST_FAIL; - } else { - retval = TEST_TIMEOUT; - } - } - - return retval; -} - -/** - * e100_diag_eeprom - validate eeprom checksum correctness - * @dev: atapter's net device data struct - * - */ -static u8 -e100_diag_eeprom (struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - u16 i, eeprom_sum, eeprom_actual_csm; - - for (i = 0, eeprom_sum = 0; i < (bdp->eeprom_size - 1); i++) { - eeprom_sum += e100_eeprom_read(bdp, i); - } - - eeprom_actual_csm = e100_eeprom_read(bdp, bdp->eeprom_size - 1); - - if (eeprom_actual_csm == (u16)(EEPROM_SUM - eeprom_sum)) { - return true; - } - - return false; -} - -/** - * e100_diag_loopback - performs loopback test - * @dev: atapter's net device data struct - */ -static u8 -e100_diag_loopback (struct net_device *dev) -{ - u8 rc = 0; - - printk(KERN_DEBUG "%s: PHY loopback test starts\n", dev->name); - e100_hw_init(dev->priv); - if (!e100_diag_one_loopback(dev, PHY_LOOPBACK)) { - rc |= PHY_LOOPBACK; - } - printk(KERN_DEBUG "%s: PHY loopback test ends\n", dev->name); - - printk(KERN_DEBUG "%s: MAC loopback test starts\n", dev->name); - e100_hw_init(dev->priv); - if (!e100_diag_one_loopback(dev, MAC_LOOPBACK)) { - rc |= MAC_LOOPBACK; - } - printk(KERN_DEBUG "%s: MAC loopback test ends\n", dev->name); - - return rc; -} - -/** - * e100_diag_loopback - performs loopback test - * @dev: atapter's net device data struct - * @mode: lopback test type - */ -static u8 -e100_diag_one_loopback (struct net_device *dev, u8 mode) -{ - struct e100_private *bdp = dev->priv; - u8 res = false; - u8 saved_dynamic_tbd = false; - u8 saved_extended_tcb = false; - - if (!e100_diag_loopback_alloc(bdp)) - return false; - - /* change the config block to standard tcb and the correct loopback */ - e100_diag_config_loopback(bdp, true, mode, - &saved_extended_tcb, &saved_dynamic_tbd); - - e100_diag_loopback_cu_ru_exec(bdp); - - if (e100_diag_rcv_loopback_pkt(bdp)) { - res = true; - } - - e100_diag_loopback_free(bdp); - - /* change the config block to previous tcb mode and the no loopback */ - e100_diag_config_loopback(bdp, false, mode, - &saved_extended_tcb, &saved_dynamic_tbd); - return res; -} - -/** - * e100_diag_config_loopback - setup/clear loopback before/after lpbk test - * @bdp: atapter's private data struct - * @set_loopback: true if the function is called to set lb - * @loopback_mode: the loopback mode(MAC or PHY) - * @tcb_extended: true if need to set extended tcb mode after clean loopback - * @dynamic_tbd: true if needed to set dynamic tbd mode after clean loopback - * - */ -void -e100_diag_config_loopback(struct e100_private* bdp, - u8 set_loopback, - u8 loopback_mode, - u8* tcb_extended, - u8* dynamic_tbd) -{ - /* if set_loopback == true - we want to clear tcb_extended/dynamic_tbd. - * the previous values are saved in the params tcb_extended/dynamic_tbd - * if set_loopback == false - we want to restore previous value. - */ - if (set_loopback || (*tcb_extended)) - *tcb_extended = e100_config_tcb_ext_enable(bdp,*tcb_extended); - - if (set_loopback || (*dynamic_tbd)) - *dynamic_tbd = e100_config_dynamic_tbd(bdp,*dynamic_tbd); - - if (set_loopback) { - /* ICH PHY loopback is broken */ - if (bdp->flags & IS_ICH && loopback_mode == PHY_LOOPBACK) - loopback_mode = MAC_LOOPBACK; - /* Configure loopback on MAC */ - e100_config_loopback_mode(bdp,loopback_mode); - } else { - e100_config_loopback_mode(bdp,NO_LOOPBACK); - } - - e100_config(bdp); - - if (loopback_mode == PHY_LOOPBACK) { - if (set_loopback) - /* Set PHY loopback mode */ - e100_phy_set_loopback(bdp); - else - /* Reset PHY loopback mode */ - e100_phy_reset(bdp); - /* Wait for PHY state change */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ); - } else { /* For MAC loopback wait 500 msec to take effect */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 2); - } -} - -/** - * e100_diag_loopback_alloc - alloc & initate tcb and rfd for the loopback - * @bdp: atapter's private data struct - * - */ -static u8 -e100_diag_loopback_alloc(struct e100_private *bdp) -{ - dma_addr_t dma_handle; - tcb_t *tcb; - rfd_t *rfd; - tbd_t *tbd; - - /* tcb, tbd and transmit buffer are allocated */ - tcb = pci_alloc_consistent(bdp->pdev, - (sizeof (tcb_t) + sizeof (tbd_t) + - LB_PACKET_SIZE), - &dma_handle); - if (tcb == NULL) - return false; - - memset(tcb, 0x00, sizeof (tcb_t) + sizeof (tbd_t) + LB_PACKET_SIZE); - tcb->tcb_phys = dma_handle; - tcb->tcb_hdr.cb_status = 0; - tcb->tcb_hdr.cb_cmd = - cpu_to_le16(CB_EL_BIT | CB_TRANSMIT | CB_TX_SF_BIT); - /* Next command is null */ - tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(0xffffffff); - tcb->tcb_cnt = 0; - tcb->tcb_thrshld = bdp->tx_thld; - tcb->tcb_tbd_num = 1; - /* Set up tcb tbd pointer */ - tcb->tcb_tbd_ptr = cpu_to_le32(tcb->tcb_phys + sizeof (tcb_t)); - tbd = (tbd_t *) ((u8 *) tcb + sizeof (tcb_t)); - /* Set up tbd transmit buffer */ - tbd->tbd_buf_addr = - cpu_to_le32(le32_to_cpu(tcb->tcb_tbd_ptr) + sizeof (tbd_t)); - tbd->tbd_buf_cnt = __constant_cpu_to_le16(1024); - /* The value of first 512 bytes is FF */ - memset((void *) ((u8 *) tbd + sizeof (tbd_t)), 0xFF, 512); - /* The value of second 512 bytes is BA */ - memset((void *) ((u8 *) tbd + sizeof (tbd_t) + 512), 0xBA, 512); - wmb(); - rfd = pci_alloc_consistent(bdp->pdev, sizeof (rfd_t), &dma_handle); - - if (rfd == NULL) { - pci_free_consistent(bdp->pdev, - sizeof (tcb_t) + sizeof (tbd_t) + - LB_PACKET_SIZE, tcb, tcb->tcb_phys); - return false; - } - - memset(rfd, 0x00, sizeof (rfd_t)); - - /* init all fields in rfd */ - rfd->rfd_header.cb_cmd = cpu_to_le16(RFD_EL_BIT); - rfd->rfd_sz = cpu_to_le16(ETH_FRAME_LEN + CHKSUM_SIZE); - /* dma_handle is physical address of rfd */ - bdp->loopback.dma_handle = dma_handle; - bdp->loopback.tcb = tcb; - bdp->loopback.rfd = rfd; - wmb(); - return true; -} - -/** - * e100_diag_loopback_cu_ru_exec - activates cu and ru to send & receive the pkt - * @bdp: atapter's private data struct - * - */ -static void -e100_diag_loopback_cu_ru_exec(struct e100_private *bdp) -{ - /*load CU & RU base */ - if(!e100_wait_exec_cmplx(bdp, bdp->loopback.dma_handle, SCB_RUC_START, 0)) - printk(KERN_ERR "e100: SCB_RUC_START failed!\n"); - - bdp->next_cu_cmd = START_WAIT; - e100_start_cu(bdp, bdp->loopback.tcb); - bdp->last_tcb = NULL; - rmb(); -} -/** - * e100_diag_check_pkt - checks if a given packet is a loopback packet - * @bdp: atapter's private data struct - * - * Returns true if OK false otherwise. - */ -static u8 -e100_diag_check_pkt(u8 *datap) -{ - int i; - for (i = 0; i<512; i++) { - if( !((*datap)==0xFF && (*(datap + 512) == 0xBA)) ) { - printk (KERN_ERR "e100: check loopback packet failed at: %x\n", i); - return false; - } - } - printk (KERN_DEBUG "e100: Check received loopback packet OK\n"); - return true; -} - -/** - * e100_diag_rcv_loopback_pkt - waits for receive and checks lpbk packet - * @bdp: atapter's private data struct - * - * Returns true if OK false otherwise. - */ -static u8 -e100_diag_rcv_loopback_pkt(struct e100_private* bdp) -{ - rfd_t *rfdp; - u16 rfd_status; - unsigned long expires = jiffies + HZ * 2; - - rfdp =bdp->loopback.rfd; - - rfd_status = le16_to_cpu(rfdp->rfd_header.cb_status); - - while (!(rfd_status & RFD_STATUS_COMPLETE)) { - if (time_before(jiffies, expires)) { - yield(); - rmb(); - rfd_status = le16_to_cpu(rfdp->rfd_header.cb_status); - } else { - break; - } - } - - if (rfd_status & RFD_STATUS_COMPLETE) { - printk(KERN_DEBUG "e100: Loopback packet received\n"); - return e100_diag_check_pkt(((u8 *)rfdp+bdp->rfd_size)); - } - else { - printk(KERN_ERR "e100: Loopback packet not received\n"); - return false; - } -} - -/** - * e100_diag_loopback_free - free data allocated for loopback pkt send/receive - * @bdp: atapter's private data struct - * - */ -static void -e100_diag_loopback_free (struct e100_private *bdp) -{ - pci_free_consistent(bdp->pdev, - sizeof(tcb_t) + sizeof(tbd_t) + LB_PACKET_SIZE, - bdp->loopback.tcb, bdp->loopback.tcb->tcb_phys); - - pci_free_consistent(bdp->pdev, sizeof(rfd_t), bdp->loopback.rfd, - bdp->loopback.dma_handle); -} - -static int -e100_cable_diag(struct e100_private *bdp) -{ - int saved_open_circut = 0xffff; - int saved_short_circut = 0xffff; - int saved_distance = 0xffff; - int saved_same = 0; - int cable_status = E100_CABLE_UNKNOWN; - int i; - - /* If we have link, */ - if (e100_get_link_state(bdp)) - return E100_CABLE_OK; - - if (bdp->rev_id < D102_REV_ID) - return E100_CABLE_UNKNOWN; - - /* Disable MDI/MDI-X auto switching */ - e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr, - MDI_MDIX_RESET_ALL_MASK); - /* Set to 100 Full as required by cable test */ - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, - BMCR_SPEED100 | BMCR_FULLDPLX); - - /* Test up to 100 times */ - for (i = 0; i < 100; i++) { - u16 ctrl_reg; - int distance, open_circut, short_circut, near_end; - - /* Enable and execute cable test */ - e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr, - (HWI_TEST_ENABLE | HWI_TEST_EXECUTE)); - /* Wait for cable test finished */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/100 + 1); - /* Read results */ - e100_mdi_read(bdp, HWI_CONTROL_REG, bdp->phy_addr, &ctrl_reg); - distance = ctrl_reg & HWI_TEST_DISTANCE; - open_circut = ctrl_reg & HWI_TEST_HIGHZ_PROBLEM; - short_circut = ctrl_reg & HWI_TEST_LOWZ_PROBLEM; - - if ((distance == saved_distance) && - (open_circut == saved_open_circut) && - (short_circut == saved_short_circut)) - saved_same++; - else { - saved_same = 0; - saved_distance = distance; - saved_open_circut = open_circut; - saved_short_circut = short_circut; - } - /* If results are the same 3 times */ - if (saved_same == 3) { - near_end = ((distance * HWI_REGISTER_GRANULARITY) < - HWI_NEAR_END_BOUNDARY); - if (open_circut) - cable_status = (near_end) ? - E100_CABLE_OPEN_NEAR : E100_CABLE_OPEN_FAR; - if (short_circut) - cable_status = (near_end) ? - E100_CABLE_SHORT_NEAR : E100_CABLE_SHORT_FAR; - break; - } - } - /* Reset cable test */ - e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr, HWI_RESET_ALL_MASK); - return cable_status; -} - diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/e100/e100_ucode.h 830-ivtv/drivers/net/e100/e100_ucode.h --- 000-virgin/drivers/net/e100/e100_ucode.h Wed Mar 26 22:54:32 2003 +++ 830-ivtv/drivers/net/e100/e100_ucode.h Wed Dec 31 16:00:00 1969 @@ -1,365 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -#ifndef _E100_UCODE_H_ -#define _E100_UCODE_H_ - -/* -e100_ucode.h - -This file contains the loadable micro code arrays to implement receive -bundling on the D101 A-step, D101 B-step, D101M (B-step only), D101S, -D102 B-step, D102 B-step with TCO work around and D102 C-step. - -Each controller has its own specific micro code array. The array for one -controller is totally incompatible with any other controller, and if used -will most likely cause the controller to lock up and stop responding to -the driver. Each micro code array has its own parameter offsets (described -below), and they each have their own version number. -*/ - -/************************************************************************* -* CPUSaver parameters -* -* All CPUSaver parameters are 16-bit literals that are part of a -* "move immediate value" instruction. By changing the value of -* the literal in the instruction before the code is loaded, the -* driver can change algorithm. -* -* CPUSAVER_DWORD - This is the location of the instruction that loads -* the dead-man timer with its inital value. By writing a 16-bit -* value to the low word of this instruction, the driver can change -* the timer value. The current default is either x600 or x800; -* experiments show that the value probably should stay within the -* range of x200 - x1000. -* -* CPUSAVER_BUNDLE_MAX_DWORD - This is the location of the instruction -* that sets the maximum number of frames that will be bundled. In -* some situations, such as the TCP windowing algorithm, it may be -* better to limit the growth of the bundle size than let it go as -* high as it can, because that could cause too much added latency. -* The default is six, because this is the number of packets in the -* default TCP window size. A value of 1 would make CPUSaver indicate -* an interrupt for every frame received. If you do not want to put -* a limit on the bundle size, set this value to xFFFF. -* -* CPUSAVER_MIN_SIZE_DWORD - This is the location of the instruction -* that contains a bit-mask describing the minimum size frame that -* will be bundled. The default masks the lower 7 bits, which means -* that any frame less than 128 bytes in length will not be bundled, -* but will instead immediately generate an interrupt. This does -* not affect the current bundle in any way. Any frame that is 128 -* bytes or large will be bundled normally. This feature is meant -* to provide immediate indication of ACK frames in a TCP environment. -* Customers were seeing poor performance when a machine with CPUSaver -* enabled was sending but not receiving. The delay introduced when -* the ACKs were received was enough to reduce total throughput, because -* the sender would sit idle until the ACK was finally seen. -* -* The current default is 0xFF80, which masks out the lower 7 bits. -* This means that any frame which is x7F (127) bytes or smaller -* will cause an immediate interrupt. Because this value must be a -* bit mask, there are only a few valid values that can be used. To -* turn this feature off, the driver can write the value xFFFF to the -* lower word of this instruction (in the same way that the other -* parameters are used). Likewise, a value of 0xF800 (2047) would -* cause an interrupt to be generated for every frame, because all -* standard Ethernet frames are <= 2047 bytes in length. -*************************************************************************/ - -#ifndef UCODE_MAX_DWORDS -#define UCODE_MAX_DWORDS 134 -#endif - -/********************************************************/ -/* CPUSaver micro code for the D101A */ -/********************************************************/ - -/* Version 2.0 */ - -/* This value is the same for both A and B step of 558. */ - -#define D101_CPUSAVER_TIMER_DWORD 72 -#define D101_CPUSAVER_BUNDLE_DWORD UCODE_MAX_DWORDS -#define D101_CPUSAVER_MIN_SIZE_DWORD UCODE_MAX_DWORDS - -#define D101_A_RCVBUNDLE_UCODE \ -{\ -0x03B301BB, 0x0046FFFF, 0xFFFFFFFF, 0x051DFFFF, 0xFFFFFFFF, 0xFFFFFFFF, \ -0x000C0001, 0x00101212, 0x000C0008, 0x003801BC, \ -0x00000000, 0x00124818, 0x000C1000, 0x00220809, \ -0x00010200, 0x00124818, 0x000CFFFC, 0x003803B5, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0010009C, 0x0024B81D, 0x00130836, 0x000C0001, \ -0x0026081C, 0x0020C81B, 0x00130824, 0x00222819, \ -0x00101213, 0x00041000, 0x003A03B3, 0x00010200, \ -0x00101B13, 0x00238081, 0x00213049, 0x0038003B, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0010009C, 0x0024B83E, 0x00130826, 0x000C0001, \ -0x0026083B, 0x00010200, 0x00134824, 0x000C0001, \ -0x00101213, 0x00041000, 0x0038051E, 0x00101313, \ -0x00010400, 0x00380521, 0x00050600, 0x00100824, \ -0x00101310, 0x00041000, 0x00080600, 0x00101B10, \ -0x0038051E, 0x00000000, 0x00000000, 0x00000000 \ -} - -/********************************************************/ -/* CPUSaver micro code for the D101B */ -/********************************************************/ - -/* Version 2.0 */ - -#define D101_B0_RCVBUNDLE_UCODE \ -{\ -0x03B401BC, 0x0047FFFF, 0xFFFFFFFF, 0x051EFFFF, 0xFFFFFFFF, 0xFFFFFFFF, \ -0x000C0001, 0x00101B92, 0x000C0008, 0x003801BD, \ -0x00000000, 0x00124818, 0x000C1000, 0x00220809, \ -0x00010200, 0x00124818, 0x000CFFFC, 0x003803B6, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0010009C, 0x0024B81D, 0x0013082F, 0x000C0001, \ -0x0026081C, 0x0020C81B, 0x00130837, 0x00222819, \ -0x00101B93, 0x00041000, 0x003A03B4, 0x00010200, \ -0x00101793, 0x00238082, 0x0021304A, 0x0038003C, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0010009C, 0x0024B83E, 0x00130826, 0x000C0001, \ -0x0026083B, 0x00010200, 0x00134837, 0x000C0001, \ -0x00101B93, 0x00041000, 0x0038051F, 0x00101313, \ -0x00010400, 0x00380522, 0x00050600, 0x00100837, \ -0x00101310, 0x00041000, 0x00080600, 0x00101790, \ -0x0038051F, 0x00000000, 0x00000000, 0x00000000 \ -} - -/********************************************************/ -/* CPUSaver micro code for the D101M (B-step only) */ -/********************************************************/ - -/* Version 2.10.1 */ - -/* Parameter values for the D101M B-step */ -#define D101M_CPUSAVER_TIMER_DWORD 78 -#define D101M_CPUSAVER_BUNDLE_DWORD 65 -#define D101M_CPUSAVER_MIN_SIZE_DWORD 126 - -#define D101M_B_RCVBUNDLE_UCODE \ -{\ -0x00550215, 0xFFFF0437, 0xFFFFFFFF, 0x06A70789, 0xFFFFFFFF, 0x0558FFFF, \ -0x000C0001, 0x00101312, 0x000C0008, 0x00380216, \ -0x0010009C, 0x00204056, 0x002380CC, 0x00380056, \ -0x0010009C, 0x00244C0B, 0x00000800, 0x00124818, \ -0x00380438, 0x00000000, 0x00140000, 0x00380555, \ -0x00308000, 0x00100662, 0x00100561, 0x000E0408, \ -0x00134861, 0x000C0002, 0x00103093, 0x00308000, \ -0x00100624, 0x00100561, 0x000E0408, 0x00100861, \ -0x000C007E, 0x00222C21, 0x000C0002, 0x00103093, \ -0x00380C7A, 0x00080000, 0x00103090, 0x00380C7A, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0010009C, 0x00244C2D, 0x00010004, 0x00041000, \ -0x003A0437, 0x00044010, 0x0038078A, 0x00000000, \ -0x00100099, 0x00206C7A, 0x0010009C, 0x00244C48, \ -0x00130824, 0x000C0001, 0x00101213, 0x00260C75, \ -0x00041000, 0x00010004, 0x00130826, 0x000C0006, \ -0x002206A8, 0x0013C926, 0x00101313, 0x003806A8, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00080600, 0x00101B10, 0x00050004, 0x00100826, \ -0x00101210, 0x00380C34, 0x00000000, 0x00000000, \ -0x0021155B, 0x00100099, 0x00206559, 0x0010009C, \ -0x00244559, 0x00130836, 0x000C0000, 0x00220C62, \ -0x000C0001, 0x00101B13, 0x00229C0E, 0x00210C0E, \ -0x00226C0E, 0x00216C0E, 0x0022FC0E, 0x00215C0E, \ -0x00214C0E, 0x00380555, 0x00010004, 0x00041000, \ -0x00278C67, 0x00040800, 0x00018100, 0x003A0437, \ -0x00130826, 0x000C0001, 0x00220559, 0x00101313, \ -0x00380559, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00130831, 0x0010090B, 0x00124813, \ -0x000CFF80, 0x002606AB, 0x00041000, 0x00010004, \ -0x003806A8, 0x00000000, 0x00000000, 0x00000000, \ -} - -/********************************************************/ -/* CPUSaver micro code for the D101S */ -/********************************************************/ - -/* Version 1.20.1 */ - -/* Parameter values for the D101S */ -#define D101S_CPUSAVER_TIMER_DWORD 78 -#define D101S_CPUSAVER_BUNDLE_DWORD 67 -#define D101S_CPUSAVER_MIN_SIZE_DWORD 128 - -#define D101S_RCVBUNDLE_UCODE \ -{\ -0x00550242, 0xFFFF047E, 0xFFFFFFFF, 0x06FF0818, 0xFFFFFFFF, 0x05A6FFFF, \ -0x000C0001, 0x00101312, 0x000C0008, 0x00380243, \ -0x0010009C, 0x00204056, 0x002380D0, 0x00380056, \ -0x0010009C, 0x00244F8B, 0x00000800, 0x00124818, \ -0x0038047F, 0x00000000, 0x00140000, 0x003805A3, \ -0x00308000, 0x00100610, 0x00100561, 0x000E0408, \ -0x00134861, 0x000C0002, 0x00103093, 0x00308000, \ -0x00100624, 0x00100561, 0x000E0408, 0x00100861, \ -0x000C007E, 0x00222FA1, 0x000C0002, 0x00103093, \ -0x00380F90, 0x00080000, 0x00103090, 0x00380F90, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0010009C, 0x00244FAD, 0x00010004, 0x00041000, \ -0x003A047E, 0x00044010, 0x00380819, 0x00000000, \ -0x00100099, 0x00206FFD, 0x0010009A, 0x0020AFFD, \ -0x0010009C, 0x00244FC8, 0x00130824, 0x000C0001, \ -0x00101213, 0x00260FF7, 0x00041000, 0x00010004, \ -0x00130826, 0x000C0006, 0x00220700, 0x0013C926, \ -0x00101313, 0x00380700, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00080600, 0x00101B10, 0x00050004, 0x00100826, \ -0x00101210, 0x00380FB6, 0x00000000, 0x00000000, \ -0x002115A9, 0x00100099, 0x002065A7, 0x0010009A, \ -0x0020A5A7, 0x0010009C, 0x002445A7, 0x00130836, \ -0x000C0000, 0x00220FE4, 0x000C0001, 0x00101B13, \ -0x00229F8E, 0x00210F8E, 0x00226F8E, 0x00216F8E, \ -0x0022FF8E, 0x00215F8E, 0x00214F8E, 0x003805A3, \ -0x00010004, 0x00041000, 0x00278FE9, 0x00040800, \ -0x00018100, 0x003A047E, 0x00130826, 0x000C0001, \ -0x002205A7, 0x00101313, 0x003805A7, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00130831, \ -0x0010090B, 0x00124813, 0x000CFF80, 0x00260703, \ -0x00041000, 0x00010004, 0x00380700 \ -} - -/********************************************************/ -/* CPUSaver micro code for the D102 B-step */ -/********************************************************/ - -/* Version 2.0 */ -/* Parameter values for the D102 B-step */ -#define D102_B_CPUSAVER_TIMER_DWORD 82 -#define D102_B_CPUSAVER_BUNDLE_DWORD 106 -#define D102_B_CPUSAVER_MIN_SIZE_DWORD 70 - -#define D102_B_RCVBUNDLE_UCODE \ -{\ -0x006F0276, 0x0EF71FFF, 0x0ED30F86, 0x0D250ED9, 0x1FFF1FFF, 0x1FFF04D2, \ -0x00300001, 0x0140D871, 0x00300008, 0x00E00277, \ -0x01406C57, 0x00816073, 0x008700FA, 0x00E00070, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x01406CBA, 0x00807F9A, 0x00901F9A, 0x0024FFFF, \ -0x014B6F6F, 0x0030FFFE, 0x01407172, 0x01496FBA, \ -0x014B6F72, 0x00308000, 0x01406C52, 0x00912EFC, \ -0x00E00EF8, 0x00000000, 0x00000000, 0x00000000, \ -0x00906F8C, 0x00900F8C, 0x00E00F87, 0x00000000, \ -0x00906ED8, 0x01406C55, 0x00E00ED4, 0x00000000, \ -0x01406C51, 0x0080DFC2, 0x01406C52, 0x00815FC2, \ -0x01406C57, 0x00917FCC, 0x00E01FDD, 0x00000000, \ -0x00822D30, 0x01406C51, 0x0080CD26, 0x01406C52, \ -0x00814D26, 0x01406C57, 0x00916D26, 0x014C6FD7, \ -0x00300000, 0x00841FD2, 0x00300001, 0x0140D772, \ -0x00E012B3, 0x014C6F91, 0x0150710B, 0x01496F72, \ -0x0030FF80, 0x00940EDD, 0x00102000, 0x00038400, \ -0x00E00EDA, 0x00000000, 0x00000000, 0x00000000, \ -0x01406C57, 0x00917FE9, 0x00001000, 0x00E01FE9, \ -0x00200600, 0x0140D76F, 0x00138400, 0x01406FD8, \ -0x0140D96F, 0x00E01FDD, 0x00038400, 0x00102000, \ -0x00971FD7, 0x00101000, 0x00050200, 0x00E804D2, \ -0x014C6FD8, 0x00300001, 0x00840D26, 0x0140D872, \ -0x00E00D26, 0x014C6FD9, 0x00300001, 0x0140D972, \ -0x00941FBD, 0x00102000, 0x00038400, 0x014C6FD8, \ -0x00300006, 0x00840EDA, 0x014F71D8, 0x0140D872, \ -0x00E00EDA, 0x01496F50, 0x00E004D3, 0x00000000, \ -} - -/********************************************************/ -/* Micro code for the D102 C-step */ -/********************************************************/ - -/* Parameter values for the D102 C-step */ -#define D102_C_CPUSAVER_TIMER_DWORD 46 -#define D102_C_CPUSAVER_BUNDLE_DWORD 74 -#define D102_C_CPUSAVER_MIN_SIZE_DWORD 54 - -#define D102_C_RCVBUNDLE_UCODE \ -{ \ -0x00700279, 0x0E6604E2, 0x02BF0CAE, 0x1508150C, 0x15190E5B, 0x0E840F13, \ -0x00E014D8, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014DC, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014F4, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014E0, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014E7, 0x00000000, 0x00000000, 0x00000000, \ -0x00141000, 0x015D6F0D, 0x00E002C0, 0x00000000, \ -0x00200600, 0x00E0150D, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0030FF80, 0x00940E6A, 0x00038200, 0x00102000, \ -0x00E00E67, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00906E65, 0x00800E60, 0x00E00E5D, 0x00000000, \ -0x00300006, 0x00E0151A, 0x00000000, 0x00000000, \ -0x00906F19, 0x00900F19, 0x00E00F14, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x01406CBA, 0x00807FDA, 0x00901FDA, 0x0024FFFF, \ -0x014B6F6F, 0x0030FFFE, 0x01407172, 0x01496FBA, \ -0x014B6F72, 0x00308000, 0x01406C52, 0x00912E89, \ -0x00E00E85, 0x00000000, 0x00000000, 0x00000000 \ -} - -/********************************************************/ -/* Micro code for the D102 E-step */ -/********************************************************/ - -/* Parameter values for the D102 E-step */ -#define D102_E_CPUSAVER_TIMER_DWORD 42 -#define D102_E_CPUSAVER_BUNDLE_DWORD 54 -#define D102_E_CPUSAVER_MIN_SIZE_DWORD 46 - -#define D102_E_RCVBUNDLE_UCODE \ -{\ -0x007D028F, 0x0E4204F9, 0x14ED0C85, 0x14FA14E9, 0x1FFF1FFF, 0x1FFF1FFF, \ -0x00E014B9, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014BD, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014D5, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014C1, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014C8, 0x00000000, 0x00000000, 0x00000000, \ -0x00200600, 0x00E014EE, 0x00000000, 0x00000000, \ -0x0030FF80, 0x00940E46, 0x00038200, 0x00102000, \ -0x00E00E43, 0x00000000, 0x00000000, 0x00000000, \ -0x00300006, 0x00E014FB, 0x00000000, 0x00000000 \ -} - -#endif /* _E100_UCODE_H_ */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/e100.c 830-ivtv/drivers/net/e100.c --- 000-virgin/drivers/net/e100.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/net/e100.c Thu Jan 8 08:54:15 2004 @@ -0,0 +1,2321 @@ +/******************************************************************************* + + + Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + Linux NICS + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +/* + * e100.c: Intel(R) PRO/100 ethernet driver + * + * (Re)written 2003 by scott.feldman@intel.com. Based loosely on + * original e100 driver, but better described as a munging of + * e100, e1000, eepro100, tg3, 8139cp, and other drivers. + * + * References: + * Intel 8255x 10/100 Mbps Ethernet Controller Family, + * Open Source Software Developers Manual, + * http://sourceforge.net/projects/e1000 + * + * + * Theory of Operation + * + * I. General + * + * The driver supports Intel(R) 10/100 Mbps PCI Fast Ethernet + * controller family, which includes the 82557, 82558, 82559, 82550, + * 82551, and 82562 devices. 82558 and greater controllers + * integrate the Intel 82555 PHY. The controllers are used in + * server and client network interface cards, as well as in + * LAN-On-Motherboard (LOM), CardBus, MiniPCI, and ICHx + * configurations. 8255x supports a 32-bit linear addressing + * mode and operates at 33Mhz PCI clock rate. + * + * II. Driver Operation + * + * Memory-mapped mode is used exclusively to access the device's + * shared-memory structure, the Control/Status Registers (CSR). All + * setup, configuration, and control of the device, including queuing + * of Tx, Rx, and configuration commands is through the CSR. + * cmd_lock serializes accesses to the CSR command register. cb_lock + * protects the shared Command Block List (CBL). + * + * 8255x is highly MII-compliant and all access to the PHY go + * through the Management Data Interface (MDI). Consequently, the + * driver leverages the mii.c library shared with other MII-compliant + * devices. + * + * Big- and Little-Endian byte order as well as 32- and 64-bit + * archs are supported. Weak-ordered memory and non-cache-coherent + * archs are supported. + * + * III. Transmit + * + * A Tx skb is mapped and hangs off of a TCB. TCBs are linked + * together in a fixed-size ring (CBL) thus forming the flexible mode + * memory structure. A TCB marked with the suspend-bit indicates + * the end of the ring. The last TCB processed suspends the + * controller, and the controller can be restarted by issue a CU + * resume command to continue from the suspend point, or a CU start + * command to start at a given position in the ring. + * + * Non-Tx commands (config, multicast setup, etc) are linked + * into the CBL ring along with Tx commands. The common structure + * used for both Tx and non-Tx commands is the Command Block (CB). + * + * cb_to_use is the next CB to use for queuing a command; cb_to_clean + * is the next CB to check for completion; cb_to_send is the first + * CB to start on in case of a previous failure to resume. CB clean + * up happens in interrupt context in response to a CU interrupt, or + * in dev->poll in the case where NAPI is enabled. cbs_avail keeps + * track of number of free CB resources available. + * + * Hardware padding of short packets to minimum packet size is + * enabled. 82557 pads with 7Eh, while the later controllers pad + * with 00h. + * + * IV. Recieve + * + * The Receive Frame Area (RFA) comprises a ring of Receive Frame + * Descriptors (RFD) + data buffer, thus forming the simplified mode + * memory structure. Rx skbs are allocated to contain both the RFD + * and the data buffer, but the RFD is pulled off before the skb is + * indicated. The data buffer is aligned such that encapsulated + * protocol headers are u32-aligned. Since the RFD is part of the + * mapped shared memory, and completion status is contained within + * the RFD, the RFD must be dma_sync'ed to maintain a consistent + * view from software and hardware. + * + * Under typical operation, the receive unit (RU) is start once, + * and the controller happily fills RFDs as frames arrive. If + * replacement RFDs cannot be allocated, or the RU goes non-active, + * the RU must be restarted. Frame arrival generates an interrupt, + * and Rx indication and re-allocation happen in the same context, + * therefore no locking is required. If NAPI is enabled, this work + * happens in dev->poll. A software-generated interrupt is gen- + * erated from the watchdog to recover from a failed allocation + * senario where all Rx resources have been indicated and none re- + * placed. + * + * V. Miscellaneous + * + * VLAN offloading of tagging, stripping and filtering is not + * supported, but driver will accommodate the extra 4-byte VLAN tag + * for processing by upper layers. Tx/Rx Checksum offloading is not + * supported. Tx Scatter/Gather is not supported. Jumbo Frames is + * not supported (hardware limitation). + * + * NAPI support is enabled with CONFIG_E100_NAPI. + * + * MagicPacket(tm) WoL support is enabled/disabled via ethtool. + * + * Thanks to JC (jchapman@katalix.com) for helping with + * testing/troubleshooting the development driver. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define DRV_NAME "e100" +#define DRV_VERSION "3.0.12_dev" +#define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver" +#define DRV_COPYRIGHT "Copyright(c) 1999-2003 Intel Corporation" +#define PFX DRV_NAME ": " + +#define E100_WATCHDOG_PERIOD 2 * HZ +#define E100_NAPI_WEIGHT 16 + +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_AUTHOR(DRV_COPYRIGHT); +MODULE_LICENSE("GPL"); + +static int debug = 3; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); +#define DPRINTK(nlevel, klevel, fmt, args...) \ + (void)((NETIF_MSG_##nlevel & nic->msg_enable) && \ + printk(KERN_##klevel PFX "%s: %s: " fmt, nic->netdev->name, \ + __FUNCTION__ , ## args)) + +#define INTEL_8255X_ETHERNET_DEVICE(device_id, ich) {\ + PCI_VENDOR_ID_INTEL, device_id, PCI_ANY_ID, PCI_ANY_ID, \ + PCI_CLASS_NETWORK_ETHERNET << 8, 0xFFFF00, ich } +static struct pci_device_id e100_id_table[] = { + INTEL_8255X_ETHERNET_DEVICE(0x1029, 0), + INTEL_8255X_ETHERNET_DEVICE(0x1030, 0), + INTEL_8255X_ETHERNET_DEVICE(0x1031, 3), + INTEL_8255X_ETHERNET_DEVICE(0x1032, 3), + INTEL_8255X_ETHERNET_DEVICE(0x1033, 3), + INTEL_8255X_ETHERNET_DEVICE(0x1034, 3), + INTEL_8255X_ETHERNET_DEVICE(0x1038, 3), + INTEL_8255X_ETHERNET_DEVICE(0x1039, 4), + INTEL_8255X_ETHERNET_DEVICE(0x103A, 4), + INTEL_8255X_ETHERNET_DEVICE(0x103B, 4), + INTEL_8255X_ETHERNET_DEVICE(0x103C, 4), + INTEL_8255X_ETHERNET_DEVICE(0x103D, 4), + INTEL_8255X_ETHERNET_DEVICE(0x103E, 4), + INTEL_8255X_ETHERNET_DEVICE(0x1050, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1051, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1052, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1053, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1054, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1055, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1064, 6), + INTEL_8255X_ETHERNET_DEVICE(0x1065, 6), + INTEL_8255X_ETHERNET_DEVICE(0x1066, 6), + INTEL_8255X_ETHERNET_DEVICE(0x1067, 6), + INTEL_8255X_ETHERNET_DEVICE(0x1068, 6), + INTEL_8255X_ETHERNET_DEVICE(0x1069, 6), + INTEL_8255X_ETHERNET_DEVICE(0x106A, 6), + INTEL_8255X_ETHERNET_DEVICE(0x106B, 6), + INTEL_8255X_ETHERNET_DEVICE(0x1059, 0), + INTEL_8255X_ETHERNET_DEVICE(0x1209, 0), + INTEL_8255X_ETHERNET_DEVICE(0x1229, 0), + INTEL_8255X_ETHERNET_DEVICE(0x2449, 2), + INTEL_8255X_ETHERNET_DEVICE(0x2459, 2), + INTEL_8255X_ETHERNET_DEVICE(0x245D, 2), + { 0, } +}; +MODULE_DEVICE_TABLE(pci, e100_id_table); + +enum mac { + mac_82557_D100_A = 0, + mac_82557_D100_B = 1, + mac_82557_D100_C = 2, + mac_82558_D101_A4 = 4, + mac_82558_D101_B0 = 5, + mac_82559_D101M = 8, + mac_82559_D101S = 9, + mac_82550_D102 = 12, + mac_82550_D102_C = 13, + mac_82551_E = 14, + mac_82551_F = 15, + mac_82551_10 = 16, + mac_unknown = 0xFF, +}; + +enum phy { + phy_100a = 0x000003E0, + phy_100c = 0x035002A8, + phy_82555_tx = 0x015002A8, + phy_nsc_tx = 0x5C002000, + phy_82562_et = 0x033002A8, + phy_82562_em = 0x032002A8, + phy_82562_eh = 0x017002A8, + phy_unknown = 0xFFFFFFFF, +}; + +/* CSR (Control/Status Registers) */ +struct csr { + struct { + u8 status; + u8 stat_ack; + u8 cmd_lo; + u8 cmd_hi; + u32 gen_ptr; + } scb; + u32 port; + u16 flash_ctrl; + u8 eeprom_ctrl_lo; + u8 eeprom_ctrl_hi; + u32 mdi_ctrl; + u32 rx_dma_count; +}; + +enum scb_status { + rus_idle = 0x00, + rus_suspended = 0x04, + rus_no_resources = 0x08, + rus_ready = 0x10, + rus_mask = 0x3C, + cus_idle = 0x00, + cus_suspended = 0x40, + cus_active = 0x80, + cus_mask = 0xC0, +}; + +enum scb_stat_ack { + stat_ack_sw_gen = 0x04, + stat_ack_rnr = 0x10, + stat_ack_cu_idle = 0x20, + stat_ack_frame_rx = 0x40, + stat_ack_cu_cmd_done = 0x80, + stat_ack_rx = (stat_ack_sw_gen | stat_ack_rnr | stat_ack_frame_rx), + stat_ack_tx = (stat_ack_cu_idle | stat_ack_cu_cmd_done), +}; + +enum scb_cmd_hi { + irq_mask_none = 0x00, + irq_mask_all = 0x01, + irq_sw_gen = 0x02, +}; + +enum scb_cmd_lo { + ruc_start = 0x01, + ruc_load_base = 0x06, + cuc_start = 0x10, + cuc_resume = 0x20, + cuc_dump_addr = 0x40, + cuc_dump_stats = 0x50, + cuc_load_base = 0x60, + cuc_dump_reset = 0x70, +}; + +enum port { + software_reset = 0x0000, + selftest = 0x0001, + selective_reset = 0x0002, +}; + +enum eeprom_ctrl_lo { + eesk = 0x01, + eecs = 0x02, + eedi = 0x04, + eedo = 0x08, +}; + +enum mdi_ctrl { + mdi_write = 0x04000000, + mdi_read = 0x08000000, + mdi_ready = 0x10000000, +}; + +enum eeprom_op { + op_write = 0x05, + op_read = 0x06, + op_ewds = 0x10, + op_ewen = 0x13, +}; + +enum eeprom_offsets { + eeprom_id = 0x0A, + eeprom_config_asf = 0x0D, + eeprom_smbus_addr = 0x90, +}; + +enum eeprom_id { + eeprom_id_wol = 0x0020, +}; + +enum eeprom_config_asf { + eeprom_asf = 0x8000, + eeprom_gcl = 0x4000, +}; + +enum cb_status { + cb_complete = 0x8000, + cb_ok = 0x2000, +}; + +enum cb_command { + cb_iaaddr = 0x0001, + cb_config = 0x0002, + cb_multi = 0x0003, + cb_tx = 0x0004, + cb_dump = 0x0006, + cb_tx_sf = 0x0008, + cb_cid = 0x1f00, + cb_i = 0x2000, + cb_s = 0x4000, + cb_el = 0x8000, +}; + +struct rfd { + u16 status; + u16 command; + u32 link; + u32 rbd; + u16 actual_size; + u16 size; +}; + +struct rx_list { + struct list_head list; + struct sk_buff *skb; + dma_addr_t dma_addr; + unsigned int length; +}; + +#if defined(__BIG_ENDIAN_BITFIELD) +#define X(a,b) b,a +#else +#define X(a,b) a,b +#endif +struct config { +/*0*/ u8 X(byte_count:6, pad0:2); +/*1*/ u8 X(X(rx_fifo_limit:4, tx_fifo_limit:3), pad1:1); +/*2*/ u8 adaptive_ifs; +/*3*/ u8 X(X(X(X(mwi_enable:1, type_enable:1), read_align_enable:1), + term_write_cache_line:1), pad3:4); +/*4*/ u8 X(rx_dma_max_count:7, pad4:1); +/*5*/ u8 X(tx_dma_max_count:7, dma_max_count_enable:1); +/*6*/ u8 X(X(X(X(X(X(X(late_scb_update:1, direct_rx_dma:1), + tno_intr:1), cna_intr:1), standard_tcb:1), standard_stat_counter:1), + rx_discard_overruns:1), rx_save_bad_frames:1); +/*7*/ u8 X(X(X(X(X(rx_discard_short_frames:1, tx_underrun_retry:2), + pad7:2), rx_extended_rfd:1), tx_two_frames_in_fifo:1), + tx_dynamic_tbd:1); +/*8*/ u8 X(X(mii_mode:1, pad8:6), csma_disabled:1); +/*9*/ u8 X(X(X(X(X(rx_tcpudp_checksum:1, pad9:3), vlan_arp_tco:1), + link_status_wake:1), arp_wake:1), mcmatch_wake:1); +/*10*/ u8 X(X(X(pad10:3, no_source_addr_insertion:1), preamble_length:2), + loopback:2); +/*11*/ u8 X(linear_priority:3, pad11:5); +/*12*/ u8 X(X(linear_priority_mode:1, pad12:3), ifs:4); +/*13*/ u8 ip_addr_lo; +/*14*/ u8 ip_addr_hi; +/*15*/ u8 X(X(X(X(X(X(X(promiscuous_mode:1, broadcast_disabled:1), + wait_after_win:1), pad15_1:1), ignore_ul_bit:1), crc_16_bit:1), + pad15_2:1), crs_or_cdt:1); +/*16*/ u8 fc_delay_lo; +/*17*/ u8 fc_delay_hi; +/*18*/ u8 X(X(X(X(X(rx_stripping:1, tx_padding:1), rx_crc_transfer:1), + rx_long_ok:1), fc_priority_threshold:3), pad18:1); +/*19*/ u8 X(X(X(X(X(X(X(addr_wake:1, magic_packet_disable:1), + fc_disable:1), fc_restop:1), fc_restart:1), fc_reject:1), + full_duplex_force:1), full_duplex_pin:1); +/*20*/ u8 X(X(X(pad20_1:5, fc_priority_location:1), multi_ia:1), pad20_2:1); +/*21*/ u8 X(X(pad21_1:3, multicast_all:1), pad21_2:4); +/*22*/ u8 X(X(rx_d102_mode:1, rx_vlan_drop:1), pad22:6); + u8 pad_d102[9]; +}; + +#define E100_MAX_MULTICAST_ADDRS 64 +struct multi { + u16 count; + u8 addr[E100_MAX_MULTICAST_ADDRS * ETH_ALEN + 2/*pad*/]; +}; + +/* Important: keep total struct u32-aligned */ +struct cb { + u16 status; + u16 command; + u32 link; + union { + u8 iaaddr[ETH_ALEN]; + struct config config; + struct multi multi; + struct { + u32 tbd_array; + u16 tcb_byte_count; + u8 threshold; + u8 tbd_count; + struct { + u32 buf_addr; + u16 size; + u16 eol; + } tbd; + } tcb; + u32 dump_buffer_addr; + } u; + struct cb *next, *prev; + dma_addr_t dma_addr; + struct sk_buff *skb; +}; + +enum loopback { + lb_none = 0, lb_mac = 1, lb_phy = 3, +}; + +struct stats { + u32 tx_good_frames, tx_max_collisions, tx_late_collisions, + tx_underruns, tx_lost_crs, tx_deferred, tx_single_collisions, + tx_multiple_collisions, tx_total_collisions; + u32 rx_good_frames, rx_crc_errors, rx_alignment_errors, + rx_resource_errors, rx_overrun_errors, rx_cdt_errors, + rx_short_frame_errors; + u32 fc_xmt_pause, fc_rcv_pause, fc_rcv_unsupported; + u16 xmt_tco_frames, rcv_tco_frames; + u32 complete; +}; + +struct mem { + struct { + u32 signature; + u32 result; + } selftest; + struct stats stats; + u8 dump_buf[596]; +}; + +struct param_range { + u32 min; + u32 max; + u32 count; +}; + +struct params { + struct param_range rfds; + struct param_range cbs; +}; + +struct nic { + /* Begin: frequently used values: keep adjacent for cache effect */ + u32 msg_enable ____cacheline_aligned; + struct net_device *netdev; + struct pci_dev *pdev; + + struct list_head rx_list_head ____cacheline_aligned; + struct rx_list *rx_list; + struct rfd blank_rfd; + + spinlock_t cb_lock ____cacheline_aligned; + spinlock_t cmd_lock; + struct csr *csr; + enum scb_cmd_lo cuc_cmd; + unsigned int cbs_avail; + struct cb *cbs; + struct cb *cb_to_use; + struct cb *cb_to_send; + struct cb *cb_to_clean; + u16 tx_command; + /* End: frequently used values: keep adjacent for cache effect */ + + enum { + ich = (1 << 0), + promiscuous = (1 << 1), + multicast_all = (1 << 2), + wol_magic = (1 << 3), + } flags ____cacheline_aligned; + + enum mac mac; + enum phy phy; + struct params params; + struct net_device_stats net_stats; + struct timer_list watchdog; + struct timer_list blink_timer; + struct mii_if_info mii; + enum loopback loopback; + + struct mem *mem; + dma_addr_t dma_addr; + + dma_addr_t cbs_dma_addr; + u8 adaptive_ifs; + u8 tx_threshold; + u32 tx_frames; + u32 tx_collisions; + u32 tx_deferred; + u32 tx_single_collisions; + u32 tx_multiple_collisions; + u32 tx_fc_pause; + u32 tx_tco_frames; + + u32 rx_fc_pause; + u32 rx_fc_unsupported; + u32 rx_tco_frames; + + u8 rev_id; + u16 leds; + u16 eeprom_wc; + u16 eeprom[256]; + u32 pm_state[16]; +}; + +static inline void e100_write_flush(struct nic *nic) +{ + /* Flush previous PCI writes through intermediate bridges + * by doing a benign read */ + (void)readb(&nic->csr->scb.status); +} + +static inline void e100_enable_irq(struct nic *nic) +{ + writeb(irq_mask_none, &nic->csr->scb.cmd_hi); + e100_write_flush(nic); +} + +static inline void e100_disable_irq(struct nic *nic) +{ + writeb(irq_mask_all, &nic->csr->scb.cmd_hi); + e100_write_flush(nic); +} + +static void e100_hw_reset(struct nic *nic) +{ + /* Put CU and RU into idle with a selective reset to get + * device off of PCI bus */ + writel(selective_reset, &nic->csr->port); + e100_write_flush(nic); udelay(20); + + /* Now fully reset device */ + writel(software_reset, &nic->csr->port); + e100_write_flush(nic); udelay(20); + + /* TCO workaround - 82559 and greater */ + if(nic->mac >= mac_82559_D101M) { + /* Issue a redundant CU load base without setting + * general pointer, and without waiting for scb to + * clear. This gets us into post-driver. Finally, + * wait 20 msec for reset to take effect. */ + writeb(cuc_load_base, &nic->csr->scb.cmd_lo); + mdelay(20); + } + + /* Mask off our interrupt line - it's unmasked after reset */ + e100_disable_irq(nic); +} + +static int e100_self_test(struct nic *nic) +{ + u32 dma_addr = nic->dma_addr + offsetof(struct mem, selftest); + + /* Passing the self-test is a pretty good indication + * that the device can DMA to/from host memory */ + + nic->mem->selftest.signature = 0; + nic->mem->selftest.result = 0xFFFFFFFF; + + writel(selftest | dma_addr, &nic->csr->port); + e100_write_flush(nic); + /* Wait 10 msec for self-test to complete */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ / 100 + 1); + + /* Interrupts are enabled after self-test */ + e100_disable_irq(nic); + + /* Check results of self-test */ + if(nic->mem->selftest.result != 0) { + DPRINTK(HW, ERR, "Self-test failed: result=0x%08X\n", + nic->mem->selftest.result); + return -ETIMEDOUT; + } + if(nic->mem->selftest.signature == 0) { + DPRINTK(HW, ERR, "Self-test failed: timed out\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static void e100_eeprom_write(struct nic *nic, u16 addr_len, u16 addr, u16 data) +{ + u32 cmd_addr_data[3]; + u8 ctrl; + int i, j; + + /* Three cmds: write/erase enable, write data, write/erase disable */ + cmd_addr_data[0] = op_ewen << (addr_len - 2); + cmd_addr_data[1] = (((op_write << addr_len) | addr) << 16) | data; + cmd_addr_data[2] = op_ewds << (addr_len - 2); + + /* Bit-bang cmds to write word to eeprom */ + for(j = 0; j < 3; j++) { + + /* Chip select */ + writeb(eecs | eesk, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + + for(i = 31; i >= 0; i--) { + ctrl = (cmd_addr_data[j] & (1 << i)) ? + eecs | eedi : eecs; + writeb(ctrl, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + } + /* Wait 10 msec for cmd to complete */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ / 100 + 1); + + /* Chip deselect */ + writeb(0, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + } + +}; + +/* General technique stolen from the eepro100 driver - very clever */ +static u16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr) +{ + u32 cmd_addr_data; + u16 data = 0; + u8 ctrl; + int i; + + cmd_addr_data = ((op_read << *addr_len) | addr) << 16; + + /* Chip select */ + writeb(eecs | eesk, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + + /* Bit-bang to read word from eeprom */ + for(i = 31; i >= 0; i--) { + ctrl = (cmd_addr_data & (1 << i)) ? eecs | eedi : eecs; + writeb(ctrl, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + /* Eeprom drives a dummy zero to EEDO after receiving + * complete address. Use this to adjust addr_len. */ + ctrl = readb(&nic->csr->eeprom_ctrl_lo); + if(!(ctrl & eedo) && i > 16) { + *addr_len -= (i - 16); + i = 17; + } + data = (data << 1) | (ctrl & eedo ? 1 : 0); + } + + /* Chip deselect */ + writeb(0, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + + return data; +}; + +/* Load entire EEPROM image into driver cache and validate checksum */ +static int e100_eeprom_load(struct nic *nic) +{ + u16 addr, addr_len = 8, checksum = 0; + + /* Try reading with an 8-bit addr len to discover actual addr len */ + e100_eeprom_read(nic, &addr_len, 0); + nic->eeprom_wc = 1 << addr_len; + + for(addr = 0; addr < nic->eeprom_wc; addr++) { + nic->eeprom[addr] = e100_eeprom_read(nic, &addr_len, addr); + if(addr < nic->eeprom_wc - 1) + checksum += nic->eeprom[addr]; + } + + /* The checksum, stored in the last word, is calculated such that + * the sum of words should be 0xBABA */ + checksum = 0xBABA - checksum; + if(checksum != nic->eeprom[nic->eeprom_wc - 1]) { + DPRINTK(PROBE, ERR, "EEPROM corrupted\n"); + return -EAGAIN; + } + + return 0; +} + +/* Save (portion of) driver EEPROM cache to device and update checksum */ +static int e100_eeprom_save(struct nic *nic, u16 start, u16 count) +{ + u16 addr, addr_len = 8, checksum = 0; + + /* Try reading with an 8-bit addr len to discover actual addr len */ + e100_eeprom_read(nic, &addr_len, 0); + nic->eeprom_wc = 1 << addr_len; + + if(start + count >= nic->eeprom_wc) + return -EINVAL; + + for(addr = start; addr < start + count; addr++) + e100_eeprom_write(nic, addr_len, addr, nic->eeprom[addr]); + + /* The checksum, stored in the last word, is calculated such that + * the sum of words should be 0xBABA */ + for(addr = 0; addr < nic->eeprom_wc - 1; addr++) + checksum += nic->eeprom[addr]; + nic->eeprom[nic->eeprom_wc - 1] = 0xBABA - checksum; + e100_eeprom_write(nic, addr_len, nic->eeprom_wc - 1, 0xBABA - checksum); + + return 0; +} + +#define E100_WAIT_SCB_TIMEOUT 40 +static inline int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr) +{ + unsigned long flags; + unsigned int i; + int err = 0; + + spin_lock_irqsave(&nic->cmd_lock, flags); + + /* Previous command is accepted when SCB clears */ + for(i = 0; i < E100_WAIT_SCB_TIMEOUT; i++) { + if(likely(!readb(&nic->csr->scb.cmd_lo))) + break; + cpu_relax(); + if(unlikely(i > (E100_WAIT_SCB_TIMEOUT >> 1))) + udelay(5); + } + if(unlikely(i == E100_WAIT_SCB_TIMEOUT)) { + err = -EAGAIN; + goto err_unlock; + } + + if(unlikely(cmd != cuc_resume)) + writel(dma_addr, &nic->csr->scb.gen_ptr); + writeb(cmd, &nic->csr->scb.cmd_lo); + +err_unlock: + spin_unlock_irqrestore(&nic->cmd_lock, flags); + + return err; +} + +static inline int e100_exec_cb(struct nic *nic, struct sk_buff *skb, + void (*cb_prepare)(struct nic *, struct cb *, struct sk_buff *)) +{ + struct cb *cb; + unsigned long flags; + int err = 0; + + spin_lock_irqsave(&nic->cb_lock, flags); + + if(unlikely(!nic->cbs_avail)) { + err = -ENOMEM; + goto err_unlock; + } + + cb = nic->cb_to_use; + nic->cb_to_use = cb->next; + nic->cbs_avail--; + cb->skb = skb; + + if(unlikely(!nic->cbs_avail)) + err = -ENOSPC; + + cb_prepare(nic, cb, skb); + + /* Order is important otherwise we'll be in a race with h/w: + * set S-bit in current first, then clear S-bit in previous. */ + cb->command |= cpu_to_le16(cb_s); + cb->prev->command &= cpu_to_le16(~cb_s); + + while(nic->cb_to_send != nic->cb_to_use) { + if(unlikely((err = e100_exec_cmd(nic, nic->cuc_cmd, + nic->cb_to_send->dma_addr)))) { + /* Ok, here's where things get sticky. It's + * possible that we can't schedule the command + * because the controller is too busy, so + * let's just queue the command and try again + * when another command is scheduled. */ + break; + } else { + nic->cuc_cmd = cuc_resume; + nic->cb_to_send = nic->cb_to_send->next; + } + } + +err_unlock: + spin_unlock_irqrestore(&nic->cb_lock, flags); + + return err; +} + +static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data) +{ + u32 data_out = 0; + unsigned int i; + + writel((reg << 16) | (addr << 21) | dir | data, &nic->csr->mdi_ctrl); + + for(i = 0; i < 100; i++) { + udelay(20); + if((data_out = readl(&nic->csr->mdi_ctrl)) & mdi_ready) + break; + } + + DPRINTK(HW, DEBUG, + "%s:addr=%d, reg=%d, data_in=0x%04X, data_out=0x%04X\n", + dir == mdi_read ? "READ" : "WRITE", addr, reg, data, data_out); + return (u16)data_out; +} + +static int mdio_read(struct net_device *netdev, int addr, int reg) +{ + return mdio_ctrl(netdev->priv, addr, mdi_read, reg, 0); +} + +static void mdio_write(struct net_device *netdev, int addr, int reg, int data) +{ + mdio_ctrl(netdev->priv, addr, mdi_write, reg, data); +} + +static void e100_get_defaults(struct nic *nic) +{ + struct param_range rfds = { .min = 64, .max = 256, .count = 64 }; + struct param_range cbs = { .min = 64, .max = 256, .count = 64 }; + + pci_read_config_byte(nic->pdev, PCI_REVISION_ID, &nic->rev_id); + /* MAC type is encoded as rev ID; exception: ICH is treated as 82559 */ + nic->mac = (nic->flags & ich) ? mac_82559_D101M : nic->rev_id; + if(nic->mac == mac_unknown) + nic->mac = mac_82557_D100_A; + + nic->params.rfds = rfds; + nic->params.cbs = cbs; + + /* Quadwords to DMA into FIFO before starting frame transmit */ + nic->tx_threshold = 0xE0; + + nic->tx_command = cpu_to_le16(cb_tx | cb_i | cb_tx_sf | + ((nic->mac >= mac_82558_D101_A4) ? cb_cid : 0)); + + /* Template for a freshly allocated RFD */ + nic->blank_rfd.command = cpu_to_le16(cb_el); + nic->blank_rfd.rbd = 0xFFFFFFFF; + nic->blank_rfd.size = cpu_to_le16(VLAN_ETH_FRAME_LEN); + + /* MII setup */ + nic->mii.phy_id_mask = 0x1F; + nic->mii.reg_num_mask = 0x1F; + nic->mii.dev = nic->netdev; + nic->mii.mdio_read = mdio_read; + nic->mii.mdio_write = mdio_write; +} + +static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb) +{ + struct config *config = &cb->u.config; + u8 *c = (u8 *)config; + + cb->command = cpu_to_le16(cb_config); + + memset(config, 0, sizeof(struct config)); + + config->byte_count = 0x16; /* bytes in this struct */ + config->rx_fifo_limit = 0x8; /* bytes in FIFO before DMA */ + config->direct_rx_dma = 0x1; /* reserved */ + config->standard_tcb = 0x1; /* 1=standard, 0=extended */ + config->standard_stat_counter = 0x1; /* 1=standard, 0=extended */ + config->rx_discard_short_frames = 0x1; /* 1=discard, 0=pass */ + config->tx_underrun_retry = 0x3; /* # of underrun retries */ + config->mii_mode = 0x1; /* 1=MII mode, 0=503 mode */ + config->pad10 = 0x6; + config->no_source_addr_insertion = 0x1; /* 1=no, 0=yes */ + config->preamble_length = 0x2; /* 0=1, 1=3, 2=7, 3=15 bytes */ + config->ifs = 0x6; /* x16 = inter frame spacing */ + config->ip_addr_hi = 0xF2; /* ARP IP filter - not used */ + config->pad15_1 = 0x1; + config->pad15_2 = 0x1; + config->crs_or_cdt = 0x0; /* 0=CRS only, 1=CRS or CDT */ + config->fc_delay_hi = 0x40; /* time delay for fc frame */ + config->tx_padding = 0x1; /* 1=pad short frames */ + config->fc_priority_threshold = 0x7; /* 7=priority fc disabled */ + config->pad18 = 0x1; + config->full_duplex_pin = 0x1; /* 1=examine FDX# pin */ + config->pad20_1 = 0x1F; + config->fc_priority_location = 0x1; /* 1=byte#31, 0=byte#19 */ + config->pad21_1 = 0x5; + + config->adaptive_ifs = nic->adaptive_ifs; + config->loopback = nic->loopback; + + if(nic->mii.force_media && nic->mii.full_duplex) + config->full_duplex_force = 0x1; /* 1=force, 0=auto */ + + if(nic->flags & promiscuous || nic->loopback) { + config->rx_save_bad_frames = 0x1; /* 1=save, 0=discard */ + config->rx_discard_short_frames = 0x0; /* 1=discard, 0=save */ + config->promiscuous_mode = 0x1; /* 1=on, 0=off */ + } + + if(nic->flags & multicast_all) + config->multicast_all = 0x1; /* 1=accept, 0=no */ + + if(!(nic->flags & wol_magic)) + config->magic_packet_disable = 0x1; /* 1=off, 0=on */ + + if(nic->mac >= mac_82558_D101_A4) { + config->fc_disable = 0x1; /* 1=Tx fc off, 0=Tx fc on */ + config->mwi_enable = 0x1; /* 1=enable, 0=disable */ + config->standard_tcb = 0x0; /* 1=standard, 0=extended */ + config->rx_long_ok = 0x1; /* 1=VLANs ok, 0=standard */ + if(nic->mac >= mac_82559_D101M) + config->tno_intr = 0x1; /* TCO stats enable */ + else + config->standard_stat_counter = 0x0; + } + + DPRINTK(HW, DEBUG, "[00-07]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]); + DPRINTK(HW, DEBUG, "[08-15]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + c[8], c[9], c[10], c[11], c[12], c[13], c[14], c[15]); + DPRINTK(HW, DEBUG, "[16-23]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23]); +} + +static void e100_setup_iaaddr(struct nic *nic, struct cb *cb, + struct sk_buff *skb) +{ + cb->command = cpu_to_le16(cb_iaaddr); + memcpy(cb->u.iaaddr, nic->netdev->dev_addr, ETH_ALEN); +} + +static void e100_dump(struct nic *nic, struct cb *cb, struct sk_buff *skb) +{ + cb->command = cpu_to_le16(cb_dump); + cb->u.dump_buffer_addr = cpu_to_le32(nic->dma_addr + + offsetof(struct mem, dump_buf)); +} + +#define NCONFIG_AUTO_SWITCH 0x0080 +#define MII_NSC_CONG MII_RESV1 +#define NSC_CONG_ENABLE 0x0100 +#define NSC_CONG_TXREADY 0x0400 +#define ADVERTISE_FC_SUPPORTED 0x0400 +static int e100_phy_init(struct nic *nic) +{ + struct net_device *netdev = nic->netdev; + u32 addr; + u16 bmcr, stat, id_lo, id_hi, cong; + + /* Discover phy addr by searching addrs in order {1,0,2,..., 31} */ + for(addr = 0; addr < 32; addr++) { + nic->mii.phy_id = (addr == 0) ? 1 : (addr == 1) ? 0 : addr; + bmcr = mdio_read(netdev, nic->mii.phy_id, MII_BMCR); + stat = mdio_read(netdev, nic->mii.phy_id, MII_BMSR); + stat = mdio_read(netdev, nic->mii.phy_id, MII_BMSR); + if(!((bmcr == 0xFFFF) || ((stat == 0) && (bmcr == 0)))) + break; + } + DPRINTK(HW, DEBUG, "phy_addr = %d\n", nic->mii.phy_id); + if(addr == 32) + return -EAGAIN; + + /* Selected the phy and isolate the rest */ + for(addr = 0; addr < 32; addr++) { + if(addr != nic->mii.phy_id) { + mdio_write(netdev, addr, MII_BMCR, BMCR_ISOLATE); + } else { + bmcr = mdio_read(netdev, addr, MII_BMCR); + mdio_write(netdev, addr, MII_BMCR, + bmcr & ~BMCR_ISOLATE); + } + } + + /* Get phy ID */ + id_lo = mdio_read(netdev, nic->mii.phy_id, MII_PHYSID1); + id_hi = mdio_read(netdev, nic->mii.phy_id, MII_PHYSID2); + nic->phy = (u32)id_hi << 16 | (u32)id_lo; + DPRINTK(HW, DEBUG, "phy ID = 0x%08X\n", nic->phy); + + /* Handle National tx phy */ + if(nic->phy == phy_nsc_tx) { + /* Disable congestion control */ + cong = mdio_read(netdev, nic->mii.phy_id, MII_NSC_CONG); + cong |= NSC_CONG_TXREADY; + cong &= ~NSC_CONG_ENABLE; + mdio_write(netdev, nic->mii.phy_id, MII_NSC_CONG, cong); + } + + if(nic->mac >= mac_82550_D102) + /* enable/disable MDI/MDI-X auto-switching */ + mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG, + nic->mii.force_media ? 0 : NCONFIG_AUTO_SWITCH); + + return 0; +} + +static int e100_hw_init(struct nic *nic) +{ + int err; + + e100_hw_reset(nic); + + DPRINTK(HW, ERR, "e100_hw_init\n"); + if(!in_interrupt() && (err = e100_self_test(nic))) + return err; + + if((err = e100_phy_init(nic))) + return err; + if((err = e100_exec_cmd(nic, cuc_load_base, 0))) + return err; + if((err = e100_exec_cmd(nic, ruc_load_base, 0))) + return err; + if((err = e100_exec_cb(nic, NULL, e100_configure))) + return err; + if((err = e100_exec_cb(nic, NULL, e100_setup_iaaddr))) + return err; + if((err = e100_exec_cmd(nic, cuc_dump_addr, + nic->dma_addr + offsetof(struct mem, stats)))) + return err; + if((err = e100_exec_cmd(nic, cuc_dump_reset, 0))) + return err; + + e100_disable_irq(nic); + + return 0; +} + +static void e100_multi(struct nic *nic, struct cb *cb, struct sk_buff *skb) +{ + struct net_device *netdev = nic->netdev; + struct dev_mc_list *list = netdev->mc_list; + u16 i, count = min(netdev->mc_count, E100_MAX_MULTICAST_ADDRS); + + cb->command = cpu_to_le16(cb_multi); + cb->u.multi.count = cpu_to_le16(count * ETH_ALEN); + for(i = 0; list && i < count; i++, list = list->next) + memcpy(&cb->u.multi.addr[i*ETH_ALEN], &list->dmi_addr, + ETH_ALEN); +} + +static void e100_set_multicast_list(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + + DPRINTK(HW, DEBUG, "mc_count=%d, flags=0x%04X\n", + netdev->mc_count, netdev->flags); + + if(netdev->flags & IFF_PROMISC) + nic->flags |= promiscuous; + else + nic->flags &= ~promiscuous; + + if(netdev->flags & IFF_ALLMULTI || + netdev->mc_count > E100_MAX_MULTICAST_ADDRS) + nic->flags |= multicast_all; + else + nic->flags &= ~multicast_all; + + e100_exec_cb(nic, NULL, e100_configure); + e100_exec_cb(nic, NULL, e100_multi); +} + +static void e100_update_stats(struct nic *nic) +{ + struct net_device_stats *ns = &nic->net_stats; + struct stats *s = &nic->mem->stats; + u32 *complete = (nic->mac < mac_82558_D101_A4) ? &s->fc_xmt_pause : + (nic->mac < mac_82559_D101M) ? (u32 *)&s->xmt_tco_frames : + &s->complete; + + /* Device's stats reporting may take several microseconds to + * complete, so where always waiting for results of the + * previous command. */ + + if(*complete == le32_to_cpu(0x0000A007)) { + *complete = 0; + nic->tx_frames = le32_to_cpu(s->tx_good_frames); + nic->tx_collisions = le32_to_cpu(s->tx_total_collisions); + ns->tx_aborted_errors += le32_to_cpu(s->tx_max_collisions); + ns->tx_window_errors += le32_to_cpu(s->tx_late_collisions); + ns->tx_carrier_errors += le32_to_cpu(s->tx_lost_crs); + ns->tx_fifo_errors += le32_to_cpu(s->tx_underruns); + ns->collisions += nic->tx_collisions; + ns->tx_errors += le32_to_cpu(s->tx_max_collisions) + + le32_to_cpu(s->tx_lost_crs); + ns->rx_dropped += le32_to_cpu(s->rx_resource_errors); + ns->rx_length_errors += le32_to_cpu(s->rx_short_frame_errors); + ns->rx_over_errors += le32_to_cpu(s->rx_resource_errors); + ns->rx_crc_errors += le32_to_cpu(s->rx_crc_errors); + ns->rx_frame_errors += le32_to_cpu(s->rx_alignment_errors); + ns->rx_fifo_errors += le32_to_cpu(s->rx_overrun_errors); + ns->rx_errors += le32_to_cpu(s->rx_crc_errors) + + le32_to_cpu(s->rx_alignment_errors) + + le32_to_cpu(s->rx_short_frame_errors) + + le32_to_cpu(s->rx_cdt_errors); + nic->tx_deferred += le32_to_cpu(s->tx_deferred); + nic->tx_single_collisions += + le32_to_cpu(s->tx_single_collisions); + nic->tx_multiple_collisions += + le32_to_cpu(s->tx_multiple_collisions); + if(nic->mac >= mac_82558_D101_A4) { + nic->tx_fc_pause += le32_to_cpu(s->fc_xmt_pause); + nic->rx_fc_pause += le32_to_cpu(s->fc_rcv_pause); + nic->rx_fc_unsupported += + le32_to_cpu(s->fc_rcv_unsupported); + if(nic->mac >= mac_82559_D101M) { + nic->tx_tco_frames += + le16_to_cpu(s->xmt_tco_frames); + nic->rx_tco_frames += + le16_to_cpu(s->rcv_tco_frames); + } + } + } + + e100_exec_cmd(nic, cuc_dump_reset, 0); +} + +static void e100_adjust_adaptive_ifs(struct nic *nic, int speed, int duplex) +{ + /* Adjust inter-frame-spacing (IFS) between two transmits if + * we're getting collisions on a half-duplex connection. */ + + if(duplex == DUPLEX_HALF) { + u32 prev = nic->adaptive_ifs; + u32 min_frames = (speed == SPEED_100) ? 1000 : 100; + + if((nic->tx_frames / 32 < nic->tx_collisions) && + (nic->tx_frames > min_frames)) { + if(nic->adaptive_ifs < 60) + nic->adaptive_ifs += 5; + } else if (nic->tx_frames < min_frames) { + if(nic->adaptive_ifs >= 5) + nic->adaptive_ifs -= 5; + } + if(nic->adaptive_ifs != prev) + e100_exec_cb(nic, NULL, e100_configure); + } +} + +static void e100_watchdog(unsigned long data) +{ + struct nic *nic = (struct nic *)data; + struct ethtool_cmd cmd; + + DPRINTK(TIMER, DEBUG, "right now = %ld\n", jiffies); + + /* mii library handles link maintenance tasks */ + + mii_ethtool_gset(&nic->mii, &cmd); + + if(mii_link_ok(&nic->mii) && !netif_carrier_ok(nic->netdev)) { + DPRINTK(LINK, INFO, "link up, %sMbps, %s-duplex\n", + cmd.speed == SPEED_100 ? "100" : "10", + cmd.duplex == DUPLEX_FULL ? "full" : "half"); + } else if(!mii_link_ok(&nic->mii) && netif_carrier_ok(nic->netdev)) { + DPRINTK(LINK, INFO, "link down\n"); + } + + mii_check_link(&nic->mii); + + /* Software generated interrupt to recover from (rare) Rx + * allocation failure */ + writeb(irq_sw_gen, &nic->csr->scb.cmd_hi); + e100_write_flush(nic); + + e100_update_stats(nic); + e100_adjust_adaptive_ifs(nic, cmd.speed, cmd.duplex); + + if(nic->mac <= mac_82557_D100_C) + /* Issue a multicast command to workaround a 557 lock up */ + e100_set_multicast_list(nic->netdev); + + mod_timer(&nic->watchdog, jiffies + E100_WATCHDOG_PERIOD); +} + +static inline void e100_xmit_prepare(struct nic *nic, struct cb *cb, + struct sk_buff *skb) +{ + cb->command = nic->tx_command; + cb->u.tcb.tbd_array = cb->dma_addr + offsetof(struct cb, u.tcb.tbd); + cb->u.tcb.tcb_byte_count = 0; + cb->u.tcb.threshold = nic->tx_threshold; + cb->u.tcb.tbd_count = 1; + cb->u.tcb.tbd.buf_addr = cpu_to_le32(pci_map_single(nic->pdev, + skb->data, skb->len, PCI_DMA_TODEVICE)); + cb->u.tcb.tbd.size = cpu_to_le16(skb->len); +} + +static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + int err = e100_exec_cb(nic, skb, e100_xmit_prepare); + + switch(err) { + case -ENOSPC: + /* We queued the skb, but now we're out of space. */ + netif_stop_queue(netdev); + break; + case -ENOMEM: + /* This is a hard error - log it. */ + DPRINTK(TX_ERR, DEBUG, "Out of Tx resources, returning skb\n"); + netif_stop_queue(netdev); + return 1; + } + + netdev->trans_start = jiffies; + return 0; +} + +static inline int e100_tx_clean(struct nic *nic) +{ + struct cb *cb; + int tx_cleaned = 0; + + spin_lock(&nic->cb_lock); + + DPRINTK(TX_DONE, DEBUG, "cb->status = 0x%04X\n", + nic->cb_to_clean->status); + + /* Clean CBs marked complete */ + for(cb = nic->cb_to_clean; + cb->status & cpu_to_le16(cb_complete); + cb = nic->cb_to_clean = cb->next) { + if(likely(cb->skb != NULL)) { + nic->net_stats.tx_packets++; + nic->net_stats.tx_bytes += cb->skb->len; + + pci_unmap_single(nic->pdev, + le32_to_cpu(cb->u.tcb.tbd.buf_addr), + le16_to_cpu(cb->u.tcb.tbd.size), + PCI_DMA_TODEVICE); + dev_kfree_skb_any(cb->skb); + tx_cleaned = 1; + } + cb->status = 0; + nic->cbs_avail++; + } + + spin_unlock(&nic->cb_lock); + + /* Recover from running out of Tx resources in xmit_frame */ + if(unlikely(tx_cleaned && netif_queue_stopped(nic->netdev))) + netif_wake_queue(nic->netdev); + + return tx_cleaned; +} + +static void e100_clean_cbs(struct nic *nic, int free_mem) +{ + if(nic->cbs) { + while(nic->cb_to_clean != nic->cb_to_use) { + struct cb *cb = nic->cb_to_clean; + if(cb->skb) { + pci_unmap_single(nic->pdev, + le32_to_cpu(cb->u.tcb.tbd.buf_addr), + le16_to_cpu(cb->u.tcb.tbd.size), + PCI_DMA_TODEVICE); + dev_kfree_skb(cb->skb); + } + nic->cb_to_clean = nic->cb_to_clean->next; + } + nic->cbs_avail = nic->params.cbs.count; + if(free_mem) { + pci_free_consistent(nic->pdev, + sizeof(struct cb) * nic->params.cbs.count, + nic->cbs, nic->cbs_dma_addr); + nic->cbs = NULL; + nic->cbs_avail = 0; + } + } + nic->cuc_cmd = cuc_start; + nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = + nic->cbs; +} + +static int e100_alloc_cbs(struct nic *nic) +{ + struct cb *cb; + unsigned int i, count = nic->params.cbs.count; + + nic->cuc_cmd = cuc_start; + nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = NULL; + nic->cbs_avail = 0; + + nic->cbs = pci_alloc_consistent(nic->pdev, + sizeof(struct cb) * count, &nic->cbs_dma_addr); + if(!nic->cbs) + return -ENOMEM; + + for(cb = nic->cbs, i = 0; i < count; cb++, i++) { + cb->next = (i + 1 < count) ? cb + 1 : nic->cbs; + cb->prev = (i == 0) ? nic->cbs + count - 1 : cb - 1; + + cb->dma_addr = nic->cbs_dma_addr + i * sizeof(struct cb); + cb->link = cpu_to_le32(nic->cbs_dma_addr + + ((i+1) % count) * sizeof(struct cb)); + } + + nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = nic->cbs; + nic->cbs_avail = count; + + return 0; +} + +static inline void e100_start_receiver(struct nic *nic) +{ + /* (Re)start RU if suspended or idle and RFA is fully allocated */ + struct rx_list *curr = + list_entry(nic->rx_list_head.next, struct rx_list, list); + if(curr->skb) { + u8 status = readb(&nic->csr->scb.status); + if(unlikely((status & rus_mask) != rus_ready)) + e100_exec_cmd(nic, ruc_start, curr->dma_addr); + } +} + +static inline int e100_rx_alloc_skb(struct nic *nic, struct rx_list *curr) +{ + unsigned int rx_offset = 2; /* u32 align protocol headers */ + + curr->dma_addr = 0; + curr->length = sizeof(struct rfd) + VLAN_ETH_FRAME_LEN; + + if(!(curr->skb = dev_alloc_skb(curr->length + rx_offset))) + return -ENOMEM; + + skb_reserve(curr->skb, rx_offset); + curr->skb->dev = nic->netdev; + curr->dma_addr = pci_map_single(nic->pdev, curr->skb->data, + curr->length, PCI_DMA_FROMDEVICE); + + return 0; +} + +static inline void e100_rx_rfa_add_tail(struct nic *nic, struct rx_list *curr) +{ + memcpy(curr->skb->data, &nic->blank_rfd, sizeof(struct rfd)); + pci_dma_sync_single(nic->pdev, curr->dma_addr, + sizeof(struct rfd), PCI_DMA_TODEVICE); + + if(likely(curr->list.prev != &nic->rx_list_head)) { + struct rx_list *prev = (struct rx_list *)curr->list.prev; + if(likely(prev->skb != NULL)) { + struct rfd *prev_rfd = (struct rfd *)prev->skb->data; + put_unaligned(cpu_to_le32(curr->dma_addr), + (u32 *)&prev_rfd->link); + prev_rfd->command = 0; + pci_dma_sync_single(nic->pdev, prev->dma_addr, + sizeof(struct rfd), PCI_DMA_TODEVICE); + } + } +} + +static inline int e100_rx_indicate(struct nic *nic, struct rx_list *curr, + unsigned int *work_done, unsigned int work_to_do) +{ + struct sk_buff *skb = curr->skb; + struct rfd *rfd = (struct rfd *)skb->data; + u16 rfd_status, actual_size; + + if(unlikely(work_done && *work_done >= work_to_do)) + return -EAGAIN; + + /* Need to sync before taking a peek at cb_complete bit */ + pci_dma_sync_single(nic->pdev, curr->dma_addr, + sizeof(struct rfd), PCI_DMA_FROMDEVICE); + rfd_status = le16_to_cpu(rfd->status); + + DPRINTK(RX_STATUS, DEBUG, "status=0x%04X\n", rfd_status); + + /* If data isn't ready, nothing to indicate */ + if(unlikely(!(rfd_status & cb_complete))) + return -EAGAIN; + + /* Get actual data size */ + actual_size = le16_to_cpu(rfd->actual_size) & 0x3FFF; + if(unlikely(actual_size > curr->length - sizeof(struct rfd))) + actual_size = curr->length - sizeof(struct rfd); + + /* Get data */ + pci_dma_sync_single(nic->pdev, curr->dma_addr, + sizeof(struct rfd) + actual_size, + PCI_DMA_FROMDEVICE); + pci_unmap_single(nic->pdev, curr->dma_addr, + curr->length, PCI_DMA_FROMDEVICE); + + /* Pull off the RFD and put the actual data (minus eth hdr) */ + skb_reserve(skb, sizeof(struct rfd)); + skb_put(skb, actual_size); + skb->protocol = eth_type_trans(skb, nic->netdev); + + if(unlikely(!(rfd_status & cb_ok)) || + actual_size > nic->netdev->mtu + VLAN_ETH_HLEN) { + /* Don't indicate if errors */ + dev_kfree_skb_any(skb); + } else { + nic->net_stats.rx_packets++; + nic->net_stats.rx_bytes += actual_size; + nic->netdev->last_rx = jiffies; +#ifdef CONFIG_E100_NAPI + netif_receive_skb(skb); +#else + netif_rx(skb); +#endif + if(work_done) + (*work_done)++; + } + + curr->length = 0; + curr->dma_addr = 0; + curr->skb = NULL; + + return 0; +} + +static inline void e100_rx_clean(struct nic *nic, unsigned int *work_done, + unsigned int work_to_do) +{ + struct list_head *list, *tmp; + struct rx_list *curr; + + /* Indicate newly arrived packets */ + list_for_each(list, &nic->rx_list_head) { + curr = list_entry(list, struct rx_list, list); + if(likely(curr->skb != NULL)) + if(e100_rx_indicate(nic, curr, work_done, work_to_do)) + break; + } + + /* Alloc new skbs to refill list */ + list_for_each_safe(list, tmp, &nic->rx_list_head) { + curr = list_entry(list, struct rx_list, list); + if(unlikely(curr->skb != NULL)) + break; /* List is full, done */ + if(unlikely(e100_rx_alloc_skb(nic, curr))) + break; /* Better luck next time (see watchdog) */ + list_del(&curr->list); + list_add_tail(&curr->list, &nic->rx_list_head); + e100_rx_rfa_add_tail(nic, curr); + } + + e100_start_receiver(nic); +} + +static void e100_rx_clean_list(struct nic *nic) +{ + struct list_head *list; + + if(!nic->rx_list) + return; + + list_for_each(list, &nic->rx_list_head) { + struct rx_list *curr = list_entry(list, + struct rx_list, list); + if(curr->skb) { + pci_unmap_single(nic->pdev, curr->dma_addr, + curr->length, PCI_DMA_FROMDEVICE); + dev_kfree_skb(curr->skb); + } + } + + kfree(nic->rx_list); + nic->rx_list = NULL; +} + +static int e100_rx_alloc_list(struct nic *nic) +{ + struct rx_list *curr; + unsigned int i, count = nic->params.rfds.count; + + INIT_LIST_HEAD(&nic->rx_list_head); + + if(!(nic->rx_list = kmalloc(sizeof(struct rx_list)*count, GFP_ATOMIC))) + return -ENOMEM; + + for(curr = nic->rx_list, i = 0; i < count; curr++, i++) { + if(e100_rx_alloc_skb(nic, curr)) { + e100_rx_clean_list(nic); + return -ENOMEM; + } + list_add_tail(&curr->list, &nic->rx_list_head); + e100_rx_rfa_add_tail(nic, curr); + } + + return 0; +} + +static irqreturn_t e100_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *netdev = dev_id; + struct nic *nic = netdev->priv; + u8 stat_ack = readb(&nic->csr->scb.stat_ack); + + DPRINTK(INTR, DEBUG, "stat_ack = 0x%02X\n", stat_ack); + + if(stat_ack == 0x00 || /* Not our interrupt */ + stat_ack == 0xFF) /* Hardware is ejected (cardbus, hotswap) */ + return IRQ_NONE; + + /* Ack interrupts */ + writeb(stat_ack, &nic->csr->scb.stat_ack); + e100_write_flush(nic); + +#ifdef CONFIG_E100_NAPI + e100_disable_irq(nic); + netif_rx_schedule(netdev); +#else + if(stat_ack & stat_ack_rx) + e100_rx_clean(nic, NULL, 0); + if(stat_ack & stat_ack_tx) + e100_tx_clean(nic); +#endif + + return IRQ_HANDLED; +} + +#ifdef CONFIG_E100_NAPI +static int e100_poll(struct net_device *netdev, int *budget) +{ + struct nic *nic = netdev->priv; + unsigned int work_to_do = min(netdev->quota, *budget); + unsigned int work_done = 0; + int tx_cleaned; + + e100_rx_clean(nic, &work_done, work_to_do); + tx_cleaned = e100_tx_clean(nic); + + /* If no Rx and Tx cleanup work was done, exit polling mode. */ + if((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) { + netif_rx_complete(netdev); + e100_enable_irq(nic); + return 0; + } + + *budget -= work_done; + netdev->quota -= work_done; + + return 1; +} +#endif + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void e100_netpoll(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + e100_disable_irq(nic); + e100_intr(nic->pdev->irq, netdev, NULL); + e100_enable_irq(nic); +} +#endif + +static struct net_device_stats *e100_get_stats(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + return &nic->net_stats; +} + +static int e100_set_mac_address(struct net_device *netdev, void *p) +{ + struct nic *nic = netdev->priv; + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + e100_exec_cb(nic, NULL, e100_setup_iaaddr); + + return 0; +} + +static int e100_change_mtu(struct net_device *netdev, int new_mtu) +{ + if(new_mtu < ETH_ZLEN || new_mtu > ETH_DATA_LEN) + return -EINVAL; + netdev->mtu = new_mtu; + return 0; +} + +static int e100_asf(struct nic *nic) +{ + /* ASF can be enabled from eeprom */ + return((nic->pdev->device >= 0x1050) && (nic->pdev->device <= 0x1055) && + (nic->eeprom[eeprom_config_asf] & eeprom_asf) && + !(nic->eeprom[eeprom_config_asf] & eeprom_gcl) && + ((nic->eeprom[eeprom_smbus_addr] & 0xFF) != 0xFE)); +} + +static int e100_up(struct nic *nic) +{ + int err; + + if((err = e100_rx_alloc_list(nic))) + return err; + if((err = e100_alloc_cbs(nic))) + goto err_rx_clean_list; + if((err = e100_hw_init(nic))) + goto err_clean_cbs; + e100_set_multicast_list(nic->netdev); + e100_start_receiver(nic); + netif_start_queue(nic->netdev); + mod_timer(&nic->watchdog, jiffies); + if((err = request_irq(nic->pdev->irq, e100_intr, SA_SHIRQ, + nic->netdev->name, nic->netdev))) + goto err_no_irq; + e100_enable_irq(nic); + return 0; + +err_no_irq: + del_timer_sync(&nic->watchdog); + netif_stop_queue(nic->netdev); +err_clean_cbs: + e100_clean_cbs(nic, 1); +err_rx_clean_list: + e100_rx_clean_list(nic); + return err; +} + +static void e100_down(struct nic *nic) +{ + e100_disable_irq(nic); + free_irq(nic->pdev->irq, nic->netdev); + del_timer_sync(&nic->watchdog); + netif_carrier_off(nic->netdev); + netif_stop_queue(nic->netdev); + e100_clean_cbs(nic, 1); + e100_rx_clean_list(nic); +} + +static void e100_tx_timeout(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + + DPRINTK(TX_ERR, DEBUG, "scb.status=0x%02X\n", + readb(&nic->csr->scb.status)); + e100_down(netdev->priv); + e100_up(netdev->priv); +} + +static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode) +{ + int err; + struct sk_buff *skb; + struct rx_list *rx; + + /* Use driver resources to perform internal MAC or PHY + * loopback test. A single packet is prepared and transmitted + * in loopback mode, and the test passes if the received + * packet compares byte-for-byte to the transmitted packet. */ + + if((err = e100_rx_alloc_list(nic))) + return err; + if((err = e100_alloc_cbs(nic))) + goto err_clean_rx; + + /* ICH PHY loopback is broken so do MAC loopback instead */ + if(nic->flags & ich && loopback_mode == lb_phy) + loopback_mode = lb_mac; + + nic->loopback = loopback_mode; + if((err = e100_hw_init(nic))) + goto err_loopback_none; + + if(loopback_mode == lb_phy) + mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR, + BMCR_LOOPBACK); + + e100_start_receiver(nic); + + if(!(skb = dev_alloc_skb(ETH_DATA_LEN))) { + err = -ENOMEM; + goto err_loopback_none; + } + skb_put(skb, ETH_DATA_LEN); + memset(skb->data, 0xFF, ETH_DATA_LEN); + e100_xmit_frame(skb, nic->netdev); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ / 100 + 1); + + rx = list_entry(nic->rx_list_head.next, struct rx_list, list); + if(memcmp(rx->skb->data + sizeof(struct rfd), skb->data, ETH_DATA_LEN)) + err = -EAGAIN; + +err_loopback_none: + mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR, 0); + nic->loopback = lb_none; + e100_hw_init(nic); + e100_clean_cbs(nic, 1); +err_clean_rx: + e100_rx_clean_list(nic); + return err; +} + +#define MII_LED_CONTROL 0x1B +static void e100_blink_led(unsigned long data) +{ + struct nic *nic = (struct nic *)data; + enum led_state { + led_on = 0x01, + led_off = 0x04, + led_on_559 = 0x05, + led_on_557 = 0x07, + }; + + nic->leds = (nic->leds & led_on) ? led_off : + (nic->mac < mac_82559_D101M) ? led_on_557 : led_on_559; + mdio_write(nic->netdev, nic->mii.phy_id, MII_LED_CONTROL, nic->leds); + mod_timer(&nic->blink_timer, jiffies + HZ / 4); +} + +static int e100_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd) +{ + struct nic *nic = netdev->priv; + return mii_ethtool_gset(&nic->mii, cmd); +} + +static int e100_set_settings(struct net_device *netdev, struct ethtool_cmd *cmd) +{ + struct nic *nic = netdev->priv; + int err; + + mdio_write(netdev, nic->mii.phy_id, MII_BMCR, BMCR_RESET); + err = mii_ethtool_sset(&nic->mii, cmd); + e100_exec_cb(nic, NULL, e100_configure); + + return err; +} + +static void e100_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *info) +{ + struct nic *nic = netdev->priv; + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); + strcpy(info->fw_version, "N/A"); + strcpy(info->bus_info, pci_name(nic->pdev)); +} + +static int e100_get_regs_len(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; +#define E100_PHY_REGS 0x1C +#define E100_REGS_LEN 1 + E100_PHY_REGS + \ + sizeof(nic->mem->dump_buf) / sizeof(u32) + return E100_REGS_LEN * sizeof(u32); +} + +static void e100_get_regs(struct net_device *netdev, + struct ethtool_regs *regs, void *p) +{ + struct nic *nic = netdev->priv; + u32 *buff = p; + int i; + + regs->version = (1 << 24) | nic->rev_id; + buff[0] = readb(&nic->csr->scb.cmd_hi) << 24 | + readb(&nic->csr->scb.cmd_lo) << 16 | + readw(&nic->csr->scb.status); + for(i = E100_PHY_REGS; i >= 0; i--) + buff[1 + E100_PHY_REGS - i] = + mdio_read(netdev, nic->mii.phy_id, i); + memset(nic->mem->dump_buf, 0, sizeof(nic->mem->dump_buf)); + e100_exec_cb(nic, NULL, e100_dump); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ / 100 + 1); + memcpy(&buff[2 + E100_PHY_REGS], nic->mem->dump_buf, + sizeof(nic->mem->dump_buf)); +} + +static void e100_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) +{ + struct nic *nic = netdev->priv; + wol->supported = (nic->mac >= mac_82558_D101_A4) ? WAKE_MAGIC : 0; + wol->wolopts = (nic->flags & wol_magic) ? WAKE_MAGIC : 0; +} + +static int e100_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) +{ + struct nic *nic = netdev->priv; + + if(wol->wolopts != WAKE_MAGIC && wol->wolopts != 0) + return -EOPNOTSUPP; + + if(wol->wolopts) + nic->flags |= wol_magic; + else + nic->flags &= ~wol_magic; + + pci_enable_wake(nic->pdev, 0, nic->flags & (wol_magic | e100_asf(nic))); + e100_exec_cb(nic, NULL, e100_configure); + + return 0; +} + +static u32 e100_get_msglevel(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + return nic->msg_enable; +} + +static void e100_set_msglevel(struct net_device *netdev, u32 value) +{ + struct nic *nic = netdev->priv; + nic->msg_enable = value; +} + +static int e100_nway_reset(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + return mii_nway_restart(&nic->mii); +} + +static u32 e100_get_link(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + return mii_link_ok(&nic->mii); +} + +static int e100_get_eeprom_len(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + return nic->eeprom_wc << 1; +} + +#define E100_EEPROM_MAGIC 0x1234 +static int e100_get_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *bytes) +{ + struct nic *nic = netdev->priv; + + eeprom->magic = E100_EEPROM_MAGIC; + memcpy(bytes, &((u8 *)nic->eeprom)[eeprom->offset], eeprom->len); + + return 0; +} + +static int e100_set_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *bytes) +{ + struct nic *nic = netdev->priv; + + if(eeprom->magic != E100_EEPROM_MAGIC) + return -EINVAL; + memcpy(&((u8 *)nic->eeprom)[eeprom->offset], bytes, eeprom->len); + + return e100_eeprom_save(nic, eeprom->offset >> 1, + (eeprom->len >> 1) + 1); +} + +static void e100_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct nic *nic = netdev->priv; + struct param_range *rfds = &nic->params.rfds; + struct param_range *cbs = &nic->params.cbs; + + ring->rx_max_pending = rfds->max; + ring->tx_max_pending = cbs->max; + ring->rx_mini_max_pending = 0; + ring->rx_jumbo_max_pending = 0; + ring->rx_pending = rfds->count; + ring->tx_pending = cbs->count; + ring->rx_mini_pending = 0; + ring->rx_jumbo_pending = 0; +} + +static int e100_set_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct nic *nic = netdev->priv; + struct param_range *rfds = &nic->params.rfds; + struct param_range *cbs = &nic->params.cbs; + + if(netif_running(netdev)) + e100_down(nic); + rfds->count = max(ring->rx_pending, rfds->min); + rfds->count = min(rfds->count, rfds->max); + cbs->count = max(ring->tx_pending, cbs->min); + cbs->count = min(cbs->count, cbs->max); + if(netif_running(netdev)) + e100_up(nic); + + return 0; +} + +static char e100_gstrings_test[][ETH_GSTRING_LEN] = { + "Link test (on/offline)", + "Eeprom test (on/offline)", + "Self test (offline)", + "Mac loopback (offline)", + "Phy loopback (offline)", +}; +#define E100_TEST_LEN sizeof(e100_gstrings_test) / ETH_GSTRING_LEN + +static int e100_diag_test_count(struct net_device *netdev) +{ + return E100_TEST_LEN; +} + +static void e100_diag_test(struct net_device *netdev, + struct ethtool_test *test, u64 *data) +{ + struct nic *nic = netdev->priv; + int i; + + memset(data, 0, E100_TEST_LEN * sizeof(u64)); + data[0] = !mii_link_ok(&nic->mii); + data[1] = e100_eeprom_load(nic); + if(test->flags & ETH_TEST_FL_OFFLINE) { + if(netif_running(netdev)) + e100_down(nic); + data[2] = e100_self_test(nic); + data[3] = e100_loopback_test(nic, lb_mac); + data[4] = e100_loopback_test(nic, lb_phy); + if(netif_running(netdev)) + e100_up(nic); + } + for(i = 0; i < E100_TEST_LEN; i++) + test->flags |= data[i] ? ETH_TEST_FL_FAILED : 0; +} + +static int e100_phys_id(struct net_device *netdev, u32 data) +{ + struct nic *nic = netdev->priv; + + if(!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)) + data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ); + mod_timer(&nic->blink_timer, jiffies); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(data * HZ); + del_timer_sync(&nic->blink_timer); + mdio_write(netdev, nic->mii.phy_id, MII_LED_CONTROL, 0); + + return 0; +} + +static char e100_gstrings_stats[][ETH_GSTRING_LEN] = { + "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", + "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions", + "rx_length_errors", "rx_over_errors", "rx_crc_errors", + "rx_frame_errors", "rx_fifo_errors", "rx_missed_errors", + "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors", + "tx_heartbeat_errors", "tx_window_errors", + /* device-specific stats */ + "tx_deferred", "tx_single_collisions", "tx_multi_collisions", + "tx_flow_control_pause", "rx_flow_control_pause", + "rx_flow_control_unsupported", "tx_tco_packets", "rx_tco_packets", +}; +#define E100_NET_STATS_LEN 21 +#define E100_STATS_LEN sizeof(e100_gstrings_stats) / ETH_GSTRING_LEN + +static int e100_get_stats_count(struct net_device *netdev) +{ + return E100_STATS_LEN; +} + +static void e100_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) +{ + struct nic *nic = netdev->priv; + int i; + + for(i = 0; i < E100_NET_STATS_LEN; i++) + data[i] = ((unsigned long *)&nic->net_stats)[i]; + + data[i++] = nic->tx_deferred; + data[i++] = nic->tx_single_collisions; + data[i++] = nic->tx_multiple_collisions; + data[i++] = nic->tx_fc_pause; + data[i++] = nic->rx_fc_pause; + data[i++] = nic->rx_fc_unsupported; + data[i++] = nic->tx_tco_frames; + data[i++] = nic->rx_tco_frames; +} + +static void e100_get_strings(struct net_device *netdev, u32 stringset, u8 *data) +{ + switch(stringset) { + case ETH_SS_TEST: + memcpy(data, *e100_gstrings_test, sizeof(e100_gstrings_test)); + break; + case ETH_SS_STATS: + memcpy(data, *e100_gstrings_stats, sizeof(e100_gstrings_stats)); + break; + } +} + +static struct ethtool_ops e100_ethtool_ops = { + .get_settings = e100_get_settings, + .set_settings = e100_set_settings, + .get_drvinfo = e100_get_drvinfo, + .get_regs_len = e100_get_regs_len, + .get_regs = e100_get_regs, + .get_wol = e100_get_wol, + .set_wol = e100_set_wol, + .get_msglevel = e100_get_msglevel, + .set_msglevel = e100_set_msglevel, + .nway_reset = e100_nway_reset, + .get_link = e100_get_link, + .get_eeprom_len = e100_get_eeprom_len, + .get_eeprom = e100_get_eeprom, + .set_eeprom = e100_set_eeprom, + .get_ringparam = e100_get_ringparam, + .set_ringparam = e100_set_ringparam, + .self_test_count = e100_diag_test_count, + .self_test = e100_diag_test, + .get_strings = e100_get_strings, + .phys_id = e100_phys_id, + .get_stats_count = e100_get_stats_count, + .get_ethtool_stats = e100_get_ethtool_stats, +}; + +static int e100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + struct nic *nic = netdev->priv; + struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&ifr->ifr_data; + + return generic_mii_ioctl(&nic->mii, mii, cmd, NULL); +} + +static int e100_alloc(struct nic *nic) +{ + nic->mem = pci_alloc_consistent(nic->pdev, sizeof(struct mem), + &nic->dma_addr); + return nic->mem ? 0 : -ENOMEM; +} + +static void e100_free(struct nic *nic) +{ + if(nic->mem) { + pci_free_consistent(nic->pdev, sizeof(struct mem), + nic->mem, nic->dma_addr); + nic->mem = NULL; + } +} + +static int e100_open(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + int err = 0; + + netif_carrier_off(netdev); + if((err = e100_up(nic))) + DPRINTK(IFUP, ERR, "Cannot open interface, aborting.\n"); + return err; +} + +static int e100_close(struct net_device *netdev) +{ + e100_down(netdev->priv); + return 0; +} + +static int __devinit e100_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *netdev; + struct nic *nic; + int err; + + if(!(netdev = alloc_etherdev(sizeof(struct nic)))) { + if(((1 << debug) - 1) & NETIF_MSG_PROBE) + printk(KERN_ERR PFX "Etherdev alloc failed, abort.\n"); + return -ENOMEM; + } + + netdev->open = e100_open; + netdev->stop = e100_close; + netdev->hard_start_xmit = e100_xmit_frame; + netdev->get_stats = e100_get_stats; + netdev->set_multicast_list = e100_set_multicast_list; + netdev->set_mac_address = e100_set_mac_address; + netdev->change_mtu = e100_change_mtu; + netdev->do_ioctl = e100_do_ioctl; + SET_ETHTOOL_OPS(netdev, &e100_ethtool_ops); + netdev->tx_timeout = e100_tx_timeout; + netdev->watchdog_timeo = E100_WATCHDOG_PERIOD; +#ifdef CONFIG_E100_NAPI + netdev->poll = e100_poll; + netdev->weight = E100_NAPI_WEIGHT; +#endif +#ifdef CONFIG_NET_POLL_CONTROLLER + netdev->poll_controller = e100_netpoll; +#endif + + nic = netdev->priv; + nic->netdev = netdev; + nic->pdev = pdev; + nic->msg_enable = (1 << debug) - 1; + pci_set_drvdata(pdev, netdev); + + if((err = pci_enable_device(pdev))) { + DPRINTK(PROBE, ERR, "Cannot enable PCI device, aborting.\n"); + goto err_out_free_dev; + } + + if(!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { + DPRINTK(PROBE, ERR, "Cannot find proper PCI device " + "base address, aborting.\n"); + err = -ENODEV; + goto err_out_disable_pdev; + } + + if((err = pci_request_regions(pdev, DRV_NAME))) { + DPRINTK(PROBE, ERR, "Cannot obtain PCI resources, aborting.\n"); + goto err_out_disable_pdev; + } + + pci_set_master(pdev); + + if((err = pci_set_dma_mask(pdev, 0xFFFFFFFFULL))) { + DPRINTK(PROBE, ERR, "No usable DMA configuration, aborting.\n"); + goto err_out_free_res; + } + + SET_MODULE_OWNER(netdev); + SET_NETDEV_DEV(netdev, &pdev->dev); + + nic->csr = ioremap(pci_resource_start(pdev, 0), sizeof(struct csr)); + if(!nic->csr) { + DPRINTK(PROBE, ERR, "Cannot map device registers, aborting.\n"); + err = -ENOMEM; + goto err_out_free_res; + } + + if(ent->driver_data) + nic->flags |= ich; + else + nic->flags &= ~ich; + + spin_lock_init(&nic->cb_lock); + spin_lock_init(&nic->cmd_lock); + + init_timer(&nic->watchdog); + nic->watchdog.function = e100_watchdog; + nic->watchdog.data = (unsigned long)nic; + init_timer(&nic->blink_timer); + nic->blink_timer.function = e100_blink_led; + nic->blink_timer.data = (unsigned long)nic; + + if((err = e100_alloc(nic))) { + DPRINTK(PROBE, ERR, "Cannot alloc driver memory, aborting.\n"); + goto err_out_iounmap; + } + + e100_get_defaults(nic); + e100_hw_reset(nic); + e100_phy_init(nic); + + if((err = e100_eeprom_load(nic))) + goto err_out_free; + ((u16 *)netdev->dev_addr)[0] = le16_to_cpu(nic->eeprom[0]); + ((u16 *)netdev->dev_addr)[1] = le16_to_cpu(nic->eeprom[1]); + ((u16 *)netdev->dev_addr)[2] = le16_to_cpu(nic->eeprom[2]); + if(!is_valid_ether_addr(netdev->dev_addr)) { + DPRINTK(PROBE, ERR, "Invalid MAC address from " + "EEPROM, aborting.\n"); + err = -EAGAIN; + goto err_out_free; + } + + /* Wol magic packet can be enabled from eeprom */ + if((nic->mac >= mac_82558_D101_A4) && + (nic->eeprom[eeprom_id] & eeprom_id_wol)) + nic->flags |= wol_magic; + + pci_enable_wake(pdev, 0, nic->flags & (wol_magic | e100_asf(nic))); + + if((err = register_netdev(netdev))) { + DPRINTK(PROBE, ERR, "Cannot register net device, aborting.\n"); + goto err_out_free; + } + + DPRINTK(PROBE, INFO, "addr 0x%lx, irq %d, " + "MAC addr %02X:%02X:%02X:%02X:%02X:%02X\n", + pci_resource_start(pdev, 0), pdev->irq, + netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], + netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]); + + return 0; + +err_out_free: + e100_free(nic); +err_out_iounmap: + iounmap(nic->csr); +err_out_free_res: + pci_release_regions(pdev); +err_out_disable_pdev: + pci_disable_device(pdev); +err_out_free_dev: + pci_set_drvdata(pdev, NULL); + free_netdev(netdev); + return err; +} + +static void __devexit e100_remove(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + + if(netdev) { + struct nic *nic = netdev->priv; + unregister_netdev(netdev); + e100_free(nic); + iounmap(nic->csr); + free_netdev(netdev); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + } +} + +#ifdef CONFIG_PM +static int e100_suspend(struct pci_dev *pdev, u32 state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct nic *nic = netdev->priv; + + if(netif_running(netdev)) + e100_down(nic); + e100_hw_reset(nic); + netif_device_detach(netdev); + + pci_save_state(pdev, nic->pm_state); + pci_enable_wake(pdev, state, nic->flags & (wol_magic | e100_asf(nic))); + pci_disable_device(pdev); + pci_set_power_state(pdev, state); + + return 0; +} + +static int e100_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct nic *nic = netdev->priv; + + pci_set_power_state(pdev, 0); + pci_restore_state(pdev, nic->pm_state); + e100_hw_init(nic); + + netif_device_attach(netdev); + if(netif_running(netdev)) + e100_up(nic); + + return 0; +} +#endif + +static struct pci_driver e100_driver = { + .name = DRV_NAME, + .id_table = e100_id_table, + .probe = e100_probe, + .remove = __devexit_p(e100_remove), +#ifdef CONFIG_PM + .suspend = e100_suspend, + .resume = e100_resume, +#endif +}; + +static int __init e100_init_module(void) +{ + if(((1 << debug) - 1) & NETIF_MSG_DRV) { + printk(KERN_INFO PFX "%s, %s\n", DRV_DESCRIPTION, DRV_VERSION); + printk(KERN_INFO PFX "%s\n", DRV_COPYRIGHT); + } + return pci_module_init(&e100_driver); +} + +static void __exit e100_cleanup_module(void) +{ + pci_unregister_driver(&e100_driver); +} + +module_init(e100_init_module); +module_exit(e100_cleanup_module); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/e1000/e1000.h 830-ivtv/drivers/net/e1000/e1000.h --- 000-virgin/drivers/net/e1000/e1000.h Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/e1000/e1000.h Thu Jan 8 08:54:15 2004 @@ -92,6 +92,16 @@ struct e1000_adapter; #define E1000_MAX_INTR 10 +/* How many descriptors for TX and RX ? */ +#define E1000_DEFAULT_TXD 256 +#define E1000_MAX_TXD 256 +#define E1000_MIN_TXD 80 +#define E1000_MAX_82544_TXD 4096 +#define E1000_DEFAULT_RXD 256 +#define E1000_MAX_RXD 256 +#define E1000_MIN_RXD 80 +#define E1000_MAX_82544_RXD 4096 + /* Supported Rx Buffer Sizes */ #define E1000_RXBUFFER_2048 2048 #define E1000_RXBUFFER_4096 4096 diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/e1000/e1000_ethtool.c 830-ivtv/drivers/net/e1000/e1000_ethtool.c --- 000-virgin/drivers/net/e1000/e1000_ethtool.c Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/e1000/e1000_ethtool.c Thu Jan 8 08:54:15 2004 @@ -39,6 +39,10 @@ extern int e1000_up(struct e1000_adapter extern void e1000_down(struct e1000_adapter *adapter); extern void e1000_reset(struct e1000_adapter *adapter); extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx); +extern int e1000_setup_rx_resources(struct e1000_adapter *adapter); +extern int e1000_setup_tx_resources(struct e1000_adapter *adapter); +extern void e1000_free_rx_resources(struct e1000_adapter *adapter); +extern void e1000_free_tx_resources(struct e1000_adapter *adapter); struct e1000_stats { char stat_string[ETH_GSTRING_LEN]; @@ -440,6 +444,71 @@ seeprom_error: return ret_val; } +static int +e1000_ethtool_gring(struct e1000_adapter *adapter, + struct ethtool_ringparam *ring) +{ + e1000_mac_type mac_type = adapter->hw.mac_type; + struct e1000_desc_ring *txdr = &adapter->tx_ring; + struct e1000_desc_ring *rxdr = &adapter->rx_ring; + + ring->rx_max_pending = (mac_type < e1000_82544) ? E1000_MAX_RXD : + E1000_MAX_82544_RXD; + ring->tx_max_pending = (mac_type < e1000_82544) ? E1000_MAX_TXD : + E1000_MAX_82544_TXD; + ring->rx_mini_max_pending = 0; + ring->rx_jumbo_max_pending = 0; + ring->rx_pending = rxdr->count; + ring->tx_pending = txdr->count; + ring->rx_mini_pending = 0; + ring->rx_jumbo_pending = 0; + + return 0; +} +static int +e1000_ethtool_sring(struct e1000_adapter *adapter, + struct ethtool_ringparam *ring) +{ + int err; + e1000_mac_type mac_type = adapter->hw.mac_type; + struct e1000_desc_ring *txdr = &adapter->tx_ring; + struct e1000_desc_ring *rxdr = &adapter->rx_ring; + + if(netif_running(adapter->netdev)) { + e1000_down(adapter); + e1000_free_rx_resources(adapter); + e1000_free_tx_resources(adapter); + } + + rxdr->count = max(ring->rx_pending,(uint32_t)E1000_MIN_RXD); + rxdr->count = min(rxdr->count,(uint32_t)(mac_type < e1000_82544 ? + E1000_MAX_RXD : E1000_MAX_82544_RXD)); + E1000_ROUNDUP(rxdr->count, REQ_RX_DESCRIPTOR_MULTIPLE); + + txdr->count = max(ring->tx_pending,(uint32_t)E1000_MIN_TXD); + txdr->count = min(txdr->count,(uint32_t)(mac_type < e1000_82544 ? + E1000_MAX_TXD : E1000_MAX_82544_TXD)); + E1000_ROUNDUP(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE); + + if(netif_running(adapter->netdev)) { + if((err = e1000_setup_rx_resources(adapter))) + goto err_setup_rx; + if((err = e1000_setup_tx_resources(adapter))) + goto err_setup_tx; + if((err = e1000_up(adapter))) + goto err_up; + } + + return 0; +err_up: + e1000_free_tx_resources(adapter); +err_setup_tx: + e1000_free_rx_resources(adapter); +err_setup_rx: + e1000_reset(adapter); + return err; +} + #define REG_PATTERN_TEST(R, M, W) \ { \ uint32_t pat, value; \ @@ -579,8 +648,8 @@ e1000_intr_test(struct e1000_adapter *ad *data = 0; /* Hook up test interrupt handler just for this test */ - if(request_irq - (netdev->irq, &e1000_test_intr, SA_SHIRQ, netdev->name, netdev)) { + if(request_irq(adapter->pdev->irq, &e1000_test_intr, SA_SHIRQ, + netdev->name, netdev)) { *data = 1; return -1; } @@ -664,7 +733,7 @@ e1000_intr_test(struct e1000_adapter *ad msec_delay(10); /* Unhook test interrupt handler */ - free_irq(netdev->irq, netdev); + free_irq(adapter->pdev->irq, netdev); return *data; } @@ -770,9 +839,9 @@ e1000_setup_desc_rings(struct e1000_adap PCI_DMA_TODEVICE); tx_desc->buffer_addr = cpu_to_le64(txdr->buffer_info[i].dma); tx_desc->lower.data = cpu_to_le32(skb->len); - tx_desc->lower.data |= E1000_TXD_CMD_EOP; - tx_desc->lower.data |= E1000_TXD_CMD_IFCS; - tx_desc->lower.data |= E1000_TXD_CMD_RPS; + tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP | + E1000_TXD_CMD_IFCS | + E1000_TXD_CMD_RPS); tx_desc->upper.data = 0; } @@ -1501,6 +1570,19 @@ err_geeprom_ioctl: addr += offsetof(struct ethtool_eeprom, data); return e1000_ethtool_seeprom(adapter, &eeprom, addr); + } + case ETHTOOL_GRINGPARAM: { + struct ethtool_ringparam ering = {ETHTOOL_GRINGPARAM}; + e1000_ethtool_gring(adapter, &ering); + if(copy_to_user(addr, &ering, sizeof(ering))) + return -EFAULT; + return 0; + } + case ETHTOOL_SRINGPARAM: { + struct ethtool_ringparam ering; + if(copy_from_user(&ering, addr, sizeof(ering))) + return -EFAULT; + return e1000_ethtool_sring(adapter, &ering); } case ETHTOOL_GPAUSEPARAM: { struct ethtool_pauseparam epause = {ETHTOOL_GPAUSEPARAM}; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/e1000/e1000_hw.c 830-ivtv/drivers/net/e1000/e1000_hw.c --- 000-virgin/drivers/net/e1000/e1000_hw.c Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/e1000/e1000_hw.c Thu Jan 8 08:54:15 2004 @@ -96,8 +96,14 @@ e1000_set_phy_type(struct e1000_hw *hw) hw->phy_type = e1000_phy_m88; break; case IGP01E1000_I_PHY_ID: - hw->phy_type = e1000_phy_igp; - break; + if(hw->mac_type == e1000_82541 || + hw->mac_type == e1000_82541_rev_2 || + hw->mac_type == e1000_82547 || + hw->mac_type == e1000_82547_rev_2) { + hw->phy_type = e1000_phy_igp; + break; + } + /* Fall Through */ default: /* Should never have loaded on this device */ hw->phy_type = e1000_phy_undefined; @@ -148,7 +154,6 @@ e1000_phy_init_script(struct e1000_hw *h e1000_write_phy_reg(hw, 0x0000, 0x3300); - if(hw->mac_type == e1000_82547) { uint16_t fused, fine, coarse; @@ -1485,8 +1490,8 @@ e1000_phy_force_speed_duplex(struct e100 if(mii_status_reg & MII_SR_LINK_STATUS) break; msec_delay(100); } - if(i == 0) { /* We didn't get link */ - /* Reset the DSP and wait again for link. */ + if((i == 0) && (hw->phy_type == e1000_phy_m88)) { + /* We didn't get link. Reset the DSP and wait again for link. */ if((ret_val = e1000_phy_reset_dsp(hw))) { DEBUGOUT("Error Resetting PHY DSP\n"); return ret_val; @@ -1533,6 +1538,25 @@ e1000_phy_force_speed_duplex(struct e100 phy_data))) return ret_val; + /* Polarity reversal workaround for forced 10F/10H links. */ + if(hw->mac_type <= e1000_82544 && + (hw->forced_speed_duplex == e1000_10_full || + hw->forced_speed_duplex == e1000_10_half)) { + if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, + 0x0019))) + return ret_val; + if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, + 0x8F0F))) + return ret_val; + /* IEEE requirement is 150ms */ + msec_delay(200); + if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, + 0x0019))) + return ret_val; + if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, + 0x8F00))) + return ret_val; + } } return E1000_SUCCESS; } @@ -1916,7 +1940,6 @@ e1000_check_for_link(struct e1000_hw *hw uint32_t signal = 0; int32_t ret_val; uint16_t phy_data; - uint16_t lp_capability; DEBUGFUNC("e1000_check_for_link"); @@ -1996,24 +2019,17 @@ e1000_check_for_link(struct e1000_hw *hw /* At this point we know that we are on copper and we have * auto-negotiated link. These are conditions for checking the link - * parter capability register. We use the link partner capability to - * determine if TBI Compatibility needs to be turned on or off. If - * the link partner advertises any speed in addition to Gigabit, then - * we assume that they are GMII-based, and TBI compatibility is not - * needed. If no other speeds are advertised, we assume the link - * partner is TBI-based, and we turn on TBI Compatibility. - */ - if(hw->tbi_compatibility_en) { - if((ret_val = e1000_read_phy_reg(hw, PHY_LP_ABILITY, - &lp_capability))) - return ret_val; - if(lp_capability & (NWAY_LPAR_10T_HD_CAPS | - NWAY_LPAR_10T_FD_CAPS | - NWAY_LPAR_100TX_HD_CAPS | - NWAY_LPAR_100TX_FD_CAPS | - NWAY_LPAR_100T4_CAPS)) { - /* If our link partner advertises anything in addition to - * gigabit, we do not need to enable TBI compatibility. + * partner capability register. We use the link speed to determine if + * TBI compatibility needs to be turned on or off. If the link is not + * at gigabit speed, then TBI compatibility is not needed. If we are + * at gigabit speed, we turn on TBI compatibility. + */ + if(hw->tbi_compatibility_en) { + uint16_t speed, duplex; + e1000_get_speed_and_duplex(hw, &speed, &duplex); + if(speed != SPEED_1000) { + /* If link speed is not set to gigabit speed, we do not need + * to enable TBI compatibility. */ if(hw->tbi_compatibility_on) { /* If we previously were in the mode, turn it off. */ @@ -2081,6 +2097,29 @@ e1000_check_for_link(struct e1000_hw *hw DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\r\n"); E1000_WRITE_REG(hw, TXCW, hw->txcw); E1000_WRITE_REG(hw, CTRL, (ctrl & ~E1000_CTRL_SLU)); + + hw->serdes_link_down = FALSE; + } + /* If we force link for non-auto-negotiation switch, check link status + * based on MAC synchronization for internal serdes media type. + */ + else if((hw->media_type == e1000_media_type_internal_serdes) && + !(E1000_TXCW_ANE & E1000_READ_REG(hw, TXCW))) { + /* SYNCH bit and IV bit are sticky. */ + udelay(10); + if(E1000_RXCW_SYNCH & E1000_READ_REG(hw, RXCW)) { + if(!(rxcw & E1000_RXCW_IV)) { + hw->serdes_link_down = FALSE; + DEBUGOUT("SERDES: Link is up.\n"); + } + } else { + hw->serdes_link_down = TRUE; + DEBUGOUT("SERDES: Link is down.\n"); + } + } + if((hw->media_type == e1000_media_type_internal_serdes) && + (E1000_TXCW_ANE & E1000_READ_REG(hw, TXCW))) { + hw->serdes_link_down = !(E1000_STATUS_LU & E1000_READ_REG(hw, STATUS)); } return E1000_SUCCESS; } @@ -2481,8 +2520,8 @@ e1000_write_phy_reg_ex(struct e1000_hw * E1000_WRITE_REG(hw, MDIC, mdic); /* Poll the ready bit to see if the MDI read completed */ - for(i = 0; i < 64; i++) { - udelay(50); + for(i = 0; i < 640; i++) { + udelay(5); mdic = E1000_READ_REG(hw, MDIC); if(mdic & E1000_MDIC_READY) break; } @@ -3498,10 +3537,12 @@ e1000_write_eeprom(struct e1000_hw *hw, if (e1000_acquire_eeprom(hw) != E1000_SUCCESS) return -E1000_ERR_EEPROM; - if(eeprom->type == e1000_eeprom_microwire) + if(eeprom->type == e1000_eeprom_microwire) { status = e1000_write_eeprom_microwire(hw, offset, words, data); - else + } else { status = e1000_write_eeprom_spi(hw, offset, words, data); + msec_delay(10); + } /* Done with writing */ e1000_release_eeprom(hw); @@ -3719,12 +3760,9 @@ e1000_read_mac_addr(struct e1000_hw * hw hw->perm_mac_addr[i+1] = (uint8_t) (eeprom_data >> 8); } if(((hw->mac_type == e1000_82546) || (hw->mac_type == e1000_82546_rev_3)) && - (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) { - if(hw->perm_mac_addr[5] & 0x01) - hw->perm_mac_addr[5] &= ~(0x01); - else - hw->perm_mac_addr[5] |= 0x01; - } + (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) + hw->perm_mac_addr[5] ^= 0x01; + for(i = 0; i < NODE_ADDRESS_SIZE; i++) hw->mac_addr[i] = hw->perm_mac_addr[i]; return E1000_SUCCESS; @@ -3743,22 +3781,13 @@ void e1000_init_rx_addrs(struct e1000_hw *hw) { uint32_t i; - uint32_t addr_low; - uint32_t addr_high; DEBUGFUNC("e1000_init_rx_addrs"); /* Setup the receive address. */ DEBUGOUT("Programming MAC Address into RAR[0]\n"); - addr_low = (hw->mac_addr[0] | - (hw->mac_addr[1] << 8) | - (hw->mac_addr[2] << 16) | (hw->mac_addr[3] << 24)); - - addr_high = (hw->mac_addr[4] | - (hw->mac_addr[5] << 8) | E1000_RAH_AV); - E1000_WRITE_REG_ARRAY(hw, RA, 0, addr_low); - E1000_WRITE_REG_ARRAY(hw, RA, 1, addr_high); + e1000_rar_set(hw, hw->mac_addr, 0); /* Zero out the other 15 receive addresses. */ DEBUGOUT("Clearing RAR[1-15]\n"); @@ -3775,6 +3804,7 @@ e1000_init_rx_addrs(struct e1000_hw *hw) * mc_addr_list - the list of new multicast addresses * mc_addr_count - number of addresses * pad - number of bytes between addresses in the list + * rar_used_count - offset where to start adding mc addresses into the RAR's * * The given list replaces any existing list. Clears the last 15 receive * address registers and the multicast table. Uses receive address registers @@ -3785,11 +3815,11 @@ void e1000_mc_addr_list_update(struct e1000_hw *hw, uint8_t *mc_addr_list, uint32_t mc_addr_count, - uint32_t pad) + uint32_t pad, + uint32_t rar_used_count) { uint32_t hash_value; uint32_t i; - uint32_t rar_used_count = 1; /* RAR[0] is used for our MAC address */ DEBUGFUNC("e1000_mc_addr_list_update"); @@ -4523,8 +4553,8 @@ uint32_t e1000_read_reg_io(struct e1000_hw *hw, uint32_t offset) { - uint32_t io_addr = hw->io_base; - uint32_t io_data = hw->io_base + 4; + unsigned long io_addr = hw->io_base; + unsigned long io_data = hw->io_base + 4; e1000_io_write(hw, io_addr, offset); return e1000_io_read(hw, io_data); @@ -4543,8 +4573,8 @@ e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, uint32_t value) { - uint32_t io_addr = hw->io_base; - uint32_t io_data = hw->io_base + 4; + unsigned long io_addr = hw->io_base; + unsigned long io_data = hw->io_base + 4; e1000_io_write(hw, io_addr, offset); e1000_io_write(hw, io_data, value); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/e1000/e1000_hw.h 830-ivtv/drivers/net/e1000/e1000_hw.h --- 000-virgin/drivers/net/e1000/e1000_hw.h Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/e1000/e1000_hw.h Thu Jan 8 08:54:15 2004 @@ -291,7 +291,7 @@ int32_t e1000_read_mac_addr(struct e1000 /* Filters (multicast, vlan, receive) */ void e1000_init_rx_addrs(struct e1000_hw *hw); -void e1000_mc_addr_list_update(struct e1000_hw *hw, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad); +void e1000_mc_addr_list_update(struct e1000_hw *hw, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad, uint32_t rar_used_count); uint32_t e1000_hash_mc_addr(struct e1000_hw *hw, uint8_t * mc_addr); void e1000_mta_set(struct e1000_hw *hw, uint32_t hash_value); void e1000_rar_set(struct e1000_hw *hw, uint8_t * mc_addr, uint32_t rar_index); @@ -317,9 +317,9 @@ void e1000_pci_clear_mwi(struct e1000_hw void e1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value); void e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value); /* Port I/O is only supported on 82544 and newer */ -uint32_t e1000_io_read(struct e1000_hw *hw, uint32_t port); +uint32_t e1000_io_read(struct e1000_hw *hw, unsigned long port); uint32_t e1000_read_reg_io(struct e1000_hw *hw, uint32_t offset); -void e1000_io_write(struct e1000_hw *hw, uint32_t port, uint32_t value); +void e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value); void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, uint32_t value); int32_t e1000_config_dsp_after_link_change(struct e1000_hw *hw, boolean_t link_up); int32_t e1000_set_d3_lplu_state(struct e1000_hw *hw, boolean_t active); @@ -978,7 +978,7 @@ struct e1000_hw { e1000_ms_type master_slave; e1000_ms_type original_master_slave; e1000_ffe_config ffe_config_state; - uint32_t io_base; + unsigned long io_base; uint32_t phy_id; uint32_t phy_revision; uint32_t phy_addr; @@ -1021,6 +1021,7 @@ struct e1000_hw { boolean_t speed_downgraded; e1000_dsp_config dsp_config_state; boolean_t get_link_status; + boolean_t serdes_link_down; boolean_t tbi_compatibility_en; boolean_t tbi_compatibility_on; boolean_t phy_reset_disable; @@ -1310,6 +1311,7 @@ struct e1000_hw { #define E1000_RCTL_DPF 0x00400000 /* discard pause frames */ #define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */ #define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ +#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */ /* Receive Descriptor */ #define E1000_RDT_DELAY 0x0000ffff /* Delay timer (1=1024us) */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/e1000/e1000_main.c 830-ivtv/drivers/net/e1000/e1000_main.c --- 000-virgin/drivers/net/e1000/e1000_main.c Mon Nov 17 18:29:42 2003 +++ 830-ivtv/drivers/net/e1000/e1000_main.c Thu Jan 8 08:54:15 2004 @@ -30,10 +30,20 @@ /* Change Log * - * 5.2.20 9/30/03 + * 5.2.27 12/14/03 + * o Added netpoll support. + * o Fixed endianess bug causing ethtool loopback diags to fail on ppc. + * o Use pdev->irq rather than netdev->irq in preparation for MSI support. + * o Report driver message on user override of InterruptThrottleRate + * module parameter. + * o Change I/O address storage from uint32_t to unsigned long. + * o Added ethtool RINGPARAM support. + * + * 5.2.22 10/15/03 * o Bug fix: SERDES devices might be connected to a back-plane * switch that doesn't support auto-neg, so add the capability - * to force 1000/Full. + * to force 1000/Full. Also, since forcing 1000/Full, sample + * RxSynchronize bit to detect link state. * o Bug fix: Flow control settings for hi/lo watermark didn't * consider changes in the Rx FIFO size, which could occur with * Jumbo Frames or with the reduced FIFO in 82547. @@ -42,29 +52,18 @@ * o Bug fix: hang under heavy Tx stress when running out of Tx * descriptors; wasn't clearing context descriptor when backing * out of send because of no-resource condition. + * o Bug fix: check netif_running in dev->poll so we don't have to + * hang in dev->close until all polls are finished. [Robert + * Ollson (robert.olsson@data.slu.se)]. + * o Revert TxDescriptor ring size back to 256 since change to 1024 + * wasn't accepted into the kernel. * * 5.2.16 8/8/03 - * o Added support for new controllers: 82545GM, 82546GB, 82541/7_B1 - * o Bug fix: reset h/w before first EEPROM read because we don't know - * who may have been messing with the device before we got there. - * [Dave Johnson (ddj -a-t- cascv.brown.edu)] - * o Bug fix: read the correct work from EEPROM to detect programmed - * WoL settings. - * o Bug fix: TSO would hang if space left in FIFO was being miscalculated - * when mss dropped without a correspoding drop in the DMA buffer size. - * o ASF for Fiber nics isn't supported. - * o Bug fix: Workaround added for potential hang with 82544 running in - * PCI-X if send buffer terminates within an evenly-aligned dword. - * o Feature: Add support for ethtool flow control setting. - * o Feature: Add support for ethtool TSO setting. - * o Feature: Increase default Tx Descriptor count to 1024 for >= 82544. - * - * 5.1.13 5/28/03 */ char e1000_driver_name[] = "e1000"; char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; -char e1000_driver_version[] = "5.2.20-k1"; +char e1000_driver_version[] = "5.2.27-k1"; char e1000_copyright[] = "Copyright (c) 1999-2003 Intel Corporation."; /* e1000_pci_tbl - PCI Device ID Table @@ -89,7 +88,6 @@ static struct pci_device_id e1000_pci_tb {0x8086, 0x1011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1015, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1017, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, @@ -113,12 +111,16 @@ static struct pci_device_id e1000_pci_tb MODULE_DEVICE_TABLE(pci, e1000_pci_tbl); -/* Local Function Prototypes */ - int e1000_up(struct e1000_adapter *adapter); void e1000_down(struct e1000_adapter *adapter); void e1000_reset(struct e1000_adapter *adapter); int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx); +int e1000_setup_tx_resources(struct e1000_adapter *adapter); +int e1000_setup_rx_resources(struct e1000_adapter *adapter); +void e1000_free_tx_resources(struct e1000_adapter *adapter); +void e1000_free_rx_resources(struct e1000_adapter *adapter); + +/* Local Function Prototypes */ static int e1000_init_module(void); static void e1000_exit_module(void); @@ -127,15 +129,11 @@ static void __devexit e1000_remove(struc static int e1000_sw_init(struct e1000_adapter *adapter); static int e1000_open(struct net_device *netdev); static int e1000_close(struct net_device *netdev); -static int e1000_setup_tx_resources(struct e1000_adapter *adapter); -static int e1000_setup_rx_resources(struct e1000_adapter *adapter); static void e1000_configure_tx(struct e1000_adapter *adapter); static void e1000_configure_rx(struct e1000_adapter *adapter); static void e1000_setup_rctl(struct e1000_adapter *adapter); static void e1000_clean_tx_ring(struct e1000_adapter *adapter); static void e1000_clean_rx_ring(struct e1000_adapter *adapter); -static void e1000_free_tx_resources(struct e1000_adapter *adapter); -static void e1000_free_rx_resources(struct e1000_adapter *adapter); static void e1000_set_multi(struct net_device *netdev); static void e1000_update_phy_info(unsigned long data); static void e1000_watchdog(unsigned long data); @@ -182,6 +180,11 @@ static int e1000_suspend(struct pci_dev static int e1000_resume(struct pci_dev *pdev); #endif +#ifdef CONFIG_NET_POLL_CONTROLLER +/* for netdump / net console */ +static void e1000_netpoll (struct net_device *dev); +#endif + struct notifier_block e1000_notifier_reboot = { .notifier_call = e1000_notify_reboot, .next = NULL, @@ -268,7 +271,7 @@ e1000_up(struct e1000_adapter *adapter) e1000_configure_rx(adapter); e1000_alloc_rx_buffers(adapter); - if((err = request_irq(netdev->irq, &e1000_intr, + if((err = request_irq(adapter->pdev->irq, &e1000_intr, SA_SHIRQ | SA_SAMPLE_RANDOM, netdev->name, netdev))) return err; @@ -285,7 +288,7 @@ e1000_down(struct e1000_adapter *adapter struct net_device *netdev = adapter->netdev; e1000_irq_disable(adapter); - free_irq(netdev->irq, netdev); + free_irq(adapter->pdev->irq, netdev); del_timer_sync(&adapter->tx_fifo_stall_timer); del_timer_sync(&adapter->watchdog_timer); del_timer_sync(&adapter->phy_info_timer); @@ -434,8 +437,10 @@ e1000_probe(struct pci_dev *pdev, netdev->vlan_rx_register = e1000_vlan_rx_register; netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid; netdev->vlan_rx_kill_vid = e1000_vlan_rx_kill_vid; +#ifdef CONFIG_NET_POLL_CONTROLLER + netdev->poll_controller = e1000_netpoll; +#endif - netdev->irq = pdev->irq; netdev->mem_start = mmio_start; netdev->mem_end = mmio_start + mmio_len; netdev->base_addr = adapter->hw.io_base; @@ -749,7 +754,7 @@ e1000_close(struct net_device *netdev) * Return 0 on success, negative on failure **/ -static int +int e1000_setup_tx_resources(struct e1000_adapter *adapter) { struct e1000_desc_ring *txdr = &adapter->tx_ring; @@ -866,7 +871,7 @@ e1000_configure_tx(struct e1000_adapter * Returns 0 on success, negative on failure **/ -static int +int e1000_setup_rx_resources(struct e1000_adapter *adapter) { struct e1000_desc_ring *rxdr = &adapter->rx_ring; @@ -1005,7 +1010,7 @@ e1000_configure_rx(struct e1000_adapter * Free all transmit software resources **/ -static void +void e1000_free_tx_resources(struct e1000_adapter *adapter) { struct pci_dev *pdev = adapter->pdev; @@ -1073,7 +1078,7 @@ e1000_clean_tx_ring(struct e1000_adapter * Free all receive software resources **/ -static void +void e1000_free_rx_resources(struct e1000_adapter *adapter) { struct e1000_desc_ring *rx_ring = &adapter->rx_ring; @@ -1281,41 +1286,6 @@ e1000_set_multi(struct net_device *netde e1000_leave_82542_rst(adapter); } -static void -e1000_tx_flush(struct e1000_adapter *adapter) -{ - uint32_t ctrl, tctl, txcw, icr; - - e1000_irq_disable(adapter); - - if(adapter->hw.mac_type < e1000_82543) { - /* Transmit Unit Reset */ - tctl = E1000_READ_REG(&adapter->hw, TCTL); - E1000_WRITE_REG(&adapter->hw, TCTL, tctl | E1000_TCTL_RST); - E1000_WRITE_REG(&adapter->hw, TCTL, tctl); - e1000_clean_tx_ring(adapter); - e1000_configure_tx(adapter); - } else { - txcw = E1000_READ_REG(&adapter->hw, TXCW); - E1000_WRITE_REG(&adapter->hw, TXCW, txcw & ~E1000_TXCW_ANE); - - ctrl = E1000_READ_REG(&adapter->hw, CTRL); - E1000_WRITE_REG(&adapter->hw, CTRL, ctrl | E1000_CTRL_SLU | - E1000_CTRL_ILOS); - - mdelay(10); - - e1000_clean_tx_irq(adapter); - E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); - E1000_WRITE_REG(&adapter->hw, TXCW, txcw); - - /* clear the link status change interrupts this caused */ - icr = E1000_READ_REG(&adapter->hw, ICR); - } - - e1000_irq_enable(adapter); -} - /* need to wait a few seconds after link up to get diagnostic information from the phy */ static void @@ -1379,10 +1349,17 @@ e1000_watchdog(unsigned long data) struct net_device *netdev = adapter->netdev; struct e1000_desc_ring *txdr = &adapter->tx_ring; unsigned int i; + uint32_t link; e1000_check_for_link(&adapter->hw); - if(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) { + if((adapter->hw.media_type == e1000_media_type_internal_serdes) && + !(E1000_READ_REG(&adapter->hw, TXCW) & E1000_TXCW_ANE)) + link = !adapter->hw.serdes_link_down; + else + link = E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU; + + if(link) { if(!netif_carrier_ok(netdev)) { e1000_get_speed_and_duplex(&adapter->hw, &adapter->link_speed, @@ -1419,10 +1396,11 @@ e1000_watchdog(unsigned long data) if(!netif_carrier_ok(netdev)) { if(E1000_DESC_UNUSED(txdr) + 1 < txdr->count) { - unsigned long flags; - spin_lock_irqsave(&netdev->xmit_lock, flags); - e1000_tx_flush(adapter); - spin_unlock_irqrestore(&netdev->xmit_lock, flags); + /* We've lost link, so the controller stops DMA, + * but we've got queued Tx work that's never going + * to get done, so reset controller to flush Tx. + * (Do the reset outside of interrupt context). */ + schedule_work(&adapter->tx_timeout_task); } } @@ -2064,7 +2042,7 @@ e1000_irq_disable(struct e1000_adapter * atomic_inc(&adapter->irq_sem); E1000_WRITE_REG(&adapter->hw, IMC, ~0); E1000_WRITE_FLUSH(&adapter->hw); - synchronize_irq(adapter->netdev->irq); + synchronize_irq(adapter->pdev->irq); } /** @@ -2093,6 +2071,7 @@ e1000_intr(int irq, void *data, struct p { struct net_device *netdev = data; struct e1000_adapter *adapter = netdev->priv; + struct e1000_hw *hw = &adapter->hw; uint32_t icr = E1000_READ_REG(&adapter->hw, ICR); #ifndef CONFIG_E1000_NAPI unsigned int i; @@ -2102,7 +2081,7 @@ e1000_intr(int irq, void *data, struct p return IRQ_NONE; /* Not our interrupt */ if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { - adapter->hw.get_link_status = 1; + hw->get_link_status = 1; mod_timer(&adapter->watchdog_timer, jiffies); } @@ -2114,14 +2093,30 @@ e1000_intr(int irq, void *data, struct p */ atomic_inc(&adapter->irq_sem); - E1000_WRITE_REG(&adapter->hw, IMC, ~0); + E1000_WRITE_REG(hw, IMC, ~0); __netif_rx_schedule(netdev); } #else + /* Writing IMC and IMS is needed for 82547. + Due to Hub Link bus being occupied, an interrupt + de-assertion message is not able to be sent. + When an interrupt assertion message is generated later, + two messages are re-ordered and sent out. + That causes APIC to think 82547 is in de-assertion + state, while 82547 is in assertion state, resulting + in dead lock. Writing IMC forces 82547 into + de-assertion state. + */ + if(hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2) + e1000_irq_disable(adapter); + for(i = 0; i < E1000_MAX_INTR; i++) if(!e1000_clean_rx_irq(adapter) & !e1000_clean_tx_irq(adapter)) break; + + if(hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2) + e1000_irq_enable(adapter); #endif return IRQ_HANDLED; @@ -2146,7 +2141,7 @@ e1000_clean(struct net_device *netdev, i *budget -= work_done; netdev->quota -= work_done; - if(work_done < work_to_do) { + if(work_done < work_to_do || !netif_running(netdev)) { netif_rx_complete(netdev); e1000_irq_enable(adapter); } @@ -2642,13 +2637,13 @@ e1000_write_pci_cfg(struct e1000_hw *hw, } uint32_t -e1000_io_read(struct e1000_hw *hw, uint32_t port) +e1000_io_read(struct e1000_hw *hw, unsigned long port) { return inl(port); } void -e1000_io_write(struct e1000_hw *hw, uint32_t port, uint32_t value) +e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value) { outl(value, port); } @@ -2897,6 +2892,22 @@ e1000_resume(struct pci_dev *pdev) } return 0; +} +#endif + +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling 'interrupt' - used by things like netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ + +static void e1000_netpoll (struct net_device *dev) +{ + struct e1000_adapter *adapter = dev->priv; + disable_irq(adapter->pdev->irq); + e1000_intr (adapter->pdev->irq, dev, NULL); + enable_irq(adapter->pdev->irq); } #endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/e1000/e1000_param.c 830-ivtv/drivers/net/e1000/e1000_param.c --- 000-virgin/drivers/net/e1000/e1000_param.c Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/e1000/e1000_param.c Thu Jan 8 08:54:15 2004 @@ -196,16 +196,6 @@ E1000_PARAM(InterruptThrottleRate, "Inte #define AUTONEG_ADV_MASK 0x2F #define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL -#define DEFAULT_TXD 256 -#define MAX_TXD 256 -#define MIN_TXD 80 -#define MAX_82544_TXD 4096 - -#define DEFAULT_RXD 256 -#define MAX_RXD 256 -#define MIN_RXD 80 -#define MAX_82544_RXD 4096 - #define DEFAULT_RDTR 0 #define MAX_RXDELAY 0xFFFF #define MIN_RXDELAY 0 @@ -320,14 +310,15 @@ e1000_check_options(struct e1000_adapter struct e1000_option opt = { .type = range_option, .name = "Transmit Descriptors", - .err = "using default of " __MODULE_STRING(DEFAULT_TXD), - .def = DEFAULT_TXD, - .arg = { .r = { .min = MIN_TXD }} + .err = "using default of " + __MODULE_STRING(E1000_DEFAULT_TXD), + .def = E1000_DEFAULT_TXD, + .arg = { .r = { .min = E1000_MIN_TXD }} }; struct e1000_desc_ring *tx_ring = &adapter->tx_ring; e1000_mac_type mac_type = adapter->hw.mac_type; opt.arg.r.max = mac_type < e1000_82544 ? - MAX_TXD : MAX_82544_TXD; + E1000_MAX_TXD : E1000_MAX_82544_TXD; tx_ring->count = TxDescriptors[bd]; e1000_validate_option(&tx_ring->count, &opt); @@ -337,13 +328,15 @@ e1000_check_options(struct e1000_adapter struct e1000_option opt = { .type = range_option, .name = "Receive Descriptors", - .err = "using default of " __MODULE_STRING(DEFAULT_RXD), - .def = DEFAULT_RXD, - .arg = { .r = { .min = MIN_RXD }} + .err = "using default of " + __MODULE_STRING(E1000_DEFAULT_RXD), + .def = E1000_DEFAULT_RXD, + .arg = { .r = { .min = E1000_MIN_RXD }} }; struct e1000_desc_ring *rx_ring = &adapter->rx_ring; e1000_mac_type mac_type = adapter->hw.mac_type; - opt.arg.r.max = mac_type < e1000_82544 ? MAX_RXD : MAX_82544_RXD; + opt.arg.r.max = mac_type < e1000_82544 ? E1000_MAX_RXD : + E1000_MAX_82544_RXD; rx_ring->count = RxDescriptors[bd]; e1000_validate_option(&rx_ring->count, &opt); @@ -446,13 +439,19 @@ e1000_check_options(struct e1000_adapter }; adapter->itr = InterruptThrottleRate[bd]; - if(adapter->itr == 0) { - printk(KERN_INFO "%s turned off\n", opt.name); - } else if(adapter->itr == 1 || adapter->itr == -1) { - /* Dynamic mode */ + switch(adapter->itr) { + case -1: adapter->itr = 1; - } else { + break; + case 0: + printk(KERN_INFO "%s turned off\n", opt.name); + break; + case 1: + printk(KERN_INFO "%s set to dynamic mode\n", opt.name); + break; + default: e1000_validate_option(&adapter->itr, &opt); + break; } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/e2100.c 830-ivtv/drivers/net/e2100.c --- 000-virgin/drivers/net/e2100.c Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/e2100.c Thu Jan 8 08:54:15 2004 @@ -95,7 +95,6 @@ static inline void mem_off(short port) #define E21_BIG_RX_STOP_PG 0xF0 /* Last page +1 of RX ring */ #define E21_TX_START_PG E21_RX_STOP_PG /* First page of TX buffer */ -int e2100_probe(struct net_device *dev); static int e21_probe1(struct net_device *dev, int ioaddr); static int e21_open(struct net_device *dev); @@ -117,10 +116,11 @@ static int e21_close(struct net_device * station address). */ -int __init e2100_probe(struct net_device *dev) +static int __init do_e2100_probe(struct net_device *dev) { int *port; int base_addr = dev->base_addr; + int irq = dev->irq; SET_MODULE_OWNER(dev); @@ -129,13 +129,46 @@ int __init e2100_probe(struct net_devic else if (base_addr != 0) /* Don't probe at all. */ return -ENXIO; - for (port = e21_probe_list; *port; port++) + for (port = e21_probe_list; *port; port++) { + dev->irq = irq; if (e21_probe1(dev, *port) == 0) return 0; + } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + /* NB: e21_close() handles free_irq */ + release_region(dev->base_addr, E21_IO_EXTENT); +} + +struct net_device * __init e2100_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_e2100_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init e21_probe1(struct net_device *dev, int ioaddr) { int i, status, retval; @@ -175,13 +208,6 @@ static int __init e21_probe1(struct net_ for (i = 0; i < 6; i++) printk(" %02X", station_addr[i]); - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk (" unable to get memory for dev->priv.\n"); - retval = -ENOMEM; - goto out; - } - if (dev->irq < 2) { int irqlist[] = {15,11,10,12,5,9,3,4}, i; for (i = 0; i < 8; i++) @@ -191,8 +217,6 @@ static int __init e21_probe1(struct net_ } if (i >= 8) { printk(" unable to get IRQ %d.\n", dev->irq); - kfree(dev->priv); - dev->priv = NULL; retval = -EAGAIN; goto out; } @@ -376,7 +400,7 @@ e21_close(struct net_device *dev) #ifdef MODULE #define MAX_E21_CARDS 4 /* Max number of E21 cards per module */ -static struct net_device dev_e21[MAX_E21_CARDS]; +static struct net_device *dev_e21[MAX_E21_CARDS]; static int io[MAX_E21_CARDS]; static int irq[MAX_E21_CARDS]; static int mem[MAX_E21_CARDS]; @@ -398,29 +422,35 @@ ISA device autoprobes on a running machi int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_E21_CARDS; this_dev++) { - struct net_device *dev = &dev_e21[this_dev]; - dev->irq = irq[this_dev]; - dev->base_addr = io[this_dev]; - dev->mem_start = mem[this_dev]; - dev->mem_end = xcvr[this_dev]; /* low 4bits = xcvr sel. */ - dev->init = e2100_probe; if (io[this_dev] == 0) { if (this_dev != 0) break; /* only autoprobe 1st one */ printk(KERN_NOTICE "e2100.c: Presently autoprobing (not recommended) for a single card.\n"); } - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "e2100.c: No E2100 card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) { /* Got at least one. */ - return 0; + dev = alloc_ei_netdev(); + if (!dev) + break; + dev->irq = irq[this_dev]; + dev->base_addr = io[this_dev]; + dev->mem_start = mem[this_dev]; + dev->mem_end = xcvr[this_dev]; /* low 4bits = xcvr sel. */ + if (do_e2100_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_e21[found++] = dev; + continue; } - return -ENXIO; + cleanup_card(dev); } - found++; + free_netdev(dev); + printk(KERN_WARNING "e2100.c: No E2100 card found (i/o = 0x%x).\n", io[this_dev]); + break; } - return 0; + if (found) + return 0; + return -ENXIO; } void @@ -429,13 +459,11 @@ cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < MAX_E21_CARDS; this_dev++) { - struct net_device *dev = &dev_e21[this_dev]; - if (dev->priv != NULL) { - void *priv = dev->priv; - /* NB: e21_close() handles free_irq */ - release_region(dev->base_addr, E21_IO_EXTENT); + struct net_device *dev = dev_e21[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(priv); + cleanup_card(dev); + free_netdev(dev); } } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/eepro.c 830-ivtv/drivers/net/eepro.c --- 000-virgin/drivers/net/eepro.c Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/eepro.c Thu Jan 8 08:54:15 2004 @@ -302,9 +302,7 @@ struct eepro_local { /* Index to functions, as function prototypes. */ -extern int eepro_probe(struct net_device *dev); - -static int eepro_probe1(struct net_device *dev, short ioaddr); +static int eepro_probe1(struct net_device *dev, int autoprobe); static int eepro_open(struct net_device *dev); static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev); static irqreturn_t eepro_interrupt(int irq, void *dev_id, struct pt_regs *regs); @@ -527,10 +525,11 @@ buffer (transmit-buffer = 32K - receive- If dev->base_addr == 2, allocate space for the device and return success (detachable devices only). */ -int __init eepro_probe(struct net_device *dev) +static int __init do_eepro_probe(struct net_device *dev) { int i; int base_addr = dev->base_addr; + int irq = dev->irq; SET_MODULE_OWNER(dev); @@ -563,24 +562,48 @@ int __init eepro_probe(struct net_device #endif if (base_addr > 0x1ff) /* Check a single specified location. */ - return eepro_probe1(dev, base_addr); + return eepro_probe1(dev, 0); else if (base_addr != 0) /* Don't probe at all. */ return -ENXIO; - for (i = 0; eepro_portlist[i]; i++) { - int ioaddr = eepro_portlist[i]; - - if (check_region(ioaddr, EEPRO_IO_EXTENT)) - continue; - if (eepro_probe1(dev, ioaddr) == 0) + dev->base_addr = eepro_portlist[i]; + dev->irq = irq; + if (eepro_probe1(dev, 1) == 0) return 0; } return -ENODEV; } +struct net_device * __init eepro_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct eepro_local)); + int err; + + if (!dev) + return ERR_PTR(-ENODEV); + + SET_MODULE_OWNER(dev); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_eepro_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + release_region(dev->base_addr, EEPRO_IO_EXTENT); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static void __init printEEPROMInfo(short ioaddr, struct net_device *dev) { unsigned short Word; @@ -713,83 +736,75 @@ static void eepro_print_info (struct net probes on the ISA bus. A good device probe avoids doing writes, and verifies that the correct device exists and functions. */ -static int __init eepro_probe1(struct net_device *dev, short ioaddr) +static int __init eepro_probe1(struct net_device *dev, int autoprobe) { unsigned short station_addr[6], id, counter; - int i, j, irqMask, retval = 0; + int i; struct eepro_local *lp; enum iftype { AUI=0, BNC=1, TPE=2 }; + int ioaddr = dev->base_addr; + + /* Grab the region so we can find another board if autoIRQ fails. */ + if (!request_region(ioaddr, EEPRO_IO_EXTENT, dev->name)) { + if (!autoprobe) + printk(KERN_WARNING "EEPRO: io-port 0x%04x in use \n", + ioaddr); + return -EBUSY; + } /* Now, we are going to check for the signature of the ID_REG (register 2 of bank 0) */ - id=inb(ioaddr + ID_REG); + id = inb(ioaddr + ID_REG); - if (((id) & ID_REG_MASK) != ID_REG_SIG) { - retval = -ENODEV; + if ((id & ID_REG_MASK) != ID_REG_SIG) goto exit; - } - /* We seem to have the 82595 signature, let's - play with its counter (last 2 bits of - register 2 of bank 0) to be sure. */ + /* We seem to have the 82595 signature, let's + play with its counter (last 2 bits of + register 2 of bank 0) to be sure. */ - counter = (id & R_ROBIN_BITS); - - if (((id=inb(ioaddr+ID_REG)) & R_ROBIN_BITS)!=(counter + 0x40)) { - retval = -ENODEV; - goto exit; - } + counter = id & R_ROBIN_BITS; - /* Initialize the device structure */ - dev->priv = kmalloc(sizeof(struct eepro_local), GFP_KERNEL); - if (!dev->priv) { - retval = -ENOMEM; + if ((inb(ioaddr + ID_REG) & R_ROBIN_BITS) != (counter + 0x40)) goto exit; - } - - memset(dev->priv, 0, sizeof(struct eepro_local)); - - lp = (struct eepro_local *)dev->priv; - /* default values */ - lp->eepro = 0; + lp = (struct eepro_local *)dev->priv; + memset(lp, 0, sizeof(struct eepro_local)); lp->xmt_bar = XMT_BAR_PRO; lp->xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_PRO; lp->xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_PRO; lp->eeprom_reg = EEPROM_REG_PRO; + spin_lock_init(&lp->lock); - /* Now, get the ethernet hardware address from - the EEPROM */ - station_addr[0] = read_eeprom(ioaddr, 2, dev); - - /* FIXME - find another way to know that we've found - * an Etherexpress 10 - */ - if (station_addr[0] == 0x0000 || - station_addr[0] == 0xffff) { - lp->eepro = LAN595FX_10ISA; + /* Now, get the ethernet hardware address from + the EEPROM */ + station_addr[0] = read_eeprom(ioaddr, 2, dev); + + /* FIXME - find another way to know that we've found + * an Etherexpress 10 + */ + if (station_addr[0] == 0x0000 || station_addr[0] == 0xffff) { + lp->eepro = LAN595FX_10ISA; lp->eeprom_reg = EEPROM_REG_10; lp->xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_10; lp->xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_10; lp->xmt_bar = XMT_BAR_10; - station_addr[0] = read_eeprom(ioaddr, 2, dev); - } - station_addr[1] = read_eeprom(ioaddr, 3, dev); - station_addr[2] = read_eeprom(ioaddr, 4, dev); + station_addr[0] = read_eeprom(ioaddr, 2, dev); + } + station_addr[1] = read_eeprom(ioaddr, 3, dev); + station_addr[2] = read_eeprom(ioaddr, 4, dev); if (!lp->eepro) { if (read_eeprom(ioaddr,7,dev)== ee_FX_INT2IRQ) lp->eepro = 2; else if (station_addr[2] == SA_ADDR1) lp->eepro = 1; - } - - /* Fill in the 'dev' fields. */ - dev->base_addr = ioaddr; + } + /* Fill in the 'dev' fields. */ for (i=0; i < 6; i++) - dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i]; + dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i]; /* RX buffer must be more than 3K and less than 29K */ if (dev->mem_end < 3072 || dev->mem_end > 29696) @@ -798,65 +813,49 @@ static int __init eepro_probe1(struct ne /* calculate {xmt,rcv}_{lower,upper}_limit */ eepro_recalc(dev); - - if (GetBit( read_eeprom(ioaddr, 5, dev),ee_BNC_TPE)) - dev->if_port = BNC; + if (GetBit( read_eeprom(ioaddr, 5, dev),ee_BNC_TPE)) + dev->if_port = BNC; else dev->if_port = TPE; - if ((dev->irq < 2) && (lp->eepro!=0)) { - i = read_eeprom(ioaddr, 1, dev); - irqMask = read_eeprom(ioaddr, 7, dev); - i &= 0x07; /* Mask off INT number */ - - for (j=0; ((j<16) && (i>=0)); j++) { - if ((irqMask & (1<irq = j; - break; /* found bit corresponding to irq */ - } - i--; /* count bits set in irqMask */ - } - } - if (dev->irq < 2) { - printk(KERN_ERR " Duh! invalid interrupt vector stored in EEPROM.\n"); - retval = -ENODEV; - goto freeall; - } else - if (dev->irq==2) dev->irq = 9; - } - - /* Grab the region so we can find another board if autoIRQ fails. */ - if (!request_region(ioaddr, EEPRO_IO_EXTENT, dev->name)) { - printk(KERN_WARNING "EEPRO: io-port 0x%04x in use \n", ioaddr); - goto freeall; - } - ((struct eepro_local *)dev->priv)->lock = SPIN_LOCK_UNLOCKED; - - dev->open = eepro_open; - dev->stop = eepro_close; - dev->hard_start_xmit = eepro_send_packet; - dev->get_stats = eepro_get_stats; - dev->set_multicast_list = &set_multicast_list; - dev->tx_timeout = eepro_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - - /* Fill in the fields of the device structure with - ethernet generic values */ - ether_setup(dev); - + if (dev->irq < 2 && lp->eepro != 0) { + /* Mask off INT number */ + int count = read_eeprom(ioaddr, 1, dev) & 7; + unsigned irqMask = read_eeprom(ioaddr, 7, dev); + + while (count--) + irqMask &= irqMask - 1; + + count = ffs(irqMask); + + if (count) + dev->irq = count - 1; + + if (dev->irq < 2) { + printk(KERN_ERR " Duh! illegal interrupt vector stored in EEPROM.\n"); + goto exit; + } else if (dev->irq == 2) { + dev->irq = 9; + } + } + + dev->open = eepro_open; + dev->stop = eepro_close; + dev->hard_start_xmit = eepro_send_packet; + dev->get_stats = eepro_get_stats; + dev->set_multicast_list = &set_multicast_list; + dev->tx_timeout = eepro_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + /* print boot time info */ eepro_print_info(dev); /* reset 82595 */ - eepro_reset(ioaddr); - + eepro_reset(ioaddr); + return 0; exit: - return retval; -freeall: - kfree(dev->priv); - goto exit; - + release_region(dev->base_addr, EEPRO_IO_EXTENT); + return -ENODEV; } /* Open/initialize the board. This is called (in the current kernel) @@ -1701,7 +1700,7 @@ eepro_transmit_interrupt(struct net_devi #ifdef MODULE #define MAX_EEPRO 8 -static struct net_device dev_eepro[MAX_EEPRO]; +static struct net_device *dev_eepro[MAX_EEPRO]; static int io[MAX_EEPRO]; static int irq[MAX_EEPRO]; @@ -1729,6 +1728,7 @@ MODULE_PARM_DESC(autodetect, "EtherExpre int init_module(void) { + struct net_device *dev; int i; if (io[0] == 0 && autodetect == 0) { printk(KERN_WARNING "eepro_init_module: Probe is very dangerous in ISA boards!\n"); @@ -1743,17 +1743,24 @@ init_module(void) } for (i = 0; i < MAX_EEPRO; i++) { - struct net_device *d = &dev_eepro[n_eepro]; - d->mem_end = mem[i]; - d->base_addr = io[i]; - d->irq = irq[i]; - d->init = eepro_probe; - - if (register_netdev(d) == 0) - n_eepro++; - else - break; + dev = alloc_etherdev(sizeof(struct eepro_local)); + if (!dev) + break; + + dev->mem_end = mem[i]; + dev->base_addr = io[i]; + dev->irq = irq[i]; + + if (do_eepro_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_eepro[n_eepro++] = dev; + continue; + } + release_region(dev->base_addr, EEPRO_IO_EXTENT); } + free_netdev(dev); + break; + } if (n_eepro) printk(KERN_INFO "%s", version); @@ -1767,15 +1774,10 @@ cleanup_module(void) int i; for (i=0; ipriv); - d->priv=NULL; - - /* If we don't do this, we can't re-insmod it later. */ - release_region(d->base_addr, EEPRO_IO_EXTENT); - + struct net_device *dev = dev_eepro[i]; + unregister_netdev(dev); + release_region(dev->base_addr, EEPRO_IO_EXTENT); + free_netdev(dev); } } #endif /* MODULE */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/eepro100.c 830-ivtv/drivers/net/eepro100.c --- 000-virgin/drivers/net/eepro100.c Mon Nov 17 18:28:14 2003 +++ 830-ivtv/drivers/net/eepro100.c Thu Jan 8 08:54:15 2004 @@ -542,6 +542,7 @@ static int speedo_start_xmit(struct sk_b static void speedo_refill_rx_buffers(struct net_device *dev, int force); static int speedo_rx(struct net_device *dev); static void speedo_tx_buffer_gc(struct net_device *dev); +static void poll_speedo (struct net_device *dev); static irqreturn_t speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs); static int speedo_close(struct net_device *dev); static struct net_device_stats *speedo_get_stats(struct net_device *dev); @@ -885,6 +886,9 @@ static int __devinit speedo_found1(struc dev->get_stats = &speedo_get_stats; dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &speedo_ioctl; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = &poll_speedo; +#endif if (register_netdevice(dev)) goto err_free_unlock; @@ -1674,6 +1678,23 @@ static irqreturn_t speedo_interrupt(int clear_bit(0, (void*)&sp->in_interrupt); return IRQ_RETVAL(handled); } + +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling 'interrupt' - used by things like netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ + +static void poll_speedo (struct net_device *dev) +{ + /* disable_irq is not very nice, but with the funny lockless design + we have no other choice. */ + disable_irq(dev->irq); + speedo_interrupt (dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry) { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/eexpress.c 830-ivtv/drivers/net/eexpress.c --- 000-virgin/drivers/net/eexpress.c Mon Nov 17 18:29:30 2003 +++ 830-ivtv/drivers/net/eexpress.c Thu Jan 8 08:54:15 2004 @@ -244,7 +244,6 @@ static char mca_irqmap[] = { 12, 9, 3, 4 * Prototypes for Linux interface */ -extern int express_probe(struct net_device *dev); static int eexp_open(struct net_device *dev); static int eexp_close(struct net_device *dev); static void eexp_timeout(struct net_device *dev); @@ -334,11 +333,13 @@ static inline unsigned short int SHADOW( * checks for presence of EtherExpress card */ -int __init express_probe(struct net_device *dev) +static int __init do_express_probe(struct net_device *dev) { unsigned short *port; static unsigned short ports[] = { 0x240,0x300,0x310,0x270,0x320,0x340,0 }; unsigned short ioaddr = dev->base_addr; + int dev_irq = dev->irq; + int err; SET_MODULE_OWNER(dev); @@ -391,27 +392,58 @@ int __init express_probe(struct net_devi } } #endif - if (ioaddr&0xfe00) - return eexp_hw_probe(dev,ioaddr); - else if (ioaddr) + if (ioaddr&0xfe00) { + if (!request_region(ioaddr, EEXP_IO_EXTENT, "EtherExpress")) + return -EBUSY; + err = eexp_hw_probe(dev,ioaddr); + release_region(ioaddr, EEXP_IO_EXTENT); + return err; + } else if (ioaddr) return -ENXIO; for (port=&ports[0] ; *port ; port++ ) { unsigned short sum = 0; int i; + if (!request_region(*port, EEXP_IO_EXTENT, "EtherExpress")) + continue; for ( i=0 ; i<4 ; i++ ) { unsigned short t; t = inb(*port + ID_PORT); sum |= (t>>4) << ((t & 0x03)<<2); } - if (sum==0xbaba && !eexp_hw_probe(dev,*port)) + if (sum==0xbaba && !eexp_hw_probe(dev,*port)) { + release_region(*port, EEXP_IO_EXTENT); return 0; + } + release_region(*port, EEXP_IO_EXTENT); + dev->irq = dev_irq; } return -ENODEV; } +struct net_device * __init express_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_express_probe(dev); + if (!err) { + err = register_netdev(dev); + if (!err) + return dev; + } + free_netdev(dev); + return ERR_PTR(err); +} + /* * open and initialize the adapter, ready for use */ @@ -1058,7 +1090,7 @@ static int __init eexp_hw_probe(struct n unsigned int memory_size; int i; unsigned short xsum = 0; - struct net_local *lp; + struct net_local *lp = dev->priv; printk("%s: EtherExpress 16 at %#x ",dev->name,ioaddr); @@ -1108,17 +1140,18 @@ static int __init eexp_hw_probe(struct n buswidth = !((setupval & 0x400) >> 10); } - dev->priv = lp = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (!dev->priv) - return -ENOMEM; - - memset(dev->priv, 0, sizeof(struct net_local)); + memset(lp, 0, sizeof(struct net_local)); spin_lock_init(&lp->lock); printk("(IRQ %d, %s connector, %d-bit bus", dev->irq, eexp_ifmap[dev->if_port], buswidth?8:16); + if (!request_region(dev->base_addr + 0x300e, 1, "EtherExpress")) + return -EBUSY; + eexp_hw_set_interface(dev); + + release_region(dev->base_addr + 0x300e, 1); /* Find out how much RAM we have on the card */ outw(0, dev->base_addr + WRITE_PTR); @@ -1156,7 +1189,6 @@ static int __init eexp_hw_probe(struct n break; default: printk(") bad memory size (%dk).\n", memory_size); - kfree(dev->priv); return -ENODEV; break; } @@ -1171,7 +1203,6 @@ static int __init eexp_hw_probe(struct n dev->set_multicast_list = &eexp_set_multicast; dev->tx_timeout = eexp_timeout; dev->watchdog_timeo = 2*HZ; - ether_setup(dev); return 0; } @@ -1654,7 +1685,7 @@ eexp_set_multicast(struct net_device *de #define EEXP_MAX_CARDS 4 /* max number of cards to support */ -static struct net_device dev_eexp[EEXP_MAX_CARDS]; +static struct net_device *dev_eexp[EEXP_MAX_CARDS]; static int irq[EEXP_MAX_CARDS]; static int io[EEXP_MAX_CARDS]; @@ -1671,25 +1702,30 @@ MODULE_LICENSE("GPL"); */ int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) { - struct net_device *dev = &dev_eexp[this_dev]; + dev = alloc_etherdev(sizeof(struct net_local)); dev->irq = irq[this_dev]; dev->base_addr = io[this_dev]; - dev->init = express_probe; if (io[this_dev] == 0) { - if (this_dev) break; + if (this_dev) + break; printk(KERN_NOTICE "eexpress.c: Module autoprobe not recommended, give io=xx.\n"); } - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "eexpress.c: Failed to register card at 0x%x.\n", io[this_dev]); - if (found != 0) return 0; - return -ENXIO; + if (do_express_probe(dev) == 0 && register_netdev(dev) == 0) { + dev_eexp[this_dev] = dev; + found++; + continue; } - found++; + printk(KERN_WARNING "eexpress.c: Failed to register card at 0x%x.\n", io[this_dev]); + free_netdev(dev); + break; } - return 0; + if (found) + return 0; + return -ENXIO; } void cleanup_module(void) @@ -1697,11 +1733,10 @@ void cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) { - struct net_device *dev = &dev_eexp[this_dev]; - if (dev->priv != NULL) { + struct net_device *dev = dev_eexp[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(dev->priv); - dev->priv = NULL; + free_netdev(dev); } } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/eql.c 830-ivtv/drivers/net/eql.c --- 000-virgin/drivers/net/eql.c Tue Sep 2 09:55:47 2003 +++ 830-ivtv/drivers/net/eql.c Thu Jan 8 08:54:16 2004 @@ -600,7 +600,7 @@ static int __init eql_init_module(void) err = register_netdev(dev_eql); if (err) - kfree(dev_eql); + free_netdev(dev_eql); return err; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/es3210.c 830-ivtv/drivers/net/es3210.c --- 000-virgin/drivers/net/es3210.c Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/es3210.c Thu Jan 8 08:54:16 2004 @@ -62,7 +62,6 @@ static const char version[] = #include "8390.h" -int es_probe(struct net_device *dev); static int es_probe1(struct net_device *dev, int ioaddr); static int es_open(struct net_device *dev); @@ -125,9 +124,11 @@ static unsigned char hi_irq_map[] __init * PROM for a match against the Racal-Interlan assigned value. */ -int __init es_probe(struct net_device *dev) +static int __init do_es_probe(struct net_device *dev) { unsigned short ioaddr = dev->base_addr; + int irq = dev->irq; + int mem_start = dev->mem_start; SET_MODULE_OWNER(dev); @@ -144,13 +145,47 @@ int __init es_probe(struct net_device *d } /* EISA spec allows for up to 16 slots, but 8 is typical. */ - for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) + for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) { if (es_probe1(dev, ioaddr) == 0) return 0; + dev->irq = irq; + dev->mem_start = mem_start; + } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + free_irq(dev->irq, dev); + release_region(dev->base_addr, ES_IO_EXTENT); +} + +struct net_device * __init es_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_es_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init es_probe1(struct net_device *dev, int ioaddr) { int i, retval; @@ -240,13 +275,6 @@ static int __init es_probe1(struct net_d printk("mem %#lx-%#lx\n", dev->mem_start, dev->mem_end-1); - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk (" unable to allocate memory for dev->priv.\n"); - retval = -ENOMEM; - goto out1; - } - #if ES_DEBUG & ES_D_PROBE if (inb(ioaddr + ES_CFG5)) printk("es3210: Warning - DMA channel enabled, but not used here.\n"); @@ -376,7 +404,7 @@ static int es_close(struct net_device *d #ifdef MODULE #define MAX_ES_CARDS 4 /* Max number of ES3210 cards per module */ #define NAMELEN 8 /* # of chars for storing dev->name */ -static struct net_device dev_es3210[MAX_ES_CARDS]; +static struct net_device *dev_es3210[MAX_ES_CARDS]; static int io[MAX_ES_CARDS]; static int irq[MAX_ES_CARDS]; static int mem[MAX_ES_CARDS]; @@ -393,26 +421,32 @@ MODULE_LICENSE("GPL"); int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_ES_CARDS; this_dev++) { - struct net_device *dev = &dev_es3210[this_dev]; + if (io[this_dev] == 0 && this_dev != 0) + break; + dev = alloc_ei_netdev(); + if (!dev) + break; dev->irq = irq[this_dev]; dev->base_addr = io[this_dev]; - dev->mem_start = mem[this_dev]; /* Currently ignored by driver */ - dev->init = es_probe; - /* Default is to only install one card. */ - if (io[this_dev] == 0 && this_dev != 0) break; - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "es3210.c: No es3210 card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) { /* Got at least one. */ - return 0; + dev->mem_start = mem[this_dev]; + if (do_es_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_es3210[found++] = dev; + continue; } - return -ENXIO; + cleanup_card(dev); } - found++; + free_netdev(dev); + printk(KERN_WARNING "es3210.c: No es3210 card found (i/o = 0x%x).\n", io[this_dev]); + break; } - return 0; + if (found) + return 0; + return -ENXIO; } void @@ -421,13 +455,11 @@ cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < MAX_ES_CARDS; this_dev++) { - struct net_device *dev = &dev_es3210[this_dev]; - if (dev->priv != NULL) { - void *priv = dev->priv; - free_irq(dev->irq, dev); - release_region(dev->base_addr, ES_IO_EXTENT); + struct net_device *dev = dev_es3210[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(priv); + cleanup_card(dev); + free_netdev(dev); } } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/eth16i.c 830-ivtv/drivers/net/eth16i.c --- 000-virgin/drivers/net/eth16i.c Mon Nov 17 18:28:14 2003 +++ 830-ivtv/drivers/net/eth16i.c Thu Jan 8 08:54:16 2004 @@ -369,7 +369,6 @@ static unsigned int eth32i_irqmap[] __in #define NUM_OF_EISA_IRQS 8 static unsigned int eth16i_tx_buf_map[] = { 2048, 2048, 4096, 8192 }; -static unsigned int boot = 1; /* Use 0 for production, 1 for verification, >2 for debug */ #ifndef ETH16I_DEBUG @@ -395,8 +394,6 @@ struct eth16i_local { /* Function prototypes */ -extern int eth16i_probe(struct net_device *dev); - static int eth16i_probe1(struct net_device *dev, int ioaddr); static int eth16i_check_signature(int ioaddr); static int eth16i_probe_port(int ioaddr); @@ -418,7 +415,7 @@ static void eth16i_timeout(struct net static void eth16i_skip_packet(struct net_device *dev); static void eth16i_multicast(struct net_device *dev); static void eth16i_select_regbank(unsigned char regbank, int ioaddr); -static void eth16i_initialize(struct net_device *dev); +static void eth16i_initialize(struct net_device *dev, int boot); #if 0 static int eth16i_set_irq(struct net_device *dev); @@ -432,7 +429,7 @@ static struct net_device_stats *eth16i_g static char cardname[] __initdata = "ICL EtherTeam 16i/32"; -int __init eth16i_probe(struct net_device *dev) +static int __init do_eth16i_probe(struct net_device *dev) { int i; int ioaddr; @@ -461,14 +458,38 @@ int __init eth16i_probe(struct net_devic return -ENODEV; } +struct net_device * __init eth16i_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct eth16i_local)); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_eth16i_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + free_irq(dev->irq, dev); + release_region(dev->base_addr, ETH16I_IO_EXTENT); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init eth16i_probe1(struct net_device *dev, int ioaddr) { - struct eth16i_local *lp; + struct eth16i_local *lp = dev->priv; static unsigned version_printed; int retval; - boot = 1; /* To inform initilization that we are in boot probe */ - /* Let's grab the region */ if (!request_region(ioaddr, ETH16I_IO_EXTENT, dev->name)) return -EBUSY; @@ -531,22 +552,13 @@ static int __init eth16i_probe1(struct n eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr); outb(0x38, ioaddr + TRANSCEIVER_MODE_REG); - eth16i_initialize(dev); /* Initialize rest of the chip's registers */ + eth16i_initialize(dev, 1); /* Initialize rest of the chip's registers */ /* Now let's same some energy by shutting down the chip ;) */ BITCLR(ioaddr + CONFIG_REG_1, POWERUP); /* Initialize the device structure */ - if(dev->priv == NULL) { - dev->priv = kmalloc(sizeof(struct eth16i_local), GFP_KERNEL); - if(dev->priv == NULL) { - free_irq(dev->irq, dev); - retval = -ENOMEM; - goto out; - } - } - - memset(dev->priv, 0, sizeof(struct eth16i_local)); + memset(lp, 0, sizeof(struct eth16i_local)); dev->open = eth16i_open; dev->stop = eth16i_close; dev->hard_start_xmit = eth16i_tx; @@ -554,15 +566,7 @@ static int __init eth16i_probe1(struct n dev->set_multicast_list = eth16i_multicast; dev->tx_timeout = eth16i_timeout; dev->watchdog_timeo = TX_TIMEOUT; - - lp = (struct eth16i_local *)dev->priv; spin_lock_init(&lp->lock); - - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - - boot = 0; - return 0; out: release_region(ioaddr, ETH16I_IO_EXTENT); @@ -570,7 +574,7 @@ out: } -static void eth16i_initialize(struct net_device *dev) +static void eth16i_initialize(struct net_device *dev, int boot) { int ioaddr = dev->base_addr; int i, node_w = 0; @@ -953,7 +957,7 @@ static int eth16i_open(struct net_device outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1); /* Initialize the chip */ - eth16i_initialize(dev); + eth16i_initialize(dev, 0); /* Set the transmit buffer size */ lp->tx_buf_size = eth16i_tx_buf_map[ETH16I_TX_BUF_SIZE & 0x03]; @@ -1401,7 +1405,7 @@ static ushort eth16i_parse_mediatype(con #define MAX_ETH16I_CARDS 4 /* Max number of Eth16i cards per module */ -static struct net_device dev_eth16i[MAX_ETH16I_CARDS]; +static struct net_device *dev_eth16i[MAX_ETH16I_CARDS]; static int io[MAX_ETH16I_CARDS]; #if 0 static int irq[MAX_ETH16I_CARDS]; @@ -1431,14 +1435,14 @@ MODULE_PARM_DESC(debug, "eth16i debug le int init_module(void) { int this_dev, found = 0; + struct net_device *dev; + + for (this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) { + dev = alloc_etherdev(sizeof(struct eth16i_local)); + if (!dev) + break; - for(this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) - { - struct net_device *dev = &dev_eth16i[this_dev]; - - dev->irq = 0; /* irq[this_dev]; */ dev->base_addr = io[this_dev]; - dev->init = eth16i_probe; if(debug != -1) eth16i_debug = debug; @@ -1448,44 +1452,43 @@ int init_module(void) dev->if_port = eth16i_parse_mediatype(mediatype[this_dev]); - if(io[this_dev] == 0) - { - if(this_dev != 0) break; /* Only autoprobe 1st one */ + if(io[this_dev] == 0) { + if(this_dev != 0) /* Only autoprobe 1st one */ + break; printk(KERN_NOTICE "eth16i.c: Presently autoprobing (not recommended) for a single card.\n"); } - if(register_netdev(dev) != 0) - { - printk(KERN_WARNING "eth16i.c No Eth16i card found (i/o = 0x%x).\n", - io[this_dev]); - - if(found != 0) return 0; - return -ENXIO; + if (do_eth16i_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_eth16i[found++] = dev; + continue; + } + free_irq(dev->irq, dev); + release_region(dev->base_addr, ETH16I_IO_EXTENT); } - - found++; + printk(KERN_WARNING "eth16i.c No Eth16i card found (i/o = 0x%x).\n", + io[this_dev]); + free_netdev(dev); + break; } - return 0; + if (found) + return 0; + return -ENXIO; } void cleanup_module(void) { int this_dev; - for(this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) - { - struct net_device* dev = &dev_eth16i[this_dev]; + for(this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) { + struct net_device *dev = dev_eth16i[this_dev]; - if(dev->priv != NULL) - { + if(dev->priv) { unregister_netdev(dev); - kfree(dev->priv); - dev->priv = NULL; - free_irq(dev->irq, dev); release_region(dev->base_addr, ETH16I_IO_EXTENT); - + free_netdev(dev); } } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/ethertap.c 830-ivtv/drivers/net/ethertap.c --- 000-virgin/drivers/net/ethertap.c Mon Dec 8 09:55:51 2003 +++ 830-ivtv/drivers/net/ethertap.c Thu Jan 8 08:54:16 2004 @@ -72,8 +72,7 @@ static int __init ethertap_probe(int un struct net_device *dev; int err = -ENOMEM; - dev = alloc_netdev(sizeof(struct net_local), "tap%d", - ether_setup); + dev = alloc_etherdev(sizeof(struct net_local)); if (!dev) goto out; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/ewrk3.c 830-ivtv/drivers/net/ewrk3.c --- 000-virgin/drivers/net/ewrk3.c Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/ewrk3.c Thu Jan 8 08:54:16 2004 @@ -324,25 +324,14 @@ static int Read_EEPROM(u_long iobase, u_ static int Write_EEPROM(short data, u_long iobase, u_char eaddr); static u_char get_hw_addr(struct net_device *dev, u_char * eeprom_image, char chipType); -static void isa_probe(struct net_device *dev, u_long iobase); -static void eisa_probe(struct net_device *dev, u_long iobase); -static struct net_device *alloc_device(struct net_device *dev, u_long iobase); -static int ewrk3_dev_index(char *s); -static struct net_device *insert_device(struct net_device *dev, u_long iobase, int (*init) (struct net_device *)); +static int ewrk3_probe1(struct net_device *dev, u_long iobase, int irq); +static int isa_probe(struct net_device *dev, u_long iobase); +static int eisa_probe(struct net_device *dev, u_long iobase); - -#ifdef MODULE -static int autoprobed = 1, loading_module = 1; - -#else -static u_char irq[] = -{5, 0, 10, 3, 11, 9, 15, 12}; -static int autoprobed, loading_module; - -#endif /* MODULE */ +static u_char irq[MAX_NUM_EWRK3S+1] = {5, 0, 10, 3, 11, 9, 15, 12}; static char name[EWRK3_STRLEN + 1]; -static int num_ewrk3s, num_eth; +static int num_ewrks3s; /* ** Miscellaneous defines... @@ -352,38 +341,50 @@ static int num_ewrk3s, num_eth; mdelay(1);\ } -int __init ewrk3_probe(struct net_device *dev) +struct net_device * __init ewrk3_probe(int unit) { - int tmp = num_ewrk3s, status = -ENODEV; - u_long iobase = dev->base_addr; + struct net_device *dev = alloc_etherdev(sizeof(struct ewrk3_private)); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } SET_MODULE_OWNER(dev); - if ((iobase == 0) && loading_module) { - printk("Autoprobing is not supported when loading a module based driver.\n"); - status = -EIO; - } else { /* First probe for the Ethernet */ - /* Address PROM pattern */ - isa_probe(dev, iobase); - eisa_probe(dev, iobase); - - if ((tmp == num_ewrk3s) && (iobase != 0) && loading_module) { - printk("%s: ewrk3_probe() cannot find device at 0x%04lx.\n", dev->name, - iobase); - } - /* - ** Walk the device list to check that at least one device - ** initialised OK - */ - for (; (dev->priv == NULL) && (dev->next != NULL); dev = dev->next); + err = ewrk3_probe1(dev, dev->base_addr, dev->irq); + if (err) + goto out; + return dev; +out: + free_netdev(dev); + return ERR_PTR(err); + +} - if (dev->priv) - status = 0; - if (iobase == 0) - autoprobed = 1; - } +static int __init ewrk3_probe1(struct net_device *dev, u_long iobase, int irq) +{ + int err; - return status; + dev->base_addr = iobase; + dev->irq = irq; + + /* Address PROM pattern */ + err = isa_probe(dev, iobase); + if (err != 0) + err = eisa_probe(dev, iobase); + + if (err) + return err; + + err = register_netdev(dev); + if (err) + release_region(dev->base_addr, EWRK3_TOTAL_SIZE); + + return err; } static int __init @@ -396,8 +397,8 @@ ewrk3_hw_init(struct net_device *dev, u_ u_char eeprom_image[EEPROM_MAX], chksum, eisa_cr = 0; /* - ** Stop the EWRK3. Enable the DBR ROM. Disable interrupts and remote boot. - ** This also disables the EISA_ENABLE bit in the EISA Control Register. + ** Stop the EWRK3. Enable the DBR ROM. Disable interrupts and remote boot. + ** This also disables the EISA_ENABLE bit in the EISA Control Register. */ if (iobase > 0x400) eisa_cr = inb(EISA_CR); @@ -409,232 +410,210 @@ ewrk3_hw_init(struct net_device *dev, u_ icr &= 0x70; outb(icr, EWRK3_ICR); /* Disable all the IRQs */ - if (nicsr == (CSR_TXD | CSR_RXD)) { + if (nicsr == (CSR_TXD | CSR_RXD)) + return -ENXIO; - /* Check that the EEPROM is alive and well and not living on Pluto... */ - for (chksum = 0, i = 0; i < EEPROM_MAX; i += 2) { - union { - short val; - char c[2]; - } tmp; - - tmp.val = (short) Read_EEPROM(iobase, (i >> 1)); - eeprom_image[i] = tmp.c[0]; - eeprom_image[i + 1] = tmp.c[1]; - chksum += eeprom_image[i] + eeprom_image[i + 1]; - } - - if (chksum != 0) { /* Bad EEPROM Data! */ - printk("%s: Device has a bad on-board EEPROM.\n", dev->name); - status = -ENXIO; - } else { - EthwrkSignature(name, eeprom_image); - if (*name != '\0') { /* found a EWRK3 device */ - dev->base_addr = iobase; - - if (iobase > 0x400) { - outb(eisa_cr, EISA_CR); /* Rewrite the EISA CR */ - } - lemac = eeprom_image[EEPROM_CHIPVER]; - cmr = inb(EWRK3_CMR); - - if (((lemac == LeMAC) && ((cmr & CMR_NO_EEPROM) != CMR_NO_EEPROM)) || - ((lemac == LeMAC2) && !(cmr & CMR_HS))) { - printk("%s: %s at %#4lx", dev->name, name, iobase); - hard_strapped = 1; - } else if ((iobase & 0x0fff) == EWRK3_EISA_IO_PORTS) { - /* EISA slot address */ - printk("%s: %s at %#4lx (EISA slot %ld)", - dev->name, name, iobase, ((iobase >> 12) & 0x0f)); - } else { /* ISA port address */ - printk("%s: %s at %#4lx", dev->name, name, iobase); - } - - if (!status) { - printk(", h/w address "); - if (lemac != LeMAC2) - DevicePresent(iobase); /* need after EWRK3_INIT */ - status = get_hw_addr(dev, eeprom_image, lemac); - for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet addr. */ - printk("%2.2x:", dev->dev_addr[i]); - } - printk("%2.2x,\n", dev->dev_addr[i]); - if (status) { - printk(" which has an EEPROM CRC error.\n"); - status = -ENXIO; - } else { - if (lemac == LeMAC2) { /* Special LeMAC2 CMR things */ - cmr &= ~(CMR_RA | CMR_WB | CMR_LINK | CMR_POLARITY | CMR_0WS); - if (eeprom_image[EEPROM_MISC0] & READ_AHEAD) - cmr |= CMR_RA; - if (eeprom_image[EEPROM_MISC0] & WRITE_BEHIND) - cmr |= CMR_WB; - if (eeprom_image[EEPROM_NETMAN0] & NETMAN_POL) - cmr |= CMR_POLARITY; - if (eeprom_image[EEPROM_NETMAN0] & NETMAN_LINK) - cmr |= CMR_LINK; - if (eeprom_image[EEPROM_MISC0] & _0WS_ENA) - cmr |= CMR_0WS; - } - if (eeprom_image[EEPROM_SETUP] & SETUP_DRAM) - cmr |= CMR_DRAM; - outb(cmr, EWRK3_CMR); - - cr = inb(EWRK3_CR); /* Set up the Control Register */ - cr |= eeprom_image[EEPROM_SETUP] & SETUP_APD; - if (cr & SETUP_APD) - cr |= eeprom_image[EEPROM_SETUP] & SETUP_PS; - cr |= eeprom_image[EEPROM_MISC0] & FAST_BUS; - cr |= eeprom_image[EEPROM_MISC0] & ENA_16; - outb(cr, EWRK3_CR); + /* Check that the EEPROM is alive and well and not living on Pluto... */ + for (chksum = 0, i = 0; i < EEPROM_MAX; i += 2) { + union { + short val; + char c[2]; + } tmp; + + tmp.val = (short) Read_EEPROM(iobase, (i >> 1)); + eeprom_image[i] = tmp.c[0]; + eeprom_image[i + 1] = tmp.c[1]; + chksum += eeprom_image[i] + eeprom_image[i + 1]; + } + + if (chksum != 0) { /* Bad EEPROM Data! */ + printk("%s: Device has a bad on-board EEPROM.\n", dev->name); + return -ENXIO; + } + + EthwrkSignature(name, eeprom_image); + if (*name == '\0') + return -ENXIO; + + dev->base_addr = iobase; + + if (iobase > 0x400) { + outb(eisa_cr, EISA_CR); /* Rewrite the EISA CR */ + } + lemac = eeprom_image[EEPROM_CHIPVER]; + cmr = inb(EWRK3_CMR); + + if (((lemac == LeMAC) && ((cmr & CMR_NO_EEPROM) != CMR_NO_EEPROM)) || + ((lemac == LeMAC2) && !(cmr & CMR_HS))) { + printk("%s: %s at %#4lx", dev->name, name, iobase); + hard_strapped = 1; + } else if ((iobase & 0x0fff) == EWRK3_EISA_IO_PORTS) { + /* EISA slot address */ + printk("%s: %s at %#4lx (EISA slot %ld)", + dev->name, name, iobase, ((iobase >> 12) & 0x0f)); + } else { /* ISA port address */ + printk("%s: %s at %#4lx", dev->name, name, iobase); + } + + printk(", h/w address "); + if (lemac != LeMAC2) + DevicePresent(iobase); /* need after EWRK3_INIT */ + status = get_hw_addr(dev, eeprom_image, lemac); + for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet addr. */ + printk("%2.2x:", dev->dev_addr[i]); + } + printk("%2.2x,\n", dev->dev_addr[i]); + + if (status) { + printk(" which has an EEPROM CRC error.\n"); + return -ENXIO; + } + + if (lemac == LeMAC2) { /* Special LeMAC2 CMR things */ + cmr &= ~(CMR_RA | CMR_WB | CMR_LINK | CMR_POLARITY | CMR_0WS); + if (eeprom_image[EEPROM_MISC0] & READ_AHEAD) + cmr |= CMR_RA; + if (eeprom_image[EEPROM_MISC0] & WRITE_BEHIND) + cmr |= CMR_WB; + if (eeprom_image[EEPROM_NETMAN0] & NETMAN_POL) + cmr |= CMR_POLARITY; + if (eeprom_image[EEPROM_NETMAN0] & NETMAN_LINK) + cmr |= CMR_LINK; + if (eeprom_image[EEPROM_MISC0] & _0WS_ENA) + cmr |= CMR_0WS; + } + if (eeprom_image[EEPROM_SETUP] & SETUP_DRAM) + cmr |= CMR_DRAM; + outb(cmr, EWRK3_CMR); + + cr = inb(EWRK3_CR); /* Set up the Control Register */ + cr |= eeprom_image[EEPROM_SETUP] & SETUP_APD; + if (cr & SETUP_APD) + cr |= eeprom_image[EEPROM_SETUP] & SETUP_PS; + cr |= eeprom_image[EEPROM_MISC0] & FAST_BUS; + cr |= eeprom_image[EEPROM_MISC0] & ENA_16; + outb(cr, EWRK3_CR); - /* - ** Determine the base address and window length for the EWRK3 - ** RAM from the memory base register. - */ - mem_start = inb(EWRK3_MBR); - shmem_length = 0; - if (mem_start != 0) { - if ((mem_start >= 0x0a) && (mem_start <= 0x0f)) { - mem_start *= SHMEM_64K; - shmem_length = SHMEM_64K; - } else if ((mem_start >= 0x14) && (mem_start <= 0x1f)) { - mem_start *= SHMEM_32K; - shmem_length = SHMEM_32K; - } else if ((mem_start >= 0x40) && (mem_start <= 0xff)) { - mem_start = mem_start * SHMEM_2K + 0x80000; - shmem_length = SHMEM_2K; - } else { - status = -ENXIO; - } - } - /* - ** See the top of this source code for comments about - ** uncommenting this line. - */ + /* + ** Determine the base address and window length for the EWRK3 + ** RAM from the memory base register. + */ + mem_start = inb(EWRK3_MBR); + shmem_length = 0; + if (mem_start != 0) { + if ((mem_start >= 0x0a) && (mem_start <= 0x0f)) { + mem_start *= SHMEM_64K; + shmem_length = SHMEM_64K; + } else if ((mem_start >= 0x14) && (mem_start <= 0x1f)) { + mem_start *= SHMEM_32K; + shmem_length = SHMEM_32K; + } else if ((mem_start >= 0x40) && (mem_start <= 0xff)) { + mem_start = mem_start * SHMEM_2K + 0x80000; + shmem_length = SHMEM_2K; + } else { + return -ENXIO; + } + } + /* + ** See the top of this source code for comments about + ** uncommenting this line. + */ /* FORCE_2K_MODE; */ + + if (hard_strapped) { + printk(" is hard strapped.\n"); + } else if (mem_start) { + printk(" has a %dk RAM window", (int) (shmem_length >> 10)); + printk(" at 0x%.5lx", mem_start); + } else { + printk(" is in I/O only mode"); + } - if (!status) { - if (hard_strapped) { - printk(" is hard strapped.\n"); - } else if (mem_start) { - printk(" has a %dk RAM window", (int) (shmem_length >> 10)); - printk(" at 0x%.5lx", mem_start); - } else { - printk(" is in I/O only mode"); - } - - /* private area & initialise */ - dev->priv = (void *) kmalloc(sizeof(struct ewrk3_private), - GFP_KERNEL); - if (dev->priv == NULL) { - return -ENOMEM; - } - lp = (struct ewrk3_private *) dev->priv; - memset(dev->priv, 0, sizeof(struct ewrk3_private)); - lp->shmem_base = mem_start; - lp->shmem_length = shmem_length; - lp->lemac = lemac; - lp->hard_strapped = hard_strapped; - lp->led_mask = CR_LED; - spin_lock_init(&lp->hw_lock); - - lp->mPage = 64; - if (cmr & CMR_DRAM) - lp->mPage <<= 1; /* 2 DRAMS on module */ - - sprintf(lp->adapter_name, "%s (%s)", name, dev->name); - request_region(iobase, EWRK3_TOTAL_SIZE, lp->adapter_name); - - lp->irq_mask = ICR_TNEM | ICR_TXDM | ICR_RNEM | ICR_RXDM; - - if (!hard_strapped) { - /* - ** Enable EWRK3 board interrupts for autoprobing - */ - icr |= ICR_IE; /* Enable interrupts */ - outb(icr, EWRK3_ICR); - - /* The DMA channel may be passed in on this parameter. */ - dev->dma = 0; - - /* To auto-IRQ we enable the initialization-done and DMA err, - interrupts. For now we will always get a DMA error. */ - if (dev->irq < 2) { + lp = (struct ewrk3_private *) dev->priv; + lp->shmem_base = mem_start; + lp->shmem_length = shmem_length; + lp->lemac = lemac; + lp->hard_strapped = hard_strapped; + lp->led_mask = CR_LED; + spin_lock_init(&lp->hw_lock); + + lp->mPage = 64; + if (cmr & CMR_DRAM) + lp->mPage <<= 1; /* 2 DRAMS on module */ + + sprintf(lp->adapter_name, "%s (%s)", name, dev->name); + + lp->irq_mask = ICR_TNEM | ICR_TXDM | ICR_RNEM | ICR_RXDM; + + if (!hard_strapped) { + /* + ** Enable EWRK3 board interrupts for autoprobing + */ + icr |= ICR_IE; /* Enable interrupts */ + outb(icr, EWRK3_ICR); + + /* The DMA channel may be passed in on this parameter. */ + dev->dma = 0; + + /* To auto-IRQ we enable the initialization-done and DMA err, + interrupts. For now we will always get a DMA error. */ + if (dev->irq < 2) { #ifndef MODULE - u_char irqnum; - unsigned long irq_mask; + u_char irqnum; + unsigned long irq_mask; - irq_mask = probe_irq_on(); - - /* - ** Trigger a TNE interrupt. - */ - icr |= ICR_TNEM; - outb(1, EWRK3_TDQ); /* Write to the TX done queue */ - outb(icr, EWRK3_ICR); /* Unmask the TXD interrupt */ - - irqnum = irq[((icr & IRQ_SEL) >> 4)]; - - mdelay(20); - dev->irq = probe_irq_off(irq_mask); - if ((dev->irq) && (irqnum == dev->irq)) { - printk(" and uses IRQ%d.\n", dev->irq); - } else { - if (!dev->irq) { - printk(" and failed to detect IRQ line.\n"); - } else if ((irqnum == 1) && (lemac == LeMAC2)) { - printk(" and an illegal IRQ line detected.\n"); - } else { - printk(", but incorrect IRQ line detected.\n"); - } - status = -ENXIO; - } - - DISABLE_IRQs; /* Mask all interrupts */ - -#endif /* MODULE */ - } else { - printk(" and requires IRQ%d.\n", dev->irq); - } - } - if (status) - release_region(iobase, EWRK3_TOTAL_SIZE); - } else { - status = -ENXIO; - } - } - } + irq_mask = probe_irq_on(); + + /* + ** Trigger a TNE interrupt. + */ + icr |= ICR_TNEM; + outb(1, EWRK3_TDQ); /* Write to the TX done queue */ + outb(icr, EWRK3_ICR); /* Unmask the TXD interrupt */ + + irqnum = irq[((icr & IRQ_SEL) >> 4)]; + + mdelay(20); + dev->irq = probe_irq_off(irq_mask); + if ((dev->irq) && (irqnum == dev->irq)) { + printk(" and uses IRQ%d.\n", dev->irq); } else { - status = -ENXIO; - } - } - - if (!status) { - if (ewrk3_debug > 1) { - printk(version); + if (!dev->irq) { + printk(" and failed to detect IRQ line.\n"); + } else if ((irqnum == 1) && (lemac == LeMAC2)) { + printk(" and an illegal IRQ line detected.\n"); + } else { + printk(", but incorrect IRQ line detected.\n"); + } + return -ENXIO; } - /* The EWRK3-specific entries in the device structure. */ - dev->open = ewrk3_open; - dev->hard_start_xmit = ewrk3_queue_pkt; - dev->stop = ewrk3_close; - dev->get_stats = ewrk3_get_stats; - dev->set_multicast_list = set_multicast_list; - dev->do_ioctl = ewrk3_ioctl; - dev->tx_timeout = ewrk3_timeout; - dev->watchdog_timeo = QUEUE_PKT_TIMEOUT; - dev->mem_start = 0; + DISABLE_IRQs; /* Mask all interrupts */ - /* Fill in the generic field of the device structure. */ - ether_setup(dev); +#endif /* MODULE */ + } else { + printk(" and requires IRQ%d.\n", dev->irq); } - } else { - status = -ENXIO; } - return status; + + if (ewrk3_debug > 1) { + printk(version); + } + /* The EWRK3-specific entries in the device structure. */ + dev->open = ewrk3_open; + dev->hard_start_xmit = ewrk3_queue_pkt; + dev->stop = ewrk3_close; + dev->get_stats = ewrk3_get_stats; + dev->set_multicast_list = set_multicast_list; + dev->do_ioctl = ewrk3_ioctl; + dev->tx_timeout = ewrk3_timeout; + dev->watchdog_timeo = QUEUE_PKT_TIMEOUT; + + dev->mem_start = 0; + + return 0; } @@ -1269,15 +1248,15 @@ static void SetMulticastFilter(struct ne /* ** ISA bus I/O device probe */ -static void __init isa_probe(struct net_device *dev, u_long ioaddr) +static int __init isa_probe(struct net_device *dev, u_long ioaddr) { - int i = num_ewrk3s, maxSlots; + int i = num_ewrks3s, maxSlots; + int ret = -ENODEV; + u_long iobase; - if (!ioaddr && autoprobed) - return; /* Been here before ! */ if (ioaddr >= 0x400) - return; /* Not ISA */ + goto out; if (ioaddr == 0) { /* Autoprobing */ iobase = EWRK3_IO_BASE; /* Get the first slot address */ @@ -1287,38 +1266,37 @@ static void __init isa_probe(struct net_ maxSlots = i + 1; } - for (; (i < maxSlots) && (dev != NULL); iobase += EWRK3_IOP_INC, i++) { - if (!check_region(iobase, EWRK3_TOTAL_SIZE)) { + for (; (i < maxSlots) && (dev != NULL); + iobase += EWRK3_IOP_INC, i++) + { + if (request_region(iobase, EWRK3_TOTAL_SIZE, dev->name)) { if (DevicePresent(iobase) == 0) { - if ((dev = alloc_device(dev, iobase)) != NULL) { - if (ewrk3_hw_init(dev, iobase) == 0) { - num_ewrk3s++; - } - num_eth++; - } + int irq = dev->irq; + ret = ewrk3_hw_init(dev, iobase); + if (!ret) + break; + dev->irq = irq; } - } else if (autoprobed) { - printk("%s: region already allocated at 0x%04lx.\n", dev->name, iobase); + release_region(iobase, EWRK3_TOTAL_SIZE); } } + out: - return; + return ret; } /* ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually ** the motherboard. */ -static void __init eisa_probe(struct net_device *dev, u_long ioaddr) +static int __init eisa_probe(struct net_device *dev, u_long ioaddr) { int i, maxSlots; u_long iobase; - char name[EWRK3_STRLEN]; + int ret = -ENODEV; - if (!ioaddr && autoprobed) - return; /* Been here before ! */ if (ioaddr < 0x1000) - return; /* Not EISA */ + goto out; if (ioaddr == 0) { /* Autoprobing */ iobase = EISA_SLOT_INC; /* Get the first slot address */ @@ -1332,114 +1310,22 @@ static void __init eisa_probe(struct net for (i = 1; (i < maxSlots) && (dev != NULL); i++, iobase += EISA_SLOT_INC) { if (EISA_signature(name, EISA_ID) == 0) { - if (!check_region(iobase, EWRK3_TOTAL_SIZE)) { - if (DevicePresent(iobase) == 0) { - if ((dev = alloc_device(dev, iobase)) != NULL) { - if (ewrk3_hw_init(dev, iobase) == 0) { - num_ewrk3s++; - } - num_eth++; - } - } - } else if (autoprobed) { - printk("%s: region already allocated at 0x%04lx.\n", dev->name, iobase); + if (request_region(iobase, EWRK3_TOTAL_SIZE, dev->name) && + DevicePresent(iobase) == 0) { + int irq = dev->irq; + ret = ewrk3_hw_init(dev, iobase); + if (!ret) + break; + dev->irq = irq; } + release_region(iobase, EWRK3_TOTAL_SIZE); } } - return; + out: + return ret; } -/* - ** Search the entire 'eth' device list for a fixed probe. If a match isn't - ** found then check for an autoprobe or unused device location. If they - ** are not available then insert a new device structure at the end of - ** the current list. - */ -static struct net_device * __init alloc_device(struct net_device *dev, u_long iobase) -{ - struct net_device *adev = NULL; - int fixed = 0, new_dev = 0; - - num_eth = ewrk3_dev_index(dev->name); - if (loading_module) - return dev; - - while (1) { - if (((dev->base_addr == EWRK3_NDA) || (dev->base_addr == 0)) && !adev) { - adev = dev; - } else if ((dev->priv == NULL) && (dev->base_addr == iobase)) { - fixed = 1; - } else { - if (dev->next == NULL) { - new_dev = 1; - } else if (strncmp(dev->next->name, "eth", 3) != 0) { - new_dev = 1; - } - } - if ((dev->next == NULL) || new_dev || fixed) - break; - dev = dev->next; - num_eth++; - } - if (adev && !fixed) { - dev = adev; - num_eth = ewrk3_dev_index(dev->name); - new_dev = 0; - } - if (((dev->next == NULL) && - ((dev->base_addr != EWRK3_NDA) && (dev->base_addr != 0)) && !fixed) || - new_dev) { - num_eth++; /* New device */ - dev = insert_device(dev, iobase, ewrk3_probe); - } - return dev; -} - -/* - ** If at end of eth device list and can't use current entry, malloc - ** one up. If memory could not be allocated, print an error message. - */ -static struct net_device * __init -insert_device(struct net_device *dev, u_long iobase, int (*init) (struct net_device *)) -{ - struct net_device *new; - - new = (struct net_device *) kmalloc(sizeof(struct net_device) + 8, GFP_KERNEL); - if (new == NULL) { - printk("eth%d: Device not initialised, insufficient memory\n", num_eth); - return NULL; - } else { - new->next = dev->next; - dev->next = new; - dev = dev->next; /* point to the new device */ - if (num_eth > 9999) { - sprintf(dev->name, "eth????"); /* New device name */ - } else { - sprintf(dev->name, "eth%d", num_eth); /* New device name */ - } - dev->base_addr = iobase; /* assign the io address */ - dev->init = init; /* initialisation routine */ - } - - return dev; -} - -static int __init -ewrk3_dev_index(char *s) -{ - int i = 0, j = 0; - - for (; *s; s++) { - if (isdigit(*s)) { - j = 1; - i = (i * 10) + (*s - '0'); - } else if (j) - break; - } - - return i; -} /* ** Read the EWRK3 EEPROM using this routine @@ -2074,8 +1960,7 @@ static int ewrk3_ioctl(struct net_device #ifdef MODULE static struct net_device *ewrk3_devs[MAX_NUM_EWRK3S]; static int ndevs; -static int io[MAX_NUM_EWRK3S+1] = { 0x300, 0, }; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */ -static int irq[MAX_NUM_EWRK3S+1] = { 5, 0, }; /* or use the insmod io= irq= options */ +static int io[MAX_NUM_EWRK3S+1] = { 0x300, 0, }; /* '21' below should really be 'MAX_NUM_EWRK3S' */ MODULE_PARM(io, "0-21i"); @@ -2083,50 +1968,39 @@ MODULE_PARM(irq, "0-21i"); MODULE_PARM_DESC(io, "EtherWORKS 3 I/O base address(es)"); MODULE_PARM_DESC(irq, "EtherWORKS 3 IRQ number(s)"); -static void ewrk3_exit_module(void) +static __exit void ewrk3_exit_module(void) { int i; for( i=0; ipriv) { - kfree(ewrk3_devs[i]->priv); - ewrk3_devs[i]->priv = NULL; - } - ewrk3_devs[i]->irq = 0; - release_region(ewrk3_devs[i]->base_addr, EWRK3_TOTAL_SIZE); free_netdev(ewrk3_devs[i]); ewrk3_devs[i] = NULL; } } -static int ewrk3_init_module(void) +static __init int ewrk3_init_module(void) { int i=0; while( io[i] && irq[i] ) { - ewrk3_devs[ndevs] = kmalloc(sizeof(struct net_device), GFP_KERNEL); - if (!ewrk3_devs[ndevs]) - goto error; - memset(ewrk3_devs[ndevs], 0, sizeof(struct net_device)); - ewrk3_devs[ndevs]->base_addr = io[i]; - ewrk3_devs[ndevs]->irq = irq[i]; - ewrk3_devs[ndevs]->init = ewrk3_probe; - - if (register_netdev(ewrk3_devs[ndevs]) == 0) - ndevs++; - else - kfree(ewrk3_devs[ndevs]); + struct net_device *dev + = alloc_etherdev(sizeof(struct ewrk3_private)); + + if (!dev) + break; + if (ewrk3_probe1(dev, io[i], irq[i]) != 0) { + free_netdev(dev); + break; + } + + ewrk3_devs[ndevs++] = dev; i++; } return ndevs ? 0 : -EIO; - -error: - ewrk3_exit_module(); - return -ENOMEM; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/fc/iph5526.c 830-ivtv/drivers/net/fc/iph5526.c --- 000-virgin/drivers/net/fc/iph5526.c Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/fc/iph5526.c Thu Jan 8 08:54:16 2004 @@ -259,6 +259,7 @@ static int __init iph5526_probe_pci(stru static int __init fcdev_init(struct net_device *dev) { + SET_MODULE_OWNER(dev); dev->open = iph5526_open; dev->stop = iph5526_close; dev->hard_start_xmit = iph5526_send_packet; @@ -2896,14 +2897,12 @@ static void update_EDB_indx(struct fc_in static int iph5526_open(struct net_device *dev) { netif_start_queue(dev); - MOD_INC_USE_COUNT; return 0; } static int iph5526_close(struct net_device *dev) { netif_stop_queue(dev); - MOD_DEC_USE_COUNT; return 0; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/fc/iph5526_scsi.h 830-ivtv/drivers/net/fc/iph5526_scsi.h --- 000-virgin/drivers/net/fc/iph5526_scsi.h Mon Dec 16 21:50:44 2002 +++ 830-ivtv/drivers/net/fc/iph5526_scsi.h Thu Jan 8 08:54:16 2004 @@ -25,7 +25,7 @@ int iph5526_queuecommand(Scsi_Cmnd *Cmnd int iph5526_release(struct Scsi_Host *host); int iph5526_abort(Scsi_Cmnd *Cmnd); const char *iph5526_info(struct Scsi_Host *host); -int iph5526_biosparam(Disk * disk, struct block_device *n, int ip[]); +int iph5526_biosparam(struct Scsi_Disk * disk, struct block_device *n, int ip[]); #endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/fmv18x.c 830-ivtv/drivers/net/fmv18x.c --- 000-virgin/drivers/net/fmv18x.c Mon Nov 17 18:28:14 2003 +++ 830-ivtv/drivers/net/fmv18x.c Thu Jan 8 08:54:16 2004 @@ -57,7 +57,7 @@ static const char version[] = #include #include -static int fmv18x_probe_list[] __initdata = { +static unsigned fmv18x_probe_list[] __initdata = { 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x300, 0x340, 0 }; @@ -109,8 +109,6 @@ struct net_local { /* Index to functions, as function prototypes. */ -extern int fmv18x_probe(struct net_device *dev); - static int fmv18x_probe1(struct net_device *dev, short ioaddr); static int net_open(struct net_device *dev); static int net_send_packet(struct sk_buff *skb, struct net_device *dev); @@ -129,23 +127,50 @@ static void set_multicast_list(struct ne (detachable devices only). */ -int __init fmv18x_probe(struct net_device *dev) +static int io = 0x220; +static int irq; + +struct net_device * __init fmv18x_probe(int unit) { - int i; - int base_addr = dev->base_addr; + struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); + unsigned *port; + int err = 0; + + if (!dev) + return ERR_PTR(-ENODEV); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + irq = dev->irq; + } SET_MODULE_OWNER(dev); - if (base_addr > 0x1ff) /* Check a single specified location. */ - return fmv18x_probe1(dev, base_addr); - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; - - for (i = 0; fmv18x_probe_list[i]; i++) - if (fmv18x_probe1(dev, fmv18x_probe_list[i]) == 0) - return 0; - - return -ENODEV; + if (io > 0x1ff) { /* Check a single specified location. */ + err = fmv18x_probe1(dev, io); + } else if (io != 0) { /* Don't probe at all. */ + err = -ENXIO; + } else { + for (port = fmv18x_probe_list; *port; port++) + if (fmv18x_probe1(dev, *port) == 0) + break; + if (!*port) + err = -ENODEV; + } + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + free_irq(dev->irq, dev); + release_region(dev->base_addr, FMV18X_IO_EXTENT); +out: + free_netdev(dev); + return ERR_PTR(err); } /* The Fujitsu datasheet suggests that the NIC be probed for by checking its @@ -160,7 +185,7 @@ static int __init fmv18x_probe1(struct n { char irqmap[4] = {3, 7, 10, 15}; char irqmap_pnp[8] = {3, 4, 5, 7, 9, 10, 11, 15}; - unsigned int i, irq, retval; + unsigned int i, retval; struct net_local *lp; /* Resetting the chip doesn't reset the ISA interface, so don't bother. @@ -170,6 +195,9 @@ static int __init fmv18x_probe1(struct n if (!request_region(ioaddr, FMV18X_IO_EXTENT, dev->name)) return -EBUSY; + dev->irq = irq; + dev->base_addr = ioaddr; + /* Check I/O address configuration and Fujitsu vendor code */ if (inb(ioaddr+FJ_MACADDR ) != 0x00 || inb(ioaddr+FJ_MACADDR+1) != 0x00 @@ -181,9 +209,8 @@ static int __init fmv18x_probe1(struct n /* Check PnP mode for FMV-183/184/183A/184A. */ /* This PnP routine is very poor. IO and IRQ should be known. */ if (inb(ioaddr + FJ_STATUS1) & 0x20) { - irq = dev->irq; for (i = 0; i < 8; i++) { - if (irq == irqmap_pnp[i]) + if (dev->irq == irqmap_pnp[i]) break; } if (i == 8) { @@ -193,22 +220,19 @@ static int __init fmv18x_probe1(struct n } else { if (fmv18x_probe_list[inb(ioaddr + FJ_CONFIG0) & 0x07] != ioaddr) return -ENODEV; - irq = irqmap[(inb(ioaddr + FJ_CONFIG0)>>6) & 0x03]; + dev->irq = irqmap[(inb(ioaddr + FJ_CONFIG0)>>6) & 0x03]; } /* Snarf the interrupt vector now. */ - retval = request_irq(irq, &net_interrupt, 0, dev->name, dev); + retval = request_irq(dev->irq, &net_interrupt, 0, dev->name, dev); if (retval) { printk ("FMV-18x found at %#3x, but it's unusable due to a conflict on" - "IRQ %d.\n", ioaddr, irq); + "IRQ %d.\n", ioaddr, dev->irq); goto out; } printk("%s: FMV-18x found at %#3x, IRQ %d, address ", dev->name, - ioaddr, irq); - - dev->base_addr = ioaddr; - dev->irq = irq; + ioaddr, dev->irq); for(i = 0; i < 6; i++) { unsigned char val = inb(ioaddr + FJ_MACADDR + i); @@ -279,14 +303,10 @@ static int __init fmv18x_probe1(struct n dev->watchdog_timeo = HZ/10; dev->get_stats = net_get_stats; dev->set_multicast_list = set_multicast_list; - - /* Fill in the fields of 'dev' with ethernet-generic values. */ - - ether_setup(dev); return 0; out_irq: - free_irq(irq, dev); + free_irq(dev->irq, dev); out: release_region(ioaddr, FMV18X_IO_EXTENT); return retval; @@ -413,9 +433,7 @@ static int net_send_packet(struct sk_buf lp->tx_queue_len = 0; dev->trans_start = jiffies; lp->tx_started = 1; - } else if (lp->tx_queue_len < 4096 - 1502) - /* Yes, there is room for one more packet. */ - else + } else if (lp->tx_queue_len >= 4096 - 1502) /* No room for a packet */ netif_stop_queue(dev); dev_kfree_skb(skb); @@ -628,9 +646,7 @@ static void set_multicast_list(struct ne } #ifdef MODULE -static struct net_device dev_fmv18x; -static int io = 0x220; -static int irq; +static struct net_device *dev_fmv18x; MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); @@ -644,26 +660,19 @@ int init_module(void) { if (io == 0) printk("fmv18x: You should not use auto-probing with insmod!\n"); - dev_fmv18x.base_addr = io; - dev_fmv18x.irq = irq; - dev_fmv18x.init = fmv18x_probe; - if (register_netdev(&dev_fmv18x) != 0) { - printk("fmv18x: register_netdev() returned non-zero.\n"); - return -EIO; - } + dev_fmv18x = fmv18x_probe(-1); + if (IS_ERR(dev_fmv18x)) + return PTR_ERR(dev_fmv18x); return 0; } void cleanup_module(void) { - unregister_netdev(&dev_fmv18x); - kfree(dev_fmv18x.priv); - dev_fmv18x.priv = NULL; - - /* If we don't do this, we can't re-insmod it later. */ - free_irq(dev_fmv18x.irq, &dev_fmv18x); - release_region(dev_fmv18x.base_addr, FMV18X_IO_EXTENT); + unregister_netdev(dev_fmv18x); + free_irq(dev_fmv18x->irq, dev_fmv18x); + release_region(dev_fmv18x->base_addr, FMV18X_IO_EXTENT); + free_netdev(dev_fmv18x); } #endif /* MODULE */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/forcedeth.c 830-ivtv/drivers/net/forcedeth.c --- 000-virgin/drivers/net/forcedeth.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/net/forcedeth.c Thu Jan 8 08:54:16 2004 @@ -0,0 +1,1495 @@ +/* + * forcedeth: Ethernet driver for NVIDIA nForce media access controllers. + * + * Note: This driver is a cleanroom reimplementation based on reverse + * engineered documentation written by Carl-Daniel Hailfinger + * and Andrew de Quincey. It's neither supported nor endorsed + * by NVIDIA Corp. Use at your own risk. + * + * NVIDIA, nForce and other NVIDIA marks are trademarks or registered + * trademarks of NVIDIA Corporation in the United States and other + * countries. + * + * Copyright (C) 2003 Manfred Spraul + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Changelog: + * 0.01: 05 Oct 2003: First release that compiles without warnings. + * 0.02: 05 Oct 2003: Fix bug for drain_tx: do not try to free NULL skbs. + * Check all PCI BARs for the register window. + * udelay added to mii_rw. + * 0.03: 06 Oct 2003: Initialize dev->irq. + * 0.04: 07 Oct 2003: Initialize np->lock, reduce handled irqs, add printks. + * 0.05: 09 Oct 2003: printk removed again, irq status print tx_timeout. + * 0.06: 10 Oct 2003: MAC Address read updated, pff flag generation updated, + * irq mask updated + * 0.07: 14 Oct 2003: Further irq mask updates. + * 0.08: 20 Oct 2003: rx_desc.Length initialization added, alloc_rx refill + * added into irq handler, NULL check for drain_ring. + * 0.09: 20 Oct 2003: Basic link speed irq implementation. Only handle the + * requested interrupt sources. + * 0.10: 20 Oct 2003: First cleanup for release. + * 0.11: 21 Oct 2003: hexdump for tx added, rx buffer sizes increased. + * MAC Address init fix, set_multicast cleanup. + * 0.12: 23 Oct 2003: Cleanups for release. + * 0.13: 25 Oct 2003: Limit for concurrent tx packets increased to 10. + * Set link speed correctly. start rx before starting + * tx (start_rx sets the link speed). + * 0.14: 25 Oct 2003: Nic dependant irq mask. + * 0.15: 08 Nov 2003: fix smp deadlock with set_multicast_list during + * open. + * 0.16: 15 Nov 2003: include file cleanup for ppc64, rx buffer size + * increased to 1628 bytes. + * 0.17: 16 Nov 2003: undo rx buffer size increase. Substract 1 from + * the tx length. + * 0.18: 17 Nov 2003: fix oops due to late initialization of dev_stats + * 0.19: 29 Nov 2003: Handle RxNoBuf, detect & handle invalid mac + * addresses, really stop rx if already running + * in start_rx, clean up a bit. + * (C) Carl-Daniel Hailfinger + * + * Known bugs: + * The irq handling is wrong - no tx done interrupts are generated. + * This means recovery from netif_stop_queue only happens in the hw timer + * interrupt (1/2 second on nForce2, 1/100 second on nForce3), or if an + * rx packet arrives by chance. + */ +#define FORCEDETH_VERSION "0.19" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#if 0 +#define dprintk printk +#else +#define dprintk(x...) do { } while (0) +#endif + + +/* + * Hardware access: + */ + +#define DEV_NEED_LASTPACKET1 0x0001 +#define DEV_IRQMASK_1 0x0002 +#define DEV_IRQMASK_2 0x0004 + +enum { + NvRegIrqStatus = 0x000, +#define NVREG_IRQSTAT_MIIEVENT 0x040 +#define NVREG_IRQSTAT_MASK 0x1ff + NvRegIrqMask = 0x004, +#define NVREG_IRQ_RX 0x0002 +#define NVREG_IRQ_RX_NOBUF 0x0004 +#define NVREG_IRQ_TX_ERR 0x0008 +#define NVREG_IRQ_TX2 0x0010 +#define NVREG_IRQ_TIMER 0x0020 +#define NVREG_IRQ_LINK 0x0040 +#define NVREG_IRQ_TX1 0x0100 +#define NVREG_IRQMASK_WANTED_1 0x005f +#define NVREG_IRQMASK_WANTED_2 0x0147 +#define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR|NVREG_IRQ_TX2|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX1)) + + NvRegUnknownSetupReg6 = 0x008, +#define NVREG_UNKSETUP6_VAL 3 + + NvRegPollingInterval = 0x00c, + NvRegMisc1 = 0x080, +#define NVREG_MISC1_HD 0x02 +#define NVREG_MISC1_FORCE 0x3b0f3c + + NvRegTransmitterControl = 0x084, +#define NVREG_XMITCTL_START 0x01 + NvRegTransmitterStatus = 0x088, +#define NVREG_XMITSTAT_BUSY 0x01 + + NvRegPacketFilterFlags = 0x8c, +#define NVREG_PFF_ALWAYS 0x7F0008 +#define NVREG_PFF_PROMISC 0x80 +#define NVREG_PFF_MYADDR 0x20 + + NvRegOffloadConfig = 0x90, +#define NVREG_OFFLOAD_HOMEPHY 0x601 +#define NVREG_OFFLOAD_NORMAL 0x5ee + NvRegReceiverControl = 0x094, +#define NVREG_RCVCTL_START 0x01 + NvRegReceiverStatus = 0x98, +#define NVREG_RCVSTAT_BUSY 0x01 + + NvRegRandomSeed = 0x9c, +#define NVREG_RNDSEED_MASK 0x00ff +#define NVREG_RNDSEED_FORCE 0x7f00 + + NvRegUnknownSetupReg1 = 0xA0, +#define NVREG_UNKSETUP1_VAL 0x16070f + NvRegUnknownSetupReg2 = 0xA4, +#define NVREG_UNKSETUP2_VAL 0x16 + NvRegMacAddrA = 0xA8, + NvRegMacAddrB = 0xAC, + NvRegMulticastAddrA = 0xB0, +#define NVREG_MCASTADDRA_FORCE 0x01 + NvRegMulticastAddrB = 0xB4, + NvRegMulticastMaskA = 0xB8, + NvRegMulticastMaskB = 0xBC, + + NvRegTxRingPhysAddr = 0x100, + NvRegRxRingPhysAddr = 0x104, + NvRegRingSizes = 0x108, +#define NVREG_RINGSZ_TXSHIFT 0 +#define NVREG_RINGSZ_RXSHIFT 16 + NvRegUnknownTransmitterReg = 0x10c, + NvRegLinkSpeed = 0x110, +#define NVREG_LINKSPEED_FORCE 0x10000 +#define NVREG_LINKSPEED_10 10 +#define NVREG_LINKSPEED_100 100 +#define NVREG_LINKSPEED_1000 1000 + NvRegUnknownSetupReg5 = 0x130, +#define NVREG_UNKSETUP5_BIT31 (1<<31) + NvRegUnknownSetupReg3 = 0x134, +#define NVREG_UNKSETUP3_VAL1 0x200010 + NvRegTxRxControl = 0x144, +#define NVREG_TXRXCTL_KICK 0x0001 +#define NVREG_TXRXCTL_BIT1 0x0002 +#define NVREG_TXRXCTL_BIT2 0x0004 +#define NVREG_TXRXCTL_IDLE 0x0008 +#define NVREG_TXRXCTL_RESET 0x0010 + NvRegMIIStatus = 0x180, +#define NVREG_MIISTAT_ERROR 0x0001 +#define NVREG_MIISTAT_LINKCHANGE 0x0008 +#define NVREG_MIISTAT_MASK 0x000f +#define NVREG_MIISTAT_MASK2 0x000f + NvRegUnknownSetupReg4 = 0x184, +#define NVREG_UNKSETUP4_VAL 8 + + NvRegAdapterControl = 0x188, +#define NVREG_ADAPTCTL_START 0x02 +#define NVREG_ADAPTCTL_LINKUP 0x04 +#define NVREG_ADAPTCTL_PHYVALID 0x4000 +#define NVREG_ADAPTCTL_RUNNING 0x100000 +#define NVREG_ADAPTCTL_PHYSHIFT 24 + NvRegMIISpeed = 0x18c, +#define NVREG_MIISPEED_BIT8 (1<<8) +#define NVREG_MIIDELAY 5 + NvRegMIIControl = 0x190, +#define NVREG_MIICTL_INUSE 0x10000 +#define NVREG_MIICTL_WRITE 0x08000 +#define NVREG_MIICTL_ADDRSHIFT 5 + NvRegMIIData = 0x194, + NvRegWakeUpFlags = 0x200, +#define NVREG_WAKEUPFLAGS_VAL 0x7770 +#define NVREG_WAKEUPFLAGS_BUSYSHIFT 24 +#define NVREG_WAKEUPFLAGS_ENABLESHIFT 16 +#define NVREG_WAKEUPFLAGS_D3SHIFT 12 +#define NVREG_WAKEUPFLAGS_D2SHIFT 8 +#define NVREG_WAKEUPFLAGS_D1SHIFT 4 +#define NVREG_WAKEUPFLAGS_D0SHIFT 0 +#define NVREG_WAKEUPFLAGS_ACCEPT_MAGPAT 0x01 +#define NVREG_WAKEUPFLAGS_ACCEPT_WAKEUPPAT 0x02 +#define NVREG_WAKEUPFLAGS_ACCEPT_LINKCHANGE 0x04 + + NvRegPatternCRC = 0x204, + NvRegPatternMask = 0x208, + NvRegPowerCap = 0x268, +#define NVREG_POWERCAP_D3SUPP (1<<30) +#define NVREG_POWERCAP_D2SUPP (1<<26) +#define NVREG_POWERCAP_D1SUPP (1<<25) + NvRegPowerState = 0x26c, +#define NVREG_POWERSTATE_POWEREDUP 0x8000 +#define NVREG_POWERSTATE_VALID 0x0100 +#define NVREG_POWERSTATE_MASK 0x0003 +#define NVREG_POWERSTATE_D0 0x0000 +#define NVREG_POWERSTATE_D1 0x0001 +#define NVREG_POWERSTATE_D2 0x0002 +#define NVREG_POWERSTATE_D3 0x0003 +}; + +struct ring_desc { + u32 PacketBuffer; + u16 Length; + u16 Flags; +}; + +#define NV_TX_LASTPACKET (1<<0) +#define NV_TX_RETRYERROR (1<<3) +#define NV_TX_LASTPACKET1 (1<<8) +#define NV_TX_DEFERRED (1<<10) +#define NV_TX_CARRIERLOST (1<<11) +#define NV_TX_LATECOLLISION (1<<12) +#define NV_TX_UNDERFLOW (1<<13) +#define NV_TX_ERROR (1<<14) +#define NV_TX_VALID (1<<15) + +#define NV_RX_DESCRIPTORVALID (1<<0) +#define NV_RX_MISSEDFRAME (1<<1) +#define NV_RX_SUBSTRACT1 (1<<3) +#define NV_RX_ERROR1 (1<<7) +#define NV_RX_ERROR2 (1<<8) +#define NV_RX_ERROR3 (1<<9) +#define NV_RX_ERROR4 (1<<10) +#define NV_RX_CRCERR (1<<11) +#define NV_RX_OVERFLOW (1<<12) +#define NV_RX_FRAMINGERR (1<<13) +#define NV_RX_ERROR (1<<14) +#define NV_RX_AVAIL (1<<15) + +/* Miscelaneous hardware related defines: */ +#define NV_PCI_REGSZ 0x270 + +/* various timeout delays: all in usec */ +#define NV_TXRX_RESET_DELAY 4 +#define NV_TXSTOP_DELAY1 10 +#define NV_TXSTOP_DELAY1MAX 500000 +#define NV_TXSTOP_DELAY2 100 +#define NV_RXSTOP_DELAY1 10 +#define NV_RXSTOP_DELAY1MAX 500000 +#define NV_RXSTOP_DELAY2 100 +#define NV_SETUP5_DELAY 5 +#define NV_SETUP5_DELAYMAX 50000 +#define NV_POWERUP_DELAY 5 +#define NV_POWERUP_DELAYMAX 5000 +#define NV_MIIBUSY_DELAY 50 +#define NV_MIIPHY_DELAY 10 +#define NV_MIIPHY_DELAYMAX 10000 + +#define NV_WAKEUPPATTERNS 5 +#define NV_WAKEUPMASKENTRIES 4 + +/* General driver defaults */ +#define NV_WATCHDOG_TIMEO (2*HZ) +#define DEFAULT_MTU 1500 /* also maximum supported, at least for now */ + +#define RX_RING 128 +#define TX_RING 16 +/* limited to 1 packet until we understand NV_TX_LASTPACKET */ +#define TX_LIMIT_STOP 10 +#define TX_LIMIT_START 5 + +/* rx/tx mac addr + type + vlan + align + slack*/ +#define RX_NIC_BUFSIZE (DEFAULT_MTU + 64) +/* even more slack */ +#define RX_ALLOC_BUFSIZE (DEFAULT_MTU + 128) + +#define OOM_REFILL (1+HZ/20) +#define POLL_WAIT (1+HZ/100) + +/* + * SMP locking: + * All hardware access under dev->priv->lock, except the performance + * critical parts: + * - rx is (pseudo-) lockless: it relies on the single-threading provided + * by the arch code for interrupts. + * - tx setup is lockless: it relies on dev->xmit_lock. Actual submission + * needs dev->priv->lock :-( + * - set_multicast_list: preparation lockless, relies on dev->xmit_lock. + */ + +/* in dev: base, irq */ +struct fe_priv { + spinlock_t lock; + + /* General data: + * Locking: spin_lock(&np->lock); */ + struct net_device_stats stats; + int in_shutdown; + u32 linkspeed; + int duplex; + int phyaddr; + + /* General data: RO fields */ + dma_addr_t ring_addr; + struct pci_dev *pci_dev; + u32 orig_mac[2]; + u32 irqmask; + + /* rx specific fields. + * Locking: Within irq hander or disable_irq+spin_lock(&np->lock); + */ + struct ring_desc *rx_ring; + unsigned int cur_rx, refill_rx; + struct sk_buff *rx_skbuff[RX_RING]; + dma_addr_t rx_dma[RX_RING]; + unsigned int rx_buf_sz; + struct timer_list oom_kick; + struct timer_list nic_poll; + + /* + * tx specific fields. + */ + struct ring_desc *tx_ring; + unsigned int next_tx, nic_tx; + struct sk_buff *tx_skbuff[TX_RING]; + dma_addr_t tx_dma[TX_RING]; + u16 tx_flags; +}; + +/* + * Maximum number of loops until we assume that a bit in the irq mask + * is stuck. Overridable with module param. + */ +static int max_interrupt_work = 5; + +static inline struct fe_priv *get_nvpriv(struct net_device *dev) +{ + return (struct fe_priv *) dev->priv; +} + +static inline u8 *get_hwbase(struct net_device *dev) +{ + return (u8 *) dev->base_addr; +} + +static inline void pci_push(u8 * base) +{ + /* force out pending posted writes */ + readl(base); +} + +static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target, + int delay, int delaymax, const char *msg) +{ + u8 *base = get_hwbase(dev); + + pci_push(base); + do { + udelay(delay); + delaymax -= delay; + if (delaymax < 0) { + if (msg) + printk(msg); + return 1; + } + } while ((readl(base + offset) & mask) != target); + return 0; +} + +#define MII_READ (-1) +/* mii_rw: read/write a register on the PHY. + * + * Caller must guarantee serialization + */ +static int mii_rw(struct net_device *dev, int addr, int miireg, int value) +{ + u8 *base = get_hwbase(dev); + int was_running; + u32 reg; + int retval; + + writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus); + was_running = 0; + reg = readl(base + NvRegAdapterControl); + if (reg & NVREG_ADAPTCTL_RUNNING) { + was_running = 1; + writel(reg & ~NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl); + } + reg = readl(base + NvRegMIIControl); + if (reg & NVREG_MIICTL_INUSE) { + writel(NVREG_MIICTL_INUSE, base + NvRegMIIControl); + udelay(NV_MIIBUSY_DELAY); + } + + reg = NVREG_MIICTL_INUSE | (addr << NVREG_MIICTL_ADDRSHIFT) | miireg; + if (value != MII_READ) { + writel(value, base + NvRegMIIData); + reg |= NVREG_MIICTL_WRITE; + } + writel(reg, base + NvRegMIIControl); + + if (reg_delay(dev, NvRegMIIControl, NVREG_MIICTL_INUSE, 0, + NV_MIIPHY_DELAY, NV_MIIPHY_DELAYMAX, NULL)) { + dprintk(KERN_DEBUG "%s: mii_rw of reg %d at PHY %d timed out.\n", + dev->name, miireg, addr); + retval = -1; + } else if (value != MII_READ) { + /* it was a write operation - fewer failures are detectable */ + dprintk(KERN_DEBUG "%s: mii_rw wrote 0x%x to reg %d at PHY %d\n", + dev->name, value, miireg, addr); + retval = 0; + } else if (readl(base + NvRegMIIStatus) & NVREG_MIISTAT_ERROR) { + dprintk(KERN_DEBUG "%s: mii_rw of reg %d at PHY %d failed.\n", + dev->name, miireg, addr); + retval = -1; + } else { + /* FIXME: why is that required? */ + udelay(50); + retval = readl(base + NvRegMIIData); + dprintk(KERN_DEBUG "%s: mii_rw read from reg %d at PHY %d: 0x%x.\n", + dev->name, miireg, addr, retval); + } + if (was_running) { + reg = readl(base + NvRegAdapterControl); + writel(reg | NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl); + } + return retval; +} + +static void start_rx(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + u8 *base = get_hwbase(dev); + + dprintk(KERN_DEBUG "%s: start_rx\n", dev->name); + /* Already running? Stop it. */ + if (readl(base + NvRegReceiverControl) & NVREG_RCVCTL_START) { + writel(0, base + NvRegReceiverControl); + pci_push(base); + } + writel(np->linkspeed, base + NvRegLinkSpeed); + pci_push(base); + writel(NVREG_RCVCTL_START, base + NvRegReceiverControl); + pci_push(base); +} + +static void stop_rx(struct net_device *dev) +{ + u8 *base = get_hwbase(dev); + + dprintk(KERN_DEBUG "%s: stop_rx\n", dev->name); + writel(0, base + NvRegReceiverControl); + reg_delay(dev, NvRegReceiverStatus, NVREG_RCVSTAT_BUSY, 0, + NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX, + KERN_INFO "stop_rx: ReceiverStatus remained busy"); + + udelay(NV_RXSTOP_DELAY2); + writel(0, base + NvRegLinkSpeed); +} + +static void start_tx(struct net_device *dev) +{ + u8 *base = get_hwbase(dev); + + dprintk(KERN_DEBUG "%s: start_tx\n", dev->name); + writel(NVREG_XMITCTL_START, base + NvRegTransmitterControl); + pci_push(base); +} + +static void stop_tx(struct net_device *dev) +{ + u8 *base = get_hwbase(dev); + + dprintk(KERN_DEBUG "%s: stop_tx\n", dev->name); + writel(0, base + NvRegTransmitterControl); + reg_delay(dev, NvRegTransmitterStatus, NVREG_XMITSTAT_BUSY, 0, + NV_TXSTOP_DELAY1, NV_TXSTOP_DELAY1MAX, + KERN_INFO "stop_tx: TransmitterStatus remained busy"); + + udelay(NV_TXSTOP_DELAY2); + writel(0, base + NvRegUnknownTransmitterReg); +} + +static void txrx_reset(struct net_device *dev) +{ + u8 *base = get_hwbase(dev); + + dprintk(KERN_DEBUG "%s: txrx_reset\n", dev->name); + writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET, base + NvRegTxRxControl); + pci_push(base); + udelay(NV_TXRX_RESET_DELAY); + writel(NVREG_TXRXCTL_BIT2, base + NvRegTxRxControl); + pci_push(base); +} + +/* + * get_stats: dev->get_stats function + * Get latest stats value from the nic. + * Called with read_lock(&dev_base_lock) held for read - + * only synchronized against unregister_netdevice. + */ +static struct net_device_stats *get_stats(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + + /* It seems that the nic always generates interrupts and doesn't + * accumulate errors internally. Thus the current values in np->stats + * are already up to date. + */ + return &np->stats; +} + + +/* + * nic_ioctl: dev->do_ioctl function + * Called with rtnl_lock held. + */ +static int nic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + return -EOPNOTSUPP; +} + +/* + * alloc_rx: fill rx ring entries. + * Return 1 if the allocations for the skbs failed and the + * rx engine is without Available descriptors + */ +static int alloc_rx(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + unsigned int refill_rx = np->refill_rx; + + while (np->cur_rx != refill_rx) { + int nr = refill_rx % RX_RING; + struct sk_buff *skb; + + if (np->rx_skbuff[nr] == NULL) { + + skb = dev_alloc_skb(RX_ALLOC_BUFSIZE); + if (!skb) + break; + + skb->dev = dev; + np->rx_skbuff[nr] = skb; + } else { + skb = np->rx_skbuff[nr]; + } + np->rx_dma[nr] = pci_map_single(np->pci_dev, skb->data, skb->len, + PCI_DMA_FROMDEVICE); + np->rx_ring[nr].PacketBuffer = cpu_to_le32(np->rx_dma[nr]); + np->rx_ring[nr].Length = cpu_to_le16(RX_NIC_BUFSIZE); + wmb(); + np->rx_ring[nr].Flags = cpu_to_le16(NV_RX_AVAIL); + dprintk(KERN_DEBUG "%s: alloc_rx: Packet %d marked as Available\n", + dev->name, refill_rx); + refill_rx++; + } + np->refill_rx = refill_rx; + if (np->cur_rx - refill_rx == RX_RING) + return 1; + return 0; +} + +static void do_rx_refill(unsigned long data) +{ + struct net_device *dev = (struct net_device *) data; + struct fe_priv *np = get_nvpriv(dev); + + disable_irq(dev->irq); + if (alloc_rx(dev)) { + spin_lock(&np->lock); + if (!np->in_shutdown) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); + spin_unlock(&np->lock); + } + enable_irq(dev->irq); +} + +static int init_ring(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + int i; + + np->next_tx = np->nic_tx = 0; + for (i = 0; i < TX_RING; i++) { + np->tx_ring[i].Flags = 0; + } + + np->cur_rx = RX_RING; + np->refill_rx = 0; + for (i = 0; i < RX_RING; i++) { + np->rx_ring[i].Flags = 0; + } + return alloc_rx(dev); +} + +static void drain_tx(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + int i; + for (i = 0; i < TX_RING; i++) { + np->tx_ring[i].Flags = 0; + if (np->tx_skbuff[i]) { + pci_unmap_single(np->pci_dev, np->tx_dma[i], + np->tx_skbuff[i]->len, + PCI_DMA_TODEVICE); + dev_kfree_skb(np->tx_skbuff[i]); + np->tx_skbuff[i] = NULL; + np->stats.tx_dropped++; + } + } +} + +static void drain_rx(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + int i; + for (i = 0; i < RX_RING; i++) { + np->rx_ring[i].Flags = 0; + wmb(); + if (np->rx_skbuff[i]) { + pci_unmap_single(np->pci_dev, np->rx_dma[i], + np->rx_skbuff[i]->len, + PCI_DMA_FROMDEVICE); + dev_kfree_skb(np->rx_skbuff[i]); + np->rx_skbuff[i] = NULL; + } + } +} + +static void drain_ring(struct net_device *dev) +{ + drain_tx(dev); + drain_rx(dev); +} + +/* + * start_xmit: dev->hard_start_xmit function + * Called with dev->xmit_lock held. + */ +static int start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + int nr = np->next_tx % TX_RING; + + np->tx_skbuff[nr] = skb; + np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data,skb->len, + PCI_DMA_TODEVICE); + + np->tx_ring[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); + np->tx_ring[nr].Length = cpu_to_le16(skb->len-1); + + spin_lock_irq(&np->lock); + wmb(); + np->tx_ring[nr].Flags = np->tx_flags; + dprintk(KERN_DEBUG "%s: start_xmit: packet packet %d queued for transmission.\n", + dev->name, np->next_tx); + { + int j; + for (j=0; j<64; j++) { + if ((j%16) == 0) + dprintk("\n%03x:", j); + dprintk(" %02x", ((unsigned char*)skb->data)[j]); + } + dprintk("\n"); + } + + np->next_tx++; + + dev->trans_start = jiffies; + if (np->next_tx - np->nic_tx >= TX_LIMIT_STOP) + netif_stop_queue(dev); + spin_unlock_irq(&np->lock); + writel(NVREG_TXRXCTL_KICK, get_hwbase(dev) + NvRegTxRxControl); + return 0; +} + +/* + * tx_done: check for completed packets, release the skbs. + * + * Caller must own np->lock. + */ +static void tx_done(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + + while (np->nic_tx < np->next_tx) { + struct ring_desc *prd; + int i = np->nic_tx % TX_RING; + + prd = &np->tx_ring[i]; + + dprintk(KERN_DEBUG "%s: tx_done: looking at packet %d, Flags 0x%x.\n", + dev->name, np->nic_tx, prd->Flags); + if (prd->Flags & cpu_to_le16(NV_TX_VALID)) + break; + if (prd->Flags & cpu_to_le16(NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION| + NV_TX_UNDERFLOW|NV_TX_ERROR)) { + if (prd->Flags & cpu_to_le16(NV_TX_UNDERFLOW)) + np->stats.tx_fifo_errors++; + if (prd->Flags & cpu_to_le16(NV_TX_CARRIERLOST)) + np->stats.tx_carrier_errors++; + np->stats.tx_errors++; + } else { + np->stats.tx_packets++; + np->stats.tx_bytes += np->tx_skbuff[i]->len; + } + pci_unmap_single(np->pci_dev, np->tx_dma[i], + np->tx_skbuff[i]->len, + PCI_DMA_TODEVICE); + dev_kfree_skb_irq(np->tx_skbuff[i]); + np->tx_skbuff[i] = NULL; + np->nic_tx++; + } + if (np->next_tx - np->nic_tx < TX_LIMIT_START) + netif_wake_queue(dev); +} + +/* + * tx_timeout: dev->tx_timeout function + * Called with dev->xmit_lock held. + */ +static void tx_timeout(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + u8 *base = get_hwbase(dev); + + dprintk(KERN_DEBUG "%s: Got tx_timeout. irq: %08x\n", dev->name, + readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK); + + spin_lock_irq(&np->lock); + + /* 1) stop tx engine */ + stop_tx(dev); + + /* 2) check that the packets were not sent already: */ + tx_done(dev); + + /* 3) if there are dead entries: clear everything */ + if (np->next_tx != np->nic_tx) { + printk(KERN_DEBUG "%s: tx_timeout: dead entries!\n", dev->name); + drain_tx(dev); + np->next_tx = np->nic_tx = 0; + writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); + netif_wake_queue(dev); + } + + /* 4) restart tx engine */ + start_tx(dev); + spin_unlock_irq(&np->lock); +} + +static void rx_process(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + + for (;;) { + struct ring_desc *prd; + struct sk_buff *skb; + int len; + int i; + if (np->cur_rx - np->refill_rx >= RX_RING) + break; /* we scanned the whole ring - do not continue */ + + i = np->cur_rx % RX_RING; + prd = &np->rx_ring[i]; + dprintk(KERN_DEBUG "%s: rx_process: looking at packet %d, Flags 0x%x.\n", + dev->name, np->cur_rx, prd->Flags); + + if (prd->Flags & cpu_to_le16(NV_RX_AVAIL)) + break; /* still owned by hardware, */ + + /* + * the packet is for us - immediately tear down the pci mapping, and + * prefetch the first cacheline of the packet. + */ + pci_unmap_single(np->pci_dev, np->rx_dma[i], + np->rx_skbuff[i]->len, + PCI_DMA_FROMDEVICE); + prefetch(np->rx_skbuff[i]->data); + + { + int j; + dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",prd->Flags); + for (j=0; j<64; j++) { + if ((j%16) == 0) + dprintk("\n%03x:", j); + dprintk(" %02x", ((unsigned char*)np->rx_skbuff[i]->data)[j]); + } + dprintk("\n"); + } + /* look at what we actually got: */ + if (!(prd->Flags & cpu_to_le16(NV_RX_DESCRIPTORVALID))) + goto next_pkt; + + + len = le16_to_cpu(prd->Length); + + if (prd->Flags & cpu_to_le16(NV_RX_MISSEDFRAME)) { + np->stats.rx_missed_errors++; + np->stats.rx_errors++; + goto next_pkt; + } + if (prd->Flags & cpu_to_le16(NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3|NV_RX_ERROR4)) { + np->stats.rx_errors++; + goto next_pkt; + } + if (prd->Flags & cpu_to_le16(NV_RX_CRCERR)) { + np->stats.rx_crc_errors++; + np->stats.rx_errors++; + goto next_pkt; + } + if (prd->Flags & cpu_to_le16(NV_RX_OVERFLOW)) { + np->stats.rx_over_errors++; + np->stats.rx_errors++; + goto next_pkt; + } + if (prd->Flags & cpu_to_le16(NV_RX_ERROR)) { + /* framing errors are soft errors, the rest is fatal. */ + if (prd->Flags & cpu_to_le16(NV_RX_FRAMINGERR)) { + if (prd->Flags & cpu_to_le16(NV_RX_SUBSTRACT1)) { + len--; + } + } else { + np->stats.rx_errors++; + goto next_pkt; + } + } + /* got a valid packet - forward it to the network core */ + skb = np->rx_skbuff[i]; + np->rx_skbuff[i] = NULL; + + skb_put(skb, len); + skb->protocol = eth_type_trans(skb, dev); + dprintk(KERN_DEBUG "%s: rx_process: packet %d with %d bytes, proto %d accepted.\n", + dev->name, np->cur_rx, len, skb->protocol); + netif_rx(skb); + dev->last_rx = jiffies; + np->stats.rx_packets++; + np->stats.rx_bytes += len; +next_pkt: + np->cur_rx++; + } +} + +/* + * change_mtu: dev->change_mtu function + * Called with dev_base_lock held for read. + */ +static int change_mtu(struct net_device *dev, int new_mtu) +{ + if (new_mtu > DEFAULT_MTU) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} + +/* + * change_mtu: dev->change_mtu function + * Called with dev->xmit_lock held. + */ +static void set_multicast(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + u8 *base = get_hwbase(dev); + u32 addr[2]; + u32 mask[2]; + u32 pff; + + memset(addr, 0, sizeof(addr)); + memset(mask, 0, sizeof(mask)); + + if (dev->flags & IFF_PROMISC) { + printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); + pff = NVREG_PFF_PROMISC; + } else { + pff = NVREG_PFF_MYADDR; + + if (dev->flags & IFF_ALLMULTI || dev->mc_list) { + u32 alwaysOff[2]; + u32 alwaysOn[2]; + + alwaysOn[0] = alwaysOn[1] = alwaysOff[0] = alwaysOff[1] = 0xffffffff; + if (dev->flags & IFF_ALLMULTI) { + alwaysOn[0] = alwaysOn[1] = alwaysOff[0] = alwaysOff[1] = 0; + } else { + struct dev_mc_list *walk; + + walk = dev->mc_list; + while (walk != NULL) { + u32 a, b; + a = le32_to_cpu(*(u32 *) walk->dmi_addr); + b = le16_to_cpu(*(u16 *) (&walk->dmi_addr[4])); + alwaysOn[0] &= a; + alwaysOff[0] &= ~a; + alwaysOn[1] &= b; + alwaysOff[1] &= ~b; + walk = walk->next; + } + } + addr[0] = alwaysOn[0]; + addr[1] = alwaysOn[1]; + mask[0] = alwaysOn[0] | alwaysOff[0]; + mask[1] = alwaysOn[1] | alwaysOff[1]; + } + } + addr[0] |= NVREG_MCASTADDRA_FORCE; + pff |= NVREG_PFF_ALWAYS; + spin_lock_irq(&np->lock); + stop_rx(dev); + writel(addr[0], base + NvRegMulticastAddrA); + writel(addr[1], base + NvRegMulticastAddrB); + writel(mask[0], base + NvRegMulticastMaskA); + writel(mask[1], base + NvRegMulticastMaskB); + writel(pff, base + NvRegPacketFilterFlags); + start_rx(dev); + spin_unlock_irq(&np->lock); +} + +static int update_linkspeed(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + int adv, lpa, newls, newdup; + + adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); + lpa = mii_rw(dev, np->phyaddr, MII_LPA, MII_READ); + dprintk(KERN_DEBUG "%s: update_linkspeed: PHY advertises 0x%04x, lpa 0x%04x.\n", + dev->name, adv, lpa); + + /* FIXME: handle parallel detection properly, handle gigabit ethernet */ + lpa = lpa & adv; + if (lpa & LPA_100FULL) { + newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_100; + newdup = 1; + } else if (lpa & LPA_100HALF) { + newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_100; + newdup = 0; + } else if (lpa & LPA_10FULL) { + newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10; + newdup = 1; + } else if (lpa & LPA_10HALF) { + newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10; + newdup = 0; + } else { + dprintk(KERN_DEBUG "%s: bad ability %04x - falling back to 10HD.\n", dev->name, lpa); + newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10; + newdup = 0; + } + if (np->duplex != newdup || np->linkspeed != newls) { + np->duplex = newdup; + np->linkspeed = newls; + return 1; + } + return 0; +} + +static void link_irq(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + u8 *base = get_hwbase(dev); + u32 miistat; + int miival; + + miistat = readl(base + NvRegMIIStatus); + writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus); + printk(KERN_DEBUG "%s: link change notification, status 0x%x.\n", dev->name, miistat); + + miival = mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ); + if (miival & BMSR_ANEGCOMPLETE) { + update_linkspeed(dev); + + if (netif_carrier_ok(dev)) { + stop_rx(dev); + } else { + netif_carrier_on(dev); + printk(KERN_INFO "%s: link up.\n", dev->name); + } + writel(NVREG_MISC1_FORCE | ( np->duplex ? 0 : NVREG_MISC1_HD), + base + NvRegMisc1); + start_rx(dev); + } else { + if (netif_carrier_ok(dev)) { + netif_carrier_off(dev); + printk(KERN_INFO "%s: link down.\n", dev->name); + stop_rx(dev); + } + writel(np->linkspeed, base + NvRegLinkSpeed); + pci_push(base); + } +} + +static irqreturn_t nic_irq(int foo, void *data, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) data; + struct fe_priv *np = get_nvpriv(dev); + u8 *base = get_hwbase(dev); + u32 events; + int i; + + dprintk(KERN_DEBUG "%s: nic_irq\n", dev->name); + + for (i=0; ; i++) { + events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK; + writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); + pci_push(base); + dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events); + if (!(events & np->irqmask)) + break; + + if (events & (NVREG_IRQ_TX1|NVREG_IRQ_TX2|NVREG_IRQ_TX_ERR)) { + spin_lock(&np->lock); + tx_done(dev); + spin_unlock(&np->lock); + } + + if (events & (NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF)) { + rx_process(dev); + if (alloc_rx(dev)) { + spin_lock(&np->lock); + if (!np->in_shutdown) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); + spin_unlock(&np->lock); + } + } + + if (events & NVREG_IRQ_LINK) { + spin_lock(&np->lock); + link_irq(dev); + spin_unlock(&np->lock); + } + if (events & (NVREG_IRQ_TX_ERR)) { + dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n", + dev->name, events); + } + if (events & (NVREG_IRQ_UNKNOWN)) { + printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n", + dev->name, events); + } + if (i > max_interrupt_work) { + spin_lock(&np->lock); + /* disable interrupts on the nic */ + writel(0, base + NvRegIrqMask); + pci_push(base); + + if (!np->in_shutdown) + mod_timer(&np->nic_poll, jiffies + POLL_WAIT); + printk(KERN_DEBUG "%s: too many iterations (%d) in nic_irq.\n", dev->name, i); + spin_unlock(&np->lock); + break; + } + + } + dprintk(KERN_DEBUG "%s: nic_irq completed\n", dev->name); + + return IRQ_RETVAL(i); +} + +static void do_nic_poll(unsigned long data) +{ + struct net_device *dev = (struct net_device *) data; + struct fe_priv *np = get_nvpriv(dev); + u8 *base = get_hwbase(dev); + + disable_irq(dev->irq); + /* + * reenable interrupts on the nic, we have to do this before calling + * nic_irq because that may decide to do otherwise + */ + writel(np->irqmask, base + NvRegIrqMask); + pci_push(base); + nic_irq((int) 0, (void *) data, (struct pt_regs *) NULL); + enable_irq(dev->irq); +} + +static int open(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + u8 *base = get_hwbase(dev); + int ret, oom, i; + + dprintk(KERN_DEBUG "forcedeth: open\n"); + + /* 1) erase previous misconfiguration */ + /* 4.1-1: stop adapter: ignored, 4.3 seems to be overkill */ + writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA); + writel(0, base + NvRegMulticastAddrB); + writel(0, base + NvRegMulticastMaskA); + writel(0, base + NvRegMulticastMaskB); + writel(0, base + NvRegPacketFilterFlags); + writel(0, base + NvRegAdapterControl); + writel(0, base + NvRegLinkSpeed); + writel(0, base + NvRegUnknownTransmitterReg); + txrx_reset(dev); + writel(0, base + NvRegUnknownSetupReg6); + + /* 2) initialize descriptor rings */ + np->in_shutdown = 0; + oom = init_ring(dev); + + /* 3) set mac address */ + { + u32 mac[2]; + + mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) + + (dev->dev_addr[2] << 16) + (dev->dev_addr[3] << 24); + mac[1] = (dev->dev_addr[4] << 0) + (dev->dev_addr[5] << 8); + + writel(mac[0], base + NvRegMacAddrA); + writel(mac[1], base + NvRegMacAddrB); + } + + /* 4) continue setup */ + np->linkspeed = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10; + np->duplex = 0; + writel(NVREG_UNKSETUP3_VAL1, base + NvRegUnknownSetupReg3); + writel(0, base + NvRegTxRxControl); + pci_push(base); + writel(NVREG_TXRXCTL_BIT1, base + NvRegTxRxControl); + reg_delay(dev, NvRegUnknownSetupReg5, NVREG_UNKSETUP5_BIT31, NVREG_UNKSETUP5_BIT31, + NV_SETUP5_DELAY, NV_SETUP5_DELAYMAX, + KERN_INFO "open: SetupReg5, Bit 31 remained off\n"); + writel(0, base + NvRegUnknownSetupReg4); + + /* 5) Find a suitable PHY */ + writel(NVREG_MIISPEED_BIT8|NVREG_MIIDELAY, base + NvRegMIISpeed); + for (i = 1; i < 32; i++) { + int id1, id2; + + id1 = mii_rw(dev, i, MII_PHYSID1, MII_READ); + if (id1 < 0) + continue; + id2 = mii_rw(dev, i, MII_PHYSID2, MII_READ); + if (id2 < 0) + continue; + dprintk(KERN_DEBUG "%s: open: Found PHY %04x:%04x at address %d.\n", + dev->name, id1, id2, i); + np->phyaddr = i; + + update_linkspeed(dev); + + break; + } + if (i == 32) { + printk(KERN_INFO "%s: open: failing due to lack of suitable PHY.\n", + dev->name); + ret = -EINVAL; + goto out_drain; + } + + /* 6) continue setup */ + writel(NVREG_MISC1_FORCE | ( np->duplex ? 0 : NVREG_MISC1_HD), + base + NvRegMisc1); + writel(readl(base + NvRegTransmitterStatus), base + NvRegTransmitterStatus); + writel(NVREG_PFF_ALWAYS, base + NvRegPacketFilterFlags); + writel(NVREG_OFFLOAD_NORMAL, base + NvRegOffloadConfig); + + writel(readl(base + NvRegReceiverStatus), base + NvRegReceiverStatus); + get_random_bytes(&i, sizeof(i)); + writel(NVREG_RNDSEED_FORCE | (i&NVREG_RNDSEED_MASK), base + NvRegRandomSeed); + writel(NVREG_UNKSETUP1_VAL, base + NvRegUnknownSetupReg1); + writel(NVREG_UNKSETUP2_VAL, base + NvRegUnknownSetupReg2); + writel(NVREG_UNKSETUP6_VAL, base + NvRegUnknownSetupReg6); + writel((np->phyaddr << NVREG_ADAPTCTL_PHYSHIFT)|NVREG_ADAPTCTL_PHYVALID, + base + NvRegAdapterControl); + writel(NVREG_UNKSETUP4_VAL, base + NvRegUnknownSetupReg4); + writel(NVREG_WAKEUPFLAGS_VAL, base + NvRegWakeUpFlags); + + /* 7) start packet processing */ + writel((u32) np->ring_addr, base + NvRegRxRingPhysAddr); + writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); + writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT), + base + NvRegRingSizes); + + i = readl(base + NvRegPowerState); + if ( (i & NVREG_POWERSTATE_POWEREDUP) == 0) { + writel(NVREG_POWERSTATE_POWEREDUP|i, base + NvRegPowerState); + } + pci_push(base); + udelay(10); + writel(readl(base + NvRegPowerState) | NVREG_POWERSTATE_VALID, base + NvRegPowerState); + writel(NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl); + + + writel(0, base + NvRegIrqMask); + pci_push(base); + writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); + pci_push(base); + writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus); + writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); + pci_push(base); + + ret = request_irq(dev->irq, &nic_irq, SA_SHIRQ, dev->name, dev); + if (ret) + goto out_drain; + + writel(np->irqmask, base + NvRegIrqMask); + + spin_lock_irq(&np->lock); + writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA); + writel(0, base + NvRegMulticastAddrB); + writel(0, base + NvRegMulticastMaskA); + writel(0, base + NvRegMulticastMaskB); + writel(NVREG_PFF_ALWAYS|NVREG_PFF_MYADDR, base + NvRegPacketFilterFlags); + start_rx(dev); + start_tx(dev); + netif_start_queue(dev); + if (oom) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); + if (!(mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ) & BMSR_ANEGCOMPLETE)) { + printk("%s: no link during initialization.\n", dev->name); + netif_carrier_off(dev); + } + + spin_unlock_irq(&np->lock); + + return 0; +out_drain: + drain_ring(dev); + return ret; +} + +static int close(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + + spin_lock_irq(&np->lock); + np->in_shutdown = 1; + spin_unlock_irq(&np->lock); + synchronize_irq(dev->irq); + + del_timer_sync(&np->oom_kick); + del_timer_sync(&np->nic_poll); + + netif_stop_queue(dev); + spin_lock_irq(&np->lock); + stop_tx(dev); + stop_rx(dev); + spin_unlock_irq(&np->lock); + + free_irq(dev->irq, dev); + + drain_ring(dev); + + /* FIXME: power down nic */ + + return 0; +} + +static int __devinit probe_nic(struct pci_dev *pci_dev, const struct pci_device_id *id) +{ + struct net_device *dev; + struct fe_priv *np; + unsigned long addr; + u8 *base; + int err, i; + + dev = alloc_etherdev(sizeof(struct fe_priv)); + np = get_nvpriv(dev); + err = -ENOMEM; + if (!dev) + goto out; + + np->pci_dev = pci_dev; + spin_lock_init(&np->lock); + SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &pci_dev->dev); + + init_timer(&np->oom_kick); + np->oom_kick.data = (unsigned long) dev; + np->oom_kick.function = &do_rx_refill; /* timer handler */ + init_timer(&np->nic_poll); + np->nic_poll.data = (unsigned long) dev; + np->nic_poll.function = &do_nic_poll; /* timer handler */ + + err = pci_enable_device(pci_dev); + if (err) { + printk(KERN_INFO "forcedeth: pci_enable_dev failed: %d\n", err); + goto out_free; + } + + pci_set_master(pci_dev); + + err = pci_request_regions(pci_dev, dev->name); + if (err < 0) + goto out_disable; + + err = -EINVAL; + addr = 0; + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { + dprintk(KERN_DEBUG "forcedeth: resource %d start %p len %ld flags 0x%08lx.\n", + i, (void*)pci_resource_start(pci_dev, i), + pci_resource_len(pci_dev, i), + pci_resource_flags(pci_dev, i)); + if (pci_resource_flags(pci_dev, i) & IORESOURCE_MEM && + pci_resource_len(pci_dev, i) >= NV_PCI_REGSZ) { + addr = pci_resource_start(pci_dev, i); + break; + } + } + if (i == DEVICE_COUNT_RESOURCE) { + printk(KERN_INFO "forcedeth: Couldn't find register window.\n"); + goto out_relreg; + } + + err = -ENOMEM; + dev->base_addr = (unsigned long) ioremap(addr, NV_PCI_REGSZ); + if (!dev->base_addr) + goto out_disable; + dev->irq = pci_dev->irq; + np->rx_ring = pci_alloc_consistent(pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), + &np->ring_addr); + if (!np->rx_ring) + goto out_unmap; + np->tx_ring = &np->rx_ring[RX_RING]; + + dev->open = open; + dev->stop = close; + dev->hard_start_xmit = start_xmit; + dev->get_stats = get_stats; + dev->change_mtu = change_mtu; + dev->set_multicast_list = set_multicast; + dev->do_ioctl = nic_ioctl; + dev->tx_timeout = tx_timeout; + dev->watchdog_timeo = NV_WATCHDOG_TIMEO; + + pci_set_drvdata(pci_dev, dev); + + err = register_netdev(dev); + if (err) { + printk(KERN_INFO "forcedeth: unable to register netdev: %d\n", err); + goto out_freering; + } + + printk(KERN_INFO "%s: forcedeth.c: subsystem: %05x:%04x\n", + dev->name, pci_dev->subsystem_vendor, pci_dev->subsystem_device); + + + /* read the mac address */ + base = get_hwbase(dev); + np->orig_mac[0] = readl(base + NvRegMacAddrA); + np->orig_mac[1] = readl(base + NvRegMacAddrB); + + dev->dev_addr[0] = (np->orig_mac[1] >> 8) & 0xff; + dev->dev_addr[1] = (np->orig_mac[1] >> 0) & 0xff; + dev->dev_addr[2] = (np->orig_mac[0] >> 24) & 0xff; + dev->dev_addr[3] = (np->orig_mac[0] >> 16) & 0xff; + dev->dev_addr[4] = (np->orig_mac[0] >> 8) & 0xff; + dev->dev_addr[5] = (np->orig_mac[0] >> 0) & 0xff; + + if (!is_valid_ether_addr(dev->dev_addr)) { + /* + * Bad mac address. At least one bios sets the mac address + * to 01:23:45:67:89:ab + */ + printk(KERN_ERR "%s: Invalid Mac address detected: %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + printk(KERN_ERR "Please complain to your hardware vendor. Switching to a random MAC.\n"); + dev->dev_addr[0] = 0x00; + dev->dev_addr[1] = 0x00; + dev->dev_addr[2] = 0x6c; + get_random_bytes(&dev->dev_addr[3], 3); + } + + dprintk(KERN_DEBUG "%s: MAC Address %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + + np->tx_flags = cpu_to_le16(NV_TX_LASTPACKET|NV_TX_LASTPACKET1|NV_TX_VALID); + if (id->driver_data & DEV_NEED_LASTPACKET1) + np->tx_flags |= cpu_to_le16(NV_TX_LASTPACKET1); + if (id->driver_data & DEV_IRQMASK_1) + np->irqmask = NVREG_IRQMASK_WANTED_1; + if (id->driver_data & DEV_IRQMASK_2) + np->irqmask = NVREG_IRQMASK_WANTED_2; + + return 0; + +out_freering: + pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), + np->rx_ring, np->ring_addr); +out_unmap: + iounmap(get_hwbase(dev)); +out_relreg: + pci_release_regions(pci_dev); +out_disable: + pci_disable_device(pci_dev); +out_free: + kfree(dev); + pci_set_drvdata(pci_dev, NULL); +out: + return err; +} + +static void __devexit remove_nic(struct pci_dev *pci_dev) +{ + struct net_device *dev = pci_get_drvdata(pci_dev); + struct fe_priv *np = get_nvpriv(dev); + u8 *base = get_hwbase(dev); + + unregister_netdev(dev); + + /* special op: write back the misordered MAC address - otherwise + * the next probe_nic would see a wrong address. + */ + writel(np->orig_mac[0], base + NvRegMacAddrA); + writel(np->orig_mac[1], base + NvRegMacAddrB); + + /* free all structures */ + pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), np->rx_ring, np->ring_addr); + iounmap(get_hwbase(dev)); + pci_release_regions(pci_dev); + pci_disable_device(pci_dev); + kfree(dev); + pci_set_drvdata(pci_dev, NULL); +} + +static struct pci_device_id pci_tbl[] = { + { /* nForce Ethernet Controller */ + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = 0x1C3, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = DEV_IRQMASK_1, + }, + { /* nForce2 Ethernet Controller */ + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = 0x0066, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2, + }, + { /* nForce3 Ethernet Controller */ + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = 0x00D6, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2, + }, + {0,}, +}; + +static struct pci_driver driver = { + .name = "forcedeth", + .id_table = pci_tbl, + .probe = probe_nic, + .remove = __devexit_p(remove_nic), +}; + + +static int __init init_nic(void) +{ + printk(KERN_INFO "forcedeth.c: Reverse Engineered nForce ethernet driver. Version %s.\n", FORCEDETH_VERSION); + return pci_module_init(&driver); +} + +static void __exit exit_nic(void) +{ + pci_unregister_driver(&driver); +} + +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM_DESC(max_interrupt_work, "forcedeth maximum events handled per interrupt"); + +MODULE_AUTHOR("Manfred Spraul "); +MODULE_DESCRIPTION("Reverse Engineered nForce ethernet driver"); +MODULE_LICENSE("GPL"); + +MODULE_DEVICE_TABLE(pci, pci_tbl); + +module_init(init_nic); +module_exit(exit_nic); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/gt96100eth.c 830-ivtv/drivers/net/gt96100eth.c --- 000-virgin/drivers/net/gt96100eth.c Tue Sep 2 09:55:47 2003 +++ 830-ivtv/drivers/net/gt96100eth.c Thu Jan 8 08:54:16 2004 @@ -729,10 +729,12 @@ gt96100_probe1(int port_num) return -EBUSY; } - dev = init_etherdev(0, sizeof(struct gt96100_private)); + dev = alloc_etherdev(sizeof(struct gt96100_private)); + if (!dev) + goto out; gtif->dev = dev; - /* private struct aligned and zeroed by init_etherdev */ + /* private struct aligned and zeroed by alloc_etherdev */ /* Fill in the 'dev' fields. */ dev->base_addr = gtif->iobase; dev->irq = gtif->irq; @@ -740,7 +742,7 @@ gt96100_probe1(int port_num) if ((retval = parse_mac_addr(dev, gtif->mac_str))) { err("%s: MAC address parse failed\n", __FUNCTION__); retval = -EINVAL; - goto free_region; + goto out1; } gp = dev->priv; @@ -768,7 +770,7 @@ gt96100_probe1(int port_num) &gp->rx_ring_dma); if (gp->rx_ring == NULL) { retval = -ENOMEM; - goto free_region; + goto out1; } gp->tx_ring = (gt96100_td_t *)(gp->rx_ring + RX_RING_SIZE); @@ -781,11 +783,8 @@ gt96100_probe1(int port_num) gp->rx_buff = dmaalloc(PKT_BUF_SZ*RX_RING_SIZE, &gp->rx_buff_dma); if (gp->rx_buff == NULL) { - dmafree(sizeof(gt96100_rd_t) * RX_RING_SIZE - + sizeof(gt96100_td_t) * TX_RING_SIZE, - gp->rx_ring); retval = -ENOMEM; - goto free_region; + goto out2; } } @@ -797,12 +796,8 @@ gt96100_probe1(int port_num) gp->hash_table = (char*)dmaalloc(RX_HASH_TABLE_SIZE, &gp->hash_table_dma); if (gp->hash_table == NULL) { - dmafree(sizeof(gt96100_rd_t) * RX_RING_SIZE - + sizeof(gt96100_td_t) * TX_RING_SIZE, - gp->rx_ring); - dmafree(PKT_BUF_SZ*RX_RING_SIZE, gp->rx_buff); retval = -ENOMEM; - goto free_region; + goto out3; } } @@ -819,14 +814,23 @@ gt96100_probe1(int port_num) dev->tx_timeout = gt96100_tx_timeout; dev->watchdog_timeo = GT96100ETH_TX_TIMEOUT; - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); + retval = register_netdev(dev); + if (retval) + goto out4; return 0; - free_region: - release_region(gtif->iobase, GT96100_ETH_IO_SIZE); - unregister_netdev(dev); +out4: + dmafree(RX_HASH_TABLE_SIZE, gp->hash_table_dma); +out3: + dmafree(PKT_BUF_SZ*RX_RING_SIZE, gp->rx_buff); +out2: + dmafree(sizeof(gt96100_rd_t) * RX_RING_SIZE + + sizeof(gt96100_td_t) * TX_RING_SIZE, + gp->rx_ring); +out1: free_netdev (dev); +out: + release_region(gtif->iobase, GT96100_ETH_IO_SIZE); err("%s failed. Returns %d\n", __FUNCTION__, retval); return retval; } @@ -1573,9 +1577,14 @@ static void gt96100_cleanup_module(void) if (gtif->dev != NULL) { struct gt96100_private *gp = (struct gt96100_private *)gtif->dev->priv; - release_region(gtif->iobase, gp->io_size); unregister_netdev(gtif->dev); - free_netdev (gtif->dev); + dmafree(RX_HASH_TABLE_SIZE, gp->hash_table_dma); + dmafree(PKT_BUF_SZ*RX_RING_SIZE, gp->rx_buff); + dmafree(sizeof(gt96100_rd_t) * RX_RING_SIZE + + sizeof(gt96100_td_t) * TX_RING_SIZE, + gp->rx_ring); + free_netdev(gtif->dev); + release_region(gtif->iobase, gp->io_size); } } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/hamradio/baycom_epp.c 830-ivtv/drivers/net/hamradio/baycom_epp.c --- 000-virgin/drivers/net/hamradio/baycom_epp.c Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/hamradio/baycom_epp.c Thu Jan 8 08:54:16 2004 @@ -1275,7 +1275,7 @@ static int baycom_ioctl(struct net_devic * If dev->base_addr == 2, allocate space for the device and return success * (detachable devices only). */ -static int baycom_probe(struct net_device *dev) +static void baycom_probe(struct net_device *dev) { static char ax25_bcast[AX25_ADDR_LEN] = { 'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1 @@ -1288,9 +1288,6 @@ static int baycom_probe(struct net_devic }; struct baycom_state *bc; - if (!dev) - return -ENXIO; - baycom_paranoia_check(dev, "baycom_probe", -ENXIO); /* * not a real probe! only initialize data structures */ @@ -1332,8 +1329,6 @@ static int baycom_probe(struct net_devic /* New style flags */ dev->flags = 0; - - return 0; } /* --------------------------------------------------------------------- */ @@ -1368,7 +1363,7 @@ static void __init baycom_epp_dev_setup( /* * initialize part of the device struct */ - dev->init = baycom_probe; + baycom_probe(dev); } static int __init init_baycomepp(void) @@ -1401,7 +1396,7 @@ static int __init init_baycomepp(void) if (register_netdev(dev)) { printk(KERN_WARNING "%s: cannot register net device %s\n", bc_drvname, dev->name); - kfree(dev); + free_netdev(dev); break; } if (set_hw && baycom_setmode(dev->priv, mode[i])) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/hamradio/bpqether.c 830-ivtv/drivers/net/hamradio/bpqether.c --- 000-virgin/drivers/net/hamradio/bpqether.c Mon Nov 17 18:29:42 2003 +++ 830-ivtv/drivers/net/hamradio/bpqether.c Thu Jan 8 08:54:16 2004 @@ -547,7 +547,7 @@ static int bpq_new_device(struct net_dev error: dev_put(edev); - kfree(ndev); + free_netdev(ndev); return err; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/hamradio/dmascc.c 830-ivtv/drivers/net/hamradio/dmascc.c --- 000-virgin/drivers/net/hamradio/dmascc.c Sat Jun 14 18:37:29 2003 +++ 830-ivtv/drivers/net/hamradio/dmascc.c Thu Jan 8 08:54:17 2004 @@ -242,7 +242,7 @@ struct scc_priv { struct scc_info { int irq_used; int twin_serial_cfg; - struct net_device dev[2]; + struct net_device *dev[2]; struct scc_priv priv[2]; struct scc_info *next; spinlock_t register_lock; /* Per device register lock */ @@ -310,18 +310,19 @@ static void __exit dmascc_exit(void) { info = first; /* Unregister devices */ - for (i = 0; i < 2; i++) { - if (info->dev[i].name) - unregister_netdev(&info->dev[i]); - } + for (i = 0; i < 2; i++) + unregister_netdev(info->dev[i]); /* Reset board */ if (info->priv[0].type == TYPE_TWIN) - outb(0, info->dev[0].base_addr + TWIN_SERIAL_CFG); + outb(0, info->dev[0]->base_addr + TWIN_SERIAL_CFG); write_scc(&info->priv[0], R9, FHWRES); - release_region(info->dev[0].base_addr, + release_region(info->dev[0]->base_addr, hw[info->priv[0].type].io_size); + for (i = 0; i < 2; i++) + free_netdev(info->dev[i]); + /* Free memory */ first = info->next; kfree(info); @@ -443,156 +444,193 @@ static int __init dmascc_init(void) { module_init(dmascc_init); module_exit(dmascc_exit); +static void dev_setup(struct net_device *dev) +{ + dev->type = ARPHRD_AX25; + dev->hard_header_len = 73; + dev->mtu = 1500; + dev->addr_len = 7; + dev->tx_queue_len = 64; + memcpy(dev->broadcast, ax25_broadcast, 7); + memcpy(dev->dev_addr, ax25_test, 7); +} -int __init setup_adapter(int card_base, int type, int n) { - int i, irq, chip; - struct scc_info *info; - struct net_device *dev; - struct scc_priv *priv; - unsigned long time; - unsigned int irqs; - int tmr_base = card_base + hw[type].tmr_offset; - int scc_base = card_base + hw[type].scc_offset; - char *chipnames[] = CHIPNAMES; - - /* Allocate memory */ - info = kmalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA); - if (!info) { - printk(KERN_ERR "dmascc: could not allocate memory for %s at %#3x\n", - hw[type].name, card_base); - return -1; - } +static int __init setup_adapter(int card_base, int type, int n) +{ + int i, irq, chip; + struct scc_info *info; + struct net_device *dev; + struct scc_priv *priv; + unsigned long time; + unsigned int irqs; + int tmr_base = card_base + hw[type].tmr_offset; + int scc_base = card_base + hw[type].scc_offset; + char *chipnames[] = CHIPNAMES; + + /* Allocate memory */ + info = kmalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA); + if (!info) { + printk(KERN_ERR "dmascc: " + "could not allocate memory for %s at %#3x\n", + hw[type].name, card_base); + goto out; + } - /* Initialize what is necessary for write_scc and write_scc_data */ - memset(info, 0, sizeof(struct scc_info)); - spin_lock_init(&info->register_lock); - - priv = &info->priv[0]; - priv->type = type; - priv->card_base = card_base; - priv->scc_cmd = scc_base + SCCA_CMD; - priv->scc_data = scc_base + SCCA_DATA; - priv->register_lock = &info->register_lock; - - /* Reset SCC */ - write_scc(priv, R9, FHWRES | MIE | NV); - - /* Determine type of chip by enabling SDLC/HDLC enhancements */ - write_scc(priv, R15, SHDLCE); - if (!read_scc(priv, R15)) { - /* WR7' not present. This is an ordinary Z8530 SCC. */ - chip = Z8530; - } else { - /* Put one character in TX FIFO */ - write_scc_data(priv, 0, 0); - if (read_scc(priv, R0) & Tx_BUF_EMP) { - /* TX FIFO not full. This is a Z85230 ESCC with a 4-byte FIFO. */ - chip = Z85230; - } else { - /* TX FIFO full. This is a Z85C30 SCC with a 1-byte FIFO. */ - chip = Z85C30; - } - } - write_scc(priv, R15, 0); + /* Initialize what is necessary for write_scc and write_scc_data */ + memset(info, 0, sizeof(struct scc_info)); - /* Start IRQ auto-detection */ - irqs = probe_irq_on(); + info->dev[0] = alloc_netdev(0, "", dev_setup); + if (!info->dev[0]) { + printk(KERN_ERR "dmascc: " + "could not allocate memory for %s at %#3x\n", + hw[type].name, card_base); + goto out1; + } - /* Enable interrupts */ - if (type == TYPE_TWIN) { - outb(0, card_base + TWIN_DMA_CFG); - inb(card_base + TWIN_CLR_TMR1); - inb(card_base + TWIN_CLR_TMR2); - outb((info->twin_serial_cfg = TWIN_EI), card_base + TWIN_SERIAL_CFG); - } else { - write_scc(priv, R15, CTSIE); - write_scc(priv, R0, RES_EXT_INT); - write_scc(priv, R1, EXT_INT_ENAB); - } + info->dev[1] = alloc_netdev(0, "", dev_setup); + if (!info->dev[1]) { + printk(KERN_ERR "dmascc: " + "could not allocate memory for %s at %#3x\n", + hw[type].name, card_base); + goto out2; + } + spin_lock_init(&info->register_lock); - /* Start timer */ - outb(1, tmr_base + TMR_CNT1); - outb(0, tmr_base + TMR_CNT1); - - /* Wait and detect IRQ */ - time = jiffies; while (jiffies - time < 2 + HZ / TMR_0_HZ); - irq = probe_irq_off(irqs); - - /* Clear pending interrupt, disable interrupts */ - if (type == TYPE_TWIN) { - inb(card_base + TWIN_CLR_TMR1); - } else { - write_scc(priv, R1, 0); - write_scc(priv, R15, 0); - write_scc(priv, R0, RES_EXT_INT); - } + priv = &info->priv[0]; + priv->type = type; + priv->card_base = card_base; + priv->scc_cmd = scc_base + SCCA_CMD; + priv->scc_data = scc_base + SCCA_DATA; + priv->register_lock = &info->register_lock; + + /* Reset SCC */ + write_scc(priv, R9, FHWRES | MIE | NV); + + /* Determine type of chip by enabling SDLC/HDLC enhancements */ + write_scc(priv, R15, SHDLCE); + if (!read_scc(priv, R15)) { + /* WR7' not present. This is an ordinary Z8530 SCC. */ + chip = Z8530; + } else { + /* Put one character in TX FIFO */ + write_scc_data(priv, 0, 0); + if (read_scc(priv, R0) & Tx_BUF_EMP) { + /* TX FIFO not full. This is a Z85230 ESCC with a 4-byte FIFO. */ + chip = Z85230; + } else { + /* TX FIFO full. This is a Z85C30 SCC with a 1-byte FIFO. */ + chip = Z85C30; + } + } + write_scc(priv, R15, 0); - if (irq <= 0) { - printk(KERN_ERR "dmascc: could not find irq of %s at %#3x (irq=%d)\n", - hw[type].name, card_base, irq); - kfree(info); - return -1; - } + /* Start IRQ auto-detection */ + irqs = probe_irq_on(); - /* Set up data structures */ - for (i = 0; i < 2; i++) { - dev = &info->dev[i]; - priv = &info->priv[i]; - priv->type = type; - priv->chip = chip; - priv->dev = dev; - priv->info = info; - priv->channel = i; - spin_lock_init(&priv->ring_lock); - priv->register_lock = &info->register_lock; - priv->card_base = card_base; - priv->scc_cmd = scc_base + (i ? SCCB_CMD : SCCA_CMD); - priv->scc_data = scc_base + (i ? SCCB_DATA : SCCA_DATA); - priv->tmr_cnt = tmr_base + (i ? TMR_CNT2 : TMR_CNT1); - priv->tmr_ctrl = tmr_base + TMR_CTRL; - priv->tmr_mode = i ? 0xb0 : 0x70; - priv->param.pclk_hz = hw[type].pclk_hz; - priv->param.brg_tc = -1; - priv->param.clocks = TCTRxCP | RCRTxCP; - priv->param.persist = 256; - priv->param.dma = -1; - INIT_WORK(&priv->rx_work, rx_bh, priv); - dev->priv = priv; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) - if (sizeof(dev->name) == sizeof(char *)) dev->name = priv->name; -#endif - sprintf(dev->name, "dmascc%i", 2*n+i); - SET_MODULE_OWNER(dev); - dev->base_addr = card_base; - dev->irq = irq; - dev->open = scc_open; - dev->stop = scc_close; - dev->do_ioctl = scc_ioctl; - dev->hard_start_xmit = scc_send_packet; - dev->get_stats = scc_get_stats; - dev->hard_header = ax25_encapsulate; - dev->rebuild_header = ax25_rebuild_header; - dev->set_mac_address = scc_set_mac_address; - dev->type = ARPHRD_AX25; - dev->hard_header_len = 73; - dev->mtu = 1500; - dev->addr_len = 7; - dev->tx_queue_len = 64; - memcpy(dev->broadcast, ax25_broadcast, 7); - memcpy(dev->dev_addr, ax25_test, 7); - rtnl_lock(); - if (register_netdevice(dev)) { - printk(KERN_ERR "dmascc: could not register %s\n", dev->name); - } - rtnl_unlock(); - } + /* Enable interrupts */ + if (type == TYPE_TWIN) { + outb(0, card_base + TWIN_DMA_CFG); + inb(card_base + TWIN_CLR_TMR1); + inb(card_base + TWIN_CLR_TMR2); + info->twin_serial_cfg = TWIN_EI; + outb(info->twin_serial_cfg, card_base + TWIN_SERIAL_CFG); + } else { + write_scc(priv, R15, CTSIE); + write_scc(priv, R0, RES_EXT_INT); + write_scc(priv, R1, EXT_INT_ENAB); + } + + /* Start timer */ + outb(1, tmr_base + TMR_CNT1); + outb(0, tmr_base + TMR_CNT1); + + /* Wait and detect IRQ */ + time = jiffies; while (jiffies - time < 2 + HZ / TMR_0_HZ); + irq = probe_irq_off(irqs); + + /* Clear pending interrupt, disable interrupts */ + if (type == TYPE_TWIN) { + inb(card_base + TWIN_CLR_TMR1); + } else { + write_scc(priv, R1, 0); + write_scc(priv, R15, 0); + write_scc(priv, R0, RES_EXT_INT); + } + + if (irq <= 0) { + printk(KERN_ERR "dmascc: could not find irq of %s at %#3x (irq=%d)\n", + hw[type].name, card_base, irq); + goto out3; + } + + /* Set up data structures */ + for (i = 0; i < 2; i++) { + dev = info->dev[i]; + priv = &info->priv[i]; + priv->type = type; + priv->chip = chip; + priv->dev = dev; + priv->info = info; + priv->channel = i; + spin_lock_init(&priv->ring_lock); + priv->register_lock = &info->register_lock; + priv->card_base = card_base; + priv->scc_cmd = scc_base + (i ? SCCB_CMD : SCCA_CMD); + priv->scc_data = scc_base + (i ? SCCB_DATA : SCCA_DATA); + priv->tmr_cnt = tmr_base + (i ? TMR_CNT2 : TMR_CNT1); + priv->tmr_ctrl = tmr_base + TMR_CTRL; + priv->tmr_mode = i ? 0xb0 : 0x70; + priv->param.pclk_hz = hw[type].pclk_hz; + priv->param.brg_tc = -1; + priv->param.clocks = TCTRxCP | RCRTxCP; + priv->param.persist = 256; + priv->param.dma = -1; + INIT_WORK(&priv->rx_work, rx_bh, priv); + dev->priv = priv; + sprintf(dev->name, "dmascc%i", 2*n+i); + SET_MODULE_OWNER(dev); + dev->base_addr = card_base; + dev->irq = irq; + dev->open = scc_open; + dev->stop = scc_close; + dev->do_ioctl = scc_ioctl; + dev->hard_start_xmit = scc_send_packet; + dev->get_stats = scc_get_stats; + dev->hard_header = ax25_encapsulate; + dev->rebuild_header = ax25_rebuild_header; + dev->set_mac_address = scc_set_mac_address; + } + if (register_netdev(info->dev[0])) { + printk(KERN_ERR "dmascc: could not register %s\n", + info->dev[0]->name); + goto out3; + } + if (register_netdev(info->dev[1])) { + printk(KERN_ERR "dmascc: could not register %s\n", + info->dev[1]->name); + goto out4; + } - info->next = first; - first = info; - printk(KERN_INFO "dmascc: found %s (%s) at %#3x, irq %d\n", hw[type].name, - chipnames[chip], card_base, irq); - return 0; + info->next = first; + first = info; + printk(KERN_INFO "dmascc: found %s (%s) at %#3x, irq %d\n", hw[type].name, + chipnames[chip], card_base, irq); + return 0; + +out4: + unregister_netdev(info->dev[0]); +out3: + if (info->priv[0].type == TYPE_TWIN) + outb(0, info->dev[0]->base_addr + TWIN_SERIAL_CFG); + write_scc(&info->priv[0], R9, FHWRES); + free_netdev(info->dev[1]); +out2: + free_netdev(info->dev[0]); +out1: + kfree(info); +out: + return -1; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/hamradio/hdlcdrv.c 830-ivtv/drivers/net/hamradio/hdlcdrv.c --- 000-virgin/drivers/net/hamradio/hdlcdrv.c Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/hamradio/hdlcdrv.c Thu Jan 8 08:54:17 2004 @@ -832,7 +832,7 @@ struct net_device *hdlcdrv_register(cons if (err < 0) { printk(KERN_WARNING "hdlcdrv: cannot register net " "device %s\n", dev->name); - kfree(dev); + free_netdev(dev); dev = ERR_PTR(err); } return dev; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/hamradio/yam.c 830-ivtv/drivers/net/hamradio/yam.c --- 000-virgin/drivers/net/hamradio/yam.c Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/hamradio/yam.c Thu Jan 8 08:54:17 2004 @@ -1192,7 +1192,7 @@ static void __exit yam_cleanup_driver(vo struct net_device *dev = yam_devs[i]; if (dev) { unregister_netdev(dev); - kfree(dev); + free_netdev(dev); } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/hp-plus.c 830-ivtv/drivers/net/hp-plus.c --- 000-virgin/drivers/net/hp-plus.c Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/hp-plus.c Thu Jan 8 08:54:17 2004 @@ -92,7 +92,6 @@ enum HP_Option { EnableIRQ = 4, FakeIntr = 8, BootROMEnb = 0x10, IOEnb = 0x20, MemEnable = 0x40, ZeroWait = 0x80, MemDisable = 0x1000, }; -int hp_plus_probe(struct net_device *dev); static int hpp_probe1(struct net_device *dev, int ioaddr); static void hpp_reset_8390(struct net_device *dev); @@ -115,10 +114,11 @@ static void hpp_io_get_8390_hdr(struct n /* Probe a list of addresses for an HP LAN+ adaptor. This routine is almost boilerplate. */ -int __init hp_plus_probe(struct net_device *dev) +static int __init do_hpp_probe(struct net_device *dev) { int i; int base_addr = dev->base_addr; + int irq = dev->irq; SET_MODULE_OWNER(dev); @@ -127,13 +127,46 @@ int __init hp_plus_probe(struct net_devi else if (base_addr != 0) /* Don't probe at all. */ return -ENXIO; - for (i = 0; hpplus_portlist[i]; i++) + for (i = 0; hpplus_portlist[i]; i++) { if (hpp_probe1(dev, hpplus_portlist[i]) == 0) return 0; + dev->irq = irq; + } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + /* NB: hpp_close() handles free_irq */ + release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT); +} + +struct net_device * __init hp_plus_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_hpp_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + /* Do the interesting part of the probe at a single address. */ static int __init hpp_probe1(struct net_device *dev, int ioaddr) { @@ -179,13 +212,6 @@ static int __init hpp_probe1(struct net_ printk(" ID %4.4x", inw(ioaddr + 12)); } - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk ("hp-plus.c: unable to allocate memory for dev->priv.\n"); - retval = -ENOMEM; - goto out; - } - /* Read the IRQ line. */ outw(HW_Page, ioaddr + HP_PAGING); { @@ -400,7 +426,7 @@ hpp_mem_block_output(struct net_device * #ifdef MODULE #define MAX_HPP_CARDS 4 /* Max number of HPP cards per module */ -static struct net_device dev_hpp[MAX_HPP_CARDS]; +static struct net_device *dev_hpp[MAX_HPP_CARDS]; static int io[MAX_HPP_CARDS]; static int irq[MAX_HPP_CARDS]; @@ -416,27 +442,33 @@ ISA device autoprobes on a running machi int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_HPP_CARDS; this_dev++) { - struct net_device *dev = &dev_hpp[this_dev]; - dev->irq = irq[this_dev]; - dev->base_addr = io[this_dev]; - dev->init = hp_plus_probe; if (io[this_dev] == 0) { if (this_dev != 0) break; /* only autoprobe 1st one */ printk(KERN_NOTICE "hp-plus.c: Presently autoprobing (not recommended) for a single card.\n"); } - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "hp-plus.c: No HP-Plus card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) { /* Got at least one. */ - return 0; + dev = alloc_ei_netdev(); + if (!dev) + break; + dev->irq = irq[this_dev]; + dev->base_addr = io[this_dev]; + if (do_hpp_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_hpp[found++] = dev; + continue; } - return -ENXIO; + cleanup_card(dev); } - found++; + free_netdev(dev); + printk(KERN_WARNING "hp-plus.c: No HP-Plus card found (i/o = 0x%x).\n", io[this_dev]); + break; } - return 0; + if (found) + return 0; + return -ENXIO; } void @@ -445,14 +477,11 @@ cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < MAX_HPP_CARDS; this_dev++) { - struct net_device *dev = &dev_hpp[this_dev]; - if (dev->priv != NULL) { - int ioaddr = dev->base_addr - NIC_OFFSET; - void *priv = dev->priv; - /* NB: hpp_close() handles free_irq */ - release_region(ioaddr, HP_IO_EXTENT); + struct net_device *dev = dev_hpp[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(priv); + cleanup_card(dev); + free_netdev(dev); } } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/hp.c 830-ivtv/drivers/net/hp.c --- 000-virgin/drivers/net/hp.c Mon Nov 17 18:28:49 2003 +++ 830-ivtv/drivers/net/hp.c Thu Jan 8 08:54:17 2004 @@ -55,7 +55,6 @@ static unsigned int hppclan_portlist[] _ #define HP_8BSTOP_PG 0x80 /* Last page +1 of RX ring */ #define HP_16BSTOP_PG 0xFF /* Same, for 16 bit cards. */ -int hp_probe(struct net_device *dev); static int hp_probe1(struct net_device *dev, int ioaddr); static int hp_open(struct net_device *dev); @@ -79,10 +78,11 @@ static char irqmap[16] __initdata= { 0, Also initialize the card and fill in STATION_ADDR with the station address. */ -int __init hp_probe(struct net_device *dev) +static int __init do_hp_probe(struct net_device *dev) { int i; int base_addr = dev->base_addr; + int irq = dev->irq; SET_MODULE_OWNER(dev); @@ -91,13 +91,46 @@ int __init hp_probe(struct net_device *d else if (base_addr != 0) /* Don't probe at all. */ return -ENXIO; - for (i = 0; hppclan_portlist[i]; i++) + for (i = 0; hppclan_portlist[i]; i++) { if (hp_probe1(dev, hppclan_portlist[i]) == 0) return 0; + dev->irq = irq; + } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + free_irq(dev->irq, dev); + release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT); +} + +struct net_device * __init hp_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_hp_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init hp_probe1(struct net_device *dev, int ioaddr) { int i, retval, board_id, wordmode; @@ -131,13 +164,6 @@ static int __init hp_probe1(struct net_d if (ei_debug && version_printed++ == 0) printk(version); - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk (" unable to get memory for dev->priv.\n"); - retval = -ENOMEM; - goto out; - } - printk("%s: %s (ID %02x) at %#3x,", dev->name, name, board_id, ioaddr); for(i = 0; i < ETHER_ADDR_LEN; i++) @@ -166,14 +192,14 @@ static int __init hp_probe1(struct net_d if (*irqp == 0) { printk(" no free IRQ lines.\n"); retval = -EBUSY; - goto out1; + goto out; } } else { if (dev->irq == 2) dev->irq = 9; if ((retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev))) { printk (" unable to get IRQ %d.\n", dev->irq); - goto out1; + goto out; } } @@ -195,9 +221,6 @@ static int __init hp_probe1(struct net_d hp_init_card(dev); return 0; -out1: - kfree(dev->priv); - dev->priv = NULL; out: release_region(ioaddr, HP_IO_EXTENT); return retval; @@ -372,7 +395,7 @@ hp_init_card(struct net_device *dev) #ifdef MODULE #define MAX_HP_CARDS 4 /* Max number of HP cards per module */ -static struct net_device dev_hp[MAX_HP_CARDS]; +static struct net_device *dev_hp[MAX_HP_CARDS]; static int io[MAX_HP_CARDS]; static int irq[MAX_HP_CARDS]; @@ -388,27 +411,33 @@ ISA device autoprobes on a running machi int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_HP_CARDS; this_dev++) { - struct net_device *dev = &dev_hp[this_dev]; - dev->irq = irq[this_dev]; - dev->base_addr = io[this_dev]; - dev->init = hp_probe; if (io[this_dev] == 0) { if (this_dev != 0) break; /* only autoprobe 1st one */ printk(KERN_NOTICE "hp.c: Presently autoprobing (not recommended) for a single card.\n"); } - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "hp.c: No HP card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) { /* Got at least one. */ - return 0; + dev = alloc_ei_netdev(); + if (!dev) + break; + dev->irq = irq[this_dev]; + dev->base_addr = io[this_dev]; + if (do_hp_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_hp[found++] = dev; + continue; } - return -ENXIO; + cleanup_card(dev); } - found++; + free_netdev(dev); + printk(KERN_WARNING "hp.c: No HP card found (i/o = 0x%x).\n", io[this_dev]); + break; } - return 0; + if (found) + return 0; + return -ENXIO; } void @@ -417,14 +446,11 @@ cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < MAX_HP_CARDS; this_dev++) { - struct net_device *dev = &dev_hp[this_dev]; - if (dev->priv != NULL) { - int ioaddr = dev->base_addr - NIC_OFFSET; - void *priv = dev->priv; - free_irq(dev->irq, dev); - release_region(ioaddr, HP_IO_EXTENT); + struct net_device *dev = dev_hp[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(priv); + cleanup_card(dev); + free_netdev(dev); } } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/hp100.c 830-ivtv/drivers/net/hp100.c --- 000-virgin/drivers/net/hp100.c Mon Nov 17 18:29:42 2003 +++ 830-ivtv/drivers/net/hp100.c Thu Jan 8 08:54:17 2004 @@ -118,8 +118,6 @@ #include #include -typedef struct net_device_stats hp100_stats_t; - #include "hp100.h" /* @@ -130,23 +128,8 @@ typedef struct net_device_stats hp100_st #define HP100_BUS_EISA 1 #define HP100_BUS_PCI 2 -#ifndef PCI_DEVICE_ID_HP_J2585B -#define PCI_DEVICE_ID_HP_J2585B 0x1031 -#endif -#ifndef PCI_VENDOR_ID_COMPEX -#define PCI_VENDOR_ID_COMPEX 0x11f6 -#endif -#ifndef PCI_DEVICE_ID_COMPEX_ENET100VG4 -#define PCI_DEVICE_ID_COMPEX_ENET100VG4 0x0112 -#endif -#ifndef PCI_VENDOR_ID_COMPEX2 -#define PCI_VENDOR_ID_COMPEX2 0x101a -#endif -#ifndef PCI_DEVICE_ID_COMPEX2_100VG -#define PCI_DEVICE_ID_COMPEX2_100VG 0x0005 -#endif - #define HP100_REGION_SIZE 0x20 /* for ioports */ +#define HP100_SIG_LEN 8 /* same as EISA_SIG_LEN */ #define HP100_MAX_PACKET_SIZE (1536+4) #define HP100_MIN_PACKET_SIZE 60 @@ -165,20 +148,9 @@ typedef struct net_device_stats hp100_st * structures */ -struct hp100_eisa_id { - u_int id; - const char *name; - u_char bus; -}; - -struct hp100_pci_id { - u_short vendor; - u_short device; -}; - struct hp100_private { - struct hp100_eisa_id *id; spinlock_t lock; + char id[HP100_SIG_LEN]; u_short chip; u_short soft_model; u_int memory_size; @@ -196,7 +168,7 @@ struct hp100_private { u_char mac1_mode; u_char mac2_mode; u_char hash_bytes[8]; - hp100_stats_t stats; + struct net_device_stats stats; /* Rings for busmaster mode: */ hp100_ring_t *rxrhead; /* Head (oldest) index into rxring */ @@ -216,83 +188,36 @@ struct hp100_private { /* * variables */ - -static struct hp100_eisa_id hp100_eisa_ids[] = { - - /* 10/100 EISA card with revision A Cascade chip */ - {0x80F1F022, "HP J2577 rev A", HP100_BUS_EISA}, - - /* 10/100 ISA card with revision A Cascade chip */ - {0x50F1F022, "HP J2573 rev A", HP100_BUS_ISA}, - - /* 10 only EISA card with Cascade chip */ - {0x2019F022, "HP 27248B", HP100_BUS_EISA}, - - /* 10/100 EISA card with Cascade chip */ - {0x4019F022, "HP J2577", HP100_BUS_EISA}, - - /* 10/100 ISA card with Cascade chip */ - {0x5019F022, "HP J2573", HP100_BUS_ISA}, - - /* 10/100 EISA card with AT&T chip */ - {0x9019f022, "HP J2577", HP100_BUS_EISA }, - - /* 10/100 PCI card - old J2585A */ - {0x1030103c, "HP J2585A", HP100_BUS_PCI}, - - /* 10/100 PCI card - new J2585B - master capable */ - {0x1041103c, "HP J2585B", HP100_BUS_PCI}, - - /* 10 Mbit Combo Adapter */ - {0x1042103c, "HP J2970", HP100_BUS_PCI}, - - /* 10 Mbit 10baseT Adapter */ - {0x1040103c, "HP J2973", HP100_BUS_PCI}, - - /* 10/100 EISA card from Compex */ - {0x0103180e, "ReadyLink ENET100-VG4", HP100_BUS_EISA}, - - /* 10/100 EISA card from Compex - FreedomLine (sq5bpf) */ - /* Note: plhbrod@mbox.vol.cz reported that same ID have ISA */ - /* version of adapter, too... */ - {0x0104180e, "FreedomLine 100/VG", HP100_BUS_EISA}, - - /* 10/100 PCI card from Compex - FreedomLine - * - * I think this card doesn't like aic7178 scsi controller, but - * I haven't tested this much. It works fine on diskless machines. - * Jacek Lipkowski - */ - {0x021211f6, "FreedomLine 100/VG", HP100_BUS_PCI}, - - /* 10/100 PCI card from Compex (J2585A compatible) */ - {0x011211f6, "ReadyLink ENET100-VG4", HP100_BUS_PCI}, - - /* 10/100 PCI card from KTI */ - {0x40008e2e, "KTI DP-200", HP100_BUS_PCI } +static const char *hp100_isa_tbl[] = { + "HWPF150", /* HP J2573 rev A */ + "HWP1950", /* HP J2573 */ }; -#define HP100_EISA_IDS_SIZE (sizeof(hp100_eisa_ids)/sizeof(struct hp100_eisa_id)) - -#ifdef CONFIG_PCI -static struct hp100_pci_id hp100_pci_ids[] = { - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A}, - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B}, - {PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_ENET100VG4}, - {PCI_VENDOR_ID_COMPEX2, PCI_DEVICE_ID_COMPEX2_100VG} +#ifdef CONFIG_EISA +static struct eisa_device_id hp100_eisa_tbl[] = { + { "HWPF180" }, /* HP J2577 rev A */ + { "HWP1920" }, /* HP 27248B */ + { "HWP1940" }, /* HP J2577 */ + { "HWP1990" }, /* HP J2577 */ + { "CPX0301" }, /* ReadyLink ENET100-VG4 */ + { "CPX0401" }, /* FreedomLine 100/VG */ }; +MODULE_DEVICE_TABLE(eisa, hp100_eisa_tbl); #endif -#define HP100_PCI_IDS_SIZE (sizeof(hp100_pci_ids)/sizeof(struct hp100_pci_id)) - +#ifdef CONFIG_PCI static struct pci_device_id hp100_pci_tbl[] = { {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A, PCI_ANY_ID, PCI_ANY_ID,}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B, PCI_ANY_ID, PCI_ANY_ID,}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2970A, PCI_ANY_ID, PCI_ANY_ID,}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2973A, PCI_ANY_ID, PCI_ANY_ID,}, {PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_ENET100VG4, PCI_ANY_ID, PCI_ANY_ID,}, {PCI_VENDOR_ID_COMPEX2, PCI_DEVICE_ID_COMPEX2_100VG, PCI_ANY_ID, PCI_ANY_ID,}, +/* {PCI_VENDOR_ID_KTI, PCI_DEVICE_ID_KTI_DP200, PCI_ANY_ID, PCI_ANY_ID }, */ {} /* Terminating entry */ }; MODULE_DEVICE_TABLE(pci, hp100_pci_tbl); +#endif static int hp100_rx_ratio = HP100_DEFAULT_RX_RATIO; static int hp100_priority_tx = HP100_DEFAULT_PRIORITY_TX; @@ -316,7 +241,7 @@ static int hp100_start_xmit(struct sk_bu static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev); static void hp100_rx(struct net_device *dev); -static hp100_stats_t *hp100_get_stats(struct net_device *dev); +static struct net_device_stats *hp100_get_stats(struct net_device *dev); static void hp100_misc_interrupt(struct net_device *dev); static void hp100_update_stats(struct net_device *dev); static void hp100_clear_stats(struct hp100_private *lp, int ioaddr); @@ -370,196 +295,180 @@ static void wait(void) * since this could cause problems when the card is not installed. */ -int __init hp100_probe(struct net_device *dev) +/* + * Read board id and convert to string. + * Effectively same code as decode_eisa_sig + */ +static __init const char *hp100_read_id(int ioaddr) { - int base_addr = dev ? dev->base_addr : 0; - int ioaddr = 0; - int pci_start_index = 0; + int i; + static char str[HP100_SIG_LEN]; + unsigned char sig[4], sum; + unsigned short rev; -#ifdef HP100_DEBUG_B - hp100_outw(0x4200, TRACE); - printk("hp100: %s: probe\n", dev->name); -#endif + hp100_page(ID_MAC_ADDR); + sum = 0; + for (i = 0; i < 4; i++) { + sig[i] = hp100_inb(BOARD_ID + i); + sum += sig[i]; + } - if (base_addr > 0xff) { /* Check a single specified location. */ - if (check_region(base_addr, HP100_REGION_SIZE)) - return -EINVAL; - if (base_addr < 0x400) - return hp100_probe1(dev, base_addr, HP100_BUS_ISA, - NULL); - if (EISA_bus && base_addr >= 0x1c38 && ((base_addr - 0x1c38) & 0x3ff) == 0) - return hp100_probe1(dev, base_addr, HP100_BUS_EISA, NULL); -#ifdef CONFIG_PCI - printk("hp100: %s: You must specify card # in i/o address parameter for PCI bus...", dev->name); -#else - return -ENODEV; -#endif - } else -#ifdef CONFIG_PCI - if (base_addr > 0 && base_addr < 8 + 1) - pci_start_index = 0x100 | (base_addr - 1); - else -#endif - if (base_addr != 0) - return -ENXIO; + sum += hp100_inb(BOARD_ID + i); + if (sum != 0xff) + return NULL; /* bad checksum */ - /* First: scan PCI bus(es) */ + str[0] = ((sig[0] >> 2) & 0x1f) + ('A' - 1); + str[1] = (((sig[0] & 3) << 3) | (sig[1] >> 5)) + ('A' - 1); + str[2] = (sig[1] & 0x1f) + ('A' - 1); + rev = (sig[2] << 8) | sig[3]; + sprintf(str + 3, "%04X", rev); -#ifdef CONFIG_PCI - { - int pci_index; - struct pci_dev *pci_dev = NULL; - int pci_id_index; - u_short pci_command; - -#ifdef HP100_DEBUG_PCI - printk("hp100: %s: PCI BIOS is present, checking for devices..\n", dev->name); -#endif - pci_index = 0; - for (pci_id_index = 0; pci_id_index < HP100_PCI_IDS_SIZE; - pci_id_index++) { - while ((pci_dev = pci_find_device(hp100_pci_ids[pci_id_index].vendor, - hp100_pci_ids[pci_id_index].device, - pci_dev)) != NULL) { - if (pci_index < (pci_start_index & 7)) { - pci_index++; - continue; - } - if (pci_enable_device(pci_dev)) - continue; - /* found... */ - ioaddr = pci_resource_start(pci_dev, 0); - if (check_region(ioaddr, HP100_REGION_SIZE)) - continue; - pci_read_config_word(pci_dev, PCI_COMMAND, &pci_command); - if (!(pci_command & PCI_COMMAND_IO)) { -#ifdef HP100_DEBUG - printk("hp100: %s: PCI I/O Bit has not been set. Setting...\n", dev->name); -#endif - pci_command |= PCI_COMMAND_IO; - pci_write_config_word(pci_dev, PCI_COMMAND, pci_command); - } - if (!(pci_command & PCI_COMMAND_MASTER)) { -#ifdef HP100_DEBUG - printk("hp100: %s: PCI Master Bit has not been set. Setting...\n", dev->name); -#endif - pci_command |= PCI_COMMAND_MASTER; - pci_write_config_word(pci_dev, PCI_COMMAND, pci_command); - } -#ifdef HP100_DEBUG - printk("hp100: %s: PCI adapter found at 0x%x\n", dev->name, ioaddr); -#endif - if (hp100_probe1(dev, ioaddr, HP100_BUS_PCI, pci_dev) == 0) - return 0; - } - } - } - if (pci_start_index > 0) - return -ENODEV; -#endif /* CONFIG_PCI */ + return str; +} - /* Second: Probe all EISA possible port regions (if EISA bus present) */ - for (ioaddr = 0x1c38; EISA_bus && ioaddr < 0x10000; ioaddr += 0x400) { - if (check_region(ioaddr, HP100_REGION_SIZE)) - continue; - if (hp100_probe1(dev, ioaddr, HP100_BUS_EISA, NULL) == 0) - return 0; - } +static __init int hp100_isa_probe1(struct net_device *dev, int addr) +{ + const char *sig; + int i; + + if (!request_region(addr, HP100_REGION_SIZE, "hp100")) + goto err; + + sig = hp100_read_id(addr); + release_region(addr, HP100_REGION_SIZE); + + if (sig == NULL) + goto err; + + for (i = 0; i < ARRAY_SIZE(hp100_isa_tbl); i++) { + if (!strcmp(hp100_isa_tbl[i], sig)) + break; - /* Third: Probe all ISA possible port regions */ - for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20) { - if (check_region(ioaddr, HP100_REGION_SIZE)) - continue; - if (hp100_probe1(dev, ioaddr, HP100_BUS_ISA, NULL) == 0) - return 0; } + if (i < ARRAY_SIZE(hp100_isa_tbl)) + return hp100_probe1(dev, addr, HP100_BUS_ISA, NULL); + err: return -ENODEV; + +} +/* + * Probe for ISA board. + * EISA and PCI are handled by device infrastructure. + */ + +static int __init hp100_isa_probe(struct net_device *dev, int addr) +{ + int err = -ENODEV; + + /* Probe for a specific ISA address */ + if (addr > 0xff && addr < 0x400) + err = hp100_isa_probe1(dev, addr); + + else if (addr != 0) + err = -ENXIO; + + else { + /* Probe all ISA possible port regions */ + for (addr = 0x100; addr < 0x400; addr += 0x20) { + err = hp100_isa_probe1(dev, addr); + if (!err) + break; + } + } + return err; +} + + +struct net_device * __init hp100_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private)); + int err; + + if (!dev) + return ERR_PTR(-ENODEV); + + SET_MODULE_OWNER(dev); + +#ifdef HP100_DEBUG_B + hp100_outw(0x4200, TRACE); + printk("hp100: %s: probe\n", dev->name); +#endif + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } + + err = hp100_isa_probe(dev, dev->base_addr); + if (err) + goto out; + + err = register_netdev(dev); + if (err) + goto out1; + return dev; + out1: + release_region(dev->base_addr, HP100_REGION_SIZE); + out: + free_netdev(dev); + return ERR_PTR(err); } static int __init hp100_probe1(struct net_device *dev, int ioaddr, u_char bus, struct pci_dev *pci_dev) { int i; - - u_char uc, uc_1; - u_int eisa_id; + int err = -ENODEV; + const char *eid; u_int chip; + u_char uc; u_int memory_size = 0, virt_memory_size = 0; u_short local_mode, lsw; short mem_mapped; unsigned long mem_ptr_phys; void **mem_ptr_virt; struct hp100_private *lp; - struct hp100_eisa_id *eid; #ifdef HP100_DEBUG_B hp100_outw(0x4201, TRACE); printk("hp100: %s: probe1\n", dev->name); #endif - if (dev == NULL) { -#ifdef HP100_DEBUG - printk("hp100_probe1: %s: dev == NULL ?\n", dev->name); -#endif - return -EIO; - } + /* memory region for programmed i/o */ + if (!request_region(ioaddr, HP100_REGION_SIZE, "hp100")) + goto out1; - if (hp100_inw(HW_ID) != HP100_HW_ID_CASCADE) { - return -ENODEV; - } else { - chip = hp100_inw(PAGING) & HP100_CHIPID_MASK; + if (hp100_inw(HW_ID) != HP100_HW_ID_CASCADE) + goto out2; + + chip = hp100_inw(PAGING) & HP100_CHIPID_MASK; #ifdef HP100_DEBUG - if (chip == HP100_CHIPID_SHASTA) - printk("hp100: %s: Shasta Chip detected. (This is a pre 802.12 chip)\n", dev->name); - else if (chip == HP100_CHIPID_RAINIER) - printk("hp100: %s: Rainier Chip detected. (This is a pre 802.12 chip)\n", dev->name); - else if (chip == HP100_CHIPID_LASSEN) - printk("hp100: %s: Lassen Chip detected.\n", dev->name); - else - printk("hp100: %s: Warning: Unknown CASCADE chip (id=0x%.4x).\n", dev->name, chip); + if (chip == HP100_CHIPID_SHASTA) + printk("hp100: %s: Shasta Chip detected. (This is a pre 802.12 chip)\n", dev->name); + else if (chip == HP100_CHIPID_RAINIER) + printk("hp100: %s: Rainier Chip detected. (This is a pre 802.12 chip)\n", dev->name); + else if (chip == HP100_CHIPID_LASSEN) + printk("hp100: %s: Lassen Chip detected.\n", dev->name); + else + printk("hp100: %s: Warning: Unknown CASCADE chip (id=0x%.4x).\n", dev->name, chip); #endif - } dev->base_addr = ioaddr; - hp100_page(ID_MAC_ADDR); - for (i = uc = eisa_id = 0; i < 4; i++) { - eisa_id >>= 8; - uc_1 = hp100_inb(BOARD_ID + i); - eisa_id |= uc_1 << 24; - uc += uc_1; - } - uc += hp100_inb(BOARD_ID + 4); - - if (uc != 0xff) { /* bad checksum? */ - printk("hp100_probe: %s: bad EISA ID checksum at base port 0x%x\n", dev->name, ioaddr); - return -ENODEV; - } - - for (i = 0; i < HP100_EISA_IDS_SIZE; i++) - if (hp100_eisa_ids[i].id == eisa_id) - break; - if (i >= HP100_EISA_IDS_SIZE) { - for (i = 0; i < HP100_EISA_IDS_SIZE; i++) - if ((hp100_eisa_ids[i].id & 0xf0ffffff) == (eisa_id & 0xf0ffffff)) - break; - if (i >= HP100_EISA_IDS_SIZE) { - printk ("hp100_probe: %s: card at port 0x%x isn't known (id = 0x%x)\n", dev->name, ioaddr, eisa_id); - return -ENODEV; - } - } - eid = &hp100_eisa_ids[i]; - if ((eid->id & 0x0f000000) < (eisa_id & 0x0f000000)) { - printk("hp100_probe: %s: newer version of card %s at port 0x%x - unsupported\n", dev->name, eid->name, ioaddr); - return -ENODEV; + eid = hp100_read_id(ioaddr); + if (eid == NULL) { /* bad checksum? */ + printk(KERN_WARNING "hp100_probe: bad ID checksum at base port 0x%x\n", ioaddr); + goto out2; } + hp100_page(ID_MAC_ADDR); for (i = uc = 0; i < 7; i++) uc += hp100_inb(LAN_ADDR + i); if (uc != 0xff) { - printk("hp100_probe: %s: bad lan address checksum (card %s at port 0x%x)\n", dev->name, eid->name, ioaddr); - return -EIO; + printk(KERN_WARNING "hp100_probe: bad lan address checksum at port 0x%x)\n", ioaddr); + err = -EIO; + goto out2; } /* Make sure, that all registers are correctly updated... */ @@ -607,17 +516,17 @@ static int __init hp100_probe1(struct ne hp100_outw(HP100_MEM_EN | HP100_RESET_LB, OPTION_LSW); hp100_outw(HP100_IO_EN | HP100_SET_LB, OPTION_LSW); hp100_outw(HP100_BM_WRITE | HP100_BM_READ | HP100_RESET_HB, OPTION_LSW); - printk("hp100: %s: IO mapped mode forced.\n", dev->name); + printk("hp100: IO mapped mode forced.\n"); } else if (local_mode == 2) { hp100_outw(HP100_MEM_EN | HP100_SET_LB, OPTION_LSW); hp100_outw(HP100_IO_EN | HP100_SET_LB, OPTION_LSW); hp100_outw(HP100_BM_WRITE | HP100_BM_READ | HP100_RESET_HB, OPTION_LSW); - printk("hp100: %s: Shared memory mode requested.\n", dev->name); + printk("hp100: Shared memory mode requested.\n"); } else if (local_mode == 4) { if (chip == HP100_CHIPID_LASSEN) { hp100_outw(HP100_BM_WRITE | HP100_BM_READ | HP100_SET_HB, OPTION_LSW); hp100_outw(HP100_IO_EN | HP100_MEM_EN | HP100_RESET_LB, OPTION_LSW); - printk("hp100: %s: Busmaster mode requested.\n", dev->name); + printk("hp100: Busmaster mode requested.\n"); } local_mode = 1; } @@ -643,7 +552,7 @@ static int __init hp100_probe1(struct ne /* Gracefully fallback to shared memory */ goto busmasterfail; } - printk("hp100: %s: Busmaster mode enabled.\n", dev->name); + printk("hp100: Busmaster mode enabled.\n"); hp100_outw(HP100_MEM_EN | HP100_IO_EN | HP100_RESET_LB, OPTION_LSW); } else { busmasterfail: @@ -675,7 +584,7 @@ static int __init hp100_probe1(struct ne mem_ptr_phys &= ~0x1fff; /* 8k alignment */ if (bus == HP100_BUS_ISA && (mem_ptr_phys & ~0xfffff) != 0) { - printk("hp100: %s: Can only use programmed i/o mode.\n", dev->name); + printk("hp100: Can only use programmed i/o mode.\n"); mem_ptr_phys = 0; mem_mapped = 0; local_mode = 3; /* Use programmed i/o */ @@ -699,7 +608,7 @@ static int __init hp100_probe1(struct ne } if (mem_ptr_virt == NULL) { /* all ioremap tries failed */ - printk("hp100: %s: Failed to ioremap the PCI card memory. Will have to use i/o mapped mode.\n", dev->name); + printk("hp100: Failed to ioremap the PCI card memory. Will have to use i/o mapped mode.\n"); local_mode = 3; virt_memory_size = 0; } @@ -710,17 +619,14 @@ static int __init hp100_probe1(struct ne mem_mapped = 0; mem_ptr_phys = 0; mem_ptr_virt = NULL; - printk("hp100: %s: Using (slow) programmed i/o mode.\n", dev->name); + printk("hp100: Using (slow) programmed i/o mode.\n"); } /* Initialise the "private" data structure for this card. */ - if ((dev->priv = kmalloc(sizeof(struct hp100_private), GFP_KERNEL)) == NULL) - return -ENOMEM; - lp = (struct hp100_private *) dev->priv; - memset(lp, 0, sizeof(struct hp100_private)); + spin_lock_init(&lp->lock); - lp->id = eid; + strlcpy(lp->id, eid, HP100_SIG_LEN); lp->chip = chip; lp->mode = local_mode; lp->bus = bus; @@ -741,9 +647,6 @@ static int __init hp100_probe1(struct ne lp->virt_memory_size = virt_memory_size; lp->rx_ratio = hp100_rx_ratio; /* can be conf'd with insmod */ - /* memory region for programmed i/o */ - request_region(dev->base_addr, HP100_REGION_SIZE, eid->name); - dev->open = hp100_open; dev->stop = hp100_close; @@ -776,10 +679,6 @@ static int __init hp100_probe1(struct ne /* Reset statistics (counters) */ hp100_clear_stats(lp, ioaddr); - SET_MODULE_OWNER(dev); - SET_NETDEV_DEV(dev, &pci_dev->dev); - ether_setup(dev); - /* If busmaster mode is wanted, a dma-capable memory area is needed for * the rx and tx PDLs * PCI cards can access the whole PC memory. Therefore GFP_DMA is not @@ -795,8 +694,10 @@ static int __init hp100_probe1(struct ne /* Conversion to new PCI API : * Pages are always aligned and zeroed, no need to it ourself. * Doc says should be OK for EISA bus as well - Jean II */ - if ((lp->page_vaddr_algn = pci_alloc_consistent(lp->pci_dev, MAX_RINGSIZE, &page_baddr)) == NULL) - return -ENOMEM; + if ((lp->page_vaddr_algn = pci_alloc_consistent(lp->pci_dev, MAX_RINGSIZE, &page_baddr)) == NULL) { + err = -ENOMEM; + goto out2; + } lp->whatever_offset = ((u_long) page_baddr) - ((u_long) lp->page_vaddr_algn); #ifdef HP100_DEBUG_BM @@ -818,7 +719,7 @@ static int __init hp100_probe1(struct ne lp->lan_type = hp100_sense_lan(dev); /* Print out a message what about what we think we have probed. */ - printk("hp100: %s: %s at 0x%x, IRQ %d, ", dev->name, lp->id->name, ioaddr, dev->irq); + printk("hp100: at 0x%x, IRQ %d, ", ioaddr, dev->irq); switch (bus) { case HP100_BUS_EISA: printk("EISA"); @@ -833,7 +734,7 @@ static int __init hp100_probe1(struct ne printk(" bus, %dk SRAM (rx/tx %d%%).\n", lp->memory_size >> 10, lp->rx_ratio); if (lp->mode == 2) { /* memory mapped */ - printk("hp100: %s: Memory area at 0x%lx-0x%lx", dev->name, mem_ptr_phys, + printk("hp100: Memory area at 0x%lx-0x%lx", mem_ptr_phys, (mem_ptr_phys + (mem_ptr_phys > 0x100000 ? (u_long) lp->memory_size : 16 * 1024)) - 1); if (mem_ptr_virt) printk(" (virtual base %p)", mem_ptr_virt); @@ -843,7 +744,8 @@ static int __init hp100_probe1(struct ne dev->mem_start = mem_ptr_phys; dev->mem_end = mem_ptr_phys + lp->memory_size; } - printk("hp100: %s: ", dev->name); + + printk("hp100: "); if (lp->lan_type != HP100_LAN_ERR) printk("Adapter is attached to "); switch (lp->lan_type) { @@ -861,6 +763,10 @@ static int __init hp100_probe1(struct ne } return 0; +out2: + release_region(ioaddr, HP100_REGION_SIZE); +out1: + return -ENODEV; } /* This procedure puts the card into a stable init state */ @@ -950,6 +856,7 @@ static void hp100_hwinit(struct net_devi /* Finally try to log in the Hub if there may be a VG connection. */ if ((lp->lan_type == HP100_LAN_100) || (lp->lan_type == HP100_LAN_ERR)) hp100_login_to_vg_hub(dev, 0); /* relogin */ + } @@ -1152,7 +1059,7 @@ static int hp100_open(struct net_device if (request_irq(dev->irq, hp100_interrupt, lp->bus == HP100_BUS_PCI || lp->bus == HP100_BUS_EISA ? SA_SHIRQ : SA_INTERRUPT, - lp->id->name, dev)) { + "hp100", dev)) { printk("hp100: %s: unable to get IRQ %d\n", dev->name, dev->irq); return -EAGAIN; } @@ -2054,7 +1961,7 @@ static void hp100_rx_bm(struct net_devic /* * statistics */ -static hp100_stats_t *hp100_get_stats(struct net_device *dev) +static struct net_device_stats *hp100_get_stats(struct net_device *dev) { unsigned long flags; int ioaddr = dev->base_addr; @@ -2558,10 +2465,14 @@ static int hp100_sense_lan(struct net_de return HP100_LAN_COAX; } - if ((lp->id->id == 0x02019F022) || - (lp->id->id == 0x01042103c) || (lp->id->id == 0x01040103c)) - return HP100_LAN_ERR; /* Those cards don't have a 100 Mbit connector */ - + /* Those cards don't have a 100 Mbit connector */ + if ( !strcmp(lp->id, "HWP1920") || + (lp->pci_dev && + lp->pci_dev->vendor == PCI_VENDOR_ID && + (lp->pci_dev->device == PCI_DEVICE_ID_HP_J2970A || + lp->pci_dev->device == PCI_DEVICE_ID_HP_J2973A))) + return HP100_LAN_ERR; + if (val_VG & HP100_LINK_CABLE_ST) /* Can hear the HUBs tone. */ return HP100_LAN_100; return HP100_LAN_ERR; @@ -2915,121 +2826,247 @@ void hp100_RegisterDump(struct net_devic #endif +static void cleanup_dev(struct net_device *d) +{ + struct hp100_private *p = (struct hp100_private *) d->priv; + + unregister_netdev(d); + release_region(d->base_addr, HP100_REGION_SIZE); + + if (p->mode == 1) /* busmaster */ + pci_free_consistent(p->pci_dev, MAX_RINGSIZE + 0x0f, + p->page_vaddr_algn, + virt_to_whatever(d, p->page_vaddr_algn)); + if (p->mem_ptr_virt) + iounmap(p->mem_ptr_virt); + + free_netdev(d); +} + +#ifdef CONFIG_EISA +static int __init hp100_eisa_probe (struct device *gendev) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private)); + struct eisa_device *edev = to_eisa_device(gendev); + int err; + + if (!dev) + return -ENOMEM; + + SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &edev->dev); + + err = hp100_probe1(dev, edev->base_addr, HP100_BUS_EISA, NULL); + if (err) + goto out1; + + err = register_netdev(dev); + if (err) + goto out2; + +#ifdef HP100_DEBUG + printk("hp100: %s: EISA adapter found at 0x%x\n", dev->name, + dev->base_addr); +#endif + gendev->driver_data = dev; + return 0; + out2: + release_region(dev->base_addr, HP100_REGION_SIZE); + out1: + free_netdev(dev); + return err; +} + +static int __devexit hp100_eisa_remove (struct device *gendev) +{ + struct net_device *dev = gendev->driver_data; + cleanup_dev(dev); + return 0; +} + +static struct eisa_driver hp100_eisa_driver = { + .id_table = hp100_eisa_tbl, + .driver = { + .name = "hp100", + .probe = hp100_eisa_probe, + .remove = __devexit_p (hp100_eisa_remove), + } +}; +#endif + +#ifdef CONFIG_PCI +static int __devinit hp100_pci_probe (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private)); + int ioaddr = pci_resource_start(pdev, 0); + u_short pci_command; + int err; + + if (!dev) + return -ENOMEM; + + SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &pdev->dev); + + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); + if (!(pci_command & PCI_COMMAND_IO)) { +#ifdef HP100_DEBUG + printk("hp100: %s: PCI I/O Bit has not been set. Setting...\n", dev->name); +#endif + pci_command |= PCI_COMMAND_IO; + pci_write_config_word(pdev, PCI_COMMAND, pci_command); + } + + if (!(pci_command & PCI_COMMAND_MASTER)) { +#ifdef HP100_DEBUG + printk("hp100: %s: PCI Master Bit has not been set. Setting...\n", dev->name); +#endif + pci_command |= PCI_COMMAND_MASTER; + pci_write_config_word(pdev, PCI_COMMAND, pci_command); + } + + + err = hp100_probe1(dev, ioaddr, HP100_BUS_PCI, pdev); + if (err) + goto out1; + err = register_netdev(dev); + if (err) + goto out2; + +#ifdef HP100_DEBUG + printk("hp100: %s: PCI adapter found at 0x%x\n", dev->name, ioaddr); +#endif + pci_set_drvdata(pdev, dev); + return 0; + out2: + release_region(dev->base_addr, HP100_REGION_SIZE); + out1: + free_netdev(dev); + return err; +} + +static void __devexit hp100_pci_remove (struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + cleanup_dev(dev); +} + + +static struct pci_driver hp100_pci_driver = { + .name = "hp100", + .id_table = hp100_pci_tbl, + .probe = hp100_pci_probe, + .remove = __devexit_p(hp100_pci_remove), +}; +#endif + /* * module section */ -#ifdef MODULE - MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jaroslav Kysela , " "Siegfried \"Frieder\" Loeffler (dg1sek) "); MODULE_DESCRIPTION("HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters"); /* - * Note: if you have more than five 100vg cards in your pc, feel free to - * increase this value - */ - -#define HP100_DEVICES 5 - -/* - * Note: to register three eisa or pci devices, use: + * Note: to register three isa devices, use: * option hp100 hp100_port=0,0,0 * to register one card at io 0x280 as eth239, use: - * option hp100 hp100_port=0x280 hp100_name=eth239 + * option hp100 hp100_port=0x280 */ - +#if defined(MODULE) && defined(CONFIG_ISA) +#define HP100_DEVICES 5 /* Parameters set by insmod */ static int hp100_port[HP100_DEVICES] = { 0, [1 ... (HP100_DEVICES-1)] = -1 }; MODULE_PARM(hp100_port, "1-" __MODULE_STRING(HP100_DEVICES) "i"); -/* Allocate HP100_DEVICES strings of length IFNAMSIZ, one string for each device */ -static char hp100_name[HP100_DEVICES][IFNAMSIZ] = { "", "", "", "", "" }; -/* Allow insmod to write those HP100_DEVICES strings individually */ -MODULE_PARM(hp100_name, "1-" __MODULE_STRING(HP100_DEVICES) "c" __MODULE_STRING(IFNAMSIZ)); - /* List of devices */ static struct net_device *hp100_devlist[HP100_DEVICES]; -static void release_dev(int i) +static int __init hp100_isa_init(void) { - struct net_device *d = hp100_devlist[i]; - struct hp100_private *p = (struct hp100_private *) d->priv; + struct net_device *dev; + int i, err, cards = 0; - unregister_netdev(d); - release_region(d->base_addr, HP100_REGION_SIZE); + /* Don't autoprobe ISA bus */ + if (hp100_port[0] == 0) + return -ENODEV; - if (p->mode == 1) /* busmaster */ - pci_free_consistent(p->pci_dev, MAX_RINGSIZE + 0x0f, p->page_vaddr_algn, virt_to_whatever(d, p->page_vaddr_algn)); - if (p->mem_ptr_virt) - iounmap(p->mem_ptr_virt); - kfree(d->priv); - d->priv = NULL; - free_netdev(d); - hp100_devlist[i] = NULL; + /* Loop on all possible base addresses */ + for (i = 0; i < HP100_DEVICES && hp100_port[i] != -1; ++i) { + dev = alloc_etherdev(sizeof(struct hp100_private)); + if (!dev) { + printk(KERN_WARNING "hp100: no memory for network device\n"); + while (cards > 0) + cleanup_dev(hp100_devlist[--cards]); + + return -ENOMEM; + } + SET_MODULE_OWNER(dev); + + err = hp100_isa_probe(dev, hp100_port[i]); + if (!err) { + err = register_netdev(dev); + if (!err) + hp100_devlist[cards++] = dev; + else + release_region(dev->base_addr, HP100_REGION_SIZE); + } + + if (err) + free_netdev(dev); + } + + return cards > 0 ? 0 : -ENODEV; } -static int __init hp100_module_init(void) +static void __exit hp100_isa_cleanup(void) { - int i, cards; + int i; -#ifndef CONFIG_PCI - if (hp100_port == 0 && !EISA_bus) - printk("hp100: You should not use auto-probing with insmod!\n"); + for (i = 0; i < HP100_DEVICES; i++) { + struct net_device *dev = hp100_devlist[i]; + if (dev) + cleanup_dev(dev); + } +} +#else +#define hp100_isa_init() (0) +#define hp100_isa_cleanup() do { } while(0) #endif - /* Loop on all possible base addresses */ - i = -1; - cards = 0; - while ((hp100_port[++i] != -1) && (i < HP100_DEVICES)) { - /* Create device and set basics args */ - hp100_devlist[i] = kmalloc(sizeof(struct net_device), GFP_KERNEL); - if (!hp100_devlist[i]) - goto fail; - memset(hp100_devlist[i], 0x00, sizeof(struct net_device)); -#if LINUX_VERSION_CODE >= 0x020362 /* 2.3.99-pre7 */ - memcpy(hp100_devlist[i]->name, hp100_name[i], IFNAMSIZ); /* Copy name */ -#else - hp100_devlist[i]->name = hp100_name[i]; -#endif /* LINUX_VERSION_CODE >= 0x020362 */ - hp100_devlist[i]->base_addr = hp100_port[i]; - hp100_devlist[i]->init = &hp100_probe; - - /* Try to create the device */ - if (register_netdev(hp100_devlist[i]) != 0) { - /* DeAllocate everything */ - /* Note: if dev->priv is mallocated, there is no way to fail */ - kfree(hp100_devlist[i]); - hp100_devlist[i] = (struct net_device *) NULL; - } else - cards++; - } /* Loop over all devices */ +static int __init hp100_module_init(void) +{ + int err; - return cards > 0 ? 0 : -ENODEV; - fail: - while (cards && --i) - if (hp100_devlist[i]) { - release_dev(i); - --cards; - } - return -ENOMEM; + err = hp100_isa_init(); + +#ifdef CONFIG_EISA + err |= eisa_driver_register(&hp100_eisa_driver); +#endif +#ifdef CONFIG_PCI + err |= pci_module_init(&hp100_pci_driver); +#endif + return err; } + static void __exit hp100_module_exit(void) { - int i; - - /* TODO: Check if all skb's are released/freed. */ - for (i = 0; i < HP100_DEVICES; i++) - if (hp100_devlist[i] != (struct net_device *) NULL) - release_dev(i); + hp100_isa_cleanup(); +#ifdef CONFIG_EISA + eisa_driver_unregister (&hp100_eisa_driver); +#endif +#ifdef CONFIG_PCI + pci_unregister_driver (&hp100_pci_driver); +#endif } module_init(hp100_module_init) module_exit(hp100_module_exit) - -#endif /* MODULE */ /* diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/hplance.c 830-ivtv/drivers/net/hplance.c --- 000-virgin/drivers/net/hplance.c Tue Sep 2 09:55:47 2003 +++ 830-ivtv/drivers/net/hplance.c Thu Jan 8 08:54:17 2004 @@ -50,8 +50,7 @@ struct hplance_private { * plus board-specific init, open and close actions. * Oh, and we need to tell the generic code how to read and write LANCE registers... */ -int hplance_probe(struct net_device *dev); -static int hplance_init(struct net_device *dev, int scode); +static void hplance_init(struct net_device *dev, int scode); static int hplance_open(struct net_device *dev); static int hplance_close(struct net_device *dev); static void hplance_writerap(void *priv, unsigned short value); @@ -62,57 +61,61 @@ static unsigned short hplance_readrdp(vo static struct hplance_private *root_hplance_dev; #endif +static void cleanup_card(struct net_device *dev) +{ + struct hplance_private *lp = dev->priv; + dio_unconfig_board(lp->scode); +} + /* Find all the HP Lance boards and initialise them... */ -int __init hplance_probe(struct net_device *dev) +struct net_device * __init hplance_probe(int unit) { - int cards = 0, called = 0; + struct net_device *dev; + + if (!MACH_IS_HP300) + return ERR_PTR(-ENODEV); + + dev = alloc_etherdev(sizeof(struct hplance_private)); + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } - if (!MACH_IS_HP300 || called) - return(ENODEV); - called++; + SET_MODULE_OWNER(dev); /* Isn't DIO nice? */ for(;;) { - int v, scode = dio_find(DIO_ID_LAN); + int scode = dio_find(DIO_ID_LAN); if (!scode) break; - if(cards) - dev = NULL; /* don't trash previous device, make a new one */ - cards++; - - v = hplance_init(dev, scode); - if (v) /* error, abort immediately */ - return v; + dio_config_board(scode); + hplance_init(dev, scode); + if (!register_netdev(dev)) { + struct hplance_private *lp = dev->priv; + lp->next_module = root_hplance_dev; + root_hplance_dev = lp; + return dev; + } + cleanup_card(dev); } - /* OK, return success, or ENODEV if we didn't find any cards */ - if (!cards) - return -ENODEV; - return 0; + free_netdev(dev); + return ERR_PTR(-ENODEV); } /* Initialise a single lance board at the given select code */ -static int __init hplance_init(struct net_device *dev, int scode) +static void __init hplance_init(struct net_device *dev, int scode) { const char *name = dio_scodetoname(scode); void *va = dio_scodetoviraddr(scode); struct hplance_private *lp; int i; -#ifdef MODULE - dev = init_etherdev(0, sizeof(struct hplance_private)); - if (!dev) - return -ENOMEM; -#else - dev->priv = kmalloc(sizeof(struct hplance_private), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct hplance_private)); -#endif - SET_MODULE_OWNER(dev); - printk("%s: %s; select code %d, addr", dev->name, name, scode); /* reset the board */ @@ -154,17 +157,7 @@ static int __init hplance_init(struct ne lp->lance.tx_ring_mod_mask = TX_RING_MOD_MASK; lp->scode = scode; lp->base = va; - ether_setup(dev); printk(", irq %d\n", lp->lance.irq); - -#ifdef MODULE - dev->ifindex = dev_new_index(); - lp->next_module = root_hplance_dev; - root_hplance_dev = lp; -#endif /* MODULE */ - - dio_config_board(scode); /* tell bus scanning code this one's taken */ - return 0; } /* This is disgusting. We have to check the DIO status register for ack every @@ -227,8 +220,10 @@ static int hplance_close(struct net_devi MODULE_LICENSE("GPL"); int init_module(void) { - root_lance_dev = NULL; - return hplance_probe(NULL); + int found = 0; + while (!IS_ERR(hplance_probe(-1))) + found++; + return found ? 0 : -ENODEV; } void cleanup_module(void) @@ -237,8 +232,8 @@ void cleanup_module(void) struct hplance_private *lp; while (root_hplance_dev) { lp = root_hplance_dev->next_module; - dio_unconfig_board(lp->scode); unregister_netdev(root_lance_dev->dev); + cleanup_card(root_lance_dev->dev); free_netdev(root_lance_dev->dev); root_lance_dev = lp; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/hydra.c 830-ivtv/drivers/net/hydra.c --- 000-virgin/drivers/net/hydra.c Tue Sep 2 09:55:47 2003 +++ 830-ivtv/drivers/net/hydra.c Thu Jan 8 08:54:17 2004 @@ -89,13 +89,14 @@ static int __init hydra_init(unsigned lo const char name[] = "NE2000"; int start_page, stop_page; int j; + int err; static u32 hydra_offsets[16] = { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, }; - dev = init_etherdev(NULL, 0); + dev = alloc_ei_netdev(); if (!dev) return -ENOMEM; SET_MODULE_OWNER(dev); @@ -113,13 +114,9 @@ static int __init hydra_init(unsigned lo /* Install the Interrupt handler */ if (request_irq(IRQ_AMIGA_PORTS, ei_interrupt, SA_SHIRQ, "Hydra Ethernet", - dev)) + dev)) { + free_netdev(dev); return -EAGAIN; - - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk("Unable to get memory for dev->priv.\n"); - return -ENOMEM; } printk("%s: hydra at 0x%08lx, address %02x:%02x:%02x:%02x:%02x:%02x (hydra.c " HYDRA_VERSION ")\n", dev->name, ZTWO_PADDR(board), @@ -146,7 +143,13 @@ static int __init hydra_init(unsigned lo root_hydra_dev = dev; #endif NS8390_init(dev, 0); - return 0; + err = register_netdev(dev); + if (!err) + return 0; + + free_irq(IRQ_AMIGA_PORTS, dev); + free_netdev(dev); + return err; } static int hydra_open(struct net_device *dev) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/ibmlana.c 830-ivtv/drivers/net/ibmlana.c --- 000-virgin/drivers/net/ibmlana.c Mon Nov 17 18:29:30 2003 +++ 830-ivtv/drivers/net/ibmlana.c Thu Jan 8 08:54:17 2004 @@ -906,7 +906,7 @@ static void ibmlana_set_multicast_list(s static int startslot; /* counts through slots when probing multiple devices */ -int ibmlana_probe(struct net_device *dev) +static int ibmlana_probe(struct net_device *dev) { int force_detect = 0; int slot, z; @@ -924,34 +924,21 @@ int ibmlana_probe(struct net_device *dev if (dev->mem_start == 1) force_detect = 1; - /* search through slots */ - if (dev != NULL) { - base = dev->mem_start; - irq = dev->irq; - } - slot = mca_find_adapter(IBM_LANA_ID, startslot); + base = dev->mem_start; + irq = dev->irq; - while (slot != -1) { + for (slot = startslot; (slot = mca_find_adapter(IBM_LANA_ID, slot)) != -1; slot++) { /* deduce card addresses */ getaddrs(slot, &base, &memlen, &iobase, &irq, &medium); /* slot already in use ? */ - if (mca_is_adapter_used(slot)) { - slot = mca_find_adapter(IBM_LANA_ID, slot + 1); + if (mca_is_adapter_used(slot)) continue; - } /* were we looking for something different ? */ - if (dev->irq != 0 || dev->mem_start != 0) { - if (dev->irq != 0 && dev->irq != irq) { - slot = mca_find_adapter(IBM_LANA_ID, slot + 1); - continue; - } - if (dev->mem_start != 0 && dev->mem_start != base) - { - slot = mca_find_adapter(IBM_LANA_ID, slot + 1); - continue; - } - } + if (dev->irq && dev->irq != irq) + continue; + if (dev->mem_start && dev->mem_start != base) + continue; /* found something that matches */ break; } @@ -977,16 +964,11 @@ int ibmlana_probe(struct net_device *dev mca_mark_as_used(slot); /* allocate structure */ - priv = dev->priv = (ibmlana_priv *) kmalloc(sizeof(ibmlana_priv), GFP_KERNEL); - if (!priv) { - release_region(iobase, IBM_LANA_IORANGE); - return -ENOMEM; - } + priv = dev->priv; priv->slot = slot; priv->realirq = irq; priv->medium = medium; spin_lock_init(&priv->lock); - memset(&priv->stat, 0, sizeof(struct net_device_stats)); /* set base + irq for this device (irq not allocated so far) */ @@ -1006,10 +988,6 @@ int ibmlana_probe(struct net_device *dev dev->set_multicast_list = ibmlana_set_multicast_list; dev->flags |= IFF_MULTICAST; - /* generic setup */ - - ether_setup(dev); - /* copy out MAC address */ for (z = 0; z < sizeof(dev->dev_addr); z++) @@ -1044,7 +1022,7 @@ int ibmlana_probe(struct net_device *dev #define DEVMAX 5 -static struct net_device moddevs[DEVMAX]; +static struct net_device *moddevs[DEVMAX]; static int irq; static int io; @@ -1056,41 +1034,47 @@ MODULE_LICENSE("GPL"); int init_module(void) { - int z, res; + int z; startslot = 0; for (z = 0; z < DEVMAX; z++) { - moddevs[z].init = ibmlana_probe; - moddevs[z].irq = irq; - moddevs[z].base_addr = io; - res = register_netdev(moddevs + z); - if (res != 0) - return (z > 0) ? 0 : -EIO; + struct net_device *dev = alloc_etherdev(sizeof(ibmlana_priv)); + if (!dev) + break; + dev->irq = irq; + dev->base_addr = io; + if (ibmlana_probe(dev)) { + free_netdev(dev); + break; + } + if (register_netdev(dev)) { + ibmlana_priv *priv = dev->priv; + release_region(dev->base_addr, IBM_LANA_IORANGE); + mca_mark_as_unused(priv->slot); + mca_set_adapter_name(priv->slot, ""); + mca_set_adapter_procfn(priv->slot, NULL, NULL); + free_netdev(dev); + break; + } + moddevs[z] = dev; } - return 0; + return (z > 0) ? 0 : -EIO; } void cleanup_module(void) { - struct net_device *dev; - ibmlana_priv *priv; int z; - for (z = 0; z < DEVMAX; z++) { - dev = moddevs + z; - if (dev->priv != NULL) { - priv = (ibmlana_priv *) dev->priv; + struct net_device *dev = moddevs[z]; + if (dev) { + ibmlana_priv *priv = (ibmlana_priv *) dev->priv; + unregister_netdev(dev); /*DeinitBoard(dev); */ - if (dev->irq != 0) - free_irq(dev->irq, dev); - dev->irq = 0; release_region(dev->base_addr, IBM_LANA_IORANGE); - unregister_netdev(dev); mca_mark_as_unused(priv->slot); mca_set_adapter_name(priv->slot, ""); mca_set_adapter_procfn(priv->slot, NULL, NULL); - kfree(dev->priv); - dev->priv = NULL; + free_netdev(dev); } } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/ibmlana.h 830-ivtv/drivers/net/ibmlana.h --- 000-virgin/drivers/net/ibmlana.h Sun Nov 17 20:29:53 2002 +++ 830-ivtv/drivers/net/ibmlana.h Thu Jan 8 08:54:17 2004 @@ -275,7 +275,4 @@ typedef struct { #endif /* _IBM_LANA_DRIVER_ */ -extern int ibmlana_probe(struct net_device *); - - #endif /* _IBM_LANA_INCLUDE_ */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/irda/sa1100_ir.c 830-ivtv/drivers/net/irda/sa1100_ir.c --- 000-virgin/drivers/net/irda/sa1100_ir.c Mon Nov 17 18:29:42 2003 +++ 830-ivtv/drivers/net/irda/sa1100_ir.c Thu Jan 8 08:54:17 2004 @@ -20,6 +20,7 @@ */ #include #include +#include #include #include #include @@ -358,9 +359,13 @@ static void sa1100_irda_shutdown(struct static int sa1100_irda_suspend(struct device *_dev, u32 state, u32 level) { struct net_device *dev = dev_get_drvdata(_dev); - struct sa1100_irda *si = dev->priv; + struct sa1100_irda *si; + + if (!dev || level != SUSPEND_DISABLE) + return 0; - if (si && si->open && level == SUSPEND_DISABLE) { + si = dev->priv; + if (si->open) { /* * Stop the transmit queue */ @@ -379,9 +384,13 @@ static int sa1100_irda_suspend(struct de static int sa1100_irda_resume(struct device *_dev, u32 level) { struct net_device *dev = dev_get_drvdata(_dev); - struct sa1100_irda *si = dev->priv; + struct sa1100_irda *si; - if (si && si->open && level == RESUME_ENABLE) { + if (!dev || level != RESUME_ENABLE) + return 0; + + si = dev->priv; + if (si->open) { /* * If we missed a speed change, initialise at the new speed * directly. It is debatable whether this is actually @@ -833,8 +842,6 @@ static int sa1100_irda_start(struct net_ struct sa1100_irda *si = dev->priv; int err; - MOD_INC_USE_COUNT; - si->speed = 9600; err = request_irq(dev->irq, sa1100_irda_irq, 0, dev->name, dev); @@ -890,7 +897,6 @@ err_tx_dma: err_rx_dma: free_irq(dev->irq, dev); err_irq: - MOD_DEC_USE_COUNT; return err; } @@ -930,8 +936,6 @@ static int sa1100_irda_stop(struct net_d sa1100_set_power(si, 0); - MOD_DEC_USE_COUNT; - return 0; } @@ -947,56 +951,48 @@ static int sa1100_irda_init_iobuf(iobuff return io->head ? 0 : -ENOMEM; } -static struct device_driver sa1100ir_driver = { - .name = "sa1100ir", - .bus = &system_bus_type, - .suspend = sa1100_irda_suspend, - .resume = sa1100_irda_resume, -}; - -static struct sys_device sa1100ir_device = { - .name = "sa1100ir", - .id = 0, - .root = NULL, - .dev = { - .name = "Intel Corporation SA11x0 [IrDA]", - .bus_id = "0", - .driver = &sa1100ir_driver, - }, -}; - -static int sa1100_irda_net_init(struct net_device *dev) +static int sa1100_irda_probe(struct device *_dev) { - struct sa1100_irda *si = dev->priv; + struct platform_device *pdev = to_platform_device(_dev); + struct net_device *dev; + struct sa1100_irda *si; unsigned int baudrate_mask; - int err = -ENOMEM; + int err; - si = kmalloc(sizeof(struct sa1100_irda), GFP_KERNEL); - if (!si) - goto out; + err = request_mem_region(__PREG(Ser2UTCR0), 0x24, "IrDA") ? 0 : -EBUSY; + if (err) + goto err_mem_1; + err = request_mem_region(__PREG(Ser2HSCR0), 0x1c, "IrDA") ? 0 : -EBUSY; + if (err) + goto err_mem_2; + err = request_mem_region(__PREG(Ser2HSCR2), 0x04, "IrDA") ? 0 : -EBUSY; + if (err) + goto err_mem_3; - memset(si, 0, sizeof(*si)); + dev = alloc_irdadev(sizeof(struct sa1100_irda)); + if (!dev) + goto err_mem_4; - si->dev = &sa1100ir_device.dev; + si = dev->priv; + si->dev = &pdev->dev; /* * Initialise the HP-SIR buffers */ err = sa1100_irda_init_iobuf(&si->rx_buff, 14384); if (err) - goto out; + goto err_mem_5; err = sa1100_irda_init_iobuf(&si->tx_buff, 4000); if (err) - goto out_free_rx; + goto err_mem_5; - dev->priv = si; dev->hard_start_xmit = sa1100_irda_hard_xmit; dev->open = sa1100_irda_start; dev->stop = sa1100_irda_stop; dev->do_ioctl = sa1100_irda_ioctl; dev->get_stats = sa1100_irda_stats; + dev->irq = IRQ_Ser2ICP; - irda_device_setup(dev); irda_init_max_qos_capabilies(&si->qos); /* @@ -1030,42 +1026,62 @@ static int sa1100_irda_net_init(struct n Ser2UTCR4 = si->utcr4; Ser2HSCR0 = HSCR0_UART; - return 0; - - kfree(si->tx_buff.head); -out_free_rx: - kfree(si->rx_buff.head); -out: - kfree(si); + err = register_netdev(dev); + if (err == 0) + dev_set_drvdata(&pdev->dev, si); + if (err) { + err_mem_5: + kfree(si->tx_buff.head); + kfree(si->rx_buff.head); + free_netdev(dev); + err_mem_4: + release_mem_region(__PREG(Ser2HSCR2), 0x04); + err_mem_3: + release_mem_region(__PREG(Ser2HSCR0), 0x1c); + err_mem_2: + release_mem_region(__PREG(Ser2UTCR0), 0x24); + } + err_mem_1: return err; } -/* - * Remove all traces of this driver module from the kernel, so we can't be - * called. Note that the device has already been stopped, so we don't have - * to worry about interrupts or dma. - */ -static void sa1100_irda_net_uninit(struct net_device *dev) +static int sa1100_irda_remove(struct device *_dev) { - struct sa1100_irda *si = dev->priv; + struct net_device *dev = dev_get_drvdata(_dev); - dev->hard_start_xmit = NULL; - dev->open = NULL; - dev->stop = NULL; - dev->do_ioctl = NULL; - dev->get_stats = NULL; - dev->priv = NULL; - - kfree(si->tx_buff.head); - kfree(si->rx_buff.head); - kfree(si); + if (dev) { + struct sa1100_irda *si = dev->priv; + unregister_netdev(dev); + kfree(si->tx_buff.head); + kfree(si->rx_buff.head); + free_netdev(dev); + } + + release_mem_region(__PREG(Ser2HSCR2), 0x04); + release_mem_region(__PREG(Ser2HSCR0), 0x1c); + release_mem_region(__PREG(Ser2UTCR0), 0x24); + + return 0; } +static struct device_driver sa1100ir_driver = { + .name = "sa11x0-ir", + .bus = &platform_bus_type, + .probe = sa1100_irda_probe, + .remove = sa1100_irda_remove, + .suspend = sa1100_irda_suspend, + .resume = sa1100_irda_resume, +}; + +static struct platform_device sa1100ir_device = { + .name = "sa11x0-ir", + .id = 0, +}; + static int __init sa1100_irda_init(void) { - struct net_device *dev; - int err; + int ret; /* * Limit power level a sensible range. @@ -1075,103 +1091,30 @@ static int __init sa1100_irda_init(void) if (power_level > 3) power_level = 3; - err = request_mem_region(__PREG(Ser2UTCR0), 0x24, "IrDA") ? 0 : -EBUSY; - if (err) - goto err_mem_1; - err = request_mem_region(__PREG(Ser2HSCR0), 0x1c, "IrDA") ? 0 : -EBUSY; - if (err) - goto err_mem_2; - err = request_mem_region(__PREG(Ser2HSCR2), 0x04, "IrDA") ? 0 : -EBUSY; - if (err) - goto err_mem_3; - - driver_register(&sa1100ir_driver); - sys_device_register(&sa1100ir_device); - - rtnl_lock(); - dev = dev_alloc("irda%d", &err); - if (dev) { - dev->irq = IRQ_Ser2ICP; - dev->init = sa1100_irda_net_init; - dev->uninit = sa1100_irda_net_uninit; - - err = register_netdevice(dev); - - if (err) - kfree(dev); - else - dev_set_drvdata(&sa1100ir_device.dev, dev); + ret = driver_register(&sa1100ir_driver); + if (ret == 0) { + ret = platform_device_register(&sa1100ir_device); + if (ret) + driver_unregister(&sa1100ir_driver); } - rtnl_unlock(); - - if (err) { - sys_device_unregister(&sa1100ir_device); - driver_unregister(&sa1100ir_driver); - - release_mem_region(__PREG(Ser2HSCR2), 0x04); -err_mem_3: - release_mem_region(__PREG(Ser2HSCR0), 0x1c); -err_mem_2: - release_mem_region(__PREG(Ser2UTCR0), 0x24); - } -err_mem_1: - return err; + return ret; } static void __exit sa1100_irda_exit(void) { - struct net_device *dev = dev_get_drvdata(&sa1100ir_device.dev); - - if (dev) - unregister_netdev(dev); - - sys_device_unregister(&sa1100ir_device); driver_unregister(&sa1100ir_driver); - - release_mem_region(__PREG(Ser2HSCR2), 0x04); - release_mem_region(__PREG(Ser2HSCR0), 0x1c); - release_mem_region(__PREG(Ser2UTCR0), 0x24); - - if(dev) - free_netdev(dev); + platform_device_unregister(&sa1100ir_device); } -static int __init sa1100ir_setup(char *line) -{ - char *opt; - - if (!line) - return 0; - - while ((opt = strsep(&line, ",")) != NULL) { - if (!strncmp(opt, "max_rate:", 9)) { - max_rate = simple_strtoul(opt + 9, NULL, 0); - continue; - } - if (!strncmp(opt, "power_level:", 12)) { - power_level = simple_strtoul(opt + 12, NULL, 0); - continue; - } - if (!strncmp(opt, "tx_lpm:", 7)) { - tx_lpm = simple_strtoul(opt + 7, NULL, 0); - continue; - } - } - - return 1; -} - -__setup("sa1100ir=", sa1100ir_setup); - module_init(sa1100_irda_init); module_exit(sa1100_irda_exit); +module_param(power_level, int, 0); +module_param(tx_lpm, int, 0); +module_param(max_rate, int, 0); MODULE_AUTHOR("Russell King "); MODULE_DESCRIPTION("StrongARM SA1100 IrDA driver"); MODULE_LICENSE("GPL"); -MODULE_PARM(power_level, "i"); MODULE_PARM_DESC(power_level, "IrDA power level, 1 (low) to 3 (high)"); -MODULE_PARM(tx_lpm, "i"); MODULE_PARM_DESC(tx_lpm, "Enable transmitter low power (1.6us) mode"); -MODULE_PARM(max_rate, "i"); MODULE_PARM_DESC(max_rate, "Maximum baud rate (4000000, 115200, 57600, 38400, 19200, 9600)"); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/ixgb/ixgb_main.c 830-ivtv/drivers/net/ixgb/ixgb_main.c --- 000-virgin/drivers/net/ixgb/ixgb_main.c Mon Nov 17 18:28:15 2003 +++ 830-ivtv/drivers/net/ixgb/ixgb_main.c Thu Jan 8 08:54:17 2004 @@ -446,7 +446,7 @@ ixgb_probe(struct pci_dev *pdev, const s iounmap(adapter->hw.hw_addr); err_ioremap: pci_release_regions(pdev); - kfree(netdev); + free_netdev(netdev); err_alloc_etherdev: return -ENOMEM; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/jazzsonic.c 830-ivtv/drivers/net/jazzsonic.c --- 000-virgin/drivers/net/jazzsonic.c Sun Dec 1 09:59:51 2002 +++ 830-ivtv/drivers/net/jazzsonic.c Thu Jan 8 08:54:17 2004 @@ -80,7 +80,6 @@ static unsigned short known_revisions[] /* Index to functions, as function prototypes. */ -extern int sonic_probe(struct net_device *dev); static int sonic_probe1(struct net_device *dev, unsigned int base_addr, unsigned int irq); @@ -89,29 +88,57 @@ static int sonic_probe1(struct net_devic * Probe for a SONIC ethernet controller on a Mips Jazz board. * Actually probing is superfluous but we're paranoid. */ -int __init sonic_probe(struct net_device *dev) +struct net_device * __init sonic_probe(int unit) { - unsigned int base_addr = dev ? dev->base_addr : 0; + struct net_device *dev; + struct sonic_local *lp; + unsigned int base_addr; + int err = 0; int i; /* * Don't probe if we're not running on a Jazz board. */ if (mips_machgroup != MACH_GROUP_JAZZ) - return -ENODEV; - if (base_addr >= KSEG0) /* Check a single specified location. */ - return sonic_probe1(dev, base_addr, dev->irq); - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; - - for (i = 0; sonic_portlist[i].port; i++) { - int base_addr = sonic_portlist[i].port; - if (check_region(base_addr, 0x100)) - continue; - if (sonic_probe1(dev, base_addr, sonic_portlist[i].irq) == 0) - return 0; + return ERR_PTR(-ENODEV); + + dev = alloc_etherdev(0); + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + base_addr = dev->base_addr; + + if (base_addr >= KSEG0) { /* Check a single specified location. */ + err = sonic_probe1(dev, base_addr, dev->irq); + } else if (base_addr != 0) { /* Don't probe at all. */ + err = -ENXIO; + } else { + for (i = 0; sonic_portlist[i].port; i++) { + int io = sonic_portlist[i].port; + if (sonic_probe1(dev, io, sonic_portlist[i].irq) == 0) + break; + } + if (!sonic_portlist[i].port) + err = -ENODEV; } - return -ENODEV; + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + lp = dev->priv; + vdma_free(lp->rba_laddr); + kfree(lp->rba); + vdma_free(lp->cda_laddr); + kfree(lp); + release_region(dev->base_addr, 0x100); +out: + free_netdev(dev); + return ERR_PTR(err); } static int __init sonic_probe1(struct net_device *dev, unsigned int base_addr, @@ -121,8 +148,11 @@ static int __init sonic_probe1(struct ne unsigned int silicon_revision; unsigned int val; struct sonic_local *lp; + int err = -ENODEV; int i; + if (!request_region(base_addr, 0x100, dev->name)) + return -EBUSY; /* * get the Silicon Revision ID. If this is one of the known * one assume that we found a SONIC ethernet controller at @@ -140,12 +170,9 @@ static int __init sonic_probe1(struct ne if (known_revisions[i] == 0xffff) { printk("SONIC ethernet controller not found (0x%4x)\n", silicon_revision); - return -ENODEV; + goto out; } - if (!request_region(base_addr, 0x100, dev->name)) - return -EBUSY; - if (sonic_debug && version_printed++ == 0) printk(version); @@ -175,6 +202,8 @@ static int __init sonic_probe1(struct ne } printk(" IRQ %d\n", irq); + + err = -ENOMEM; /* Initialize the device structure. */ if (dev->priv == NULL) { @@ -196,7 +225,7 @@ static int __init sonic_probe1(struct ne if (lp == NULL) { printk("%s: couldn't allocate memory for descriptors\n", dev->name); - return -ENOMEM; + goto out; } memset(lp, 0, sizeof(struct sonic_local)); @@ -206,7 +235,7 @@ static int __init sonic_probe1(struct ne if (lp->cda_laddr == ~0UL) { printk("%s: couldn't get DMA page entry for " "descriptors\n", dev->name); - return -ENOMEM; + goto out1; } lp->tda_laddr = lp->cda_laddr + sizeof (lp->cda); @@ -219,7 +248,7 @@ static int __init sonic_probe1(struct ne if (!lp->rba) { printk("%s: couldn't allocate receive buffers\n", dev->name); - return -ENOMEM; + goto out2; } /* get virtual dma address */ @@ -228,7 +257,7 @@ static int __init sonic_probe1(struct ne if (lp->rba_laddr == ~0UL) { printk("%s: couldn't get DMA page entry for receive " "buffers\n",dev->name); - return -ENOMEM; + goto out3; } /* now convert pointer to KSEG1 pointer */ @@ -252,9 +281,16 @@ static int __init sonic_probe1(struct ne SONIC_WRITE(SONIC_FAET,0xffff); SONIC_WRITE(SONIC_MPT,0xffff); - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); return 0; +out3: + kfree(lp->rba); +out2: + vdma_free(lp->cda_laddr); +out1: + kfree(lp); +out: + release_region(base_addr, 0x100); + return err; } /* diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/kgdb_eth.c 830-ivtv/drivers/net/kgdb_eth.c --- 000-virgin/drivers/net/kgdb_eth.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/net/kgdb_eth.c Thu Jan 8 09:30:18 2004 @@ -0,0 +1,131 @@ +/* + * Network interface GDB stub + * + * Written by San Mehat (nettwerk@biodome.org) + * Based upon 'gdbserial' by David Grothe (dave@gcom.com) + * and Scott Foehner (sfoehner@engr.sgi.com) + * + * Twiddled for 2.6 by Robert Walsh + * and wangdi . + * + * Refactored for netpoll API by Matt Mackall + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define IN_BUF_SIZE 512 /* power of 2, please */ +#define OUT_BUF_SIZE 256 + +static char in_buf[IN_BUF_SIZE], out_buf[OUT_BUF_SIZE]; +static int in_head, in_tail, out_count; +static atomic_t in_count; +int kgdboe = 0; /* Default to tty mode */ + +extern void set_debug_traps(void); +extern void breakpoint(void); +static void rx_hook(struct netpoll *np, int port, char *msg, int len); + +static struct netpoll np = { + .name = "kgdboe", + .dev_name = "eth0", + .rx_hook = rx_hook, + .local_port = 6443, + .remote_port = 6442, + .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, +}; + +int eth_getDebugChar(void) +{ + int chr; + + while (atomic_read(&in_count) == 0) + netpoll_poll(&np); + + chr = in_buf[in_tail++]; + in_tail &= (IN_BUF_SIZE - 1); + atomic_dec(&in_count); + return chr; +} + +void eth_flushDebugChar(void) +{ + if(out_count && np.dev) { + netpoll_send_udp(&np, out_buf, out_count); + out_count = 0; + } +} + +void eth_putDebugChar(int chr) +{ + out_buf[out_count++] = chr; + if(out_count == OUT_BUF_SIZE) + eth_flushDebugChar(); +} + +static void rx_hook(struct netpoll *np, int port, char *msg, int len) +{ + int i; + + np->remote_port = port; + + /* Is this gdb trying to attach? */ + if (!netpoll_trap() && len == 8 && !strncmp(msg, "$Hc-1#09", 8)) + kgdb_schedule_breakpoint(); + + for (i = 0; i < len; i++) { + if (msg[i] == 3) + kgdb_schedule_breakpoint(); + + if (atomic_read(&in_count) >= IN_BUF_SIZE) { + /* buffer overflow, clear it */ + in_head = in_tail = 0; + atomic_set(&in_count, 0); + break; + } + in_buf[in_head++] = msg[i]; + in_head &= (IN_BUF_SIZE - 1); + atomic_inc(&in_count); + } +} + +static int option_setup(char *opt) +{ + return netpoll_parse_options(&np, opt); +} + +__setup("kgdboe=", option_setup); + +static int init_kgdboe(void) +{ +#ifdef CONFIG_SMP + if (num_online_cpus() > CONFIG_NO_KGDB_CPUS) { + printk("kgdb: too manu cpus. Cannot enable debugger with more than %d cpus\n", CONFIG_NO_KGDB_CPUS); + return -1; + } +#endif + + set_debug_traps(); + + if(!np.remote_ip || netpoll_setup(&np)) + return 1; + + kgdboe = 1; + printk(KERN_INFO "kgdb: debugging over ethernet enabled\n"); + + return 0; +} + +module_init(init_kgdboe); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/lance.c 830-ivtv/drivers/net/lance.c --- 000-virgin/drivers/net/lance.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/lance.c Thu Jan 8 08:54:17 2004 @@ -59,8 +59,8 @@ static const char version[] = "lance.c:v #include static unsigned int lance_portlist[] __initdata = { 0x300, 0x320, 0x340, 0x360, 0}; -int lance_probe(struct net_device *dev); static int lance_probe1(struct net_device *dev, int ioaddr, int irq, int options); +static int __init do_lance_probe(struct net_device *dev); #ifdef LANCE_DEBUG static int lance_debug = LANCE_DEBUG; @@ -274,7 +274,6 @@ enum {OLD_LANCE = 0, PCNET_ISA=1, PCNET_ static unsigned char lance_need_isa_bounce_buffers = 1; static int lance_open(struct net_device *dev); -static int lance_open_fail(struct net_device *dev); static void lance_init_ring(struct net_device *dev, int mode); static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev); static int lance_rx(struct net_device *dev); @@ -286,10 +285,21 @@ static void lance_tx_timeout (struct net +static void cleanup_card(struct net_device *dev) +{ + struct lance_private *lp = dev->priv; + if (dev->dma != 4) + free_dma(dev->dma); + release_region(dev->base_addr, LANCE_TOTAL_SIZE); + kfree(lp->tx_bounce_buffs); + kfree((void*)lp->rx_buffs); + kfree(lp); +} + #ifdef MODULE #define MAX_CARDS 8 /* Max number of interfaces (cards) per module */ -static struct net_device dev_lance[MAX_CARDS]; +static struct net_device *dev_lance[MAX_CARDS]; static int io[MAX_CARDS]; static int dma[MAX_CARDS]; static int irq[MAX_CARDS]; @@ -305,28 +315,35 @@ MODULE_PARM_DESC(lance_debug, "LANCE/PCn int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) { - struct net_device *dev = &dev_lance[this_dev]; - dev->irq = irq[this_dev]; - dev->base_addr = io[this_dev]; - dev->dma = dma[this_dev]; - dev->init = lance_probe; if (io[this_dev] == 0) { - if (this_dev != 0) break; /* only complain once */ + if (this_dev != 0) /* only complain once */ + break; printk(KERN_NOTICE "lance.c: Module autoprobing not allowed. Append \"io=0xNNN\" value(s).\n"); return -EPERM; } - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "lance.c: No PCnet/LANCE card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) return 0; /* Got at least one. */ - return -ENXIO; + dev = alloc_etherdev(0); + if (!dev) + break; + dev->irq = irq[this_dev]; + dev->base_addr = io[this_dev]; + dev->dma = dma[this_dev]; + if (do_lance_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_lance[found++] = dev; + continue; + } + cleanup_card(dev); } - found++; + free_netdev(dev); + break; } - - return 0; + if (found != 0) + return 0; + return -ENXIO; } void cleanup_module(void) @@ -334,13 +351,11 @@ void cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) { - struct net_device *dev = &dev_lance[this_dev]; - if (dev->priv != NULL) { + struct net_device *dev = dev_lance[this_dev]; + if (dev) { unregister_netdev(dev); - free_dma(dev->dma); - release_region(dev->base_addr, LANCE_TOTAL_SIZE); - kfree(dev->priv); - dev->priv = NULL; + cleanup_card(dev); + free_netdev(dev); } } } @@ -352,7 +367,7 @@ MODULE_LICENSE("GPL"); board probes now that kmalloc() can allocate ISA DMA-able regions. This also allows the LANCE driver to be used as a module. */ -int __init lance_probe(struct net_device *dev) +static int __init do_lance_probe(struct net_device *dev) { int *port, result; @@ -387,6 +402,31 @@ int __init lance_probe(struct net_device return -ENODEV; } +struct net_device * __init lance_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(0); + int err; + + if (!dev) + return ERR_PTR(-ENODEV); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_lance_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int options) { struct lance_private *lp; @@ -398,6 +438,7 @@ static int __init lance_probe1(struct ne int hp_builtin = 0; /* HP on-board ethernet. */ static int did_version; /* Already printed version info. */ unsigned long flags; + int err = -ENOMEM; /* First we look for special cases. Check for HP's on-board ethernet by looking for 'HP' in the BIOS. @@ -432,7 +473,7 @@ static int __init lance_probe1(struct ne outw(88, ioaddr+LANCE_ADDR); if (inw(ioaddr+LANCE_ADDR) != 88) { lance_version = 0; - } else { /* Good, it's a newer chip. */ + } else { /* Good, it's a newer chip. */ int chip_version = inw(ioaddr+LANCE_DATA); outw(89, ioaddr+LANCE_ADDR); chip_version |= inw(ioaddr+LANCE_DATA) << 16; @@ -447,13 +488,9 @@ static int __init lance_probe1(struct ne } } - /* We can't use init_etherdev() to allocate dev->priv because it must + /* We can't allocate dev->priv from alloc_etherdev() because it must a ISA DMA-able region. */ - dev = init_etherdev(dev, 0); - if (!dev) - return -ENOMEM; SET_MODULE_OWNER(dev); - dev->open = lance_open_fail; chipname = chip_table[lance_version].name; printk("%s: %s at %#3x,", dev->name, chipname, ioaddr); @@ -465,8 +502,7 @@ static int __init lance_probe1(struct ne dev->base_addr = ioaddr; /* Make certain the data structures used by the LANCE are aligned and DMAble. */ - lp = (struct lance_private *)(((unsigned long)kmalloc(sizeof(*lp)+7, - GFP_DMA | GFP_KERNEL)+7) & ~7); + lp = kmalloc(sizeof(*lp), GFP_DMA | GFP_KERNEL); if(lp==NULL) return -ENODEV; if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp); @@ -486,7 +522,7 @@ static int __init lance_probe1(struct ne lp->tx_bounce_buffs = NULL; lp->chip_version = lance_version; - lp->devlock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&lp->devlock); lp->init_block.mode = 0x0003; /* Disable Rx and Tx. */ for (i = 0; i < 6; i++) @@ -540,6 +576,7 @@ static int __init lance_probe1(struct ne dma_channels = ((inb(DMA1_STAT_REG) >> 4) & 0x0f) | (inb(DMA2_STAT_REG) & 0xf0); } + err = -ENODEV; if (dev->irq >= 2) printk(" assigned IRQ %d", dev->irq); else if (lance_version != 0) { /* 7990 boards need DMA detection first. */ @@ -559,7 +596,7 @@ static int __init lance_probe1(struct ne printk(", probed IRQ %d", dev->irq); else { printk(", failed to detect IRQ line.\n"); - return -ENODEV; + goto out_tx; } /* Check for the initialization done bit, 0x0100, which means @@ -573,7 +610,7 @@ static int __init lance_probe1(struct ne } else if (dev->dma) { if (request_dma(dev->dma, chipname)) { printk("DMA %d allocation failed.\n", dev->dma); - return -ENODEV; + goto out_tx; } else printk(", assigned DMA %d.\n", dev->dma); } else { /* OK, we have to auto-DMA. */ @@ -613,7 +650,7 @@ static int __init lance_probe1(struct ne } if (i == 4) { /* Failure: bail. */ printk("DMA detection failed.\n"); - return -ENODEV; + goto out_tx; } } @@ -629,7 +666,7 @@ static int __init lance_probe1(struct ne dev->irq = probe_irq_off(irq_mask); if (dev->irq == 0) { printk(" Failed to detect the 7990 IRQ line.\n"); - return -ENODEV; + goto out_dma; } printk(" Auto-IRQ detected IRQ%d.\n", dev->irq); } @@ -655,17 +692,17 @@ static int __init lance_probe1(struct ne dev->watchdog_timeo = TX_TIMEOUT; return 0; -out_rx: kfree((void*)lp->rx_buffs); -out_lp: kfree(lp); - return -ENOMEM; +out_dma: + if (dev->dma != 4) + free_dma(dev->dma); +out_tx: + kfree(lp->tx_bounce_buffs); +out_rx: + kfree((void*)lp->rx_buffs); +out_lp: + kfree(lp); + return err; } - -static int -lance_open_fail(struct net_device *dev) -{ - return -ENODEV; -} - static int diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/lasi_82596.c 830-ivtv/drivers/net/lasi_82596.c --- 000-virgin/drivers/net/lasi_82596.c Mon Nov 17 18:28:15 2003 +++ 830-ivtv/drivers/net/lasi_82596.c Thu Jan 8 08:54:17 2004 @@ -1149,12 +1149,11 @@ static void print_eth(unsigned char *add #define LAN_PROM_ADDR 0xF0810000 -static int __devinit i82596_probe(struct net_device *dev) +static int __devinit i82596_probe(struct net_device *dev, + struct device *gen_dev) { int i; struct i596_private *lp; - /* we're going to overwrite dev->priv, so pull the device out */ - struct device *gen_dev = dev->priv; char eth_addr[6]; dma_addr_t dma_addr; @@ -1204,7 +1203,6 @@ static int __devinit i82596_probe(struct return -ENOMEM; } - ether_setup(dev); DEB(DEB_PROBE,printk("%s: 82596 at %#3lx,", dev->name, dev->base_addr)); for (i = 0; i < 6; i++) @@ -1537,12 +1535,19 @@ lan_init_chip(struct parisc_device *dev) netdevice->base_addr = dev->hpa; netdevice->irq = dev->irq; - netdevice->init = i82596_probe; - netdevice->priv = &dev->dev; + + retval = i82596_probe(netdevice, &dev->dev); + if (retval) { + free_netdev(netdevice); + return -ENODEV; + } retval = register_netdev(netdevice); if (retval) { + struct i596_private *lp = netdevice->priv; printk(KERN_WARNING __FILE__ ": register_netdevice ret'd %d\n", retval); + dma_free_noncoherent(lp->dev, sizeof(struct i596_private), + (void *)netdevice->mem_start, lp->dma_addr); free_netdev(netdevice); return -ENODEV; }; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/lne390.c 830-ivtv/drivers/net/lne390.c --- 000-virgin/drivers/net/lne390.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/lne390.c Thu Jan 8 08:54:17 2004 @@ -49,7 +49,6 @@ static const char *version = #include "8390.h" -int lne390_probe(struct net_device *dev); static int lne390_probe1(struct net_device *dev, int ioaddr); static int lne390_open(struct net_device *dev); @@ -103,9 +102,11 @@ static unsigned int shmem_mapB[] __initd * PROM for a match against the value assigned to Mylex. */ -int __init lne390_probe(struct net_device *dev) +static int __init do_lne390_probe(struct net_device *dev) { unsigned short ioaddr = dev->base_addr; + int irq = dev->irq; + int mem_start = dev->mem_start; int ret; SET_MODULE_OWNER(dev); @@ -135,11 +136,46 @@ int __init lne390_probe(struct net_devic if (lne390_probe1(dev, ioaddr) == 0) return 0; release_region(ioaddr, LNE390_IO_EXTENT); + dev->irq = irq; + dev->mem_start = mem_start; } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + free_irq(dev->irq, dev); + release_region(dev->base_addr, LNE390_IO_EXTENT); + if (ei_status.reg0) + iounmap((void *)dev->mem_start); +} + +struct net_device * __init lne390_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_lne390_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init lne390_probe1(struct net_device *dev, int ioaddr) { int i, revision, ret; @@ -174,11 +210,6 @@ static int __init lne390_probe1(struct n return -ENODEV; } #endif - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk ("lne390.c: unable to allocate memory for dev->priv!\n"); - return -ENOMEM; - } printk("lne390.c: LNE390%X in EISA slot %d, address", 0xa+revision, ioaddr/0x1000); for(i = 0; i < ETHER_ADDR_LEN; i++) @@ -199,8 +230,6 @@ static int __init lne390_probe1(struct n if ((ret = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev))) { printk (" unable to get IRQ %d.\n", dev->irq); - kfree(dev->priv); - dev->priv = NULL; return ret; } @@ -274,8 +303,6 @@ static int __init lne390_probe1(struct n return 0; cleanup: free_irq(dev->irq, dev); - kfree(dev->priv); - dev->priv = NULL; return ret; } @@ -373,7 +400,7 @@ static int lne390_close(struct net_devic #ifdef MODULE #define MAX_LNE_CARDS 4 /* Max number of LNE390 cards per module */ -static struct net_device dev_lne[MAX_LNE_CARDS]; +static struct net_device *dev_lne[MAX_LNE_CARDS]; static int io[MAX_LNE_CARDS]; static int irq[MAX_LNE_CARDS]; static int mem[MAX_LNE_CARDS]; @@ -389,26 +416,32 @@ MODULE_LICENSE("GPL"); int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_LNE_CARDS; this_dev++) { - struct net_device *dev = &dev_lne[this_dev]; + if (io[this_dev] == 0 && this_dev != 0) + break; + dev = alloc_ei_netdev(); + if (!dev) + break; dev->irq = irq[this_dev]; dev->base_addr = io[this_dev]; dev->mem_start = mem[this_dev]; - dev->init = lne390_probe; - /* Default is to only install one card. */ - if (io[this_dev] == 0 && this_dev != 0) break; - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "lne390.c: No LNE390 card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) { /* Got at least one. */ - return 0; + if (do_lne390_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_lne[found++] = dev; + continue; } - return -ENXIO; + cleanup_card(dev); } - found++; - } - return 0; + free_netdev(dev); + printk(KERN_WARNING "lne390.c: No LNE390 card found (i/o = 0x%x).\n", io[this_dev]); + break; + } + if (found) + return 0; + return -ENXIO; } void cleanup_module(void) @@ -416,15 +449,11 @@ void cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < MAX_LNE_CARDS; this_dev++) { - struct net_device *dev = &dev_lne[this_dev]; - if (dev->priv != NULL) { - void *priv = dev->priv; - free_irq(dev->irq, dev); - release_region(dev->base_addr, LNE390_IO_EXTENT); - if (ei_status.reg0) - iounmap((void *)dev->mem_start); + struct net_device *dev = dev_lne[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(priv); + cleanup_card(dev); + free_netdev(dev); } } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/loopback.c 830-ivtv/drivers/net/loopback.c --- 000-virgin/drivers/net/loopback.c Mon Nov 17 18:29:42 2003 +++ 830-ivtv/drivers/net/loopback.c Thu Jan 8 10:20:53 2004 @@ -173,7 +173,7 @@ struct net_device loopback_dev = { .rebuild_header = eth_rebuild_header, .flags = IFF_LOOPBACK, .features = NETIF_F_SG|NETIF_F_FRAGLIST - |NETIF_F_NO_CSUM|NETIF_F_HIGHDMA|NETIF_F_TSO, + |NETIF_F_NO_CSUM|NETIF_F_HIGHDMA, }; /* Setup and register the of the LOOPBACK device. */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/lp486e.c 830-ivtv/drivers/net/lp486e.c --- 000-virgin/drivers/net/lp486e.c Mon Nov 17 18:28:15 2003 +++ 830-ivtv/drivers/net/lp486e.c Thu Jan 8 08:54:18 2004 @@ -1314,18 +1314,23 @@ static int io = IOADDR; static int irq = IRQ; static int __init lp486e_init_module(void) { - struct net_device *dev; - - dev = alloc_etherdev(sizeof(struct i596_private)); + int err; + struct net_device *dev = alloc_etherdev(sizeof(struct i596_private)); if (!dev) return -ENOMEM; dev->irq = irq; dev->base_addr = io; - dev->init = lp486e_probe; - if (register_netdev(dev) != 0) { + err = lp486e_probe(dev); + if (err) { + free_netdev(dev); + return err; + } + err = register_netdev(dev); + if (err) { + release_region(dev->base_addr, LP486E_TOTAL_SIZE); free_netdev(dev); - return -EIO; + return err; } dev_lp486e = dev; full_duplex = 0; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/mac8390.c 830-ivtv/drivers/net/mac8390.c --- 000-virgin/drivers/net/mac8390.c Mon Nov 17 18:29:30 2003 +++ 830-ivtv/drivers/net/mac8390.c Thu Jan 8 08:54:18 2004 @@ -124,11 +124,10 @@ static int useresources[] = { static char version[] __initdata = "mac8390.c: v0.4 2001-05-15 David Huggins-Daines and others\n"; -extern int mac8390_probe(struct net_device * dev); extern enum mac8390_type mac8390_ident(struct nubus_dev * dev); extern int mac8390_memsize(unsigned long membase); extern int mac8390_memtest(struct net_device * dev); -extern int mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev, +static int mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev, enum mac8390_type type); static int mac8390_open(struct net_device * dev); @@ -223,43 +222,43 @@ int __init mac8390_memsize(unsigned long return i * 0x1000; } -static int probed __initdata = 0; - -int __init mac8390_probe(struct net_device * dev) +struct net_device * __init mac8390_probe(int unit) { + struct net_device *dev; volatile unsigned short *i; - int boards_found = 0; int version_disp = 0; struct nubus_dev * ndev = NULL; + int err = -ENODEV; struct nubus_dir dir; struct nubus_dirent ent; int offset; + static unsigned int slots; enum mac8390_type cardtype; - if (probed) - return -ENODEV; - probed++; - /* probably should check for Nubus instead */ if (!MACH_IS_MAC) - return -ENODEV; + return ERR_PTR(-ENODEV); + + dev = alloc_ei_netdev(); + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) + sprintf(dev->name, "eth%d", unit); + + SET_MODULE_OWNER(dev); while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, NUBUS_TYPE_ETHERNET, ndev))) { - - dev = NULL; - - if ((cardtype = mac8390_ident(ndev)) == MAC8390_NONE) + /* Have we seen it already? */ + if (slots & (1<board->slot)) continue; + slots |= 1<board->slot; - dev = init_etherdev(dev, 0); - if (dev == NULL) { - printk(KERN_ERR "Unable to allocate etherdev" - "structure!\n"); - return -ENOMEM; - } + if ((cardtype = mac8390_ident(ndev)) == MAC8390_NONE) + continue; if (version_disp == 0) { version_disp = 1; @@ -358,21 +357,25 @@ int __init mac8390_probe(struct net_devi printk(KERN_ERR "Card type %s is" " unsupported, sorry\n", cardname[cardtype]); - return -ENODEV; + continue; } } /* Do the nasty 8390 stuff */ - if (mac8390_initdev(dev, ndev, cardtype)) - continue; - boards_found++; + if (!mac8390_initdev(dev, ndev, cardtype)) + break; } - /* We're outta here */ - if (boards_found > 0) - return 0; - else - return -ENODEV; + if (!ndev) + goto out; + err = register_netdev(dev); + if (err) + goto out; + return dev; + +out: + free_netdev(dev); + return ERR_PTR(err); } #ifdef MODULE @@ -380,26 +383,39 @@ MODULE_AUTHOR("David Huggins-Daines priv */ - if (ethdev_init(dev)) { - printk(KERN_ERR "%s: Unable to allocate memory for dev->priv!\n", dev->name); - return -ENOMEM; - } - /* Now fill in our stuff */ dev->open = &mac8390_open; dev->stop = &mac8390_close; @@ -529,7 +539,6 @@ static int mac8390_open(struct net_devic printk ("%s: unable to get IRQ %d.\n", dev->name, dev->irq); return -EAGAIN; } - MOD_INC_USE_COUNT; return 0; } @@ -537,7 +546,6 @@ static int mac8390_close(struct net_devi { free_irq(dev->irq, dev); ei_close(dev); - MOD_DEC_USE_COUNT; return 0; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/mac89x0.c 830-ivtv/drivers/net/mac89x0.c --- 000-virgin/drivers/net/mac89x0.c Sat May 10 18:34:41 2003 +++ 830-ivtv/drivers/net/mac89x0.c Thu Jan 8 08:54:18 2004 @@ -123,7 +123,6 @@ struct net_local { /* Index to functions, as function prototypes. */ -extern int mac89x0_probe(struct net_device *dev); #if 0 extern void reset_chip(struct net_device *dev); #endif @@ -170,8 +169,9 @@ writereg(struct net_device *dev, int por /* Probe for the CS8900 card in slot E. We won't bother looking anywhere else until we have a really good reason to do so. */ -int __init mac89x0_probe(struct net_device *dev) +struct net_device * __init mac89x0_probe(int unit) { + struct net_device *dev; static int once_is_enough; struct net_local *lp; static unsigned version_printed; @@ -179,18 +179,28 @@ int __init mac89x0_probe(struct net_devi unsigned rev_type = 0; unsigned long ioaddr; unsigned short sig; + int err = -ENODEV; + + dev = alloc_etherdev(sizeof(struct net_local)); + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } SET_MODULE_OWNER(dev); if (once_is_enough) - return -ENODEV; + goto out; once_is_enough = 1; /* We might have to parameterize this later */ slot = 0xE; /* Get out now if there's a real NuBus card in slot E */ if (nubus_find_slot(slot, NULL) != NULL) - return -ENODEV; + goto out; /* The pseudo-ISA bits always live at offset 0x300 (gee, wonder why...) */ @@ -206,21 +216,15 @@ int __init mac89x0_probe(struct net_devi local_irq_restore(flags); if (!card_present) - return -ENODEV; + goto out; } nubus_writew(0, ioaddr + ADD_PORT); sig = nubus_readw(ioaddr + DATA_PORT); if (sig != swab16(CHIP_EISA_ID_SIG)) - return -ENODEV; + goto out; /* Initialize the net_device structure. */ - if (dev->priv == NULL) { - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (!dev->priv) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct net_local)); - } lp = (struct net_local *)dev->priv; /* Fill in the 'dev' fields. */ @@ -258,9 +262,7 @@ int __init mac89x0_probe(struct net_devi /* Try to read the MAC address */ if ((readreg(dev, PP_SelfST) & (EEPROM_PRESENT | EEPROM_OK)) == 0) { printk("\nmac89x0: No EEPROM, giving up now.\n"); - kfree(dev->priv); - dev->priv = NULL; - return -ENODEV; + goto out1; } else { for (i = 0; i < ETH_ALEN; i += 2) { /* Big-endian (why??!) */ @@ -277,6 +279,7 @@ int __init mac89x0_probe(struct net_devi for (i = 0; i < ETH_ALEN; i++) printk("%2.2x%s", dev->dev_addr[i], ((i < ETH_ALEN-1) ? ":" : "")); + printk("\n"); dev->open = net_open; dev->stop = net_close; @@ -285,11 +288,15 @@ int __init mac89x0_probe(struct net_devi dev->set_multicast_list = &set_multicast_list; dev->set_mac_address = &set_mac_address; - /* Fill in the fields of the net_device structure with ethernet values. */ - ether_setup(dev); - - printk("\n"); + err = register_netdev(dev); + if (err) + goto out1; return 0; +out1: + nubus_writew(0, dev->base_addr + ADD_PORT); +out: + free_netdev(dev); + return ERR_PTR(err); } #if 0 @@ -619,7 +626,7 @@ static int set_mac_address(struct net_de #ifdef MODULE -static struct net_device dev_cs89x0; +static struct net_device *dev_cs89x0; static int debug; MODULE_PARM(debug, "i"); @@ -630,36 +637,20 @@ int init_module(void) { net_debug = debug; - dev_cs89x0.init = mac89x0_probe; - dev_cs89x0.priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (!dev_cs89x0.priv) - return -ENOMEM; - memset(dev_cs89x0.priv, 0, sizeof(struct net_local)); - - if (register_netdev(&dev_cs89x0) != 0) { + dev_cs89x0 = mac89x0_probe(-1); + if (IS_ERR(dev_cs89x0)) { printk(KERN_WARNING "mac89x0.c: No card found\n"); - kfree(dev_cs89x0.priv); - return -ENXIO; - } + return PTR_ERR(dev_cs89x0); + } return 0; } void cleanup_module(void) { - -#endif -#ifdef MODULE - nubus_writew(0, dev_cs89x0.base_addr + ADD_PORT); -#endif -#ifdef MODULE - - if (dev_cs89x0.priv != NULL) { - /* Free up the private structure, or leak memory :-) */ - unregister_netdev(&dev_cs89x0); - kfree(dev_cs89x0.priv); - dev_cs89x0.priv = NULL; /* gets re-allocated by cs89x0_probe1 */ - } + unregister_netdev(dev_cs89x0); + nubus_writew(0, dev_cs89x0->base_addr + ADD_PORT); + free_netdev(dev_cs89x0); } #endif /* MODULE */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/mace.c 830-ivtv/drivers/net/mace.c --- 000-virgin/drivers/net/mace.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/mace.c Thu Jan 8 08:54:18 2004 @@ -142,6 +142,10 @@ static void __init mace_probe1(struct de } } + /* + * lazy allocation - it's a driver-wide thing and it will live until + * the unload, but we don't allocate it until it's needed + */ if (dummy_buf == NULL) { dummy_buf = kmalloc(RX_BUFLEN+2, GFP_KERNEL); if (dummy_buf == NULL) { @@ -150,7 +154,7 @@ static void __init mace_probe1(struct de } } - dev = init_etherdev(0, PRIV_BYTES); + dev = alloc_etherdev(PRIV_BYTES); if (!dev) return; SET_MODULE_OWNER(dev); @@ -160,16 +164,16 @@ static void __init mace_probe1(struct de if (!request_OF_resource(mace, 0, " (mace)")) { printk(KERN_ERR "MACE: can't request IO resource !\n"); - goto err_out; + goto out1; } if (!request_OF_resource(mace, 1, " (mace tx dma)")) { printk(KERN_ERR "MACE: can't request TX DMA resource !\n"); - goto err_out; + goto out2; } if (!request_OF_resource(mace, 2, " (mace tx dma)")) { printk(KERN_ERR "MACE: can't request RX DMA resource !\n"); - goto err_out; + goto out3; } dev->base_addr = mace->addrs[0].address; @@ -229,30 +233,42 @@ static void __init mace_probe1(struct de dev->set_multicast_list = mace_set_multicast; dev->set_mac_address = mace_set_address; - ether_setup(dev); - mace_reset(dev); - if (request_irq(dev->irq, mace_interrupt, 0, "MACE", dev)) + if (request_irq(dev->irq, mace_interrupt, 0, "MACE", dev)) { printk(KERN_ERR "MACE: can't get irq %d\n", dev->irq); + goto out4; + } if (request_irq(mace->intrs[1].line, mace_txdma_intr, 0, "MACE-txdma", - dev)) + dev)) { printk(KERN_ERR "MACE: can't get irq %d\n", mace->intrs[1].line); + goto out5; + } if (request_irq(mace->intrs[2].line, mace_rxdma_intr, 0, "MACE-rxdma", - dev)) + dev)) { printk(KERN_ERR "MACE: can't get irq %d\n", mace->intrs[2].line); + goto out6; + } + if (register_netdev(dev) != 0) + goto out7; mp->next_mace = mace_devs; mace_devs = dev; return; -err_out: - unregister_netdev(dev); - if (mp->of_node) { - release_OF_resource(mp->of_node, 0); - release_OF_resource(mp->of_node, 1); - release_OF_resource(mp->of_node, 2); - } +out7: + free_irq(mp->rx_dma_intr, dev); +out6: + free_irq(mp->tx_dma_intr, dev); +out5: + free_irq(dev->irq, dev); +out4: + release_OF_resource(mp->of_node, 2); +out3: + release_OF_resource(mp->of_node, 1); +out2: + release_OF_resource(mp->of_node, 0); +out1: free_netdev(dev); } @@ -975,7 +991,7 @@ static void __exit mace_cleanup (void) release_OF_resource(mp->of_node, 1); release_OF_resource(mp->of_node, 2); - kfree(dev); + free_netdev(dev); } if (dummy_buf != NULL) { kfree(dummy_buf); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/macmace.c 830-ivtv/drivers/net/macmace.c --- 000-virgin/drivers/net/macmace.c Fri May 30 19:02:12 2003 +++ 830-ivtv/drivers/net/macmace.c Thu Jan 8 08:54:18 2004 @@ -180,7 +180,7 @@ static void mace_dma_off(struct net_devi * model of Macintrash has a MACE (AV macintoshes) */ -int mace_probe(struct net_device *unused) +struct net_device *mace_probe(int unit) { int j; struct mace_data *mp; @@ -188,13 +188,19 @@ int mace_probe(struct net_device *unused struct net_device *dev; unsigned char checksum = 0; static int found = 0; + int err; - if (found || macintosh_config->ether_type != MAC_ETHER_MACE) return -ENODEV; + if (found || macintosh_config->ether_type != MAC_ETHER_MACE) + return ERR_PTR(-ENODEV); found = 1; /* prevent 'finding' one on every device probe */ - dev = init_etherdev(0, PRIV_BYTES); - if (!dev) return -ENOMEM; + dev = alloc_etherdev(PRIV_BYTES); + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) + sprintf(dev->name, "eth%d", unit); mp = (struct mace_data *) dev->priv; dev->base_addr = (u32)MACE_BASE; @@ -221,7 +227,10 @@ int mace_probe(struct net_device *unused checksum ^= bitrev(addr[j<<4]); } - if (checksum != 0xFF) return -ENODEV; + if (checksum != 0xFF) { + free_netdev(dev); + return ERR_PTR(-ENODEV); + } memset(&mp->stats, 0, sizeof(mp->stats)); @@ -234,13 +243,16 @@ int mace_probe(struct net_device *unused dev->set_multicast_list = mace_set_multicast; dev->set_mac_address = mace_set_address; - ether_setup(dev); - printk(KERN_INFO "%s: 68K MACE, hardware address %.2X", dev->name, dev->dev_addr[0]); for (j = 1 ; j < 6 ; j++) printk(":%.2X", dev->dev_addr[j]); printk("\n"); - return 0; + err = register_netdev(dev); + if (!err) + return dev; + + free_netdev(dev); + return ERR_PTR(err); } /* diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/macsonic.c 830-ivtv/drivers/net/macsonic.c --- 000-virgin/drivers/net/macsonic.c Tue Aug 5 20:01:51 2003 +++ 830-ivtv/drivers/net/macsonic.c Thu Jan 8 08:54:18 2004 @@ -74,7 +74,6 @@ static int sonic_version_printed; static int reg_offset; -extern int macsonic_probe(struct net_device* dev); extern int mac_onboard_sonic_probe(struct net_device* dev); extern int mac_nubus_sonic_probe(struct net_device* dev); @@ -110,14 +109,38 @@ enum macsonic_type { #define SONIC_READ_PROM(addr) nubus_readb(prom_addr+addr) -int __init macsonic_probe(struct net_device* dev) +struct net_device * __init macsonic_probe(int unit) { - int rv; + struct net_device *dev = alloc_etherdev(0); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) + sprintf(dev->name, "eth%d", unit); + + SET_MODULE_OWNER(dev); /* This will catch fatal stuff like -ENOMEM as well as success */ - if ((rv = mac_onboard_sonic_probe(dev)) != -ENODEV) - return rv; - return mac_nubus_sonic_probe(dev); + err = mac_onboard_sonic_probe(dev); + if (err == 0) + goto found; + if (err != -ENODEV) + goto out; + err = mac_nubus_sonic_probe(dev); + if (err) + goto out; +found: + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + kfree(dev->priv); +out: + free_netdev(dev); + return ERR_PTR(err); } /* @@ -195,6 +218,7 @@ int __init macsonic_init(struct net_devi if ((lp->rba = (char *) kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL | GFP_DMA)) == NULL) { printk(KERN_ERR "%s: couldn't allocate receive buffers\n", dev->name); + dev->priv = NULL; kfree(lp); return -ENOMEM; } @@ -229,8 +253,6 @@ int __init macsonic_init(struct net_devi sonic_write(dev, SONIC_FAET, 0xffff); sonic_write(dev, SONIC_MPT, 0xffff); - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); return 0; } @@ -344,30 +366,6 @@ int __init mac_onboard_sonic_probe(struc printk("yes\n"); - if (dev) { - dev = init_etherdev(dev, sizeof(struct sonic_local)); - if (!dev) - return -ENOMEM; - /* methinks this will always be true but better safe than sorry */ - if (dev->priv == NULL) { - dev->priv = kmalloc(sizeof(struct sonic_local), GFP_KERNEL); - if (!dev->priv) - return -ENOMEM; - } - } else { - dev = init_etherdev(NULL, sizeof(struct sonic_local)); - } - - if (dev == NULL) - return -ENOMEM; - - if(dev->priv) { - printk("%s: warning! sonic entering with priv already allocated!\n", - dev->name); - printk("%s: discarding, will attempt to reallocate\n", dev->name); - dev->priv = NULL; - } - /* Danger! My arms are flailing wildly! You *must* set this before using sonic_read() */ @@ -497,7 +495,6 @@ int __init mac_nubus_sonic_probe(struct { static int slots; struct nubus_dev* ndev = NULL; - struct sonic_local* lp; unsigned long base_addr, prom_addr; u16 sonic_dcr; int id; @@ -567,25 +564,6 @@ int __init mac_nubus_sonic_probe(struct return -ENODEV; } - if (dev) { - dev = init_etherdev(dev, sizeof(struct sonic_local)); - if (!dev) - return -ENOMEM; - /* methinks this will always be true but better safe than sorry */ - if (dev->priv == NULL) { - dev->priv = kmalloc(sizeof(struct sonic_local), GFP_KERNEL); - if (!dev->priv) /* FIXME: kfree dev if necessary */ - return -ENOMEM; - } - } else { - dev = init_etherdev(NULL, sizeof(struct sonic_local)); - } - - if (dev == NULL) - return -ENOMEM; - - lp = (struct sonic_local*) dev->priv; - memset(lp, 0, sizeof(struct sonic_local)); /* Danger! My arms are flailing wildly! You *must* set this before using sonic_read() */ dev->base_addr = base_addr; @@ -631,8 +609,7 @@ int __init mac_nubus_sonic_probe(struct } #ifdef MODULE -static char namespace[16] = ""; -static struct net_device dev_macsonic; +static struct net_device *dev_macsonic; MODULE_PARM(sonic_debug, "i"); MODULE_PARM_DESC(sonic_debug, "macsonic debug level (1-4)"); @@ -641,24 +618,20 @@ MODULE_LICENSE("GPL"); int init_module(void) { - dev_macsonic.name = namespace; - dev_macsonic.init = macsonic_probe; - - if (register_netdev(&dev_macsonic) != 0) { + dev_macsonic = macsonic_probe(-1); + if (IS_ERR(dev_macsonic)) { printk(KERN_WARNING "macsonic.c: No card found\n"); - return -ENXIO; - } + return PTR_ERR(dev_macsonic); + } return 0; } void cleanup_module(void) { - if (dev_macsonic.priv != NULL) { - unregister_netdev(&dev_macsonic); - kfree(dev_macsonic.priv); - dev_macsonic.priv = NULL; - } + unregister_netdev(dev_macsonic); + kfree(dev_macsonic->priv); + free_netdev(dev_macsonic); } #endif /* MODULE */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/meth.c 830-ivtv/drivers/net/meth.c --- 000-virgin/drivers/net/meth.c Tue Sep 2 09:55:47 2003 +++ 830-ivtv/drivers/net/meth.c Thu Jan 8 08:54:18 2004 @@ -95,7 +95,6 @@ typedef struct meth_private { spinlock_t meth_lock; } meth_private; -extern struct net_device meth_devs[]; void meth_tx_timeout (struct net_device *dev); void meth_interrupt(int irq, void *dev_id, struct pt_regs *pregs); @@ -762,17 +761,16 @@ struct net_device_stats *meth_stats(stru /* * The init function (sometimes called probe). - * It is invoked by register_netdev() */ -int meth_init(struct net_device *dev) +static struct net_device *meth_init(struct net_device *dev) { + struct net_device *dev; meth_private *priv; int ret; - /* - * Then, assign other fields in dev, using ether_setup() and some - * hand assignments - */ - ether_setup(dev); /* assign some of the fields */ + + dev = alloc_etherdev(sizeof(struct meth_private)); + if (!dev) + return ERR_PTR(-ENOMEM); dev->open = meth_open; dev->stop = meth_release; @@ -787,16 +785,8 @@ int meth_init(struct net_device *dev) dev->irq = MACE_ETHERNET_IRQ; SET_MODULE_OWNER(dev); - /* - * Then, allocate the priv field. This encloses the statistics - * and a few private fields. - */ - priv = kmalloc(sizeof(struct meth_private), GFP_KERNEL); - if (priv == NULL) - return -ENOMEM; - dev->priv=priv; - memset(priv, 0, sizeof(struct meth_private)); - spin_lock_init(&((struct meth_private *) dev->priv)->meth_lock); + priv = dev->priv; + spin_lock_init(&priv->meth_lock); /* * Make the usual checks: check_region(), probe irq, ... -ENODEV * should be returned if no device found. No resource should be @@ -807,28 +797,41 @@ int meth_init(struct net_device *dev) priv->phy_addr = -1; /* No phy is known yet... */ /* Initialize the hardware */ - if((ret=meth_reset(dev)) < 0) - return ret; + ret = meth_reset(dev); + if (ret < 0) + goto out; /* Allocate the ring buffers */ - if((ret=meth_init_tx_ring(priv))<0||(ret=meth_init_rx_ring(priv))<0){ - meth_free_tx_ring(priv); - meth_free_rx_ring(priv); - return ret; - } + ret = meth_init_tx_ring(priv); + if (ret < 0) + goto out; + + ret = meth_init_rx_ring(priv); + if (ret < 0) + goto out1; + + ret = register_netdev(dev); + if (ret) + goto out2; printk("SGI O2 Fast Ethernet rev. %ld\n", priv->regs->mac_ctrl >> 29); - return 0; + return ret; + +out2: + meth_free_rx_ring(priv); +out1: + meth_free_tx_ring(priv); +out: + free_netdev(dev); + return ERR_PTR(ret); } /* * The devices */ -struct net_device meth_devs[1] = { - { init: meth_init, } /* init, nothing more */ -}; +struct net_device *meth_dev; /* * Finally, the module stuff @@ -836,23 +839,19 @@ struct net_device meth_devs[1] = { int meth_init_module(void) { - int result, device_present = 0; - - strcpy(meth_devs[0].name, "eth%d"); - - if ( (result = register_netdev(meth_devs)) ) - printk("meth: error %i registering device \"%s\"\n", - result, meth_devs->name); - else device_present++; - - return device_present ? 0 : -ENODEV; + meth_dev = meth_init(); + if (IS_ERR(meth_dev)) + return PTR_ERR(meth_dev); + return 0; } void meth_cleanup(void) { - kfree(meth_devs->priv); - unregister_netdev(meth_devs); - return; + meth_private *priv = meth_dev->priv; + unregister_netdev(meth_dev); + meth_free_rx_ring(priv); + meth_free_tx_ring(priv); + free_netdev(meth_dev); } module_init(meth_init_module); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/mvme147.c 830-ivtv/drivers/net/mvme147.c --- 000-virgin/drivers/net/mvme147.c Tue Sep 2 09:55:47 2003 +++ 830-ivtv/drivers/net/mvme147.c Thu Jan 8 08:54:18 2004 @@ -41,7 +41,7 @@ struct m147lance_private { struct lance_private lance; void *base; - void *ram; + unsigned long ram; }; /* function prototypes... This is easy because all the grot is in the @@ -49,7 +49,6 @@ struct m147lance_private { * plus board-specific init, open and close actions. * Oh, and we need to tell the generic code how to read and write LANCE registers... */ -int mvme147lance_probe(struct net_device *dev); static int m147lance_open(struct net_device *dev); static int m147lance_close(struct net_device *dev); static void m147lance_writerap(struct m147lance_private *lp, unsigned short value); @@ -60,29 +59,29 @@ typedef void (*writerap_t)(void *, unsig typedef void (*writerdp_t)(void *, unsigned short); typedef unsigned short (*readrdp_t)(void *); -#ifdef MODULE -static struct m147lance_private *root_m147lance_dev; -#endif - /* Initialise the one and only on-board 7990 */ -int __init mvme147lance_probe(struct net_device *dev) +struct net_device * __init mvme147lance_probe(int unit) { + struct net_device *dev; static int called; static const char name[] = "MVME147 LANCE"; struct m147lance_private *lp; u_long *addr; u_long address; + int err; if (!MACH_IS_MVME147 || called) - return -ENODEV; + return ERR_PTR(-ENODEV); called++; - SET_MODULE_OWNER(dev); + dev = alloc_etherdev(sizeof(struct m147lance_private)); + if (!dev) + return ERR_PTR(-ENOMEM); - dev->priv = kmalloc(sizeof(struct m147lance_private), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct m147lance_private)); + if (unit >= 0) + sprintf(dev->name, "eth%d", unit); + + SET_MODULE_OWNER(dev); /* Fill the dev fields */ dev->base_addr = (unsigned long)MVME147_LANCE_BASE; @@ -114,11 +113,12 @@ int __init mvme147lance_probe(struct net dev->dev_addr[5]); lp = (struct m147lance_private *)dev->priv; - lp->ram = (void *)__get_dma_pages(GFP_ATOMIC, 3); /* 16K */ + lp->ram = __get_dma_pages(GFP_ATOMIC, 3); /* 16K */ if (!lp->ram) { printk("%s: No memory for LANCE buffers\n", dev->name); - return -ENODEV; + free_netdev(dev); + return ERR_PTR(-ENOMEM); } lp->lance.name = (char*)name; /* discards const, shut up gcc */ @@ -134,15 +134,15 @@ int __init mvme147lance_probe(struct net lp->lance.lance_log_tx_bufs = LANCE_LOG_TX_BUFFERS; lp->lance.rx_ring_mod_mask = RX_RING_MOD_MASK; lp->lance.tx_ring_mod_mask = TX_RING_MOD_MASK; - ether_setup(dev); -#ifdef MODULE - dev->ifindex = dev_new_index(); - lp->next_module = root_m147lance_dev; - root_m147lance_dev = lp; -#endif /* MODULE */ + err = register_netdev(dev); + if (err) { + free_pages(lp->ram, 3); + free_netdev(dev); + return ERR_PTR(err); + } - return 0; + return dev; } static void m147lance_writerap(struct m147lance_private *lp, unsigned short value) @@ -185,23 +185,21 @@ static int m147lance_close(struct net_de #ifdef MODULE MODULE_LICENSE("GPL"); +static struct net_device *dev_mvme147_lance; int init_module(void) { - root_lance_dev = NULL; - return mvme147lance_probe(NULL); + dev_mvme147_lance = mvme147lance_probe(-1); + if (IS_ERR(dev_mvme147_lance)) + return PTR_ERR(dev_mvme147_lance); + return 0; } void cleanup_module(void) { - /* Walk the chain of devices, unregistering them */ - struct m147lance_private *lp; - while (root_m147lance_dev) { - lp = root_m147lance_dev->next_module; - unregister_netdev(root_lance_dev->dev); - free_pages(lp->ram, 3); - free_netdev(root_lance_dev->dev); - root_lance_dev = lp; - } + struct m147lance_private *lp = dev_mvme147_lance->priv; + unregister_netdev(dev_mvme147_lance); + free_pages(lp->ram, 3); + free_netdev(dev_mvme147_lance); } #endif /* MODULE */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/natsemi.c 830-ivtv/drivers/net/natsemi.c --- 000-virgin/drivers/net/natsemi.c Mon Nov 17 18:29:42 2003 +++ 830-ivtv/drivers/net/natsemi.c Thu Jan 8 08:54:18 2004 @@ -765,19 +765,13 @@ static int __devinit natsemi_probe1 (str SET_NETDEV_DEV(dev, &pdev->dev); i = pci_request_regions(pdev, dev->name); - if (i) { - free_netdev(dev); - return i; - } + if (i) + goto err_pci_request_regions; - { - void *mmio = ioremap (ioaddr, iosize); - if (!mmio) { - pci_release_regions(pdev); - free_netdev(dev); - return -ENOMEM; - } - ioaddr = (unsigned long) mmio; + ioaddr = (unsigned long) ioremap (ioaddr, iosize); + if (!ioaddr) { + i = -ENOMEM; + goto err_ioremap; } /* Work around the dropped serial bit. */ @@ -835,13 +829,9 @@ static int __devinit natsemi_probe1 (str dev->mtu = mtu; i = register_netdev(dev); - if (i) { - pci_release_regions(pdev); - unregister_netdev(dev); - free_netdev(dev); - pci_set_drvdata(pdev, NULL); - return i; - } + if (i) + goto err_register_netdev; + netif_carrier_off(dev); if (netif_msg_drv(np)) { @@ -878,6 +868,17 @@ static int __devinit natsemi_probe1 (str return 0; + + err_register_netdev: + iounmap ((void *) dev->base_addr); + + err_ioremap: + pci_release_regions(pdev); + pci_set_drvdata(pdev, NULL); + + err_pci_request_regions: + free_netdev(dev); + return i; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/ne.c 830-ivtv/drivers/net/ne.c --- 000-virgin/drivers/net/ne.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/ne.c Thu Jan 8 08:54:19 2004 @@ -126,7 +126,6 @@ bad_clone_list[] __initdata = { #define NESM_START_PG 0x40 /* First page of TX buffer */ #define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ -int ne_probe(struct net_device *dev); static int ne_probe1(struct net_device *dev, int ioaddr); static int ne_probe_isapnp(struct net_device *dev); @@ -163,9 +162,10 @@ static void ne_block_output(struct net_d E2010 starts at 0x100 and ends at 0x4000. E2010-x starts at 0x100 and ends at 0xffff. */ -int __init ne_probe(struct net_device *dev) +static int __init do_ne_probe(struct net_device *dev) { unsigned int base_addr = dev->base_addr; + int irq = dev->irq; SET_MODULE_OWNER(dev); @@ -183,6 +183,7 @@ int __init ne_probe(struct net_device *d /* Last resort. The semi-risky ISA auto-probe. */ for (base_addr = 0; netcard_portlist[base_addr] != 0; base_addr++) { int ioaddr = netcard_portlist[base_addr]; + dev->irq = irq; if (ne_probe1(dev, ioaddr) == 0) return 0; } @@ -191,6 +192,40 @@ int __init ne_probe(struct net_device *d return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv; + if (idev) + pnp_device_detach(idev); + free_irq(dev->irq, dev); + release_region(dev->base_addr, NE_IO_EXTENT); +} + +struct net_device * __init ne_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_ne_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init ne_probe_isapnp(struct net_device *dev) { int i; @@ -425,20 +460,12 @@ static int __init ne_probe1(struct net_d goto err_out; } - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) - { - printk (" unable to get memory for dev->priv.\n"); - ret = -ENOMEM; - goto err_out; - } - /* Snarf the interrupt now. There's no point in waiting since we cannot share and the board will usually be enabled. */ ret = request_irq(dev->irq, ei_interrupt, 0, name, dev); if (ret) { printk (" unable to get IRQ %d (errno=%d).\n", dev->irq, ret); - goto err_out_kfree; + goto err_out; } dev->base_addr = ioaddr; @@ -472,9 +499,6 @@ static int __init ne_probe1(struct net_d NS8390_init(dev, 0); return 0; -err_out_kfree: - kfree(dev->priv); - dev->priv = NULL; err_out: release_region(ioaddr, NE_IO_EXTENT); return ret; @@ -734,7 +758,7 @@ retry: #ifdef MODULE #define MAX_NE_CARDS 4 /* Max number of NE cards per module */ -static struct net_device dev_ne[MAX_NE_CARDS]; +static struct net_device *dev_ne[MAX_NE_CARDS]; static int io[MAX_NE_CARDS]; static int irq[MAX_NE_CARDS]; static int bad[MAX_NE_CARDS]; /* 0xbad = bad sig or no reset ack */ @@ -758,25 +782,31 @@ int init_module(void) int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = &dev_ne[this_dev]; + struct net_device *dev = alloc_ei_netdev(); + if (!dev) + break; dev->irq = irq[this_dev]; dev->mem_end = bad[this_dev]; dev->base_addr = io[this_dev]; - dev->init = ne_probe; - if (register_netdev(dev) == 0) { - found++; - continue; - } - if (found != 0) { /* Got at least one. */ - return 0; + if (do_ne_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_ne[found++] = dev; + continue; + } + cleanup_card(dev); } + free_netdev(dev); + if (found) + break; if (io[this_dev] != 0) printk(KERN_WARNING "ne.c: No NE*000 card found at i/o = %#x\n", io[this_dev]); else printk(KERN_NOTICE "ne.c: You must supply \"io=0xNNN\" value(s) for ISA cards.\n"); return -ENXIO; } - return 0; + if (found) + return 0; + return -ENODEV; } void cleanup_module(void) @@ -784,16 +814,11 @@ void cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = &dev_ne[this_dev]; - if (dev->priv != NULL) { - void *priv = dev->priv; - struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv; - if (idev) - pnp_device_detach(idev); - free_irq(dev->irq, dev); - release_region(dev->base_addr, NE_IO_EXTENT); + struct net_device *dev = dev_ne[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(priv); + cleanup_card(dev); + free_netdev(dev); } } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/ne2.c 830-ivtv/drivers/net/ne2.c --- 000-virgin/drivers/net/ne2.c Mon Nov 17 18:29:30 2003 +++ 830-ivtv/drivers/net/ne2.c Thu Jan 8 08:54:19 2004 @@ -242,7 +242,7 @@ static unsigned int __init dlink_get_eep * Note that at boot, this probe only picks up one card at a time. */ -int __init ne2_probe(struct net_device *dev) +static int __init do_ne2_probe(struct net_device *dev) { static int current_mca_slot = -1; int i; @@ -262,16 +262,52 @@ int __init ne2_probe(struct net_device * mca_find_unused_adapter(ne2_adapters[i].id, 0); if((current_mca_slot != MCA_NOTFOUND) && !adapter_found) { + int res; mca_set_adapter_name(current_mca_slot, ne2_adapters[i].name); mca_mark_as_used(current_mca_slot); - return ne2_probe1(dev, current_mca_slot); + res = ne2_probe1(dev, current_mca_slot); + if (res) + mca_mark_as_unused(current_mca_slot); + return res; } } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + mca_mark_as_unused(ei_status.priv); + mca_set_adapter_procfn( ei_status.priv, NULL, NULL); + free_irq(dev->irq, dev); + release_region(dev->base_addr, NE_IO_EXTENT); +} + +struct net_device * __init ne2_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_ne2_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} static int ne2_procinfo(char *buf, int slot, struct net_device *dev) { @@ -443,14 +479,6 @@ static int __init ne2_probe1(struct net_ dev->base_addr = base_addr; - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk (" unable to get memory for dev->priv.\n"); - free_irq(dev->irq, dev); - retval = -ENOMEM; - goto out; - } - for(i = 0; i < ETHER_ADDR_LEN; i++) { printk(" %2.2x", SA_prom[i]); dev->dev_addr[i] = SA_prom[i]; @@ -735,7 +763,7 @@ retry: #ifdef MODULE #define MAX_NE_CARDS 4 /* Max number of NE cards per module */ -static struct net_device dev_ne[MAX_NE_CARDS]; +static struct net_device *dev_ne[MAX_NE_CARDS]; static int io[MAX_NE_CARDS]; static int irq[MAX_NE_CARDS]; static int bad[MAX_NE_CARDS]; /* 0xbad = bad sig or no reset ack */ @@ -754,23 +782,30 @@ MODULE_PARM_DESC(bad, "(ignored)"); int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = &dev_ne[this_dev]; + dev = alloc_ei_netdev(); + if (!dev) + break; dev->irq = irq[this_dev]; dev->mem_end = bad[this_dev]; dev->base_addr = io[this_dev]; - dev->init = ne2_probe; - if (register_netdev(dev) != 0) { - if (found != 0) return 0; /* Got at least one. */ - - printk(KERN_WARNING "ne2.c: No NE/2 card found.\n"); - return -ENXIO; + if (do_ne2_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_ne[found++] = dev; + continue; + } + cleanup_card(dev); } - found++; + free_netdev(dev); + break; } - return 0; + if (found) + return 0; + printk(KERN_WARNING "ne2.c: No NE/2 card found\n"); + return -ENXIO; } void cleanup_module(void) @@ -778,14 +813,11 @@ void cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = &dev_ne[this_dev]; - if (dev->priv != NULL) { - mca_mark_as_unused(ei_status.priv); - mca_set_adapter_procfn( ei_status.priv, NULL, NULL); - kfree(dev->priv); - free_irq(dev->irq, dev); - release_region(dev->base_addr, NE_IO_EXTENT); + struct net_device *dev = dev_ne[this_dev]; + if (dev) { unregister_netdev(dev); + cleanup_card(dev); + free_netdev(dev); } } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/ne2k-pci.c 830-ivtv/drivers/net/ne2k-pci.c --- 000-virgin/drivers/net/ne2k-pci.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/ne2k-pci.c Thu Jan 8 08:54:19 2004 @@ -115,6 +115,7 @@ enum ne2k_pci_chipsets { CH_Winbond_W89C940F, CH_Holtek_HT80232, CH_Holtek_HT80229, + CH_Winbond_89C940_8c4a, }; @@ -132,6 +133,7 @@ static struct { {"Winbond W89C940F", 0}, {"Holtek HT80232", ONLY_16BIT_IO | HOLTEK_FDX}, {"Holtek HT80229", ONLY_32BIT_IO | HOLTEK_FDX | STOP_PG_0x60 }, + {"Winbond W89C940(misprogrammed)", 0}, {0,} }; @@ -147,6 +149,7 @@ static struct pci_device_id ne2k_pci_tbl { 0x1050, 0x5a5a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_W89C940F }, { 0x12c3, 0x0058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Holtek_HT80232 }, { 0x12c3, 0x5598, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Holtek_HT80229 }, + { 0x8c4a, 0x1980, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_89C940_8c4a }, { 0, } }; MODULE_DEVICE_TABLE(pci, ne2k_pci_tbl); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/ne2k_cbus.c 830-ivtv/drivers/net/ne2k_cbus.c --- 000-virgin/drivers/net/ne2k_cbus.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/ne2k_cbus.c Thu Jan 8 08:54:19 2004 @@ -78,7 +78,6 @@ bad_clone_list[] __initdata = { #include "ne2k_cbus.h" -int ne_probe(struct net_device *dev); static int ne_probe1(struct net_device *dev, int ioaddr); static int ne_open(struct net_device *dev); static int ne_close(struct net_device *dev); @@ -113,9 +112,10 @@ static void ne_block_output(struct net_d E2010 starts at 0x100 and ends at 0x4000. E2010-x starts at 0x100 and ends at 0xffff. */ -int __init ne_probe(struct net_device *dev) +static int __init do_ne_probe(struct net_device *dev) { unsigned int base_addr = dev->base_addr; + int irq = dev->irq; SET_MODULE_OWNER(dev); @@ -135,7 +135,7 @@ int __init ne_probe(struct net_device *d if (ei_debug > 2) printk(KERN_DEBUG "ne_probe(): call ne_probe_cbus(base_addr=0x%x)\n", base_addr); - result = ne_probe_cbus(dev, hw, base_addr); + result = ne_probe_cbus(dev, hw, base_addr, irq); if (result != 0) ne2k_cbus_destroy(dev); @@ -156,13 +156,13 @@ int __init ne_probe(struct net_device *d if (hw && hw->hwtype) { const unsigned short *plist; for (plist = hw->portlist; *plist; plist++) - if (ne_probe_cbus(dev, hw, *plist) == 0) + if (ne_probe_cbus(dev, hw, *plist, irq) == 0) return 0; } else { for (hw = &ne2k_cbus_hwinfo_list[0]; hw->hwtype; hw++) { const unsigned short *plist; for (plist = hw->portlist; *plist; plist++) - if (ne_probe_cbus(dev, hw, *plist) == 0) + if (ne_probe_cbus(dev, hw, *plist, irq) == 0) return 0; } } @@ -174,7 +174,45 @@ int __init ne_probe(struct net_device *d return -ENODEV; } -static int __init ne_probe_cbus(struct net_device *dev, const struct ne2k_cbus_hwinfo *hw, int ioaddr) +static void cleanup_card(struct net_device *dev) +{ + const struct ne2k_cbus_region *rlist; + const struct ne2k_cbus_hwinfo *hw = ne2k_cbus_get_hwinfo((int)(dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK)); + + free_irq(dev->irq, dev); + for (rlist = hw->regionlist; rlist->range; rlist++) { + release_region(dev->base_addr + rlist->start, + rlist->range); + } + ne2k_cbus_destroy(dev); +} + +struct net_device * __init ne_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_ne_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + +static int __init ne_probe_cbus(struct net_device *dev, const struct ne2k_cbus_hwinfo *hw, int ioaddr, int irq) { if (ei_debug > 2) printk(KERN_DEBUG "ne_probe_cbus(): entered. (called from %p)\n", @@ -182,6 +220,7 @@ static int __init ne_probe_cbus(struct n if (hw && hw->hwtype) { ne2k_cbus_set_hwtype(dev, hw, ioaddr); + dev->irq = irq; return ne_probe1(dev, ioaddr); } else { /* auto detect */ @@ -189,6 +228,7 @@ static int __init ne_probe_cbus(struct n printk(KERN_DEBUG "ne_probe_cbus(): try to determine hardware types.\n"); for (hw = &ne2k_cbus_hwinfo_list[0]; hw->hwtype; hw++) { ne2k_cbus_set_hwtype(dev, hw, ioaddr); + dev->irq = irq; if (ne_probe1(dev, ioaddr) == 0) return 0; } @@ -301,11 +341,12 @@ static int __init ne_probe1(struct net_d if (ei_debug > 2) printk(" [CNET98EL-specific initialize..."); outb_p(E8390_NODMA | E8390_STOP, ioaddr + E8390_CMD); /* 0x20|0x1 */ + ret = -ENODEV; i = inb(ioaddr); if ((i & ~0x2) != (0x20 | 0x01)) - return -ENODEV; + goto err_out; if ((inb(ioaddr + 0x7) & 0x80) != 0x80) - return -ENODEV; + goto err_out; outb_p(E8390_RXOFF, ioaddr + EN0_RXCR); /* out(ioaddr+0xc, 0x20) */ /* outb_p(ENDCFG_WTS|ENDCFG_FT1|ENDCFG_LS, ioaddr+EN0_DCFG); */ outb_p(ENDCFG_WTS | 0x48, ioaddr + EN0_DCFG); /* 0x49 */ @@ -330,7 +371,7 @@ static int __init ne_probe1(struct net_d if (ei_debug > 2) printk("] "); printk("memory failure at %x\n", i); - return -ENODEV; + goto err_out; } if (ei_debug > 2) printk(" good..."); @@ -338,7 +379,7 @@ static int __init ne_probe1(struct net_d if (ei_debug > 2) printk("] "); printk("IRQ must be specified for C-NET(98)E/L. probe failed.\n"); - return -ENODEV; + goto err_out; } outb((dev->irq > 5) ? (dev->irq & 4):(dev->irq >> 1), ioaddr + (0x2 | 0x400)); outb(0x7e, ioaddr + (0x4 | 0x400)); @@ -457,14 +498,6 @@ static int __init ne_probe1(struct net_d goto err_out; } - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) - { - printk (" unable to get memory for dev->priv.\n"); - ret = -ENOMEM; - goto err_out; - } - /* Snarf the interrupt now. There's no point in waiting since we cannot share and the board will usually be enabled. */ ret = request_irq(dev->irq, ei_interrupt, 0, name, dev); @@ -779,7 +812,7 @@ retry: #ifdef MODULE #define MAX_NE_CARDS 4 /* Max number of NE cards per module */ -static struct net_device dev_ne[MAX_NE_CARDS]; +static struct net_device *dev_ne[MAX_NE_CARDS]; static int io[MAX_NE_CARDS]; static int irq[MAX_NE_CARDS]; static int bad[MAX_NE_CARDS]; /* 0xbad = bad sig or no reset ack */ @@ -806,26 +839,32 @@ int init_module(void) int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = &dev_ne[this_dev]; + struct net_device *dev = alloc_ei_netdev(); + if (!dev) + break; dev->irq = irq[this_dev]; dev->mem_end = bad[this_dev]; dev->base_addr = io[this_dev]; dev->mem_start = hwtype[this_dev]; - dev->init = ne_probe; - if (register_netdev(dev) == 0) { - found++; - continue; - } - if (found != 0) { /* Got at least one. */ - return 0; + if (do_ne_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_ne[found++] = dev; + continue; + } + cleanup_card(dev); } + free_netdev(dev); + if (found) + break; if (io[this_dev] != 0) printk(KERN_WARNING "ne2k_cbus: No NE*000 card found at i/o = %#x\n", io[this_dev]); else - printk(KERN_NOTICE "ne2k_cbus: You must supply \"io=0xNNN\" value(s) for C-Bus cards.\n"); + printk(KERN_NOTICE "ne.c: You must supply \"io=0xNNN\" value(s) for ISA cards.\n"); return -ENXIO; } - return 0; + if (found) + return 0; + return -ENODEV; } void cleanup_module(void) @@ -833,18 +872,11 @@ void cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = &dev_ne[this_dev]; - if (dev->priv != NULL) { - const struct ne2k_cbus_region *rlist; - const struct ne2k_cbus_hwinfo *hw = ne2k_cbus_get_hwinfo((int)(dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK)); - - free_irq(dev->irq, dev); - for (rlist = hw->regionlist; rlist->range; rlist++) { - release_region(dev->base_addr + rlist->start, - rlist->range); - } + struct net_device *dev = dev_ne[this_dev]; + if (dev) { unregister_netdev(dev); - ne2k_cbus_destroy(dev); + cleanup_card(dev); + free_netdev(dev); } } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/ne2k_cbus.h 830-ivtv/drivers/net/ne2k_cbus.h --- 000-virgin/drivers/net/ne2k_cbus.h Wed Mar 26 22:54:32 2003 +++ 830-ivtv/drivers/net/ne2k_cbus.h Thu Jan 8 08:54:19 2004 @@ -477,5 +477,5 @@ static void __init ne2k_cbus_writemem(st } #endif -static int ne_probe_cbus(struct net_device *dev, const struct ne2k_cbus_hwinfo *hw, int ioaddr); +static int ne_probe_cbus(struct net_device *dev, const struct ne2k_cbus_hwinfo *hw, int ioaddr, int irq); /* End of ne2k_cbus.h */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/ne3210.c 830-ivtv/drivers/net/ne3210.c --- 000-virgin/drivers/net/ne3210.c Mon Nov 17 18:29:30 2003 +++ 830-ivtv/drivers/net/ne3210.c Thu Jan 8 08:54:19 2004 @@ -111,12 +111,6 @@ static int __init ne3210_eisa_probe (str device->driver_data = dev; ioaddr = edev->base_addr; - if (ethdev_init (dev)) { - printk ("ne3210.c: unable to allocate memory for dev->priv!\n"); - retval = -ENOMEM; - goto out; - } - if (!request_region(ioaddr, NE3210_IO_EXTENT, dev->name)) { retval = -EBUSY; goto out; @@ -356,24 +350,6 @@ static struct eisa_driver ne3210_eisa_dr .remove = __devexit_p (ne3210_eisa_remove), }, }; - -#ifdef MODULE -#if 0 -#define MAX_NE3210_CARDS 4 /* Max number of NE3210 cards per module */ -static struct net_device dev_ne3210[MAX_NE3210_CARDS]; -static int io[MAX_NE3210_CARDS]; -static int irq[MAX_NE3210_CARDS]; -static int mem[MAX_NE3210_CARDS]; - -MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NE3210_CARDS) "i"); -MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_NE3210_CARDS) "i"); -MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_NE3210_CARDS) "i"); -MODULE_PARM_DESC(io, "I/O base address(es)"); -MODULE_PARM_DESC(irq, "IRQ number(s)"); -MODULE_PARM_DESC(mem, "memory base address(es)"); -#endif -#endif /* MODULE */ - MODULE_DESCRIPTION("NE3210 EISA Ethernet driver"); MODULE_LICENSE("GPL"); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/net_init.c 830-ivtv/drivers/net/net_init.c --- 000-virgin/drivers/net/net_init.c Mon Nov 17 18:29:42 2003 +++ 830-ivtv/drivers/net/net_init.c Thu Jan 8 08:54:19 2004 @@ -73,23 +73,28 @@ struct net_device *alloc_netdev(int sizeof_priv, const char *mask, void (*setup)(struct net_device *)) { + void *p; struct net_device *dev; int alloc_size; - /* ensure 32-byte alignment of the private area */ - alloc_size = sizeof (*dev) + sizeof_priv + 31; + /* ensure 32-byte alignment of both the device and private area */ - dev = (struct net_device *) kmalloc (alloc_size, GFP_KERNEL); - if (dev == NULL) - { - printk(KERN_ERR "alloc_dev: Unable to allocate device memory.\n"); + alloc_size = (sizeof(struct net_device) + 31) & ~31; + alloc_size += sizeof_priv + 31; + + p = kmalloc (alloc_size, GFP_KERNEL); + if (!p) { + printk(KERN_ERR "alloc_dev: Unable to allocate device.\n"); return NULL; } - memset(dev, 0, alloc_size); + memset(p, 0, alloc_size); + + dev = (struct net_device *)(((long)p + 31) & ~31); + dev->padded = (char *)dev - (char *)p; if (sizeof_priv) - dev->priv = (void *) (((long)(dev + 1) + 31) & ~31); + dev->priv = netdev_priv(dev); setup(dev); strcpy(dev->name, mask); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/netconsole.c 830-ivtv/drivers/net/netconsole.c --- 000-virgin/drivers/net/netconsole.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/net/netconsole.c Thu Jan 8 08:54:19 2004 @@ -0,0 +1,120 @@ +/* + * linux/drivers/net/netconsole.c + * + * Copyright (C) 2001 Ingo Molnar + * + * This file contains the implementation of an IRQ-safe, crash-safe + * kernel console implementation that outputs kernel messages to the + * network. + * + * Modification history: + * + * 2001-09-17 started by Ingo Molnar. + * 2003-08-11 2.6 port by Matt Mackall + * simplified options + * generic card hooks + * works non-modular + * 2003-09-07 rewritten with netpoll api + */ + +/**************************************************************** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ****************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Maintainer: Matt Mackall "); +MODULE_DESCRIPTION("Console driver for network interfaces"); +MODULE_LICENSE("GPL"); + +static char config[256]; +module_param_string(netconsole, config, 256, 0); +MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@/[tgt-macaddr]\n"); + +static struct netpoll np = { + .name = "netconsole", + .dev_name = "eth0", + .local_port = 6665, + .remote_port = 6666, + .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, +}; + +#define MAX_PRINT_CHUNK 1000 + +static void write_msg(struct console *con, const char *msg, unsigned int len) +{ + int frag, left; + unsigned long flags; + + if (!np.dev) + return; + + local_irq_save(flags); + + for(left = len; left; ) { + frag = min(left, MAX_PRINT_CHUNK); + netpoll_send_udp(&np, msg, frag); + msg += frag; + left -= frag; + } + + local_irq_restore(flags); +} + +static struct console netconsole = { + .flags = CON_ENABLED | CON_PRINTBUFFER, + .write = write_msg +}; + +static int option_setup(char *opt) +{ + return netpoll_parse_options(&np, opt); +} + +__setup("netconsole=", option_setup); + +static int init_netconsole(void) +{ + if(strlen(config) && option_setup(config)) + return 1; + + if(!np.remote_ip || netpoll_setup(&np)) + return 1; + + register_console(&netconsole); + printk(KERN_INFO "netconsole: network logging started\n"); + return 0; +} + +static void cleanup_netconsole(void) +{ + unregister_console(&netconsole); + netpoll_cleanup(&np); +} + +module_init(init_netconsole); +module_exit(cleanup_netconsole); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/ni5010.c 830-ivtv/drivers/net/ni5010.c --- 000-virgin/drivers/net/ni5010.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/ni5010.c Thu Jan 8 08:54:19 2004 @@ -82,7 +82,7 @@ static unsigned int bufsize_rcv; #ifndef FULL_IODETECT /* A zero-terminated list of I/O addresses to be probed. */ -static unsigned int ni5010_portlist[] __initdata = +static unsigned int ports[] __initdata = { 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0 }; #endif @@ -95,13 +95,11 @@ static unsigned int ni5010_portlist[] __ struct ni5010_local { struct net_device_stats stats; int o_pkt_size; - int i_pkt_size; spinlock_t lock; }; /* Index to functions, as function prototypes. */ -extern int ni5010_probe(struct net_device *dev); static int ni5010_probe1(struct net_device *dev, int ioaddr); static int ni5010_open(struct net_device *dev); static int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev); @@ -120,38 +118,58 @@ static void chipset_init(struct net_dev static void dump_packet(void *buf, int len); static void ni5010_show_registers(struct net_device *dev); +static int io; +static int irq; -int __init ni5010_probe(struct net_device *dev) +struct net_device * __init ni5010_probe(int unit) { + struct net_device *dev = alloc_etherdev(sizeof(struct ni5010_local)); int *port; - int base_addr = dev->base_addr; + int err = 0; - PRINTK2((KERN_DEBUG "%s: Entering ni5010_probe\n", dev->name)); + if (!dev) + return ERR_PTR(-ENOMEM); - SET_MODULE_OWNER(dev); + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + irq = dev->irq; + } - if (base_addr > 0x1ff) /* Check a single specified location. */ - return ni5010_probe1(dev, base_addr); - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; + PRINTK2((KERN_DEBUG "%s: Entering ni5010_probe\n", dev->name)); + SET_MODULE_OWNER(dev); + + if (io > 0x1ff) { /* Check a single specified location. */ + err = ni5010_probe1(dev, io); + } else if (io != 0) { /* Don't probe at all. */ + err = -ENXIO; + } else { #ifdef FULL_IODETECT - for (int ioaddr=0x200; ioaddr<0x400; ioaddr+=0x20) { - if (check_region(ioaddr, NI5010_IO_EXTENT)) - continue; - if (ni5010_probe1(dev, ioaddr) == 0) - return 0; - } + for (io=0x200; io<0x400 && ni5010_probe1(dev, io) ; io+=0x20) + ; + if (io == 0x400) + err = -ENODEV; + #else - for (port = ni5010_portlist; *port; port++) { - int ioaddr = *port; - if (check_region(ioaddr, NI5010_IO_EXTENT)) - continue; - if (ni5010_probe1(dev, ioaddr) == 0) - return 0; - } + for (port = ports; *port && ni5010_probe1(dev, *port); port++) + ; + if (!*port) + err = -ENODEV; #endif /* FULL_IODETECT */ - return -ENODEV; + } + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + release_region(dev->base_addr, NI5010_IO_EXTENT); +out: + free_netdev(dev); + return ERR_PTR(err); } static inline int rd_port(int ioaddr) @@ -188,9 +206,17 @@ static void __init trigger_irq(int ioadd static int __init ni5010_probe1(struct net_device *dev, int ioaddr) { static unsigned version_printed; + struct ni5010_local *lp; int i; unsigned int data = 0; int boguscount = 40; + int err = -ENODEV; + + dev->base_addr = ioaddr; + dev->irq = irq; + + if (!request_region(ioaddr, NI5010_IO_EXTENT, boardname)) + return -EBUSY; /* * This is no "official" probe method, I've rather tested which @@ -205,36 +231,40 @@ static int __init ni5010_probe1(struct n * * - Andreas */ - + PRINTK2((KERN_DEBUG "%s: entering ni5010_probe1(%#3x)\n", dev->name, ioaddr)); - if (inb(ioaddr+0) == 0xff) return -ENODEV; + if (inb(ioaddr+0) == 0xff) + goto out; while ( (rd_port(ioaddr) & rd_port(ioaddr) & rd_port(ioaddr) & rd_port(ioaddr) & rd_port(ioaddr) & rd_port(ioaddr)) != 0xff) { - if (boguscount-- == 0) return -ENODEV; + if (boguscount-- == 0) + goto out; } PRINTK2((KERN_DEBUG "%s: I/O #1 passed!\n", dev->name)); for (i=0; i<32; i++) if ( (data = rd_port(ioaddr)) != 0xff) break; - if (data==0xff) return -ENODEV; + if (data==0xff) + goto out; PRINTK2((KERN_DEBUG "%s: I/O #2 passed!\n", dev->name)); - if ( (data == SA_ADDR0) && - (rd_port(ioaddr) == SA_ADDR1) && - (rd_port(ioaddr) == SA_ADDR2) ) { - for (i=0; i<4; i++) rd_port(ioaddr); - if ( (rd_port(ioaddr) != NI5010_MAGICVAL1) || - (rd_port(ioaddr) != NI5010_MAGICVAL2) ) { - return -ENODEV; - } - } else return -ENODEV; - + if ((data != SA_ADDR0) || (rd_port(ioaddr) != SA_ADDR1) || + (rd_port(ioaddr) != SA_ADDR2)) + goto out; + + for (i=0; i<4; i++) + rd_port(ioaddr); + + if ( (rd_port(ioaddr) != NI5010_MAGICVAL1) || + (rd_port(ioaddr) != NI5010_MAGICVAL2) ) + goto out; + PRINTK2((KERN_DEBUG "%s: I/O #3 passed!\n", dev->name)); if (NI5010_DEBUG && version_printed++ == 0) @@ -267,8 +297,9 @@ static int __init ni5010_probe1(struct n PRINTK2((KERN_DEBUG "%s: I/O #6 passed!\n", dev->name)); if (dev->irq == 0) { + err = -EAGAIN; printk(KERN_WARNING "%s: no IRQ found!\n", dev->name); - return -EAGAIN; + goto out; } PRINTK2((KERN_DEBUG "%s: I/O #7 passed!\n", dev->name)); } else if (dev->irq == 2) { @@ -278,19 +309,9 @@ static int __init ni5010_probe1(struct n PRINTK2((KERN_DEBUG "%s: I/O #9 passed!\n", dev->name)); /* DMA is not supported (yet?), so no use detecting it */ + lp = (struct ni5010_local*)dev->priv; - if (dev->priv == NULL) { - struct ni5010_local* lp; - - dev->priv = kmalloc(sizeof(struct ni5010_local), GFP_KERNEL|GFP_DMA); - if (dev->priv == NULL) { - printk(KERN_WARNING "%s: Failed to allocate private memory\n", dev->name); - return -ENOMEM; - } - - lp = (struct ni5010_local*)dev->priv; - spin_lock_init(&lp->lock); - } + spin_lock_init(&lp->lock); PRINTK2((KERN_DEBUG "%s: I/O #10 passed!\n", dev->name)); @@ -315,9 +336,6 @@ static int __init ni5010_probe1(struct n } printk("// bufsize rcv/xmt=%d/%d\n", bufsize_rcv, NI5010_BUFSIZE); memset(dev->priv, 0, sizeof(struct ni5010_local)); - - /* Grab the region so we can find another board if autoIRQ fails. */ - request_region(ioaddr, NI5010_IO_EXTENT, boardname); dev->open = ni5010_open; dev->stop = ni5010_close; @@ -327,9 +345,6 @@ static int __init ni5010_probe1(struct n dev->tx_timeout = ni5010_timeout; dev->watchdog_timeo = HZ/20; - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - dev->flags &= ~IFF_MULTICAST; /* Multicast doesn't work */ /* Shut up the ni5010 */ @@ -345,6 +360,9 @@ static int __init ni5010_probe1(struct n printk(KERN_INFO "Join the NI5010 driver development team!\n"); printk(KERN_INFO "Mail to a.mohr@mailto.de or jvbest@wi.leidenuniv.nl\n"); return 0; +out: + release_region(dev->base_addr, NI5010_IO_EXTENT); + return err; } /* @@ -513,6 +531,7 @@ static void ni5010_rx(struct net_device int ioaddr = dev->base_addr; unsigned char rcv_stat; struct sk_buff *skb; + int i_pkt_size; PRINTK2((KERN_DEBUG "%s: entering ni5010_rx()\n", dev->name)); @@ -532,17 +551,17 @@ static void ni5010_rx(struct net_device outb(0xff, EDLC_RCLR); /* Clear the interrupt */ - lp->i_pkt_size = inw(IE_RCNT); - if (lp->i_pkt_size > ETH_FRAME_LEN || lp->i_pkt_size < 10 ) { + i_pkt_size = inw(IE_RCNT); + if (i_pkt_size > ETH_FRAME_LEN || i_pkt_size < 10 ) { PRINTK((KERN_DEBUG "%s: Packet size error, packet size = %#4.4x\n", - dev->name, lp->i_pkt_size)); + dev->name, i_pkt_size)); lp->stats.rx_errors++; lp->stats.rx_length_errors++; return; } /* Malloc up new buffer. */ - skb = dev_alloc_skb(lp->i_pkt_size + 3); + skb = dev_alloc_skb(i_pkt_size + 3); if (skb == NULL) { printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); lp->stats.rx_dropped++; @@ -555,7 +574,7 @@ static void ni5010_rx(struct net_device /* Read packet into buffer */ outb(MM_MUX, IE_MMODE); /* Rcv buffer to system bus */ outw(0, IE_GP); /* Seek to beginning of packet */ - insb(IE_RBUF, skb_put(skb, lp->i_pkt_size), lp->i_pkt_size); + insb(IE_RBUF, skb_put(skb, i_pkt_size), i_pkt_size); if (NI5010_DEBUG >= 4) dump_packet(skb->data, skb->len); @@ -564,10 +583,10 @@ static void ni5010_rx(struct net_device netif_rx(skb); dev->last_rx = jiffies; lp->stats.rx_packets++; - lp->stats.rx_bytes += lp->i_pkt_size; + lp->stats.rx_bytes += i_pkt_size; PRINTK2((KERN_DEBUG "%s: Received packet, size=%#4.4x\n", - dev->name, lp->i_pkt_size)); + dev->name, i_pkt_size)); } @@ -697,10 +716,10 @@ static void hardware_send_packet(struct if (NI5010_DEBUG > 3) dump_packet(buf, length); - buf_offs = NI5010_BUFSIZE - length - pad; - lp->o_pkt_size = length + pad; + buf_offs = NI5010_BUFSIZE - length - pad; spin_lock_irqsave(&lp->lock, flags); + lp->o_pkt_size = length + pad; outb(0, EDLC_RMASK); /* Mask all receive interrupts */ outb(0, IE_MMODE); /* Put Xmit buffer on system bus */ @@ -745,9 +764,7 @@ static void ni5010_show_registers(struct } #ifdef MODULE -static struct net_device dev_ni5010; -static int io; -static int irq; +static struct net_device *dev_ni5010; MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); @@ -756,8 +773,6 @@ MODULE_PARM_DESC(irq, "ni5010 IRQ number int init_module(void) { - int result; - PRINTK2((KERN_DEBUG "%s: entering init_module\n", boardname)); /* if(io <= 0 || irq == 0){ @@ -771,29 +786,18 @@ int init_module(void) } PRINTK2((KERN_DEBUG "%s: init_module irq=%#2x, io=%#3x\n", boardname, irq, io)); - dev_ni5010.irq=irq; - dev_ni5010.base_addr=io; - dev_ni5010.init=ni5010_probe; - if ((result = register_netdev(&dev_ni5010)) != 0) { - PRINTK((KERN_WARNING "%s: register_netdev returned %d.\n", - boardname, result)); - return -EIO; - } + dev_ni5010 = ni5010_probe(-1); + if (IS_ERR(dev_ni5010)) + return PTR_ERR(dev_ni5010); return 0; } -void -cleanup_module(void) +void cleanup_module(void) { PRINTK2((KERN_DEBUG "%s: entering cleanup_module\n", boardname)); - - unregister_netdev(&dev_ni5010); - - release_region(dev_ni5010.base_addr, NI5010_IO_EXTENT); - if (dev_ni5010.priv != NULL){ - kfree(dev_ni5010.priv); - dev_ni5010.priv = NULL; - } + unregister_netdev(dev_ni5010); + release_region(dev_ni5010->base_addr, NI5010_IO_EXTENT); + free_netdev(dev_ni5010); } #endif /* MODULE */ MODULE_LICENSE("GPL"); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/ni52.c 830-ivtv/drivers/net/ni52.c --- 000-virgin/drivers/net/ni52.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/ni52.c Thu Jan 8 08:54:19 2004 @@ -354,50 +354,76 @@ static void alloc586(struct net_device * memset((char *)p->scb,0,sizeof(struct scb_struct)); } +/* set: io,irq,memstart,memend or set it when calling insmod */ +static int irq=9; +static int io=0x300; +static long memstart; /* e.g 0xd0000 */ +static long memend; /* e.g 0xd4000 */ + /********************************************** * probe the ni5210-card */ -int __init ni52_probe(struct net_device *dev) +struct net_device * __init ni52_probe(int unit) { -#ifndef MODULE - int *port; + struct net_device *dev = alloc_etherdev(sizeof(struct priv)); static int ports[] = {0x300, 0x280, 0x360 , 0x320 , 0x340, 0}; -#endif - int base_addr = dev->base_addr; - - SET_MODULE_OWNER(dev); + int *port; + int err = 0; - if (base_addr > 0x1ff) /* Check a single specified location. */ - return ni52_probe1(dev, base_addr); - else if (base_addr > 0) /* Don't probe at all. */ - return -ENXIO; + if (!dev) + return ERR_PTR(-ENOMEM); -#ifdef MODULE - printk("%s: no autoprobing allowed for modules.\n",dev->name); -#else - for (port = ports; *port; port++) { - int ioaddr = *port; - dev->base_addr = ioaddr; - if (ni52_probe1(dev, ioaddr) == 0) - return 0; + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + irq = dev->irq; + memstart = dev->mem_start; + memend = dev->mem_end; } -#ifdef FULL_IO_PROBE - for(dev->base_addr=0x200; dev->base_addr<0x400; dev->base_addr+=8) - if (ni52_probe1(dev, dev->base_addr) == 0) - return 0; -#endif + SET_MODULE_OWNER(dev); + if (io > 0x1ff) { /* Check a single specified location. */ + err = ni52_probe1(dev, io); + } else if (io > 0) { /* Don't probe at all. */ + err = -ENXIO; + } else { + for (port = ports; *port && ni52_probe1(dev, *port) ; port++) + ; + if (*port) + goto got_it; +#ifdef FULL_IO_PROBE + for (io = 0x200; io < 0x400 && ni52_probe1(dev, io); io += 8) + ; + if (io < 0x400) + goto got_it; #endif - - dev->base_addr = base_addr; - return -ENODEV; + err = -ENODEV; + } + if (err) + goto out; +got_it: + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + release_region(dev->base_addr, NI52_TOTAL_SIZE); +out: + free_netdev(dev); + return ERR_PTR(err); } static int __init ni52_probe1(struct net_device *dev,int ioaddr) { int i, size, retval; + dev->base_addr = ioaddr; + dev->irq = irq; + dev->mem_start = memstart; + dev->mem_end = memend; + if (!request_region(ioaddr, NI52_TOTAL_SIZE, dev->name)) return -EBUSY; @@ -416,7 +442,7 @@ static int __init ni52_probe1(struct net goto out; } - printk("%s: NI5210 found at %#3lx, ",dev->name,dev->base_addr); + printk(KERN_INFO "%s: NI5210 found at %#3lx, ",dev->name,dev->base_addr); /* * check (or search) IO-Memory, 8K and 16K @@ -469,13 +495,6 @@ static int __init ni52_probe1(struct net dev->mem_end = dev->mem_start + size; /* set mem_end showed by 'ifconfig' */ #endif - dev->priv = (void *) kmalloc(sizeof(struct priv),GFP_KERNEL); - if(dev->priv == NULL) { - printk("%s: Ooops .. can't allocate private driver memory.\n",dev->name); - retval = -ENOMEM; - goto out; - } - /* warning: we don't free it on errors */ memset((char *) dev->priv,0,sizeof(struct priv)); ((struct priv *) (dev->priv))->memtop = isa_bus_to_virt(dev->mem_start) + size; @@ -503,8 +522,6 @@ static int __init ni52_probe1(struct net if(!dev->irq) { printk("?autoirq, Failed to detect IRQ line!\n"); - kfree(dev->priv); - dev->priv = NULL; retval = -EAGAIN; goto out; } @@ -526,8 +543,6 @@ static int __init ni52_probe1(struct net dev->if_port = 0; - ether_setup(dev); - return 0; out: release_region(ioaddr, NI52_TOTAL_SIZE); @@ -1295,13 +1310,7 @@ static void set_multicast_list(struct ne } #ifdef MODULE -static struct net_device dev_ni52; - -/* set: io,irq,memstart,memend or set it when calling insmod */ -static int irq=9; -static int io=0x300; -static long memstart; /* e.g 0xd0000 */ -static long memend; /* e.g 0xd4000 */ +static struct net_device *dev_ni52; MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); @@ -1318,22 +1327,17 @@ int init_module(void) printk("ni52: Autoprobing not allowed for modules.\nni52: Set symbols 'io' 'irq' 'memstart' and 'memend'\n"); return -ENODEV; } - dev_ni52.init = ni52_probe; - dev_ni52.irq = irq; - dev_ni52.base_addr = io; - dev_ni52.mem_end = memend; - dev_ni52.mem_start = memstart; - if (register_netdev(&dev_ni52) != 0) - return -EIO; + dev_ni52 = ni52_probe(-1); + if (IS_ERR(dev_ni52)) + return PTR_ERR(dev_ni52); return 0; } void cleanup_module(void) { - release_region(dev_ni52.base_addr, NI52_TOTAL_SIZE); - unregister_netdev(&dev_ni52); - kfree(dev_ni52.priv); - dev_ni52.priv = NULL; + unregister_netdev(dev_ni52); + release_region(dev_ni52->base_addr, NI52_TOTAL_SIZE); + free_netdev(dev_ni52); } #endif /* MODULE */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/ni65.c 830-ivtv/drivers/net/ni65.c --- 000-virgin/drivers/net/ni65.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/ni65.c Thu Jan 8 08:54:19 2004 @@ -343,29 +343,64 @@ static int ni65_close(struct net_device return 0; } +static void cleanup_card(struct net_device *dev) +{ + struct priv *p = (struct priv *) dev->priv; + disable_dma(dev->dma); + free_dma(dev->dma); + release_region(dev->base_addr, cards[p->cardno].total_size); + ni65_free_buffer(p); +} + +/* set: io,irq,dma or set it when calling insmod */ +static int irq; +static int io; +static int dma; + /* * Probe The Card (not the lance-chip) */ -#ifdef MODULE -static -#endif -int __init ni65_probe(struct net_device *dev) +struct net_device * __init ni65_probe(int unit) { - int *port; + struct net_device *dev = alloc_etherdev(0); static int ports[] = {0x360,0x300,0x320,0x340, 0}; + int *port; + int err = 0; - if (dev->base_addr > 0x1ff) /* Check a single specified location. */ - return ni65_probe1(dev, dev->base_addr); - else if (dev->base_addr > 0) /* Don't probe at all. */ - return -ENXIO; + if (!dev) + return ERR_PTR(-ENOMEM); - for (port = ports; *port; port++) - { - if (ni65_probe1(dev, *port) == 0) - return 0; - } - - return -ENODEV; + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + irq = dev->irq; + dma = dev->dma; + } else { + dev->base_addr = io; + } + + if (dev->base_addr > 0x1ff) { /* Check a single specified location. */ + err = ni65_probe1(dev, dev->base_addr); + } else if (dev->base_addr > 0) { /* Don't probe at all. */ + err = -ENXIO; + } else { + for (port = ports; *port && ni65_probe1(dev, *port); port++) + ; + if (!*port) + err = -ENODEV; + } + if (err) + goto out; + + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); } /* @@ -377,6 +412,9 @@ static int __init ni65_probe1(struct net struct priv *p; unsigned long flags; + dev->irq = irq; + dev->dma = dma; + for(i=0;iwatchdog_timeo = HZ/2; dev->get_stats = ni65_get_stats; dev->set_multicast_list = set_multicast_list; - - ether_setup(dev); - return 0; /* everything is OK */ } @@ -1213,12 +1248,7 @@ static void set_multicast_list(struct ne } #ifdef MODULE -static struct net_device dev_ni65 = { .base_addr = 0x360, .irq = 9, .init = ni65_probe }; - -/* set: io,irq,dma or set it when calling insmod */ -static int irq; -static int io; -static int dma; +static struct net_device *dev_ni65; MODULE_PARM(irq, "i"); MODULE_PARM(io, "i"); @@ -1229,26 +1259,15 @@ MODULE_PARM_DESC(dma, "ni6510 ISA DMA ch int init_module(void) { - dev_ni65.irq = irq; - dev_ni65.dma = dma; - dev_ni65.base_addr = io; - if (register_netdev(&dev_ni65) != 0) - return -EIO; - return 0; + dev_ni65 = ni65_probe(-1); + return IS_ERR(dev_ni65) ? PTR_ERR(dev_ni65) : 0; } void cleanup_module(void) { - struct priv *p; - p = (struct priv *) dev_ni65.priv; - if(!p) - BUG(); - disable_dma(dev_ni65.dma); - free_dma(dev_ni65.dma); - unregister_netdev(&dev_ni65); - release_region(dev_ni65.base_addr,cards[p->cardno].total_size); - ni65_free_buffer(p); - dev_ni65.priv = NULL; + unregister_netdev(dev_ni65); + cleanup_card(dev_ni65); + free_netdev(dev_ni65); } #endif /* MODULE */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/ns83820.c 830-ivtv/drivers/net/ns83820.c --- 000-virgin/drivers/net/ns83820.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/ns83820.c Thu Jan 8 08:54:19 2004 @@ -374,19 +374,6 @@ static int lnksts = 0; /* CFG_LNKSTS bi #define LINK_DOWN 0x02 #define LINK_UP 0x04 -#define __kick_rx(dev) writel(CR_RXE, dev->base + CR) - -#define kick_rx(dev) do { \ - dprintk("kick_rx: maybe kicking\n"); \ - if (test_and_clear_bit(0, &dev->rx_info.idle)) { \ - dprintk("actually kicking\n"); \ - writel(dev->rx_info.phy_descs + (4 * DESC_SIZE * dev->rx_info.next_rx), dev->base + RXDP); \ - if (dev->rx_info.next_rx == dev->rx_info.next_empty) \ - printk(KERN_DEBUG "%s: uh-oh: next_rx == next_empty???\n", dev->net_dev.name);\ - __kick_rx(dev); \ - } \ -} while(0) - #ifdef USE_64BIT_ADDR #define HW_ADDR_LEN 8 #define desc_addr_set(desc, addr) \ @@ -438,7 +425,6 @@ struct rx_info { struct ns83820 { - struct net_device net_dev; /* must be first */ struct net_device_stats stats; u8 *base; @@ -478,6 +464,29 @@ struct ns83820 { struct timer_list tx_watchdog; }; +static inline struct ns83820 *PRIV(struct net_device *dev) +{ + return netdev_priv(dev); +} + +#define __kick_rx(dev) writel(CR_RXE, dev->base + CR) + +static inline void kick_rx(struct net_device *ndev) +{ + struct ns83820 *dev = PRIV(ndev); + dprintk("kick_rx: maybe kicking\n"); + if (test_and_clear_bit(0, &dev->rx_info.idle)) { + dprintk("actually kicking\n"); + writel(dev->rx_info.phy_descs + + (4 * DESC_SIZE * dev->rx_info.next_rx), + dev->base + RXDP); + if (dev->rx_info.next_rx == dev->rx_info.next_empty) + printk(KERN_DEBUG "%s: uh-oh: next_rx == next_empty???\n", + ndev->name); + __kick_rx(dev); + } +} + //free = (tx_done_idx + NR_TX_DESC-2 - free_idx) % NR_TX_DESC #define start_tx_okay(dev) \ (((NR_TX_DESC-2 + dev->tx_done_idx - dev->tx_free_idx) % NR_TX_DESC) > MIN_TX_DESC_FREE) @@ -546,15 +555,16 @@ static inline int ns83820_add_rx_skb(str return 0; } -static inline int rx_refill(struct ns83820 *dev, int gfp) +static inline int rx_refill(struct net_device *ndev, int gfp) { + struct ns83820 *dev = PRIV(ndev); unsigned i; unsigned long flags = 0; if (unlikely(nr_rx_empty(dev) <= 2)) return 0; - dprintk("rx_refill(%p)\n", dev); + dprintk("rx_refill(%p)\n", ndev); if (gfp == GFP_ATOMIC) spin_lock_irqsave(&dev->rx_info.lock, flags); for (i=0; idev = &dev->net_dev; + skb->dev = ndev; if (gfp != GFP_ATOMIC) spin_lock_irqsave(&dev->rx_info.lock, flags); res = ns83820_add_rx_skb(dev, skb); @@ -587,20 +597,21 @@ static inline int rx_refill(struct ns838 return i ? 0 : -ENOMEM; } -static void FASTCALL(rx_refill_atomic(struct ns83820 *dev)); -static void rx_refill_atomic(struct ns83820 *dev) +static void FASTCALL(rx_refill_atomic(struct net_device *ndev)); +static void rx_refill_atomic(struct net_device *ndev) { - rx_refill(dev, GFP_ATOMIC); + rx_refill(ndev, GFP_ATOMIC); } /* REFILL */ static inline void queue_refill(void *_dev) { - struct ns83820 *dev = _dev; + struct net_device *ndev = _dev; + struct ns83820 *dev = PRIV(ndev); - rx_refill(dev, GFP_KERNEL); + rx_refill(ndev, GFP_KERNEL); if (dev->rx_info.up) - kick_rx(dev); + kick_rx(ndev); } static inline void clear_rx_desc(struct ns83820 *dev, unsigned i) @@ -608,9 +619,10 @@ static inline void clear_rx_desc(struct build_rx_desc(dev, dev->rx_info.descs + (DESC_SIZE * i), 0, 0, CMDSTS_OWN, 0); } -static void FASTCALL(phy_intr(struct ns83820 *dev)); -static void phy_intr(struct ns83820 *dev) +static void FASTCALL(phy_intr(struct net_device *ndev)); +static void phy_intr(struct net_device *ndev) { + struct ns83820 *dev = PRIV(ndev); static char *speeds[] = { "10", "100", "1000", "1000(?)", "1000F" }; u32 cfg, new_cfg; u32 tbisr, tanar, tanlpar; @@ -688,27 +700,28 @@ static void phy_intr(struct ns83820 *dev if (newlinkstate & LINK_UP && dev->linkstate != newlinkstate) { - netif_start_queue(&dev->net_dev); - netif_wake_queue(&dev->net_dev); + netif_start_queue(ndev); + netif_wake_queue(ndev); printk(KERN_INFO "%s: link now %s mbps, %s duplex and up.\n", - dev->net_dev.name, + ndev->name, speeds[speed], fullduplex ? "full" : "half"); } else if (newlinkstate & LINK_DOWN && dev->linkstate != newlinkstate) { - netif_stop_queue(&dev->net_dev); - printk(KERN_INFO "%s: link now down.\n", dev->net_dev.name); + netif_stop_queue(ndev); + printk(KERN_INFO "%s: link now down.\n", ndev->name); } dev->linkstate = newlinkstate; } -static int ns83820_setup_rx(struct ns83820 *dev) +static int ns83820_setup_rx(struct net_device *ndev) { + struct ns83820 *dev = PRIV(ndev); unsigned i; int ret; - dprintk("ns83820_setup_rx(%p)\n", dev); + dprintk("ns83820_setup_rx(%p)\n", ndev); dev->rx_info.idle = 1; dev->rx_info.next_rx = 0; @@ -721,7 +734,7 @@ static int ns83820_setup_rx(struct ns838 writel(0, dev->base + RXDP_HI); writel(dev->rx_info.phy_descs, dev->base + RXDP); - ret = rx_refill(dev, GFP_KERNEL); + ret = rx_refill(ndev, GFP_KERNEL); if (!ret) { dprintk("starting receiver\n"); /* prevent the interrupt handler from stomping on us */ @@ -734,7 +747,7 @@ static int ns83820_setup_rx(struct ns838 dev->rx_info.up = 1; - phy_intr(dev); + phy_intr(ndev); /* Okay, let it rip */ spin_lock_irq(&dev->misc_lock); @@ -753,7 +766,7 @@ static int ns83820_setup_rx(struct ns838 writel(1, dev->base + IER); spin_unlock_irq(&dev->misc_lock); - kick_rx(dev); + kick_rx(ndev); spin_unlock_irq(&dev->rx_info.lock); } @@ -793,37 +806,39 @@ static void ns83820_cleanup_rx(struct ns } } -static void FASTCALL(ns83820_rx_kick(struct ns83820 *dev)); -static void ns83820_rx_kick(struct ns83820 *dev) +static void FASTCALL(ns83820_rx_kick(struct net_device *ndev)); +static void ns83820_rx_kick(struct net_device *ndev) { + struct ns83820 *dev = PRIV(ndev); /*if (nr_rx_empty(dev) >= NR_RX_DESC/4)*/ { if (dev->rx_info.up) { - rx_refill_atomic(dev); - kick_rx(dev); + rx_refill_atomic(ndev); + kick_rx(ndev); } } if (dev->rx_info.up && nr_rx_empty(dev) > NR_RX_DESC*3/4) schedule_work(&dev->tq_refill); else - kick_rx(dev); + kick_rx(ndev); if (dev->rx_info.idle) - printk(KERN_DEBUG "%s: BAD\n", dev->net_dev.name); + printk(KERN_DEBUG "%s: BAD\n", ndev->name); } /* rx_irq * */ -static void FASTCALL(rx_irq(struct ns83820 *dev)); -static void rx_irq(struct ns83820 *dev) +static void FASTCALL(rx_irq(struct net_device *ndev)); +static void rx_irq(struct net_device *ndev) { + struct ns83820 *dev = PRIV(ndev); struct rx_info *info = &dev->rx_info; unsigned next_rx; u32 cmdsts, *desc; unsigned long flags; int nr = 0; - dprintk("rx_irq(%p)\n", dev); + dprintk("rx_irq(%p)\n", ndev); dprintk("rxdp: %08x, descs: %08lx next_rx[%d]: %p next_empty[%d]: %p\n", readl(dev->base + RXDP), (long)(dev->rx_info.phy_descs), @@ -873,7 +888,7 @@ static void rx_irq(struct ns83820 *dev) } else { skb->ip_summed = CHECKSUM_NONE; } - skb->protocol = eth_type_trans(skb, &dev->net_dev); + skb->protocol = eth_type_trans(skb, ndev); if (NET_RX_DROP == netif_rx(skb)) { netdev_mangle_me_harder_failed: dev->stats.rx_dropped ++; @@ -899,8 +914,9 @@ out: static void rx_action(unsigned long _dev) { - struct ns83820 *dev = (void *)_dev; - rx_irq(dev); + struct net_device *ndev = (void *)_dev; + struct ns83820 *dev = PRIV(ndev); + rx_irq(ndev); writel(ihr, dev->base + IHR); spin_lock_irq(&dev->misc_lock); @@ -908,8 +924,8 @@ static void rx_action(unsigned long _dev writel(dev->IMR_cache, dev->base + IMR); spin_unlock_irq(&dev->misc_lock); - rx_irq(dev); - ns83820_rx_kick(dev); + rx_irq(ndev); + ns83820_rx_kick(ndev); } /* Packet Transmit code @@ -924,13 +940,14 @@ static inline void kick_tx(struct ns8382 /* No spinlock needed on the transmit irq path as the interrupt handler is * serialized. */ -static void do_tx_done(struct ns83820 *dev) +static void do_tx_done(struct net_device *ndev) { + struct ns83820 *dev = PRIV(ndev); u32 cmdsts, tx_done_idx, *desc; spin_lock_irq(&dev->tx_lock); - dprintk("do_tx_done(%p)\n", dev); + dprintk("do_tx_done(%p)\n", ndev); tx_done_idx = dev->tx_done_idx; desc = dev->tx_descs + (tx_done_idx * DESC_SIZE); @@ -980,10 +997,10 @@ static void do_tx_done(struct ns83820 *d /* Allow network stack to resume queueing packets after we've * finished transmitting at least 1/4 of the packets in the queue. */ - if (netif_queue_stopped(&dev->net_dev) && start_tx_okay(dev)) { - dprintk("start_queue(%p)\n", dev); - netif_start_queue(&dev->net_dev); - netif_wake_queue(&dev->net_dev); + if (netif_queue_stopped(ndev) && start_tx_okay(dev)) { + dprintk("start_queue(%p)\n", ndev); + netif_start_queue(ndev); + netif_wake_queue(ndev); } spin_unlock_irq(&dev->tx_lock); } @@ -1015,9 +1032,9 @@ static void ns83820_cleanup_tx(struct ns * while trying to track down a bug in either the zero copy code or * the tx fifo (hence the MAX_FRAG_LEN). */ -static int ns83820_hard_start_xmit(struct sk_buff *skb, struct net_device *_dev) +static int ns83820_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) { - struct ns83820 *dev = (struct ns83820 *)_dev; + struct ns83820 *dev = PRIV(ndev); u32 free_idx, cmdsts, extsts; int nr_free, nr_frags; unsigned tx_done_idx, last_idx; @@ -1033,10 +1050,10 @@ static int ns83820_hard_start_xmit(struc nr_frags = skb_shinfo(skb)->nr_frags; again: if (unlikely(dev->CFG_cache & CFG_LNKSTS)) { - netif_stop_queue(&dev->net_dev); + netif_stop_queue(ndev); if (unlikely(dev->CFG_cache & CFG_LNKSTS)) return 1; - netif_start_queue(&dev->net_dev); + netif_start_queue(ndev); } last_idx = free_idx = dev->tx_free_idx; @@ -1044,13 +1061,13 @@ again: nr_free = (tx_done_idx + NR_TX_DESC-2 - free_idx) % NR_TX_DESC; nr_free -= 1; if (nr_free <= nr_frags) { - dprintk("stop_queue - not enough(%p)\n", dev); - netif_stop_queue(&dev->net_dev); + dprintk("stop_queue - not enough(%p)\n", ndev); + netif_stop_queue(ndev); /* Check again: we may have raced with a tx done irq */ if (dev->tx_done_idx != tx_done_idx) { - dprintk("restart queue(%p)\n", dev); - netif_start_queue(&dev->net_dev); + dprintk("restart queue(%p)\n", ndev); + netif_start_queue(ndev); goto again; } return 1; @@ -1063,8 +1080,8 @@ again: nr_free -= nr_frags; if (nr_free < MIN_TX_DESC_FREE) { - dprintk("stop_queue - last entry(%p)\n", dev); - netif_stop_queue(&dev->net_dev); + dprintk("stop_queue - last entry(%p)\n", ndev); + netif_stop_queue(ndev); stopped = 1; } @@ -1136,10 +1153,10 @@ again: /* Check again: we may have raced with a tx done irq */ if (stopped && (dev->tx_done_idx != tx_done_idx) && start_tx_okay(dev)) - netif_start_queue(&dev->net_dev); + netif_start_queue(ndev); /* set the transmit start time to catch transmit timeouts */ - dev->net_dev.trans_start = jiffies; + ndev->trans_start = jiffies; return 0; } @@ -1161,9 +1178,9 @@ static void ns83820_update_stats(struct dev->stats.tx_carrier_errors += readl(base + 0x88) & 0xff; } -static struct net_device_stats *ns83820_get_stats(struct net_device *_dev) +static struct net_device_stats *ns83820_get_stats(struct net_device *ndev) { - struct ns83820 *dev = (void *)_dev; + struct ns83820 *dev = PRIV(ndev); /* somewhat overkill */ spin_lock_irq(&dev->misc_lock); @@ -1213,9 +1230,9 @@ static int ns83820_ethtool_ioctl (struct return -EOPNOTSUPP; } -static int ns83820_ioctl(struct net_device *_dev, struct ifreq *rq, int cmd) +static int ns83820_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) { - struct ns83820 *dev = (struct ns83820 *)_dev; + struct ns83820 *dev = PRIV(ndev); switch(cmd) { case SIOCETHTOOL: @@ -1233,23 +1250,25 @@ static void ns83820_mib_isr(struct ns838 spin_unlock(&dev->misc_lock); } -static void ns83820_do_isr(struct ns83820 *dev, u32 isr); +static void ns83820_do_isr(struct net_device *ndev, u32 isr); static irqreturn_t ns83820_irq(int foo, void *data, struct pt_regs *regs) { - struct ns83820 *dev = data; + struct net_device *ndev = data; + struct ns83820 *dev = PRIV(ndev); u32 isr; - dprintk("ns83820_irq(%p)\n", dev); + dprintk("ns83820_irq(%p)\n", ndev); dev->ihr = 0; isr = readl(dev->base + ISR); dprintk("irq: %08x\n", isr); - ns83820_do_isr(dev, isr); + ns83820_do_isr(ndev, isr); return IRQ_HANDLED; } -static void ns83820_do_isr(struct ns83820 *dev, u32 isr) +static void ns83820_do_isr(struct net_device *ndev, u32 isr) { + struct ns83820 *dev = PRIV(ndev); #ifdef DEBUG if (isr & ~(ISR_PHY | ISR_RXDESC | ISR_RXEARLY | ISR_RXOK | ISR_RXERR | ISR_TXIDLE | ISR_TXOK | ISR_TXDESC)) Dprintk("odd isr? 0x%08x\n", isr); @@ -1258,7 +1277,7 @@ static void ns83820_do_isr(struct ns8382 if (ISR_RXIDLE & isr) { dev->rx_info.idle = 1; Dprintk("oh dear, we are idle\n"); - ns83820_rx_kick(dev); + ns83820_rx_kick(ndev); } if ((ISR_RXDESC | ISR_RXOK) & isr) { @@ -1270,12 +1289,12 @@ static void ns83820_do_isr(struct ns8382 spin_unlock_irq(&dev->misc_lock); tasklet_schedule(&dev->rx_tasklet); - //rx_irq(dev); + //rx_irq(ndev); //writel(4, dev->base + IHR); } if ((ISR_RXIDLE | ISR_RXORN | ISR_RXDESC | ISR_RXOK | ISR_RXERR) & isr) - ns83820_rx_kick(dev); + ns83820_rx_kick(ndev); if (unlikely(ISR_RXSOVR & isr)) { //printk("overrun: rxsovr\n"); @@ -1297,7 +1316,7 @@ static void ns83820_do_isr(struct ns8382 txdp -= dev->tx_phy_descs; dev->tx_idx = txdp / (DESC_SIZE * 4); if (dev->tx_idx >= NR_TX_DESC) { - printk(KERN_ALERT "%s: BUG -- txdp out of range\n", dev->net_dev.name); + printk(KERN_ALERT "%s: BUG -- txdp out of range\n", ndev->name); dev->tx_idx = 0; } /* The may have been a race between a pci originated read @@ -1313,7 +1332,7 @@ static void ns83820_do_isr(struct ns8382 * work has accumulated */ if ((ISR_TXDESC | ISR_TXIDLE | ISR_TXOK | ISR_TXERR) & isr) { - do_tx_done(dev); + do_tx_done(ndev); /* Disable TxOk if there are no outstanding tx packets. */ @@ -1345,7 +1364,7 @@ static void ns83820_do_isr(struct ns8382 /* PHY: Link up/down/negotiation state change */ if (unlikely(ISR_PHY & isr)) - phy_intr(dev); + phy_intr(ndev); #if 0 /* Still working on the interrupt mitigation strategy */ if (dev->ihr) @@ -1363,9 +1382,9 @@ static void ns83820_do_reset(struct ns83 Dprintk("okay!\n"); } -static int ns83820_stop(struct net_device *_dev) +static int ns83820_stop(struct net_device *ndev) { - struct ns83820 *dev = (struct ns83820 *)_dev; + struct ns83820 *dev = PRIV(ndev); /* FIXME: protect against interrupt handler? */ del_timer_sync(&dev->tx_watchdog); @@ -1392,10 +1411,9 @@ static int ns83820_stop(struct net_devic return 0; } -static void ns83820_do_isr(struct ns83820 *dev, u32 isr); -static void ns83820_tx_timeout(struct net_device *_dev) +static void ns83820_tx_timeout(struct net_device *ndev) { - struct ns83820 *dev = (struct ns83820 *)_dev; + struct ns83820 *dev = PRIV(ndev); u32 tx_done_idx, *desc; unsigned long flags; @@ -1405,7 +1423,7 @@ static void ns83820_tx_timeout(struct ne desc = dev->tx_descs + (tx_done_idx * DESC_SIZE); printk(KERN_INFO "%s: tx_timeout: tx_done_idx=%d free_idx=%d cmdsts=%08x\n", - dev->net_dev.name, + ndev->name, tx_done_idx, dev->tx_free_idx, le32_to_cpu(desc[DESC_CMDSTS])); #if defined(DEBUG) @@ -1413,17 +1431,17 @@ static void ns83820_tx_timeout(struct ne u32 isr; isr = readl(dev->base + ISR); printk("irq: %08x imr: %08x\n", isr, dev->IMR_cache); - ns83820_do_isr(dev, isr); + ns83820_do_isr(ndev, isr); } #endif - do_tx_done(dev); + do_tx_done(ndev); tx_done_idx = dev->tx_done_idx; desc = dev->tx_descs + (tx_done_idx * DESC_SIZE); printk(KERN_INFO "%s: after: tx_done_idx=%d free_idx=%d cmdsts=%08x\n", - dev->net_dev.name, + ndev->name, tx_done_idx, dev->tx_free_idx, le32_to_cpu(desc[DESC_CMDSTS])); local_irq_restore(flags); @@ -1431,7 +1449,8 @@ static void ns83820_tx_timeout(struct ne static void ns83820_tx_watch(unsigned long data) { - struct ns83820 *dev = (void *)data; + struct net_device *ndev = (void *)data; + struct ns83820 *dev = PRIV(ndev); #if defined(DEBUG) printk("ns83820_tx_watch: %u %u %d\n", @@ -1439,21 +1458,21 @@ static void ns83820_tx_watch(unsigned lo ); #endif - if (time_after(jiffies, dev->net_dev.trans_start + 1*HZ) && + if (time_after(jiffies, ndev->trans_start + 1*HZ) && dev->tx_done_idx != dev->tx_free_idx) { printk(KERN_DEBUG "%s: ns83820_tx_watch: %u %u %d\n", - dev->net_dev.name, + ndev->name, dev->tx_done_idx, dev->tx_free_idx, atomic_read(&dev->nr_tx_skbs)); - ns83820_tx_timeout(&dev->net_dev); + ns83820_tx_timeout(ndev); } mod_timer(&dev->tx_watchdog, jiffies + 2*HZ); } -static int ns83820_open(struct net_device *_dev) +static int ns83820_open(struct net_device *ndev) { - struct ns83820 *dev = (struct ns83820 *)_dev; + struct ns83820 *dev = PRIV(ndev); unsigned i; u32 desc; int ret; @@ -1462,7 +1481,7 @@ static int ns83820_open(struct net_devic writel(0, dev->base + PQCR); - ret = ns83820_setup_rx(dev); + ret = ns83820_setup_rx(ndev); if (ret) goto failed; @@ -1481,16 +1500,16 @@ static int ns83820_open(struct net_devic writel(desc, dev->base + TXDP); init_timer(&dev->tx_watchdog); - dev->tx_watchdog.data = (unsigned long)dev; + dev->tx_watchdog.data = (unsigned long)ndev; dev->tx_watchdog.function = ns83820_tx_watch; mod_timer(&dev->tx_watchdog, jiffies + 2*HZ); - netif_start_queue(&dev->net_dev); /* FIXME: wait for phy to come up */ + netif_start_queue(ndev); /* FIXME: wait for phy to come up */ return 0; failed: - ns83820_stop(_dev); + ns83820_stop(ndev); return ret; } @@ -1513,28 +1532,28 @@ static void ns83820_getmac(struct ns8382 } } -static int ns83820_change_mtu(struct net_device *_dev, int new_mtu) +static int ns83820_change_mtu(struct net_device *ndev, int new_mtu) { if (new_mtu > RX_BUF_SIZE) return -EINVAL; - _dev->mtu = new_mtu; + ndev->mtu = new_mtu; return 0; } -static void ns83820_set_multicast(struct net_device *_dev) +static void ns83820_set_multicast(struct net_device *ndev) { - struct ns83820 *dev = (void *)_dev; + struct ns83820 *dev = PRIV(ndev); u8 *rfcr = dev->base + RFCR; u32 and_mask = 0xffffffff; u32 or_mask = 0; u32 val; - if (dev->net_dev.flags & IFF_PROMISC) + if (ndev->flags & IFF_PROMISC) or_mask |= RFCR_AAU | RFCR_AAM; else and_mask &= ~(RFCR_AAU | RFCR_AAM); - if (dev->net_dev.flags & IFF_ALLMULTI) + if (ndev->flags & IFF_ALLMULTI) or_mask |= RFCR_AAM; else and_mask &= ~RFCR_AAM; @@ -1547,14 +1566,15 @@ static void ns83820_set_multicast(struct spin_unlock_irq(&dev->misc_lock); } -static void ns83820_run_bist(struct ns83820 *dev, const char *name, u32 enable, u32 done, u32 fail) +static void ns83820_run_bist(struct net_device *ndev, const char *name, u32 enable, u32 done, u32 fail) { + struct ns83820 *dev = PRIV(ndev); int timed_out = 0; long start; u32 status; int loops = 0; - dprintk("%s: start %s\n", dev->net_dev.name, name); + dprintk("%s: start %s\n", ndev->name, name); start = jiffies; @@ -1578,12 +1598,12 @@ static void ns83820_run_bist(struct ns83 if (status & fail) printk(KERN_INFO "%s: %s failed! (0x%08x & 0x%08x)\n", - dev->net_dev.name, name, status, fail); + ndev->name, name, status, fail); else if (timed_out) printk(KERN_INFO "%s: run_bist %s timed out! (%08x)\n", - dev->net_dev.name, name, status); + ndev->name, name, status); - dprintk("%s: done %s in %d loops\n", dev->net_dev.name, name, loops); + dprintk("%s: done %s in %d loops\n", ndev->name, name, loops); } #ifdef PHY_CODE_IS_FINISHED @@ -1706,8 +1726,9 @@ static unsigned ns83820_mii_write_reg(st return data; } -static void ns83820_probe_phy(struct ns83820 *dev) +static void ns83820_probe_phy(struct net_device *ndev) { + struct ns83820 *dev = PRIV(ndev); static int first; int i; #define MII_PHYIDR1 0x02 @@ -1734,11 +1755,11 @@ static void ns83820_probe_phy(struct ns8 b = ns83820_mii_read_reg(dev, i, MII_PHYIDR2); //printk("%s: phy %d: 0x%04x 0x%04x\n", - // dev->net_dev.name, i, a, b); + // ndev->name, i, a, b); for (j=0; j<0x16; j+=4) { dprintk("%s: [0x%02x] %04x %04x %04x %04x\n", - dev->net_dev.name, j, + ndev->name, j, ns83820_mii_read_reg(dev, i, 0 + j), ns83820_mii_read_reg(dev, i, 1 + j), ns83820_mii_read_reg(dev, i, 2 + j), @@ -1763,6 +1784,7 @@ static void ns83820_probe_phy(struct ns8 static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_device_id *id) { + struct net_device *ndev; struct ns83820 *dev; long addr; int err; @@ -1778,7 +1800,8 @@ static int __devinit ns83820_init_one(st return -ENODEV; } - dev = (struct ns83820 *)alloc_etherdev((sizeof *dev) - (sizeof dev->net_dev)); + ndev = alloc_etherdev(sizeof(struct ns83820)); + dev = PRIV(ndev); err = -ENOMEM; if (!dev) goto out; @@ -1790,12 +1813,11 @@ static int __devinit ns83820_init_one(st dev->ee.cache = &dev->MEAR_cache; dev->ee.lock = &dev->misc_lock; - SET_MODULE_OWNER(dev->net_dev); - SET_NETDEV_DEV(&dev->net_dev, &pci_dev->dev); - dev->net_dev.priv = dev; + SET_MODULE_OWNER(ndev); + SET_NETDEV_DEV(ndev, &pci_dev->dev); - INIT_WORK(&dev->tq_refill, queue_refill, dev); - tasklet_init(&dev->rx_tasklet, rx_action, (unsigned long)dev); + INIT_WORK(&dev->tq_refill, queue_refill, ndev); + tasklet_init(&dev->rx_tasklet, rx_action, (unsigned long)ndev); err = pci_enable_device(pci_dev); if (err) { @@ -1829,55 +1851,63 @@ static int __devinit ns83820_init_one(st 0); err = request_irq(pci_dev->irq, ns83820_irq, SA_SHIRQ, - dev->net_dev.name, dev); + ndev->name, ndev); if (err) { printk(KERN_INFO "ns83820: unable to register irq %d\n", pci_dev->irq); goto out_disable; } - err = register_netdev(&dev->net_dev); - if (err) { - printk(KERN_INFO "ns83820: unable to register netdev: %d\n", err); + /* + * FIXME: we are holding rtnl_lock() over obscenely long area only + * because some of the setup code uses dev->name. It's Wrong(tm) - + * we should be using driver-specific names for all that stuff. + * For now that will do, but we really need to come back and kill + * most of the dev_alloc_name() users later. + */ + rtnl_lock(); + err = dev_alloc_name(ndev, ndev->name); + if (err < 0) { + printk(KERN_INFO "ns83820: unable to get netdev name: %d\n", err); goto out_free_irq; } printk("%s: ns83820.c: 0x22c: %08x, subsystem: %04x:%04x\n", - dev->net_dev.name, le32_to_cpu(readl(dev->base + 0x22c)), + ndev->name, le32_to_cpu(readl(dev->base + 0x22c)), pci_dev->subsystem_vendor, pci_dev->subsystem_device); - dev->net_dev.open = ns83820_open; - dev->net_dev.stop = ns83820_stop; - dev->net_dev.hard_start_xmit = ns83820_hard_start_xmit; - dev->net_dev.get_stats = ns83820_get_stats; - dev->net_dev.change_mtu = ns83820_change_mtu; - dev->net_dev.set_multicast_list = ns83820_set_multicast; - dev->net_dev.do_ioctl = ns83820_ioctl; - dev->net_dev.tx_timeout = ns83820_tx_timeout; - dev->net_dev.watchdog_timeo = 5 * HZ; + ndev->open = ns83820_open; + ndev->stop = ns83820_stop; + ndev->hard_start_xmit = ns83820_hard_start_xmit; + ndev->get_stats = ns83820_get_stats; + ndev->change_mtu = ns83820_change_mtu; + ndev->set_multicast_list = ns83820_set_multicast; + ndev->do_ioctl = ns83820_ioctl; + ndev->tx_timeout = ns83820_tx_timeout; + ndev->watchdog_timeo = 5 * HZ; - pci_set_drvdata(pci_dev, dev); + pci_set_drvdata(pci_dev, ndev); ns83820_do_reset(dev, CR_RST); /* Must reset the ram bist before running it */ writel(PTSCR_RBIST_RST, dev->base + PTSCR); - ns83820_run_bist(dev, "sram bist", PTSCR_RBIST_EN, + ns83820_run_bist(ndev, "sram bist", PTSCR_RBIST_EN, PTSCR_RBIST_DONE, PTSCR_RBIST_FAIL); - ns83820_run_bist(dev, "eeprom bist", PTSCR_EEBIST_EN, 0, + ns83820_run_bist(ndev, "eeprom bist", PTSCR_EEBIST_EN, 0, PTSCR_EEBIST_FAIL); - ns83820_run_bist(dev, "eeprom load", PTSCR_EELOAD_EN, 0, 0); + ns83820_run_bist(ndev, "eeprom load", PTSCR_EELOAD_EN, 0, 0); /* I love config registers */ dev->CFG_cache = readl(dev->base + CFG); if ((dev->CFG_cache & CFG_PCI64_DET)) { printk(KERN_INFO "%s: detected 64 bit PCI data bus.\n", - dev->net_dev.name); + ndev->name); /*dev->CFG_cache |= CFG_DATA64_EN;*/ if (!(dev->CFG_cache & CFG_DATA64_EN)) printk(KERN_INFO "%s: EEPROM did not enable 64 bit bus. Disabled.\n", - dev->net_dev.name); + ndev->name); } else dev->CFG_cache &= ~(CFG_DATA64_EN); @@ -1905,7 +1935,7 @@ static int __devinit ns83820_init_one(st /* setup optical transceiver if we have one */ if (dev->CFG_cache & CFG_TBI_EN) { printk(KERN_INFO "%s: enabling optical transceiver\n", - dev->net_dev.name); + ndev->name); writel(readl(dev->base + GPIOR) | 0x3e8, dev->base + GPIOR); /* setup auto negotiation feature advertisement */ @@ -1926,7 +1956,7 @@ static int __devinit ns83820_init_one(st dprintk("CFG: %08x\n", dev->CFG_cache); if (reset_phy) { - printk(KERN_INFO "%s: resetting phy\n", dev->net_dev.name); + printk(KERN_INFO "%s: resetting phy\n", ndev->name); writel(dev->CFG_cache | CFG_PHY_RST, dev->base + CFG); set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((HZ+99)/100); @@ -1996,37 +2026,49 @@ static int __devinit ns83820_init_one(st /* Disable Wake On Lan */ writel(0, dev->base + WCSR); - ns83820_getmac(dev, dev->net_dev.dev_addr); + ns83820_getmac(dev, ndev->dev_addr); /* Yes, we support dumb IP checksum on transmit */ - dev->net_dev.features |= NETIF_F_SG; - dev->net_dev.features |= NETIF_F_IP_CSUM; + ndev->features |= NETIF_F_SG; + ndev->features |= NETIF_F_IP_CSUM; if (using_dac) { printk(KERN_INFO "%s: using 64 bit addressing.\n", - dev->net_dev.name); - dev->net_dev.features |= NETIF_F_HIGHDMA; + ndev->name); + ndev->features |= NETIF_F_HIGHDMA; } printk(KERN_INFO "%s: ns83820 v" VERSION ": DP83820 v%u.%u: %02x:%02x:%02x:%02x:%02x:%02x io=0x%08lx irq=%d f=%s\n", - dev->net_dev.name, + ndev->name, (unsigned)readl(dev->base + SRR) >> 8, (unsigned)readl(dev->base + SRR) & 0xff, - dev->net_dev.dev_addr[0], dev->net_dev.dev_addr[1], - dev->net_dev.dev_addr[2], dev->net_dev.dev_addr[3], - dev->net_dev.dev_addr[4], dev->net_dev.dev_addr[5], + ndev->dev_addr[0], ndev->dev_addr[1], + ndev->dev_addr[2], ndev->dev_addr[3], + ndev->dev_addr[4], ndev->dev_addr[5], addr, pci_dev->irq, - (dev->net_dev.features & NETIF_F_HIGHDMA) ? "h,sg" : "sg" + (ndev->features & NETIF_F_HIGHDMA) ? "h,sg" : "sg" ); #ifdef PHY_CODE_IS_FINISHED - ns83820_probe_phy(dev); + ns83820_probe_phy(ndev); #endif + err = register_netdevice(ndev); + if (err) { + printk(KERN_INFO "ns83820: unable to register netdev: %d\n", err); + goto out_cleanup; + } + rtnl_unlock(); + return 0; +out_cleanup: + writel(0, dev->base + IMR); /* paranoia */ + writel(0, dev->base + IER); + readl(dev->base + IER); out_free_irq: - free_irq(pci_dev->irq, dev); + rtnl_unlock(); + free_irq(pci_dev->irq, ndev); out_disable: if (dev->base) iounmap(dev->base); @@ -2034,7 +2076,7 @@ out_disable: pci_free_consistent(pci_dev, 4 * DESC_SIZE * NR_RX_DESC, dev->rx_info.descs, dev->rx_info.phy_descs); pci_disable_device(pci_dev); out_free: - kfree(dev); + free_netdev(ndev); pci_set_drvdata(pci_dev, NULL); out: return err; @@ -2042,24 +2084,25 @@ out: static void __devexit ns83820_remove_one(struct pci_dev *pci_dev) { - struct ns83820 *dev = pci_get_drvdata(pci_dev); + struct net_device *ndev = pci_get_drvdata(pci_dev); + struct ns83820 *dev = PRIV(ndev); /* ok even if NULL */ - if (!dev) /* paranoia */ + if (!ndev) /* paranoia */ return; writel(0, dev->base + IMR); /* paranoia */ writel(0, dev->base + IER); readl(dev->base + IER); - unregister_netdev(&dev->net_dev); - free_irq(dev->pci_dev->irq, dev); + unregister_netdev(ndev); + free_irq(dev->pci_dev->irq, ndev); iounmap(dev->base); pci_free_consistent(dev->pci_dev, 4 * DESC_SIZE * NR_TX_DESC, dev->tx_descs, dev->tx_phy_descs); pci_free_consistent(dev->pci_dev, 4 * DESC_SIZE * NR_RX_DESC, dev->rx_info.descs, dev->rx_info.phy_descs); pci_disable_device(dev->pci_dev); - free_netdev(&dev->net_dev); + free_netdev(ndev); pci_set_drvdata(pci_dev, NULL); } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/oaknet.c 830-ivtv/drivers/net/oaknet.c --- 000-virgin/drivers/net/oaknet.c Tue Sep 2 09:55:47 2003 +++ 830-ivtv/drivers/net/oaknet.c Thu Jan 8 08:54:19 2004 @@ -94,8 +94,8 @@ static int __init oaknet_init(void) { register int i; int reg0, regd; - int ret; - struct net_device tmp, *dev = NULL; + int ret = -ENOMEM; + struct net_device *dev; #if 0 unsigned long ioaddr = OAKNET_IO_BASE; #else @@ -105,17 +105,14 @@ static int __init oaknet_init(void) if (!ioaddr) return -ENOMEM; - /* - * This MUST happen here because of the nic_* macros - * which have an implicit dependency on dev->base_addr. - */ - tmp.base_addr = ioaddr; - dev = &tmp; + dev = alloc_ei_netdev(); + if (!dev) + goto out_unmap; ret = -EBUSY; if (!request_region(OAKNET_IO_BASE, OAKNET_IO_SIZE, name)) - goto out_unmap; + goto out_dev; /* Quick register check to see if the device is really there. */ @@ -144,17 +141,7 @@ static int __init oaknet_init(void) goto out_region; } - /* - * We're not using the old-style probing API, so we have to allocate - * our own device structure. - */ - - dev = init_etherdev(NULL, 0); - ret = -ENOMEM; - if (!dev) - goto out_region; SET_MODULE_OWNER(dev); - oaknet_devs = dev; /* * This controller is on an embedded board, so the base address @@ -164,14 +151,6 @@ static int __init oaknet_init(void) dev->base_addr = ioaddr; dev->irq = OAKNET_INT; - /* Allocate 8390-specific device-private area and fields. */ - - ret = -ENOMEM; - if (ethdev_init(dev)) { - printk(" unable to get memory for dev->priv.\n"); - goto out_dev; - } - /* * Disable all chip interrupts for now and ACK all pending * interrupts. @@ -186,7 +165,7 @@ static int __init oaknet_init(void) if (request_irq(dev->irq, ei_interrupt, 0, name, dev)) { printk("%s: unable to request interrupt %d.\n", dev->name, dev->irq); - goto out_priv; + goto out_region; } /* Tell the world about what and where we've found. */ @@ -215,15 +194,19 @@ static int __init oaknet_init(void) dev->stop = oaknet_close; NS8390_init(dev, FALSE); + ret = register_netdev(dev); + if (ret) + goto out_irq; + + oaknet_devs = dev; + return 0; - return (0); -out_priv: - kfree(dev->priv); -out_dev: - unregister_netdev(dev); - kfree(dev); +out_irq; + free_irq(dev->irq, dev); out_region: release_region(OAKNET_IO_BASE, OAKNET_IO_SIZE); +out_dev: + free_netdev(dev); out_unmap: iounmap(ioaddr); return ret; @@ -662,38 +645,18 @@ oaknet_dma_error(struct net_device *dev, } /* - * Oak Ethernet module load interface. - */ -static int __init oaknet_init_module (void) -{ - if (oaknet_devs != NULL) - return (-EBUSY); - - return (oaknet_init()); -} - -/* * Oak Ethernet module unload interface. */ static void __exit oaknet_cleanup_module (void) { - if (oaknet_devs == NULL) - return; - - if (oaknet_devs->priv != NULL) { - int ioaddr = oaknet_devs->base_addr; - void *priv = oaknet_devs->priv; - free_irq(oaknet_devs->irq, oaknet_devs); - release_region(ioaddr, OAKNET_IO_SIZE); - iounmap(ioaddr); - unregister_netdev(oaknet_dev); - free_netdev(priv); - } - /* Convert to loop once driver supports multiple devices. */ - kfree(oaknet_devs); + unregister_netdev(oaknet_dev); + free_irq(oaknet_devs->irq, oaknet_devs); + release_region(oaknet_devs->base_addr, OAKNET_IO_SIZE); + iounmap(ioaddr); + free_netdev(oaknet_devs); } -module_init(oaknet_init_module); +module_init(oaknet_init); module_exit(oaknet_cleanup_module); MODULE_LICENSE("GPL"); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/pci-skeleton.c 830-ivtv/drivers/net/pci-skeleton.c --- 000-virgin/drivers/net/pci-skeleton.c Wed Dec 24 18:16:47 2003 +++ 830-ivtv/drivers/net/pci-skeleton.c Thu Jan 8 08:54:19 2004 @@ -730,7 +730,7 @@ err_out_free_res: #endif pci_release_regions (pdev); err_out: - kfree (dev); + free_netdev (dev); DPRINTK ("EXIT, returning %d\n", rc); return rc; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/pcmcia/3c574_cs.c 830-ivtv/drivers/net/pcmcia/3c574_cs.c --- 000-virgin/drivers/net/pcmcia/3c574_cs.c Thu Jan 8 08:35:38 2004 +++ 830-ivtv/drivers/net/pcmcia/3c574_cs.c Thu Jan 8 08:54:19 2004 @@ -362,23 +362,17 @@ static void tc574_detach(dev_link_t *lin if (*linkp == NULL) return; - if (link->state & DEV_CONFIG) { + if (link->state & DEV_CONFIG) tc574_release(link); - if (link->state & DEV_STALE_CONFIG) - return; - } if (link->handle) CardServices(DeregisterClient, link->handle); /* Unlink device structure, free bits */ *linkp = link->next; - if (link->dev) { + if (link->dev) unregister_netdev(dev); - free_netdev(dev); - } else - kfree(dev); - + free_netdev(dev); } /* tc574_detach */ /* @@ -557,21 +551,11 @@ static void tc574_release(dev_link_t *li { DEBUG(0, "3c574_release(0x%p)\n", link); - if (link->open) { - DEBUG(1, "3c574_cs: release postponed, '%s' still open\n", - link->dev->dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } - CardServices(ReleaseConfiguration, link->handle); CardServices(ReleaseIO, link->handle, &link->io); CardServices(ReleaseIRQ, link->handle, &link->irq); link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_CONFIG) - tc574_detach(link); } /* @@ -1300,8 +1284,7 @@ static int el3_close(struct net_device * link->open--; netif_stop_queue(dev); del_timer_sync(&lp->media); - if (link->state & DEV_STALE_CONFIG) - tc574_release(link); + return 0; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/pcmcia/3c589_cs.c 830-ivtv/drivers/net/pcmcia/3c589_cs.c --- 000-virgin/drivers/net/pcmcia/3c589_cs.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/pcmcia/3c589_cs.c Thu Jan 8 08:54:19 2004 @@ -276,23 +276,17 @@ static void tc589_detach(dev_link_t *lin if (*linkp == NULL) return; - if (link->state & DEV_CONFIG) { + if (link->state & DEV_CONFIG) tc589_release(link); - if (link->state & DEV_STALE_CONFIG) - return; - } if (link->handle) CardServices(DeregisterClient, link->handle); /* Unlink device structure, free bits */ *linkp = link->next; - if (link->dev) { + if (link->dev) unregister_netdev(dev); - free_netdev(dev); - } else - kfree(dev); - + free_netdev(dev); } /* tc589_detach */ /*====================================================================== @@ -433,21 +427,11 @@ static void tc589_release(dev_link_t *li { DEBUG(0, "3c589_release(0x%p)\n", link); - if (link->open) { - DEBUG(1, "3c589_cs: release postponed, '%s' still open\n", - link->dev->dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } - CardServices(ReleaseConfiguration, link->handle); CardServices(ReleaseIO, link->handle, &link->io); CardServices(ReleaseIRQ, link->handle, &link->irq); link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_CONFIG) - tc589_detach(link); } /*====================================================================== @@ -1076,8 +1060,6 @@ static int el3_close(struct net_device * link->open--; netif_stop_queue(dev); del_timer_sync(&lp->media); - if (link->state & DEV_STALE_CONFIG) - tc589_release(link); return 0; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/pcmcia/Kconfig 830-ivtv/drivers/net/pcmcia/Kconfig --- 000-virgin/drivers/net/pcmcia/Kconfig Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/pcmcia/Kconfig Thu Jan 8 10:20:07 2004 @@ -119,7 +119,7 @@ config ARCNET_COM20020_CS config PCMCIA_IBMTR tristate "IBM PCMCIA tokenring adapter support" - depends on NET_PCMCIA && IBMTR!=y && TR && PCMCIA + depends on NET_PCMCIA && IBMTR!=y && TR && PCMCIA && !64BIT help Say Y here if you intend to attach this type of Token Ring PCMCIA card to your computer. You then also need to say Y to "Token Ring diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/pcmcia/axnet_cs.c 830-ivtv/drivers/net/pcmcia/axnet_cs.c --- 000-virgin/drivers/net/pcmcia/axnet_cs.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/pcmcia/axnet_cs.c Thu Jan 8 08:54:19 2004 @@ -119,7 +119,7 @@ static void axnet_detach(dev_link_t *); static dev_info_t dev_info = "axnet_cs"; static dev_link_t *dev_list; -static int axdev_init(struct net_device *dev); +static void axdev_setup(struct net_device *dev); static void AX88190_init(struct net_device *dev, int startp); static int ax_open(struct net_device *dev); static int ax_close(struct net_device *dev); @@ -128,7 +128,6 @@ static irqreturn_t ax_interrupt(int irq, /*====================================================================*/ typedef struct axnet_dev_t { - struct net_device dev; /* so &dev == &axnet_dev_t */ dev_link_t link; dev_node_t node; caddr_t base; @@ -140,16 +139,10 @@ typedef struct axnet_dev_t { int flags; } axnet_dev_t; -/*====================================================================== - - We never need to do anything when a axnet device is "initialized" - by the net software, because we only register already-found cards. - -======================================================================*/ - -static int axnet_init(struct net_device *dev) +static inline axnet_dev_t *PRIV(struct net_device *dev) { - return 0; + void *p = (char *)netdev_priv(dev) + sizeof(struct ei_device); + return p; } /*====================================================================== @@ -170,12 +163,15 @@ static dev_link_t *axnet_attach(void) DEBUG(0, "axnet_attach()\n"); - /* Create new ethernet device */ - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) return NULL; - memset(info, 0, sizeof(*info)); - link = &info->link; dev = &info->dev; - link->priv = info; + dev = alloc_netdev(sizeof(struct ei_device) + sizeof(axnet_dev_t), + "eth%d", axdev_setup); + + if (!dev) + return NULL; + + info = PRIV(dev); + link = &info->link; + link->priv = dev; link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; if (irq_list[0] == -1) @@ -186,8 +182,6 @@ static dev_link_t *axnet_attach(void) link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; - axdev_init(dev); - dev->init = &axnet_init; dev->open = &axnet_open; dev->stop = &axnet_close; dev->do_ioctl = &axnet_ioctl; @@ -226,7 +220,7 @@ static dev_link_t *axnet_attach(void) static void axnet_detach(dev_link_t *link) { - axnet_dev_t *info = link->priv; + struct net_device *dev = link->priv; dev_link_t **linkp; DEBUG(0, "axnet_detach(0x%p)\n", link); @@ -237,23 +231,17 @@ static void axnet_detach(dev_link_t *lin if (*linkp == NULL) return; - if (link->state & DEV_CONFIG) { + if (link->state & DEV_CONFIG) axnet_release(link); - if (link->state & DEV_STALE_CONFIG) - return; - } if (link->handle) CardServices(DeregisterClient, link->handle); /* Unlink device structure, free bits */ *linkp = link->next; - if (link->dev) { - unregister_netdev(&info->dev); - free_netdev(&info->dev); - } else - kfree(info); - + if (link->dev) + unregister_netdev(dev); + free_netdev(dev); } /* axnet_detach */ /*====================================================================== @@ -352,8 +340,8 @@ static int try_io_port(dev_link_t *link) static void axnet_config(dev_link_t *link) { client_handle_t handle = link->handle; - axnet_dev_t *info = link->priv; - struct net_device *dev = &info->dev; + struct net_device *dev = link->priv; + axnet_dev_t *info = PRIV(dev); tuple_t tuple; cisparse_t parse; int i, j, last_ret, last_fn; @@ -428,15 +416,10 @@ static void axnet_config(dev_link_t *lin CS_CHECK(RequestConfiguration, handle, &link->conf); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; - if (register_netdev(dev) != 0) { - printk(KERN_NOTICE "axnet_cs: register_netdev() failed\n"); - goto failed; - } if (!get_prom(link)) { printk(KERN_NOTICE "axnet_cs: this is not an AX88190 card!\n"); printk(KERN_NOTICE "axnet_cs: use pcnet_cs instead.\n"); - unregister_netdev(dev); goto failed; } @@ -451,7 +434,6 @@ static void axnet_config(dev_link_t *lin ei_status.block_output = &block_output; strcpy(info->node.dev_name, dev->name); - link->dev = &info->node; if (inb(dev->base_addr + AXNET_TEST) != 0) info->flags |= IS_AX88790; @@ -490,6 +472,12 @@ static void axnet_config(dev_link_t *lin printk(KERN_NOTICE " No MII transceivers found!\n"); } + if (register_netdev(dev) != 0) { + printk(KERN_NOTICE "axnet_cs: register_netdev() failed\n"); + goto failed; + } + + link->dev = &info->node; link->state &= ~DEV_CONFIG_PENDING; return; @@ -513,21 +501,11 @@ static void axnet_release(dev_link_t *li { DEBUG(0, "axnet_release(0x%p)\n", link); - if (link->open) { - DEBUG(1, "axnet_cs: release postponed, '%s' still open\n", - ((axnet_dev_t *)(link->priv))->node.dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } - CardServices(ReleaseConfiguration, link->handle); CardServices(ReleaseIO, link->handle, &link->io); CardServices(ReleaseIRQ, link->handle, &link->irq); link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_CONFIG) - axnet_detach(link); } /*====================================================================== @@ -543,7 +521,7 @@ static int axnet_event(event_t event, in event_callback_args_t *args) { dev_link_t *link = args->client_data; - axnet_dev_t *info = link->priv; + struct net_device *dev = link->priv; DEBUG(2, "axnet_event(0x%06x)\n", event); @@ -551,7 +529,7 @@ static int axnet_event(event_t event, in case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { - netif_device_detach(&info->dev); + netif_device_detach(dev); axnet_release(link); } break; @@ -565,7 +543,7 @@ static int axnet_event(event_t event, in case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { if (link->open) - netif_device_detach(&info->dev); + netif_device_detach(dev); CardServices(ReleaseConfiguration, link->handle); } break; @@ -576,9 +554,9 @@ static int axnet_event(event_t event, in if (link->state & DEV_CONFIG) { CardServices(RequestConfiguration, link->handle, &link->conf); if (link->open) { - axnet_reset_8390(&info->dev); - AX88190_init(&info->dev, 1); - netif_device_attach(&info->dev); + axnet_reset_8390(dev); + AX88190_init(dev, 1); + netif_device_attach(dev); } } break; @@ -648,7 +626,7 @@ static void mdio_write(ioaddr_t addr, in static int axnet_open(struct net_device *dev) { - axnet_dev_t *info = (axnet_dev_t *)dev; + axnet_dev_t *info = PRIV(dev); dev_link_t *link = &info->link; DEBUG(2, "axnet_open('%s')\n", dev->name); @@ -663,7 +641,7 @@ static int axnet_open(struct net_device info->link_status = 0x00; init_timer(&info->watchdog); info->watchdog.function = &ei_watchdog; - info->watchdog.data = (u_long)info; + info->watchdog.data = (u_long)dev; info->watchdog.expires = jiffies + HZ; add_timer(&info->watchdog); @@ -674,7 +652,7 @@ static int axnet_open(struct net_device static int axnet_close(struct net_device *dev) { - axnet_dev_t *info = (axnet_dev_t *)dev; + axnet_dev_t *info = PRIV(dev); dev_link_t *link = &info->link; DEBUG(2, "axnet_close('%s')\n", dev->name); @@ -685,8 +663,6 @@ static int axnet_close(struct net_device link->open--; netif_stop_queue(dev); del_timer_sync(&info->watchdog); - if (link->state & DEV_STALE_CONFIG) - axnet_release(link); return 0; } /* axnet_close */ @@ -726,15 +702,15 @@ static void axnet_reset_8390(struct net_ static irqreturn_t ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs) { - axnet_dev_t *info = dev_id; - info->stale = 0; + struct net_device *dev = dev_id; + PRIV(dev)->stale = 0; return ax_interrupt(irq, dev_id, regs); } static void ei_watchdog(u_long arg) { - axnet_dev_t *info = (axnet_dev_t *)(arg); - struct net_device *dev = &info->dev; + struct net_device *dev = (struct net_device *)(arg); + axnet_dev_t *info = PRIV(dev); ioaddr_t nic_base = dev->base_addr; ioaddr_t mii_addr = nic_base + AXNET_MII_EEP; u_short link; @@ -804,7 +780,7 @@ static struct ethtool_ops netdev_ethtool static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - axnet_dev_t *info = (axnet_dev_t *)dev; + axnet_dev_t *info = PRIV(dev); u16 *data = (u16 *)&rq->ifr_data; ioaddr_t mii_addr = dev->base_addr + AXNET_MII_EEP; switch (cmd) { @@ -1053,14 +1029,7 @@ static void do_set_multicast_list(struct static int ax_open(struct net_device *dev) { unsigned long flags; - struct ei_device *ei_local = (struct ei_device *) dev->priv; - - /* This can't happen unless somebody forgot to call axdev_init(). */ - if (ei_local == NULL) - { - printk(KERN_EMERG "%s: ax_open passed a non-existent device!\n", dev->name); - return -ENXIO; - } + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); #ifdef HAVE_TX_TIMEOUT /* The card I/O part of the driver (e.g. 3c503) can hook a Tx timeout @@ -1086,7 +1055,7 @@ static int ax_open(struct net_device *de return 0; } -#define dev_lock(dev) (((struct ei_device *)(dev)->priv)->page_lock) +#define dev_lock(dev) (((struct ei_device *)netdev_priv(dev))->page_lock) /** * ax_close - shut down network device @@ -1120,7 +1089,7 @@ int ax_close(struct net_device *dev) void ei_tx_timeout(struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); int txsr, isr, tickssofar = jiffies - dev->trans_start; unsigned long flags; @@ -1166,7 +1135,7 @@ void ei_tx_timeout(struct net_device *de static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); int length, send_length, output_page; unsigned long flags; u8 packet[ETH_ZLEN]; @@ -1312,7 +1281,7 @@ static irqreturn_t ax_interrupt(int irq, } e8390_base = dev->base_addr; - ei_local = (struct ei_device *) dev->priv; + ei_local = (struct ei_device *) netdev_priv(dev); /* * Protect the irq test too. @@ -1424,7 +1393,7 @@ static irqreturn_t ax_interrupt(int irq, static void ei_tx_err(struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned char txsr = inb_p(e8390_base+EN0_TSR); unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU); @@ -1465,7 +1434,7 @@ static void ei_tx_err(struct net_device static void ei_tx_intr(struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); int status = inb(e8390_base + EN0_TSR); /* @@ -1546,7 +1515,7 @@ static void ei_tx_intr(struct net_device static void ei_receive(struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned char rxing_page, this_frame, next_frame; unsigned short current_offset; int rx_pkt_count = 0; @@ -1666,7 +1635,7 @@ static void ei_rx_overrun(struct net_dev axnet_dev_t *info = (axnet_dev_t *)dev; long e8390_base = dev->base_addr; unsigned char was_txing, must_resend = 0; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); /* * Record whether a Tx was in progress and then issue the @@ -1733,7 +1702,7 @@ static void ei_rx_overrun(struct net_dev static struct net_device_stats *get_stats(struct net_device *dev) { long ioaddr = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned long flags; /* If the card is stopped, just return the present stats. */ @@ -1786,39 +1755,30 @@ static void set_multicast_list(struct ne } /** - * axdev_init - init rest of 8390 device struct + * axdev_setup - init rest of 8390 device struct * @dev: network device structure to init * * Initialize the rest of the 8390 device structure. Do NOT __init * this, as it is used by 8390 based modular drivers too. */ -static int axdev_init(struct net_device *dev) +static void axdev_setup(struct net_device *dev) { + struct ei_device *ei_local; if (ei_debug > 1) printk(version_8390); SET_MODULE_OWNER(dev); - if (dev->priv == NULL) - { - struct ei_device *ei_local; - dev->priv = kmalloc(sizeof(struct ei_device), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct ei_device)); - ei_local = (struct ei_device *)dev->priv; - spin_lock_init(&ei_local->page_lock); - } + ei_local = (struct ei_device *)netdev_priv(dev); + spin_lock_init(&ei_local->page_lock); dev->hard_start_xmit = &ei_start_xmit; dev->get_stats = get_stats; dev->set_multicast_list = &set_multicast_list; ether_setup(dev); - - return 0; } /* This page of functions should be 8390 generic */ @@ -1834,9 +1794,9 @@ static int axdev_init(struct net_device static void AX88190_init(struct net_device *dev, int startp) { - axnet_dev_t *info = (axnet_dev_t *)dev; + axnet_dev_t *info = PRIV(dev); long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); int i; int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS) : 0x48; @@ -1905,7 +1865,7 @@ static void NS8390_trigger_send(struct n int start_page) { long e8390_base = dev->base_addr; - struct ei_device *ei_local __attribute((unused)) = (struct ei_device *) dev->priv; + struct ei_device *ei_local __attribute((unused)) = (struct ei_device *) netdev_priv(dev); if (inb_p(e8390_base) & E8390_TRANS) { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/pcmcia/com20020_cs.c 830-ivtv/drivers/net/pcmcia/com20020_cs.c --- 000-virgin/drivers/net/pcmcia/com20020_cs.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/pcmcia/com20020_cs.c Thu Jan 8 08:54:20 2004 @@ -145,20 +145,6 @@ typedef struct com20020_dev_t { dev_node_t node; } com20020_dev_t; -static void com20020_setup(struct net_device *dev) -{ - struct arcnet_local *lp = dev->priv; - - lp->timeout = timeout; - lp->backplane = backplane; - lp->clockp = clockp; - lp->clockm = clockm & 3; - lp->hw.owner = THIS_MODULE; - - /* fill in our module parameters as defaults */ - dev->dev_addr[0] = node; -} - /*====================================================================== com20020_attach() creates an "instance" of the driver, allocating @@ -187,14 +173,21 @@ static dev_link_t *com20020_attach(void) if (!info) goto fail_alloc_info; - dev = alloc_netdev(sizeof(struct arcnet_local), "arc%d", - com20020_setup); + dev = alloc_arcdev(""); if (!dev) goto fail_alloc_dev; memset(info, 0, sizeof(struct com20020_dev_t)); memset(link, 0, sizeof(struct dev_link_t)); lp = dev->priv; + lp->timeout = timeout; + lp->backplane = backplane; + lp->clockp = clockp; + lp->clockm = clockm & 3; + lp->hw.owner = THIS_MODULE; + + /* fill in our module parameters as defaults */ + dev->dev_addr[0] = node; link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.NumPorts1 = 16; @@ -270,11 +263,8 @@ static void com20020_detach(dev_link_t * dev = info->dev; - if (link->state & DEV_CONFIG) { + if (link->state & DEV_CONFIG) com20020_release(link); - if (link->state & DEV_STALE_CONFIG) - return; - } if (link->handle) CardServices(DeregisterClient, link->handle); @@ -293,6 +283,8 @@ static void com20020_detach(dev_link_t * if (netif_running(dev)) dev->stop(dev); + + unregister_netdev(dev); /* * this is necessary because we register our IRQ separately @@ -300,10 +292,7 @@ static void com20020_detach(dev_link_t * */ if (dev->irq) free_irq(dev->irq, dev); - /* ...but I/O ports are done automatically by card services */ - - unregister_netdev(dev); } DEBUG(1,"kfree...\n"); @@ -447,21 +436,11 @@ static void com20020_release(dev_link_t DEBUG(0, "com20020_release(0x%p)\n", link); - if (link->open) { - DEBUG(1,"postpone...\n"); - DEBUG(1, "com20020_cs: release postponed, device stll open\n"); - link->state |= DEV_STALE_CONFIG; - return; - } - CardServices(ReleaseConfiguration, link->handle); CardServices(ReleaseIO, link->handle, &link->io); CardServices(ReleaseIRQ, link->handle, &link->irq); link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING); - - if (link->state & DEV_STALE_CONFIG) - com20020_detach(link); } /*====================================================================== diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/pcmcia/fmvj18x_cs.c 830-ivtv/drivers/net/pcmcia/fmvj18x_cs.c --- 000-virgin/drivers/net/pcmcia/fmvj18x_cs.c Mon Dec 8 09:55:51 2003 +++ 830-ivtv/drivers/net/pcmcia/fmvj18x_cs.c Thu Jan 8 08:54:20 2004 @@ -332,11 +332,8 @@ static void fmvj18x_detach(dev_link_t *l if (*linkp == NULL) return; - if (link->state & DEV_CONFIG) { + if (link->state & DEV_CONFIG) fmvj18x_release(link); - if (link->state & DEV_STALE_CONFIG) - return; - } /* Break the link with Card Services */ if (link->handle) @@ -344,12 +341,9 @@ static void fmvj18x_detach(dev_link_t *l /* Unlink device structure, free pieces */ *linkp = link->next; - if (link->dev) { + if (link->dev) unregister_netdev(dev); - free_netdev(dev); - } else - kfree(dev); - + free_netdev(dev); } /* fmvj18x_detach */ /*====================================================================*/ @@ -725,17 +719,6 @@ static void fmvj18x_release(dev_link_t * DEBUG(0, "fmvj18x_release(0x%p)\n", link); - /* - If the device is currently in use, we won't release until it - is actually closed. - */ - if (link->open) { - DEBUG(1, "fmvj18x_cs: release postponed, '%s' " - "still open\n", link->dev->dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } - /* Don't bother checking to see if these succeed or not */ CardServices(ReleaseWindow, link->win); CardServices(ReleaseConfiguration, link->handle); @@ -743,9 +726,6 @@ static void fmvj18x_release(dev_link_t * CardServices(ReleaseIRQ, link->handle, &link->irq); link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_CONFIG) - fmvj18x_detach(link); } /*====================================================================*/ @@ -1253,8 +1233,6 @@ static int fjn_close(struct net_device * outb(INTR_OFF, ioaddr + LAN_CTRL); link->open--; - if (link->state & DEV_STALE_CONFIG) - fmvj18x_release(link); return 0; } /* fjn_close */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/pcmcia/ibmtr_cs.c 830-ivtv/drivers/net/pcmcia/ibmtr_cs.c --- 000-virgin/drivers/net/pcmcia/ibmtr_cs.c Mon Dec 8 09:55:51 2003 +++ 830-ivtv/drivers/net/pcmcia/ibmtr_cs.c Thu Jan 8 08:54:20 2004 @@ -125,8 +125,7 @@ static void ibmtr_detach(dev_link_t *); static dev_link_t *dev_list; -extern int ibmtr_probe(struct net_device *dev); -extern int trdev_init(struct net_device *dev); +extern int ibmtr_probe_card(struct net_device *dev); extern irqreturn_t tok_interrupt (int irq, void *dev_id, struct pt_regs *regs); /*====================================================================*/ @@ -199,7 +198,6 @@ static dev_link_t *ibmtr_attach(void) link->irq.Instance = info->dev = dev; - dev->init = &ibmtr_probe; SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); /* Register with Card Services */ @@ -253,22 +251,22 @@ static void ibmtr_detach(dev_link_t *lin return; dev = info->dev; + + if (link->dev) + unregister_netdev(dev); + { struct tok_info *ti = (struct tok_info *)dev->priv; del_timer_sync(&(ti->tr_timer)); } - if (link->state & DEV_CONFIG) { + if (link->state & DEV_CONFIG) ibmtr_release(link); - if (link->state & DEV_STALE_CONFIG) - return; - } if (link->handle) CardServices(DeregisterClient, link->handle); /* Unlink device structure, free bits */ *linkp = link->next; - unregister_netdev(dev); free_netdev(dev); kfree(info); } /* ibmtr_detach */ @@ -371,7 +369,7 @@ static void ibmtr_config(dev_link_t *lin Adapters Technical Reference" SC30-3585 for this info. */ ibmtr_hw_setup(dev, mmiobase); - i = register_netdev(dev); + i = ibmtr_probe_card(dev); if (i != 0) { printk(KERN_NOTICE "ibmtr_cs: register_netdev() failed\n"); @@ -412,13 +410,6 @@ static void ibmtr_release(dev_link_t *li DEBUG(0, "ibmtr_release(0x%p)\n", link); - if (link->open) { - DEBUG(1, "ibmtr_cs: release postponed, '%s' " - "still open\n", info->node.dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } - CardServices(ReleaseConfiguration, link->handle); CardServices(ReleaseIO, link->handle, &link->io); CardServices(ReleaseIRQ, link->handle, &link->irq); @@ -430,9 +421,6 @@ static void ibmtr_release(dev_link_t *li } link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_CONFIG) - ibmtr_detach(link); } /*====================================================================== @@ -484,7 +472,7 @@ static int ibmtr_event(event_t event, in if (link->state & DEV_CONFIG) { CardServices(RequestConfiguration, link->handle, &link->conf); if (link->open) { - (dev->init)(dev); + ibmtr_probe(dev); /* really? */ netif_device_attach(dev); } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/pcmcia/nmclan_cs.c 830-ivtv/drivers/net/pcmcia/nmclan_cs.c --- 000-virgin/drivers/net/pcmcia/nmclan_cs.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/pcmcia/nmclan_cs.c Thu Jan 8 08:54:20 2004 @@ -551,23 +551,17 @@ static void nmclan_detach(dev_link_t *li if (*linkp == NULL) return; - if (link->state & DEV_CONFIG) { + if (link->state & DEV_CONFIG) nmclan_release(link); - if (link->state & DEV_STALE_CONFIG) - return; - } if (link->handle) CardServices(DeregisterClient, link->handle); /* Unlink device structure, free bits */ *linkp = link->next; - if (link->dev) { + if (link->dev) unregister_netdev(dev); - free_netdev(dev); - } else - kfree(dev); - + free_netdev(dev); } /* nmclan_detach */ /* ---------------------------------------------------------------------------- @@ -812,21 +806,11 @@ static void nmclan_release(dev_link_t *l DEBUG(0, "nmclan_release(0x%p)\n", link); - if (link->open) { - DEBUG(1, "nmclan_cs: release postponed, '%s' " - "still open\n", link->dev->dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } - CardServices(ReleaseConfiguration, link->handle); CardServices(ReleaseIO, link->handle, &link->io); CardServices(ReleaseIRQ, link->handle, &link->irq); link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_CONFIG) - nmclan_detach(link); } /* ---------------------------------------------------------------------------- @@ -993,8 +977,6 @@ static int mace_close(struct net_device link->open--; netif_stop_queue(dev); - if (link->state & DEV_STALE_CONFIG) - nmclan_release(link); return 0; } /* mace_close */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/pcmcia/pcnet_cs.c 830-ivtv/drivers/net/pcmcia/pcnet_cs.c --- 000-virgin/drivers/net/pcmcia/pcnet_cs.c Thu Jan 8 08:35:38 2004 +++ 830-ivtv/drivers/net/pcmcia/pcnet_cs.c Thu Jan 8 08:54:20 2004 @@ -224,7 +224,6 @@ static hw_info_t dl10019_info = { 0, 0, static hw_info_t dl10022_info = { 0, 0, 0, 0, IS_DL10022|HAS_MII }; typedef struct pcnet_dev_t { - struct net_device dev; /* so &dev == &pcnet_dev_t */ dev_link_t link; dev_node_t node; u_int flags; @@ -237,16 +236,10 @@ typedef struct pcnet_dev_t { u_long mii_reset; } pcnet_dev_t; -/*====================================================================== - - We never need to do anything when a pcnet device is "initialized" - by the net software, because we only register already-found cards. - -======================================================================*/ - -static int pcnet_init(struct net_device *dev) +static inline pcnet_dev_t *PRIV(struct net_device *dev) { - return 0; + char *p = netdev_priv(dev); + return (pcnet_dev_t *)(p + sizeof(struct ei_device)); } /*====================================================================== @@ -268,11 +261,11 @@ static dev_link_t *pcnet_attach(void) DEBUG(0, "pcnet_attach()\n"); /* Create new ethernet device */ - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) return NULL; - memset(info, 0, sizeof(*info)); - link = &info->link; dev = &info->dev; - link->priv = info; + dev = __alloc_ei_netdev(sizeof(pcnet_dev_t)); + if (!dev) return NULL; + info = PRIV(dev); + link = &info->link; + link->priv = dev; link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; @@ -284,9 +277,7 @@ static dev_link_t *pcnet_attach(void) link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; - ethdev_init(dev); SET_MODULE_OWNER(dev); - dev->init = &pcnet_init; dev->open = &pcnet_open; dev->stop = &pcnet_close; dev->set_config = &set_config; @@ -324,7 +315,7 @@ static dev_link_t *pcnet_attach(void) static void pcnet_detach(dev_link_t *link) { - pcnet_dev_t *info = link->priv; + struct net_device *dev = link->priv; dev_link_t **linkp; DEBUG(0, "pcnet_detach(0x%p)\n", link); @@ -335,23 +326,17 @@ static void pcnet_detach(dev_link_t *lin if (*linkp == NULL) return; - if (link->state & DEV_CONFIG) { + if (link->state & DEV_CONFIG) pcnet_release(link); - if (link->state & DEV_STALE_CONFIG) - return; - } if (link->handle) CardServices(DeregisterClient, link->handle); /* Unlink device structure, free bits */ *linkp = link->next; - if (link->dev) { - unregister_netdev(&info->dev); - free_netdev(&info->dev); - } else - kfree(info); - + if (link->dev) + unregister_netdev(dev); + free_netdev(dev); } /* pcnet_detach */ /*====================================================================== @@ -583,8 +568,8 @@ static int try_io_port(dev_link_t *link) static void pcnet_config(dev_link_t *link) { client_handle_t handle = link->handle; - pcnet_dev_t *info = link->priv; - struct net_device *dev = &info->dev; + struct net_device *dev = link->priv; + pcnet_dev_t *info = PRIV(dev); tuple_t tuple; cisparse_t parse; int i, last_ret, last_fn, start_pg, stop_pg, cm_offset; @@ -786,17 +771,10 @@ failed: static void pcnet_release(dev_link_t *link) { - pcnet_dev_t *info = link->priv; + pcnet_dev_t *info = PRIV(link->priv); DEBUG(0, "pcnet_release(0x%p)\n", link); - if (link->open) { - DEBUG(1, "pcnet_cs: release postponed, '%s' still open\n", - info->node.dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } - if (info->flags & USE_SHMEM) { iounmap(info->base); CardServices(ReleaseWindow, link->win); @@ -806,9 +784,6 @@ static void pcnet_release(dev_link_t *li CardServices(ReleaseIRQ, link->handle, &link->irq); link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_CONFIG) - pcnet_detach(link); } /*====================================================================== @@ -824,7 +799,7 @@ static int pcnet_event(event_t event, in event_callback_args_t *args) { dev_link_t *link = args->client_data; - pcnet_dev_t *info = link->priv; + struct net_device *dev = link->priv; DEBUG(2, "pcnet_event(0x%06x)\n", event); @@ -832,7 +807,7 @@ static int pcnet_event(event_t event, in case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { - netif_device_detach(&info->dev); + netif_device_detach(dev); pcnet_release(link); } break; @@ -846,7 +821,7 @@ static int pcnet_event(event_t event, in case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { if (link->open) - netif_device_detach(&info->dev); + netif_device_detach(dev); CardServices(ReleaseConfiguration, link->handle); } break; @@ -857,9 +832,9 @@ static int pcnet_event(event_t event, in if (link->state & DEV_CONFIG) { CardServices(RequestConfiguration, link->handle, &link->conf); if (link->open) { - pcnet_reset_8390(&info->dev); - NS8390_init(&info->dev, 1); - netif_device_attach(&info->dev); + pcnet_reset_8390(dev); + NS8390_init(dev, 1); + netif_device_attach(dev); } } break; @@ -1039,7 +1014,7 @@ static void write_asic(ioaddr_t ioaddr, static void set_misc_reg(struct net_device *dev) { ioaddr_t nic_base = dev->base_addr; - pcnet_dev_t *info = (pcnet_dev_t *)dev; + pcnet_dev_t *info = PRIV(dev); u_char tmp; if (info->flags & HAS_MISC_REG) { @@ -1069,7 +1044,7 @@ static void set_misc_reg(struct net_devi static void mii_phy_probe(struct net_device *dev) { - pcnet_dev_t *info = (pcnet_dev_t *)dev; + pcnet_dev_t *info = PRIV(dev); ioaddr_t mii_addr = dev->base_addr + DLINK_GPIO; int i; u_int tmp, phyid; @@ -1093,7 +1068,7 @@ static void mii_phy_probe(struct net_dev static int pcnet_open(struct net_device *dev) { - pcnet_dev_t *info = (pcnet_dev_t *)dev; + pcnet_dev_t *info = PRIV(dev); dev_link_t *link = &info->link; DEBUG(2, "pcnet_open('%s')\n", dev->name); @@ -1110,7 +1085,7 @@ static int pcnet_open(struct net_device info->link_status = 0x00; init_timer(&info->watchdog); info->watchdog.function = &ei_watchdog; - info->watchdog.data = (u_long)info; + info->watchdog.data = (u_long)dev; info->watchdog.expires = jiffies + HZ; add_timer(&info->watchdog); @@ -1121,7 +1096,7 @@ static int pcnet_open(struct net_device static int pcnet_close(struct net_device *dev) { - pcnet_dev_t *info = (pcnet_dev_t *)dev; + pcnet_dev_t *info = PRIV(dev); dev_link_t *link = &info->link; DEBUG(2, "pcnet_close('%s')\n", dev->name); @@ -1132,8 +1107,6 @@ static int pcnet_close(struct net_device link->open--; netif_stop_queue(dev); del_timer_sync(&info->watchdog); - if (link->state & DEV_STALE_CONFIG) - pcnet_release(link); return 0; } /* pcnet_close */ @@ -1174,7 +1147,7 @@ static void pcnet_reset_8390(struct net_ static int set_config(struct net_device *dev, struct ifmap *map) { - pcnet_dev_t *info = (pcnet_dev_t *)dev; + pcnet_dev_t *info = PRIV(dev); if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) { if (!(info->flags & HAS_MISC_REG)) return -EOPNOTSUPP; @@ -1192,7 +1165,8 @@ static int set_config(struct net_device static irqreturn_t ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs) { - pcnet_dev_t *info = dev_id; + struct net_device *dev = dev_id; + pcnet_dev_t *info = PRIV(dev); info->stale = 0; ei_interrupt(irq, dev_id, regs); /* FIXME! Was it really ours? */ @@ -1201,8 +1175,8 @@ static irqreturn_t ei_irq_wrapper(int ir static void ei_watchdog(u_long arg) { - pcnet_dev_t *info = (pcnet_dev_t *)(arg); - struct net_device *dev = &info->dev; + struct net_device *dev = (struct net_device *)arg; + pcnet_dev_t *info = PRIV(dev); ioaddr_t nic_base = dev->base_addr; ioaddr_t mii_addr = nic_base + DLINK_GPIO; u_short link; @@ -1305,7 +1279,7 @@ static struct ethtool_ops netdev_ethtool static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - pcnet_dev_t *info = (pcnet_dev_t *)dev; + pcnet_dev_t *info = PRIV(dev); u16 *data = (u16 *)&rq->ifr_data; ioaddr_t mii_addr = dev->base_addr + DLINK_GPIO; switch (cmd) { @@ -1416,7 +1390,7 @@ static void dma_block_output(struct net_ const u_char *buf, const int start_page) { ioaddr_t nic_base = dev->base_addr; - pcnet_dev_t *info = (pcnet_dev_t *)dev; + pcnet_dev_t *info = PRIV(dev); #ifdef PCMCIA_DEBUG int retries = 0; #endif @@ -1602,7 +1576,7 @@ static int setup_shmem_window(dev_link_t int stop_pg, int cm_offset) { struct net_device *dev = link->priv; - pcnet_dev_t *info = link->priv; + pcnet_dev_t *info = PRIV(dev); win_req_t req; memreq_t mem; int i, window_size, offset, last_ret, last_fn; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/pcmcia/smc91c92_cs.c 830-ivtv/drivers/net/pcmcia/smc91c92_cs.c --- 000-virgin/drivers/net/pcmcia/smc91c92_cs.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/pcmcia/smc91c92_cs.c Thu Jan 8 08:54:20 2004 @@ -411,23 +411,17 @@ static void smc91c92_detach(dev_link_t * if (*linkp == NULL) return; - if (link->state & DEV_CONFIG) { + if (link->state & DEV_CONFIG) smc91c92_release(link); - if (link->state & DEV_STALE_CONFIG) - return; - } if (link->handle) CardServices(DeregisterClient, link->handle); /* Unlink device structure, free bits */ *linkp = link->next; - if (link->dev) { + if (link->dev) unregister_netdev(dev); - free_netdev(dev); - } else - kfree(dev); - + free_netdev(dev); } /* smc91c92_detach */ /*====================================================================*/ @@ -1063,13 +1057,6 @@ static void smc91c92_release(dev_link_t DEBUG(0, "smc91c92_release(0x%p)\n", link); - if (link->open) { - DEBUG(1, "smc91c92_cs: release postponed, '%s' still open\n", - link->dev->dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } - CardServices(ReleaseConfiguration, link->handle); CardServices(ReleaseIO, link->handle, &link->io); CardServices(ReleaseIRQ, link->handle, &link->irq); @@ -1081,9 +1068,6 @@ static void smc91c92_release(dev_link_t } link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_CONFIG) - smc91c92_detach(link); } /*====================================================================== @@ -1309,8 +1293,6 @@ static int smc_close(struct net_device * link->open--; del_timer_sync(&smc->media); - if (link->state & DEV_STALE_CONFIG) - smc91c92_release(link); return 0; } /* smc_close */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/pcmcia/xirc2ps_cs.c 830-ivtv/drivers/net/pcmcia/xirc2ps_cs.c --- 000-virgin/drivers/net/pcmcia/xirc2ps_cs.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/pcmcia/xirc2ps_cs.c Thu Jan 8 08:54:20 2004 @@ -684,12 +684,9 @@ xirc2ps_detach(dev_link_t * link) /* Unlink device structure, free it */ *linkp = link->next; - if (link->dev) { + if (link->dev) unregister_netdev(dev); - free_netdev(dev); - } else - kfree(dev); - + free_netdev(dev); } /* xirc2ps_detach */ /**************** diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/pcnet32.c 830-ivtv/drivers/net/pcnet32.c --- 000-virgin/drivers/net/pcnet32.c Wed Dec 24 18:16:47 2003 +++ 830-ivtv/drivers/net/pcnet32.c Thu Jan 8 08:54:20 2004 @@ -456,6 +456,14 @@ static struct pcnet32_access pcnet32_dwi .reset = pcnet32_dwio_reset }; +#ifdef CONFIG_NET_POLL_CONTROLLER +static void pcnet32_poll_controller(struct net_device *dev) +{ + disable_irq(dev->irq); + pcnet32_interrupt(0, dev, NULL); + enable_irq(dev->irq); +} +#endif /* only probes for non-PCI devices, the rest are handled by @@ -805,12 +813,16 @@ pcnet32_probe1(unsigned long ioaddr, uns dev->do_ioctl = &pcnet32_ioctl; dev->tx_timeout = pcnet32_tx_timeout; dev->watchdog_timeo = (5*HZ); +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = pcnet32_poll_controller; +#endif + + /* Fill in the generic fields of the device structure. */ + if (register_netdev(dev)) + goto err_free_consistent; lp->next = pcnet32_dev; pcnet32_dev = dev; - - /* Fill in the generic fields of the device structure. */ - register_netdev(dev); printk(KERN_INFO "%s: registered as %s\n",dev->name, lp->name); cards_found++; return 0; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/plip.c 830-ivtv/drivers/net/plip.c --- 000-virgin/drivers/net/plip.c Tue Sep 2 09:55:47 2003 +++ 830-ivtv/drivers/net/plip.c Thu Jan 8 08:54:20 2004 @@ -277,19 +277,11 @@ inline static unsigned char read_status then calls us here. */ -static int +static void plip_init_netdev(struct net_device *dev) { struct net_local *nl = dev->priv; - printk(KERN_INFO "%s", version); - if (dev->irq != -1) - printk(KERN_INFO "%s: Parallel port at %#3lx, using IRQ %d.\n", - dev->name, dev->base_addr, dev->irq); - else - printk(KERN_INFO "%s: Parallel port at %#3lx, not using IRQ.\n", - dev->name, dev->base_addr); - /* Then, override parts of it */ dev->hard_start_xmit = plip_tx_packet; dev->open = plip_open; @@ -323,8 +315,6 @@ plip_init_netdev(struct net_device *dev) INIT_WORK(&nl->timer, (void (*)(void *))plip_timer_bh, dev); spin_lock_init(&nl->lock); - - return 0; } /* Bottom half handler for the delayed request. @@ -1282,14 +1272,13 @@ static void plip_attach (struct parport } sprintf(name, "plip%d", unit); - dev = alloc_netdev(sizeof(struct net_local), name, - ether_setup); + dev = alloc_etherdev(sizeof(struct net_local)); if (!dev) { printk(KERN_ERR "plip: memory squeeze\n"); return; } - dev->init = plip_init_netdev; + strcpy(dev->name, name); SET_MODULE_OWNER(dev); dev->irq = port->irq; @@ -1306,17 +1295,35 @@ static void plip_attach (struct parport if (!nl->pardev) { printk(KERN_ERR "%s: parport_register failed\n", name); - kfree(dev); + goto err_free_dev; return; } + plip_init_netdev(dev); + if (register_netdev(dev)) { printk(KERN_ERR "%s: network register failed\n", name); - kfree(dev); - } else { - dev_plip[unit++] = dev; + goto err_parport_unregister; } + + printk(KERN_INFO "%s", version); + if (dev->irq != -1) + printk(KERN_INFO "%s: Parallel port at %#3lx, " + "using IRQ %d.\n", + dev->name, dev->base_addr, dev->irq); + else + printk(KERN_INFO "%s: Parallel port at %#3lx, " + "not using IRQ.\n", + dev->name, dev->base_addr); + dev_plip[unit++] = dev; } + return; + +err_parport_unregister: + parport_unregister_device(nl->pardev); +err_free_dev: + free_netdev(dev); + return; } /* plip_detach() is called (by the parport code) when a port is diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/ppp_generic.c 830-ivtv/drivers/net/ppp_generic.c --- 000-virgin/drivers/net/ppp_generic.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/ppp_generic.c Thu Jan 8 08:54:21 2004 @@ -917,19 +917,14 @@ ppp_net_ioctl(struct net_device *dev, st return err; } -static int -ppp_net_init(struct net_device *dev) +static void ppp_setup(struct net_device *dev) { dev->hard_header_len = PPP_HDRLEN; dev->mtu = PPP_MTU; - dev->hard_start_xmit = ppp_start_xmit; - dev->get_stats = ppp_net_stats; - dev->do_ioctl = ppp_net_ioctl; dev->addr_len = 0; dev->tx_queue_len = 3; dev->type = ARPHRD_PPP; dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; - return 0; } /* @@ -2272,23 +2267,13 @@ ppp_create_interface(int unit, int *retp int i; ppp = kmalloc(sizeof(struct ppp), GFP_KERNEL); - if (ppp == 0) - goto err; - dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); - if (dev == 0) - goto err; + if (!ppp) + goto out; + dev = alloc_netdev(0, "", ppp_setup); + if (!dev) + goto out1; memset(ppp, 0, sizeof(struct ppp)); - memset(dev, 0, sizeof(struct net_device)); - ret = -EEXIST; - down(&all_ppp_sem); - if (unit < 0) - unit = cardmap_find_first_free(all_ppp_units); - else if (cardmap_get(all_ppp_units, unit) != NULL) - goto err_unlock; /* unit already exists */ - - /* Initialize the new ppp unit */ - ppp->file.index = unit; ppp->mru = PPP_MRU; init_ppp_file(&ppp->file, INTERFACE); ppp->file.hdrlen = PPP_HDRLEN - 2; /* don't count proto bytes */ @@ -2301,20 +2286,29 @@ ppp_create_interface(int unit, int *retp ppp->minseq = -1; skb_queue_head_init(&ppp->mrq); #endif /* CONFIG_PPP_MULTILINK */ - ppp->dev = dev; - dev->init = ppp_net_init; - sprintf(dev->name, "ppp%d", unit); dev->priv = ppp; - dev->destructor = free_netdev; - rtnl_lock(); - ret = register_netdevice(dev); - rtnl_unlock(); + dev->hard_start_xmit = ppp_start_xmit; + dev->get_stats = ppp_net_stats; + dev->do_ioctl = ppp_net_ioctl; + + ret = -EEXIST; + down(&all_ppp_sem); + if (unit < 0) + unit = cardmap_find_first_free(all_ppp_units); + else if (cardmap_get(all_ppp_units, unit) != NULL) + goto out2; /* unit already exists */ + + /* Initialize the new ppp unit */ + ppp->file.index = unit; + sprintf(dev->name, "ppp%d", unit); + + ret = register_netdev(dev); if (ret != 0) { printk(KERN_ERR "PPP: couldn't register device %s (%d)\n", dev->name, ret); - goto err_unlock; + goto out2; } atomic_inc(&ppp_unit_count); @@ -2323,14 +2317,13 @@ ppp_create_interface(int unit, int *retp *retp = 0; return ppp; - err_unlock: +out2: up(&all_ppp_sem); - err: + free_netdev(dev); +out1: + kfree(ppp); +out: *retp = ret; - if (ppp) - kfree(ppp); - if (dev) - kfree(dev); return NULL; } @@ -2361,8 +2354,10 @@ static void ppp_shutdown_interface(struc ppp->dev = 0; ppp_unlock(ppp); /* This will call dev_close() for us. */ - if (dev) + if (dev) { unregister_netdev(dev); + free_netdev(dev); + } cardmap_set(&all_ppp_units, ppp->file.index, NULL); ppp->file.dead = 1; ppp->owner = NULL; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/r8169.c 830-ivtv/drivers/net/r8169.c --- 000-virgin/drivers/net/r8169.c Wed Dec 24 18:16:47 2003 +++ 830-ivtv/drivers/net/r8169.c Thu Jan 8 08:54:21 2004 @@ -56,9 +56,11 @@ VERSION 1.2 <2002/11/30> printk( "Assertion failed! %s,%s,%s,line=%d\n", \ #expr,__FILE__,__FUNCTION__,__LINE__); \ } +#define dprintk(fmt, args...) do { printk(PFX fmt, ## args) } while (0) #else #define assert(expr) do {} while (0) -#endif +#define dprintk(fmt, args...) do {} while (0) +#endif /* RTL8169_DEBUG */ /* media options */ #define MAX_UNITS 8 @@ -89,9 +91,12 @@ static int multicast_filter_limit = 32; #define NUM_TX_DESC 64 /* Number of Tx descriptor registers */ #define NUM_RX_DESC 64 /* Number of Rx descriptor registers */ #define RX_BUF_SIZE 1536 /* Rx Buffer size */ +#define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc)) +#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc)) #define RTL_MIN_IO_SIZE 0x80 -#define TX_TIMEOUT (6*HZ) +#define RTL8169_TX_TIMEOUT (6*HZ) +#define RTL8169_PHY_TIMEOUT (HZ) /* write/read MMIO register */ #define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg)) @@ -101,11 +106,35 @@ static int multicast_filter_limit = 32; #define RTL_R16(reg) readw (ioaddr + (reg)) #define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg))) -static struct { +enum mac_version { + RTL_GIGA_MAC_VER_B = 0x00, + /* RTL_GIGA_MAC_VER_C = 0x03, */ + RTL_GIGA_MAC_VER_D = 0x01, + RTL_GIGA_MAC_VER_E = 0x02 +}; + +enum phy_version { + RTL_GIGA_PHY_VER_C = 0x03, /* PHY Reg 0x03 bit0-3 == 0x0000 */ + RTL_GIGA_PHY_VER_D = 0x04, /* PHY Reg 0x03 bit0-3 == 0x0000 */ + RTL_GIGA_PHY_VER_E = 0x05, /* PHY Reg 0x03 bit0-3 == 0x0000 */ + RTL_GIGA_PHY_VER_F = 0x06, /* PHY Reg 0x03 bit0-3 == 0x0001 */ + RTL_GIGA_PHY_VER_G = 0x07, /* PHY Reg 0x03 bit0-3 == 0x0002 */ +}; + + +#define _R(NAME,MAC,MASK) \ + { .name = NAME, .mac_version = MAC, .RxConfigMask = MASK } + +const static struct { const char *name; -} board_info[] __devinitdata = { - { -"RealTek RTL8169 Gigabit Ethernet"},}; + u8 mac_version; + u32 RxConfigMask; /* Clears the bits supported by this chip */ +} rtl_chip_info[] __devinitdata = { + _R("RTL8169", RTL_GIGA_MAC_VER_B, 0xff7e1880), + _R("RTL8169s/8110s", RTL_GIGA_MAC_VER_D, 0xff7e1880), + _R("RTL8169s/8110s", RTL_GIGA_MAC_VER_E, 0xff7e1880) +}; +#undef _R static struct pci_device_id rtl8169_pci_tbl[] = { {0x10ec, 0x8169, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, @@ -114,6 +143,8 @@ static struct pci_device_id rtl8169_pci_ MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl); +static int rx_copybreak = 200; + enum RTL8169_registers { MAC0 = 0, /* Ethernet hardware address. */ MAR0 = 8, /* Multicast filter. */ @@ -242,14 +273,6 @@ enum RTL8169_register_content { TBILinkOK = 0x02000000, }; -const static struct { - const char *name; - u8 version; /* depend on RTL8169 docs */ - u32 RxConfigMask; /* should clear the bits supported by this chip */ -} rtl_chip_info[] = { - { -"RTL-8169", 0x00, 0xff7e1880,},}; - enum _DescStatusBit { OWNbit = 0x80000000, EORbit = 0x40000000, @@ -257,6 +280,8 @@ enum _DescStatusBit { LSbit = 0x10000000, }; +#define RsvdMask 0x3fffc000 + struct TxDesc { u32 status; u32 vlan_tag; @@ -277,28 +302,33 @@ struct rtl8169_private { struct net_device_stats stats; /* statistics of net device */ spinlock_t lock; /* spin lock flag */ int chipset; - unsigned long cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */ - unsigned long cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */ - unsigned long dirty_tx; - unsigned char *TxDescArrays; /* Index of Tx Descriptor buffer */ - unsigned char *RxDescArrays; /* Index of Rx Descriptor buffer */ + int mac_version; + int phy_version; + u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */ + u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */ + u32 dirty_rx; + u32 dirty_tx; struct TxDesc *TxDescArray; /* Index of 256-alignment Tx Descriptor buffer */ struct RxDesc *RxDescArray; /* Index of 256-alignment Rx Descriptor buffer */ - unsigned char *RxBufferRings; /* Index of Rx Buffer */ - unsigned char *RxBufferRing[NUM_RX_DESC]; /* Index of Rx Buffer array */ + dma_addr_t TxPhyAddr; + dma_addr_t RxPhyAddr; + struct sk_buff *Rx_skbuff[NUM_RX_DESC]; /* Rx data buffers */ struct sk_buff *Tx_skbuff[NUM_TX_DESC]; /* Index of Transmit data buffer */ + struct timer_list timer; + unsigned long phy_link_down_cnt; }; MODULE_AUTHOR("Realtek"); MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver"); MODULE_PARM(media, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(rx_copybreak, "i"); MODULE_LICENSE("GPL"); static int rtl8169_open(struct net_device *dev); static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev); static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs); -static void rtl8169_init_ring(struct net_device *dev); +static int rtl8169_init_ring(struct net_device *dev); static void rtl8169_hw_start(struct net_device *dev); static int rtl8169_close(struct net_device *dev); static void rtl8169_set_rx_mode(struct net_device *dev); @@ -306,11 +336,15 @@ static void rtl8169_tx_timeout(struct ne static struct net_device_stats *rtl8169_get_stats(struct net_device *netdev); static const u16 rtl8169_intr_mask = - SYSErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | - RxErr | RxOK; + RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK; static const unsigned int rtl8169_rx_config = (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift); +#define PHY_Cap_10_Half_Or_Less PHY_Cap_10_Half +#define PHY_Cap_10_Full_Or_Less PHY_Cap_10_Full | PHY_Cap_10_Half_Or_Less +#define PHY_Cap_100_Half_Or_Less PHY_Cap_100_Half | PHY_Cap_10_Full_Or_Less +#define PHY_Cap_100_Full_Or_Less PHY_Cap_100_Full | PHY_Cap_100_Half_Or_Less + void mdio_write(void *ioaddr, int RegAddr, int value) { @@ -342,13 +376,258 @@ mdio_read(void *ioaddr, int RegAddr) if (RTL_R32(PHYAR) & 0x80000000) { value = (int) (RTL_R32(PHYAR) & 0xFFFF); break; - } else { - udelay(100); } + udelay(100); } return value; } +static void rtl8169_write_gmii_reg_bit(void *ioaddr, int reg, int bitnum, + int bitval) +{ + int val; + + val = mdio_read(ioaddr, reg); + val = (bitval == 1) ? + val | (bitval << bitnum) : val & ~(0x0001 << bitnum); + mdio_write(ioaddr, reg, val & 0xffff); +} + +static void rtl8169_get_mac_version(struct rtl8169_private *tp, void *ioaddr) +{ + const struct { + u32 mask; + int mac_version; + } mac_info[] = { + { 0x1 << 26, RTL_GIGA_MAC_VER_E }, + { 0x1 << 23, RTL_GIGA_MAC_VER_D }, + { 0x00000000, RTL_GIGA_MAC_VER_B } /* Catch-all */ + }, *p = mac_info; + u32 reg; + + reg = RTL_R32(TxConfig) & 0x7c800000; + while ((reg & p->mask) != p->mask) + p++; + tp->mac_version = p->mac_version; +} + +static void rtl8169_print_mac_version(struct rtl8169_private *tp) +{ + struct { + int version; + char *msg; + } mac_print[] = { + { RTL_GIGA_MAC_VER_E, "RTL_GIGA_MAC_VER_E" }, + { RTL_GIGA_MAC_VER_D, "RTL_GIGA_MAC_VER_D" }, + { RTL_GIGA_MAC_VER_B, "RTL_GIGA_MAC_VER_B" }, + { 0, NULL } + }, *p; + + for (p = mac_print; p->msg; p++) { + if (tp->mac_version == p->version) { + dprintk("mac_version == %s (%04d)\n", p->msg, + p->version); + return; + } + } + dprintk("mac_version == Unknown\n"); +} + +static void rtl8169_get_phy_version(struct rtl8169_private *tp, void *ioaddr) +{ + const struct { + u16 mask; + u16 set; + int phy_version; + } phy_info[] = { + { 0x000f, 0x0002, RTL_GIGA_PHY_VER_G }, + { 0x000f, 0x0001, RTL_GIGA_PHY_VER_F }, + { 0x000f, 0x0000, RTL_GIGA_PHY_VER_E }, + { 0x0000, 0x0000, RTL_GIGA_PHY_VER_D } /* Catch-all */ + }, *p = phy_info; + u16 reg; + + reg = mdio_read(ioaddr, 3) & 0xffff; + while ((reg & p->mask) != p->set) + p++; + tp->phy_version = p->phy_version; +} + +static void rtl8169_print_phy_version(struct rtl8169_private *tp) +{ + struct { + int version; + char *msg; + u32 reg; + } phy_print[] = { + { RTL_GIGA_PHY_VER_G, "RTL_GIGA_PHY_VER_G", 0x0002 }, + { RTL_GIGA_PHY_VER_F, "RTL_GIGA_PHY_VER_F", 0x0001 }, + { RTL_GIGA_PHY_VER_E, "RTL_GIGA_PHY_VER_E", 0x0000 }, + { RTL_GIGA_PHY_VER_D, "RTL_GIGA_PHY_VER_D", 0x0000 }, + { 0, NULL, 0x0000 } + }, *p; + + for (p = phy_print; p->msg; p++) { + if (tp->phy_version == p->version) { + dprintk("phy_version == %s (%04x)\n", p->msg, p->reg); + return; + } + } + dprintk("phy_version == Unknown\n"); +} + +static void rtl8169_hw_phy_config(struct net_device *dev) +{ + struct rtl8169_private *tp = dev->priv; + void *ioaddr = tp->mmio_addr; + struct { + u16 regs[5]; /* Beware of bit-sign propagation */ + } phy_magic[5] = { { + { 0x0000, //w 4 15 12 0 + 0x00a1, //w 3 15 0 00a1 + 0x0008, //w 2 15 0 0008 + 0x1020, //w 1 15 0 1020 + 0x1000 } },{ //w 0 15 0 1000 + { 0x7000, //w 4 15 12 7 + 0xff41, //w 3 15 0 ff41 + 0xde60, //w 2 15 0 de60 + 0x0140, //w 1 15 0 0140 + 0x0077 } },{ //w 0 15 0 0077 + { 0xa000, //w 4 15 12 a + 0xdf01, //w 3 15 0 df01 + 0xdf20, //w 2 15 0 df20 + 0xff95, //w 1 15 0 ff95 + 0xfa00 } },{ //w 0 15 0 fa00 + { 0xb000, //w 4 15 12 b + 0xff41, //w 3 15 0 ff41 + 0xde20, //w 2 15 0 de20 + 0x0140, //w 1 15 0 0140 + 0x00bb } },{ //w 0 15 0 00bb + { 0xf000, //w 4 15 12 f + 0xdf01, //w 3 15 0 df01 + 0xdf20, //w 2 15 0 df20 + 0xff95, //w 1 15 0 ff95 + 0xbf00 } //w 0 15 0 bf00 + } + }, *p = phy_magic; + int i; + + rtl8169_print_mac_version(tp); + rtl8169_print_phy_version(tp); + + if (tp->mac_version <= RTL_GIGA_MAC_VER_B) + return; + if (tp->phy_version >= RTL_GIGA_PHY_VER_F) + return; + + dprintk("MAC version != 0 && PHY version == 0 or 1\n"); + dprintk("Do final_reg2.cfg\n"); + + /* Shazam ! */ + + // phy config for RTL8169s mac_version C chip + mdio_write(ioaddr, 31, 0x0001); //w 31 2 0 1 + mdio_write(ioaddr, 21, 0x1000); //w 21 15 0 1000 + mdio_write(ioaddr, 24, 0x65c7); //w 24 15 0 65c7 + rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0 + + for (i = ARRAY_SIZE(phy_magic); i > 0; i++, p++) { + int val, pos = 4; + + val = (mdio_read(ioaddr, pos) & 0x0fff) | (p->regs[0] & 0xffff); + mdio_write(ioaddr, pos, val); + while (--pos >= 0) + mdio_write(ioaddr, pos, p->regs[4 - pos] & 0xffff); + rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 1); //w 4 11 11 1 + rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0 + } + mdio_write(ioaddr, 31, 0x0000); //w 31 2 0 0 +} + +static void rtl8169_hw_phy_reset(struct net_device *dev) +{ + struct rtl8169_private *tp = dev->priv; + void *ioaddr = tp->mmio_addr; + int i, val; + + printk(KERN_WARNING PFX "%s: Reset RTL8169s PHY\n", dev->name); + + val = (mdio_read(ioaddr, 0) | 0x8000) & 0xffff; + mdio_write(ioaddr, 0, val); + + for (i = 50; i >= 0; i--) { + if (!(mdio_read(ioaddr, 0) & 0x8000)) + break; + udelay(100); /* Gross */ + } + + if (i < 0) { + printk(KERN_WARNING PFX "%s: no PHY Reset ack. Giving up.\n", + dev->name); + } +} + +static void rtl8169_phy_timer(unsigned long __opaque) +{ + struct net_device *dev = (struct net_device *)__opaque; + struct rtl8169_private *tp = dev->priv; + struct timer_list *timer = &tp->timer; + void *ioaddr = tp->mmio_addr; + + assert(tp->mac_version > RTL_GIGA_MAC_VER_B); + assert(tp->phy_version < RTL_GIGA_PHY_VER_G); + + if (RTL_R8(PHYstatus) & LinkStatus) + tp->phy_link_down_cnt = 0; + else { + tp->phy_link_down_cnt++; + if (tp->phy_link_down_cnt >= 12) { + int reg; + + // If link on 1000, perform phy reset. + reg = mdio_read(ioaddr, PHY_1000_CTRL_REG); + if (reg & PHY_Cap_1000_Full) + rtl8169_hw_phy_reset(dev); + + tp->phy_link_down_cnt = 0; + } + } + + mod_timer(timer, RTL8169_PHY_TIMEOUT); +} + +static inline void rtl8169_delete_timer(struct net_device *dev) +{ + struct rtl8169_private *tp = dev->priv; + struct timer_list *timer = &tp->timer; + + if ((tp->mac_version <= RTL_GIGA_MAC_VER_B) || + (tp->phy_version >= RTL_GIGA_PHY_VER_G)) + return; + + del_timer_sync(timer); + + tp->phy_link_down_cnt = 0; +} + +static inline void rtl8169_request_timer(struct net_device *dev) +{ + struct rtl8169_private *tp = dev->priv; + struct timer_list *timer = &tp->timer; + + if ((tp->mac_version <= RTL_GIGA_MAC_VER_B) || + (tp->phy_version >= RTL_GIGA_PHY_VER_G)) + return; + + tp->phy_link_down_cnt = 0; + + init_timer(timer); + timer->expires = jiffies + RTL8169_PHY_TIMEOUT; + timer->data = (unsigned long)(dev); + timer->function = rtl8169_phy_timer; + add_timer(timer); +} + static int __devinit rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out, void **ioaddr_out) @@ -356,9 +635,9 @@ rtl8169_init_board(struct pci_dev *pdev, void *ioaddr = NULL; struct net_device *dev; struct rtl8169_private *tp; - int rc, i; unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; - u32 tmp; + int rc, i, acpi_idle_state = 0, pm_cap; + assert(pdev != NULL); assert(ioaddr_out != NULL); @@ -379,8 +658,22 @@ rtl8169_init_board(struct pci_dev *pdev, // enable device (incl. PCI PM wakeup and hotplug setup) rc = pci_enable_device(pdev); - if (rc) + if (rc) { + printk(KERN_ERR PFX "%s: unable to enable device\n", pdev->slot_name); goto err_out; + } + + /* save power state before pci_enable_device overwrites it */ + pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); + if (pm_cap) { + u16 pwr_command; + + pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pwr_command); + acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK; + } else { + printk(KERN_ERR PFX "Cannot find PowerManagement capability, aborting.\n"); + goto err_out_free_res; + } mmio_start = pci_resource_start(pdev, 1); mmio_end = pci_resource_end(pdev, 1); @@ -402,8 +695,10 @@ rtl8169_init_board(struct pci_dev *pdev, } rc = pci_request_regions(pdev, dev->name); - if (rc) + if (rc) { + printk(KERN_ERR PFX "%s: Could not request regions.\n", pdev->slot_name); goto err_out_disable; + } // enable PCI bus-mastering pci_set_master(pdev); @@ -420,30 +715,32 @@ rtl8169_init_board(struct pci_dev *pdev, RTL_W8(ChipCmd, CmdReset); // Check that the chip has finished the reset. - for (i = 1000; i > 0; i--) + for (i = 1000; i > 0; i--) { if ((RTL_R8(ChipCmd) & CmdReset) == 0) break; - else - udelay(10); + udelay(10); + } - // identify chip attached to board - tmp = RTL_R32(TxConfig); - tmp = ((tmp & 0x7c000000) + ((tmp & 0x00800000) << 2)) >> 24; - - for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--) - if (tmp == rtl_chip_info[i].version) { - tp->chipset = i; - goto match; - } - //if unknown chip, assume array element #0, original RTL-8169 in this case - printk(KERN_DEBUG PFX - "PCI device %s: unknown chip version, assuming RTL-8169\n", - pci_name(pdev)); - printk(KERN_DEBUG PFX "PCI device %s: TxConfig = 0x%lx\n", - pci_name(pdev), (unsigned long) RTL_R32(TxConfig)); - tp->chipset = 0; + // Identify chip attached to board + rtl8169_get_mac_version(tp, ioaddr); + rtl8169_get_phy_version(tp, ioaddr); + + rtl8169_print_mac_version(tp); + rtl8169_print_phy_version(tp); + + for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--) { + if (tp->mac_version == rtl_chip_info[i].mac_version) + break; + } + if (i < 0) { + /* Unknown chip: assume array element #0, original RTL-8169 */ + printk(KERN_DEBUG PFX + "PCI device %s: unknown chip version, assuming %s\n", + pci_name(pdev), rtl_chip_info[0].name); + i++; + } + tp->chipset = i; -match: *ioaddr_out = ioaddr; *dev_out = dev; return 0; @@ -499,7 +796,7 @@ rtl8169_init_one(struct pci_dev *pdev, c dev->stop = rtl8169_close; dev->tx_timeout = rtl8169_tx_timeout; dev->set_multicast_list = rtl8169_set_rx_mode; - dev->watchdog_timeo = TX_TIMEOUT; + dev->watchdog_timeo = RTL8169_TX_TIMEOUT; dev->irq = pdev->irq; dev->base_addr = (unsigned long) ioaddr; // dev->do_ioctl = mii_ioctl; @@ -528,12 +825,29 @@ rtl8169_init_one(struct pci_dev *pdev, c "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " "IRQ %d\n", dev->name, - board_info[ent->driver_data].name, + rtl_chip_info[ent->driver_data].name, dev->base_addr, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5], dev->irq); + rtl8169_hw_phy_config(dev); + + dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n"); + RTL_W8(0x82, 0x01); + + if (tp->mac_version < RTL_GIGA_MAC_VER_E) { + dprintk("Set PCI Latency=0x40\n"); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40); + } + + if (tp->mac_version == RTL_GIGA_MAC_VER_D) { + dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n"); + RTL_W8(0x82, 0x01); + dprintk("Set PHY Reg 0x0bh = 0x00h\n"); + mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0 + } + // if TBI is not endbled if (!(RTL_R8(PHYstatus) & TBI_Enable)) { int val = mdio_read(ioaddr, PHY_AUTO_NEGO_REG); @@ -546,23 +860,23 @@ rtl8169_init_one(struct pci_dev *pdev, c Cap10_100 = 0, Cap1000 = 0; switch (option) { case _10_Half: - Cap10_100 = PHY_Cap_10_Half; + Cap10_100 = PHY_Cap_10_Half_Or_Less; Cap1000 = PHY_Cap_Null; break; case _10_Full: - Cap10_100 = PHY_Cap_10_Full; + Cap10_100 = PHY_Cap_10_Full_Or_Less; Cap1000 = PHY_Cap_Null; break; case _100_Half: - Cap10_100 = PHY_Cap_100_Half; + Cap10_100 = PHY_Cap_100_Half_Or_Less; Cap1000 = PHY_Cap_Null; break; case _100_Full: - Cap10_100 = PHY_Cap_100_Full; + Cap10_100 = PHY_Cap_100_Full_Or_Less; Cap1000 = PHY_Cap_Null; break; case _1000_Full: - Cap10_100 = PHY_Cap_Null; + Cap10_100 = PHY_Cap_100_Full_Or_Less; Cap1000 = PHY_Cap_1000_Full; break; default: @@ -576,9 +890,7 @@ rtl8169_init_one(struct pci_dev *pdev, c // enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged mdio_write(ioaddr, PHY_AUTO_NEGO_REG, - PHY_Cap_10_Half | PHY_Cap_10_Full | - PHY_Cap_100_Half | PHY_Cap_100_Full | (val & - 0x1F)); + PHY_Cap_100_Full_Or_Less | (val & 0x1f)); // enable 1000 Full Mode mdio_write(ioaddr, PHY_1000_CTRL_REG, @@ -647,56 +959,96 @@ rtl8169_remove_one(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); } +#ifdef CONFIG_PM + +static int rtl8169_suspend(struct pci_dev *pdev, u32 state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct rtl8169_private *tp = dev->priv; + void *ioaddr = tp->mmio_addr; + unsigned long flags; + + if (!netif_running(dev)) + return 0; + + netif_device_detach(dev); + netif_stop_queue(dev); + spin_lock_irqsave(&tp->lock, flags); + + /* Disable interrupts, stop Rx and Tx */ + RTL_W16(IntrMask, 0); + RTL_W8(ChipCmd, 0); + + /* Update the error counts. */ + tp->stats.rx_missed_errors += RTL_R32(RxMissed); + RTL_W32(RxMissed, 0); + spin_unlock_irqrestore(&tp->lock, flags); + + return 0; +} + +static int rtl8169_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + if (!netif_running(dev)) + return 0; + + netif_device_attach(dev); + rtl8169_hw_start(dev); + + return 0; +} + +#endif /* CONFIG_PM */ + static int rtl8169_open(struct net_device *dev) { struct rtl8169_private *tp = dev->priv; + struct pci_dev *pdev = tp->pci_dev; int retval; - u8 diff; - u32 TxPhyAddr, RxPhyAddr; retval = request_irq(dev->irq, rtl8169_interrupt, SA_SHIRQ, dev->name, dev); - if (retval) { - return retval; - } + if (retval < 0) + goto out; - tp->TxDescArrays = - kmalloc(NUM_TX_DESC * sizeof (struct TxDesc) + 256, GFP_KERNEL); - // Tx Desscriptor needs 256 bytes alignment; - TxPhyAddr = virt_to_bus(tp->TxDescArrays); - diff = 256 - (TxPhyAddr - ((TxPhyAddr >> 8) << 8)); - TxPhyAddr += diff; - tp->TxDescArray = (struct TxDesc *) (tp->TxDescArrays + diff); - - tp->RxDescArrays = - kmalloc(NUM_RX_DESC * sizeof (struct RxDesc) + 256, GFP_KERNEL); - // Rx Desscriptor needs 256 bytes alignment; - RxPhyAddr = virt_to_bus(tp->RxDescArrays); - diff = 256 - (RxPhyAddr - ((RxPhyAddr >> 8) << 8)); - RxPhyAddr += diff; - tp->RxDescArray = (struct RxDesc *) (tp->RxDescArrays + diff); + retval = -ENOMEM; - if (tp->TxDescArrays == NULL || tp->RxDescArrays == NULL) { - printk(KERN_INFO - "Allocate RxDescArray or TxDescArray failed\n"); - free_irq(dev->irq, dev); - if (tp->TxDescArrays) - kfree(tp->TxDescArrays); - if (tp->RxDescArrays) - kfree(tp->RxDescArrays); - return -ENOMEM; - } - tp->RxBufferRings = kmalloc(RX_BUF_SIZE * NUM_RX_DESC, GFP_KERNEL); - if (tp->RxBufferRings == NULL) { - printk(KERN_INFO "Allocate RxBufferRing failed\n"); - } + /* + * Rx and Tx desscriptors needs 256 bytes alignment. + * pci_alloc_consistent provides more. + */ + tp->TxDescArray = pci_alloc_consistent(pdev, R8169_TX_RING_BYTES, + &tp->TxPhyAddr); + if (!tp->TxDescArray) + goto err_free_irq; + + tp->RxDescArray = pci_alloc_consistent(pdev, R8169_RX_RING_BYTES, + &tp->RxPhyAddr); + if (!tp->RxDescArray) + goto err_free_tx; + + retval = rtl8169_init_ring(dev); + if (retval < 0) + goto err_free_rx; - rtl8169_init_ring(dev); rtl8169_hw_start(dev); - return 0; - + rtl8169_request_timer(dev); +out: + return retval; + +err_free_rx: + pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray, + tp->RxPhyAddr); +err_free_tx: + pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray, + tp->TxPhyAddr); +err_free_irq: + free_irq(dev->irq, dev); + goto out; } static void @@ -733,11 +1085,17 @@ rtl8169_hw_start(struct net_device *dev) RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) | (InterFrameGap << TxInterFrameGapShift)); + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd)); + + if (tp->mac_version == RTL_GIGA_MAC_VER_D) { + dprintk(KERN_INFO PFX "Set MAC Reg C+CR Offset 0xE0: bit-3 and bit-14 MUST be 1\n"); + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | (1 << 14) | (1 << 3)); + } tp->cur_rx = 0; - RTL_W32(TxDescStartAddr, virt_to_bus(tp->TxDescArray)); - RTL_W32(RxDescStartAddr, virt_to_bus(tp->RxDescArray)); + RTL_W32(TxDescStartAddr, tp->TxPhyAddr); + RTL_W32(RxDescStartAddr, tp->RxPhyAddr); RTL_W8(Cfg9346, Cfg9346_Lock); udelay(10); @@ -755,31 +1113,131 @@ rtl8169_hw_start(struct net_device *dev) } -static void -rtl8169_init_ring(struct net_device *dev) +static inline void rtl8169_make_unusable_by_asic(struct RxDesc *desc) +{ + desc->buf_addr = 0xdeadbeef; + desc->status &= ~cpu_to_le32(OWNbit | RsvdMask); +} + +static void rtl8169_free_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff, + struct RxDesc *desc) +{ + pci_unmap_single(pdev, le32_to_cpu(desc->buf_addr), RX_BUF_SIZE, + PCI_DMA_FROMDEVICE); + dev_kfree_skb(*sk_buff); + *sk_buff = NULL; + rtl8169_make_unusable_by_asic(desc); +} + +static inline void rtl8169_return_to_asic(struct RxDesc *desc) +{ + desc->status |= cpu_to_le32(OWNbit + RX_BUF_SIZE); +} + +static inline void rtl8169_give_to_asic(struct RxDesc *desc, dma_addr_t mapping) +{ + desc->buf_addr = cpu_to_le32(mapping); + desc->status |= cpu_to_le32(OWNbit + RX_BUF_SIZE); +} + +static int rtl8169_alloc_rx_skb(struct pci_dev *pdev, struct net_device *dev, + struct sk_buff **sk_buff, struct RxDesc *desc) +{ + struct sk_buff *skb; + dma_addr_t mapping; + int ret = 0; + + skb = dev_alloc_skb(RX_BUF_SIZE); + if (!skb) + goto err_out; + + skb->dev = dev; + skb_reserve(skb, 2); + *sk_buff = skb; + + mapping = pci_map_single(pdev, skb->tail, RX_BUF_SIZE, + PCI_DMA_FROMDEVICE); + + rtl8169_give_to_asic(desc, mapping); + +out: + return ret; + +err_out: + ret = -ENOMEM; + rtl8169_make_unusable_by_asic(desc); + goto out; +} + +static void rtl8169_rx_clear(struct rtl8169_private *tp) { - struct rtl8169_private *tp = dev->priv; int i; - tp->cur_rx = 0; - tp->cur_tx = 0; - tp->dirty_tx = 0; + for (i = 0; i < NUM_RX_DESC; i++) { + if (tp->Rx_skbuff[i]) { + rtl8169_free_rx_skb(tp->pci_dev, tp->Rx_skbuff + i, + tp->RxDescArray + i); + } + } +} + +static u32 rtl8169_rx_fill(struct rtl8169_private *tp, struct net_device *dev, + u32 start, u32 end) +{ + u32 cur; + + for (cur = start; end - start > 0; cur++) { + int ret, i = cur % NUM_RX_DESC; + + if (tp->Rx_skbuff[i]) + continue; + + ret = rtl8169_alloc_rx_skb(tp->pci_dev, dev, tp->Rx_skbuff + i, + tp->RxDescArray + i); + if (ret < 0) + break; + } + return cur - start; +} + +static inline void rtl8169_mark_as_last_descriptor(struct RxDesc *desc) +{ + desc->status |= cpu_to_le32(EORbit); +} + +static int rtl8169_init_ring(struct net_device *dev) +{ + struct rtl8169_private *tp = dev->priv; + + tp->cur_rx = tp->dirty_rx = 0; + tp->cur_tx = tp->dirty_tx = 0; memset(tp->TxDescArray, 0x0, NUM_TX_DESC * sizeof (struct TxDesc)); memset(tp->RxDescArray, 0x0, NUM_RX_DESC * sizeof (struct RxDesc)); - for (i = 0; i < NUM_TX_DESC; i++) { - tp->Tx_skbuff[i] = NULL; - } - for (i = 0; i < NUM_RX_DESC; i++) { - if (i == (NUM_RX_DESC - 1)) - tp->RxDescArray[i].status = - (OWNbit | EORbit) + RX_BUF_SIZE; - else - tp->RxDescArray[i].status = OWNbit + RX_BUF_SIZE; + memset(tp->Tx_skbuff, 0x0, NUM_TX_DESC * sizeof(struct sk_buff *)); + memset(tp->Rx_skbuff, 0x0, NUM_RX_DESC * sizeof(struct sk_buff *)); - tp->RxBufferRing[i] = &(tp->RxBufferRings[i * RX_BUF_SIZE]); - tp->RxDescArray[i].buf_addr = virt_to_bus(tp->RxBufferRing[i]); - } + if (rtl8169_rx_fill(tp, dev, 0, NUM_RX_DESC) != NUM_RX_DESC) + goto err_out; + + rtl8169_mark_as_last_descriptor(tp->RxDescArray + NUM_RX_DESC - 1); + + return 0; + +err_out: + rtl8169_rx_clear(tp); + return -ENOMEM; +} + +static void rtl8169_unmap_tx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff, + struct TxDesc *desc) +{ + u32 len = sk_buff[0]->len; + + pci_unmap_single(pdev, le32_to_cpu(desc->buf_addr), + len < ETH_ZLEN ? ETH_ZLEN : len, PCI_DMA_TODEVICE); + desc->buf_addr = 0x00; + *sk_buff = NULL; } static void @@ -789,9 +1247,12 @@ rtl8169_tx_clear(struct rtl8169_private tp->cur_tx = 0; for (i = 0; i < NUM_TX_DESC; i++) { - if (tp->Tx_skbuff[i] != NULL) { - dev_kfree_skb(tp->Tx_skbuff[i]); - tp->Tx_skbuff[i] = NULL; + struct sk_buff *skb = tp->Tx_skbuff[i]; + + if (skb) { + rtl8169_unmap_tx_skb(tp->pci_dev, tp->Tx_skbuff + i, + tp->TxDescArray + i); + dev_kfree_skb(skb); tp->stats.tx_dropped++; } } @@ -829,41 +1290,51 @@ rtl8169_start_xmit(struct sk_buff *skb, struct rtl8169_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; int entry = tp->cur_tx % NUM_TX_DESC; + u32 len = skb->len; - if (skb->len < ETH_ZLEN) { + if (unlikely(skb->len < ETH_ZLEN)) { skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) - return 0; + if (!skb) + goto err_update_stats; + len = ETH_ZLEN; } spin_lock_irq(&tp->lock); - if ((tp->TxDescArray[entry].status & OWNbit) == 0) { + if (!(le32_to_cpu(tp->TxDescArray[entry].status) & OWNbit)) { + dma_addr_t mapping; + + mapping = pci_map_single(tp->pci_dev, skb->data, len, + PCI_DMA_TODEVICE); + tp->Tx_skbuff[entry] = skb; - tp->TxDescArray[entry].buf_addr = virt_to_bus(skb->data); - if (entry != (NUM_TX_DESC - 1)) - tp->TxDescArray[entry].status = - (OWNbit | FSbit | LSbit) | ((skb->len > ETH_ZLEN) ? - skb->len : ETH_ZLEN); - else - tp->TxDescArray[entry].status = - (OWNbit | EORbit | FSbit | LSbit) | - ((skb->len > ETH_ZLEN) ? skb->len : ETH_ZLEN); + tp->TxDescArray[entry].buf_addr = cpu_to_le32(mapping); + tp->TxDescArray[entry].status = cpu_to_le32(OWNbit | FSbit | + LSbit | len | (EORbit * !((entry + 1) % NUM_TX_DESC))); + RTL_W8(TxPoll, 0x40); //set polling bit dev->trans_start = jiffies; tp->cur_tx++; - } + } else + goto err_drop; - spin_unlock_irq(&tp->lock); if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) { netif_stop_queue(dev); } +out: + spin_unlock_irq(&tp->lock); return 0; + +err_drop: + dev_kfree_skb(skb); +err_update_stats: + tp->stats.tx_dropped++; + goto out; } static void @@ -881,11 +1352,17 @@ rtl8169_tx_interrupt(struct net_device * tx_left = tp->cur_tx - dirty_tx; while (tx_left > 0) { - if ((tp->TxDescArray[entry].status & OWNbit) == 0) { - dev_kfree_skb_irq(tp-> - Tx_skbuff[dirty_tx % NUM_TX_DESC]); - tp->Tx_skbuff[dirty_tx % NUM_TX_DESC] = NULL; + if (!(le32_to_cpu(tp->TxDescArray[entry].status) & OWNbit)) { + int cur = dirty_tx % NUM_TX_DESC; + struct sk_buff *skb = tp->Tx_skbuff[cur]; + + /* FIXME: is it really accurate for TxErr ? */ + tp->stats.tx_bytes += skb->len >= ETH_ZLEN ? + skb->len : ETH_ZLEN; tp->stats.tx_packets++; + rtl8169_unmap_tx_skb(tp->pci_dev, tp->Tx_skbuff + cur, + tp->TxDescArray + cur); + dev_kfree_skb_irq(skb); dirty_tx++; tx_left--; entry++; @@ -899,70 +1376,95 @@ rtl8169_tx_interrupt(struct net_device * } } +static inline int rtl8169_try_rx_copy(struct sk_buff **sk_buff, int pkt_size, + struct RxDesc *desc, + struct net_device *dev) +{ + int ret = -1; + + if (pkt_size < rx_copybreak) { + struct sk_buff *skb; + + skb = dev_alloc_skb(pkt_size + 2); + if (skb) { + skb->dev = dev; + skb_reserve(skb, 2); + eth_copy_and_sum(skb, sk_buff[0]->tail, pkt_size, 0); + *sk_buff = skb; + rtl8169_return_to_asic(desc); + ret = 0; + } + } + return ret; +} + static void rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, void *ioaddr) { - int cur_rx; - struct sk_buff *skb; - int pkt_size = 0; + int cur_rx, delta; assert(dev != NULL); assert(tp != NULL); assert(ioaddr != NULL); - cur_rx = tp->cur_rx; + cur_rx = tp->cur_rx % RX_BUF_SIZE; - while ((tp->RxDescArray[cur_rx].status & OWNbit) == 0) { + while (!(le32_to_cpu(tp->RxDescArray[cur_rx].status) & OWNbit)) { + u32 status = le32_to_cpu(tp->RxDescArray[cur_rx].status); - if (tp->RxDescArray[cur_rx].status & RxRES) { + if (status & RxRES) { printk(KERN_INFO "%s: Rx ERROR!!!\n", dev->name); tp->stats.rx_errors++; - if (tp->RxDescArray[cur_rx].status & (RxRWT | RxRUNT)) + if (status & (RxRWT | RxRUNT)) tp->stats.rx_length_errors++; - if (tp->RxDescArray[cur_rx].status & RxCRC) + if (status & RxCRC) tp->stats.rx_crc_errors++; } else { - pkt_size = - (int) (tp->RxDescArray[cur_rx]. - status & 0x00001FFF) - 4; - skb = dev_alloc_skb(pkt_size + 2); - if (skb != NULL) { - skb->dev = dev; - skb_reserve(skb, 2); // 16 byte align the IP fields. // - eth_copy_and_sum(skb, tp->RxBufferRing[cur_rx], - pkt_size, 0); - skb_put(skb, pkt_size); - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - - if (cur_rx == (NUM_RX_DESC - 1)) - tp->RxDescArray[cur_rx].status = - (OWNbit | EORbit) + RX_BUF_SIZE; - else - tp->RxDescArray[cur_rx].status = - OWNbit + RX_BUF_SIZE; - - tp->RxDescArray[cur_rx].buf_addr = - virt_to_bus(tp->RxBufferRing[cur_rx]); - dev->last_rx = jiffies; - tp->stats.rx_bytes += pkt_size; - tp->stats.rx_packets++; - } else { - printk(KERN_WARNING - "%s: Memory squeeze, deferring packet.\n", - dev->name); - /* We should check that some rx space is free. - If not, free one and mark stats->rx_dropped++. */ - tp->stats.rx_dropped++; + struct RxDesc *desc = tp->RxDescArray + cur_rx; + struct sk_buff *skb = tp->Rx_skbuff[cur_rx]; + int pkt_size = (status & 0x00001FFF) - 4; + + pci_dma_sync_single(tp->pci_dev, + le32_to_cpu(desc->buf_addr), + RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + + if (rtl8169_try_rx_copy(&skb, pkt_size, desc, dev)) { + pci_unmap_single(tp->pci_dev, + le32_to_cpu(desc->buf_addr), + RX_BUF_SIZE, + PCI_DMA_FROMDEVICE); + tp->Rx_skbuff[cur_rx] = NULL; } - } - - cur_rx = (cur_rx + 1) % NUM_RX_DESC; - - } - tp->cur_rx = cur_rx; + skb_put(skb, pkt_size); + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + + dev->last_rx = jiffies; + tp->stats.rx_bytes += pkt_size; + tp->stats.rx_packets++; + } + + tp->cur_rx++; + cur_rx = tp->cur_rx % NUM_RX_DESC; + } + + delta = rtl8169_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx); + if (delta > 0) + tp->dirty_rx += delta; + else if (delta < 0) + printk(KERN_INFO "%s: no Rx buffer allocated\n", dev->name); + + /* + * FIXME: until there is periodic timer to try and refill the ring, + * a temporary shortage may definitely kill the Rx process. + * - disable the asic to try and avoid an overflow and kick it again + * after refill ? + * - how do others driver handle this condition (Uh oh...). + */ + if (tp->dirty_rx + NUM_RX_DESC == tp->cur_rx) + printk(KERN_EMERG "%s: Rx buffers exhausted\n", dev->name); } /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ @@ -991,9 +1493,7 @@ rtl8169_interrupt(int irq, void *dev_ins RTL_W16(IntrStatus, (status & RxFIFOOver) ? (status | RxOverflow) : status); - if ((status & - (SYSErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver - | TxErr | TxOK | RxErr | RxOK)) == 0) + if (!(status & rtl8169_intr_mask)) break; // Rx interrupt @@ -1023,11 +1523,13 @@ static int rtl8169_close(struct net_device *dev) { struct rtl8169_private *tp = dev->priv; + struct pci_dev *pdev = tp->pci_dev; void *ioaddr = tp->mmio_addr; - int i; netif_stop_queue(dev); + rtl8169_delete_timer(dev); + spin_lock_irq(&tp->lock); /* Stop the chip's Tx and Rx DMA processes. */ @@ -1046,16 +1548,15 @@ rtl8169_close(struct net_device *dev) free_irq(dev->irq, dev); rtl8169_tx_clear(tp); - kfree(tp->TxDescArrays); - kfree(tp->RxDescArrays); - tp->TxDescArrays = NULL; - tp->RxDescArrays = NULL; + + rtl8169_rx_clear(tp); + + pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray, + tp->RxPhyAddr); + pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray, + tp->TxPhyAddr); tp->TxDescArray = NULL; tp->RxDescArray = NULL; - kfree(tp->RxBufferRings); - for (i = 0; i < NUM_RX_DESC; i++) { - tp->RxBufferRing[i] = NULL; - } return 0; } @@ -1109,11 +1610,26 @@ rtl8169_set_rx_mode(struct net_device *d spin_unlock_irqrestore(&tp->lock, flags); } +/** + * rtl8169_get_stats - Get rtl8169 read/write statistics + * @dev: The Ethernet Device to get statistics for + * + * Get TX/RX statistics for rtl8169 + */ struct net_device_stats * rtl8169_get_stats(struct net_device *dev) { struct rtl8169_private *tp = dev->priv; + void *ioaddr = tp->mmio_addr; + unsigned long flags; + if (netif_running(dev)) { + spin_lock_irqsave(&tp->lock, flags); + tp->stats.rx_missed_errors += RTL_R32(RxMissed); + RTL_W32(RxMissed, 0); + spin_unlock_irqrestore(&tp->lock, flags); + } + return &tp->stats; } @@ -1122,8 +1638,10 @@ static struct pci_driver rtl8169_pci_dri .id_table = rtl8169_pci_tbl, .probe = rtl8169_init_one, .remove = __devexit_p(rtl8169_remove_one), - .suspend = NULL, - .resume = NULL, +#ifdef CONFIG_PM + .suspend = rtl8169_suspend, + .resume = rtl8169_resume, +#endif }; static int __init diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/saa9730.c 830-ivtv/drivers/net/saa9730.c --- 000-virgin/drivers/net/saa9730.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/saa9730.c Thu Jan 8 08:54:21 2004 @@ -996,11 +996,11 @@ static void __devexit saa9730_remove_one struct net_device *dev = pci_get_drvdata(pdev); if (dev) { - + unregister_netdev(dev); + if (dev->priv) kfree(dev->priv); - unregister_netdev(dev); free_netdev(dev); pci_release_regions(pdev); pci_disable_device(pdev); @@ -1015,17 +1015,10 @@ static int lan_saa9730_init(struct net_d unsigned char ethernet_addr[6]; int ret = 0; - dev = init_etherdev(dev, 0); - - if (!dev) - return -ENOMEM; - dev->open = lan_saa9730_open_fail; - if (get_ethernet_addr(ethernet_addr)) { - ret = -ENODEV; - goto out; - } + if (get_ethernet_addr(ethernet_addr)) + return -ENODEV; memcpy(dev->dev_addr, ethernet_addr, 6); dev->base_addr = ioaddr; @@ -1040,10 +1033,8 @@ static int lan_saa9730_init(struct net_d GFP_DMA | GFP_KERNEL) + 7) & ~7); - if (!lp) { - ret = -ENOMEM; - goto out; - } + if (!lp) + return -ENOMEM; dev->priv = lp; memset(lp, 0, sizeof(*lp)); @@ -1057,6 +1048,7 @@ static int lan_saa9730_init(struct net_d SAA9730_EVM_REGS_ADDR); /* Allocate LAN RX/TX frame buffer space. */ + /* FIXME: a leak */ if ((ret = lan_saa9730_allocate_buffers(lp))) goto out; @@ -1095,63 +1087,70 @@ static int lan_saa9730_init(struct net_d dev->watchdog_timeo = (HZ >> 1); dev->dma = 0; + ret = register_netdev(dev); + if (ret) + goto out; return 0; out: - if (dev) { - if (dev->priv) - kfree(dev->priv); - unregister_netdevice(dev); - free_netdev(dev); - } - + if (dev->priv) + kfree(dev->priv); + free_netdev(dev); return ret; } static int __devinit saa9730_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { - struct net_device *dev = NULL; + struct net_device *dev; unsigned int pci_ioaddr; int err; if (lan_saa9730_debug > 1) printk("saa9730.c: PCI bios is present, checking for devices...\n"); + err = -ENOMEM; + dev = alloc_etherdev(0); + if (!dev) + goto out; + + SET_MODULE_OWNER(dev); + err = pci_enable_device(pdev); if (err) { printk(KERN_ERR "Cannot enable PCI device, aborting.\n"); - goto out; + goto out1; } err = pci_request_regions(pdev, DRV_MODULE_NAME); if (err) { printk(KERN_ERR "Cannot obtain PCI resources, aborting.\n"); - goto out_disable_pdev; + goto out2; } pci_irq_line = pdev->irq; /* LAN base address in located at BAR 1. */ - + pci_ioaddr = pci_resource_start(pdev, 1); pci_set_master(pdev); - + printk("Found SAA9730 (PCI) at %#x, irq %d.\n", pci_ioaddr, pci_irq_line); err = lan_saa9730_init(dev, pci_ioaddr, pci_irq_line); if (err) { printk("Lan init failed"); - goto out_disable_pdev; + goto out2; } - + pci_set_drvdata(pdev, dev); return 0; - out_disable_pdev: +out2: pci_disable_device(pdev); - out: - pci_set_drvdata(pdev, NULL); +out1: + free_netdev(dev); +out: return err; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sb1250-mac.c 830-ivtv/drivers/net/sb1250-mac.c --- 000-virgin/drivers/net/sb1250-mac.c Tue Sep 2 09:55:47 2003 +++ 830-ivtv/drivers/net/sb1250-mac.c Thu Jan 8 08:54:22 2004 @@ -2372,6 +2372,7 @@ static int sbmac_init(struct net_device unsigned char *eaddr; uint64_t ea_reg; int i; + int err; sc = (struct sbmac_softc *)dev->priv; @@ -2430,7 +2431,6 @@ static int sbmac_init(struct net_device spin_lock_init(&(sc->sbm_lock)); - ether_setup(dev); dev->open = sbmac_open; dev->hard_start_xmit = sbmac_start_tx; dev->stop = sbmac_close; @@ -2444,8 +2444,11 @@ static int sbmac_init(struct net_device /* This is needed for PASS2 for Rx H/W checksum feature */ sbmac_set_iphdr_offset(sc); - - return 0; + + err = register_netdev(dev); + if (err) + sbmac_uninitctx(sc); + return err; } @@ -2811,13 +2814,12 @@ sbmac_setup_hwaddr(int chan,char *addr) } #endif -static struct net_device *dev_sbmac[MAX_UNITS] = {0,0,0}; +static struct net_device *dev_sbmac[MAX_UNITS]; static int __init sbmac_init_module(void) { int idx; - int macidx = 0; struct net_device *dev; sbmac_port_t port; int chip_max_units; @@ -2884,26 +2886,24 @@ sbmac_init_module(void) * Okay, cool. Initialize this MAC. */ - dev = init_etherdev(NULL,sizeof(struct sbmac_softc)); + dev = alloc_etherdev(sizeof(struct sbmac_softc)); if (!dev) - return -ENOMEM; /* return ENOMEM */ + return -ENOMEM; /* return ENOMEM */ printk(KERN_DEBUG "sbmac: configuring MAC at %lx\n", port); dev->irq = K_INT_MAC_0 + idx; dev->base_addr = port; dev->mem_end = 0; - /*dev->init = sbmac_init;*/ - sbmac_init(dev, macidx); - - dev_sbmac[macidx] = dev; - macidx++; + if (sbmac_init(dev, idx)) { + port = A_MAC_CHANNEL_BASE(idx); + SBMAC_WRITECSR(KSEG1ADDR(port+R_MAC_ETHERNET_ADDR), + sbmac_orig_hwaddr[idx] ); + free_netdev(dev); + continue; + } + dev_sbmac[idx++] = dev; } - - /* - * Should we care, 'macidx' is the total number of enabled MACs. - */ - return 0; } @@ -2916,21 +2916,12 @@ sbmac_cleanup_module(void) sbmac_port_t port; for (idx = 0; idx < MAX_UNITS; idx++) { dev = dev_sbmac[idx]; - if (dev == NULL) - continue; - if (dev->priv != NULL) { - struct sbmac_softc *sc = (struct sbmac_softc *) dev->priv; - + if (!dev) { + struct sbmac_softc *sc = dev->priv; unregister_netdev(dev); - sbmac_uninitctx(sc); - + free_netdev(dev); } - - port = A_MAC_CHANNEL_BASE(idx); - SBMAC_WRITECSR(KSEG1ADDR(port+R_MAC_ETHERNET_ADDR), sbmac_orig_hwaddr[idx] ); - free_netdev(dev); - dev_sbmac[idx] = NULL; } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/seeq8005.c 830-ivtv/drivers/net/seeq8005.c --- 000-virgin/drivers/net/seeq8005.c Mon Nov 17 18:28:15 2003 +++ 830-ivtv/drivers/net/seeq8005.c Thu Jan 8 08:54:22 2004 @@ -78,8 +78,6 @@ struct net_local { /* Index to functions, as function prototypes. */ -extern int seeq8005_probe(struct net_device *dev); - static int seeq8005_probe1(struct net_device *dev, int ioaddr); static int seeq8005_open(struct net_device *dev); static void seeq8005_timeout(struct net_device *dev); @@ -102,22 +100,48 @@ static inline void wait_for_buffer(struc If dev->base_addr == 1, always return failure. */ -int __init -seeq8005_probe(struct net_device *dev) -{ - int i; - int base_addr = dev ? dev->base_addr : 0; - - if (base_addr > 0x1ff) /* Check a single specified location. */ - return seeq8005_probe1(dev, base_addr); - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; - - for (i = 0; seeq8005_portlist[i]; i++) - if (seeq8005_probe1(dev, seeq8005_portlist[i]) == 0) - return 0; +static int io = 0x320; +static int irq = 10; - return -ENODEV; +struct net_device * __init seeq8005_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); + unsigned *port; + int err = 0; + + if (!dev) + return ERR_PTR(-ENODEV); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + irq = dev->irq; + } + + if (io > 0x1ff) { /* Check a single specified location. */ + err = seeq8005_probe1(dev, io); + } else if (io != 0) { /* Don't probe at all. */ + err = -ENXIO; + } else { + for (port = seeq8005_portlist; *port; port++) { + if (seeq8005_probe1(dev, *port) == 0) + break; + } + if (!*port) + err = -ENODEV; + } + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + release_region(dev->base_addr, SEEQ8005_IO_EXTENT); +out: + free_netdev(dev); + return ERR_PTR(err); } /* This is the real probe routine. Linux has a history of friendly device @@ -274,6 +298,7 @@ static int __init seeq8005_probe1(struct /* Fill in the 'dev' fields. */ dev->base_addr = ioaddr; + dev->irq = irq; /* Retrieve and print the ethernet address. */ for (i = 0; i < 6; i++) @@ -307,13 +332,6 @@ static int __init seeq8005_probe1(struct } } #endif - - /* Initialize the device structure. */ - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct net_local)); - dev->open = seeq8005_open; dev->stop = seeq8005_close; dev->hard_start_xmit = seeq8005_send_packet; @@ -321,10 +339,6 @@ static int __init seeq8005_probe1(struct dev->watchdog_timeo = HZ/20; dev->get_stats = seeq8005_get_stats; dev->set_multicast_list = set_multicast_list; - - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - dev->flags &= ~IFF_MULTICAST; return 0; @@ -721,9 +735,7 @@ inline void wait_for_buffer(struct net_d #ifdef MODULE -static struct net_device dev_seeq = { .init = seeq8005_probe }; -static int io = 0x320; -static int irq = 10; +static struct net_device *dev_seeq; MODULE_LICENSE("GPL"); MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); @@ -732,28 +744,17 @@ MODULE_PARM_DESC(irq, "SEEQ 8005 IRQ num int init_module(void) { - dev_seeq.irq=irq; - dev_seeq.base_addr=io; - if (register_netdev(&dev_seeq) != 0) - return -EIO; + dev_seeq = seeq8005_probe(-1); + if (IS_ERR(dev_seeq)) + return PTR_ERR(dev_seeq); return 0; } void cleanup_module(void) { - unregister_netdev(&dev_seeq); - - /* - * Free up the private structure, or leak memory :-) - */ - - kfree(dev_seeq.priv); - dev_seeq.priv = NULL; /* gets re-allocated by el1_probe1 */ - - /* - * If we don't do this, we can't re-insmod it later. - */ - release_region(dev_seeq.base_addr, SEEQ8005_IO_EXTENT); + unregister_netdev(dev_seeq); + release_region(dev_seeq->base_addr, SEEQ8005_IO_EXTENT); + free_netdev(dev_seeq); } #endif /* MODULE */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sgiseeq.c 830-ivtv/drivers/net/sgiseeq.c --- 000-virgin/drivers/net/sgiseeq.c Tue Sep 2 09:55:47 2003 +++ 830-ivtv/drivers/net/sgiseeq.c Thu Jan 8 08:54:22 2004 @@ -600,6 +600,7 @@ int sgiseeq_init(struct hpc3_regs* regs, { struct net_device *dev; struct sgiseeq_private *sp; + int err = -ENOMEM; int i; sp = (struct sgiseeq_private *) get_zeroed_page(GFP_KERNEL); @@ -609,19 +610,17 @@ int sgiseeq_init(struct hpc3_regs* regs, return -ENOMEM; } - dev = init_etherdev(NULL, 0); + dev = alloc_etherdev(0); if (!dev) { printk (KERN_ERR "Seeq8003: Could not allocate memory for device.\n"); - free_page((unsigned long) sp); - return -ENOMEM; + goto out; } if (request_irq(irq, sgiseeq_interrupt, 0, sgiseeqstr, dev)) { - printk(KERN_ERR "Seeq8003: Can't get irq %d\n", dev->irq); - free_page((unsigned long) sp); - unregister_netdev(dev); - return -EAGAIN; + printk(KERN_ERR "Seeq8003: Can't get irq %d\n", irq); + err = -EAGAIN; + goto out1; } printk(KERN_INFO "%s: SGI Seeq8003 ", dev->name); @@ -637,6 +636,8 @@ int sgiseeq_init(struct hpc3_regs* regs, } printk("\n"); + SET_MODULE_OWNER(dev); + dev->priv = sp; #ifdef DEBUG gpriv = sp; @@ -677,12 +678,22 @@ int sgiseeq_init(struct hpc3_regs* regs, dev->set_multicast_list = sgiseeq_set_multicast; dev->irq = irq; dev->dma = 0; - ether_setup(dev); + + err = register_netdev(dev); + if (err) + goto out2; sp->next_module = root_sgiseeq_dev; root_sgiseeq_dev = dev; return 0; +out2: + free_irq(dev->irq, dev); +out1: + free_netdev(dev); +out: + free_page((unsigned long) sp); + return err; } static int __init sgiseeq_probe(void) @@ -701,9 +712,9 @@ static void __exit sgiseeq_exit(void) while (dev) { sp = (struct sgiseeq_private *) dev->priv; next = sp->next_module; + unregister_netdev(dev); free_irq(dev->irq, dev); free_page((unsigned long) sp); - unregister_netdev(dev); free_netdev(dev); dev = next; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/shaper.c 830-ivtv/drivers/net/shaper.c --- 000-virgin/drivers/net/shaper.c Tue Sep 2 09:55:47 2003 +++ 830-ivtv/drivers/net/shaper.c Thu Jan 8 08:54:22 2004 @@ -718,8 +718,10 @@ static int __init shaper_init(void) if (!dev) break; - if (register_netdev(dev)) + if (register_netdev(dev)) { + free_netdev(dev); break; + } devs[i] = dev; shapers_registered++; @@ -737,9 +739,12 @@ static void __exit shaper_exit (void) { int i; - for (i = 0; i < shapers_registered; i++) - if (devs[i]) + for (i = 0; i < shapers_registered; i++) { + if (devs[i]) { unregister_netdev(devs[i]); + free_netdev(devs[i]); + } + } kfree(devs); devs = NULL; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/Makefile 830-ivtv/drivers/net/sk98lin/Makefile --- 000-virgin/drivers/net/sk98lin/Makefile Wed Aug 13 20:24:25 2003 +++ 830-ivtv/drivers/net/sk98lin/Makefile Thu Jan 8 08:54:22 2004 @@ -76,7 +76,7 @@ endif # SK_DBGCAT_DRV_INT_SRC 0x04000000 interrupts sources # SK_DBGCAT_DRV_EVENT 0x08000000 driver events -EXTRA_CFLAGS += -Idrivers/net/sk98lin -DSK_USE_CSUM -DGENESIS -DYUKON $(DBGDEF) $(SKPARAM) +EXTRA_CFLAGS += -Idrivers/net/sk98lin -DSK_DIAG_SUPPORT -DSK_USE_CSUM -DGENESIS -DYUKON $(DBGDEF) $(SKPARAM) clean: rm -f core *.o *.a *.s diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/h/skcsum.h 830-ivtv/drivers/net/sk98lin/h/skcsum.h --- 000-virgin/drivers/net/sk98lin/h/skcsum.h Sun Nov 17 20:29:22 2002 +++ 830-ivtv/drivers/net/sk98lin/h/skcsum.h Thu Jan 8 08:54:22 2004 @@ -2,8 +2,8 @@ * * Name: skcsum.h * Project: GEnesis - SysKonnect SK-NET Gigabit Ethernet (SK-98xx) - * Version: $Revision: 1.9 $ - * Date: $Date: 2001/02/06 11:21:39 $ + * Version: $Revision: 1.10 $ + * Date: $Date: 2003/08/20 13:59:57 $ * Purpose: Store/verify Internet checksum in send/receive packets. * ******************************************************************************/ @@ -26,6 +26,10 @@ * History: * * $Log: skcsum.h,v $ + * Revision 1.10 2003/08/20 13:59:57 mschmid + * Changed notation of #ifndef SkCsCalculateChecksum to + * #ifndef SK_CS_CALCULATE_CHECKSUM + * * Revision 1.9 2001/02/06 11:21:39 rassmann * Editorial changes. * @@ -226,11 +230,11 @@ typedef struct s_CsPacketInfo { /* function prototypes ********************************************************/ -#ifndef SkCsCalculateChecksum +#ifndef SK_CS_CALCULATE_CHECKSUM extern unsigned SkCsCalculateChecksum( void *pData, unsigned Length); -#endif +#endif /* SK_CS_CALCULATE_CHECKSUM */ extern int SkCsEvent( SK_AC *pAc, diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/h/skdrv1st.h 830-ivtv/drivers/net/sk98lin/h/skdrv1st.h --- 000-virgin/drivers/net/sk98lin/h/skdrv1st.h Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/sk98lin/h/skdrv1st.h Thu Jan 8 08:54:22 2004 @@ -2,15 +2,16 @@ * * Name: skdrv1st.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.1 $ - * Date: $Date: 2003/07/21 07:22:43 $ + * Version: $Revision: 1.4 $ + * Date: $Date: 2003/11/12 14:28:14 $ * Purpose: First header file for driver and all other modules * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998-2003 SysKonnect GmbH. + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +27,15 @@ * History: * * $Log: skdrv1st.h,v $ + * Revision 1.4 2003/11/12 14:28:14 rroesler + * Fix: use dedicated ip_fast_csum() on X86_64 systems + * + * Revision 1.3 2003/10/07 08:16:52 mlindner + * Fix: Copyright changes + * + * Revision 1.2 2003/09/29 12:05:59 mlindner + * Fix: Added define SK_CS_CALCULSTE_CHECKSUM + * * Revision 1.1 2003/07/21 07:22:43 rroesler * Fix: Re-Enter after CVS crash * @@ -110,6 +120,9 @@ #ifndef __INC_SKDRV1ST_H #define __INC_SKDRV1ST_H +/* Check kernel version */ +#include + typedef struct s_AC SK_AC; /* Set card versions */ @@ -124,17 +137,15 @@ typedef struct s_AC SK_AC; #define SK_PNMI_READ_U32(p,v) memcpy((char*)&(v),(char*)(p),4) #define SK_PNMI_READ_U64(p,v) memcpy((char*)&(v),(char*)(p),8) -#define SkCsCalculateChecksum(p,l) ((~ip_compute_csum(p, l)) & 0xffff) - #define SK_ADDR_EQUAL(a1,a2) (!memcmp(a1,a2,6)) - #if !defined(__OPTIMIZE__) || !defined(__KERNEL__) #warning You must compile this file with the correct options! #warning See the last lines of the source file. #error You must compile this driver with "-O". #endif +#include #include #include #include @@ -153,6 +164,13 @@ typedef struct s_AC SK_AC; #include #include #include + +#define SK_CS_CALCULATE_CHECKSUM +#ifndef CONFIG_X86_64 +#define SkCsCalculateChecksum(p,l) ((~ip_compute_csum(p, l)) & 0xffff) +#else +#define SkCsCalculateChecksum(p,l) ((~ip_fast_csum(p, l)) & 0xffff) +#endif #include "h/sktypes.h" #include "h/skerror.h" diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/h/skdrv2nd.h 830-ivtv/drivers/net/sk98lin/h/skdrv2nd.h --- 000-virgin/drivers/net/sk98lin/h/skdrv2nd.h Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/sk98lin/h/skdrv2nd.h Thu Jan 8 08:54:22 2004 @@ -2,15 +2,16 @@ * * Name: skdrv2nd.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.3 $ - * Date: $Date: 2003/08/12 16:51:18 $ + * Version: $Revision: 1.10 $ + * Date: $Date: 2003/12/11 16:04:45 $ * Purpose: Second header file for driver and all other modules * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998-2003 SysKonnect GmbH. + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +27,27 @@ * History: * * $Log: skdrv2nd.h,v $ + * Revision 1.10 2003/12/11 16:04:45 mlindner + * Add: New pnmi data backup structure + * + * Revision 1.9 2003/11/10 09:31:37 rroesler + * Add: pnmiBackup structure for DIAG backup restore + * + * Revision 1.8 2003/10/22 14:18:32 rroesler + * Fix: DIAG handling for DualNet cards + * + * Revision 1.7 2003/10/07 09:34:59 mlindner + * Add: New defines for lower and upper range values (interrupt moderation) + * + * Revision 1.6 2003/10/07 08:16:51 mlindner + * Fix: Copyright changes + * + * Revision 1.5 2003/09/01 13:10:39 rroesler + * Add: Prototypes for DIAG Attach/Detach functions + * + * Revision 1.4 2003/09/01 12:33:38 rroesler + * Add: Defines for optimized DIAG interaction + * * Revision 1.3 2003/08/12 16:51:18 mlindner * Fix: UDP and TCP Proto checks * Fix: UDP header offset @@ -206,6 +228,11 @@ extern int SkPciWriteCfgWord(SK_AC*, in extern int SkPciWriteCfgByte(SK_AC*, int, SK_U8); extern int SkDrvEvent(SK_AC*, SK_IOC IoC, SK_U32, SK_EVPARA); +#ifdef SK_DIAG_SUPPORT +extern int SkDrvEnterDiagMode(SK_AC *pAc); +extern int SkDrvLeaveDiagMode(SK_AC *pAc); +#endif + struct s_DrvRlmtMbuf { SK_MBUF *pNext; /* Pointer to next RLMT Mbuf. */ SK_U8 *pData; /* Data buffer (virtually contig.). */ @@ -247,6 +274,7 @@ struct s_DrvRlmtMbuf { #define SK_IOCTL_SETMIB (SK_IOCTL_BASE + 1) #define SK_IOCTL_PRESETMIB (SK_IOCTL_BASE + 2) #define SK_IOCTL_GEN (SK_IOCTL_BASE + 3) +#define SK_IOCTL_DIAG (SK_IOCTL_BASE + 4) typedef struct s_IOCTL SK_GE_IOCTL; @@ -462,6 +490,9 @@ struct s_RxPort { #define C_INTS_PER_SEC_DEFAULT 2000 #define C_INT_MOD_ENABLE_PERCENTAGE 50 /* if higher 50% enable */ #define C_INT_MOD_DISABLE_PERCENTAGE 50 /* if lower 50% disable */ +#define C_INT_MOD_IPS_LOWER_RANGE 30 +#define C_INT_MOD_IPS_UPPER_RANGE 40000 + typedef struct s_DynIrqModInfo DIM_INFO; struct s_DynIrqModInfo { @@ -493,6 +524,11 @@ typedef struct s_PerStrm PER_STRM; #define SK_ALLOC_IRQ 0x00000001 +#ifdef SK_DIAG_SUPPORT +#define DIAG_ACTIVE 1 +#define DIAG_NOTACTIVE 0 +#endif + /**************************************************************************** * Per board structure / Adapter Context structure: * Allocated within attach(9e) and freed within detach(9e). @@ -563,9 +599,18 @@ struct s_AC { int PortUp; int PortDown; int ChipsetType; /* Chipset family type - * 0 == Genesis family support - * 1 == Yukon family support - */ + * 0 == Genesis family support + * 1 == Yukon family support + */ +#ifdef SK_DIAG_SUPPORT + SK_U32 DiagModeActive; /* is diag active? */ + SK_BOOL DiagFlowCtrl; /* for control purposes */ + SK_PNMI_STRUCT_DATA PnmiBackup; /* backup structure for all Pnmi-Data */ + SK_BOOL WasIfUp[SK_MAX_MACS]; /* for OpenClose while + * DIAG is busy with NIC + */ +#endif + }; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/h/skgehw.h 830-ivtv/drivers/net/sk98lin/h/skgehw.h --- 000-virgin/drivers/net/sk98lin/h/skgehw.h Wed Aug 13 20:24:25 2003 +++ 830-ivtv/drivers/net/sk98lin/h/skgehw.h Thu Jan 8 08:54:22 2004 @@ -2,8 +2,8 @@ * * Name: skgehw.h * Project: Gigabit Ethernet Adapters, Common Modules - * Version: $Revision: 1.53 $ - * Date: $Date: 2003/07/04 12:39:01 $ + * Version: $Revision: 1.56 $ + * Date: $Date: 2003/09/23 09:01:00 $ * Purpose: Defines and Macros for the Gigabit Ethernet Adapter Product Family * ******************************************************************************/ @@ -26,6 +26,17 @@ * * History: * $Log: skgehw.h,v $ + * Revision 1.56 2003/09/23 09:01:00 malthoff + * Minor change: Define I2C device size constants as long. + * + * Revision 1.55 2003/09/16 14:03:34 rschmidt + * Added define for YUKON-Lite Rev. A1,A2 Chip Revision + * Moved defines for PHY power down modes to skgeinit.h + * Editorial changes + * + * Revision 1.54 2003/09/16 07:37:58 mschmid + * Added defines for Marvell PHY low power modes + * * Revision 1.53 2003/07/04 12:39:01 rschmidt * Added SK_FAR to pointers in XM_IN32() and GM_IN32() macros (for PXE) * Editorial changes @@ -84,7 +95,7 @@ * Editorial changes * * Revision 1.39 2002/06/10 09:37:07 rschmidt - * Added macros for the ADDR-Modul + * Added macros for the ADDR-Module * * Revision 1.38 2002/06/05 08:15:19 rschmidt * Added defines for WOL Registers @@ -628,12 +639,12 @@ extern "C" { #define B2_FAR 0x0120 /* 32 bit Flash-Prom Addr Reg/Cnt */ #define B2_FDP 0x0124 /* 8 bit Flash-Prom Data Port */ /* 0x0125 - 0x0127: reserved */ -#define B2_LD_CRTL 0x0128 /* 8 bit EPROM loader control register */ +#define B2_LD_CTRL 0x0128 /* 8 bit EPROM loader control register */ #define B2_LD_TEST 0x0129 /* 8 bit EPROM loader test register */ /* 0x012a - 0x012f: reserved */ #define B2_TI_INI 0x0130 /* 32 bit Timer Init Value */ #define B2_TI_VAL 0x0134 /* 32 bit Timer Value */ -#define B2_TI_CRTL 0x0138 /* 8 bit Timer Control */ +#define B2_TI_CTRL 0x0138 /* 8 bit Timer Control */ #define B2_TI_TEST 0x0139 /* 8 Bit Timer Test */ /* 0x013a - 0x013f: reserved */ #define B2_IRQM_INI 0x0140 /* 32 bit IRQ Moderation Timer Init Reg.*/ @@ -1021,7 +1032,7 @@ extern "C" { /* Bit 7: reserved */ #define RAP_RAP 0x3f /* Bit 6..0: 0 = block 0,..,6f = block 6f */ -/* B0_CTST 16 bit Control/Status register */ +/* B0_CTST 16 bit Control/Status register */ /* Bit 15..14: reserved */ #define CS_CLK_RUN_HOT BIT_13S /* CLK_RUN hot m. (YUKON-Lite only) */ #define CS_CLK_RUN_RST BIT_12S /* CLK_RUN reset (YUKON-Lite only) */ @@ -1038,7 +1049,7 @@ extern "C" { #define CS_RST_CLR BIT_1S /* Clear Software reset */ #define CS_RST_SET BIT_0S /* Set Software reset */ -/* B0_LED 8 Bit LED register */ +/* B0_LED 8 Bit LED register */ /* Bit 7.. 2: reserved */ #define LED_STAT_ON BIT_1S /* Status LED on */ #define LED_STAT_OFF BIT_0S /* Status LED off */ @@ -1053,9 +1064,9 @@ extern "C" { #define PC_VCC_ON BIT_1 /* Switch VCC On */ #define PC_VCC_OFF BIT_0 /* Switch VCC Off */ -/* B0_ISRC 32 bit Interrupt Source Register */ -/* B0_IMSK 32 bit Interrupt Mask Register */ -/* B0_SP_ISRC 32 bit Special Interrupt Source Reg */ +/* B0_ISRC 32 bit Interrupt Source Register */ +/* B0_IMSK 32 bit Interrupt Mask Register */ +/* B0_SP_ISRC 32 bit Special Interrupt Source Reg */ /* B2_IRQM_MSK 32 bit IRQ Moderation Mask */ #define IS_ALL_MSK 0xbfffffffUL /* All Interrupt bits */ #define IS_HW_ERR BIT_31 /* Interrupt HW Error */ @@ -1099,9 +1110,9 @@ extern "C" { #define IS_XA2_C BIT_0 /* Q_XA2 Encoding Error */ -/* B0_HWE_ISRC 32 bit HW Error Interrupt Src Reg */ -/* B0_HWE_IMSK 32 bit HW Error Interrupt Mask Reg */ -/* B2_IRQM_HWE_MSK 32 bit IRQ Moderation HW Error Mask */ +/* B0_HWE_ISRC 32 bit HW Error Interrupt Src Reg */ +/* B0_HWE_IMSK 32 bit HW Error Interrupt Mask Reg */ +/* B2_IRQM_HWE_MSK 32 bit IRQ Moderation HW Error Mask */ #define IS_ERR_MSK 0x00000fffL /* All Error bits */ /* Bit 31..14: reserved */ #define IS_IRQ_TIST_OV BIT_13 /* Time Stamp Timer Overflow (YUKON only) */ @@ -1119,29 +1130,32 @@ extern "C" { #define IS_R1_PAR_ERR BIT_1 /* Queue R1 Parity Error */ #define IS_R2_PAR_ERR BIT_0 /* Queue R2 Parity Error */ -/* B2_CONN_TYP 8 bit Connector type */ -/* B2_PMD_TYP 8 bit PMD type */ +/* B2_CONN_TYP 8 bit Connector type */ +/* B2_PMD_TYP 8 bit PMD type */ /* Values of connector and PMD type comply to SysKonnect internal std */ -/* B2_MAC_CFG 8 bit MAC Configuration / Chip Revision */ +/* B2_MAC_CFG 8 bit MAC Configuration / Chip Revision */ #define CFG_CHIP_R_MSK (0xf<<4) /* Bit 7.. 4: Chip Revision */ /* Bit 3.. 2: reserved */ #define CFG_DIS_M2_CLK BIT_1S /* Disable Clock for 2nd MAC */ #define CFG_SNG_MAC BIT_0S /* MAC Config: 0=2 MACs / 1=1 MAC*/ -/* B2_CHIP_ID 8 bit Chip Identification Number */ +/* B2_CHIP_ID 8 bit Chip Identification Number */ #define CHIP_ID_GENESIS 0x0a /* Chip ID for GENESIS */ #define CHIP_ID_YUKON 0xb0 /* Chip ID for YUKON */ -#define CHIP_ID_YUKON_LITE 0xb1 /* Chip ID for YUKON-Lite (Rev. A1) */ +#define CHIP_ID_YUKON_LITE 0xb1 /* Chip ID for YUKON-Lite (Rev. A1-A3) */ #define CHIP_ID_YUKON_LP 0xb2 /* Chip ID for YUKON-LP */ -/* B2_FAR 32 bit Flash-Prom Addr Reg/Cnt */ +#define CHIP_REV_YU_LITE_A1 3 /* Chip Rev. for YUKON-Lite A1,A2 */ +#define CHIP_REV_YU_LITE_A3 7 /* Chip Rev. for YUKON-Lite A3 */ + +/* B2_FAR 32 bit Flash-Prom Addr Reg/Cnt */ #define FAR_ADDR 0x1ffffL /* Bit 16.. 0: FPROM Address mask */ -/* B2_LD_CRTL 8 bit EPROM loader control register */ +/* B2_LD_CTRL 8 bit EPROM loader control register */ /* Bits are currently reserved */ -/* B2_LD_TEST 8 bit EPROM loader test register */ +/* B2_LD_TEST 8 bit EPROM loader test register */ /* Bit 7.. 4: reserved */ #define LD_T_ON BIT_3S /* Loader Test mode on */ #define LD_T_OFF BIT_2S /* Loader Test mode off */ @@ -1151,16 +1165,16 @@ extern "C" { /* * Timer Section */ -/* B2_TI_CRTL 8 bit Timer control */ +/* B2_TI_CTRL 8 bit Timer control */ /* B2_IRQM_CTRL 8 bit IRQ Moderation Timer Control */ /* Bit 7.. 3: reserved */ #define TIM_START BIT_2S /* Start Timer */ #define TIM_STOP BIT_1S /* Stop Timer */ #define TIM_CLR_IRQ BIT_0S /* Clear Timer IRQ (!IRQM) */ -/* B2_TI_TEST 8 Bit Timer Test */ +/* B2_TI_TEST 8 Bit Timer Test */ /* B2_IRQM_TEST 8 bit IRQ Moderation Timer Test */ -/* B28_DPT_TST 8 bit Descriptor Poll Timer Test Reg */ +/* B28_DPT_TST 8 bit Descriptor Poll Timer Test Reg */ /* Bit 7.. 3: reserved */ #define TIM_T_ON BIT_2S /* Test mode on */ #define TIM_T_OFF BIT_1S /* Test mode off */ @@ -1197,7 +1211,7 @@ extern "C" { #define TST_FRC_APERR_1M64 BIT_1S /* AddrPERR on 1. phase */ #define TST_FRC_APERR_2M64 BIT_0S /* AddrPERR on 2. phase */ -/* B2_GP_IO 32 bit General Purpose I/O Register */ +/* B2_GP_IO 32 bit General Purpose I/O Register */ /* Bit 31..26: reserved */ #define GP_DIR_9 BIT_25 /* IO_9 direct, 0=In/1=Out */ #define GP_DIR_8 BIT_24 /* IO_8 direct, 0=In/1=Out */ @@ -1221,28 +1235,28 @@ extern "C" { #define GP_IO_1 BIT_1 /* IO_1 pin */ #define GP_IO_0 BIT_0 /* IO_0 pin */ -/* B2_I2C_CTRL 32 bit I2C HW Control Register */ +/* B2_I2C_CTRL 32 bit I2C HW Control Register */ #define I2C_FLAG BIT_31 /* Start read/write if WR */ #define I2C_ADDR (0x7fffL<<16) /* Bit 30..16: Addr to be RD/WR */ #define I2C_DEV_SEL (0x7fL<<9) /* Bit 15.. 9: I2C Device Select */ /* Bit 8.. 5: reserved */ #define I2C_BURST_LEN BIT_4 /* Burst Len, 1/4 bytes */ -#define I2C_DEV_SIZE (7L<<1) /* Bit 3.. 1: I2C Device Size */ -#define I2C_025K_DEV (0L<<1) /* 0: 256 Bytes or smal. */ -#define I2C_05K_DEV (1L<<1) /* 1: 512 Bytes */ -#define I2C_1K_DEV (2L<<1) /* 2: 1024 Bytes */ -#define I2C_2K_DEV (3L<<1) /* 3: 2048 Bytes */ -#define I2C_4K_DEV (4L<<1) /* 4: 4096 Bytes */ -#define I2C_8K_DEV (5L<<1) /* 5: 8192 Bytes */ -#define I2C_16K_DEV (6L<<1) /* 6: 16384 Bytes */ -#define I2C_32K_DEV (7L<<1) /* 7: 32768 Bytes */ +#define I2C_DEV_SIZE (7<<1) /* Bit 3.. 1: I2C Device Size */ +#define I2C_025K_DEV (0<<1) /* 0: 256 Bytes or smal. */ +#define I2C_05K_DEV (1<<1) /* 1: 512 Bytes */ +#define I2C_1K_DEV (2<<1) /* 2: 1024 Bytes */ +#define I2C_2K_DEV (3<<1) /* 3: 2048 Bytes */ +#define I2C_4K_DEV (4<<1) /* 4: 4096 Bytes */ +#define I2C_8K_DEV (5<<1) /* 5: 8192 Bytes */ +#define I2C_16K_DEV (6<<1) /* 6: 16384 Bytes */ +#define I2C_32K_DEV (7<<1) /* 7: 32768 Bytes */ #define I2C_STOP BIT_0 /* Interrupt I2C transfer */ -/* B2_I2C_IRQ 32 bit I2C HW IRQ Register */ +/* B2_I2C_IRQ 32 bit I2C HW IRQ Register */ /* Bit 31.. 1 reserved */ #define I2C_CLR_IRQ BIT_0 /* Clear I2C IRQ */ -/* B2_I2C_SW 32 bit (8 bit access) I2C HW SW Port Register */ +/* B2_I2C_SW 32 bit (8 bit access) I2C HW SW Port Register */ /* Bit 7.. 3: reserved */ #define I2C_DATA_DIR BIT_2S /* direction of I2C_DATA */ #define I2C_DATA BIT_1S /* I2C Data Port */ @@ -1254,27 +1268,27 @@ extern "C" { #define I2C_SENS_ADDR LM80_ADDR /* I2C Sensor Address, (Volt and Temp)*/ -/* B2_BSC_CTRL 8 bit Blink Source Counter Control */ +/* B2_BSC_CTRL 8 bit Blink Source Counter Control */ /* Bit 7.. 2: reserved */ #define BSC_START BIT_1S /* Start Blink Source Counter */ #define BSC_STOP BIT_0S /* Stop Blink Source Counter */ -/* B2_BSC_STAT 8 bit Blink Source Counter Status */ +/* B2_BSC_STAT 8 bit Blink Source Counter Status */ /* Bit 7.. 1: reserved */ #define BSC_SRC BIT_0S /* Blink Source, 0=Off / 1=On */ -/* B2_BSC_TST 16 bit Blink Source Counter Test Reg */ +/* B2_BSC_TST 16 bit Blink Source Counter Test Reg */ #define BSC_T_ON BIT_2S /* Test mode on */ #define BSC_T_OFF BIT_1S /* Test mode off */ #define BSC_T_STEP BIT_0S /* Test step */ -/* B3_RAM_ADDR 32 bit RAM Address, to read or write */ +/* B3_RAM_ADDR 32 bit RAM Address, to read or write */ /* Bit 31..19: reserved */ #define RAM_ADR_RAN 0x0007ffffL /* Bit 18.. 0: RAM Address Range */ /* RAM Interface Registers */ -/* B3_RI_CTRL 16 bit RAM Iface Control Register */ +/* B3_RI_CTRL 16 bit RAM Iface Control Register */ /* Bit 15..10: reserved */ #define RI_CLR_RD_PERR BIT_9S /* Clear IRQ RAM Read Parity Err */ #define RI_CLR_WR_PERR BIT_8S /* Clear IRQ RAM Write Parity Err*/ @@ -1282,7 +1296,7 @@ extern "C" { #define RI_RST_CLR BIT_1S /* Clear RAM Interface Reset */ #define RI_RST_SET BIT_0S /* Set RAM Interface Reset */ -/* B3_RI_TEST 8 bit RAM Iface Test Register */ +/* B3_RI_TEST 8 bit RAM Iface Test Register */ /* Bit 15.. 4: reserved */ #define RI_T_EV BIT_3S /* Timeout Event occured */ #define RI_T_ON BIT_2S /* Timeout Timer Test On */ @@ -1309,7 +1323,7 @@ extern "C" { #define MA_DIS_REC_RX1 BIT_0S /* Disable Recovery Timer RX1 */ /* Packet Arbiter Registers */ -/* B3_PA_CTRL 16 bit Packet Arbiter Ctrl Register */ +/* B3_PA_CTRL 16 bit Packet Arbiter Ctrl Register */ /* Bit 15..14: reserved */ #define PA_CLR_TO_TX2 BIT_13S /* Clear IRQ Packet Timeout TX2 */ #define PA_CLR_TO_TX1 BIT_12S /* Clear IRQ Packet Timeout TX1 */ @@ -1332,7 +1346,7 @@ extern "C" { /* Rx/Tx Path related Arbiter Test Registers */ /* B3_MA_TO_TEST 16 bit MAC Arbiter Timeout Test Reg */ /* B3_MA_RC_TEST 16 bit MAC Arbiter Recovery Test Reg */ -/* B3_PA_TEST 16 bit Packet Arbiter Test Register */ +/* B3_PA_TEST 16 bit Packet Arbiter Test Register */ /* Bit 15, 11, 7, and 3 are reserved in B3_PA_TEST */ #define TX2_T_EV BIT_15S /* TX2 Timeout/Recv Event occured */ #define TX2_T_ON BIT_14S /* TX2 Timeout/Recv Timer Test On */ @@ -1353,14 +1367,14 @@ extern "C" { /* Transmit Arbiter Registers MAC 1 and 2, use MR_ADDR() to access */ -/* TXA_ITI_INI 32 bit Tx Arb Interval Timer Init Val */ -/* TXA_ITI_VAL 32 bit Tx Arb Interval Timer Value */ -/* TXA_LIM_INI 32 bit Tx Arb Limit Counter Init Val */ -/* TXA_LIM_VAL 32 bit Tx Arb Limit Counter Value */ +/* TXA_ITI_INI 32 bit Tx Arb Interval Timer Init Val */ +/* TXA_ITI_VAL 32 bit Tx Arb Interval Timer Value */ +/* TXA_LIM_INI 32 bit Tx Arb Limit Counter Init Val */ +/* TXA_LIM_VAL 32 bit Tx Arb Limit Counter Value */ /* Bit 31..24: reserved */ #define TXA_MAX_VAL 0x00ffffffUL/* Bit 23.. 0: Max TXA Timer/Cnt Val */ -/* TXA_CTRL 8 bit Tx Arbiter Control Register */ +/* TXA_CTRL 8 bit Tx Arbiter Control Register */ #define TXA_ENA_FSYNC BIT_7S /* Enable force of sync Tx queue */ #define TXA_DIS_FSYNC BIT_6S /* Disable force of sync Tx queue */ #define TXA_ENA_ALLOC BIT_5S /* Enable alloc of free bandwidth */ @@ -1370,7 +1384,7 @@ extern "C" { #define TXA_ENA_ARB BIT_1S /* Enable Tx Arbiter */ #define TXA_DIS_ARB BIT_0S /* Disable Tx Arbiter */ -/* TXA_TEST 8 bit Tx Arbiter Test Register */ +/* TXA_TEST 8 bit Tx Arbiter Test Register */ /* Bit 7.. 6: reserved */ #define TXA_INT_T_ON BIT_5S /* Tx Arb Interval Timer Test On */ #define TXA_INT_T_OFF BIT_4S /* Tx Arb Interval Timer Test Off */ @@ -1379,22 +1393,22 @@ extern "C" { #define TXA_LIM_T_OFF BIT_1S /* Tx Arb Limit Timer Test Off */ #define TXA_LIM_T_STEP BIT_0S /* Tx Arb Limit Timer Step */ -/* TXA_STAT 8 bit Tx Arbiter Status Register */ +/* TXA_STAT 8 bit Tx Arbiter Status Register */ /* Bit 7.. 1: reserved */ #define TXA_PRIO_XS BIT_0S /* sync queue has prio to send */ -/* Q_BC 32 bit Current Byte Counter */ +/* Q_BC 32 bit Current Byte Counter */ /* Bit 31..16: reserved */ #define BC_MAX 0xffff /* Bit 15.. 0: Byte counter */ /* BMU Control Status Registers */ -/* B0_R1_CSR 32 bit BMU Ctrl/Stat Rx Queue 1 */ -/* B0_R2_CSR 32 bit BMU Ctrl/Stat Rx Queue 2 */ -/* B0_XA1_CSR 32 bit BMU Ctrl/Stat Sync Tx Queue 1 */ -/* B0_XS1_CSR 32 bit BMU Ctrl/Stat Async Tx Queue 1 */ -/* B0_XA2_CSR 32 bit BMU Ctrl/Stat Sync Tx Queue 2 */ -/* B0_XS2_CSR 32 bit BMU Ctrl/Stat Async Tx Queue 2 */ -/* Q_CSR 32 bit BMU Control/Status Register */ +/* B0_R1_CSR 32 bit BMU Ctrl/Stat Rx Queue 1 */ +/* B0_R2_CSR 32 bit BMU Ctrl/Stat Rx Queue 2 */ +/* B0_XA1_CSR 32 bit BMU Ctrl/Stat Sync Tx Queue 1 */ +/* B0_XS1_CSR 32 bit BMU Ctrl/Stat Async Tx Queue 1 */ +/* B0_XA2_CSR 32 bit BMU Ctrl/Stat Sync Tx Queue 2 */ +/* B0_XS2_CSR 32 bit BMU Ctrl/Stat Async Tx Queue 2 */ +/* Q_CSR 32 bit BMU Control/Status Register */ /* Bit 31..25: reserved */ #define CSR_SV_IDLE BIT_24 /* BMU SM Idle */ /* Bit 23..22: reserved */ @@ -1428,7 +1442,7 @@ extern "C" { CSR_SV_RUN | CSR_DREAD_RUN | CSR_DWRITE_RUN |\ CSR_TRANS_RUN) -/* Q_F 32 bit Flag Register */ +/* Q_F 32 bit Flag Register */ /* Bit 31..28: reserved */ #define F_ALM_FULL BIT_27 /* Rx FIFO: almost full */ #define F_EMPTY BIT_27 /* Tx FIFO: empty flag */ @@ -1439,17 +1453,17 @@ extern "C" { /* Bit 15..11: reserved */ #define F_WATER_MARK 0x0007ffL /* Bit 10.. 0: Watermark */ -/* Q_T1 32 bit Test Register 1 */ +/* Q_T1 32 bit Test Register 1 */ /* Holds four State Machine control Bytes */ -#define SM_CRTL_SV_MSK (0xffL<<24) /* Bit 31..24: Control Supervisor SM */ -#define SM_CRTL_RD_MSK (0xffL<<16) /* Bit 23..16: Control Read Desc SM */ -#define SM_CRTL_WR_MSK (0xffL<<8) /* Bit 15.. 8: Control Write Desc SM */ -#define SM_CRTL_TR_MSK 0xffL /* Bit 7.. 0: Control Transfer SM */ - -/* Q_T1_TR 8 bit Test Register 1 Transfer SM */ -/* Q_T1_WR 8 bit Test Register 1 Write Descriptor SM */ -/* Q_T1_RD 8 bit Test Register 1 Read Descriptor SM */ -/* Q_T1_SV 8 bit Test Register 1 Supervisor SM */ +#define SM_CTRL_SV_MSK (0xffL<<24) /* Bit 31..24: Control Supervisor SM */ +#define SM_CTRL_RD_MSK (0xffL<<16) /* Bit 23..16: Control Read Desc SM */ +#define SM_CTRL_WR_MSK (0xffL<<8) /* Bit 15.. 8: Control Write Desc SM */ +#define SM_CTRL_TR_MSK 0xffL /* Bit 7.. 0: Control Transfer SM */ + +/* Q_T1_TR 8 bit Test Register 1 Transfer SM */ +/* Q_T1_WR 8 bit Test Register 1 Write Descriptor SM */ +/* Q_T1_RD 8 bit Test Register 1 Read Descriptor SM */ +/* Q_T1_SV 8 bit Test Register 1 Supervisor SM */ /* The control status byte of each machine looks like ... */ #define SM_STATE 0xf0 /* Bit 7.. 4: State which shall be loaded */ @@ -1459,7 +1473,7 @@ extern "C" { #define SM_STEP BIT_0S /* Step the State Machine */ /* The encoding of the states is not supported by the Diagnostics Tool */ -/* Q_T2 32 bit Test Register 2 */ +/* Q_T2 32 bit Test Register 2 */ /* Bit 31.. 8: reserved */ #define T2_AC_T_ON BIT_7 /* Address Counter Test Mode on */ #define T2_AC_T_OFF BIT_6 /* Address Counter Test Mode off */ @@ -1470,23 +1484,23 @@ extern "C" { #define T2_STEP02 BIT_1 /* Inc AC/Dec BC by 2 */ #define T2_STEP01 BIT_0 /* Inc AC/Dec BC by 1 */ -/* Q_T3 32 bit Test Register 3 */ +/* Q_T3 32 bit Test Register 3 */ /* Bit 31.. 7: reserved */ #define T3_MUX_MSK (7<<4) /* Bit 6.. 4: Mux Position */ /* Bit 3: reserved */ #define T3_VRAM_MSK 7 /* Bit 2.. 0: Virtual RAM Buffer Address */ /* RAM Buffer Register Offsets, use RB_ADDR(Queue, Offs) to access */ -/* RB_START 32 bit RAM Buffer Start Address */ -/* RB_END 32 bit RAM Buffer End Address */ -/* RB_WP 32 bit RAM Buffer Write Pointer */ -/* RB_RP 32 bit RAM Buffer Read Pointer */ -/* RB_RX_UTPP 32 bit Rx Upper Threshold, Pause Pack */ -/* RB_RX_LTPP 32 bit Rx Lower Threshold, Pause Pack */ -/* RB_RX_UTHP 32 bit Rx Upper Threshold, High Prio */ -/* RB_RX_LTHP 32 bit Rx Lower Threshold, High Prio */ -/* RB_PC 32 bit RAM Buffer Packet Counter */ -/* RB_LEV 32 bit RAM Buffer Level Register */ +/* RB_START 32 bit RAM Buffer Start Address */ +/* RB_END 32 bit RAM Buffer End Address */ +/* RB_WP 32 bit RAM Buffer Write Pointer */ +/* RB_RP 32 bit RAM Buffer Read Pointer */ +/* RB_RX_UTPP 32 bit Rx Upper Threshold, Pause Pack */ +/* RB_RX_LTPP 32 bit Rx Lower Threshold, Pause Pack */ +/* RB_RX_UTHP 32 bit Rx Upper Threshold, High Prio */ +/* RB_RX_LTHP 32 bit Rx Lower Threshold, High Prio */ +/* RB_PC 32 bit RAM Buffer Packet Counter */ +/* RB_LEV 32 bit RAM Buffer Level Register */ /* Bit 31..19: reserved */ #define RB_MSK 0x0007ffff /* Bit 18.. 0: RAM Buffer Pointer Bits */ @@ -1519,17 +1533,17 @@ extern "C" { /* Receive and Transmit MAC FIFO Registers (GENESIS only) */ -/* RX_MFF_EA 32 bit Receive MAC FIFO End Address */ -/* RX_MFF_WP 32 bit Receive MAC FIFO Write Pointer */ -/* RX_MFF_RP 32 bit Receive MAC FIFO Read Pointer */ -/* RX_MFF_PC 32 bit Receive MAC FIFO Packet Counter */ -/* RX_MFF_LEV 32 bit Receive MAC FIFO Level */ -/* TX_MFF_EA 32 bit Transmit MAC FIFO End Address */ -/* TX_MFF_WP 32 bit Transmit MAC FIFO Write Pointer */ -/* TX_MFF_WSP 32 bit Transmit MAC FIFO WR Shadow Pointer */ -/* TX_MFF_RP 32 bit Transmit MAC FIFO Read Pointer */ -/* TX_MFF_PC 32 bit Transmit MAC FIFO Packet Cnt */ -/* TX_MFF_LEV 32 bit Transmit MAC FIFO Level */ +/* RX_MFF_EA 32 bit Receive MAC FIFO End Address */ +/* RX_MFF_WP 32 bit Receive MAC FIFO Write Pointer */ +/* RX_MFF_RP 32 bit Receive MAC FIFO Read Pointer */ +/* RX_MFF_PC 32 bit Receive MAC FIFO Packet Counter */ +/* RX_MFF_LEV 32 bit Receive MAC FIFO Level */ +/* TX_MFF_EA 32 bit Transmit MAC FIFO End Address */ +/* TX_MFF_WP 32 bit Transmit MAC FIFO Write Pointer */ +/* TX_MFF_WSP 32 bit Transmit MAC FIFO WR Shadow Pointer */ +/* TX_MFF_RP 32 bit Transmit MAC FIFO Read Pointer */ +/* TX_MFF_PC 32 bit Transmit MAC FIFO Packet Cnt */ +/* TX_MFF_LEV 32 bit Transmit MAC FIFO Level */ /* Bit 31.. 6: reserved */ #define MFF_MSK 0x007fL /* Bit 5.. 0: MAC FIFO Address/Ptr Bits */ @@ -1682,7 +1696,7 @@ extern "C" { #define RX_GMF_FL_THR_DEF 0x0a /* Rx GMAC FIFO Flush Threshold default */ -/* GMAC_TI_ST_CTRL 8 bit Time Stamp Timer Ctrl Reg (YUKON only) */ +/* GMAC_TI_ST_CTRL 8 bit Time Stamp Timer Ctrl Reg (YUKON only) */ /* Bit 7.. 3: reserved */ #define GMT_ST_START BIT_2S /* Start Time Stamp Timer */ #define GMT_ST_STOP BIT_1S /* Stop Time Stamp Timer */ @@ -1766,13 +1780,13 @@ extern "C" { #define GMAC_DEF_MSK (GM_IS_TX_CO_OV | GM_IS_RX_CO_OV | \ GM_IS_TX_FF_UR) -/* GMAC_LINK_CTRL 16 bit GMAC Link Control Reg (YUKON only) */ +/* GMAC_LINK_CTRL 16 bit GMAC Link Control Reg (YUKON only) */ /* Bits 15.. 2: reserved */ #define GMLC_RST_CLR BIT_1S /* Clear GMAC Link Reset */ #define GMLC_RST_SET BIT_0S /* Set GMAC Link Reset */ -/* WOL_CTRL_STAT 16 bit WOL Control/Status Reg */ +/* WOL_CTRL_STAT 16 bit WOL Control/Status Reg */ #define WOL_CTL_LINK_CHG_OCC BIT_15S #define WOL_CTL_MAGIC_PKT_OCC BIT_14S #define WOL_CTL_PATTERN_OCC BIT_13S @@ -1801,7 +1815,7 @@ extern "C" { WOL_CTL_DIS_PATTERN_UNIT | \ WOL_CTL_DIS_MAGIC_PKT_UNIT) -/* WOL_MATCH_CTL 8 bit WOL Match Control Reg */ +/* WOL_MATCH_CTL 8 bit WOL Match Control Reg */ #define WOL_CTL_PATT_ENA(x) (BIT_0 << (x)) #define SK_NUM_WOL_PATTERN 7 diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/h/skgehwt.h 830-ivtv/drivers/net/sk98lin/h/skgehwt.h --- 000-virgin/drivers/net/sk98lin/h/skgehwt.h Wed Aug 13 20:24:25 2003 +++ 830-ivtv/drivers/net/sk98lin/h/skgehwt.h Thu Jan 8 08:54:22 2004 @@ -1,9 +1,9 @@ /****************************************************************************** * * Name: skhwt.h - * Project: Gigabit Ethernet Adapters, Schedule-Modul - * Version: $Revision: 1.6 $ - * Date: $Date: 2003/05/13 17:57:48 $ + * Project: Gigabit Ethernet Adapters, Event Scheduler Module + * Version: $Revision: 1.7 $ + * Date: $Date: 2003/09/16 12:55:08 $ * Purpose: Defines for the hardware timer functions * ******************************************************************************/ @@ -27,6 +27,9 @@ * History: * * $Log: skgehwt.h,v $ + * Revision 1.7 2003/09/16 12:55:08 rschmidt + * Editorial changes + * * Revision 1.6 2003/05/13 17:57:48 mkarl * Editorial changes. * @@ -34,7 +37,7 @@ * Changed license header to GPL. * * Revision 1.4 1998/08/19 09:50:58 gklug - * fix: remove struct keyword from c-code (see CCC) add typedefs + * fix: remove struct keyword from C-code (see CCC) add typedefs * * Revision 1.3 1998/08/14 07:09:29 gklug * fix: chg pAc -> pAC @@ -44,10 +47,6 @@ * * Revision 1.1 1998/08/07 09:32:58 gklug * first version - * - * - * - * * ******************************************************************************/ @@ -64,14 +63,14 @@ * - use in Adapters context name pAC->Hwt */ typedef struct s_Hwt { - SK_U32 TStart ; /* HWT start */ - SK_U32 TStop ; /* HWT stop */ - int TActive ; /* HWT: flag : active/inactive */ + SK_U32 TStart; /* HWT start */ + SK_U32 TStop; /* HWT stop */ + int TActive; /* HWT: flag : active/inactive */ } SK_HWT; extern void SkHwtInit(SK_AC *pAC, SK_IOC Ioc); extern void SkHwtStart(SK_AC *pAC, SK_IOC Ioc, SK_U32 Time); extern void SkHwtStop(SK_AC *pAC, SK_IOC Ioc); -extern SK_U32 SkHwtRead(SK_AC *pAC,SK_IOC Ioc); +extern SK_U32 SkHwtRead(SK_AC *pAC, SK_IOC Ioc); extern void SkHwtIsr(SK_AC *pAC, SK_IOC Ioc); #endif /* _SKGEHWT_H_ */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/h/skgei2c.h 830-ivtv/drivers/net/sk98lin/h/skgei2c.h --- 000-virgin/drivers/net/sk98lin/h/skgei2c.h Wed Aug 13 20:24:25 2003 +++ 830-ivtv/drivers/net/sk98lin/h/skgei2c.h Thu Jan 8 08:54:22 2004 @@ -1,16 +1,17 @@ /****************************************************************************** * * Name: skgei2c.h - * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.23 $ - * Date: $Date: 2002/12/19 14:34:27 $ - * Purpose: Special GEnesis defines for TWSI + * Project: Gigabit Ethernet Adapters, TWSI-Module + * Version: $Revision: 1.25 $ + * Date: $Date: 2003/10/20 09:06:05 $ + * Purpose: Special defines for TWSI * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 1998-2002 SysKonnect. + * (C)Copyright 2002-2003 Marvell. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +27,12 @@ * History: * * $Log: skgei2c.h,v $ + * Revision 1.25 2003/10/20 09:06:05 rschmidt + * Editorial changes. + * + * Revision 1.24 2003/09/23 09:31:15 malthoff + * Parameter dev_size added to macro definition of SK_I2C_CTL. + * * Revision 1.23 2002/12/19 14:34:27 rschmidt * Added cast in macros SK_I2C_SET_BIT() and SK_I2C_CLR_BIT() * Editorial changes (TWSI) @@ -107,8 +114,6 @@ * Revision 1.1 1998/07/17 11:27:56 gklug * Created. * - * - * ******************************************************************************/ /* @@ -121,12 +126,13 @@ /* * Macros to access the B2_I2C_CTRL */ -#define SK_I2C_CTL(IoC, flag, dev, reg, burst) \ +#define SK_I2C_CTL(IoC, flag, dev, dev_size, reg, burst) \ SK_OUT32(IoC, B2_I2C_CTRL,\ (flag ? 0x80000000UL : 0x0L) | \ - (((SK_U32) reg << 16) & I2C_ADDR) | \ - (((SK_U32) dev << 9) & I2C_DEV_SEL) | \ - (( burst << 4) & I2C_BURST_LEN)) + (((SK_U32)reg << 16) & I2C_ADDR) | \ + (((SK_U32)dev << 9) & I2C_DEV_SEL) | \ + (dev_size & I2C_DEV_SIZE) | \ + ((burst << 4) & I2C_BURST_LEN)) #define SK_I2C_STOP(IoC) { \ SK_U32 I2cCtrl; \ @@ -166,42 +172,42 @@ */ #define SK_LM80_VT_LSB 22 /* 22mV LSB resolution */ #define SK_LM80_TEMP_LSB 10 /* 1 degree LSB resolution */ -#define SK_LM80_TEMPEXT_LSB 5 /* 0.5 degree LSB resolution for the - * extension value - */ -#define SK_LM80_FAN_FAKTOR ((22500L*60)/(1*2)) -/* formula: counter = (22500*60)/(rpm * divisor * pulses/2) +#define SK_LM80_TEMPEXT_LSB 5 /* 0.5 degree LSB resolution for ext. val. */ + +/* + * formula: counter = (22500*60)/(rpm * divisor * pulses/2) * assuming: 6500rpm, 4 pulses, divisor 1 */ +#define SK_LM80_FAN_FAKTOR ((22500L*60)/(1*2)) /* * Define sensor management data - * Maximum is reached on copperfield with dual Broadcom. + * Maximum is reached on Genesis copper dual port and Yukon-64 * Board specific maximum is in pAC->I2c.MaxSens */ #define SK_MAX_SENSORS 8 /* maximal no. of installed sensors */ #define SK_MIN_SENSORS 5 /* minimal no. of installed sensors */ /* - * To watch the statemachine (JS) use the timer in two ways instead of one as hitherto + * To watch the state machine (SM) use the timer in two ways + * instead of one as hitherto */ -#define SK_TIMER_WATCH_STATEMACHINE 0 /* Watch the statemachine to finish in a specific time */ -#define SK_TIMER_NEW_GAUGING 1 /* Start a new gauging when timer expires */ - +#define SK_TIMER_WATCH_SM 0 /* Watch the SM to finish in a spec. time */ +#define SK_TIMER_NEW_GAUGING 1 /* Start a new gauging when timer expires */ /* - * Defines for the individual Thresholds + * Defines for the individual thresholds */ /* Temperature sensor */ -#define SK_SEN_TEMP_HIGH_ERR 800 /* Temperature High Err Threshold */ +#define SK_SEN_TEMP_HIGH_ERR 800 /* Temperature High Err Threshold */ #define SK_SEN_TEMP_HIGH_WARN 700 /* Temperature High Warn Threshold */ #define SK_SEN_TEMP_LOW_WARN 100 /* Temperature Low Warn Threshold */ -#define SK_SEN_TEMP_LOW_ERR 0 /* Temperature Low Err Threshold */ +#define SK_SEN_TEMP_LOW_ERR 0 /* Temperature Low Err Threshold */ /* VCC which should be 5 V */ -#define SK_SEN_PCI_5V_HIGH_ERR 5588 /* Voltage PCI High Err Threshold */ -#define SK_SEN_PCI_5V_HIGH_WARN 5346 /* Voltage PCI High Warn Threshold */ +#define SK_SEN_PCI_5V_HIGH_ERR 5588 /* Voltage PCI High Err Threshold */ +#define SK_SEN_PCI_5V_HIGH_WARN 5346 /* Voltage PCI High Warn Threshold */ #define SK_SEN_PCI_5V_LOW_WARN 4664 /* Voltage PCI Low Warn Threshold */ #define SK_SEN_PCI_5V_LOW_ERR 4422 /* Voltage PCI Low Err Threshold */ @@ -229,17 +235,16 @@ #define SK_SEN_PCI_IO_3V3_HIGH_ERR 3850 /* + 15% V PCI-IO High Err Threshold */ #define SK_SEN_PCI_IO_3V3_HIGH_WARN 3674 /* + 10% V PCI-IO High Warn Threshold */ /* 3300 mVolt */ -#define SK_SEN_PCI_IO_3V3_LOW_WARN 2926 /* - 10% V PCI-IO Low Warn Threshold */ -#define SK_SEN_PCI_IO_3V3_LOW_ERR 2772 /* - 15% V PCI-IO Low Err Threshold */ - +#define SK_SEN_PCI_IO_3V3_LOW_WARN 2926 /* - 10% V PCI-IO Low Warn Threshold */ +#define SK_SEN_PCI_IO_3V3_LOW_ERR 2772 /* - 15% V PCI-IO Low Err Threshold */ /* * VDD voltage */ -#define SK_SEN_VDD_HIGH_ERR 3630 /* Voltage ASIC High Err Threshold */ -#define SK_SEN_VDD_HIGH_WARN 3476 /* Voltage ASIC High Warn Threshold */ -#define SK_SEN_VDD_LOW_WARN 3146 /* Voltage ASIC Low Warn Threshold */ -#define SK_SEN_VDD_LOW_ERR 2970 /* Voltage ASIC Low Err Threshold */ +#define SK_SEN_VDD_HIGH_ERR 3630 /* Voltage ASIC High Err Threshold */ +#define SK_SEN_VDD_HIGH_WARN 3476 /* Voltage ASIC High Warn Threshold */ +#define SK_SEN_VDD_LOW_WARN 3146 /* Voltage ASIC Low Warn Threshold */ +#define SK_SEN_VDD_LOW_ERR 2970 /* Voltage ASIC Low Err Threshold */ /* * PHY PLL 3V3 voltage @@ -255,8 +260,8 @@ #define SK_SEN_VAUX_3V3_HIGH_ERR 3630 /* Voltage VAUX High Err Threshold */ #define SK_SEN_VAUX_3V3_HIGH_WARN 3476 /* Voltage VAUX High Warn Threshold */ #define SK_SEN_VAUX_3V3_LOW_WARN 3146 /* Voltage VAUX Low Warn Threshold */ -#define SK_SEN_VAUX_3V3_LOW_ERR 2970 /* Voltage VAUX Low Err Threshold */ -#define SK_SEN_VAUX_0V_WARN_ERR 0 /* if VAUX not present */ +#define SK_SEN_VAUX_3V3_LOW_ERR 2970 /* Voltage VAUX Low Err Threshold */ +#define SK_SEN_VAUX_0V_WARN_ERR 0 /* if VAUX not present */ #define SK_SEN_VAUX_RANGE_LIMITER 1000 /* 1000 mV range delimiter */ /* @@ -270,7 +275,7 @@ /* * ASIC Core 1V5 voltage (YUKON only) */ -#define SK_SEN_CORE_1V5_HIGH_ERR 1650 /* Voltage ASIC Core High Err Threshold */ +#define SK_SEN_CORE_1V5_HIGH_ERR 1650 /* Voltage ASIC Core High Err Threshold */ #define SK_SEN_CORE_1V5_HIGH_WARN 1575 /* Voltage ASIC Core High Warn Threshold */ #define SK_SEN_CORE_1V5_LOW_WARN 1425 /* Voltage ASIC Core Low Warn Threshold */ #define SK_SEN_CORE_1V5_LOW_ERR 1350 /* Voltage ASIC Core Low Err Threshold */ @@ -285,8 +290,8 @@ */ #define SK_SEN_FAN_HIGH_ERR 20000 /* FAN Speed High Err Threshold */ #define SK_SEN_FAN_HIGH_WARN 20000 /* FAN Speed High Warn Threshold */ -#define SK_SEN_FAN_LOW_WARN 5200 /* FAN Speed Low Warn Threshold */ -#define SK_SEN_FAN_LOW_ERR 4550 /* FAN Speed Low Err Threshold */ +#define SK_SEN_FAN_LOW_WARN 5200 /* FAN Speed Low Warn Threshold */ +#define SK_SEN_FAN_LOW_ERR 4550 /* FAN Speed Low Err Threshold */ /* * Some Voltages need dynamic thresholds diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/h/skgeinit.h 830-ivtv/drivers/net/sk98lin/h/skgeinit.h --- 000-virgin/drivers/net/sk98lin/h/skgeinit.h Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/sk98lin/h/skgeinit.h Thu Jan 8 08:54:22 2004 @@ -2,8 +2,8 @@ * * Name: skgeinit.h * Project: Gigabit Ethernet Adapters, Common Modules - * Version: $Revision: 1.81 $ - * Date: $Date: 2003/07/04 12:30:38 $ + * Version: $Revision: 1.83 $ + * Date: $Date: 2003/09/16 14:07:37 $ * Purpose: Structures and prototypes for the GE Init Module * ******************************************************************************/ @@ -27,6 +27,23 @@ * History: * * $Log: skgeinit.h,v $ + * Revision 1.83 2003/09/16 14:07:37 rschmidt + * Moved defines for PHY power down modes from skgehw.h + * Added prototypes for SkMacClearRst() + * Editorial changes + * + * Revision 1.82 2003/09/16 07:18:36 mschmid + * Added members to port structure for MAC control + * - PMacColThres + * - PMacJamLen + * - PMacJamIpgVal + * - PMacJamIpgData + * - PMacIpgData + * - PMacLimit4 + * Added PHY power state to port structure + * - PPhyPowerState + * Added function prototypes to enter and leave low power modes + * * Revision 1.81 2003/07/04 12:30:38 rschmidt * Added SK_FAR to pointers in MAC statistic functions (for PXE) * Editorial changes @@ -594,6 +611,13 @@ extern "C" { #define SK_PRT_INIT 2 /* the port is initialized */ #define SK_PRT_RUN 3 /* the port has an active link */ +/* PHY power down modes */ +#define PHY_PM_OPERATIONAL_MODE 0 /* PHY operational mode */ +#define PHY_PM_DEEP_SLEEP 1 /* coma mode --> minimal power */ +#define PHY_PM_IEEE_POWER_DOWN 2 /* IEEE 22.2.4.1.5 compl. power down */ +#define PHY_PM_ENERGY_DETECT 3 /* energy detect */ +#define PHY_PM_ENERGY_DETECT_PLUS 4 /* energy detect plus */ + /* Default receive frame limit for Workaround of XMAC Errata */ #define SK_DEF_RX_WA_LIM SK_CONSTU64(100) @@ -685,6 +709,13 @@ typedef struct s_GePort { SK_U8 PCableLen; /* Cable Length */ SK_U8 PMdiPairLen[4]; /* MDI[0..3] Pair Length */ SK_U8 PMdiPairSts[4]; /* MDI[0..3] Pair Diagnostic Status */ + SK_U8 PPhyPowerState; /* PHY current power state */ + int PMacColThres; /* MAC Collision Threshold */ + int PMacJamLen; /* MAC Jam length */ + int PMacJamIpgVal; /* MAC Jam IPG */ + int PMacJamIpgData; /* MAC IPG Jam to Data */ + int PMacIpgData; /* MAC Data IPG */ + SK_BOOL PMacLimit4; /* reset collision counter and backoff algorithm */ } SK_GEPORT; /* @@ -865,6 +896,11 @@ extern void SkMacHardRst( SK_IOC IoC, int Port); +extern void SkMacClearRst( + SK_AC *pAC, + SK_IOC IoC, + int Port); + extern void SkXmInitMac( SK_AC *pAC, SK_IOC IoC, @@ -1040,6 +1076,17 @@ extern int SkGmCableDiagStatus( int Port, SK_BOOL StartTest); +extern int SkGmEnterLowPowerMode( + SK_AC *pAC, + SK_IOC IoC, + int Port, + SK_U8 Mode); + +extern int SkGmLeaveLowPowerMode( + SK_AC *pAC, + SK_IOC IoC, + int Port); + #ifdef SK_DIAG extern void SkGePhyRead( SK_AC *pAC, @@ -1101,6 +1148,7 @@ extern int SkGeInitAssignRamToQueues(); extern void SkMacRxTxDisable(); extern void SkMacSoftRst(); extern void SkMacHardRst(); +extern void SkMacClearRst(); extern void SkMacInitPhy(); extern int SkMacRxTxEnable(); extern void SkMacPromiscMode(); @@ -1131,6 +1179,8 @@ extern int SkGmResetCounter(); extern int SkXmOverflowStatus(); extern int SkGmOverflowStatus(); extern int SkGmCableDiagStatus(); +extern int SkGmEnterLowPowerMode(); +extern int SkGmLeaveLowPowerMode(); #ifdef SK_DIAG extern void SkGePhyRead(); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/h/skgepnmi.h 830-ivtv/drivers/net/sk98lin/h/skgepnmi.h --- 000-virgin/drivers/net/sk98lin/h/skgepnmi.h Wed Aug 13 20:24:25 2003 +++ 830-ivtv/drivers/net/sk98lin/h/skgepnmi.h Thu Jan 8 08:54:22 2004 @@ -2,8 +2,8 @@ * * Name: skgepnmi.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.61 $ - * Date: $Date: 2003/05/23 12:53:52 $ + * Version: $Revision: 1.62 $ + * Date: $Date: 2003/08/15 12:31:52 $ * Purpose: Defines for Private Network Management Interface * ****************************************************************************/ @@ -27,6 +27,18 @@ * History: * * $Log: skgepnmi.h,v $ + * Revision 1.62 2003/08/15 12:31:52 tschilli + * Added new OIDs: + * OID_SKGE_DRIVER_RELDATE + * OID_SKGE_DRIVER_FILENAME + * OID_SKGE_CHIPID + * OID_SKGE_RAMSIZE + * OID_SKGE_VAUXAVAIL + * OID_SKGE_PHY_TYPE + * OID_SKGE_PHY_LP_MODE + * + * Added new define SK_DIAG_ATTACHED for OID_SKGE_DIAG_MODE handling. + * * Revision 1.61 2003/05/23 12:53:52 tschilli * Generic PNMI IOCTL subcommands added. * Function prototype SkPnmiGenIoctl() added. @@ -568,15 +580,23 @@ #define OID_SKGE_ALL_DATA 0xFF020190 /* Defines for VCT. */ -#define OID_SKGE_VCT_GET 0xFF020200 -#define OID_SKGE_VCT_SET 0xFF020201 -#define OID_SKGE_VCT_STATUS 0xFF020202 +#define OID_SKGE_VCT_GET 0xFF020200 +#define OID_SKGE_VCT_SET 0xFF020201 +#define OID_SKGE_VCT_STATUS 0xFF020202 #ifdef SK_DIAG_SUPPORT /* Defines for driver DIAG mode. */ -#define OID_SKGE_DIAG_MODE 0xFF020204 +#define OID_SKGE_DIAG_MODE 0xFF020204 #endif /* SK_DIAG_SUPPORT */ +/* New OIDs */ +#define OID_SKGE_DRIVER_RELDATE 0xFF020210 +#define OID_SKGE_DRIVER_FILENAME 0xFF020211 +#define OID_SKGE_CHIPID 0xFF020212 +#define OID_SKGE_RAMSIZE 0xFF020213 +#define OID_SKGE_VAUXAVAIL 0xFF020214 +#define OID_SKGE_PHY_TYPE 0xFF020215 +#define OID_SKGE_PHY_LP_MODE 0xFF020216 /* VCT struct to store a backup copy of VCT data after a port reset. */ typedef struct s_PnmiVct { @@ -613,6 +633,12 @@ typedef struct s_PnmiVct { #define OID_SKGE_TRAP_RLMT_PORT_UP 523 #define OID_SKGE_TRAP_RLMT_SEGMENTATION 524 +#ifdef SK_DIAG_SUPPORT +/* Defines for driver DIAG mode. */ +#define SK_DIAG_ATTACHED 2 +#define SK_DIAG_RUNNING 1 +#define SK_DIAG_IDLE 0 +#endif /* SK_DIAG_SUPPORT */ /* * Generic PNMI IOCTL subcommand definitions. @@ -730,6 +756,14 @@ typedef struct s_PnmiVct { #define SK_PNMI_ERR051MSG "SkPnmiEvent: Port switch suspicious" #define SK_PNMI_ERR052 (SK_ERRBASE_PNMI + 52) #define SK_PNMI_ERR052MSG "" +#define SK_PNMI_ERR053 (SK_ERRBASE_PNMI + 53) +#define SK_PNMI_ERR053MSG "General: Driver release date not initialized" +#define SK_PNMI_ERR054 (SK_ERRBASE_PNMI + 54) +#define SK_PNMI_ERR054MSG "General: Driver release date string too long" +#define SK_PNMI_ERR055 (SK_ERRBASE_PNMI + 55) +#define SK_PNMI_ERR055MSG "General: Driver file name not initialized" +#define SK_PNMI_ERR056 (SK_ERRBASE_PNMI + 56) +#define SK_PNMI_ERR056MSG "General: Driver file name string too long" /* * Management counter macros called by the driver @@ -740,6 +774,11 @@ typedef struct s_PnmiVct { #define SK_PNMI_SET_DRIVER_VER(pAC,v) ((pAC)->Pnmi.pDriverVersion = \ (char *)(v)) +#define SK_PNMI_SET_DRIVER_RELDATE(pAC,v) ((pAC)->Pnmi.pDriverReleaseDate = \ + (char *)(v)) + +#define SK_PNMI_SET_DRIVER_FILENAME(pAC,v) ((pAC)->Pnmi.pDriverFileName = \ + (char *)(v)) #define SK_PNMI_CNT_TX_QUEUE_LEN(pAC,v,p) \ { \ @@ -916,6 +955,8 @@ typedef struct s_PnmiConf { char ConfMacFactoryAddr[6]; SK_U8 ConfPMD; SK_U8 ConfConnector; + SK_U32 ConfPhyType; + SK_U32 ConfPhyMode; SK_U8 ConfLinkCapability; SK_U8 ConfLinkMode; SK_U8 ConfLinkModeStatus; @@ -964,9 +1005,14 @@ typedef struct s_PnmiStrucData { SK_U32 DeviceType; char DriverDescr[SK_PNMI_STRINGLEN1]; char DriverVersion[SK_PNMI_STRINGLEN2]; + char DriverReleaseDate[SK_PNMI_STRINGLEN1]; + char DriverFileName[SK_PNMI_STRINGLEN1]; char HwDescr[SK_PNMI_STRINGLEN1]; char HwVersion[SK_PNMI_STRINGLEN2]; SK_U16 Chipset; + SK_U32 ChipId; + SK_U8 VauxAvail; + SK_U32 RamSize; SK_U32 MtuSize; SK_U32 Action; SK_U32 TestResult; @@ -1090,6 +1136,8 @@ typedef struct s_PnmiData { char *pDriverDescription; char *pDriverVersion; + char *pDriverReleaseDate; + char *pDriverFileName; int MacUpdatedFlag; int RlmtUpdatedFlag; @@ -1119,6 +1167,9 @@ typedef struct s_PnmiData { SK_U8 VctStatus[SK_MAX_MACS]; SK_PNMI_VCT VctBackup[SK_MAX_MACS]; SK_PNMI_VCT_TIMER VctTimeout[SK_MAX_MACS]; +#ifdef SK_DIAG_SUPPORT + SK_U32 DiagAttached; +#endif /* SK_DIAG_SUPPORT */ } SK_PNMI; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/h/ski2c.h 830-ivtv/drivers/net/sk98lin/h/ski2c.h --- 000-virgin/drivers/net/sk98lin/h/ski2c.h Wed Aug 13 20:24:25 2003 +++ 830-ivtv/drivers/net/sk98lin/h/ski2c.h Thu Jan 8 08:54:22 2004 @@ -1,16 +1,17 @@ /****************************************************************************** * * Name: ski2c.h - * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.34 $ - * Date: $Date: 2003/01/28 09:11:21 $ + * Project: Gigabit Ethernet Adapters, TWSI-Module + * Version: $Revision: 1.35 $ + * Date: $Date: 2003/10/20 09:06:30 $ * Purpose: Defines to access Voltage and Temperature Sensor * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998-2003 SysKonnect GmbH. + * (C)Copyright 1998-2002 SysKonnect. + * (C)Copyright 2002-2003 Marvell. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +27,10 @@ * History: * * $Log: ski2c.h,v $ + * Revision 1.35 2003/10/20 09:06:30 rschmidt + * Added prototypes for SkI2cRead() and SkI2cWrite(). + * Editorial changes. + * * Revision 1.34 2003/01/28 09:11:21 rschmidt * Editorial changes * @@ -137,7 +142,6 @@ * Revision 1.1 1998/06/19 14:30:10 malthoff * Created. Sources taken from ML Project. * - * ******************************************************************************/ /* @@ -252,7 +256,7 @@ struct s_Sensor { SK_I32 SenThreWarnLow; /* Lower warning Threshold of the sensor */ int SenErrFlag; /* Sensor indicated an error */ SK_BOOL SenInit; /* Is sensor initialized ? */ - SK_U64 SenErrCts; /* Error trap counter */ + SK_U64 SenErrCts; /* Error trap counter */ SK_U64 SenWarnCts; /* Warning trap counter */ SK_U64 SenBegErrTS; /* Begin error timestamp */ SK_U64 SenBegWarnTS; /* Begin warning timestamp */ @@ -279,13 +283,17 @@ typedef struct s_I2c { #endif /* !SK_DIAG */ } SK_I2C; +extern int SkI2cInit(SK_AC *pAC, SK_IOC IoC, int Level); +extern int SkI2cWrite(SK_AC *pAC, SK_IOC IoC, SK_U32 Data, int Dev, int Size, + int Reg, int Burst); extern int SkI2cReadSensor(SK_AC *pAC, SK_IOC IoC, SK_SENSOR *pSen); -#ifndef SK_DIAG +#ifdef SK_DIAG +extern SK_U32 SkI2cRead(SK_AC *pAC, SK_IOC IoC, int Dev, int Size, int Reg, + int Burst); +#else /* !SK_DIAG */ extern int SkI2cEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event, SK_EVPARA Para); -extern int SkI2cInit(SK_AC *pAC, SK_IOC IoC, int Level); extern void SkI2cWaitIrq(SK_AC *pAC, SK_IOC IoC); extern void SkI2cIsr(SK_AC *pAC, SK_IOC IoC); - -#endif +#endif /* !SK_DIAG */ #endif /* n_SKI2C_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/h/skqueue.h 830-ivtv/drivers/net/sk98lin/h/skqueue.h --- 000-virgin/drivers/net/sk98lin/h/skqueue.h Wed Aug 13 20:24:25 2003 +++ 830-ivtv/drivers/net/sk98lin/h/skqueue.h Thu Jan 8 08:54:22 2004 @@ -1,9 +1,9 @@ /****************************************************************************** * * Name: skqueue.h - * Project: Gigabit Ethernet Adapters, Schedule-Modul - * Version: $Revision: 1.15 $ - * Date: $Date: 2003/05/13 17:54:57 $ + * Project: Gigabit Ethernet Adapters, Event Scheduler Module + * Version: $Revision: 1.16 $ + * Date: $Date: 2003/09/16 12:50:32 $ * Purpose: Defines for the Event queue * ******************************************************************************/ @@ -27,6 +27,9 @@ * History: * * $Log: skqueue.h,v $ + * Revision 1.16 2003/09/16 12:50:32 rschmidt + * Editorial changes + * * Revision 1.15 2003/05/13 17:54:57 mkarl * Editorial changes. * @@ -47,7 +50,7 @@ * add: typedef SK_QUEUE * * Revision 1.9 1998/08/19 09:50:59 gklug - * fix: remove struct keyword from c-code (see CCC) add typedefs + * fix: remove struct keyword from C-code (see CCC) add typedefs * * Revision 1.8 1998/08/18 07:00:01 gklug * fix: SK_PTR not defined use void * instead. @@ -74,8 +77,6 @@ * Revision 1.1 1998/07/30 14:52:12 gklug * Initial version. * Defines Event Classes, Event structs and queue management variables. - * - * * ******************************************************************************/ @@ -92,7 +93,7 @@ */ #define SKGE_DRV 1 /* Driver Event Class */ #define SKGE_RLMT 2 /* RLMT Event Class */ -#define SKGE_I2C 3 /* i2C Event Class */ +#define SKGE_I2C 3 /* I2C Event Class */ #define SKGE_PNMI 4 /* PNMI Event Class */ #define SKGE_CSUM 5 /* Checksum Event Class */ #define SKGE_HWAC 6 /* Hardware Access Event Class */ @@ -121,25 +122,25 @@ typedef union u_EvPara { * Event Queue * skqueue.c * events are class/value pairs - * class is addressee, e.g. RMT, PCM etc. + * class is addressee, e.g. RLMT, PNMI etc. * value is command, e.g. line state change, ring op change etc. */ typedef struct s_EventElem { - SK_U32 Class ; /* Event class */ - SK_U32 Event ; /* Event value */ - SK_EVPARA Para ; /* Event parameter */ + SK_U32 Class; /* Event class */ + SK_U32 Event; /* Event value */ + SK_EVPARA Para; /* Event parameter */ } SK_EVENTELEM; typedef struct s_Queue { SK_EVENTELEM EvQueue[SK_MAX_EVENT]; - SK_EVENTELEM *EvPut ; - SK_EVENTELEM *EvGet ; + SK_EVENTELEM *EvPut; + SK_EVENTELEM *EvGet; } SK_QUEUE; extern void SkEventInit(SK_AC *pAC, SK_IOC Ioc, int Level); extern void SkEventQueue(SK_AC *pAC, SK_U32 Class, SK_U32 Event, SK_EVPARA Para); -extern int SkEventDispatcher(SK_AC *pAC,SK_IOC Ioc); +extern int SkEventDispatcher(SK_AC *pAC, SK_IOC Ioc); /* Define Error Numbers and messages */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/h/sktimer.h 830-ivtv/drivers/net/sk98lin/h/sktimer.h --- 000-virgin/drivers/net/sk98lin/h/sktimer.h Wed Aug 13 20:24:25 2003 +++ 830-ivtv/drivers/net/sk98lin/h/sktimer.h Thu Jan 8 08:54:23 2004 @@ -1,9 +1,9 @@ /****************************************************************************** * * Name: sktimer.h - * Project: Gigabit Ethernet Adapters, Schedule-Modul - * Version: $Revision: 1.10 $ - * Date: $Date: 2003/05/13 17:56:44 $ + * Project: Gigabit Ethernet Adapters, Event Scheduler Module + * Version: $Revision: 1.11 $ + * Date: $Date: 2003/09/16 12:58:18 $ * Purpose: Defines for the timer functions * ******************************************************************************/ @@ -27,6 +27,9 @@ * History: * * $Log: sktimer.h,v $ + * Revision 1.11 2003/09/16 12:58:18 rschmidt + * Editorial changes + * * Revision 1.10 2003/05/13 17:56:44 mkarl * Editorial changes. * @@ -40,7 +43,7 @@ * fix: SK_TIMCTRL needs to be defined * * Revision 1.6 1998/08/19 09:51:00 gklug - * fix: remove struct keyword from c-code (see CCC) add typedefs + * fix: remove struct keyword from C-code (see CCC) add typedefs * * Revision 1.5 1998/08/17 13:43:21 gklug * chg: Parameter will be union of 64bit para, 2 times SK_U32 or SK_PTR @@ -78,25 +81,25 @@ typedef struct s_Timer SK_TIMER; struct s_Timer { - SK_TIMER *TmNext ; /* linked list */ - SK_U32 TmClass ; /* Timer Event class */ - SK_U32 TmEvent ; /* Timer Event value */ - SK_EVPARA TmPara ; /* Timer Event parameter */ - SK_U32 TmDelta ; /* delta time */ - int TmActive ; /* flag : active/inactive */ -} ; + SK_TIMER *TmNext; /* linked list */ + SK_U32 TmClass; /* Timer Event class */ + SK_U32 TmEvent; /* Timer Event value */ + SK_EVPARA TmPara; /* Timer Event parameter */ + SK_U32 TmDelta; /* delta time */ + int TmActive; /* flag: active/inactive */ +}; /* * Timer control struct. * - use in Adapters context name pAC->Tim */ typedef struct s_TimCtrl { - SK_TIMER *StQueue ; /* Head of Timer queue */ -} SK_TIMCTRL ; + SK_TIMER *StQueue; /* Head of Timer queue */ +} SK_TIMCTRL; -extern void SkTimerInit(SK_AC *pAC,SK_IOC Ioc, int Level); -extern void SkTimerStop(SK_AC *pAC,SK_IOC Ioc,SK_TIMER *pTimer); -extern void SkTimerStart(SK_AC *pAC,SK_IOC Ioc,SK_TIMER *pTimer, - SK_U32 Time,SK_U32 Class,SK_U32 Event,SK_EVPARA Para); -extern void SkTimerDone(SK_AC *pAC,SK_IOC Ioc); +extern void SkTimerInit(SK_AC *pAC, SK_IOC Ioc, int Level); +extern void SkTimerStop(SK_AC *pAC, SK_IOC Ioc, SK_TIMER *pTimer); +extern void SkTimerStart(SK_AC *pAC, SK_IOC Ioc, SK_TIMER *pTimer, + SK_U32 Time, SK_U32 Class, SK_U32 Event, SK_EVPARA Para); +extern void SkTimerDone(SK_AC *pAC, SK_IOC Ioc); #endif /* _SKTIMER_H_ */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/h/sktypes.h 830-ivtv/drivers/net/sk98lin/h/sktypes.h --- 000-virgin/drivers/net/sk98lin/h/sktypes.h Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/sk98lin/h/sktypes.h Thu Jan 8 08:54:23 2004 @@ -2,15 +2,16 @@ * * Name: sktypes.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.1 $ - * Date: $Date: 2003/07/21 07:26:01 $ + * Version: $Revision: 1.2 $ + * Date: $Date: 2003/10/07 08:16:51 $ * Purpose: Define data types for Linux * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998-2003 SysKonnect GmbH. + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +27,9 @@ * History: * * $Log: sktypes.h,v $ + * Revision 1.2 2003/10/07 08:16:51 mlindner + * Fix: Copyright changes + * * Revision 1.1 2003/07/21 07:26:01 rroesler * Fix: Re-Enter after CVS crash * diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/h/skversion.h 830-ivtv/drivers/net/sk98lin/h/skversion.h --- 000-virgin/drivers/net/sk98lin/h/skversion.h Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/sk98lin/h/skversion.h Thu Jan 8 08:54:23 2004 @@ -2,15 +2,16 @@ * * Name: version.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.3 $ - * Date: $Date: 2003/08/25 13:34:48 $ + * Version: $Revision: 1.5 $ + * Date: $Date: 2003/10/07 08:16:51 $ * Purpose: SK specific Error log support * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998-2003 SysKonnect GmbH. + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,6 +26,12 @@ * * History: * $Log: skversion.h,v $ + * Revision 1.5 2003/10/07 08:16:51 mlindner + * Fix: Copyright changes + * + * Revision 1.4 2003/09/22 08:40:10 mlindner + * Add: Added DRIVER_FILE_NAME and DRIVER_REL_DATE + * * Revision 1.3 2003/08/25 13:34:48 mlindner * Fix: Lint changes * @@ -54,12 +61,14 @@ #ifdef lint static const char SysKonnectFileId[] = "@(#) (C) SysKonnect GmbH."; static const char SysKonnectBuildNumber[] = - "@(#)SK-BUILD: 6.18 PL: 01"; + "@(#)SK-BUILD: 6.21 PL: 01"; #endif /* !defined(lint) */ -#define BOOT_STRING "sk98lin: Network Device Driver v6.18\n" \ +#define BOOT_STRING "sk98lin: Network Device Driver v6.21\n" \ "(C)Copyright 1999-2003 Marvell(R)." -#define VER_STRING "6.18" +#define VER_STRING "6.21" +#define DRIVER_FILE_NAME "sk98lin" +#define DRIVER_REL_DATE "Dec-15-2003" diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/h/xmac_ii.h 830-ivtv/drivers/net/sk98lin/h/xmac_ii.h --- 000-virgin/drivers/net/sk98lin/h/xmac_ii.h Wed Aug 13 20:24:25 2003 +++ 830-ivtv/drivers/net/sk98lin/h/xmac_ii.h Thu Jan 8 08:54:23 2004 @@ -2,8 +2,8 @@ * * Name: xmac_ii.h * Project: Gigabit Ethernet Adapters, Common Modules - * Version: $Revision: 1.48 $ - * Date: $Date: 2003/05/13 17:17:55 $ + * Version: $Revision: 1.52 $ + * Date: $Date: 2003/10/02 16:35:50 $ * Purpose: Defines and Macros for Gigabit Ethernet Controller * ******************************************************************************/ @@ -27,6 +27,22 @@ * History: * * $Log: xmac_ii.h,v $ + * Revision 1.52 2003/10/02 16:35:50 rschmidt + * Added defines for default values of GMAC parameters + * Changed defines for setting GMAC parameters + * Editorial changes + * + * Revision 1.51 2003/09/23 09:04:27 malthoff + * Add bit definitions for PHY_MARV_EXT_P_STAT. + * + * Revision 1.50 2003/09/16 14:15:07 rschmidt + * Added defines for Extended PHY Specific Control + * Editorial changes + * + * Revision 1.49 2003/09/16 07:22:46 mschmid + * Added defines for Marvell PHY energy detect modes + * Added macros for MAC parameter setting in port structure + * * Revision 1.48 2003/05/13 17:17:55 mkarl * Editorial changes. * @@ -676,7 +692,7 @@ extern "C" { #define PHY_XMAC_AUNE_LP 0x05 /* 16 bit r/o Link Partner Abi Reg */ #define PHY_XMAC_AUNE_EXP 0x06 /* 16 bit r/o Auto-Neg. Expansion Reg */ #define PHY_XMAC_NEPG 0x07 /* 16 bit r/w Next Page Register */ -#define PHY_XMAC_NEPG_LP 0x08 /* 16 bit r/o Next Page Link P Reg */ +#define PHY_XMAC_NEPG_LP 0x08 /* 16 bit r/o Next Page Link Partner */ /* 0x09 - 0x0e: reserved */ #define PHY_XMAC_EXT_STAT 0x0f /* 16 bit r/o Ext Status Register */ #define PHY_XMAC_RES_ABI 0x10 /* 16 bit r/o PHY Resolved Ability */ @@ -693,7 +709,7 @@ extern "C" { #define PHY_BCOM_AUNE_LP 0x05 /* 16 bit r/o Link Part Ability Reg */ #define PHY_BCOM_AUNE_EXP 0x06 /* 16 bit r/o Auto-Neg. Expansion Reg */ #define PHY_BCOM_NEPG 0x07 /* 16 bit r/w Next Page Register */ -#define PHY_BCOM_NEPG_LP 0x08 /* 16 bit r/o Next Page Link P Reg */ +#define PHY_BCOM_NEPG_LP 0x08 /* 16 bit r/o Next Page Link Partner */ /* Broadcom-specific registers */ #define PHY_BCOM_1000T_CTRL 0x09 /* 16 bit r/w 1000Base-T Ctrl Reg */ #define PHY_BCOM_1000T_STAT 0x0a /* 16 bit r/o 1000Base-T Status Reg */ @@ -702,7 +718,7 @@ extern "C" { #define PHY_BCOM_P_EXT_CTRL 0x10 /* 16 bit r/w PHY Extended Ctrl Reg */ #define PHY_BCOM_P_EXT_STAT 0x11 /* 16 bit r/o PHY Extended Stat Reg */ #define PHY_BCOM_RE_CTR 0x12 /* 16 bit r/w Receive Error Counter */ -#define PHY_BCOM_FC_CTR 0x13 /* 16 bit r/w False Carr Sense Cnt */ +#define PHY_BCOM_FC_CTR 0x13 /* 16 bit r/w False Carrier Sense Cnt */ #define PHY_BCOM_RNO_CTR 0x14 /* 16 bit r/w Receiver NOT_OK Cnt */ /* 0x15 - 0x17: reserved */ #define PHY_BCOM_AUX_CTRL 0x18 /* 16 bit r/w Auxiliary Control Reg */ @@ -724,7 +740,7 @@ extern "C" { #define PHY_MARV_AUNE_LP 0x05 /* 16 bit r/o Link Part Ability Reg */ #define PHY_MARV_AUNE_EXP 0x06 /* 16 bit r/o Auto-Neg. Expansion Reg */ #define PHY_MARV_NEPG 0x07 /* 16 bit r/w Next Page Register */ -#define PHY_MARV_NEPG_LP 0x08 /* 16 bit r/o Next Page Link P Reg */ +#define PHY_MARV_NEPG_LP 0x08 /* 16 bit r/o Next Page Link Partner */ /* Marvel-specific registers */ #define PHY_MARV_1000T_CTRL 0x09 /* 16 bit r/w 1000Base-T Ctrl Reg */ #define PHY_MARV_1000T_STAT 0x0a /* 16 bit r/o 1000Base-T Status Reg */ @@ -757,7 +773,7 @@ extern "C" { #define PHY_LONE_AUNE_LP 0x05 /* 16 bit r/o Link Part Ability Reg */ #define PHY_LONE_AUNE_EXP 0x06 /* 16 bit r/o Auto-Neg. Expansion Reg */ #define PHY_LONE_NEPG 0x07 /* 16 bit r/w Next Page Register */ -#define PHY_LONE_NEPG_LP 0x08 /* 16 bit r/o Next Page Link Partner*/ +#define PHY_LONE_NEPG_LP 0x08 /* 16 bit r/o Next Page Link Partner */ /* Level One-specific registers */ #define PHY_LONE_1000T_CTRL 0x09 /* 16 bit r/w 1000Base-T Control Reg*/ #define PHY_LONE_1000T_STAT 0x0a /* 16 bit r/o 1000Base-T Status Reg */ @@ -804,12 +820,13 @@ extern "C" { /* * PHY bit definitions * Bits defined as PHY_X_..., PHY_B_..., PHY_L_... or PHY_N_... are - * Xmac/Broadcom/LevelOne/National-specific. + * XMAC/Broadcom/LevelOne/National/Marvell-specific. * All other are general. */ /***** PHY_XMAC_CTRL 16 bit r/w PHY Control Register *****/ /***** PHY_BCOM_CTRL 16 bit r/w PHY Control Register *****/ +/***** PHY_MARV_CTRL 16 bit r/w PHY Status Register *****/ /***** PHY_LONE_CTRL 16 bit r/w PHY Control Register *****/ #define PHY_CT_RESET (1<<15) /* Bit 15: (sc) clear all PHY related regs */ #define PHY_CT_LOOP (1<<14) /* Bit 14: enable Loopback over PHY */ @@ -909,27 +926,20 @@ extern "C" { /***** PHY_XMAC_AUNE_EXP 16 bit r/o Auto-Negotiation Expansion Reg *****/ /* Bit 15..4: reserved */ -#define PHY_AN_LP_NP (1<<3) /* Bit 3: Link Partner can Next Page */ -#define PHY_AN_LOC_NP (1<<2) /* Bit 2: Local PHY can Next Page */ -#define PHY_AN_RX_PG (1<<1) /* Bit 1: Page Received */ +#define PHY_ANE_LP_NP (1<<3) /* Bit 3: Link Partner can Next Page */ +#define PHY_ANE_LOC_NP (1<<2) /* Bit 2: Local PHY can Next Page */ +#define PHY_ANE_RX_PG (1<<1) /* Bit 1: Page Received */ /* Bit 0: reserved */ /***** PHY_BCOM_AUNE_EXP 16 bit r/o Auto-Negotiation Expansion Reg *****/ - /* Bit 15..5: reserved */ -#define PHY_B_AN_PDF (1<<4) /* Bit 4: Parallel Detection Fault */ -/* PHY_AN_LP_NP (see XMAC) Bit 3: Link Partner can Next Page */ -/* PHY_AN_LOC_NP (see XMAC) Bit 2: Local PHY can Next Page */ -/* PHY_AN_RX_PG (see XMAC) Bit 1: Page Received */ -#define PHY_B_AN_LP_CAP (1<<0) /* Bit 0: Link Partner Auto-Neg. Cap. */ - /***** PHY_LONE_AUNE_EXP 16 bit r/o Auto-Negotiation Expansion Reg *****/ -#define PHY_L_AN_BP (1<<5) /* Bit 5: Base Page Indication */ -#define PHY_L_AN_PDF (1<<4) /* Bit 4: Parallel Detection Fault */ -/* PHY_AN_LP_NP (see XMAC) Bit 3: Link Partner can Next Page */ -/* PHY_AN_LOC_NP (see XMAC) Bit 2: Local PHY can Next Page */ -/* PHY_AN_RX_PG (see XMAC) Bit 1: Page Received */ -#define PHY_B_AN_LP_CAP (1<<0) /* Bit 0: Link Partner Auto-Neg. Cap. */ - +/***** PHY_MARV_AUNE_EXP 16 bit r/o Auto-Negotiation Expansion Reg *****/ + /* Bit 15..5: reserved */ +#define PHY_ANE_PAR_DF (1<<4) /* Bit 4: Parallel Detection Fault */ +/* PHY_ANE_LP_NP (see XMAC) Bit 3: Link Partner can Next Page */ +/* PHY_ANE_LOC_NP (see XMAC) Bit 2: Local PHY can Next Page */ +/* PHY_ANE_RX_PG (see XMAC) Bit 1: Page Received */ +#define PHY_ANE_LP_CAP (1<<0) /* Bit 0: Link Partner Auto-Neg. Cap. */ /***** PHY_XMAC_NEPG 16 bit r/w Next Page Register *****/ /***** PHY_BCOM_NEPG 16 bit r/w Next Page Register *****/ @@ -958,7 +968,7 @@ extern "C" { #define PHY_X_RS_HD (1<<6) /* Bit 6: Half Duplex Mode selected */ #define PHY_X_RS_FD (1<<5) /* Bit 5: Full Duplex Mode selected */ #define PHY_X_RS_ABLMIS (1<<4) /* Bit 4: duplex or pause cap mismatch */ -#define PHY_X_RS_PAUMIS (1<<3) /* Bit 3: pause capability missmatch */ +#define PHY_X_RS_PAUMIS (1<<3) /* Bit 3: pause capability mismatch */ /* Bit 2..0: reserved */ /* * Remote Fault Bits (PHY_X_AN_RFB) encoding @@ -990,6 +1000,7 @@ extern "C" { /* Bit 7..0: reserved */ /***** PHY_BCOM_1000T_STAT 16 bit r/o 1000Base-T Status Reg *****/ +/***** PHY_MARV_1000T_STAT 16 bit r/o 1000Base-T Status Reg *****/ #define PHY_B_1000S_MSF (1<<15) /* Bit 15: Master/Slave Fault */ #define PHY_B_1000S_MSR (1<<14) /* Bit 14: Master/Slave Result */ #define PHY_B_1000S_LRS (1<<13) /* Bit 13: Local Receiver Status */ @@ -1309,7 +1320,6 @@ extern "C" { /* Bit 7..0: reserved */ /***** PHY_MARV_PHY_CTRL 16 bit r/w PHY Specific Ctrl Reg *****/ - #define PHY_M_PC_TX_FFD_MSK (3<<14) /* Bit 15..14: Tx FIFO Depth Mask */ #define PHY_M_PC_RX_FFD_MSK (3<<12) /* Bit 13..12: Rx FIFO Depth Mask */ #define PHY_M_PC_ASS_CRS_TX (1<<11) /* Bit 11: Assert CRS on Transmit */ @@ -1323,6 +1333,9 @@ extern "C" { #define PHY_M_PC_POL_R_DIS (1<<1) /* Bit 1: Polarity Reversal Disabled */ #define PHY_M_PC_DIS_JABBER (1<<0) /* Bit 0: Disable Jabber */ +#define PHY_M_PC_EN_DET SHIFT8(2) /* Energy Detect (Mode 1) */ +#define PHY_M_PC_EN_DET_PLUS SHIFT8(3) /* Energy Detect Plus (Mode 2) */ + #define PHY_M_PC_MDI_XMODE(x) SHIFT5(x) #define PHY_M_PC_MAN_MDI 0 /* 00 = Manual MDI configuration */ #define PHY_M_PC_MAN_MDIX 1 /* 01 = Manual MDIX configuration */ @@ -1373,6 +1386,7 @@ extern "C" { #define PHY_M_EC_M_DSC_MSK (3<<10) /* Bit 11..10: Master downshift counter */ #define PHY_M_EC_S_DSC_MSK (3<<8) /* Bit 9.. 8: Slave downshift counter */ #define PHY_M_EC_MAC_S_MSK (7<<4) /* Bit 6.. 4: Def. MAC interface speed */ +#define PHY_M_EC_FIB_AN_ENA (1<<3) /* Bit 3: Fiber Auto-Neg. Enable */ #define PHY_M_EC_M_DSC(x) SHIFT10(x) /* 00=1x; 01=2x; 10=3x; 11=4x */ #define PHY_M_EC_S_DSC(x) SHIFT8(x) /* 00=dis; 01=1x; 10=2x; 11=3x */ @@ -1434,6 +1448,18 @@ extern "C" { #define PHY_M_EC2_FO_BOOST (1<<3) /* Bit 3: Fiber Output Boost */ #define PHY_M_EC2_FO_AM_MSK 7 /* Bit 2.. 0: Fiber Output Amplitude */ +/***** PHY_MARV_EXT_P_STAT 16 bit r/w Ext. PHY Specific Status *****/ +#define PHY_M_FC_AUTO_SEL (1<<15) /* Bit 15: Fiber/Copper Auto Sel. dis. */ +#define PHY_M_FC_AN_REG_ACC (1<<14) /* Bit 14: Fiber/Copper Autoneg. reg acc */ +#define PHY_M_FC_RESULUTION (1<<13) /* Bit 13: Fiber/Copper Resulution */ +#define PHY_M_SER_IF_AN_BP (1<<12) /* Bit 12: Ser IF autoneg. bypass enable */ +#define PHY_M_SER_IF_BP_ST (1<<11) /* Bit 11: Ser IF autoneg. bypass status */ +#define PHY_M_IRQ_POLARITY (1<<10) /* Bit 10: IRQ polarity */ + /* Bit 9..4: reserved */ +#define PHY_M_UNDOC1 (1<< 7) /* undocumented bit !! */ +#define PHY_M_MODE_MASK (0xf<<0)/* Bit 3..0: copy of HWCFG MODE[3:0] */ + + /***** PHY_MARV_CABLE_DIAG 16 bit r/o Cable Diagnostic Reg *****/ #define PHY_M_CABD_ENA_TEST (1<<15) /* Bit 15: Enable Test */ #define PHY_M_CABD_STAT_MSK (3<<13) /* Bit 14..13: Status */ @@ -1531,7 +1557,7 @@ extern "C" { #define GM_RXF_SHT \ (GM_MIB_CNT_BASE + 80) /* Frames <64 Byte Received OK */ #define GM_RXE_FRAG \ - (GM_MIB_CNT_BASE + 88) /* Frames <64 Byte Receeived with FCS Err */ + (GM_MIB_CNT_BASE + 88) /* Frames <64 Byte Received with FCS Err */ #define GM_RXF_64B \ (GM_MIB_CNT_BASE + 96) /* 64 Byte Rx Frame */ #define GM_RXF_127B \ @@ -1606,7 +1632,6 @@ extern "C" { */ /* GM_GP_STAT 16 bit r/o General Purpose Status Register */ - #define GM_GPSR_SPEED (1<<15) /* Bit 15: Port Speed (1 = 100 Mbps) */ #define GM_GPSR_DUPLEX (1<<14) /* Bit 14: Duplex Mode (1 = Full) */ #define GM_GPSR_FC_TX_DIS (1<<13) /* Bit 13: Tx Flow-Control Mode Disabled */ @@ -1646,11 +1671,14 @@ extern "C" { GM_GPCR_AU_SPD_DIS) /* GM_TX_CTRL 16 bit r/w Transmit Control Register */ - #define GM_TXCR_FORCE_JAM (1<<15) /* Bit 15: Force Jam / Flow-Control */ #define GM_TXCR_CRC_DIS (1<<14) /* Bit 14: Disable insertion of CRC */ #define GM_TXCR_PAD_DIS (1<<13) /* Bit 13: Disable padding of packets */ -#define GM_TXCR_COL_THR (4<<10) /* Bit 12..10: Collision Threshold */ +#define GM_TXCR_COL_THR_MSK (1<<10) /* Bit 12..10: Collision Threshold */ + +#define TX_COL_THR(x) (SHIFT10(x) & GM_TXCR_COL_THR_MSK) + +#define TX_COL_DEF 0x04 /* GM_RX_CTRL 16 bit r/w Receive Control Register */ #define GM_RXCR_UCF_ENA (1<<15) /* Bit 15: Enable Unicast filtering */ @@ -1663,35 +1691,41 @@ extern "C" { #define GM_TXPA_JAMIPG_MSK (0x1f<<9) /* Bit 13..9: Jam IPG */ #define GM_TXPA_JAMDAT_MSK (0x1f<<4) /* Bit 8..4: IPG Jam to Data */ /* Bit 3..0: reserved */ -#define JAM_LEN_VAL(x) SHIFT14(x) -#define JAM_IPG_VAL(x) SHIFT9(x) -#define IPG_JAM_DATA(x) SHIFT4(x) + +#define TX_JAM_LEN_VAL(x) (SHIFT14(x) & GM_TXPA_JAMLEN_MSK) +#define TX_JAM_IPG_VAL(x) (SHIFT9(x) & GM_TXPA_JAMIPG_MSK) +#define TX_IPG_JAM_DATA(x) (SHIFT4(x) & GM_TXPA_JAMDAT_MSK) + +#define TX_JAM_LEN_DEF 0x03 +#define TX_JAM_IPG_DEF 0x0b +#define TX_IPG_JAM_DEF 0x1c /* GM_SERIAL_MODE 16 bit r/w Serial Mode Register */ -#define GM_SMOD_DATABL_MSK (0x1f<<11) /* Bit 15..11: Data Blinder */ +#define GM_SMOD_DATABL_MSK (0x1f<<11) /* Bit 15..11: Data Blinder (r/o) */ #define GM_SMOD_LIMIT_4 (1<<10) /* Bit 10: 4 consecutive Tx trials */ #define GM_SMOD_VLAN_ENA (1<<9) /* Bit 9: Enable VLAN (Max. Frame Len) */ #define GM_SMOD_JUMBO_ENA (1<<8) /* Bit 8: Enable Jumbo (Max. Frame Len) */ /* Bit 7..5: reserved */ #define GM_SMOD_IPG_MSK 0x1f /* Bit 4..0: Inter-Packet Gap (IPG) */ -#define DATA_BLIND_VAL(x) SHIFT11(x) -#define DATA_BLIND_FAST_ETH 0x1c -#define DATA_BLIND_GIGABIT 4 +#define DATA_BLIND_VAL(x) (SHIFT11(x) & GM_SMOD_DATABL_MSK) +#define DATA_BLIND_DEF 0x04 -#define IPG_VAL_FAST_ETH 0x1e -#define IPG_VAL_GIGABIT 6 +#define IPG_DATA_VAL(x) (x & GM_SMOD_IPG_MSK) +#define IPG_DATA_DEF 0x1e /* GM_SMI_CTRL 16 bit r/w SMI Control Register */ - -#define GM_SMI_CT_PHY_AD(x) SHIFT11(x) -#define GM_SMI_CT_REG_AD(x) SHIFT6(x) +#define GM_SMI_CT_PHY_A_MSK (0x1f<<11) /* Bit 15..11: PHY Device Address */ +#define GM_SMI_CT_REG_A_MSK (0x1f<<6) /* Bit 10.. 6: PHY Register Address */ #define GM_SMI_CT_OP_RD (1<<5) /* Bit 5: OpCode Read (0=Write)*/ #define GM_SMI_CT_RD_VAL (1<<4) /* Bit 4: Read Valid (Read completed) */ #define GM_SMI_CT_BUSY (1<<3) /* Bit 3: Busy (Operation in progress) */ /* Bit 2..0: reserved */ -/* GM_PHY_ADDR 16 bit r/w GPHY Address Register */ +#define GM_SMI_CT_PHY_AD(x) (SHIFT11(x) & GM_SMI_CT_PHY_A_MSK) +#define GM_SMI_CT_REG_AD(x) (SHIFT6(x) & GM_SMI_CT_REG_A_MSK) + + /* GM_PHY_ADDR 16 bit r/w GPHY Address Register */ /* Bit 15..6: reserved */ #define GM_PAR_MIB_CLR (1<<5) /* Bit 5: Set MIB Clear Counter Mode */ #define GM_PAR_MIB_TST (1<<4) /* Bit 4: MIB Load Counter (Test Mode) */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/skcsum.c 830-ivtv/drivers/net/sk98lin/skcsum.c --- 000-virgin/drivers/net/sk98lin/skcsum.c Wed Aug 13 20:24:25 2003 +++ 830-ivtv/drivers/net/sk98lin/skcsum.c Thu Jan 8 08:54:23 2004 @@ -2,8 +2,8 @@ * * Name: skcsum.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.11 $ - * Date: $Date: 2003/03/11 14:05:55 $ + * Version: $Revision: 1.12 $ + * Date: $Date: 2003/08/20 13:55:53 $ * Purpose: Store/verify Internet checksum in send/receive packets. * ******************************************************************************/ @@ -26,6 +26,10 @@ * History: * * $Log: skcsum.c,v $ + * Revision 1.12 2003/08/20 13:55:53 mschmid + * Changed notation of #ifndef SkCsCalculateChecksum to + * #ifndef SK_CS_CALCULATE_CHECKSUM + * * Revision 1.11 2003/03/11 14:05:55 rschmidt * Replaced memset() by macro SK_MEMSET() * Editorial changes @@ -78,7 +82,7 @@ #ifndef lint static const char SysKonnectFileId[] = - "@(#) $Id: skcsum.c,v 1.11 2003/03/11 14:05:55 rschmidt Exp $ (C) SysKonnect."; + "@(#) $Id: skcsum.c,v 1.12 2003/08/20 13:55:53 mschmid Exp $ (C) SysKonnect."; #endif /* !lint */ /****************************************************************************** @@ -791,7 +795,7 @@ int NetNumber) *pChecksum2Offset = SKCS_MAC_HEADER_SIZE + SKCS_IP_HEADER_SIZE; } /* SkCsSetReceiveFlags */ -#ifndef SkCsCalculateChecksum +#ifndef SK_CS_CALCULATE_CHECKSUM /****************************************************************************** * @@ -856,7 +860,7 @@ unsigned Length) /* Length of data. */ return ((unsigned) Checksum); } /* SkCsCalculateChecksum */ -#endif /* SkCsCalculateChecksum */ +#endif /* SK_CS_CALCULATE_CHECKSUM */ /****************************************************************************** * diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/skdim.c 830-ivtv/drivers/net/sk98lin/skdim.c --- 000-virgin/drivers/net/sk98lin/skdim.c Mon Nov 17 18:29:30 2003 +++ 830-ivtv/drivers/net/sk98lin/skdim.c Thu Jan 8 08:54:23 2004 @@ -2,8 +2,8 @@ * * Name: skdim.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.2 $ - * Date: $Date: 2003/08/21 12:35:05 $ + * Version: $Revision: 1.5 $ + * Date: $Date: 2003/11/28 12:55:40 $ * Purpose: All functions to maintain interrupt moderation * ******************************************************************************/ @@ -11,6 +11,7 @@ /****************************************************************************** * * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +27,15 @@ * History: * * $Log: skdim.c,v $ + * Revision 1.5 2003/11/28 12:55:40 rroesler + * Fix: support for new process timing interface added + * + * Revision 1.4 2003/10/10 10:58:56 mlindner + * Fix: CPU detection under the kernel 2.6 + * + * Revision 1.3 2003/10/07 08:17:08 mlindner + * Fix: Copyright changes + * * Revision 1.2 2003/08/21 12:35:05 mlindner * Fix: Corrected CPU detection and compile errors on single CPU machines * @@ -62,7 +72,7 @@ #ifndef lint static const char SysKonnectFileId[] = - "@(#) $Id: skdim.c,v 1.2 2003/08/21 12:35:05 mlindner Exp $ (C) SysKonnect."; + "@(#) $Id: skdim.c,v 1.5 2003/11/28 12:55:40 rroesler Exp $ (C) SysKonnect."; #endif #define __SKADDR_C @@ -327,7 +337,9 @@ GetCurrentSystemLoad(SK_AC *pAC) { ** ** struct kernel_stat kstat ** - ** is not marked as an exported symbol + ** is not marked as an exported symbol in the file + ** + ** kernel/ksyms.c ** ** As a consequence, using this driver as KLM is not possible ** and any access of the structure kernel_stat via the diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/skge.c 830-ivtv/drivers/net/sk98lin/skge.c --- 000-virgin/drivers/net/sk98lin/skge.c Mon Nov 17 18:29:42 2003 +++ 830-ivtv/drivers/net/sk98lin/skge.c Thu Jan 8 08:54:24 2004 @@ -1,35 +1,20 @@ /****************************************************************************** * - * Name: skge.c + * Name: skge.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.11 $ - * Date: $Date: 2003/08/26 16:05:19 $ + * Version: $Revision: 1.42 $ + * Date: $Date: 2003/12/12 10:05:43 $ * Purpose: The main driver source module * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998-2003 SysKonnect GmbH. + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. * - * Driver for SysKonnect Gigabit Ethernet Server Adapters: - * - * SK-9871 (single link 1000Base-ZX) - * SK-9872 (dual link 1000Base-ZX) - * SK-9861 (single link 1000Base-SX, VF45 Volition Plug) - * SK-9862 (dual link 1000Base-SX, VF45 Volition Plug) - * SK-9841 (single link 1000Base-LX) - * SK-9842 (dual link 1000Base-LX) - * SK-9843 (single link 1000Base-SX) - * SK-9844 (dual link 1000Base-SX) - * SK-9821 (single link 1000Base-T) - * SK-9822 (dual link 1000Base-T) - * SK-9881 (single link 1000Base-SX V2 LC) - * SK-9871 (single link 1000Base-ZX V2) - * SK-9861 (single link 1000Base-SX V2, VF45 Volition Plug) - * SK-9841 (single link 1000Base-LX V2) - * SK-9843 (single link 1000Base-SX V2) - * SK-9821 (single link 1000Base-T V2) + * Driver for Marvell Yukon chipset and SysKonnect Gigabit Ethernet + * Server Adapters. * * Created 10-Feb-1999, based on Linux' acenic.c, 3c59x.c and * SysKonnects GEnesis Solaris driver @@ -56,6 +41,87 @@ * History: * * $Log: skge.c,v $ + * Revision 1.42 2003/12/12 10:05:43 mlindner + * Fix: Format of error message corrected + * + * Revision 1.41 2003/12/11 16:03:57 mlindner + * Fix: Create backup from pnmi data structure + * + * Revision 1.40 2003/12/11 12:14:48 mlindner + * Fix: Initalize Board before network configuration + * Fix: Change device names to driver name + * + * Revision 1.39 2003/12/10 08:57:38 rroesler + * Fix: Modifications regarding try_module_get() and capable() + * + * Revision 1.38 2003/12/01 17:16:50 mlindner + * Fix: Remove useless register_netdev + * + * Revision 1.37 2003/12/01 17:11:30 mlindner + * Fix: Register net device before SkGeBoardInit + * + * Revision 1.36 2003/11/28 13:04:27 rroesler + * Fix: do not print interface status in case DIAG is used + * + * Revision 1.35 2003/11/17 14:41:06 mlindner + * Fix: Endif command + * + * Revision 1.34 2003/11/17 13:29:05 mlindner + * Fix: Editorial changes + * + * Revision 1.33 2003/11/14 14:56:54 rroesler + * Fix: corrected compilation warnings kernel 2.2 + * + * Revision 1.32 2003/11/13 14:18:47 rroesler + * Fix: added latest changes regarding the use of the proc system + * + * Revision 1.31 2003/11/13 09:28:35 rroesler + * Fix: removed kernel warning 'driver changed get_stats after register' + * + * Revision 1.30 2003/11/11 13:15:27 rroesler + * Fix: use suitables kernel usage count macros when using the diag + * + * Revision 1.29 2003/11/10 09:38:26 rroesler + * Fix: restore PNMI structure backup for DIAG actions + * + * Revision 1.28 2003/11/07 17:28:45 rroesler + * Fix: Additions for the LeaveDiagMode + * + * Revision 1.27 2003/11/03 13:21:14 mlindner + * Add: SkGeBuffPad function for padding to ensure the trailing bytes exist + * + * Revision 1.26 2003/10/30 09:20:40 mlindner + * Fix: Control bit check + * + * Revision 1.25 2003/10/29 07:43:37 rroesler + * Fix: Implemented full None values handling for parameter Moderation + * + * Revision 1.24 2003/10/22 14:18:12 rroesler + * Fix: DIAG handling for DualNet cards + * + * Revision 1.23 2003/10/17 10:05:13 mlindner + * Add: New blinkmode for Morvell cards + * + * Revision 1.22 2003/10/15 12:31:25 rroesler + * Fix: Corrected bugreport #10954 (Linux System crash when using vlans) + * + * Revision 1.21 2003/10/07 12:32:28 mlindner + * Fix: Editorial changes + * + * Revision 1.20 2003/10/07 12:22:40 mlindner + * Fix: Compiler warnings + * + * Revision 1.19 2003/10/07 09:33:40 mlindner + * Fix: No warnings for illegal values of Mod and IntsPerSec + * Fix: Speed 100 in Half Duplex not allowed for Yukon + * Fix: PrefPort=B not allowed on single NICs + * + * Revision 1.18 2003/10/07 08:17:08 mlindner + * Fix: Copyright changes + * + * Revision 1.17 2003/09/29 12:06:59 mlindner + * *** empty log message *** + * * Revision 1.16 2003/09/23 11:07:35 mlindner * Fix: IO-control return race condition * Fix: Interrupt moderation value check @@ -68,6 +134,12 @@ * Add: Yukon Plus changes (ChipID, PCI...) * Fix: TCP and UDP Checksum calculation * + * Revision 1.13 2003/09/01 13:30:08 rroesler + * Fix: Corrected missing defines + * + * Revision 1.12 2003/09/01 13:12:02 rroesler + * Add: Code for improved DIAG Attach/Detach interface + * * Revision 1.11 2003/08/26 16:05:19 mlindner * Fix: Compiler warnings (void *) * @@ -406,7 +478,6 @@ * * * "h/skdrv1st.h" - * * * * @@ -568,6 +639,12 @@ static void StartDrvCleanupTimer(SK_AC * static void StopDrvCleanupTimer(SK_AC *pAC); static int XmitFrameSG(SK_AC*, TX_PORT*, struct sk_buff*); +#ifdef SK_DIAG_SUPPORT +static SK_U32 ParseDeviceNbrFromSlotName(const char *SlotName); +static int SkDrvInitAdapter(SK_AC *pAC, int devNbr); +static int SkDrvDeInitAdapter(SK_AC *pAC, int devNbr); +#endif + /******************************************************************************* * * Extern Function Prototypes @@ -576,8 +653,8 @@ static int XmitFrameSG(SK_AC*, TX_PORT*, #ifdef CONFIG_PROC_FS static const char SK_Root_Dir_entry[] = "sk98lin"; -static struct proc_dir_entry *pSkRootDir; -extern struct file_operations sk_proc_fops; +static struct proc_dir_entry *pSkRootDir = NULL; +extern struct file_operations sk_proc_fops; #endif extern void SkDimEnableModerationIfNeeded(SK_AC *pAC); @@ -595,12 +672,19 @@ static void DumpLong(char*, int); static const char *BootString = BOOT_STRING; struct SK_NET_DEVICE *SkGeRootDev = NULL; static int probed __initdata = 0; +static SK_BOOL DoPrintInterfaceChange = SK_TRUE; /* local variables **********************************************************/ static uintptr_t TxQueueAddr[SK_MAX_MACS][2] = {{0x680, 0x600},{0x780, 0x700}}; static uintptr_t RxQueueAddr[SK_MAX_MACS] = {0x400, 0x480}; +#ifdef CONFIG_PROC_FS +static struct proc_dir_entry *pSkRootDir; +#endif + + + /***************************************************************************** * * skge_probe - find all SK-98xx adapters @@ -626,6 +710,7 @@ static int __init skge_probe (void) SK_BOOL BootStringCount = SK_FALSE; int retval; #ifdef CONFIG_PROC_FS + int proc_root_initialized = 0; struct proc_dir_entry *pProcFile; #endif @@ -700,6 +785,7 @@ static int __init skge_probe (void) dev->stop = &SkGeClose; dev->hard_start_xmit = &SkGeXmit; dev->get_stats = &SkGeStats; + dev->last_stats = &SkGeStats; dev->set_multicast_list = &SkGeSetRxMode; dev->set_mac_address = &SkGeSetMacAddr; dev->do_ioctl = &SkGeIoctl; @@ -718,15 +804,13 @@ static int __init skge_probe (void) #endif pAC->Index = boards_found; + if (SkGeBoardInit(dev, pAC)) { - FreeResources(dev); free_netdev(dev); continue; } - memcpy((caddr_t) &dev->dev_addr, - (caddr_t) &pAC->Addr.Net[0].CurrentMacAddress, 6); - + /* Register net device */ if (register_netdev(dev)) { printk(KERN_ERR "SKGE: Could not register device.\n"); FreeResources(dev); @@ -734,6 +818,25 @@ static int __init skge_probe (void) continue; } + /* Print adapter specific string from vpd */ + ProductStr(pAC); + printk("%s: %s\n", dev->name, pAC->DeviceStr); + + /* Print configuration settings */ + printk(" PrefPort:%c RlmtMode:%s\n", + 'A' + pAC->Rlmt.Net[0].Port[pAC->Rlmt.Net[0].PrefPort]->PortNumber, + (pAC->RlmtMode==0) ? "Check Link State" : + ((pAC->RlmtMode==1) ? "Check Link State" : + ((pAC->RlmtMode==3) ? "Check Local Port" : + ((pAC->RlmtMode==7) ? "Check Segmentation" : + ((pAC->RlmtMode==17) ? "Dual Check Link State" :"Error"))))); + + SkGeYellowLED(pAC, pAC->IoBase, 1); + + + memcpy((caddr_t) &dev->dev_addr, + (caddr_t) &pAC->Addr.Net[0].CurrentMacAddress, 6); + /* First adapter... Create proc and print message */ #ifdef CONFIG_PROC_FS if (!DeviceFound) { @@ -744,25 +847,27 @@ static int __init skge_probe (void) /*Create proc (directory)*/ if(!pSkRootDir) { pSkRootDir = proc_mkdir(SK_Root_Dir_entry, proc_net); - if (!pSkRootDir) + if (!pSkRootDir) { printk(KERN_WARNING "%s: Unable to create /proc/net/%s", - dev->name, SK_Root_Dir_entry); - else + dev->name, SK_Root_Dir_entry); + } else { pSkRootDir->owner = THIS_MODULE; + } } } - + /* Create proc file */ - if (pSkRootDir - && (pProcFile = create_proc_entry(dev->name, S_IRUGO, - pSkRootDir))) { + if (pSkRootDir && + (pProcFile = create_proc_entry(dev->name, S_IRUGO, + pSkRootDir))) { pProcFile->proc_fops = &sk_proc_fops; - pProcFile->data = dev; + pProcFile->data = dev; } + #endif pNet->PortNr = 0; - pNet->NetNr = 0; + pNet->NetNr = 0; boards_found++; @@ -774,23 +879,24 @@ static int __init skge_probe (void) break; } - pAC->dev[1] = dev; - pNet = dev->priv; - pNet->PortNr = 1; - pNet->NetNr = 1; - pNet->pAC = pAC; - pNet->Mtu = 1500; - pNet->Up = 0; - - dev->open = &SkGeOpen; - dev->stop = &SkGeClose; - dev->hard_start_xmit = &SkGeXmit; - dev->get_stats = &SkGeStats; + pAC->dev[1] = dev; + pNet = dev->priv; + pNet->PortNr = 1; + pNet->NetNr = 1; + pNet->pAC = pAC; + pNet->Mtu = 1500; + pNet->Up = 0; + + dev->open = &SkGeOpen; + dev->stop = &SkGeClose; + dev->hard_start_xmit = &SkGeXmit; + dev->get_stats = &SkGeStats; + dev->last_stats = &SkGeStats; dev->set_multicast_list = &SkGeSetRxMode; - dev->set_mac_address = &SkGeSetMacAddr; - dev->do_ioctl = &SkGeIoctl; - dev->change_mtu = &SkGeChangeMtu; - dev->flags &= ~IFF_RUNNING; + dev->set_mac_address = &SkGeSetMacAddr; + dev->do_ioctl = &SkGeIoctl; + dev->change_mtu = &SkGeChangeMtu; + dev->flags &= ~IFF_RUNNING; #ifdef SK_ZEROCOPY #ifdef USE_SK_TX_CHECKSUM @@ -802,34 +908,39 @@ static int __init skge_probe (void) #endif if (register_netdev(dev)) { - printk(KERN_ERR "SKGE: Could not register " - "second port.\n"); + printk(KERN_ERR "SKGE: Could not register device.\n"); free_netdev(dev); pAC->dev[1] = pAC->dev[0]; } else { #ifdef CONFIG_PROC_FS if (pSkRootDir && (pProcFile = create_proc_entry(dev->name, - S_IRUGO, - pSkRootDir))) { + S_IRUGO, pSkRootDir))) { pProcFile->proc_fops = &sk_proc_fops; - pProcFile->data = dev; + pProcFile->data = dev; } #endif - memcpy((caddr_t) &dev->dev_addr, - (caddr_t) &pAC->Addr.Net[1].CurrentMacAddress, 6); + memcpy((caddr_t) &dev->dev_addr, + (caddr_t) &pAC->Addr.Net[1].CurrentMacAddress, 6); - printk("%s: %s\n", dev->name, pAC->DeviceStr); - printk(" PrefPort:B RlmtMode:Dual Check Link State\n"); + printk("%s: %s\n", dev->name, pAC->DeviceStr); + printk(" PrefPort:B RlmtMode:Dual Check Link State\n"); } } - /* Save the hardware revision */ pAC->HWRevision = (((pAC->GIni.GIPciHwRev >> 4) & 0x0F)*10) + (pAC->GIni.GIPciHwRev & 0x0F); + /* Set driver globals */ + pAC->Pnmi.pDriverFileName = DRIVER_FILE_NAME; + pAC->Pnmi.pDriverReleaseDate = DRIVER_REL_DATE; + + SK_MEMSET(&(pAC->PnmiBackup), 0, sizeof(SK_PNMI_STRUCT_DATA)); + SK_MEMCPY(&(pAC->PnmiBackup), &(pAC->PnmiStruct), + sizeof(SK_PNMI_STRUCT_DATA)); + /* * This is bollocks, but we need to tell the net-init * code that it shall go for the next device. @@ -849,7 +960,6 @@ static int __init skge_probe (void) } /* skge_probe */ - /***************************************************************************** * * SkGeInitPCI - Init the PCI resources @@ -1143,7 +1253,7 @@ SK_EVPARA EvPara; if ((pAC->GIni.GIMacsFound == 2) && pAC->RlmtNets == 2){ unregister_netdev(pAC->dev[1]); - kfree(pAC->dev[1]); + free_netdev(pAC->dev[1]); } FreeResources(SkGeRootDev); @@ -1161,8 +1271,7 @@ SK_EVPARA EvPara; #ifdef CONFIG_PROC_FS /* clear proc-dir */ - if (pSkRootDir) - remove_proc_entry(pSkRootDir->name, proc_net); + remove_proc_entry(pSkRootDir->name, proc_net); #endif } /* skge_cleanup_module */ @@ -1224,7 +1333,7 @@ SK_BOOL DualNet; SkAddrInit( pAC, pAC->IoBase, SK_INIT_DATA); SkRlmtInit( pAC, pAC->IoBase, SK_INIT_DATA); SkTimerInit(pAC, pAC->IoBase, SK_INIT_DATA); - + pAC->BoardLevel = SK_INIT_DATA; pAC->RxBufSize = ETH_BUF_SIZE; @@ -1236,7 +1345,7 @@ SK_BOOL DualNet; /* level 1 init common modules here (HW init) */ spin_lock_irqsave(&pAC->SlowPathLock, Flags); if (SkGeInit(pAC, pAC->IoBase, SK_INIT_IO) != 0) { - printk("HWInit (1) failed.\n"); + printk("sk98lin: HWInit (1) failed.\n"); spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); return(-EAGAIN); } @@ -1268,14 +1377,14 @@ SK_BOOL DualNet; Ret = request_irq(dev->irq, SkGeIsrOnePort, SA_SHIRQ, pAC->Name, dev); } else { - printk(KERN_WARNING "%s: Illegal number of ports: %d\n", - dev->name, pAC->GIni.GIMacsFound); + printk(KERN_WARNING "sk98lin: Illegal number of ports: %d\n", + pAC->GIni.GIMacsFound); return -EAGAIN; } if (Ret) { - printk(KERN_WARNING "%s: Requested IRQ %d is busy.\n", - dev->name, dev->irq); + printk(KERN_WARNING "sk98lin: Requested IRQ %d is busy.\n", + dev->irq); return -EAGAIN; } pAC->AllocFlag |= SK_ALLOC_IRQ; @@ -1303,25 +1412,10 @@ SK_BOOL DualNet; pAC->ActivePort, DualNet)) { BoardFreeMem(pAC); - printk("SkGeInitAssignRamToQueues failed.\n"); + printk("sk98lin: SkGeInitAssignRamToQueues failed.\n"); return(-EAGAIN); } - /* Print adapter specific string from vpd */ - ProductStr(pAC); - printk("%s: %s\n", dev->name, pAC->DeviceStr); - - /* Print configuration settings */ - printk(" PrefPort:%c RlmtMode:%s\n", - 'A' + pAC->Rlmt.Net[0].Port[pAC->Rlmt.Net[0].PrefPort]->PortNumber, - (pAC->RlmtMode==0) ? "Check Link State" : - ((pAC->RlmtMode==1) ? "Check Link State" : - ((pAC->RlmtMode==3) ? "Check Local Port" : - ((pAC->RlmtMode==7) ? "Check Segmentation" : - ((pAC->RlmtMode==17) ? "Dual Check Link State" :"Error"))))); - - SkGeYellowLED(pAC, pAC->IoBase, 1); - /* * Register the device here */ @@ -1879,14 +1973,26 @@ struct SK_NET_DEVICE *dev) SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, ("SkGeOpen: pAC=0x%lX:\n", (unsigned long)pAC)); +#ifdef SK_DIAG_SUPPORT + if (pAC->DiagModeActive == DIAG_ACTIVE) { + if (pAC->Pnmi.DiagAttached == SK_DIAG_RUNNING) { + return (-1); /* still in use by diag; deny actions */ + } + } +#endif + + if (!try_module_get(THIS_MODULE)) { + return (-1); /* increase of usage count not possible */ + } /* Set blink mode */ - if (pAC->PciDev->vendor == 0x1186) + if ((pAC->PciDev->vendor == 0x1186) || (pAC->PciDev->vendor == 0x11ab )) pAC->GIni.GILedBlinkCtrl = OEM_CONFIG_VALUE; if (pAC->BoardLevel == SK_INIT_DATA) { /* level 1 init common modules here */ if (SkGeInit(pAC, pAC->IoBase, SK_INIT_IO) != 0) { + module_put(THIS_MODULE); /* decrease usage count */ printk("%s: HWInit (1) failed.\n", pAC->dev[pNet->PortNr]->name); return (-1); } @@ -1902,6 +2008,7 @@ struct SK_NET_DEVICE *dev) if (pAC->BoardLevel != SK_INIT_RUN) { /* tschilling: Level 2 init modules here, check return value. */ if (SkGeInit(pAC, pAC->IoBase, SK_INIT_RUN) != 0) { + module_put(THIS_MODULE); /* decrease usage count */ printk("%s: HWInit (2) failed.\n", pAC->dev[pNet->PortNr]->name); return (-1); } @@ -1953,7 +2060,6 @@ struct SK_NET_DEVICE *dev) pAC->MaxPorts++; pNet->Up = 1; - try_module_get(THIS_MODULE); SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, ("SkGeOpen suceeded\n")); @@ -1976,26 +2082,50 @@ struct SK_NET_DEVICE *dev) static int SkGeClose( struct SK_NET_DEVICE *dev) { - DEV_NET *pNet; - SK_AC *pAC; + DEV_NET *pNet; + DEV_NET *newPtrNet; + SK_AC *pAC; unsigned long Flags; /* for spin lock */ - int i; - int PortIdx; - SK_EVPARA EvPara; + int i; + int PortIdx; + SK_EVPARA EvPara; + + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, + ("SkGeClose: pAC=0x%lX ", (unsigned long)pAC)); - netif_stop_queue(dev); pNet = (DEV_NET*) dev->priv; pAC = pNet->pAC; +#ifdef SK_DIAG_SUPPORT + if (pAC->DiagModeActive == DIAG_ACTIVE) { + if (pAC->DiagFlowCtrl == SK_FALSE) { + module_put(THIS_MODULE); + /* + ** notify that the interface which has been closed + ** by operator interaction must not be started up + ** again when the DIAG has finished. + */ + newPtrNet = (DEV_NET *) pAC->dev[0]->priv; + if (newPtrNet == pNet) { + pAC->WasIfUp[0] = SK_FALSE; + } else { + pAC->WasIfUp[1] = SK_FALSE; + } + return 0; /* return to system everything is fine... */ + } else { + pAC->DiagFlowCtrl = SK_FALSE; + } + } +#endif + + netif_stop_queue(dev); + if (pAC->RlmtNets == 1) PortIdx = pAC->ActivePort; else PortIdx = pNet->NetNr; - SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, - ("SkGeClose: pAC=0x%lX ", (unsigned long)pAC)); - StopDrvCleanupTimer(pAC); /* @@ -2053,6 +2183,10 @@ struct SK_NET_DEVICE *dev) SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, ("SkGeClose: done ")); + SK_MEMSET(&(pAC->PnmiBackup), 0, sizeof(SK_PNMI_STRUCT_DATA)); + SK_MEMCPY(&(pAC->PnmiBackup), &(pAC->PnmiStruct), + sizeof(SK_PNMI_STRUCT_DATA)); + pAC->MaxPorts--; pNet->Up = 0; @@ -2199,9 +2333,10 @@ struct sk_buff *pMessage) /* pointer to ** This is to resolve faulty padding by the HW with 0xaa bytes. */ if (BytesSend < C_LEN_ETHERNET_MINSIZE) { - skb_put(pMessage, (C_LEN_ETHERNET_MINSIZE-BytesSend)); - SK_MEMSET( ((char *)(pMessage->data))+BytesSend, - 0, C_LEN_ETHERNET_MINSIZE-BytesSend); + if ((pMessage = skb_padto(pMessage, C_LEN_ETHERNET_MINSIZE)) == NULL) { + return 0; + } + pMessage->len = C_LEN_ETHERNET_MINSIZE; } /* @@ -3318,6 +3453,16 @@ SK_EVPARA EvPara; return -EINVAL; } +#ifdef SK_DIAG_SUPPORT + if (pAC->DiagModeActive == DIAG_ACTIVE) { + if (pAC->DiagFlowCtrl == SK_FALSE) { + return -1; /* still in use, deny any actions of MTU */ + } else { + pAC->DiagFlowCtrl = SK_FALSE; + } + } +#endif + pNet->Mtu = NewMtu; pOtherNet = (DEV_NET*)pAC->dev[1 - pNet->NetNr]->priv; if ((pOtherNet->Mtu>1500) && (NewMtu<=1500) && (pOtherNet->Up==1)) { @@ -3537,11 +3682,20 @@ unsigned long Flags; /* for spin lock SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, ("SkGeStats starts now...\n")); pPnmiStruct = &pAC->PnmiStruct; - memset(pPnmiStruct, 0, sizeof(SK_PNMI_STRUCT_DATA)); + +#ifdef SK_DIAG_SUPPORT + if ((pAC->DiagModeActive == DIAG_NOTACTIVE) && + (pAC->BoardLevel == SK_INIT_RUN)) { +#endif + SK_MEMSET(pPnmiStruct, 0, sizeof(SK_PNMI_STRUCT_DATA)); spin_lock_irqsave(&pAC->SlowPathLock, Flags); Size = SK_PNMI_STRUCT_SIZE; SkPnmiGetStruct(pAC, pAC->IoBase, pPnmiStruct, &Size, pNet->NetNr); spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); +#ifdef SK_DIAG_SUPPORT + } +#endif + pPnmiStat = &pPnmiStruct->Stat[0]; pPnmiConf = &pPnmiStruct->Conf[0]; @@ -3604,7 +3758,7 @@ static int SkGeIoctl(struct SK_NET_DEVIC DEV_NET *pNet; SK_AC *pAC; void *pMemBuf; - +struct pci_dev *pdev = NULL; SK_GE_IOCTL Ioctl; unsigned int Err = 0; int Size = 0; @@ -3671,6 +3825,45 @@ int HeaderLength = sizeof(SK_U32) + siz fault_gen: kfree(pMemBuf); /* cleanup everything */ break; +#ifdef SK_DIAG_SUPPORT + case SK_IOCTL_DIAG: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (Ioctl.Len < (sizeof(pAC->PnmiStruct) + HeaderLength)) { + Length = Ioctl.Len; + } else { + Length = sizeof(pAC->PnmiStruct) + HeaderLength; + } + if (NULL == (pMemBuf = kmalloc(Length, GFP_KERNEL))) { + return -ENOMEM; + } + if(copy_from_user(pMemBuf, Ioctl.pData, Length)) { + Err = -EFAULT; + goto fault_diag; + } + pdev = pAC->PciDev; + Length = 3 * sizeof(SK_U32); /* Error, Bus and Device */ + /* + ** While coding this new IOCTL interface, only a few lines of code + ** are to to be added. Therefore no dedicated function has been + ** added. If more functionality is added, a separate function + ** should be used... + */ + * ((SK_U32 *)pMemBuf) = 0; + * ((SK_U32 *)pMemBuf + 1) = pdev->bus->number; + * ((SK_U32 *)pMemBuf + 2) = ParseDeviceNbrFromSlotName(pdev->slot_name); + if(copy_to_user(Ioctl.pData, pMemBuf, Length) ) { + Err = -EFAULT; + goto fault_diag; + } + Ioctl.Len = Length; + if(copy_to_user(rq->ifr_data, &Ioctl, sizeof(SK_GE_IOCTL))) { + Err = -EFAULT; + goto fault_diag; + } +fault_diag: + kfree(pMemBuf); /* cleanup everything */ + break; +#endif default: Err = -EOPNOTSUPP; } @@ -3826,10 +4019,9 @@ int Capabilities[3][3] = (strcmp(ConType[pAC->Index],"Auto")!=0) && (strcmp(ConType[pAC->Index],"")!=0)) { /* Set the speed parameter back */ - printk("%s: Illegal value \"%s\" " + printk("sk98lin: Illegal value \"%s\" " "for ConType." " Using Auto.\n", - pAC->dev[0]->name, ConType[pAC->Index]); sprintf(ConType[pAC->Index], "Auto"); @@ -3873,8 +4065,8 @@ int Capabilities[3][3] = M_CurrPort.PLinkSpeed = SK_LSPEED_10MBPS; } } else { - printk("%s: Illegal value \"%s\" for ConType\n", - pAC->dev[0]->name, ConType[pAC->Index]); + printk("sk98lin: Illegal value \"%s\" for ConType\n", + ConType[pAC->Index]); IsConTypeDefined = SK_FALSE; /* Wrong ConType defined */ } } else { @@ -3898,8 +4090,8 @@ int Capabilities[3][3] = } else if (strcmp(Speed_A[pAC->Index],"1000")==0) { LinkSpeed = SK_LSPEED_1000MBPS; } else { - printk("%s: Illegal value \"%s\" for Speed_A\n", - pAC->dev[0]->name, Speed_A[pAC->Index]); + printk("sk98lin: Illegal value \"%s\" for Speed_A\n", + Speed_A[pAC->Index]); IsLinkSpeedDefined = SK_FALSE; } } else { @@ -3913,9 +4105,9 @@ int Capabilities[3][3] = if (((!pAC->ChipsetType) || (pAC->GIni.GICopperType != SK_TRUE)) && ((LinkSpeed != SK_LSPEED_AUTO) && (LinkSpeed != SK_LSPEED_1000MBPS))) { - printk("%s: Illegal value for Speed_A. " + printk("sk98lin: Illegal value for Speed_A. " "Not a copper card or GE V2 card\n Using " - "speed 1000\n", pAC->dev[0]->name); + "speed 1000\n"); LinkSpeed = SK_LSPEED_1000MBPS; } @@ -3945,8 +4137,8 @@ int Capabilities[3][3] = } else if (strcmp(AutoNeg_A[pAC->Index],"Sense")==0) { AutoNeg = AN_SENS; } else { - printk("%s: Illegal value \"%s\" for AutoNeg_A\n", - pAC->dev[0]->name, AutoNeg_A[pAC->Index]); + printk("sk98lin: Illegal value \"%s\" for AutoNeg_A\n", + AutoNeg_A[pAC->Index]); } } @@ -3964,33 +4156,32 @@ int Capabilities[3][3] = } else if (strcmp(DupCap_A[pAC->Index],"Half")==0) { DuplexCap = DC_HALF; } else { - printk("%s: Illegal value \"%s\" for DupCap_A\n", - pAC->dev[0]->name, DupCap_A[pAC->Index]); + printk("sk98lin: Illegal value \"%s\" for DupCap_A\n", + DupCap_A[pAC->Index]); } } - + /* ** Check for illegal combinations */ - if ((LinkSpeed = SK_LSPEED_1000MBPS) && + if ((LinkSpeed == SK_LSPEED_1000MBPS) && ((DuplexCap == SK_LMODE_STAT_AUTOHALF) || (DuplexCap == SK_LMODE_STAT_HALF)) && (pAC->ChipsetType)) { - printk("%s: Half Duplex not possible with Gigabit speed!\n" - " Using Full Duplex.\n", - pAC->dev[0]->name); + printk("sk98lin: Half Duplex not possible with Gigabit speed!\n" + " Using Full Duplex.\n"); DuplexCap = DC_FULL; } if ( AutoSet && AutoNeg==AN_SENS && DupSet) { - printk("%s, Port A: DuplexCapabilities" - " ignored using Sense mode\n", pAC->dev[0]->name); + printk("sk98lin, Port A: DuplexCapabilities" + " ignored using Sense mode\n"); } if (AutoSet && AutoNeg==AN_OFF && DupSet && DuplexCap==DC_BOTH){ - printk("%s, Port A: Illegal combination" + printk("sk98lin: Port A: Illegal combination" " of values AutoNeg. and DuplexCap.\n Using " - "Full Duplex\n", pAC->dev[0]->name); + "Full Duplex\n"); DuplexCap = DC_FULL; } @@ -3999,10 +4190,9 @@ int Capabilities[3][3] = } if (!AutoSet && DupSet) { - printk("%s, Port A: Duplex setting not" + printk("sk98lin: Port A: Duplex setting not" " possible in\n default AutoNegotiation mode" - " (Sense).\n Using AutoNegotiation On\n", - pAC->dev[0]->name); + " (Sense).\n Using AutoNegotiation On\n"); AutoNeg = AN_ON; } @@ -4029,8 +4219,8 @@ int Capabilities[3][3] = } else if (strcmp(FlowCtrl_A[pAC->Index],"None")==0) { FlowCtrl = SK_FLOW_MODE_NONE; } else { - printk("%s: Illegal value \"%s\" for FlowCtrl_A\n", - pAC->dev[0]->name, FlowCtrl_A[pAC->Index]); + printk("sk98lin: Illegal value \"%s\" for FlowCtrl_A\n", + FlowCtrl_A[pAC->Index]); IsFlowCtrlDefined = SK_FALSE; } } else { @@ -4039,9 +4229,9 @@ int Capabilities[3][3] = if (IsFlowCtrlDefined) { if ((AutoNeg == AN_OFF) && (FlowCtrl != SK_FLOW_MODE_NONE)) { - printk("%s, Port A: FlowControl" + printk("sk98lin: Port A: FlowControl" " impossible without AutoNegotiation," - " disabled\n", pAC->dev[0]->name); + " disabled\n"); FlowCtrl = SK_FLOW_MODE_NONE; } pAC->GIni.GP[0].PFlowCtrlMode = FlowCtrl; @@ -4061,8 +4251,8 @@ int Capabilities[3][3] = } else if (strcmp(Role_A[pAC->Index],"Slave")==0) { MSMode = SK_MS_MODE_SLAVE; } else { - printk("%s: Illegal value \"%s\" for Role_A\n", - pAC->dev[0]->name, Role_A[pAC->Index]); + printk("sk98lin: Illegal value \"%s\" for Role_A\n", + Role_A[pAC->Index]); IsRoleDefined = SK_FALSE; } } else { @@ -4097,8 +4287,8 @@ int Capabilities[3][3] = } else if (strcmp(Speed_B[pAC->Index],"1000")==0) { LinkSpeed = SK_LSPEED_1000MBPS; } else { - printk("%s: Illegal value \"%s\" for Speed_B\n", - pAC->dev[1]->name, Speed_B[pAC->Index]); + printk("sk98lin: Illegal value \"%s\" for Speed_B\n", + Speed_B[pAC->Index]); IsLinkSpeedDefined = SK_FALSE; } } else { @@ -4112,9 +4302,9 @@ int Capabilities[3][3] = if (((!pAC->ChipsetType) || (pAC->GIni.GICopperType != SK_TRUE)) && ((LinkSpeed != SK_LSPEED_AUTO) && (LinkSpeed != SK_LSPEED_1000MBPS))) { - printk("%s: Illegal value for Speed_B. " + printk("sk98lin: Illegal value for Speed_B. " "Not a copper card or GE V2 card\n Using " - "speed 1000\n", pAC->dev[1]->name); + "speed 1000\n"); LinkSpeed = SK_LSPEED_1000MBPS; } @@ -4144,8 +4334,8 @@ int Capabilities[3][3] = } else if (strcmp(AutoNeg_B[pAC->Index],"Sense")==0) { AutoNeg = AN_SENS; } else { - printk("%s: Illegal value \"%s\" for AutoNeg_B\n", - pAC->dev[0]->name, AutoNeg_B[pAC->Index]); + printk("sk98lin: Illegal value \"%s\" for AutoNeg_B\n", + AutoNeg_B[pAC->Index]); } } @@ -4163,8 +4353,8 @@ int Capabilities[3][3] = } else if (strcmp(DupCap_B[pAC->Index],"Half")==0) { DuplexCap = DC_HALF; } else { - printk("%s: Illegal value \"%s\" for DupCap_B\n", - pAC->dev[0]->name, DupCap_B[pAC->Index]); + printk("sk98lin: Illegal value \"%s\" for DupCap_B\n", + DupCap_B[pAC->Index]); } } @@ -4172,25 +4362,24 @@ int Capabilities[3][3] = /* ** Check for illegal combinations */ - if ((LinkSpeed = SK_LSPEED_1000MBPS) && + if ((LinkSpeed == SK_LSPEED_1000MBPS) && ((DuplexCap == SK_LMODE_STAT_AUTOHALF) || (DuplexCap == SK_LMODE_STAT_HALF)) && (pAC->ChipsetType)) { - printk("%s: Half Duplex not possible with Gigabit speed!\n" - " Using Full Duplex.\n", - pAC->dev[1]->name); + printk("sk98lin: Half Duplex not possible with Gigabit speed!\n" + " Using Full Duplex.\n"); DuplexCap = DC_FULL; } if (AutoSet && AutoNeg==AN_SENS && DupSet) { - printk("%s, Port B: DuplexCapabilities" - " ignored using Sense mode\n", pAC->dev[1]->name); + printk("sk98lin, Port B: DuplexCapabilities" + " ignored using Sense mode\n"); } if (AutoSet && AutoNeg==AN_OFF && DupSet && DuplexCap==DC_BOTH){ - printk("%s, Port B: Illegal combination" + printk("sk98lin: Port B: Illegal combination" " of values AutoNeg. and DuplexCap.\n Using " - "Full Duplex\n", pAC->dev[1]->name); + "Full Duplex\n"); DuplexCap = DC_FULL; } @@ -4199,10 +4388,9 @@ int Capabilities[3][3] = } if (!AutoSet && DupSet) { - printk("%s, Port B: Duplex setting not" + printk("sk98lin: Port B: Duplex setting not" " possible in\n default AutoNegotiation mode" - " (Sense).\n Using AutoNegotiation On\n", - pAC->dev[1]->name); + " (Sense).\n Using AutoNegotiation On\n"); AutoNeg = AN_ON; } @@ -4229,8 +4417,8 @@ int Capabilities[3][3] = } else if (strcmp(FlowCtrl_B[pAC->Index],"None")==0) { FlowCtrl = SK_FLOW_MODE_NONE; } else { - printk("%s: Illegal value \"%s\" for FlowCtrl_B\n", - pAC->dev[0]->name, FlowCtrl_B[pAC->Index]); + printk("sk98lin: Illegal value \"%s\" for FlowCtrl_B\n", + FlowCtrl_B[pAC->Index]); IsFlowCtrlDefined = SK_FALSE; } } else { @@ -4239,9 +4427,9 @@ int Capabilities[3][3] = if (IsFlowCtrlDefined) { if ((AutoNeg == AN_OFF) && (FlowCtrl != SK_FLOW_MODE_NONE)) { - printk("%s, Port B: FlowControl" + printk("sk98lin: Port B: FlowControl" " impossible without AutoNegotiation," - " disabled\n", pAC->dev[1]->name); + " disabled\n"); FlowCtrl = SK_FLOW_MODE_NONE; } pAC->GIni.GP[1].PFlowCtrlMode = FlowCtrl; @@ -4261,8 +4449,8 @@ int Capabilities[3][3] = } else if (strcmp(Role_B[pAC->Index],"Slave")==0) { MSMode = SK_MS_MODE_SLAVE; } else { - printk("%s: Illegal value \"%s\" for Role_B\n", - pAC->dev[1]->name, Role_B[pAC->Index]); + printk("sk98lin: Illegal value \"%s\" for Role_B\n", + Role_B[pAC->Index]); IsRoleDefined = SK_FALSE; } } else { @@ -4280,28 +4468,37 @@ int Capabilities[3][3] = if (PrefPort != NULL && pAC->IndexIndex] != NULL) { if (strcmp(PrefPort[pAC->Index],"") == 0) { /* Auto */ - pAC->ActivePort = 0; - pAC->Rlmt.Net[0].Preference = -1; /* auto */ - pAC->Rlmt.Net[0].PrefPort = 0; + pAC->ActivePort = 0; + pAC->Rlmt.Net[0].Preference = -1; /* auto */ + pAC->Rlmt.Net[0].PrefPort = 0; } else if (strcmp(PrefPort[pAC->Index],"A") == 0) { - /* - ** do not set ActivePort here, thus a port - ** switch is issued after net up. - */ - Port = 0; - pAC->Rlmt.Net[0].Preference = Port; - pAC->Rlmt.Net[0].PrefPort = Port; + /* + ** do not set ActivePort here, thus a port + ** switch is issued after net up. + */ + Port = 0; + pAC->Rlmt.Net[0].Preference = Port; + pAC->Rlmt.Net[0].PrefPort = Port; } else if (strcmp(PrefPort[pAC->Index],"B") == 0) { - /* - ** do not set ActivePort here, thus a port - ** switch is issued after net up. - */ - Port = 1; - pAC->Rlmt.Net[0].Preference = Port; - pAC->Rlmt.Net[0].PrefPort = Port; + /* + ** do not set ActivePort here, thus a port + ** switch is issued after net up. + */ + if (pAC->GIni.GIMacsFound == 1) { + printk("sk98lin: Illegal value \"B\" for PrefPort.\n" + " Port B not available on single port adapters.\n"); + + pAC->ActivePort = 0; + pAC->Rlmt.Net[0].Preference = -1; /* auto */ + pAC->Rlmt.Net[0].PrefPort = 0; + } else { + Port = 1; + pAC->Rlmt.Net[0].Preference = Port; + pAC->Rlmt.Net[0].PrefPort = Port; + } } else { - printk("%s: Illegal value \"%s\" for PrefPort\n", - pAC->dev[0]->name, PrefPort[pAC->Index]); + printk("sk98lin: Illegal value \"%s\" for PrefPort\n", + PrefPort[pAC->Index]); } } @@ -4325,9 +4522,9 @@ int Capabilities[3][3] = pAC->RlmtMode = SK_RLMT_CHECK_LINK; pAC->RlmtNets = 2; } else { - printk("%s: Illegal value \"%s\" for" + printk("sk98lin: Illegal value \"%s\" for" " RlmtMode, using default\n", - pAC->dev[0]->name, RlmtMode[pAC->Index]); + RlmtMode[pAC->Index]); pAC->RlmtMode = 0; } } else { @@ -4338,97 +4535,111 @@ int Capabilities[3][3] = ** Check the interrupt moderation parameters */ if (Moderation[pAC->Index] != NULL) { - if (strcmp(Moderation[pAC->Index], "Static") == 0) { - pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_STATIC; - } else if (strcmp(Moderation[pAC->Index], "Dynamic") == 0) { - pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_DYNAMIC; - } else { - pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_NONE; - } + if (strcmp(Moderation[pAC->Index], "") == 0) { + pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_NONE; + } else if (strcmp(Moderation[pAC->Index], "Static") == 0) { + pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_STATIC; + } else if (strcmp(Moderation[pAC->Index], "Dynamic") == 0) { + pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_DYNAMIC; + } else if (strcmp(Moderation[pAC->Index], "None") == 0) { + pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_NONE; + } else { + printk("sk98lin: Illegal value \"%s\" for Moderation.\n" + " Disable interrupt moderation.\n", + Moderation[pAC->Index]); + pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_NONE; + } } else { - pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_NONE; + pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_NONE; } if (Stats[pAC->Index] != NULL) { - if (strcmp(Stats[pAC->Index], "Yes") == 0) { - pAC->DynIrqModInfo.DisplayStats = SK_TRUE; - } else { - pAC->DynIrqModInfo.DisplayStats = SK_FALSE; - } + if (strcmp(Stats[pAC->Index], "Yes") == 0) { + pAC->DynIrqModInfo.DisplayStats = SK_TRUE; + } else { + pAC->DynIrqModInfo.DisplayStats = SK_FALSE; + } } else { - pAC->DynIrqModInfo.DisplayStats = SK_FALSE; + pAC->DynIrqModInfo.DisplayStats = SK_FALSE; } - if (ModerationMask[pAC->Index] != NULL) { - if (strcmp(ModerationMask[pAC->Index], "Rx") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_ONLY; - } else if (strcmp(ModerationMask[pAC->Index], "Tx") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_ONLY; - } else if (strcmp(ModerationMask[pAC->Index], "Sp") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_ONLY; - } else if (strcmp(ModerationMask[pAC->Index], "RxSp") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_RX; - } else if (strcmp(ModerationMask[pAC->Index], "SpRx") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_RX; - } else if (strcmp(ModerationMask[pAC->Index], "RxTx") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_RX; - } else if (strcmp(ModerationMask[pAC->Index], "TxRx") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_RX; - } else if (strcmp(ModerationMask[pAC->Index], "TxSp") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_TX; - } else if (strcmp(ModerationMask[pAC->Index], "SpTx") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_TX; - } else if (strcmp(ModerationMask[pAC->Index], "RxTxSp") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; - } else if (strcmp(ModerationMask[pAC->Index], "RxSpTx") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; - } else if (strcmp(ModerationMask[pAC->Index], "TxRxSp") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; - } else if (strcmp(ModerationMask[pAC->Index], "TxSpRx") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; - } else if (strcmp(ModerationMask[pAC->Index], "SpTxRx") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; - } else if (strcmp(ModerationMask[pAC->Index], "SpRxTx") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; - } else { /* some rubbish */ - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_ONLY; - } - } else { /* operator has stated nothing */ - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_RX; - } - - if (AutoSizing[pAC->Index] != NULL) { - if (strcmp(AutoSizing[pAC->Index], "On") == 0) { - pAC->DynIrqModInfo.AutoSizing = SK_FALSE; - } else { - pAC->DynIrqModInfo.AutoSizing = SK_FALSE; - } - } else { /* operator has stated nothing */ - pAC->DynIrqModInfo.AutoSizing = SK_FALSE; - } + if (ModerationMask[pAC->Index] != NULL) { + if (strcmp(ModerationMask[pAC->Index], "Rx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_ONLY; + } else if (strcmp(ModerationMask[pAC->Index], "Tx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_ONLY; + } else if (strcmp(ModerationMask[pAC->Index], "Sp") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_ONLY; + } else if (strcmp(ModerationMask[pAC->Index], "RxSp") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_RX; + } else if (strcmp(ModerationMask[pAC->Index], "SpRx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_RX; + } else if (strcmp(ModerationMask[pAC->Index], "RxTx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_RX; + } else if (strcmp(ModerationMask[pAC->Index], "TxRx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_RX; + } else if (strcmp(ModerationMask[pAC->Index], "TxSp") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_TX; + } else if (strcmp(ModerationMask[pAC->Index], "SpTx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_TX; + } else if (strcmp(ModerationMask[pAC->Index], "RxTxSp") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; + } else if (strcmp(ModerationMask[pAC->Index], "RxSpTx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; + } else if (strcmp(ModerationMask[pAC->Index], "TxRxSp") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; + } else if (strcmp(ModerationMask[pAC->Index], "TxSpRx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; + } else if (strcmp(ModerationMask[pAC->Index], "SpTxRx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; + } else if (strcmp(ModerationMask[pAC->Index], "SpRxTx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; + } else { /* some rubbish */ + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_ONLY; + } + } else { /* operator has stated nothing */ + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_RX; + } + + if (AutoSizing[pAC->Index] != NULL) { + if (strcmp(AutoSizing[pAC->Index], "On") == 0) { + pAC->DynIrqModInfo.AutoSizing = SK_FALSE; + } else { + pAC->DynIrqModInfo.AutoSizing = SK_FALSE; + } + } else { /* operator has stated nothing */ + pAC->DynIrqModInfo.AutoSizing = SK_FALSE; + } - if (IntsPerSec[pAC->Index] != 0) { - if ((IntsPerSec[pAC->Index]< 30) || (IntsPerSec[pAC->Index]> 40000)) { - pAC->DynIrqModInfo.MaxModIntsPerSec = C_INTS_PER_SEC_DEFAULT; - } else { - pAC->DynIrqModInfo.MaxModIntsPerSec = IntsPerSec[pAC->Index]; - } - } else { - pAC->DynIrqModInfo.MaxModIntsPerSec = C_INTS_PER_SEC_DEFAULT; - } + if (IntsPerSec[pAC->Index] != 0) { + if ((IntsPerSec[pAC->Index]< C_INT_MOD_IPS_LOWER_RANGE) || + (IntsPerSec[pAC->Index] > C_INT_MOD_IPS_UPPER_RANGE)) { + printk("sk98lin: Illegal value \"%d\" for IntsPerSec. (Range: %d - %d)\n" + " Using default value of %i.\n", + IntsPerSec[pAC->Index], + C_INT_MOD_IPS_LOWER_RANGE, + C_INT_MOD_IPS_UPPER_RANGE, + C_INTS_PER_SEC_DEFAULT); + pAC->DynIrqModInfo.MaxModIntsPerSec = C_INTS_PER_SEC_DEFAULT; + } else { + pAC->DynIrqModInfo.MaxModIntsPerSec = IntsPerSec[pAC->Index]; + } + } else { + pAC->DynIrqModInfo.MaxModIntsPerSec = C_INTS_PER_SEC_DEFAULT; + } - /* + /* ** Evaluate upper and lower moderation threshold */ - pAC->DynIrqModInfo.MaxModIntsPerSecUpperLimit = - pAC->DynIrqModInfo.MaxModIntsPerSec + - (pAC->DynIrqModInfo.MaxModIntsPerSec / 2); - - pAC->DynIrqModInfo.MaxModIntsPerSecLowerLimit = - pAC->DynIrqModInfo.MaxModIntsPerSec - - (pAC->DynIrqModInfo.MaxModIntsPerSec / 2); + pAC->DynIrqModInfo.MaxModIntsPerSecUpperLimit = + pAC->DynIrqModInfo.MaxModIntsPerSec + + (pAC->DynIrqModInfo.MaxModIntsPerSec / 2); + + pAC->DynIrqModInfo.MaxModIntsPerSecLowerLimit = + pAC->DynIrqModInfo.MaxModIntsPerSec - + (pAC->DynIrqModInfo.MaxModIntsPerSec / 2); - pAC->DynIrqModInfo.PrevTimeVal = jiffies; /* initial value */ + pAC->DynIrqModInfo.PrevTimeVal = jiffies; /* initial value */ } /* GetConfiguration */ @@ -4826,6 +5037,10 @@ SK_BOOL DualNet; FromPort = Param.Para32[0]; SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT, ("NET UP EVENT, Port: %d ", Param.Para32[0])); + /* Mac update */ + SkAddrMcUpdate(pAC,IoC, FromPort); + + if (DoPrintInterfaceChange) { printk("%s: network connection up using" " port %c\n", pAC->dev[Param.Para32[0]]->name, 'A'+Param.Para32[0]); @@ -4841,8 +5056,6 @@ SK_BOOL DualNet; printk(" speed: unknown\n"); } - /* Mac update */ - SkAddrMcUpdate(pAC,IoC, FromPort); Stat = pAC->GIni.GP[FromPort].PLinkModeStatus; if (Stat == SK_LMODE_STAT_AUTOHALF || @@ -4920,6 +5133,9 @@ SK_BOOL DualNet; printk(" rx-checksum: disabled\n"); #endif + } else { + DoPrintInterfaceChange = SK_TRUE; + } if ((Param.Para32[0] != pAC->ActivePort) && (pAC->RlmtNets == 1)) { @@ -4937,7 +5153,12 @@ SK_BOOL DualNet; /* action list 7 */ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT, ("NET DOWN EVENT ")); - printk("%s: network connection down\n", pAC->dev[Param.Para32[1]]->name); + if (DoPrintInterfaceChange) { + printk("%s: network connection down\n", + pAC->dev[Param.Para32[1]]->name); + } else { + DoPrintInterfaceChange = SK_TRUE; + } pAC->dev[Param.Para32[1]]->flags &= ~IFF_RUNNING; break; case SK_DRV_SWITCH_HARD: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */ @@ -5121,6 +5342,231 @@ char ClassStr[80]; ClassStr, ErrNum, pErrorMsg); } /* SkErrorLog */ + +#ifdef SK_DIAG_SUPPORT + +/***************************************************************************** + * + * SkDrvEnterDiagMode - handles DIAG attach request + * + * Description: + * Notify the kernel to NOT access the card any longer due to DIAG + * Deinitialize the Card + * + * Returns: + * int + */ +int SkDrvEnterDiagMode( +SK_AC *pAc) /* pointer to adapter context */ +{ + SK_AC *pAC = NULL; + DEV_NET *pNet = NULL; + + pNet = (DEV_NET *) pAc->dev[0]->priv; + pAC = pNet->pAC; + + SK_MEMCPY(&(pAc->PnmiBackup), &(pAc->PnmiStruct), + sizeof(SK_PNMI_STRUCT_DATA)); + + pAC->DiagModeActive = DIAG_ACTIVE; + if (pAC->BoardLevel > SK_INIT_DATA) { + if (pNet->Up) { + pAC->WasIfUp[0] = SK_TRUE; + pAC->DiagFlowCtrl = SK_TRUE; /* for SkGeClose */ + DoPrintInterfaceChange = SK_FALSE; + SkDrvDeInitAdapter(pAC, 0); /* performs SkGeClose */ + } else { + pAC->WasIfUp[0] = SK_FALSE; + } + if (pNet != (DEV_NET *) pAc->dev[1]->priv) { + pNet = (DEV_NET *) pAc->dev[1]->priv; + if (pNet->Up) { + pAC->WasIfUp[1] = SK_TRUE; + pAC->DiagFlowCtrl = SK_TRUE; /* for SkGeClose */ + DoPrintInterfaceChange = SK_FALSE; + SkDrvDeInitAdapter(pAC, 1); /* do SkGeClose */ + } else { + pAC->WasIfUp[1] = SK_FALSE; + } + } + pAC->BoardLevel = SK_INIT_DATA; + } + return(0); +} + +/***************************************************************************** + * + * SkDrvLeaveDiagMode - handles DIAG detach request + * + * Description: + * Notify the kernel to may access the card again after use by DIAG + * Initialize the Card + * + * Returns: + * int + */ +int SkDrvLeaveDiagMode( +SK_AC *pAc) /* pointer to adapter control context */ +{ + SK_MEMCPY(&(pAc->PnmiStruct), &(pAc->PnmiBackup), + sizeof(SK_PNMI_STRUCT_DATA)); + pAc->DiagModeActive = DIAG_NOTACTIVE; + pAc->Pnmi.DiagAttached = SK_DIAG_IDLE; + if (pAc->WasIfUp[0] == SK_TRUE) { + pAc->DiagFlowCtrl = SK_TRUE; /* for SkGeClose */ + DoPrintInterfaceChange = SK_FALSE; + SkDrvInitAdapter(pAc, 0); /* first device */ + } + if (pAc->WasIfUp[1] == SK_TRUE) { + pAc->DiagFlowCtrl = SK_TRUE; /* for SkGeClose */ + DoPrintInterfaceChange = SK_FALSE; + SkDrvInitAdapter(pAc, 1); /* second device */ + } + return(0); +} + +/***************************************************************************** + * + * ParseDeviceNbrFromSlotName - Evaluate PCI device number + * + * Description: + * This function parses the PCI slot name information string and will + * retrieve the devcie number out of it. The slot_name maintianed by + * linux is in the form of '02:0a.0', whereas the first two characters + * represent the bus number in hex (in the sample above this is + * pci bus 0x02) and the next two characters the device number (0x0a). + * + * Returns: + * SK_U32: The device number from the PCI slot name + */ + +static SK_U32 ParseDeviceNbrFromSlotName( +const char *SlotName) /* pointer to pci slot name eg. '02:0a.0' */ +{ + char *CurrCharPos = (char *) SlotName; + int FirstNibble = -1; + int SecondNibble = -1; + SK_U32 Result = 0; + + while (*CurrCharPos != '\0') { + if (*CurrCharPos == ':') { + while (*CurrCharPos != '.') { + CurrCharPos++; + if ( (*CurrCharPos >= '0') && + (*CurrCharPos <= '9')) { + if (FirstNibble == -1) { + /* dec. value for '0' */ + FirstNibble = *CurrCharPos - 48; + } else { + SecondNibble = *CurrCharPos - 48; + } + } else if ( (*CurrCharPos >= 'a') && + (*CurrCharPos <= 'f') ) { + if (FirstNibble == -1) { + FirstNibble = *CurrCharPos - 87; + } else { + SecondNibble = *CurrCharPos - 87; + } + } else { + Result = 0; + } + } + + Result = FirstNibble; + Result = Result << 4; /* first nibble is higher one */ + Result = Result | SecondNibble; + } + CurrCharPos++; /* next character */ + } + return (Result); +} + +/**************************************************************************** + * + * SkDrvDeInitAdapter - deinitialize adapter (this function is only + * called if Diag attaches to that card) + * + * Description: + * Close initialized adapter. + * + * Returns: + * 0 - on success + * error code - on error + */ +static int SkDrvDeInitAdapter( +SK_AC *pAC, /* pointer to adapter context */ +int devNbr) /* what device is to be handled */ +{ + struct SK_NET_DEVICE *dev; + + dev = pAC->dev[devNbr]; + + /* + ** Function SkGeClose() uses MOD_DEC_USE_COUNT (2.2/2.4) + ** or module_put() (2.6) to decrease the number of users for + ** a device, but if a device is to be put under control of + ** the DIAG, that count is OK already and does not need to + ** be adapted! Hence the opposite MOD_INC_USE_COUNT or + ** try_module_get() needs to be used again to correct that. + */ + if (!try_module_get(THIS_MODULE)) { + return (-1); + } + + if (SkGeClose(dev) != 0) { + module_put(THIS_MODULE); + return (-1); + } + return (0); + +} /* SkDrvDeInitAdapter() */ + +/**************************************************************************** + * + * SkDrvInitAdapter - Initialize adapter (this function is only + * called if Diag deattaches from that card) + * + * Description: + * Close initialized adapter. + * + * Returns: + * 0 - on success + * error code - on error + */ +static int SkDrvInitAdapter( +SK_AC *pAC, /* pointer to adapter context */ +int devNbr) /* what device is to be handled */ +{ + struct SK_NET_DEVICE *dev; + + dev = pAC->dev[devNbr]; + + if (SkGeOpen(dev) != 0) { + return (-1); + } else { + /* + ** Function SkGeOpen() uses MOD_INC_USE_COUNT (2.2/2.4) + ** or try_module_get() (2.6) to increase the number of + ** users for a device, but if a device was just under + ** control of the DIAG, that count is OK already and + ** does not need to be adapted! Hence the opposite + ** MOD_DEC_USE_COUNT or module_put() needs to be used + ** again to correct that. + */ + module_put(THIS_MODULE); + } + + /* + ** Use correct MTU size and indicate to kernel TX queue can be started + */ + if (SkGeChangeMtu(dev, dev->mtu) != 0) { + return (-1); + } + return (0); + +} /* SkDrvInitAdapter */ + +#endif #ifdef DEBUG /****************************************************************************/ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/skgehwt.c 830-ivtv/drivers/net/sk98lin/skgehwt.c --- 000-virgin/drivers/net/sk98lin/skgehwt.c Wed Aug 13 20:24:25 2003 +++ 830-ivtv/drivers/net/sk98lin/skgehwt.c Thu Jan 8 08:54:24 2004 @@ -1,10 +1,10 @@ /****************************************************************************** * * Name: skgehwt.c - * Project: Gigabit Ethernet Adapters, Common Modules - * Version: $Revision: 1.14 $ - * Date: $Date: 2003/05/13 18:01:58 $ - * Purpose: Hardware Timer. + * Project: Gigabit Ethernet Adapters, Event Scheduler Module + * Version: $Revision: 1.15 $ + * Date: $Date: 2003/09/16 13:41:23 $ + * Purpose: Hardware Timer * ******************************************************************************/ @@ -27,6 +27,10 @@ * History: * * $Log: skgehwt.c,v $ + * Revision 1.15 2003/09/16 13:41:23 rschmidt + * Added (C) Marvell to SysKonnectFileId + * Editorial changes + * * Revision 1.14 2003/05/13 18:01:58 mkarl * Editorial changes. * @@ -69,19 +73,15 @@ * * Revision 1.1 1998/08/05 11:28:36 gklug * first version: adapted from SMT/FDDI - * - * - * * ******************************************************************************/ - /* - Event queue and dispatcher -*/ + * Event queue and dispatcher + */ #if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM)))) static const char SysKonnectFileId[] = - "$Header: /usr56/projects/ge/schedule/skgehwt.c,v 1.14 2003/05/13 18:01:58 mkarl Exp $" ; + "@(#) $Id: skgehwt.c,v 1.15 2003/09/16 13:41:23 rschmidt Exp $ (C) Marvell."; #endif #include "h/skdrv1st.h" /* Driver Specific Definitions */ @@ -89,10 +89,7 @@ static const char SysKonnectFileId[] = #ifdef __C2MAN__ /* - Hardware Timer function queue management. - - General Description: - + * Hardware Timer function queue management. */ intro() {} @@ -117,9 +114,9 @@ SK_IOC Ioc) /* IoContext */ { pAC->Hwt.TStart = 0 ; pAC->Hwt.TStop = 0 ; - pAC->Hwt.TActive = SK_FALSE ; + pAC->Hwt.TActive = SK_FALSE; - SkHwtStop(pAC,Ioc) ; + SkHwtStop(pAC, Ioc); } /* @@ -132,28 +129,29 @@ SK_AC *pAC, /* Adapters context */ SK_IOC Ioc, /* IoContext */ SK_U32 Time) /* Time in units of 16us to load the timer with. */ { - SK_U32 Cnt ; + SK_U32 Cnt; if (Time > SK_HWT_MAX) - Time = SK_HWT_MAX ; + Time = SK_HWT_MAX; - pAC->Hwt.TStart = Time ; - pAC->Hwt.TStop = 0L ; + pAC->Hwt.TStart = Time; + pAC->Hwt.TStop = 0L; - Cnt = Time ; + Cnt = Time; /* * if time < 16 us * time = 16 us */ if (!Cnt) { - Cnt++ ; + Cnt++; } - SK_OUT32(Ioc, B2_TI_INI, Cnt * SK_HWT_FAC) ; - SK_OUT16(Ioc, B2_TI_CRTL, TIM_START) ; /* Start timer. */ + SK_OUT32(Ioc, B2_TI_INI, Cnt * SK_HWT_FAC); + + SK_OUT16(Ioc, B2_TI_CTRL, TIM_START); /* Start timer. */ - pAC->Hwt.TActive = SK_TRUE ; + pAC->Hwt.TActive = SK_TRUE; } /* @@ -164,10 +162,11 @@ void SkHwtStop( SK_AC *pAC, /* Adapters context */ SK_IOC Ioc) /* IoContext */ { - SK_OUT16(Ioc, B2_TI_CRTL, TIM_STOP) ; - SK_OUT16(Ioc, B2_TI_CRTL, TIM_CLR_IRQ) ; + SK_OUT16(Ioc, B2_TI_CTRL, TIM_STOP); + + SK_OUT16(Ioc, B2_TI_CTRL, TIM_CLR_IRQ); - pAC->Hwt.TActive = SK_FALSE ; + pAC->Hwt.TActive = SK_FALSE; } @@ -182,26 +181,31 @@ SK_U32 SkHwtRead( SK_AC *pAC, /* Adapters context */ SK_IOC Ioc) /* IoContext */ { - SK_U32 TRead ; - SK_U32 IStatus ; + SK_U32 TRead; + SK_U32 IStatus; if (pAC->Hwt.TActive) { - SkHwtStop(pAC,Ioc) ; + + SkHwtStop(pAC, Ioc); SK_IN32(Ioc, B2_TI_VAL, &TRead); TRead /= SK_HWT_FAC; SK_IN32(Ioc, B0_ISRC, &IStatus); - /* Check if timer expired (or wraparound). */ + /* Check if timer expired (or wraped around) */ if ((TRead > pAC->Hwt.TStart) || (IStatus & IS_TIMINT)) { - SkHwtStop(pAC,Ioc) ; - pAC->Hwt.TStop = pAC->Hwt.TStart ; - } else { - pAC->Hwt.TStop = pAC->Hwt.TStart - TRead ; + + SkHwtStop(pAC, Ioc); + + pAC->Hwt.TStop = pAC->Hwt.TStart; + } + else { + + pAC->Hwt.TStop = pAC->Hwt.TStart - TRead; } } - return (pAC->Hwt.TStop) ; + return(pAC->Hwt.TStop); } /* @@ -211,9 +215,11 @@ void SkHwtIsr( SK_AC *pAC, /* Adapters context */ SK_IOC Ioc) /* IoContext */ { - SkHwtStop(pAC,Ioc); + SkHwtStop(pAC, Ioc); + pAC->Hwt.TStop = pAC->Hwt.TStart; - SkTimerDone(pAC,Ioc) ; + + SkTimerDone(pAC, Ioc); } /* End of file */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/skgeinit.c 830-ivtv/drivers/net/sk98lin/skgeinit.c --- 000-virgin/drivers/net/sk98lin/skgeinit.c Wed Aug 13 20:24:25 2003 +++ 830-ivtv/drivers/net/sk98lin/skgeinit.c Thu Jan 8 08:54:24 2004 @@ -2,8 +2,8 @@ * * Name: skgeinit.c * Project: Gigabit Ethernet Adapters, Common Modules - * Version: $Revision: 1.93 $ - * Date: $Date: 2003/05/28 15:44:43 $ + * Version: $Revision: 1.97 $ + * Date: $Date: 2003/10/02 16:45:31 $ * Purpose: Contains functions to initialize the adapter * ******************************************************************************/ @@ -27,6 +27,32 @@ * History: * * $Log: skgeinit.c,v $ + * Revision 1.97 2003/10/02 16:45:31 rschmidt + * Replaced default values of GMAC parameters with defines. + * Removed hard reset of MACs in SkGeDeInit(). + * Added define SK_PHY_LP_MODE around power saving mode in SkGeDeInit(). + * Added check for VAUX available before switch power to VAUX. + * + * Revision 1.96 2003/09/18 14:02:41 rroesler + * Add: Perform a hardreset of MACs in GeDeInit() + * + * Revision 1.95 2003/09/16 14:26:59 rschmidt + * Added switch power to VCC (WA for VAUX problem) in SkGeInit1(). + * Fixed setting PHY to coma mode and D3 power state in SkGeDeInit(). + * Editorial changes. + * + * Revision 1.94 2003/09/16 07:17:10 mschmid + * Added init for new members in port structure for MAC control + * - PMacColThres + * - PMacJamLen + * - PMacJamIpgVal + * - PMacJamIpgData + * - PMacIpgData + * - PMacLimit4 + * Added init for PHY power state in port structure + * - PPhyPowerState + * Added shutdown handling for Yukon Plus in SkGeDeInit() + * * Revision 1.93 2003/05/28 15:44:43 rschmidt * Added check for chip Id on WOL WA for chip Rev. A. * Added setting of GILevel in SkGeDeInit(). @@ -446,7 +472,7 @@ #if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM)))) static const char SysKonnectFileId[] = - "@(#) $Id: skgeinit.c,v 1.93 2003/05/28 15:44:43 rschmidt Exp $ (C) Marvell."; + "@(#) $Id: skgeinit.c,v 1.97 2003/10/02 16:45:31 rschmidt Exp $ (C) Marvell."; #endif struct s_QOffTab { @@ -1013,8 +1039,6 @@ int Port) /* Port Index (MAC_1 + n) */ * - enable the FIFO */ - Word = (SK_U16)GMF_RX_CTRL_DEF; - #ifdef GENESIS if (pAC->GIni.GIGenesis) { /* Configure Rx MAC FIFO */ @@ -1039,6 +1063,8 @@ int Port) /* Port Index (MAC_1 + n) */ /* set Rx GMAC FIFO Flush Mask */ SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_FL_MSK), (SK_U16)RX_FF_FL_DEF_MSK); + Word = (SK_U16)GMF_RX_CTRL_DEF; + /* disable Rx GMAC FIFO Flush for YUKON-Lite Rev. A0 only */ if (pAC->GIni.GIYukonLite && pAC->GIni.GIChipId == CHIP_ID_YUKON) { @@ -1809,6 +1835,13 @@ SK_IOC IoC) /* IO context */ pPrt->PAutoNegFail = SK_FALSE; pPrt->PHWLinkUp = SK_FALSE; pPrt->PLinkBroken = SK_TRUE; /* See WA code */ + pPrt->PPhyPowerState = PHY_PM_OPERATIONAL_MODE; + pPrt->PMacColThres = TX_COL_DEF; + pPrt->PMacJamLen = TX_JAM_LEN_DEF; + pPrt->PMacJamIpgVal = TX_JAM_IPG_DEF; + pPrt->PMacJamIpgData = TX_IPG_JAM_DEF; + pPrt->PMacIpgData = IPG_DATA_DEF; + pPrt->PMacLimit4 = SK_FALSE; } pAC->GIni.GIPortUsage = SK_RED_LINK; @@ -1963,7 +1996,7 @@ SK_IOC IoC) /* IO context */ /* restore CLK_RUN bits */ SK_OUT16(IoC, B0_CTST, (SK_U16)(CtrlStat & (CS_CLK_RUN_HOT | CS_CLK_RUN_RST | CS_CLK_RUN_ENA))); - + /* read Chip Identification Number */ SK_IN8(IoC, B2_CHIP_ID, &Byte); pAC->GIni.GIChipId = Byte; @@ -2053,6 +2086,10 @@ SK_IOC IoC) /* IO context */ } } + /* switch power to VCC (WA for VAUX problem) */ + SK_OUT8(IoC, B0_POWER_CTRL, (SK_U8)(PC_VAUX_ENA | PC_VCC_ENA | + PC_VAUX_OFF | PC_VCC_ON)); + /* read the Interrupt source */ SK_IN32(IoC, B0_ISRC, &DWord); @@ -2395,6 +2432,11 @@ SK_IOC IoC) /* IO context */ int i; SK_U16 Word; +#ifdef SK_PHY_LP_MODE + SK_U8 Byte; + SK_U16 PmCtlSts; +#endif /* SK_PHY_LP_MODE */ + #if (!defined(SK_SLIM) && !defined(VCPU)) /* ensure I2C is ready */ SkI2cWaitIrq(pAC, IoC); @@ -2408,6 +2450,38 @@ SK_IOC IoC) /* IO context */ SkGeStopPort(pAC, IoC, i, SK_STOP_ALL, SK_HARD_RST); } } + +#ifdef SK_PHY_LP_MODE + /* + * for power saving purposes within mobile environments + * we set the PHY to coma mode and switch to D3 power state. + */ + if (pAC->GIni.GIYukonLite && + pAC->GIni.GIChipRev == CHIP_REV_YU_LITE_A3) { + + /* for all ports switch PHY to coma mode */ + for (i = 0; i < pAC->GIni.GIMacsFound; i++) { + + SkGmEnterLowPowerMode(pAC, IoC, i, PHY_PM_DEEP_SLEEP); + } + + if (pAC->GIni.GIVauxAvail) { + /* switch power to VAUX */ + Byte = PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_ON | PC_VCC_OFF; + + SK_OUT8(IoC, B0_POWER_CTRL, Byte); + } + + /* switch to D3 state */ + SK_IN16(IoC, PCI_C(PCI_PM_CTL_STS), &PmCtlSts); + + PmCtlSts |= PCI_PM_STATE_D3; + + SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON); + + SK_OUT16(IoC, PCI_C(PCI_PM_CTL_STS), PmCtlSts); + } +#endif /* SK_PHY_LP_MODE */ /* Reset all bits in the PCI STATUS register */ /* diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/skgemib.c 830-ivtv/drivers/net/sk98lin/skgemib.c --- 000-virgin/drivers/net/sk98lin/skgemib.c Wed Aug 13 20:24:25 2003 +++ 830-ivtv/drivers/net/sk98lin/skgemib.c Thu Jan 8 08:54:24 2004 @@ -2,8 +2,8 @@ * * Name: skgemib.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.9 $ - * Date: $Date: 2003/05/23 12:55:20 $ + * Version: $Revision: 1.11 $ + * Date: $Date: 2003/09/15 13:38:12 $ * Purpose: Private Network Management Interface Management Database * ****************************************************************************/ @@ -27,6 +27,19 @@ * History: * * $Log: skgemib.c,v $ + * Revision 1.11 2003/09/15 13:38:12 tschilli + * OID_SKGE_PHY_LP_MODE included only after using #define SK_PHY_LP_MODE. + * + * Revision 1.10 2003/08/15 12:28:59 tschilli + * Added new OIDs: + * OID_SKGE_DRIVER_RELDATE + * OID_SKGE_DRIVER_FILENAME + * OID_SKGE_CHIPID + * OID_SKGE_RAMSIZE + * OID_SKGE_VAUXAVAIL + * OID_SKGE_PHY_TYPE + * OID_SKGE_PHY_LP_MODE + * * Revision 1.9 2003/05/23 12:55:20 tschilli * OID_SKGE_BOARDLEVEL added. * @@ -356,6 +369,16 @@ PNMI_STATIC const SK_PNMI_TAB_ENTRY IdTa 0, SK_PNMI_MAI_OFF(DriverVersion), SK_PNMI_RO, General, 0}, + {OID_SKGE_DRIVER_RELDATE, + 1, + 0, + SK_PNMI_MAI_OFF(DriverReleaseDate), + SK_PNMI_RO, General, 0}, + {OID_SKGE_DRIVER_FILENAME, + 1, + 0, + SK_PNMI_MAI_OFF(DriverFileName), + SK_PNMI_RO, General, 0}, {OID_SKGE_HW_DESCR, 1, 0, @@ -371,6 +394,21 @@ PNMI_STATIC const SK_PNMI_TAB_ENTRY IdTa 0, SK_PNMI_MAI_OFF(Chipset), SK_PNMI_RO, General, 0}, + {OID_SKGE_CHIPID, + 1, + 0, + SK_PNMI_MAI_OFF(ChipId), + SK_PNMI_RO, General, 0}, + {OID_SKGE_RAMSIZE, + 1, + 0, + SK_PNMI_MAI_OFF(RamSize), + SK_PNMI_RO, General, 0}, + {OID_SKGE_VAUXAVAIL, + 1, + 0, + SK_PNMI_MAI_OFF(VauxAvail), + SK_PNMI_RO, General, 0}, {OID_SKGE_ACTION, 1, 0, @@ -876,6 +914,18 @@ PNMI_STATIC const SK_PNMI_TAB_ENTRY IdTa sizeof(SK_PNMI_CONF), SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfConnector), SK_PNMI_RO, MacPrivateConf, 0}, + {OID_SKGE_PHY_TYPE, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_CONF), + SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyType), + SK_PNMI_RO, MacPrivateConf, 0}, +#ifdef SK_PHY_LP_MODE + {OID_SKGE_PHY_LP_MODE, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_CONF), + SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyMode), + SK_PNMI_RW, MacPrivateConf, 0}, +#endif {OID_SKGE_LINK_CAP, SK_PNMI_MAC_ENTRIES, sizeof(SK_PNMI_CONF), diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/skgepnmi.c 830-ivtv/drivers/net/sk98lin/skgepnmi.c --- 000-virgin/drivers/net/sk98lin/skgepnmi.c Wed Aug 13 20:24:25 2003 +++ 830-ivtv/drivers/net/sk98lin/skgepnmi.c Thu Jan 8 08:54:24 2004 @@ -2,8 +2,8 @@ * * Name: skgepnmi.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.109 $ - * Date: $Date: 2003/07/17 14:15:24 $ + * Version: $Revision: 1.111 $ + * Date: $Date: 2003/09/15 13:35:35 $ * Purpose: Private Network Management Interface * ****************************************************************************/ @@ -27,6 +27,22 @@ * History: * * $Log: skgepnmi.c,v $ + * Revision 1.111 2003/09/15 13:35:35 tschilli + * Code for OID_SKGE_PHY_LP_MODE completed (using #define SK_PHY_LP_MODE). + * SK_DIAG_ATTACHED handling for OID_SKGE_DIAG_MODE in DiagActions() changed. + * + * Revision 1.110 2003/08/15 12:28:04 tschilli + * Added new OIDs: + * OID_SKGE_DRIVER_RELDATE + * OID_SKGE_DRIVER_FILENAME + * OID_SKGE_CHIPID + * OID_SKGE_RAMSIZE + * OID_SKGE_VAUXAVAIL + * OID_SKGE_PHY_TYPE + * OID_SKGE_PHY_LP_MODE + * + * Added SK_DIAG_ATTACHED handling for OID_SKGE_DIAG_MODE in DiagActions(). + * * Revision 1.109 2003/07/17 14:15:24 tschilli * Bug in SkPnmiGenIoctl() fixed. * @@ -471,7 +487,7 @@ #ifndef _lint static const char SysKonnectFileId[] = - "@(#) $Id: skgepnmi.c,v 1.109 2003/07/17 14:15:24 tschilli Exp $ (C) Marvell."; + "@(#) $Id: skgepnmi.c,v 1.111 2003/09/15 13:35:35 tschilli Exp $ (C) Marvell."; #endif /* !_lint */ #include "h/skdrv1st.h" @@ -4008,14 +4024,6 @@ SK_U32 NetIndex) /* NetIndex (0..n), in #endif /* SK_NDIS_64BIT_CTR */ break; - case OID_SKGE_BOARDLEVEL: - if (*pLen < sizeof(SK_U32)) { - - *pLen = sizeof(SK_U32); - return (SK_PNMI_ERR_TOO_SHORT); - } - break; - case OID_SKGE_PORT_NUMBER: case OID_SKGE_DEVICE_TYPE: case OID_SKGE_RESULT: @@ -4023,6 +4031,9 @@ SK_U32 NetIndex) /* NetIndex (0..n), in case OID_GEN_TRANSMIT_QUEUE_LENGTH: case OID_SKGE_TRAP_NUMBER: case OID_SKGE_MDB_VERSION: + case OID_SKGE_BOARDLEVEL: + case OID_SKGE_CHIPID: + case OID_SKGE_RAMSIZE: if (*pLen < sizeof(SK_U32)) { *pLen = sizeof(SK_U32); @@ -4043,6 +4054,7 @@ SK_U32 NetIndex) /* NetIndex (0..n), in case OID_SKGE_BUS_WIDTH: case OID_SKGE_SENSOR_NUMBER: case OID_SKGE_CHKSM_NUMBER: + case OID_SKGE_VAUXAVAIL: if (*pLen < sizeof(SK_U8)) { *pLen = sizeof(SK_U8); @@ -4234,6 +4246,66 @@ SK_U32 NetIndex) /* NetIndex (0..n), in *pLen = Len; break; + case OID_SKGE_DRIVER_RELDATE: + if (pAC->Pnmi.pDriverReleaseDate == NULL) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR030, + SK_PNMI_ERR053MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + Len = SK_STRLEN(pAC->Pnmi.pDriverReleaseDate) + 1; + if (Len > SK_PNMI_STRINGLEN1) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR031, + SK_PNMI_ERR054MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + if (*pLen < Len) { + + *pLen = Len; + return (SK_PNMI_ERR_TOO_SHORT); + } + *pBuf = (char)(Len - 1); + SK_MEMCPY(pBuf + 1, pAC->Pnmi.pDriverReleaseDate, Len - 1); + *pLen = Len; + break; + + case OID_SKGE_DRIVER_FILENAME: + if (pAC->Pnmi.pDriverFileName == NULL) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR030, + SK_PNMI_ERR055MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + Len = SK_STRLEN(pAC->Pnmi.pDriverFileName) + 1; + if (Len > SK_PNMI_STRINGLEN1) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR031, + SK_PNMI_ERR056MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + if (*pLen < Len) { + + *pLen = Len; + return (SK_PNMI_ERR_TOO_SHORT); + } + *pBuf = (char)(Len - 1); + SK_MEMCPY(pBuf + 1, pAC->Pnmi.pDriverFileName, Len - 1); + *pLen = Len; + break; + case OID_SKGE_HW_DESCR: /* * The hardware description is located in the VPD. This @@ -4291,8 +4363,25 @@ SK_U32 NetIndex) /* NetIndex (0..n), in *pLen = sizeof(SK_U16); break; + case OID_SKGE_CHIPID: + Val32 = pAC->GIni.GIChipId; + SK_PNMI_STORE_U32(pBuf, Val32); + *pLen = sizeof(SK_U32); + break; + + case OID_SKGE_RAMSIZE: + Val32 = pAC->GIni.GIRamSize; + SK_PNMI_STORE_U32(pBuf, Val32); + *pLen = sizeof(SK_U32); + break; + + case OID_SKGE_VAUXAVAIL: + *pBuf = (char) pAC->GIni.GIVauxAvail; + *pLen = sizeof(char); + break; + case OID_SKGE_BUS_TYPE: - *pBuf = (char)SK_PNMI_BUS_PCI; + *pBuf = (char) SK_PNMI_BUS_PCI; *pLen = sizeof(char); break; @@ -5435,6 +5524,9 @@ SK_U32 NetIndex) /* NetIndex (0..n), in case OID_SKGE_SPEED_CAP: case OID_SKGE_SPEED_MODE: case OID_SKGE_SPEED_STATUS: +#ifdef SK_PHY_LP_MODE + case OID_SKGE_PHY_LP_MODE: +#endif if (*pLen < (Limit - LogPortIndex) * sizeof(SK_U8)) { *pLen = (Limit - LogPortIndex) * sizeof(SK_U8); @@ -5443,6 +5535,7 @@ SK_U32 NetIndex) /* NetIndex (0..n), in break; case OID_SKGE_MTU: + case OID_SKGE_PHY_TYPE: if (*pLen < (Limit - LogPortIndex) * sizeof(SK_U32)) { *pLen = (Limit - LogPortIndex) * sizeof(SK_U32); @@ -5488,6 +5581,49 @@ SK_U32 NetIndex) /* NetIndex (0..n), in Offset += sizeof(char); break; + case OID_SKGE_PHY_TYPE: + if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */ + if (LogPortIndex == 0) { + continue; + } + else { + /* Get value for physical ports */ + PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( + pAC, LogPortIndex); + Val32 = pAC->GIni.GP[PhysPortIndex].PhyType; + SK_PNMI_STORE_U32(pBufPtr, Val32); + } + } + else { /* DualNetMode */ + + Val32 = pAC->GIni.GP[NetIndex].PhyType; + SK_PNMI_STORE_U32(pBufPtr, Val32); + } + Offset += sizeof(SK_U32); + break; + +#ifdef SK_PHY_LP_MODE + case OID_SKGE_PHY_LP_MODE: + if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */ + if (LogPortIndex == 0) { + continue; + } + else { + /* Get value for physical ports */ + PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex); + Val8 = (SK_U8) pAC->GIni.GP[PhysPortIndex].PPhyPowerState; + *pBufPtr = Val8; + } + } + else { /* DualNetMode */ + + Val8 = (SK_U8) pAC->GIni.GP[PhysPortIndex].PPhyPowerState; + *pBufPtr = Val8; + } + Offset += sizeof(SK_U8); + break; +#endif + case OID_SKGE_LINK_CAP: if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */ if (LogPortIndex == 0) { @@ -5804,6 +5940,16 @@ SK_U32 NetIndex) /* NetIndex (0..n), in } break; +#ifdef SK_PHY_LP_MODE + case OID_SKGE_PHY_LP_MODE: + if (*pLen < Limit - LogPortIndex) { + + *pLen = Limit - LogPortIndex; + return (SK_PNMI_ERR_TOO_SHORT); + } + break; +#endif + case OID_SKGE_MTU: if (*pLen < sizeof(SK_U32)) { @@ -6160,6 +6306,116 @@ SK_U32 NetIndex) /* NetIndex (0..n), in Offset += sizeof(SK_U32); break; + +#ifdef SK_PHY_LP_MODE + case OID_SKGE_PHY_LP_MODE: + /* The preset ends here */ + if (Action == SK_PNMI_PRESET) { + + return (SK_PNMI_ERR_OK); + } + + if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */ + if (LogPortIndex == 0) { + Offset = 0; + continue; + } + else { + /* Set value for physical ports */ + PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex); + + switch (*(pBuf + Offset)) { + case 0: + /* If LowPowerMode is active, we can leave it. */ + if (pAC->GIni.GP[PhysPortIndex].PPhyPowerState) { + + Val32 = SkGmLeaveLowPowerMode(pAC, IoC, PhysPortIndex); + + if (pAC->GIni.GP[PhysPortIndex].PPhyPowerState < 3) { + + SkDrvInitAdapter(pAC); + } + break; + } + else { + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + case 1: + case 2: + case 3: + case 4: + /* If no LowPowerMode is active, we can enter it. */ + if (!pAC->GIni.GP[PhysPortIndex].PPhyPowerState) { + + if ((*(pBuf + Offset)) < 3) { + + SkDrvDeInitAdapter(pAC); + } + + Val32 = SkGmEnterLowPowerMode(pAC, IoC, PhysPortIndex, *pBuf); + break; + } + else { + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + default: + *pLen = 0; + return (SK_PNMI_ERR_BAD_VALUE); + } + } + } + else { /* DualNetMode */ + + switch (*(pBuf + Offset)) { + case 0: + /* If we are in a LowPowerMode, we can leave it. */ + if (pAC->GIni.GP[PhysPortIndex].PPhyPowerState) { + + Val32 = SkGmLeaveLowPowerMode(pAC, IoC, PhysPortIndex); + + if (pAC->GIni.GP[PhysPortIndex].PPhyPowerState < 3) { + + SkDrvInitAdapter(pAC); + } + break; + } + else { + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + case 1: + case 2: + case 3: + case 4: + /* If we are not already in LowPowerMode, we can enter it. */ + if (!pAC->GIni.GP[PhysPortIndex].PPhyPowerState) { + + if ((*(pBuf + Offset)) < 3) { + + SkDrvDeInitAdapter(pAC); + } + else { + + Val32 = SkGmEnterLowPowerMode(pAC, IoC, PhysPortIndex, *pBuf); + } + break; + } + else { + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + default: + *pLen = 0; + return (SK_PNMI_ERR_BAD_VALUE); + } + } + Offset += sizeof(SK_U8); + break; +#endif default: SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR, @@ -6318,6 +6574,7 @@ char *pBuf) /* Buffer used for the mana unsigned int PhysPortMax; unsigned int PhysPortIndex; SK_U8 Val8; + SK_U32 Val32; SK_BOOL PortActiveFlag; SK_GEPORT *pPrt; @@ -6340,6 +6597,14 @@ char *pBuf) /* Buffer used for the mana switch (Id) { + case OID_SKGE_PHY_TYPE: + /* Check if it is the first active port */ + if (*pBuf == 0) { + Val32 = pPrt->PhyType; + SK_PNMI_STORE_U32(pBuf, Val32); + continue; + } + case OID_SKGE_LINK_CAP: /* @@ -7974,6 +8239,7 @@ unsigned int TableIndex, /* Index to the SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ { + SK_U32 DiagStatus; SK_U32 RetCode = SK_PNMI_ERR_GENERAL; /* @@ -8012,7 +8278,8 @@ SK_U32 NetIndex) /* NetIndex (0..n), in switch (Id) { case OID_SKGE_DIAG_MODE: - SK_PNMI_STORE_U32(pBuf, pAC->DiagModeActive); + DiagStatus = pAC->Pnmi.DiagAttached; + SK_PNMI_STORE_U32(pBuf, DiagStatus); *pLen = sizeof(SK_U32); RetCode = SK_PNMI_ERR_OK; break; @@ -8022,7 +8289,6 @@ SK_U32 NetIndex) /* NetIndex (0..n), in RetCode = SK_PNMI_ERR_GENERAL; break; } - return (RetCode); } @@ -8039,23 +8305,84 @@ SK_U32 NetIndex) /* NetIndex (0..n), in /* Handle the SET. */ switch (*pBuf) { - + + /* Attach the DIAG to this adapter. */ + case SK_DIAG_ATTACHED: + /* Check if we come from running */ + if (pAC->Pnmi.DiagAttached == SK_DIAG_RUNNING) { + + RetCode = SkDrvLeaveDiagMode(pAC); + + } + else if (pAC->Pnmi.DiagAttached == SK_DIAG_IDLE) { + + RetCode = SK_PNMI_ERR_OK; + } + + else { + + RetCode = SK_PNMI_ERR_GENERAL; + + } + + if (RetCode == SK_PNMI_ERR_OK) { + + pAC->Pnmi.DiagAttached = SK_DIAG_ATTACHED; + } + break; + /* Enter the DIAG mode in the driver. */ - case 1: - /* If DiagMode is not active, we can enter it. */ - if (!pAC->DiagModeActive) { + case SK_DIAG_RUNNING: + RetCode = SK_PNMI_ERR_OK; + + /* + * If DiagAttached is set, we can tell the driver + * to enter the DIAG mode. + */ + if (pAC->Pnmi.DiagAttached == SK_DIAG_ATTACHED) { + /* If DiagMode is not active, we can enter it. */ + if (!pAC->DiagModeActive) { + + RetCode = SkDrvEnterDiagMode(pAC); + } + else { - RetCode = SkDrvEnterDiagMode(pAC); + RetCode = SK_PNMI_ERR_GENERAL; + } } else { RetCode = SK_PNMI_ERR_GENERAL; } + + if (RetCode == SK_PNMI_ERR_OK) { + + pAC->Pnmi.DiagAttached = SK_DIAG_RUNNING; + } break; - /* Leave the DIAG mode in the driver. */ - case 0: - RetCode = SkDrvLeaveDiagMode(pAC); + case SK_DIAG_IDLE: + /* Check if we come from running */ + if (pAC->Pnmi.DiagAttached == SK_DIAG_RUNNING) { + + RetCode = SkDrvLeaveDiagMode(pAC); + + } + else if (pAC->Pnmi.DiagAttached == SK_DIAG_ATTACHED) { + + RetCode = SK_PNMI_ERR_OK; + } + + else { + + RetCode = SK_PNMI_ERR_GENERAL; + + } + + if (RetCode == SK_PNMI_ERR_OK) { + + pAC->Pnmi.DiagAttached = SK_DIAG_IDLE; + } break; default: diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/skgesirq.c 830-ivtv/drivers/net/sk98lin/skgesirq.c --- 000-virgin/drivers/net/sk98lin/skgesirq.c Wed Aug 13 20:24:25 2003 +++ 830-ivtv/drivers/net/sk98lin/skgesirq.c Thu Jan 8 08:54:24 2004 @@ -2,8 +2,8 @@ * * Name: skgesirq.c * Project: Gigabit Ethernet Adapters, Common Modules - * Version: $Revision: 1.91 $ - * Date: $Date: 2003/07/04 12:46:22 $ + * Version: $Revision: 1.92 $ + * Date: $Date: 2003/09/16 14:37:07 $ * Purpose: Special IRQ module * ******************************************************************************/ @@ -27,6 +27,12 @@ * History: * * $Log: skgesirq.c,v $ + * Revision 1.92 2003/09/16 14:37:07 rschmidt + * Added debug messages in some SkGePortCheckUp...() routines. + * Fixed compiler warnings for different types. + * Avoided port check up in reset state (eg. coma mode). + * Editorial changes. + * * Revision 1.91 2003/07/04 12:46:22 rschmidt * Added debug messages in SkGePortCheckUpGmac(). * Added error log message and new driver event SK_DRV_DOWNSHIFT_DET @@ -410,7 +416,7 @@ #if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM)))) static const char SysKonnectFileId[] = - "@(#) $Id: skgesirq.c,v 1.91 2003/07/04 12:46:22 rschmidt Exp $ (C) Marvell."; + "@(#) $Id: skgesirq.c,v 1.92 2003/09/16 14:37:07 rschmidt Exp $ (C) Marvell."; #endif #include "h/skdrv1st.h" /* Driver Specific Definitions */ @@ -490,7 +496,7 @@ int Port) /* Port Index (MAC_1 + n) */ ("AutoSensing: First mode %d on Port %d\n", (int)SK_LMODE_AUTOFULL, Port)); - pPrt->PLinkMode = SK_LMODE_AUTOFULL; + pPrt->PLinkMode = (SK_U8)SK_LMODE_AUTOFULL; return; } /* SkHWInitDefSense */ @@ -606,7 +612,7 @@ int Port) /* Port Index (MAC_1 + n) */ /* Reset Port stati */ pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_UNKNOWN; pPrt->PFlowCtrlStatus = (SK_U8)SK_FLOW_STAT_NONE; - pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_INDETERMINATED; + pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_INDETERMINATED; /* Re-init Phy especially when the AutoSense default is set now */ SkMacInitPhy(pAC, IoC, Port, SK_FALSE); @@ -655,19 +661,19 @@ int Port) /* Port Index (MAC_1 + n) */ case SK_LSPEED_AUTO: /* default is 1000 Mbps */ case SK_LSPEED_1000MBPS: - pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_1000MBPS; + pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS; break; case SK_LSPEED_100MBPS: - pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_100MBPS; + pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_100MBPS; break; case SK_LSPEED_10MBPS: - pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_10MBPS; + pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_10MBPS; break; } /* Set Link Mode Status */ if (pPrt->PLinkMode == SK_LMODE_FULL) { - pPrt->PLinkModeStatus = SK_LMODE_STAT_FULL; + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_FULL; } else { pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_HALF; @@ -1598,8 +1604,7 @@ SK_BOOL AutoNeg) /* Is Auto-negotiation * (clear Page Received bit if set) */ SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_AUNE_EXP, &ExtStat); - SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, - ("AutoNeg done Port %d\n", Port)); + return(SK_HW_PS_LINK); } @@ -1870,7 +1875,7 @@ SK_BOOL AutoNeg) /* Is Auto-negotiation SkMacAutoNegLipaPhy(pAC, IoC, Port, PhyStat); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, - ("AutoNeg: %d, PhyStat: 0x%04X\n", AutoNeg, PhyStat)); + ("CheckUp Port %d, PhyStat: 0x%04X\n", Port, PhyStat)); SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ResAb); @@ -1897,8 +1902,11 @@ SK_BOOL AutoNeg) /* Is Auto-negotiation if (AutoNeg) { if ((PhyStat & PHY_ST_AN_OVER) != 0) { + SkHWLinkUp(pAC, IoC, Port); + Done = SkMacAutoNegDone(pAC, IoC, Port); + if (Done != SK_AND_OK) { #ifdef DEBUG /* Get PHY parameters, for debugging only */ @@ -1924,9 +1932,6 @@ SK_BOOL AutoNeg) /* Is Auto-negotiation (void *)NULL); } #endif /* DEBUG */ - - SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, - ("AutoNeg done Port %d\n", Port)); return(SK_HW_PS_LINK); } } @@ -1989,9 +1994,22 @@ SK_BOOL AutoNeg) /* Is Auto-negotiation SK_U16 PhySpecStat;/* PHY Specific Status */ SK_U16 ResAb; /* Master/Slave resolution */ SK_EVPARA Para; +#ifdef DEBUG + SK_U16 Word; /* I/O helper */ +#endif /* DEBUG */ pPrt = &pAC->GIni.GP[Port]; + if (pPrt->PHWLinkUp) { + return(SK_HW_PS_NONE); + } + + /* Read PHY Status */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_STAT, &PhyStat); + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("CheckUp Port %d, PhyStat: 0x%04X\n", Port, PhyStat)); + /* Read PHY Interrupt Status */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_INT_STAT, &PhyIsrc); @@ -2005,16 +2023,6 @@ SK_BOOL AutoNeg) /* Is Auto-negotiation ("Link Speed Changed, PhyIsrc: 0x%04X\n", PhyIsrc)); } - if (pPrt->PHWLinkUp) { - return(SK_HW_PS_NONE); - } - - /* Read PHY Status */ - SkGmPhyRead(pAC, IoC, Port, PHY_MARV_STAT, &PhyStat); - - SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, - ("AutoNeg: %d, PhyStat: 0x%04X\n", AutoNeg, PhyStat)); - SkMacAutoNegLipaPhy(pAC, IoC, Port, PhyStat); SkGmPhyRead(pAC, IoC, Port, PHY_MARV_1000T_STAT, &ResAb); @@ -2034,7 +2042,20 @@ SK_BOOL AutoNeg) /* Is Auto-negotiation SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_STAT, &PhySpecStat); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, - ("AutoNeg: %d, PhySpecStat: 0x%04X\n", AutoNeg, PhySpecStat)); + ("Phy1000BT: 0x%04X, PhySpecStat: 0x%04X\n", ResAb, PhySpecStat)); + +#ifdef DEBUG + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_EXP, &Word); + + if ((PhyIsrc & PHY_M_IS_AN_PR) != 0 || (Word & PHY_ANE_RX_PG) != 0 || + (PhySpecStat & PHY_M_PS_PAGE_REC) != 0) { + /* Read PHY Next Page Link Partner */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_NEPG_LP, &Word); + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Page Received, NextPage: 0x%04X\n", Word)); + } +#endif /* DEBUG */ if ((PhySpecStat & PHY_M_PS_LINK_UP) == 0) { return(SK_HW_PS_NONE); @@ -2069,8 +2090,6 @@ SK_BOOL AutoNeg) /* Is Auto-negotiation return(SK_HW_PS_RESTART); } - SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, - ("AutoNeg done Port %d\n", Port)); return(SK_HW_PS_LINK); } } @@ -2179,8 +2198,6 @@ SK_BOOL AutoNeg) /* Is Auto-negotiation * extra link down/ups */ SkXmPhyRead(pAC, IoC, Port, PHY_LONE_INT_STAT, &ExtStat); - SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, - ("AutoNeg done Port %d\n", Port)); return(SK_HW_PS_LINK); } } @@ -2278,8 +2295,14 @@ SK_EVPARA Para) /* Event specific Param switch (Event) { case SK_HWEV_WATIM: - /* Check whether port came up */ - PortStat = SkGePortCheckUp(pAC, IoC, (int)Port); + if (pPrt->PState == SK_PRT_RESET) { + + PortStat = SK_HW_PS_NONE; + } + else { + /* Check whether port came up */ + PortStat = SkGePortCheckUp(pAC, IoC, (int)Port); + } switch (PortStat) { case SK_HW_PS_RESTART: diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/ski2c.c 830-ivtv/drivers/net/sk98lin/ski2c.c --- 000-virgin/drivers/net/sk98lin/ski2c.c Wed Aug 13 20:24:25 2003 +++ 830-ivtv/drivers/net/sk98lin/ski2c.c Thu Jan 8 08:54:24 2004 @@ -1,16 +1,17 @@ /****************************************************************************** * * Name: ski2c.c - * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.57 $ - * Date: $Date: 2003/01/28 09:17:38 $ + * Project: Gigabit Ethernet Adapters, TWSI-Module + * Version: $Revision: 1.59 $ + * Date: $Date: 2003/10/20 09:07:25 $ * Purpose: Functions to access Voltage and Temperature Sensor * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998-2003 SysKonnect GmbH. + * (C)Copyright 1998-2002 SysKonnect. + * (C)Copyright 2002-2003 Marvell. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +27,14 @@ * History: * * $Log: ski2c.c,v $ + * Revision 1.59 2003/10/20 09:07:25 rschmidt + * Added cast SK_U32 in SkI2cWrite() to avoid compiler warning. + * Editorial changes. + * + * Revision 1.58 2003/09/23 09:22:53 malthoff + * Parameter I2cDevSize added in SkI2cRead and SkI2cWrite to + * support larger devices on the TWSI bus. + * * Revision 1.57 2003/01/28 09:17:38 rschmidt * Fixed handling for sensors on YUKON Fiber. * Editorial changes. @@ -224,15 +233,15 @@ * Created. Sources taken from ML Projekt. * Sources have to be reworked for GE. * - * ******************************************************************************/ - /* * I2C Protocol */ +#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM)))) static const char SysKonnectFileId[] = - "$Id: ski2c.c,v 1.57 2003/01/28 09:17:38 rschmidt Exp $"; + "@(#) $Id: ski2c.c,v 1.59 2003/10/20 09:07:25 rschmidt Exp $ (C) Marvell. "; +#endif #include "h/skdrv1st.h" /* Driver Specific Definitions */ #include "h/lm80.h" @@ -312,7 +321,7 @@ intro() {} #endif -#ifdef SK_DIAG +#ifdef SK_DIAG /* * I2C Fast Mode timing values used by the LM80. * If new devices are added to the I2C bus the timing values have to be checked. @@ -516,7 +525,6 @@ SK_IOC IoC) /* I/O Context */ { /* * Received bit must be zero. - * */ SkI2cSndBit(IoC, 0); } /* SkI2cSndAck */ @@ -590,7 +598,7 @@ int Rw) /* Read / Write Flag */ return(SkI2cSndByte(IoC, (Addr<<1) | Rw)); } /* SkI2cSndDev */ -#endif /* SK_DIAG */ +#endif /* SK_DIAG */ /*----------------- I2C CTRL Register Functions ----------*/ @@ -620,7 +628,7 @@ int Event) /* complete event to wait fo SK_I2C_STOP(IoC); #ifndef SK_DIAG SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E002, SKERR_I2C_E002MSG); -#endif /* !SK_DIAG */ +#endif /* !SK_DIAG */ return(1); } @@ -661,15 +669,19 @@ SK_IOC IoC) /* I/O Context */ } StartTime = SkOsGetTime(pAC); + do { if (SkOsGetTime(pAC) - StartTime > SK_TICKS_PER_SEC / 8) { + SK_I2C_STOP(IoC); #ifndef SK_DIAG SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E016, SKERR_I2C_E016MSG); -#endif /* !SK_DIAG */ +#endif /* !SK_DIAG */ return; } + SK_IN32(IoC, B0_ISRC, &IrqSrc); + } while ((IrqSrc & IS_I2C_READY) == 0); pSen->SenState = SK_SEN_IDLE; @@ -687,18 +699,19 @@ SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_U32 I2cData, /* I2C Data to write */ int I2cDev, /* I2C Device Address */ +int I2cDevSize, /* I2C Device Size (e.g. I2C_025K_DEV or I2C_2K_DEV) */ int I2cReg, /* I2C Device Register Address */ int I2cBurst) /* I2C Burst Flag */ { SK_OUT32(IoC, B2_I2C_DATA, I2cData); - SK_I2C_CTL(IoC, I2C_WRITE, I2cDev, I2cReg, I2cBurst); + + SK_I2C_CTL(IoC, I2C_WRITE, I2cDev, I2cDevSize, I2cReg, I2cBurst); return(SkI2cWait(pAC, IoC, I2C_WRITE)); } /* SkI2cWrite*/ #ifdef SK_DIAG - /* * reads a single byte or 4 bytes from the I2C device * @@ -708,23 +721,24 @@ SK_U32 SkI2cRead( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int I2cDev, /* I2C Device Address */ +int I2cDevSize, /* I2C Device Size (e.g. I2C_025K_DEV or I2C_2K_DEV) */ int I2cReg, /* I2C Device Register Address */ int I2cBurst) /* I2C Burst Flag */ { SK_U32 Data; SK_OUT32(IoC, B2_I2C_DATA, 0); - SK_I2C_CTL(IoC, I2C_READ, I2cDev, I2cReg, I2cBurst); + SK_I2C_CTL(IoC, I2C_READ, I2cDev, I2cDevSize, I2cReg, I2cBurst); if (SkI2cWait(pAC, IoC, I2C_READ) != 0) { w_print("%s\n", SKERR_I2C_E002MSG); } SK_IN32(IoC, B2_I2C_DATA, &Data); + return(Data); } /* SkI2cRead */ - -#endif /* SK_DIAG */ +#endif /* SK_DIAG */ /* @@ -745,9 +759,10 @@ SK_SENSOR *pSen) /* Sensor to be read */ if (pSen->SenRead != NULL) { return((*pSen->SenRead)(pAC, IoC, pSen)); } - else + else { return(0); /* no success */ -} /* SkI2cReadSensor*/ + } +} /* SkI2cReadSensor */ /* * Do the Init state 0 initialization @@ -761,12 +776,12 @@ SK_AC *pAC) /* Adapter Context */ pAC->I2c.CurrSens = 0; /* Begin with timeout control for state machine */ - pAC->I2c.TimerMode = SK_TIMER_WATCH_STATEMACHINE; + pAC->I2c.TimerMode = SK_TIMER_WATCH_SM; /* Set sensor number to zero */ pAC->I2c.MaxSens = 0; -#ifndef SK_DIAG +#ifndef SK_DIAG /* Initialize Number of Dummy Reads */ pAC->I2c.DummyReads = SK_MAX_SENSORS; #endif @@ -840,19 +855,20 @@ SK_IOC IoC) /* I/O Context */ } /* Check for 64 Bit Yukon without sensors */ - if (SkI2cWrite(pAC, IoC, 0, LM80_ADDR, LM80_CFG, 0) != 0) { + if (SkI2cWrite(pAC, IoC, 0, LM80_ADDR, I2C_025K_DEV, LM80_CFG, 0) != 0) { return(0); } - (void)SkI2cWrite(pAC, IoC, 0xff, LM80_ADDR, LM80_IMSK_1, 0); + (void)SkI2cWrite(pAC, IoC, 0xffUL, LM80_ADDR, I2C_025K_DEV, LM80_IMSK_1, 0); - (void)SkI2cWrite(pAC, IoC, 0xff, LM80_ADDR, LM80_IMSK_2, 0); + (void)SkI2cWrite(pAC, IoC, 0xffUL, LM80_ADDR, I2C_025K_DEV, LM80_IMSK_2, 0); - (void)SkI2cWrite(pAC, IoC, 0, LM80_ADDR, LM80_FAN_CTRL, 0); + (void)SkI2cWrite(pAC, IoC, 0, LM80_ADDR, I2C_025K_DEV, LM80_FAN_CTRL, 0); - (void)SkI2cWrite(pAC, IoC, 0, LM80_ADDR, LM80_TEMP_CTRL, 0); + (void)SkI2cWrite(pAC, IoC, 0, LM80_ADDR, I2C_025K_DEV, LM80_TEMP_CTRL, 0); - (void)SkI2cWrite(pAC, IoC, LM80_CFG_START, LM80_ADDR, LM80_CFG, 0); + (void)SkI2cWrite(pAC, IoC, (SK_U32)LM80_CFG_START, LM80_ADDR, I2C_025K_DEV, + LM80_CFG, 0); /* * MaxSens has to be updated here, because PhyType is not @@ -957,7 +973,7 @@ SK_IOC IoC) /* I/O Context */ pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PHY_2V5_LOW_ERR; } else { - pAC->I2c.SenTable[i].SenDesc = "Voltage ASIC-Co 1V5"; + pAC->I2c.SenTable[i].SenDesc = "Voltage Core 1V5"; pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_CORE_1V5_HIGH_ERR; pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_CORE_1V5_HIGH_WARN; pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_CORE_1V5_LOW_WARN; @@ -1015,9 +1031,9 @@ SK_IOC IoC) /* I/O Context */ pAC->I2c.SenTable[i].SenDev = LM80_ADDR; } -#ifndef SK_DIAG +#ifndef SK_DIAG pAC->I2c.DummyReads = pAC->I2c.MaxSens; -#endif /* !SK_DIAG */ +#endif /* !SK_DIAG */ /* Clear I2C IRQ */ SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ); @@ -1208,15 +1224,13 @@ SK_SENSOR *pSen) pSen->SenLastErrLogTS = CurrTime; if (pSen->SenType == SK_SEN_TEMP) { - SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E011, - SKERR_I2C_E011MSG); - } else if (pSen->SenType == SK_SEN_VOLT) { - SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E012, - SKERR_I2C_E012MSG); - } else - { - SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E015, - SKERR_I2C_E015MSG); + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E011, SKERR_I2C_E011MSG); + } + else if (pSen->SenType == SK_SEN_VOLT) { + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E012, SKERR_I2C_E012MSG); + } + else { + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E015, SKERR_I2C_E015MSG); } } } @@ -1235,8 +1249,7 @@ SK_SENSOR *pSen) /* This state is the former one */ /* So check first whether we have to send a trap */ - if (pSen->SenLastWarnTrapTS + SK_SEN_WARN_TR_HOLD > - CurrTime) { + if (pSen->SenLastWarnTrapTS + SK_SEN_WARN_TR_HOLD > CurrTime) { /* * Do NOT send the Trap. The hold back time * has to run out first. @@ -1245,8 +1258,7 @@ SK_SENSOR *pSen) } /* Check now whether we have to log an Error */ - if (pSen->SenLastWarnLogTS + SK_SEN_WARN_LOG_HOLD > - CurrTime) { + if (pSen->SenLastWarnLogTS + SK_SEN_WARN_LOG_HOLD > CurrTime) { /* * Do NOT log the error. The hold back time * has to run out first. @@ -1277,15 +1289,13 @@ SK_SENSOR *pSen) pSen->SenLastWarnLogTS = CurrTime; if (pSen->SenType == SK_SEN_TEMP) { - SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E009, - SKERR_I2C_E009MSG); - } else if (pSen->SenType == SK_SEN_VOLT) { - SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E010, - SKERR_I2C_E010MSG); - } else - { - SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E014, - SKERR_I2C_E014MSG); + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E009, SKERR_I2C_E009MSG); + } + else if (pSen->SenType == SK_SEN_VOLT) { + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E010, SKERR_I2C_E010MSG); + } + else { + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E014, SKERR_I2C_E014MSG); } } } @@ -1317,7 +1327,7 @@ SK_SENSOR *pSen) } } -#if 0 +#ifdef TEST_ONLY /* Dynamic thresholds also for VAUX of LM80 sensor */ if (pSen->SenInit == SK_SEN_DYN_INIT_VAUX) { @@ -1359,7 +1369,7 @@ SK_SENSOR *pSen) if (pSen->SenInit != SK_SEN_DYN_INIT_NONE) { SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E013, SKERR_I2C_E013MSG); } -} /* SkI2cCheckSensor*/ +} /* SkI2cCheckSensor */ /* @@ -1390,7 +1400,7 @@ SK_EVPARA Para) /* Event specific Parame if (ReadComplete) { /* Check sensor against defined thresholds */ - SkI2cCheckSensor (pAC, pSen); + SkI2cCheckSensor(pAC, pSen); /* Increment Current sensor and set appropriate Timeout */ pAC->I2c.CurrSens++; @@ -1414,7 +1424,7 @@ SK_EVPARA Para) /* Event specific Parame /* Start Timer */ ParaLocal.Para64 = (SK_U64)0; - pAC->I2c.TimerMode = SK_TIMER_WATCH_STATEMACHINE; + pAC->I2c.TimerMode = SK_TIMER_WATCH_SM; SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, SK_I2C_TIM_WATCH, SKGE_I2C, SK_I2CEV_TIM, ParaLocal); @@ -1431,7 +1441,7 @@ SK_EVPARA Para) /* Event specific Parame if (ReadComplete) { /* Check sensor against defined thresholds */ - SkI2cCheckSensor (pAC, pSen); + SkI2cCheckSensor(pAC, pSen); /* Increment Current sensor and set appropriate Timeout */ pAC->I2c.CurrSens++; @@ -1496,4 +1506,4 @@ SK_EVPARA Para) /* Event specific Parame return(0); } /* SkI2cEvent*/ -#endif /* !SK_DIAG */ +#endif /* !SK_DIAG */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/sklm80.c 830-ivtv/drivers/net/sk98lin/sklm80.c --- 000-virgin/drivers/net/sk98lin/sklm80.c Wed Aug 13 20:24:25 2003 +++ 830-ivtv/drivers/net/sk98lin/sklm80.c Thu Jan 8 08:54:24 2004 @@ -1,16 +1,17 @@ /****************************************************************************** * * Name: sklm80.c - * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.20 $ - * Date: $Date: 2002/08/13 09:16:27 $ - * Purpose: Funktions to access Voltage and Temperature Sensor (LM80) + * Project: Gigabit Ethernet Adapters, TWSI-Module + * Version: $Revision: 1.22 $ + * Date: $Date: 2003/10/20 09:08:21 $ + * Purpose: Functions to access Voltage and Temperature Sensor (LM80) * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 1998-2002 SysKonnect. + * (C)Copyright 2002-2003 Marvell. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,15 +27,21 @@ * History: * * $Log: sklm80.c,v $ + * Revision 1.22 2003/10/20 09:08:21 rschmidt + * Editorial changes. + * + * Revision 1.21 2003/09/23 09:29:04 malthoff + * Parameter Dev_Size added to macro SK_I2C_CTL. + * * Revision 1.20 2002/08/13 09:16:27 rschmidt * Changed return value for SkLm80ReadSensor() back to 'int' - * Editorial changes + * Editorial changes. * * Revision 1.19 2002/08/06 09:43:31 jschmalz - * Extensions and changes for Yukon + * Extensions and changes for Yukon. * * Revision 1.18 2002/08/02 12:26:57 rschmidt - * Editorial changes + * Editorial changes. * * Revision 1.17 1999/11/22 13:35:51 cgoos * Changed license header to GPL. @@ -93,16 +100,15 @@ * Revision 1.1 1998/07/17 09:57:12 gklug * initial version * - * - * ******************************************************************************/ - /* LM80 functions */ +#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM)))) static const char SysKonnectFileId[] = - "$Id: sklm80.c,v 1.20 2002/08/13 09:16:27 rschmidt Exp $" ; + "@(#) $Id: sklm80.c,v 1.22 2003/10/20 09:08:21 rschmidt Exp $ (C) Marvell. "; +#endif #include "h/skdrv1st.h" /* Driver Specific Definitions */ #include "h/lm80.h" @@ -202,7 +208,7 @@ SK_SENSOR *pSen) /* Sensor to be read */ switch (pSen->SenState) { case SK_SEN_IDLE: /* Send address to ADDR register */ - SK_I2C_CTL(IoC, I2C_READ, pSen->SenDev, pSen->SenReg, 0); + SK_I2C_CTL(IoC, I2C_READ, pSen->SenDev, I2C_025K_DEV, pSen->SenReg, 0); pSen->SenState = SK_SEN_VALUE ; BREAK_OR_WAIT(pAC, IoC, I2C_READ); @@ -250,7 +256,7 @@ SK_SENSOR *pSen) /* Sensor to be read */ (pSen->SenValue % SK_LM80_TEMP_LSB); /* Send address to ADDR register */ - SK_I2C_CTL(IoC, I2C_READ, pSen->SenDev, LM80_TEMP_CTRL, 0); + SK_I2C_CTL(IoC, I2C_READ, pSen->SenDev, I2C_025K_DEV, LM80_TEMP_CTRL, 0); pSen->SenState = SK_SEN_VALEXT ; BREAK_OR_WAIT(pAC, IoC, I2C_READ); @@ -284,3 +290,4 @@ SK_SENSOR *pSen) /* Sensor to be read */ /* Not completed */ return(0); } + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/skproc.c 830-ivtv/drivers/net/sk98lin/skproc.c --- 000-virgin/drivers/net/sk98lin/skproc.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/sk98lin/skproc.c Thu Jan 8 08:54:24 2004 @@ -1,16 +1,17 @@ /****************************************************************************** * - * Name: skproc.c + * Name: skproc.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.2 $ - * Date: $Date: 2003/08/12 16:45:29 $ + * Version: $Revision: 1.11 $ + * Date: $Date: 2003/12/11 16:03:57 $ * Purpose: Funktions to display statictic data * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998-2003 SysKonnect GmbH. + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,6 +29,33 @@ * History: * * $Log: skproc.c,v $ + * Revision 1.11 2003/12/11 16:03:57 mlindner + * Fix: Create backup from pnmi data structure + * + * Revision 1.10 2003/11/19 16:25:36 mlindner + * Fix: Print output as 64-bit digit + * + * Revision 1.9 2003/11/17 13:29:05 mlindner + * Fix: Editorial changes + * + * Revision 1.8 2003/11/13 14:18:48 rroesler + * Fix: added latest changes regarding the use of the proc system + * + * Revision 1.7 2003/11/10 09:35:07 rroesler + * Fix: diag backup restore of PNMI structure + * + * Revision 1.6 2003/11/07 17:31:39 rroesler + * Add: security counter for the proc file system + * + * Revision 1.5 2003/10/07 08:17:08 mlindner + * Fix: Copyright changes + * + * Revision 1.4 2003/09/01 15:29:24 mlindner + * Fix: Editorial changes + * + * Revision 1.3 2003/08/29 12:30:58 mlindner + * Add: Version entry in the proc file system + * * Revision 1.2 2003/08/12 16:45:29 mlindner * Add: Removed SkNumber and SkDoDiv * Add: Counter output as (unsigned long long) @@ -94,223 +122,350 @@ #include "h/skdrv1st.h" #include "h/skdrv2nd.h" +#include "h/skversion.h" -#ifdef CONFIG_PROC_FS +extern struct SK_NET_DEVICE *SkGeRootDev; +static int sk_proc_print(void *writePtr, char *format, ...); +static void sk_gen_browse(void *buffer); +int len; -extern struct net_device *SkGeRootDev; +static int sk_seq_show(struct seq_file *seq, void *v); +static int sk_proc_open(struct inode *inode, struct file *file); +struct file_operations sk_proc_fops = { + .owner = THIS_MODULE, + .open = sk_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +struct net_device *currDev = NULL; -static int sk_seq_show(struct seq_file *seq, void *v) +/***************************************************************************** + * + * sk_gen_browse -generic print "summaries" entry + * + * Description: + * This function fills the proc entry with statistic data about + * the ethernet device. + * + * Returns: - + * + */ +static void sk_gen_browse(void *buffer) { - struct net_device *dev = seq->private; - DEV_NET *pNet = dev->priv; - SK_AC *pAC = pNet->pAC; - SK_PNMI_STRUCT_DATA *pPnmiStruct = &pAC->PnmiStruct; - SK_PNMI_STAT *pPnmiStat = &pPnmiStruct->Stat[0]; - int unit = !(pAC->dev[0] == dev); - int i; - char sens_msg[50]; - - seq_printf(seq, - "\nDetailed statistic for device %s\n", - dev->name); - seq_printf(seq, - "=======================================\n"); - - /* Board statistics */ - seq_printf(seq, - "\nBoard statistics\n\n"); - seq_printf(seq, - "Active Port %c\n", - 'A' + pAC->Rlmt.Net[unit].Port[pAC->Rlmt. - Net[unit].PrefPort]->PortNumber); - seq_printf(seq, - "Preferred Port %c\n", - 'A' + pAC->Rlmt.Net[unit].Port[pAC->Rlmt. - Net[unit].PrefPort]->PortNumber); - - seq_printf(seq, - "Bus speed (MHz) %d\n", - pPnmiStruct->BusSpeed); - - seq_printf(seq, - "Bus width (Bit) %d\n", - pPnmiStruct->BusWidth); - seq_printf(seq, - "Hardware revision v%d.%d\n", - (pAC->GIni.GIPciHwRev >> 4) & 0x0F, - pAC->GIni.GIPciHwRev & 0x0F); - - /* Print sensor informations */ - for (i=0; i < pAC->I2c.MaxSens; i ++) { - /* Check type */ - switch (pAC->I2c.SenTable[i].SenType) { - case 1: - strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc); - strcat(sens_msg, " (C)"); - seq_printf(seq, - "%-25s %d.%02d\n", - sens_msg, - pAC->I2c.SenTable[i].SenValue / 10, - pAC->I2c.SenTable[i].SenValue % 10); - - strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc); - strcat(sens_msg, " (F)"); - seq_printf(seq, - "%-25s %d.%02d\n", - sens_msg, - ((((pAC->I2c.SenTable[i].SenValue) - *10)*9)/5 + 3200)/100, - ((((pAC->I2c.SenTable[i].SenValue) - *10)*9)/5 + 3200) % 10); - break; - case 2: - strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc); - strcat(sens_msg, " (V)"); - seq_printf(seq, - "%-25s %d.%03d\n", - sens_msg, - pAC->I2c.SenTable[i].SenValue / 1000, - pAC->I2c.SenTable[i].SenValue % 1000); - break; - case 3: - strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc); - strcat(sens_msg, " (rpm)"); - seq_printf(seq, - "%-25s %d\n", - sens_msg, - pAC->I2c.SenTable[i].SenValue); - break; - default: - break; + struct SK_NET_DEVICE *SkgeProcDev = SkGeRootDev; + struct SK_NET_DEVICE *next; + SK_PNMI_STRUCT_DATA *pPnmiStruct; + SK_PNMI_STAT *pPnmiStat; + unsigned long Flags; + unsigned int Size; + DEV_NET *pNet; + SK_AC *pAC; + char sens_msg[50]; + int MaxSecurityCount = 0; + int t; + int i; + + while (SkgeProcDev) { + MaxSecurityCount++; + if (MaxSecurityCount > 100) { + printk("Max limit for sk_proc_read security counter!\n"); + return; } - } + pNet = (DEV_NET*) SkgeProcDev->priv; + pAC = pNet->pAC; + next = pAC->Next; + pPnmiStruct = &pAC->PnmiStruct; + /* NetIndex in GetStruct is now required, zero is only dummy */ + + for (t=pAC->GIni.GIMacsFound; t > 0; t--) { + if ((pAC->GIni.GIMacsFound == 2) && pAC->RlmtNets == 1) + t--; + + spin_lock_irqsave(&pAC->SlowPathLock, Flags); + Size = SK_PNMI_STRUCT_SIZE; +#ifdef SK_DIAG_SUPPORT + if (pAC->BoardLevel == SK_INIT_DATA) { + SK_MEMCPY(&(pAC->PnmiStruct), &(pAC->PnmiBackup), sizeof(SK_PNMI_STRUCT_DATA)); + if (pAC->DiagModeActive == DIAG_NOTACTIVE) { + pAC->Pnmi.DiagAttached = SK_DIAG_IDLE; + } + } else { + SkPnmiGetStruct(pAC, pAC->IoBase, pPnmiStruct, &Size, t-1); + } +#else + SkPnmiGetStruct(pAC, pAC->IoBase, + pPnmiStruct, &Size, t-1); +#endif + spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); + + if (strcmp(pAC->dev[t-1]->name, currDev->name) == 0) { + pPnmiStat = &pPnmiStruct->Stat[0]; + len = sk_proc_print(buffer, + "\nDetailed statistic for device %s\n", + pAC->dev[t-1]->name); + len += sk_proc_print(buffer, + "=======================================\n"); + + /* Board statistics */ + len += sk_proc_print(buffer, + "\nBoard statistics\n\n"); + len += sk_proc_print(buffer, + "Active Port %c\n", + 'A' + pAC->Rlmt.Net[t-1].Port[pAC->Rlmt. + Net[t-1].PrefPort]->PortNumber); + len += sk_proc_print(buffer, + "Preferred Port %c\n", + 'A' + pAC->Rlmt.Net[t-1].Port[pAC->Rlmt. + Net[t-1].PrefPort]->PortNumber); + + len += sk_proc_print(buffer, + "Bus speed (MHz) %d\n", + pPnmiStruct->BusSpeed); + + len += sk_proc_print(buffer, + "Bus width (Bit) %d\n", + pPnmiStruct->BusWidth); + len += sk_proc_print(buffer, + "Driver version %s\n", + VER_STRING); + len += sk_proc_print(buffer, + "Hardware revision v%d.%d\n", + (pAC->GIni.GIPciHwRev >> 4) & 0x0F, + pAC->GIni.GIPciHwRev & 0x0F); + + /* Print sensor informations */ + for (i=0; i < pAC->I2c.MaxSens; i ++) { + /* Check type */ + switch (pAC->I2c.SenTable[i].SenType) { + case 1: + strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc); + strcat(sens_msg, " (C)"); + len += sk_proc_print(buffer, + "%-25s %d.%02d\n", + sens_msg, + pAC->I2c.SenTable[i].SenValue / 10, + pAC->I2c.SenTable[i].SenValue % 10); + + strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc); + strcat(sens_msg, " (F)"); + len += sk_proc_print(buffer, + "%-25s %d.%02d\n", + sens_msg, + ((((pAC->I2c.SenTable[i].SenValue) + *10)*9)/5 + 3200)/100, + ((((pAC->I2c.SenTable[i].SenValue) + *10)*9)/5 + 3200) % 10); + break; + case 2: + strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc); + strcat(sens_msg, " (V)"); + len += sk_proc_print(buffer, + "%-25s %d.%03d\n", + sens_msg, + pAC->I2c.SenTable[i].SenValue / 1000, + pAC->I2c.SenTable[i].SenValue % 1000); + break; + case 3: + strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc); + strcat(sens_msg, " (rpm)"); + len += sk_proc_print(buffer, + "%-25s %d\n", + sens_msg, + pAC->I2c.SenTable[i].SenValue); + break; + default: + break; + } + } - /*Receive statistics */ - seq_printf(seq, - "\nReceive statistics\n\n"); - - seq_printf(seq, - "Received bytes %Ld\n", - (unsigned long long) pPnmiStat->StatRxOctetsOkCts); - seq_printf(seq, - "Received packets %Ld\n", - (unsigned long long) pPnmiStat->StatRxOkCts); + /*Receive statistics */ + len += sk_proc_print(buffer, + "\nReceive statistics\n\n"); + + len += sk_proc_print(buffer, + "Received bytes %Lu\n", + (unsigned long long) pPnmiStat->StatRxOctetsOkCts); + len += sk_proc_print(buffer, + "Received packets %Lu\n", + (unsigned long long) pPnmiStat->StatRxOkCts); #if 0 - if (pAC->GIni.GP[0].PhyType == SK_PHY_XMAC && - pAC->HWRevision < 12) { - pPnmiStruct->InErrorsCts = pPnmiStruct->InErrorsCts - - pPnmiStat->StatRxShortsCts; - pPnmiStat->StatRxShortsCts = 0; - } + if (pAC->GIni.GP[0].PhyType == SK_PHY_XMAC && + pAC->HWRevision < 12) { + pPnmiStruct->InErrorsCts = pPnmiStruct->InErrorsCts - + pPnmiStat->StatRxShortsCts; + pPnmiStat->StatRxShortsCts = 0; + } #endif - if (pNet->Mtu > 1500) - pPnmiStruct->InErrorsCts = pPnmiStruct->InErrorsCts - - pPnmiStat->StatRxTooLongCts; - - seq_printf(seq, - "Receive errors %Ld\n", - (unsigned long long) pPnmiStruct->InErrorsCts); - seq_printf(seq, - "Receive dropped %Ld\n", - (unsigned long long) pPnmiStruct->RxNoBufCts); - seq_printf(seq, - "Received multicast %Ld\n", - (unsigned long long) pPnmiStat->StatRxMulticastOkCts); - seq_printf(seq, - "Receive error types\n"); - seq_printf(seq, - " length %Ld\n", - (unsigned long long) pPnmiStat->StatRxRuntCts); - seq_printf(seq, - " buffer overflow %Ld\n", - (unsigned long long) pPnmiStat->StatRxFifoOverflowCts); - seq_printf(seq, - " bad crc %Ld\n", - (unsigned long long) pPnmiStat->StatRxFcsCts); - seq_printf(seq, - " framing %Ld\n", - (unsigned long long) pPnmiStat->StatRxFramingCts); - seq_printf(seq, - " missed frames %Ld\n", - (unsigned long long) pPnmiStat->StatRxMissedCts); - - if (pNet->Mtu > 1500) - pPnmiStat->StatRxTooLongCts = 0; - - seq_printf(seq, - " too long %Ld\n", - (unsigned long long) pPnmiStat->StatRxTooLongCts); - seq_printf(seq, - " carrier extension %Ld\n", - (unsigned long long) pPnmiStat->StatRxCextCts); - seq_printf(seq, - " too short %Ld\n", - (unsigned long long) pPnmiStat->StatRxShortsCts); - seq_printf(seq, - " symbol %Ld\n", - (unsigned long long) pPnmiStat->StatRxSymbolCts); - seq_printf(seq, - " LLC MAC size %Ld\n", - (unsigned long long) pPnmiStat->StatRxIRLengthCts); - seq_printf(seq, - " carrier event %Ld\n", - (unsigned long long) pPnmiStat->StatRxCarrierCts); - seq_printf(seq, - " jabber %Ld\n", - (unsigned long long) pPnmiStat->StatRxJabberCts); - - - /*Transmit statistics */ - seq_printf(seq, - "\nTransmit statistics\n\n"); + if (pNet->Mtu > 1500) + pPnmiStruct->InErrorsCts = pPnmiStruct->InErrorsCts - + pPnmiStat->StatRxTooLongCts; + + len += sk_proc_print(buffer, + "Receive errors %Lu\n", + (unsigned long long) pPnmiStruct->InErrorsCts); + len += sk_proc_print(buffer, + "Receive dropped %Lu\n", + (unsigned long long) pPnmiStruct->RxNoBufCts); + len += sk_proc_print(buffer, + "Received multicast %Lu\n", + (unsigned long long) pPnmiStat->StatRxMulticastOkCts); + len += sk_proc_print(buffer, + "Receive error types\n"); + len += sk_proc_print(buffer, + " length %Lu\n", + (unsigned long long) pPnmiStat->StatRxRuntCts); + len += sk_proc_print(buffer, + " buffer overflow %Lu\n", + (unsigned long long) pPnmiStat->StatRxFifoOverflowCts); + len += sk_proc_print(buffer, + " bad crc %Lu\n", + (unsigned long long) pPnmiStat->StatRxFcsCts); + len += sk_proc_print(buffer, + " framing %Lu\n", + (unsigned long long) pPnmiStat->StatRxFramingCts); + len += sk_proc_print(buffer, + " missed frames %Lu\n", + (unsigned long long) pPnmiStat->StatRxMissedCts); + + if (pNet->Mtu > 1500) + pPnmiStat->StatRxTooLongCts = 0; + + len += sk_proc_print(buffer, + " too long %Lu\n", + (unsigned long long) pPnmiStat->StatRxTooLongCts); + len += sk_proc_print(buffer, + " carrier extension %Lu\n", + (unsigned long long) pPnmiStat->StatRxCextCts); + len += sk_proc_print(buffer, + " too short %Lu\n", + (unsigned long long) pPnmiStat->StatRxShortsCts); + len += sk_proc_print(buffer, + " symbol %Lu\n", + (unsigned long long) pPnmiStat->StatRxSymbolCts); + len += sk_proc_print(buffer, + " LLC MAC size %Lu\n", + (unsigned long long) pPnmiStat->StatRxIRLengthCts); + len += sk_proc_print(buffer, + " carrier event %Lu\n", + (unsigned long long) pPnmiStat->StatRxCarrierCts); + len += sk_proc_print(buffer, + " jabber %Lu\n", + (unsigned long long) pPnmiStat->StatRxJabberCts); + + + /*Transmit statistics */ + len += sk_proc_print(buffer, + "\nTransmit statistics\n\n"); - seq_printf(seq, - "Transmited bytes %Ld\n", - (unsigned long long) pPnmiStat->StatTxOctetsOkCts); - seq_printf(seq, - "Transmited packets %Ld\n", - (unsigned long long) pPnmiStat->StatTxOkCts); - seq_printf(seq, - "Transmit errors %Ld\n", - (unsigned long long) pPnmiStat->StatTxSingleCollisionCts); - seq_printf(seq, - "Transmit dropped %Ld\n", - (unsigned long long) pPnmiStruct->TxNoBufCts); - seq_printf(seq, - "Transmit collisions %Ld\n", - (unsigned long long) pPnmiStat->StatTxSingleCollisionCts); - seq_printf(seq, - "Transmit error types\n"); - seq_printf(seq, - " excessive collision %ld\n", - pAC->stats.tx_aborted_errors); - seq_printf(seq, - " carrier %Ld\n", - (unsigned long long) pPnmiStat->StatTxCarrierCts); - seq_printf(seq, - " fifo underrun %Ld\n", - (unsigned long long) pPnmiStat->StatTxFifoUnderrunCts); - seq_printf(seq, - " heartbeat %Ld\n", - (unsigned long long) pPnmiStat->StatTxCarrierCts); - seq_printf(seq, - " window %ld\n", - pAC->stats.tx_window_errors); + len += sk_proc_print(buffer, + "Transmited bytes %Lu\n", + (unsigned long long) pPnmiStat->StatTxOctetsOkCts); + len += sk_proc_print(buffer, + "Transmited packets %Lu\n", + (unsigned long long) pPnmiStat->StatTxOkCts); + len += sk_proc_print(buffer, + "Transmit errors %Lu\n", + (unsigned long long) pPnmiStat->StatTxSingleCollisionCts); + len += sk_proc_print(buffer, + "Transmit dropped %Lu\n", + (unsigned long long) pPnmiStruct->TxNoBufCts); + len += sk_proc_print(buffer, + "Transmit collisions %Lu\n", + (unsigned long long) pPnmiStat->StatTxSingleCollisionCts); + len += sk_proc_print(buffer, + "Transmit error types\n"); + len += sk_proc_print(buffer, + " excessive collision %ld\n", + pAC->stats.tx_aborted_errors); + len += sk_proc_print(buffer, + " carrier %Lu\n", + (unsigned long long) pPnmiStat->StatTxCarrierCts); + len += sk_proc_print(buffer, + " fifo underrun %Lu\n", + (unsigned long long) pPnmiStat->StatTxFifoUnderrunCts); + len += sk_proc_print(buffer, + " heartbeat %Lu\n", + (unsigned long long) pPnmiStat->StatTxCarrierCts); + len += sk_proc_print(buffer, + " window %ld\n", + pAC->stats.tx_window_errors); - return 0; + } /* if (strcmp(pACname, currDeviceName) == 0) */ + } + SkgeProcDev = next; + } } +/***************************************************************************** + * + * sk_proc_print -generic line print + * + * Description: + * This function fills the proc entry with statistic data about + * the ethernet device. + * + * Returns: number of bytes written + * + */ +static int sk_proc_print(void *writePtr, char *format, ...) +{ +#define MAX_LEN_SINGLE_LINE 256 + char str[MAX_LEN_SINGLE_LINE]; + va_list a_start; + int lenght = 0; + + struct seq_file *seq = (struct seq_file *) writePtr; + + SK_MEMSET(str, 0, MAX_LEN_SINGLE_LINE); + + va_start(a_start, format); + vsprintf(str, format, a_start); + va_end(a_start); + + lenght = strlen(str); + seq_printf(seq, str); + return lenght; +} + +/***************************************************************************** + * + * sk_seq_show - show proc information of a particular adapter + * + * Description: + * This function fills the proc entry with statistic data about + * the ethernet device. It invokes the generic sk_gen_browse() to + * print out all items one per one. + * + * Returns: number of bytes written + * + */ +static int sk_seq_show(struct seq_file *seq, void *v) +{ + void *castedBuffer = (void *) seq; + currDev = seq->private; + sk_gen_browse(castedBuffer); + return 0; +} + +/***************************************************************************** + * + * sk_proc_open - register the show function when proc is open'ed + * + * Description: + * This function is called whenever a sk98lin proc file is queried. + * + * Returns: the return value of single_open() + * + */ static int sk_proc_open(struct inode *inode, struct file *file) { - return single_open(file, sk_seq_show, PDE(inode)->data); + return single_open(file, sk_seq_show, PDE(inode)->data); } -struct file_operations sk_proc_fops = { - .owner = THIS_MODULE, - .open = sk_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; -#endif +/******************************************************************************* + * + * End of file + * + ******************************************************************************/ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/skqueue.c 830-ivtv/drivers/net/sk98lin/skqueue.c --- 000-virgin/drivers/net/sk98lin/skqueue.c Wed Aug 13 20:24:25 2003 +++ 830-ivtv/drivers/net/sk98lin/skqueue.c Thu Jan 8 08:54:24 2004 @@ -1,9 +1,9 @@ /****************************************************************************** * * Name: skqueue.c - * Project: Gigabit Ethernet Adapters, Schedule-Modul - * Version: $Revision: 1.19 $ - * Date: $Date: 2003/05/13 18:00:07 $ + * Project: Gigabit Ethernet Adapters, Event Scheduler Module + * Version: $Revision: 1.20 $ + * Date: $Date: 2003/09/16 13:44:00 $ * Purpose: Management of an event queue. * ******************************************************************************/ @@ -27,6 +27,10 @@ * History: * * $Log: skqueue.c,v $ + * Revision 1.20 2003/09/16 13:44:00 rschmidt + * Added (C) Marvell to SysKonnectFileId + * Editorial changes + * * Revision 1.19 2003/05/13 18:00:07 mkarl * Removed calls to RLMT, TWSI, and PNMI for SLIM driver (SK_SLIM). * Editorial changes. @@ -85,18 +89,16 @@ * * Revision 1.1 1998/07/30 15:14:01 gklug * Initial version. Adapted from SMT - * - * * ******************************************************************************/ /* - Event queue and dispatcher -*/ + * Event queue and dispatcher + */ #if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM)))) static const char SysKonnectFileId[] = - "$Header: /usr56/projects/ge/schedule/skqueue.c,v 1.19 2003/05/13 18:00:07 mkarl Exp $" ; + "@(#) $Id: skqueue.c,v 1.20 2003/09/16 13:44:00 rschmidt Exp $ (C) Marvell."; #endif #include "h/skdrv1st.h" /* Driver Specific Definitions */ @@ -124,11 +126,11 @@ intro() void SkEventInit( SK_AC *pAC, /* Adapter context */ SK_IOC Ioc, /* IO context */ -int Level) /* Init level */ +int Level) /* Init level */ { switch (Level) { case SK_INIT_DATA: - pAC->Event.EvPut = pAC->Event.EvGet = pAC->Event.EvQueue ; + pAC->Event.EvPut = pAC->Event.EvGet = pAC->Event.EvQueue; break; default: break; @@ -144,14 +146,15 @@ SK_U32 Class, /* Event Class */ SK_U32 Event, /* Event to be queued */ SK_EVPARA Para) /* Event parameter */ { - pAC->Event.EvPut->Class = Class ; - pAC->Event.EvPut->Event = Event ; - pAC->Event.EvPut->Para = Para ; + pAC->Event.EvPut->Class = Class; + pAC->Event.EvPut->Event = Event; + pAC->Event.EvPut->Para = Para; + if (++pAC->Event.EvPut == &pAC->Event.EvQueue[SK_MAX_EVENT]) - pAC->Event.EvPut = pAC->Event.EvQueue ; + pAC->Event.EvPut = pAC->Event.EvQueue; if (pAC->Event.EvPut == pAC->Event.EvGet) { - SK_ERR_LOG(pAC, SK_ERRCL_NORES, SKERR_Q_E001, SKERR_Q_E001MSG) ; + SK_ERR_LOG(pAC, SK_ERRCL_NORES, SKERR_Q_E001, SKERR_Q_E001MSG); } } @@ -168,77 +171,79 @@ int SkEventDispatcher( SK_AC *pAC, /* Adapters Context */ SK_IOC Ioc) /* Io context */ { - SK_EVENTELEM *pEv ; /* pointer into queue */ - SK_U32 Class ; - int Rtv ; - - pEv = pAC->Event.EvGet ; - PRINTF("dispatch get %x put %x\n",pEv,pAC->Event.ev_put) ; + SK_EVENTELEM *pEv; /* pointer into queue */ + SK_U32 Class; + int Rtv; + + pEv = pAC->Event.EvGet; + + PRINTF("dispatch get %x put %x\n", pEv, pAC->Event.ev_put); + while (pEv != pAC->Event.EvPut) { - PRINTF("dispatch Class %d Event %d\n",pEv->Class,pEv->Event) ; - switch(Class = pEv->Class) { + PRINTF("dispatch Class %d Event %d\n", pEv->Class, pEv->Event); + + switch (Class = pEv->Class) { #ifndef SK_USE_LAC_EV #ifndef SK_SLIM - case SKGE_RLMT : /* RLMT Event */ - Rtv = SkRlmtEvent(pAC,Ioc,pEv->Event,pEv->Para); - break ; - case SKGE_I2C : /* I2C Event */ - Rtv = SkI2cEvent(pAC,Ioc,pEv->Event,pEv->Para); - break ; - case SKGE_PNMI : - Rtv = SkPnmiEvent(pAC,Ioc,pEv->Event,pEv->Para); - break ; + case SKGE_RLMT: /* RLMT Event */ + Rtv = SkRlmtEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; + case SKGE_I2C: /* I2C Event */ + Rtv = SkI2cEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; + case SKGE_PNMI: /* PNMI Event */ + Rtv = SkPnmiEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; #endif /* not SK_SLIM */ #endif /* not SK_USE_LAC_EV */ - case SKGE_DRV : /* Driver Event */ - Rtv = SkDrvEvent(pAC,Ioc,pEv->Event,pEv->Para); - break ; -#ifndef SK_USE_SW_TIMER - case SKGE_HWAC : - Rtv = SkGeSirqEvent(pAC,Ioc,pEv->Event,pEv->Para); - break ; + case SKGE_DRV: /* Driver Event */ + Rtv = SkDrvEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; +#ifndef SK_USE_SW_TIMER + case SKGE_HWAC: + Rtv = SkGeSirqEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; #else /* !SK_USE_SW_TIMER */ - case SKGE_SWT : - Rtv = SkSwtEvent(pAC,Ioc,pEv->Event,pEv->Para); - break ; + case SKGE_SWT : + Rtv = SkSwtEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; #endif /* !SK_USE_SW_TIMER */ -#ifdef SK_USE_LAC_EV +#ifdef SK_USE_LAC_EV case SKGE_LACP : - Rtv = SkLacpEvent(pAC,Ioc,pEv->Event,pEv->Para); - break ; + Rtv = SkLacpEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; case SKGE_RSF : - Rtv = SkRsfEvent(pAC,Ioc,pEv->Event,pEv->Para); - break ; + Rtv = SkRsfEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; case SKGE_MARKER : - Rtv = SkMarkerEvent(pAC,Ioc,pEv->Event,pEv->Para); - break ; + Rtv = SkMarkerEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; case SKGE_FD : - Rtv = SkFdEvent(pAC,Ioc,pEv->Event,pEv->Para); - break ; + Rtv = SkFdEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; #endif /* SK_USE_LAC_EV */ #ifdef SK_USE_CSUM case SKGE_CSUM : - Rtv = SkCsEvent(pAC,Ioc,pEv->Event,pEv->Para); - break ; + Rtv = SkCsEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; #endif /* SK_USE_CSUM */ default : - SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_Q_E002, - SKERR_Q_E002MSG) ; + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_Q_E002, SKERR_Q_E002MSG); Rtv = 0; } if (Rtv != 0) { - return(Rtv) ; + return(Rtv); } if (++pEv == &pAC->Event.EvQueue[SK_MAX_EVENT]) - pEv = pAC->Event.EvQueue ; + pEv = pAC->Event.EvQueue; /* Renew get: it is used in queue_events to detect overruns */ pAC->Event.EvGet = pEv; } - return(0) ; + return(0); } /* End of file */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/sktimer.c 830-ivtv/drivers/net/sk98lin/sktimer.c --- 000-virgin/drivers/net/sk98lin/sktimer.c Wed Aug 13 20:24:25 2003 +++ 830-ivtv/drivers/net/sk98lin/sktimer.c Thu Jan 8 08:54:24 2004 @@ -1,9 +1,9 @@ /****************************************************************************** * * Name: sktimer.c - * Project: Gigabit Ethernet Adapters, Schedule-Modul - * Version: $Revision: 1.13 $ - * Date: $Date: 2003/05/13 18:01:01 $ + * Project: Gigabit Ethernet Adapters, Event Scheduler Module + * Version: $Revision: 1.14 $ + * Date: $Date: 2003/09/16 13:46:51 $ * Purpose: High level timer functions. * ******************************************************************************/ @@ -27,6 +27,10 @@ * History: * * $Log: sktimer.c,v $ + * Revision 1.14 2003/09/16 13:46:51 rschmidt + * Added (C) Marvell to SysKonnectFileId + * Editorial changes + * * Revision 1.13 2003/05/13 18:01:01 mkarl * Editorial changes. * @@ -68,19 +72,16 @@ * * Revision 1.1 1998/08/05 11:27:55 gklug * first version: adapted from SMT - * - * - * * ******************************************************************************/ /* - Event queue and dispatcher -*/ + * Event queue and dispatcher + */ #if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM)))) static const char SysKonnectFileId[] = - "$Header: /usr56/projects/ge/schedule/sktimer.c,v 1.13 2003/05/13 18:01:01 mkarl Exp $" ; + "@(#) $Id: sktimer.c,v 1.14 2003/09/16 13:46:51 rschmidt Exp $ (C) Marvell."; #endif #include "h/skdrv1st.h" /* Driver Specific Definitions */ @@ -110,14 +111,14 @@ static void timer_done(SK_AC *pAC,SK_IOC void SkTimerInit( SK_AC *pAC, /* Adapters context */ SK_IOC Ioc, /* IoContext */ -int Level) /* Init Level */ +int Level) /* Init Level */ { switch (Level) { case SK_INIT_DATA: - pAC->Tim.StQueue = 0 ; + pAC->Tim.StQueue = 0; break; case SK_INIT_IO: - SkHwtInit(pAC,Ioc) ; + SkHwtInit(pAC, Ioc); SkTimerDone(pAC, Ioc); break; default: @@ -134,31 +135,34 @@ SK_AC *pAC, /* Adapters context */ SK_IOC Ioc, /* IoContext */ SK_TIMER *pTimer) /* Timer Pointer to be started */ { - SK_TIMER **ppTimPrev ; - SK_TIMER *pTm ; + SK_TIMER **ppTimPrev; + SK_TIMER *pTm; /* * remove timer from queue */ - pTimer->TmActive = SK_FALSE ; + pTimer->TmActive = SK_FALSE; + if (pAC->Tim.StQueue == pTimer && !pTimer->TmNext) { - SkHwtStop(pAC,Ioc) ; + SkHwtStop(pAC, Ioc); } - for (ppTimPrev = &pAC->Tim.StQueue ; (pTm = *ppTimPrev) ; + + for (ppTimPrev = &pAC->Tim.StQueue; (pTm = *ppTimPrev); ppTimPrev = &pTm->TmNext ) { + if (pTm == pTimer) { /* * Timer found in queue * - dequeue it and * - correct delta of the next timer */ - *ppTimPrev = pTm->TmNext ; + *ppTimPrev = pTm->TmNext; if (pTm->TmNext) { /* correct delta of next timer in queue */ - pTm->TmNext->TmDelta += pTm->TmDelta ; + pTm->TmNext->TmDelta += pTm->TmDelta; } - return ; + return; } } } @@ -175,65 +179,67 @@ SK_U32 Class, /* Event Class for this SK_U32 Event, /* Event Value for this timer */ SK_EVPARA Para) /* Event Parameter for this timer */ { - SK_TIMER **ppTimPrev ; - SK_TIMER *pTm ; - SK_U32 Delta ; + SK_TIMER **ppTimPrev; + SK_TIMER *pTm; + SK_U32 Delta; - Time /= 16 ; /* input is uS, clock ticks are 16uS */ + Time /= 16; /* input is uS, clock ticks are 16uS */ + if (!Time) - Time = 1 ; + Time = 1; - SkTimerStop(pAC,Ioc,pTimer) ; + SkTimerStop(pAC, Ioc, pTimer); - pTimer->TmClass = Class ; - pTimer->TmEvent = Event ; - pTimer->TmPara = Para ; - pTimer->TmActive = SK_TRUE ; + pTimer->TmClass = Class; + pTimer->TmEvent = Event; + pTimer->TmPara = Para; + pTimer->TmActive = SK_TRUE; if (!pAC->Tim.StQueue) { /* First Timer to be started */ - pAC->Tim.StQueue = pTimer ; - pTimer->TmNext = 0 ; - pTimer->TmDelta = Time ; - SkHwtStart(pAC,Ioc,Time) ; - return ; + pAC->Tim.StQueue = pTimer; + pTimer->TmNext = 0; + pTimer->TmDelta = Time; + + SkHwtStart(pAC, Ioc, Time); + + return; } /* * timer correction */ - timer_done(pAC,Ioc,0) ; + timer_done(pAC, Ioc, 0); /* * find position in queue */ - Delta = 0 ; - for (ppTimPrev = &pAC->Tim.StQueue ; (pTm = *ppTimPrev) ; + Delta = 0; + for (ppTimPrev = &pAC->Tim.StQueue; (pTm = *ppTimPrev); ppTimPrev = &pTm->TmNext ) { + if (Delta + pTm->TmDelta > Time) { /* Position found */ /* Here the timer needs to be inserted. */ - break ; + break; } - Delta += pTm->TmDelta ; + Delta += pTm->TmDelta; } /* insert in queue */ - *ppTimPrev = pTimer ; - pTimer->TmNext = pTm ; - pTimer->TmDelta = Time - Delta ; + *ppTimPrev = pTimer; + pTimer->TmNext = pTm; + pTimer->TmDelta = Time - Delta; if (pTm) { /* There is a next timer * -> correct its Delta value. */ - pTm->TmDelta -= pTimer->TmDelta ; + pTm->TmDelta -= pTimer->TmDelta; } - /* - * start new with first - */ - SkHwtStart(pAC,Ioc,pAC->Tim.StQueue->TmDelta) ; + /* restart with first */ + SkHwtStart(pAC, Ioc, pAC->Tim.StQueue->TmDelta); } @@ -241,55 +247,56 @@ void SkTimerDone( SK_AC *pAC, /* Adapters context */ SK_IOC Ioc) /* IoContext */ { - timer_done(pAC,Ioc,1) ; + timer_done(pAC, Ioc, 1); } static void timer_done( SK_AC *pAC, /* Adapters context */ SK_IOC Ioc, /* IoContext */ -int Restart) /* Do we need to restart the Hardware timer ? */ +int Restart) /* Do we need to restart the Hardware timer ? */ { - SK_U32 Delta ; - SK_TIMER *pTm ; - SK_TIMER *pTComp ; /* Timer completed now now */ - SK_TIMER **ppLast ; /* Next field of Last timer to be deq */ - int Done = 0 ; - - Delta = SkHwtRead(pAC,Ioc) ; - ppLast = &pAC->Tim.StQueue ; - pTm = pAC->Tim.StQueue ; + SK_U32 Delta; + SK_TIMER *pTm; + SK_TIMER *pTComp; /* Timer completed now now */ + SK_TIMER **ppLast; /* Next field of Last timer to be deq */ + int Done = 0; + + Delta = SkHwtRead(pAC, Ioc); + + ppLast = &pAC->Tim.StQueue; + pTm = pAC->Tim.StQueue; while (pTm && !Done) { if (Delta >= pTm->TmDelta) { /* Timer ran out */ - pTm->TmActive = SK_FALSE ; - Delta -= pTm->TmDelta ; - ppLast = &pTm->TmNext ; - pTm = pTm->TmNext ; - } else { + pTm->TmActive = SK_FALSE; + Delta -= pTm->TmDelta; + ppLast = &pTm->TmNext; + pTm = pTm->TmNext; + } + else { /* We found the first timer that did not run out */ - pTm->TmDelta -= Delta ; - Delta = 0 ; - Done = 1 ; + pTm->TmDelta -= Delta; + Delta = 0; + Done = 1; } } - *ppLast = 0 ; + *ppLast = 0; /* * pTm points to the first Timer that did not run out. * StQueue points to the first Timer that run out. */ - for ( pTComp = pAC->Tim.StQueue ; pTComp ; pTComp = pTComp->TmNext) { - SkEventQueue(pAC,pTComp->TmClass, pTComp->TmEvent, - pTComp->TmPara) ; + for ( pTComp = pAC->Tim.StQueue; pTComp; pTComp = pTComp->TmNext) { + SkEventQueue(pAC,pTComp->TmClass, pTComp->TmEvent, pTComp->TmPara); } /* Set head of timer queue to the first timer that did not run out */ - pAC->Tim.StQueue = pTm ; + pAC->Tim.StQueue = pTm; if (Restart && pAC->Tim.StQueue) { /* Restart HW timer */ - SkHwtStart(pAC,Ioc,pAC->Tim.StQueue->TmDelta) ; + SkHwtStart(pAC, Ioc, pAC->Tim.StQueue->TmDelta); } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk98lin/skxmac2.c 830-ivtv/drivers/net/sk98lin/skxmac2.c --- 000-virgin/drivers/net/sk98lin/skxmac2.c Wed Aug 13 20:24:25 2003 +++ 830-ivtv/drivers/net/sk98lin/skxmac2.c Thu Jan 8 08:54:25 2004 @@ -2,8 +2,8 @@ * * Name: skxmac2.c * Project: Gigabit Ethernet Adapters, Common Modules - * Version: $Revision: 1.99 $ - * Date: $Date: 2003/07/11 12:19:33 $ + * Version: $Revision: 1.102 $ + * Date: $Date: 2003/10/02 16:53:58 $ * Purpose: Contains functions to initialize the MACs and PHYs * ******************************************************************************/ @@ -27,6 +27,23 @@ * History: * * $Log: skxmac2.c,v $ + * Revision 1.102 2003/10/02 16:53:58 rschmidt + * Changed setting of GMAC parameters with new macros. + * Added define SLIM around SkGm...LowPowerMode(). + * Editorial changes. + * + * Revision 1.101 2003/09/16 14:49:07 rschmidt + * Added routines SkGmClearRst(), SkXmClearRst, SkMacClearRst(). + * Added WA code for Yukon-Lite's COMA mode in SkGmHardRst(). + * Replaced PCI-Config R/W through internal access. + * Fixed return from coma mode in SkGmLeaveLowPowerMode(). + * Fixed compiler warnings for different types. + * Editorial changes. + * + * Revision 1.100 2003/09/16 07:09:11 mschmid + * Added functions SkGmEnterLowPowerMode() and + * SkGmLeaveLowPowerMode() + * * Revision 1.99 2003/07/11 12:19:33 rschmidt * Reduced init values for Master & Slave downshift counters to * minimum values. @@ -164,7 +181,7 @@ * Revision 1.74 2002/08/12 14:00:17 rschmidt * Replaced usage of Broadcom PHY Ids with defines. * Corrected error messages in SkGmMacStatistic(). - * Made SkMacPromiscMode() public for ADDR-Modul. + * Made SkMacPromiscMode() public for ADDR-Module. * Editorial changes. * * Revision 1.73 2002/08/08 16:26:24 rschmidt @@ -475,7 +492,7 @@ typedef struct s_PhyHack { #if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM)))) static const char SysKonnectFileId[] = - "@(#) $Id: skxmac2.c,v 1.99 2003/07/11 12:19:33 rschmidt Exp $ (C) Marvell."; + "@(#) $Id: skxmac2.c,v 1.102 2003/10/02 16:53:58 rschmidt Exp $ (C) Marvell."; #endif #ifdef GENESIS @@ -1343,7 +1360,7 @@ int Port) /* Port Index (MAC_1 + n) */ * Description: * The XMAC of the specified 'Port' and all connected devices * (PHY and SERDES) will receive a reset signal on its *Reset pins. - * External PHYs must be reset be clearing a bit in the GPIO register + * External PHYs must be reset by clearing a bit in the GPIO register * (Timing requirements: Broadcom: 400ns, Level One: none, National: 80ns). * * ATTENTION: @@ -1386,23 +1403,62 @@ int Port) /* Port Index (MAC_1 + n) */ /* For external PHYs there must be special handling */ if (pAC->GIni.GP[Port].PhyType != SK_PHY_XMAC) { - /* reset external PHY */ + SK_IN32(IoC, B2_GP_IO, &Reg); + if (Port == 0) { - Reg |= GP_DIR_0; /* set to output */ - Reg &= ~GP_IO_0; + Reg |= GP_DIR_0; /* set to output */ + Reg &= ~GP_IO_0; /* set PHY reset (active low) */ } else { - Reg |= GP_DIR_2; /* set to output */ - Reg &= ~GP_IO_2; + Reg |= GP_DIR_2; /* set to output */ + Reg &= ~GP_IO_2; /* set PHY reset (active low) */ } + /* reset external PHY */ SK_OUT32(IoC, B2_GP_IO, Reg); /* short delay */ SK_IN32(IoC, B2_GP_IO, &Reg); } - } /* SkXmHardRst */ + + +/****************************************************************************** + * + * SkXmClearRst() - Release the PHY & XMAC reset + * + * Description: + * + * Returns: + * nothing + */ +static void SkXmClearRst( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_U32 DWord; + + /* clear HW reset */ + SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_CLR_MAC_RST); + + if (pAC->GIni.GP[Port].PhyType != SK_PHY_XMAC) { + + SK_IN32(IoC, B2_GP_IO, &DWord); + + if (Port == 0) { + DWord |= (GP_DIR_0 | GP_IO_0); /* set to output */ + } + else { + DWord |= (GP_DIR_2 | GP_IO_2); /* set to output */ + } + /* Clear PHY reset */ + SK_OUT32(IoC, B2_GP_IO, DWord); + + /* Enable GMII interface */ + XM_OUT16(IoC, Port, XM_HW_CFG, XM_HW_GMII_MD); + } +} /* SkXmClearRst */ #endif /* GENESIS */ @@ -1452,10 +1508,6 @@ int Port) /* Port Index (MAC_1 + n) */ * * Description: * - * ATTENTION: - * It is absolutely necessary to reset the SW_RST Bit first - * before calling this function. - * * Returns: * nothing */ @@ -1464,6 +1516,20 @@ SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ int Port) /* Port Index (MAC_1 + n) */ { + SK_U32 DWord; + + /* WA code for COMA mode */ + if (pAC->GIni.GIYukonLite && + pAC->GIni.GIChipRev == CHIP_REV_YU_LITE_A3) { + + SK_IN32(IoC, B2_GP_IO, &DWord); + + DWord |= (GP_DIR_9 | GP_IO_9); + + /* set PHY reset */ + SK_OUT32(IoC, B2_GP_IO, DWord); + } + /* set GPHY Control reset */ SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), GPC_RST_SET); @@ -1471,6 +1537,73 @@ int Port) /* Port Index (MAC_1 + n) */ SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_SET); } /* SkGmHardRst */ + + +/****************************************************************************** + * + * SkGmClearRst() - Release the GPHY & GMAC reset + * + * Description: + * + * Returns: + * nothing + */ +static void SkGmClearRst( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_U32 DWord; + +#ifdef XXX + /* clear GMAC Control reset */ + SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_CLR); + + /* set GMAC Control reset */ + SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_SET); +#endif /* XXX */ + + /* WA code for COMA mode */ + if (pAC->GIni.GIYukonLite && + pAC->GIni.GIChipRev == CHIP_REV_YU_LITE_A3) { + + SK_IN32(IoC, B2_GP_IO, &DWord); + + DWord |= GP_DIR_9; /* set to output */ + DWord &= ~GP_IO_9; /* clear PHY reset (active high) */ + + /* clear PHY reset */ + SK_OUT32(IoC, B2_GP_IO, DWord); + } + + /* set HWCFG_MODE */ + DWord = GPC_INT_POL_HI | GPC_DIS_FC | GPC_DIS_SLEEP | + GPC_ENA_XC | GPC_ANEG_ADV_ALL_M | GPC_ENA_PAUSE | + (pAC->GIni.GICopperType ? GPC_HWCFG_GMII_COP : + GPC_HWCFG_GMII_FIB); + + /* set GPHY Control reset */ + SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), DWord | GPC_RST_SET); + + /* release GPHY Control reset */ + SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), DWord | GPC_RST_CLR); + +#ifdef VCPU + VCpuWait(9000); +#endif /* VCPU */ + + /* clear GMAC Control reset */ + SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_PAUSE_ON | GMC_RST_CLR); + +#ifdef VCPU + VCpuWait(2000); + + SK_IN32(IoC, MR_ADDR(Port, GPHY_CTRL), &DWord); + + SK_IN32(IoC, B0_ISRC, &DWord); +#endif /* VCPU */ + +} /* SkGmClearRst */ #endif /* YUKON */ @@ -1553,6 +1686,38 @@ int Port) /* Port Index (MAC_1 + n) */ } /* SkMacHardRst */ +/****************************************************************************** + * + * SkMacClearRst() - Clear the MAC reset + * + * Description: calls a clear MAC reset routine dep. on board type + * + * Returns: + * nothing + */ +void SkMacClearRst( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + + SkXmClearRst(pAC, IoC, Port); + } +#endif /* GENESIS */ + +#ifdef YUKON + if (pAC->GIni.GIYukon) { + + SkGmClearRst(pAC, IoC, Port); + } +#endif /* YUKON */ + +} /* SkMacClearRst */ + + #ifdef GENESIS /****************************************************************************** * @@ -1574,7 +1739,6 @@ SK_IOC IoC, /* IO context */ int Port) /* Port Index (MAC_1 + n) */ { SK_GEPORT *pPrt; - SK_U32 Reg; int i; SK_U16 SWord; @@ -1594,32 +1758,10 @@ int Port) /* Port Index (MAC_1 + n) */ } if (pPrt->PState == SK_PRT_RESET) { - /* - * clear HW reset - * Note: The SW reset is self clearing, therefore there is - * nothing to do here. - */ - SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_CLR_MAC_RST); - /* Ensure that XMAC reset release is done (errata from LReinbold?) */ - SK_IN16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), &SWord); + SkXmClearRst(pAC, IoC, Port); - /* Clear PHY reset */ if (pPrt->PhyType != SK_PHY_XMAC) { - - SK_IN32(IoC, B2_GP_IO, &Reg); - - if (Port == 0) { - Reg |= (GP_DIR_0 | GP_IO_0); /* set to output */ - } - else { - Reg |= (GP_DIR_2 | GP_IO_2); /* set to output */ - } - SK_OUT32(IoC, B2_GP_IO, Reg); - - /* Enable GMII interface */ - XM_OUT16(IoC, Port, XM_HW_CFG, XM_HW_GMII_MD); - /* read Id from external PHY (all have the same address) */ SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_ID1, &pPrt->PhyId1); @@ -1831,43 +1973,11 @@ int Port) /* Port Index (MAC_1 + n) */ } if (pPrt->PState == SK_PRT_RESET) { - /* set GPHY Control reset */ - SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), GPC_RST_SET); - - /* set GMAC Control reset */ - SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_SET); - -#ifdef XXX - /* clear GMAC Control reset */ - SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_CLR); - - /* set GMAC Control reset */ - SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_SET); -#endif /* XXX */ - - /* set HWCFG_MODE */ - DWord = GPC_INT_POL_HI | GPC_DIS_FC | GPC_DIS_SLEEP | - GPC_ENA_XC | GPC_ANEG_ADV_ALL_M | GPC_ENA_PAUSE | - (pAC->GIni.GICopperType ? GPC_HWCFG_GMII_COP : - GPC_HWCFG_GMII_FIB); - - /* set GPHY Control reset */ - SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), DWord | GPC_RST_SET); - - /* release GPHY Control reset */ - SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), DWord | GPC_RST_CLR); - -#ifdef VCPU - VCpuWait(9000); -#endif /* VCPU */ - - /* clear GMAC Control reset */ - SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_PAUSE_ON | GMC_RST_CLR); - -#ifdef VCPU - VCpuWait(2000); -#endif /* VCPU */ + + SkGmHardRst(pAC, IoC, Port); + SkGmClearRst(pAC, IoC, Port); + /* Auto-negotiation ? */ if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) { /* Auto-negotiation disabled */ @@ -1906,6 +2016,7 @@ int Port) /* Port Index (MAC_1 + n) */ SWord |= GM_GPCR_DUP_FULL; } + /* flow-control settings */ switch (pPrt->PFlowCtrlMode) { case SK_FLOW_MODE_NONE: /* set Pause Off */ @@ -1940,7 +2051,7 @@ int Port) /* Port Index (MAC_1 + n) */ (void)SkGmResetCounter(pAC, IoC, Port); /* setup Transmit Control Register */ - GM_OUT16(IoC, Port, GM_TX_CTRL, GM_TXCR_COL_THR); + GM_OUT16(IoC, Port, GM_TX_CTRL, TX_COL_THR(pPrt->PMacColThres)); /* setup Receive Control Register */ GM_OUT16(IoC, Port, GM_RX_CTRL, GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA | @@ -1954,7 +2065,9 @@ int Port) /* Port Index (MAC_1 + n) */ GM_IN16(IoC, Port, GM_TX_PARAM, &SWord); #endif /* VCPU */ - SWord = (SK_U16)(JAM_LEN_VAL(3) | JAM_IPG_VAL(11) | IPG_JAM_DATA(26)); + SWord = TX_JAM_LEN_VAL(pPrt->PMacJamLen) | + TX_JAM_IPG_VAL(pPrt->PMacJamIpgVal) | + TX_IPG_JAM_DATA(pPrt->PMacJamIpgData); GM_OUT16(IoC, Port, GM_TX_PARAM, SWord); @@ -1963,7 +2076,12 @@ int Port) /* Port Index (MAC_1 + n) */ GM_IN16(IoC, Port, GM_SERIAL_MODE, &SWord); #endif /* VCPU */ - SWord = GM_SMOD_VLAN_ENA | IPG_VAL_FAST_ETH; + SWord = GM_SMOD_VLAN_ENA | IPG_DATA_VAL(pPrt->PMacIpgData); + + if (pPrt->PMacLimit4) { + /* reset of collision counter after 4 consecutive collisions */ + SWord |= GM_SMOD_LIMIT_4; + } if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) { /* enable jumbo mode (Max. Frame Length = 9018) */ @@ -2021,11 +2139,13 @@ int Port) /* Port Index (MAC_1 + n) */ GM_OUT16(IoC, Port, GM_RX_IRQ_MSK, 0); GM_OUT16(IoC, Port, GM_TR_IRQ_MSK, 0); +#if defined(SK_DIAG) || defined(DEBUG) /* read General Purpose Status */ GM_IN16(IoC, Port, GM_GP_STAT, &SWord); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, - ("MAC Stat Reg=0x%04X\n", SWord)); + ("MAC Stat Reg.=0x%04X\n", SWord)); +#endif /* SK_DIAG || DEBUG */ #ifdef SK_DIAG c_print("MAC Stat Reg=0x%04X\n", SWord); @@ -2226,6 +2346,7 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac SKERR_HWI_E015MSG); } + /* Set Flow-control capabilities */ switch (pPrt->PFlowCtrlMode) { case SK_FLOW_MODE_NONE: Ctrl |= PHY_X_P_NO_PAUSE; @@ -2306,7 +2427,9 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("InitPhyBcom: no auto-negotiation Port %d\n", Port)); /* Set DuplexMode in Config register */ - Ctrl1 |= (pPrt->PLinkMode == SK_LMODE_FULL ? PHY_CT_DUP_MD : 0); + if (pPrt->PLinkMode == SK_LMODE_FULL) { + Ctrl1 |= PHY_CT_DUP_MD; + } /* Determine Master/Slave manually if not already done */ if (pPrt->PMSMode == SK_MS_MODE_AUTO) { @@ -2346,6 +2469,7 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac SKERR_HWI_E015MSG); } + /* Set Flow-control capabilities */ switch (pPrt->PFlowCtrlMode) { case SK_FLOW_MODE_NONE: Ctrl3 |= PHY_B_P_NO_PAUSE; @@ -2375,12 +2499,12 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac /* Write 1000Base-T Control Register */ SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_1000T_CTRL, Ctrl2); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, - ("1000B-T Ctrl Reg=0x%04X\n", Ctrl2)); + ("Set 1000B-T Ctrl Reg=0x%04X\n", Ctrl2)); /* Write AutoNeg Advertisement Register */ SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUNE_ADV, Ctrl3); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, - ("Auto-Neg.Adv.Reg=0x%04X\n", Ctrl3)); + ("Set Auto-Neg.Adv.Reg=0x%04X\n", Ctrl3)); if (DoLoop) { /* Set the Phy Loopback bit, too */ @@ -2409,6 +2533,281 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac #ifdef YUKON +#ifndef SK_SLIM +/****************************************************************************** + * + * SkGmEnterLowPowerMode() + * + * Description: + * This function sets the Marvell Alaska PHY to the low power mode + * given by parameter mode. + * The following low power modes are available: + * + * - Coma Mode (Deep Sleep): + * Power consumption: ~15 - 30 mW + * The PHY cannot wake up on its own. + * + * - IEEE 22.2.4.1.5 compatible power down mode + * Power consumption: ~240 mW + * The PHY cannot wake up on its own. + * + * - energy detect mode + * Power consumption: ~160 mW + * The PHY can wake up on its own by detecting activity + * on the CAT 5 cable. + * + * - energy detect plus mode + * Power consumption: ~150 mW + * The PHY can wake up on its own by detecting activity + * on the CAT 5 cable. + * Connected devices can be woken up by sending normal link + * pulses every one second. + * + * Note: + * + * Returns: + * 0: ok + * 1: error + */ +int SkGmEnterLowPowerMode( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port, /* Port Index (e.g. MAC_1) */ +SK_U8 Mode) /* low power mode */ +{ + SK_U16 Word; + SK_U32 DWord; + SK_U8 LastMode; + int Ret = 0; + + if (pAC->GIni.GIYukonLite && + pAC->GIni.GIChipRev == CHIP_REV_YU_LITE_A3) { + + /* save current power mode */ + LastMode = pAC->GIni.GP[Port].PPhyPowerState; + pAC->GIni.GP[Port].PPhyPowerState = Mode; + + switch (Mode) { + /* coma mode (deep sleep) */ + case PHY_PM_DEEP_SLEEP: + /* setup General Purpose Control Register */ + GM_OUT16(IoC, 0, GM_GP_CTRL, GM_GPCR_FL_PASS | + GM_GPCR_SPEED_100 | GM_GPCR_AU_ALL_DIS); + + /* apply COMA mode workaround */ + SkGmPhyWrite(pAC, IoC, Port, 29, 0x001f); + SkGmPhyWrite(pAC, IoC, Port, 30, 0xfff3); + + SK_IN32(IoC, PCI_C(PCI_OUR_REG_1), &DWord); + + SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON); + + /* Set PHY to Coma Mode */ + SK_OUT32(IoC, PCI_C(PCI_OUR_REG_1), DWord | PCI_PHY_COMA); + + SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF); + + break; + + /* IEEE 22.2.4.1.5 compatible power down mode */ + case PHY_PM_IEEE_POWER_DOWN: + /* + * - disable MAC 125 MHz clock + * - allow MAC power down + */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word); + Word |= PHY_M_PC_DIS_125CLK; + Word &= ~PHY_M_PC_MAC_POW_UP; + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word); + + /* + * register changes must be followed by a software + * reset to take effect + */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &Word); + Word |= PHY_CT_RESET; + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, Word); + + /* switch IEEE compatible power down mode on */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &Word); + Word |= PHY_CT_PDOWN; + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, Word); + break; + + /* energy detect and energy detect plus mode */ + case PHY_PM_ENERGY_DETECT: + case PHY_PM_ENERGY_DETECT_PLUS: + /* + * - disable MAC 125 MHz clock + */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word); + Word |= PHY_M_PC_DIS_125CLK; + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word); + + /* activate energy detect mode 1 */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word); + + /* energy detect mode */ + if (Mode == PHY_PM_ENERGY_DETECT) { + Word |= PHY_M_PC_EN_DET; + } + /* energy detect plus mode */ + else { + Word |= PHY_M_PC_EN_DET_PLUS; + } + + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word); + + /* + * reinitialize the PHY to force a software reset + * which is necessary after the register settings + * for the energy detect modes. + * Furthermore reinitialisation prevents that the + * PHY is running out of a stable state. + */ + SkGmInitPhyMarv(pAC, IoC, Port, SK_FALSE); + break; + + /* don't change current power mode */ + default: + pAC->GIni.GP[Port].PPhyPowerState = LastMode; + Ret = 1; + break; + } + } + /* low power modes are not supported by this chip */ + else { + Ret = 1; + } + + return(Ret); + +} /* SkGmEnterLowPowerMode */ + +/****************************************************************************** + * + * SkGmLeaveLowPowerMode() + * + * Description: + * Leave the current low power mode and switch to normal mode + * + * Note: + * + * Returns: + * 0: ok + * 1: error + */ +int SkGmLeaveLowPowerMode( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (e.g. MAC_1) */ +{ + SK_U32 DWord; + SK_U16 Word; + SK_U8 LastMode; + int Ret = 0; + + if (pAC->GIni.GIYukonLite && + pAC->GIni.GIChipRev == CHIP_REV_YU_LITE_A3) { + + /* save current power mode */ + LastMode = pAC->GIni.GP[Port].PPhyPowerState; + pAC->GIni.GP[Port].PPhyPowerState = PHY_PM_OPERATIONAL_MODE; + + switch (LastMode) { + /* coma mode (deep sleep) */ + case PHY_PM_DEEP_SLEEP: + SK_IN32(IoC, PCI_C(PCI_OUR_REG_1), &DWord); + + SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON); + + /* Release PHY from Coma Mode */ + SK_OUT32(IoC, PCI_C(PCI_OUR_REG_1), DWord & ~PCI_PHY_COMA); + + SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF); + + SK_IN32(IoC, B2_GP_IO, &DWord); + + /* set to output */ + DWord |= (GP_DIR_9 | GP_IO_9); + + /* set PHY reset */ + SK_OUT32(IoC, B2_GP_IO, DWord); + + DWord &= ~GP_IO_9; /* clear PHY reset (active high) */ + + /* clear PHY reset */ + SK_OUT32(IoC, B2_GP_IO, DWord); + break; + + /* IEEE 22.2.4.1.5 compatible power down mode */ + case PHY_PM_IEEE_POWER_DOWN: + /* + * - enable MAC 125 MHz clock + * - set MAC power up + */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word); + Word &= ~PHY_M_PC_DIS_125CLK; + Word |= PHY_M_PC_MAC_POW_UP; + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word); + + /* + * register changes must be followed by a software + * reset to take effect + */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &Word); + Word |= PHY_CT_RESET; + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, Word); + + /* switch IEEE compatible power down mode off */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &Word); + Word &= ~PHY_CT_PDOWN; + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, Word); + break; + + /* energy detect and energy detect plus mode */ + case PHY_PM_ENERGY_DETECT: + case PHY_PM_ENERGY_DETECT_PLUS: + /* + * - enable MAC 125 MHz clock + */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word); + Word &= ~PHY_M_PC_DIS_125CLK; + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word); + + /* disable energy detect mode */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word); + Word &= ~PHY_M_PC_EN_DET_MSK; + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word); + + /* + * reinitialize the PHY to force a software reset + * which is necessary after the register settings + * for the energy detect modes. + * Furthermore reinitialisation prevents that the + * PHY is running out of a stable state. + */ + SkGmInitPhyMarv(pAC, IoC, Port, SK_FALSE); + break; + + /* don't change current power mode */ + default: + pAC->GIni.GP[Port].PPhyPowerState = LastMode; + Ret = 1; + break; + } + } + /* low power modes are not supported by this chip */ + else { + Ret = 1; + } + + return(Ret); + +} /* SkGmLeaveLowPowerMode */ +#endif /* !SK_SLIM */ + + /****************************************************************************** * * SkGmInitPhyMarv() - Initialize the Marvell Phy registers @@ -2457,7 +2856,6 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac VCPUprintf(0, "SkGmInitPhyMarv(), Port=%u, DoLoop=%u\n", Port, DoLoop); #else /* VCPU */ - if (DoLoop) { /* Set 'MAC Power up'-bit, set Manual MDI configuration */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, @@ -2475,16 +2873,20 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_CTRL, ExtPhyCtrl); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, - ("Ext. PHY Ctrl=0x%04X\n", ExtPhyCtrl)); + ("Set Ext. PHY Ctrl=0x%04X\n", ExtPhyCtrl)); } /* Read PHY Control */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &PhyCtrl); + if (!AutoNeg) { + /* Disable Auto-negotiation */ + PhyCtrl &= ~PHY_CT_ANE; + } + PhyCtrl |= PHY_CT_RESET; /* Assert software reset */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, PhyCtrl); - #endif /* VCPU */ PhyCtrl = 0 /* PHY_CT_COL_TST */; @@ -2533,13 +2935,9 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac if (!DoLoop) { PhyCtrl |= PHY_CT_RESET; } - /* - * Do NOT enable Auto-negotiation here. This would hold - * the link down because no IDLES are transmitted - */ } else { - PhyCtrl |= PHY_CT_ANE; + /* Set Auto-negotiation advertisement */ if (pAC->GIni.GICopperType) { /* Set Speed capabilities */ @@ -2554,6 +2952,7 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac break; case SK_LSPEED_100MBPS: AutoNegAdv |= PHY_M_AN_100_FD | PHY_M_AN_100_HD | + /* advertise 10Base-T also */ PHY_M_AN_10_FD | PHY_M_AN_10_HD; break; case SK_LSPEED_10MBPS: @@ -2581,7 +2980,7 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac SKERR_HWI_E015MSG); } - /* Set Auto-negotiation advertisement */ + /* Set Flow-control capabilities */ switch (pPrt->PFlowCtrlMode) { case SK_FLOW_MODE_NONE: AutoNegAdv |= PHY_B_P_NO_PAUSE; @@ -2618,7 +3017,7 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac SKERR_HWI_E015MSG); } - /* Set Auto-negotiation advertisement */ + /* Set Flow-control capabilities */ switch (pPrt->PFlowCtrlMode) { case SK_FLOW_MODE_NONE: AutoNegAdv |= PHY_M_P_NO_PAUSE_X; @@ -2640,7 +3039,7 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac if (!DoLoop) { /* Restart Auto-negotiation */ - PhyCtrl |= PHY_CT_RE_CFG; + PhyCtrl |= PHY_CT_ANE | PHY_CT_RE_CFG; } } @@ -2659,12 +3058,12 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac /* Write 1000Base-T Control Register */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_1000T_CTRL, C1000BaseT); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, - ("1000B-T Ctrl=0x%04X\n", C1000BaseT)); + ("Set 1000B-T Ctrl =0x%04X\n", C1000BaseT)); /* Write AutoNeg Advertisement Register */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_AUNE_ADV, AutoNegAdv); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, - ("Auto-Neg.Ad.=0x%04X\n", AutoNegAdv)); + ("Set Auto-Neg.Adv.=0x%04X\n", AutoNegAdv)); #endif /* VCPU */ if (DoLoop) { @@ -2694,6 +3093,8 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac /* Write to the PHY Control register */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, PhyCtrl); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Set PHY Ctrl Reg.=0x%04X\n", PhyCtrl)); #ifdef VCPU VCpuWait(2000); @@ -2712,7 +3113,7 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_LED_CTRL, LedCtrl); if ((pAC->GIni.GILedBlinkCtrl & SK_LED_LINK100_ON) != 0) { - /* only in forced 100Mbps mode */ + /* only in forced 100 Mbps mode */ if (!AutoNeg && pPrt->PLinkSpeed == SK_LSPEED_100MBPS) { SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_LED_OVER, @@ -2741,7 +3142,7 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac /* Read AutoNeg Advertisement Register */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_ADV, &AutoNegAdv); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, - ("Auto-Neg. Ad.=0x%04X\n", AutoNegAdv)); + ("Auto-Neg.Adv.=0x%04X\n", AutoNegAdv)); /* Read Ext. PHY Specific Control */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_EXT_CTRL, &ExtPhyCtrl); @@ -2818,13 +3219,15 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac /* Auto-negotiation ? */ if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) { /* - * level one spec say: "1000Mbps: manual mode not allowed" + * level one spec say: "1000 Mbps: manual mode not allowed" * but lets see what happens... */ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("InitPhyLone: no auto-negotiation Port %d\n", Port)); /* Set DuplexMode in Config register */ - Ctrl1 = (pPrt->PLinkMode == SK_LMODE_FULL ? PHY_CT_DUP_MD : 0); + if (pPrt->PLinkMode == SK_LMODE_FULL) { + Ctrl1 |= PHY_CT_DUP_MD; + } /* Determine Master/Slave manually if not already done */ if (pPrt->PMSMode == SK_MS_MODE_AUTO) { @@ -2857,6 +3260,7 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac SKERR_HWI_E015MSG); } + /* Set Flow-control capabilities */ switch (pPrt->PFlowCtrlMode) { case SK_FLOW_MODE_NONE: Ctrl3 |= PHY_L_P_NO_PAUSE; @@ -2877,7 +3281,6 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac /* Restart Auto-negotiation */ Ctrl1 = PHY_CT_ANE | PHY_CT_RE_CFG; - } /* Write 1000Base-T Control Register */ @@ -3019,10 +3422,10 @@ int Port) /* Port Index (MAC_1 + n) */ /* Check Duplex mismatch */ if ((ResAb & (PHY_X_RS_HD | PHY_X_RS_FD)) == PHY_X_RS_FD) { - pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL; + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL; } else if ((ResAb & (PHY_X_RS_HD | PHY_X_RS_FD)) == PHY_X_RS_HD) { - pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF; + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF; } else { /* Error */ @@ -3055,7 +3458,7 @@ int Port) /* Port Index (MAC_1 + n) */ /* PAUSE mismatch -> no PAUSE */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE; } - pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_1000MBPS; + pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS; return(SK_AND_OK); } /* SkXmAutoNegDoneXmac */ @@ -3110,10 +3513,10 @@ int Port) /* Port Index (MAC_1 + n) */ /* Check Duplex mismatch */ if ((AuxStat & PHY_B_AS_AN_RES_MSK) == PHY_B_RES_1000FD) { - pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL; + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL; } else if ((AuxStat & PHY_B_AS_AN_RES_MSK) == PHY_B_RES_1000HD) { - pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF; + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF; } else { /* Error */ @@ -3156,7 +3559,7 @@ int Port) /* Port Index (MAC_1 + n) */ /* PAUSE mismatch -> no PAUSE */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE; } - pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_1000MBPS; + pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS; return(SK_AND_OK); } /* SkXmAutoNegDoneBcom */ @@ -3192,6 +3595,8 @@ int Port) /* Port Index (MAC_1 + n) */ /* Get PHY parameters */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_LP, &LPAb); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Link P.Abil.=0x%04X\n", LPAb)); if ((LPAb & PHY_M_AN_RF) != 0) { SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, @@ -3222,15 +3627,15 @@ int Port) /* Port Index (MAC_1 + n) */ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("AutoNegFail: Speed & Duplex not resolved, Port %d\n", Port)); pPrt->PAutoNegFail = SK_TRUE; - pPrt->PLinkModeStatus = SK_LMODE_STAT_UNKNOWN; + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_UNKNOWN; return(SK_AND_DUP_CAP); } if ((AuxStat & PHY_M_PS_FULL_DUP) != 0) { - pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL; + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL; } else { - pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF; + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF; } /* Check PAUSE mismatch ??? */ @@ -3255,13 +3660,13 @@ int Port) /* Port Index (MAC_1 + n) */ /* set used link speed */ switch ((unsigned)(AuxStat & PHY_M_PS_SPEED_MSK)) { case (unsigned)PHY_M_PS_SPEED_1000: - pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_1000MBPS; + pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS; break; case PHY_M_PS_SPEED_100: - pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_100MBPS; + pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_100MBPS; break; default: - pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_10MBPS; + pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_10MBPS; } return(SK_AND_OK); @@ -3312,10 +3717,10 @@ int Port) /* Port Index (MAC_1 + n) */ /* Check Duplex mismatch */ if ((QuickStat & PHY_L_QS_DUP_MOD) != 0) { - pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL; + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL; } else { - pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF; + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF; } /* Check Master/Slave resolution */ @@ -3338,6 +3743,7 @@ int Port) /* Port Index (MAC_1 + n) */ /* We are using IEEE 802.3z/D5.0 Table 37-4 */ /* we must manually resolve the abilities here */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE; + switch (pPrt->PFlowCtrlMode) { case SK_FLOW_MODE_NONE: /* default */ @@ -3457,6 +3863,9 @@ int Port) /* Port Index (MAC_1 + n) */ return(Rtv); } + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("AutoNeg done Port %d\n", Port)); + /* We checked everything and may now enable the link */ pPrt->PAutoNegFail = SK_FALSE; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk_g16.c 830-ivtv/drivers/net/sk_g16.c --- 000-virgin/drivers/net/sk_g16.c Tue Sep 2 09:55:47 2003 +++ 830-ivtv/drivers/net/sk_g16.c Thu Jan 8 08:54:25 2004 @@ -457,8 +457,6 @@ struct priv /* static variables */ static SK_RAM *board; /* pointer to our memory mapped board components */ -static struct net_device *SK_dev; -unsigned long SK_ioaddr; static spinlock_t SK_lock = SPIN_LOCK_UNLOCKED; /* Macros */ @@ -472,7 +470,6 @@ static spinlock_t SK_lock = SPIN_LOCK_UN * See for short explanation of each function its definitions header. */ -int SK_init(struct net_device *dev); static int SK_probe(struct net_device *dev, short ioaddr); static void SK_timeout(struct net_device *dev); @@ -530,84 +527,71 @@ void SK_print_ram(struct net_device *dev * YY/MM/DD uid Description -*/ +static int io; /* 0 == probe */ + /* * Check for a network adaptor of this type, and return '0' if one exists. * If dev->base_addr == 0, probe all likely locations. * If dev->base_addr == 1, always return failure. */ -int __init SK_init(struct net_device *dev) +struct net_device * __init SK_init(int unit) { - int ioaddr; /* I/O port address used for POS regs */ int *port, ports[] = SK_IO_PORTS; /* SK_G16 supported ports */ static unsigned version_printed; + struct net_device *dev = alloc_etherdev(sizeof(struct priv)); + int err = -ENODEV; - /* get preconfigured base_addr from dev which is done in Space.c */ - int base_addr = dev->base_addr; + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + } if (version_printed++ == 0) PRINTK(("%s: %s", SK_NAME, rcsid)); - if (base_addr > 0x0ff) /* Check a single specified address */ - { - int rc = -ENODEV; - - ioaddr = base_addr; + if (io > 0xff) { /* Check a single specified address */ + err = -EBUSY; + /* Check if on specified address is a SK_G16 */ + if (request_region(io, ETHERCARD_TOTAL_SIZE, "sk_g16")) { + err = SK_probe(dev, io); + if (!err) + goto got_it; + release_region(io, ETHERCARD_TOTAL_SIZE); + } + } else if (io > 0) { /* Don't probe at all */ + err = -ENXIO; + } else { + /* Autoprobe base_addr */ + for (port = &ports[0]; *port; port++) { + io = *port; + + /* Check if I/O Port region is used by another board */ + if (!request_region(io, ETHERCARD_TOTAL_SIZE, "sk_g16")) + continue; /* Try next Port address */ + + /* Check if at ioaddr is a SK_G16 */ + if (SK_probe(dev, io) == 0) + goto got_it; - /* Check if on specified address is a SK_G16 */ - if (!request_region(ioaddr, ETHERCARD_TOTAL_SIZE, "sk_g16")) - return -EBUSY; - - if ( (inb(SK_POS0) == SK_IDLOW) || - (inb(SK_POS1) == SK_IDHIGH) ) - { - rc = SK_probe(dev, ioaddr); - } - - if (rc) - release_region(ioaddr, ETHERCARD_TOTAL_SIZE); - return rc; - } - else if (base_addr > 0) /* Don't probe at all */ - { - return -ENXIO; + release_region(io, ETHERCARD_TOTAL_SIZE); + } } - - /* Autoprobe base_addr */ - - for (port = &ports[0]; *port; port++) - { - ioaddr = *port; /* we need ioaddr for accessing POS regs */ - - /* Check if I/O Port region is used by another board */ - - if (!request_region(ioaddr, ETHERCARD_TOTAL_SIZE, "sk_g16")) - { - continue; /* Try next Port address */ - } - - /* Check if at ioaddr is a SK_G16 */ - - if ( !(inb(SK_POS0) == SK_IDLOW) || - !(inb(SK_POS1) == SK_IDHIGH) ) - { - release_region(ioaddr, ETHERCARD_TOTAL_SIZE); - continue; /* Try next Port address */ - } - - dev->base_addr = ioaddr; /* Set I/O Port Address */ - - if (SK_probe(dev, ioaddr) == 0) - { - return 0; /* Card found and initialized */ - } - - release_region(ioaddr, ETHERCARD_TOTAL_SIZE); +err_out: + free_netdev(dev); + return ERR_PTR(err); + +got_it: + err = register_netdev(dev); + if (err) { + release_region(dev->base_addr, ETHERCARD_TOTAL_SIZE); + goto err_out; } - - dev->base_addr = base_addr; /* Write back original base_addr */ - - return -ENODEV; /* Failed to find or init driver */ + return dev; } /* End of SK_init */ @@ -620,54 +604,25 @@ MODULE_PARM_DESC(io, "0 to probe common #ifdef MODULE -static int io; /* 0 == probe */ + +static struct net_device *SK_dev; static int __init SK_init_module (void) { - int rc; - - SK_dev = init_etherdev (NULL, 0); - if (!SK_dev) - return -ENOMEM; - - SK_dev->base_addr = io; - - rc = SK_init (SK_dev); - if (rc) { - unregister_netdev (SK_dev); - kfree (SK_dev); - SK_dev = NULL; - } - - return rc; + SK_dev = SK_init(-1); + return IS_ERR(SK_dev) ? PTR_ERR(SK_dev) : 0; } -#endif /* MODULE */ - static void __exit SK_cleanup_module (void) { - if (SK_dev) { - if (SK_dev->priv) { - kfree(SK_dev->priv); - SK_dev->priv = NULL; - } - unregister_netdev(SK_dev); - free_netdev(SK_dev); - SK_dev = NULL; - } - if (SK_ioaddr) { - release_region(SK_ioaddr, ETHERCARD_TOTAL_SIZE); - SK_ioaddr = 0; - } - + unregister_netdev(SK_dev); + release_region(SK_dev->base_addr, ETHERCARD_TOTAL_SIZE); + free_netdev(SK_dev); } - -#ifdef MODULE module_init(SK_init_module); -#endif module_exit(SK_cleanup_module); - +#endif /*- @@ -695,7 +650,11 @@ int __init SK_probe(struct net_device *d int sk_addr_flag = 0; /* SK ADDR correct? 1 - no, 0 - yes */ unsigned int rom_addr; /* used to store RAM address used for POS_ADDR */ - struct priv *p; /* SK_G16 private structure */ + struct priv *p = dev->priv; /* SK_G16 private structure */ + + if (inb(SK_POS0) != SK_IDLOW || inb(SK_POS1) != SK_IDHIGH) + return -ENODEV; + dev->base_addr = ioaddr; if (SK_ADDR & 0x3fff || SK_ADDR < 0xa0000) { @@ -837,12 +796,6 @@ int __init SK_probe(struct net_device *d dev->dev_addr[4], dev->dev_addr[5]); - /* Allocate memory for private structure */ - p = dev->priv = (void *) kmalloc(sizeof(struct priv), GFP_KERNEL); - if (p == NULL) { - printk("%s: ERROR - no memory for driver data!\n", dev->name); - return -ENOMEM; - } memset((char *) dev->priv, 0, sizeof(struct priv)); /* clear memory */ /* Assign our Device Driver functions */ @@ -856,10 +809,6 @@ int __init SK_probe(struct net_device *d dev->watchdog_timeo = HZ/7; - /* Set the generic fields of the device structure */ - - ether_setup(dev); - dev->flags &= ~IFF_MULTICAST; /* Initialize private structure */ @@ -884,12 +833,7 @@ int __init SK_probe(struct net_device *d SK_print_pos(dev, "End of SK_probe"); SK_print_ram(dev); #endif - - SK_dev = dev; - SK_ioaddr = ioaddr; - return 0; /* Initialization done */ - } /* End of SK_probe() */ @@ -1280,7 +1224,7 @@ static int SK_send_packet(struct sk_buff memcpy_toio((tmdp->u.buffer & 0x00ffffff), skb->data, skb->len); if (len != skb->len) - memcpy_toio((tmdp->u.buffer & 0x00ffffff) + sb->len, pad, len-skb->len); + memcpy_toio((tmdp->u.buffer & 0x00ffffff) + skb->len, pad, len-skb->len); writew(-len, &tmdp->blen); /* set length to transmit */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk_mca.c 830-ivtv/drivers/net/sk_mca.c --- 000-virgin/drivers/net/sk_mca.c Mon Nov 17 18:29:30 2003 +++ 830-ivtv/drivers/net/sk_mca.c Thu Jan 8 08:54:25 2004 @@ -1022,18 +1022,39 @@ static void skmca_set_multicast_list(str static int startslot; /* counts through slots when probing multiple devices */ -int __init skmca_probe(struct net_device *dev) +static void cleanup_card(struct net_device *dev) { + skmca_priv *priv = dev->priv; + DeinitBoard(dev); + if (dev->irq != 0) + free_irq(dev->irq, dev); + mca_mark_as_unused(priv->slot); + mca_set_adapter_procfn(priv->slot, NULL, NULL); +} + +struct net_device * __init skmca_probe(int unit) +{ + struct net_device *dev; int force_detect = 0; int junior, slot, i; int base = 0, irq = 0; skmca_priv *priv; skmca_medium medium; + int err; /* can't work without an MCA bus ;-) */ if (MCA_bus == 0) - return -ENODEV; + return ERR_PTR(-ENODEV); + + dev = alloc_etherdev(sizeof(skmca_priv)); + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } SET_MODULE_OWNER(dev); @@ -1044,37 +1065,24 @@ int __init skmca_probe(struct net_device /* search through slots */ - if (dev != NULL) { - base = dev->mem_start; - irq = dev->irq; - } - slot = dofind(&junior, startslot); - - while (slot != -1) { + base = dev->mem_start; + irq = dev->base_addr; + for (slot = startslot; (slot = dofind(&junior, slot)) != -1; slot++) { /* deduce card addresses */ getaddrs(slot, junior, &base, &irq, &medium); /* slot already in use ? */ - if (mca_is_adapter_used(slot)) { - slot = dofind(&junior, slot + 1); + if (mca_is_adapter_used(slot)) continue; - } /* were we looking for something different ? */ - if ((dev->irq != 0) || (dev->mem_start != 0)) { - if ((dev->irq != 0) && (dev->irq != irq)) { - slot = dofind(&junior, slot + 1); - continue; - } - if ((dev->mem_start != 0) - && (dev->mem_start != base)) { - slot = dofind(&junior, slot + 1); - continue; - } - } + if (dev->irq && dev->irq != irq) + continue; + if (dev->mem_start && dev->mem_start != base) + continue; /* found something that matches */ @@ -1083,8 +1091,10 @@ int __init skmca_probe(struct net_device /* nothing found ? */ - if (slot == -1) - return ((base != 0) || (irq != 0)) ? ENXIO : ENODEV; + if (slot == -1) { + free_netdev(dev); + return (base || irq) ? ERR_PTR(-ENXIO) : ERR_PTR(-ENODEV); + } /* make procfs entries */ @@ -1102,17 +1112,14 @@ int __init skmca_probe(struct net_device junior ? "Junior MC2" : "MC2+", slot + 1); /* allocate structure */ - priv = dev->priv = - (skmca_priv *) kmalloc(sizeof(skmca_priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; + priv = dev->priv; priv->slot = slot; priv->macbase = base + 0x3fc0; priv->ioregaddr = base + 0x3ff0; priv->ctrladdr = base + 0x3ff2; priv->cmdaddr = base + 0x3ff3; priv->medium = medium; - memset(&(priv->stat), 0, sizeof(struct net_device_stats)); + memset(&priv->stat, 0, sizeof(struct net_device_stats)); spin_lock_init(&priv->lock); /* set base + irq for this device (irq not allocated so far) */ @@ -1146,9 +1153,6 @@ int __init skmca_probe(struct net_device dev->set_multicast_list = skmca_set_multicast_list; dev->flags |= IFF_MULTICAST; - /* generic setup */ - ether_setup(dev); - /* copy out MAC address */ for (i = 0; i < 6; i++) dev->dev_addr[i] = SKMCA_READB(priv->macbase + (i << 1)); @@ -1167,7 +1171,13 @@ int __init skmca_probe(struct net_device startslot = slot + 1; - return 0; + err = register_netdev(dev); + if (err) { + cleanup_card(dev); + free_netdev(dev); + dev = ERR_PTR(err); + } + return dev; } /* ------------------------------------------------------------------------ @@ -1179,51 +1189,34 @@ MODULE_LICENSE("GPL"); #define DEVMAX 5 -static struct net_device moddevs[DEVMAX] = { - { .name = " ", .init = skmca_probe }, - { .name = " ", .init = skmca_probe }, - { .name = " ", .init = skmca_probe }, - { .name = " ", .init = skmca_probe }, - { .name = " ", .init = skmca_probe } -}; - -int irq; -int io; +static struct net_device *moddevs[DEVMAX]; int init_module(void) { - int z, res; + int z; startslot = 0; for (z = 0; z < DEVMAX; z++) { - strcpy(moddevs[z].name, " "); - res = register_netdev(moddevs + z); - if (res != 0) - return (z > 0) ? 0 : -EIO; + struct net_device *dev = skmca_probe(-1); + if (IS_ERR(dev)) + break; + moddevs[z] = dev; } - + if (!z) + return -EIO; return 0; } void cleanup_module(void) { - struct net_device *dev; - skmca_priv *priv; int z; for (z = 0; z < DEVMAX; z++) { - dev = moddevs + z; - if (dev->priv != NULL) { - priv = (skmca_priv *) dev->priv; - DeinitBoard(dev); - if (dev->irq != 0) - free_irq(dev->irq, dev); - dev->irq = 0; + struct net_device *dev = moddevs[z]; + if (dev) { unregister_netdev(dev); - mca_mark_as_unused(priv->slot); - mca_set_adapter_procfn(priv->slot, NULL, NULL); - kfree(dev->priv); - dev->priv = NULL; + cleanup_card(dev); + free_netdev(dev); } } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sk_mca.h 830-ivtv/drivers/net/sk_mca.h --- 000-virgin/drivers/net/sk_mca.h Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/sk_mca.h Thu Jan 8 08:54:25 2004 @@ -178,7 +178,4 @@ typedef struct { /* LANCE Rx descriptor #endif /* _SK_MCA_DRIVER_ */ -extern int skmca_probe(struct net_device *); - - #endif /* _SK_MCA_INCLUDE_ */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/skfp/skfddi.c 830-ivtv/drivers/net/skfp/skfddi.c --- 000-virgin/drivers/net/skfp/skfddi.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/skfp/skfddi.c Thu Jan 8 08:54:25 2004 @@ -39,12 +39,6 @@ * are skfddi.c, h/types.h, h/osdef1st.h, h/targetos.h. * The others belong to the SysKonnect FDDI Hardware Module and * should better not be changed. - * NOTE: - * Compiling this driver produces some warnings, but I did not fix - * this, because the Hardware Module source is used for different - * drivers, and fixing it for Linux might bring problems on other - * projects. To keep the source common for all those drivers (and - * thus simplify fixes to it), please do not clean it up! * * Modification History: * Date Name Description @@ -58,6 +52,7 @@ * 07-May-00 DM 64 bit fixes, new dma interface * 31-Jul-03 DB Audit copy_*_user in skfp_ioctl * Daniele Bellucci + * 03-Dec-03 SH Convert to PCI device model * * Compilation options (-Dxxx): * DRIVERDEBUG print lots of messages to log file @@ -70,7 +65,7 @@ /* Version information string - should be updated prior to */ /* each new release!!! */ -#define VERSION "2.06" +#define VERSION "2.07" static const char *boot_msg = "SysKonnect FDDI PCI Adapter driver v" VERSION " for\n" @@ -80,15 +75,11 @@ static const char *boot_msg = #include #include -#include -#include #include #include #include #include #include -#include -#include // isdigit #include #include #include @@ -106,17 +97,7 @@ static const char *boot_msg = #include "h/smtstate.h" -// Define global routines -int skfp_probe(struct net_device *dev); - - // Define module-wide (static) routines -static struct net_device *alloc_device(struct net_device *dev, u_long iobase); -static struct net_device *insert_device(struct net_device *dev, - int (*init) (struct net_device *)); -static int fddi_dev_index(unsigned char *s); -static void init_dev(struct net_device *dev, u_long iobase); -static void link_modules(struct net_device *dev, struct net_device *tmp); static int skfp_driver_init(struct net_device *dev); static int skfp_open(struct net_device *dev); static int skfp_close(struct net_device *dev); @@ -193,15 +174,6 @@ MODULE_AUTHOR("Mirko Lindner priv)->os)) /* - * ============== - * = skfp_probe = - * ============== + * ================= + * = skfp_init_one = + * ================= * * Overview: * Probes for supported FDDI PCI controllers @@ -223,30 +195,11 @@ static int loading_module; * Condition code * * Arguments: - * dev - pointer to device information + * pdev - pointer to PCI device information * * Functional Description: - * This routine is called by the OS for each FDDI device name (fddi0, - * fddi1,...,fddi6, fddi7) specified in drivers/net/Space.c. - * If loaded as a module, it will detect and initialize all - * adapters the first time it is called. - * - * Let's say that skfp_probe() is getting called to initialize fddi0. - * Furthermore, let's say there are three supported controllers in the - * system. Before skfp_probe() leaves, devices fddi0, fddi1, and fddi2 - * will be initialized and a global flag will be set to indicate that - * skfp_probe() has already been called. - * - * However...the OS doesn't know that we've already initialized - * devices fddi1 and fddi2 so skfp_probe() gets called again and again - * until it reaches the end of the device list for FDDI (presently, - * fddi7). It's important that the driver "pretend" to probe for - * devices fddi1 and fddi2 and return success. Devices fddi3 - * through fddi7 will return failure since they weren't initialized. - * - * This algorithm seems to work for the time being. As other FDDI - * drivers are written for Linux, a more generic approach (perhaps - * similar to the Ethernet card approach) may need to be implemented. + * This is now called by PCI driver registration process + * for each board found. * * Return Codes: * 0 - This device (fddi0, fddi1, etc) configured successfully @@ -259,374 +212,176 @@ static int loading_module; * initialized and the board resources are read and stored in * the device structure. */ -int skfp_probe(struct net_device *dev) +static int skfp_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) { - int i; /* used in for loops */ - struct pci_dev *pdev = NULL; /* PCI device structure */ -#ifndef MEM_MAPPED_IO - u16 port; /* temporary I/O (port) address */ - int port_len; /* length of port address range (in bytes) */ -#else - unsigned long port; -#endif - u16 command; /* PCI Configuration space Command register val */ + struct net_device *dev; struct s_smc *smc; /* board pointer */ - struct net_device *tmp = dev; - u8 first_dev_used = 0; - u16 SubSysId; + u32 port, len; + int err; - PRINTK(KERN_INFO "entering skfp_probe\n"); - - /* - * Verify whether we're going through skfp_probe() again - * - * If so, see if we're going through for a subsequent fddi device that - * we've already initialized. If we are, return success (0). If not, - * return failure (-ENODEV). - */ - - if (autoprobed) { - PRINTK(KERN_INFO "Already entered skfp_probe\n"); - if (dev != NULL) { - if ((strncmp(dev->name, "fddi", 4) == 0) && - (dev->base_addr != 0)) { - return (0); - } - return (-ENODEV); - } - } - autoprobed = 1; /* set global flag */ + PRINTK(KERN_INFO "entering skfp_init_one\n"); - printk("%s\n", boot_msg); + if (num_boards == 0) + printk("%s\n", boot_msg); - /* Scan for Syskonnect FDDI PCI controllers */ - for (i = 0; i < SKFP_MAX_NUM_BOARDS; i++) { // scan for PCI cards - PRINTK(KERN_INFO "Check device %d\n", i); - if ((pdev=pci_find_device(PCI_VENDOR_ID_SK, PCI_DEVICE_ID_SK_FP, - pdev)) == 0) { - break; - } - if (pci_enable_device(pdev)) - continue; + err = pci_enable_device(pdev); + if (err) + goto err_out1; -#ifndef MEM_MAPPED_IO - /* Verify that I/O enable bit is set (PCI slot is enabled) */ - pci_read_config_word(pdev, PCI_COMMAND, &command); - if ((command & PCI_COMMAND_IO) == 0) { - PRINTK("I/O enable bit not set!"); - PRINTK(" Verify that slot is enabled\n"); - continue; - } - /* Turn off memory mapped space and enable mastering */ +#ifdef MEM_MAPPED_IO + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { + printk(KERN_ERR "skfp: region is not an MMIO resource\n"); + err = -EIO; + goto err_out1; + } + port = pci_resource_start(pdev, 0); + len = pci_resource_len(pdev, 0); - PRINTK(KERN_INFO "Command Reg: %04x\n", command); - command |= PCI_COMMAND_MASTER; - command &= ~PCI_COMMAND_MEMORY; - pci_write_config_word(pdev, PCI_COMMAND, command); - - /* Read I/O base address from PCI Configuration Space */ - - pci_read_config_word(pdev, PCI_BASE_ADDRESS_1, &port); - port &= PCI_BASE_ADDRESS_IO_MASK; // clear I/O bit (bit 0) - - /* Verify port address range is not already being used */ - - port_len = FP_IO_LEN; - if (check_region(port, port_len) != 0) { - printk("I/O range allocated to adapter"); - printk(" (0x%X-0x%X) is already being used!\n", port, - (port + port_len - 1)); - continue; - } + if (len < 0x4000) { + printk(KERN_ERR "skfp: Invalid PCI region size: %d\n", len); + err = -EIO; + goto err_out1; + } #else - /* Verify that MEM enable bit is set (PCI slot is enabled) */ - pci_read_config_word(pdev, PCI_COMMAND, &command); - if ((command & PCI_COMMAND_MEMORY) == 0) { - PRINTK("MEMORY-I/O enable bit not set!"); - PRINTK(" Verify that slot is enabled\n"); - continue; - } - - /* Turn off IO mapped space and enable mastering */ - - PRINTK(KERN_INFO "Command Reg: %04x\n", command); - command |= PCI_COMMAND_MASTER; - command &= ~PCI_COMMAND_IO; - pci_write_config_word(pdev, PCI_COMMAND, command); - - port = pci_resource_start(pdev, 0); - - port = (unsigned long)ioremap(port, 0x4000); - if (!port){ - printk("skfp: Unable to map MEMORY register, " - "FDDI adapter will be disabled.\n"); - break; - } -#endif - - if ((!loading_module) || first_dev_used) { - /* Allocate a device structure for this adapter */ - tmp = alloc_device(dev, port); - } - first_dev_used = 1; // only significant first time - - pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &SubSysId); - - if (tmp != NULL) { - if (loading_module) - link_modules(dev, tmp); - dev = tmp; - init_dev(dev, port); - dev->irq = pdev->irq; - - /* Initialize board structure with bus-specific info */ - - smc = (struct s_smc *) dev->priv; - smc->os.dev = dev; - smc->os.bus_type = SK_BUS_TYPE_PCI; - smc->os.pdev = *pdev; - smc->os.QueueSkb = MAX_TX_QUEUE_LEN; - smc->os.MaxFrameSize = MAX_FRAME_SIZE; - smc->os.dev = dev; - smc->hw.slot = -1; - smc->os.ResetRequested = FALSE; - skb_queue_head_init(&smc->os.SendSkbQueue); - - if (skfp_driver_init(dev) == 0) { - // only increment global board - // count on success - num_boards++; - request_region(dev->base_addr, - FP_IO_LEN, dev->name); - if ((SubSysId & 0xff00) == 0x5500 || - (SubSysId & 0xff00) == 0x5800) { - printk("%s: SysKonnect FDDI PCI adapter" - " found (SK-%04X)\n", dev->name, - SubSysId); - } else { - printk("%s: FDDI PCI adapter found\n", - dev->name); - } - } else { - kfree(dev); - i = SKFP_MAX_NUM_BOARDS; // stop search - - } - - } // if (dev != NULL) - - } // for SKFP_MAX_NUM_BOARDS - - /* - * If we're at this point we're going through skfp_probe() for the - * first time. Return success (0) if we've initialized 1 or more - * boards. Otherwise, return failure (-ENODEV). - */ - - if (num_boards > 0) - return (0); - else { - printk("no SysKonnect FDDI adapter found\n"); - return (-ENODEV); + if (!(pci_resource_flags(pdev, 1) & IO_RESOURCE_IO)) { + printk(KERN_ERR "skfp: region is not PIO resource\n"); + err = -EIO; + goto err_out1; } -} // skfp_probe - - -/************************ - * - * Search the entire 'fddi' device list for a fixed probe. If a match isn't - * found then check for an autoprobe or unused device location. If they - * are not available then insert a new device structure at the end of - * the current list. - * - ************************/ -static struct net_device *alloc_device(struct net_device *dev, u_long iobase) -{ - struct net_device *adev = NULL; - int fixed = 0, new_dev = 0; - - PRINTK(KERN_INFO "entering alloc_device\n"); - if (!dev) - return dev; - num_fddi = fddi_dev_index(dev->name); - if (loading_module) { - num_fddi++; - dev = insert_device(dev, skfp_probe); - return dev; + port = pci_resource_start(pdev, 1); + len = pci_resource_len(pdev, 1); + if (len < FP_IO_LEN) { + printk(KERN_ERR "skfp: Invalid PCI region size: %d\n", + io_len); + err = -EIO; + goto err_out1; } - while (1) { - if (((dev->base_addr == NO_ADDRESS) || - (dev->base_addr == 0)) && !adev) { - adev = dev; - } else if ((dev->priv == NULL) && (dev->base_addr == iobase)) { - fixed = 1; - } else { - if (dev->next == NULL) { - new_dev = 1; - } else if (strncmp(dev->next->name, "fddi", 4) != 0) { - new_dev = 1; - } - } - if ((dev->next == NULL) || new_dev || fixed) - break; - dev = dev->next; - num_fddi++; - } // while (1) - - if (adev && !fixed) { - dev = adev; - num_fddi = fddi_dev_index(dev->name); - new_dev = 0; - } - if (((dev->next == NULL) && ((dev->base_addr != NO_ADDRESS) && - (dev->base_addr != 0)) && !fixed) || - new_dev) { - num_fddi++; /* New device */ - dev = insert_device(dev, skfp_probe); - } - if (dev) { - if (!dev->priv) { - /* Allocate space for private board structure */ - dev->priv = (void *) kmalloc(sizeof(struct s_smc), - GFP_KERNEL); - if (dev->priv == NULL) { - printk("%s: Could not allocate memory for", - dev->name); - printk(" private board structure!\n"); - return (NULL); - } - /* clear structure */ - memset(dev->priv, 0, sizeof(struct s_smc)); - } +#endif + err = pci_request_regions(pdev, "skfddi"); + if (err) + goto err_out1; + + pci_set_master(pdev); + + dev = alloc_fddidev(sizeof(struct s_smc)); + if (!dev) { + printk(KERN_ERR "skfp: Unable to allocate fddi device, " + "FDDI adapter will be disabled.\n"); + err = -ENOMEM; + goto err_out2; + } + +#ifdef MEM_MAPPED_IO + dev->base_addr = (unsigned long) ioremap(port, len); + if (!dev->base_addr) { + printk(KERN_ERR "skfp: Unable to map MEMORY register, " + "FDDI adapter will be disabled.\n"); + err = -EIO; + goto err_out3; } - return dev; -} // alloc_device - - - -/************************ - * - * Initialize device structure - * - ************************/ -static void init_dev(struct net_device *dev, u_long iobase) -{ - /* Initialize new device structure */ - - dev->mem_end = 0; /* shared memory isn't used */ - dev->mem_start = 0; /* shared memory isn't used */ - dev->base_addr = iobase; /* save port (I/O) base address */ - dev->if_port = 0; /* not applicable to FDDI adapters */ - dev->dma = 0; /* Bus Master DMA doesn't require channel */ - dev->irq = 0; - - netif_start_queue(dev); +#else + dev->base_addr = port; +#endif + dev->irq = pdev->irq; dev->get_stats = &skfp_ctl_get_stats; dev->open = &skfp_open; dev->stop = &skfp_close; dev->hard_start_xmit = &skfp_send_pkt; - dev->hard_header = NULL; /* set in fddi_setup() */ - dev->rebuild_header = NULL; /* set in fddi_setup() */ dev->set_multicast_list = &skfp_ctl_set_multicast_list; dev->set_mac_address = &skfp_ctl_set_mac_address; dev->do_ioctl = &skfp_ioctl; - dev->set_config = NULL; /* not supported for now &&& */ dev->header_cache_update = NULL; /* not supported */ - dev->change_mtu = NULL; /* set in fddi_setup() */ SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &pdev->dev); - /* Initialize remaining device structure information */ - fddi_setup(dev); -} // init_device - - -/************************ - * - * If at end of fddi device list and can't use current entry, malloc - * one up. If memory could not be allocated, print an error message. - * -************************/ -static struct net_device *insert_device(struct net_device *dev, - int (*init) (struct net_device *)) -{ - struct net_device *new; - int len; - - PRINTK(KERN_INFO "entering insert_device\n"); - len = sizeof(struct net_device) + sizeof(struct s_smc); - new = (struct net_device *) kmalloc(len, GFP_KERNEL); - if (new == NULL) { - printk("fddi%d: Device not initialised, insufficient memory\n", - num_fddi); - return NULL; - } else { - memset((char *) new, 0, len); - new->priv = (struct s_smc *) (new + 1); - new->init = init; /* initialisation routine */ - if (!loading_module) { - new->next = dev->next; - dev->next = new; - } - /* create new device name */ - if (num_fddi > 999) { - sprintf(new->name, "fddi????"); - } else { - sprintf(new->name, "fddi%d", num_fddi); - } - } - return new; -} // insert_device - - -/************************ - * - * Get the number of a "fddiX" string - * - ************************/ -static int fddi_dev_index(unsigned char *s) -{ - int i = 0, j = 0; - - for (; *s; s++) { - if (isdigit(*s)) { - j = 1; - i = (i * 10) + (*s - '0'); - } else if (j) - break; - } - return i; -} // fddi_dev_index + /* Initialize board structure with bus-specific info */ + smc = (struct s_smc *) dev->priv; + smc->os.dev = dev; + smc->os.bus_type = SK_BUS_TYPE_PCI; + smc->os.pdev = *pdev; + smc->os.QueueSkb = MAX_TX_QUEUE_LEN; + smc->os.MaxFrameSize = MAX_FRAME_SIZE; + smc->os.dev = dev; + smc->hw.slot = -1; + smc->os.ResetRequested = FALSE; + skb_queue_head_init(&smc->os.SendSkbQueue); + + err = skfp_driver_init(dev); + if (err) + goto err_out4; + + err = register_netdev(dev); + if (err) + goto err_out5; + + ++num_boards; + pci_set_drvdata(pdev, dev); + + if ((pdev->subsystem_device & 0xff00) == 0x5500 || + (pdev->subsystem_device & 0xff00) == 0x5800) + printk("%s: SysKonnect FDDI PCI adapter" + " found (SK-%04X)\n", dev->name, + pdev->subsystem_device); + else + printk("%s: FDDI PCI adapter found\n", dev->name); + return 0; +err_out5: + if (smc->os.SharedMemAddr) + pci_free_consistent(pdev, smc->os.SharedMemSize, + smc->os.SharedMemAddr, + smc->os.SharedMemDMA); + pci_free_consistent(pdev, MAX_FRAME_SIZE, + smc->os.LocalRxBuffer, smc->os.LocalRxBufferDMA); +err_out4: +#ifdef MEM_MAPPED_IO + iounmap((void *) dev->base_addr); +#endif +err_out3: + free_netdev(dev); +err_out2: + pci_release_regions(pdev); +err_out1: + return err; +} -/************************ - * - * Used if loaded as module only. Link the device structures - * together. Needed to release them all at unload. - * -************************/ -static void link_modules(struct net_device *dev, struct net_device *tmp) +/* + * Called for each adapter board from pci_unregister_driver + */ +static void __devexit skfp_remove_one(struct pci_dev *pdev) { - struct net_device *p = dev; + struct net_device *p = pci_get_drvdata(pdev); + struct s_smc *lp = p->priv; - if (p) { - while (((struct s_smc *) (p->priv))->os.next_module) { - p = ((struct s_smc *) (p->priv))->os.next_module; - } + unregister_netdev(p); - if (dev != tmp) { - ((struct s_smc *) (p->priv))->os.next_module = tmp; - } else { - ((struct s_smc *) (p->priv))->os.next_module = NULL; - } + if (lp->os.SharedMemAddr) { + pci_free_consistent(&lp->os.pdev, + lp->os.SharedMemSize, + lp->os.SharedMemAddr, + lp->os.SharedMemDMA); + lp->os.SharedMemAddr = NULL; + } + if (lp->os.LocalRxBuffer) { + pci_free_consistent(&lp->os.pdev, + MAX_FRAME_SIZE, + lp->os.LocalRxBuffer, + lp->os.LocalRxBufferDMA); + lp->os.LocalRxBuffer = NULL; } - return; -} // link_modules - +#ifdef MEM_MAPPED_IO + iounmap((void *) p->base_addr); +#endif + pci_release_regions(pdev); + free_netdev(p); + pci_set_drvdata(pdev, NULL); +} /* * ==================== @@ -653,11 +408,11 @@ static void link_modules(struct net_devi * 0 - initialization succeeded * -1 - initialization failed */ -static int skfp_driver_init(struct net_device *dev) +static int skfp_driver_init(struct net_device *dev) { struct s_smc *smc = (struct s_smc *) dev->priv; skfddi_priv *bp = PRIV(dev); - u8 val; /* used for I/O read/writes */ + int err = -EIO; PRINTK(KERN_INFO "entering skfp_driver_init\n"); @@ -666,9 +421,7 @@ static int skfp_driver_init(struct net_d smc->hw.iop = dev->base_addr; // Get the interrupt level from the PCI Configuration Table - val = dev->irq; - - smc->hw.irq = val; + smc->hw.irq = dev->irq; spin_lock_init(&bp->DriverLock); @@ -738,7 +491,7 @@ fail: bp->LocalRxBuffer, bp->LocalRxBufferDMA); bp->LocalRxBuffer = NULL; } - return (-1); + return err; } // skfp_driver_init @@ -766,14 +519,15 @@ fail: static int skfp_open(struct net_device *dev) { struct s_smc *smc = (struct s_smc *) dev->priv; + int err; PRINTK(KERN_INFO "entering skfp_open\n"); /* Register IRQ - support shared interrupts by passing device ptr */ - if (request_irq(dev->irq, (void *) skfp_interrupt, SA_SHIRQ, - dev->name, dev)) { - printk("%s: Requested IRQ %d is busy\n", dev->name, dev->irq); - return (-EAGAIN); - } + err = request_irq(dev->irq, (void *) skfp_interrupt, SA_SHIRQ, + dev->name, dev); + if (err) + return err; + /* * Set current address to factory MAC address * @@ -797,6 +551,7 @@ static int skfp_open(struct net_device * /* Disable promiscuous filter settings */ mac_drv_rx_mode(smc, RX_DISABLE_PROMISC); + netif_start_queue(dev); return (0); } // skfp_open @@ -831,7 +586,6 @@ static int skfp_open(struct net_device * static int skfp_close(struct net_device *dev) { struct s_smc *smc = (struct s_smc *) dev->priv; - struct sk_buff *skb; skfddi_priv *bp = PRIV(dev); CLI_FBI(); @@ -844,13 +598,8 @@ static int skfp_close(struct net_device /* Deregister (free) IRQ */ free_irq(dev->irq, dev); - for (;;) { - skb = skb_dequeue(&bp->SendSkbQueue); - if (skb == NULL) - break; - bp->QueueSkb++; - dev_kfree_skb(skb); - } + skb_queue_purge(&bp->SendSkbQueue); + bp->QueueSkb = MAX_TX_QUEUE_LEN; return (0); } // skfp_close @@ -1285,6 +1034,8 @@ static int skfp_ioctl(struct net_device break; default: printk("ioctl for %s: unknow cmd: %04x\n", dev->name, ioc.cmd); + status = -EOPNOTSUPP; + } // switch return status; @@ -2538,63 +2289,21 @@ void drv_reset_indication(struct s_smc * } // drv_reset_indication - -static struct net_device *mdev; +static struct pci_driver skfddi_pci_driver = { + .name = "skfddi", + .id_table = skfddi_pci_tbl, + .probe = skfp_init_one, + .remove = __devexit_p(skfp_remove_one), +}; static int __init skfd_init(void) { - struct net_device *p; - - if ((mdev = insert_device(NULL, skfp_probe)) == NULL) - return -ENOMEM; - - for (p = mdev; p != NULL; p = ((struct s_smc *)p->priv)->os.next_module) { - if (register_netdev(p) != 0) { - printk("skfddi init_module failed\n"); - return -EIO; - } - } - - return 0; + return pci_module_init(&skfddi_pci_driver); } -static struct net_device *unlink_modules(struct net_device *p) -{ - struct net_device *next = NULL; - - if (p->priv) { /* Private areas allocated? */ - struct s_smc *lp = (struct s_smc *) p->priv; - - next = lp->os.next_module; - - if (lp->os.SharedMemAddr) { - pci_free_consistent(&lp->os.pdev, - lp->os.SharedMemSize, - lp->os.SharedMemAddr, - lp->os.SharedMemDMA); - lp->os.SharedMemAddr = NULL; - } - if (lp->os.LocalRxBuffer) { - pci_free_consistent(&lp->os.pdev, - MAX_FRAME_SIZE, - lp->os.LocalRxBuffer, - lp->os.LocalRxBufferDMA); - lp->os.LocalRxBuffer = NULL; - } - release_region(p->base_addr, - (lp->os.bus_type == SK_BUS_TYPE_PCI ? FP_IO_LEN : 0)); - } - unregister_netdev(p); - printk("%s: unloaded\n", p->name); - free_netdev(p); /* Free the device structure */ - - return next; -} // unlink_modules - static void __exit skfd_exit(void) { - while (mdev) - mdev = unlink_modules(mdev); + pci_unregister_driver(&skfddi_pci_driver); } module_init(skfd_init); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/smc-mca.c 830-ivtv/drivers/net/smc-mca.c --- 000-virgin/drivers/net/smc-mca.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/smc-mca.c Thu Jan 8 08:54:25 2004 @@ -202,22 +202,18 @@ int __init ultramca_probe(struct device return -ENXIO; /* Adapter found. */ - dev = alloc_etherdev(0); + dev = alloc_ei_netdev(); if(!dev) return -ENODEV; SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, gen_dev); - - rc = register_netdev(dev); - if (rc) - goto err_free_netdev; - - printk(KERN_INFO "%s: %s found in slot %d\n", - dev->name, smc_mca_adapter_names[adapter], slot + 1); - mca_device_set_name(mca_dev, smc_mca_adapter_names[adapter]); mca_device_set_claim(mca_dev, 1); + + printk(KERN_INFO "smc_mca: %s found in slot %d\n", + smc_mca_adapter_names[adapter], slot + 1); + ultra_found++; dev->base_addr = ioaddr = mca_device_transform_ioport(mca_dev, tbase); @@ -266,18 +262,18 @@ int __init ultramca_probe(struct device /* sanity check, shouldn't happen */ if (dev->mem_start == 0) { rc = -ENODEV; - goto err_unregister_netdev; + goto err_unclaim; } if (!request_region(ioaddr, ULTRA_IO_EXTENT, dev->name)) { rc = -ENODEV; - goto err_unregister_netdev; + goto err_unclaim; } reg4 = inb(ioaddr + 4) & 0x7f; outb(reg4, ioaddr + 4); - printk(KERN_INFO "%s: Parameters: %#3x,", dev->name, ioaddr); + printk(KERN_INFO "smc_mca[%d]: Parameters: %#3x,", slot + 1, ioaddr); for (i = 0; i < 6; i++) printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i)); @@ -299,14 +295,6 @@ int __init ultramca_probe(struct device outb(reg4, ioaddr + 4); - /* Allocate dev->priv and fill in 8390 specific dev fields. - */ - - rc = ethdev_init(dev); - if (rc) { - printk (", no memory for dev->priv.\n"); - goto err_release_region; - } gen_dev->driver_data = dev; /* The 8390 isn't at the base address, so fake the offset @@ -339,13 +327,16 @@ int __init ultramca_probe(struct device NS8390_init(dev, 0); + rc = register_netdev(dev); + if (rc) + goto err_release_region; + return 0; err_release_region: release_region(ioaddr, ULTRA_IO_EXTENT); -err_unregister_netdev: - unregister_netdev(dev); -err_free_netdev: +err_unclaim: + mca_device_set_claim(mca_dev, 0); free_netdev(dev); return rc; } @@ -463,14 +454,14 @@ static int ultramca_remove(struct device struct mca_device *mca_dev = to_mca_device(gen_dev); struct net_device *dev = (struct net_device *)gen_dev->driver_data; - if(dev && dev->priv) { + if (dev) { /* NB: ultra_close_card() does free_irq */ int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; + unregister_netdev(dev); mca_device_set_claim(mca_dev, 0); release_region(ioaddr, ULTRA_IO_EXTENT); - unregister_netdev(dev); - kfree(dev->priv); + free_netdev(dev); } return 0; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/smc-ultra.c 830-ivtv/drivers/net/smc-ultra.c --- 000-virgin/drivers/net/smc-ultra.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/smc-ultra.c Thu Jan 8 08:54:25 2004 @@ -76,7 +76,6 @@ static const char version[] = static unsigned int ultra_portlist[] __initdata = {0x200, 0x220, 0x240, 0x280, 0x300, 0x340, 0x380, 0}; -int ultra_probe(struct net_device *dev); static int ultra_probe1(struct net_device *dev, int ioaddr); #ifdef __ISAPNP__ @@ -122,18 +121,30 @@ MODULE_DEVICE_TABLE(isapnp, ultra_device #define ULTRA_IO_EXTENT 32 #define EN0_ERWCNT 0x08 /* Early receive warning count. */ +#ifdef CONFIG_NET_POLL_CONTROLLER +static void ultra_poll(struct net_device *dev) +{ + disable_irq(dev->irq); + ei_interrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif /* Probe for the Ultra. This looks like a 8013 with the station address PROM at I/O ports +8 to +13, with a checksum following. */ -int __init ultra_probe(struct net_device *dev) +static int __init do_ultra_probe(struct net_device *dev) { int i; int base_addr = dev->base_addr; + int irq = dev->irq; SET_MODULE_OWNER(dev); +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = &ultra_poll; +#endif if (base_addr > 0x1ff) /* Check a single specified location. */ return ultra_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ @@ -147,13 +158,51 @@ int __init ultra_probe(struct net_device printk(KERN_NOTICE "smc-ultra.c: No ISAPnP cards found, trying standard ones...\n"); #endif - for (i = 0; ultra_portlist[i]; i++) + for (i = 0; ultra_portlist[i]; i++) { + dev->irq = irq; if (ultra_probe1(dev, ultra_portlist[i]) == 0) return 0; + } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + /* NB: ultra_close_card() does free_irq */ +#ifdef __ISAPNP__ + struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv; + if (idev) + pnp_device_detach(idev); +#endif + release_region(dev->base_addr - ULTRA_NIC_OFFSET, ULTRA_IO_EXTENT); +} + +struct net_device * __init ultra_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_ultra_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init ultra_probe1(struct net_device *dev, int ioaddr) { int i, retval; @@ -226,13 +275,6 @@ static int __init ultra_probe1(struct ne eeprom_irq = 1; } - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk (", no memory for dev->priv.\n"); - retval = -ENOMEM; - goto out; - } - /* The 8390 isn't at the base address, so fake the offset */ dev->base_addr = ioaddr+ULTRA_NIC_OFFSET; @@ -500,7 +542,7 @@ ultra_close_card(struct net_device *dev) #ifdef MODULE #define MAX_ULTRA_CARDS 4 /* Max number of Ultra cards per module */ -static struct net_device dev_ultra[MAX_ULTRA_CARDS]; +static struct net_device *dev_ultra[MAX_ULTRA_CARDS]; static int io[MAX_ULTRA_CARDS]; static int irq[MAX_ULTRA_CARDS]; @@ -516,26 +558,33 @@ ISA device autoprobes on a running machi int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_ULTRA_CARDS; this_dev++) { - struct net_device *dev = &dev_ultra[this_dev]; - dev->irq = irq[this_dev]; - dev->base_addr = io[this_dev]; - dev->init = ultra_probe; if (io[this_dev] == 0) { if (this_dev != 0) break; /* only autoprobe 1st one */ printk(KERN_NOTICE "smc-ultra.c: Presently autoprobing (not recommended) for a single card.\n"); } - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "smc-ultra.c: No SMC Ultra card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) return 0; /* Got at least one. */ - return -ENXIO; + dev = alloc_ei_netdev(); + if (!dev) + break; + dev->irq = irq[this_dev]; + dev->base_addr = io[this_dev]; + if (do_ultra_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_ultra[found++] = dev; + continue; + } + cleanup_card(dev); } - found++; + free_netdev(dev); + printk(KERN_WARNING "smc-ultra.c: No SMC Ultra card found (i/o = 0x%x).\n", io[this_dev]); + break; } - - return 0; + if (found) + return 0; + return -ENXIO; } void @@ -544,20 +593,11 @@ cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < MAX_ULTRA_CARDS; this_dev++) { - struct net_device *dev = &dev_ultra[this_dev]; - if (dev->priv != NULL) { - /* NB: ultra_close_card() does free_irq */ - int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; - -#ifdef __ISAPNP__ - struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv; - if (idev) - pnp_device_detach(idev); -#endif - + struct net_device *dev = dev_ultra[this_dev]; + if (dev) { unregister_netdev(dev); - release_region(ioaddr, ULTRA_IO_EXTENT); - kfree(dev->priv); + cleanup_card(dev); + free_netdev(dev); } } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/smc-ultra32.c 830-ivtv/drivers/net/smc-ultra32.c --- 000-virgin/drivers/net/smc-ultra32.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/smc-ultra32.c Thu Jan 8 08:54:25 2004 @@ -61,7 +61,6 @@ static const char *version = "smc-ultra3 #include "8390.h" -int ultra32_probe(struct net_device *dev); static int ultra32_probe1(struct net_device *dev, int ioaddr); static int ultra32_open(struct net_device *dev); static void ultra32_reset_8390(struct net_device *dev); @@ -98,26 +97,59 @@ static int ultra32_close(struct net_devi #define ULTRA32_CFG6 (-0x15) /* 0xc8b */ #define ULTRA32_CFG7 0x0d /* 0xcad */ +static void cleanup_card(struct net_device *dev) +{ + int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; + /* NB: ultra32_close_card() does free_irq */ + release_region(ioaddr, ULTRA32_IO_EXTENT); +} /* Probe for the Ultra32. This looks like a 8013 with the station address PROM at I/O ports +8 to +13, with a checksum following. */ -int __init ultra32_probe(struct net_device *dev) +struct net_device * __init ultra32_probe(int unit) { - int ioaddr; - - if (!EISA_bus) return -ENODEV; + struct net_device *dev; + int base; + int irq; + int err = -ENODEV; + + if (!EISA_bus) + return ERR_PTR(-ENODEV); + + dev = alloc_ei_netdev(); + + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } SET_MODULE_OWNER(dev); - /* EISA spec allows for up to 16 slots, but 8 is typical. */ - for (ioaddr = 0x1000 + ULTRA32_BASE; ioaddr < 0x9000; ioaddr += 0x1000) - if (ultra32_probe1(dev, ioaddr) == 0) - return 0; + irq = dev->irq; - return -ENODEV; + /* EISA spec allows for up to 16 slots, but 8 is typical. */ + for (base = 0x1000 + ULTRA32_BASE; base < 0x9000; base += 0x1000) { + if (ultra32_probe1(dev, base) == 0) + break; + dev->irq = irq; + } + if (base >= 0x9000) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); } static int __init ultra32_probe1(struct net_device *dev, int ioaddr) @@ -210,13 +242,6 @@ static int __init ultra32_probe1(struct dev->irq = irq; } - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk (", no memory for dev->priv.\n"); - retval = -ENOMEM; - goto out; - } - /* The 8390 isn't at the base address, so fake the offset */ dev->base_addr = ioaddr + ULTRA32_NIC_OFFSET; @@ -380,7 +405,7 @@ static void ultra32_block_output(struct #ifdef MODULE #define MAX_ULTRA32_CARDS 4 /* Max number of Ultra cards per module */ -static struct net_device dev_ultra[MAX_ULTRA32_CARDS]; +static struct net_device *dev_ultra[MAX_ULTRA32_CARDS]; MODULE_DESCRIPTION("SMC Ultra32 EISA ethernet driver"); MODULE_LICENSE("GPL"); @@ -390,18 +415,15 @@ int init_module(void) int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_ULTRA32_CARDS; this_dev++) { - struct net_device *dev = &dev_ultra[this_dev]; - dev->init = ultra32_probe; - if (register_netdev(dev) != 0) { - if (found > 0) { /* Got at least one. */ - return 0; - } - printk(KERN_WARNING "smc-ultra32.c: No SMC Ultra32 found.\n"); - return -ENXIO; - } - found++; + struct net_device *dev = ultra32_probe(-1); + if (IS_ERR(dev)) + break; + dev_ultra[found++] = dev; } - return 0; + if (found) + return 0; + printk(KERN_WARNING "smc-ultra32.c: No SMC Ultra32 found.\n"); + return -ENXIO; } void cleanup_module(void) @@ -409,14 +431,11 @@ void cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < MAX_ULTRA32_CARDS; this_dev++) { - struct net_device *dev = &dev_ultra[this_dev]; - if (dev->priv != NULL) { - int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; - void *priv = dev->priv; - /* NB: ultra32_close_card() does free_irq */ - release_region(ioaddr, ULTRA32_IO_EXTENT); + struct net_device *dev = dev_ultra[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(priv); + cleanup_card(dev); + free_netdev(dev); } } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/smc9194.c 830-ivtv/drivers/net/smc9194.c --- 000-virgin/drivers/net/smc9194.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/smc9194.c Thu Jan 8 08:54:25 2004 @@ -191,7 +191,7 @@ struct smc_local { . . NB:This shouldn't be static since it is referred to externally. */ -int smc_init(struct net_device *dev); +struct net_device *smc_init(int unit); /* . The kernel calls this function when someone wants to use the device, @@ -672,7 +672,7 @@ static void smc_hardware_send_packet( st /*------------------------------------------------------------------------- | - | smc_init( struct net_device * dev ) + | smc_init(int unit) | Input parameters: | dev->base_addr == 0, try to find all possible locations | dev->base_addr == 1, return failure code @@ -680,31 +680,56 @@ static void smc_hardware_send_packet( st | dev->base_addr == this is the address to check | | Output: - | 0 --> there is a device - | anything else, error + | pointer to net_device or ERR_PTR(error) | --------------------------------------------------------------------------- */ -int __init smc_init(struct net_device *dev) +static int io; +static int irq; +static int ifport; + +struct net_device * __init smc_init(int unit) { - int i; - int base_addr = dev->base_addr; + struct net_device *dev = alloc_etherdev(sizeof(struct smc_local)); + unsigned *port; + int err = 0; + + if (!dev) + return ERR_PTR(-ENODEV); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + irq = dev->irq; + } SET_MODULE_OWNER(dev); - /* try a specific location */ - if (base_addr > 0x1ff) - return smc_probe(dev, base_addr); - else if (base_addr != 0) - return -ENXIO; - - /* check every ethernet address */ - for (i = 0; smc_portlist[i]; i++) - if (smc_probe(dev, smc_portlist[i]) == 0) - return 0; - - /* couldn't find anything */ - return -ENODEV; + if (io > 0x1ff) { /* Check a single specified location. */ + err = smc_probe(dev, io); + } else if (io != 0) { /* Don't probe at all. */ + err = -ENXIO; + } else { + for (port = smc_portlist; *port; port++) { + if (smc_probe(dev, *port) == 0) + break; + } + if (!*port) + err = -ENODEV; + } + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + free_irq(dev->irq, dev); + release_region(dev->base_addr, SMC_IO_EXTENT); +out: + free_netdev(dev); + return ERR_PTR(err); } /*---------------------------------------------------------------------- @@ -821,6 +846,9 @@ static int __init smc_probe(struct net_d if (!request_region(ioaddr, SMC_IO_EXTENT, dev->name)) return -EBUSY; + dev->irq = irq; + dev->if_port = ifport; + /* First, see if the high byte is 0x33 */ bank = inw( ioaddr + BANK_SELECT ); if ( (bank & 0xFF00) != 0x3300 ) { @@ -969,28 +997,14 @@ static int __init smc_probe(struct net_d printk("%2.2x:", dev->dev_addr[i] ); printk("%2.2x \n", dev->dev_addr[5] ); - - /* Initialize the private structure. */ - if (dev->priv == NULL) { - dev->priv = kmalloc(sizeof(struct smc_local), GFP_KERNEL); - if (dev->priv == NULL) { - retval = -ENOMEM; - goto err_out; - } - } /* set the private data to zero by default */ memset(dev->priv, 0, sizeof(struct smc_local)); - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - /* Grab the IRQ */ retval = request_irq(dev->irq, &smc_interrupt, 0, dev->name, dev); if (retval) { printk("%s: unable to get IRQ %d (irqval=%d).\n", dev->name, dev->irq, retval); - kfree(dev->priv); - dev->priv = NULL; goto err_out; } @@ -1524,10 +1538,7 @@ static void smc_set_multicast_list(struc #ifdef MODULE -static struct net_device devSMC9194; -static int io; -static int irq; -static int ifport; +static struct net_device *devSMC9194; MODULE_LICENSE("GPL"); MODULE_PARM(io, "i"); @@ -1539,32 +1550,23 @@ MODULE_PARM_DESC(ifport, "SMC 99194 inte int init_module(void) { - int result; - if (io == 0) printk(KERN_WARNING CARDNAME": You shouldn't use auto-probing with insmod!\n" ); /* copy the parameters from insmod into the device structure */ - devSMC9194.base_addr = io; - devSMC9194.irq = irq; - devSMC9194.if_port = ifport; - devSMC9194.init = smc_init; - if ((result = register_netdev(&devSMC9194)) != 0) - return result; - + devSMC9194 = smc_init(-1); + if (IS_ERR(devSMC9194)) + return PTR_ERR(devSMC9194); return 0; } void cleanup_module(void) { - unregister_netdev(&devSMC9194); - - free_irq(devSMC9194.irq, &devSMC9194); - release_region(devSMC9194.base_addr, SMC_IO_EXTENT); - - if (devSMC9194.priv) - kfree(devSMC9194.priv); + unregister_netdev(devSMC9194); + free_irq(devSMC9194->irq, devSMC9194); + release_region(devSMC9194->base_addr, SMC_IO_EXTENT); + free_netdev(devSMC9194); } #endif /* MODULE */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/starfire.c 830-ivtv/drivers/net/starfire.c --- 000-virgin/drivers/net/starfire.c Mon Dec 8 09:55:51 2003 +++ 830-ivtv/drivers/net/starfire.c Thu Jan 8 08:54:25 2004 @@ -139,7 +139,6 @@ TODO: bugfixes (no bugs known as of righ #include #include #include -#include #include #include #include diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/stnic.c 830-ivtv/drivers/net/stnic.c --- 000-virgin/drivers/net/stnic.c Sun Dec 1 09:59:52 2002 +++ 830-ivtv/drivers/net/stnic.c Thu Jan 8 08:54:25 2004 @@ -98,28 +98,20 @@ STNIC_WRITE (int reg, byte val) STNIC_DELAY (); } -int __init stnic_probe(void) +static int __init stnic_probe(void) { struct net_device *dev; - int i; + int i, err; /* If we are not running on a SolutionEngine, give up now */ if (! MACH_SE) return -ENODEV; /* New style probing API */ - dev = init_etherdev (NULL, 0); + dev = alloc_ei_netdev(); if (!dev) return -ENOMEM; SET_MODULE_OWNER(dev); - stnic_dev = dev; - - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init (dev)) - { - printk (KERN_EMERG "Unable to get memory for dev->priv.\n"); - return -ENOMEM; - } #ifdef CONFIG_SH_STANDARD_BIOS sh_bios_get_node_addr (stnic_eadr); @@ -135,13 +127,11 @@ int __init stnic_probe(void) /* Snarf the interrupt now. There's no point in waiting since we cannot share and the board will usually be enabled. */ - i = request_irq (dev->irq, ei_interrupt, 0, dev->name, dev); - if (i) { + err = request_irq (dev->irq, ei_interrupt, 0, dev->name, dev); + if (err) { printk (KERN_EMERG " unable to get IRQ %d.\n", dev->irq); - unregister_netdev(dev); - kfree(dev->priv); - kfree(dev); - return i; + free_netdev(dev); + return err; } ei_status.name = dev->name; @@ -162,6 +152,14 @@ int __init stnic_probe(void) stnic_init (dev); + err = register_netdev(dev); + if (err) { + free_irq(dev->irq, dev); + free_netdev(dev); + return err; + } + stnic_dev = dev; + printk (KERN_INFO "NS ST-NIC 83902A\n"); return 0; @@ -305,15 +303,13 @@ stnic_init (struct net_device *dev) return; } -/* Hardware interrupt handler. */ -extern void ei_interrupt (int irq, void *dev_id, struct pt_regs *regs); - -void -do_stnic_intr (int irq, void *dev_id, struct pt_regs *regs) +static void __exit stnic_cleanup(void) { - ei_interrupt (0, stnic_dev, regs); + unregister_netdev(stnic_dev); + free_irq(stnic_dev->irq, stnic_dev); + free_netdev(stnic_dev); } module_init(stnic_probe); -/* No cleanup routine. */ +module_exit(stnic_cleanup); MODULE_LICENSE("GPL"); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sun3_82586.c 830-ivtv/drivers/net/sun3_82586.c --- 000-virgin/drivers/net/sun3_82586.c Sat May 10 18:34:41 2003 +++ 830-ivtv/drivers/net/sun3_82586.c Thu Jan 8 08:54:25 2004 @@ -55,6 +55,7 @@ static int fifo=0x8; /* don't change */ #define DEBUG /* debug on */ #define SYSBUSVAL 0 /* 16 Bit */ +#define SUN3_82586_TOTAL_SIZE PAGE_SIZE #define sun3_attn586() {*(volatile unsigned char *)(dev->base_addr) |= IEOB_ATTEN; *(volatile unsigned char *)(dev->base_addr) &= ~IEOB_ATTEN;} #define sun3_reset586() {*(volatile unsigned char *)(dev->base_addr) = 0; udelay(100); *(volatile unsigned char *)(dev->base_addr) = IEOB_NORSET;} @@ -277,10 +278,12 @@ static void alloc586(struct net_device * memset((char *)p->scb,0,sizeof(struct scb_struct)); } -int __init sun3_82586_probe(struct net_device *dev) +struct net_device * __init sun3_82586_probe(int unit) { + struct net_device *dev; unsigned long ioaddr; static int found = 0; + int err = -ENOMEM; /* check that this machine has an onboard 82586 */ switch(idprom->id_machtype) { @@ -290,31 +293,51 @@ int __init sun3_82586_probe(struct net_d break; default: - return(-ENODEV); + return ERR_PTR(-ENODEV); } - if(found) - return -ENODEV; + if (found) + return ERR_PTR(-ENODEV); - ioaddr = (unsigned long)ioremap(IE_OBIO, PAGE_SIZE); + ioaddr = (unsigned long)ioremap(IE_OBIO, SUN3_82586_TOTAL_SIZE); + if (!ioaddr) + return ERR_PTR(-ENOMEM); found = 1; + dev = alloc_etherdev(sizeof(struct priv)); + if (!dev) + goto out; + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } SET_MODULE_OWNER(dev); dev->irq = IE_IRQ; dev->base_addr = ioaddr; - if(sun3_82586_probe1(dev, ioaddr) == 0) - return 0; - - return -ENODEV; + err = sun3_82586_probe1(dev, ioaddr); + if (err) + goto out1; + err = register_netdev(dev); + if (err) + goto out2; + return dev; + +out2: + release_region(ioaddr, SUN3_82586_TOTAL_SIZE); +out1: + free_netdev(dev); +out: + iounmap((void *)ioaddr); + return ERR_PTR(err); } static int __init sun3_82586_probe1(struct net_device *dev,int ioaddr) { int i, size, retval; -// if (!request_region(ioaddr, SUN3_82586_TOTAL_SIZE, dev->name)) -// return -EBUSY; + if (!request_region(ioaddr, SUN3_82586_TOTAL_SIZE, dev->name)) + return -EBUSY; /* copy in the ethernet address from the prom */ for(i = 0; i < 6 ; i++) @@ -341,16 +364,6 @@ static int __init sun3_82586_probe1(stru goto out; } - dev->priv = (void *) kmalloc(sizeof(struct priv),GFP_KERNEL); - if(dev->priv == NULL) { - printk("%s: Ooops .. can't allocate private driver memory.\n",dev->name); - retval = -ENOMEM; - goto out; - } - - /* warning: we don't free it on errors */ - memset((char *) dev->priv,0,sizeof(struct priv)); - ((struct priv *) (dev->priv))->memtop = (char *)dvma_btov(dev->mem_start); ((struct priv *) (dev->priv))->base = (unsigned long) dvma_btov(0); alloc586(dev); @@ -374,11 +387,9 @@ static int __init sun3_82586_probe1(stru dev->set_multicast_list = set_multicast_list; dev->if_port = 0; - - ether_setup(dev); - return 0; out: + release_region(ioaddr, SUN3_82586_TOTAL_SIZE); return retval; } @@ -1138,21 +1149,23 @@ static void set_multicast_list(struct ne #ifdef MODULE #error This code is not currently supported as a module -static struct net_device dev_sun3_82586; +static struct net_device *dev_sun3_82586; int init_module(void) { - dev_sun3_82586.init = sun3_82586_probe; - if (register_netdev(&dev_sun3_82586) != 0) - return -EIO; + dev_sun3_82586 = sun3_82586_probe(-1); + if (IS_ERR(dev_sun3_82586)) + return PTR_ERR(dev_sun3_82586); return 0; } void cleanup_module(void) { - unregister_netdev(&dev_sun3_82586); - kfree(dev_sun3_82586.priv); - dev_sun3_82586.priv = NULL; + unsigned long ioaddr = dev_sun3_82586->base_addr; + unregister_netdev(dev_sun3_82586); + release_region(ioaddr, SUN3_82586_TOTAL_SIZE); + iounmap((void *)ioaddr); + free_netdev(dev_sun3_82586); } #endif /* MODULE */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/sun3lance.c 830-ivtv/drivers/net/sun3lance.c --- 000-virgin/drivers/net/sun3lance.c Fri May 30 19:02:13 2003 +++ 830-ivtv/drivers/net/sun3lance.c Thu Jan 8 08:54:25 2004 @@ -246,9 +246,11 @@ static void set_multicast_list( struct n /************************* End of Prototypes **************************/ -int __init sun3lance_probe( struct net_device *dev ) -{ +struct net_device * __init sun3lance_probe(int unit) +{ + struct net_device *dev; static int found; + int err = -ENODEV; /* check that this machine has an onboard lance */ switch(idprom->id_machtype) { @@ -259,18 +261,37 @@ int __init sun3lance_probe( struct net_d break; default: - return(-ENODEV); + return ERR_PTR(-ENODEV); } - if(found) - return(-ENODEV); + if (found) + return ERR_PTR(-ENODEV); - if (lance_probe(dev)) { - found = 1; - return( 0 ); + dev = alloc_etherdev(sizeof(struct lance_private)); + if (!dev) + return ERR_PTR(-ENOMEM); + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); } + SET_MODULE_OWNER(dev); + + if (!lance_probe(dev)) + goto out; - return( -ENODEV ); + err = register_netdev(dev); + if (err) + goto out1; + found = 1; + return dev; + +out1: +#ifdef CONFIG_SUN3 + iounmap((void *)dev->base_addr); +#endif +out: + free_netdev(dev); + return ERR_PTR(err); } static int __init lance_probe( struct net_device *dev) @@ -285,6 +306,8 @@ static int __init lance_probe( struct ne #ifdef CONFIG_SUN3 ioaddr = (unsigned long)ioremap(LANCE_OBIO, PAGE_SIZE); + if (!ioaddr) + return 0; #else ioaddr = SUN3X_LANCE; #endif @@ -303,17 +326,15 @@ static int __init lance_probe( struct ne ioaddr_probe[0] = tmp1; ioaddr_probe[1] = tmp2; +#ifdef CONFIG_SUN3 + iounmap((void *)ioaddr); +#endif return 0; } - init_etherdev( dev, sizeof(struct lance_private) ); - if (!dev->priv) { - dev->priv = kmalloc( sizeof(struct lance_private), GFP_KERNEL ); - if (!dev->priv) - return 0; - } lp = (struct lance_private *)dev->priv; + /* XXX - leak? */ MEM = dvma_malloc_align(sizeof(struct lance_memory), 0x10000); lp->iobase = (volatile unsigned short *)ioaddr; @@ -921,32 +942,24 @@ static void set_multicast_list( struct n #ifdef MODULE -static char devicename[9]; -static struct net_device sun3lance_dev = -{ - devicename, /* filled in by register_netdev() */ - 0, 0, 0, 0, /* memory */ - 0, 0, /* base, irq */ - 0, 0, 0, NULL, sun3lance_probe, -}; +static struct net_device *sun3lance_dev; int init_module(void) { - int err; - - if ((err = register_netdev( &sun3lance_dev ))) { - if (err == -EIO) { - printk( "SUN3 Lance not detected. Module not loaded.\n"); - } - return( err ); - } - return( 0 ); + sun3lance_dev = sun3lance_probe(-1); + if (IS_ERR(sun3lance_dev)) + return PTR_ERR(sun3lance_dev); + return 0; } void cleanup_module(void) { - unregister_netdev( &sun3lance_dev ); + unregister_netdev(sun3lance_dev); +#ifdef CONFIG_SUN3 + iounmap((void *)sun3lance_dev->base_addr); +#endif + free_netdev(sun3lance_dev); } #endif /* MODULE */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/tc35815.c 830-ivtv/drivers/net/tc35815.c --- 000-virgin/drivers/net/tc35815.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/tc35815.c Thu Jan 8 08:54:25 2004 @@ -463,7 +463,6 @@ static void tc35815_set_multicast_list(s static void tc35815_chip_reset(struct net_device *dev); static void tc35815_chip_init(struct net_device *dev); static void tc35815_phy_chip_init(struct net_device *dev); -static int tc35815_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data); /* A list of all installed tc35815 devices. */ static struct net_device *root_tc35815_dev = NULL; @@ -482,78 +481,76 @@ int tc35815_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - static int called = 0; int err = 0; int ret; + unsigned long pci_memaddr; + unsigned int pci_irq_line; - if (called) - return -ENODEV; - called++; + printk(KERN_INFO "tc35815_probe: found device %#08x.%#08x\n", ent->vendor, ent->device); - if (pdev) { - unsigned int pci_memaddr; - unsigned int pci_irq_line; + err = pci_enable_device(pdev); + if (err) + return err; - printk(KERN_INFO "tc35815_probe: found device %#08x.%#08x\n", ent->vendor, ent->device); + pci_memaddr = pci_resource_start (pdev, 1); - pci_memaddr = pci_resource_start (pdev, 1); + printk(KERN_INFO " pci_memaddr=%#08lx resource_flags=%#08lx\n", pci_memaddr, pci_resource_flags (pdev, 0)); - printk(KERN_INFO " pci_memaddr=%#08lx resource_flags=%#08lx\n", pci_memaddr, pci_resource_flags (pdev, 0)); + if (!pci_memaddr) { + printk(KERN_WARNING "no PCI MEM resources, aborting\n"); + ret = -ENODEV; + goto err_out; + } + pci_irq_line = pdev->irq; + /* irq disabled. */ + if (pci_irq_line == 0) { + printk(KERN_WARNING "no PCI irq, aborting\n"); + ret = -ENODEV; + goto err_out; + } - if (!pci_memaddr) { - printk(KERN_WARNING "no PCI MEM resources, aborting\n"); - return -ENODEV; - } - pci_irq_line = pdev->irq; - /* irq disabled. */ - if (pci_irq_line == 0) { - printk(KERN_WARNING "no PCI irq, aborting\n"); - return -ENODEV; - } + ret = tc35815_probe1(pdev, pci_memaddr, pci_irq_line); + if (ret) + goto err_out; - ret = tc35815_probe1(pdev, pci_memaddr, pci_irq_line); + pci_set_master(pdev); - if (!ret) { - if ((err = pci_enable_device(pdev)) < 0) { - printk(KERN_ERR "tc35815_probe: failed to enable device -- err=%d\n", err); - return err; - } - pci_set_master(pdev); - } + return 0; - return ret; - } - return -ENODEV; +err_out: + pci_disable_device(pdev); + return ret; } static int __devinit tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq) { static unsigned version_printed = 0; - int i; + int i, ret; struct tc35815_local *lp; struct tc35815_regs *tr; struct net_device *dev; /* Allocate a new 'dev' if needed. */ - dev = init_etherdev(NULL, sizeof(struct tc35815_local)); + dev = alloc_etherdev(sizeof(struct tc35815_local)); if (dev == NULL) return -ENOMEM; /* - * init_etherdev allocs and zeros dev->priv + * alloc_etherdev allocs and zeros dev->priv */ lp = dev->priv; if (tc35815_debug && version_printed++ == 0) printk(KERN_DEBUG "%s", version); - printk(KERN_INFO "%s: %s found at %#x, irq %d\n", - dev->name, cardname, base_addr, irq); - /* Fill in the 'dev' fields. */ dev->irq = irq; dev->base_addr = (unsigned long)ioremap(base_addr, sizeof(struct tc35815_regs)); + if (!dev->base_addr) { + ret = -ENOMEM; + goto err_out; + } tr = (struct tc35815_regs*)dev->base_addr; tc35815_chip_reset(dev); @@ -570,9 +567,6 @@ static int __devinit tc35815_probe1(stru dev->dev_addr[i] = data & 0xff; dev->dev_addr[i+1] = data >> 8; } - for (i = 0; i < 6; i++) - printk(" %2.2x", dev->dev_addr[i]); - printk("\n"); /* Initialize the device structure. */ lp->pdev = pdev; @@ -594,8 +588,6 @@ static int __devinit tc35815_probe1(stru /* do auto negotiation */ tc35815_phy_chip_init(dev); - printk(KERN_INFO "%s: linkspeed %dMbps, %s Duplex\n", - dev->name, lp->linkspeed, lp->fullduplex ? "Full" : "Half"); dev->open = tc35815_open; dev->stop = tc35815_close; @@ -604,20 +596,34 @@ static int __devinit tc35815_probe1(stru dev->hard_start_xmit = tc35815_send_packet; dev->get_stats = tc35815_get_stats; dev->set_multicast_list = tc35815_set_multicast_list; + SET_MODULE_OWNER(dev); -#if 0 /* XXX called in init_etherdev */ - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); -#endif + ret = register_netdev(dev); + if (ret) + goto err_out_iounmap; + + printk(KERN_INFO "%s: %s found at %#x, irq %d, MAC", + dev->name, cardname, base_addr, irq); + for (i = 0; i < 6; i++) + printk(" %2.2x", dev->dev_addr[i]); + printk("\n"); + printk(KERN_INFO "%s: linkspeed %dMbps, %s Duplex\n", + dev->name, lp->linkspeed, lp->fullduplex ? "Full" : "Half"); return 0; + +err_out_iounmap: + iounmap((void *) dev->base_addr); +err_out: + free_netdev(dev); + return ret; } static int tc35815_init_queues(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; int i; unsigned long fd_addr; @@ -702,7 +708,7 @@ tc35815_init_queues(struct net_device *d static void tc35815_clear_queues(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; int i; for (i = 0; i < TX_FD_NUM; i++) { @@ -719,7 +725,7 @@ tc35815_clear_queues(struct net_device * static void tc35815_free_queues(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; int i; if (lp->tfd_base) { @@ -805,7 +811,7 @@ dump_frfd(struct FrFD *fd) static void panic_queues(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; int i; printk("TxFD base %p, start %d, end %d\n", @@ -823,6 +829,7 @@ panic_queues(struct net_device *dev) panic("%s: Illegal queue state.", dev->name); } +#if 0 static void print_buf(char *add, int length) { int i; @@ -839,6 +846,7 @@ static void print_buf(char *add, int len } printk("\n"); } +#endif static void print_eth(char *add) { @@ -864,7 +872,7 @@ static void print_eth(char *add) static int tc35815_open(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; /* * This is used if the interrupt line can turned off (shared). * See 3c503.c for an example of selecting the IRQ at config-time. @@ -888,19 +896,17 @@ tc35815_open(struct net_device *dev) lp->tbusy = 0; netif_start_queue(dev); - MOD_INC_USE_COUNT; - return 0; } static void tc35815_tx_timeout(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr; - int flags; + unsigned long flags; spin_lock_irqsave(&lp->lock, flags); - printk(KERN_WARNING "%s: transmit timed out, status %#x\n", + printk(KERN_WARNING "%s: transmit timed out, status %#lx\n", dev->name, tc_readl(&tr->Tx_Stat)); /* Try to restart the adaptor. */ tc35815_chip_reset(dev); @@ -914,7 +920,7 @@ static void tc35815_tx_timeout(struct ne static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr; if (netif_queue_stopped(dev)) { @@ -925,7 +931,7 @@ static int tc35815_send_packet(struct sk int tickssofar = jiffies - dev->trans_start; if (tickssofar < 5) return 1; - printk(KERN_WARNING "%s: transmit timed out, status %#x\n", + printk(KERN_WARNING "%s: transmit timed out, status %#lx\n", dev->name, tc_readl(&tr->Tx_Stat)); /* Try to restart the adaptor. */ tc35815_chip_reset(dev); @@ -947,7 +953,7 @@ static int tc35815_send_packet(struct sk short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned char *buf = skb->data; struct TxFD *txfd = &lp->tfd_base[lp->tfd_start]; - int flags; + unsigned long flags; lp->stats.tx_bytes += skb->len; @@ -1051,7 +1057,7 @@ static irqreturn_t tc35815_interrupt(int } tr = (struct tc35815_regs*)dev->base_addr; - lp = (struct tc35815_local *)dev->priv; + lp = dev->priv; do { status = tc_readl(&tr->Int_Src); @@ -1107,7 +1113,7 @@ static irqreturn_t tc35815_interrupt(int static void tc35815_rx(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; unsigned int fdctl; int i; @@ -1157,7 +1163,9 @@ tc35815_rx(struct net_device *dev) offset += len; cur_bd++; } - // print_buf(data,pkt_len); +#if 0 + print_buf(data,pkt_len); +#endif if (tc35815_debug > 3) print_eth(data); skb->protocol = eth_type_trans(skb, dev); @@ -1247,7 +1255,7 @@ tc35815_rx(struct net_device *dev) static void tc35815_check_tx_stat(struct net_device *dev, int status) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; const char *msg = NULL; /* count collisions */ @@ -1304,7 +1312,7 @@ tc35815_check_tx_stat(struct net_device static void tc35815_txdone(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; struct TxFD *txfd; unsigned int fdctl; @@ -1379,7 +1387,7 @@ tc35815_txdone(struct net_device *dev) static int tc35815_close(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; lp->tbusy = 1; netif_stop_queue(dev); @@ -1391,8 +1399,6 @@ tc35815_close(struct net_device *dev) tc35815_free_queues(dev); - MOD_DEC_USE_COUNT; - return 0; } @@ -1402,7 +1408,7 @@ tc35815_close(struct net_device *dev) */ static struct net_device_stats *tc35815_get_stats(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; unsigned long flags; @@ -1456,7 +1462,7 @@ static void tc35815_set_cam_entry(struct int i; for (i = cam_index / 4; i < cam_index / 4 + 2; i++) { tc_writel(i * 4, &tr->CAM_Adr); - printk("CAM 0x%x: %08x", + printk("CAM 0x%x: %08lx", i * 4, tc_readl(&tr->CAM_Data)); } } @@ -1513,9 +1519,9 @@ tc35815_set_multicast_list(struct net_de static unsigned long tc_phy_read(struct net_device *dev, struct tc35815_regs *tr, int phy, int phy_reg) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; unsigned long data; - int flags; + unsigned long flags; spin_lock_irqsave(&lp->lock, flags); @@ -1529,8 +1535,8 @@ static unsigned long tc_phy_read(struct static void tc_phy_write(struct net_device *dev, unsigned long d, struct tc35815_regs *tr, int phy, int phy_reg) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; - int flags; + struct tc35815_local *lp = dev->priv; + unsigned long flags; spin_lock_irqsave(&lp->lock, flags); @@ -1543,7 +1549,7 @@ static void tc_phy_write(struct net_devi static void tc35815_phy_chip_init(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; static int first = 1; unsigned short ctl; @@ -1648,9 +1654,9 @@ static void tc35815_chip_reset(struct ne static void tc35815_chip_init(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; - int flags; + unsigned long flags; unsigned long txctl = TX_CTL_CMD; tc35815_phy_chip_init(dev); @@ -1694,40 +1700,6 @@ static void tc35815_chip_init(struct net tc_writel(virt_to_bus(lp->tfd_base), &tr->TxFrmPtr); /* start DMA transmitter */ #endif spin_unlock_irqrestore(&lp->lock, flags); -} - -static int tc35815_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data) -{ - int len = 0; - off_t pos = 0; - off_t begin = 0; - struct net_device *dev; - - len += sprintf(buffer, "TC35815 statistics:\n"); - for (dev = root_tc35815_dev; dev; dev = ((struct tc35815_local *)dev->priv)->next_module) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; - len += sprintf(buffer + len, - "%s: tx_ints %d, rx_ints %d, max_tx_qlen %d\n", - dev->name, - lp->lstats.tx_ints, - lp->lstats.rx_ints, - lp->lstats.max_tx_qlen); - pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; - } - - if (pos > offset+length) break; - } - - *start = buffer + (offset - begin); - len -= (offset - begin); - - if (len > length) len = length; - - return len; } /* XXX */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/tg3.c 830-ivtv/drivers/net/tg3.c --- 000-virgin/drivers/net/tg3.c Thu Jan 8 08:35:38 2004 +++ 830-ivtv/drivers/net/tg3.c Thu Jan 8 08:54:25 2004 @@ -2479,6 +2479,13 @@ static irqreturn_t tg3_interrupt(int irq static int tg3_init_hw(struct tg3 *); static int tg3_halt(struct tg3 *); +#ifdef CONFIG_NET_POLL_CONTROLLER +static void tg3_poll_controller(struct net_device *dev) +{ + tg3_interrupt(dev->irq, dev, NULL); +} +#endif + static void tg3_reset_task(void *_data) { struct tg3 *tp = _data; @@ -7665,6 +7672,10 @@ static int __devinit tg3_init_one(struct dev->watchdog_timeo = TG3_TX_TIMEOUT; dev->change_mtu = tg3_change_mtu; dev->irq = pdev->irq; + #ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = tg3_poll_controller; + #endif + err = tg3_get_invariants(tp); if (err) { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/tlan.c 830-ivtv/drivers/net/tlan.c --- 000-virgin/drivers/net/tlan.c Mon Dec 8 09:55:51 2003 +++ 830-ivtv/drivers/net/tlan.c Thu Jan 8 08:54:25 2004 @@ -814,6 +814,14 @@ static void __init TLan_EisaProbe (void } /* TLan_EisaProbe */ +#ifdef CONFIG_NET_POLL_CONTROLLER +static void TLan_Poll(struct net_device *dev) +{ + disable_irq(dev->irq); + TLan_HandleInterrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif @@ -893,6 +901,9 @@ static int TLan_Init( struct net_device dev->get_stats = &TLan_GetStats; dev->set_multicast_list = &TLan_SetMulticastList; dev->do_ioctl = &TLan_ioctl; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = &TLan_Poll; +#endif dev->tx_timeout = &TLan_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/tokenring/3c359.c 830-ivtv/drivers/net/tokenring/3c359.c --- 000-virgin/drivers/net/tokenring/3c359.c Tue Sep 2 09:55:48 2003 +++ 830-ivtv/drivers/net/tokenring/3c359.c Thu Jan 8 08:54:25 2004 @@ -314,7 +314,6 @@ int __devinit xl_probe(struct pci_dev *p dev->irq=pdev->irq; dev->base_addr=pci_resource_start(pdev,0) ; - dev->init=NULL ; /* Must be null with new api, otherwise get called twice */ xl_priv->xl_card_name = pci_name(pdev); xl_priv->xl_mmio=ioremap(pci_resource_start(pdev,1), XL_IO_SPACE); xl_priv->pdev = pdev ; @@ -332,7 +331,7 @@ int __devinit xl_probe(struct pci_dev *p if((i = xl_init(dev))) { iounmap(xl_priv->xl_mmio) ; - kfree(dev) ; + free_netdev(dev) ; pci_release_regions(pdev) ; return i ; } @@ -352,7 +351,7 @@ int __devinit xl_probe(struct pci_dev *p printk(KERN_ERR "3C359, register netdev failed\n") ; pci_set_drvdata(pdev,NULL) ; iounmap(xl_priv->xl_mmio) ; - kfree(dev) ; + free_netdev(dev) ; pci_release_regions(pdev) ; return i ; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/tokenring/abyss.c 830-ivtv/drivers/net/tokenring/abyss.c --- 000-virgin/drivers/net/tokenring/abyss.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/tokenring/abyss.c Thu Jan 8 08:54:25 2004 @@ -181,7 +181,7 @@ err_out_irq: err_out_region: release_region(pci_ioaddr, ABYSS_IO_EXTENT); err_out_trdev: - kfree(dev); + free_netdev(dev); return ret; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/tokenring/ibmtr.c 830-ivtv/drivers/net/tokenring/ibmtr.c --- 000-virgin/drivers/net/tokenring/ibmtr.c Mon Dec 8 09:55:51 2003 +++ 830-ivtv/drivers/net/tokenring/ibmtr.c Thu Jan 8 08:54:25 2004 @@ -187,7 +187,7 @@ char __devinit *adapter_def(char type) #define TRC_INITV 0x02 /* verbose init trace points */ unsigned char ibmtr_debug_trace = 0; -int ibmtr_probe(struct net_device *dev); +static int ibmtr_probe(struct net_device *dev); static int ibmtr_probe1(struct net_device *dev, int ioaddr); static unsigned char get_sram_size(struct tok_info *adapt_info); static int trdev_init(struct net_device *dev); @@ -313,6 +313,39 @@ static void __devinit find_turbo_adapter } } +static void ibmtr_cleanup_card(struct net_device *dev) +{ + if (dev->base_addr) { + outb(0,dev->base_addr+ADAPTRESET); + + schedule_timeout(TR_RST_TIME); /* wait 50ms */ + + outb(0,dev->base_addr+ADAPTRESETREL); + } + +#ifndef PCMCIA + free_irq(dev->irq, dev); + release_region(dev->base_addr, IBMTR_IO_EXTENT); + + { + struct tok_info *ti = (struct tok_info *) dev->priv; + iounmap((u32 *)ti->mmio); + iounmap((u32 *)ti->sram_virt); + } +#endif +} + +int ibmtr_probe_card(struct net_device *dev) +{ + int err = ibmtr_probe(dev); + if (!err) { + err = register_netdev(dev); + if (err) + ibmtr_cleanup_card(dev); + } + return err; +} + /**************************************************************************** * ibmtr_probe(): Routine specified in the network device structure * to probe for an IBM Token Ring Adapter. Routine outline: @@ -325,7 +358,7 @@ static void __devinit find_turbo_adapter * which references it. ****************************************************************************/ -int __devinit ibmtr_probe(struct net_device *dev) +static int ibmtr_probe(struct net_device *dev) { int i; int base_addr = dev->base_addr; @@ -1925,23 +1958,24 @@ static int __init ibmtr_init(void) find_turbo_adapters(io); for (i = 0; io[i] && (i < IBMTR_MAX_ADAPTERS); i++) { + struct net_device *dev; irq[i] = 0; mem[i] = 0; - dev_ibmtr[i] = alloc_trdev(sizeof(struct tok_info)); - if (dev_ibmtr[i] == NULL) { + dev = alloc_trdev(sizeof(struct tok_info)); + if (dev == NULL) { if (i == 0) return -ENOMEM; break; } - dev_ibmtr[i]->base_addr = io[i]; - dev_ibmtr[i]->irq = irq[i]; - dev_ibmtr[i]->mem_start = mem[i]; - dev_ibmtr[i]->init = &ibmtr_probe; - if (register_netdev(dev_ibmtr[i]) != 0) { - kfree(dev_ibmtr[i]); - dev_ibmtr[i] = NULL; + dev->base_addr = io[i]; + dev->irq = irq[i]; + dev->mem_start = mem[i]; + + if (ibmtr_probe_card(dev)) { + free_netdev(dev); continue; } + dev_ibmtr[i] = dev; count++; } if (count) return 0; @@ -1957,27 +1991,9 @@ static void __exit ibmtr_cleanup(void) for (i = 0; i < IBMTR_MAX_ADAPTERS; i++){ if (!dev_ibmtr[i]) continue; - if (dev_ibmtr[i]->base_addr) { - outb(0,dev_ibmtr[i]->base_addr+ADAPTRESET); - - schedule_timeout(TR_RST_TIME); /* wait 50ms */ - - outb(0,dev_ibmtr[i]->base_addr+ADAPTRESETREL); - } - unregister_netdev(dev_ibmtr[i]); - free_irq(dev_ibmtr[i]->irq, dev_ibmtr[i]); - release_region(dev_ibmtr[i]->base_addr, IBMTR_IO_EXTENT); -#ifndef PCMCIA - { - struct tok_info *ti = (struct tok_info *) - dev_ibmtr[i]->priv; - iounmap((u32 *)ti->mmio); - iounmap((u32 *)ti->sram_virt); - } -#endif + ibmtr_cleanup_card(dev_ibmtr[i]); free_netdev(dev_ibmtr[i]); - dev_ibmtr[i] = NULL; } } module_exit(ibmtr_cleanup); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/tokenring/madgemc.c 830-ivtv/drivers/net/tokenring/madgemc.c --- 000-virgin/drivers/net/tokenring/madgemc.c Mon Nov 17 18:29:30 2003 +++ 830-ivtv/drivers/net/tokenring/madgemc.c Thu Jan 8 08:54:25 2004 @@ -197,7 +197,7 @@ static int __init madgemc_probe(void) card = kmalloc(sizeof(struct madgemc_card), GFP_KERNEL); if (card==NULL) { printk("madgemc: unable to allocate card struct\n"); - kfree(dev); + free_netdev(dev); if (madgemc_card_list) return 0; return -1; @@ -360,7 +360,7 @@ static int __init madgemc_probe(void) kfree(card); tmsdev_term(dev); - kfree(dev); + free_netdev(dev); if (madgemc_card_list) return 0; return -1; @@ -399,7 +399,7 @@ static int __init madgemc_probe(void) MADGEMC_IO_EXTENT); getout1: kfree(card); - kfree(dev); + free_netdev(dev); slot++; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/tokenring/olympic.c 830-ivtv/drivers/net/tokenring/olympic.c --- 000-virgin/drivers/net/tokenring/olympic.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/tokenring/olympic.c Thu Jan 8 08:54:25 2004 @@ -228,7 +228,6 @@ static int __devinit olympic_probe(struc #endif dev->irq=pdev->irq; dev->base_addr=pci_resource_start(pdev, 0); - dev->init=NULL; /* Must be NULL otherwise we get called twice */ olympic_priv->olympic_card_name = pci_name(pdev); olympic_priv->pdev = pdev; olympic_priv->olympic_mmio = ioremap(pci_resource_start(pdev,1),256); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/tokenring/proteon.c 830-ivtv/drivers/net/tokenring/proteon.c --- 000-virgin/drivers/net/tokenring/proteon.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/tokenring/proteon.c Thu Jan 8 08:54:25 2004 @@ -63,7 +63,7 @@ static int dmalist[] __initdata = { static char cardname[] = "Proteon 1392\0"; -int proteon_probe(struct net_device *dev); +struct net_device *proteon_probe(int unit); static int proteon_open(struct net_device *dev); static int proteon_close(struct net_device *dev); static void proteon_read_eeprom(struct net_device *dev); @@ -89,80 +89,69 @@ static void proteon_sifwritew(struct net outw(val, dev->base_addr + reg); } -struct proteon_card { - struct net_device *dev; - struct proteon_card *next; -}; - -static struct proteon_card *proteon_card_list; - -static int __init proteon_probe1(int ioaddr) +static int __init proteon_probe1(struct net_device *dev, int ioaddr) { unsigned char chk1, chk2; int i; + if (!request_region(ioaddr, PROTEON_IO_EXTENT, cardname)) + return -ENODEV; + + chk1 = inb(ioaddr + 0x1f); /* Get Proteon ID reg 1 */ - if (chk1 != 0x1f) - return (-1); + if (chk1 != 0x1f) + goto nodev; + chk1 = inb(ioaddr + 0x1e) & 0x07; /* Get Proteon ID reg 0 */ for (i=0; i<16; i++) { chk2 = inb(ioaddr + 0x1e) & 0x07; if (((chk1 + 1) & 0x07) != chk2) - return (-1); + goto nodev; chk1 = chk2; } + + dev->base_addr = ioaddr; return (0); +nodev: + release_region(ioaddr, PROTEON_IO_EXTENT); + return -ENODEV; } -int __init proteon_probe(struct net_device *dev) +struct net_device * __init proteon_probe(int unit) { - static int versionprinted; + struct net_device *dev = alloc_trdev(sizeof(struct net_local)); struct net_local *tp; - int i,j; - struct proteon_card *card; - -#ifndef MODULE - netdev_boot_setup_check(dev); - tr_setup(dev); -#endif + static int versionprinted; + const unsigned *port; + int j,err = 0; - SET_MODULE_OWNER(dev); - if (!dev->base_addr) - { - for(i = 0; portlist[i]; i++) - { - if (!request_region(portlist[i], PROTEON_IO_EXTENT, cardname)) - continue; + if (!dev) + return ERR_PTR(-ENOMEM); - if(proteon_probe1(portlist[i])) - { - release_region(dev->base_addr, PROTEON_IO_EXTENT); - continue; - } + if (unit >= 0) { + sprintf(dev->name, "tr%d", unit); + netdev_boot_setup_check(dev); + } - dev->base_addr = portlist[i]; - break; + SET_MODULE_OWNER(dev); + if (dev->base_addr) /* probe specific location */ + err = proteon_probe1(dev, dev->base_addr); + else { + for (port = portlist; *port; port++) { + err = proteon_probe1(dev, *port); + if (!err) + break; } - if(!dev->base_addr) - return -1; } - else - { - if (!request_region(dev->base_addr, PROTEON_IO_EXTENT, cardname)) - return -1; - - if(proteon_probe1(dev->base_addr)) - { - release_region(dev->base_addr, PROTEON_IO_EXTENT); - return -1; - } - } + if (err) + goto out4; /* At this point we have found a valid card. */ if (versionprinted++ == 0) printk(KERN_DEBUG "%s", version); + err = -EIO; if (tmsdev_init(dev, ISA_MAX_ADDRESS, NULL)) goto out4; @@ -264,14 +253,11 @@ int __init proteon_probe(struct net_devi printk(KERN_DEBUG "%s: IO: %#4lx IRQ: %d DMA: %d\n", dev->name, dev->base_addr, dev->irq, dev->dma); - /* Enlist in the card list */ - card = kmalloc(sizeof(struct proteon_card), GFP_KERNEL); - if (!card) + err = register_netdev(dev); + if (err) goto out; - card->next = proteon_card_list; - proteon_card_list = card; - card->dev = dev; - return 0; + + return dev; out: free_dma(dev->dma); out2: @@ -280,7 +266,8 @@ out3: tmsdev_term(dev); out4: release_region(dev->base_addr, PROTEON_IO_EXTENT); - return -1; + free_netdev(dev); + return ERR_PTR(err); } /* @@ -370,50 +357,50 @@ MODULE_PARM(io, "1-" __MODULE_STRING(ISA MODULE_PARM(irq, "1-" __MODULE_STRING(ISATR_MAX_ADAPTERS) "i"); MODULE_PARM(dma, "1-" __MODULE_STRING(ISATR_MAX_ADAPTERS) "i"); -static int __init setup_card(unsigned long io, unsigned irq, unsigned char dma) +static struct net_device *proteon_dev[ISATR_MAX_ADAPTERS]; + +static struct net_device * __init setup_card(unsigned long io, unsigned irq, unsigned char dma) { - int res = -ENOMEM; - struct proteon_card *this_card; - struct net_device *dev = alloc_trdev(0); - - if (dev) { - dev->base_addr = io; - dev->irq = irq; - dev->dma = dma; - res = -ENODEV; - if (proteon_probe(dev) == 0) { - res = register_netdev(dev); - if (!res) - return 0; - release_region(dev->base_addr, PROTEON_IO_EXTENT); - free_irq(dev->irq, dev); - free_dma(dev->dma); - tmsdev_term(dev); - this_card = proteon_card_list; - proteon_card_list = this_card->next; - kfree(this_card); - } - kfree(dev); - } - return res; + struct net_device *dev = alloc_trdev(sizeof(struct net_local)); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + dev->irq = irq; + dev->dma = dma; + err = proteon_probe1(dev, io); + if (err) + goto out; + + err = register_netdev(dev); + if (err) + goto out1; + return dev; + out1: + release_region(dev->base_addr, PROTEON_IO_EXTENT); + free_irq(dev->irq, dev); + free_dma(dev->dma); + tmsdev_term(dev); + out: + free_netdev(dev); + return ERR_PTR(err); } int init_module(void) { - int i, num; + struct net_device *dev; + int i, num = 0; - num = 0; - if (io[0]) { /* Only probe addresses from command line */ - for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { - if (io[i] && setup_card(io[i], irq[i], dma[i]) == 0) - num++; - } - } else { - for(i = 0; num < ISATR_MAX_ADAPTERS && portlist[i]; i++) { - if (setup_card(portlist[i], irq[num], dma[num]) == 0) - num++; + for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { + dev = io[0] ? setup_card(io[i], irq[i], dma[i]) + : proteon_probe(-1); + if (!IS_ERR(dev)) { + proteon_dev[i] = dev; + ++num; } } + printk(KERN_NOTICE "proteon.c: %d cards found.\n", num); /* Probe for cards. */ if (num == 0) { @@ -425,11 +412,13 @@ int init_module(void) void cleanup_module(void) { - struct net_device *dev; - struct proteon_card *this_card; + int i; - while (proteon_card_list) { - dev = proteon_card_list->dev; + for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { + struct net_device *dev = proteon_dev[i]; + + if (!dev) + continue; unregister_netdev(dev); release_region(dev->base_addr, PROTEON_IO_EXTENT); @@ -437,9 +426,6 @@ void cleanup_module(void) free_dma(dev->dma); tmsdev_term(dev); free_netdev(dev); - this_card = proteon_card_list; - proteon_card_list = this_card->next; - kfree(this_card); } } #endif /* MODULE */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/tokenring/skisa.c 830-ivtv/drivers/net/tokenring/skisa.c --- 000-virgin/drivers/net/tokenring/skisa.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/tokenring/skisa.c Thu Jan 8 08:54:25 2004 @@ -56,7 +56,7 @@ static unsigned int portlist[] __initdat /* A zero-terminated list of IRQs to be probed. * Used again after initial probe for sktr_chipset_init, called from sktr_open. */ -static unsigned short irqlist[] = { +static const unsigned short irqlist[] = { 3, 5, 9, 10, 11, 12, 15, 0 }; @@ -69,7 +69,6 @@ static int dmalist[] __initdata = { static char isa_cardname[] = "SK NET TR 4/16 ISA\0"; -int sk_isa_probe(struct net_device *dev); static int sk_isa_open(struct net_device *dev); static int sk_isa_close(struct net_device *dev); static void sk_isa_read_eeprom(struct net_device *dev); @@ -95,17 +94,14 @@ static void sk_isa_sifwritew(struct net_ outw(val, dev->base_addr + reg); } -struct sk_isa_card { - struct net_device *dev; - struct sk_isa_card *next; -}; - -static struct sk_isa_card *sk_isa_card_list; -static int __init sk_isa_probe1(int ioaddr) +static int __init sk_isa_probe1(struct net_device *dev, int ioaddr) { unsigned char old, chk1, chk2; + if (!request_region(ioaddr, SK_ISA_IO_EXTENT, isa_cardname)) + return -ENODEV; + old = inb(ioaddr + SIFADR); /* Get the old SIFADR value */ chk1 = 0; /* Begin with check value 0 */ @@ -122,8 +118,10 @@ static int __init sk_isa_probe1(int ioad chk2 = inb(ioaddr + SIFADD); chk2 ^= 0x0FE; - if(chk1 != chk2) - return (-1); /* No adapter */ + if(chk1 != chk2) { + release_region(ioaddr, SK_ISA_IO_EXTENT); + return -ENODEV; + } chk1 -= 2; } while(chk1 != 0); /* Repeat 128 times (all byte values) */ @@ -131,58 +129,45 @@ static int __init sk_isa_probe1(int ioad /* Restore the SIFADR value */ outb(old, ioaddr + SIFADR); - return (0); + dev->base_addr = ioaddr; + return 0; } -int __init sk_isa_probe(struct net_device *dev) +struct net_device * __init sk_isa_probe(int unit) { - static int versionprinted; + struct net_device *dev = alloc_trdev(sizeof(struct net_local)); struct net_local *tp; - int i,j; - struct sk_isa_card *card; + static int versionprinted; + const unsigned *port; + int j, err = 0; -#ifndef MODULE - netdev_boot_setup_check(dev); - tr_setup(dev); -#endif + if (!dev) + return ERR_PTR(-ENOMEM); - SET_MODULE_OWNER(dev); - if (!dev->base_addr) - { - for(i = 0; portlist[i]; i++) - { - if (!request_region(portlist[i], SK_ISA_IO_EXTENT, isa_cardname)) - continue; - - if(sk_isa_probe1(portlist[i])) - { - release_region(dev->base_addr, SK_ISA_IO_EXTENT); - continue; - } + if (unit >= 0) { + sprintf(dev->name, "tr%d", unit); + netdev_boot_setup_check(dev); + } - dev->base_addr = portlist[i]; - break; + SET_MODULE_OWNER(dev); + if (dev->base_addr) /* probe specific location */ + err = sk_isa_probe1(dev, dev->base_addr); + else { + for (port = portlist; *port; port++) { + err = sk_isa_probe1(dev, *port); + if (!err) + break; } - if(!dev->base_addr) - return -1; } - else - { - if (!request_region(dev->base_addr, SK_ISA_IO_EXTENT, isa_cardname)) - return -1; - - if(sk_isa_probe1(dev->base_addr)) - { - release_region(dev->base_addr, SK_ISA_IO_EXTENT); - return -1; - } - } + if (err) + goto out4; /* At this point we have found a valid card. */ if (versionprinted++ == 0) printk(KERN_DEBUG "%s", version); + err = -EIO; if (tmsdev_init(dev, ISA_MAX_ADDRESS, NULL)) goto out4; @@ -284,14 +269,11 @@ int __init sk_isa_probe(struct net_devic printk(KERN_DEBUG "%s: IO: %#4lx IRQ: %d DMA: %d\n", dev->name, dev->base_addr, dev->irq, dev->dma); - /* Enlist in the card list */ - card = kmalloc(sizeof(struct sk_isa_card), GFP_KERNEL); - if (!card) + err = register_netdev(dev); + if (err) goto out; - card->next = sk_isa_card_list; - sk_isa_card_list = card; - card->dev = dev; - return 0; + + return dev; out: free_dma(dev->dma); out2: @@ -300,7 +282,8 @@ out3: tmsdev_term(dev); out4: release_region(dev->base_addr, SK_ISA_IO_EXTENT); - return -1; + free_netdev(dev); + return ERR_PTR(err); } /* @@ -373,6 +356,8 @@ static int sk_isa_close(struct net_devic #define ISATR_MAX_ADAPTERS 3 +static struct net_device *sk_isa_dev[ISATR_MAX_ADAPTERS]; + static int io[ISATR_MAX_ADAPTERS]; static int irq[ISATR_MAX_ADAPTERS]; static int dma[ISATR_MAX_ADAPTERS]; @@ -383,50 +368,54 @@ MODULE_PARM(io, "1-" __MODULE_STRING(ISA MODULE_PARM(irq, "1-" __MODULE_STRING(ISATR_MAX_ADAPTERS) "i"); MODULE_PARM(dma, "1-" __MODULE_STRING(ISATR_MAX_ADAPTERS) "i"); -static int __init setup_card(unsigned long io, unsigned irq, unsigned char dma) +static struct net_device * __init setup_card(unsigned long io, unsigned irq, unsigned char dma) { - int res = -ENOMEM; - struct sk_isa_card *this_card; - struct net_device *dev = alloc_trdev(0); - - if (dev) { - dev->base_addr = io; - dev->irq = irq; - dev->dma = dma; - res = -ENODEV; - if (sk_isa_probe(dev) == 0) { - res = register_netdev(dev); - if (!res) - return 0; - release_region(dev->base_addr, SK_ISA_IO_EXTENT); - free_irq(dev->irq, dev); - free_dma(dev->dma); - tmsdev_term(dev); - this_card = sk_isa_card_list; - sk_isa_card_list = this_card->next; - kfree(this_card); - } - kfree(dev); - } - return res; + struct net_device *dev = alloc_trdev(sizeof(struct net_local)); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + dev->base_addr = io; + dev->irq = irq; + dev->dma = dma; + + err = sk_isa_probe1(dev, io); + if (err) + goto out; + + err = register_netdev(dev); + if (err) + goto out1; + return dev; + + out1: + release_region(dev->base_addr, SK_ISA_IO_EXTENT); + free_irq(dev->irq, dev); + free_dma(dev->dma); + tmsdev_term(dev); + out: + free_netdev(dev); + return ERR_PTR(err); } int init_module(void) { + struct net_device *dev; int i, num; num = 0; - if (io[0]) { /* Only probe addresses from command line */ - for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { - if (io[i] && setup_card(io[i], irq[i], dma[i]) == 0) - num++; - } - } else { - for(i = 0; num < ISATR_MAX_ADAPTERS && portlist[i]; i++) { - if (setup_card(portlist[i], irq[num], dma[num]) == 0) - num++; + for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { + if (io[0]) /* Only probe addresses from command line */ + dev = setup_card(io[i], irq[i], dma[i]); + else + dev = sk_isa_probe(-1); + if (!IS_ERR(dev)) { + sk_isa_dev[i] = dev; + ++num; } } + printk(KERN_NOTICE "skisa.c: %d cards found.\n", num); /* Probe for cards. */ if (num == 0) { @@ -438,11 +427,13 @@ int init_module(void) void cleanup_module(void) { - struct net_device *dev; - struct sk_isa_card *this_card; + int i; + + for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { + struct net_device *dev = sk_isa_dev[i]; - while (sk_isa_card_list) { - dev = sk_isa_card_list->dev; + if (!dev) + continue; unregister_netdev(dev); release_region(dev->base_addr, SK_ISA_IO_EXTENT); @@ -450,9 +441,6 @@ void cleanup_module(void) free_dma(dev->dma); tmsdev_term(dev); free_netdev(dev); - this_card = sk_isa_card_list; - sk_isa_card_list = this_card->next; - kfree(this_card); } } #endif /* MODULE */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/tokenring/smctr.c 830-ivtv/drivers/net/tokenring/smctr.c --- 000-virgin/drivers/net/tokenring/smctr.c Mon Nov 17 18:29:30 2003 +++ 830-ivtv/drivers/net/tokenring/smctr.c Thu Jan 8 08:54:26 2004 @@ -69,13 +69,6 @@ static const char cardname[] = "smctr"; #define SMCTR_IO_EXTENT 20 -/* A zero-terminated list of I/O addresses to be probed. */ -static unsigned int smctr_portlist[] __initdata = { - 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0, 0x300, - 0x320, 0x340, 0x360, 0x380, - 0 -}; - #ifdef CONFIG_MCA static unsigned int smctr_posid = 0x6ec6; #endif @@ -219,7 +212,7 @@ static int smctr_open(struct net_device static int smctr_open_tr(struct net_device *dev); /* P */ -int __init smctr_probe (struct net_device *dev); +struct net_device *smctr_probe(int unit); static int __init smctr_probe1(struct net_device *dev, int ioaddr); static int smctr_process_rx_packet(MAC_HEADER *rmf, __u16 size, struct net_device *dev, __u16 rx_status); @@ -729,10 +722,6 @@ static int smctr_close(struct net_device netif_stop_queue(dev); -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif - tp->cleanup = 1; /* Check to see if adapter is already in a closed state. */ @@ -3490,10 +3479,6 @@ static int smctr_open(struct net_device if(err < 0) return (err); -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif - return (err); } @@ -3591,71 +3576,72 @@ out: return (err); } -/* Check for a network adapter of this type, and return '0 if one exists. - * If dev->base_addr == 0, probe all likely locations. - * If dev->base_addr == 1, always return failure. +/* Check for a network adapter of this type, + * and return device structure if one exists. */ -int __init smctr_probe (struct net_device *dev) +struct net_device __init *smctr_probe(int unit) { - int i; - int base_addr; - -#ifndef MODULE - netdev_boot_setup_check(dev); - tr_setup(dev); -#endif + struct net_device *dev = alloc_trdev(sizeof(struct net_local)); + static const unsigned ports[] = { + 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0, 0x300, + 0x320, 0x340, 0x360, 0x380, 0 + }; + const unsigned *port; + int err = 0; - base_addr = dev->base_addr; - if(base_addr > 0x1ff) /* Check a single specified location. */ - return (smctr_probe1(dev, base_addr)); - else if(base_addr != 0) /* Don't probe at all. */ - return (-ENXIO); + if (!dev) + return ERR_PTR(-ENOMEM); - for(i = 0; smctr_portlist[i]; i++) - { - int ioaddr = smctr_portlist[i]; - if (!smctr_probe1(dev, ioaddr)) - return (0); - } + SET_MODULE_OWNER(dev); - return (-ENODEV); -} + if (unit >= 0) { + sprintf(dev->name, "tr%d", unit); + netdev_boot_setup_check(dev); + } -static void cleanup_card(struct net_device *dev) -{ + if (dev->base_addr > 0x1ff) /* Check a single specified location. */ + err = smctr_probe1(dev, dev->base_addr); + else if(dev->base_addr != 0) /* Don't probe at all. */ + err =-ENXIO; + else { + for (port = ports; *port; port++) { + err = smctr_probe1(dev, *port); + if (!err) + break; + } + } + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: #ifdef CONFIG_MCA - struct net_local *tp = (struct net_local *)dev->priv; - if (tp->slot_num) + { struct net_local *tp = (struct net_local *)dev->priv; + if (tp->slot_num) mca_mark_as_unused(tp->slot_num); + } #endif release_region(dev->base_addr, SMCTR_IO_EXTENT); - if (dev->irq) - free_irq(dev->irq, dev); - if (dev->priv) - kfree(dev->priv); + free_irq(dev->irq, dev); +out: + free_netdev(dev); + return ERR_PTR(err); } + static int __init smctr_probe1(struct net_device *dev, int ioaddr) { static unsigned version_printed; - struct net_local *tp; + struct net_local *tp = dev->priv; int err; __u32 *ram; if(smctr_debug && version_printed++ == 0) printk(version); - /* Setup this devices private information structure */ - tp = (struct net_local *)kmalloc(sizeof(struct net_local), - GFP_KERNEL); - if(tp == NULL) { - err = -ENOMEM; - goto out; - } - memset(tp, 0, sizeof(struct net_local)); spin_lock_init(&tp->lock); - - dev->priv = tp; dev->base_addr = ioaddr; /* Actually detect an adapter now. */ @@ -3664,7 +3650,7 @@ static int __init smctr_probe1(struct ne { if ((err = smctr_chk_mca(dev)) < 0) { err = -ENODEV; - goto out_tp; + goto out; } } @@ -3679,7 +3665,6 @@ static int __init smctr_probe1(struct ne if(err != UCODE_PRESENT && err != SUCCESS) { printk(KERN_ERR "%s: Firmware load failed (%d)\n", dev->name, err); - cleanup_card(dev); err = -EIO; goto out; } @@ -3704,8 +3689,6 @@ static int __init smctr_probe1(struct ne dev->set_multicast_list = &smctr_set_multicast_list; return (0); -out_tp: - kfree(tp); out: return err; } @@ -5677,47 +5660,59 @@ static int smctr_wait_while_cbusy(struct static struct net_device* dev_smctr[SMCTR_MAX_ADAPTERS]; static int io[SMCTR_MAX_ADAPTERS]; static int irq[SMCTR_MAX_ADAPTERS]; -static int mem[SMCTR_MAX_ADAPTERS]; MODULE_LICENSE("GPL"); -MODULE_PARM(io, "1-" __MODULE_STRING(SMCTR_MAX_ADAPTERS) "i"); +MODULE_PARM(io, "1-" __MODULE_STRING(SMCTR_MAX_ADAPTERS) "i"); MODULE_PARM(irq, "1-" __MODULE_STRING(SMCTR_MAX_ADAPTERS) "i"); -MODULE_PARM(mem, "1-" __MODULE_STRING(SMCTR_MAX_ADAPTERS) "i"); -MODULE_PARM(ringspeed, "1-" __MODULE_STRING(SMCTR_MAX_ADAPTERS) "i"); +MODULE_PARM(ringspeed, "i"); + +static struct net_device *setup_card(int n) +{ + struct net_device *dev = alloc_trdev(sizeof(struct net_local)); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + dev->irq = irq[n]; + err = smctr_probe1(dev, io[n]); + if (err) + goto out; + + err = register_netdev(dev); + if (err) + goto out1; + return dev; + out1: +#ifdef CONFIG_MCA + { struct net_local *tp = (struct net_local *)dev->priv; + if (tp->slot_num) + mca_mark_as_unused(tp->slot_num); + } +#endif + release_region(dev->base_addr, SMCTR_IO_EXTENT); + free_irq(dev->irq, dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + int init_module(void) { - int i; + int i, found = 0; + struct net_device *dev; for(i = 0; i < SMCTR_MAX_ADAPTERS; i++) { - struct net_device *dev = alloc_trdev(0); - irq[i] = 0; - mem[i] = 0; - if (!dev) - return -ENOMEM; - dev->base_addr = io[i]; - dev->irq = irq[i]; - dev->mem_start = mem[i]; - - if (smctr_probe(dev) != 0) { - kfree(dev); - if (i == 0) { - printk(KERN_ERR "%s: smctr_probe failed.\n", - cardname); - return -EIO; - } - return 0; - } - if (register_netdev(dev) != 0) { - cleanup_card(dev); - kfree(dev); - continue; - } - dev_smctr[i] = dev; + dev = io[0]? setup_card(i) : smctr_probe(-1); + if (!IS_ERR(dev)) { + ++found; + dev_smctr[i] = dev; + } } - return (0); + return found ? 0 : -ENODEV; } void cleanup_module(void) @@ -5726,9 +5721,20 @@ void cleanup_module(void) for(i = 0; i < SMCTR_MAX_ADAPTERS; i++) { struct net_device *dev = dev_smctr[i]; + if (dev) { + unregister_netdev(dev); - cleanup_card(dev); +#ifdef CONFIG_MCA + { struct net_local *tp = dev->priv; + if (tp->slot_num) + mca_mark_as_unused(tp->slot_num); + } +#endif + release_region(dev->base_addr, SMCTR_IO_EXTENT); + if (dev->irq) + free_irq(dev->irq, dev); + free_netdev(dev); } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/tokenring/tms380tr.c 830-ivtv/drivers/net/tokenring/tms380tr.c --- 000-virgin/drivers/net/tokenring/tms380tr.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/tokenring/tms380tr.c Thu Jan 8 08:54:26 2004 @@ -147,7 +147,6 @@ static void tms380tr_hardware_send_pack struct net_local* tp); /* "I" */ static int tms380tr_init_adapter(struct net_device *dev); -static int tms380tr_init_card(struct net_device *dev); static void tms380tr_init_ipb(struct net_local *tp); static void tms380tr_init_net_local(struct net_device *dev); static void tms380tr_init_opb(struct net_device *dev); @@ -232,15 +231,6 @@ static int madgemc_sifprobe(struct net_d } #endif -/* Dummy function */ -static int tms380tr_init_card(struct net_device *dev) -{ - if(tms380tr_debug > 3) - printk(KERN_DEBUG "%s: tms380tr_init_card\n", dev->name); - - return (0); -} - /* * Open/initialize the board. This is called sometime after * booting when the 'ifconfig' program is run. @@ -2386,7 +2376,6 @@ int tmsdev_init(struct net_device *dev, } /* These can be overridden by the card driver if needed */ - dev->init = tms380tr_init_card; dev->open = tms380tr_open; dev->stop = tms380tr_close; dev->do_ioctl = NULL; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/tokenring/tmspci.c 830-ivtv/drivers/net/tokenring/tmspci.c --- 000-virgin/drivers/net/tokenring/tmspci.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/tokenring/tmspci.c Thu Jan 8 08:54:26 2004 @@ -179,7 +179,7 @@ err_out_irq: err_out_region: release_region(pci_ioaddr, TMS_PCI_IO_EXTENT); err_out_trdev: - kfree(dev); + free_netdev(dev); return ret; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/tulip/Kconfig 830-ivtv/drivers/net/tulip/Kconfig --- 000-virgin/drivers/net/tulip/Kconfig Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/tulip/Kconfig Thu Jan 8 08:54:26 2004 @@ -68,6 +68,26 @@ config TULIP_MMIO obscure bugs if your mainboard has memory controller timing issues. If in doubt, say N. +config TULIP_NAPI + bool "Use NAPI RX polling " + depends on TULIP + ---help--- + This is of useful for servers and routers dealing with high network loads. + + See . + + If in doubt, say N. + +config TULIP_NAPI_HW_MITIGATION + bool "Use Interrupt Mitigation " + depends on TULIP_NAPI + ---help--- + Use HW to reduce RX interrupts. Not strict necessary since NAPI reduces + RX interrupts but itself. Although this reduces RX interrupts even at + low levels traffic at the cost of a small latency. + + If in doubt, say Y. + config DE4X5 tristate "Generic DECchip & DIGITAL EtherWORKS PCI/EISA" depends on NET_TULIP && (PCI || EISA) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/tulip/de2104x.c 830-ivtv/drivers/net/tulip/de2104x.c --- 000-virgin/drivers/net/tulip/de2104x.c Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/tulip/de2104x.c Thu Jan 8 08:54:26 2004 @@ -2084,7 +2084,7 @@ err_out_res: err_out_disable: pci_disable_device(pdev); err_out_free: - kfree(dev); + free_netdev(dev); return rc; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/tulip/dmfe.c 830-ivtv/drivers/net/tulip/dmfe.c --- 000-virgin/drivers/net/tulip/dmfe.c Mon Nov 17 18:28:15 2003 +++ 830-ivtv/drivers/net/tulip/dmfe.c Thu Jan 8 08:54:26 2004 @@ -457,7 +457,7 @@ err_out_disable: pci_disable_device(pdev); err_out_free: pci_set_drvdata(pdev, NULL); - kfree(dev); + free_netdev(dev); return err; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/tulip/interrupt.c 830-ivtv/drivers/net/tulip/interrupt.c --- 000-virgin/drivers/net/tulip/interrupt.c Fri May 30 19:02:13 2003 +++ 830-ivtv/drivers/net/tulip/interrupt.c Thu Jan 8 08:54:26 2004 @@ -19,13 +19,13 @@ #include #include - int tulip_rx_copybreak; unsigned int tulip_max_interrupt_work; -#ifdef CONFIG_NET_HW_FLOWCONTROL - +#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION #define MIT_SIZE 15 +#define MIT_TABLE 15 /* We use 0 or max */ + unsigned int mit_table[MIT_SIZE+1] = { /* CRS11 21143 hardware Mitigation Control Interrupt @@ -99,16 +99,28 @@ int tulip_refill_rx(struct net_device *d return refilled; } +#ifdef CONFIG_TULIP_NAPI -static int tulip_rx(struct net_device *dev) +void oom_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + netif_rx_schedule(dev); +} + +int tulip_poll(struct net_device *dev, int *budget) { struct tulip_private *tp = (struct tulip_private *)dev->priv; int entry = tp->cur_rx % RX_RING_SIZE; - int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx; + int rx_work_limit = *budget; int received = 0; -#ifdef CONFIG_NET_HW_FLOWCONTROL - int drop = 0, mit_sel = 0; + if (!netif_running(dev)) + goto done; + + if (rx_work_limit > dev->quota) + rx_work_limit = dev->quota; + +#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION /* that one buffer is needed for mit activation; or might be a bug in the ring buffer code; check later -- JHS*/ @@ -119,6 +131,237 @@ static int tulip_rx(struct net_device *d if (tulip_debug > 4) printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry, tp->rx_ring[entry].status); + + do { + /* Acknowledge current RX interrupt sources. */ + outl((RxIntr | RxNoBuf), dev->base_addr + CSR5); + + + /* If we own the next entry, it is a new packet. Send it up. */ + while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { + s32 status = le32_to_cpu(tp->rx_ring[entry].status); + + + if (tp->dirty_rx + RX_RING_SIZE == tp->cur_rx) + break; + + if (tulip_debug > 5) + printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n", + dev->name, entry, status); + if (--rx_work_limit < 0) + goto not_done; + + if ((status & 0x38008300) != 0x0300) { + if ((status & 0x38000300) != 0x0300) { + /* Ingore earlier buffers. */ + if ((status & 0xffff) != 0x7fff) { + if (tulip_debug > 1) + printk(KERN_WARNING "%s: Oversized Ethernet frame " + "spanned multiple buffers, status %8.8x!\n", + dev->name, status); + tp->stats.rx_length_errors++; + } + } else if (status & RxDescFatalErr) { + /* There was a fatal error. */ + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n", + dev->name, status); + tp->stats.rx_errors++; /* end of a packet.*/ + if (status & 0x0890) tp->stats.rx_length_errors++; + if (status & 0x0004) tp->stats.rx_frame_errors++; + if (status & 0x0002) tp->stats.rx_crc_errors++; + if (status & 0x0001) tp->stats.rx_fifo_errors++; + } + } else { + /* Omit the four octet CRC from the length. */ + short pkt_len = ((status >> 16) & 0x7ff) - 4; + struct sk_buff *skb; + +#ifndef final_version + if (pkt_len > 1518) { + printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n", + dev->name, pkt_len, pkt_len); + pkt_len = 1518; + tp->stats.rx_length_errors++; + } +#endif + /* Check if the packet is long enough to accept without copying + to a minimally-sized skbuff. */ + if (pkt_len < tulip_rx_copybreak + && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte align the IP header */ + pci_dma_sync_single(tp->pdev, + tp->rx_buffers[entry].mapping, + pkt_len, PCI_DMA_FROMDEVICE); +#if ! defined(__alpha__) + eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->tail, + pkt_len, 0); + skb_put(skb, pkt_len); +#else + memcpy(skb_put(skb, pkt_len), + tp->rx_buffers[entry].skb->tail, + pkt_len); +#endif + } else { /* Pass up the skb already on the Rx ring. */ + char *temp = skb_put(skb = tp->rx_buffers[entry].skb, + pkt_len); + +#ifndef final_version + if (tp->rx_buffers[entry].mapping != + le32_to_cpu(tp->rx_ring[entry].buffer1)) { + printk(KERN_ERR "%s: Internal fault: The skbuff addresses " + "do not match in tulip_rx: %08x vs. %08x %p / %p.\n", + dev->name, + le32_to_cpu(tp->rx_ring[entry].buffer1), + tp->rx_buffers[entry].mapping, + skb->head, temp); + } +#endif + + pci_unmap_single(tp->pdev, tp->rx_buffers[entry].mapping, + PKT_BUF_SZ, PCI_DMA_FROMDEVICE); + + tp->rx_buffers[entry].skb = NULL; + tp->rx_buffers[entry].mapping = 0; + } + skb->protocol = eth_type_trans(skb, dev); + + netif_receive_skb(skb); + + dev->last_rx = jiffies; + tp->stats.rx_packets++; + tp->stats.rx_bytes += pkt_len; + } + received++; + + entry = (++tp->cur_rx) % RX_RING_SIZE; + if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/4) + tulip_refill_rx(dev); + + } + + /* New ack strategy... irq does not ack Rx any longer + hopefully this helps */ + + /* Really bad things can happen here... If new packet arrives + * and an irq arrives (tx or just due to occasionally unset + * mask), it will be acked by irq handler, but new thread + * is not scheduled. It is major hole in design. + * No idea how to fix this if "playing with fire" will fail + * tomorrow (night 011029). If it will not fail, we won + * finally: amount of IO did not increase at all. */ + } while ((inl(dev->base_addr + CSR5) & RxIntr)); + +done: + + #ifdef CONFIG_TULIP_NAPI_HW_MITIGATION + + /* We use this simplistic scheme for IM. It's proven by + real life installations. We can have IM enabled + continuesly but this would cause unnecessary latency. + Unfortunely we can't use all the NET_RX_* feedback here. + This would turn on IM for devices that is not contributing + to backlog congestion with unnecessary latency. + + We monitor the the device RX-ring and have: + + HW Interrupt Mitigation either ON or OFF. + + ON: More then 1 pkt received (per intr.) OR we are dropping + OFF: Only 1 pkt received + + Note. We only use min and max (0, 15) settings from mit_table */ + + + if( tp->flags & HAS_INTR_MITIGATION) { + if( received > 1 ) { + if( ! tp->mit_on ) { + tp->mit_on = 1; + outl(mit_table[MIT_TABLE], dev->base_addr + CSR11); + } + } + else { + if( tp->mit_on ) { + tp->mit_on = 0; + outl(0, dev->base_addr + CSR11); + } + } + } + +#endif /* CONFIG_TULIP_NAPI_HW_MITIGATION */ + + dev->quota -= received; + *budget -= received; + + tulip_refill_rx(dev); + + /* If RX ring is not full we are out of memory. */ + if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) goto oom; + + /* Remove us from polling list and enable RX intr. */ + + netif_rx_complete(dev); + outl(tulip_tbl[tp->chip_id].valid_intrs, dev->base_addr+CSR7); + + /* The last op happens after poll completion. Which means the following: + * 1. it can race with disabling irqs in irq handler + * 2. it can race with dise/enabling irqs in other poll threads + * 3. if an irq raised after beginning loop, it will be immediately + * triggered here. + * + * Summarizing: the logic results in some redundant irqs both + * due to races in masking and due to too late acking of already + * processed irqs. But it must not result in losing events. + */ + + return 0; + + not_done: + if (!received) { + + received = dev->quota; /* Not to happen */ + } + dev->quota -= received; + *budget -= received; + + if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/2 || + tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) + tulip_refill_rx(dev); + + if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) goto oom; + + return 1; + + + oom: /* Executed with RX ints disabled */ + + + /* Start timer, stop polling, but do not enable rx interrupts. */ + mod_timer(&tp->oom_timer, jiffies+1); + + /* Think: timer_pending() was an explicit signature of bug. + * Timer can be pending now but fired and completed + * before we did netif_rx_complete(). See? We would lose it. */ + + /* remove ourselves from the polling list */ + netif_rx_complete(dev); + + return 0; +} + +#else /* CONFIG_TULIP_NAPI */ + +static int tulip_rx(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int entry = tp->cur_rx % RX_RING_SIZE; + int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx; + int received = 0; + + if (tulip_debug > 4) + printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry, + tp->rx_ring[entry].status); /* If we own the next entry, it is a new packet. Send it up. */ while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { s32 status = le32_to_cpu(tp->rx_ring[entry].status); @@ -163,11 +406,6 @@ static int tulip_rx(struct net_device *d } #endif -#ifdef CONFIG_NET_HW_FLOWCONTROL - drop = atomic_read(&netdev_dropping); - if (drop) - goto throttle; -#endif /* Check if the packet is long enough to accept without copying to a minimally-sized skbuff. */ if (pkt_len < tulip_rx_copybreak @@ -209,44 +447,9 @@ static int tulip_rx(struct net_device *d tp->rx_buffers[entry].mapping = 0; } skb->protocol = eth_type_trans(skb, dev); -#ifdef CONFIG_NET_HW_FLOWCONTROL - mit_sel = -#endif - netif_rx(skb); -#ifdef CONFIG_NET_HW_FLOWCONTROL - switch (mit_sel) { - case NET_RX_SUCCESS: - case NET_RX_CN_LOW: - case NET_RX_CN_MOD: - break; - - case NET_RX_CN_HIGH: - rx_work_limit -= NET_RX_CN_HIGH; /* additional*/ - break; - case NET_RX_DROP: - rx_work_limit = -1; - break; - default: - printk("unknown feedback return code %d\n", mit_sel); - break; - } + netif_rx(skb); - drop = atomic_read(&netdev_dropping); - if (drop) { -throttle: - rx_work_limit = -1; - mit_sel = NET_RX_DROP; - - if (tp->fc_bit) { - long ioaddr = dev->base_addr; - - /* disable Rx & RxNoBuf ints. */ - outl(tulip_tbl[tp->chip_id].valid_intrs&RX_A_NBF_STOP, ioaddr + CSR7); - set_bit(tp->fc_bit, &netdev_fc_xoff); - } - } -#endif dev->last_rx = jiffies; tp->stats.rx_packets++; tp->stats.rx_bytes += pkt_len; @@ -254,42 +457,9 @@ throttle: received++; entry = (++tp->cur_rx) % RX_RING_SIZE; } -#ifdef CONFIG_NET_HW_FLOWCONTROL - - /* We use this simplistic scheme for IM. It's proven by - real life installations. We can have IM enabled - continuesly but this would cause unnecessary latency. - Unfortunely we can't use all the NET_RX_* feedback here. - This would turn on IM for devices that is not contributing - to backlog congestion with unnecessary latency. - - We monitor the device RX-ring and have: - - HW Interrupt Mitigation either ON or OFF. - - ON: More then 1 pkt received (per intr.) OR we are dropping - OFF: Only 1 pkt received - - Note. We only use min and max (0, 15) settings from mit_table */ - - - if( tp->flags & HAS_INTR_MITIGATION) { - if((received > 1 || mit_sel == NET_RX_DROP) - && tp->mit_sel != 15 ) { - tp->mit_sel = 15; - tp->mit_change = 1; /* Force IM change */ - } - if((received <= 1 && mit_sel != NET_RX_DROP) && tp->mit_sel != 0 ) { - tp->mit_sel = 0; - tp->mit_change = 1; /* Force IM change */ - } - } - - return RX_RING_SIZE+1; /* maxrx+1 */ -#else return received; -#endif } +#endif /* CONFIG_TULIP_NAPI */ static inline unsigned int phy_interrupt (struct net_device *dev) { @@ -323,7 +493,6 @@ irqreturn_t tulip_interrupt(int irq, voi struct tulip_private *tp = (struct tulip_private *)dev->priv; long ioaddr = dev->base_addr; int csr5; - int entry; int missed; int rx = 0; int tx = 0; @@ -331,6 +500,11 @@ irqreturn_t tulip_interrupt(int irq, voi int maxrx = RX_RING_SIZE; int maxtx = TX_RING_SIZE; int maxoi = TX_RING_SIZE; +#ifdef CONFIG_TULIP_NAPI + int rxd = 0; +#else + int entry; +#endif unsigned int work_count = tulip_max_interrupt_work; unsigned int handled = 0; @@ -346,22 +520,41 @@ irqreturn_t tulip_interrupt(int irq, voi tp->nir++; do { + +#ifdef CONFIG_TULIP_NAPI + + if (!rxd && (csr5 & (RxIntr | RxNoBuf))) { + rxd++; + /* Mask RX intrs and add the device to poll list. */ + outl(tulip_tbl[tp->chip_id].valid_intrs&~RxPollInt, ioaddr + CSR7); + netif_rx_schedule(dev); + + if (!(csr5&~(AbnormalIntr|NormalIntr|RxPollInt|TPLnkPass))) + break; + } + + /* Acknowledge the interrupt sources we handle here ASAP + the poll function does Rx and RxNoBuf acking */ + + outl(csr5 & 0x0001ff3f, ioaddr + CSR5); + +#else /* Acknowledge all of the current interrupt sources ASAP. */ outl(csr5 & 0x0001ffff, ioaddr + CSR5); - if (tulip_debug > 4) - printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n", - dev->name, csr5, inl(dev->base_addr + CSR5)); if (csr5 & (RxIntr | RxNoBuf)) { -#ifdef CONFIG_NET_HW_FLOWCONTROL - if ((!tp->fc_bit) || - (!test_bit(tp->fc_bit, &netdev_fc_xoff))) -#endif rx += tulip_rx(dev); tulip_refill_rx(dev); } +#endif /* CONFIG_TULIP_NAPI */ + + if (tulip_debug > 4) + printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n", + dev->name, csr5, inl(dev->base_addr + CSR5)); + + if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) { unsigned int dirty_tx; @@ -462,15 +655,8 @@ irqreturn_t tulip_interrupt(int irq, voi } if (csr5 & RxDied) { /* Missed a Rx frame. */ tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; -#ifdef CONFIG_NET_HW_FLOWCONTROL - if (tp->fc_bit && !test_bit(tp->fc_bit, &netdev_fc_xoff)) { - tp->stats.rx_errors++; - tulip_start_rxtx(tp); - } -#else tp->stats.rx_errors++; tulip_start_rxtx(tp); -#endif } /* * NB: t21142_lnk_change() does a del_timer_sync(), so be careful if this @@ -504,10 +690,6 @@ irqreturn_t tulip_interrupt(int irq, voi if (tulip_debug > 2) printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n", dev->name, csr5); -#ifdef CONFIG_NET_HW_FLOWCONTROL - if (tp->fc_bit && (test_bit(tp->fc_bit, &netdev_fc_xoff))) - if (net_ratelimit()) printk("BUG!! enabling interrupt when FC off (timerintr.) \n"); -#endif outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); tp->ttimer = 0; oi++; @@ -520,16 +702,9 @@ irqreturn_t tulip_interrupt(int irq, voi /* Acknowledge all interrupt sources. */ outl(0x8001ffff, ioaddr + CSR5); if (tp->flags & HAS_INTR_MITIGATION) { -#ifdef CONFIG_NET_HW_FLOWCONTROL - if(tp->mit_change) { - outl(mit_table[tp->mit_sel], ioaddr + CSR11); - tp->mit_change = 0; - } -#else /* Josip Loncaric at ICASE did extensive experimentation to develop a good interrupt mitigation setting.*/ outl(0x8b240000, ioaddr + CSR11); -#endif } else if (tp->chip_id == LC82C168) { /* the LC82C168 doesn't have a hw timer.*/ outl(0x00, ioaddr + CSR7); @@ -537,10 +712,8 @@ irqreturn_t tulip_interrupt(int irq, voi } else { /* Mask all interrupting sources, set timer to re-enable. */ -#ifndef CONFIG_NET_HW_FLOWCONTROL outl(((~csr5) & 0x0001ebef) | AbnormalIntr | TimerInt, ioaddr + CSR7); outl(0x0012, ioaddr + CSR11); -#endif } break; } @@ -550,6 +723,21 @@ irqreturn_t tulip_interrupt(int irq, voi break; csr5 = inl(ioaddr + CSR5); + +#ifdef CONFIG_TULIP_NAPI + if (rxd) + csr5 &= ~RxPollInt; + } while ((csr5 & (TxNoBuf | + TxDied | + TxIntr | + TimerInt | + /* Abnormal intr. */ + RxDied | + TxFIFOUnderflow | + TxJabber | + TPLnkFail | + SytemError )) != 0); +#else } while ((csr5 & (NormalIntr|AbnormalIntr)) != 0); tulip_refill_rx(dev); @@ -574,6 +762,7 @@ irqreturn_t tulip_interrupt(int irq, voi } } } +#endif /* CONFIG_TULIP_NAPI */ if ((missed = inl(ioaddr + CSR8) & 0x1ffff)) { tp->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/tulip/tulip.h 830-ivtv/drivers/net/tulip/tulip.h --- 000-virgin/drivers/net/tulip/tulip.h Fri May 30 19:02:13 2003 +++ 830-ivtv/drivers/net/tulip/tulip.h Thu Jan 8 08:54:26 2004 @@ -126,6 +126,7 @@ enum pci_cfg_driver_reg { CFDD_Snooze = (1 << 30), }; +#define RxPollInt (RxIntr|RxNoBuf|RxDied|RxJabber) /* The bits in the CSR5 status registers, mostly interrupt sources. */ enum status_bits { @@ -251,9 +252,9 @@ enum t21143_csr6_bits { Making the Tx ring too large decreases the effectiveness of channel bonding and packet priority. There are no ill effects from too-large receive rings. */ -#define TX_RING_SIZE 16 -#define RX_RING_SIZE 32 +#define TX_RING_SIZE 32 +#define RX_RING_SIZE 128 #define MEDIA_MASK 31 #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ @@ -343,17 +344,15 @@ struct tulip_private { int flags; struct net_device_stats stats; struct timer_list timer; /* Media selection timer. */ + struct timer_list oom_timer; /* Out of memory timer. */ u32 mc_filter[2]; spinlock_t lock; spinlock_t mii_lock; unsigned int cur_rx, cur_tx; /* The next free ring entry */ unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ -#ifdef CONFIG_NET_HW_FLOWCONTROL -#define RX_A_NBF_STOP 0xffffff3f /* To disable RX and RX-NOBUF ints. */ - int fc_bit; - int mit_sel; - int mit_change; /* Signal for Interrupt Mitigtion */ +#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION + int mit_on; #endif unsigned int full_duplex:1; /* Full-duplex operation requested. */ unsigned int full_duplex_lock:1; @@ -415,6 +414,10 @@ extern unsigned int tulip_max_interrupt_ extern int tulip_rx_copybreak; irqreturn_t tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs); int tulip_refill_rx(struct net_device *dev); +#ifdef CONFIG_TULIP_NAPI +int tulip_poll(struct net_device *dev, int *budget); +#endif + /* media.c */ int tulip_mdio_read(struct net_device *dev, int phy_id, int location); @@ -438,6 +441,7 @@ extern int tulip_debug; extern const char * const medianame[]; extern const char tulip_media_cap[]; extern struct tulip_chip_table tulip_tbl[]; +void oom_timer(unsigned long data); extern u8 t21040_csr13[]; #ifndef USE_IO_OPS diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/tulip/tulip_core.c 830-ivtv/drivers/net/tulip/tulip_core.c --- 000-virgin/drivers/net/tulip/tulip_core.c Mon Dec 8 09:55:52 2003 +++ 830-ivtv/drivers/net/tulip/tulip_core.c Thu Jan 8 08:54:26 2004 @@ -14,11 +14,17 @@ */ +#include + #define DRV_NAME "tulip" +#ifdef CONFIG_TULIP_NAPI +#define DRV_VERSION "1.1.13-NAPI" /* Keep at least for test */ +#else #define DRV_VERSION "1.1.13" +#endif #define DRV_RELDATE "May 11, 2002" -#include + #include #include "tulip.h" #include @@ -247,7 +253,7 @@ static void tulip_down(struct net_device static struct net_device_stats *tulip_get_stats(struct net_device *dev); static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static void set_rx_mode(struct net_device *dev); - +static void poll_tulip(struct net_device *dev); static void tulip_set_power_state (struct tulip_private *tp, @@ -466,29 +472,16 @@ media_picked: to an alternate media type. */ tp->timer.expires = RUN_AT(next_tick); add_timer(&tp->timer); -} - -#ifdef CONFIG_NET_HW_FLOWCONTROL -/* Enable receiver */ -void tulip_xon(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - - clear_bit(tp->fc_bit, &netdev_fc_xoff); - if (netif_running(dev)){ - - tulip_refill_rx(dev); - outl(tulip_tbl[tp->chip_id].valid_intrs, dev->base_addr+CSR7); - } -} +#ifdef CONFIG_TULIP_NAPI + init_timer(&tp->oom_timer); + tp->oom_timer.data = (unsigned long)dev; + tp->oom_timer.function = oom_timer; #endif +} static int tulip_open(struct net_device *dev) { -#ifdef CONFIG_NET_HW_FLOWCONTROL - struct tulip_private *tp = (struct tulip_private *)dev->priv; -#endif int retval; if ((retval = request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev))) @@ -498,10 +491,6 @@ tulip_open(struct net_device *dev) tulip_up (dev); -#ifdef CONFIG_NET_HW_FLOWCONTROL - tp->fc_bit = netdev_register_fc(dev, tulip_xon); -#endif - netif_start_queue (dev); return 0; @@ -582,10 +571,7 @@ static void tulip_tx_timeout(struct net_ #endif /* Stop and restart the chip's Tx processes . */ -#ifdef CONFIG_NET_HW_FLOWCONTROL - if (tp->fc_bit && test_bit(tp->fc_bit,&netdev_fc_xoff)) - printk("BUG tx_timeout restarting rx when fc on\n"); -#endif + tulip_restart_rxtx(tp); /* Trigger an immediate transmit demand. */ outl(0, ioaddr + CSR1); @@ -742,7 +728,9 @@ static void tulip_down (struct net_devic unsigned long flags; del_timer_sync (&tp->timer); - +#ifdef CONFIG_TULIP_NAPI + del_timer_sync (&tp->oom_timer); +#endif spin_lock_irqsave (&tp->lock, flags); /* Disable interrupts by clearing the interrupt mask. */ @@ -781,13 +769,6 @@ static int tulip_close (struct net_devic netif_stop_queue (dev); -#ifdef CONFIG_NET_HW_FLOWCONTROL - if (tp->fc_bit) { - int bit = tp->fc_bit; - tp->fc_bit = 0; - netdev_unregister_fc(bit); - } -#endif tulip_down (dev); if (tulip_debug > 1) @@ -1629,10 +1610,17 @@ static int __devinit tulip_init_one (str dev->hard_start_xmit = tulip_start_xmit; dev->tx_timeout = tulip_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; +#ifdef CONFIG_TULIP_NAPI + dev->poll = tulip_poll; + dev->weight = 16; +#endif dev->stop = tulip_close; dev->get_stats = tulip_get_stats; dev->do_ioctl = private_ioctl; dev->set_multicast_list = set_rx_mode; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = &poll_tulip; +#endif if (register_netdev(dev)) goto err_out_free_ring; @@ -1725,7 +1713,7 @@ err_out_free_res: pci_release_regions (pdev); err_out_free_netdev: - kfree (dev); + free_netdev (dev); return -ENODEV; } @@ -1789,6 +1777,22 @@ static void __devexit tulip_remove_one ( /* pci_power_off (pdev, -1); */ } +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling 'interrupt' - used by things like netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ + +static void poll_tulip (struct net_device *dev) +{ + /* disable_irq here is not very nice, but with the lockless + interrupt handler we have no other choice. */ + disable_irq(dev->irq); + tulip_interrupt (dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif static struct pci_driver tulip_driver = { .name = DRV_NAME, diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/tulip/winbond-840.c 830-ivtv/drivers/net/tulip/winbond-840.c --- 000-virgin/drivers/net/tulip/winbond-840.c Mon Nov 17 18:28:15 2003 +++ 830-ivtv/drivers/net/tulip/winbond-840.c Thu Jan 8 08:54:26 2004 @@ -530,7 +530,7 @@ err_out_free_res: #endif pci_release_regions(pdev); err_out_netdev: - kfree (dev); + free_netdev (dev); return -ENODEV; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/tulip/xircom_tulip_cb.c 830-ivtv/drivers/net/tulip/xircom_tulip_cb.c --- 000-virgin/drivers/net/tulip/xircom_tulip_cb.c Tue Sep 2 09:55:48 2003 +++ 830-ivtv/drivers/net/tulip/xircom_tulip_cb.c Thu Jan 8 08:54:26 2004 @@ -648,8 +648,7 @@ err_out_cleardev: pci_set_drvdata(pdev, NULL); pci_release_regions(pdev); err_out_free_netdev: - unregister_netdev(dev); - kfree(dev); + free_netdev(dev); return -ENODEV; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/tun.c 830-ivtv/drivers/net/tun.c --- 000-virgin/drivers/net/tun.c Mon Nov 17 18:28:15 2003 +++ 830-ivtv/drivers/net/tun.c Thu Jan 8 08:54:27 2004 @@ -377,6 +377,7 @@ static struct tun_struct *tun_get_by_nam static int tun_set_iff(struct file *file, struct ifreq *ifr) { struct tun_struct *tun; + struct net_device *dev; int err; tun = tun_get_by_name(ifr->ifr_name); @@ -394,7 +395,6 @@ static int tun_set_iff(struct file *file else { char *name; unsigned long flags = 0; - struct net_device *dev; err = -EINVAL; @@ -424,16 +424,13 @@ static int tun_set_iff(struct file *file if (strchr(dev->name, '%')) { err = dev_alloc_name(dev, dev->name); - if (err < 0) { - kfree(dev); - goto failed; - } + if (err < 0) + goto err_free_dev; } - if ((err = register_netdevice(tun->dev))) { - kfree(dev); - goto failed; - } + err = register_netdevice(tun->dev); + if (err < 0) + goto err_free_dev; list_add(&tun->list, &tun_dev_list); } @@ -451,6 +448,9 @@ static int tun_set_iff(struct file *file strcpy(ifr->ifr_name, tun->dev->name); return 0; + + err_free_dev: + free_netdev(dev); failed: return err; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/via-rhine.c 830-ivtv/drivers/net/via-rhine.c --- 000-virgin/drivers/net/via-rhine.c Mon Nov 17 18:28:15 2003 +++ 830-ivtv/drivers/net/via-rhine.c Thu Jan 8 08:54:27 2004 @@ -615,6 +615,15 @@ static void __devinit reload_eeprom(long break; } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void via_rhine_poll(struct net_device *dev) +{ + disable_irq(dev->irq); + via_rhine_interrupt(dev->irq, (void *)dev, NULL); + enable_irq(dev->irq); +} +#endif + static int __devinit via_rhine_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -784,6 +793,9 @@ static int __devinit via_rhine_init_one dev->ethtool_ops = &netdev_ethtool_ops; dev->tx_timeout = via_rhine_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = via_rhine_poll; +#endif if (np->drv_flags & ReqTxAlign) dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/wan/Kconfig 830-ivtv/drivers/net/wan/Kconfig --- 000-virgin/drivers/net/wan/Kconfig Thu Jan 8 08:35:39 2004 +++ 830-ivtv/drivers/net/wan/Kconfig Thu Jan 8 08:54:27 2004 @@ -325,6 +325,21 @@ config HDLC_X25 comment "X.25/LAPB support is disabled" depends on WAN && HDLC && (LAPB!=m || HDLC!=m) && LAPB!=y +config PCI200SYN + tristate "Goramo PCI200SYN support" + depends on HDLC && PCI + help + This driver is for PCI200SYN cards made by Goramo sp. j. + If you have such a card, say Y here and see + + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read . The module + will be called pci200syn. + + If unsure, say N here. + config WANXL tristate "SBE Inc. wanXL support" depends on HDLC && PCI diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/wan/Makefile 830-ivtv/drivers/net/wan/Makefile --- 000-virgin/drivers/net/wan/Makefile Mon Nov 17 18:28:50 2003 +++ 830-ivtv/drivers/net/wan/Makefile Thu Jan 8 08:54:27 2004 @@ -67,6 +67,7 @@ endif obj-$(CONFIG_N2) += n2.o obj-$(CONFIG_C101) += c101.o obj-$(CONFIG_WANXL) += wanxl.o +obj-$(CONFIG_PCI200SYN) += pci200syn.o ifeq ($(CONFIG_WANXL_BUILD_FIRMWARE),y) ifeq ($(ARCH),m68k) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/wan/cosa.c 830-ivtv/drivers/net/wan/cosa.c --- 000-virgin/drivers/net/wan/cosa.c Mon Nov 17 18:29:42 2003 +++ 830-ivtv/drivers/net/wan/cosa.c Thu Jan 8 08:54:27 2004 @@ -594,40 +594,47 @@ err_out: /*---------- SPPP/HDLC netdevice ---------- */ +static void cosa_setup(struct net_device *d) +{ + d->open = cosa_sppp_open; + d->stop = cosa_sppp_close; + d->hard_start_xmit = cosa_sppp_tx; + d->do_ioctl = cosa_sppp_ioctl; + d->get_stats = cosa_net_stats; + d->tx_timeout = cosa_sppp_timeout; + d->watchdog_timeo = TX_TIMEOUT; +} + static void sppp_channel_init(struct channel_data *chan) { struct net_device *d; chan->if_ptr = &chan->pppdev; - chan->pppdev.dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); - memset(chan->pppdev.dev, 0, sizeof(struct net_device)); + d = alloc_netdev(0, chan->name, cosa_setup); + if (!d) { + printk(KERN_WARNING "%s: alloc_netdev failed.\n", chan->name); + return; + } + chan->pppdev.dev = d; sppp_attach(&chan->pppdev); - d=chan->pppdev.dev; - strcpy(d->name, chan->name); d->base_addr = chan->cosa->datareg; d->irq = chan->cosa->irq; d->dma = chan->cosa->dma; d->priv = chan; - d->init = NULL; - d->open = cosa_sppp_open; - d->stop = cosa_sppp_close; - d->hard_start_xmit = cosa_sppp_tx; - d->do_ioctl = cosa_sppp_ioctl; - d->get_stats = cosa_net_stats; - d->tx_timeout = cosa_sppp_timeout; - d->watchdog_timeo = TX_TIMEOUT; if (register_netdev(d)) { printk(KERN_WARNING "%s: register_netdev failed.\n", d->name); - sppp_detach(chan->pppdev.dev); - free_netdev(chan->pppdev.dev); + sppp_detach(d); + free_netdev(d); + chan->pppdev.dev = NULL; return; } } static void sppp_channel_delete(struct channel_data *chan) { - sppp_detach(chan->pppdev.dev); unregister_netdev(chan->pppdev.dev); + sppp_detach(chan->pppdev.dev); free_netdev(chan->pppdev.dev); + chan->pppdev.dev = NULL; } static int cosa_sppp_open(struct net_device *d) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/wan/farsync.c 830-ivtv/drivers/net/wan/farsync.c --- 000-virgin/drivers/net/wan/farsync.c Mon Nov 17 18:29:30 2003 +++ 830-ivtv/drivers/net/wan/farsync.c Thu Jan 8 08:54:27 2004 @@ -1313,8 +1313,6 @@ fst_open ( struct net_device *dev ) if ( err ) return err; - MOD_INC_USE_COUNT; - fst_openport ( dev_to_port ( dev )); netif_wake_queue ( dev ); return 0; @@ -1326,7 +1324,6 @@ fst_close ( struct net_device *dev ) netif_stop_queue ( dev ); fst_closeport ( dev_to_port ( dev )); hdlc_close ( dev_to_hdlc ( dev )); - MOD_DEC_USE_COUNT; return 0; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/wan/hd64572.h 830-ivtv/drivers/net/wan/hd64572.h --- 000-virgin/drivers/net/wan/hd64572.h Sun Nov 17 20:29:50 2002 +++ 830-ivtv/drivers/net/wan/hd64572.h Thu Jan 8 08:54:27 2004 @@ -23,8 +23,8 @@ * */ -#ifndef _HD64572_H -#define _HD64572_H +#ifndef __HD64572_H +#define __HD64572_H /* Illegal Access Register */ #define ILAR 0x00 @@ -59,6 +59,9 @@ #define IR0_M(val, chan) ((val)<<(8*(chan))) /* Int MSCI */ /* MSCI Channel Registers */ +#define MSCI0_OFFSET 0x00 +#define MSCI1_OFFSET 0x80 + #define MD0 0x138 /* Mode reg 0 */ #define MD1 0x139 /* Mode reg 1 */ #define MD2 0x13a /* Mode reg 2 */ @@ -107,6 +110,11 @@ #define RCR 0x156 /* Rx DMA Critical Request Reg */ /* Timer Registers */ +#define TIMER0RX_OFFSET 0x00 +#define TIMER0TX_OFFSET 0x10 +#define TIMER1RX_OFFSET 0x20 +#define TIMER1TX_OFFSET 0x30 + #define TCNTL 0x200 /* Timer Upcounter L */ #define TCNTH 0x201 /* Timer Upcounter H */ #define TCONRL 0x204 /* Timer Constant Register L */ @@ -132,6 +140,11 @@ #define DCR_TX(chan) (0x59 + 2*chan) /* DMA Command Reg (Tx) */ /* DMA Channel Registers */ +#define DMAC0RX_OFFSET 0x00 +#define DMAC0TX_OFFSET 0x20 +#define DMAC1RX_OFFSET 0x40 +#define DMAC1TX_OFFSET 0x60 + #define DARL 0x80 /* Dest Addr Register L (single-block, RX only) */ #define DARH 0x81 /* Dest Addr Register H (single-block, RX only) */ #define DARB 0x82 /* Dest Addr Register B (single-block, RX only) */ @@ -166,7 +179,17 @@ typedef struct { unsigned char filler[5]; /* alignment filler (16 bytes) */ } pcsca_bd_t; -/* +/* Block Descriptor Structure */ +typedef struct { + u32 cp; /* pointer to next block descriptor */ + u32 bp; /* buffer pointer */ + u16 len; /* data length */ + u8 stat; /* status */ + u8 unused; /* pads to 4-byte boundary */ +}pkt_desc; + + +/* Descriptor Status definitions: Bit Transmission Reception @@ -190,6 +213,23 @@ typedef struct { #define DST_SHRT 0x40 /* Short Frame */ #define DST_EOM 0x80 /* End of Message */ +/* Packet Descriptor Status bits */ + +#define ST_TX_EOM 0x80 /* End of frame */ +#define ST_TX_UNDRRUN 0x08 +#define ST_TX_OWNRSHP 0x02 +#define ST_TX_EOT 0x01 /* End of transmition */ + +#define ST_RX_EOM 0x80 /* End of frame */ +#define ST_RX_SHORT 0x40 /* Short frame */ +#define ST_RX_ABORT 0x20 /* Abort */ +#define ST_RX_RESBIT 0x10 /* Residual bit */ +#define ST_RX_OVERRUN 0x08 /* Overrun */ +#define ST_RX_CRC 0x04 /* CRC */ +#define ST_RX_OWNRSHP 0x02 + +#define ST_ERROR_MASK 0x7C + /* Status Counter Registers */ #define CMCR 0x158 /* Counter Master Ctl Reg */ #define TECNTL 0x160 /* Tx EOM Counter L */ @@ -246,11 +286,25 @@ typedef struct { #define MD0_BIT_SYNC 0x80 #define MD0_TRANSP 0xc0 +#define MD0_HDLC 0x80 /* Bit-sync HDLC mode */ + +#define MD0_CRC_NONE 0x00 +#define MD0_CRC_16_0 0x04 +#define MD0_CRC_16 0x05 +#define MD0_CRC_ITU32 0x06 +#define MD0_CRC_ITU 0x07 + #define MD1_NOADDR 0x00 #define MD1_SADDR1 0x40 #define MD1_SADDR2 0x80 #define MD1_DADDR 0xc0 +#define MD2_NRZI_IEEE 0x40 +#define MD2_MANCHESTER 0x80 +#define MD2_FM_MARK 0xA0 +#define MD2_FM_SPACE 0xC0 +#define MD2_LOOPBACK 0x03 /* Local data Loopback */ + #define MD2_F_DUPLEX 0x00 #define MD2_AUTO_ECHO 0x01 #define MD2_LOOP_HI_Z 0x02 @@ -274,6 +328,10 @@ typedef struct { #define CTL_URSKP 0x40 #define CTL_URCT 0x80 +#define CTL_NORTS 0x01 +#define CTL_NODTR 0x02 +#define CTL_IDLE 0x10 + #define RXS_BR0 0x01 #define RXS_BR1 0x02 #define RXS_BR2 0x04 @@ -302,6 +360,12 @@ typedef struct { #define EXS_TES1 0x20 #define EXS_TES2 0x40 +#define CLK_BRG_MASK 0x0F +#define CLK_PIN_OUT 0x80 +#define CLK_LINE 0x00 /* clock line input */ +#define CLK_BRG 0x40 /* internal baud rate generator */ +#define CLK_TX_RXCLK 0x60 /* TX clock from RX clock */ + #define CMD_RX_RST 0x11 #define CMD_RX_ENA 0x12 #define CMD_RX_DIS 0x13 @@ -324,6 +388,10 @@ typedef struct { #define CMD_SRCH_MODE 0x31 #define CMD_NOP 0x00 +#define CMD_RESET 0x21 +#define CMD_TX_ENABLE 0x02 +#define CMD_RX_ENABLE 0x12 + #define ST0_RXRDY 0x01 #define ST0_TXRDY 0x02 #define ST0_RXINTB 0x20 @@ -374,6 +442,8 @@ typedef struct { #define IE0_RXINTB 0x20 #define IE0_RXINTA 0x40 #define IE0_TXINT 0x80 +#define IE0_UDRN 0x00008000 /* TX underrun MSCI interrupt enable */ +#define IE0_CDCD 0x00000400 /* CD level change interrupt enable */ #define IE1_IDLD 0x01 #define IE1_ABTD 0x02 @@ -424,14 +494,28 @@ typedef struct { #define DIR_EOM 0x40 #define DIR_EOT 0x80 +#define DIR_REFE 0x04 +#define DIR_UDRFE 0x04 +#define DIR_COAE 0x08 +#define DIR_COFE 0x10 +#define DIR_BOFE 0x20 +#define DIR_EOME 0x40 +#define DIR_EOTE 0x80 + #define DMR_CNTE 0x02 #define DMR_NF 0x04 #define DMR_SEOME 0x08 #define DMR_TMOD 0x10 +#define DMER_DME 0x80 /* DMA Master Enable */ + #define DCR_SW_ABT 0x01 #define DCR_FCT_CLR 0x02 +#define DCR_ABORT 0x01 +#define DCR_CLEAR_EOF 0x02 + +#define PCR_COTE 0x80 #define PCR_PR0 0x01 #define PCR_PR1 0x02 #define PCR_PR2 0x04 @@ -440,4 +524,4 @@ typedef struct { #define PCR_OSB 0x40 #define PCR_BURST 0x80 -#endif /* (_HD64572_H) */ +#endif /* (__HD64572_H) */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/wan/lmc/lmc_main.c 830-ivtv/drivers/net/wan/lmc/lmc_main.c --- 000-virgin/drivers/net/wan/lmc/lmc_main.c Tue Sep 2 09:55:48 2003 +++ 830-ivtv/drivers/net/wan/lmc/lmc_main.c Thu Jan 8 08:54:27 2004 @@ -78,30 +78,22 @@ #include "lmc_debug.h" #include "lmc_proto.h" - -static int Lmc_Count = 0; -static struct net_device *Lmc_root_dev = NULL; -static u8 cards_found = 0; - static int lmc_first_load = 0; -int LMC_PKT_BUF_SZ = 1542; +static int LMC_PKT_BUF_SZ = 1542; -#ifdef MODULE static struct pci_device_id lmc_pci_tbl[] = { - { 0x1011, 0x009, 0x1379, PCI_ANY_ID, 0, 0, 0}, - { 0, } + { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST, + PCI_VENDOR_ID_LMC, PCI_ANY_ID }, + { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST, + PCI_ANY_ID, PCI_VENDOR_ID_LMC }, + { 0 } }; MODULE_DEVICE_TABLE(pci, lmc_pci_tbl); - MODULE_LICENSE("GPL"); -#endif -int lmc_probe_fake(struct net_device *dev); -static struct net_device *lmc_probe1(struct net_device *dev, unsigned long ioaddr, unsigned int irq, - int chip_id, int subdevice, int board_idx); static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev); static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev); static int lmc_rx (struct net_device *dev); @@ -115,12 +107,9 @@ static void lmc_softreset(lmc_softc_t * static void lmc_running_reset(struct net_device *dev); static int lmc_ifdown(struct net_device * const); static void lmc_watchdog(unsigned long data); -static int lmc_init(struct net_device * const); static void lmc_reset(lmc_softc_t * const sc); static void lmc_dec_reset(lmc_softc_t * const sc); static void lmc_driver_timeout(struct net_device *dev); -int lmc_setup(void); - /* * linux reserves 16 device specific IOCTLs. We call them @@ -815,67 +804,77 @@ kick_timer: } -static int lmc_init(struct net_device * const dev) /*fold00*/ +static void lmc_setup(struct net_device * const dev) /*fold00*/ { - lmc_trace(dev, "lmc_init in"); - lmc_trace(dev, "lmc_init out"); - - return 0; + lmc_trace(dev, "lmc_setup in"); + + dev->type = ARPHRD_HDLC; + dev->hard_start_xmit = lmc_start_xmit; + dev->open = lmc_open; + dev->stop = lmc_close; + dev->get_stats = lmc_get_stats; + dev->do_ioctl = lmc_ioctl; + dev->set_config = lmc_set_config; + dev->tx_timeout = lmc_driver_timeout; + dev->watchdog_timeo = (HZ); /* 1 second */ + + lmc_trace(dev, "lmc_setup out"); } -/* This initializes each card from lmc_probe() */ -static struct net_device *lmc_probe1 (struct net_device *dev, unsigned long ioaddr, unsigned int irq, /*fold00*/ - int chip_id, int subdevice, int board_idx) + +static int __devinit lmc_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) { - lmc_softc_t *sc = NULL; + struct net_device *dev; + lmc_softc_t *sc; + u16 subdevice; u_int16_t AdapModelNum; - - /* - * Allocate our own device structure - */ - - dev = kmalloc (sizeof (struct net_device)+8, GFP_KERNEL); - if (dev == NULL){ - printk (KERN_ERR "lmc: kmalloc for device failed\n"); - return NULL; - } - memset (dev, 0, sizeof (struct net_device)); - + int err = -ENOMEM; + static int cards_found; #ifndef GCOM - /* - * Switch to common hdlc%d naming. We name by type not by vendor - */ - - dev_alloc_name(dev, "hdlc%d"); + /* We name by type not by vendor */ + static const char lmcname[] = "hdlc%d"; #else - /* + /* * GCOM uses LMC vendor name so that clients can know which card * to attach to. */ - dev_alloc_name(dev, "lmc%d"); + static const char lmcname[] = "lmc%d"; #endif - lmc_trace(dev, "lmc_probe1 in"); + + /* + * Allocate our own device structure + */ + dev = alloc_netdev(sizeof(lmc_softc_t), lmcname, lmc_setup); + if (!dev) { + printk (KERN_ERR "lmc:alloc_netdev for device failed\n"); + goto out1; + } + + lmc_trace(dev, "lmc_init_one in"); + + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR "lmc: pci enable failed:%d\n", err); + goto out2; + } - Lmc_Count++; + if (pci_request_regions(pdev, "lmc")) { + printk(KERN_ERR "lmc: pci_request_region failed\n"); + err = -EIO; + goto out3; + } + + pci_set_drvdata(pdev, dev); if(lmc_first_load == 0){ - printk(KERN_INFO "Lan Media Corporation WAN Driver Version %d.%d.%d\n",DRIVER_MAJOR_VERSION, DRIVER_MINOR_VERSION,DRIVER_SUB_VERSION); + printk(KERN_INFO "Lan Media Corporation WAN Driver Version %d.%d.%d\n", + DRIVER_MAJOR_VERSION, DRIVER_MINOR_VERSION,DRIVER_SUB_VERSION); lmc_first_load = 1; } - /* - * Allocate space for the private data structure - */ - - sc = kmalloc (sizeof (lmc_softc_t), GFP_KERNEL); - if (sc == NULL) { - printk (KERN_WARNING "%s: Cannot allocate memory for device state\n", - dev->name); - return (NULL); - } - memset (sc, 0, sizeof (lmc_softc_t)); - dev->priv = sc; + sc = dev->priv; sc->lmc_device = dev; sc->name = dev->name; @@ -883,8 +882,12 @@ static struct net_device *lmc_probe1 (st /* An ioctl can cause a subsequent detach for raw frame interface */ sc->if_type = LMC_PPP; sc->check = 0xBEAFCAFE; - dev->base_addr = ioaddr; - dev->irq = irq; + dev->base_addr = pci_resource_start(pdev, 0); + dev->irq = pdev->irq; + + SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &pdev->dev); + /* * This will get the protocol layer ready and do any 1 time init's * Must have a valid sc and dev structure @@ -893,19 +896,6 @@ static struct net_device *lmc_probe1 (st lmc_proto_attach(sc); - /* Just fill in the entries for the device */ - - dev->init = lmc_init; - dev->type = ARPHRD_HDLC; - dev->hard_start_xmit = lmc_start_xmit; - dev->open = lmc_open; - dev->stop = lmc_close; - dev->get_stats = lmc_get_stats; - dev->do_ioctl = lmc_ioctl; - dev->set_config = lmc_set_config; - dev->tx_timeout = lmc_driver_timeout; - dev->watchdog_timeo = (HZ); /* 1 second */ - /* * Why were we changing this??? dev->tx_queue_len = 100; @@ -914,44 +904,45 @@ static struct net_device *lmc_probe1 (st /* Init the spin lock so can call it latter */ spin_lock_init(&sc->lmc_lock); + pci_set_master(pdev); - printk ("%s: detected at %lx, irq %d\n", dev->name, ioaddr, dev->irq); + printk ("%s: detected at %lx, irq %d\n", dev->name, + dev->base_addr, dev->irq); if (register_netdev (dev) != 0) { printk (KERN_ERR "%s: register_netdev failed.\n", dev->name); - lmc_proto_detach(sc); - kfree (dev->priv); - kfree (dev); - return NULL; + goto out4; } - /* - * Request the region of registers we need, so that - * later on, no one else will take our card away from - * us. - */ - request_region (ioaddr, LMC_REG_RANGE, dev->name); - sc->lmc_cardtype = LMC_CARDTYPE_UNKNOWN; sc->lmc_timing = LMC_CTL_CLOCK_SOURCE_EXT; + /* + * + * Check either the subvendor or the subdevice, some systems reverse + * the setting in the bois, seems to be version and arch dependent? + * Fix the error, exchange the two values + */ + if ((subdevice = pdev->subsystem_device) == PCI_VENDOR_ID_LMC) + subdevice = pdev->subsystem_vendor; + switch (subdevice) { - case PCI_PRODUCT_LMC_HSSI: + case PCI_DEVICE_ID_LMC_HSSI: printk ("%s: LMC HSSI\n", dev->name); sc->lmc_cardtype = LMC_CARDTYPE_HSSI; sc->lmc_media = &lmc_hssi_media; break; - case PCI_PRODUCT_LMC_DS3: + case PCI_DEVICE_ID_LMC_DS3: printk ("%s: LMC DS3\n", dev->name); sc->lmc_cardtype = LMC_CARDTYPE_DS3; sc->lmc_media = &lmc_ds3_media; break; - case PCI_PRODUCT_LMC_SSI: + case PCI_DEVICE_ID_LMC_SSI: printk ("%s: LMC SSI\n", dev->name); sc->lmc_cardtype = LMC_CARDTYPE_SSI; sc->lmc_media = &lmc_ssi_media; break; - case PCI_PRODUCT_LMC_T1: + case PCI_DEVICE_ID_LMC_T1: printk ("%s: LMC T1\n", dev->name); sc->lmc_cardtype = LMC_CARDTYPE_T1; sc->lmc_media = &lmc_t1_media; @@ -976,13 +967,13 @@ static struct net_device *lmc_probe1 (st AdapModelNum = (lmc_mii_readreg (sc, 0, 3) & 0x3f0) >> 4; if ((AdapModelNum == LMC_ADAP_T1 - && subdevice == PCI_PRODUCT_LMC_T1) || /* detect LMC1200 */ + && subdevice == PCI_DEVICE_ID_LMC_T1) || /* detect LMC1200 */ (AdapModelNum == LMC_ADAP_SSI - && subdevice == PCI_PRODUCT_LMC_SSI) || /* detect LMC1000 */ + && subdevice == PCI_DEVICE_ID_LMC_SSI) || /* detect LMC1000 */ (AdapModelNum == LMC_ADAP_DS3 - && subdevice == PCI_PRODUCT_LMC_DS3) || /* detect LMC5245 */ + && subdevice == PCI_DEVICE_ID_LMC_DS3) || /* detect LMC5245 */ (AdapModelNum == LMC_ADAP_HSSI - && subdevice == PCI_PRODUCT_LMC_HSSI)) + && subdevice == PCI_DEVICE_ID_LMC_HSSI)) { /* detect LMC5200 */ } @@ -996,10 +987,7 @@ static struct net_device *lmc_probe1 (st */ LMC_CSR_WRITE (sc, csr_gp_timer, 0xFFFFFFFFUL); - sc->board_idx = board_idx; - - memset (&sc->stats, 0, sizeof (struct lmc_statistics)); - + sc->board_idx = cards_found++; sc->stats.check = STATCHECK; sc->stats.version_size = (DRIVER_VERSION << 16) + sizeof (struct lmc_statistics); @@ -1008,105 +996,40 @@ static struct net_device *lmc_probe1 (st sc->lmc_ok = 0; sc->last_link_status = 0; - lmc_trace(dev, "lmc_probe1 out"); - - return dev; -} - - -/* This is the entry point. This is what is called immediately. */ -/* This goes out and finds the card */ + lmc_trace(dev, "lmc_init_one out"); + return 0; -int lmc_probe_fake(struct net_device *dev) /*fold00*/ -{ - lmc_probe(NULL); - /* Return 1 to unloaded bogus device */ - return 1; + out4: + lmc_proto_detach(sc); + out3: + if (pdev) { + pci_release_regions(pdev); + pci_set_drvdata(pdev, NULL); + } + out2: + free_netdev(dev); + out1: + return err; } -int lmc_probe (struct net_device *dev) /*fold00*/ +/* + * Called from pci when removing module. + */ +static void __devexit lmc_remove_one (struct pci_dev *pdev) { - int pci_index = 0; - unsigned long pci_ioaddr; - unsigned int pci_irq_line; - u16 vendor, subvendor, device, subdevice; - u32 foundaddr = 0; - u8 intcf = 0; - struct pci_dev *pdev = NULL; - - /* Loop basically until we don't find anymore. */ - while ((pdev = pci_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pdev))) { - if (pci_enable_device(pdev)) - break; - - vendor = pdev->vendor; - device = pdev->device; - pci_irq_line = pdev->irq; - pci_ioaddr = pci_resource_start (pdev, 0); - subvendor = pdev->subsystem_vendor; - subdevice = pdev->subsystem_device; - - pci_set_master (pdev); - - /* - * Make sure it's the correct card. CHECK SUBVENDOR ID! - * There are lots of tulip's out there. - * Also check the region of registers we will soon be - * poking, to make sure no one else has reserved them. - * This prevents taking someone else's device. - * - * Check either the subvendor or the subdevice, some systems reverse - * the setting in the bois, seems to be version and arch dependent? - * Fix the two variables - * - */ - if (!(check_region (pci_ioaddr, LMC_REG_RANGE)) && - (vendor == CORRECT_VENDOR_ID) && - (device == CORRECT_DEV_ID) && - ((subvendor == PCI_VENDOR_LMC) || (subdevice == PCI_VENDOR_LMC))){ - struct net_device *cur, *prev = NULL; - - /* Fix the error, exchange the two values */ - if(subdevice == PCI_VENDOR_LMC){ - subdevice = subvendor; - subvendor = PCI_VENDOR_LMC ; - } - - /* Make the call to actually setup this card */ - dev = lmc_probe1 (dev, pci_ioaddr, pci_irq_line, - device, subdevice, cards_found); - if (dev == NULL) { - printk ("lmc_probe: lmc_probe1 failed\n"); - goto lmc_probe_next_card; - } - /* insert the device into the chain of lmc devices */ - for (cur = Lmc_root_dev; - cur != NULL; - cur = ((lmc_softc_t *) cur->priv)->next_module) { - prev = cur; - } - - if (prev == NULL) - Lmc_root_dev = dev; - else - ((lmc_softc_t *) prev->priv)->next_module = dev; - - ((lmc_softc_t *) dev->priv)->next_module = NULL; - /* end insert */ - - foundaddr = dev->base_addr; - - cards_found++; - intcf++; - } - lmc_probe_next_card: - pci_index++; + struct net_device *dev = pci_get_drvdata(pdev); + + if (dev) { + lmc_softc_t *sc = dev->priv; + + printk("%s: removing...\n", dev->name); + lmc_proto_detach(sc); + unregister_netdev(dev); + free_netdev(dev); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); } - - if (cards_found < 1) - return -1; - - return foundaddr; } /* After this is called, packets can be sent. @@ -1181,8 +1104,6 @@ static int lmc_open (struct net_device * sc->stats.tx_tbusy0++ ; - MOD_INC_USE_COUNT; - /* * select what interrupts we want to get */ @@ -1352,7 +1273,6 @@ static int lmc_ifdown (struct net_device lmc_trace(dev, "lmc_ifdown out"); - MOD_DEC_USE_COUNT; return 0; } @@ -1850,12 +1770,11 @@ skip_out_of_mem: static struct net_device_stats *lmc_get_stats (struct net_device *dev) /*fold00*/ { - lmc_softc_t *sc; + lmc_softc_t *sc = dev->priv; unsigned long flags; lmc_trace(dev, "lmc_get_stats in"); - sc = dev->priv; spin_lock_irqsave(&sc->lmc_lock, flags); @@ -1868,58 +1787,21 @@ static struct net_device_stats *lmc_get_ return (struct net_device_stats *) &sc->stats; } +static struct pci_driver lmc_driver = { + .name = "lmc", + .id_table = lmc_pci_tbl, + .probe = lmc_init_one, + .remove = __devexit_p(lmc_remove_one), +}; + static int __init init_lmc(void) { - printk ("lmc: module loaded\n"); - - /* Have lmc_probe search for all the cards, and allocate devices */ - if (lmc_probe (NULL) < 0) - return -EIO; - - return 0; + return pci_module_init(&lmc_driver); } static void __exit exit_lmc(void) { - struct net_device *dev, *next; - lmc_softc_t *sc; - - /* we have no pointer to our devices, since they are all dynamically - * allocated. So, here we loop through all the network devices - * looking for ours. When found, dispose of them properly. - */ - - for (dev = Lmc_root_dev; - dev != NULL; - dev = next ) - { - - next = ((lmc_softc_t *) dev->priv)->next_module; /* get it now before we deallocate it */ - printk ("%s: removing...\n", dev->name); - - /* close the syncppp stuff, and release irq. Close is run on unreg net */ - lmc_close (dev); - sc = dev->priv; - if (sc != NULL) - lmc_proto_detach(sc); - - /* Remove the device from the linked list */ - unregister_netdev (dev); - - /* Let go of the io region */; - release_region (dev->base_addr, LMC_REG_RANGE); - - /* free our allocated structures. */ - kfree (dev->priv); - dev->priv = NULL; - - free_netdev (dev); - dev = NULL; - } - - - Lmc_root_dev = NULL; - printk ("lmc module unloaded\n"); + pci_unregister_driver(&lmc_driver); } module_init(init_lmc); @@ -2326,8 +2208,3 @@ bug_out: } - -int lmc_setup(void) { /*FOLD00*/ - return lmc_probe(NULL); -} - diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/wan/lmc/lmc_var.h 830-ivtv/drivers/net/wan/lmc/lmc_var.h --- 000-virgin/drivers/net/wan/lmc/lmc_var.h Sat Jun 14 18:37:30 2003 +++ 830-ivtv/drivers/net/wan/lmc/lmc_var.h Thu Jan 8 08:54:27 2004 @@ -390,7 +390,7 @@ struct lmc___softc { struct timer_list timer; lmc_ctl_t ictl; u_int32_t TxDescriptControlInit; - struct net_device *next_module; /* Link to the next module */ + int tx_TimeoutInd; /* additional driver state */ int tx_TimeoutDisplay; unsigned int lastlmc_taint_tx; @@ -519,18 +519,7 @@ struct lmc___softc { #define TULIP_CMD_RECEIVEALL 0x40000000L #endif - -/* PCI register values */ -#define CORRECT_VENDOR_ID 0x1011 -#define CORRECT_DEV_ID 9 - -#define PCI_VENDOR_LMC 0x1376 -#define PCI_PRODUCT_LMC_HSSI 0x0003 -#define PCI_PRODUCT_LMC_DS3 0x0004 -#define PCI_PRODUCT_LMC_SSI 0x0005 -#define PCI_PRODUCT_LMC_T1 0x0006 - -/* Adapcter module number */ +/* Adapter module number */ #define LMC_ADAP_HSSI 2 #define LMC_ADAP_DS3 3 #define LMC_ADAP_SSI 4 diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/wan/pc300_drv.c 830-ivtv/drivers/net/wan/pc300_drv.c --- 000-virgin/drivers/net/wan/pc300_drv.c Mon Nov 17 18:28:51 2003 +++ 830-ivtv/drivers/net/wan/pc300_drv.c Thu Jan 8 08:54:27 2004 @@ -3165,7 +3165,6 @@ int cpc_open(struct net_device *dev) return result; } - MOD_INC_USE_COUNT; sprintf(ifr.ifr_name, "%s", dev->name); cpc_opench(d); netif_start_queue(dev); @@ -3201,7 +3200,6 @@ int cpc_close(struct net_device *dev) } #endif - MOD_DEC_USE_COUNT; return 0; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/wan/pci200syn.c 830-ivtv/drivers/net/wan/pci200syn.c --- 000-virgin/drivers/net/wan/pci200syn.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/net/wan/pci200syn.c Thu Jan 8 08:54:27 2004 @@ -0,0 +1,475 @@ +/* + * Goramo PCI200SYN synchronous serial card driver for Linux + * + * Copyright (C) 2002-2003 Krzysztof Halasa + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * For information see http://hq.pm.waw.pl/hdlc/ + * + * Sources of information: + * Hitachi HD64572 SCA-II User's Manual + * PLX Technology Inc. PCI9052 Data Book + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hd64572.h" + +static const char* version = "Goramo PCI200SYN driver version: 1.16"; +static const char* devname = "PCI200SYN"; + +#undef DEBUG_PKT +#define DEBUG_RINGS + +#define PCI200SYN_PLX_SIZE 0x80 /* PLX control window size (128b) */ +#define PCI200SYN_SCA_SIZE 0x400 /* SCA window size (1Kb) */ +#define ALL_PAGES_ALWAYS_MAPPED +#define NEED_DETECT_RAM +#define NEED_SCA_MSCI_INTR +#define MAX_TX_BUFFERS 10 + +static int pci_clock_freq = 33000000; +#define CLOCK_BASE pci_clock_freq + +#define PCI_VENDOR_ID_GORAMO 0x10B5 /* uses PLX:9050 ID - this card */ +#define PCI_DEVICE_ID_PCI200SYN 0x9050 /* doesn't have its own ID */ + + +/* + * PLX PCI9052 local configuration and shared runtime registers. + * This structure can be used to access 9052 registers (memory mapped). + */ +typedef struct { + u32 loc_addr_range[4]; /* 00-0Ch : Local Address Ranges */ + u32 loc_rom_range; /* 10h : Local ROM Range */ + u32 loc_addr_base[4]; /* 14-20h : Local Address Base Addrs */ + u32 loc_rom_base; /* 24h : Local ROM Base */ + u32 loc_bus_descr[4]; /* 28-34h : Local Bus Descriptors */ + u32 rom_bus_descr; /* 38h : ROM Bus Descriptor */ + u32 cs_base[4]; /* 3C-48h : Chip Select Base Addrs */ + u32 intr_ctrl_stat; /* 4Ch : Interrupt Control/Status */ + u32 init_ctrl; /* 50h : EEPROM ctrl, Init Ctrl, etc */ +}plx9052; + + + +typedef struct port_s { + hdlc_device hdlc; /* HDLC device struct - must be first */ + struct card_s *card; + spinlock_t lock; /* TX lock */ + sync_serial_settings settings; + int rxpart; /* partial frame received, next frame invalid*/ + unsigned short encoding; + unsigned short parity; + u16 rxin; /* rx ring buffer 'in' pointer */ + u16 txin; /* tx ring buffer 'in' and 'last' pointers */ + u16 txlast; + u8 rxs, txs, tmc; /* SCA registers */ + u8 phy_node; /* physical port # - 0 or 1 */ +}port_t; + + + +typedef struct card_s { + u8* rambase; /* buffer memory base (virtual) */ + u8* scabase; /* SCA memory base (virtual) */ + plx9052* plxbase; /* PLX registers memory base (virtual) */ + u16 rx_ring_buffers; /* number of buffers in a ring */ + u16 tx_ring_buffers; + u16 buff_offset; /* offset of first buffer of first channel */ + u8 irq; /* interrupt request level */ + + port_t ports[2]; +}card_t; + + +#define sca_in(reg, card) readb(card->scabase + (reg)) +#define sca_out(value, reg, card) writeb(value, card->scabase + (reg)) +#define sca_inw(reg, card) readw(card->scabase + (reg)) +#define sca_outw(value, reg, card) writew(value, card->scabase + (reg)) +#define sca_inl(reg, card) readl(card->scabase + (reg)) +#define sca_outl(value, reg, card) writel(value, card->scabase + (reg)) + +#define port_to_card(port) (port->card) +#define log_node(port) (port->phy_node) +#define phy_node(port) (port->phy_node) +#define winbase(card) (card->rambase) +#define get_port(card, port) (&card->ports[port]) +#define sca_flush(card) (sca_in(IER0, card)); + +static inline void new_memcpy_toio(char *dest, char *src, int length) +{ + int len; + do { + len = length > 256 ? 256 : length; + memcpy_toio(dest, src, len); + dest += len; + src += len; + length -= len; + readb(dest); + } while (len); +} + +#undef memcpy_toio +#define memcpy_toio new_memcpy_toio + +#include "hd6457x.c" + + +static void pci200_set_iface(port_t *port) +{ + card_t *card = port->card; + u16 msci = get_msci(port); + u8 rxs = port->rxs & CLK_BRG_MASK; + u8 txs = port->txs & CLK_BRG_MASK; + + sca_out(EXS_TES1, (phy_node(port) ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS, + port_to_card(port)); + switch(port->settings.clock_type) { + case CLOCK_INT: + rxs |= CLK_BRG; /* BRG output */ + txs |= CLK_PIN_OUT | CLK_TX_RXCLK; /* RX clock */ + break; + + case CLOCK_TXINT: + rxs |= CLK_LINE; /* RXC input */ + txs |= CLK_PIN_OUT | CLK_BRG; /* BRG output */ + break; + + case CLOCK_TXFROMRX: + rxs |= CLK_LINE; /* RXC input */ + txs |= CLK_PIN_OUT | CLK_TX_RXCLK; /* RX clock */ + break; + + default: /* EXTernal clock */ + rxs |= CLK_LINE; /* RXC input */ + txs |= CLK_PIN_OUT | CLK_LINE; /* TXC input */ + break; + } + + port->rxs = rxs; + port->txs = txs; + sca_out(rxs, msci + RXS, card); + sca_out(txs, msci + TXS, card); + sca_set_port(port); +} + + + +static int pci200_open(struct net_device *dev) +{ + hdlc_device *hdlc = dev_to_hdlc(dev); + port_t *port = hdlc_to_port(hdlc); + + int result = hdlc_open(hdlc); + if (result) + return result; + + sca_open(hdlc); + pci200_set_iface(port); + sca_flush(port_to_card(port)); + return 0; +} + + + +static int pci200_close(struct net_device *dev) +{ + hdlc_device *hdlc = dev_to_hdlc(dev); + sca_close(hdlc); + sca_flush(port_to_card(dev_to_port(dev))); + hdlc_close(hdlc); + return 0; +} + + + +static int pci200_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + const size_t size = sizeof(sync_serial_settings); + sync_serial_settings new_line, *line = ifr->ifr_settings.ifs_ifsu.sync; + hdlc_device *hdlc = dev_to_hdlc(dev); + port_t *port = hdlc_to_port(hdlc); + +#ifdef DEBUG_RINGS + if (cmd == SIOCDEVPRIVATE) { + sca_dump_rings(hdlc); + return 0; + } +#endif + if (cmd != SIOCWANDEV) + return hdlc_ioctl(dev, ifr, cmd); + + switch(ifr->ifr_settings.type) { + case IF_GET_IFACE: + ifr->ifr_settings.type = IF_IFACE_V35; + if (ifr->ifr_settings.size < size) { + ifr->ifr_settings.size = size; /* data size wanted */ + return -ENOBUFS; + } + if (copy_to_user(line, &port->settings, size)) + return -EFAULT; + return 0; + + case IF_IFACE_V35: + case IF_IFACE_SYNC_SERIAL: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + if (copy_from_user(&new_line, line, size)) + return -EFAULT; + + if (new_line.clock_type != CLOCK_EXT && + new_line.clock_type != CLOCK_TXFROMRX && + new_line.clock_type != CLOCK_INT && + new_line.clock_type != CLOCK_TXINT) + return -EINVAL; /* No such clock setting */ + + if (new_line.loopback != 0 && new_line.loopback != 1) + return -EINVAL; + + memcpy(&port->settings, &new_line, size); /* Update settings */ + pci200_set_iface(port); + sca_flush(port_to_card(port)); + return 0; + + default: + return hdlc_ioctl(dev, ifr, cmd); + } +} + + + +static void pci200_pci_remove_one(struct pci_dev *pdev) +{ + int i; + card_t *card = pci_get_drvdata(pdev); + + for(i = 0; i < 2; i++) + if (card->ports[i].card) + unregister_hdlc_device(&card->ports[i].hdlc); + + if (card->irq) + free_irq(card->irq, card); + + if (card->rambase) + iounmap(card->rambase); + if (card->scabase) + iounmap(card->scabase); + if (card->plxbase) + iounmap(card->plxbase); + + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + kfree(card); +} + + + +static int __devinit pci200_pci_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + card_t *card; + u8 rev_id; + u32 *p; + int i; + u32 ramsize; + u32 ramphys; /* buffer memory base */ + u32 scaphys; /* SCA memory base */ + u32 plxphys; /* PLX registers memory base */ + +#ifndef MODULE + static int printed_version; + if (!printed_version++) + printk(KERN_INFO "%s\n", version); +#endif + + i = pci_enable_device(pdev); + if (i) + return i; + + i = pci_request_regions(pdev, "PCI200SYN"); + if (i) { + pci_disable_device(pdev); + return i; + } + + card = kmalloc(sizeof(card_t), GFP_KERNEL); + if (card == NULL) { + printk(KERN_ERR "pci200syn: unable to allocate memory\n"); + pci_release_regions(pdev); + pci_disable_device(pdev); + return -ENOBUFS; + } + memset(card, 0, sizeof(card_t)); + pci_set_drvdata(pdev, card); + + pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id); + if (pci_resource_len(pdev, 0) != PCI200SYN_PLX_SIZE || + pci_resource_len(pdev, 2) != PCI200SYN_SCA_SIZE || + pci_resource_len(pdev, 3) < 16384) { + printk(KERN_ERR "pci200syn: invalid card EEPROM parameters\n"); + pci200_pci_remove_one(pdev); + return -EFAULT; + } + + plxphys = pci_resource_start(pdev,0) & PCI_BASE_ADDRESS_MEM_MASK; + card->plxbase = ioremap(plxphys, PCI200SYN_PLX_SIZE); + + scaphys = pci_resource_start(pdev,2) & PCI_BASE_ADDRESS_MEM_MASK; + card->scabase = ioremap(scaphys, PCI200SYN_SCA_SIZE); + + ramphys = pci_resource_start(pdev,3) & PCI_BASE_ADDRESS_MEM_MASK; + card->rambase = ioremap(ramphys, pci_resource_len(pdev,3)); + + if (card->plxbase == NULL || + card->scabase == NULL || + card->rambase == NULL) { + printk(KERN_ERR "pci200syn: ioremap() failed\n"); + pci200_pci_remove_one(pdev); + } + + /* Reset PLX */ + p = &card->plxbase->init_ctrl; + writel(readl(p) | 0x40000000, p); + readl(p); /* Flush the write - do not use sca_flush */ + udelay(1); + + writel(readl(p) & ~0x40000000, p); + readl(p); /* Flush the write - do not use sca_flush */ + udelay(1); + + ramsize = sca_detect_ram(card, card->rambase, + pci_resource_len(pdev, 3)); + + /* number of TX + RX buffers for one port - this is dual port card */ + i = ramsize / (2 * (sizeof(pkt_desc) + HDLC_MAX_MRU)); + card->tx_ring_buffers = min(i / 2, MAX_TX_BUFFERS); + card->rx_ring_buffers = i - card->tx_ring_buffers; + + card->buff_offset = 2 * sizeof(pkt_desc) * (card->tx_ring_buffers + + card->rx_ring_buffers); + + printk(KERN_INFO "pci200syn: %u KB RAM at 0x%x, IRQ%u, using %u TX +" + " %u RX packets rings\n", ramsize / 1024, ramphys, + pdev->irq, card->tx_ring_buffers, card->rx_ring_buffers); + + if (card->tx_ring_buffers < 1) { + printk(KERN_ERR "pci200syn: RAM test failed\n"); + pci200_pci_remove_one(pdev); + return -EFAULT; + } + + /* Enable interrupts on the PCI bridge */ + p = &card->plxbase->intr_ctrl_stat; + writew(readw(p) | 0x0040, p); + + /* Allocate IRQ */ + if(request_irq(pdev->irq, sca_intr, SA_SHIRQ, devname, card)) { + printk(KERN_WARNING "pci200syn: could not allocate IRQ%d.\n", + pdev->irq); + pci200_pci_remove_one(pdev); + return -EBUSY; + } + card->irq = pdev->irq; + + sca_init(card, 0); + + for(i = 0; i < 2; i++) { + port_t *port = &card->ports[i]; + struct net_device *dev = hdlc_to_dev(&port->hdlc); + port->phy_node = i; + + spin_lock_init(&port->lock); + SET_MODULE_OWNER(dev); + dev->irq = card->irq; + dev->mem_start = ramphys; + dev->mem_end = ramphys + ramsize - 1; + dev->tx_queue_len = 50; + dev->do_ioctl = pci200_ioctl; + dev->open = pci200_open; + dev->stop = pci200_close; + port->hdlc.attach = sca_attach; + port->hdlc.xmit = sca_xmit; + port->settings.clock_type = CLOCK_EXT; + if(register_hdlc_device(&port->hdlc)) { + printk(KERN_ERR "pci200syn: unable to register hdlc " + "device\n"); + pci200_pci_remove_one(pdev); + return -ENOBUFS; + } + port->card = card; + sca_init_sync_port(port); /* Set up SCA memory */ + + printk(KERN_INFO "%s: PCI200SYN node %d\n", + hdlc_to_name(&port->hdlc), port->phy_node); + } + + sca_flush(card); + return 0; +} + + + +static struct pci_device_id pci200_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_GORAMO, PCI_DEVICE_ID_PCI200SYN, PCI_ANY_ID, + PCI_ANY_ID, 0, 0, 0 }, + { 0, } +}; + + +static struct pci_driver pci200_pci_driver = { + name: "PCI200SYN", + id_table: pci200_pci_tbl, + probe: pci200_pci_init_one, + remove: pci200_pci_remove_one, +}; + + +static int __init pci200_init_module(void) +{ +#ifdef MODULE + printk(KERN_INFO "%s\n", version); +#endif + if (pci_clock_freq < 1000000 || pci_clock_freq > 80000000) { + printk(KERN_ERR "pci200syn: Invalid PCI clock frequency\n"); + return -EINVAL; + } + return pci_module_init(&pci200_pci_driver); +} + + + +static void __exit pci200_cleanup_module(void) +{ + pci_unregister_driver(&pci200_pci_driver); +} + +MODULE_AUTHOR("Krzysztof Halasa "); +MODULE_DESCRIPTION("Goramo PCI200SYN serial port driver"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(pci, pci200_pci_tbl); +module_param(pci_clock_freq, int, 0444); +MODULE_PARM_DESC(pci_clock_freq, "System PCI clock frequency in Hz"); +module_init(pci200_init_module); +module_exit(pci200_cleanup_module); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/wan/x25_asy.c 830-ivtv/drivers/net/wan/x25_asy.c --- 000-virgin/drivers/net/wan/x25_asy.c Tue Sep 2 09:55:48 2003 +++ 830-ivtv/drivers/net/wan/x25_asy.c Thu Jan 8 08:54:28 2004 @@ -94,7 +94,7 @@ static struct x25_asy *x25_asy_alloc(voi return sl; } else { printk("x25_asy_alloc() - register_netdev() failure.\n"); - kfree(dev); + free_netdev(dev); } } return NULL; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/wd.c 830-ivtv/drivers/net/wd.c --- 000-virgin/drivers/net/wd.c Mon Nov 17 18:28:51 2003 +++ 830-ivtv/drivers/net/wd.c Thu Jan 8 08:54:28 2004 @@ -47,7 +47,6 @@ static const char version[] = static unsigned int wd_portlist[] __initdata = {0x300, 0x280, 0x380, 0x240, 0}; -int wd_probe(struct net_device *dev); static int wd_probe1(struct net_device *dev, int ioaddr); static int wd_open(struct net_device *dev); @@ -83,11 +82,14 @@ static int wd_close(struct net_device *d The wd_probe1() routine initializes the card and fills the station address field. */ -int __init wd_probe(struct net_device *dev) +static int __init do_wd_probe(struct net_device *dev) { int i; struct resource *r; int base_addr = dev->base_addr; + int irq = dev->irq; + int mem_start = dev->mem_start; + int mem_end = dev->mem_end; SET_MODULE_OWNER(dev); @@ -115,11 +117,45 @@ int __init wd_probe(struct net_device *d return 0; } release_region(ioaddr, WD_IO_EXTENT); + dev->irq = irq; + dev->mem_start = mem_start; + dev->mem_end = mem_end; } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + free_irq(dev->irq, dev); + release_region(dev->base_addr - WD_NIC_OFFSET, WD_IO_EXTENT); +} + +struct net_device * __init wd_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_wd_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init wd_probe1(struct net_device *dev, int ioaddr) { int i; @@ -262,19 +298,11 @@ static int __init wd_probe1(struct net_d } else if (dev->irq == 2) /* Fixup bogosity: IRQ2 is really IRQ9 */ dev->irq = 9; - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk (" unable to get memory for dev->priv.\n"); - return -ENOMEM; - } - /* Snarf the interrupt now. There's no point in waiting since we cannot share and the board will usually be enabled. */ i = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev); if (i) { printk (" unable to get IRQ %d.\n", dev->irq); - kfree(dev->priv); - dev->priv = NULL; return i; } @@ -446,7 +474,7 @@ wd_close(struct net_device *dev) #ifdef MODULE #define MAX_WD_CARDS 4 /* Max number of wd cards per module */ -static struct net_device dev_wd[MAX_WD_CARDS]; +static struct net_device *dev_wd[MAX_WD_CARDS]; static int io[MAX_WD_CARDS]; static int irq[MAX_WD_CARDS]; static int mem[MAX_WD_CARDS]; @@ -468,29 +496,35 @@ ISA device autoprobes on a running machi int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_WD_CARDS; this_dev++) { - struct net_device *dev = &dev_wd[this_dev]; - dev->irq = irq[this_dev]; - dev->base_addr = io[this_dev]; - dev->mem_start = mem[this_dev]; - dev->mem_end = mem_end[this_dev]; - dev->init = wd_probe; if (io[this_dev] == 0) { if (this_dev != 0) break; /* only autoprobe 1st one */ printk(KERN_NOTICE "wd.c: Presently autoprobing (not recommended) for a single card.\n"); } - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "wd.c: No wd80x3 card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) { /* Got at least one. */ - return 0; + dev = alloc_ei_netdev(); + if (!dev) + break; + dev->irq = irq[this_dev]; + dev->base_addr = io[this_dev]; + dev->mem_start = mem[this_dev]; + dev->mem_end = mem_end[this_dev]; + if (do_wd_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_wd[found++] = dev; + continue; } - return -ENXIO; + cleanup_card(dev); } - found++; + free_netdev(dev); + printk(KERN_WARNING "wd.c: No wd80x3 card found (i/o = 0x%x).\n", io[this_dev]); + break; } - return 0; + if (found) + return 0; + return -ENXIO; } void @@ -499,14 +533,11 @@ cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < MAX_WD_CARDS; this_dev++) { - struct net_device *dev = &dev_wd[this_dev]; - if (dev->priv != NULL) { - void *priv = dev->priv; - int ioaddr = dev->base_addr - WD_NIC_OFFSET; - free_irq(dev->irq, dev); - release_region(ioaddr, WD_IO_EXTENT); + struct net_device *dev = dev_wd[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(priv); + cleanup_card(dev); + free_netdev(dev); } } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/wireless/airo.c 830-ivtv/drivers/net/wireless/airo.c --- 000-virgin/drivers/net/wireless/airo.c Wed Dec 24 18:16:47 2003 +++ 830-ivtv/drivers/net/wireless/airo.c Thu Jan 8 08:54:28 2004 @@ -1027,7 +1027,6 @@ struct airo_info { #define FLAG_802_11 7 #define FLAG_PENDING_XMIT 9 #define FLAG_PENDING_XMIT11 10 -#define FLAG_PCI 11 #define JOB_MASK 0x1ff0000 #define JOB_DIE 16 #define JOB_XMIT 17 @@ -4623,7 +4622,6 @@ static int __devinit airo_pci_probe(stru return -ENODEV; pci_set_drvdata(pdev, dev); - set_bit (FLAG_PCI, &((struct airo_info *)dev->priv)->flags); return 0; } @@ -4653,7 +4651,7 @@ static int __init airo_init_module( void #ifdef CONFIG_PCI printk( KERN_INFO "airo: Probing for PCI adapters\n" ); - pci_module_init(&airo_driver); + pci_register_driver(&airo_driver); printk( KERN_INFO "airo: Finished probing for PCI adapters\n" ); #endif @@ -4665,22 +4663,15 @@ static int __init airo_init_module( void static void __exit airo_cleanup_module( void ) { - int is_pci = 0; while( airo_devices ) { printk( KERN_INFO "airo: Unregistering %s\n", airo_devices->dev->name ); -#ifdef CONFIG_PCI - if (test_bit(FLAG_PCI, &((struct airo_info *)airo_devices->dev->priv)->flags)) - is_pci = 1; -#endif stop_airo_card( airo_devices->dev, 1 ); } remove_proc_entry("aironet", proc_root_driver); - if (is_pci) { #ifdef CONFIG_PCI - pci_unregister_driver(&airo_driver); + pci_unregister_driver(&airo_driver); #endif - } } #ifdef WIRELESS_EXT diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/wireless/airport.c 830-ivtv/drivers/net/wireless/airport.c --- 000-virgin/drivers/net/wireless/airport.c Mon Nov 17 18:28:15 2003 +++ 830-ivtv/drivers/net/wireless/airport.c Thu Jan 8 08:54:29 2004 @@ -216,7 +216,7 @@ airport_attach(struct macio_dev *mdev, c if (! request_OF_resource(of_node, 0, " (airport)")) { printk(KERN_ERR "airport: can't request IO resource !\n"); - kfree(dev); + free_netdev(dev); return -ENODEV; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/wireless/arlan-main.c 830-ivtv/drivers/net/wireless/arlan-main.c --- 000-virgin/drivers/net/wireless/arlan-main.c Mon Nov 17 18:29:30 2003 +++ 830-ivtv/drivers/net/wireless/arlan-main.c Thu Jan 8 08:54:29 2004 @@ -19,9 +19,7 @@ struct net_device *arlan_device[MAX_ARLA static int SID = SIDUNKNOWN; static int radioNodeId = radioNodeIdUNKNOWN; static char encryptionKey[12] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}; -static int mem = memUNKNOWN; int arlan_debug = debugUNKNOWN; -static int numDevices = numDevicesUNKNOWN; static int spreadingCode = spreadingCodeUNKNOWN; static int channelNumber = channelNumberUNKNOWN; static int channelSet = channelSetUNKNOWN; @@ -45,9 +43,7 @@ static int mdebug; MODULE_PARM(irq, "i"); MODULE_PARM(mem, "i"); -MODULE_PARM(probe, "i"); MODULE_PARM(arlan_debug, "i"); -MODULE_PARM(numDevices, "i"); MODULE_PARM(testMemory, "i"); MODULE_PARM(spreadingCode, "i"); MODULE_PARM(channelNumber, "i"); @@ -69,9 +65,7 @@ MODULE_PARM(arlan_entry_and_exit_debug, MODULE_PARM(arlan_EEPROM_bad, "i"); MODULE_PARM_DESC(irq, "(unused)"); MODULE_PARM_DESC(mem, "Arlan memory address for single device probing"); -MODULE_PARM_DESC(probe, "Arlan probe at initialization (0-1)"); MODULE_PARM_DESC(arlan_debug, "Arlan debug enable (0-1)"); -MODULE_PARM_DESC(numDevices, "Number of Arlan devices; ignored if >1"); MODULE_PARM_DESC(testMemory, "(unused)"); MODULE_PARM_DESC(mdebug, "Arlan multicast debugging (0-1)"); MODULE_PARM_DESC(retries, "Arlan maximum packet retransmisions"); @@ -88,7 +82,6 @@ MODULE_PARM_DESC(arlan_entry_and_exit_de struct arlan_conf_stru arlan_conf[MAX_ARLANS]; static int arlans_found; -static int arlan_probe_here(struct net_device *dev, int ioaddr); static int arlan_open(struct net_device *dev); static int arlan_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t arlan_interrupt(int irq, void *dev_id, struct pt_regs *regs); @@ -975,24 +968,27 @@ static int lastFoundAt = 0xbe000; * probes on the ISA bus. A good device probes avoids doing writes, and * verifies that the correct device exists and functions. */ - -static int __init arlan_check_fingerprint(int memaddr) +#define ARLAN_SHMEM_SIZE 0x2000 +static int __init arlan_check_fingerprint(unsigned long memaddr) { - static char probeText[] = "TELESYSTEM SLW INC. ARLAN \0"; - char tempBuf[49]; + static const char probeText[] = "TELESYSTEM SLW INC. ARLAN \0"; volatile struct arlan_shmem *arlan = (struct arlan_shmem *) memaddr; + unsigned long paddr = virt_to_phys((void *) memaddr); + char tempBuf[49]; ARLAN_DEBUG_ENTRY("arlan_check_fingerprint"); - if (check_mem_region(virt_to_phys((void *)memaddr),0x2000 )){ - // printk(KERN_WARNING "arlan: memory region %lx excluded from probing \n",virt_to_phys((void*)memaddr)); + + if (!request_mem_region(paddr, ARLAN_SHMEM_SIZE, "arlan")) { + // printk(KERN_WARNING "arlan: memory region %lx excluded from probing \n",paddr); return -ENODEV; } + memcpy_fromio(tempBuf, arlan->textRegion, 29); tempBuf[30] = 0; /* check for card at this address */ if (0 != strncmp(tempBuf, probeText, 29)){ -// not release_mem_region(virt_to_phys((void*)memaddr),0x2000); + release_mem_region(paddr, ARLAN_SHMEM_SIZE); return -ENODEV; } @@ -1000,51 +996,8 @@ static int __init arlan_check_fingerprin ARLAN_DEBUG_EXIT("arlan_check_fingerprint"); return 0; - - -} - -static int __init arlan_probe_everywhere(struct net_device *dev) -{ - int m; - int probed = 0; - int found = 0; - - SET_MODULE_OWNER(dev); - - ARLAN_DEBUG_ENTRY("arlan_probe_everywhere"); - if (mem != 0 && numDevices == 1) /* Check a single specified location. */ - { - if (arlan_probe_here(dev, (int) phys_to_virt( mem) ) == 0) - return 0; - else - return -ENODEV; - } - for (m = (int)phys_to_virt(lastFoundAt) + 0x2000; m <= (int)phys_to_virt(0xDE000); m += 0x2000) - { - if (arlan_probe_here(dev, m) == 0) - { - found++; - lastFoundAt = (int)virt_to_phys((void*)m); - break; - } - probed++; - } - if (found == 0 && probed != 0) - { - if (lastFoundAt == 0xbe000) - printk(KERN_ERR "arlan: No Arlan devices found \n"); - return -ENODEV; - } - else - return 0; - - ARLAN_DEBUG_EXIT("arlan_probe_everywhere"); - - return -ENODEV; } - static int arlan_change_mtu(struct net_device *dev, int new_mtu) { struct arlan_private *priv = dev->priv; @@ -1085,47 +1038,15 @@ static int arlan_mac_addr(struct net_dev - -static int __init - arlan_allocate_device(int num, struct net_device *devs) +static int __init arlan_setup_device(struct net_device *dev, int num) { + struct arlan_private *ap = dev->priv; + int err; - struct net_device *dev; - struct arlan_private *ap; + ARLAN_DEBUG_ENTRY("arlan_setup_device"); - ARLAN_DEBUG_ENTRY("arlan_allocate_device"); + ap->conf = (struct arlan_shmem *)(ap+1); - if (!devs) { - dev = init_etherdev(0, sizeof(struct arlan_private) + sizeof(struct arlan_shmem)); - if (!dev) { - printk(KERN_ERR "ARLAN: init_etherdev failed\n"); - return 0; - } - ap = dev->priv; - ap->conf = dev->priv + sizeof(struct arlan_private); - ap->init_etherdev_alloc = 1; - } else { - dev = devs; - dev->priv = kmalloc(sizeof(struct arlan_private) + sizeof(struct arlan_shmem), GFP_KERNEL); - if (!dev->priv) { - printk(KERN_ERR "ARLAN: kmalloc of dev->priv failed\n"); - return 0; - } - ap = dev->priv; - ap->conf = dev->priv + sizeof(struct arlan_private); - memset(ap, 0, sizeof(*ap)); - } - - /* Fill in the 'dev' fields. */ - dev->base_addr = 0; - dev->mem_start = 0; - dev->mem_end = 0; - dev->mtu = 1500; - dev->flags = 0; /* IFF_BROADCAST & IFF_MULTICAST & IFF_PROMISC; */ - dev->irq = 0; - dev->dma = 0; - dev->tx_queue_len = tx_queue_len; - ether_setup(dev); dev->tx_queue_len = tx_queue_len; dev->open = arlan_open; dev->stop = arlan_close; @@ -1138,41 +1059,45 @@ static int __init dev->watchdog_timeo = 3*HZ; ap->irq_test_done = 0; - arlan_device[num] = dev; ap->Conf = &arlan_conf[num]; ap->Conf->pre_Command_Wait = 40; ap->Conf->rx_tweak1 = 30; ap->Conf->rx_tweak2 = 0; - ARLAN_DEBUG_EXIT("arlan_allocate_device"); - return (int) dev; -} + err = register_netdev(dev); + if (err) { + release_mem_region(virt_to_phys((void *) dev->mem_start), + ARLAN_SHMEM_SIZE); + free_netdev(dev); + return err; + } + arlan_device[num] = dev; + ARLAN_DEBUG_EXIT("arlan_setup_device"); + return 0; +} -static int __init arlan_probe_here(struct net_device *dev, int memaddr) +static int __init arlan_probe_here(struct net_device *dev, + unsigned long memaddr) { - volatile struct arlan_shmem *arlan; + struct arlan_private *ap = dev->priv; ARLAN_DEBUG_ENTRY("arlan_probe_here"); if (arlan_check_fingerprint(memaddr)) return -ENODEV; - printk(KERN_NOTICE "%s: Arlan found at %x, \n ", dev->name, (int) virt_to_phys((void*)memaddr)); - - if (!arlan_allocate_device(arlans_found, dev)) - return -1; - - ((struct arlan_private *) dev->priv)->card = (struct arlan_shmem *) memaddr; - arlan = (void *) memaddr; + printk(KERN_NOTICE "%s: Arlan found at %x, \n ", dev->name, + (int) virt_to_phys((void*)memaddr)); + ap->card = (void *) memaddr; dev->mem_start = memaddr; - dev->mem_end = memaddr + 0x1FFF; + dev->mem_end = memaddr + ARLAN_SHMEM_SIZE-1; if (dev->irq < 2) { - READSHM(dev->irq, arlan->irqLevel, u_char); + READSHM(dev->irq, ap->card->irqLevel, u_char); } else if (dev->irq == 2) dev->irq = 9; @@ -1183,8 +1108,6 @@ static int __init arlan_probe_here(struc } - - static int arlan_open(struct net_device *dev) { struct arlan_private *priv = dev->priv; @@ -1193,12 +1116,6 @@ static int arlan_open(struct net_device ARLAN_DEBUG_ENTRY("arlan_open"); - if (dev->mem_start == 0) - ret = arlan_probe_everywhere(dev); - if (ret != 0) - return ret; - - arlan = priv->card; ret = request_irq(dev->irq, &arlan_interrupt, 0, dev->name, dev); if (ret) { @@ -1768,14 +1685,9 @@ static int arlan_close(struct net_device { struct arlan_private *priv = dev->priv; - if (!priv) - { - printk(KERN_CRIT "arlan: No Device priv \n"); - return 0; - } ARLAN_DEBUG_ENTRY("arlan_close"); - del_timer(&priv->timer); + del_timer_sync(&priv->timer); arlan_command(dev, ARLAN_COMMAND_POWERDOWN); @@ -1867,39 +1779,70 @@ static void arlan_set_multicast(struct n } -int __init arlan_probe(struct net_device *dev) +struct net_device * __init arlan_probe(int unit) { - printk("Arlan driver %s\n", arlan_version); + struct net_device *dev; + int err; + int m; - if (arlan_probe_everywhere(dev)) - return -ENODEV; + ARLAN_DEBUG_ENTRY("arlan_probe"); - arlans_found++; - return 0; -} + if (arlans_found == MAX_ARLANS) + return ERR_PTR(-ENODEV); -#ifdef MODULE + /* + * Reserve space for local data and a copy of the shared memory + * that is used by the /proc interface. + */ + dev = alloc_etherdev(sizeof(struct arlan_private) + + sizeof(struct arlan_shmem)); + if (!dev) + return ERR_PTR(-ENOMEM); -static int probe = probeUNKNOWN; + SET_MODULE_OWNER(dev); -static int __init arlan_find_devices(void) -{ - int m; - int found = 0; + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + if (dev->mem_start) { + if (arlan_probe_here(dev, dev->mem_start) == 0) + goto found; + goto not_found; + } + + } - ARLAN_DEBUG_ENTRY("arlan_find_devices"); - if (mem != 0 && numDevices == 1) /* Check a single specified location. */ - return 1; - for (m =(int) phys_to_virt(0xc0000); m <=(int) phys_to_virt(0xDE000); m += 0x2000) + + for (m = (int)phys_to_virt(lastFoundAt) + ARLAN_SHMEM_SIZE; + m <= (int)phys_to_virt(0xDE000); + m += ARLAN_SHMEM_SIZE) { - if (arlan_check_fingerprint(m) == 0) - found++; + if (arlan_probe_here(dev, m) == 0) + { + lastFoundAt = (int)virt_to_phys((void*)m); + goto found; + } } - ARLAN_DEBUG_EXIT("arlan_find_devices"); - return found; + if (lastFoundAt == 0xbe000) + printk(KERN_ERR "arlan: No Arlan devices found \n"); + + not_found: + free_netdev(dev); + return ERR_PTR(-ENODEV); + + found: + err = arlan_setup_device(dev, arlans_found); + if (err) + dev = ERR_PTR(err); + else if (!arlans_found++) + printk(KERN_INFO "Arlan driver %s\n", arlan_version); + + return dev; } +#ifdef MODULE int init_module(void) { int i = 0; @@ -1909,21 +1852,11 @@ int init_module(void) if (channelSet != channelSetUNKNOWN || channelNumber != channelNumberUNKNOWN || systemId != systemIdUNKNOWN) return -EINVAL; - numDevices = arlan_find_devices(); - if (numDevices == 0) - return -ENODEV; - - for (i = 0; i < numDevices && i < MAX_ARLANS; i++) - { - if (!arlan_allocate_device(i, NULL)) - return -ENOMEM; + for (i = 0; i < MAX_ARLANS; i++) { + struct net_device *dev = arlan_probe(i); - if (arlan_device[i] == NULL) - return -ENOMEM; - - if (probe) - arlan_probe_everywhere(arlan_device[i]); -// arlan_command(arlan_device[i], ARLAN_COMMAND_POWERDOWN ); + if (IS_ERR(dev)) + return PTR_ERR(dev); } init_arlan_proc(); printk(KERN_INFO "Arlan driver %s\n", arlan_version); @@ -1935,7 +1868,7 @@ int init_module(void) void cleanup_module(void) { int i = 0; - struct arlan_private *ap; + struct net_device *dev; ARLAN_DEBUG_ENTRY("cleanup_module"); @@ -1946,22 +1879,18 @@ void cleanup_module(void) for (i = 0; i < MAX_ARLANS; i++) { - if (arlan_device[i]) - { - arlan_command(arlan_device[i], ARLAN_COMMAND_POWERDOWN ); - -// release_mem_region(virt_to_phys(arlan_device[i]->mem_start), 0x2000 ); - unregister_netdev(arlan_device[i]); - ap = arlan_device[i]->priv; - if (ap->init_etherdev_alloc) { - free_netdev(arlan_device[i]); - arlan_device[i] = NULL; - } else { - kfree(ap); - ap = NULL; - } + dev = arlan_device[i]; + if (dev) { + arlan_command(dev, ARLAN_COMMAND_POWERDOWN ); + + unregister_netdev(dev); + release_mem_region(virt_to_phys((void *) dev->mem_start), + ARLAN_SHMEM_SIZE); + free_netdev(dev); + arlan_device[i] = NULL; } } + ARLAN_DEBUG_EXIT("cleanup_module"); } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/wireless/arlan.h 830-ivtv/drivers/net/wireless/arlan.h --- 000-virgin/drivers/net/wireless/arlan.h Mon Nov 17 18:28:51 2003 +++ 830-ivtv/drivers/net/wireless/arlan.h Thu Jan 8 08:54:29 2004 @@ -57,12 +57,8 @@ extern int arlan_command(struct net_ #define SIDUNKNOWN -1 #define radioNodeIdUNKNOWN -1 -#define encryptionKeyUNKNOWN '\0'; #define irqUNKNOWN 0 -#define memUNKNOWN 0 #define debugUNKNOWN 0 -#define probeUNKNOWN 1 -#define numDevicesUNKNOWN 1 #define testMemoryUNKNOWN 1 #define spreadingCodeUNKNOWN 0 #define channelNumberUNKNOWN 0 @@ -81,6 +77,8 @@ extern int arlan_command(struct net_ #else #define ARLAN_DEBUG(a,b) #endif + +#define ARLAN_SHMEM_SIZE 0x2000 struct arlan_shmem { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/wireless/atmel.c 830-ivtv/drivers/net/wireless/atmel.c --- 000-virgin/drivers/net/wireless/atmel.c Thu Jan 8 08:35:39 2004 +++ 830-ivtv/drivers/net/wireless/atmel.c Thu Jan 8 08:54:29 2004 @@ -1443,7 +1443,7 @@ struct net_device *init_atmel_card( unsi err_out_irq: free_irq(dev->irq, dev); err_out_free: - kfree(dev); + free_netdev(dev); return NULL; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/wireless/orinoco_pci.c 830-ivtv/drivers/net/wireless/orinoco_pci.c --- 000-virgin/drivers/net/wireless/orinoco_pci.c Tue Sep 2 09:55:48 2003 +++ 830-ivtv/drivers/net/wireless/orinoco_pci.c Thu Jan 8 08:54:29 2004 @@ -261,7 +261,7 @@ static int orinoco_pci_init_one(struct p if (dev->irq) free_irq(dev->irq, dev); - kfree(dev); + free_netdev(dev); } if (pci_ioaddr) @@ -360,6 +360,7 @@ static int orinoco_pci_resume(struct pci } static struct pci_device_id orinoco_pci_pci_id_table[] = { + {0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,}, {0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,}, {0,}, }; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/wireless/orinoco_plx.c 830-ivtv/drivers/net/wireless/orinoco_plx.c --- 000-virgin/drivers/net/wireless/orinoco_plx.c Tue Sep 2 09:55:48 2003 +++ 830-ivtv/drivers/net/wireless/orinoco_plx.c Thu Jan 8 08:54:29 2004 @@ -263,7 +263,7 @@ static int orinoco_plx_init_one(struct p if (dev->irq) free_irq(dev->irq, dev); - kfree(dev); + free_netdev(dev); } if (pccard_ioaddr) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/wireless/orinoco_tmd.c 830-ivtv/drivers/net/wireless/orinoco_tmd.c --- 000-virgin/drivers/net/wireless/orinoco_tmd.c Tue Sep 2 09:55:48 2003 +++ 830-ivtv/drivers/net/wireless/orinoco_tmd.c Thu Jan 8 08:54:29 2004 @@ -157,7 +157,7 @@ static int orinoco_tmd_init_one(struct p if (dev->irq) free_irq(dev->irq, dev); - kfree(dev); + free_netdev(dev); } if (pccard_ioaddr) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/wireless/ray_cs.c 830-ivtv/drivers/net/wireless/ray_cs.c --- 000-virgin/drivers/net/wireless/ray_cs.c Mon Nov 17 18:28:51 2003 +++ 830-ivtv/drivers/net/wireless/ray_cs.c Thu Jan 8 08:54:29 2004 @@ -344,19 +344,14 @@ static dev_link_t *ray_attach(void) return NULL; /* Allocate space for private device-specific data */ - dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); + dev = alloc_etherdev(sizeof(ray_dev_t)); if (!dev) goto fail_alloc_dev; - local = kmalloc(sizeof(ray_dev_t), GFP_KERNEL); - - if (!local) - goto fail_alloc_local; + local = dev->priv; memset(link, 0, sizeof(struct dev_link_t)); - memset(dev, 0, sizeof(struct net_device)); - memset(local, 0, sizeof(ray_dev_t)); /* The io structure describes IO port mapping. None used here */ link->io.NumPorts1 = 0; @@ -379,7 +374,6 @@ static dev_link_t *ray_attach(void) link->priv = dev; link->irq.Instance = dev; - dev->priv = local; local->finder = link; local->card_status = CARD_INSERTED; local->authentication_state = UNAUTHENTICATED; @@ -401,7 +395,6 @@ static dev_link_t *ray_attach(void) DEBUG(2,"ray_cs ray_attach calling ether_setup.)\n"); SET_MODULE_OWNER(dev); - ether_setup(dev); dev->init = &ray_dev_init; dev->open = &ray_open; dev->stop = &ray_dev_close; @@ -434,8 +427,6 @@ static dev_link_t *ray_attach(void) DEBUG(2,"ray_cs ray_attach ending\n"); return link; -fail_alloc_local: - kfree(dev); fail_alloc_dev: kfree(link); return NULL; @@ -478,9 +469,7 @@ static void ray_detach(dev_link_t *link) if (link->priv) { struct net_device *dev = link->priv; if (link->dev) unregister_netdev(dev); - if (dev->priv) - kfree(dev->priv); - kfree(link->priv); + free_netdev(dev); } kfree(link); DEBUG(2,"ray_cs ray_detach ending\n"); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/wireless/strip.c 830-ivtv/drivers/net/wireless/strip.c --- 000-virgin/drivers/net/wireless/strip.c Mon Nov 17 18:28:51 2003 +++ 830-ivtv/drivers/net/wireless/strip.c Thu Jan 8 08:54:29 2004 @@ -2564,7 +2564,7 @@ static void strip_free(struct strip *str strip_info->magic = 0; - kfree(strip_info->dev); + free_netdev(strip_info->dev); } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/wireless/wavelan.c 830-ivtv/drivers/net/wireless/wavelan.c --- 000-virgin/drivers/net/wireless/wavelan.c Tue Sep 2 09:55:48 2003 +++ 830-ivtv/drivers/net/wireless/wavelan.c Thu Jan 8 08:54:29 2004 @@ -153,7 +153,7 @@ static inline void wv_16_on(unsigned lon * Disable interrupts on the WaveLAN hardware. * (called by wv_82586_stop()) */ -static inline void wv_ints_off(device * dev) +static inline void wv_ints_off(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -167,7 +167,7 @@ static inline void wv_ints_off(device * * Enable interrupts on the WaveLAN hardware. * (called by wv_hw_reset()) */ -static inline void wv_ints_on(device * dev) +static inline void wv_ints_on(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -268,7 +268,7 @@ static inline u16 psa_crc(u8 * psa, /* T /* * update the checksum field in the Wavelan's PSA */ -static void update_psa_checksum(device * dev, unsigned long ioaddr, u16 hacr) +static void update_psa_checksum(struct net_device * dev, unsigned long ioaddr, u16 hacr) { #ifdef SET_PSA_CRC psa_t psa; @@ -547,7 +547,7 @@ static inline void obram_write(unsigned /* * Acknowledge the reading of the status issued by the i82586. */ -static void wv_ack(device * dev) +static void wv_ack(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -589,7 +589,7 @@ static void wv_ack(device * dev) * Set channel attention bit and busy wait until command has * completed, then acknowledge completion of the command. */ -static inline int wv_synchronous_cmd(device * dev, const char *str) +static inline int wv_synchronous_cmd(struct net_device * dev, const char *str) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -636,7 +636,7 @@ static inline int wv_synchronous_cmd(dev * Check if done, and if OK. */ static inline int -wv_config_complete(device * dev, unsigned long ioaddr, net_local * lp) +wv_config_complete(struct net_device * dev, unsigned long ioaddr, net_local * lp) { unsigned short mcs_addr; unsigned short status; @@ -703,7 +703,7 @@ wv_config_complete(device * dev, unsigne * (called in wavelan_interrupt()). * Note : the spinlock is already grabbed for us. */ -static int wv_complete(device * dev, unsigned long ioaddr, net_local * lp) +static int wv_complete(struct net_device * dev, unsigned long ioaddr, net_local * lp) { int nreaped = 0; @@ -845,7 +845,7 @@ if (lp->tx_n_in_use > 0) * wavelan_interrupt is not an option), so you may experience * delays sometimes. */ -static inline void wv_82586_reconfig(device * dev) +static inline void wv_82586_reconfig(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long flags; @@ -954,7 +954,7 @@ static void wv_psa_show(psa_t * p) * Print the formatted status of the Modem Management Controller. * This function needs to be completed. */ -static void wv_mmc_show(device * dev) +static void wv_mmc_show(struct net_device * dev) { unsigned long ioaddr = dev->base_addr; net_local *lp = (net_local *) dev->priv; @@ -1137,7 +1137,7 @@ static void wv_scb_show(unsigned long io /* * Print the formatted status of the i82586's receive unit. */ -static void wv_ru_show(device * dev) +static void wv_ru_show(struct net_device * dev) { /* net_local *lp = (net_local *) dev->priv; */ @@ -1154,7 +1154,7 @@ static void wv_ru_show(device * dev) /* * Display info about one control block of the i82586 memory. */ -static void wv_cu_show_one(device * dev, net_local * lp, int i, u16 p) +static void wv_cu_show_one(struct net_device * dev, net_local * lp, int i, u16 p) { unsigned long ioaddr; ac_tx_t actx; @@ -1183,7 +1183,7 @@ static void wv_cu_show_one(device * dev, /* * Print status of the command unit of the i82586. */ -static void wv_cu_show(device * dev) +static void wv_cu_show(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned int i; @@ -1209,7 +1209,7 @@ static void wv_cu_show(device * dev) /* * Print the formatted status of the WaveLAN PCMCIA device driver. */ -static void wv_dev_show(device * dev) +static void wv_dev_show(struct net_device * dev) { printk(KERN_DEBUG "dev:"); printk(" state=%lX,", dev->state); @@ -1223,7 +1223,7 @@ static void wv_dev_show(device * dev) * Print the formatted status of the WaveLAN PCMCIA device driver's * private information. */ -static void wv_local_show(device * dev) +static void wv_local_show(struct net_device * dev) { net_local *lp; @@ -1285,7 +1285,7 @@ static inline void wv_packet_info(u8 * p * This is the information which is displayed by the driver at startup. * There are lots of flags for configuring it to your liking. */ -static inline void wv_init_info(device * dev) +static inline void wv_init_info(struct net_device * dev) { short ioaddr = dev->base_addr; net_local *lp = (net_local *) dev->priv; @@ -1395,7 +1395,7 @@ static inline void wv_init_info(device * * card open or closed. * Used when the user read /proc/net/dev */ -static en_stats *wavelan_get_stats(device * dev) +static en_stats *wavelan_get_stats(struct net_device * dev) { #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name); @@ -1412,7 +1412,7 @@ static en_stats *wavelan_get_stats(devic * num_addrs > 0 Multicast mode, receive normal and MC packets, * and do best-effort filtering. */ -static void wavelan_set_multicast_list(device * dev) +static void wavelan_set_multicast_list(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; @@ -1485,7 +1485,7 @@ static void wavelan_set_multicast_list(d * (Note : it was a nice way to test the reconfigure stuff...) */ #ifdef SET_MAC_ADDRESS -static int wavelan_set_mac_address(device * dev, void *addr) +static int wavelan_set_mac_address(struct net_device * dev, void *addr) { struct sockaddr *mac = addr; @@ -1724,7 +1724,7 @@ static inline int wv_frequency_list(unsi * address with our list, and if they match, get the statistics. * Sorry, but this function really needs the wireless extensions. */ -static inline void wl_spy_gather(device * dev, +static inline void wl_spy_gather(struct net_device * dev, u8 * mac, /* MAC address */ u8 * stats) /* Statistics to gather */ { @@ -1750,7 +1750,7 @@ static inline void wl_spy_gather(device * With this histogram you may detect if one WaveLAN is really weak, * or you may also calculate the mean and standard deviation of the level. */ -static inline void wl_his_gather(device * dev, u8 * stats) +static inline void wl_his_gather(struct net_device * dev, u8 * stats) { /* Statistics to gather */ net_local *lp = (net_local *) dev->priv; u8 level = stats[0] & MMR_SIGNAL_LVL; @@ -2415,7 +2415,7 @@ static const struct iw_handler_def wavel * Get wireless statistics. * Called by /proc/net/wireless */ -static iw_stats *wavelan_get_wireless_stats(device * dev) +static iw_stats *wavelan_get_wireless_stats(struct net_device * dev) { unsigned long ioaddr = dev->base_addr; net_local *lp = (net_local *) dev->priv; @@ -2492,7 +2492,7 @@ static iw_stats *wavelan_get_wireless_st * (called by wv_packet_rcv()) */ static inline void -wv_packet_read(device * dev, u16 buf_off, int sksize) +wv_packet_read(struct net_device * dev, u16 buf_off, int sksize) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -2587,7 +2587,7 @@ wv_packet_read(device * dev, u16 buf_off * (called in wavelan_interrupt()). * Note : the spinlock is already grabbed for us. */ -static inline void wv_receive(device * dev) +static inline void wv_receive(struct net_device * dev) { unsigned long ioaddr = dev->base_addr; net_local *lp = (net_local *) dev->priv; @@ -2770,7 +2770,7 @@ static inline void wv_receive(device * d * * (called in wavelan_packet_xmit()) */ -static inline int wv_packet_write(device * dev, void *buf, short length) +static inline int wv_packet_write(struct net_device * dev, void *buf, short length) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -2901,7 +2901,7 @@ static inline int wv_packet_write(device * the packet. We also prevent reentrance. Then we call the function * to send the packet. */ -static int wavelan_packet_xmit(struct sk_buff *skb, device * dev) +static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long flags; @@ -2966,7 +2966,7 @@ static int wavelan_packet_xmit(struct sk * Routine to initialize the Modem Management Controller. * (called by wv_hw_reset()) */ -static inline int wv_mmc_init(device * dev) +static inline int wv_mmc_init(struct net_device * dev) { unsigned long ioaddr = dev->base_addr; net_local *lp = (net_local *) dev->priv; @@ -3138,7 +3138,7 @@ static inline int wv_mmc_init(device * d * Start the receive unit. * (called by wv_hw_reset()) */ -static inline int wv_ru_start(device * dev) +static inline int wv_ru_start(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -3230,7 +3230,7 @@ static inline int wv_ru_start(device * d * * (called by wv_hw_reset()) */ -static inline int wv_cu_start(device * dev) +static inline int wv_cu_start(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -3331,7 +3331,7 @@ static inline int wv_cu_start(device * d * * (called by wv_hw_reset()) */ -static inline int wv_82586_start(device * dev) +static inline int wv_82586_start(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -3463,7 +3463,7 @@ static inline int wv_82586_start(device * * (called by wv_hw_reset(), wv_82586_reconfig(), wavelan_packet_xmit()) */ -static void wv_82586_config(device * dev) +static void wv_82586_config(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -3643,7 +3643,7 @@ static void wv_82586_config(device * dev * WaveLAN controller (i82586). * (called by wavelan_close()) */ -static inline void wv_82586_stop(device * dev) +static inline void wv_82586_stop(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -3680,7 +3680,7 @@ static inline void wv_82586_stop(device * 5. Start the LAN controller's receive unit * (called by wavelan_interrupt(), wavelan_watchdog() & wavelan_open()) */ -static int wv_hw_reset(device * dev) +static int wv_hw_reset(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -3770,7 +3770,7 @@ static int wv_check_ioaddr(unsigned long */ static irqreturn_t wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - device *dev; + struct net_device *dev; unsigned long ioaddr; net_local *lp; u16 hasr; @@ -3923,7 +3923,7 @@ static irqreturn_t wavelan_interrupt(int * kernel. If the transmission completes, this timer is disabled. If * the timer expires, we are called and we try to unlock the hardware. */ -static void wavelan_watchdog(device * dev) +static void wavelan_watchdog(struct net_device * dev) { net_local * lp = (net_local *)dev->priv; u_long ioaddr = dev->base_addr; @@ -4003,7 +4003,7 @@ static void wavelan_watchdog(device * de * Configure and start up the WaveLAN PCMCIA adaptor. * Called by NET3 when it "opens" the device. */ -static int wavelan_open(device * dev) +static int wavelan_open(struct net_device * dev) { net_local * lp = (net_local *)dev->priv; unsigned long flags; @@ -4058,7 +4058,7 @@ static int wavelan_open(device * dev) * Shut down the WaveLAN ISA card. * Called by NET3 when it "closes" the device. */ -static int wavelan_close(device * dev) +static int wavelan_close(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long flags; @@ -4091,12 +4091,24 @@ static int wavelan_close(device * dev) * device structure * (called by wavelan_probe() and via init_module()). */ -static int __init wavelan_config(device * dev) +static int __init wavelan_config(struct net_device *dev, unsigned short ioaddr) { - unsigned long ioaddr = dev->base_addr; u8 irq_mask; int irq; net_local *lp; + mac_addr mac; + int err; + + if (!request_region(ioaddr, sizeof(ha_t), "wavelan")) + return -EADDRINUSE; + + err = wv_check_ioaddr(ioaddr, mac); + if (err) + goto out; + + memcpy(dev->dev_addr, mac, 6); + + dev->base_addr = ioaddr; #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "%s: ->wavelan_config(dev=0x%x, ioaddr=0x%lx)\n", @@ -4136,25 +4148,18 @@ static int __init wavelan_config(device "%s: wavelan_config(): could not wavelan_map_irq(%d).\n", dev->name, irq_mask); #endif - return -EAGAIN; + err = -EAGAIN; + goto out; } dev->irq = irq; - if (!request_region(ioaddr, sizeof(ha_t), "wavelan")) - return -EBUSY; - dev->mem_start = 0x0000; dev->mem_end = 0x0000; dev->if_port = 0; /* Initialize device structures */ - dev->priv = kmalloc(sizeof(net_local), GFP_KERNEL); - if (dev->priv == NULL) { - release_region(ioaddr, sizeof(ha_t)); - return -ENOMEM; - } - memset(dev->priv, 0x00, sizeof(net_local)); + memset(dev->priv, 0, sizeof(net_local)); lp = (net_local *) dev->priv; /* Back link to the device structure. */ @@ -4172,12 +4177,6 @@ static int __init wavelan_config(device /* Init spinlock */ spin_lock_init(&lp->spinlock); - /* - * Fill in the fields of the device structure - * with generic Ethernet values. - */ - ether_setup(dev); - SET_MODULE_OWNER(dev); dev->open = wavelan_open; dev->stop = wavelan_close; @@ -4204,6 +4203,9 @@ static int __init wavelan_config(device printk(KERN_DEBUG "%s: <-wavelan_config()\n", dev->name); #endif return 0; +out: + release_region(ioaddr, sizeof(ha_t)); + return err; } /*------------------------------------------------------------------*/ @@ -4214,19 +4216,13 @@ static int __init wavelan_config(device * We follow the example in drivers/net/ne.c. * (called in "Space.c") */ -int __init wavelan_probe(device * dev) +struct net_device * __init wavelan_probe(int unit) { + struct net_device *dev; short base_addr; - mac_addr mac; /* MAC address (check existence of WaveLAN) */ + int def_irq; int i; - int r; - -#ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG - "%s: ->wavelan_probe(dev=0x%x (base_addr=0x%x))\n", - dev->name, (unsigned int) dev, - (unsigned int) dev->base_addr); -#endif + int r = 0; #ifdef STRUCT_CHECK if (wv_struct_check() != (char *) NULL) { @@ -4237,8 +4233,20 @@ int __init wavelan_probe(device * dev) } #endif /* STRUCT_CHECK */ - /* Check the value of the command line parameter for base address. */ + dev = alloc_etherdev(sizeof(net_local)); + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); base_addr = dev->base_addr; + def_irq = dev->irq; + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG + "%s: ->wavelan_probe(dev=%p (base_addr=0x%x))\n", + dev->name, dev, (unsigned int) dev->base_addr); +#endif /* Don't probe at all. */ if (base_addr < 0) { @@ -4247,16 +4255,9 @@ int __init wavelan_probe(device * dev) "%s: wavelan_probe(): invalid base address\n", dev->name); #endif - return -ENXIO; - } - - /* Check a single specified location. */ - if (base_addr > 0x100) { - /* Check if there is something at this base address */ - if ((r = wv_check_ioaddr(base_addr, mac)) == 0) { - memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */ - r = wavelan_config(dev); - } + r = -ENXIO; + } else if (base_addr > 0x100) { /* Check a single specified location. */ + r = wavelan_config(dev, base_addr); #ifdef DEBUG_CONFIG_INFO if (r != 0) printk(KERN_DEBUG @@ -4267,35 +4268,33 @@ int __init wavelan_probe(device * dev) #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name); #endif - return r; - } - - /* Scan all possible addresses of the WaveLAN hardware. */ - for (i = 0; i < NELS(iobase); i++) { - /* Check whether there is something at this base address. */ - if (wv_check_ioaddr(iobase[i], mac) == 0) { - dev->base_addr = iobase[i]; /* Copy base address. */ - memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */ - if (wavelan_config(dev) == 0) { + } else { /* Scan all possible addresses of the WaveLAN hardware. */ + for (i = 0; i < NELS(iobase); i++) { + dev->irq = def_irq; + if (wavelan_config(dev, iobase[i]) == 0) { #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name); #endif - return 0; + break; } } + if (i == NELS(iobase)) + r = -ENODEV; } - - /* We may have touched base_addr. Another driver may not like it. */ - dev->base_addr = base_addr; - -#ifdef DEBUG_CONFIG_INFO - printk(KERN_DEBUG "%s: wavelan_probe(): no device found\n", - dev->name); -#endif - - return -ENODEV; + if (r) + goto out; + r = register_netdev(dev); + if (r) + goto out1; + return dev; +out1: + release_region(dev->base_addr, sizeof(ha_t)); + wavelan_list = wavelan_list->next; +out: + free_netdev(dev); + return ERR_PTR(r); } /****************************** MODULE ******************************/ @@ -4311,7 +4310,6 @@ int __init wavelan_probe(device * dev) */ int init_module(void) { - mac_addr mac; /* MAC address (check WaveLAN existence) */ int ret = -EIO; /* Return error if no cards found */ int i; @@ -4337,38 +4335,28 @@ int init_module(void) /* Loop on all possible base addresses. */ i = -1; while ((io[++i] != 0) && (i < NELS(io))) { - /* Check if there is something at this base address. */ - if (wv_check_ioaddr(io[i], mac) == 0) { - device *dev; - - /* Create device and set basic arguments. */ - dev = - kmalloc(sizeof(struct net_device), GFP_KERNEL); - if (dev == NULL) { - ret = -ENOMEM; - break; - } - memset(dev, 0x00, sizeof(struct net_device)); - memcpy(dev->name, name[i], IFNAMSIZ); /* Copy name */ - dev->base_addr = io[i]; - dev->irq = irq[i]; - dev->init = &wavelan_config; - memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */ + struct net_device *dev = alloc_etherdev(sizeof(net_local)); + if (!dev) + break; + memcpy(dev->name, name[i], IFNAMSIZ); /* Copy name */ + dev->base_addr = io[i]; + dev->irq = irq[i]; - /* Try to create the device. */ + /* Check if there is something at this base address. */ + if (wavelan_config(dev, io[i]) == 0) { if (register_netdev(dev) != 0) { - /* Deallocate everything. */ - /* Note: if dev->priv is mallocated, there is no way to fail. */ - kfree(dev); + release_region(dev->base_addr, sizeof(ha_t)); + wavelan_list = wavelan_list->next; } else { - /* If at least one device OK, we do not fail */ ret = 0; + continue; } - } /* if there is something at the address */ - } /* Loop on all addresses. */ + } + free_netdev(dev); + } #ifdef DEBUG_CONFIG_ERROR - if (wavelan_list == (net_local *) NULL) + if (!wavelan_list) printk(KERN_WARNING "WaveLAN init_module(): no device found\n"); #endif @@ -4390,26 +4378,19 @@ void cleanup_module(void) #endif /* Loop on all devices and release them. */ - while (wavelan_list != (net_local *) NULL) { - device *dev = wavelan_list->dev; + while (wavelan_list) { + struct net_device *dev = wavelan_list->dev; #ifdef DEBUG_CONFIG_INFO printk(KERN_DEBUG "%s: cleanup_module(): removing device at 0x%x\n", dev->name, (unsigned int) dev); #endif - - /* Release the ioport region. */ - release_region(dev->base_addr, sizeof(ha_t)); - - /* Definitely remove the device. */ unregister_netdev(dev); - /* Unlink the device. */ + release_region(dev->base_addr, sizeof(ha_t)); wavelan_list = wavelan_list->next; - /* Free pieces. */ - kfree(dev->priv); free_netdev(dev); } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/wireless/wavelan.p.h 830-ivtv/drivers/net/wireless/wavelan.p.h --- 000-virgin/drivers/net/wireless/wavelan.p.h Fri May 30 19:02:13 2003 +++ 830-ivtv/drivers/net/wireless/wavelan.p.h Thu Jan 8 08:54:29 2004 @@ -469,7 +469,6 @@ static const char *version = "wavelan.c /****************************** TYPES ******************************/ /* Shortcuts */ -typedef struct net_device device; typedef struct net_device_stats en_stats; typedef struct iw_statistics iw_stats; typedef struct iw_quality iw_qual; @@ -492,7 +491,7 @@ typedef u_char mac_addr[WAVELAN_ADDR_SI struct net_local { net_local * next; /* linked list of the devices */ - device * dev; /* reverse link */ + struct net_device * dev; /* reverse link */ spinlock_t spinlock; /* Serialize access to the hardware (SMP) */ en_stats stats; /* Ethernet interface statistics */ int nresets; /* number of hardware resets */ @@ -542,8 +541,8 @@ static inline void u_short), /* hacr */ wv_16_on(u_long, /* ioaddr */ u_short), /* hacr */ - wv_ints_off(device *), - wv_ints_on(device *); + wv_ints_off(struct net_device *), + wv_ints_on(struct net_device *); /* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */ static void psa_read(u_long, /* Read the Parameter Storage Area. */ @@ -592,57 +591,57 @@ static inline void u_char *, /* b */ int); /* n */ static void - wv_ack(device *); + wv_ack(struct net_device *); static inline int - wv_synchronous_cmd(device *, + wv_synchronous_cmd(struct net_device *, const char *), - wv_config_complete(device *, + wv_config_complete(struct net_device *, u_long, net_local *); static int - wv_complete(device *, + wv_complete(struct net_device *, u_long, net_local *); static inline void - wv_82586_reconfig(device *); + wv_82586_reconfig(struct net_device *); /* ------------------- DEBUG & INFO SUBROUTINES ------------------- */ #ifdef DEBUG_I82586_SHOW static void wv_scb_show(unsigned short); #endif static inline void - wv_init_info(device *); /* display startup info */ + wv_init_info(struct net_device *); /* display startup info */ /* ------------------- IOCTL, STATS & RECONFIG ------------------- */ static en_stats * - wavelan_get_stats(device *); /* Give stats /proc/net/dev */ + wavelan_get_stats(struct net_device *); /* Give stats /proc/net/dev */ static void - wavelan_set_multicast_list(device *); + wavelan_set_multicast_list(struct net_device *); /* ----------------------- PACKET RECEPTION ----------------------- */ static inline void - wv_packet_read(device *, /* Read a packet from a frame. */ + wv_packet_read(struct net_device *, /* Read a packet from a frame. */ u_short, int), - wv_receive(device *); /* Read all packets waiting. */ + wv_receive(struct net_device *); /* Read all packets waiting. */ /* --------------------- PACKET TRANSMISSION --------------------- */ static inline int - wv_packet_write(device *, /* Write a packet to the Tx buffer. */ + wv_packet_write(struct net_device *, /* Write a packet to the Tx buffer. */ void *, short); static int wavelan_packet_xmit(struct sk_buff *, /* Send a packet. */ - device *); + struct net_device *); /* -------------------- HARDWARE CONFIGURATION -------------------- */ static inline int - wv_mmc_init(device *), /* Initialize the modem. */ - wv_ru_start(device *), /* Start the i82586 receiver unit. */ - wv_cu_start(device *), /* Start the i82586 command unit. */ - wv_82586_start(device *); /* Start the i82586. */ + wv_mmc_init(struct net_device *), /* Initialize the modem. */ + wv_ru_start(struct net_device *), /* Start the i82586 receiver unit. */ + wv_cu_start(struct net_device *), /* Start the i82586 command unit. */ + wv_82586_start(struct net_device *); /* Start the i82586. */ static void - wv_82586_config(device *); /* Configure the i82586. */ + wv_82586_config(struct net_device *); /* Configure the i82586. */ static inline void - wv_82586_stop(device *); + wv_82586_stop(struct net_device *); static int - wv_hw_reset(device *), /* Reset the WaveLAN hardware. */ + wv_hw_reset(struct net_device *), /* Reset the WaveLAN hardware. */ wv_check_ioaddr(u_long, /* ioaddr */ u_char *); /* mac address (read) */ /* ---------------------- INTERRUPT HANDLING ---------------------- */ @@ -651,14 +650,13 @@ static irqreturn_t void *, struct pt_regs *); static void - wavelan_watchdog(device *); /* transmission watchdog */ + wavelan_watchdog(struct net_device *); /* transmission watchdog */ /* ------------------- CONFIGURATION CALLBACKS ------------------- */ static int - wavelan_open(device *), /* Open the device. */ - wavelan_close(device *), /* Close the device. */ - wavelan_config(device *); /* Configure one device. */ -extern int - wavelan_probe(device *); /* See Space.c. */ + wavelan_open(struct net_device *), /* Open the device. */ + wavelan_close(struct net_device *), /* Close the device. */ + wavelan_config(struct net_device *, unsigned short);/* Configure one device. */ +extern struct net_device *wavelan_probe(int unit); /* See Space.c. */ /**************************** VARIABLES ****************************/ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/wireless/wavelan_cs.c 830-ivtv/drivers/net/wireless/wavelan_cs.c --- 000-virgin/drivers/net/wireless/wavelan_cs.c Mon Nov 17 18:28:51 2003 +++ 830-ivtv/drivers/net/wireless/wavelan_cs.c Thu Jan 8 08:54:29 2004 @@ -131,7 +131,7 @@ hacr_write_slow(u_long base, * Read the Parameter Storage Area from the WaveLAN card's memory */ static void -psa_read(device * dev, +psa_read(struct net_device * dev, int o, /* offset in PSA */ u_char * b, /* buffer to fill */ int n) /* size to read */ @@ -155,7 +155,7 @@ psa_read(device * dev, * Write the Paramter Storage Area to the WaveLAN card's memory */ static void -psa_write(device * dev, +psa_write(struct net_device * dev, int o, /* Offset in psa */ u_char * b, /* Buffer in memory */ int n) /* Length of buffer */ @@ -229,7 +229,7 @@ psa_crc(unsigned char * psa, /* The PSA * update the checksum field in the Wavelan's PSA */ static void -update_psa_checksum(device * dev) +update_psa_checksum(struct net_device * dev) { #ifdef SET_PSA_CRC psa_t psa; @@ -753,7 +753,7 @@ void wv_roam_handover(wavepoint_history } /* Called when a WavePoint beacon is received */ -static inline void wl_roam_gather(device * dev, +static inline void wl_roam_gather(struct net_device * dev, u_char * hdr, /* Beacon header */ u_char * stats) /* SNR, Signal quality of packet */ @@ -831,7 +831,7 @@ static inline int WAVELAN_BEACON(unsigne * wv_82593_config() & wv_diag()) */ static int -wv_82593_cmd(device * dev, +wv_82593_cmd(struct net_device * dev, char * str, int cmd, int result) @@ -942,7 +942,7 @@ wv_82593_cmd(device * dev, * status for the WaveLAN. */ static inline int -wv_diag(device * dev) +wv_diag(struct net_device * dev) { int ret = FALSE; @@ -963,7 +963,7 @@ wv_diag(device * dev) * The return value is the address to use for next the call. */ static int -read_ringbuf(device * dev, +read_ringbuf(struct net_device * dev, int addr, char * buf, int len) @@ -1004,10 +1004,10 @@ read_ringbuf(device * dev, * some delay sometime... */ static inline void -wv_82593_reconfig(device * dev) +wv_82593_reconfig(struct net_device * dev) { net_local * lp = (net_local *)dev->priv; - dev_link_t * link = ((net_local *) dev->priv)->link; + dev_link_t * link = lp->link; unsigned long flags; /* Arm the flag, will be cleard in wv_82593_config() */ @@ -1132,7 +1132,7 @@ wv_psa_show(psa_t * p) * This function need to be completed... */ static void -wv_mmc_show(device * dev) +wv_mmc_show(struct net_device * dev) { ioaddr_t base = dev->base_addr; net_local * lp = (net_local *)dev->priv; @@ -1222,7 +1222,7 @@ wv_mmc_show(device * dev) * Print the formatted status of the i82593's receive unit. */ static void -wv_ru_show(device * dev) +wv_ru_show(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; @@ -1241,7 +1241,7 @@ wv_ru_show(device * dev) * Print the formatted status of the WaveLAN PCMCIA device driver. */ static void -wv_dev_show(device * dev) +wv_dev_show(struct net_device * dev) { printk(KERN_DEBUG "dev:"); printk(" state=%lX,", dev->state); @@ -1256,7 +1256,7 @@ wv_dev_show(device * dev) * private information. */ static void -wv_local_show(device * dev) +wv_local_show(struct net_device * dev) { net_local *lp; @@ -1314,7 +1314,7 @@ wv_packet_info(u_char * p, /* Packet t * There is a lot of flag to configure it at your will... */ static inline void -wv_init_info(device * dev) +wv_init_info(struct net_device * dev) { ioaddr_t base = dev->base_addr; psa_t psa; @@ -1412,7 +1412,7 @@ wv_init_info(device * dev) * Used when the user read /proc/net/dev */ static en_stats * -wavelan_get_stats(device * dev) +wavelan_get_stats(struct net_device * dev) { #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name); @@ -1431,7 +1431,7 @@ wavelan_get_stats(device * dev) */ static void -wavelan_set_multicast_list(device * dev) +wavelan_set_multicast_list(struct net_device * dev) { net_local * lp = (net_local *) dev->priv; @@ -1529,7 +1529,7 @@ wavelan_set_multicast_list(device * dev) */ #ifdef SET_MAC_ADDRESS static int -wavelan_set_mac_address(device * dev, +wavelan_set_mac_address(struct net_device * dev, void * addr) { struct sockaddr * mac = addr; @@ -1796,7 +1796,7 @@ wv_frequency_list(u_long base, /* i/o po * Sorry, but this function really need wireless extensions... */ static inline void -wl_spy_gather(device * dev, +wl_spy_gather(struct net_device * dev, u_char * mac, /* MAC address */ u_char * stats) /* Statistics to gather */ { @@ -1823,7 +1823,7 @@ wl_spy_gather(device * dev, * or you may also calculate the mean and standard deviation of the level... */ static inline void -wl_his_gather(device * dev, +wl_his_gather(struct net_device * dev, u_char * stats) /* Statistics to gather */ { net_local * lp = (net_local *) dev->priv; @@ -2785,7 +2785,7 @@ wavelan_ioctl(struct net_device * dev, / * Called by /proc/net/wireless... */ static iw_stats * -wavelan_get_wireless_stats(device * dev) +wavelan_get_wireless_stats(struct net_device * dev) { ioaddr_t base = dev->base_addr; net_local * lp = (net_local *) dev->priv; @@ -2847,7 +2847,7 @@ wavelan_get_wireless_stats(device * dev) * (called by wv_packet_rcv()) */ static inline int -wv_start_of_frame(device * dev, +wv_start_of_frame(struct net_device * dev, int rfp, /* end of frame */ int wrap) /* start of buffer */ { @@ -2909,7 +2909,7 @@ wv_start_of_frame(device * dev, * (called by wv_packet_rcv()) */ static inline void -wv_packet_read(device * dev, +wv_packet_read(struct net_device * dev, int fd_p, int sksize) { @@ -3012,7 +3012,7 @@ wv_packet_read(device * dev, * Note : the spinlock is already grabbed for us and irq are disabled. */ static inline void -wv_packet_rcv(device * dev) +wv_packet_rcv(struct net_device * dev) { ioaddr_t base = dev->base_addr; net_local * lp = (net_local *) dev->priv; @@ -3146,7 +3146,7 @@ wv_packet_rcv(device * dev) * (called in wavelan_packet_xmit()) */ static inline void -wv_packet_write(device * dev, +wv_packet_write(struct net_device * dev, void * buf, short length) { @@ -3209,7 +3209,7 @@ wv_packet_write(device * dev, */ static int wavelan_packet_xmit(struct sk_buff * skb, - device * dev) + struct net_device * dev) { net_local * lp = (net_local *)dev->priv; unsigned long flags; @@ -3273,7 +3273,7 @@ wavelan_packet_xmit(struct sk_buff * skb * (called by wv_hw_config()) */ static inline int -wv_mmc_init(device * dev) +wv_mmc_init(struct net_device * dev) { ioaddr_t base = dev->base_addr; psa_t psa; @@ -3467,7 +3467,7 @@ wv_mmc_init(device * dev) * (called in wv_ru_start() and wavelan_close() and wavelan_event()) */ static int -wv_ru_stop(device * dev) +wv_ru_stop(struct net_device * dev) { ioaddr_t base = dev->base_addr; net_local * lp = (net_local *) dev->priv; @@ -3530,7 +3530,7 @@ wv_ru_stop(device * dev) * (called in wv_hw_reset() & wavelan_open()) */ static int -wv_ru_start(device * dev) +wv_ru_start(struct net_device * dev) { ioaddr_t base = dev->base_addr; net_local * lp = (net_local *) dev->priv; @@ -3618,7 +3618,7 @@ wv_ru_start(device * dev) * (called by wv_hw_config(), wv_82593_reconfig() & wavelan_packet_xmit()) */ static int -wv_82593_config(device * dev) +wv_82593_config(struct net_device * dev) { ioaddr_t base = dev->base_addr; net_local * lp = (net_local *) dev->priv; @@ -3792,7 +3792,7 @@ wv_82593_config(device * dev) * (called by wv_config()) */ static inline int -wv_pcmcia_reset(device * dev) +wv_pcmcia_reset(struct net_device * dev) { int i; conf_reg_t reg = { 0, CS_READ, CISREG_COR, 0 }; @@ -3854,7 +3854,7 @@ wv_pcmcia_reset(device * dev) * (called by wavelan_event() & wv_hw_reset()) */ static int -wv_hw_config(device * dev) +wv_hw_config(struct net_device * dev) { net_local * lp = (net_local *) dev->priv; ioaddr_t base = dev->base_addr; @@ -3961,7 +3961,7 @@ wv_hw_config(device * dev) * (called by wavelan_event(), wavelan_watchdog() and wavelan_open()) */ static inline void -wv_hw_reset(device * dev) +wv_hw_reset(struct net_device * dev) { net_local * lp = (net_local *) dev->priv; @@ -4004,7 +4004,7 @@ wv_pcmcia_config(dev_link_t * link) memreq_t mem; handle = link->handle; - dev = (device *) link->priv; + dev = (struct net_device *) link->priv; #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "->wv_pcmcia_config(0x%p)\n", link); @@ -4150,7 +4150,7 @@ wv_pcmcia_config(dev_link_t * link) static void wv_pcmcia_release(dev_link_t *link) { - device * dev = (device *) link->priv; + struct net_device * dev = (struct net_device *) link->priv; #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: -> wv_pcmcia_release(0x%p)\n", dev->name, link); @@ -4200,13 +4200,13 @@ wavelan_interrupt(int irq, void * dev_id, struct pt_regs * regs) { - device * dev; + struct net_device * dev; net_local * lp; ioaddr_t base; int status0; u_int tx_status; - if((dev = (device *)dev_id) == (device *) NULL) + if ((dev = dev_id) == NULL) { #ifdef DEBUG_INTERRUPT_ERROR printk(KERN_WARNING "wavelan_interrupt(): irq %d for unknown device.\n", @@ -4467,7 +4467,7 @@ wavelan_interrupt(int irq, * deal with the multiple Tx buffers... */ static void -wavelan_watchdog(device * dev) +wavelan_watchdog(struct net_device * dev) { net_local * lp = (net_local *) dev->priv; ioaddr_t base = dev->base_addr; @@ -4542,7 +4542,7 @@ wavelan_watchdog(device * dev) * Called by NET3 when it "open" the device. */ static int -wavelan_open(device * dev) +wavelan_open(struct net_device * dev) { dev_link_t * link = ((net_local *) dev->priv)->link; net_local * lp = (net_local *)dev->priv; @@ -4597,7 +4597,7 @@ wavelan_open(device * dev) * Called by NET3 when it "close" the device. */ static int -wavelan_close(device * dev) +wavelan_close(struct net_device * dev) { dev_link_t * link = ((net_local *) dev->priv)->link; ioaddr_t base = dev->base_addr; @@ -4661,7 +4661,7 @@ wavelan_attach(void) { client_reg_t client_reg; /* Register with cardmgr */ dev_link_t * link; /* Info for cardmgr */ - device * dev; /* Interface generic data */ + struct net_device * dev; /* Interface generic data */ net_local * lp; /* Interface specific data */ int i, ret; @@ -4699,22 +4699,14 @@ wavelan_attach(void) dev_list = link; /* Allocate the generic data structure */ - dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); + dev = alloc_etherdev(sizeof(net_local)); if (!dev) { kfree(link); return NULL; } - memset(dev, 0x00, sizeof(struct net_device)); link->priv = link->irq.Instance = dev; - /* Allocate the wavelan-specific data structure. */ - dev->priv = lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL); - if (!lp) { - kfree(link); - kfree(dev); - return NULL; - } - memset(lp, 0x00, sizeof(net_local)); + lp = dev->priv; /* Init specific data */ lp->configured = 0; @@ -4732,9 +4724,6 @@ wavelan_attach(void) lp->link = link; lp->dev = dev; - /* Standard setup for generic data */ - ether_setup(dev); - /* wavelan NET3 callbacks */ SET_MODULE_OWNER(dev); dev->open = &wavelan_open; @@ -4852,22 +4841,16 @@ wavelan_detach(dev_link_t * link) /* Free pieces */ if(link->priv) { - device * dev = (device *) link->priv; + struct net_device * dev = (struct net_device *) link->priv; /* Remove ourselves from the kernel list of ethernet devices */ /* Warning : can't be called from interrupt, timer or wavelan_close() */ - if(link->dev != NULL) + if (link->dev) unregister_netdev(dev); link->dev = NULL; - - if(dev->priv) - { - /* Sound strange, but safe... */ - ((net_local *) dev->priv)->link = (dev_link_t *) NULL; - ((net_local *) dev->priv)->dev = (device *) NULL; - kfree(dev->priv); - } - kfree(link->priv); + ((net_local *) dev->priv)->link = NULL; + ((net_local *) dev->priv)->dev = NULL; + free_netdev(dev); } kfree(link); @@ -4889,7 +4872,7 @@ wavelan_event(event_t event, /* The ev event_callback_args_t * args) { dev_link_t * link = (dev_link_t *) args->client_data; - device * dev = (device *) link->priv; + struct net_device * dev = (struct net_device *) link->priv; #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "->wavelan_event(): %s\n", diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/wireless/wavelan_cs.p.h 830-ivtv/drivers/net/wireless/wavelan_cs.p.h --- 000-virgin/drivers/net/wireless/wavelan_cs.p.h Mon Nov 17 18:28:51 2003 +++ 830-ivtv/drivers/net/wireless/wavelan_cs.p.h Thu Jan 8 08:54:29 2004 @@ -588,7 +588,6 @@ struct wavepoint_table /****************************** TYPES ******************************/ /* Shortcuts */ -typedef struct net_device device; typedef struct net_device_stats en_stats; typedef struct iw_statistics iw_stats; typedef struct iw_quality iw_qual; @@ -611,7 +610,7 @@ typedef u_char mac_addr[WAVELAN_ADDR_SI struct net_local { dev_node_t node; /* ???? What is this stuff ???? */ - device * dev; /* Reverse link... */ + struct net_device * dev; /* Reverse link... */ spinlock_t spinlock; /* Serialize access to the hardware (SMP) */ dev_link_t * link; /* pcmcia structure */ en_stats stats; /* Ethernet interface statistics */ @@ -673,11 +672,11 @@ static inline void hacr_write_slow(u_long, u_char); static void - psa_read(device *, /* Read the Parameter Storage Area */ + psa_read(struct net_device *, /* Read the Parameter Storage Area */ int, /* offset in PSA */ u_char *, /* buffer to fill */ int), /* size to read */ - psa_write(device *, /* Write to the PSA */ + psa_write(struct net_device *, /* Write to the PSA */ int, /* Offset in psa */ u_char *, /* Buffer in memory */ int); /* Length of buffer */ @@ -707,57 +706,57 @@ static void int); /* number of registers */ /* ---------------------- I82593 SUBROUTINES ----------------------- */ static int - wv_82593_cmd(device *, /* synchronously send a command to i82593 */ + wv_82593_cmd(struct net_device *, /* synchronously send a command to i82593 */ char *, int, int); static inline int - wv_diag(device *); /* Diagnostique the i82593 */ + wv_diag(struct net_device *); /* Diagnostique the i82593 */ static int - read_ringbuf(device *, /* Read a receive buffer */ + read_ringbuf(struct net_device *, /* Read a receive buffer */ int, char *, int); static inline void - wv_82593_reconfig(device *); /* Reconfigure the controller */ + wv_82593_reconfig(struct net_device *); /* Reconfigure the controller */ /* ------------------- DEBUG & INFO SUBROUTINES ------------------- */ static inline void - wv_init_info(device *); /* display startup info */ + wv_init_info(struct net_device *); /* display startup info */ /* ------------------- IOCTL, STATS & RECONFIG ------------------- */ static en_stats * - wavelan_get_stats(device *); /* Give stats /proc/net/dev */ + wavelan_get_stats(struct net_device *); /* Give stats /proc/net/dev */ /* ----------------------- PACKET RECEPTION ----------------------- */ static inline int - wv_start_of_frame(device *, /* Seek beggining of current frame */ + wv_start_of_frame(struct net_device *, /* Seek beggining of current frame */ int, /* end of frame */ int); /* start of buffer */ static inline void - wv_packet_read(device *, /* Read a packet from a frame */ + wv_packet_read(struct net_device *, /* Read a packet from a frame */ int, int), - wv_packet_rcv(device *); /* Read all packets waiting */ + wv_packet_rcv(struct net_device *); /* Read all packets waiting */ /* --------------------- PACKET TRANSMISSION --------------------- */ static inline void - wv_packet_write(device *, /* Write a packet to the Tx buffer */ + wv_packet_write(struct net_device *, /* Write a packet to the Tx buffer */ void *, short); static int wavelan_packet_xmit(struct sk_buff *, /* Send a packet */ - device *); + struct net_device *); /* -------------------- HARDWARE CONFIGURATION -------------------- */ static inline int - wv_mmc_init(device *); /* Initialize the modem */ + wv_mmc_init(struct net_device *); /* Initialize the modem */ static int - wv_ru_stop(device *), /* Stop the i82593 receiver unit */ - wv_ru_start(device *); /* Start the i82593 receiver unit */ + wv_ru_stop(struct net_device *), /* Stop the i82593 receiver unit */ + wv_ru_start(struct net_device *); /* Start the i82593 receiver unit */ static int - wv_82593_config(device *); /* Configure the i82593 */ + wv_82593_config(struct net_device *); /* Configure the i82593 */ static inline int - wv_pcmcia_reset(device *); /* Reset the pcmcia interface */ + wv_pcmcia_reset(struct net_device *); /* Reset the pcmcia interface */ static int - wv_hw_config(device *); /* Reset & configure the whole hardware */ + wv_hw_config(struct net_device *); /* Reset & configure the whole hardware */ static inline void - wv_hw_reset(device *); /* Same, + start receiver unit */ + wv_hw_reset(struct net_device *); /* Same, + start receiver unit */ static inline int wv_pcmcia_config(dev_link_t *); /* Configure the pcmcia interface */ static void @@ -768,11 +767,11 @@ static irqreturn_t void *, struct pt_regs *); static void - wavelan_watchdog(device *); /* Transmission watchdog */ + wavelan_watchdog(struct net_device *); /* Transmission watchdog */ /* ------------------- CONFIGURATION CALLBACKS ------------------- */ static int - wavelan_open(device *), /* Open the device */ - wavelan_close(device *); /* Close the device */ + wavelan_open(struct net_device *), /* Open the device */ + wavelan_close(struct net_device *); /* Close the device */ static dev_link_t * wavelan_attach(void); /* Create a new device */ static void diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/wireless/wl3501_cs.c 830-ivtv/drivers/net/wireless/wl3501_cs.c --- 000-virgin/drivers/net/wireless/wl3501_cs.c Mon Nov 17 18:28:51 2003 +++ 830-ivtv/drivers/net/wireless/wl3501_cs.c Thu Jan 8 08:54:29 2004 @@ -1449,18 +1449,6 @@ fail: goto out; } -/** - * wl3501_init - "initialize" board - * @dev - network device - * - * We never need to do anything when a wl3501 device is "initialized" by the net - * software, because we only register already-found cards. - */ -static int wl3501_init(struct net_device *dev) -{ - return 0; -} - struct net_device_stats *wl3501_get_stats(struct net_device *dev) { struct wl3501_card *this = dev->priv; @@ -2056,7 +2044,6 @@ static dev_link_t *wl3501_attach(void) dev = alloc_etherdev(sizeof(struct wl3501_card)); if (!dev) goto out_link; - dev->init = wl3501_init; dev->open = wl3501_open; dev->stop = wl3501_close; dev->hard_start_xmit = wl3501_hard_start_xmit; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/znet.c 830-ivtv/drivers/net/znet.c --- 000-virgin/drivers/net/znet.c Tue Sep 2 09:55:48 2003 +++ 830-ivtv/drivers/net/znet.c Thu Jan 8 08:54:29 2004 @@ -372,10 +372,8 @@ static int __init znet_probe (void) struct znet_private *znet; struct net_device *dev; char *p; + int err = -ENOMEM; - if (znet_dev) /* Only look for a single adaptor */ - return -ENODEV; - /* This code scans the region 0xf0000 to 0xfffff for a "NETIDBLK". */ for(p = (char *)phys_to_virt(0xf0000); p < (char *)phys_to_virt(0x100000); p++) if (*p == 'N' && strncmp(p, "NETIDBLK", 8) == 0) @@ -387,12 +385,14 @@ static int __init znet_probe (void) return -ENODEV; } - if (!(znet_dev = dev = init_etherdev(0, sizeof(struct znet_private)))) - return -ENOMEM; + dev = alloc_etherdev(sizeof(struct znet_private)); + if (!dev) + return -ENOMEM; + + SET_MODULE_OWNER (dev); znet = dev->priv; - SET_MODULE_OWNER (dev); netinfo = (struct netidblk *)p; dev->base_addr = netinfo->iobase1; dev->irq = netinfo->irq1; @@ -430,7 +430,7 @@ static int __init znet_probe (void) znet->io_size = 2; if (!(znet->rx_start = kmalloc (DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA))) - goto free_netdev; + goto free_dev; if (!(znet->tx_start = kmalloc (DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA))) goto free_rx; @@ -452,19 +452,19 @@ static int __init znet_probe (void) dev->set_multicast_list = &znet_set_multicast_list; dev->tx_timeout = znet_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - + err = register_netdev(dev); + if (err) + goto free_tx; + znet_dev = dev; return 0; free_tx: - kfree (znet->tx_start); + kfree(znet->tx_start); free_rx: - kfree (znet->rx_start); - free_netdev: - unregister_netdev (dev); - kfree (dev); - znet_dev = NULL; - - return -ENOMEM; + kfree(znet->rx_start); + free_dev: + free_netdev(dev); + return err; } @@ -934,16 +934,14 @@ static void update_stop_hit(short ioaddr static __exit void znet_cleanup (void) { -#ifdef MODULE if (znet_dev) { struct znet_private *znet = znet_dev->priv; + unregister_netdev (znet_dev); kfree (znet->rx_start); kfree (znet->tx_start); - unregister_netdev (znet_dev); free_netdev (znet_dev); } -#endif } module_init (znet_probe); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/net/zorro8390.c 830-ivtv/drivers/net/zorro8390.c --- 000-virgin/drivers/net/zorro8390.c Tue Sep 2 09:55:48 2003 +++ 830-ivtv/drivers/net/zorro8390.c Thu Jan 8 08:54:29 2004 @@ -103,18 +103,18 @@ static int __init zorro8390_probe(void) continue; board = z->resource.start; ioaddr = board+cards[i].offset; - dev = init_etherdev(0, 0); - SET_MODULE_OWNER(dev); + dev = alloc_ei_netdev(); if (!dev) return -ENOMEM; + SET_MODULE_OWNER(dev); if (!request_mem_region(ioaddr, NE_IO_EXTENT*2, dev->name)) { - kfree(dev); + free_netdev(dev); continue; } if ((err = zorro8390_init(dev, board, cards[i].name, ZTWO_VADDR(ioaddr)))) { release_mem_region(ioaddr, NE_IO_EXTENT*2); - kfree(dev); + free_netdev(dev); return err; } err = 0; @@ -129,6 +129,7 @@ static int __init zorro8390_init(struct const char *name, unsigned long ioaddr) { int i; + int err; unsigned char SA_prom[32]; int start_page, stop_page; static u32 zorro8390_offsets[16] = { @@ -195,12 +196,6 @@ static int __init zorro8390_init(struct i = request_irq(IRQ_AMIGA_PORTS, ei_interrupt, SA_SHIRQ, dev->name, dev); if (i) return i; - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk("Unable to get memory for dev->priv.\n"); - return -ENOMEM; - } - for(i = 0; i < ETHER_ADDR_LEN; i++) { #ifdef DEBUG printk(" %2.2x", SA_prom[i]); @@ -232,7 +227,10 @@ static int __init zorro8390_init(struct root_zorro8390_dev = dev; #endif NS8390_init(dev, 0); - return 0; + err = register_netdev(dev); + if (err) + free_irq(IRQ_AMIGA_PORTS, dev); + return err; } static int zorro8390_open(struct net_device *dev) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/pci/bus.c 830-ivtv/drivers/pci/bus.c --- 000-virgin/drivers/pci/bus.c Tue Jun 24 21:29:20 2003 +++ 830-ivtv/drivers/pci/bus.c Thu Jan 8 10:22:31 2004 @@ -116,6 +116,8 @@ void __devinit pci_bus_add_devices(struc list_add_tail(&dev->subordinate->node, &dev->bus->children); spin_unlock(&pci_bus_lock); pci_bus_add_devices(dev->subordinate); + + sysfs_create_link(&dev->subordinate->class_dev.kobj, &dev->dev.kobj, "bridge"); } } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/pci/pci.ids 830-ivtv/drivers/pci/pci.ids --- 000-virgin/drivers/pci/pci.ids Thu Jan 8 08:35:39 2004 +++ 830-ivtv/drivers/pci/pci.ids Thu Jan 8 08:54:30 2004 @@ -3247,8 +3247,6 @@ 1148 5061 SK-9861 V2.0 Gigabit Ethernet 1000Base-SX Adapter 1148 5071 SK-9871 V2.0 Gigabit Ethernet 1000Base-ZX Adapter 1148 9521 SK-9521 10/100/1000Base-T Adapter - 4400 SK-9Dxx Gigabit Ethernet Adapter - 4500 SK-9Mxx Gigabit Ethernet Adapter 1149 Win System Corporation 114a VMIC 5579 VMIPCI-5579 (Reflective Memory Card) @@ -3540,7 +3538,22 @@ 11ab Galileo Technology Ltd. 0146 GT-64010/64010A System Controller 4320 Gigabit Ethernet Adapter - 11ab 9521 Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Adapter + 1019 0f38 Marvell 88E8001 Gigabit LOM Ethernet Adapter (ECS) + 1019 8001 Marvell 88E8001 Gigabit LOM Ethernet Adapter (ECS) + 1043 173c Marvell 88E8001 Gigabit LOM Ethernet Adapter (Asus) + 1043 811a Marvell 88E8001 Gigabit LOM Ethernet Adapter (Asus) + 105b 0c19 Marvell 88E8001 Gigabit LOM Ethernet Adapter (Foxconn) + 10b8 b452 SMC EZ Card 1000 (SMC9452TXV.2) + 11ab 0121 Marvell RDK-8001 Adapter + 11ab 0321 Marvell RDK-8003 Adapter + 11ab 1021 Marvell RDK-8010 Adapter + 11ab 5021 Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Adapter (64 bit) + 11ab 9521 Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Adapter (32 bit) + 1458 e000 Marvell 88E8001 Gigabit LOM Ethernet Adapter (Gigabyte) + 147b 1406 Marvell 88E8001 Gigabit LOM Ethernet Adapter (Abit) + 15d4 0047 Marvell 88E8001 Gigabit LOM Ethernet Adapter (Iwill) + 1695 9025 Marvell 88E8001 Gigabit LOM Ethernet Adapter (Epox) + 17f2 1c03 Marvell 88E8001 Gigabit LOM Ethernet Adapter (Albatron) 4611 GT-64115 System Controller 4620 GT-64120/64120A/64121A System Controller 4801 GT-48001 @@ -3803,8 +3816,6 @@ 0802 Rocketport UPCI 8 port w/external I/F 0803 Rocketport UPCI 16 port w/external I/F 0805 Rocketport UPCI 8 port w/octa cable - 080C RocketModem III 8 port - 080D RocketModem III 4 port 0903 Rocketport Compact PCI 16 port w/external I/F 11ff Scion Corporation 1200 CSS Corporation diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/pci/probe.c 830-ivtv/drivers/pci/probe.c --- 000-virgin/drivers/pci/probe.c Thu Jan 8 08:35:39 2004 +++ 830-ivtv/drivers/pci/probe.c Thu Jan 8 10:22:31 2004 @@ -25,6 +25,39 @@ EXPORT_SYMBOL(pci_root_buses); LIST_HEAD(pci_devices); /* + * PCI Bus Class + */ +static void release_pcibus_dev(struct class_device *class_dev) +{ + struct pci_bus *pci_bus = to_pci_bus(class_dev); + if (pci_bus->bridge) + put_device(pci_bus->bridge); + kfree(pci_bus); +} + +static struct class pcibus_class = { + .name = "pci_bus", + .release = &release_pcibus_dev, +}; + +static int __init pcibus_class_init(void) +{ + return class_register(&pcibus_class); +} +postcore_initcall(pcibus_class_init); + +/* + * PCI Bus Class Devices + */ +static ssize_t pci_bus_show_cpuaffinity(struct class_device *class_dev, char *buf) +{ + struct pci_bus *pcibus = to_pci_bus(class_dev); + + return sprintf(buf, "%lx\n", (unsigned long)pcibus_to_cpumask(pcibus->number)); +} +static CLASS_DEVICE_ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpuaffinity, NULL); + +/* * Translate the low bits of the PCI base * to the resource type */ @@ -176,7 +209,7 @@ void __devinit pci_read_bridge_bases(str limit |= (io_limit_hi << 16); } - if (base && base <= limit) { + if (base <= limit) { res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO; res->start = base; res->end = limit + 0xfff; @@ -187,7 +220,7 @@ void __devinit pci_read_bridge_bases(str pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo); base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16; limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16; - if (base && base <= limit) { + if (base <= limit) { res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM; res->start = base; res->end = limit + 0xfffff; @@ -213,7 +246,7 @@ void __devinit pci_read_bridge_bases(str } #endif } - if (base && base <= limit) { + if (base <= limit) { res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH; res->start = base; res->end = limit + 0xfffff; @@ -238,37 +271,40 @@ static struct pci_bus * __devinit pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr) { struct pci_bus *child; + int i; /* * Allocate a new bus, and inherit stuff from the parent.. */ child = pci_alloc_bus(); + if (!child) + return NULL; - if (child) { - int i; - - child->self = bridge; - child->parent = parent; - child->ops = parent->ops; - child->sysdata = parent->sysdata; - child->dev = &bridge->dev; + child->self = bridge; + child->parent = parent; + child->ops = parent->ops; + child->sysdata = parent->sysdata; + child->bridge = get_device(&bridge->dev); + + child->class_dev.class = &pcibus_class; + sprintf(child->class_dev.class_id, "%04x:%02x", pci_domain_nr(child), busnr); + class_device_register(&child->class_dev); + class_device_create_file(&child->class_dev, &class_device_attr_cpuaffinity); - /* - * Set up the primary, secondary and subordinate - * bus numbers. - */ - child->number = child->secondary = busnr; - child->primary = parent->secondary; - child->subordinate = 0xff; - - /* Set up default resource pointers and names.. */ - for (i = 0; i < 4; i++) { - child->resource[i] = &bridge->resource[PCI_BRIDGE_RESOURCES+i]; - child->resource[i]->name = child->name; - } - - bridge->subordinate = child; + /* + * Set up the primary, secondary and subordinate + * bus numbers. + */ + child->number = child->secondary = busnr; + child->primary = parent->secondary; + child->subordinate = 0xff; + + /* Set up default resource pointers and names.. */ + for (i = 0; i < 4; i++) { + child->resource[i] = &bridge->resource[PCI_BRIDGE_RESOURCES+i]; + child->resource[i]->name = child->name; } + bridge->subordinate = child; return child; } @@ -307,18 +343,17 @@ int __devinit pci_scan_bridge(struct pci pci_name(dev), buses & 0xffffff, pass); if ((buses & 0xffff00) && !pcibios_assign_all_busses() && !is_cardbus) { - unsigned int cmax; + unsigned int cmax, busnr; /* * Bus already configured by firmware, process it in the first * pass and just note the configuration. */ if (pass) return max; - child = pci_alloc_child_bus(bus, dev, 0); + busnr = (buses >> 8) & 0xFF; + child = pci_alloc_child_bus(bus, dev, busnr); child->primary = buses & 0xFF; - child->secondary = (buses >> 8) & 0xFF; child->subordinate = (buses >> 16) & 0xFF; - child->number = child->secondary; cmax = pci_scan_child_bus(child); if (cmax > max) max = cmax; } else { @@ -508,7 +543,7 @@ pci_scan_device(struct pci_bus *bus, int memset(dev, 0, sizeof(struct pci_dev)); dev->bus = bus; dev->sysdata = bus->sysdata; - dev->dev.parent = bus->dev; + dev->dev.parent = bus->bridge; dev->dev.bus = &pci_bus_type; dev->devfn = devfn; dev->hdr_type = hdr_type & 0x7f; @@ -635,13 +670,14 @@ unsigned int __devinit pci_do_scan_bus(s struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, int bus, struct pci_ops *ops, void *sysdata) { struct pci_bus *b; + struct device *dev; b = pci_alloc_bus(); if (!b) return NULL; - b->dev = kmalloc(sizeof(*(b->dev)),GFP_KERNEL); - if (!b->dev){ + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev){ kfree(b); return NULL; } @@ -652,17 +688,24 @@ struct pci_bus * __devinit pci_scan_bus_ if (pci_find_bus(pci_domain_nr(b), bus)) { /* If we already got to this bus through a different bridge, ignore it */ DBG("PCI: Bus %02x already known\n", bus); - kfree(b->dev); + kfree(dev); kfree(b); return NULL; } - list_add_tail(&b->node, &pci_root_buses); - memset(b->dev,0,sizeof(*(b->dev))); - b->dev->parent = parent; - sprintf(b->dev->bus_id,"pci%04x:%02x", pci_domain_nr(b), bus); - device_register(b->dev); + memset(dev, 0, sizeof(*dev)); + dev->parent = parent; + sprintf(dev->bus_id, "pci%04x:%02x", pci_domain_nr(b), bus); + device_register(dev); + b->bridge = get_device(dev); + + b->class_dev.class = &pcibus_class; + sprintf(b->class_dev.class_id, "%04x:%02x", pci_domain_nr(b), bus); + class_device_register(&b->class_dev); + class_device_create_file(&b->class_dev, &class_device_attr_cpuaffinity); + + sysfs_create_link(&b->class_dev.kobj, &b->bridge->kobj, "bridge"); b->number = b->secondary = bus; b->resource[0] = &ioport_resource; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/s390/net/qeth.c 830-ivtv/drivers/s390/net/qeth.c --- 000-virgin/drivers/s390/net/qeth.c Mon Nov 17 18:29:31 2003 +++ 830-ivtv/drivers/s390/net/qeth.c Thu Jan 8 08:54:30 2004 @@ -9739,28 +9739,28 @@ static int qeth_get_internal_functions(void) { struct net_device *dev; - - dev = (struct net_device *) kmalloc(sizeof (struct net_device), - GFP_KERNEL); +#ifdef CONFIG_NET_ETHERNET + dev = alloc_etherdev(0); if (!dev) { PRINT_ERR("Not enough memory for internal functions.\n"); return -ENOMEM; } -#ifdef CONFIG_NET_ETHERNET - ether_setup(dev); qeth_my_eth_header = dev->hard_header; qeth_my_eth_rebuild_header = dev->rebuild_header; qeth_my_eth_header_cache = dev->hard_header_cache; qeth_my_eth_header_cache_update = dev->header_cache_update; + free_netdev(dev); #endif #ifdef CONFIG_TR - tr_setup(dev); + dev = alloc_trdev(0); + if (!dev) { + PRINT_ERR("Not enough memory for internal functions.\n"); + return -ENOMEM; + } qeth_my_tr_header = dev->hard_header; qeth_my_tr_rebuild_header = dev->rebuild_header; + free_netdev(dev); #endif - - kfree(dev); - return 0; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/Kconfig 830-ivtv/drivers/scsi/Kconfig --- 000-virgin/drivers/scsi/Kconfig Thu Jan 8 08:35:40 2004 +++ 830-ivtv/drivers/scsi/Kconfig Thu Jan 8 11:16:54 2004 @@ -55,6 +55,14 @@ config BLK_DEV_SD In this case, do not compile the driver for your SCSI host adapter (below) as a module either. +config MAX_SD_DISKS + int "Maximum number of SCSI disks to support (256-8192)" + depends on BLK_DEV_SD + default "256" + help + The maximum number SCSI disks to support. Default is 256. + Change this value if you want kernel to support lots of SCSI devices. + config CHR_DEV_ST tristate "SCSI tape support" depends on SCSI @@ -137,6 +145,24 @@ config CHR_DEV_SG If unsure, say N. +config CHR_DEV_SCH + tristate "SCSI media changer support" + depends on SCSI + ---help--- + This is a driver for SCSI media changers. Most common devices are + tape libraries and MOD/CDROM jukeboxes. *Real* jukeboxes, you + don't need this for those tiny 6-slot cdrom changers. Media + changers are listed as "Type: Medium Changer" in /proc/scsi/scsi. + If you have such hardware and want to use it with linux, say Y + here. Check for details. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read and + . The module will be called ch.o. + If unsure, say N. + + comment "Some SCSI devices (e.g. CD jukebox) support multiple LUNs" depends on SCSI @@ -1210,6 +1236,8 @@ config SCSI_QLOGICPTI To compile this driver as a module, choose M here: the module will be called qlogicpti. +source "drivers/scsi/qla2xxx/Kconfig" + config SCSI_SEAGATE tristate "Seagate ST-02 and Future Domain TMC-8xx SCSI support" depends on X86 && ISA && SCSI && BROKEN @@ -1388,7 +1416,7 @@ config SCSI_ULTRASTOR config SCSI_NSP32 tristate "Workbit NinjaSCSI-32Bi/UDE support" - depends on PCI && SCSI + depends on PCI && SCSI && !64BIT help This is support for the Workbit NinjaSCSI-32Bi/UDE PCI/Cardbus SCSI host adapter. Please read the SCSI-HOWTO, available from @@ -1454,6 +1482,13 @@ config SCSI_MAC53C94 module will be called mac53c94. source "drivers/scsi/arm/Kconfig" + +config SCSI_LPFC + tristate "Emulex LP support" + depends on PCI && SCSI + ---help--- + This driver supports the Emulex LP hardware (fibre channel + adapter cards). config JAZZ_ESP bool "MIPS JAZZ FAS216 SCSI support" diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/Makefile 830-ivtv/drivers/scsi/Makefile --- 000-virgin/drivers/scsi/Makefile Mon Nov 17 18:29:48 2003 +++ 830-ivtv/drivers/scsi/Makefile Thu Jan 8 11:16:54 2004 @@ -74,6 +74,7 @@ obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicf obj-$(CONFIG_SCSI_QLOGIC_ISP) += qlogicisp.o obj-$(CONFIG_SCSI_QLOGIC_FC) += qlogicfc.o obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o +obj-$(CONFIG_SCSI_QLA2XXX) += qla2xxx/ obj-$(CONFIG_SCSI_PAS16) += pas16.o obj-$(CONFIG_SCSI_SEAGATE) += seagate.o obj-$(CONFIG_SCSI_FD_8xx) += seagate.o @@ -119,12 +120,14 @@ obj-$(CONFIG_SCSI_SATA_SIL) += libata.o obj-$(CONFIG_SCSI_SATA_VIA) += libata.o sata_via.o obj-$(CONFIG_ARM) += arm/ +obj-$(CONFIG_SCSI_LPFC) += lpfc/ obj-$(CONFIG_CHR_DEV_ST) += st.o obj-$(CONFIG_CHR_DEV_OSST) += osst.o obj-$(CONFIG_BLK_DEV_SD) += sd_mod.o obj-$(CONFIG_BLK_DEV_SR) += sr_mod.o obj-$(CONFIG_CHR_DEV_SG) += sg.o +obj-$(CONFIG_CHR_DEV_SCH) += ch.o scsi_mod-y += scsi.o hosts.o scsi_ioctl.o constants.o \ scsicam.o scsi_error.o scsi_lib.o \ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/ch.c 830-ivtv/drivers/scsi/ch.c --- 000-virgin/drivers/scsi/ch.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/ch.c Thu Jan 8 11:16:54 2004 @@ -0,0 +1,1085 @@ +/* + * SCSI Media Changer device driver for Linux 2.6 + * + * (c) 1996-2003 Gerd Knorr + * + */ + +#define VERSION "0.22" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* here are all the ioctls */ + +#define MAJOR_NR SCSI_CHANGER_MAJOR + +#define CH_DT_MAX 16 +#define CH_TYPES 8 + +#include +#include +#include + +#include "scsi.h" +#include "hosts.h" + +MODULE_SUPPORTED_DEVICE("sch"); +MODULE_DESCRIPTION("device driver for scsi media changer devices"); +MODULE_AUTHOR("Gerd Knorr "); +MODULE_LICENSE("GPL"); + +static int check_busy = 1; +MODULE_PARM(check_busy,"i"); +MODULE_PARM_DESC(check_busy, \ + "enable/disable busy check for data transfer elements (default: on)"); + +static int init = 1; +MODULE_PARM(init,"i"); +MODULE_PARM_DESC(init, \ + "initialize element status on driver load (default: on)"); + +static int timeout_move = 300; +MODULE_PARM(timeout_move,"i"); +MODULE_PARM_DESC(timeout_move,"timeout for move commands " + "(default: 300 seconds)"); + +static int timeout_init = 3600; +MODULE_PARM(timeout_init,"i"); +MODULE_PARM_DESC(timeout_init,"timeout for INITIALIZE ELEMENT STATUS " + "(default: 3600 seconds)"); + +static int verbose = 1; +MODULE_PARM(verbose,"i"); +MODULE_PARM_DESC(verbose,"be verbose (default: on)"); + +static int debug = 0; +MODULE_PARM(debug,"i"); +MODULE_PARM_DESC(debug,"enable/disable debug messages, also prints more " + "detailed sense codes on scsi errors (default: off)"); + +static int dt_id[CH_DT_MAX] = { [ 0 ... (CH_DT_MAX-1) ] = -1 }; +static int dt_lun[CH_DT_MAX]; +MODULE_PARM(dt_id,"1-" __MODULE_STRING(CH_DT_MAX) "i"); +MODULE_PARM(dt_lun,"1-" __MODULE_STRING(CH_DT_MAX) "i"); + +/* tell the driver about vendor-specific slots */ +static int vendor_firsts[CH_TYPES-4]; +static int vendor_counts[CH_TYPES-4]; +static char *vendor_labels[CH_TYPES-4]; +MODULE_PARM(vendor_firsts,"1-4i"); +MODULE_PARM(vendor_counts,"1-4i"); +MODULE_PARM(vendor_labels,"1-4s"); + +#define dprintk(fmt, arg...) if (debug) \ + printk(KERN_DEBUG "%s: " fmt, ch->name, ##arg) +#define vprintk(fmt, arg...) if (verbose) \ + printk(KERN_INFO "%s: " fmt, ch->name, ##arg) + +/* ------------------------------------------------------------------- */ + +#define MAX_RETRIES 1 + +static int ch_probe(struct device *); +static int ch_remove(struct device *); +static int ch_open(struct inode * inode, struct file * filp); +static int ch_release(struct inode * inode, struct file * filp); +static int ch_ioctl(struct inode * inode, struct file * filp, + unsigned int cmd, unsigned long arg); + +typedef struct { + struct list_head list; + int minor; + char name[8]; + Scsi_Device *device; + Scsi_Device **dt; /* ptrs to data transfer elements */ + u_int firsts[CH_TYPES]; + u_int counts[CH_TYPES]; + u_int unit_attention; + u_int voltags; + struct semaphore lock; +} scsi_changer; + +static LIST_HEAD(ch_devlist); +static spinlock_t ch_devlist_lock = SPIN_LOCK_UNLOCKED; +static int ch_devcount; + +struct scsi_driver ch_template = +{ + .owner = THIS_MODULE, + .gendrv = { + .name = "ch", + .probe = ch_probe, + .remove = ch_remove, + }, +}; + +static struct file_operations changer_fops = +{ + .owner = THIS_MODULE, + .open = ch_open, + .release = ch_release, + .ioctl = ch_ioctl, +}; + +static struct { + unsigned char sense; + unsigned char asc; + unsigned char ascq; + int errno; +} err[] = { +/* Just filled in what looks right. Hav'nt checked any standard paper for + these errno assignments, so they may be wrong... */ + { + .sense = ILLEGAL_REQUEST, + .asc = 0x21, + .ascq = 0x01, + .errno = EBADSLT, /* Invalid element address */ + },{ + .sense = ILLEGAL_REQUEST, + .asc = 0x28, + .ascq = 0x01, + .errno = EBADE, /* Import or export element accessed */ + },{ + .sense = ILLEGAL_REQUEST, + .asc = 0x3B, + .ascq = 0x0D, + .errno = EXFULL, /* Medium destination element full */ + },{ + .sense = ILLEGAL_REQUEST, + .asc = 0x3B, + .ascq = 0x0E, + .errno = EBADE, /* Medium source element empty */ + },{ + .sense = ILLEGAL_REQUEST, + .asc = 0x20, + .ascq = 0x00, + .errno = EBADRQC, /* Invalid command operation code */ + },{ + /* end of list */ + } +}; + +/* ------------------------------------------------------------------- */ +/* ioctl32 compat */ + +#ifdef CONFIG_COMPAT + +struct changer_element_status32 { + int ces_type; + compat_uptr_t ces_data; +}; +#define CHIOGSTATUS32 _IOW('c', 8,struct changer_element_status32) + +static struct { + unsigned int cmd; + int reg; +} ioctl32_cmds[] = { + { .cmd = CHIOMOVE }, + { .cmd = CHIOEXCHANGE }, + { .cmd = CHIOPOSITION }, + { .cmd = CHIOGPICKER }, + { .cmd = CHIOSPICKER }, + { .cmd = CHIOGPARAMS }, + { .cmd = CHIOGELEM }, + { .cmd = CHIOINITELEM }, + { .cmd = CHIOSVOLTAG }, + { .cmd = CHIOGVPARAMS }, + { .cmd = CHIOGSTATUS32 }, +}; + +static int ioctl32_register(void) +{ + unsigned int i; + int err; + + for (i = 0; i < ARRAY_SIZE(ioctl32_cmds); i++) { + err = register_ioctl32_conversion(ioctl32_cmds[i].cmd,NULL); + if (err >= 0) + ioctl32_cmds[i].reg++; + } + return 0; +} +static int ioctl32_unregister(void) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ioctl32_cmds); i++) { + if (ioctl32_cmds[i].reg) { + unregister_ioctl32_conversion(ioctl32_cmds[i].cmd); + ioctl32_cmds[i].reg--; + } + } + return 0; +} + +#else + +static int ioctl32_register(void) { return 0; } +static int ioctl32_unregister(void) { return 0; } + +#endif + +/* ------------------------------------------------------------------- */ + +static int ch_find_errno(unsigned char *sense_buffer) +{ + int i,errno = 0; + + /* Check to see if additional sense information is available */ + if (sense_buffer[7] > 5 && + sense_buffer[12] != 0) { + for (i = 0; err[i].errno != 0; i++) { + if (err[i].sense == sense_buffer[ 2] && + err[i].asc == sense_buffer[12] && + err[i].ascq == sense_buffer[13]) { + errno = -err[i].errno; + break; + } + } + } + if (errno == 0) + errno = -EIO; + return errno; +} + +static void +ch_request_done (Scsi_Cmnd * sc) +{ + sc->request->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */ + if (sc->request->waiting != NULL) + complete(sc->request->waiting); +} + +static int +ch_do_scsi(scsi_changer *ch, unsigned char *cmd, + void *buffer, unsigned buflength) +{ + int errno, retries = 0, timeout; + DECLARE_COMPLETION(wait); + Scsi_Request *sr; + + sr = scsi_allocate_request(ch->device, GFP_ATOMIC); + if (NULL == sr) + return -ENOMEM; + + retry: + errno = 0; + if (debug) { + dprintk("command: %s",""); + print_command(cmd); + } + + sr->sr_request->waiting = &wait; + timeout = (cmd[0] == INITIALIZE_ELEMENT_STATUS) + ? timeout_init : timeout_move; + scsi_do_req(sr, cmd, buffer, buflength, ch_request_done, + timeout * HZ, MAX_RETRIES); + wait_for_completion(&wait); + sr->sr_request->waiting = NULL; + + dprintk("result: 0x%x\n",sr->sr_result); + if (driver_byte(sr->sr_result) != 0) { + if (debug) + print_req_sense(ch->name, sr); + errno = ch_find_errno(sr->sr_sense_buffer); + + switch(sr->sr_sense_buffer[2] & 0xf) { + case UNIT_ATTENTION: + ch->unit_attention = 1; + if (retries++ < 3) + goto retry; + break; + } + } + scsi_release_request(sr); + return errno; +} + +/* ------------------------------------------------------------------------ */ + +static int +ch_elem_to_typecode(scsi_changer *ch, u_int elem) +{ + int i; + + for (i = 0; i < CH_TYPES; i++) { + if (elem >= ch->firsts[i] && + elem < ch->firsts[i] + + ch->counts[i]) + return i+1; + } + return 0; +} + +static int +ch_read_element_status(scsi_changer *ch, u_int elem, char *data) +{ + u_char cmd[12]; + u_char *buffer; + int result; + + buffer = kmalloc(512, GFP_KERNEL); + if(!buffer) + return -ENOMEM; + + retry: + memset(cmd,0,sizeof(cmd)); + cmd[0] = READ_ELEMENT_STATUS; + cmd[1] = (ch->device->lun << 5) | + (ch->voltags ? 0x10 : 0) | + ch_elem_to_typecode(ch,elem); + cmd[2] = (elem >> 8) & 0xff; + cmd[3] = elem & 0xff; + cmd[5] = 1; + cmd[9] = 255; + if (0 == (result = ch_do_scsi(ch, cmd, buffer, 256))) { + if (((buffer[16] << 8) | buffer[17]) != elem) { + dprintk("asked for element 0x%02x, got 0x%02x\n", + elem,(buffer[16] << 8) | buffer[17]); + kfree(buffer); + return -EIO; + } + memcpy(data,buffer+16,16); + } else { + if (ch->voltags) { + ch->voltags = 0; + vprintk("device has no volume tag support%s\n",""); + goto retry; + } + dprintk("READ ELEMENT STATUS for element 0x%x failed\n",elem); + } + kfree(buffer); + return result; +} + +static int +ch_init_elem(scsi_changer *ch) +{ + int err; + u_char cmd[6]; + + vprintk("INITIALIZE ELEMENT STATUS, may take some time ...%s\n",""); + memset(cmd,0,sizeof(cmd)); + cmd[0] = INITIALIZE_ELEMENT_STATUS; + cmd[1] = ch->device->lun << 5; + err = ch_do_scsi(ch, cmd, NULL, 0); + vprintk("... finished%s\n",""); + return err; +} + +static int +ch_readconfig(scsi_changer *ch) +{ + u_char cmd[10], data[16]; + u_char *buffer; + int result,id,lun,i; + u_int elem; + + buffer = kmalloc(512, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + memset(buffer,0,512); + + memset(cmd,0,sizeof(cmd)); + cmd[0] = MODE_SENSE; + cmd[1] = ch->device->lun << 5; + cmd[2] = 0x1d; + cmd[4] = 255; + result = ch_do_scsi(ch, cmd, buffer, 255); + if (0 != result) { + cmd[1] |= (1<<3); + result = ch_do_scsi(ch, cmd, buffer, 255); + } + if (0 == result) { + ch->firsts[CHET_MT] = + (buffer[buffer[3]+ 6] << 8) | buffer[buffer[3]+ 7]; + ch->counts[CHET_MT] = + (buffer[buffer[3]+ 8] << 8) | buffer[buffer[3]+ 9]; + ch->firsts[CHET_ST] = + (buffer[buffer[3]+10] << 8) | buffer[buffer[3]+11]; + ch->counts[CHET_ST] = + (buffer[buffer[3]+12] << 8) | buffer[buffer[3]+13]; + ch->firsts[CHET_IE] = + (buffer[buffer[3]+14] << 8) | buffer[buffer[3]+15]; + ch->counts[CHET_IE] = + (buffer[buffer[3]+16] << 8) | buffer[buffer[3]+17]; + ch->firsts[CHET_DT] = + (buffer[buffer[3]+18] << 8) | buffer[buffer[3]+19]; + ch->counts[CHET_DT] = + (buffer[buffer[3]+20] << 8) | buffer[buffer[3]+21]; + vprintk("type #1 (mt): 0x%x+%d [medium transport]\n", + ch->firsts[CHET_MT], + ch->counts[CHET_MT]); + vprintk("type #2 (st): 0x%x+%d [storage]\n", + ch->firsts[CHET_ST], + ch->counts[CHET_ST]); + vprintk("type #3 (ie): 0x%x+%d [import/export]\n", + ch->firsts[CHET_IE], + ch->counts[CHET_IE]); + vprintk("type #4 (dt): 0x%x+%d [data transfer]\n", + ch->firsts[CHET_DT], + ch->counts[CHET_DT]); + } else { + vprintk("reading element address assigment page failed!%s\n", + ""); + } + + /* vendor specific element types */ + for (i = 0; i < 4; i++) { + if (0 == vendor_counts[i]) + continue; + if (NULL == vendor_labels[i]) + continue; + ch->firsts[CHET_V1+i] = vendor_firsts[i]; + ch->counts[CHET_V1+i] = vendor_counts[i]; + vprintk("type #%d (v%d): 0x%x+%d [%s, vendor specific]\n", + i+5,i+1,vendor_firsts[i],vendor_counts[i], + vendor_labels[i]); + } + + /* look up the devices of the data transfer elements */ + ch->dt = + kmalloc(ch->counts[CHET_DT]*sizeof(Scsi_Device*), + GFP_ATOMIC); + for (elem = 0; elem < ch->counts[CHET_DT]; elem++) { + id = -1; + lun = 0; + if (-1 != dt_id[elem]) { + id = dt_id[elem]; + lun = dt_lun[elem]; + vprintk("dt 0x%x: [insmod option] ", + elem+ch->firsts[CHET_DT]); + } else if (0 != ch_read_element_status + (ch,elem+ch->firsts[CHET_DT],data)) { + vprintk("dt 0x%x: READ ELEMENT STATUS failed\n", + elem+ch->firsts[CHET_DT]); + } else { + vprintk("dt 0x%x: ",elem+ch->firsts[CHET_DT]); + if (data[6] & 0x80) { + if (verbose) + printk("not this SCSI bus\n"); + ch->dt[elem] = NULL; + } else if (0 == (data[6] & 0x30)) { + if (verbose) + printk("ID/LUN unknown\n"); + ch->dt[elem] = NULL; + } else { + id = ch->device->id; + lun = 0; + if (data[6] & 0x20) id = data[7]; + if (data[6] & 0x10) lun = data[6] & 7; + } + } + if (-1 != id) { + if (verbose) + printk("ID %i, LUN %i, ",id,lun); + ch->dt[elem] = + scsi_device_lookup(ch->device->host, + ch->device->channel, + id,lun); + if (!ch->dt[elem]) { + /* should not happen */ + if (verbose) + printk("Huh? device not found!\n"); + } else { + if (verbose) + printk("name: %8.8s %16.16s %4.4s\n", + ch->dt[elem]->vendor, + ch->dt[elem]->model, + ch->dt[elem]->rev); + } + } + } + ch->voltags = 1; + kfree(buffer); + + return 0; +} + +/* ------------------------------------------------------------------------ */ + +static int +ch_position(scsi_changer *ch, u_int trans, u_int elem, int rotate) +{ + u_char cmd[10]; + + dprintk("position: 0x%x\n",elem); + if (0 == trans) + trans = ch->firsts[CHET_MT]; + memset(cmd,0,sizeof(cmd)); + cmd[0] = POSITION_TO_ELEMENT; + cmd[1] = ch->device->lun << 5; + cmd[2] = (trans >> 8) & 0xff; + cmd[3] = trans & 0xff; + cmd[4] = (elem >> 8) & 0xff; + cmd[5] = elem & 0xff; + cmd[8] = rotate ? 1 : 0; + return ch_do_scsi(ch, cmd, NULL,0); +} + +static int +ch_move(scsi_changer *ch, u_int trans, u_int src, u_int dest, int rotate) +{ + u_char cmd[12]; + + dprintk("move: 0x%x => 0x%x\n",src,dest); + if (0 == trans) + trans = ch->firsts[CHET_MT]; + memset(cmd,0,sizeof(cmd)); + cmd[0] = MOVE_MEDIUM; + cmd[1] = ch->device->lun << 5; + cmd[2] = (trans >> 8) & 0xff; + cmd[3] = trans & 0xff; + cmd[4] = (src >> 8) & 0xff; + cmd[5] = src & 0xff; + cmd[6] = (dest >> 8) & 0xff; + cmd[7] = dest & 0xff; + cmd[10] = rotate ? 1 : 0; + return ch_do_scsi(ch, cmd, NULL,0); +} + +static int +ch_exchange(scsi_changer *ch, u_int trans, u_int src, + u_int dest1, u_int dest2, int rotate1, int rotate2) +{ + u_char cmd[12]; + + dprintk("exchange: 0x%x => 0x%x => 0x%x\n", + src,dest1,dest2); + if (0 == trans) + trans = ch->firsts[CHET_MT]; + memset(cmd,0,sizeof(cmd)); + cmd[0] = EXCHANGE_MEDIUM; + cmd[1] = ch->device->lun << 5; + cmd[2] = (trans >> 8) & 0xff; + cmd[3] = trans & 0xff; + cmd[4] = (src >> 8) & 0xff; + cmd[5] = src & 0xff; + cmd[6] = (dest1 >> 8) & 0xff; + cmd[7] = dest1 & 0xff; + cmd[8] = (dest2 >> 8) & 0xff; + cmd[9] = dest2 & 0xff; + cmd[10] = (rotate1 ? 1 : 0) | (rotate2 ? 2 : 0); + + return ch_do_scsi(ch, cmd, NULL,0); +} + +static void +ch_check_voltag(char *tag) +{ + int i; + + for (i = 0; i < 32; i++) { + /* restrict to ascii */ + if (tag[i] >= 0x7f || tag[i] < 0x20) + tag[i] = ' '; + /* don't allow search wildcards */ + if (tag[i] == '?' || + tag[i] == '*') + tag[i] = ' '; + } +} + +static int +ch_set_voltag(scsi_changer *ch, u_int elem, + int alternate, int clear, u_char *tag) +{ + u_char cmd[12]; + u_char *buffer; + int result; + + buffer = kmalloc(512, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + memset(buffer,0,512); + + dprintk("%s %s voltag: 0x%x => \"%s\"\n", + clear ? "clear" : "set", + alternate ? "alternate" : "primary", + elem, tag); + memset(cmd,0,sizeof(cmd)); + cmd[0] = SEND_VOLUME_TAG; + cmd[1] = (ch->device->lun << 5) | + ch_elem_to_typecode(ch,elem); + cmd[2] = (elem >> 8) & 0xff; + cmd[3] = elem & 0xff; + cmd[5] = clear + ? (alternate ? 0x0d : 0x0c) + : (alternate ? 0x0b : 0x0a); + + cmd[9] = 255; + + memcpy(buffer,tag,32); + ch_check_voltag(buffer); + + result = ch_do_scsi(ch, cmd, buffer, 256); + kfree(buffer); + return result; +} + +static int ch_gstatus(scsi_changer *ch, int type, unsigned char *dest) +{ + int retval = 0; + u_char data[16]; + unsigned int i; + + down(&ch->lock); + for (i = 0; i < ch->counts[type]; i++) { + if (0 != ch_read_element_status + (ch, ch->firsts[type]+i,data)) { + retval = -EIO; + break; + } + put_user(data[2], dest+i); + if (data[2] & CESTATUS_EXCEPT) + vprintk("element 0x%x: asc=0x%x, ascq=0x%x\n", + ch->firsts[type]+i, + (int)data[4],(int)data[5]); + retval = ch_read_element_status + (ch, ch->firsts[type]+i,data); + if (0 != retval) + break; + } + up(&ch->lock); + return retval; +} + +/* ------------------------------------------------------------------------ */ + +static int +ch_release(struct inode *inode, struct file *file) +{ + scsi_changer *ch = file->private_data; + + scsi_device_put(ch->device); + file->private_data = NULL; + return 0; +} + +static int +ch_open(struct inode *inode, struct file *file) +{ + struct list_head *item; + scsi_changer *tmp, *ch; + int minor = iminor(inode); + + spin_lock(&ch_devlist_lock); + ch = NULL; + list_for_each(item,&ch_devlist) { + tmp = list_entry(item, scsi_changer, list); + if (tmp->minor == minor) + ch = tmp; + } + if (NULL == ch || scsi_device_get(ch->device)) { + spin_unlock(&ch_devlist_lock); + return -ENXIO; + } + spin_unlock(&ch_devlist_lock); + + file->private_data = ch; + return 0; +} + +static int +ch_checkrange(scsi_changer *ch, unsigned int type, unsigned int unit) +{ + if (type >= CH_TYPES || unit >= ch->counts[type]) + return -1; + return 0; +} + +/* for data transfer elements: check if they are busy */ +static int +ch_is_busy(scsi_changer *ch, int type, int unit) +{ +#if 0 /* hmm, access_count is gone :-/ */ + if (!check_busy) + return 0; + if (type != CHET_DT) + return 0; + if (!ch->dt[unit]) + return 0; + return atomic_read(&ch->dt[unit]->access_count); +#else + return 0; +#endif +} + +static int ch_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + scsi_changer *ch = file->private_data; + int retval; + + switch (cmd) { + case CHIOGPARAMS: + { + struct changer_params params; + + params.cp_curpicker = 0; + params.cp_npickers = ch->counts[CHET_MT]; + params.cp_nslots = ch->counts[CHET_ST]; + params.cp_nportals = ch->counts[CHET_IE]; + params.cp_ndrives = ch->counts[CHET_DT]; + + if (copy_to_user((void *) arg, ¶ms, sizeof(params))) + return -EFAULT; + return 0; + } + case CHIOGVPARAMS: + { + struct changer_vendor_params vparams; + + memset(&vparams,0,sizeof(vparams)); + if (ch->counts[CHET_V1]) { + vparams.cvp_n1 = ch->counts[CHET_V1]; + strncpy(vparams.cvp_label1,vendor_labels[0],16); + } + if (ch->counts[CHET_V2]) { + vparams.cvp_n2 = ch->counts[CHET_V2]; + strncpy(vparams.cvp_label2,vendor_labels[1],16); + } + if (ch->counts[CHET_V3]) { + vparams.cvp_n3 = ch->counts[CHET_V3]; + strncpy(vparams.cvp_label3,vendor_labels[2],16); + } + if (ch->counts[CHET_V4]) { + vparams.cvp_n4 = ch->counts[CHET_V4]; + strncpy(vparams.cvp_label4,vendor_labels[3],16); + } + if (copy_to_user((void *) arg, &vparams, sizeof(vparams))) + return -EFAULT; + return 0; + } + + case CHIOPOSITION: + { + struct changer_position pos; + + if (copy_from_user(&pos, (void*)arg, sizeof (pos))) + return -EFAULT; + + if (0 != ch_checkrange(ch, pos.cp_type, pos.cp_unit)) { + dprintk("CHIOPOSITION: invalid parameter%s\n",""); + return -EBADSLT; + } + down(&ch->lock); + retval = ch_position(ch,0, + ch->firsts[pos.cp_type] + pos.cp_unit, + pos.cp_flags & CP_INVERT); + up(&ch->lock); + return retval; + } + + case CHIOMOVE: + { + struct changer_move mv; + + if (copy_from_user(&mv, (void*)arg, sizeof (mv))) + return -EFAULT; + + if (0 != ch_checkrange(ch, mv.cm_fromtype, mv.cm_fromunit) || + 0 != ch_checkrange(ch, mv.cm_totype, mv.cm_tounit )) { + dprintk("CHIOMOVE: invalid parameter%s\n",""); + return -EBADSLT; + } + if (ch_is_busy(ch, mv.cm_fromtype, mv.cm_fromunit) || + ch_is_busy(ch, mv.cm_totype, mv.cm_tounit )) + return -EBUSY; + + down(&ch->lock); + retval = ch_move(ch,0, + ch->firsts[mv.cm_fromtype] + mv.cm_fromunit, + ch->firsts[mv.cm_totype] + mv.cm_tounit, + mv.cm_flags & CM_INVERT); + up(&ch->lock); + return retval; + } + + case CHIOEXCHANGE: + { + struct changer_exchange mv; + + if (copy_from_user(&mv, (void*)arg, sizeof (mv))) + return -EFAULT; + + if (0 != ch_checkrange(ch, mv.ce_srctype, mv.ce_srcunit ) || + 0 != ch_checkrange(ch, mv.ce_fdsttype, mv.ce_fdstunit) || + 0 != ch_checkrange(ch, mv.ce_sdsttype, mv.ce_sdstunit)) { + dprintk("CHIOEXCHANGE: invalid parameter%s\n",""); + return -EBADSLT; + } + if (0 != ch_is_busy(ch, mv.ce_srctype, mv.ce_srcunit ) || + 0 != ch_is_busy(ch, mv.ce_fdsttype, mv.ce_fdstunit) || + 0 != ch_is_busy(ch, mv.ce_sdsttype, mv.ce_sdstunit)) + return -EBUSY; + + down(&ch->lock); + retval = ch_exchange + (ch,0, + ch->firsts[mv.ce_srctype] + mv.ce_srcunit, + ch->firsts[mv.ce_fdsttype] + mv.ce_fdstunit, + ch->firsts[mv.ce_sdsttype] + mv.ce_sdstunit, + mv.ce_flags & CE_INVERT1, mv.ce_flags & CE_INVERT2); + up(&ch->lock); + return retval; + } + + case CHIOGSTATUS: + { + struct changer_element_status ces; + + if (copy_from_user(&ces, (void*)arg, sizeof (ces))) + return -EFAULT; + if (ces.ces_type < 0 || ces.ces_type >= CH_TYPES) + return -EINVAL; + + return ch_gstatus(ch, ces.ces_type, ces.ces_data); + } + +#ifdef CONFIG_COMPAT + case CHIOGSTATUS32: + { + struct changer_element_status32 ces32; + unsigned char *data; + + if (copy_from_user(&ces32, (void*)arg, sizeof (ces32))) + return -EFAULT; + if (ces32.ces_type < 0 || ces32.ces_type >= CH_TYPES) + return -EINVAL; + + data = compat_ptr(ces32.ces_data); + return ch_gstatus(ch, ces32.ces_type, data); + } +#endif + + case CHIOGELEM: + { + struct changer_get_element cge; + u_char cmd[12]; + u_char *buffer; + unsigned int elem; + int result,i; + + if (copy_from_user(&cge, (void*)arg, sizeof (cge))) + return -EFAULT; + + if (0 != ch_checkrange(ch, cge.cge_type, cge.cge_unit)) + return -EINVAL; + elem = ch->firsts[cge.cge_type] + cge.cge_unit; + + buffer = kmalloc(512, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + down(&ch->lock); + + voltag_retry: + memset(cmd,0,sizeof(cmd)); + cmd[0] = READ_ELEMENT_STATUS; + cmd[1] = (ch->device->lun << 5) | + (ch->voltags ? 0x10 : 0) | + ch_elem_to_typecode(ch,elem); + cmd[2] = (elem >> 8) & 0xff; + cmd[3] = elem & 0xff; + cmd[5] = 1; + cmd[9] = 255; + + if (0 == (result = ch_do_scsi(ch, cmd, buffer, 256))) { + cge.cge_status = buffer[18]; + cge.cge_flags = 0; + if (buffer[18] & CESTATUS_EXCEPT) { + /* FIXME: fill cge_errno */ + } + if (buffer[25] & 0x80) { + cge.cge_flags |= CGE_SRC; + if (buffer[25] & 0x40) + cge.cge_flags |= CGE_INVERT; + elem = (buffer[26]<<8) | buffer[27]; + for (i = 0; i < 4; i++) { + if (elem >= ch->firsts[i] && + elem < ch->firsts[i] + ch->counts[i]) { + cge.cge_srctype = i; + cge.cge_srcunit = elem-ch->firsts[i]; + } + } + } + if ((buffer[22] & 0x30) == 0x30) { + cge.cge_flags |= CGE_IDLUN; + cge.cge_id = buffer[23]; + cge.cge_lun = buffer[22] & 7; + } + if (buffer[9] & 0x80) { + cge.cge_flags |= CGE_PVOLTAG; + memcpy(cge.cge_pvoltag,buffer+28,36); + } + if (buffer[9] & 0x40) { + cge.cge_flags |= CGE_AVOLTAG; + memcpy(cge.cge_avoltag,buffer+64,36); + } + } else if (ch->voltags) { + ch->voltags = 0; + vprintk("device has no volume tag support%s\n",""); + goto voltag_retry; + } + kfree(buffer); + up(&ch->lock); + + if (copy_to_user((void*)arg, &cge, sizeof (cge))) + return -EFAULT; + return result; + } + + case CHIOINITELEM: + { + down(&ch->lock); + retval = ch_init_elem(ch); + up(&ch->lock); + return retval; + } + + case CHIOSVOLTAG: + { + struct changer_set_voltag csv; + int elem; + + if (copy_from_user(&csv, (void*)arg, sizeof(csv))) + return -EFAULT; + + if (0 != ch_checkrange(ch, csv.csv_type, csv.csv_unit)) { + dprintk("CHIOSVOLTAG: invalid parameter%s\n",""); + return -EBADSLT; + } + elem = ch->firsts[csv.csv_type] + csv.csv_unit; + down(&ch->lock); + retval = ch_set_voltag(ch, elem, + csv.csv_flags & CSV_AVOLTAG, + csv.csv_flags & CSV_CLEARTAG, + csv.csv_voltag); + up(&ch->lock); + return retval; + } + + default: + return scsi_ioctl(ch->device, cmd, (void*)arg); + + } +} + +/* ------------------------------------------------------------------------ */ + +static int ch_probe(struct device *dev) +{ + struct scsi_device *sd = to_scsi_device(dev); + scsi_changer *ch; + + if (sd->type != TYPE_MEDIUM_CHANGER) + return -ENODEV; + + ch = kmalloc(sizeof(*ch), GFP_KERNEL); + if (NULL == ch) + return -ENOMEM; + + memset(ch,0,sizeof(*ch)); + ch->minor = ch_devcount; + sprintf(ch->name,"ch%d",ch->minor); + init_MUTEX(&ch->lock); + ch->device = sd; + ch_readconfig(ch); + if (init) + ch_init_elem(ch); + + devfs_mk_cdev(MKDEV(MAJOR_NR,ch->minor), + S_IFCHR | S_IRUGO | S_IWUGO, ch->name); + + printk(KERN_INFO "Attached scsi changer %s " + "at scsi%d, channel %d, id %d, lun %d\n", + ch->name, sd->host->host_no, sd->channel, sd->id, sd->lun); + + spin_lock(&ch_devlist_lock); + list_add_tail(&ch->list,&ch_devlist); + ch_devcount++; + spin_unlock(&ch_devlist_lock); + return 0; +} + +static int ch_remove(struct device *dev) +{ + struct scsi_device *sd = to_scsi_device(dev); + struct list_head *item; + scsi_changer *tmp, *ch; + + spin_lock(&ch_devlist_lock); + ch = NULL; + list_for_each(item,&ch_devlist) { + tmp = list_entry(item, scsi_changer, list); + if (tmp->device == sd) + ch = tmp; + } + BUG_ON(NULL == ch); + list_del(&ch->list); + spin_unlock(&ch_devlist_lock); + + devfs_remove(ch->name); + kfree(ch->dt); + kfree(ch); + ch_devcount--; + return 0; +} + +static int __init init_ch_module(void) +{ + int rc; + + printk(KERN_INFO "SCSI Media Changer driver v" VERSION + " for Linux " UTS_RELEASE "\n"); + rc = register_chrdev(MAJOR_NR,"ch",&changer_fops); + if (rc < 0) { + printk("Unable to get major %d for SCSI-Changer\n", + MAJOR_NR); + return rc; + } + ioctl32_register(); + rc = scsi_register_driver(&ch_template.gendrv); + if (rc < 0) + goto fail1; + return 0; + + fail1: + ioctl32_unregister(); + unregister_chrdev(MAJOR_NR, "ch"); + return rc; +} + +static void __exit exit_ch_module(void) +{ + scsi_unregister_driver(&ch_template.gendrv); + unregister_chrdev(MAJOR_NR, "ch"); + ioctl32_unregister(); +} + +module_init(init_ch_module); +module_exit(exit_ch_module); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/COPYING 830-ivtv/drivers/scsi/lpfc/COPYING --- 000-virgin/drivers/scsi/lpfc/COPYING Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/COPYING Thu Jan 8 10:21:53 2004 @@ -0,0 +1,342 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/Makefile 830-ivtv/drivers/scsi/lpfc/Makefile --- 000-virgin/drivers/scsi/lpfc/Makefile Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/Makefile Thu Jan 8 10:21:53 2004 @@ -0,0 +1,6 @@ +obj-$(CONFIG_SCSI_LPFC) += lpfcdd.o + +EXTRA_CFLAGS += -DLP6000 -D_LINUX -Idrivers/scsi + +lpfcdd-objs := fcscsib.o fcmboxb.o fcmemb.o fcelsb.o fcstratb.o \ + fcxmitb.o fcrpib.o fcclockb.o fcLINUXfcp.o lpfc.conf.o diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/README 830-ivtv/drivers/scsi/lpfc/README --- 000-virgin/drivers/scsi/lpfc/README Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/README Thu Jan 8 10:21:53 2004 @@ -0,0 +1,43 @@ +************************************************************************ +Emulex Corporation + +README for the Driver kit 1.23a for Emulex Fibre Channel Host Adapters + +September 12, 2003 +************************************************************************ + +This Application kit has been designed for the following environment: + +- Supported Hardware architecture platforms: + - 32-bit Intel platforms (IA-32) + - 64-bit Intel platforms (IA-64) + - Power PC 64 bits (PPC) + +- Supported Linux OS (note that testing has been conducted only with the kernels in parenthesis): + - Red Hat Pro 7.3 (kernel 2.4.18-27) + - Red Hat Pro 8.0 (kernel 2.4.18-27) + - Red Hat Advanced Server 2.1 x86 (kernel 2.4.9-e.16) + - SLES 7 x86 (kernel 2.4.16) + - SLES 8 x86 (kernel 2.4.19) + - Red Hat Advanced Server 2.1 IA-64 (kernel 2.4.18-e.25) + - SuSE 8.0 ppc64 (kernel 2.4.19-u11-ppc64) + +- Supported Emulex enterprise adapters: + - LP8000 + - LP9000 + - LP9002L + - LP9002DC + - LP9402DC + - LP9802 + - LP10000 + - LP9802 + - LP10000 + +- This driver supports any mix of the above Emulex adapters within a single host system. + +Main driver features: +1. Full fabric support, discovery, FCP and fibre channel device/error and exception handling +2. Concurrent multi-protocol (FCP and IP) support +3. Supports INT13 (EDD 2.1/3.0) fabric boot. +4. This driver is entirely self-contained and intended for configuration using lpfc. No external utility is required or supported. +5. This driver will not be dependent on any non-open source program for its execution. It will not taint an open source kernel. diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/dfc.h 830-ivtv/drivers/scsi/lpfc/dfc.h --- 000-virgin/drivers/scsi/lpfc/dfc.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/dfc.h Thu Jan 8 10:21:53 2004 @@ -0,0 +1,199 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Enterprise Fibre Channel Host Bus Adapters. * + * Refer to the README file included with this package for * + * driver version and adapter support. * + * Copyright (C) 2003 Emulex Corporation. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details, a copy of which * + * can be found in the file COPYING included with this package. * + *******************************************************************/ +#if !defined(_KERNEL) && !defined(__KERNEL__) +#endif + + +#define _DFC_64BIT 1 + +#ifdef BITS_PER_LONG +#if BITS_PER_LONG < 64 +#undef _DFC_64BIT +#endif +#endif + +#ifdef i386 +#undef _DFC_64BIT +#endif + +#ifdef powerpc +#ifndef CONFIG_PPC64 +#undef _DFC_64BIT +#endif +#endif + + +struct dfccmdinfo { +#ifdef _DFC_64BIT + char *c_datain; + char *c_dataout; + unsigned short c_cmd; + unsigned short c_insz; + uint32 c_outsz; +#else + void *c_filler1; + char *c_datain; + void *c_filler2; + char *c_dataout; + unsigned short c_cmd; + unsigned short c_insz; + uint32 c_outsz; +#endif +}; + +struct cmd_input { +#ifdef _DFC_64BIT + short c_brd; + short c_ring; + short c_iocb; + short c_flag; + void *c_arg1; + void *c_arg2; + void *c_arg3; + char c_string[16]; +#else + short c_brd; + short c_ring; + short c_iocb; + short c_flag; + void *c_filler1; + void *c_arg1; + void *c_filler2; + void *c_arg2; + void *c_filler3; + void *c_arg3; + char c_string[16]; +#endif +}; + + + +struct cmdinfo { + int c_cmd; + char *c_string; + int (*c_routine)(struct cmdinfo *cp, void *p); + char *c_datain; + char *c_dataout; + unsigned short c_insz; + unsigned short c_outsz; +}; + +#define C_INVAL 0x0 +#define C_DISPLAY_PCI_ALL 0x1 +#define C_WRITE_PCI 0x2 +#define C_WRITE_HC 0x3 +#define C_WRITE_HS 0x4 +#define C_WRITE_HA 0x5 +#define C_WRITE_CA 0x6 +#define C_READ_PCI 0x7 +#define C_READ_HC 0x8 +#define C_READ_HS 0x9 +#define C_READ_HA 0xa +#define C_READ_CA 0xb +#define C_READ_MB 0xc +#define C_EXIT 0xd +#define C_SET 0xe +#define C_READ_RING 0xf +#define C_READ_MEM 0x10 +#define C_READ_IOCB 0x11 +#define C_READ_RPILIST 0x12 +#define C_READ_BPLIST 0x13 +#define C_READ_MEMSEG 0x14 +#define C_MBOX 0x15 +#define C_RESET 0x16 +#define C_READ_BINFO 0x17 +#define C_NDD_STAT 0x18 +#define C_FC_STAT 0x19 +#define C_WRITE_MEM 0x1a +#define C_WRITE_CTLREG 0x1b +#define C_READ_CTLREG 0x1c +#define C_INITBRDS 0x1d +#define C_SETDIAG 0x1e +#define C_DBG 0x1f +#define C_GET_PHYSADDR 0x20 +#define C_PUT_PHYSADDR 0x21 +#define C_NODE 0x22 +#define C_DEVP 0x23 +#define C_INST 0x24 +#define C_LIP 0x25 +#define C_LINKINFO 0x26 +#define C_IOINFO 0x27 +#define C_NODEINFO 0x28 +#define C_GETCFG 0x29 +#define C_SETCFG 0x2a +#define C_FAILIO 0x2b +#define C_OUTFCPIO 0x2c +#define C_RSTQDEPTH 0x2d +#define C_CT 0x2e +#define C_HBA_ADAPTERATRIBUTES 0x33 +#define C_HBA_PORTATRIBUTES 0x34 +#define C_HBA_PORTSTATISTICS 0x35 +#define C_HBA_DISCPORTATRIBUTES 0x36 +#define C_HBA_WWPNPORTATRIBUTES 0x37 +#define C_HBA_INDEXPORTATRIBUTES 0x38 +#define C_HBA_FCPTARGETMAPPING 0x39 +#define C_HBA_FCPBINDING 0x3a +#define C_HBA_SETMGMTINFO 0x3b +#define C_HBA_GETMGMTINFO 0x3c +#define C_HBA_RNID 0x3d +#define C_HBA_GETEVENT 0x3e +#define C_HBA_RESETSTAT 0x3f +#define C_HBA_SEND_SCSI 0x40 +#define C_HBA_REFRESHINFO 0x41 +#define C_SEND_ELS 0x42 +#define C_LISTN 0x45 +#define C_TRACE 0x46 +#define C_HELP 0x47 +#define C_HBA_SEND_FCP 0x48 +#define C_SET_EVENT 0x49 +#define C_GET_EVENT 0x4a +#define C_SEND_MGMT_CMD 0x4b +#define C_SEND_MGMT_RSP 0x4c +#define C_LISTEVT 0x59 +#define C_MAX_CMDS 0x5a + +#define DFC_MBX_MAX_CMDS 29 + +/* Structure for OUTFCPIO command */ +struct out_fcp_io { + ushort tx_count; + ushort txp_count; + ushort timeout_count; + ushort devp_count; + void * tx_head; + void * tx_tail; + void * txp_head; + void * txp_tail; + void * timeout_head; +}; + +struct out_fcp_devp { + ushort target; + ushort lun; + uint32 standby_count; + uint32 pend_count; + uint32 clear_count; + void *standby_queue_head; + void *standby_queue_tail; + void *pend_head; + void *pend_tail; + void *clear_head; +}; + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/dfcdd.c 830-ivtv/drivers/scsi/lpfc/dfcdd.c --- 000-virgin/drivers/scsi/lpfc/dfcdd.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/dfcdd.c Thu Jan 8 10:21:53 2004 @@ -0,0 +1,4595 @@ + +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Enterprise Fibre Channel Host Bus Adapters. * + * Refer to the README file included with this package for * + * driver version and adapter support. * + * Copyright (C) 2003 Emulex Corporation. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details, a copy of which * + * can be found in the file COPYING included with this package. * + *******************************************************************/ + +#include "dfc.h" + +/*************************************************************************/ +/* Global data structures */ +/*************************************************************************/ + + int rc = 0; + int do_cp = 0; + +#ifdef DFC_SUBSYSTEM + +struct dfc { + uint32 dfc_init; + uint32 dfc_pad; + uchar dfc_buffer[4096]; + struct dfc_info dfc_info[MAX_FC_BRDS]; +}; + +_static_ struct dfc dfc; + +struct dfc_mem { + uint32 fc_outsz; + uint32 fc_filler; + void * fc_dataout; +}; + +extern uint32 fc_dbg_flag; +uint32 fc_out_event = 4; + +/* Routine Declaration - Local */ +_local_ fc_dev_ctl_t * dfc_getpdev(struct cmd_input *ci); +_local_ int dfc_msdelay(fc_dev_ctl_t *p, ulong ms); +_local_ int dfc_issue_mbox( fc_dev_ctl_t *p, MAILBOX * mb, ulong *ipri); +_local_ DMATCHMAP * dfc_cmd_data_alloc(fc_dev_ctl_t *p, uchar *inp, ULP_BDE64 *bpl, uint32 size); +_local_ int dfc_cmd_data_free(fc_dev_ctl_t *p, DMATCHMAP *mlist); +_local_ int dfc_rsp_data_copy(fc_dev_ctl_t *p, uchar * op, DMATCHMAP *mlist, uint32 size); +_local_ DMATCHMAP * dfc_fcp_data_alloc(fc_dev_ctl_t *p, ULP_BDE64 *bpl); +_local_ int dfc_fcp_data_free(fc_dev_ctl_t *p, DMATCHMAP *fcpmp); +_forward_ int dfc_data_alloc(fc_dev_ctl_t * p_dev_ctl, struct dfc_mem *dm, uint32 size); +_forward_ int dfc_hba_rnid(fc_dev_ctl_t * p_dev_ctl, struct dfc_mem *dm, struct cmd_input *cip, struct dfccmdinfo *infop, MBUF_INFO *buf_info, ulong ipri); +_forward_ int dfc_hba_sendmgmt_ct(fc_dev_ctl_t * p_dev_ctl, struct dfc_mem *dm, struct cmd_input *cip, struct dfccmdinfo *infop, ulong ipri); +_forward_ int dfc_hba_fcpbind(fc_dev_ctl_t * p_dev_ctl, struct dfc_mem *dm, struct cmd_input *cip, struct dfccmdinfo *infop, ulong ipri); +_forward_ int dfc_hba_targetmapping(fc_dev_ctl_t * p_dev_ctl, struct dfc_mem *dm, struct cmd_input *cip, struct dfccmdinfo *infop, ulong ipri); +_forward_ int dfc_hba_sendscsi_fcp(fc_dev_ctl_t * p_dev_ctl, struct dfc_mem *dm, struct cmd_input *cip, struct dfccmdinfo *infop, ulong ipri); +_forward_ int dfc_hba_set_event(fc_dev_ctl_t * p_dev_ctl, struct dfc_mem *dm, struct cmd_input *cip, struct dfccmdinfo *infop, ulong ipri); +_forward_ int dfc_data_free(fc_dev_ctl_t * p_dev_ctl, struct dfc_mem *dm); +_forward_ uint32 dfc_getLunId(node_t *nodep, uint32 lunIndex); +/* End Routine Declaration - Local */ + +/*****************************************************************************/ +/* + * NAME: dfc_ioctl + * + * FUNCTION: diagnostic ioctl interface + * + * EXECUTION ENVIRONMENT: process only + * + * NOTES: + * + * CALLED FROM: + * dfc_config + * + * RETURNS: + * 0 - successful + * EINVAL - invalid parameter was passed + * + */ +/*****************************************************************************/ +_static_ int +dfc_ioctl( +struct dfccmdinfo *infop, +struct cmd_input *cip) +{ + uint32 outshift; + int i, j; /* loop index */ + ulong ipri; + int max; + FC_BRD_INFO * binfo; + uint32 * lptr; + MBUF_INFO * buf_info; + MBUF_INFO * dmdata_info; + MBUF_INFO * mbox_info; + uchar * bp; + uint32 incr; + uint32 size; + uint32 buf1sz; + int total_mem; + uint32 offset; + uint32 cnt; + NODELIST * nlp; + node_t * nodep; + dvi_t * dev_ptr; + void * ioa; + fc_dev_ctl_t * p_dev_ctl; + iCfgParam * clp; + RING * rp; + MAILBOX * mb; + MATCHMAP * mm; + node_t * node_ptr; + fcipbuf_t * fbp; + struct out_fcp_io * fp; + struct out_fcp_devp * dp; + struct dfc_info * di; + struct dfc_mem * dm; + HBA_PORTATTRIBUTES * hp; + fc_vpd_t * vp; + MAILBOX * mbox; + MBUF_INFO bufinfo; + + if ((p_dev_ctl = dfc_getpdev(cip)) == 0) { + return(EINVAL); + } + + binfo = &BINFO; + cnt = binfo->fc_brd_no; + clp = DD_CTL.p_config[cnt]; + di = &dfc.dfc_info[cip->c_brd]; + buf_info = &bufinfo; + + dmdata_info = &bufinfo; + dmdata_info->virt = 0; + dmdata_info->phys = 0; + dmdata_info->flags = (FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + dmdata_info->align = sizeof(void *); + dmdata_info->size = sizeof(* dm); + dmdata_info->dma_handle = 0; + fc_malloc(p_dev_ctl, dmdata_info); + if (buf_info->virt == NULL) { + return (ENOMEM); + } + dm = (struct dfc_mem *)dmdata_info->virt; + fc_bzero((void *)dm, sizeof(struct dfc_mem)); + + mbox_info = &bufinfo; + mbox_info->virt = 0; + mbox_info->phys = 0; + mbox_info->flags = (FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + mbox_info->align = sizeof(void *); + mbox_info->size = sizeof(* mbox); + mbox_info->dma_handle = 0; + fc_malloc(p_dev_ctl, mbox_info); + if (mbox_info->virt == NULL) { + return (ENOMEM); + } + mbox = (MAILBOX *)mbox_info->virt; + + + /* dfc_ioctl entry */ + + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0400, /* ptr to msg structure */ + fc_mes0400, /* ptr to msg */ + fc_msgBlk0400.msgPreambleStr, /* begin varargs */ + infop->c_cmd, + (uint32)((ulong)cip->c_arg1), + (uint32)((ulong)cip->c_arg2), + infop->c_outsz); /* end varargs */ + + outshift = 0; + if(infop->c_outsz) { + if(infop->c_outsz <= (64 * 1024)) + total_mem = infop->c_outsz; + else + total_mem = 64 * 1024; + if(dfc_data_alloc(p_dev_ctl, dm, total_mem)) { + return(ENOMEM); + } + } + else { + /* Allocate memory for ioctl data */ + if(dfc_data_alloc(p_dev_ctl, dm, 4096)) { + return(ENOMEM); + } + total_mem = 4096; + } + + /* Make sure driver instance is attached */ + if(p_dev_ctl != DD_CTL.p_dev[cnt]) { + return(ENODEV); + } + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + di->fc_refcnt++; + + + switch (infop->c_cmd) { + /* Diagnostic Interface Library Support */ + + case C_WRITE_PCI: + offset = (uint32)((ulong)cip->c_arg1); + if (!(binfo->fc_flag & FC_OFFLINE_MODE)) { + rc = EPERM; + break; + } + if (offset > 255) { + rc = ERANGE; + break; + } + cnt = (uint32)((ulong)cip->c_arg2); + if ((cnt + offset) > 256) { + rc = ERANGE; + break; + } + + dfc_unlock_enable(ipri, &CMD_LOCK); + if (fc_copyin((uchar *)infop->c_dataout, (uchar *)dfc.dfc_buffer, (ulong)cnt)) { + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + rc = EIO; + break; + } + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + rc = fc_writepci(di, offset, (char *)dfc.dfc_buffer, (cnt >> 2)); + break; + + case C_READ_PCI: + offset = (uint32)((ulong)cip->c_arg1); + if (offset > 255) { + rc = ERANGE; + break; + } + cnt = (uint32)((ulong)cip->c_arg2); + if ((cnt + offset) > 256) { + rc = ERANGE; + break; + } + rc = fc_readpci(di, offset, (char *)dm->fc_dataout, (cnt >> 2)); + break; + + case C_WRITE_MEM: + offset = (uint32)((ulong)cip->c_arg1); + if (!(binfo->fc_flag & FC_OFFLINE_MODE)) { + if (offset != 256) { + rc = EPERM; + break; + } + if (cnt > 128) { + rc = EPERM; + break; + } + } + if (offset >= 4096) { + rc = ERANGE; + break; + } + cnt = (uint32)((ulong)cip->c_arg2); + if ((cnt + offset) > 4096) { + rc = ERANGE; + break; + } + + dfc_unlock_enable(ipri, &CMD_LOCK); + if (fc_copyin((uchar *)infop->c_dataout, (uchar *)dfc.dfc_buffer, (ulong)cnt)) { + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + rc = EIO; + break; + } + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + binfo = &BINFO; + if ((binfo->fc_flag & FC_SLI2) && (!(binfo->fc_flag & FC_OFFLINE_MODE))) { + fc_pcimem_bcopy((uint32 * )dfc.dfc_buffer, + (uint32 * )(((char *)(binfo->fc_slim2.virt)) + offset), cnt); + } else { + ioa = (void *)FC_MAP_MEM(&di->fc_iomap_mem); /* map in slim */ + WRITE_SLIM_COPY(binfo, (uint32 * )dfc.dfc_buffer, + (volatile uint32 * )((volatile char *)ioa + offset), + (cnt / sizeof(uint32))); + FC_UNMAP_MEMIO(ioa); + } + + break; + + case C_READ_MEM: + offset = (uint32)((ulong)cip->c_arg1); + if (offset >= 4096) { + rc = ERANGE; + break; + } + cnt = (uint32)((ulong)cip->c_arg2); + if ((cnt + offset) > 4096) { + rc = ERANGE; + break; + } + + binfo = &BINFO; + if ((binfo->fc_flag & FC_SLI2) && (!(binfo->fc_flag & FC_OFFLINE_MODE))) { + fc_pcimem_bcopy((uint32 * )(((char *)(binfo->fc_slim2.virt)) + offset), + (uint32 * )dm->fc_dataout, cnt); + } else { + ioa = (void *)FC_MAP_MEM(&di->fc_iomap_mem); /* map in slim */ + READ_SLIM_COPY(binfo, (uint32 * )dm->fc_dataout, + (volatile uint32 * )((volatile char *)ioa + offset), + (cnt / sizeof(uint32))); + FC_UNMAP_MEMIO(ioa); + } + break; + + case C_WRITE_CTLREG: + offset = (uint32)((ulong)cip->c_arg1); + if (!(binfo->fc_flag & FC_OFFLINE_MODE)) { + rc = EPERM; + break; + } + if (offset > 255) { + rc = ERANGE; + break; + } + incr = (uint32)((ulong)cip->c_arg2); + ioa = (void *)FC_MAP_IO(&di->fc_iomap_io); /* map in io registers */ + WRITE_CSR_REG(binfo, + ((volatile uint32 * )((volatile char *)ioa + (offset))), incr); + FC_UNMAP_MEMIO(ioa); + + break; + + case C_READ_CTLREG: + offset = (uint32)((ulong)cip->c_arg1); + if (offset > 255) { + rc = ERANGE; + break; + } + ioa = (void *)FC_MAP_IO(&di->fc_iomap_io); /* map in io registers */ + incr = READ_CSR_REG(binfo, + ((volatile uint32 * )((volatile char *)ioa + (offset)))); + FC_UNMAP_MEMIO(ioa); + *((uint32 * )dm->fc_dataout) = incr; + break; + + case C_INITBRDS: + dfc_unlock_enable(ipri, &CMD_LOCK); + if (fc_copyin((uchar*)infop->c_dataout, (uchar*)&di->fc_ba, sizeof(brdinfo))) { + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + rc = EIO; + break; + } + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + if (fc_initpci(di, p_dev_ctl)) { + rc = EIO; + break; + } + if (binfo->fc_flag & FC_OFFLINE_MODE) + di->fc_ba.a_offmask |= OFFDI_OFFLINE; + + fc_bcopy((uchar * ) & di->fc_ba, dm->fc_dataout, sizeof(brdinfo)); + infop->c_outsz = sizeof(brdinfo); + break; + + case C_SETDIAG: + dfc_unlock_enable(ipri, &CMD_LOCK); + offset = (uint32)((ulong)cip->c_arg1); + switch (offset) { + case DDI_ONDI: + if (fc_diag_state == DDI_OFFDI) { + fc_online(0); + } + *((uint32 * )(dm->fc_dataout)) = fc_diag_state; + break; + case DDI_OFFDI: + if (fc_diag_state == DDI_ONDI) { + fc_offline(0); + } + *((uint32 * )(dm->fc_dataout)) = fc_diag_state; + break; + case DDI_SHOW: + *((uint32 * )(dm->fc_dataout)) = fc_diag_state; + break; + case DDI_BRD_ONDI: + if (binfo->fc_flag & FC_OFFLINE_MODE) { + fc_online(p_dev_ctl); + } + *((uint32 * )(dm->fc_dataout)) = DDI_ONDI; + break; + case DDI_BRD_OFFDI: + if (!(binfo->fc_flag & FC_OFFLINE_MODE)) { + fc_offline(p_dev_ctl); + } + *((uint32 * )(dm->fc_dataout)) = DDI_OFFDI; + break; + case DDI_BRD_SHOW: + if (binfo->fc_flag & FC_OFFLINE_MODE) { + *((uint32 * )(dm->fc_dataout)) = DDI_OFFDI; + } + else { + *((uint32 * )(dm->fc_dataout)) = DDI_ONDI; + } + break; + default: + rc = ERANGE; + break; + } + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + break; + + case C_LIP: + binfo = &BINFO; + mb = (MAILBOX * )mbox; + fc_bzero((void *)mb, sizeof(MAILBOX)); + + if ((binfo->fc_ffstate == FC_READY) && (binfo->fc_process_LA)) { + /* Turn off link attentions */ + binfo->fc_process_LA = 0; + ioa = (void *)FC_MAP_IO(&binfo->fc_iomap_io); /* map in io registers */ + offset = READ_CSR_REG(binfo, FC_HC_REG(binfo, ioa)); + offset &= ~HC_LAINT_ENA; + WRITE_CSR_REG(binfo, FC_HC_REG(binfo, ioa), offset); + FC_UNMAP_MEMIO(ioa); + + switch (clp[CFG_TOPOLOGY].a_current) { + case FLAGS_TOPOLOGY_MODE_LOOP_PT: + mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_LOOP; + mb->un.varInitLnk.link_flags |= FLAGS_TOPOLOGY_FAILOVER; + break; + case FLAGS_TOPOLOGY_MODE_PT_PT: + mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_PT_PT; + break; + case FLAGS_TOPOLOGY_MODE_LOOP: + mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_LOOP; + break; + case FLAGS_TOPOLOGY_MODE_PT_LOOP: + mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_PT_PT; + mb->un.varInitLnk.link_flags |= FLAGS_TOPOLOGY_FAILOVER; + break; + } + + vp = &VPD; + if (binfo->fc_flag & FC_2G_CAPABLE) { + if ((vp->rev.feaLevelHigh >= 0x02) && + (clp[CFG_LINK_SPEED].a_current > 0)) { + mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED; + mb->un.varInitLnk.link_speed = clp[CFG_LINK_SPEED].a_current; + } + } + mb->mbxCommand = MBX_INIT_LINK; + mb->mbxOwner = OWN_HOST; + goto mbxbegin; + } + mb->mbxStatus = MBXERR_ERROR; + fc_bcopy((char *) & mb->mbxStatus, dm->fc_dataout, sizeof(ushort)); + break; + + case C_FAILIO: + { + uint32 tgt; + uint32 lun; + uint32 dev_index; + + binfo = &BINFO; + i = (uint32)((ulong)cip->c_arg1); + tgt = (uint32)((ulong)cip->c_arg2); + lun = (uint32)((ulong)cip->c_arg3); + switch(i) { + case 1: + fc_failio(p_dev_ctl); + break; + case 2: /* stop */ + dev_index = INDEX(0, tgt); + dev_ptr = fc_find_lun(binfo, dev_index, lun); + if(dev_ptr == 0) { + rc = ERANGE; + goto out; + } + dev_ptr->stop_send_io = 1; + break; + case 3: /* start */ + dev_index = INDEX(0, tgt); + dev_ptr = fc_find_lun(binfo, dev_index, lun); + if(dev_ptr == 0) { + rc = ERANGE; + goto out; + } + if(dev_ptr->stop_send_io == 1) { + dev_ptr->stop_send_io = 0; + fc_restart_device(dev_ptr); + } + break; + } + break; + } + + case C_RSTQDEPTH: + fc_reset_dev_q_depth(p_dev_ctl); + break; + + case C_OUTFCPIO: + { + max = (infop->c_outsz / sizeof(struct out_fcp_devp)) - 1; + + binfo = &BINFO; + fp = (struct out_fcp_io *)dm->fc_dataout; + dp = (struct out_fcp_devp *)((uchar *)fp + sizeof(struct out_fcp_io)); + rp = &binfo->fc_ring[FC_FCP_RING]; + fp->tx_head = rp->fc_tx.q_first; + fp->tx_tail = rp->fc_tx.q_last; + fp->txp_head = rp->fc_txp.q_first; + fp->txp_tail = rp->fc_txp.q_last; + fp->tx_count = rp->fc_tx.q_cnt; + fp->txp_count = rp->fc_txp.q_cnt; + fp->timeout_head = p_dev_ctl->timeout_head; + fp->timeout_count = p_dev_ctl->timeout_count; + fp->devp_count = 0; + for (i = 0; i < MAX_FC_TARGETS; i++) { + if ((node_ptr = binfo->device_queue_hash[i].node_ptr) != NULL) { + for (dev_ptr = node_ptr->lunlist; dev_ptr != NULL; + dev_ptr = dev_ptr->next) { + if(fp->devp_count++ >= max) + goto outio; + dp->target = dev_ptr->nodep->scsi_id; + dp->lun = (ushort)(dev_ptr->lun_id); + dp->standby_queue_head = dev_ptr->standby_queue_head; + dp->standby_queue_tail = dev_ptr->standby_queue_tail; + dp->standby_count = dev_ptr->standby_count; + dp->pend_head = dev_ptr->pend_head; + dp->pend_tail = dev_ptr->pend_tail; + dp->pend_count = dev_ptr->pend_count; + dp->clear_head = dev_ptr->clear_head; + dp->clear_count = dev_ptr->clear_count; + dp++; + } + } + } +outio: + infop->c_outsz = (sizeof(struct out_fcp_io) + + (fp->devp_count * sizeof(struct out_fcp_devp))); + } + break; + + case C_HBA_SEND_SCSI: + case C_HBA_SEND_FCP: + ipri = dfc_hba_sendscsi_fcp(p_dev_ctl, dm, cip, infop, ipri); + break; + + case C_SEND_ELS: + { + uint32 did; + uint32 opcode; + + binfo = &BINFO; + did = (uint32)((ulong)cip->c_arg1); + opcode = (uint32)((ulong)cip->c_arg2); + did = (did & Mask_DID); + + if(((nlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, did))) == 0) { + if((nlp = (NODELIST *)fc_mem_get(binfo, MEM_NLP))) { + fc_bzero((void *)nlp, sizeof(NODELIST)); + nlp->sync = binfo->fc_sync; + nlp->capabilities = binfo->fc_capabilities; + nlp->nlp_DID = did; + nlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, nlp); + } + else { + rc = ENOMEM; + break; + } + } + + fc_els_cmd(binfo, opcode, (void *)((ulong)did), (uint32)0, (ushort)0, nlp); + } + break; + + case C_SEND_MGMT_RSP: + { + ULP_BDE64 * bpl; + MATCHMAP * bmp; + DMATCHMAP * indmp; + uint32 tag; + + tag = (uint32)cip->c_flag; /* XRI for XMIT_SEQUENCE */ + buf1sz = (uint32)((ulong)cip->c_arg2); + + if((buf1sz == 0) || + (buf1sz > (80 * 4096))) { + rc = ERANGE; + goto out; + } + + /* Allocate buffer for Buffer ptr list */ + if ((bmp = (MATCHMAP * )fc_mem_get(binfo, MEM_BPL)) == 0) { + rc = ENOMEM; + goto out; + } + bpl = (ULP_BDE64 * )bmp->virt; + dfc_unlock_enable(ipri, &CMD_LOCK); + + if((indmp = dfc_cmd_data_alloc(p_dev_ctl, (uchar *)cip->c_arg1, bpl, buf1sz)) == 0) { + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + fc_mem_put(binfo, MEM_BPL, (uchar * )bmp); + rc = ENOMEM; + goto out; + } + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + if((rc=fc_issue_ct_rsp(binfo, tag, bmp, indmp))) { + if(rc == ENODEV) + rc = EACCES; + goto xmout1; + } + + j = 0; + dfc_unlock_enable(ipri, &CMD_LOCK); + dfc_msdelay(p_dev_ctl, 1); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + /* Wait for CT request to complete or timeout */ + while(indmp->dfc_flag == 0) { + dfc_unlock_enable(ipri, &CMD_LOCK); + dfc_msdelay(p_dev_ctl, 50); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + if(j >= 600) { + indmp->dfc_flag = -1; + break; + } + j++; + } + + j = indmp->dfc_flag; + if(j == -1) { + rc = ETIMEDOUT; + } + +xmout1: + dfc_unlock_enable(ipri, &CMD_LOCK); + dfc_cmd_data_free(p_dev_ctl, indmp); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + fc_mem_put(binfo, MEM_BPL, (uchar * )bmp); + } + break; + + case C_SEND_MGMT_CMD: + case C_CT: + ipri = dfc_hba_sendmgmt_ct(p_dev_ctl, dm, cip, infop, ipri); + break; + + case C_MBOX: + binfo = &BINFO; + mb = (MAILBOX * )mbox; + + dfc_unlock_enable(ipri, &CMD_LOCK); + if (fc_copyin((uchar *)cip->c_arg1, (uchar *)mb, + MAILBOX_CMD_WSIZE * sizeof(uint32))) { + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + rc = EIO; + goto out; + } + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + +mbxbegin: + + cnt = 0; + while ((binfo->fc_mbox_active) || (di->fc_flag & DFC_MBOX_ACTIVE)) { + dfc_unlock_enable(ipri, &CMD_LOCK); + dfc_msdelay(p_dev_ctl, 5); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + if(cnt++ == 200) + break; + } + + if (cnt >= 200) { + mb->mbxStatus = MBXERR_ERROR; + } + else { + binfo->fc_mbox_active = 2; +#ifdef _LP64 + if((mb->mbxCommand == MBX_READ_SPARM) || + (mb->mbxCommand == MBX_READ_RPI) || + (mb->mbxCommand == MBX_REG_LOGIN) || + (mb->mbxCommand == MBX_READ_LA)) { + mb->mbxStatus = MBXERR_ERROR; + rc = ENODEV; + binfo->fc_mbox_active = 0; + goto mbout; + } +#endif + lptr = 0; + size = 0; + switch (mb->mbxCommand) { + /* Offline only */ + case MBX_WRITE_NV: + case MBX_INIT_LINK: + case MBX_DOWN_LINK: + case MBX_CONFIG_LINK: + case MBX_PART_SLIM: + case MBX_CONFIG_RING: + case MBX_RESET_RING: + case MBX_UNREG_LOGIN: + case MBX_CLEAR_LA: + case MBX_DUMP_CONTEXT: + case MBX_RUN_DIAGS: + case MBX_RESTART: + case MBX_FLASH_WR_ULA: + case MBX_SET_MASK: + case MBX_SET_SLIM: + case MBX_SET_DEBUG: + if (!(binfo->fc_flag & FC_OFFLINE_MODE)) { + if (infop->c_cmd != C_LIP) { + mb->mbxStatus = MBXERR_ERROR; + binfo->fc_mbox_active = 0; + goto mbout; + } + } + break; + + /* Online / Offline */ + case MBX_LOAD_SM: + case MBX_READ_NV: + case MBX_READ_CONFIG: + case MBX_READ_RCONFIG: + case MBX_READ_STATUS: + case MBX_READ_XRI: + case MBX_READ_REV: + case MBX_READ_LNK_STAT: + case MBX_DUMP_MEMORY: + case MBX_DOWN_LOAD: + case MBX_UPDATE_CFG: + case MBX_LOAD_AREA: + case MBX_LOAD_EXP_ROM: + break; + + /* Offline only - with DMA */ + case MBX_REG_LOGIN: + if (!(binfo->fc_flag & FC_OFFLINE_MODE)) { + mb->mbxStatus = MBXERR_ERROR; + binfo->fc_mbox_active = 0; + goto mbout; + } + lptr = (uint32 * )((ulong)mb->un.varRegLogin.un.sp.bdeAddress); + size = (int)mb->un.varRegLogin.un.sp.bdeSize; + if (lptr) { + buf_info->virt = (void * )dfc.dfc_buffer; + buf_info->flags = (FC_MBUF_PHYSONLY | FC_MBUF_DMA | + FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + buf_info->align = DMA_READ; + buf_info->size = sizeof(SERV_PARM); + buf_info->dma_handle = 0; + + dfc_unlock_enable(ipri, &CMD_LOCK); + fc_malloc(p_dev_ctl, buf_info); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + if (buf_info->phys == NULL) { + mb->mbxStatus = MBXERR_ERROR; + binfo->fc_mbox_active = 0; + goto mbout; + } + mb->un.varRegLogin.un.sp.bdeAddress = + (uint32)putPaddrLow(buf_info->phys); + } + break; + case MBX_RUN_BIU_DIAG: + if (!(binfo->fc_flag & FC_OFFLINE_MODE)) { + mb->mbxStatus = MBXERR_ERROR; + binfo->fc_mbox_active = 0; + goto mbout; + } + mb->mbxStatus = MBXERR_ERROR; + binfo->fc_mbox_active = 0; + goto mbout; + + /* Online / Offline - with DMA */ + case MBX_READ_SPARM64: + if (!((binfo->fc_flag & FC_SLI2) && (!(binfo->fc_flag & FC_OFFLINE_MODE)))) { + mb->mbxStatus = MBXERR_ERROR; + binfo->fc_mbox_active = 0; + goto mbout; + } + case MBX_READ_SPARM: + if ((binfo->fc_flag & FC_SLI2) && (!(binfo->fc_flag & FC_OFFLINE_MODE))) { + if (mb->mbxCommand == MBX_READ_SPARM) { + mb->mbxStatus = MBXERR_ERROR; + binfo->fc_mbox_active = 0; + goto mbout; + } + lptr = (uint32 * )getPaddr(mb->un.varRdSparm.un.sp64.addrHigh, + mb->un.varRdSparm.un.sp64.addrLow); + size = (int)mb->un.varRdSparm.un.sp64.tus.f.bdeSize; + } else { + lptr = (uint32 * )((ulong)mb->un.varRdSparm.un.sp.bdeAddress); + size = (int)mb->un.varRdSparm.un.sp.bdeSize; + } + if (lptr) { + buf_info->virt = (void * )dfc.dfc_buffer; + buf_info->flags = (FC_MBUF_PHYSONLY | FC_MBUF_DMA | + FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + buf_info->align = DMA_READ; + buf_info->size = sizeof(SERV_PARM); + buf_info->dma_handle = 0; + buf_info->phys = 0; + + dfc_unlock_enable(ipri, &CMD_LOCK); + fc_malloc(p_dev_ctl, buf_info); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + if (buf_info->phys == NULL) { + mb->mbxStatus = MBXERR_ERROR; + binfo->fc_mbox_active = 0; + goto mbout; + } + if ((binfo->fc_flag & FC_SLI2) && (!(binfo->fc_flag & FC_OFFLINE_MODE))) { + mb->un.varRdSparm.un.sp64.addrHigh = + (uint32)putPaddrHigh(buf_info->phys); + mb->un.varRdSparm.un.sp64.addrLow = + (uint32)putPaddrLow(buf_info->phys); + } + else + mb->un.varRdSparm.un.sp.bdeAddress = + (uint32)putPaddrLow(buf_info->phys); + } + break; + case MBX_READ_RPI64: + if (!((binfo->fc_flag & FC_SLI2) && (!(binfo->fc_flag & FC_OFFLINE_MODE)))) { + mb->mbxStatus = MBXERR_ERROR; + binfo->fc_mbox_active = 0; + goto mbout; + } + case MBX_READ_RPI: + if ((binfo->fc_flag & FC_SLI2) && (!(binfo->fc_flag & FC_OFFLINE_MODE))) { + if (mb->mbxCommand == MBX_READ_RPI) { + mb->mbxStatus = MBXERR_ERROR; + binfo->fc_mbox_active = 0; + goto mbout; + } + lptr = (uint32 * )getPaddr(mb->un.varRdRPI.un.sp64.addrHigh, + mb->un.varRdRPI.un.sp64.addrLow); + size = (int)mb->un.varRdRPI.un.sp64.tus.f.bdeSize; + } else { + lptr = (uint32 * )((ulong)mb->un.varRdRPI.un.sp.bdeAddress); + size = (int)mb->un.varRdRPI.un.sp.bdeSize; + } + if (lptr) { + buf_info->virt = (void * )dfc.dfc_buffer; + buf_info->flags = (FC_MBUF_PHYSONLY | FC_MBUF_DMA | + FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + buf_info->align = DMA_READ; + buf_info->size = sizeof(SERV_PARM); + buf_info->dma_handle = 0; + + dfc_unlock_enable(ipri, &CMD_LOCK); + fc_malloc(p_dev_ctl, buf_info); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + if (buf_info->phys == NULL) { + mb->mbxStatus = MBXERR_ERROR; + binfo->fc_mbox_active = 0; + goto mbout; + } + if ((binfo->fc_flag & FC_SLI2) && (!(binfo->fc_flag & FC_OFFLINE_MODE))) { + mb->un.varRdRPI.un.sp64.addrHigh = + (uint32)putPaddrHigh(buf_info->phys); + mb->un.varRdRPI.un.sp64.addrLow = + (uint32)putPaddrLow(buf_info->phys); + } + else + mb->un.varRdRPI.un.sp.bdeAddress = + (uint32)putPaddrLow(buf_info->phys); + } + break; + case MBX_READ_LA: + if (!(binfo->fc_flag & FC_OFFLINE_MODE)) { + mb->mbxStatus = MBXERR_ERROR; + binfo->fc_mbox_active = 0; + goto mbout; + } + lptr = (uint32 * )((ulong)mb->un.varReadLA.un.lilpBde.bdeAddress); + size = (int)mb->un.varReadLA.un.lilpBde.bdeSize; + if (lptr) { + buf_info->virt = (void * )dfc.dfc_buffer; + buf_info->flags = (FC_MBUF_PHYSONLY | FC_MBUF_DMA | + FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + buf_info->align = DMA_READ; + buf_info->size = 128; + buf_info->dma_handle = 0; + + dfc_unlock_enable(ipri, &CMD_LOCK); + fc_malloc(p_dev_ctl, buf_info); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + if (buf_info->phys == NULL) { + mb->mbxStatus = MBXERR_ERROR; + binfo->fc_mbox_active = 0; + goto mbout; + } + mb->un.varReadLA.un.lilpBde.bdeAddress = + (uint32)putPaddrLow(buf_info->phys); + } + break; + + case MBX_CONFIG_PORT: + case MBX_REG_LOGIN64: + case MBX_READ_LA64: + mb->mbxStatus = MBXERR_ERROR; + binfo->fc_mbox_active = 0; + goto mbout; + + default: + if (!(binfo->fc_flag & FC_OFFLINE_MODE)) { + mb->mbxStatus = MBXERR_ERROR; + binfo->fc_mbox_active = 0; + goto mbout; + } + break; + } + + binfo->fc_mbox_active = 0; + if(dfc_issue_mbox(p_dev_ctl, mb, &ipri)) + goto mbout; + + if (lptr) { + buf_info->virt = 0; + buf_info->flags = (FC_MBUF_PHYSONLY | FC_MBUF_DMA | + FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + buf_info->dma_handle = 0; + switch (mb->mbxCommand) { + case MBX_REG_LOGIN: + buf_info->phys = (uint32 * ) + ((ulong)mb->un.varRegLogin.un.sp.bdeAddress); + buf_info->size = sizeof(SERV_PARM); + break; + + case MBX_READ_SPARM: + buf_info->phys = (uint32 * ) + ((ulong)mb->un.varRdSparm.un.sp.bdeAddress); + buf_info->size = sizeof(SERV_PARM); + break; + + case MBX_READ_RPI: + buf_info->phys = (uint32 * ) + ((ulong)mb->un.varRdRPI.un.sp.bdeAddress); + buf_info->size = sizeof(SERV_PARM); + break; + + case MBX_READ_LA: + buf_info->phys = (uint32 * ) + ((ulong)mb->un.varReadLA.un.lilpBde.bdeAddress); + buf_info->size = 128; + break; + } + + dfc_unlock_enable(ipri, &CMD_LOCK); + fc_free(p_dev_ctl, buf_info); + + if ((fc_copyout((uchar *)dfc.dfc_buffer, (uchar *)lptr, (ulong)size))) { + rc = EIO; + } + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + } + } + +mbout: + if (infop->c_cmd == C_LIP) { + /* Turn on Link Attention interrupts */ + binfo->fc_process_LA = 1; + ioa = (void *)FC_MAP_IO(&binfo->fc_iomap_io); /* map in io registers */ + offset = READ_CSR_REG(binfo, FC_HC_REG(binfo, ioa)); + offset |= HC_LAINT_ENA; + WRITE_CSR_REG(binfo, FC_HC_REG(binfo, ioa), offset); + FC_UNMAP_MEMIO(ioa); + } + + if (infop->c_cmd == C_LIP) + fc_bcopy((char *) & mb->mbxStatus, dm->fc_dataout, sizeof(ushort)); + else + fc_bcopy((char *)mb, dm->fc_dataout, MAILBOX_CMD_WSIZE * sizeof(uint32)); + break; + + + case C_DISPLAY_PCI_ALL: + + if ((rc = fc_readpci(di, 0, (char *)dm->fc_dataout, 64))) + break; + break; + + case C_SET: + if(cip->c_iocb == 0) { + bp = binfo->fc_portname.IEEE; + } + else { + cnt = 0; + bp = 0; + nlp = binfo->fc_nlpunmap_start; + if(nlp == (NODELIST *)&binfo->fc_nlpunmap_start) + nlp = binfo->fc_nlpmap_start; + while(nlp != (NODELIST *)&binfo->fc_nlpmap_start) { + if((int)cnt == cip->c_iocb-1) { + if ((nlp->nlp_type & NLP_IP_NODE) && (nlp->nlp_Rpi) && + (nlp->nlp_Xri)) { + bp = nlp->nlp_nodename.IEEE; + } + else { + bp = binfo->fc_portname.IEEE; + } + break; + } + cnt++; + nlp = (NODELIST *)nlp->nlp_listp_next; + if(nlp == (NODELIST *)&binfo->fc_nlpunmap_start) + nlp = binfo->fc_nlpmap_start; + } + } + break; + + case C_WRITE_HC: + incr = (uint32)((ulong)cip->c_arg1); + ioa = (void *)FC_MAP_IO(&di->fc_iomap_io); /* map in io registers */ + WRITE_CSR_REG(binfo, + ((volatile uint32 * )((volatile char *)ioa + (sizeof(uint32) * HC_REG_OFFSET))), incr); + FC_UNMAP_MEMIO(ioa); + case C_READ_HC: + ioa = (void *)FC_MAP_IO(&di->fc_iomap_io); /* map in io registers */ + offset = READ_CSR_REG(binfo, FC_HC_REG(binfo, ioa)); + FC_UNMAP_MEMIO(ioa); + + *((uint32 * )dm->fc_dataout) = offset; + break; + + case C_WRITE_HS: + incr = (uint32)((ulong)cip->c_arg1); + ioa = (void *)FC_MAP_IO(&di->fc_iomap_io); /* map in io registers */ + WRITE_CSR_REG(binfo, + ((volatile uint32 * )((volatile char *)ioa + (sizeof(uint32) * HS_REG_OFFSET))), incr); + FC_UNMAP_MEMIO(ioa); + case C_READ_HS: + ioa = (void *)FC_MAP_IO(&di->fc_iomap_io); /* map in io registers */ + offset = READ_CSR_REG(binfo, FC_STAT_REG(binfo, ioa)); + FC_UNMAP_MEMIO(ioa); + + *((uint32 * )dm->fc_dataout) = offset; + break; + + case C_WRITE_HA: + incr = (uint32)((ulong)cip->c_arg1); + ioa = (void *)FC_MAP_IO(&di->fc_iomap_io); /* map in io registers */ + WRITE_CSR_REG(binfo, + ((volatile uint32 * )((volatile char *)ioa + (sizeof(uint32) * HA_REG_OFFSET))), incr); + FC_UNMAP_MEMIO(ioa); + case C_READ_HA: + ioa = (void *)FC_MAP_IO(&di->fc_iomap_io); /* map in io registers */ + offset = READ_CSR_REG(binfo, FC_HA_REG(binfo, ioa)); + FC_UNMAP_MEMIO(ioa); + + *((uint32 * )dm->fc_dataout) = offset; + break; + + case C_WRITE_CA: + incr = (uint32)((ulong)cip->c_arg1); + ioa = (void *)FC_MAP_IO(&di->fc_iomap_io); /* map in io registers */ + WRITE_CSR_REG(binfo, + ((volatile uint32 * )((volatile char *)ioa + (sizeof(uint32) * CA_REG_OFFSET))), incr); + FC_UNMAP_MEMIO(ioa); + case C_READ_CA: + ioa = (void *)FC_MAP_IO(&di->fc_iomap_io); /* map in io registers */ + offset = READ_CSR_REG(binfo, FC_FF_REG(binfo, ioa)); + FC_UNMAP_MEMIO(ioa); + + *((uint32 * )dm->fc_dataout) = offset; + break; + + case C_READ_MB: + binfo = &BINFO; + if ((binfo->fc_flag & FC_SLI2) && (!(binfo->fc_flag & FC_OFFLINE_MODE))) { + mb = FC_SLI2_MAILBOX(binfo); + fc_pcimem_bcopy((uint32 * )mb, (uint32 * )dm->fc_dataout, 128); + } else { + ioa = (void *)FC_MAP_MEM(&di->fc_iomap_mem); /* map in slim */ + READ_SLIM_COPY(binfo, (uint32 * )dm->fc_dataout, (uint32 * )ioa, + MAILBOX_CMD_WSIZE); + FC_UNMAP_MEMIO(ioa); + } + break; + + case C_DBG: + offset = (uint32)((ulong)cip->c_arg1); + switch (offset) { + case 0xffffffff: + break; + default: + fc_dbg_flag = offset; + break; + } + + fc_bcopy((uchar * ) & fc_dbg_flag , dm->fc_dataout, sizeof(uint32)); + break; + + case C_INST: + fc_bcopy((uchar * ) &fcinstcnt, dm->fc_dataout, sizeof(int)); + fc_bcopy((uchar * ) fcinstance, ((uchar *)dm->fc_dataout) + sizeof(int), sizeof(int) * MAX_FC_BRDS); + break; + + case C_READ_RING: + fc_bcopy(&binfo->fc_ring[cip->c_ring], dm->fc_dataout, sizeof(RING)); + break; + + case C_LISTN: + { + NODELIST *npp; + ulong lcnt; + ulong *lcntp; + + offset = (uint32)((ulong)cip->c_arg1); + total_mem -= sizeof(NODELIST); + lcnt = 0; + switch (offset) { + case 1: /* bind */ + lcntp = dm->fc_dataout; + fc_bcopy((uchar * ) &lcnt , dm->fc_dataout, sizeof(ulong)); + npp = (NODELIST *)((char *)(dm->fc_dataout) + sizeof(ulong)); + nlp = binfo->fc_nlpbind_start; + while((nlp != (NODELIST *)&binfo->fc_nlpbind_start) && (total_mem > 0)) { + fc_bcopy((char *)nlp, npp, (sizeof(NODELIST))); + total_mem -= sizeof(NODELIST); + npp++; + lcnt++; + nlp = (NODELIST *)nlp->nlp_listp_next; + } + *lcntp = lcnt; + break; + case 2: /* unmap */ + lcntp = dm->fc_dataout; + fc_bcopy((uchar * ) &lcnt , dm->fc_dataout, sizeof(ulong)); + npp = (NODELIST *)((char *)(dm->fc_dataout) + sizeof(ulong)); + nlp = binfo->fc_nlpunmap_start; + while((nlp != (NODELIST *)&binfo->fc_nlpunmap_start) && (total_mem > 0)) { + fc_bcopy((char *)nlp, npp, (sizeof(NODELIST))); + total_mem -= sizeof(NODELIST); + npp++; + lcnt++; + nlp = (NODELIST *)nlp->nlp_listp_next; + } + *lcntp = lcnt; + break; + case 3: /* map */ + lcntp = dm->fc_dataout; + fc_bcopy((uchar * ) &lcnt , dm->fc_dataout, sizeof(ulong)); + npp = (NODELIST *)((char *)(dm->fc_dataout) + sizeof(ulong)); + nlp = binfo->fc_nlpmap_start; + while((nlp != (NODELIST *)&binfo->fc_nlpmap_start) && (total_mem > 0)) { + fc_bcopy((char *)nlp, npp, (sizeof(NODELIST))); + total_mem -= sizeof(NODELIST); + npp++; + lcnt++; + nlp = (NODELIST *)nlp->nlp_listp_next; + } + *lcntp = lcnt; + break; + case 4: /* all */ + lcntp = dm->fc_dataout; + fc_bcopy((uchar * ) &lcnt , dm->fc_dataout, sizeof(ulong)); + npp = (NODELIST *)((char *)(dm->fc_dataout) + sizeof(ulong)); + nlp = binfo->fc_nlpbind_start; + while((nlp != (NODELIST *)&binfo->fc_nlpbind_start) && (total_mem > 0)) { + fc_bcopy((char *)nlp, npp, (sizeof(NODELIST))); + total_mem -= sizeof(NODELIST); + npp++; + lcnt++; + nlp = (NODELIST *)nlp->nlp_listp_next; + } + nlp = binfo->fc_nlpunmap_start; + while((nlp != (NODELIST *)&binfo->fc_nlpunmap_start) && (total_mem > 0)) { + fc_bcopy((char *)nlp, npp, (sizeof(NODELIST))); + total_mem -= sizeof(NODELIST); + npp++; + lcnt++; + nlp = (NODELIST *)nlp->nlp_listp_next; + } + nlp = binfo->fc_nlpmap_start; + while((nlp != (NODELIST *)&binfo->fc_nlpmap_start) && (total_mem > 0)) { + fc_bcopy((char *)nlp, npp, (sizeof(NODELIST))); + total_mem -= sizeof(NODELIST); + npp++; + lcnt++; + nlp = (NODELIST *)nlp->nlp_listp_next; + } + *lcntp = lcnt; + break; + default: + rc = ERANGE; + break; + } + infop->c_outsz = (sizeof(ulong) + (lcnt * sizeof(NODELIST))); + break; + } + + case C_LISTEVT: + { + uint32 ehdcnt; + uint32 ecnt; + uint32 *ehdcntp; + uint32 *ecntp; + fcEvent *ep; + fcEvent_header *ehp; + + offset = (uint32)((ulong)cip->c_arg1); + total_mem -= sizeof(uint32); + infop->c_outsz = sizeof(uint32); + ehdcnt = 0; + ehdcntp = (uint32 *)dm->fc_dataout; + bp = (uchar *)((char *)(dm->fc_dataout) + sizeof(uint32)); + switch (offset) { + case 1: /* link */ + offset = FC_REG_LINK_EVENT; + break; + case 2: /* rscn */ + offset = FC_REG_RSCN_EVENT; + break; + case 3: /* ct */ + offset = FC_REG_CT_EVENT; + break; + case 7: /* all */ + offset = 0; + break; + default: + rc = ERANGE; + goto out; + } + ehp = (fcEvent_header *)p_dev_ctl->fc_evt_head; + while (ehp) { + if ((offset == 0) || (ehp->e_mask == offset)) { + ehdcnt++; + fc_bcopy((char *)ehp, bp, (sizeof(fcEvent_header))); + bp += (sizeof(fcEvent_header)); + total_mem -= sizeof(fcEvent_header); + if(total_mem <= 0) { + rc = ENOMEM; + goto out; + } + infop->c_outsz += sizeof(fcEvent_header); + ecnt = 0; + ecntp = (uint32 *)bp; + bp += (sizeof(uint32)); + total_mem -= sizeof(uint32); + infop->c_outsz += sizeof(uint32); + ep = ehp->e_head; + while(ep) { + ecnt++; + fc_bcopy((char *)ehp, bp, (sizeof(fcEvent))); + bp += (sizeof(fcEvent)); + total_mem -= sizeof(fcEvent); + if(total_mem <= 0) { + rc = ENOMEM; + goto out; + } + infop->c_outsz += sizeof(fcEvent); + ep = ep->evt_next; + } + *ecntp = ecnt; + } + ehp = (fcEvent_header *)ehp->e_next_header; + } + + *ehdcntp = ehdcnt; + break; + } + + case C_READ_RPILIST: + { + NODELIST *npp; + + cnt = 0; + npp = (NODELIST *)(dm->fc_dataout); + nlp = binfo->fc_nlpbind_start; + if(nlp == (NODELIST *)&binfo->fc_nlpbind_start) + nlp = binfo->fc_nlpunmap_start; + if(nlp == (NODELIST *)&binfo->fc_nlpunmap_start) + nlp = binfo->fc_nlpmap_start; + while((nlp != (NODELIST *)&binfo->fc_nlpmap_start) && (total_mem > 0)) { + fc_bcopy((char *)nlp, (char *)npp, sizeof(NODELIST)); + npp++; + cnt++; + nlp = (NODELIST *)nlp->nlp_listp_next; + if(nlp == (NODELIST *)&binfo->fc_nlpbind_start) + nlp = binfo->fc_nlpunmap_start; + if(nlp == (NODELIST *)&binfo->fc_nlpunmap_start) + nlp = binfo->fc_nlpmap_start; + } + if(cnt) { + infop->c_outsz = (uint32)(cnt * sizeof(NODELIST)); + } + } + break; + + case C_READ_BPLIST: + rp = &binfo->fc_ring[cip->c_ring]; + lptr = (uint32 * )dm->fc_dataout; + + mm = (MATCHMAP * )rp->fc_mpoff; + total_mem -= (3*sizeof(ulong)); + while ((mm) && (total_mem > 0)) { + if (cip->c_ring == FC_ELS_RING) { + *lptr++ = (uint32)((ulong)mm); + *lptr++ = (uint32)((ulong)mm->virt); + *lptr++ = (uint32)((ulong)mm->phys); + mm = (MATCHMAP * )mm->fc_mptr; + } + if (cip->c_ring == FC_IP_RING) { + fbp = (fcipbuf_t * )mm; + *lptr++ = (uint32)((ulong)fbp); + *lptr++ = (uint32)((ulong)fcdata(fbp)); + *lptr++ = (uint32)((ulong)fcnextpkt(fbp)); + mm = (MATCHMAP * )fcnextdata(fbp); + } + total_mem -= (3 * sizeof(ulong)); + } + *lptr++ = 0; + *lptr++ = (uint32)((ulong)rp->fc_mpon); + + infop->c_outsz = ((uchar * )lptr - (uchar *)(dm->fc_dataout)); + break; + + case C_READ_MEMSEG: + fc_bcopy(&binfo->fc_memseg, dm->fc_dataout, (sizeof(MEMSEG) * FC_MAX_SEG)); + break; + + case C_RESET: + offset = (uint32)((ulong)cip->c_arg1); + switch (offset) { + case 1: /* hba */ + fc_brdreset(p_dev_ctl); + break; + case 2: /* link */ + fc_rlip(p_dev_ctl); + break; + case 3: /* target */ + fc_fcp_abort(p_dev_ctl, TARGET_RESET, (int)((ulong)cip->c_arg2), -1); + break; + case 4: /* lun */ + fc_fcp_abort(p_dev_ctl, LUN_RESET, (int)((ulong)cip->c_arg2), + (int)((ulong)cip->c_arg3)); + break; + case 5: /* task set */ + fc_fcp_abort(p_dev_ctl, ABORT_TASK_SET, (int)((ulong)cip->c_arg2), + (int)((ulong)cip->c_arg3)); + break; + case 6: /* bus */ + fc_fcp_abort(p_dev_ctl, TARGET_RESET, -1, -1); + break; + default: + rc = ERANGE; + break; + } + break; + + case C_READ_BINFO: + case C_FC_STAT: + fc_bcopy(binfo, dm->fc_dataout, sizeof(FC_BRD_INFO)); + break; + + case C_NODE: + break; + + case C_DEVP: + offset = (uint32)((ulong)cip->c_arg1); + cnt = (uint32)((ulong)cip->c_arg2); + if ((offset >= (MAX_FC_TARGETS)) || (cnt >= 128)) { + rc = ERANGE; + break; + } + fc_bzero(dm->fc_dataout, (sizeof(dvi_t))+(sizeof(nodeh_t))+(sizeof(node_t))); + fc_bcopy((char *)&binfo->device_queue_hash[offset], (uchar *)dm->fc_dataout, (sizeof(nodeh_t))); + + nodep = binfo->device_queue_hash[offset].node_ptr; + if (nodep == 0) { + break; + } + dev_ptr = nodep->lunlist; + while ((dev_ptr != 0)) { + if(dev_ptr->lun_id == cnt) + break; + dev_ptr = dev_ptr->next; + } + if (dev_ptr == 0) { + break; + } + + fc_bcopy((char *)&binfo->device_queue_hash[offset], (uchar *)dm->fc_dataout, + (sizeof(nodeh_t))); + fc_bcopy((char *)nodep, ((uchar *)dm->fc_dataout + sizeof(nodeh_t)), + (sizeof(node_t))); + fc_bcopy((char *)dev_ptr, + ((uchar *)dm->fc_dataout + sizeof(nodeh_t) + sizeof(node_t)), + (sizeof(dvi_t))); + break; + + case C_NDD_STAT: + fc_bcopy(&NDDSTAT, dm->fc_dataout, sizeof(ndd_genstats_t)); + break; + + case C_LINKINFO: +linfo: + { + LinkInfo *linkinfo; + + linkinfo = (LinkInfo *)dm->fc_dataout; + linkinfo->a_linkEventTag = binfo->fc_eventTag; + linkinfo->a_linkUp = FCSTATCTR.LinkUp; + linkinfo->a_linkDown = FCSTATCTR.LinkDown; + linkinfo->a_linkMulti = FCSTATCTR.LinkMultiEvent; + linkinfo->a_DID = binfo->fc_myDID; + if (binfo->fc_topology == TOPOLOGY_LOOP) { + if(binfo->fc_flag & FC_PUBLIC_LOOP) { + linkinfo->a_topology = LNK_PUBLIC_LOOP; + fc_bcopy((uchar * )binfo->alpa_map, + (uchar *)linkinfo->a_alpaMap, 128); + linkinfo->a_alpaCnt = binfo->alpa_map[0]; + } + else { + linkinfo->a_topology = LNK_LOOP; + fc_bcopy((uchar * )binfo->alpa_map, + (uchar *)linkinfo->a_alpaMap, 128); + linkinfo->a_alpaCnt = binfo->alpa_map[0]; + } + } + else { + fc_bzero((uchar *)linkinfo->a_alpaMap, 128); + linkinfo->a_alpaCnt = 0; + if(binfo->fc_flag & FC_FABRIC) { + linkinfo->a_topology = LNK_FABRIC; + } + else { + linkinfo->a_topology = LNK_PT2PT; + } + } + linkinfo->a_linkState = 0; + switch (binfo->fc_ffstate) { + case FC_INIT_START: + case FC_INIT_NVPARAMS: + case FC_INIT_REV: + case FC_INIT_PARTSLIM: + case FC_INIT_CFGRING: + case FC_INIT_INITLINK: + case FC_LINK_DOWN: + linkinfo->a_linkState = LNK_DOWN; + fc_bzero((uchar *)linkinfo->a_alpaMap, 128); + linkinfo->a_alpaCnt = 0; + break; + case FC_LINK_UP: + case FC_INIT_SPARAM: + case FC_CFG_LINK: + linkinfo->a_linkState = LNK_UP; + break; + case FC_FLOGI: + linkinfo->a_linkState = LNK_FLOGI; + break; + case FC_LOOP_DISC: + case FC_NS_REG: + case FC_NS_QRY: + case FC_NODE_DISC: + case FC_REG_LOGIN: + case FC_CLEAR_LA: + linkinfo->a_linkState = LNK_DISCOVERY; + break; + case FC_READY: + linkinfo->a_linkState = LNK_READY; + break; + } + linkinfo->a_alpa = (uchar)(binfo->fc_myDID & 0xff); + fc_bcopy((uchar * )&binfo->fc_portname, (uchar *)linkinfo->a_wwpName, 8); + fc_bcopy((uchar * )&binfo->fc_nodename, (uchar *)linkinfo->a_wwnName, 8); + } + break; + + case C_IOINFO: + { + IOinfo *ioinfo; + + ioinfo = (IOinfo *)dm->fc_dataout; + ioinfo->a_mbxCmd = FCSTATCTR.issueMboxCmd; + ioinfo->a_mboxCmpl = FCSTATCTR.mboxEvent; + ioinfo->a_mboxErr = FCSTATCTR.mboxStatErr; + ioinfo->a_iocbCmd = FCSTATCTR.IssueIocb; + ioinfo->a_iocbRsp = FCSTATCTR.iocbRsp; + ioinfo->a_adapterIntr = (FCSTATCTR.linkEvent + FCSTATCTR.iocbRsp + + FCSTATCTR.mboxEvent); + ioinfo->a_fcpCmd = FCSTATCTR.fcpCmd; + ioinfo->a_fcpCmpl = FCSTATCTR.fcpCmpl; + ioinfo->a_fcpErr = FCSTATCTR.fcpRspErr + FCSTATCTR.fcpRemoteStop + + FCSTATCTR.fcpPortRjt + FCSTATCTR.fcpPortBusy + FCSTATCTR.fcpError + + FCSTATCTR.fcpLocalErr; + ioinfo->a_seqXmit = NDDSTAT.ndd_ifOutUcastPkts_lsw; + ioinfo->a_seqRcv = NDDSTAT.ndd_recvintr_lsw; + ioinfo->a_bcastXmit = NDDSTAT.ndd_ifOutBcastPkts_lsw + + NDDSTAT.ndd_ifOutMcastPkts_lsw; + ioinfo->a_bcastRcv = FCSTATCTR.frameRcvBcast; + ioinfo->a_elsXmit = FCSTATCTR.elsXmitFrame; + ioinfo->a_elsRcv = FCSTATCTR.elsRcvFrame; + ioinfo->a_RSCNRcv = FCSTATCTR.elsRcvRSCN; + ioinfo->a_seqXmitErr = NDDSTAT.ndd_oerrors; + ioinfo->a_elsXmitErr = FCSTATCTR.elsXmitErr; + ioinfo->a_elsBufPost = binfo->fc_ring[FC_ELS_RING].fc_bufcnt; + ioinfo->a_ipBufPost = binfo->fc_ring[FC_IP_RING].fc_bufcnt; + ioinfo->a_cnt1 = 0; + ioinfo->a_cnt2 = 0; + ioinfo->a_cnt3 = 0; + ioinfo->a_cnt4 = 0; + } + break; + + case C_NODEINFO: + { + NodeInfo * np; + + /* First uint32 word will be count */ + np = (NodeInfo *)dm->fc_dataout; + cnt = 0; + total_mem -= sizeof(NODELIST); + + nlp = binfo->fc_nlpbind_start; + if(nlp == (NODELIST *)&binfo->fc_nlpbind_start) + nlp = binfo->fc_nlpunmap_start; + if(nlp == (NODELIST *)&binfo->fc_nlpunmap_start) + nlp = binfo->fc_nlpmap_start; + while((nlp != (NODELIST *)&binfo->fc_nlpmap_start) && (total_mem > 0)) { + fc_bzero((uchar *)np, sizeof(NODELIST)); + if(nlp->nlp_flag & NLP_NS_REMOVED) + np->a_flag |= NODE_NS_REMOVED; + if(nlp->nlp_flag & NLP_RPI_XRI) + np->a_flag |= NODE_RPI_XRI; + if(nlp->nlp_flag & NLP_REQ_SND) + np->a_flag |= NODE_REQ_SND; + if(nlp->nlp_flag & NLP_RM_ENTRY) + np->a_flag |= NODE_RM_ENTRY; + if(nlp->nlp_flag & NLP_FARP_SND) + np->a_flag |= NODE_FARP_SND; + if(nlp->nlp_type & NLP_FABRIC) + np->a_flag |= NODE_FABRIC; + if(nlp->nlp_type & NLP_FCP_TARGET) + np->a_flag |= NODE_FCP_TARGET; + if(nlp->nlp_type & NLP_IP_NODE) + np->a_flag |= NODE_IP_NODE; + if(nlp->nlp_type & NLP_SEED_WWPN) + np->a_flag |= NODE_SEED_WWPN; + if(nlp->nlp_type & NLP_SEED_WWNN) + np->a_flag |= NODE_SEED_WWNN; + if(nlp->nlp_type & NLP_SEED_DID) + np->a_flag |= NODE_SEED_DID; + if(nlp->nlp_type & NLP_AUTOMAP) + np->a_flag |= NODE_AUTOMAP; + if(nlp->nlp_action & NLP_DO_DISC_START) + np->a_flag |= NODE_DISC_START; + if(nlp->nlp_action & NLP_DO_ADDR_AUTH) + np->a_flag |= NODE_ADDR_AUTH; + np->a_state = nlp->nlp_state; + np->a_did = nlp->nlp_DID; + np->a_targetid = FC_SCSID(nlp->id.nlp_pan, nlp->id.nlp_sid); + fc_bcopy(&nlp->nlp_portname, np->a_wwpn, 8); + fc_bcopy(&nlp->nlp_nodename, np->a_wwnn, 8); + total_mem -= sizeof(NODELIST); + np++; + cnt++; + nlp = (NODELIST *)nlp->nlp_listp_next; + if(nlp == (NODELIST *)&binfo->fc_nlpbind_start) + nlp = binfo->fc_nlpunmap_start; + if(nlp == (NODELIST *)&binfo->fc_nlpunmap_start) + nlp = binfo->fc_nlpmap_start; + } + if(cnt) { + infop->c_outsz = (uint32)(cnt * sizeof(NodeInfo)); + } + } + break; + + case C_HBA_ADAPTERATRIBUTES: + { + HBA_ADAPTERATTRIBUTES * ha; + + vp = &VPD; + ha = (HBA_ADAPTERATTRIBUTES *)dm->fc_dataout; + fc_bzero(dm->fc_dataout, (sizeof(HBA_ADAPTERATTRIBUTES))); + ha->NumberOfPorts = 1; + ha->VendorSpecificID = di->fc_ba.a_pci; + fc_bcopy(di->fc_ba.a_drvrid, ha->DriverVersion, 16); + fc_bcopy(di->fc_ba.a_fwname, ha->FirmwareVersion, 32); + fc_bcopy((uchar * )&binfo->fc_sparam.nodeName, (uchar * )&ha->NodeWWN, + sizeof(HBA_WWN)); + fc_bcopy("Emulex Corporation", ha->Manufacturer, 20); + + switch(((SWAP_LONG(ha->VendorSpecificID))>>16) & 0xffff) { + case PCI_DEVICE_ID_SUPERFLY: + if((vp->rev.biuRev == 1) || + (vp->rev.biuRev == 2) || (vp->rev.biuRev == 3)) { + fc_bcopy("LP7000", ha->Model, 8); + fc_bcopy("Emulex LightPulse LP7000 1 Gigabit PCI Fibre Channel Adapter", ha->ModelDescription, 62); + } + else { + fc_bcopy("LP7000E", ha->Model, 9); + fc_bcopy("Emulex LightPulse LP7000E 1 Gigabit PCI Fibre Channel Adapter", ha->ModelDescription, 62); + } + break; + case PCI_DEVICE_ID_DRAGONFLY: + fc_bcopy("LP8000", ha->Model, 8); + fc_bcopy("Emulex LightPulse LP8000 1 Gigabit PCI Fibre Channel Adapter", ha->ModelDescription, 62); + break; + case PCI_DEVICE_ID_CENTAUR: + if(FC_JEDEC_ID(vp->rev.biuRev) == CENTAUR_2G_JEDEC_ID) { + fc_bcopy("LP9002", ha->Model, 8); + fc_bcopy("Emulex LightPulse LP9002 2 Gigabit PCI Fibre Channel Adapter", ha->ModelDescription, 62); + } + else { + fc_bcopy("LP9000", ha->Model, 8); + fc_bcopy("Emulex LightPulse LP9000 1 Gigabit PCI Fibre Channel Adapter", ha->ModelDescription, 62); + } + break; + case PCI_DEVICE_ID_PEGASUS: + fc_bcopy("LP9802", ha->Model, 8); + fc_bcopy("Emulex LightPulse LP9802 2 Gigabit PCI Fibre Channel Adapter", ha->ModelDescription, 62); + break; + case PCI_DEVICE_ID_THOR: + fc_bcopy("LP10000", ha->Model, 9); + fc_bcopy("Emulex LightPulse LP10000 2 Gigabit PCI Fibre Channel Adapter", ha->ModelDescription, 63); + break; + case PCI_DEVICE_ID_PFLY: + fc_bcopy("LP982", ha->Model, 7); + fc_bcopy("Emulex LightPulse LP982 2 Gigabit PCI Fibre Channel Adapter", ha->ModelDescription, 62); + break; + case PCI_DEVICE_ID_TFLY: + fc_bcopy("LP1050", ha->Model, 8); + fc_bcopy("Emulex LightPulse LP1050 2 Gigabit PCI Fibre Channel Adapter", ha->ModelDescription, 63); + break; + } + fc_bcopy("lpfcdd", ha->DriverName, 7); + fc_bcopy(binfo->fc_SerialNumber, ha->SerialNumber, 32); + fc_bcopy(binfo->fc_OptionROMVersion, ha->OptionROMVersion, 32); + + /* Convert JEDEC ID to ascii for hardware version */ + incr = vp->rev.biuRev; + for(i=0;i<8;i++) { + j = (incr & 0xf); + if(j <= 9) + ha->HardwareVersion[7-i] = (char)((uchar)0x30 + (uchar)j); + else + ha->HardwareVersion[7-i] = (char)((uchar)0x61 + (uchar)(j-10)); + incr = (incr >> 4); + } + ha->HardwareVersion[8] = 0; + + } + break; + + case C_HBA_PORTATRIBUTES: + { + SERV_PARM * hsp; + HBA_OSDN * osdn; + +localport: + vp = &VPD; + hsp = (SERV_PARM *)&binfo->fc_sparam; + hp = (HBA_PORTATTRIBUTES *)dm->fc_dataout; + fc_bzero(dm->fc_dataout, (sizeof(HBA_PORTATTRIBUTES))); + fc_bcopy((uchar * )&binfo->fc_sparam.nodeName, (uchar * )&hp->NodeWWN, + sizeof(HBA_WWN)); + fc_bcopy((uchar * )&binfo->fc_sparam.portName, (uchar * )&hp->PortWWN, + sizeof(HBA_WWN)); + + if( binfo->fc_linkspeed == LA_2GHZ_LINK) + hp->PortSpeed = HBA_PORTSPEED_2GBIT; + else + hp->PortSpeed = HBA_PORTSPEED_1GBIT; + + if(FC_JEDEC_ID(vp->rev.biuRev) == CENTAUR_2G_JEDEC_ID) + hp->PortSupportedSpeed = HBA_PORTSPEED_2GBIT; + else + hp->PortSupportedSpeed = HBA_PORTSPEED_1GBIT; + + hp->PortFcId = binfo->fc_myDID; + hp->PortType = HBA_PORTTYPE_UNKNOWN; + if (binfo->fc_topology == TOPOLOGY_LOOP) { + if(binfo->fc_flag & FC_PUBLIC_LOOP) { + hp->PortType = HBA_PORTTYPE_NLPORT; + fc_bcopy((uchar * )&binfo->fc_fabparam.nodeName, + (uchar * )&hp->FabricName, sizeof(HBA_WWN)); + } + else { + hp->PortType = HBA_PORTTYPE_LPORT; + } + } + else { + if(binfo->fc_flag & FC_FABRIC) { + hp->PortType = HBA_PORTTYPE_NPORT; + fc_bcopy((uchar * )&binfo->fc_fabparam.nodeName, + (uchar * )&hp->FabricName, sizeof(HBA_WWN)); + } + else { + hp->PortType = HBA_PORTTYPE_PTP; + } + } + + if (binfo->fc_flag & FC_BYPASSED_MODE) { + hp->PortState = HBA_PORTSTATE_BYPASSED; + } + else if (binfo->fc_flag & FC_OFFLINE_MODE) { + hp->PortState = HBA_PORTSTATE_DIAGNOSTICS; + } + else { + switch (binfo->fc_ffstate) { + case FC_INIT_START: + case FC_INIT_NVPARAMS: + case FC_INIT_REV: + case FC_INIT_PARTSLIM: + case FC_INIT_CFGRING: + case FC_INIT_INITLINK: + hp->PortState = HBA_PORTSTATE_UNKNOWN; + case FC_LINK_DOWN: + case FC_LINK_UP: + case FC_INIT_SPARAM: + case FC_CFG_LINK: + case FC_FLOGI: + case FC_LOOP_DISC: + case FC_NS_REG: + case FC_NS_QRY: + case FC_NODE_DISC: + case FC_REG_LOGIN: + case FC_CLEAR_LA: + hp->PortState = HBA_PORTSTATE_LINKDOWN; + break; + case FC_READY: + hp->PortState = HBA_PORTSTATE_ONLINE; + break; + default: + hp->PortState = HBA_PORTSTATE_ERROR; + break; + } + } + cnt = binfo->fc_map_cnt + binfo->fc_unmap_cnt; + hp->NumberofDiscoveredPorts = cnt; + if (hsp->cls1.classValid) { + hp->PortSupportedClassofService |= 1; /* bit 1 */ + } + if (hsp->cls2.classValid) { + hp->PortSupportedClassofService |= 2; /* bit 2 */ + } + if (hsp->cls3.classValid) { + hp->PortSupportedClassofService |= 4; /* bit 3 */ + } + hp->PortMaxFrameSize = (((uint32)hsp->cmn.bbRcvSizeMsb) << 8) | + (uint32)hsp->cmn.bbRcvSizeLsb; + + hp->PortSupportedFc4Types.bits[2] = 0x1; + hp->PortSupportedFc4Types.bits[3] = 0x20; + hp->PortSupportedFc4Types.bits[7] = 0x1; + if(clp[CFG_FCP_ON].a_current) { + hp->PortActiveFc4Types.bits[2] = 0x1; + } + if(clp[CFG_NETWORK_ON].a_current) { + hp->PortActiveFc4Types.bits[3] = 0x20; + } + hp->PortActiveFc4Types.bits[7] = 0x1; + + + /* OSDeviceName is the device info filled into the HBA_OSDN structure */ + osdn = (HBA_OSDN *)&hp->OSDeviceName[0]; + fc_bcopy("lpfc", osdn->drvname, 4); + osdn->instance = fc_brd_to_inst(binfo->fc_brd_no); + osdn->target = (HBA_UINT32)(-1); + osdn->lun = (HBA_UINT32)(-1); + + } + break; + + case C_HBA_PORTSTATISTICS: + { + HBA_PORTSTATISTICS * hs; + FCCLOCK_INFO * clock_info; + + hs = (HBA_PORTSTATISTICS *)dm->fc_dataout; + fc_bzero(dm->fc_dataout, (sizeof(HBA_PORTSTATISTICS))); + + mb = (MAILBOX * )mbox; + fc_read_status(binfo, mb); + mb->un.varRdStatus.clrCounters = 0; + if(dfc_issue_mbox(p_dev_ctl, mb, &ipri)) { + rc = ENODEV; + break; + } + hs->TxFrames = mb->un.varRdStatus.xmitFrameCnt; + hs->RxFrames = mb->un.varRdStatus.rcvFrameCnt; + /* Convert KBytes to words */ + hs->TxWords = (mb->un.varRdStatus.xmitByteCnt * 256); + hs->RxWords = (mb->un.varRdStatus.rcvbyteCnt * 256); + fc_read_lnk_stat(binfo, mb); + if(dfc_issue_mbox(p_dev_ctl, mb, &ipri)) { + rc = ENODEV; + break; + } + hs->LinkFailureCount = mb->un.varRdLnk.linkFailureCnt; + hs->LossOfSyncCount = mb->un.varRdLnk.lossSyncCnt; + hs->LossOfSignalCount = mb->un.varRdLnk.lossSignalCnt; + hs->PrimitiveSeqProtocolErrCount = mb->un.varRdLnk.primSeqErrCnt; + hs->InvalidTxWordCount = mb->un.varRdLnk.invalidXmitWord; + hs->InvalidCRCCount = mb->un.varRdLnk.crcCnt; + hs->ErrorFrames = mb->un.varRdLnk.crcCnt; + + if (binfo->fc_topology == TOPOLOGY_LOOP) { + hs->LIPCount = (binfo->fc_eventTag >> 1); + hs->NOSCount = -1; + } + else { + hs->LIPCount = -1; + hs->NOSCount = (binfo->fc_eventTag >> 1); + } + + hs->DumpedFrames = -1; + clock_info = &DD_CTL.fc_clock_info; + hs->SecondsSinceLastReset = clock_info->ticks; + + } + break; + + case C_HBA_WWPNPORTATRIBUTES: + { + HBA_WWN findwwn; + + hp = (HBA_PORTATTRIBUTES *)dm->fc_dataout; + vp = &VPD; + fc_bzero(dm->fc_dataout, (sizeof(HBA_PORTATTRIBUTES))); + + dfc_unlock_enable(ipri, &CMD_LOCK); + if (fc_copyin((uchar *)cip->c_arg1, (uchar *)&findwwn, (ulong)(sizeof(HBA_WWN)))) { + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + rc = EIO; + break; + } + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + /* First Mapped ports, then unMapped ports */ + nlp = binfo->fc_nlpmap_start; + if(nlp == (NODELIST *)&binfo->fc_nlpmap_start) + nlp = binfo->fc_nlpunmap_start; + while(nlp != (NODELIST *)&binfo->fc_nlpunmap_start) { + if (fc_geportname(&nlp->nlp_portname, (NAME_TYPE *)&findwwn) == 2) + goto foundit; + nlp = (NODELIST *)nlp->nlp_listp_next; + if(nlp == (NODELIST *)&binfo->fc_nlpmap_start) + nlp = binfo->fc_nlpunmap_start; + } + rc = ERANGE; + break; + } + + case C_HBA_DISCPORTATRIBUTES: + { + SERV_PARM * hsp; + MATCHMAP * mp; + HBA_OSDN * osdn; + uint32 refresh; + + vp = &VPD; + hp = (HBA_PORTATTRIBUTES *)dm->fc_dataout; + fc_bzero(dm->fc_dataout, (sizeof(HBA_PORTATTRIBUTES))); + offset = (uint32)((ulong)cip->c_arg2); + refresh = (uint32)((ulong)cip->c_arg3); + if(refresh != binfo->nlptimer) { + hp->PortFcId = 0xffffffff; + break; + } + cnt = 0; + /* First Mapped ports, then unMapped ports */ + nlp = binfo->fc_nlpmap_start; + if(nlp == (NODELIST *)&binfo->fc_nlpmap_start) + nlp = binfo->fc_nlpunmap_start; + while(nlp != (NODELIST *)&binfo->fc_nlpunmap_start) { + if(cnt == offset) + goto foundit; + cnt++; + nlp = (NODELIST *)nlp->nlp_listp_next; + if(nlp == (NODELIST *)&binfo->fc_nlpmap_start) + nlp = binfo->fc_nlpunmap_start; + } + rc = ERANGE; + break; + +foundit: + /* Check if its the local port */ + if(binfo->fc_myDID == nlp->nlp_DID) { + goto localport; + } + + mb = (MAILBOX * )mbox; + fc_read_rpi(binfo, (uint32)nlp->nlp_Rpi, + (MAILBOX * )mb, (uint32)0); + + if ((mp = (MATCHMAP * )fc_mem_get(binfo, MEM_BUF)) == 0) { + rc = ENOMEM; + break; + } + hsp = (SERV_PARM *)mp->virt; + if (binfo->fc_flag & FC_SLI2) { + mb->un.varRdRPI.un.sp64.addrHigh = + (uint32)putPaddrHigh(mp->phys); + mb->un.varRdRPI.un.sp64.addrLow = + (uint32)putPaddrLow(mp->phys); + mb->un.varRdRPI.un.sp64.tus.f.bdeSize = sizeof(SERV_PARM); + } + else { + mb->un.varRdRPI.un.sp.bdeAddress = + (uint32)putPaddrLow(mp->phys); + mb->un.varRdRPI.un.sp.bdeSize = sizeof(SERV_PARM); + } + + if(dfc_issue_mbox(p_dev_ctl, mb, &ipri)) { + rc = ENODEV; + break; + } + + if (hsp->cls1.classValid) { + hp->PortSupportedClassofService |= 1; /* bit 1 */ + } + if (hsp->cls2.classValid) { + hp->PortSupportedClassofService |= 2; /* bit 2 */ + } + if (hsp->cls3.classValid) { + hp->PortSupportedClassofService |= 4; /* bit 3 */ + } + hp->PortMaxFrameSize = (((uint32)hsp->cmn.bbRcvSizeMsb) << 8) | + (uint32)hsp->cmn.bbRcvSizeLsb; + + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + + fc_bcopy((uchar * )&nlp->nlp_nodename, (uchar * )&hp->NodeWWN, + sizeof(HBA_WWN)); + fc_bcopy((uchar * )&nlp->nlp_portname, (uchar * )&hp->PortWWN, + sizeof(HBA_WWN)); + + hp->PortSpeed = 0; + if(((binfo->fc_myDID & 0xffff00) == (nlp->nlp_DID & 0xffff00)) && + (binfo->fc_topology == TOPOLOGY_LOOP)) { + if( binfo->fc_linkspeed == LA_2GHZ_LINK) + hp->PortSpeed = HBA_PORTSPEED_2GBIT; + else + hp->PortSpeed = HBA_PORTSPEED_1GBIT; + } + + hp->PortFcId = nlp->nlp_DID; + if((binfo->fc_flag & FC_FABRIC) && + ((binfo->fc_myDID & 0xff0000) == (nlp->nlp_DID & 0xff0000))) { + fc_bcopy((uchar * )&binfo->fc_fabparam.nodeName, + (uchar * )&hp->FabricName, sizeof(HBA_WWN)); + } + hp->PortState = HBA_PORTSTATE_ONLINE; + if (nlp->nlp_type & NLP_FCP_TARGET) { + hp->PortActiveFc4Types.bits[2] = 0x1; + } + if (nlp->nlp_type & NLP_IP_NODE) { + hp->PortActiveFc4Types.bits[3] = 0x20; + } + hp->PortActiveFc4Types.bits[7] = 0x1; + + hp->PortType = HBA_PORTTYPE_UNKNOWN; + if (binfo->fc_topology == TOPOLOGY_LOOP) { + if(binfo->fc_flag & FC_PUBLIC_LOOP) { + /* Check if Fabric port */ + if (fc_geportname(&nlp->nlp_nodename, (NAME_TYPE *)&(binfo->fc_fabparam.nodeName)) == 2) { + hp->PortType = HBA_PORTTYPE_FLPORT; + } + else { + /* Based on DID */ + if((nlp->nlp_DID & 0xff) == 0) { + hp->PortType = HBA_PORTTYPE_NPORT; + } + else { + if((nlp->nlp_DID & 0xff0000) != 0xff0000) { + hp->PortType = HBA_PORTTYPE_NLPORT; + } + } + } + } + else { + hp->PortType = HBA_PORTTYPE_LPORT; + } + } + else { + if(binfo->fc_flag & FC_FABRIC) { + /* Check if Fabric port */ + if (fc_geportname(&nlp->nlp_nodename, (NAME_TYPE *)&(binfo->fc_fabparam.nodeName)) == 2) { + hp->PortType = HBA_PORTTYPE_FPORT; + } + else { + /* Based on DID */ + if((nlp->nlp_DID & 0xff) == 0) { + hp->PortType = HBA_PORTTYPE_NPORT; + } + else { + if((nlp->nlp_DID & 0xff0000) != 0xff0000) { + hp->PortType = HBA_PORTTYPE_NLPORT; + } + } + } + } + else { + hp->PortType = HBA_PORTTYPE_PTP; + } + } + + /* for mapped devices OSDeviceName is device info filled into HBA_OSDN structure */ + if(nlp->nlp_flag & NLP_MAPPED) { + osdn = (HBA_OSDN *)&hp->OSDeviceName[0]; + fc_bcopy("lpfc", osdn->drvname, 4); + osdn->instance = fc_brd_to_inst(binfo->fc_brd_no); + osdn->target = FC_SCSID(nlp->id.nlp_pan, nlp->id.nlp_sid); + osdn->lun = (HBA_UINT32)(-1); + } + + } + break; + + case C_HBA_INDEXPORTATRIBUTES: + { + uint32 refresh; + + vp = &VPD; + hp = (HBA_PORTATTRIBUTES *)dm->fc_dataout; + fc_bzero(dm->fc_dataout, (sizeof(HBA_PORTATTRIBUTES))); + offset = (uint32)((ulong)cip->c_arg2); + refresh = (uint32)((ulong)cip->c_arg3); + if(refresh != binfo->nlptimer) { + hp->PortFcId = 0xffffffff; + break; + } + cnt = 0; + /* Mapped NPorts only */ + nlp = binfo->fc_nlpmap_start; + while(nlp != (NODELIST *)&binfo->fc_nlpmap_start) { + if(cnt == offset) + goto foundit; + cnt++; + nlp = (NODELIST *)nlp->nlp_listp_next; + } + rc = ERANGE; + } + break; + + case C_HBA_SETMGMTINFO: + { + HBA_MGMTINFO *mgmtinfo; + + mgmtinfo = (HBA_MGMTINFO *)dfc.dfc_buffer; + + dfc_unlock_enable(ipri, &CMD_LOCK); + if (fc_copyin((uchar *)cip->c_arg1, (uchar *)mgmtinfo, sizeof(HBA_MGMTINFO))) { + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + rc = EIO; + break; + } + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + binfo->ipVersion = mgmtinfo->IPVersion; + binfo->UDPport = mgmtinfo->UDPPort; + if(binfo->ipVersion == RNID_IPV4) { + fc_bcopy((uchar *)&mgmtinfo->IPAddress[0], + (uchar * )&binfo->ipAddr[0], 4); + } + else { + fc_bcopy((uchar *)&mgmtinfo->IPAddress[0], + (uchar * )&binfo->ipAddr[0], 16); + } + } + break; + + case C_HBA_GETMGMTINFO: + { + HBA_MGMTINFO *mgmtinfo; + + mgmtinfo = (HBA_MGMTINFO *)dm->fc_dataout; + fc_bcopy((uchar * )&binfo->fc_nodename, (uchar *)&mgmtinfo->wwn, 8); + mgmtinfo->unittype = RNID_HBA; + mgmtinfo->PortId = binfo->fc_myDID; + mgmtinfo->NumberOfAttachedNodes = 0; + mgmtinfo->TopologyDiscoveryFlags = 0; + mgmtinfo->IPVersion = binfo->ipVersion; + mgmtinfo->UDPPort = binfo->UDPport; + if(binfo->ipVersion == RNID_IPV4) { + fc_bcopy((void *) & binfo->ipAddr[0], + (void *) & mgmtinfo->IPAddress[0], 4); + } + else { + fc_bcopy((void *) & binfo->ipAddr[0], + (void *) & mgmtinfo->IPAddress[0], 16); + } + } + break; + + case C_HBA_REFRESHINFO: + { + lptr = (uint32 *)dm->fc_dataout; + *lptr = binfo->nlptimer; + } + break; + + case C_HBA_RNID: + ipri = dfc_hba_rnid( p_dev_ctl, dm, cip, infop, buf_info, ipri); + break; + + case C_HBA_GETEVENT: + { + HBA_UINT32 outsize; + HBAEVENT *rec; + HBAEVENT *recout; + + size = (uint32)((ulong)cip->c_arg1); /* size is number of event entries */ + + recout = (HBAEVENT * )dm->fc_dataout; + for(j=0;jhba_event_get == p_dev_ctl->hba_event_put)) + break; + rec = &p_dev_ctl->hbaevent[p_dev_ctl->hba_event_get]; + fc_bcopy((uchar * )rec, (uchar *)recout, sizeof(HBAEVENT)); + recout++; + p_dev_ctl->hba_event_get++; + if(p_dev_ctl->hba_event_get >= MAX_HBAEVENT) { + p_dev_ctl->hba_event_get = 0; + } + } + outsize = j; + + /* copy back size of response */ + dfc_unlock_enable(ipri, &CMD_LOCK); + if (fc_copyout((uchar *)&outsize, (uchar *)cip->c_arg2, sizeof(HBA_UINT32))) { + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + rc = EIO; + break; + } + /* copy back number of missed records */ + if (fc_copyout((uchar *)&p_dev_ctl->hba_event_missed, (uchar *)cip->c_arg3, sizeof(HBA_UINT32))) { + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + rc = EIO; + break; + } + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + p_dev_ctl->hba_event_missed = 0; + infop->c_outsz = (uint32)(outsize * sizeof(HBA_EVENTINFO)); + } + + break; + + case C_HBA_FCPTARGETMAPPING: + ipri = dfc_hba_targetmapping(p_dev_ctl, dm, cip, infop, ipri); + break; + + case C_HBA_FCPBINDING: + ipri = dfc_hba_fcpbind(p_dev_ctl, dm, cip, infop, ipri); + break; + + case C_GETCFG: + { + CfgParam * cp; + iCfgParam * icp; + + /* First uint32 word will be count */ + cp = (CfgParam *)dm->fc_dataout; + cnt = 0; + for (i = 0; i < NUM_CFG_PARAM; i++) { + icp = &clp[i]; + cp->a_low = icp->a_low; + cp->a_hi = icp->a_hi; + cp->a_flag = icp->a_flag; + cp->a_default = icp->a_default; + cp->a_current = icp->a_current; + cp->a_changestate = icp->a_changestate; + fc_bcopy(icp->a_string, cp->a_string, 32); + fc_bcopy(icp->a_help, cp->a_help, 80); + cp++; + cnt++; + } + if(cnt) { + infop->c_outsz = (uint32)(cnt * sizeof(CfgParam)); + } + } + break; + + case C_SETCFG: + { + RING * rp; + iCfgParam * icp; + + offset = (uint32)((ulong)cip->c_arg1); + cnt = (uint32)((ulong)cip->c_arg2); + if (offset >= NUM_CFG_PARAM) { + rc = ERANGE; + break; + } + icp = &clp[offset]; + if(icp->a_changestate != CFG_DYNAMIC) { + rc = EPERM; + break; + } + if (((icp->a_low != 0) && (cnt < icp->a_low)) || (cnt > icp->a_hi)) { + rc = ERANGE; + break; + } + switch(offset) { + case CFG_FCP_CLASS: + switch (cnt) { + case 1: + clp[CFG_FCP_CLASS].a_current = CLASS1; + break; + case 2: + clp[CFG_FCP_CLASS].a_current = CLASS2; + break; + case 3: + clp[CFG_FCP_CLASS].a_current = CLASS3; + break; + } + icp->a_current = cnt; + break; + + case CFG_IP_CLASS: + switch (cnt) { + case 1: + clp[CFG_IP_CLASS].a_current = CLASS1; + break; + case 2: + clp[CFG_IP_CLASS].a_current = CLASS2; + break; + case 3: + clp[CFG_IP_CLASS].a_current = CLASS3; + break; + } + icp->a_current = cnt; + break; + + case CFG_LINKDOWN_TMO: + icp->a_current = cnt; + rp = &binfo->fc_ring[FC_FCP_RING]; + if(clp[CFG_LINKDOWN_TMO].a_current) { + rp->fc_ringtmo = clp[CFG_LINKDOWN_TMO].a_current; + } + break; + + default: + icp->a_current = cnt; + } + } + break; + + case C_GET_EVENT: + { + fcEvent *ep; + fcEvent *oep; + fcEvent_header *ehp; + uchar *cp; + MATCHMAP *omm; + int no_more; + + no_more = 1; + + offset = ((uint32)((ulong)cip->c_arg3) & FC_REG_EVENT_MASK); /* event mask */ + incr = (uint32)cip->c_flag; /* event id */ + size = (uint32)cip->c_iocb; /* process requesting event */ + ehp = (fcEvent_header *)p_dev_ctl->fc_evt_head; + while (ehp) { + if (ehp->e_mask == offset) + break; + ehp = (fcEvent_header *)ehp->e_next_header; + } + + if (!ehp) { + rc = ENOENT; + break; + } + + ep = ehp->e_head; + oep = 0; + while(ep) { + /* Find an event that matches the event mask */ + if(ep->evt_sleep == 0) { + /* dequeue event from event list */ + if(oep == 0) { + ehp->e_head = ep->evt_next; + } else { + oep->evt_next = ep->evt_next; + } + if(ehp->e_tail == ep) + ehp->e_tail = oep; + + switch(offset) { + case FC_REG_LINK_EVENT: + break; + case FC_REG_RSCN_EVENT: + /* Return data length */ + cnt = sizeof(uint32); + + dfc_unlock_enable(ipri, &CMD_LOCK); + if (fc_copyout((uchar *)&cnt, (uchar *)cip->c_arg1, sizeof(uint32))) { + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + rc = EIO; + } + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + fc_bcopy((char *)&ep->evt_data0, dm->fc_dataout, cnt); + infop->c_outsz = (uint32)cnt; + break; + case FC_REG_CT_EVENT: + /* Return data length */ + cnt = (ulong)(ep->evt_data2); + + dfc_unlock_enable(ipri, &CMD_LOCK); + if (fc_copyout((uchar *)&cnt, (uchar *)cip->c_arg1, sizeof(uint32))) { + rc = EIO; + } + else { + if (fc_copyout((uchar *)&ep->evt_data0, (uchar *)cip->c_arg2, + sizeof(uint32))) { + rc = EIO; + } + } + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + infop->c_outsz = (uint32)cnt; + i = cnt; + mm = (MATCHMAP * )ep->evt_data1; + cp = (uchar *)dm->fc_dataout; + while(mm) { + + if(cnt > FCELSSIZE) + i = FCELSSIZE; + else + i = cnt; + + if(total_mem > 0) { + fc_bcopy((char *)mm->virt, cp, i); + total_mem -= i; + } + + omm = mm; + mm = (MATCHMAP *)mm->fc_mptr; + cp += i; + fc_mem_put(binfo, MEM_BUF, (uchar * )omm); + } + break; + } + + if((offset == FC_REG_CT_EVENT) && (ep->evt_next) && + (((fcEvent *)(ep->evt_next))->evt_sleep == 0)) { + ep->evt_data0 |= 0x80000000; /* More event is waiting */ + if (fc_copyout((uchar *)&ep->evt_data0, (uchar *)cip->c_arg2, + sizeof(uint32))) { + rc = EIO; + } + no_more = 0; + } + + /* Requeue event entry */ + ep->evt_next = 0; + ep->evt_data0 = 0; + ep->evt_data1 = 0; + ep->evt_data2 = 0; + ep->evt_sleep = 1; + ep->evt_flags = 0; + + if(ehp->e_head == 0) { + ehp->e_head = ep; + ehp->e_tail = ep; + } + else { + ehp->e_tail->evt_next = ep; + ehp->e_tail = ep; + } + + if(offset == FC_REG_LINK_EVENT) { + ehp->e_flag &= ~E_GET_EVENT_ACTIVE; + goto linfo; + } + + dfc_unlock_enable(ipri, &CMD_LOCK); + if (fc_copyout((char *)dm->fc_dataout, infop->c_dataout, (int)infop->c_outsz)) { + rc = EIO; + } + dfc_data_free(p_dev_ctl, dm); + + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + if (no_more) + ehp->e_flag &= ~E_GET_EVENT_ACTIVE; + di->fc_refcnt--; + dfc_unlock_enable(ipri, &CMD_LOCK); + + return (rc); + } + oep = ep; + ep = ep->evt_next; + } + if(ep == 0) { + /* No event found */ + rc = ENOENT; + } + } + break; + + case C_SET_EVENT: + ipri = dfc_hba_set_event(p_dev_ctl, dm, cip, infop, ipri); + break; + + default: + rc = EINVAL; + break; + } + +out: + /* dfc_ioctl exit */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0401, /* ptr to msg structure */ + fc_mes0401, /* ptr to msg */ + fc_msgBlk0401.msgPreambleStr, /* begin varargs */ + rc, + infop->c_outsz, + (uint32)((ulong)infop->c_dataout)); /* end varargs */ + + di->fc_refcnt--; + dfc_unlock_enable(ipri, &CMD_LOCK); + + /* Copy data to user space config method */ + if ((rc == 0) || (do_cp == 1)) { + if (infop->c_outsz) { + if (fc_copyout((char *)dm->fc_dataout, infop->c_dataout, (int)infop->c_outsz)) { + rc = EIO; + } + } + } + + /* Now free the space for these structures */ + dmdata_info->virt = (struct dfc_mem *)dm; + dmdata_info->phys = 0; + dmdata_info->flags = (FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + dmdata_info->size = sizeof(* dm); + dmdata_info->dma_handle = 0; + dmdata_info->data_handle = 0; + fc_free(p_dev_ctl, dmdata_info); + + mbox_info->virt = (char *)mbox; + mbox_info->phys = 0; + mbox_info->flags = (FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + mbox_info->size = sizeof(* mbox); + mbox_info->dma_handle = 0; + mbox_info->data_handle = 0; + fc_free(p_dev_ctl, mbox_info); + + dfc_data_free(p_dev_ctl, dm); + return (rc); +} + + +uint32 +dfc_getLunId( +node_t *nodep, uint32 lunIndex) +{ + static uint32 lun; + static int i; + static dvi_t *dev_ptr; + static FCP_CMND *tmp; + + tmp = (FCP_CMND *)nodep->virtRptLunData; + + if(tmp == 0) { + dev_ptr = nodep->lunlist; + lun = dev_ptr->lun_id; + } else { + i = (lunIndex + 1) * 8; + tmp = (FCP_CMND *)(((uchar *)nodep->virtRptLunData) + i); + lun = ((tmp->fcpLunMsl >> FC_LUN_SHIFT) & 0xff); + } + return lun; +} + +_static_ int +dfc_bcopy( +uint32 *lsrc, +uint32 *ldest, +int cnt, +int incr) +{ + static ushort * ssrc; + static ushort * sdest; + static uchar * csrc; + static uchar * cdest; + static int i; + + csrc = (uchar * )lsrc; + cdest = (uchar * )ldest; + ssrc = (ushort * )lsrc; + sdest = (ushort * )ldest; + + for (i = 0; i < cnt; i += incr) { + if (incr == sizeof(char)) { + *cdest++ = *csrc++; + } else if (incr == sizeof(short)) { + *sdest++ = *ssrc++; + } else { + *ldest++ = *lsrc++; + } + } + return(0); +} + + +_static_ fc_dev_ctl_t * +dfc_getpdev( +struct cmd_input *ci) +{ + static fc_dev_ctl_t * p_dev_ctl;/* pointer to dev_ctl area */ + static FC_BRD_INFO * binfo; + + p_dev_ctl = DD_CTL.p_dev[ci->c_brd]; + binfo = &BINFO; + + if (p_dev_ctl == 0) { + return(0); + } + + /* Make sure command specified ring is within range */ + if (ci->c_ring >= binfo->fc_ffnumrings) { + return(0); + } + + return(p_dev_ctl); +} + + +_static_ int +fc_inst_to_brd( +int ddiinst) +{ + int i; + + for (i = 0; i < fcinstcnt; i++) + if (fcinstance[i] == ddiinst) + return(i); + + return(MAX_FC_BRDS); +} + + +_static_ int +dfc_msdelay( +fc_dev_ctl_t * p_dev_ctl, +ulong ms) +{ + DELAYMSctx(ms); + return(0); +} + +_local_ int +dfc_issue_mbox( +fc_dev_ctl_t * p_dev_ctl, +MAILBOX * mb, +ulong * ipri) +{ + static int j; + static MAILBOX * mbslim; + static FC_BRD_INFO * binfo; + static iCfgParam * clp; + struct dfc_info * di; + static volatile uint32 word0, ldata; + static uint32 ha_copy; + static void * ioa; + + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + di = &dfc.dfc_info[binfo->fc_brd_no]; + if (binfo->fc_ffstate == FC_ERROR) { + mb->mbxStatus = MBXERR_ERROR; + return(1); + } + j = 0; + while((binfo->fc_mbox_active) || (di->fc_flag & DFC_MBOX_ACTIVE)) { + dfc_unlock_enable(*ipri, &CMD_LOCK); + + if (j < 10) { + dfc_msdelay(p_dev_ctl, 1); + } else { + dfc_msdelay(p_dev_ctl, 50); + } + + *ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + if (j++ >= 600) { + mb->mbxStatus = MBXERR_ERROR; + return(1); + } + } + binfo->fc_mbox_active = 2; + di->fc_flag |= DFC_MBOX_ACTIVE; + +retrycmd: + /* next set own bit for the adapter and copy over command word */ + mb->mbxOwner = OWN_CHIP; + + if ((binfo->fc_flag & FC_SLI2) && (!(binfo->fc_flag & FC_OFFLINE_MODE))) { + /* First copy command data */ + mbslim = FC_SLI2_MAILBOX(binfo); + fc_pcimem_bcopy((uint32 * )mb, (uint32 * )mbslim, + (sizeof(uint32) * (MAILBOX_CMD_WSIZE))); + } else { + /* First copy command data */ + ioa = (void *)FC_MAP_MEM(&di->fc_iomap_mem); /* map in SLIM */ + mbslim = FC_MAILBOX(binfo, ioa); + WRITE_SLIM_COPY(binfo, &mb->un.varWords, &mbslim->un.varWords, + (MAILBOX_CMD_WSIZE - 1)); + + /* copy over last word, with mbxOwner set */ + ldata = *((volatile uint32 * )mb); + + + WRITE_SLIM_ADDR(binfo, ((volatile uint32 * )mbslim), ldata); + FC_UNMAP_MEMIO(ioa); + } + + fc_bcopy((char *)(mb), (char *)&p_dev_ctl->dfcmb[0], + (sizeof(uint32) * (MAILBOX_CMD_WSIZE))); + + /* interrupt board to doit right away */ + ioa = (void *)FC_MAP_IO(&di->fc_iomap_io); /* map in io registers */ + WRITE_CSR_REG(binfo, FC_FF_REG(binfo, ioa), CA_MBATT); + FC_UNMAP_MEMIO(ioa); + + FCSTATCTR.issueMboxCmd++; + + if ((binfo->fc_flag & FC_SLI2) && (!(binfo->fc_flag & FC_OFFLINE_MODE))) { + /* First copy command data */ + word0 = p_dev_ctl->dfcmb[0]; + } else { + /* First copy command data */ + ioa = (void *)FC_MAP_MEM(&di->fc_iomap_mem); /* map in SLIM */ + mbslim = FC_MAILBOX(binfo, ioa); + word0 = READ_SLIM_ADDR(binfo, ((volatile uint32 * )mbslim)); + FC_UNMAP_MEMIO(ioa); + } + + ioa = (void *)FC_MAP_IO(&di->fc_iomap_io); /* map in io registers */ + ha_copy = READ_CSR_REG(binfo, FC_HA_REG(binfo, ioa)); + FC_UNMAP_MEMIO(ioa); + + /* Wait for command to complete */ + while (((word0 & OWN_CHIP) == OWN_CHIP) || !(ha_copy & HA_MBATT)) { + dfc_unlock_enable(*ipri, &CMD_LOCK); + + if ((j < 20) && (mb->mbxCommand != MBX_INIT_LINK)) { + dfc_msdelay(p_dev_ctl, 1); + } else { + dfc_msdelay(p_dev_ctl, 50); + } + + *ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + if (j++ >= 600) { + mb->mbxStatus = MBXERR_ERROR; + binfo->fc_mbox_active = 0; + di->fc_flag &= ~DFC_MBOX_ACTIVE; + return(1); + } + + if ((binfo->fc_flag & FC_SLI2) && (!(binfo->fc_flag & FC_OFFLINE_MODE))) { + /* First copy command data */ + word0 = p_dev_ctl->dfcmb[0]; + } else { + /* First copy command data */ + ioa = (void *)FC_MAP_MEM(&di->fc_iomap_mem); /* map in SLIM */ + mbslim = FC_MAILBOX(binfo, ioa); + word0 = READ_SLIM_ADDR(binfo, ((volatile uint32 * )mbslim)); + FC_UNMAP_MEMIO(ioa); + } + ha_copy = HA_MBATT; + } + + mbslim = (MAILBOX * ) & word0; + if (mbslim->mbxCommand != mb->mbxCommand) { + j++; + if(mb->mbxCommand == MBX_INIT_LINK) { + /* Do not retry init_link's */ + mb->mbxStatus = 0; + binfo->fc_mbox_active = 0; + di->fc_flag &= ~DFC_MBOX_ACTIVE; + return(1); + } + goto retrycmd; + } + + /* copy results back to user */ + if ((binfo->fc_flag & FC_SLI2) && (!(binfo->fc_flag & FC_OFFLINE_MODE))) { + /* First copy command data */ + fc_bcopy((char *)&p_dev_ctl->dfcmb[0], (char *)mb, + (sizeof(uint32) * (MAILBOX_CMD_WSIZE))); + } else { + /* First copy command data */ + ioa = (void *)FC_MAP_MEM(&di->fc_iomap_mem); /* map in SLIM */ + mbslim = FC_MAILBOX(binfo, ioa); + /* copy results back to user */ + READ_SLIM_COPY(binfo, (uint32 * )mb, (uint32 * )mbslim, + MAILBOX_CMD_WSIZE); + FC_UNMAP_MEMIO(ioa); + } + + ioa = (void *)FC_MAP_IO(&di->fc_iomap_io); /* map in io registers */ + WRITE_CSR_REG(binfo, FC_HA_REG(binfo, ioa), HA_MBATT); + FC_UNMAP_MEMIO(ioa); + + + binfo->fc_mbox_active = 0; + di->fc_flag &= ~DFC_MBOX_ACTIVE; + + return(0); +} + +int +dfc_put_event( +fc_dev_ctl_t * p_dev_ctl, +uint32 evcode, +uint32 evdata0, +void * evdata1, +void * evdata2) +{ + static fcEvent *ep; + static fcEvent *oep; + static fcEvent_header *ehp = NULL; + static int found; + static MATCHMAP *mp; + static uint32 fstype; + static SLI_CT_REQUEST * ctp; + + ehp = (fcEvent_header *)p_dev_ctl->fc_evt_head; + + while (ehp) { + if (ehp->e_mask == evcode) + break; + ehp = (fcEvent_header *)ehp->e_next_header; + } + + if (!ehp) { + return (0); + } + + ep = ehp->e_head; + oep = 0; + found = 0; + + while(ep && (!found)) { + if(ep->evt_sleep) { + switch(evcode) { + case FC_REG_CT_EVENT: + mp = (MATCHMAP *)evdata1; + ctp = (SLI_CT_REQUEST *)mp->virt; + fstype = (uint32)(ctp->FsType); + if((ep->evt_type == FC_FSTYPE_ALL) || + (ep->evt_type == fstype)) { + found++; + ep->evt_data0 = evdata0; /* tag */ + ep->evt_data1 = evdata1; /* buffer ptr */ + ep->evt_data2 = evdata2; /* count */ + ep->evt_sleep = 0; + if ((ehp->e_mode & E_SLEEPING_MODE) && !(ehp->e_flag & E_GET_EVENT_ACTIVE)) { + ehp->e_flag |= E_GET_EVENT_ACTIVE; + dfc_wakeup(p_dev_ctl, ehp); + } + + } + break; + default: + found++; + ep->evt_data0 = evdata0; + ep->evt_data1 = evdata1; + ep->evt_data2 = evdata2; + ep->evt_sleep = 0; + if ((ehp->e_mode & E_SLEEPING_MODE) && !(ehp->e_flag & E_GET_EVENT_ACTIVE)) { + ehp->e_flag |= E_GET_EVENT_ACTIVE; + dfc_wakeup(p_dev_ctl, ehp); + } + break; + } + } + oep = ep; + ep = ep->evt_next; + } + return(found); +} + +int +dfc_wakeupall( +fc_dev_ctl_t * p_dev_ctl, +int flag) +{ + static fcEvent *ep; + static fcEvent *oep; + static fcEvent_header *ehp = NULL; + static int found; + + ehp = (fcEvent_header *)p_dev_ctl->fc_evt_head; + found = 0; + + while (ehp) { + ep = ehp->e_head; + oep = 0; + while(ep) { + ep->evt_sleep = 0; + if(flag) { + dfc_wakeup(p_dev_ctl, ehp); + } + else if (!(ehp->e_flag & E_GET_EVENT_ACTIVE)) { + found++; + ehp->e_flag |= E_GET_EVENT_ACTIVE; + dfc_wakeup(p_dev_ctl, ehp); + } + oep = ep; + ep = ep->evt_next; + } + ehp = (fcEvent_header *)ehp->e_next_header; + } + return(found); +} + +int +dfc_hba_put_event( +fc_dev_ctl_t * p_dev_ctl, +uint32 evcode, +uint32 evdata1, +uint32 evdata2, +uint32 evdata3, +uint32 evdata4) +{ + static HBAEVENT *rec; + static FC_BRD_INFO * binfo; + + binfo = &BINFO; + rec = &p_dev_ctl->hbaevent[p_dev_ctl->hba_event_put]; + rec->fc_eventcode = evcode; + + rec->fc_evdata1 = evdata1; + rec->fc_evdata2 = evdata2; + rec->fc_evdata3 = evdata3; + rec->fc_evdata4 = evdata4; + p_dev_ctl->hba_event_put++; + if(p_dev_ctl->hba_event_put >= MAX_HBAEVENT) { + p_dev_ctl->hba_event_put = 0; + } + if(p_dev_ctl->hba_event_put == p_dev_ctl->hba_event_get) { + p_dev_ctl->hba_event_missed++; + p_dev_ctl->hba_event_get++; + if(p_dev_ctl->hba_event_get >= MAX_HBAEVENT) { + p_dev_ctl->hba_event_get = 0; + } + } + + return(0); +} /* End dfc_hba_put_event */ + +int +dfc_hba_set_event( +fc_dev_ctl_t * p_dev_ctl, +struct dfc_mem *dm, +struct cmd_input *cip, +struct dfccmdinfo *infop, +ulong ipri) +{ + static fcEvent *evp; + static fcEvent *ep; + static fcEvent *oep; + static fcEvent_header *ehp; + static fcEvent_header *oehp; + static int found; + static MBUF_INFO * buf_info; + static MBUF_INFO bufinfo; + static uint32 offset; + static uint32 incr; + + offset = ((uint32)((ulong)cip->c_arg3) & FC_REG_EVENT_MASK); + incr = (uint32)cip->c_flag; + + switch(offset) { + case FC_REG_CT_EVENT: + found = fc_out_event; + break; + case FC_REG_RSCN_EVENT: + found = fc_out_event; + break; + case FC_REG_LINK_EVENT: + found = 2; + break; + default: + found = 0; + rc = EINTR; + return(ipri); + } + + oehp = 0; + ehp = (fcEvent_header *)p_dev_ctl->fc_evt_head; + while (ehp) { + if (ehp->e_mask == offset) { + found = 0; + break; + } + oehp = ehp; + ehp = (fcEvent_header *)ehp->e_next_header; + } + + if (!ehp) { + buf_info = &bufinfo; + buf_info->virt = 0; + buf_info->phys = 0; + buf_info->flags = (FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + buf_info->align = sizeof(void *); + buf_info->size = sizeof(fcEvent_header); + buf_info->dma_handle = 0; + + dfc_unlock_enable(ipri, &CMD_LOCK); + fc_malloc(p_dev_ctl, buf_info); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + if (buf_info->virt == NULL) { + rc = EINTR; + return(ipri); + } + ehp = (fcEvent_header *)(buf_info->virt); + fc_bzero((char *)ehp, sizeof(fcEvent_header)); + if(p_dev_ctl->fc_evt_head == 0) { + p_dev_ctl->fc_evt_head = ehp; + p_dev_ctl->fc_evt_tail = ehp; + } else { + ((fcEvent_header *)(p_dev_ctl->fc_evt_tail))->e_next_header = ehp; + p_dev_ctl->fc_evt_tail = (void *)ehp; + } + ehp->e_handle = incr; + ehp->e_mask = offset; + + } + + while(found) { + /* Save event id for C_GET_EVENT */ + buf_info = &bufinfo; + buf_info->virt = 0; + buf_info->phys = 0; + buf_info->flags = (FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + buf_info->align = sizeof(void *); + buf_info->size = sizeof(fcEvent); + buf_info->dma_handle = 0; + + dfc_unlock_enable(ipri, &CMD_LOCK); + fc_malloc(p_dev_ctl, buf_info); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + if (buf_info->virt == NULL) { + rc = EINTR; + break; + } + oep = (fcEvent *)(buf_info->virt); + fc_bzero((char *)oep, sizeof(fcEvent)); + + oep->evt_sleep = 1; + oep->evt_handle = incr; + oep->evt_mask = offset; + switch(offset) { + case FC_REG_CT_EVENT: + oep->evt_type = (uint32)((ulong)cip->c_arg2); /* fstype for CT */ + break; + default: + oep->evt_type = 0; + } + + if(ehp->e_head == 0) { + ehp->e_head = oep; + ehp->e_tail = oep; + } else { + ehp->e_tail->evt_next = (void *)oep; + ehp->e_tail = oep; + } + oep->evt_next = 0; + found--; + } + + switch(offset) { + case FC_REG_CT_EVENT: + case FC_REG_RSCN_EVENT: + case FC_REG_LINK_EVENT: + if(dfc_sleep(p_dev_ctl, ehp)) { + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + rc = EINTR; + /* Remove all eventIds from queue */ + ep = ehp->e_head; + oep = 0; + found = 0; + while(ep) { + if(ep->evt_handle == incr) { + /* dequeue event from event list */ + if(oep == 0) { + ehp->e_head = ep->evt_next; + } + else { + oep->evt_next = ep->evt_next; + } + if(ehp->e_tail == ep) + ehp->e_tail = oep; + evp = ep; + ep = ep->evt_next; + dfc_unlock_enable(ipri, &CMD_LOCK); + buf_info = &bufinfo; + buf_info->virt = (uchar *)evp; + buf_info->size = sizeof(fcEvent); + buf_info->phys = 0; + buf_info->flags = (FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + buf_info->align = 0; + buf_info->dma_handle = 0; + fc_free(p_dev_ctl, buf_info); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + } else { + oep = ep; + ep = ep->evt_next; + } + } + if (ehp->e_head == 0) { + + if (oehp == 0) { + p_dev_ctl->fc_evt_head = ehp->e_next_header; + } else { + oehp->e_next_header = ehp->e_next_header; + } + if (p_dev_ctl->fc_evt_tail == ehp) + p_dev_ctl->fc_evt_tail = oehp; + + dfc_unlock_enable(ipri, &CMD_LOCK); + buf_info = &bufinfo; + buf_info->virt = (uchar *)ehp; + buf_info->size = sizeof(fcEvent_header); + buf_info->phys = 0; + buf_info->flags = (FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + buf_info->align = 0; + buf_info->dma_handle = 0; + fc_free(p_dev_ctl, buf_info); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + } + return(ipri); + } + return(ipri); + } + return(ipri); +} + +int +dfc_hba_sendscsi_fcp( +fc_dev_ctl_t * p_dev_ctl, +struct dfc_mem *dm, +struct cmd_input *cip, +struct dfccmdinfo *infop, +ulong ipri) +{ + static HBA_WWN findwwn; + static DMATCHMAP * fcpmp; + static RING * rp; + static fc_buf_t * fcptr; + static FCP_CMND * fcpCmnd; + static FCP_RSP * fcpRsp; + static ULP_BDE64 * bpl; + static MATCHMAP * bmp; + static DMATCHMAP * outdmp; + static MBUF_INFO * buf_info; + static MBUF_INFO bufinfo; + static uint32 buf1sz; + static uint32 buf2sz; + static uint32 j; + static uint32 * lptr; + static char * bp; + static uint32 max; + static struct { + uint32 rspcnt; + uint32 snscnt; + } count; + static struct dev_info *dev_info; + static FC_BRD_INFO * binfo; + + binfo = &BINFO; + lptr = (uint32 *)&cip->c_string[0]; + buf1sz = *lptr++; /* Request data size */ + buf2sz = *lptr; /* Sns / rsp buffer size */ + if((buf1sz + infop->c_outsz) > (80 * 4096)) { + rc = ERANGE; + return(ipri); + } + + dfc_unlock_enable(ipri, &CMD_LOCK); + if (fc_copyin((uchar *)cip->c_arg3, (uchar *)&findwwn, (ulong)(sizeof(HBA_WWN)))) { + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + rc = EIO; + return(ipri); + } + + buf_info = &bufinfo; + buf_info->virt = 0; + buf_info->phys = 0; + buf_info->flags = (FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + buf_info->align = sizeof(void *); + buf_info->size = sizeof(struct dev_info); + buf_info->dma_handle = 0; + + fc_malloc(p_dev_ctl, buf_info); + if (buf_info->virt == NULL) { + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + rc = ENOMEM; + return(ipri); + } + dev_info = (struct dev_info *)buf_info->virt; + + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + /* Allocate buffer for Buffer ptr list */ + if ((bmp = (MATCHMAP * )fc_mem_get(binfo, MEM_BPL)) == 0) { + rc = ENOMEM; + goto ssout3; + } + bpl = (ULP_BDE64 * )bmp->virt; + dfc_unlock_enable(ipri, &CMD_LOCK); + + if((fcpmp = dfc_fcp_data_alloc(p_dev_ctl, bpl)) == 0) { + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + fc_mem_put(binfo, MEM_BUF, (uchar * )bmp); + rc = ENOMEM; + goto ssout3; + } + bpl += 2; /* Cmnd and Rsp ptrs */ + fcpCmnd = (FCP_CMND *)fcpmp->dfc.virt; + fcpRsp = (FCP_RSP *)((uchar *)fcpCmnd + sizeof(FCP_CMND)); + +{ +lptr = (uint32 *)bmp->virt; +} + if (fc_copyin((uchar *)cip->c_arg1, (uchar *)fcpCmnd, (ulong)(buf1sz))) { + dfc_fcp_data_free(p_dev_ctl, fcpmp); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + fc_mem_put(binfo, MEM_BUF, (uchar * )bmp); + rc = ENOMEM; + goto ssout3; + } +{ +lptr = (uint32 *)fcpCmnd; +} + fc_mpdata_sync(fcpmp->dfc.dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV); + + if(fcpCmnd->fcpCntl3 == WRITE_DATA) { + bp = (uchar *)infop->c_dataout; + } + else { + bp = 0; + } + + if(infop->c_outsz == 0) + outdmp = dfc_cmd_data_alloc(p_dev_ctl, bp, bpl, 512); + else + outdmp = dfc_cmd_data_alloc(p_dev_ctl, bp, bpl, infop->c_outsz); + + if(!(outdmp)) { + dfc_fcp_data_free(p_dev_ctl, fcpmp); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + fc_mem_put(binfo, MEM_BUF, (uchar * )bmp); + rc = ENOMEM; + goto ssout3; + } + + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + max = 0; +redoss: +{ +lptr = (uint32 *)bmp->virt; +} + + if((rc=fc_snd_scsi_req(p_dev_ctl, (NAME_TYPE *)&findwwn, bmp, fcpmp, outdmp, infop->c_outsz, dev_info))) + { + if((rc == ENODEV) && (max < 4)) { + max++; + dfc_unlock_enable(ipri, &CMD_LOCK); + dfc_msdelay(p_dev_ctl, 500); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + goto redoss; + } + if(rc == ENODEV) + rc = EACCES; + dfc_unlock_enable(ipri, &CMD_LOCK); + dfc_cmd_data_free(p_dev_ctl, outdmp); + dfc_fcp_data_free(p_dev_ctl, fcpmp); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + fc_mem_put(binfo, MEM_BUF, (uchar * )bmp); + rc = ENOMEM; + goto ssout3; + } + + rp = &binfo->fc_ring[FC_FCP_RING]; + fcptr = (fc_buf_t *)fcpmp->dfc.virt; + + j = 0; + dfc_unlock_enable(ipri, &CMD_LOCK); + dfc_msdelay(p_dev_ctl, 1); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + /* Wait for FCP I/O to complete or timeout */ + while(dev_info->queue_state == ACTIVE_PASSTHRU) { + dfc_unlock_enable(ipri, &CMD_LOCK); + dfc_msdelay(p_dev_ctl, 50); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + if(j >= 600) { + break; + } + j++; + } + + /* Check for timeout conditions */ + if(dev_info->queue_state == ACTIVE_PASSTHRU) { + /* Free resources */ + fc_deq_fcbuf_active(rp, fcptr->iotag); + rc = ETIMEDOUT; + dfc_unlock_enable(ipri, &CMD_LOCK); + dfc_cmd_data_free(p_dev_ctl, outdmp); + dfc_fcp_data_free(p_dev_ctl, fcpmp); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + goto ssout3; + } + if ((infop->c_cmd == C_HBA_SEND_FCP) && + (dev_info->ioctl_event != IOSTAT_LOCAL_REJECT)) { + if(buf2sz < sizeof(FCP_RSP)) + count.snscnt = buf2sz; + else + count.snscnt = sizeof(FCP_RSP); +{ +lptr = (uint32 *)fcpRsp; +} + dfc_unlock_enable(ipri, &CMD_LOCK); + if (fc_copyout((uchar *)fcpRsp, (uchar *)cip->c_arg2, count.snscnt)) { + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + rc = EIO; + goto ssout0; + } + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + } + + switch(dev_info->ioctl_event) { + case IOSTAT_SUCCESS: +cpdata: + /* copy back response data */ + if(infop->c_outsz < dev_info->clear_count) { + infop->c_outsz = 0; + rc = ERANGE; + goto ssout0; + } + infop->c_outsz = dev_info->clear_count; + + if (infop->c_cmd == C_HBA_SEND_SCSI) { + count.rspcnt = infop->c_outsz; + count.snscnt = 0; + } else { + /* For C_HBA_SEND_FCP, snscnt is already set */ + count.rspcnt = infop->c_outsz; + } + + /* Return data length */ + dfc_unlock_enable(ipri, &CMD_LOCK); + if (fc_copyout((uchar *)&count, (uchar *)cip->c_arg3, (2*sizeof(uint32)))) { + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + rc = EIO; + goto ssout0; + } + + infop->c_outsz = 0; + if(count.rspcnt) { + if(dfc_rsp_data_copy(p_dev_ctl, (uchar *)infop->c_dataout, outdmp, count.rspcnt)) { + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + rc = EIO; + goto ssout0; + } + } + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + break; + case IOSTAT_LOCAL_REJECT: + infop->c_outsz = 0; + if(dev_info->ioctl_errno == IOERR_SEQUENCE_TIMEOUT) { + rc = ETIMEDOUT; + goto ssout0; + } + rc = EFAULT; + goto ssout0; + case IOSTAT_FCP_RSP_ERROR: + j = 0; + + if(fcpCmnd->fcpCntl3 == READ_DATA) { + dev_info->clear_count = infop->c_outsz - dev_info->clear_count; + if ((fcpRsp->rspStatus2 & RESID_UNDER) && + (dev_info->clear_count)) { + goto cpdata; + } + } + else + dev_info->clear_count = 0; + + count.rspcnt = (uint32)dev_info->clear_count; + infop->c_outsz = 0; + + if (fcpRsp->rspStatus2 & RSP_LEN_VALID) { + j = SWAP_DATA(fcpRsp->rspRspLen); + } + if (fcpRsp->rspStatus2 & SNS_LEN_VALID) { + if (infop->c_cmd == C_HBA_SEND_SCSI) { + if(buf2sz < (int)dev_info->sense_length) + count.snscnt = buf2sz; + else + count.snscnt = dev_info->sense_length; + + /* Return sense info from rsp packet */ + dfc_unlock_enable(ipri, &CMD_LOCK); + if (fc_copyout(((uchar *)&fcpRsp->rspInfo0) + j, + (uchar *)cip->c_arg2, count.snscnt)) { + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + rc = EIO; + goto ssout0; + } + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + } + } + else { + rc = EFAULT; + goto ssout0; + } + + /* Return data length */ + dfc_unlock_enable(ipri, &CMD_LOCK); + if (fc_copyout((uchar *)&count, (uchar *)cip->c_arg3, (2*sizeof(uint32)))) { + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + rc = EIO; + goto ssout0; + } + + /* return data for read */ + if(count.rspcnt) { + if(dfc_rsp_data_copy(p_dev_ctl, (uchar *)infop->c_dataout, outdmp, count.rspcnt)) { + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + rc = EIO; + goto ssout0; + } + } + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + break; + + default: + infop->c_outsz = 0; + rc = EFAULT; + goto ssout0; + } + +ssout0: + dfc_unlock_enable(ipri, &CMD_LOCK); + dfc_cmd_data_free(p_dev_ctl, outdmp); + dfc_fcp_data_free(p_dev_ctl, fcpmp); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); +ssout3: + dfc_unlock_enable(ipri, &CMD_LOCK); + buf_info->size = sizeof(struct dev_info); + buf_info->virt = (uint32 * )dev_info; + buf_info->phys = 0; + buf_info->flags = (FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + + fc_free(p_dev_ctl, buf_info); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + return(ipri); +} + +int +dfc_hba_fcpbind( +fc_dev_ctl_t * p_dev_ctl, +struct dfc_mem *dm, +struct cmd_input *cip, +struct dfccmdinfo *infop, +ulong ipri) +{ + static HBA_FCPBINDING * hb; + static HBA_FCPBINDINGENTRY *ep; + static uint32 room; + static uint32 total; + static uint32 lunIndex, totalLuns; /* these 2 vars are per target id */ + static uint32 lunId; /* what we get back at lunIndex in virtRptLunData */ + static int memsz, mapList; + static char *appPtr; + static uint32 cnt; + static node_t * nodep; + static dvi_t * dev_ptr; + static uint32 total_mem; + static uint32 offset, j; + static NODELIST * nlp; + static FC_BRD_INFO * binfo; + + binfo = &BINFO; + hb = (HBA_FCPBINDING *)dm->fc_dataout; + ep = &hb->entry[0]; + room = (uint32)((ulong)cip->c_arg1); + cnt = 0; + total = 0; + memsz = 0; + lunIndex = 0; + totalLuns = 0; + appPtr = ((char *)infop->c_dataout) + sizeof(ulong); + mapList = 1; + + /* First Mapped ports, then unMapped ports, then binding list */ + nlp = binfo->fc_nlpmap_start; + if(nlp == (NODELIST *)&binfo->fc_nlpmap_start) { + nlp = binfo->fc_nlpunmap_start; + mapList = 0; + } + if(nlp == (NODELIST *)&binfo->fc_nlpunmap_start) + nlp = binfo->fc_nlpbind_start; + while(nlp != (NODELIST *)&binfo->fc_nlpbind_start) { + + if (nlp->nlp_type & NLP_SEED_MASK) { + offset = FC_SCSID(nlp->id.nlp_pan, nlp->id.nlp_sid); + if(offset > MAX_FC_TARGETS) { + goto nextbind; + } + nodep = binfo->device_queue_hash[offset].node_ptr; + if(nodep) + dev_ptr = nodep->lunlist; + else + dev_ptr = 0; + + if((!nodep) || (!dev_ptr)) { + dev_ptr=fc_alloc_devp(p_dev_ctl, offset, 0); + nodep = dev_ptr->nodep; + } + + if(mapList) { + /* For devices on the map list, we need to issue REPORT_LUN + * in case the device's config has changed */ + nodep->rptlunstate = REPORT_LUN_ONGOING; + issue_report_lun(p_dev_ctl, dev_ptr, 0); + + j = 0; + dfc_unlock_enable(ipri, &CMD_LOCK); + dfc_msdelay(p_dev_ctl, 1); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + /* Wait for ReportLun request to complete or timeout */ + while(nodep->rptlunstate == REPORT_LUN_ONGOING) { + dfc_unlock_enable(ipri, &CMD_LOCK); + dfc_msdelay(p_dev_ctl, 50); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + if(j >= 600) { + break; + } + j++; + } + if(nodep->rptlunstate == REPORT_LUN_ONGOING) { + break; + } + /* + * If nodep->virtRptLunData is null, then we just report 1 lun. + * If not null, we will report luns from virtRptLunData buffer. + */ + lunIndex = 0; + totalLuns = 1; + dev_ptr = 0; + if (nodep->virtRptLunData) { + uint32 *tmp; + tmp = (uint32*)nodep->virtRptLunData; + totalLuns = SWAP_DATA(*tmp) / 8; + } + } + + while(((mapList) && (lunIndex < totalLuns)) || + (dev_ptr)) { + if(mapList) { + lunId = dfc_getLunId(nodep, lunIndex); + dev_ptr = fc_find_lun(binfo, offset, lunId); + } else + lunId = dev_ptr->lun_id; + + if((mapList) || + ((dev_ptr) && (dev_ptr->opened))) + { + if(cnt < room) { + HBA_OSDN *osdn; + HBA_UINT32 fcpLun[2]; + if(total_mem - memsz < sizeof(HBA_FCPBINDINGENTRY)) { + dfc_unlock_enable(ipri, &CMD_LOCK); + fc_copyout((char *)(&hb->entry[0]), appPtr, memsz); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + appPtr = appPtr + memsz; + ep = &hb->entry[0]; + memsz = 0; + } + fc_bzero((void *)ep->ScsiId.OSDeviceName, 256); + if(nlp->nlp_flag & NLP_MAPPED) { + osdn = (HBA_OSDN *)&ep->ScsiId.OSDeviceName[0]; + fc_bcopy("lpfc", osdn->drvname, 4); + osdn->instance = fc_brd_to_inst(binfo->fc_brd_no); + osdn->target = FC_SCSID(nlp->id.nlp_pan, nlp->id.nlp_sid); + osdn->lun = (HBA_UINT32)(lunId); + } + + ep->ScsiId.ScsiTargetNumber = + FC_SCSID(nlp->id.nlp_pan, nlp->id.nlp_sid); + ep->ScsiId.ScsiOSLun = (HBA_UINT32)(lunId); + ep->ScsiId.ScsiBusNumber = 0; + + fc_bzero((char *)fcpLun, sizeof(HBA_UINT64)); + fcpLun[0] = (lunId << FC_LUN_SHIFT); + if (nodep->addr_mode == VOLUME_SET_ADDRESSING) { + fcpLun[0] |= SWAP_DATA(0x40000000); + } + fc_bcopy((char *)&fcpLun[0], (char *)&ep->FcpId.FcpLun, sizeof(HBA_UINT64)); + if (nlp->nlp_type & NLP_SEED_DID) { + ep->type = TO_D_ID; + ep->FcpId.FcId = nlp->nlp_DID; + ep->FcId = nlp->nlp_DID; + fc_bzero((uchar *)&ep->FcpId.PortWWN, sizeof(HBA_WWN)); + fc_bzero((uchar *)&ep->FcpId.NodeWWN, sizeof(HBA_WWN)); + } + else { + ep->type = TO_WWN; + ep->FcId = 0; + ep->FcpId.FcId = 0; + if (nlp->nlp_type & NLP_SEED_WWPN) + fc_bcopy(&nlp->nlp_portname, (uchar *)&ep->FcpId.PortWWN, sizeof(HBA_WWN)); + else + fc_bcopy(&nlp->nlp_nodename, (uchar *)&ep->FcpId.NodeWWN, sizeof(HBA_WWN)); + } + if (nlp->nlp_state == NLP_ALLOC) { + ep->FcpId.FcId = nlp->nlp_DID; + fc_bcopy(&nlp->nlp_portname, (uchar *)&ep->FcpId.PortWWN, sizeof(HBA_WWN)); + fc_bcopy(&nlp->nlp_nodename, (uchar *)&ep->FcpId.NodeWWN, sizeof(HBA_WWN)); + } + ep++; + cnt++; + memsz = memsz + sizeof(HBA_FCPBINDINGENTRY); + total++; + } + } + if(mapList) { + /* for map list, we want the while loop to go stricly + * based on lunIndex and totalLuns. */ + lunIndex++; + dev_ptr = 0; + } else + dev_ptr = dev_ptr->next; + } /* while loop */ + } + +nextbind: + nlp = (NODELIST *)nlp->nlp_listp_next; + if(nlp == (NODELIST *)&binfo->fc_nlpmap_start) { + nlp = binfo->fc_nlpunmap_start; + mapList = 0; + } + if(nlp == (NODELIST *)&binfo->fc_nlpunmap_start) + nlp = binfo->fc_nlpbind_start; + } + + dfc_unlock_enable(ipri, &CMD_LOCK); + fc_copyout((char *)(&hb->entry[0]), appPtr, memsz); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + hb->NumberOfEntries = (HBA_UINT32)total; + dfc_unlock_enable(ipri, &CMD_LOCK); + fc_copyout((char *)(&hb->NumberOfEntries), infop->c_dataout, sizeof(ulong)); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + infop->c_outsz = 0; + if (total > room) { + rc = ERANGE; + do_cp = 1; + } + return (ipri); +} + +int +dfc_hba_sendmgmt_ct( +fc_dev_ctl_t * p_dev_ctl, +struct dfc_mem *dm, +struct cmd_input *cip, +struct dfccmdinfo *infop, +ulong ipri) + +{ + static ULP_BDE64 * bpl; + static MATCHMAP * bmp; + static DMATCHMAP * indmp; + static DMATCHMAP * outdmp; + static uint32 portid; + static HBA_WWN findwwn; + static uint32 buf1sz; + static uint32 buf2sz; + static int j; + static uint32 max; + static uint32 incr; + static uint32 * lptr; + static NODELIST * nlp; + static FC_BRD_INFO * binfo; + + binfo = &BINFO; + incr = (uint32)cip->c_flag; /* timeout for CT request */ + lptr = (uint32 *)&cip->c_string[0]; + buf1sz = *lptr++; + buf2sz = *lptr; + + if((buf1sz == 0) || + (buf2sz == 0) || + (buf1sz + buf2sz > (80 * 4096))) { + rc = ERANGE; + return(ipri); + } + + dfc_unlock_enable(ipri, &CMD_LOCK); + + if(infop->c_cmd == C_SEND_MGMT_CMD) { + if (fc_copyin((uchar *)cip->c_arg3, (uchar *)&findwwn, (ulong)(sizeof(HBA_WWN)))) { + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + rc = EIO; + return(ipri); + } + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + /* First Mapped ports, then unMapped ports */ + nlp = binfo->fc_nlpmap_start; + if(nlp == (NODELIST *)&binfo->fc_nlpmap_start) + nlp = binfo->fc_nlpunmap_start; + while(nlp != (NODELIST *)&binfo->fc_nlpunmap_start) { + if (fc_geportname(&nlp->nlp_portname, (NAME_TYPE *)&findwwn) == 2) + goto gotit; + nlp = (NODELIST *)nlp->nlp_listp_next; + if(nlp == (NODELIST *)&binfo->fc_nlpmap_start) + nlp = binfo->fc_nlpunmap_start; + } + rc = ERANGE; + return(ipri); +gotit: + portid = nlp->nlp_DID; + dfc_unlock_enable(ipri, &CMD_LOCK); + } + else { + portid = (uint32)((ulong)cip->c_arg3); + } + + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + /* Allocate buffer for Buffer ptr list */ + if ((bmp = (MATCHMAP * )fc_mem_get(binfo, MEM_BPL)) == 0) { + rc = ENOMEM; + return(ipri); + } + bpl = (ULP_BDE64 * )bmp->virt; + dfc_unlock_enable(ipri, &CMD_LOCK); + + if((indmp = dfc_cmd_data_alloc(p_dev_ctl, (uchar *)cip->c_arg1, bpl, buf1sz)) == 0) { + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + fc_mem_put(binfo, MEM_BPL, (uchar * )bmp); + rc = ENOMEM; + return(ipri); + } + bpl += indmp->dfc_flag; + + if((outdmp = dfc_cmd_data_alloc(p_dev_ctl, 0, bpl, buf2sz)) == 0) { + dfc_cmd_data_free(p_dev_ctl, indmp); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + fc_mem_put(binfo, MEM_BPL, (uchar * )bmp); + rc = ENOMEM; + return(ipri); + } + + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + max = 0; +redoct: + if((rc=fc_issue_ct_req(binfo, portid, bmp, indmp, outdmp, incr))) { + if((rc == ENODEV) && (max < 4)) { + max++; + dfc_unlock_enable(ipri, &CMD_LOCK); + dfc_msdelay(p_dev_ctl, 500); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + goto redoct; + } + if(rc == ENODEV) + rc = EACCES; + goto ctout1; + } + + j = 0; + dfc_unlock_enable(ipri, &CMD_LOCK); + dfc_msdelay(p_dev_ctl, 1); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + /* Wait for CT request to complete or timeout */ + while(outdmp->dfc_flag == 0) { + dfc_unlock_enable(ipri, &CMD_LOCK); + dfc_msdelay(p_dev_ctl, 50); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + if(j >= 600) { + outdmp->dfc_flag = -1; + break; + } + j++; + } + + j = outdmp->dfc_flag; + if(j == -1) { + rc = ETIMEDOUT; + goto ctout1; + } + + if(j == -2) { + rc = EFAULT; + goto ctout1; + } + + /* copy back response data */ + if(j > buf2sz) { + rc = ERANGE; + /* C_CT Request error */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk1208, /* ptr to msg structure */ + fc_mes1208, /* ptr to msg */ + fc_msgBlk1208.msgPreambleStr, /* begin varargs */ + outdmp->dfc_flag, + 4096); /* end varargs */ + goto ctout1; + } + fc_bcopy((char *)&j, dm->fc_dataout, sizeof(int)); + + /* copy back data */ + dfc_unlock_enable(ipri, &CMD_LOCK); + if(dfc_rsp_data_copy(p_dev_ctl, (uchar *)cip->c_arg2, outdmp, j)) + rc = EIO; + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + +ctout1: + dfc_unlock_enable(ipri, &CMD_LOCK); + dfc_cmd_data_free(p_dev_ctl, indmp); + dfc_cmd_data_free(p_dev_ctl, outdmp); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + fc_mem_put(binfo, MEM_BPL, (uchar * )bmp); + return(ipri); +} + +int +dfc_hba_rnid( +fc_dev_ctl_t * p_dev_ctl, +struct dfc_mem *dm, +struct cmd_input *cip, +struct dfccmdinfo *infop, +MBUF_INFO *buf_info, +ulong ipri) +{ + static HBA_WWN findwwn; + static ELS_PKT * ep; + static DMATCHMAP inmatp; + static DMATCHMAP outmatp; + static MATCHMAP * bmptr; + static uint32 * lptr; + static NODELIST * nlp; + static int j; + static uint32 size, incr; + static uint32 max; + static FC_BRD_INFO * binfo; + + binfo = &BINFO; + dfc_unlock_enable(ipri, &CMD_LOCK); + if (fc_copyin((uchar *)cip->c_arg1, (uchar *)&findwwn, (ulong)(sizeof(HBA_WWN)))) { + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + rc = EIO; + return(ipri); + } + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + size = NLP_ALLOC; + incr = 0; +nlpchk: + nlp = binfo->fc_nlpbind_start; + if(nlp == (NODELIST *)&binfo->fc_nlpbind_start) + nlp = binfo->fc_nlpunmap_start; + if(nlp == (NODELIST *)&binfo->fc_nlpunmap_start) + nlp = binfo->fc_nlpmap_start; + while(nlp != (NODELIST *)&binfo->fc_nlpmap_start) { + if(cip->c_flag == NODE_WWN) { + if (fc_geportname(&nlp->nlp_nodename, (NAME_TYPE *)&findwwn) == 2) + goto foundrnid; + } + else { + if (fc_geportname(&nlp->nlp_portname, (NAME_TYPE *)&findwwn) == 2) + goto foundrnid; + } + nlp = (NODELIST *)nlp->nlp_listp_next; + if(nlp == (NODELIST *)&binfo->fc_nlpbind_start) + nlp = binfo->fc_nlpunmap_start; + if(nlp == (NODELIST *)&binfo->fc_nlpunmap_start) + nlp = binfo->fc_nlpmap_start; + } + rc = ERANGE; + return(ipri); + +foundrnid: + if(nlp->nlp_action & NLP_DO_RNID) + goto waitloop; + + if(nlp->nlp_Rpi == 0) { + int wait_sec; + + size = nlp->nlp_DID; + if(size == 0) { + size = nlp->nlp_oldDID; + } + if((size == 0) || (size == 0xffffffff) || (size == 0xffffff) || + (incr == 3)) { + rc = ERANGE; + return(ipri); + } + incr++; + nlp->nlp_action |= NLP_DO_RNID; + fc_els_cmd(binfo, ELS_CMD_PLOGI, (void *)((ulong)size), + (uint32)0, (ushort)0, nlp); +waitloop: + wait_sec = 0; + while(nlp->nlp_action & NLP_DO_RNID) { + dfc_unlock_enable(ipri, &CMD_LOCK); + dfc_msdelay(p_dev_ctl, 1000); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + if(wait_sec++ == 10) + return(ipri); + } + nlp->nlp_action &= ~NLP_DO_RNID; + goto nlpchk; + } + + buf_info->virt = 0; + buf_info->phys = 0; + buf_info->flags = (FC_MBUF_DMA | FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + buf_info->align = (int)FCELSSIZE; + buf_info->size = (int)FCELSSIZE; + buf_info->dma_handle = 0; + + dfc_unlock_enable(ipri, &CMD_LOCK); + fc_malloc(p_dev_ctl, buf_info); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + if (buf_info->phys == NULL) { + rc = ENOMEM; + return(ipri); + } + inmatp.dfc.virt = buf_info->virt; + if (buf_info->dma_handle) { + inmatp.dfc.dma_handle = buf_info->dma_handle; + inmatp.dfc.data_handle = buf_info->data_handle; + } + inmatp.dfc.phys = (uchar * )buf_info->phys; + + /* Save size of RNID request in this field */ + inmatp.dfc.fc_mptr = (uchar *)((ulong)(2*sizeof(uint32))); + fc_bzero((void *)inmatp.dfc.virt, (2 * sizeof(uint32))); + + buf_info->virt = 0; + buf_info->phys = 0; + buf_info->flags = (FC_MBUF_DMA | FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + buf_info->align = 4096; + buf_info->size = infop->c_outsz + sizeof(uint32); + buf_info->dma_handle = 0; + + dfc_unlock_enable(ipri, &CMD_LOCK); + fc_malloc(p_dev_ctl, buf_info); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + if (buf_info->phys == NULL) { + rc = ENOMEM; + goto rnidout2; + } + outmatp.dfc.virt = buf_info->virt; + if (buf_info->dma_handle) { + outmatp.dfc.dma_handle = buf_info->dma_handle; + outmatp.dfc.data_handle = buf_info->data_handle; + } + outmatp.dfc.phys = (uchar * )buf_info->phys; + + /* Save size in this field */ + outmatp.dfc.fc_mptr = (uchar *)((ulong)(infop->c_outsz + sizeof(uint32))); + + /* Setup RNID command */ + lptr = (uint32 *)inmatp.dfc.virt; + *lptr = ELS_CMD_RNID; + ep = (ELS_PKT * )lptr; + ep->un.rnid.Format = RNID_TOPOLOGY_DISC; + + max = 0; + bmptr = 0; +redornid: + outmatp.dfc_flag = 0; + if((rc=fc_rnid_req( binfo, &inmatp, &outmatp, &bmptr, nlp->nlp_Rpi))) { + if(bmptr) + fc_mem_put(binfo, MEM_BPL, (uchar * )bmptr); + + if((rc == ENODEV) && (max < 4)) { + max++; + dfc_unlock_enable(ipri, &CMD_LOCK); + dfc_msdelay(p_dev_ctl, 500); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + goto redornid; + } + if(rc == ENODEV) + rc = EACCES; + goto rnidout1; + } + + j = 0; + dfc_unlock_enable(ipri, &CMD_LOCK); + dfc_msdelay(p_dev_ctl, 1); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + /* Wait for RNID request to complete or timeout */ + while(outmatp.dfc_flag == 0) { + dfc_unlock_enable(ipri, &CMD_LOCK); + dfc_msdelay(p_dev_ctl, 50); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + if(j >= 600) { + outmatp.dfc_flag = -1; + return(ipri); + } + j++; + } + + if(bmptr) + fc_mem_put(binfo, MEM_BPL, (uchar * )bmptr); + + j = (int)((ulong)outmatp.dfc_flag); + if(outmatp.dfc_flag == -1) { + + rc = ETIMEDOUT; + goto rnidout1; + } + + if(outmatp.dfc_flag == -2) { + + rc = EFAULT; + goto rnidout1; + } + + /* copy back response data */ + if(j > 4096) { + rc = ERANGE; + /* RNID Request error */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk1209, /* ptr to msg structure */ + fc_mes1209, /* ptr to msg */ + fc_msgBlk1209.msgPreambleStr, /* begin varargs */ + (int)((ulong)outmatp.dfc.fc_mptr), + 4096); /* end varargs */ + goto rnidout1; + } + lptr = (uint32 *)outmatp.dfc.virt; + if(*lptr != ELS_CMD_ACC) { + rc = EFAULT; + goto rnidout1; + } + lptr++; + j -= sizeof(uint32); + fc_bcopy((char *)lptr, dm->fc_dataout, j); + + /* copy back size of response */ + dfc_unlock_enable(ipri, &CMD_LOCK); + if (fc_copyout((uchar *)&j, (uchar *)cip->c_arg2, sizeof(int))) { + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + rc = EIO; + goto rnidout1; + } + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + infop->c_outsz = (uint32)((ulong)outmatp.dfc.fc_mptr); + +rnidout1: + buf_info->size = (int)((ulong)outmatp.dfc.fc_mptr); + buf_info->virt = (uint32 * )outmatp.dfc.virt; + buf_info->phys = (uint32 * )outmatp.dfc.phys; + buf_info->flags = (FC_MBUF_DMA | FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + if (outmatp.dfc.dma_handle) { + buf_info->dma_handle = outmatp.dfc.dma_handle; + buf_info->data_handle = outmatp.dfc.data_handle; + } + dfc_unlock_enable(ipri, &CMD_LOCK); + fc_free(p_dev_ctl, buf_info); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + +rnidout2: + buf_info->size = (int)((ulong)inmatp.dfc.fc_mptr); + buf_info->virt = (uint32 * )inmatp.dfc.virt; + buf_info->phys = (uint32 * )inmatp.dfc.phys; + buf_info->flags = (FC_MBUF_DMA | FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + if (inmatp.dfc.dma_handle) { + buf_info->dma_handle = inmatp.dfc.dma_handle; + buf_info->data_handle = inmatp.dfc.data_handle; + } + dfc_unlock_enable(ipri, &CMD_LOCK); + fc_free(p_dev_ctl, buf_info); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + return(ipri); +} + +int +dfc_hba_targetmapping( +fc_dev_ctl_t * p_dev_ctl, +struct dfc_mem *dm, +struct cmd_input *cip, +struct dfccmdinfo *infop, +ulong ipri) +{ + static HBA_FCPTARGETMAPPING * hf; + static HBA_FCPSCSIENTRY *ep; + static uint32 room; + static uint32 total; + static uint32 lunIndex, totalLuns; /* these 2 vars are per target id */ + static uint32 lunId; /* what we get back at lunIndex in virtRptLunData */ + static int memsz; + static char *appPtr; + static NODELIST * nlp; + static node_t * nodep; + static dvi_t * dev_ptr; + static FC_BRD_INFO * binfo; + static uint32 offset; + static uint32 total_mem; + static uint32 j; + static uint32 cnt; + + binfo = &BINFO; + hf = (HBA_FCPTARGETMAPPING *)dm->fc_dataout; + ep = &hf->entry[0]; + room = (uint32)((ulong)cip->c_arg1); + cnt = 0; + total = 0; + memsz = 0; + appPtr = ((char *)infop->c_dataout) + sizeof(ulong); + + /* Mapped ports only */ + nlp = binfo->fc_nlpmap_start; + while(nlp != (NODELIST *)&binfo->fc_nlpmap_start) { + offset = FC_SCSID(nlp->id.nlp_pan, nlp->id.nlp_sid); + if(offset > MAX_FC_TARGETS) { + nlp = (NODELIST *)nlp->nlp_listp_next; + continue; + } + nodep = binfo->device_queue_hash[offset].node_ptr; + if(nodep) + dev_ptr = nodep->lunlist; + else + dev_ptr = 0; + + if((!nodep) || (!dev_ptr)) { + dev_ptr=fc_alloc_devp(p_dev_ctl, offset, 0); + nodep = dev_ptr->nodep; + } + + /* we need to issue REPORT_LUN here in case the device's + * config has changed */ + nodep->rptlunstate = REPORT_LUN_ONGOING; + issue_report_lun(p_dev_ctl, dev_ptr, 0); + + j = 0; + dfc_unlock_enable(ipri, &CMD_LOCK); + dfc_msdelay(p_dev_ctl, 1); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + /* Wait for ReportLun request to complete or timeout */ + while(nodep->rptlunstate == REPORT_LUN_ONGOING) { + dfc_unlock_enable(ipri, &CMD_LOCK); + dfc_msdelay(p_dev_ctl, 50); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + if(j >= 600) { + break; + } + j++; + } + if(nodep->rptlunstate == REPORT_LUN_ONGOING) { + break; + } + + lunIndex = 0; + totalLuns = 1; + if (nodep->virtRptLunData) { + uint32 *tmp; + tmp = (uint32*)nodep->virtRptLunData; + totalLuns = SWAP_DATA(*tmp) / 8; + } + + while(lunIndex < totalLuns) { + lunId = dfc_getLunId(nodep, lunIndex); + dev_ptr = fc_find_lun(binfo, offset, lunId); + + if((!dev_ptr) || + ((dev_ptr) && (dev_ptr->opened) && (dev_ptr->queue_state == ACTIVE))) { + if(cnt < room) { + HBA_OSDN *osdn; + HBA_UINT32 fcpLun[2]; + + if(total_mem - memsz < sizeof(HBA_FCPSCSIENTRY)) { + dfc_unlock_enable(ipri, &CMD_LOCK); + fc_copyout((char *)(&hf->entry[0]), appPtr,memsz); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + appPtr = appPtr + memsz; + ep = &hf->entry[0]; + memsz = 0; + } + + fc_bzero((void *)ep->ScsiId.OSDeviceName, 256); + osdn = (HBA_OSDN *)&ep->ScsiId.OSDeviceName[0]; + fc_bcopy("lpfc", osdn->drvname, 4); + osdn->instance = fc_brd_to_inst(binfo->fc_brd_no); + osdn->target = FC_SCSID(nlp->id.nlp_pan, nlp->id.nlp_sid); + osdn->lun = (HBA_UINT32)(lunId); + osdn->flags = 0; + ep->ScsiId.ScsiTargetNumber = + FC_SCSID(nlp->id.nlp_pan, nlp->id.nlp_sid); + ep->ScsiId.ScsiOSLun = (HBA_UINT32)(lunId); + ep->ScsiId.ScsiBusNumber = 0; + ep->FcpId.FcId = nlp->nlp_DID; + fc_bzero((char *)fcpLun, sizeof(HBA_UINT64)); + + fcpLun[0] = (lunId << FC_LUN_SHIFT); + if (nodep->addr_mode == VOLUME_SET_ADDRESSING) { + fcpLun[0] |= SWAP_DATA(0x40000000); + } + fc_bcopy((char *)&fcpLun[0], (char *)&ep->FcpId.FcpLun, sizeof(HBA_UINT64)); + fc_bcopy(&nlp->nlp_portname, (uchar *)&ep->FcpId.PortWWN, sizeof(HBA_WWN)); + fc_bcopy(&nlp->nlp_nodename, (uchar *)&ep->FcpId.NodeWWN, sizeof(HBA_WWN)); + cnt++; + ep++; + memsz = memsz + sizeof(HBA_FCPSCSIENTRY); + } + total++; + } + lunIndex++; + } + nlp = (NODELIST *)nlp->nlp_listp_next; + } + dfc_unlock_enable(ipri, &CMD_LOCK); + fc_copyout((char *)(&hf->entry[0]), appPtr,memsz); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + hf->NumberOfEntries = (HBA_UINT32)total; + dfc_unlock_enable(ipri, &CMD_LOCK); + fc_copyout((char *)(&hf->NumberOfEntries), infop->c_dataout, sizeof(ulong)); + ipri = dfc_disable_lock(FC_LVL, &CMD_LOCK); + + infop->c_outsz = 0; /* no more copy needed */ + if (total > room) { + rc = ERANGE; + do_cp = 1; + } + return(ipri); +} + +int +dfc_data_alloc( +fc_dev_ctl_t * p_dev_ctl, +struct dfc_mem *dm, +uint32 size) +{ + static FC_BRD_INFO * binfo; +#ifndef powerpc + static MBUF_INFO * buf_info; + static MBUF_INFO bufinfo; +#endif + + binfo = &BINFO; + + if(dm->fc_dataout) + return(EACCES); + +#ifdef powerpc + dm->fc_dataout = p_dev_ctl->dfc_kernel_buf; + dm->fc_outsz = size; +#else + size = ((size + 0xfff) & 0xfffff000); + buf_info = &bufinfo; + buf_info->virt = 0; + buf_info->phys = 0; + buf_info->flags = (FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + buf_info->align = sizeof(void *); + buf_info->size = (int)size; + buf_info->dma_handle = 0; + + fc_malloc(p_dev_ctl, buf_info); + if (buf_info->virt == NULL) { + return(ENOMEM); + } + dm->fc_dataout = buf_info->virt; + dm->fc_outsz = size; + /* dfc_data_alloc */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0402, /* ptr to msg structure */ + fc_mes0402, /* ptr to msg */ + fc_msgBlk0402.msgPreambleStr, /* begin varargs */ + (uint32)((ulong)dm->fc_dataout), + dm->fc_outsz); /* end varargs */ +#endif + + return(0); +} + +int +dfc_data_free( +fc_dev_ctl_t * p_dev_ctl, +struct dfc_mem *dm) +{ + static FC_BRD_INFO * binfo; +#ifndef powerpc + static MBUF_INFO * buf_info; + static MBUF_INFO bufinfo; +#endif + + binfo = &BINFO; + + /* dfc_data_free */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0403, /* ptr to msg structure */ + fc_mes0403, /* ptr to msg */ + fc_msgBlk0403.msgPreambleStr, /* begin varargs */ + (uint32)((ulong)dm->fc_dataout), + dm->fc_outsz); /* end varargs */ + if(dm->fc_dataout == 0) + return(EACCES); + +#ifdef powerpc + dm->fc_dataout = 0; + dm->fc_outsz = 0; +#else + buf_info = &bufinfo; + buf_info->virt = dm->fc_dataout; + buf_info->size = dm->fc_outsz; + buf_info->phys = 0; + buf_info->flags = (FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + buf_info->align = 0; + buf_info->dma_handle = 0; + fc_free(p_dev_ctl, buf_info); + dm->fc_dataout = 0; + dm->fc_outsz = 0; +#endif + return(0); +} + +DMATCHMAP * +dfc_cmd_data_alloc( +fc_dev_ctl_t * p_dev_ctl, +uchar * indataptr, +ULP_BDE64 * bpl, +uint32 size) +{ + static FC_BRD_INFO * binfo; + static MBUF_INFO * buf_info; + static MBUF_INFO bufinfo; + static DMATCHMAP * mlist; + static DMATCHMAP * mlast; + static DMATCHMAP * dmp; + static int cnt, offset, i; + + binfo = &BINFO; + buf_info = &bufinfo; + mlist = 0; + mlast = 0; + i = 0; + offset = 0; + + while(size) { + + if(size > 4096) + cnt = 4096; + else + cnt = size; + + /* allocate DMATCHMAP buffer header */ + buf_info->virt = 0; + buf_info->phys = 0; + buf_info->flags = (FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + buf_info->align = (int)sizeof(long); + buf_info->size = (int)sizeof(DMATCHMAP); + buf_info->dma_handle = 0; + + fc_malloc(p_dev_ctl, buf_info); + + if (buf_info->virt == NULL) { + goto out; + } + dmp = buf_info->virt; + dmp->dfc.fc_mptr = 0; + dmp->dfc.virt = 0; + + /* Queue it to a linked list */ + if(mlast == 0) { + mlist = dmp; + mlast = dmp; + } + else { + mlast->dfc.fc_mptr = (uchar *)dmp; + mlast = dmp; + } + dmp->dfc.fc_mptr = 0; + + /* allocate buffer */ + buf_info->virt = 0; + buf_info->phys = 0; + buf_info->flags = (FC_MBUF_DMA | FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + buf_info->align = (int)4096; + buf_info->size = (int)cnt; + buf_info->dma_handle = 0; + + fc_malloc(p_dev_ctl, buf_info); + + if (buf_info->phys == NULL) { + goto out; + } + dmp->dfc.virt = buf_info->virt; + if (buf_info->dma_handle) { + dmp->dfc.dma_handle = buf_info->dma_handle; + dmp->dfc.data_handle = buf_info->data_handle; + } + dmp->dfc.phys = (uchar * )buf_info->phys; + dmp->dfc_size = cnt; + + if(indataptr) { + /* Copy data from user space in */ + if (fc_copyin((indataptr+offset), (uchar *)dmp->dfc.virt, (ulong)cnt)) { + goto out; + } + bpl->tus.f.bdeFlags = 0; + fc_mpdata_sync(dmp->dfc.dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV); + } + else { + bpl->tus.f.bdeFlags = BUFF_USE_RCV; + } + + /* build buffer ptr list for IOCB */ + bpl->addrLow = PCIMEM_LONG(putPaddrLow((ulong)dmp->dfc.phys)); + bpl->addrHigh = PCIMEM_LONG(putPaddrHigh((ulong)dmp->dfc.phys)); + bpl->tus.f.bdeSize = (ushort)cnt; + bpl->tus.w = PCIMEM_LONG(bpl->tus.w); + bpl++; + + i++; + offset += cnt; + size -= cnt; + } + + mlist->dfc_flag = i; + return(mlist); +out: + dfc_cmd_data_free(p_dev_ctl, mlist); + return(0); +} + +DMATCHMAP * +dfc_fcp_data_alloc( +fc_dev_ctl_t * p_dev_ctl, +ULP_BDE64 * bpl) +{ + static DMATCHMAP * fcpmp; + static fc_buf_t * fcptr; + static FC_BRD_INFO * binfo; + static MBUF_INFO * buf_info; + static MBUF_INFO bufinfo; + + binfo = &BINFO; + buf_info = &bufinfo; + + /* allocate DMATCHMAP buffer header */ + buf_info->virt = 0; + buf_info->phys = 0; + buf_info->flags = (FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + buf_info->align = (int)sizeof(long); + buf_info->size = (int)sizeof(DMATCHMAP); + buf_info->dma_handle = 0; + + fc_malloc(p_dev_ctl, buf_info); + + if (buf_info->virt == NULL) { + return(0); + } + fcpmp = buf_info->virt; + fc_bzero((char *)fcpmp, sizeof(DMATCHMAP)); + + /* allocate buffer */ + buf_info->virt = 0; + buf_info->phys = 0; + buf_info->flags = (FC_MBUF_DMA | FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + buf_info->align = (int)4096; + buf_info->size = (int)4096; + buf_info->dma_handle = 0; + + fc_malloc(p_dev_ctl, buf_info); + + if (buf_info->phys == NULL) { + buf_info->flags = (FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + buf_info->size = (int)sizeof(DMATCHMAP); + buf_info->virt = (uint32 * )fcpmp; + buf_info->phys = (uint32 * )0; + buf_info->dma_handle = 0; + buf_info->data_handle = 0; + fc_free(p_dev_ctl, buf_info); + return(0); + } + fcpmp->dfc.virt = buf_info->virt; + if (buf_info->dma_handle) { + fcpmp->dfc.dma_handle = buf_info->dma_handle; + fcpmp->dfc.data_handle = buf_info->data_handle; + } + fcpmp->dfc.phys = (uchar * )buf_info->phys; + fcpmp->dfc_size = 4096; + fc_bzero((char *)fcpmp->dfc.virt, 4096); + + fcptr = (fc_buf_t *)fcpmp->dfc.virt; + fcptr->phys_adr = (char *)fcpmp->dfc.phys; + + bpl->addrHigh = PCIMEM_LONG((uint32)putPaddrHigh(GET_PAYLOAD_PHYS_ADDR(fcptr))); + bpl->addrLow = PCIMEM_LONG((uint32)putPaddrLow(GET_PAYLOAD_PHYS_ADDR(fcptr))); + bpl->tus.f.bdeSize = sizeof(FCP_CMND); + bpl->tus.f.bdeFlags = BUFF_USE_CMND; + bpl->tus.w = PCIMEM_LONG(bpl->tus.w); + bpl++; + bpl->addrHigh = PCIMEM_LONG((uint32)putPaddrHigh(GET_PAYLOAD_PHYS_ADDR(fcptr)+sizeof(FCP_CMND))); + bpl->addrLow = PCIMEM_LONG((uint32)putPaddrLow(GET_PAYLOAD_PHYS_ADDR(fcptr)+sizeof(FCP_CMND))); + bpl->tus.f.bdeSize = sizeof(FCP_RSP); + bpl->tus.f.bdeFlags = (BUFF_USE_CMND | BUFF_USE_RCV); + bpl->tus.w = PCIMEM_LONG(bpl->tus.w); + return(fcpmp); +} + +int +dfc_fcp_data_free( +fc_dev_ctl_t * p_dev_ctl, +DMATCHMAP * fcpmp) +{ + static FC_BRD_INFO * binfo; + static MBUF_INFO * buf_info; + static MBUF_INFO bufinfo; + + binfo = &BINFO; + buf_info = &bufinfo; + + if(fcpmp->dfc.virt) { + buf_info->size = fcpmp->dfc_size; + buf_info->virt = (uint32 * )fcpmp->dfc.virt; + buf_info->phys = (uint32 * )fcpmp->dfc.phys; + buf_info->flags = (FC_MBUF_DMA | FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + if (fcpmp->dfc.dma_handle) { + buf_info->dma_handle = fcpmp->dfc.dma_handle; + buf_info->data_handle = fcpmp->dfc.data_handle; + } + fc_free(p_dev_ctl, buf_info); + } + buf_info->flags = (FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + buf_info->size = (int)sizeof(DMATCHMAP); + buf_info->virt = (uint32 * )fcpmp; + buf_info->phys = (uint32 * )0; + buf_info->dma_handle = 0; + buf_info->data_handle = 0; + fc_free(p_dev_ctl, buf_info); + + return(0); +} + +int +dfc_rsp_data_copy( +fc_dev_ctl_t * p_dev_ctl, +uchar * outdataptr, +DMATCHMAP * mlist, +uint32 size) +{ + static FC_BRD_INFO * binfo; + static DMATCHMAP * mlast; + static int cnt, offset; + + binfo = &BINFO; + mlast = 0; + offset = 0; + + while(mlist && size) { + if(size > 4096) + cnt = 4096; + else + cnt = size; + + mlast = mlist; + mlist = (DMATCHMAP *)mlist->dfc.fc_mptr; + + if(outdataptr) { + fc_mpdata_sync(mlast->dfc.dma_handle, 0, 0, DDI_DMA_SYNC_FORKERNEL); + /* Copy data to user space */ + if (fc_copyout((uchar *)mlast->dfc.virt, (outdataptr+offset), (ulong)cnt)) { + return(1); + } + } + offset += cnt; + size -= cnt; + } + return(0); +} + +int +dfc_cmd_data_free( +fc_dev_ctl_t * p_dev_ctl, +DMATCHMAP * mlist) +{ + static FC_BRD_INFO * binfo; + static MBUF_INFO * buf_info; + static MBUF_INFO bufinfo; + static DMATCHMAP * mlast; + + binfo = &BINFO; + buf_info = &bufinfo; + while(mlist) { + mlast = mlist; + mlist = (DMATCHMAP *)mlist->dfc.fc_mptr; + if(mlast->dfc.virt) { + buf_info->size = mlast->dfc_size; + buf_info->virt = (uint32 * )mlast->dfc.virt; + buf_info->phys = (uint32 * )mlast->dfc.phys; + buf_info->flags = (FC_MBUF_DMA | FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + if (mlast->dfc.dma_handle) { + buf_info->dma_handle = mlast->dfc.dma_handle; + buf_info->data_handle = mlast->dfc.data_handle; + } + fc_free(p_dev_ctl, buf_info); + } + buf_info->flags = (FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + buf_info->size = (int)sizeof(DMATCHMAP); + buf_info->virt = (uint32 * )mlast; + buf_info->phys = (uint32 * )0; + buf_info->dma_handle = 0; + buf_info->data_handle = 0; + fc_free(p_dev_ctl, buf_info); + } + return(0); +} + + +_static_ int +dfc_fmw_rev( +fc_dev_ctl_t * p_dev_ctl) +{ + FC_BRD_INFO * binfo; + struct dfc_info * di; + + binfo = &BINFO; + di = &dfc.dfc_info[binfo->fc_brd_no]; + decode_firmware_rev( binfo, &VPD); + fc_bcopy((uchar *)fwrevision, di->fc_ba.a_fwname, 32); + return(0); +} + + +#else /* DFC_SUBSYSTEM */ + +_static_ int +dfc_ioctl( +struct dfccmdinfo *infop, +struct cmd_input *cip) +{ + return (ENODEV); +} + +int +dfc_put_event( +fc_dev_ctl_t * p_dev_ctl, +uint32 evcode, +uint32 evdata0, +void * evdata1, +void * evdata2) +{ + return(0); +} + +int +dfc_hba_put_event( +fc_dev_ctl_t * p_dev_ctl, +uint32 evcode, +uint32 evdata1, +uint32 evdata2, +uint32 evdata3, +uint32 evdata4) +{ + return(0); +} /* End dfc_hba_put_event */ + +_static_ int +dfc_fmw_rev( +fc_dev_ctl_t * p_dev_ctl) +{ + return(0); +} + +#endif /* DFC_SUBSYSTEM */ + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/fc.h 830-ivtv/drivers/scsi/lpfc/fc.h --- 000-virgin/drivers/scsi/lpfc/fc.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/fc.h Thu Jan 8 10:21:53 2004 @@ -0,0 +1,1264 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Enterprise Fibre Channel Host Bus Adapters. * + * Refer to the README file included with this package for * + * driver version and adapter support. * + * Copyright (C) 2003 Emulex Corporation. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details, a copy of which * + * can be found in the file COPYING included with this package. * + *******************************************************************/ + +#ifndef _H_FC +#define _H_FC + +/* Open Source defines */ +#define DFC_SUBSYSTEM 1 /* Include dfc subsystem */ + +#include "fcdiag.h" +#include "fcdds.h" + +#define LONGW_ALIGN 2 /* longword align for xmalloc */ +#define FC_MAX_SEQUENCE 65536 /* maximum fc sequence size */ +#define FC_MIN_SEQUENCE 0 /* minimum fc sequence size */ +#define FC_MAX_IP_VECS 16 /* Max scatter list for mapping */ +#define RING_TMO_DFT 30 /* default cmd timeout for IOCB rings */ +#define MBOX_TMO_DFT 30 /* dft mailbox timeout for mbox cmds */ +#define FC_CAP_AUTOSENSE 0x0400 /* SCSI capability for autosense */ +#define FC_MAX_HOLD_RSCN 32 /* max number of deferred RSCNs */ +#define FC_MAX_NS_RSP 65536 /* max size NameServer rsp */ + +/* Definitions for Binding Entry Type for fc_parse_binding_entry() */ +#define FC_BIND_WW_NN_PN 0 +#define FC_BIND_DID 1 + +#define FC_DMX_ID 0x100 +#define FL_DMX_ID 0x101 + +/* + * Debug printf event ids. + */ + +/* Check if WWN is 0 */ +#define isWWNzero(wwn) ((wwn.nameType == 0) && (wwn.IEEE[0] == 0) && (wwn.IEEE[1] == 0) && (wwn.IEEE[2] == 0) && (wwn.IEEE[3] == 0) && (wwn.IEEE[4] == 0) && (wwn.IEEE[5] == 0)) + +#define ERRID_NOTICE 0x100 +#define ERRID_ERROR 0x200 +#define ERRID_PANIC 0x400 +#define ERRID_MASK 0xf00 + +#define ERRID_VERBOSE 0x10ff + +/* These are verbose logging masks and debug printf masks */ +#define DBG_ELS 0x1 /* ELS events */ +#define DBG_DISCOVERY 0x2 /* Link discovery events */ +#define DBG_MBOX 0x4 /* Mailbox events */ +#define DBG_INIT 0x8 /* Initialization events */ +#define DBG_LINK_EVENT 0x10 /* link events */ +#define DBG_IP 0x20 /* IP traffic history */ +#define DBG_FCP 0x40 /* FCP traffic history */ +#define DBG_NODE 0x80 /* Node Table events */ +#define DBG_CHK_COND 0x1000 /* FCP Check condition flag */ + +/* These are debug printf masks */ +#define DBG_XRI 0x1000 /* Exchange events */ +#define DBG_IP_DATA 0x2000 /* IP traffic history */ +#define DBG_INTR 0x4000 /* Interrupts */ +#define DBG_IOCB_RSP 0x8000 /* IOCB Response ring events */ +#define DBG_IOCB_RSP_DATA 0x10000 /* IOCB Response ring events */ +#define DBG_IOCB_CMD 0x20000 /* IOCB Command ring events */ +#define DBG_IOCB_CMD_DATA 0x40000 /* IOCB Command ring events */ +#define DBG_FCP_DATA 0x100000/* FCP traffic history */ +#define DBG_ERROR 0x800000/* ERROR events */ + + +/* + * These definitions define SYNTAX errors that occur during the parsing + * of binding config lines. + */ +#define FC_SYNTAX_OK 0 +#define FC_SYNTAX_OK_BUT_NOT_THIS_BRD 1 +#define FC_SYNTAX_ERR_ASC_CONVERT 2 +#define FC_SYNTAX_ERR_EXP_COLON 3 +#define FC_SYNTAX_ERR_EXP_LPFC 4 +#define FC_SYNTAX_ERR_INV_LPFC_NUM 5 +#define FC_SYNTAX_ERR_EXP_T 6 +#define FC_SYNTAX_ERR_INV_TARGET_NUM 7 +#define FC_SYNTAX_ERR_EXP_D 8 +#define FC_SYNTAX_ERR_INV_DEVICE_NUM 9 +#define FC_SYNTAX_ERR_EXP_NULL_TERM 13 + +/*****************************************************************************/ +/* device states */ +/*****************************************************************************/ + +#define CLOSED 0 /* initial device state */ +#define DEAD 1 /* fatal hardware error encountered */ +#define LIMBO 2 /* error recovery period */ +#define OPEN_PENDING 3 /* open initiated */ +#define OPENED 4 /* opened successfully, functioning */ +#define CLOSE_PENDING 5 /* close initiated */ + +#define NORMAL_OPEN 0x0 /* opened in normal mode */ +#define DIAG_OPEN 0x1 /* opened in diagnostics mode */ + +/*****************************************************************************/ +/* This is the board information structure for the fc device */ +/*****************************************************************************/ + +struct fc_q { + uchar *q_first; /* queue first element */ + uchar *q_last; /* queue last element */ + ushort q_cnt; /* current length of queue */ + ushort q_max; /* max length queue can get */ +}; +typedef struct fc_q Q; + +typedef struct fclink { + struct fclink *_f; + struct fclink *_b; +} FCLINK; + +/* +*** fc_enque - enqueue element 'x' after element 'p' in +*** a queue without protection for critical sections. +*/ +#define fc_enque(x,p) {(((FCLINK *)x)->_f = ((FCLINK *)p)->_f, \ + ((FCLINK *)x)->_b = ((FCLINK *)p), \ + ((FCLINK *)p)->_f->_b = ((FCLINK *)x), \ + ((FCLINK *)p)->_f = ((FCLINK *)x));} + +/* +*** fc_deque - dequeue element 'x' (the user must make +*** sure its not the queue header +*/ +#define fc_deque(x) {(((FCLINK *)x)->_b->_f = ((FCLINK *)x)->_f, \ + ((FCLINK *)x)->_f->_b = ((FCLINK *)x)->_b, \ + ((FCLINK *)x)->_b = 0, \ + ((FCLINK *)x)->_f = 0);} + +/* This structure is used when allocating a buffer pool. + */ +typedef struct mbuf_info { + int size; /* Specifies the number of bytes to allocate. */ + int align; /* The desired address boundary. */ + + int flags; +#define FC_MBUF_DMA 0x1 /* blocks are for DMA */ +#define FC_MBUF_PHYSONLY 0x2 /* For malloc - map a given virtual address + * to physical (skip the malloc). For free - + * just unmap the given physical address + * (skip the free). + */ +#define FC_MBUF_IOCTL 0x4 /* called from dfc_ioctl */ +#define FC_MBUF_UNLOCK 0x8 /* called with driver unlocked */ + void * virt; /* specifies the virtual buffer pointer */ + void * phys; /* specifies the physical buffer pointer */ + ulong * data_handle; + ulong * dma_handle; +} MBUF_INFO; + + +struct fc_match { + uchar * fc_mptr; + uchar * virt; /* virtual address ptr */ + uchar * phys; /* mapped address */ + ulong * data_handle; + ulong * dma_handle; +}; +typedef struct fc_match MATCHMAP; + +struct dfc_match { + MATCHMAP dfc; + uint32 dfc_size; + int dfc_flag; +}; +typedef struct dfc_match DMATCHMAP; + +/* Kernel level Event structure */ +struct fcEvent { + uint32 evt_handle; + uint32 evt_mask; + uint32 evt_type; + uint32 evt_data0; + ushort evt_sleep; + ushort evt_flags; + void *evt_next; + void *evt_data1; + void *evt_data2; +}; +typedef struct fcEvent fcEvent; + +/* Define for e_mode */ +#define E_SLEEPING_MODE 0x0001 + +/* Define for e_flag */ +#define E_GET_EVENT_ACTIVE 0x0001 + +/* Kernel level Event Header */ +struct fcEvent_header { + uint32 e_handle; + uint32 e_mask; + ushort e_mode; + ushort e_flag; + fcEvent * e_head; + fcEvent * e_tail; + void * e_next_header; +/* Add something here */ +}; +typedef struct fcEvent_header fcEvent_header; + +/* Structures using for clock / timeout handling */ +typedef struct fcclock { + struct fcclock *cl_fw; /* forward linkage */ + union { + struct { + ushort cl_soft_arg; + ushort cl_soft_cmd; + } c1; + struct fcclock *cl_bw; /* backward linkage */ + } un; + uint32 cl_tix; /* differential number of clock ticks */ + void (*cl_func)(void *, void *, void *); + void * cl_p_dev_ctl; + void * cl_arg1; /* argument 1 to function */ + void * cl_arg2; /* argument 2 to function */ +} FCCLOCK; + +#define cl_bw un.cl_bw + +typedef struct clkhdr { + FCCLOCK *cl_f; + FCCLOCK * cl_b; + uint32 count; /* number of clock blocks in list */ +} CLKHDR; + +#define FC_NUM_GLBL_CLK 4 /* number of global clock blocks */ + +typedef struct fcclock_info { + CLKHDR fc_clkhdr; /* fc_clock queue head */ + uint32 ticks; /* elapsed time since initialization */ + uint32 Tmr_ct; /* Timer expired count */ + uint32 timestamp[2]; /* SMT 64 bit timestamp */ + void * clktimer; /* used for scheduling clock routine */ + Simple_lock clk_slock; /* clock routine lock */ + FCCLOCK clk_block[FC_NUM_GLBL_CLK]; /* global clock blocks */ +} FCCLOCK_INFO; + + +/* Structure used to access adapter rings */ +struct fc_ring { + IOCBQ * fc_iocbhd; /* ptr to head iocb rsp list for ring */ + IOCBQ * fc_iocbtl; /* ptr to tail iocb rsp list for ring */ + uchar fc_numCiocb; /* number of command iocb's per ring */ + uchar fc_numRiocb; /* number of rsp iocb's per ring */ + uchar fc_rspidx; /* current index in response ring */ + uchar fc_cmdidx; /* current index in command ring */ + uchar fc_ringno; /* ring number */ + uchar fc_xmitstate; /* state needed for xmit */ + void * fc_cmdringaddr; /* virtual offset for cmd rings */ + void * fc_rspringaddr; /* virtual offset for rsp rings */ + ushort fc_iotag; /* used to identify I/Os */ + + ushort fc_missbufcnt; /* buf cnt we need to repost */ + ushort fc_wdt_inited; /* timer is inited */ + ushort fc_bufcnt; /* cnt of buffers posted */ + uchar * fc_mpon; /* index ptr for match structure */ + uchar * fc_mpoff; /* index ptr for match structure */ + uchar * fc_binfo; /* ptr to FC_BRD_INFO for ring */ + Q fc_tx; /* iocb command queue */ + Q fc_txp; /* iocb pending queue */ + FCCLOCK * fc_wdt; /* timer for ring activity */ + int fc_ringtmo; /* timer timeout value */ +}; +typedef struct fc_ring RING; + +/* Defines for nlp_state (uchar) */ +#define NLP_UNUSED 0 /* unused NL_PORT entry */ +#define NLP_LIMBO 0x1 /* entry needs to hang around for wwpn / sid */ +#define NLP_LOGOUT 0x2 /* NL_PORT is not logged in - entry is cached */ +#define NLP_PLOGI 0x3 /* PLOGI was sent to NL_PORT */ +#define NLP_LOGIN 0x4 /* NL_PORT is logged in / login REG_LOGINed */ +#define NLP_PRLI 0x5 /* PRLI was sent to NL_PORT */ +#define NLP_ALLOC 0x6 /* NL_PORT is ready to initiate adapter I/O */ +#define NLP_SEED 0x7 /* seed scsi id bind in table */ + +/* Defines for nlp_flag (uint32) */ +#define NLP_RPI_XRI 0x1 /* creating xri for entry */ +#define NLP_REQ_SND 0x2 /* sent ELS request for this entry */ +#define NLP_RM_ENTRY 0x4 /* Remove this entry */ +#define NLP_FARP_SND 0x8 /* sent FARP request for this entry */ +#define NLP_NS_NODE 0x10 /* Authenticated entry by NameServer */ +#define NLP_NODEV_TMO 0x20 /* nodev timeout is running for node */ +#define NLP_REG_INP 0x40 /* Reglogin in progress for node */ +#define NLP_UNREG_LOGO 0x80 /* Perform LOGO after unreglogin */ +#define NLP_RCV_PLOGI 0x100 /* Rcv'ed PLOGI from remote system */ +#define NLP_MAPPED 0x200 /* Node is now mapped */ +#define NLP_UNMAPPED 0x400 /* Node is now unmapped */ +#define NLP_BIND 0x800 /* Node is now bound */ +#define NLP_LIST_MASK 0xe00 /* mask to see what list node is on */ +#define NLP_SND_PLOGI 0x1000 /* Flg to indicate send PLOGI */ +#define NLP_REQ_SND_PRLI 0x2000 /* Send PRLI ELS command */ +#define NLP_REQ_SND_ADISC 0x2000 /* Send ADISC ELS command */ +#define NLP_REQ_SND_PDISC 0x2000 /* Send PDISC ELS command */ +#define NLP_NS_REMOVED 0x4000 /* Node removed from NameServer */ + +/* Defines for nlp_action (uchar) */ +#define NLP_DO_ADDR_AUTH 0x1 /* Authenticating addr for entry */ +#define NLP_DO_DISC_START 0x2 /* start discovery on this entry */ +#define NLP_DO_RSCN 0x4 /* Authenticate entry for by RSCN */ +#define NLP_DO_RNID 0x8 /* Authenticate entry for by RSCN */ +#define NLP_DO_SCSICMD 0x10 /* Authenticate entry for by RSCN */ +#define NLP_DO_CT_USR 0x20 /* Authenticate entry for by RSCN */ +#define NLP_DO_CT_DRVR 0x40 /* Authenticate entry for by RSCN */ + +/* Defines for nlp_type (uchar) */ +#define NLP_FABRIC 0x1 /* this entry represents the Fabric */ +#define NLP_FCP_TARGET 0x2 /* this entry is an FCP target */ +#define NLP_IP_NODE 0x4 /* this entry is an IP node */ +#define NLP_SEED_WWPN 0x10 /* Entry scsi id is seeded for WWPN */ +#define NLP_SEED_WWNN 0x20 /* Entry scsi id is seeded for WWNN */ +#define NLP_SEED_DID 0x40 /* Entry scsi id is seeded for DID */ +#define NLP_SEED_MASK 0x70 /* mask for seeded flags */ +#define NLP_AUTOMAP 0x80 /* Entry was automap'ed */ + +/* Defines for list searchs */ +#define NLP_SEARCH_MAPPED 0x1 /* search mapped */ +#define NLP_SEARCH_UNMAPPED 0x2 /* search unmapped */ +#define NLP_SEARCH_BIND 0x4 /* search bind */ +#define NLP_SEARCH_ALL 0x7 /* search all lists */ + +/* Defines for nlp_fcp_info */ +#define NLP_FCP_2_DEVICE 0x10 /* FCP-2 device */ + +struct nlp_nodeList { /* NOTE: any changes to this structure + * must be dup'ed in fcdds.h, cnode_t. + */ + void * nlp_listp_next; /* Node table ptr bind / map / unmap list */ + void * nlp_listp_prev; /* Node table ptr bind / map / unmap list */ + uchar nlp_state; /* state transition indicator */ + uchar nlp_action; /* Action being performed on node */ + uchar nlp_type; /* node type identifier */ + uchar nlp_alpa; /* SCSI device AL_PA */ + ushort nlp_Rpi; /* login id returned by REG_LOGIN */ + ushort nlp_Xri; /* output exchange id for RPI */ + ushort capabilities; + ushort sync; + uint32 target_scsi_options; + uint32 nlp_flag; /* entry flags */ + uint32 nlp_DID; /* fibre channel D_ID of entry */ + uint32 nlp_time; /* timestamp */ + uint32 nlp_oldDID; + NAME_TYPE nlp_portname; /* port name */ + NAME_TYPE nlp_nodename; /* node name */ + struct { /* device id - for FCP */ + uchar nlp_pan; /* pseudo adapter number */ + uchar nlp_sid; /* scsi id */ + uchar nlp_fcp_info; /* Remote class info */ + uchar nlp_ip_info; /* Remote class info */ + } id; + uchar * nlp_bp; /* save buffer ptr - for IP */ + uchar * nlp_targetp; /* Node table ptr for target */ +}; +typedef struct nlp_nodeList NODELIST; + +/* For now stick fc_lun_t in here, + * should move to fc_os.h eventually. + */ +typedef uint32 fc_lun_t; + +#define mapLun(di) ((di)->lun_id) + +#define NLP_MAXREQ 32 /* max num of outstanding NODELIST requests */ +#define NLP_MAXSID 16 /* max number of scsi devices / adapter */ +#define NLP_MAXPAN 32 /* max number of pseudo adapters */ +#define PA_MASK 0x1f /* mask devno to get pseudo adapter number */ +#define DABS 5 /* convert devno to adapter number bit shift */ +#define FC_MIN_QFULL 1 /* lowest we can decrement throttle + to on qfull */ + +#define FC_SCSID(pan, sid) ((uint32)((pan << 16) | sid)) /* For logging */ + +/* Max number of fibre channel devices supported in network */ +#define NLP_MAXRPI 512 /* firmware supports 512 rpis [0-511] */ + +#define FC_MAXLOOP 126 /* max devices supported on a single fc loop */ +#define FC_MAX_MCAST 16 /* max number of multicast addresses */ +#define MULTI_BIT_MASK (0x01) /* Multicast Bit Mask */ +#define FC_MAX_ADPTMSG (8*28) /* max size of a msg from adapter */ +#define FC_INIT_RING_BUF 12 + +struct fc_networkhdr { + NAME_TYPE fc_destname; /* destination port name */ + NAME_TYPE fc_srcname; /* source port name */ +}; +typedef struct fc_networkhdr NETHDR; + +#define MEM_NLP 0 /* memory segment to hold node list entries */ +#define MEM_IOCB 1 /* memory segment to hold iocb commands */ +#define MEM_CLOCK 1 /* memory segment to hold clock blocks */ +#define MEM_MBOX 2 /* memory segment to hold mailbox cmds */ +#define MEM_BUF 3 /* memory segment to hold buffer data */ +#define MEM_BPL 3 /* and to hold buffer ptr lists - SLI2 */ +#define FC_MAX_SEG 4 + +#define MEM_SEG_MASK 0xff /* mask used to mask off the priority bit */ +#define MEM_PRI 0x100 /* Priority bit: set to exceed low water */ + +#define MIN_CLK_BLKS 256 + +struct fc_memseg { + uchar *fc_memptr; /* ptr to memory blocks */ + uchar *fc_endmemptr; /* ptr to last memory block */ + uchar *fc_memhi; /* highest address in pool */ + uchar *fc_memlo; /* lowest address in pool */ + ushort fc_memsize; /* size of memory blocks */ + ushort fc_numblks; /* number of memory blocks */ + ushort fc_free; /* number of free memory blocks */ + ushort fc_memflag; /* what to do when list is exhausted */ + ushort fc_lowmem; /* low water mark, used w/MEM_PRI flag */ +}; +typedef struct fc_memseg MEMSEG; + +#define FC_MEM_ERR 1 /* return error memflag */ +#define FC_MEM_GETMORE 2 /* get more memory memflag */ +#define FC_MEM_DMA 4 /* blocks are for DMA */ +#define FC_MEM_LOWHIT 8 /* low water mark was hit */ + +#define FC_MEMPAD 16 /* offset used for a FC_MEM_DMA buffer */ + +/* + * Board stat counters + */ +struct fc_stats { + uint32 chipRingFree; + uint32 cmdCreateXri; + uint32 cmdQbuf; + uint32 elsCmdIocbInval; + uint32 elsCmdPktInval; + uint32 elsLogiCol; + uint32 elsRetryExceeded; + uint32 elsStrayXmitCmpl; + uint32 elsXmitCmpl; + uint32 elsXmitErr; + uint32 elsXmitFrame; + uint32 elsXmitRetry; + uint32 elsRcvDrop; + uint32 elsRcvFrame; + uint32 elsRcvRSCN; + uint32 elsRcvFARP; + uint32 elsRcvFARPR; + uint32 elsRcvFLOGI; + uint32 elsRcvPLOGI; + uint32 elsRcvADISC; + uint32 elsRcvPDISC; + uint32 elsRcvFAN; + uint32 elsRcvLOGO; + uint32 elsRcvPRLO; + uint32 elsRcvRRQ; + uint32 frameRcvBcast; + uint32 frameRcvMulti; + uint32 hostRingFree; + uint32 iocbCmdInval; + uint32 iocbRingBusy; + uint32 IssueIocb; + uint32 iocbRsp; + uint32 issueMboxCmd; + uint32 linkEvent; + uint32 xmitnoroom; + uint32 NoIssueIocb; + uint32 mapPageErr; + uint32 mboxCmdBusy; + uint32 mboxCmdInval; + uint32 mboxEvent; + uint32 mboxStatErr; + uint32 memAllocErr; + uint32 noRpiList; + uint32 noVirtPtr; + uint32 ringEvent; + uint32 strayXmitCmpl; + uint32 frameXmitDelay; + uint32 xriCmdCmpl; + uint32 xriStatErr; + uint32 mbufcopy; + uint32 LinkUp; + uint32 LinkDown; + uint32 LinkMultiEvent; + uint32 NoRcvBuf; + uint32 fcpCmd; + uint32 fcpCmpl; + uint32 fcpStrayCmpl; + uint32 fcpFirstCheck; + uint32 fcpGood; + uint32 fcpRspErr; + uint32 fcpRemoteStop; + uint32 fcpLocalErr; + uint32 fcpLocalTmo; + uint32 fcpLocalNores; + uint32 fcpLocalBufShort; + uint32 fcpLocalSfw; + uint32 fcpLocalTxDMA; + uint32 fcpLocalRxDMA; + uint32 fcpLocalinternal; + uint32 fcpLocalCorrupt; + uint32 fcpLocalIllFrm; + uint32 fcpLocalDupFrm; + uint32 fcpLocalLnkCtlFrm; + uint32 fcpLocalLoopOpen; + uint32 fcpLocalInvalRpi; + uint32 fcpLocalLinkDown; + uint32 fcpLocalOOO; + uint32 fcpLocalAbtInp; + uint32 fcpLocalAbtReq; + uint32 fcpLocal; + uint32 fcpPortRjt; + uint32 fcpPortBusy; + uint32 fcpError; + uint32 fcpScsiTmo; + uint32 fcpSense; + uint32 fcpNoDevice; + uint32 fcMallocCnt; + uint32 fcMallocByte; + uint32 fcFreeCnt; + uint32 fcFreeByte; + uint32 fcMapCnt; + uint32 fcUnMapCnt; + uint32 fcpRsvd0; + uint32 fcpRsvd1; + uint32 fcpRsvd2; + uint32 fcpRsvd3; + uint32 fcpRsvd4; + uint32 fcpRsvd5; + uint32 fcpRsvd6; + uint32 fcpRsvd7; + uint32 fcpRsvd8; +}; +typedef struct fc_stats fc_stat_t; + + +/* Defines / Structures used to support IP profile */ + +#define FC_MIN_MTU 0 /* minimum size FC message */ +#define FC_MAX_MTU 65280 /* maximum size FC message */ + +/* structure for MAC header */ +typedef struct { + uchar dest_addr[MACADDR_LEN]; /* 48 bit unique address */ + uchar src_addr[MACADDR_LEN]; /* 48 bit unique address */ + ushort llc_len; /* length of LLC data */ +} emac_t; +#define HDR_LEN 14 /* MAC header size */ + +/* structure for LLC/SNAP header */ +typedef struct { + unsigned char dsap; /* DSAP */ + unsigned char ssap; /* SSAP */ + unsigned char ctrl; /* control field */ + unsigned char prot_id[3]; /* protocol id */ + unsigned short type; /* type field */ +} snaphdr_t; + +struct fc_hdr { + emac_t mac; + snaphdr_t llc; +}; + +struct fc_nethdr { + NETHDR fcnet; + snaphdr_t llc; +}; + +#define FC_LLC_SSAP 0xaa /* specifies LLC SNAP header */ +#define FC_LLC_DSAP 0xaa /* specifies LLC SNAP header */ +#define FC_LLC_CTRL 3 /* UI */ + + +/* + * The fc_buf structure is used to communicate SCSI commands to the adapter + */ +typedef struct sc_buf T_SCSIBUF; +#define SET_ADAPTER_STATUS(bp, val) bp->general_card_status = val; + +#define P_DEPTH ((FC_MAX_TRANSFER/PAGESIZE) + 2) + +typedef struct fc_buf { + FCP_CMND fcp_cmd; /* FCP command - This MUST be first */ + FCP_RSP fcp_rsp; /* FCP response - This MUST be next */ + struct fc_buf *fc_fwd; /* forward list pointer */ + struct fc_buf *fc_bkwd; /* backward list pointer */ + char *phys_adr; /* physical address of this fc_buf */ + T_SCSIBUF *sc_bufp; /* pointer to sc_buf for this cmd */ + struct dev_info *dev_ptr; /* pointer to SCSI device structure */ + uint32 timeout; /* Fill in how OS represents a time stamp */ + /* Fill in any OS specific members */ + int offset; + ulong * fc_cmd_dma_handle; + ushort iotag; /* iotag for this cmd */ + ushort flags; /* flags for this cmd */ +#define DATA_MAPPED 0x0001 /* data buffer has been D_MAPed */ +#define FCBUF_ABTS 0x0002 /* ABTS has been sent for this cmd */ +#define FCBUF_ABTS2 0x0004 /* ABTS has been sent twice */ +#define FCBUF_INTERNAL 0x0008 /* Internal generated driver command */ + + /* + * Save the buffer pointer list for later use. + * In SLI2, the fc_deq_fcbuf_active uses this pointer to + * free up MEM_BPL buffer + */ + MATCHMAP *bmp; +} fc_buf_t; + +#define FCP_CONTINUE 0x01 /* flag for issue_fcp_cmd */ +#define FCP_REQUEUE 0x02 /* flag for issue_fcp_cmd */ +#define FCP_EXIT 0x04 /* flag for issue_fcp_cmd */ + +/* + * The fcp_table structure is used to relate FCP iotags to an fc_buf + */ + +typedef struct fcp_table { + fc_buf_t *fcp_array[MAX_FCP_CMDS];/* fc_buf pointers indexed by iotag */ +} FCPTBL; + + +/* + * SCSI node structure for each open Fibre Channel node + */ + +typedef struct scsi_node { + struct fc_dev_ctl * ap; /* adapter structure ptr */ + struct dev_info * lunlist; /* LUN structure list for this node */ + NODELIST * nlp; /* nlp structure ptr */ + struct dev_info * last_dev; /* The last device had an I/O */ + FCCLOCK * nodev_tmr; /* Timer for nodev-tmo */ + int devno; /* pseudo adapter major/minor number */ + int max_lun; /* max number of luns */ + ushort tgt_queue_depth; /* Max throttle of this node */ + ushort num_active_io; /* Total number of active I/O */ + ushort rpi; /* Device rpi */ + ushort last_good_rpi; /* Last known good device rpi */ + ushort scsi_id; /* SCSI ID of this device */ + ushort flags; +#define FC_NODEV_TMO 0x1 /* nodev-tmo tmr started and expired */ +#define FC_FCP2_RECOVERY 0x2 /* set FCP2 Recovery for commands */ +#define RETRY_RPTLUN 0x4 /* Report Lun has been retried */ + ushort addr_mode; /* SCSI address method */ +#define PERIPHERAL_DEVICE_ADDRESSING 0 +#define VOLUME_SET_ADDRESSING 1 +#define LOGICAL_UNIT_ADDRESSING 2 + ushort rptlunstate; /* For report lun SCSI command */ +#define REPORT_LUN_REQUIRED 0 +#define REPORT_LUN_ONGOING 1 +#define REPORT_LUN_COMPLETE 2 + void *virtRptLunData; + void *physRptLunData; +} node_t; + +/* Values for node_flag and fcp_mapping are in fcdds.h */ + +/* + * SCSI device structure for each open LUN + */ + +#define MAX_FCBUF_PAGES 6 /* This value may need to change when + * lun-queue-depth > 256 in lpfc.conf + */ + +typedef struct dev_info { + node_t *nodep; /* Pointer to the node structure */ + struct dev_info *next; /* Used for list of LUNs on this node */ + fc_lun_t lun_id; /* LUN ID of this device */ + uchar first_check; /* flag for first check condition */ +#define FIRST_CHECK_COND 0x1 +#define FIRST_IO 0x2 + + uchar opened; + uchar ioctl_wakeup; /* wakeup sleeping ioctl call */ + int ioctl_event; + int ioctl_errno; + int stop_event; + int active_io_count; + + struct dev_info *DEVICE_WAITING_fwd; + struct dev_info *ABORT_BDR_fwd; + struct dev_info *ABORT_BDR_bkwd; + + long qfullcnt; + /* Fill in any OS specific members */ + T_SCSIBUF *scp; + void *scsi_dev; + long scpcnt; + long qcmdcnt; + long iodonecnt; + long errorcnt; + /* + * A command lives in a pending queue until it is sent to the HBA. + * Throttling constraints apply: + * No more than N commands total to a single target + * No more than M commands total to a single LUN on that target + * + * A command that has left the pending queue and been sent to the HBA + * is an "underway" command. We count underway commands, per-LUN, + * to obey the LUN throttling constraint. + * + * Because we only allocate enough fc_buf_t structures to handle N + * commands, per target, we implicitly obey the target throttling + * constraint by being unable to send a command when we run out of + * free fc_buf_t structures. + * + * We count the number of pending commands to determine whether the + * target has I/O to be issued at all. + * + * We use next_pending to rotor through the LUNs, issuing one I/O at + * a time for each LUN. This mechanism guarantees a fair distribution + * of I/Os across LUNs in the face of a target queue_depth lower than + * #LUNs*fcp_lun_queue_depth. + */ + T_SCSIBUF *standby_queue_head; /* ptr to retry command queue */ + T_SCSIBUF *standby_queue_tail; /* ptr to retry command queue */ + uint32 standby_count; /* # of I/Os on standby queue */ + /* END: added by andy kong for SCSI */ + + ushort fcp_cur_queue_depth; /* Current maximum # cmds outstanding + * to dev; */ + ushort fcp_lun_queue_depth; /* maximum # cmds to each lun */ + T_SCSIBUF *pend_head; /* ptr to pending cmd queue */ + T_SCSIBUF *pend_tail; /* ptr to pending cmd queue */ + uint32 pend_count; +#define QUEUE_HEAD 1 +#define QUEUE_TAIL 0 + struct buf *clear_head; /* ptr to bufs to iodone after clear */ + uint32 clear_count; + + uchar numfcbufs; /* number of free fc_bufs */ + uchar stop_send_io; /* stop sending any io to this dev */ + + +#define ACTIVE 0 +#define STOPPING 1 +#define HALTED 2 +#define RESTART_WHEN_READY 3 +#define ACTIVE_PASSTHRU 4 +#define WAIT_RESUME 8 +#define WAIT_INFO 10 +#define WAIT_ACA 11 +#define WAIT_FLUSH 12 +#define WAIT_HEAD_RESUME 13 + uchar queue_state; /* device general queue state */ + /* ACTIVE, STOPPING, or HALTED */ + +#define SCSI_TQ_HALTED 0x0001 /* The transaction Q is halted */ +#define SCSI_TQ_CLEARING 0x0002 /* The transaction Q is clearing */ +#define SCSI_TQ_CLEAR_ACA 0x0004 /* a CLEAR_ACA is PENDING */ +#define SCSI_LUN_RESET 0x0008 /* sent LUN_RESET not of TARGET_RESET */ +#define SCSI_ABORT_TSET 0x0010 /* BDR requested but not yet sent */ +#define SCSI_TARGET_RESET 0x0020 /* a SCSI BDR is active for device */ +#define CHK_SCSI_ABDR 0x0038 /* value used to check tm flags */ +#define QUEUED_FOR_ABDR 0x0040 /* dev_ptr is on ABORT_BDR queue */ +#define NORPI_RESET_DONE 0x0100 /* BOGUS_RPI Bus Reset attempted */ +#define DONT_LOG_INVALID_RPI 0x0200 /* if flag is set, the I/O issuing */ + /* to an invalid RPI won't be logged */ +#define SCSI_IOCTL_INPROGRESS 0x0400 /* An ioctl is in progress */ +#define SCSI_SEND_INQUIRY_SN 0x1000 /* Serial number inq should be sent */ +#define SCSI_INQUIRY_SN 0x2000 /* Serial number inq has been sent */ +#define SCSI_INQUIRY_P0 0x4000 /* Page 0 inq has been sent */ +#define SCSI_INQUIRY_CMD 0x6000 /* Serial number or Page 0 inq sent */ +#define SCSI_DEV_RESET 0x8000 /* device is in process of resetting */ + ushort flags; /* flags for the drive */ + + struct dio vlist; /* virtual address of fc_bufs */ + struct dio blist; /* physical addresses of fc_bufs */ + fc_buf_t * fcbuf_head; /* head ptr to list of free fc_bufs */ + fc_buf_t * fcbuf_tail; /* tail ptr to list of free fc_bufs */ + + uchar sense[MAX_FCP_SNS]; /* Temporary request sense buffer */ + uchar sense_valid; /* flag to indicate new sense data */ + uchar sizeSN; /* size of InquirySN */ + uint32 sense_length; /* new sense data length */ + +#define MAX_QFULL_RETRIES 255 +#define MAX_QFULL_RETRY_INTERVAL 1000 /* 1000 (ms) */ + short qfull_retries; /* number of retries on a qfull condition */ + short qfull_retry_interval; /* the interval for qfull retry */ + void * qfull_tmo_id; + T_SCSIBUF scbuf; /* sc_buf for task management cmds */ + +} dvi_t; + + +typedef struct node_info_hash { + node_t *node_ptr; /* SCSI device node pointer */ + uint32 node_flag; /* match node on WWPN WWNN or DID */ + union { + NAME_TYPE dev_nodename; /* SCSI node name */ + NAME_TYPE dev_portname; /* SCSI port name */ + uint32 dev_did; /* SCSI did */ + } un; +} nodeh_t; + +/* + * LONGWAIT is used to define a default scsi_timeout value in seconds. + */ +#define LONGWAIT 30 + + +/* +*** Board Information Data Structure +*/ + +struct fc_brd_info { + /* Configuration Parameters */ + int fc_ffnumrings; /* number of FF rings being used */ + NAME_TYPE fc_nodename; /* fc nodename */ + NAME_TYPE fc_portname; /* fc portname */ + uint32 fc_pref_DID; /* preferred D_ID */ + uchar fc_pref_ALPA; /* preferred AL_PA */ + uchar fc_deferip; /* defer IP processing */ + uchar fc_nummask[4]; /* number of masks/rings being used */ + uchar fc_rval[6]; /* rctl for ring assume mask is 0xff */ + uchar fc_tval[6]; /* type for ring assume mask is 0xff */ + uchar ipAddr[16]; /* For RNID support */ + ushort ipVersion; /* For RNID support */ + ushort UDPport; /* For RNID support */ + uint32 fc_edtov; /* E_D_TOV timer value */ + uint32 fc_arbtov; /* ARB_TOV timer value */ + uint32 fc_ratov; /* R_A_TOV timer value */ + uint32 fc_rttov; /* R_T_TOV timer value */ + uint32 fc_altov; /* AL_TOV timer value */ + uint32 fc_crtov; /* C_R_TOV timer value */ + uint32 fc_citov; /* C_I_TOV timer value */ + uint32 fc_myDID; /* fibre channel S_ID */ + uint32 fc_prevDID; /* previous fibre channel S_ID */ + + /* The next three structures get DMA'ed directly into, + * so they must be in the first page of the adapter structure! + */ + volatile SERV_PARM fc_sparam; /* buffer for our service parameters */ + volatile SERV_PARM fc_fabparam; /* fabric service parameters buffer */ + volatile uchar alpa_map[128]; /* AL_PA map from READ_LA */ + + uchar fc_mbox_active; /* flag for mailbox in use */ + uchar fc_process_LA; /* flag to process Link Attention */ + uchar fc_ns_retry; /* retries for fabric nameserver */ + uchar fc_sli; /* configured SLI, 1 or 2 */ + int fc_nlp_cnt; /* cnt outstanding NODELIST requests */ + int fc_open_count; /* count of devices opened */ + int fc_rscn_id_cnt; /* count of RSCNs dids in list */ + uint32 fc_rscn_id_list[FC_MAX_HOLD_RSCN]; + Q fc_plogi; /* ELS PLOGI cmd queue */ + Q fc_mbox; /* mailbox cmd queue */ + Q fc_rscn; /* RSCN cmd queue */ + Q fc_defer_rscn; /* deferred RSCN cmd queue */ + uchar * fc_mbbp; /* buffer pointer for mbox command */ + uchar * fc_p_dev_ctl; /* pointer to driver device ctl */ + + /* Board dependent variables */ + int fc_flag; /* FC flags */ + int fc_brd_no; /* FC board number */ + int fc_ints_disabled; /* DEBUG: interrupts disabled */ + volatile int fc_ffstate; /* Current state of FF init process */ + int fc_interrupts; /* number of fc interrupts */ + int fc_cnt; /* generic counter for board */ + int fc_topology; /* link topology, from LINK INIT */ + int fc_firstopen; /* First open to driver flag */ + int fc_msgidx; /* current index to adapter msg buf */ + uint32 fc_eventTag; /* event tag for link attention */ + ulong fc_fabrictmo; /* timeout for fabric timer */ + uchar fc_multi; /* number of multicast addresses */ + uchar fc_linkspeed; /* Link speed after last READ_LA */ + uchar fc_max_data_rate; /* max_data_rate */ + + void * physaddr[FC_MAX_IP_VECS]; /* used in mbuf_to_iocb for */ + uint32 cntaddr[FC_MAX_IP_VECS]; /* phys mapping */ + + uchar fc_busflag; /* bus access flags */ +#define FC_HOSTPTR 2 /* Default is ring pointers in SLIM */ + + volatile uint32 * fc_mboxaddr; /* virtual offset for mailbox/SLIM */ + volatile uint32 fc_BCregaddr; /* virtual offset for BIU config reg */ + volatile uint32 fc_HAregaddr; /* virtual offset for host attn reg */ + volatile uint32 fc_HCregaddr; /* virtual offset for host ctl reg */ + volatile uint32 fc_FFregaddr; /* virtual offset for FF attn reg */ + volatile uint32 fc_STATregaddr; /* virtual offset for status reg */ + + + MATCHMAP fc_slim2; /* pointers to slim for SLI-2 */ + + void *fc_iomap_io; /* starting address for registers */ + void *fc_iomap_mem; /* starting address for SLIM */ + /* Fill in any OS specific members */ + /* dma handle, mem map, pci config access */ + + + + + + FCCLOCK * fc_mbox_wdt; /* timer for mailbox */ + FCCLOCK * fc_fabric_wdt; /* timer for fabric */ + FCCLOCK * fc_rscn_disc_wdt; /* timer for RSCN discovery */ + fc_stat_t fc_stats; /* fc driver generic statistics */ + + NAME_TYPE fc_multiaddr[FC_MAX_MCAST];/* multicast adrs for interface */ + NODELIST * fc_nlpbind_start; /* ptr to bind list */ + NODELIST * fc_nlpbind_end; /* ptr to bind list */ + NODELIST * fc_nlpunmap_start; /* ptr to unmap list */ + NODELIST * fc_nlpunmap_end; /* ptr to unmap list */ + NODELIST * fc_nlpmap_start; /* ptr to map list */ + NODELIST * fc_nlpmap_end; /* ptr to map list */ + ushort fc_bind_cnt; + ushort fc_unmap_cnt; + ushort fc_map_cnt; + ushort fc_rpi_used; + NODELIST * fc_nlplookup[NLP_MAXRPI]; /* ptr to active D_ID / RPIs */ + NODELIST fc_fcpnodev; /* nodelist entry for no device */ + uint32 nlptimer; /* timestamp for nlplist entry */ + ushort fc_capabilities; /* default value for NODELIST caps */ + ushort fc_sync; /* default value for NODELIST sync */ + + nodeh_t device_queue_hash[MAX_FC_TARGETS]; /* SCSI node pointers */ + FCPTBL * fc_table; /* FCP iotag table pointer */ + IOCBQ * fc_delayxmit; /* List of IOCBs for delayed xmit */ + + + char fc_adaptermsg[FC_MAX_ADPTMSG]; /* adapter printf messages */ + char fc_SerialNumber[32]; /* adapter Serial Number */ + char fc_OptionROMVersion[32]; /* adapter BIOS / Fcode version */ + MEMSEG fc_memseg[FC_MAX_SEG]; /* memory for buffers / structures */ + RING fc_ring[MAX_RINGS]; +}; + +typedef struct fc_brd_info FC_BRD_INFO; + + +/* Host Attn reg */ +#define FC_HA_REG(binfo,sa) ((volatile uint32 *)((volatile char *)sa + (binfo->fc_HAregaddr))) +#define FC_FF_REG(binfo,sa) ((volatile uint32 *)((volatile char *)sa + (binfo->fc_FFregaddr))) + +/* Host Status reg */ +#define FC_STAT_REG(binfo,sa) ((volatile uint32 *)((volatile char *)sa +(binfo->fc_STATregaddr))) + +/* Host Cntl reg */ +#define FC_HC_REG(binfo,sa) ((volatile uint32 *)((volatile char *)sa + (binfo->fc_HCregaddr))) + +/* BIU Configuration reg */ +#define FC_BC_REG(binfo,sa) ((volatile uint32 *)((volatile char *)sa + (binfo->fc_BCregaddr))) + +/* SLIM defines for SLI-1 */ +#define FC_MAILBOX(binfo,sa) ((MAILBOX *)((volatile char *)sa + ((uint32)((ulong)binfo->fc_mboxaddr)))) + +/* SLIM defines for SLI-2 */ +#define FC_SLI2_MAILBOX(binfo) ((MAILBOX *)(binfo->fc_mboxaddr)) + +#define FC_IOCB(binfo,sa) ((volatile uchar *)((volatile char *)sa + ((uint32)binfo->fc_mboxaddr + 0x100))) + +#define FC_RING(ringoff,sa) ((volatile uchar *)((volatile char *)sa + (ulong)(ringoff))) + + + +/* Write 32-bit value to CSR register pointed to by regp */ +#define WRITE_CSR_REG(binfo, regp, val) fc_writel((uint32 *)(regp), (uint32)val) + +/* Write 32-bit value to SLIM address pointed to by regp */ +#define WRITE_SLIM_ADDR(binfo, regp, val) fc_writel((uint32 *)(regp), (uint32)val) + +/* Read 32-bit value from CSR register pointed to by regp */ +#define READ_CSR_REG(binfo, regp) fc_readl((uint32 *)(regp)) + +/* Read 32-bit value from SLIM address pointed to by regp */ +#define READ_SLIM_ADDR(binfo, regp) fc_readl((uint32 *)(regp)) + +/* Write wcnt 32-bit words to SLIM address pointed to by slimp */ +#define WRITE_SLIM_COPY(binfo, bufp, slimp, wcnt) \ + fc_write_toio((uint32*)bufp, (uint32*)slimp, (sizeof(uint32)*(wcnt))) + +/* Read wcnt 32-bit words from SLIM address pointed to by slimp */ +#define READ_SLIM_COPY(binfo, bufp, slimp, wcnt) \ + fc_read_fromio((uint32*)slimp, (uint32*)bufp, (sizeof(uint32)*(wcnt)));\ + +#define WRITE_FLASH_COPY(binfo, bufp, flashp, wcnt) \ + fc_write_toio(bufp, flashp ,(sizeof(uint32)*(wcnt))) + +#define READ_FLASH_COPY(binfo, bufp, flashp, wcnt) \ + fc_read_fromio(flashp, bufp, (sizeof(uint32)*(wcnt))) + + + + + +/* defines for fc_open_count */ +#define FC_LAN_OPEN 0x1 /* LAN open completed */ +#define FC_FCP_OPEN 0x2 /* FCP open completed */ + +/* defines for fc_flag */ +#define FC_FCP_WWNN 0x0 /* Match FCP targets on WWNN */ +#define FC_FCP_WWPN 0x1 /* Match FCP targets on WWPN */ +#define FC_FCP_DID 0x2 /* Match FCP targets on DID */ +#define FC_FCP_MATCH 0x3 /* Mask for match FCP targets */ +#define FC_PENDING_RING0 0x4 /* Defer ring 0 IOCB processing */ +#define FC_LNK_DOWN 0x8 /* Link is down */ +#define FC_PT2PT 0x10 /* pt2pt with no fabric */ +#define FC_PT2PT_PLOGI 0x20 /* pt2pt initiate PLOGI */ +#define FC_DELAY_DISC 0x40 /* Delay discovery till after cfglnk */ +#define FC_PUBLIC_LOOP 0x80 /* Public loop */ +#define FC_INTR_THREAD 0x100 /* In interrupt code */ +#define FC_LBIT 0x200 /* LOGIN bit in loopinit set */ +#define FC_RSCN_MODE 0x400 /* RSCN cmd rcv'ed */ +#define FC_RSCN_DISC_TMR 0x800 /* wait edtov before processing RSCN */ +#define FC_NLP_MORE 0x1000 /* More node to process in node tbl */ +#define FC_OFFLINE_MODE 0x2000 /* Interface is offline for diag */ +#define FC_LD_TIMER 0x4000 /* Linkdown timer has been started */ +#define FC_LD_TIMEOUT 0x8000 /* Linkdown timeout has occurred */ +#define FC_FABRIC 0x10000 /* We are fabric attached */ +#define FC_DELAY_PLOGI 0x20000 /* Delay login till unreglogin */ +#define FC_SLI2 0x40000 /* SLI-2 CONFIG_PORT cmd completed */ +#define FC_INTR_WORK 0x80000 /* Was there work last intr */ +#define FC_NO_ROOM_IP 0x100000 /* No room on IP xmit queue */ +#define FC_NO_RCV_BUF 0x200000 /* No Rcv Buffers posted IP ring */ +#define FC_BUS_RESET 0x400000 /* SCSI BUS RESET */ +#define FC_ESTABLISH_LINK 0x800000 /* Reestablish Link */ +#define FC_SCSI_RLIP 0x1000000 /* SCSI rlip routine called */ +#define FC_DELAY_NSLOGI 0x2000000 /* Delay NameServer till ureglogin */ +#define FC_NSLOGI_TMR 0x4000000 /* NameServer in process of logout */ +#define FC_DELAY_RSCN 0x8000000 /* Delay RSCN till ureg/reg login */ +#define FC_RSCN_DISCOVERY 0x10000000 /* Authenticate all devices after RSCN */ +#define FC_2G_CAPABLE 0x20000000 /* HBA is 2 Gig capable */ +#define FC_POLL_MODE 0x40000000 /* [SYNC] I/O is in the polling mode */ +#define FC_BYPASSED_MODE 0x80000000 /* Interface is offline for diag */ + +/* defines for fc_ffstate */ +#define FC_INIT_START 1 +#define FC_INIT_NVPARAMS 2 +#define FC_INIT_REV 3 +#define FC_INIT_PARTSLIM 4 +#define FC_INIT_CFGRING 5 +#define FC_INIT_INITLINK 6 +#define FC_LINK_DOWN 7 +#define FC_LINK_UP 8 +#define FC_INIT_SPARAM 9 +#define FC_CFG_LINK 10 +#define FC_FLOGI 11 +#define FC_LOOP_DISC 12 +#define FC_NS_REG 13 +#define FC_NS_QRY 14 +#define FC_NODE_DISC 15 +#define FC_REG_LOGIN 16 +#define FC_CLEAR_LA 17 +#define FC_READY 32 +#define FC_ERROR 0xff + +#define NADDR_LEN 6 /* MAC network address length */ + +/* This should correspond with the HBA API event structure */ +struct fc_hba_event { + uint32 fc_eventcode; + uint32 fc_evdata1; + uint32 fc_evdata2; + uint32 fc_evdata3; + uint32 fc_evdata4; +}; + +typedef struct fc_hba_event HBAEVENT; +#define MAX_HBAEVENT 32 + +/***************************************************************************/ +/* + * This is the whole device control area for the adapter + */ +/***************************************************************************/ + +struct fc_dev_ctl { /* NOTE: struct intr must be FIRST */ + struct intr ihs; /* interrupt handler control struct */ + ndd_t ndd; /* ndd for NS ndd chain */ + struct fc_dev_ctl *next; /* point to the next device */ + uchar phys_addr[NADDR_LEN]; /* actual network address in use */ + Simple_lock cmd_slock; /* adapter command lock */ + void * ctl_correlator;/* point to the dd_ctl table */ + uchar device_state; /* main state of the device */ + uchar open_state; /* open state of the device */ + uchar intr_inited; /* flag for interrupt registration */ + uchar fcp_mapping; /* Map FCP devices based on WWNN WWPN or DID */ + ulong fc_ipri; /* save priority */ + int power_up; + uint32 dev_flag; /* device flags */ +#define FC_SCHED_CFG_INIT 2 /* schedule a call to fc_cfg_init() */ +#define FC_FULL_INFO_CALL 4 /* set if fc_info() can return full info */ +#define FC_NEEDS_DPC 0x10 + + uchar * devinfo; /* point to the device info */ + uchar * dip; /* point to device information */ + uchar * tran; /* point to device information */ + FCCLOCK * fc_estabtmo; /* link establishment timer */ + FCCLOCK * fc_waitflogi; /* link establishment timer */ + fc_dds_t dds; /* device dependent structure */ + fc_vpd_t vpd; /* vital product data */ + FC_BRD_INFO info; /* device specific info */ + uchar * mbufl_head; /* mbuf for offlevel intr handler */ + uchar * mbufl_tail; /* mbuf for offlevel intr handler */ + void * fc_evt_head; /* waiting for event queue */ + void * fc_evt_tail; /* waiting for event queue */ + + dvi_t * DEVICE_WAITING_head; + dvi_t * DEVICE_WAITING_tail; + dvi_t * ABORT_BDR_head; + dvi_t * ABORT_BDR_tail; + struct buf * timeout_head; /* bufs to iodone after RLIP done */ + + ushort timeout_count; + ushort init_eventTag; /* initial READ_LA eventtag from cfg */ + ushort hba_event_put; /* hbaevent event put word anchor */ + ushort hba_event_get; /* hbaevent event get word anchor */ + int hba_event_missed;/* hbaevent missed event word anchor */ + uchar pan_cnt; /* pseudo adapter number counter */ + uchar sid_cnt; /* SCSI ID counter */ + uchar adapter_state[NLP_MAXPAN]; + /* open/close state for pseudo adapters */ + + Simple_lock iostrat_lock; /* lock for ioctl IOSTRAT */ + int iostrat_event; /* iostrat event word anchor */ + struct buf * iostrat_head; /* head ptr to list of returned bufs */ + struct buf * iostrat_tail; /* tail ptr to list of returned bufs */ + HBAEVENT hbaevent[MAX_HBAEVENT]; + uint32 vendor_flag; + uint32 dfcmb[MAILBOX_CMD_WSIZE]; + /* Fill in any OS specific members */ + struct Scsi_Host *host; + struct pci_dev *pcidev; + struct buf *iodone_head; + struct buf *iodone_list; + void *dfc_kernel_buf; + void *abort_head; + void *abort_list; + void *rdev_head; + void *rdev_list; + void *rbus_head; + void *rbus_list; + void *rhst_head; + void *rhst_list; + void *qcmd_head; + void *qcmd_list; + void *qclk_head; + void *qclk_list; + uint32 dpc_ha_copy; /* copy of Host Attention Reg for DPC */ + uint32 dpc_hstatus; /* copy of Host Status Reg for DPC */ + uint32 dpc_cnt; + uint32 save_dpc_cnt; + ulong iflg; + ulong siflg; + WAIT_QUEUE linkwq; + WAIT_QUEUE rscnwq; + WAIT_QUEUE ctwq; +}; + +typedef struct fc_dev_ctl fc_dev_ctl_t; + + +/***************************************************************************/ +/* + * This is the global device driver control structure + */ +/***************************************************************************/ + +struct fc_dd_ctl { + FCCLOCK_INFO fc_clock_info; /* clock setup */ + FCCLOCK * fc_scsitmo; /* scsi timeout timer */ + fc_dev_ctl_t * p_dev[MAX_FC_BRDS]; /* device array */ + void * p_config[MAX_FC_BRDS]; + ushort num_devs; /* count of devices configed */ + + spinlock_t smp_lock; /* keep this at end */ +}; + +typedef struct fc_dd_ctl fc_dd_ctl_t; + +/* + * Macros for accessing device control area. The pointer to this area has to + * be named p_dev_ctl for using these macros. + */ + +#define DD_CTL fc_dd_ctl +#define CMD_LOCK p_dev_ctl->cmd_slock +#define IOCTL_SLP_LOCK ioctl_slp_lock +#define CLOCK_LOCK clock_info->clk_slock +#define IOSTRAT_LOCK p_dev_ctl->iostrat_lock +#define SCSI_TMO DD_CTL.fc_scsitmo +#define CLOCKWDT clock_info->clktimer + +#define IHS p_dev_ctl->ihs +#define NDD p_dev_ctl->ndd +#define NDDSTAT p_dev_ctl->ndd.ndd_genstats +#define VPD p_dev_ctl->vpd +#define DDS p_dev_ctl->dds +#define BINFO p_dev_ctl->info +#define RINGTMO rp->fc_wdt +#define MBOXTMO binfo->fc_mbox_wdt +#define FABRICTMO binfo->fc_fabric_wdt +#define FCSTATCTR binfo->fc_stats + +/* + * Lock class registration number for lock instrumentation. + * These numbers should be unique on the system and they should be + * controlled by the lock registration procedure set up for the lock + * instrumentations. + */ +#define FC_CMD_LOCK 47 +#define FC_IOSTRAT_LOCK 48 +#define FC_CFG_LOCK 49 +#define FC_CLOCK_LOCK 50 +#define FC_IOCTL_SLP_LOCK 51 + +#ifndef LITTLE_ENDIAN_HOST +#if defined(i386) +#define LITTLE_ENDIAN_HOST 1 +#endif + +#endif +#if LITTLE_ENDIAN_HOST +#define SWAP_SHORT(x) (x) +#define SWAP_LONG(x) (x) +#define SWAP_DATA(x) ((((x) & 0xFF)<<24) | (((x) & 0xFF00)<<8) | \ + (((x) & 0xFF0000)>>8) | (((x) & 0xFF000000)>>24)) +#define SWAP_DATA16(x) ((((x) & 0xFF) << 8) | ((x) >> 8)) +#define PCIMEM_SHORT(x) SWAP_SHORT(x) +#define PCIMEM_LONG(x) SWAP_LONG(x) +#define PCIMEM_DATA(x) SWAP_DATA(x) + +#else /* BIG_ENDIAN_HOST */ + +#define SWAP_SHORT(x) ((((x) & 0xFF) << 8) | ((x) >> 8)) +#define SWAP_LONG(x) ((((x) & 0xFF)<<24) | (((x) & 0xFF00)<<8) | \ + (((x) & 0xFF0000)>>8) | (((x) & 0xFF000000)>>24)) +#define SWAP_DATA(x) (x) +#define SWAP_DATA16(x) (x) + +#ifdef BIU_BSE /* This feature only makes sense for Big Endian */ +#define PCIMEM_SHORT(x) (x) +#define PCIMEM_LONG(x) (x) +#define PCIMEM_DATA(x) ((((x) & 0xFF)<<24) | (((x) & 0xFF00)<<8) | \ + (((x) & 0xFF0000)>>8) | (((x) & 0xFF000000)>>24)) +#else +#define PCIMEM_SHORT(x) SWAP_SHORT(x) +#define PCIMEM_LONG(x) SWAP_LONG(x) +#define PCIMEM_DATA(x) SWAP_DATA(x) +#endif +#endif + +#define SWAP_ALWAYS(x) ((((x) & 0xFF)<<24) | (((x) & 0xFF00)<<8) | \ + (((x) & 0xFF0000)>>8) | (((x) & 0xFF000000)>>24)) +#define SWAP_ALWAYS16(x) ((((x) & 0xFF) << 8) | ((x) >> 8)) + +/* + * For PCI configuration + */ +#define ADDR_LO(addr) ((int)(addr) & 0xffff) /* low 16 bits */ +#define ADDR_HI(addr) (((int)(addr) >> 16) & 0xffff) /* high 16 bits */ + +#endif /* _H_FC */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/fcLINUXfcp.c 830-ivtv/drivers/scsi/lpfc/fcLINUXfcp.c --- 000-virgin/drivers/scsi/lpfc/fcLINUXfcp.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/fcLINUXfcp.c Thu Jan 8 10:21:57 2004 @@ -0,0 +1,6948 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Enterprise Fibre Channel Host Bus Adapters. * + * Refer to the README file included with this package for * + * driver version and adapter support. * + * Copyright (C) 2003 Emulex Corporation. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details, a copy of which * + * can be found in the file COPYING included with this package. * + *******************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4) +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fc_os.h" +#include "fc_hw.h" +#include "fc.h" +#include "dfc.h" +#include "fcdiag.h" +#include "fcmsg.h" +#include "fc_crtn.h" +#include "fc_ertn.h" + + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) +#include +#include +#else +#include +#endif +#include +#include +#include +#include + +#ifdef powerpc +#include + +#ifdef NO_TCE +#define INVALID_PHYS NO_TCE +#else +#define INVALID_PHYS 0 +#endif + +#else +#define INVALID_PHYS 0 +#endif + +#define is_invalid_phys(addr) ((addr) == (void *)((ulong)INVALID_PHYS)) + +static long IOcnt = 0; +static long lpfcdiag_cnt = 0; + +#define LPFC_DRIVER_VERSION "1.23a-2.6-3" +_static_ char *lpfc_release_version = LPFC_DRIVER_VERSION; + +/* Declare memory for global structure that is used to access + * per adapter specific info.c + */ +_static_ fc_dd_ctl_t DD_CTL; +_static_ spinlock_t lpfc_smp_lock; +_static_ struct watchdog lpfc_clktimer; +_static_ int lpfc_initTimer = 0; +_static_ int lpfc_one_cpu = 1; /* Just bind DPC to CPU 0 */ +_static_ int lpfc_use_hostptr = 0; + +_static_ spinlock_t lpfc_q_lock[MAX_FC_BRDS]; +_static_ spinlock_t lpfc_mempool_lock[MAX_FC_BRDS]; + +struct lpfc_dpc { + struct task_struct *dpc_handler; /* kernel thread */ + struct semaphore *dpc_wait; /* DPC waits on this semaphore */ + struct semaphore *dpc_notify; /* requester waits for DPC on sem */ + int dpc_active; /* DPC routine is active */ + int dpc_ticks; /* DPC routine current tick count */ + struct semaphore dpc_sem; +} lpfc_dpc[MAX_FC_BRDS]; + +_static_ int lpfc_dpc_timer = 0; + +_forward_ void lpfc_timer(void *p); +_forward_ int do_fc_timer(fc_dev_ctl_t *p_dev_ctl); +_forward_ void lpfc_do_dpc(void *p); +_forward_ int fc_dpc_lstchk(fc_dev_ctl_t *p_dev_ctl, struct scsi_cmnd *Cmnd); + +/* Binding Definitions: Max string size */ +#define FC_MAX_DID_STRING 6 +#define FC_MAX_WW_NN_PN_STRING 16 + +int lpfcMallocCnt = 0; +int lpfcMallocByte = 0; +int lpfcFreeCnt = 0; +int lpfcFreeByte = 0; + +/* This defines memory for the common configuration parameters */ +#define DEF_ICFG 1 +#include "fcfgparm.h" + +#define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM)) + +#ifdef MODULE + +#ifndef EXPORT_SYMTAB +#define EXPORT_SYMTAB +#endif + +#include + +MODULE_PARM(lpfc_vendor, "i"); +MODULE_PARM(lpfc_bind_entries, "i"); +MODULE_PARM(lpfc_fcp_bind_WWPN, "1-" __MODULE_STRING(MAX_FC_BINDINGS) "s"); +MODULE_PARM(lpfc_fcp_bind_WWNN, "1-" __MODULE_STRING(MAX_FC_BINDINGS) "s"); +MODULE_PARM(lpfc_fcp_bind_DID, "1-" __MODULE_STRING(MAX_FC_BINDINGS) "s"); + +MODULE_PARM(lpfc_lun0_missing, "i"); +MODULE_PARM(lpfc_lun_skip, "i"); +MODULE_PARM(lpfc_use_removable, "i"); +MODULE_PARM(lpfc_max_lun, "i"); +MODULE_PARM(lpfc_use_data_direction, "i"); + + +#ifndef FC_NEW_EH +int lpfc_reset(struct scsi_cmnd *, unsigned int); +int fc_proc_info( char *, char **, off_t, int, int, int); +#endif +int fc_abort(struct scsi_cmnd *); +int fc_reset_device(struct scsi_cmnd *); +int fc_reset_bus(struct scsi_cmnd *); +int fc_reset_host(struct scsi_cmnd *); +int fc_queuecommand(struct scsi_cmnd *, void (*done)(struct scsi_cmnd *)); +void fc_queue_done_cmd(fc_dev_ctl_t * , struct buf *); +void fc_flush_done_cmds(fc_dev_ctl_t *, ulong); +void lpfc_nodev(unsigned long); +void local_timeout(unsigned long data); +irqreturn_t do_fc_intr_handler(int , void *, struct pt_regs *); +int do_fc_intr(struct intr *); +void * lpfc_kmalloc( unsigned int, unsigned int, void **, fc_dev_ctl_t *); +void lpfc_kfree( unsigned int, void *, void *, fc_dev_ctl_t *); + +EXPORT_SYMBOL(fc_abort); +EXPORT_SYMBOL(fc_reset_device); +EXPORT_SYMBOL(fc_reset_bus); +EXPORT_SYMBOL(fc_reset_host); +EXPORT_SYMBOL(local_timeout); +EXPORT_SYMBOL(do_fc_intr_handler); +EXPORT_SYMBOL(fc_queuecommand); +EXPORT_SYMBOL(fc_queue_done_cmd); +EXPORT_SYMBOL(fc_flush_done_cmds); +EXPORT_SYMBOL(do_fc_intr); +#else /* MODULE */ +#ifndef FC_NEW_EH +int fc_reset_device(struct scsi_cmnd *); +int fc_reset_bus(struct scsi_cmnd *); +int fc_reset_host(struct scsi_cmnd *); +#endif +void local_timeout(unsigned long data); +irqreturn_t do_fc_intr_handler(int , void *, struct pt_regs *); +int do_fc_intr(struct intr *); +void * lpfc_kmalloc( unsigned int, unsigned int, void **, fc_dev_ctl_t *); +void lpfc_kfree( unsigned int, void *, void *, fc_dev_ctl_t *); +extern int lpfn_probe(void); +static int lpfc_detect_called = 0; +#endif /* MODULE */ +int do_fc_abort(fc_dev_ctl_t *); +int do_fc_reset_device(fc_dev_ctl_t *); +int do_fc_reset_bus(fc_dev_ctl_t *); +int do_fc_reset_host(fc_dev_ctl_t *); +int do_fc_queuecommand(fc_dev_ctl_t *, ulong); +void fc_select_queue_depth(struct Scsi_Host *, struct scsi_device *); +int fc_device_queue_depth(fc_dev_ctl_t *, struct scsi_device *); +int fc_DetectInstance(int, struct pci_dev *pdev, uint, struct scsi_host_template *); + +#include "lpfc.conf.defs" + +#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0) +#ifdef MODULE +struct scsi_host_template driver_template = EMULEXFC; +#include "scsi_module.c" +#endif +#else /* new kernel scsi initialization scheme */ +static struct scsi_host_template driver_template = EMULEXFC; +#include "scsi_module.c" +#endif + +#ifndef __GENKSYMS__ +#include "fcmsgcom.c" +extern char fwrevision[32]; + +_local_ int lpfcdfc_init(void); +_local_ int fc_rtalloc(fc_dev_ctl_t *, struct dev_info *); +_local_ int fc_bind_wwpn(fc_dev_ctl_t *, char **, u_int ); +_local_ int fc_bind_wwnn(fc_dev_ctl_t *, char **, u_int ); +_local_ int fc_bind_did(fc_dev_ctl_t *, char **, u_int ); +_local_ dvi_t *fc_getDVI(fc_dev_ctl_t *, int, fc_lun_t); +_local_ ulong fc_po2(ulong); +_local_ int linux_attach(int, struct scsi_host_template *, struct pci_dev *); +_local_ int lpfc_find_cmd( fc_dev_ctl_t *p_dev_ctl, struct scsi_cmnd *cmnd); +_local_ void deviFree(fc_dev_ctl_t *, dvi_t *, node_t *); +_local_ int linux_detach(int ); +_local_ void *fc_kmem_zalloc(unsigned int ); + +extern int dfc_ioctl( struct dfccmdinfo *infop, struct cmd_input *cip); + +int lpfcdiag_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg); +int lpfcdiag_open(struct inode * inode, struct file * file); +int lpfcdiag_release(struct inode * inode, struct file * file); +int fc_ioctl(int , void *); + +static struct file_operations lpfc_fops = { + ioctl: lpfcdiag_ioctl, + open: lpfcdiag_open, + release: lpfcdiag_release, +}; + +static int lpfc_major = 0; + +/* If we want to define a new entry for Emulex boards*/ +/* #define PROC_SCSI_EMULEXFC PROC_SCSI_FILE+1 */ +/* For now we use the FC entry */ +#define NAMEEMULEX "lpfc" +#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0) +static struct proc_dir_entry proc_scsi_emulex = { + PROC_SCSI_FCAL , 4, "lpfc", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; +#endif + +struct dfc { + uint32 dfc_init; + uint32 filler; + uchar bufout[sizeof(FC_BRD_INFO)]; + struct dfc_info dfc_info[MAX_FC_BRDS]; +}; +extern struct dfc dfc; + +/*Extra configuration parameters as defined in lpfc.conf.c*/ +extern int lpfc_vendor; +extern int lpfc_bind_entries; +extern char *lpfc_fcp_bind_WWPN[]; +extern char *lpfc_fcp_bind_WWNN[]; +extern char *lpfc_fcp_bind_DID[]; +extern int lpfc_lun0_missing; +extern int lpfc_lun_skip; +extern int lpfc_use_removable; +extern int lpfc_max_lun; +extern int lpfc_use_data_direction; + +/*Other configuration parameters, not available to user*/ +static int lpfc_pci_latency_clocks =0; +static int lpfc_pci_cache_line =0; + +/*Other configuration parameters, not available to user*/ +static int lpfc_mtu = 4032; /* define IP max MTU size */ +static int lpfc_intr_ack = 1; +static int lpfc_first_check = 1; +static int lpfc_zone_rscn = 1; +static int lpfc_qfull_retry = 5; + +int lpfc_nethdr = 1; +int lpfc_driver_unloading = 0; + +/* The size of a physical memory page */ +uint32 fcPAGESIZE = 4096; /*PAGE_SIZE;*/ + +/* Can be used to map driver instance number and hardware adapter number */ +int fcinstance[MAX_FC_BRDS]; +int fcinstcnt = 0; + +/* Current driver state for diagnostic mode, online / offline, see fcdiag.h */ +uint32 fc_diag_state; +uint32 fc_dbg_flag = 0; +#define FC_MAX_SEGSZ 4096 + +#define FC_MAX_POOL 1024 +struct fc_mem_pool { + void *p_virt; + void *p_phys; + ushort p_refcnt; + ushort p_left; +}; +struct fc_mem_pool *fc_mem_dmapool[MAX_FC_BRDS]; +int fc_idx_dmapool[MAX_FC_BRDS]; +int fc_size_dmapool[MAX_FC_BRDS]; + +#define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code) + +#define ZERO_PAN 0 + +_static_ unsigned int lpfc_page_mask; + +/* Used in generating timeouts for timers */ +_static_ uint32 fc_scsi_abort_timeout_ticks; +_static_ uint32 fc_ticks_per_second; + +/* Can be used to map driver instance number and hardware adapter number */ +extern int fcinstance[]; +extern int fcinstcnt; + +/* Current driver state for diagnostic mode, online / offline, see fcdiag.h */ +extern uint32 fc_diag_state; + +extern int fc_check_for_vpd; +extern int fc_reset_on_attach; +extern int fc_max_ns_retry; +extern int fc_fdmi_on; +extern int fc_max_els_sent; + + + +void lpfc_scsi_add_timer(struct scsi_cmnd *, int); +int lpfc_scsi_delete_timer(struct scsi_cmnd *); + +#ifdef powerpc +#if LINUX_VERSION_CODE > LinuxVersionCode(2,4,14) +#define NO_BCOPY 1 +#endif +#endif + +#ifndef FC_NEW_EH +/****************************************************************************** +* Function name : fc_proc_info +* +* Description : +* +******************************************************************************/ +int fc_proc_info(char *buffer, + char **start, + off_t offset, + int length, + int hostno, + int inout) +{ + return(0); +} +#endif + +#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0) +/****************************************************************************** +* Function name : fc_pci_alloc_consistent +* +* Description : +* +******************************************************************************/ +void * fc_pci_alloc_consistent(struct pci_dev *hwdev, + size_t size, + dma_addr_t *dma_handle) +{ + void *virt_ptr; + u_long a_size; + int order; + + if ((size % PAGE_SIZE) == 0) { + for (order = 0, a_size = PAGE_SIZE; + a_size < size; order++, a_size <<= 1); + virt_ptr = (void *) __get_free_pages(GFP_ATOMIC, order); + } + else{ + a_size = fc_po2(size); + if(a_size == 256) + a_size = 512; + virt_ptr = kmalloc(a_size, GFP_KERNEL); + } + *dma_handle = virt_to_bus(virt_ptr); + return virt_ptr; +} + +/****************************************************************************** +* Function name : fc_pci_free_consistent +* +* Description : +* +******************************************************************************/ +void fc_pci_free_consistent(struct pci_dev *hwdev, + size_t size, + void *virt_ptr, + dma_addr_t dma_handle) +{ + u_long a_size; + int order; + + if(!virt_ptr) + return; + + /* + * Check which method was used to allocate the memory + */ + if ((size % PAGE_SIZE) == 0) { + for (order = 0, a_size = PAGE_SIZE; + a_size < size; order++, a_size <<= 1) + ; + free_pages((unsigned long)virt_ptr, order); + } + else{ + kfree(virt_ptr); + } +} +#else +/****************************************************************************** +* Function name : fc_pci_dma_sync_single +* +* Description : +* +******************************************************************************/ +void fc_pci_dma_sync_single(struct pci_dev *hwdev, + dma_addr_t h, + size_t size, + int c) +{ + pci_dma_sync_single(hwdev, h, 4096, c); +} +#endif + +#if defined (MODULE) || defined (NO_BCOPY) +/****************************************************************************** +* Function name : bcopy +* +* Description : kernel-space to kernel-space copy +* +******************************************************************************/ +_static_ void bcopy(void *src, + void *dest, + size_t n) +{ + memcpy(dest, src, n); +} +#else +/****************************************************************************** +* Function name : bcopy +* +* Description : kernel-space to kernel-space copy +* +******************************************************************************/ +_static_ void bcopy(void *src, void *dest, size_t n); + +#endif /* MODULE or NO_BCOPY */ + +/****************************************************************************** +* Function name : lpfc_DELAYMS +* +* Description : Called to delay cnt ms +* +******************************************************************************/ +_static_ int lpfc_DELAYMS(fc_dev_ctl_t *new_dev_ctl, + int cnt) +{ + int i; + fc_dev_ctl_t *p_dev_ctl; + FC_BRD_INFO *binfo; + struct lpfc_dpc *ldp; + + for (i = 0; i < MAX_FC_BRDS; i++) { + if((p_dev_ctl = (fc_dev_ctl_t *)DD_CTL.p_dev[i])) { + if(new_dev_ctl == p_dev_ctl) + continue; + binfo = &BINFO; + ldp = &lpfc_dpc[binfo->fc_brd_no]; + if ((ldp->dpc_active == 0) && ldp->dpc_wait) + up(ldp->dpc_wait); + } + } + if(new_dev_ctl->info.fc_ffstate != FC_INIT_START) { + barrier(); + schedule(); + } + mdelay(cnt); + for (i = 0; i < MAX_FC_BRDS; i++) { + if((p_dev_ctl = (fc_dev_ctl_t *)DD_CTL.p_dev[i])) { + if(new_dev_ctl == p_dev_ctl) + continue; + binfo = &BINFO; + ldp = &lpfc_dpc[binfo->fc_brd_no]; + if ((ldp->dpc_active == 0) && ldp->dpc_wait) + up(ldp->dpc_wait); + } + } + if(new_dev_ctl->info.fc_ffstate != FC_INIT_START) { + barrier(); + schedule(); + } + return(0); +} + +/****************************************************************************** +* Function name : kmem_alloc +* +* Description : Kernel memory alloc and free +* +******************************************************************************/ +_static_ void *fc_kmem_alloc(unsigned int size) +{ + void *ptr; + lpfcMallocCnt++; + lpfcMallocByte += size; + ptr = lpfc_kmalloc(size, GFP_ATOMIC, 0, 0); + return ptr; + +} + +/****************************************************************************** +* Function name : fc_kmem_free +* +* Description : +* +******************************************************************************/ +_static_ void fc_kmem_free(void *obj, + unsigned int size) +{ + lpfcFreeCnt++; + lpfcFreeByte += size; + if(obj) + lpfc_kfree(size, obj, (void *)((ulong)INVALID_PHYS), 0); +} + +/****************************************************************************** +* Function name : fc_kmem_zalloc +* +* Description : allocate memory and initialize to zeros +* +******************************************************************************/ +_static_ void *fc_kmem_zalloc(unsigned int size) +{ + void *ptr = fc_kmem_alloc(size); + if(ptr) + fc_bzero(ptr,size); + return ptr; +} + +/****************************************************************************** +* Function name : dfc_disable_lock +* +* Description : +* +******************************************************************************/ +_static_ ulong dfc_disable_lock(ulong p1, + Simple_lock *p2) + +{ + ulong iflg; + + iflg = 0; + spin_lock_irqsave(&lpfc_smp_lock, iflg); + return(iflg); +} + +/****************************************************************************** +* Function name : dfc_unlock_enable +* +* Description : +* +******************************************************************************/ +_static_ void dfc_unlock_enable(ulong p1, + Simple_lock *p2) +{ + ulong iflg; + + iflg = p1; + spin_unlock_irqrestore(&lpfc_smp_lock, iflg); + return; +} + +_static_ ulong lpfc_q_disable_lock(fc_dev_ctl_t *p_dev_ctl) +{ + ulong iflg; + + iflg = 0; + spin_lock_irqsave(&lpfc_q_lock[p_dev_ctl->info.fc_brd_no], iflg); + return(iflg); +} + + +_static_ void lpfc_q_unlock_enable(fc_dev_ctl_t *p_dev_ctl, ulong p1) +{ + ulong iflg; + + iflg = p1; + spin_unlock_irqrestore(&lpfc_q_lock[p_dev_ctl->info.fc_brd_no], iflg); + return; +} + +_static_ ulong lpfc_mempool_disable_lock(fc_dev_ctl_t *p_dev_ctl) +{ + ulong iflg; + + iflg = 0; + spin_lock_irqsave(&lpfc_mempool_lock[p_dev_ctl->info.fc_brd_no], iflg); + return(iflg); +} + + +_static_ void lpfc_mempool_unlock_enable(fc_dev_ctl_t *p_dev_ctl, ulong p1) +{ + ulong iflg; + + iflg = p1; + spin_unlock_irqrestore(&lpfc_mempool_lock[p_dev_ctl->info.fc_brd_no], iflg); + return; +} + +/****************************************************************************** +* Function name : fc_flush_done_cmds +* +* Description : flush all done commands at once +* +******************************************************************************/ +void fc_flush_done_cmds(fc_dev_ctl_t *p_dev_ctl, + ulong siflg) +{ + int count, first_inq; + struct scsi_cmnd *cmd; + struct buf * head; + FC_BRD_INFO *binfo; + struct dev_info *devp; + struct sc_buf *sp; + uint32 *iptr; + ulong iflg; + + iflg = 0; + LPFC_LOCK_DRIVER(1); + + head = p_dev_ctl->iodone_head; + binfo = &BINFO; + count = 0; + while(head) { + count++; + cmd = head->cmnd; + devp = ((struct sc_buf *)head)->current_devp; + head=head->av_forw; + + if(devp) + devp->iodonecnt++; + else + panic("NULL devp in flush_done\n"); + + if(cmd && (cmd->scsi_done != NULL)) { + sp = (struct sc_buf *)cmd->host_scribble; + if (!sp) { + /* NULL sp in flush_done */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0708, /* ptr to msg structure */ + fc_mes0708, /* ptr to msg */ + fc_msgBlk0708.msgPreambleStr, /* begin varargs */ + cmd->cmnd[0], + cmd->serial_number, + cmd->retries, + cmd->result); /* end varargs */ + continue; + } + + FCSTATCTR.fcpRsvd1++; + + if(devp->scp) { + sp->bufstruct.av_forw = devp->scp; + devp->scp = sp; + } + else { + devp->scp = sp; + devp->scp->bufstruct.av_forw = 0; + } + devp->scpcnt++; + cmd->host_scribble = 0; + + first_inq = 0; + if(devp->first_check & FIRST_IO) { + uchar *buf; + if(cmd->cmnd[0] == FCP_SCSI_INQUIRY) { + buf = (uchar *)cmd->request_buffer; + if((cmd->result) || + ((*buf & 0x70) != 0)) { /* lun not there */ +#ifdef FREE_LUN + deviFree(p_dev_ctl, devp, devp->nodep); +#else + devp->first_check &= ~FIRST_IO; +#endif + } else { + devp->first_check &= ~FIRST_IO; + } + first_inq = 1; + } + } + + + LPFC_UNLOCK_DRIVER; + iptr = (uint32 *)&cmd->sense_buffer[0]; + if((cmd->result) || *iptr) { + devp->errorcnt++; + /* iodone error return */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0710, /* ptr to msg structure */ + fc_mes0710, /* ptr to msg */ + fc_msgBlk0710.msgPreambleStr, /* begin varargs */ + (uint32)((cmd->device->id << 16) | cmd->device->lun), + (uint32)((cmd->retries << 16 ) | cmd->cmnd[0]), + cmd->result, + *iptr); /* end varargs */ + } + + lpfc_scsi_add_timer(cmd, cmd->timeout_per_command); + cmd->scsi_done(cmd); + iflg = 0; + LPFC_LOCK_DRIVER(2); + } + else + panic("Cmnd in done queue without scsi_done\n"); + } + p_dev_ctl->iodone_head = 0; + p_dev_ctl->iodone_list = 0; + LPFC_UNLOCK_DRIVER; + return; +} + +/****************************************************************************** +* Function name : fc_queue_done_cmd +* +* Description : add done command to a queue to be flushed later +* +******************************************************************************/ +void fc_queue_done_cmd(fc_dev_ctl_t *p_dev_ctl, + struct buf *sb) +{ + struct sc_buf *sp; + + if(p_dev_ctl->iodone_head == NULL) { + p_dev_ctl->iodone_head = sb; + p_dev_ctl->iodone_list = sb; + } else { + p_dev_ctl->iodone_list->av_forw = sb; + p_dev_ctl->iodone_list = sb; + } + sb->av_forw = NULL; + + sp = (struct sc_buf *)sb; + if (sp->cmd_flag & FLAG_ABORT) + sp->cmd_flag &= ~FLAG_ABORT; +} + +/****************************************************************************** +* Function name : remap_pci_mem +* +* Description : remap pci memory, makes sure mapped memory is page-aligned +* +******************************************************************************/ +_local_ void * remap_pci_mem(u_long base, + u_long size) +{ +#ifdef powerpc + return (ioremap (base, size)); +#else + u_long page_base = ((u_long) base)& PAGE_MASK; + u_long page_offs = ((u_long) base) - page_base; + u_long page_remapped = (u_long) ioremap(page_base, page_offs+size); + return (void *) (page_remapped? (page_remapped + page_offs) : ((ulong)-1)); +#endif +} + +/****************************************************************************** +* Function name : unmap_pci_mem +* +* Description : unmap pci memory +* +******************************************************************************/ +_local_ void unmap_pci_mem(u_long vaddr) +{ + if (vaddr) { + } +} + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) +/****************************************************************************** +* Function name : pci_getadd +* +* Description : get address from a pci register, accounts for 64 bit addresses +* returns next register +* +******************************************************************************/ +_local_ int pci_getadd(struct pci_dev *pdev, + int reg, + u_long *base) + +{ + *base = pci_resource_start(pdev, reg); + reg++; + return ++reg; +} +#else +/****************************************************************************** +* Function name : pci_getadd +* +* Description : get address from a pci register, accounts for 64 bit addresses +* returns next register +* +******************************************************************************/ +_local_ int pci_getadd(struct pci_dev *pdev, + int reg, + u_long *base) +{ + *base = pdev->base_address[reg++]; + if ((*base & 0x7) == 0x4) { +#if BITS_PER_LONG > 32 + *base |= (((u_long)pdev->base_address[reg]) << 32); +#endif + ++reg; + } + return reg; +} +#endif + +/****************************************************************************** +* Function name : fc_DetectInstance +* +* Description : +* +******************************************************************************/ +int fc_DetectInstance( int instance, + struct pci_dev *pdev, + uint type, + struct scsi_host_template *tmpt) +{ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + /* PCI_SUBSYSTEM_IDS supported */ + while ((pdev = pci_find_subsys(PCI_VENDOR_ID_EMULEX, type, + PCI_ANY_ID, PCI_ANY_ID, pdev) )) + { + if (pci_enable_device(pdev)) continue; +#else + while ((pdev = pci_find_device(PCI_VENDOR_ID_EMULEX, type, + pdev))) + { +#endif + if(linux_attach(instance, tmpt, pdev) ) + continue; + instance++; + } + + return(instance); +} + +/****************************************************************************** +* Function name : fc_detect +* +* Description : Mid-level driver entry function for detecting the boards +* Also provides some initialization +* +******************************************************************************/ +int fc_detect(struct scsi_host_template *tmpt) +{ +#define WAIT_4_FC_READY 200 /* Thats 200 * 25 ms = 5 sec */ +#define MSEC_25_DELAY 25 +#define PRE_FC_READY_DELAY 40 +#define POST_FC_READY_DELAY 60 + + int instance = 0; + struct pci_dev *pdev = NULL; + fc_dev_ctl_t *p_dev_ctl; + FC_BRD_INFO *binfo; + int i, j, cnt; + /* To add another, add 1 to number of elements, add a line + * sType[x] = id, leave last sType[x+1] = 0; + */ + uint sType [8]; + + sType[0] = PCI_DEVICE_ID_THOR; + sType[1] = PCI_DEVICE_ID_SUPERFLY; + sType[2] = PCI_DEVICE_ID_PEGASUS; + sType[3] = PCI_DEVICE_ID_PFLY; + sType[4] = PCI_DEVICE_ID_CENTAUR; + sType[5] = PCI_DEVICE_ID_DRAGONFLY; + sType[6] = PCI_DEVICE_ID_TFLY; + /* sType[x] = PCI_DEVICE_ID_XXX; */ + sType[7] = 0; + + /* + * Intialization + */ + lpfc_page_mask = ((unsigned int) ~(fcPAGESIZE - 1)); + fc_ticks_per_second = HZ; + fc_scsi_abort_timeout_ticks = 300 * HZ /*CLOCK_TICK_RATE*/ ; + fc_bzero(&DD_CTL, sizeof(fc_dd_ctl_t)); + for (i = 0; i < MAX_FC_BRDS; i++) { + DD_CTL.p_dev[i] = NULL; + DD_CTL.p_config[i] = NULL; + fcinstance[i] = -1; + } + DD_CTL.num_devs = 0; + + fc_check_for_vpd = 1; /* issue dump mbox command during HBA initialization + * to check VPD data (if any) for a Serial Number */ + fc_reset_on_attach = 0; /* Always reset HBA before initialization in attach */ + fc_fdmi_on = 0; /* Enable FDMI */ + fc_max_ns_retry = 3; /* max number of retries for NameServer CT requests + * during discovery. */ + + fc_max_els_sent = 1; + if(fc_max_els_sent > NLP_MAXREQ) + fc_max_els_sent = NLP_MAXREQ; + +#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0) + tmpt->proc_dir = &proc_scsi_emulex; +#else + tmpt->proc_name = NAMEEMULEX; +#endif + + printk("Emulex LightPulse FC SCSI/IP %s\n", lpfc_release_version); + /* + * the mid-level clears interrupts + * no need to re-intialize pdev + */ + i = 0; + while(sType[i]) + { + instance = fc_DetectInstance(instance, pdev, sType[i], tmpt); + i++; + } + + if(instance) { + lpfcdfc_init(); /* Initialize diagnostic interface */ + } + + p_dev_ctl = (fc_dev_ctl_t *)NULL; /* Prevent compiler warning */ + if( (PRE_FC_READY_DELAY > 0) && + (instance > 0) && + (p_dev_ctl = (fc_dev_ctl_t *)DD_CTL.p_dev[0])) { + binfo = &BINFO; + for( i=0; ifc_ffstate >= FC_LINK_UP) && (binfo->fc_ffstate != FC_READY)) { + cnt++; + } + } + } + if(cnt) { + /* HBA(s) not FC_READY yet */ + lpfc_DELAYMS( p_dev_ctl, MSEC_25_DELAY); /* 25 millisec */ + continue; + } + break; + } + + /* There are cases where the HBAs are FC_READY but not all FC nodes + * have completed their FC PLOGI/PRLI sequence due to collisions. The + * following delay loop provides a chance for these noded to complete + * their FC PLOGI/PRLI sequence prior to allowing the SCSI layer to + * start up upon the return from this routine. + */ + + if( (POST_FC_READY_DELAY > 0) && + (instance > 0) && + (p_dev_ctl = (fc_dev_ctl_t *)DD_CTL.p_dev[0])) { + binfo = &BINFO; + for( i=0; ipcidev; + if(!pdev) + return(INTR_FAIL); + if (request_irq(pdev->irq, do_fc_intr_handler, SA_INTERRUPT | SA_SHIRQ, + "lpfcdd", (void *)ihs)) + return(INTR_FAIL); + return(INTR_SUCC); +} + +/****************************************************************************** +* Function name : i_clear +* +* Description : Called from fc_detach to remove interrupt vector for adapter +* +******************************************************************************/ +_static_ int i_clear(struct intr *ihs) +{ + struct pci_dev *pdev; + fc_dev_ctl_t *p_dev_ctl; + + p_dev_ctl = (fc_dev_ctl_t * )ihs; /* Since struct intr is at beginning */ + + /* + * Get PCI for this board + */ + pdev = p_dev_ctl->pcidev; + if(!pdev) + return(1); + free_irq(pdev->irq, p_dev_ctl); + p_dev_ctl->intr_inited=0; + return(0); +} + +/****************************************************************************** +* Function name : linux_attach +* +* Description : LINUX initialization entry point, called from environment +* to attach to / initialize a specific adapter. +* +******************************************************************************/ +_local_ int linux_attach(int instance, + struct scsi_host_template *tmpt, + struct pci_dev *pdev) +{ + struct Scsi_Host *host; + fc_dev_ctl_t *p_dev_ctl=NULL; + FC_BRD_INFO *binfo; + FCCLOCK_INFO *clock_info; + iCfgParam *clp=NULL; + int initTimer = 0; + ulong iflg; + + /* + * must have a valid pci_dev + */ + if(!pdev) + return (1); + + /* Allocate memory to manage HBA dma pool */ + fc_mem_dmapool[instance] = kmalloc((sizeof(struct fc_mem_pool) * FC_MAX_POOL), + GFP_ATOMIC); + if(fc_mem_dmapool[instance] == 0) + return(1); + + fc_bzero((void *)fc_mem_dmapool[instance], + (sizeof(struct fc_mem_pool) * FC_MAX_POOL)); + fc_idx_dmapool[instance] = 0; + fc_size_dmapool[instance] = FC_MAX_POOL; + + /* + * Allocate space for adapter info structure + */ + if (!(p_dev_ctl = (fc_dev_ctl_t *)fc_kmem_zalloc(sizeof(fc_dev_ctl_t)))) { + return (1); + } + /* + * Allocate space for configuration parameters + */ + if (!(clp = (iCfgParam *)fc_kmem_zalloc(sizeof(icfgparam)))) { + goto fail1; + } + + p_dev_ctl->pcidev = pdev; + p_dev_ctl->sid_cnt = 0; /* Start scsid assignment at 1 */ + binfo = &BINFO; + binfo->fc_brd_no = instance; + spin_lock_init(&lpfc_q_lock[instance]); + spin_lock_init(&lpfc_mempool_lock[instance]); + + if(lpfc_use_hostptr) + binfo->fc_busflag = FC_HOSTPTR; +#ifdef powerpc + binfo->fc_busflag = FC_HOSTPTR; +#endif + + binfo->fc_p_dev_ctl = (uchar * )p_dev_ctl; + DD_CTL.p_dev[instance] = p_dev_ctl; + DD_CTL.p_config[instance] = clp; + fcinstance[instance] = instance; + + /* + * Initialize config parameters + */ + bcopy((void * )&icfgparam, (void *)clp, sizeof(icfgparam)); + + /* + * Initialize locks, and timeout functions + */ + clock_info = &DD_CTL.fc_clock_info; + CLOCKWDT = (void *)&lpfc_clktimer; +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) + init_waitqueue_head(&p_dev_ctl->linkwq); + init_waitqueue_head(&p_dev_ctl->rscnwq); + init_waitqueue_head(&p_dev_ctl->ctwq); +#endif + + + initTimer = 0; + if(lpfc_initTimer == 0) { + LPFC_INIT_LOCK_DRIVER; /* Just one global lock for driver */ + fc_clock_init(); + ((struct watchdog *)(CLOCKWDT))->func = fc_timer; + ((struct watchdog *)(CLOCKWDT))->restart = 1; + ((struct watchdog *)(CLOCKWDT))->count = 0; + ((struct watchdog *)(CLOCKWDT))->stopping = 0; + ((struct watchdog *)(CLOCKWDT))->timeout_id = 1; + /* + * add our watchdog timer routine to kernel's list + */ + ((struct watchdog *)(CLOCKWDT))->timer.expires = HZ + jiffies; + ((struct watchdog *)(CLOCKWDT))->timer.function = local_timeout; + ((struct watchdog *)(CLOCKWDT))->timer.data = (unsigned long)(CLOCKWDT); + init_timer(&((struct watchdog *)(CLOCKWDT))->timer); + add_timer(&((struct watchdog *)(CLOCKWDT))->timer); + lpfc_initTimer = 1; + initTimer = 1; + } + + { + struct lpfc_dpc *ldp; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) + struct semaphore sem = MUTEX_LOCKED; +#else + DECLARE_MUTEX_LOCKED(sem); +#endif + + ldp = &lpfc_dpc[instance]; + ldp->dpc_notify = &sem; + kernel_thread((int (*)(void *))lpfc_do_dpc, (void *) p_dev_ctl, 0); + /* + * Now wait for the kernel dpc thread to initialize and go to sleep. + */ + down(&sem); + ldp->dpc_notify = NULL; + } + + p_dev_ctl->intr_inited = 0; + fcinstcnt++; + if (fc_attach(instance, (uint32 * )((ulong)instance))) { + /* + * lower level routine will log error + */ + fcinstcnt--; + goto fail; + } + + /* + * Register this board + */ + host = scsi_register(tmpt, sizeof(unsigned long)); + + /* + * Adjust the number of id's + * Although max_id is an int, target id's are unsined chars + * Do not exceed 255, otherwise the device scan will wrap around + */ + host->max_id = MAX_FCP_TARGET; + if(!lpfc_max_lun) { + host->max_lun = MAX_FCP_LUN+1; + lpfc_max_lun = MAX_FCP_LUN+1; + } + else { + host->max_lun = lpfc_max_lun; + } + host->unique_id = instance; + + /* Adapter ID */ + host->this_id = MAX_FCP_TARGET - 1; + + /* + * Starting with 2.4.0 kernel, Linux can support commands longer + * than 12 bytes. However, scsi_register() always sets it to 12. + * For it to be useful to the midlayer, we have to set it here. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + host->max_cmd_len = 16; +#endif + + /* + * Queue depths per lun + */ + host->cmd_per_lun = 1; + + /* + * Save a pointer to device control in host and increment board + */ + host->hostdata[0] = (unsigned long)p_dev_ctl; + p_dev_ctl->host = host; + DD_CTL.num_devs++; + + iflg = 0; + LPFC_LOCK_DRIVER(23); + /* + * Need to start scsi timeout if FCP is turned on + * The SCSI timeout watch dog is for all adaptors, so do it once only + */ + + if((SCSI_TMO == 0) && clp[CFG_FCP_ON].a_current) { + SCSI_TMO = fc_clk_set(0, 5, fc_scsi_timeout, 0, 0); + } + + /* DQFULL */ + if ((clp[CFG_DQFULL_THROTTLE].a_current) && + (clp[CFG_DFT_LUN_Q_DEPTH].a_current > FC_MIN_QFULL)) { + if ((clp[CFG_DQFULL_THROTTLE_UP_TIME].a_current) && + (clp[CFG_DQFULL_THROTTLE_UP_INC].a_current)) { + fc_clk_set(p_dev_ctl, clp[CFG_DQFULL_THROTTLE_UP_TIME].a_current, + fc_q_depth_up, 0, 0); + } + } + LPFC_UNLOCK_DRIVER; + return(0); + +fail: + if(initTimer) { + if(SCSI_TMO) { + fc_clk_can(0, SCSI_TMO); + SCSI_TMO = 0; + } + clock_info = &DD_CTL.fc_clock_info; + ((struct watchdog *)(CLOCKWDT))->stopping = 1; + if (((struct watchdog *)(CLOCKWDT))->timer.function) + del_timer(&((struct watchdog *)(CLOCKWDT))->timer); + ((struct watchdog *)(CLOCKWDT))->timer.function=NULL; + ((struct watchdog *)(CLOCKWDT))->timeout_id=0; + } + + { + struct lpfc_dpc *ldp; + ldp = &lpfc_dpc[instance]; + if(ldp->dpc_handler != NULL ) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) + struct semaphore sem = MUTEX_LOCKED; +#else + DECLARE_MUTEX_LOCKED(sem); +#endif + + ldp->dpc_notify = &sem; + send_sig(SIGKILL, ldp->dpc_handler, 1); + down(&sem); + ldp->dpc_notify = NULL; + } + } + /* + * Free up any allocated resources + */ + fc_kmem_free(clp, sizeof(icfgparam)); + fail1: + /* + * Just in case the interrupt is still on + */ + if(p_dev_ctl->intr_inited) + i_clear((struct intr *)p_dev_ctl); + fc_kmem_free(p_dev_ctl, sizeof(fc_dev_ctl_t)); + + return(1); +} + +/****************************************************************************** +* Function name : fc_device_queue_depth +* +* Description : Determines the queue depth for a given device. +* There are two ways +* a queue depth can be obtained for a tagged queueing device. +* One way is the default queue depth which is determined by +* whether if it is defined, then it is used as the default +* queue depth. +* Otherwise, we use either 4 or 8 as the default queue depth +* (dependent on the number of hardware SCBs). +******************************************************************************/ +int fc_device_queue_depth(fc_dev_ctl_t *p_dev_ctl, + struct scsi_device *device) +{ + iCfgParam * clp; + FC_BRD_INFO *binfo; + + binfo = &p_dev_ctl->info; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + if( device->tagged_supported ) { +#ifdef NEEDS_CHECKING + /* + * XXX double check that we can remove this. + */ + device->tagged_queue = 1; +#endif + device->current_tag = 0; + device->queue_depth = clp[CFG_DFT_LUN_Q_DEPTH].a_current; + } else { + device->queue_depth = 16; + } + return(device->queue_depth); +} + +/****************************************************************************** +* Function name : lpfc_do_dpc +* +* Description : +* +******************************************************************************/ +void lpfc_do_dpc(void *p) +{ + fc_dev_ctl_t * p_dev_ctl=(fc_dev_ctl_t*)p; + FC_BRD_INFO * binfo; + FCCLOCK_INFO * clock_info; + iCfgParam * clp; + struct lpfc_dpc * ldp; + void * ioa; + unsigned long secs; + int instance, ev; + ulong iflg; + ulong siflg; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) + struct fs_struct *fs; + struct semaphore sem = MUTEX_LOCKED; +#else + DECLARE_MUTEX_LOCKED(sem); +#endif + + lock_kernel(); + secs = 0; + + /* + * If we were started as result of loading a module, close all of the + * user space pages. We don't need them, and if we didn't close them + * they would be locked into memory. + */ + exit_mm(current); + + binfo = &BINFO; + clock_info = &DD_CTL.fc_clock_info; + instance = binfo->fc_brd_no ; + + daemonize("lpfc_do_dpc_%d", instance); + + clp = DD_CTL.p_config[instance]; + ldp = &lpfc_dpc[instance]; + + /* Since this is a kernel process, lets be nice to it! */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +#ifdef DEF_NICE + current->nice = -20; + current->processor = smp_processor_id(); +#endif /* DEF_NICE */ + + +#else + { + int niceval; + uint32 priority; + + niceval = -20; + priority = niceval; + if (niceval < 0) + priority = -niceval; + if (priority > 20) + priority = 20; + priority = (priority * DEF_PRIORITY + 10) / 20 + DEF_PRIORITY; + + if (niceval >= 0) { + priority = 2*DEF_PRIORITY - priority; + if (!priority) + priority = 1; + } + current->priority = priority; + } + current->session = 1; + current->pgrp = 1; +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) + siginitsetinv(¤t->blocked, SHUTDOWN_SIGS); +#else + siginitsetinv(¤t->blocked, sigmask(SIGKILL)); +#endif + + ldp->dpc_wait = &sem; + ldp->dpc_handler = current; + + unlock_kernel(); + + /* + * Wake up the thread that created us. + */ + if( ldp->dpc_notify != NULL ) + up(ldp->dpc_notify); + ev = 0; + + while( 1 ) { + /* + * If we get a signal, it means we are supposed to go + * away and die. This typically happens if the user is + * trying to unload a module. + */ + if(ev == 0) { + ldp->dpc_ticks = clock_info->ticks; + + if(clp[CFG_NETWORK_ON].a_current) { + } + + /* Only wait if we go thru KP once with no work */ + down_interruptible(&sem); + if( signal_pending(current) ) { + + iflg = 0; + flush_signals(current); + + /* Only allow our driver unload to kill the KP */ + if( ldp->dpc_notify != NULL ) + break; /* get out */ + } + ldp->dpc_ticks = clock_info->ticks; + if(clp[CFG_NETWORK_ON].a_current) { + } + + } + ev = 0; + + siflg = 0; + iflg = 0; + LPFC_LOCK_DRIVER(22); + ldp->dpc_active = 1; + + p_dev_ctl->dpc_cnt++; + p_dev_ctl->dev_flag &= ~FC_NEEDS_DPC; + + /* Handle timer interrupts */ + if(p_dev_ctl->qclk_head) { + ev++; + do_fc_timer(p_dev_ctl); + } + + /* Handle adapter interrupts */ + if(p_dev_ctl->dpc_ha_copy) { + ev++; + do_fc_intr((struct intr *)p_dev_ctl); + } + + if(p_dev_ctl->qcmd_head) { + ev++; + if(clp[CFG_CR_DELAY].a_current != 0) { + ioa = FC_MAP_MEM(&binfo->fc_iomap_mem); /* map in io registers */ + if ((uchar)READ_SLIM_ADDR(binfo, ((volatile uint32 *)ioa + (SLIMOFF+(FC_ELS_RING*2)+1))) != + ((SLI2_SLIM * )binfo->fc_slim2.virt)->mbx.us.s2.port[FC_ELS_RING].rspPutInx) { + handle_ring_event(p_dev_ctl, FC_ELS_RING, HA_R0CE_RSP); + } + if ((uchar)READ_SLIM_ADDR(binfo, ((volatile uint32 *)ioa + (SLIMOFF+(FC_FCP_RING*2)+1))) != + ((SLI2_SLIM * )binfo->fc_slim2.virt)->mbx.us.s2.port[FC_FCP_RING].rspPutInx) { + handle_ring_event(p_dev_ctl, FC_FCP_RING, HA_R2CE_RSP); + } + FC_UNMAP_MEMIO(ioa); + } + do_fc_queuecommand(p_dev_ctl, siflg); + } + + /* Handle SCSI layer aborts */ + if(p_dev_ctl->abort_head) { + ev++; + do_fc_abort(p_dev_ctl); + } + + /* Handle SCSI layer device resets */ + if(p_dev_ctl->rdev_head) { + ev++; + do_fc_reset_device(p_dev_ctl); + } + + /* Handle SCSI layer bus resets */ + if(p_dev_ctl->rbus_head) { + ev++; + do_fc_reset_bus(p_dev_ctl); + } + + /* Handle SCSI layer host resets */ + if(p_dev_ctl->rhst_head) { + ev++; + do_fc_reset_host(p_dev_ctl); + } + + /* Handle iodone processing */ + if(p_dev_ctl->iodone_head) { + int count, first_inq; + struct scsi_cmnd *cmd; + struct buf * head; + struct dev_info *devp; + struct sc_buf *sp; + uint32 *iptr; + + ev++; + ldp->dpc_active = 0; + + head = p_dev_ctl->iodone_head; + count = 0; + while(head) { + count++; + cmd = head->cmnd; + devp = ((struct sc_buf *)head)->current_devp; + head=head->av_forw; + + if(devp) + devp->iodonecnt++; + else + panic("NULL devp in flush_done\n"); + + if(cmd && (cmd->scsi_done != NULL)) { + sp = (struct sc_buf *)cmd->host_scribble; + if (!sp) { + /* NULL sp in DPC flush_done */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0709, /* ptr to msg structure */ + fc_mes0709, /* ptr to msg */ + fc_msgBlk0709.msgPreambleStr, /* begin varargs */ + cmd->cmnd[0], + cmd->serial_number, + cmd->retries, + cmd->result); /* end varargs */ + continue; + } + + FCSTATCTR.fcpRsvd1++; + + if(devp->scp) { + sp->bufstruct.av_forw = devp->scp; + devp->scp = sp; + } + else { + devp->scp = sp; + devp->scp->bufstruct.av_forw = 0; + } + devp->scpcnt++; + cmd->host_scribble = 0; + + iptr = (uint32 *)&cmd->sense_buffer[0]; + if((cmd->result) || *iptr) { + devp->errorcnt++; + /* iodone error return */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0711, /* ptr to msg structure */ + fc_mes0711, /* ptr to msg */ + fc_msgBlk0711.msgPreambleStr, /* begin varargs */ + (uint32)((cmd->device->id << 16) | cmd->device->lun), + (uint32)((cmd->retries << 16 ) | cmd->cmnd[0]), + cmd->result, + *iptr); /* end varargs */ + } + + first_inq = 0; + if(devp->first_check & FIRST_IO) { + uchar *buf; + if(cmd->cmnd[0] == FCP_SCSI_INQUIRY) { + buf = (uchar *)cmd->request_buffer; + if((cmd->result) || + ((*buf & 0x70) != 0)) { /* lun not there */ +#ifdef FREE_LUN + deviFree(p_dev_ctl, devp, devp->nodep); +#else + devp->first_check &= ~FIRST_IO; +#endif + } else { + devp->first_check &= ~FIRST_IO; + } + first_inq = 1; + } + } + + LPFC_UNLOCK_DRIVER; + lpfc_scsi_add_timer(cmd, cmd->timeout_per_command); + cmd->scsi_done(cmd); + iflg = 0; + LPFC_LOCK_DRIVER(2); + } + else + panic("Cmnd in done queue without scsi_done\n"); + } + p_dev_ctl->iodone_head = 0; + p_dev_ctl->iodone_list = 0; + LPFC_UNLOCK_DRIVER; + } + else { + ldp->dpc_active = 0; + LPFC_UNLOCK_DRIVER; + } + + if(p_dev_ctl->dev_flag & FC_SCHED_CFG_INIT) { + p_dev_ctl->dev_flag &= ~FC_SCHED_CFG_INIT; + fc_cfg_init(p_dev_ctl); + + LPFC_LOCK_DRIVER(27); + if(p_dev_ctl->fc_estabtmo) { + fc_clk_can(p_dev_ctl, p_dev_ctl->fc_estabtmo); + } + if (binfo->fc_ffstate != FC_READY) { + p_dev_ctl->fc_estabtmo = + fc_clk_set(p_dev_ctl, 60, fc_establish_link_tmo, 0, 0); + } + LPFC_UNLOCK_DRIVER; + } + } + + /* + * Make sure that nobody tries to wake us up again. + */ + ldp->dpc_wait = NULL; + ldp->dpc_handler = NULL; + ldp->dpc_active = 0; + + /* + * If anyone is waiting for us to exit (i.e. someone trying to unload + * a driver), then wake up that process to let them know we are on + * the way out the door. This may be overkill - I *think* that we + * could probably just unload the driver and send the signal, and when + * the error handling thread wakes up that it would just exit without + * needing to touch any memory associated with the driver itself. + */ + if( ldp->dpc_notify != NULL ) + up(ldp->dpc_notify); +} + +/****************************************************************************** +* Function name : fc_release +* +* Description : +* +******************************************************************************/ +int fc_release(struct Scsi_Host *host) +{ + fc_dev_ctl_t *p_dev_ctl; + FC_BRD_INFO *binfo; + node_t *node_ptr; + struct dev_info *dev_ptr; + struct lpfc_dpc *ldp; + int instance; + int dev_index,target; + fc_lun_t lun; + ulong iflg; + + /* + * Indicate driver unloading so our interrupt handler can stop + * accepting interrupts. + */ + lpfc_driver_unloading = 1; + + /* + * get dev control from host + */ + p_dev_ctl = (fc_dev_ctl_t *)host->hostdata[0]; + binfo = &BINFO; + instance = binfo->fc_brd_no ; + + if(lpfcdiag_cnt) { + /* Cannot unload driver while lpfcdiag Interface is active */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk1200, /* ptr to msg structure */ + fc_mes1200, /* ptr to msg */ + fc_msgBlk1200.msgPreambleStr, /* begin varargs */ + lpfcdiag_cnt, + (uint32)instance); /* end varargs */ + } + + iflg = 0; + LPFC_LOCK_DRIVER(24); + linux_detach(instance); + /* + *Clear all devi's + *Although host_queue has all devices, its not a good idea to touch it! + *instead we will loop on all possible targets and luns + */ + for(target=0; target < host->max_id; target++) { + dev_index = INDEX(ZERO_PAN, target); + node_ptr = binfo->device_queue_hash[dev_index].node_ptr; + if(!node_ptr) + continue; + for(lun=0; lun <= host->max_lun; lun++){ + dev_ptr = fc_find_lun(binfo, dev_index, lun); + if(!dev_ptr) + continue; + /* + * Free this device + */ + deviFree(p_dev_ctl, dev_ptr, node_ptr); + } + fc_kmem_free(node_ptr, sizeof(node_t)); + binfo->device_queue_hash[dev_index].node_ptr = 0; + } + + fcinstcnt--; + DD_CTL.num_devs--; + LPFC_UNLOCK_DRIVER; + + if(lpfc_major) + unregister_chrdev(lpfc_major, "lpfcdfc"); + + ldp = &lpfc_dpc[instance]; + if(ldp->dpc_handler != NULL ) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) + struct semaphore sem = MUTEX_LOCKED; +#else + DECLARE_MUTEX_LOCKED(sem); +#endif + + ldp->dpc_notify = &sem; + send_sig(SIGKILL, ldp->dpc_handler, 1); + down(&sem); + ldp->dpc_notify = NULL; + } + scsi_unregister(host); + + return 0; +} + +/****************************************************************************** +* Function name : linux_detach +* +* Description : LINUX deinitialization entry point, called from environment +* to detach from / free resources for a specific adapter. +******************************************************************************/ +_local_ int linux_detach( int instance) +{ + FC_BRD_INFO * binfo; + iCfgParam * clp; + fc_dev_ctl_t * p_dev_ctl = (fc_dev_ctl_t * ) NULL; + + p_dev_ctl = DD_CTL.p_dev[instance]; + if (p_dev_ctl == NULL) { + return(0); + } + binfo = &BINFO; + clp = DD_CTL.p_config[instance]; + if (clp == NULL) { + return(0); + } + + /* + * Stop and free resources associated with scsi timeout timer + */ + if(DD_CTL.num_devs == 1) { + FCCLOCK_INFO * clock_info; + + if(SCSI_TMO) { + fc_clk_can(0, SCSI_TMO); + SCSI_TMO = 0; + } + clock_info = &DD_CTL.fc_clock_info; + ((struct watchdog *)(CLOCKWDT))->stopping = 1; + if (((struct watchdog *)(CLOCKWDT))->timer.function) + del_timer(&((struct watchdog *)(CLOCKWDT))->timer); + ((struct watchdog *)(CLOCKWDT))->timer.function=NULL; + ((struct watchdog *)(CLOCKWDT))->timeout_id=0; + } + fc_detach(instance); + + fc_kmem_free(DD_CTL.p_dev[instance], sizeof(fc_dev_ctl_t)); + DD_CTL.p_dev[instance] = 0; + fc_kmem_free(DD_CTL.p_config[instance], sizeof(icfgparam)); + DD_CTL.p_config[instance] = 0; + + kfree(fc_mem_dmapool[instance]); + return(0); +} + +/****************************************************************************** +* Function name : fc_abort +* +* Description : Linux mid-level command abort entry +* Note we are using the new error handling routines +******************************************************************************/ +int fc_abort(struct scsi_cmnd *Cmnd) +{ + struct Scsi_Host *host; + fc_dev_ctl_t *p_dev_ctl; + FC_BRD_INFO * binfo; + ulong iflg; + struct lpfc_dpc *ldp; + + + host = Cmnd->device->host; + if(!host) { +#ifdef FC_NEW_EH + return FAILED ; +#else + return SCSI_ABORT_NOT_RUNNING ; +#endif + } + p_dev_ctl = (fc_dev_ctl_t *)host->hostdata[0]; + if(!p_dev_ctl) { +#if FC_NEW_EH + return FAILED ; +#else + return SCSI_ABORT_NOT_RUNNING ; +#endif + } + binfo = &BINFO; + + iflg = 0; + LPFC_LOCK_DRIVER(5); + ldp = &lpfc_dpc[binfo->fc_brd_no]; + if (ldp->dpc_wait == NULL) { + LPFC_UNLOCK_DRIVER; +#if FC_NEW_EH + return SUCCESS; +#else + return SCSI_ABORT_SUCCESS ; +#endif + } + + fc_dpc_lstchk(p_dev_ctl, Cmnd); + if(p_dev_ctl->abort_head == NULL) { + p_dev_ctl->abort_head = (void *)Cmnd; + p_dev_ctl->abort_list = (void *)Cmnd; + } else { + SCMD_NEXT((struct scsi_cmnd *)(p_dev_ctl->abort_list)) = Cmnd; + p_dev_ctl->abort_list = (void *)Cmnd; + } + SCMD_NEXT(Cmnd) = NULL; + + + if (ldp->dpc_active == 0) { + LPFC_UNLOCK_DRIVER; + up(ldp->dpc_wait); + } + else { + LPFC_UNLOCK_DRIVER; + } + +#if FC_NEW_EH + return SUCCESS; +#else + return SCSI_ABORT_SUCCESS ; +#endif +} + +/****************************************************************************** +* Function name : do_fc_abort +* +* Description : +* +******************************************************************************/ +int do_fc_abort(fc_dev_ctl_t *p_dev_ctl) +{ + struct scsi_cmnd * Cmnd; + struct scsi_cmnd * oCmnd; + FC_BRD_INFO * binfo; + dvi_t * dev_ptr; + struct sc_buf * sp; + int dev_index,target; + fc_lun_t lun; + + binfo = &BINFO; + Cmnd = (struct scsi_cmnd *)p_dev_ctl->abort_head; + while(Cmnd) { + target = (int)Cmnd->device->id; + lun = (fc_lun_t)Cmnd->device->lun; + dev_index = INDEX(ZERO_PAN, target); + + dev_ptr = fc_find_lun(binfo, dev_index, lun); + /* SCSI layer issued abort device */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0712, /* ptr to msg structure */ + fc_mes0712, /* ptr to msg */ + fc_msgBlk0712.msgPreambleStr, /* begin varargs */ + target, + (uint32)lun, + Cmnd->cmnd[0], + Cmnd->serial_number); /* end varargs */ + if(!dev_ptr || !(dev_ptr->nodep)) { + goto done; + } + + if (dev_ptr->flags & CHK_SCSI_ABDR) { + goto done; + } + + sp = (struct sc_buf *)Cmnd->host_scribble; + if (lpfc_find_cmd(p_dev_ctl, Cmnd)) { + FCSTATCTR.fcpRsvd2++; + } else { + if (fc_abort_clk_blk(p_dev_ctl, lpfc_scsi_selto_timeout, sp, 0)) { + FCSTATCTR.fcpRsvd2++; + } + } +done: + oCmnd = Cmnd; + Cmnd = SCMD_NEXT(Cmnd); + SCMD_NEXT(oCmnd) = 0; + } + p_dev_ctl->abort_head = 0; + p_dev_ctl->abort_list = 0; + + return(0); +} + +#ifndef FC_NEW_EH +/****************************************************************************** +* Function name : lpfc_reset +* +* Description : +* +******************************************************************************/ +int lpfc_reset(struct scsi_cmnd *Cmnd, + unsigned int flags) +{ + int action; + + if( flags & SCSI_RESET_SUGGEST_HOST_RESET ) { + if((action = fc_reset_host(Cmnd)) == FAILED) + return(SCSI_RESET_ERROR); + action = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET; + } + else if( flags & SCSI_RESET_SUGGEST_BUS_RESET ) { + if((action = fc_reset_bus(Cmnd)) == FAILED) + return(SCSI_RESET_ERROR); + action = SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET; + } + else { + if((action = fc_reset_device(Cmnd)) == FAILED) + return(SCSI_RESET_ERROR); + action = SCSI_RESET_SUCCESS; + } + return(action); +} +#endif + +/****************************************************************************** +* Function name : fc_reset_device +* +* Description : Linux mid-level reset device entry +* Note we are using the new error handling routines +* In the old handlers there is only one reset entry which has +* two arguments +******************************************************************************/ +int fc_reset_device(struct scsi_cmnd *Cmnd) +{ + struct Scsi_Host *host; + fc_dev_ctl_t *p_dev_ctl; + FC_BRD_INFO *binfo; + ulong iflg; + struct lpfc_dpc *ldp; + + host = Cmnd->device->host; + if(!host) { + return FAILED ; + } + p_dev_ctl = (fc_dev_ctl_t *)host->hostdata[0]; + if(!p_dev_ctl) { + return FAILED; + } + binfo = &BINFO; + + iflg = 0; + LPFC_LOCK_DRIVER(6); + ldp = &lpfc_dpc[binfo->fc_brd_no]; + if (ldp->dpc_wait == NULL) { + LPFC_UNLOCK_DRIVER; + return SUCCESS; + } + + fc_dpc_lstchk(p_dev_ctl, Cmnd); + if(p_dev_ctl->rdev_head == NULL) { + p_dev_ctl->rdev_head = (void *)Cmnd; + p_dev_ctl->rdev_list = (void *)Cmnd; + } else { + SCMD_NEXT((struct scsi_cmnd *)(p_dev_ctl->rdev_list)) = Cmnd; + p_dev_ctl->rdev_list = (void *)Cmnd; + } + SCMD_NEXT(Cmnd) = NULL; + + if (ldp->dpc_active == 0) { + LPFC_UNLOCK_DRIVER; + up(ldp->dpc_wait); + } + else { + LPFC_UNLOCK_DRIVER; + } + + return SUCCESS; +} + +/****************************************************************************** +* Function name : do_fc_reset_device +* +* Description : +* +******************************************************************************/ +int do_fc_reset_device(fc_dev_ctl_t *p_dev_ctl) +{ + struct scsi_cmnd * Cmnd; + struct scsi_cmnd * oCmnd; + struct dev_info * dev_ptr; + FC_BRD_INFO * binfo; + int dev_index, target, j; + fc_lun_t lun; + + binfo = &BINFO; + Cmnd = (struct scsi_cmnd *)p_dev_ctl->rdev_head; + while(Cmnd) { + target = (int)Cmnd->device->id; + lun = (fc_lun_t)Cmnd->device->lun; + dev_index = INDEX(ZERO_PAN, target); + + dev_ptr = fc_find_lun(binfo, dev_index, lun); + j = 0; + /* SCSI layer issued target reset */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0713, /* ptr to msg structure */ + fc_mes0713, /* ptr to msg */ + fc_msgBlk0713.msgPreambleStr, /* begin varargs */ + target, + (uint32)lun, + dev_index); /* end varargs */ + if(dev_ptr == 0) { + goto done; + } + if ((binfo->fc_ffstate != FC_READY) || + (!(dev_ptr->nodep)) || + (dev_ptr->nodep->rpi == 0xfffe)) { + goto done; + } + fc_fcp_abort(p_dev_ctl, TARGET_RESET, dev_index, -1); + + +done: + oCmnd = Cmnd; + Cmnd = SCMD_NEXT(Cmnd); + SCMD_NEXT(oCmnd) = 0; + } + p_dev_ctl->rdev_head = 0; + p_dev_ctl->rdev_list = 0; + + return(0); +} + +/****************************************************************************** +* Function name : fc_reset_bus +* +* Description : Linux mid-level reset host/bus entry +* +******************************************************************************/ +int fc_reset_bus(struct scsi_cmnd *Cmnd) +{ + struct Scsi_Host *host; + fc_dev_ctl_t *p_dev_ctl; + FC_BRD_INFO *binfo; + ulong iflg; + struct lpfc_dpc *ldp; + + host = Cmnd->device->host; + if(!host) { + return FAILED; + } + p_dev_ctl = (fc_dev_ctl_t *)host->hostdata[0]; + if(!p_dev_ctl) { + return FAILED; + } + binfo = &p_dev_ctl->info; + + iflg = 0; + LPFC_LOCK_DRIVER(8); + ldp = &lpfc_dpc[binfo->fc_brd_no]; + if (ldp->dpc_wait == NULL) { + LPFC_UNLOCK_DRIVER; + return SUCCESS; + } + + fc_dpc_lstchk(p_dev_ctl, Cmnd); + if(p_dev_ctl->rbus_head == NULL) { + p_dev_ctl->rbus_head = (void *)Cmnd; + p_dev_ctl->rbus_list = (void *)Cmnd; + } else { + SCMD_NEXT((struct scsi_cmnd *)(p_dev_ctl->rbus_list)) = Cmnd; + p_dev_ctl->rbus_list = (void *)Cmnd; + } + SCMD_NEXT(Cmnd) = NULL; + + if (ldp->dpc_active == 0) { + LPFC_UNLOCK_DRIVER; + up(ldp->dpc_wait); + } + else { + LPFC_UNLOCK_DRIVER; + } + + return SUCCESS; +} + +/****************************************************************************** +* Function name : do_fc_reset_bus +* +* Description : +* +******************************************************************************/ +int do_fc_reset_bus(fc_dev_ctl_t *p_dev_ctl) +{ + struct scsi_cmnd * Cmnd; + struct scsi_cmnd * oCmnd; + FC_BRD_INFO *binfo; + node_t * node_ptr; + struct dev_info * dev_ptr; + NODELIST * nlp; + NODELIST * new_nlp; + iCfgParam *clp; + int rets = FAILED; + + binfo = &p_dev_ctl->info; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + Cmnd = (struct scsi_cmnd *)p_dev_ctl->rbus_head; + while(Cmnd) { + /* SCSI layer issued Bus Reset */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0714, /* ptr to msg structure */ + fc_mes0714, /* ptr to msg */ + fc_msgBlk0714.msgPreambleStr, /* begin varargs */ + Cmnd->device->id, + (uint32)Cmnd->device->lun); /* end varargs */ + /* + * Tell them + */ + if (binfo->fc_ffstate == FC_READY) { + rets = SUCCESS; + fc_fcp_abort(p_dev_ctl, TARGET_RESET, -1, -1); + } + else { + /* + * Check to see if we should wait for FC_READY + */ + if ((binfo->fc_ffstate < FC_LINK_DOWN) || + (binfo->fc_ffstate == FC_ERROR)) { + rets = FAILED; + } + else { + rets = SUCCESS; + } + } + + /* Reset first_check */ + nlp = binfo->fc_nlpmap_start; + while(nlp != (NODELIST *)&binfo->fc_nlpmap_start) { + new_nlp = (NODELIST *)nlp->nlp_listp_next; + if (nlp->nlp_type & NLP_FCP_TARGET) { + if(clp[CFG_FIRST_CHECK].a_current) { + /* If we are an FCP node, update first_check flag for all LUNs */ + if ((node_ptr = (node_t * )nlp->nlp_targetp) != NULL) { + for (dev_ptr = node_ptr->lunlist; dev_ptr != NULL; + dev_ptr = dev_ptr->next) { + dev_ptr->first_check = FIRST_CHECK_COND; + } + } + } + } + nlp = new_nlp; + } + oCmnd = Cmnd; + Cmnd = SCMD_NEXT(Cmnd); + SCMD_NEXT(oCmnd) = 0; + } + p_dev_ctl->rbus_head = 0; + p_dev_ctl->rbus_list = 0; + + return rets; +} + +/****************************************************************************** +* Function name : fc_reset_host +* +* Description : +* +******************************************************************************/ +int fc_reset_host(struct scsi_cmnd *Cmnd) +{ + struct Scsi_Host *host; + fc_dev_ctl_t *p_dev_ctl; + FC_BRD_INFO *binfo; + ulong iflg; + struct lpfc_dpc *ldp; + + host = Cmnd->device->host; + if(!host) { + return FAILED; + } + p_dev_ctl = (fc_dev_ctl_t *)host->hostdata[0]; + if(!p_dev_ctl) { + return FAILED; + } + binfo = &p_dev_ctl->info; + + iflg = 0; + LPFC_LOCK_DRIVER(10); + ldp = &lpfc_dpc[binfo->fc_brd_no]; + if (ldp->dpc_wait == NULL) { + LPFC_UNLOCK_DRIVER; + return SUCCESS; + } + + fc_dpc_lstchk(p_dev_ctl, Cmnd); + if(p_dev_ctl->rhst_head == NULL) { + p_dev_ctl->rhst_head = (void *)Cmnd; + p_dev_ctl->rhst_list = (void *)Cmnd; + } else { + SCMD_NEXT((struct scsi_cmnd *)(p_dev_ctl->rhst_list)) = Cmnd; + p_dev_ctl->rhst_list = (void *)Cmnd; + } + SCMD_NEXT(Cmnd) = NULL; + + if (ldp->dpc_active == 0) { + LPFC_UNLOCK_DRIVER; + up(ldp->dpc_wait); + } + else { + LPFC_UNLOCK_DRIVER; + } + + return SUCCESS; +} + +/****************************************************************************** +* Function name : do_fc_reset_host +* +* Description : +* +******************************************************************************/ +int do_fc_reset_host(fc_dev_ctl_t *p_dev_ctl) +{ + struct scsi_cmnd * Cmnd; + struct scsi_cmnd * oCmnd; + FC_BRD_INFO *binfo; + int rets = FAILED; + + binfo = &p_dev_ctl->info; + Cmnd = (struct scsi_cmnd *)p_dev_ctl->rhst_head; + while(Cmnd) { + /* SCSI layer issued Host Reset */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0715, /* ptr to msg structure */ + fc_mes0715, /* ptr to msg */ + fc_msgBlk0715.msgPreambleStr, /* begin varargs */ + Cmnd->device->id, + (uint32)Cmnd->device->lun); /* end varargs */ + /* + * Check to see if we should wait for FC_READY + */ + if ((binfo->fc_ffstate < FC_LINK_DOWN) || (binfo->fc_ffstate == FC_ERROR)) { + rets = FAILED; + } + else { + rets = SUCCESS; + } + oCmnd = Cmnd; + Cmnd = SCMD_NEXT(Cmnd); + SCMD_NEXT(oCmnd) = 0; + } + p_dev_ctl->rhst_head = 0; + p_dev_ctl->rhst_list = 0; + + return(rets); +} + + +static char addrStr[18]; + +/****************************************************************************** +* Function name : addr_sprintf +* +* Description : Used by fc_info for displaying WWNN / WWPNs +* +******************************************************************************/ +_static_ char * addr_sprintf(register uchar *ap) +{ + register int i; + register char *cp = addrStr; + static char digits[] = "0123456789abcdef"; + + for (i = 0; i < 8; i++) { + *cp++ = digits[*ap >> 4]; + *cp++ = digits[*ap++ & 0xf]; + *cp++ = ':'; + } + *--cp = 0; + return(addrStr); +} /* End addr_sprintf */ + +/****************************************************************************** +* Function name : fc_info +* +* Description : Prepare host information for mid-level +* +******************************************************************************/ +const char *fc_info(struct Scsi_Host *host) +{ + static char buf[4096]; + fc_dev_ctl_t *p_dev_ctl; + FC_BRD_INFO * binfo; + struct pci_dev *pdev; + char *multip; + int idx, i, j, incr; + char hdw[9]; + NODELIST *nlp; + + buf[0]='\0'; + p_dev_ctl = (fc_dev_ctl_t *)host->hostdata[0]; + if(!p_dev_ctl) + return buf; + binfo = &BINFO; + pdev = p_dev_ctl->pcidev ; + + for(idx=0; idx < MAX_FC_BRDS; idx++) { + if(p_dev_ctl == DD_CTL.p_dev[idx]) + break; + } + + multip = "LPFC"; + + if (!(p_dev_ctl->dev_flag & FC_FULL_INFO_CALL)) { + if(pdev != NULL) { + switch(pdev->device){ + case PCI_DEVICE_ID_CENTAUR: + if(FC_JEDEC_ID(VPD.rev.biuRev) == CENTAUR_2G_JEDEC_ID) { + sprintf(&buf[strlen(buf)], + "HBA: Emulex LightPulse LP9002 on PCI bus %02x device %02x irq %d", + p_dev_ctl->pcidev->bus->number, p_dev_ctl->pcidev->devfn, + p_dev_ctl->pcidev->irq); + } else { + sprintf(&buf[strlen(buf)], + "HBA: Emulex LightPulse LP9000 on PCI bus %02x device %02x irq %d", + p_dev_ctl->pcidev->bus->number, p_dev_ctl->pcidev->devfn, + p_dev_ctl->pcidev->irq); + } + break; + case PCI_DEVICE_ID_DRAGONFLY: + sprintf(&buf[strlen(buf)], + "HBA: Emulex LightPulse LP8000 on PCI bus %02x device %02x irq %d", + p_dev_ctl->pcidev->bus->number, p_dev_ctl->pcidev->devfn, + p_dev_ctl->pcidev->irq); + break; + case PCI_DEVICE_ID_PEGASUS: + sprintf(&buf[strlen(buf)], + "HBA: Emulex LightPulse LP9802 on PCI bus %02x device %02x irq %d", + p_dev_ctl->pcidev->bus->number, p_dev_ctl->pcidev->devfn, + p_dev_ctl->pcidev->irq); + break; + case PCI_DEVICE_ID_PFLY: + sprintf(&buf[strlen(buf)], + "HBA: Emulex LightPulse LP982 on PCI bus %02x device %02x irq %d", + p_dev_ctl->pcidev->bus->number, p_dev_ctl->pcidev->devfn, + p_dev_ctl->pcidev->irq); + break; + case PCI_DEVICE_ID_THOR: + sprintf(&buf[strlen(buf)], + "HBA: Emulex LightPulse LP10000 on PCI bus %02x device %02x irq %d", + p_dev_ctl->pcidev->bus->number, p_dev_ctl->pcidev->devfn, + p_dev_ctl->pcidev->irq); + break; + case PCI_DEVICE_ID_TFLY: + sprintf(&buf[strlen(buf)], + "HBA: Emulex LightPulse LP1050 on PCI bus %02x device %02x irq %d", + p_dev_ctl->pcidev->bus->number, p_dev_ctl->pcidev->devfn, + p_dev_ctl->pcidev->irq); + break; + default: + sprintf(&buf[strlen(buf)], + "HBA: Emulex LightPulse on PCI bus %02x device %02x irq %d", + p_dev_ctl->pcidev->bus->number, p_dev_ctl->pcidev->devfn, + p_dev_ctl->pcidev->irq); + } + } + p_dev_ctl->dev_flag |= FC_FULL_INFO_CALL; + return(buf); + } + + sprintf(buf, "Emulex LightPulse %s Driver Version: %s\n", + multip, lpfc_release_version); + + if(pdev != NULL) { + switch(pdev->device){ + case PCI_DEVICE_ID_CENTAUR: + if(FC_JEDEC_ID(VPD.rev.biuRev) == CENTAUR_2G_JEDEC_ID) { + sprintf(&buf[strlen(buf)], + "HBA: Emulex LightPulse LP9002 2 Gigabit PCI Fibre Channel Adapter\n"); + } else { + sprintf(&buf[strlen(buf)], + "HBA: Emulex LightPulse LP9000 1 Gigabit PCI Fibre Channel Adapter\n"); + } + break; + case PCI_DEVICE_ID_DRAGONFLY: + sprintf(&buf[strlen(buf)], + "HBA: Emulex LightPulse LP8000 1 Gigabit PCI Fibre Channel Adapter\n"); + break; + case PCI_DEVICE_ID_PEGASUS: + sprintf(&buf[strlen(buf)], + "HBA: Emulex LightPulse LP9802 2 Gigabit PCI Fibre Channel Adapter\n"); + break; + case PCI_DEVICE_ID_PFLY: + sprintf(&buf[strlen(buf)], + "HBA: Emulex LightPulse LP982 2 Gigabit PCI Fibre Channel Adapter\n"); + break; + case PCI_DEVICE_ID_THOR: + sprintf(&buf[strlen(buf)], + "HBA: Emulex LightPulse LP10000 2 Gigabit PCI Fibre Channel Adapter\n"); + break; + case PCI_DEVICE_ID_TFLY: + sprintf(&buf[strlen(buf)], + "HBA: Emulex LightPulse LP1050 2 Gigabit PCI Fibre Channel Adapter\n"); + break; + default: + sprintf(&buf[strlen(buf)], + "HBA: Emulex LightPulse PCI Fibre Channel Adapter\n"); + } + } + + sprintf(&buf[strlen(buf)], "SerialNum: %s\n", binfo->fc_SerialNumber); + + decode_firmware_rev(binfo, &VPD); + sprintf(&buf[strlen(buf)], "Firmware Version: %s\n", fwrevision); + + sprintf(&buf[strlen(buf)], "Hdw: "); + /* Convert JEDEC ID to ascii for hardware version */ + incr = VPD.rev.biuRev; + for(i=0;i<8;i++) { + j = (incr & 0xf); + if(j <= 9) + hdw[7-i] = (char)((uchar)0x30 + (uchar)j); + else + hdw[7-i] = (char)((uchar)0x61 + (uchar)(j-10)); + incr = (incr >> 4); + } + hdw[8] = 0; + strcat(buf, hdw); + + sprintf(&buf[strlen(buf)], "\nVendorId: 0x%x\n", + ((((uint32)pdev->device) << 16) | (uint32)(pdev->vendor))); + + sprintf(&buf[strlen(buf)], "Portname: "); + strcat(buf, addr_sprintf((uchar *)&binfo->fc_portname)); + + sprintf(&buf[strlen(buf)], " Nodename: "); + strcat(buf, addr_sprintf((uchar *)&binfo->fc_nodename)); + + switch (binfo->fc_ffstate) { + case FC_INIT_START: + case FC_INIT_NVPARAMS: + case FC_INIT_REV: + case FC_INIT_PARTSLIM: + case FC_INIT_CFGRING: + case FC_INIT_INITLINK: + case FC_LINK_DOWN: + sprintf(&buf[strlen(buf)], "\n\nLink Down\n"); + break; + case FC_LINK_UP: + case FC_INIT_SPARAM: + case FC_CFG_LINK: + sprintf(&buf[strlen(buf)], "\n\nLink Up\n"); + break; + case FC_FLOGI: + case FC_LOOP_DISC: + case FC_NS_REG: + case FC_NS_QRY: + case FC_NODE_DISC: + case FC_REG_LOGIN: + case FC_CLEAR_LA: + sprintf(&buf[strlen(buf)], "\n\nLink Up - Discovery\n"); + break; + case FC_READY: + sprintf(&buf[strlen(buf)], "\n\nLink Up - Ready:\n"); + sprintf(&buf[strlen(buf)], " PortID 0x%x\n", binfo->fc_myDID); + if (binfo->fc_topology == TOPOLOGY_LOOP) { + if(binfo->fc_flag & FC_PUBLIC_LOOP) + sprintf(&buf[strlen(buf)], " Public Loop\n"); + else + sprintf(&buf[strlen(buf)], " Private Loop\n"); + } else { + if(binfo->fc_flag & FC_FABRIC) + sprintf(&buf[strlen(buf)], " Fabric\n"); + else + sprintf(&buf[strlen(buf)], " Point-2-Point\n"); + } + + if(binfo->fc_linkspeed == LA_2GHZ_LINK) + sprintf(&buf[strlen(buf)], " Current speed 2G\n"); + else + sprintf(&buf[strlen(buf)], " Current speed 1G\n"); + + nlp = binfo->fc_nlpmap_start; + while(nlp != (NODELIST *)&binfo->fc_nlpmap_start) { + if (nlp->nlp_state == NLP_ALLOC) { + sprintf(&buf[strlen(buf)], "\nlpfc%dt%02x DID %06x WWPN ", + idx, FC_SCSID(nlp->id.nlp_pan, nlp->id.nlp_sid), nlp->nlp_DID); + strcat(buf, addr_sprintf((uchar *)&nlp->nlp_portname)); + strcat(buf, " WWNN "); + strcat(buf, addr_sprintf((uchar *)&nlp->nlp_nodename)); + } + if ((4096 - strlen(buf)) < 90) + break; + nlp = (NODELIST *)nlp->nlp_listp_next; + } + if(nlp != (NODELIST *)&binfo->fc_nlpmap_start) + strcat(buf,"\n....\n"); + } + + return (buf); +} + +/****************************************************************************** +* Function name : fc_data_direction +* +* Description : If we do not relay on Cmnd->sc_data_direction call this +* routine to determine if we are doing a read or write. +* +******************************************************************************/ +int fc_data_direction(struct scsi_cmnd *Cmnd) +{ + int ret_code; + + switch (Cmnd->cmnd[0]) { + case WRITE_6: + case WRITE_10: + case WRITE_12: + case CHANGE_DEFINITION: + case LOG_SELECT: + case MODE_SELECT: + case MODE_SELECT_10: + case WRITE_BUFFER: + case VERIFY: + case WRITE_VERIFY: + case WRITE_VERIFY_12: + case WRITE_LONG: + case WRITE_LONG_2: + case WRITE_SAME: + case SEND_DIAGNOSTIC: + case FORMAT_UNIT: + case REASSIGN_BLOCKS: + case FCP_SCSI_RELEASE_LUNR: + case FCP_SCSI_RELEASE_LUNV: + case HPVA_SETPASSTHROUGHMODE: + case HPVA_EXECUTEPASSTHROUGH: + case HPVA_CREATELUN: + case HPVA_SETLUNSECURITYLIST: + case HPVA_SETCLOCK: + case HPVA_RECOVER: + case HPVA_GENERICSERVICEOUT: + case DMEP_EXPORT_OUT: + ret_code = B_WRITE; + break; + case MDACIOCTL_DIRECT_CMD: + switch (Cmnd->cmnd[2]) { + case MDACIOCTL_STOREIMAGE: + case MDACIOCTL_WRITESIGNATURE: + case MDACIOCTL_SETREALTIMECLOCK: + case MDACIOCTL_PASS_THRU_CDB: + case MDACIOCTL_CREATENEWCONF: + case MDACIOCTL_ADDNEWCONF: + case MDACIOCTL_MORE: + case MDACIOCTL_SETPHYSDEVPARAMETER: + case MDACIOCTL_SETLOGDEVPARAMETER: + case MDACIOCTL_SETCONTROLLERPARAMETER: + case MDACIOCTL_WRITESANMAP: + case MDACIOCTL_SETMACADDRESS: + ret_code = B_WRITE; + break; + case MDACIOCTL_PASS_THRU_INITIATE: + if (Cmnd->cmnd[3] & 0x80) { + ret_code = B_WRITE; + } + else { + ret_code = B_READ; + } + break; + default: + ret_code = B_READ; + } + break; + default: +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) + if (Cmnd->sc_data_direction == SCSI_DATA_WRITE) + ret_code = B_WRITE; + else +#endif + ret_code = B_READ; + } +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) + if(ret_code == B_WRITE) + Cmnd->sc_data_direction = SCSI_DATA_WRITE; + else + Cmnd->sc_data_direction = SCSI_DATA_READ; +#endif + return ret_code; +} + +int +chkLun( +node_t *node_ptr, +fc_lun_t lun) +{ + uint32 rptLunLen; + uint32 *datap32; + uint32 lunvalue, i; + + if(node_ptr->virtRptLunData) { + datap32 = (uint32 *)node_ptr->virtRptLunData; + rptLunLen = SWAP_DATA(*datap32); + for(i=0; i < rptLunLen; i+=8) { + datap32 += 2; + lunvalue = (((* datap32) >> FC_LUN_SHIFT) & 0xff); + if (lunvalue == (uint32)lun) + return 1; + } + return 0; + } + else { + return 1; + } +} +/****************************************************************************** +* Function name : fc_queuecommand +* +* Description : Linux queue command entry +* +******************************************************************************/ +int fc_queuecommand(struct scsi_cmnd *Cmnd, + void (*done)(struct scsi_cmnd *)) +{ + FC_BRD_INFO * binfo; + struct Scsi_Host *host; + fc_dev_ctl_t *p_dev_ctl; + iCfgParam *clp; + struct dev_info *dev_ptr; + node_t *node_ptr; + struct sc_buf *sp; + int dev_index,target,retcod; + fc_lun_t lun; + ulong iflg; + struct lpfc_dpc *ldp; + + + host = Cmnd->device->host; + fc_bzero(Cmnd->sense_buffer, 16); + if(!host){ + retcod=DID_BAD_TARGET; + Cmnd->result = ScsiResult(retcod, 0); + done(Cmnd); + return(0); + } + Cmnd->scsi_done = done; /* Save done routine for this command */ + + p_dev_ctl = (fc_dev_ctl_t *)host->hostdata[0]; + if(p_dev_ctl == 0) { + retcod=DID_BAD_TARGET; + Cmnd->result = ScsiResult(retcod, 0); + done(Cmnd); + return(0); + } + + + retcod = 0; + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + + LPFC_LOCK_DRIVER(12); + ldp = &lpfc_dpc[binfo->fc_brd_no]; + if (ldp->dpc_wait == NULL) { + retcod=DID_NO_CONNECT; +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) + if(lpfc_use_removable) { + Cmnd->sense_buffer[0] = 0x70; + Cmnd->sense_buffer[2] = UNIT_ATTENTION; + Cmnd->device->removable = 1; + } +#endif + Cmnd->result = ScsiResult(retcod, 0); + FCSTATCTR.fcpRsvd8++; + done(Cmnd); + LPFC_UNLOCK_DRIVER; + return(0); + } + + target = (int)Cmnd->device->id; + lun = (fc_lun_t)Cmnd->device->lun; + + if(lun > MAX_FCP_LUN) { + retcod=DID_BAD_TARGET; + Cmnd->result = ScsiResult(retcod, 0); + LPFC_UNLOCK_DRIVER; + done(Cmnd); + return(0); + } + + /* + * Device for target/lun + */ + dev_index = INDEX(ZERO_PAN, target); + if (!(dev_ptr = fc_find_lun(binfo, dev_index, lun))) { + if(!(dev_ptr=fc_getDVI(p_dev_ctl, target, lun))){ + retcod=DID_NO_CONNECT; + Cmnd->result = ScsiResult(retcod, 0); + FCSTATCTR.fcpRsvd3++; + LPFC_UNLOCK_DRIVER; + done(Cmnd); + return(0); + } + } + + node_ptr = binfo->device_queue_hash[dev_index].node_ptr; + if((node_ptr) && + ((node_ptr->flags & FC_NODEV_TMO) || (lun >= node_ptr->max_lun))) { + retcod=DID_NO_CONNECT; + Cmnd->result = ScsiResult(retcod, 0); + LPFC_UNLOCK_DRIVER; + done(Cmnd); + return(0); + } + + if((node_ptr) && (Cmnd->cmnd[0] == 0x12) && (!chkLun(node_ptr, lun))) { + retcod=DID_NO_CONNECT; + Cmnd->result = ScsiResult(retcod, 0); + LPFC_UNLOCK_DRIVER; + done(Cmnd); + return(0); + } + + if(binfo->fc_flag & FC_LD_TIMEOUT) { + retcod=DID_NO_CONNECT; + Cmnd->result = ScsiResult(retcod, 0); + LPFC_UNLOCK_DRIVER; + done(Cmnd); + return(0); + } + + dev_ptr->qcmdcnt++; + + sp = dev_ptr->scp; + if(!sp){ + retcod=DID_NO_CONNECT; + Cmnd->result = ScsiResult(retcod, 0); + dev_ptr->iodonecnt++; + dev_ptr->errorcnt++; + FCSTATCTR.fcpRsvd5++; + LPFC_UNLOCK_DRIVER; + done(Cmnd); + return(0); + } + + Cmnd->host_scribble = (void *)sp; + dev_ptr->scp = sp->bufstruct.av_forw; + dev_ptr->scpcnt--; + fc_bzero(sp,sizeof(struct sc_buf)); + sp->bufstruct.cmnd = Cmnd; + sp->current_devp = dev_ptr; + FCSTATCTR.fcpRsvd0++; + lpfc_scsi_delete_timer(Cmnd); + + /* Since we delete active timers, we can use eh_timeout.data as a linked + * list ptr internally within the driver. + */ + if(p_dev_ctl->qcmd_head == NULL) { + p_dev_ctl->qcmd_head = (void *)Cmnd; + p_dev_ctl->qcmd_list = (void *)Cmnd; + } else { + ((struct scsi_cmnd *)(p_dev_ctl->qcmd_list))->eh_timeout.data = (ulong)Cmnd; + p_dev_ctl->qcmd_list = (void *)Cmnd; + } + Cmnd->eh_timeout.data = (unsigned long) NULL; + + if (ldp->dpc_active == 0) { + LPFC_UNLOCK_DRIVER; + up(ldp->dpc_wait); + } + else { + LPFC_UNLOCK_DRIVER; + } + return 0; +} + +/****************************************************************************** +* Function name : do_fc_queuecommand +* +* Description : +* +******************************************************************************/ +int do_fc_queuecommand(fc_dev_ctl_t *p_dev_ctl, + ulong siflg) +{ + FC_BRD_INFO * binfo; + iCfgParam * clp; + struct dev_info * dev_ptr; + struct sc_buf * sp; + struct buf * bp; + struct scsi_cmnd * Cmnd; + struct scsi_cmnd * oCmnd; + int i, retcod, firstin; + + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + Cmnd = (struct scsi_cmnd *)p_dev_ctl->qcmd_head; + firstin = 1; + + + while(Cmnd) { + sp = (struct sc_buf *)(Cmnd->host_scribble); + dev_ptr = sp->current_devp; + + sp->flags = SC_RESUME; + + + IOcnt++; + /* + * Buffer count depends on whether scatter-gather is used or not + */ + if(!Cmnd->use_sg){ + sp->bufstruct.b_bcount = (int)Cmnd->request_bufflen; + } + else { + struct scatterlist *scatter = (struct scatterlist *)Cmnd->buffer; + sp->bufstruct.b_bcount = 0; + + for(i=0; i < Cmnd->use_sg; i++) + sp->bufstruct.b_bcount += scatter[i].length; + } + + /* + * Set read/write flag + */ +#if LINUX_VERSION_CODE > LinuxVersionCode(2,4,4) + if(lpfc_use_data_direction) { + if(Cmnd->sc_data_direction == SCSI_DATA_WRITE) + sp->bufstruct.b_flags = B_WRITE; + else + sp->bufstruct.b_flags = B_READ; + } + else { + sp->bufstruct.b_flags = fc_data_direction(Cmnd); + } +#else + sp->bufstruct.b_flags = fc_data_direction(Cmnd); +#endif + + if (Cmnd->cmnd[0] == TEST_UNIT_READY) + sp->bufstruct.b_bcount = 0; + + /* + * Fill in the sp struct + */ + bcopy((void *)Cmnd->cmnd, (void *)&sp->scsi_command.scsi_cmd, 16); + + sp->scsi_command.scsi_length=Cmnd->cmd_len; + sp->scsi_command.scsi_id=Cmnd->device->id; + sp->scsi_command.scsi_lun=Cmnd->device->lun; + if (Cmnd->device->tagged_supported) { + switch (Cmnd->tag) { + case HEAD_OF_QUEUE_TAG: + sp->scsi_command.flags = HEAD_OF_Q; + break; + case ORDERED_QUEUE_TAG: + sp->scsi_command.flags = ORDERED_Q; + break; + default: + sp->scsi_command.flags = SIMPLE_Q; + break; + } + } + else + sp->scsi_command.flags = 0; + + sp->timeout_value = Cmnd->timeout_per_command / fc_ticks_per_second; + sp->adap_q_status = 0; + sp->bufstruct.av_forw = NULL; + + retcod = 0; + if(p_dev_ctl->device_state == DEAD) { + retcod=DID_NO_CONNECT; + Cmnd->result = ScsiResult(retcod, 0); + FCSTATCTR.fcpRsvd8++; + goto done; + } + + /* + * Is it a valid target? + */ + if((dev_ptr == 0) || (dev_ptr->nodep == 0)) { + retcod=DID_NO_CONNECT; + Cmnd->result = ScsiResult(retcod, 0); + FCSTATCTR.fcpRsvd4++; + goto done; + } + + if(dev_ptr->nodep == 0) { + FCSTATCTR.fcpRsvd6++; + retcod=DID_SOFT_ERROR; + } + else { + if((clp[CFG_LINKDOWN_TMO].a_current == 0) || clp[CFG_HOLDIO].a_current) { + retcod=0; + } + else { + retcod=0; + if (binfo->fc_flag & FC_LD_TIMEOUT) { + if(clp[CFG_NODEV_TMO].a_current == 0) { + retcod=DID_SOFT_ERROR; + FCSTATCTR.fcpRsvd7++; + } + else { + if(dev_ptr->nodep->flags & FC_NODEV_TMO) { + retcod=DID_SOFT_ERROR; + FCSTATCTR.fcpRsvd7++; + } + } + } + } + } + if(retcod) + goto done; + retcod=DID_OK; + + + if (dev_ptr->pend_head == NULL) { + dev_ptr->pend_head = sp; + dev_ptr->pend_tail = sp; + } else { + dev_ptr->pend_tail->bufstruct.av_forw = (struct buf *)sp; + dev_ptr->pend_tail = sp; + } + dev_ptr->pend_count++; + + /* + * put on the DEVICE_WAITING_head + */ + fc_enq_wait(dev_ptr); + + /* + * Send out the SCSI REPORT LUN command before sending the very + * first SCSI command to that device. + */ + if (dev_ptr->nodep->rptlunstate == REPORT_LUN_REQUIRED) { + dev_ptr->nodep->rptlunstate = REPORT_LUN_ONGOING; + issue_report_lun(p_dev_ctl, dev_ptr, 0); + } else { + if ( (dev_ptr->nodep->rptlunstate == REPORT_LUN_COMPLETE) && + !(dev_ptr->flags & CHK_SCSI_ABDR) && dev_ptr->numfcbufs) + fc_issue_cmd(p_dev_ctl); + } + + /* + * Done + */ +done: + if(retcod!=DID_OK) { + dev_ptr->iodonecnt++; + dev_ptr->errorcnt++; + bp = (struct buf *) sp; + bp->b_error = EIO; + bp->b_flags |= B_ERROR; + sp->status_validity = SC_ADAPTER_ERROR; + sp->general_card_status = SC_SCSI_BUS_RESET; + fc_delay_iodone(p_dev_ctl, sp); + } + oCmnd = Cmnd; + Cmnd = (struct scsi_cmnd *)Cmnd->eh_timeout.data; + oCmnd->eh_timeout.data = 0; + } + p_dev_ctl->qcmd_head = 0; + p_dev_ctl->qcmd_list = 0; + + return 0; +} + +/****************************************************************************** +* Function name : fc_rtalloc +* +* Description : +* +******************************************************************************/ +_local_ int fc_rtalloc(fc_dev_ctl_t *p_dev_ctl, + struct dev_info *dev_ptr) +{ + int i; + unsigned int size; + fc_buf_t *fcptr; + struct sc_buf *sp; + dma_addr_t phys; + FC_BRD_INFO * binfo; + MBUF_INFO * buf_info; + MBUF_INFO bufinfo; + + binfo = &p_dev_ctl->info; + for (i = 0; i < dev_ptr->fcp_lun_queue_depth+1 ; i++) { + + size = fc_po2(sizeof(fc_buf_t)); + phys = (dma_addr_t)((ulong)INVALID_PHYS); + + buf_info = &bufinfo; + buf_info->size = size; + buf_info->flags = FC_MBUF_DMA; + buf_info->align = size; + buf_info->phys = 0; + buf_info->dma_handle = 0; + buf_info->data_handle = 0; + fc_malloc(p_dev_ctl, buf_info); + fcptr = buf_info->virt; + phys = (dma_addr_t)((ulong)buf_info->phys); + if (!fcptr || is_invalid_phys((void *)((ulong)phys))) { + return(0); + } + + fc_bzero(fcptr, sizeof(fc_buf_t)); + + fcptr->dev_ptr = dev_ptr; + fcptr->phys_adr = (void *)((ulong)phys); + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) + fcptr->fc_cmd_dma_handle = (ulong *)fcptr->phys_adr; +#endif + fc_enq_fcbuf(fcptr); + + sp = (struct sc_buf *)fc_kmem_zalloc(sizeof(struct sc_buf)); + if (!sp) { + return(0); + } + if(dev_ptr->scp) { + sp->bufstruct.av_forw = dev_ptr->scp; + dev_ptr->scp = sp; + } + else { + dev_ptr->scp = sp; + dev_ptr->scp->bufstruct.av_forw = 0; + } + dev_ptr->scpcnt++; + } /* end for loop */ + return(1); +} /* end of fc_rtalloc */ + +/****************************************************************************** +* Function name : do_fc_intr_handler +* +* Description : Local interupt handler +* +******************************************************************************/ +irqreturn_t do_fc_intr_handler(int irq, + void *dev_id, + struct pt_regs *regs) +{ + struct intr *ihs; + FC_BRD_INFO * binfo; + fc_dev_ctl_t * p_dev_ctl; + void *ioa; + volatile uint32 ha_copy; + uint32 i; + ulong siflg; + ulong iflg; + + /* + * If driver is unloading, we can stop processing interrupt. + */ + if (lpfc_driver_unloading) + return IRQ_HANDLED; + + ihs = (struct intr *)dev_id; + p_dev_ctl = (fc_dev_ctl_t * )ihs; + if(!p_dev_ctl){ + return IRQ_HANDLED; + } + + for(i=0;iinfo; + /* Ignore all interrupts during initialization. */ + if(binfo->fc_ffstate < FC_LINK_DOWN) { + LPFC_UNLOCK_DRIVER; + return IRQ_HANDLED; + } + + ioa = FC_MAP_IO(&binfo->fc_iomap_io); /* map in io registers */ + + /* Read host attention register to determine interrupt source */ + ha_copy = READ_CSR_REG(binfo, FC_HA_REG(binfo, ioa)); + + /* Clear Attention Sources, except ERROR (to preserve status) & LATT + * (ha_copy & ~HA_ERATT & ~HA_LATT); + */ + WRITE_CSR_REG(binfo, FC_HA_REG(binfo,ioa), (ha_copy & ~(HA_LATT | HA_ERATT))); + + if (ha_copy & HA_ERATT) { /* Link / board error */ + volatile uint32 status; + + /* do what needs to be done, get error from STATUS REGISTER */ + status = READ_CSR_REG(binfo, FC_STAT_REG(binfo, ioa)); + /* Clear Chip error bit */ + WRITE_CSR_REG(binfo, FC_HA_REG(binfo, ioa), HA_ERATT); + if(p_dev_ctl->dpc_hstatus == 0) + p_dev_ctl->dpc_hstatus = status; + } + + if (ha_copy & HA_LATT) { /* Link Attention interrupt */ + volatile uint32 control; + + if (binfo->fc_process_LA) { + control = READ_CSR_REG(binfo, FC_HC_REG(binfo, ioa)); + control &= ~HC_LAINT_ENA; + WRITE_CSR_REG(binfo, FC_HC_REG(binfo, ioa), control); + /* Clear Link Attention in HA REG */ + WRITE_CSR_REG(binfo, FC_HA_REG(binfo,ioa), (volatile uint32)(HA_LATT)); + } + } + + FC_UNMAP_MEMIO(ioa); + + + p_dev_ctl->dpc_ha_copy |= ha_copy; + + { + struct lpfc_dpc *ldp; + ldp = &lpfc_dpc[binfo->fc_brd_no]; + if ((p_dev_ctl->power_up == 0) || (ldp->dpc_wait == NULL)) { + do_fc_intr((struct intr *)p_dev_ctl); + LPFC_UNLOCK_DRIVER; + fc_flush_done_cmds(p_dev_ctl, siflg); + } + else { + if (ldp->dpc_active == 0) { + LPFC_UNLOCK_DRIVER; + up(ldp->dpc_wait); + } + else { + LPFC_UNLOCK_DRIVER; + fc_flush_done_cmds(p_dev_ctl, siflg); + } + } + } + return IRQ_HANDLED; +} + +/****************************************************************************** +* Function name : do_fc_intr +* +* Description : +* p_ihs also points to device control area +******************************************************************************/ +int do_fc_intr(struct intr *p_ihs) +{ + fc_dev_ctl_t * p_dev_ctl = (fc_dev_ctl_t * )p_ihs; + volatile uint32 ha_copy; + FC_BRD_INFO * binfo; + iCfgParam * clp; + fcipbuf_t * mbp; + MAILBOXQ * mb; + IOCBQ * delayiocb; + IOCBQ * temp; + IOCBQ * processiocb; + IOCBQ * endiocb; + int ipri, rc; + + binfo = &BINFO; + ipri = disable_lock(FC_LVL, &CMD_LOCK); + binfo->fc_flag |= FC_INTR_THREAD; + + /* Read host attention register to determine interrupt source */ + ha_copy = p_dev_ctl->dpc_ha_copy; + p_dev_ctl->dpc_ha_copy = 0; + + if (ha_copy) { + rc = INTR_SUCC; + binfo->fc_flag |= FC_INTR_WORK; + } else { + clp = DD_CTL.p_config[binfo->fc_brd_no]; + if (clp[CFG_INTR_ACK].a_current && (binfo->fc_flag&FC_INTR_WORK)) { + rc = INTR_SUCC; /* Just claim the first non-working interrupt */ + binfo->fc_flag &= ~FC_INTR_WORK; + } else { + if (clp[CFG_INTR_ACK].a_current == 2) + rc = INTR_SUCC; /* Always claim the interrupt */ + else + rc = INTR_FAIL; + } + } + + if (binfo->fc_flag & FC_OFFLINE_MODE) { + binfo->fc_flag &= ~FC_INTR_THREAD; + unlock_enable(ipri, &CMD_LOCK); + return(INTR_FAIL); + } + processiocb = 0; + if(binfo->fc_delayxmit) { + delayiocb = binfo->fc_delayxmit; + binfo->fc_delayxmit = 0; + endiocb = 0; + while(delayiocb) { + temp = delayiocb; + delayiocb = (IOCBQ *)temp->q; + temp->rsvd2--; + /* If retry == 0, process IOCB */ + if(temp->rsvd2 == 0) { + if(processiocb == 0) { + processiocb = temp; + } + else { + endiocb->q = (uchar *)temp; + } + endiocb = temp; + temp->q = 0; + } + else { + /* Make delayxmit point to first non-zero retry */ + if(binfo->fc_delayxmit == 0) + binfo->fc_delayxmit = temp; + } + } + if(processiocb) { + /* Handle any delayed IOCBs */ + endiocb = processiocb; + while(endiocb) { + temp = endiocb; + endiocb = (IOCBQ *)temp->q; + temp->q = 0; + issue_iocb_cmd(binfo, &binfo->fc_ring[FC_ELS_RING], temp); + } + } + } + + if (ha_copy & HA_ERATT) { /* Link / board error */ + unlock_enable(ipri, &CMD_LOCK); + handle_ff_error(p_dev_ctl); + return(rc); + } else { + if (ha_copy & HA_MBATT) { /* Mailbox interrupt */ + handle_mb_event(p_dev_ctl); + if(binfo->fc_flag & FC_PENDING_RING0) { + binfo->fc_flag &= ~FC_PENDING_RING0; + ha_copy |= HA_R0ATT; /* event on ring 0 */ + } + } + + if (ha_copy & HA_LATT) { /* Link Attention interrupt */ + if (binfo->fc_process_LA) { + handle_link_event(p_dev_ctl); + } + } + + if (ha_copy & HA_R0ATT) { /* event on ring 0 */ + if(binfo->fc_mbox_active == 0) + handle_ring_event(p_dev_ctl, 0, (ha_copy & 0x0000000F)); + else + binfo->fc_flag |= FC_PENDING_RING0; + } + + if (ha_copy & HA_R1ATT) { /* event on ring 1 */ + /* This ring handles IP. Defer processing anything on this ring + * till all FCP ELS traffic settles down. + */ + if (binfo->fc_ffstate <= FC_NODE_DISC) + binfo->fc_deferip |= (uchar)((ha_copy >> 4) & 0x0000000F); + else + handle_ring_event(p_dev_ctl, 1, ((ha_copy >> 4) & 0x0000000F)); + } + + if (ha_copy & HA_R2ATT) { /* event on ring 2 */ + handle_ring_event(p_dev_ctl, 2, ((ha_copy >> 8) & 0x0000000F)); + } + + if (ha_copy & HA_R3ATT) { /* event on ring 3 */ + handle_ring_event(p_dev_ctl, 3, ((ha_copy >> 12) & 0x0000000F)); + } + } + + if((processiocb == 0) && (binfo->fc_delayxmit) && + (binfo->fc_mbox_active == 0)) { + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX))) { + fc_read_rpi(binfo, (uint32)1, (MAILBOX * )mb, (uint32)0); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + } + + binfo->fc_flag &= ~FC_INTR_THREAD; + + while (p_dev_ctl->mbufl_head != 0) { + binfo->fc_flag |= FC_INTR_WORK; + mbp = (fcipbuf_t * )p_dev_ctl->mbufl_head; + p_dev_ctl->mbufl_head = (uchar * )fcnextpkt(mbp); + fcnextpkt(mbp) = 0; + fc_xmit(p_dev_ctl, mbp); + } + p_dev_ctl->mbufl_tail = 0; + unlock_enable(ipri, &CMD_LOCK); + return(rc); +} /* End do_fc_intr */ + +/****************************************************************************** +* Function name : fc_memmap +* +* Description : Called from fc_attach to map shared memory (SLIM and CSRs) +* for adapter and to setup memory for SLI2 interface. +******************************************************************************/ +int fc_memmap(fc_dev_ctl_t *p_dev_ctl) +{ + FC_BRD_INFO *binfo; + struct pci_dev *pdev; + int reg; + ulong base; + + binfo = &BINFO; + + /* + * Get PCI for board + */ + pdev = p_dev_ctl->pcidev; + if(!pdev){ + panic("no dev in pcimap\n"); + return(1); + } +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,3) + /* Configure DMA attributes. */ +#if BITS_PER_LONG > 32 + if (pci_set_dma_mask(pdev, (uint64_t) 0xffffffffffffffff)) { + printk("Cannot set dma mask\n"); + return(1); + } +#else + if (pci_set_dma_mask(pdev, (uint64_t) 0xffffffff)) { + printk("Cannot set dma mask\n"); + return(1); + } +#endif +#else +#if BITS_PER_LONG > 32 + pdev->dma_mask = 0xffffffffffffffff; +#endif +#endif + + /* + * address in first register + */ + reg = 0; + reg = pci_getadd(pdev, reg, &base); + + /* + * need to mask the value to get the physical address + */ + base &= PCI_BASE_ADDRESS_MEM_MASK; + DDS.bus_mem_addr = base; + + /* + * next two registers are the control, get the first one, if doing direct io + * if i/o port is to be used get the second + * Note that pci_getadd returns the correct next register + */ + reg = pci_getadd(pdev, reg, &base); + base &= PCI_BASE_ADDRESS_MEM_MASK; + DDS.bus_io_addr = base; + /* + * Map adapter SLIM and Control Registers + */ + binfo->fc_iomap_mem = remap_pci_mem((ulong)DDS.bus_mem_addr,FF_SLIM_SIZE); + if(binfo->fc_iomap_mem == ((void *)(-1))){ + return (ENOMEM); + } + + binfo->fc_iomap_io =remap_pci_mem((ulong)DDS.bus_io_addr,FF_REG_AREA_SIZE); + if(binfo->fc_iomap_io == ((void *)(-1))){ + unmap_pci_mem((ulong)binfo->fc_iomap_mem); + return (ENOMEM); + } + + + /* + * Setup SLI2 interface + */ + if ((binfo->fc_sli == 2) && (binfo->fc_slim2.virt == 0)) { + MBUF_INFO * buf_info; + MBUF_INFO bufinfo; + + buf_info = &bufinfo; + + /* + * Allocate memory for SLI-2 structures + */ + buf_info->size = sizeof(SLI2_SLIM); + buf_info->flags = FC_MBUF_DMA; + buf_info->align = fcPAGESIZE; + buf_info->dma_handle = 0; + buf_info->data_handle = 0; + fc_malloc(p_dev_ctl, buf_info); + if (buf_info->virt == NULL) { + + /* + * unmap adapter SLIM and Control Registers + */ + unmap_pci_mem((ulong)binfo->fc_iomap_mem); + unmap_pci_mem((ulong)binfo->fc_iomap_io); + + return (ENOMEM); + } + + binfo->fc_slim2.virt = (uchar * )buf_info->virt; + binfo->fc_slim2.phys = (uchar * )buf_info->phys; + binfo->fc_slim2.data_handle = buf_info->data_handle; + binfo->fc_slim2.dma_handle = buf_info->dma_handle; + fc_bzero((char *)binfo->fc_slim2.virt, sizeof(SLI2_SLIM)); + } + return(0); +} + +/****************************************************************************** +* Function name : fc_unmemmap +* +* Description : Called from fc_detach to unmap shared memory (SLIM and CSRs) +* for adapter +* +******************************************************************************/ +int fc_unmemmap(fc_dev_ctl_t *p_dev_ctl) +{ + FC_BRD_INFO *binfo; + + binfo = &BINFO; + + /* + * unmap adapter SLIM and Control Registers + */ + unmap_pci_mem((ulong)binfo->fc_iomap_mem); + unmap_pci_mem((ulong)binfo->fc_iomap_io); + /* + * Free resources associated with SLI2 interface + */ + if (binfo->fc_slim2.virt) { + MBUF_INFO * buf_info; + MBUF_INFO bufinfo; + + buf_info = &bufinfo; + buf_info->phys = (uint32 * )binfo->fc_slim2.phys; + buf_info->data_handle = binfo->fc_slim2.data_handle; + buf_info->dma_handle = binfo->fc_slim2.dma_handle; + buf_info->flags = FC_MBUF_DMA; + + buf_info->virt = (uint32 * )binfo->fc_slim2.virt; + buf_info->size = sizeof(SLI2_SLIM); + fc_free(p_dev_ctl, buf_info); + binfo->fc_slim2.virt = 0; + binfo->fc_slim2.phys = 0; + binfo->fc_slim2.dma_handle = 0; + binfo->fc_slim2.data_handle = 0; + } + return(0); +} + +/****************************************************************************** +* Function name : fc_pcimap +* +* Description : Called from fc_attach to setup PCI configuration registers +* +******************************************************************************/ +int fc_pcimap(fc_dev_ctl_t *p_dev_ctl) +{ + FC_BRD_INFO *binfo; + iCfgParam *clp; + struct pci_dev *pdev; + u16 cmd; + + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + + /* + * PCI for board + */ + pdev = p_dev_ctl->pcidev; + if(!pdev) + return(1); + + /* + * bus mastering and parity checking enabled + */ + pci_read_config_word(pdev, PCI_COMMAND, &cmd); + if(cmd & CMD_PARITY_CHK) + cmd = CMD_CFG_VALUE ; + else + cmd = (CMD_CFG_VALUE & ~(CMD_PARITY_CHK)); + + + pci_write_config_word(pdev, PCI_COMMAND, cmd); + + if(lpfc_pci_latency_clocks) + pci_write_config_byte(pdev, PCI_LATENCY_TMR_REGISTER,(uchar)lpfc_pci_latency_clocks); + + if(lpfc_pci_cache_line) + pci_write_config_byte(pdev, PCI_CACHE_LINE_REGISTER,(uchar)lpfc_pci_cache_line); + + /* + * Get the irq from the pdev structure + */ + DDS.bus_intr_lvl = (int)pdev->irq; + + return(0); +} + +/****************************************************************************** +* Function name : lpfc_cfg_init +* +* Description : Called from handle_ff_error() to bring link back up +* +******************************************************************************/ +int lpfc_cfg_init(fc_dev_ctl_t *p_dev_ctl) +{ + FC_BRD_INFO * binfo; + struct lpfc_dpc *ldp; + + binfo = &BINFO; + p_dev_ctl->dev_flag |= FC_SCHED_CFG_INIT; + ldp = &lpfc_dpc[binfo->fc_brd_no]; + if ((ldp->dpc_active == 0) && ldp->dpc_wait) + up(ldp->dpc_wait); + return(0); +} + +/****************************************************************************** +* Function name : lpfc_kfree_skb +* +* Description : This routine is only called by the IP portion of the driver +* and the Fabric NameServer portion of the driver. It should +* free a fcipbuf chain. +******************************************************************************/ +int lpfc_kfree_skb(struct sk_buff *skb) +{ + struct sk_buff *sskb; + + while(skb->next) { + sskb = skb; + skb = skb->next; + sskb->next = 0; +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) + if(in_interrupt()) { + dev_kfree_skb_irq(sskb); + } + else { + dev_kfree_skb(sskb); + } +#else + dev_kfree_skb(sskb); +#endif + } +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) + if(in_interrupt()) { + dev_kfree_skb_irq(skb); + } + else { + dev_kfree_skb(skb); + } +#else + dev_kfree_skb(skb); +#endif + return(0); +} + +/****************************************************************************** +* Function name : lpfc_alloc_skb +* +* Description : +* +******************************************************************************/ +struct sk_buff *lpfc_alloc_skb(unsigned int size) +{ + return(alloc_skb(size, GFP_ATOMIC)); +} + +/****************************************************************************** +* Function name : fc_malloc +* +* Description : fc_malloc environment specific routine for memory +* allocation / mapping +* The buf_info->flags field describes the memory operation requested. +* +* FC_MBUF_PHYSONLY set requests a supplied virtual address be mapped for DMA +* Virtual address is supplied in buf_info->virt +* DMA mapping flag is in buf_info->align (DMA_READ, DMA_WRITE_ONLY, both) +* The mapped physical address is returned buf_info->phys +* +* FC_MBUF_PHYSONLY cleared requests memory be allocated for driver use and +* if FC_MBUF_DMA is set the memory is also mapped for DMA +* The byte alignment of the memory request is supplied in buf_info->align +* The byte size of the memory request is supplied in buf_info->size +* The virtual address is returned buf_info->virt +* The mapped physical address is returned buf_info->phys (for FC_MBUF_DMA) +* +******************************************************************************/ +uchar *fc_malloc(fc_dev_ctl_t *p_dev_ctl, + MBUF_INFO *buf_info) +{ + FC_BRD_INFO * binfo; + unsigned int size; + + binfo = &BINFO; + buf_info->phys = (void *)((ulong)INVALID_PHYS); + buf_info->dma_handle = 0; + if (buf_info->flags & FC_MBUF_PHYSONLY) { + if(buf_info->virt == NULL) + return NULL; +#if LINUX_VERSION_CODE <= LinuxVersionCode(2,4,12) + buf_info->phys = (void *)((ulong)pci_map_single(p_dev_ctl->pcidev, + buf_info->virt, buf_info->size, PCI_DMA_BIDIRECTIONAL)); +#else + { + struct page *page = virt_to_page((ulong)(buf_info->virt)); + unsigned long offset = ((unsigned long)buf_info->virt & ~PAGE_MASK); + + buf_info->phys = (void *)((ulong)pci_map_page(p_dev_ctl->pcidev, + page, offset, buf_info->size, PCI_DMA_BIDIRECTIONAL)); + } +#endif + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) + buf_info->dma_handle = buf_info->phys; +#endif + FCSTATCTR.fcMapCnt++; + return((uchar * )buf_info->virt); + } + if((buf_info->flags & FC_MBUF_DMA)) { + size = fc_po2(buf_info->size); + buf_info->phys = (void *)((ulong)INVALID_PHYS); + buf_info->virt = lpfc_kmalloc(size, GFP_ATOMIC, &buf_info->phys, p_dev_ctl); + if (buf_info->virt) { + if(is_invalid_phys(buf_info->phys)) { + lpfc_kfree((unsigned int)buf_info->size, (void *)buf_info->virt, (void *)buf_info->phys, p_dev_ctl); + buf_info->virt = 0; + } + } +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) + buf_info->dma_handle = buf_info->phys; +#endif + if(buf_info->virt == 0) { + buf_info->phys = (void *)((ulong)INVALID_PHYS); + buf_info->dma_handle = 0; + } + } + else { + buf_info->size = ((buf_info->size + 7) & 0xfffffff8); + buf_info->virt = (uint32 * )lpfc_kmalloc((unsigned int)buf_info->size, GFP_ATOMIC, 0, 0); + if(buf_info->virt) + fc_bzero(buf_info->virt, buf_info->size); + buf_info->phys = (void *)((ulong)INVALID_PHYS); + } + FCSTATCTR.fcMallocCnt++; + FCSTATCTR.fcMallocByte += buf_info->size; + return((uchar * )buf_info->virt); +} + +/****************************************************************************** +* Function name : fc_po2 +* +* Description : Convert size to next highest power of 2 +* +******************************************************************************/ +ulong fc_po2(ulong size) +{ + ulong order; + + for (order = 1; order < size; order <<= 1); + return(order); +} + +void *lpfc_last_dma_page = 0; +int lpfc_dma_page_offset = 0; + +/****************************************************************************** +* Function name : fc_free +* +* Description : Environment specific routine for memory de-allocation/unmapping +* The buf_info->flags field describes the memory operation requested. +* FC_MBUF_PHYSONLY set requests a supplied virtual address be unmapped +* for DMA, but not freed. +* The mapped physical address to be unmapped is in buf_info->phys +* FC_MBUF_PHYSONLY cleared requests memory be freed and unmapped for DMA +* only if FC_MBUF_DMA is set. +* The mapped physical address to be unmapped is in buf_info->phys +* The virtual address to be freed is in buf_info->virt +******************************************************************************/ +void fc_free(fc_dev_ctl_t *p_dev_ctl, + MBUF_INFO *buf_info) +{ + FC_BRD_INFO * binfo; + unsigned int size; + + binfo = &BINFO; + + if (buf_info->flags & FC_MBUF_PHYSONLY) { +#if LINUX_VERSION_CODE <= LinuxVersionCode(2,4,12) + pci_unmap_single(p_dev_ctl->pcidev, + (ulong)(buf_info->phys), buf_info->size, PCI_DMA_BIDIRECTIONAL); +#else + pci_unmap_page(p_dev_ctl->pcidev, + (ulong)(buf_info->phys), buf_info->size, PCI_DMA_BIDIRECTIONAL); +#endif + FCSTATCTR.fcUnMapCnt++; + } + else { + if((buf_info->flags & FC_MBUF_DMA)) { + size = fc_po2(buf_info->size); + lpfc_kfree((unsigned int)buf_info->size, (void *)buf_info->virt, (void *)buf_info->phys, p_dev_ctl); + } + else { + buf_info->size = ((buf_info->size + 7) & 0xfffffff8); + lpfc_kfree((unsigned int)buf_info->size, (void *)buf_info->virt, (void *)((ulong)INVALID_PHYS), 0); + } + FCSTATCTR.fcFreeCnt++; + FCSTATCTR.fcFreeByte += buf_info->size; + } +} + +/****************************************************************************** +* Function name : fc_rdpci_cmd +* +******************************************************************************/ +ushort fc_rdpci_cmd(fc_dev_ctl_t *p_dev_ctl) +{ + u16 cmd; + struct pci_dev *pdev; + + /* + * PCI device + */ + pdev = p_dev_ctl->pcidev; + if(!pdev){ + panic("no dev in fc_rdpci_cmd\n"); + return((ushort)0); + } + pci_read_config_word(pdev, PCI_COMMAND, &cmd); + return((ushort)cmd); +} + +/****************************************************************************** +* Function name : fc_rdpci_32 +* +******************************************************************************/ +uint32 fc_rdpci_32(fc_dev_ctl_t *p_dev_ctl, + uint32 offset) +{ + uint32 cmd; + struct pci_dev *pdev; + + /* + * PCI device + */ + pdev = p_dev_ctl->pcidev; + if(!pdev){ + panic("no dev in fc_rdpci_32\n"); + return((ushort)0); + } + pci_read_config_dword(pdev, offset, &cmd); + return(cmd); +} + +/****************************************************************************** +* Function name : fc_wrpci_cmd +* +******************************************************************************/ +void fc_wrpci_cmd(fc_dev_ctl_t *p_dev_ctl, + ushort cfg_value) +{ + struct pci_dev *pdev; + + /* + * PCI device + */ + pdev = p_dev_ctl->pcidev; + if(!pdev){ + panic("no dev in fc_wrpci_cmd\n"); + return; + } + pci_write_config_word(pdev, PCI_COMMAND, cfg_value); +} +/****************************************************************************** +* +* Function name : lpfc_fcp_error() +* +* Description : Handle an FCP response error +* +* Context : called from handle_fcp_event +* Can be called by interrupt thread. +******************************************************************************/ +_static_ void lpfc_fcp_error(fc_buf_t * fcptr, + IOCB * cmd) +{ + FCP_RSP *fcpRsp = &fcptr->fcp_rsp; + struct sc_buf *sp = fcptr->sc_bufp; + struct buf *bp; + struct scsi_cmnd *Cmnd; + + bp = (struct buf *)sp; + Cmnd = bp->cmnd; + + if (fcpRsp->rspStatus2 & RESID_UNDER) { + uint32 len, resid, brd; + + if((fcptr->dev_ptr) && (fcptr->dev_ptr->nodep)) + brd = fcptr->dev_ptr->nodep->ap->info.fc_brd_no; + else + brd = 0; + + len = SWAP_DATA(fcptr->fcp_cmd.fcpDl); + resid = SWAP_DATA(fcpRsp->rspResId); + + /* FCP residual underrun, expected , residual */ + fc_log_printf_msg_vargs( brd, + &fc_msgBlk0716, /* ptr to msg structure */ + fc_mes0716, /* ptr to msg */ + fc_msgBlk0716.msgPreambleStr, /* begin varargs */ + len, + resid, + Cmnd->cmnd[0], + Cmnd->underflow); /* end varargs */ + + switch (Cmnd->cmnd[0]) { + case TEST_UNIT_READY: + case REQUEST_SENSE: + case INQUIRY: + case RECEIVE_DIAGNOSTIC: + case READ_CAPACITY: + case FCP_SCSI_READ_DEFECT_LIST: + case MDACIOCTL_DIRECT_CMD: + break; + default: + if((!(fcpRsp->rspStatus2 & SNS_LEN_VALID)) && + (len - resid < Cmnd->underflow)) { + /* FCP command residual underrun converted to error */ + fc_log_printf_msg_vargs( brd, + &fc_msgBlk0717, /* ptr to msg structure */ + fc_mes0717, /* ptr to msg */ + fc_msgBlk0717.msgPreambleStr, /* begin varargs */ + Cmnd->cmnd[0], + Cmnd->underflow, + len, + resid); /* end varargs */ + fcpRsp->rspStatus3 = SC_COMMAND_TERMINATED; + fcpRsp->rspStatus2 &= ~RESID_UNDER; + sp->scsi_status = 0; + } + break; + } + } +} +/****************************************************************************** +* Function name : fc_do_iodone +* +* Description : Return a SCSI initiated I/O to above layer +* when the I/O completes. +******************************************************************************/ +int fc_do_iodone(struct buf *bp) +{ + struct scsi_cmnd *Cmnd; + struct sc_buf * sp = (struct sc_buf *) bp; + FC_BRD_INFO * binfo; + iCfgParam * clp; + fc_dev_ctl_t * p_dev_ctl; + NODELIST * nlp; + node_t * node_ptr; + struct Scsi_Host *host; + struct dev_info * dev_ptr; + int dev_index; + int host_status = DID_OK; + + IOcnt--; + + if(!bp) { + return(1); + } + /* + * Linux command from our buffer + */ + Cmnd = bp->cmnd; + + /* + * must have Cmnd and Linux completion functions + */ + if(!Cmnd || !Cmnd->scsi_done){ + return (0); + } + + /* + * retrieve host adapter and device control + */ + host = Cmnd->device->host; + if(!host){ + return (0); + } + p_dev_ctl = (fc_dev_ctl_t *)host->hostdata[0]; + if(!p_dev_ctl){ + return (0); + } + + fc_fcp_bufunmap(p_dev_ctl, sp); + + dev_index = INDEX(ZERO_PAN, Cmnd->device->id); + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + dev_ptr = sp->current_devp; + + if (!dev_ptr) { + node_ptr = binfo->device_queue_hash[dev_index].node_ptr; + goto qf; + } + + if((node_ptr = dev_ptr->nodep) == 0) { + node_ptr = binfo->device_queue_hash[dev_index].node_ptr; + if(!node_ptr) { + dev_ptr = 0; + goto qf; + } + } + + if(node_ptr->rpi == 0xfffe) { +qf: + if ((binfo->fc_ffstate > FC_LINK_DOWN) && (binfo->fc_ffstate < FC_READY)) + goto force_retry; + + if(node_ptr) + nlp = node_ptr->nlp; + else + nlp = 0; + if (nlp && + (binfo->fc_flag & FC_RSCN_MODE) && (binfo->fc_ffstate == FC_READY) && + (nlp->nlp_action & (NLP_DO_ADDR_AUTH | NLP_DO_DISC_START | NLP_DO_RSCN))) + goto force_retry; + + if ((node_ptr) && (clp[CFG_NODEV_TMO].a_current)) { + if(node_ptr->flags & FC_NODEV_TMO) { +#ifdef FC_NEW_EH + Cmnd->retries = Cmnd->allowed; /* no more retries */ +#endif + host_status = DID_NO_CONNECT; +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) + if(lpfc_use_removable) { + Cmnd->sense_buffer[0] = 0x70; + Cmnd->sense_buffer[2] = UNIT_ATTENTION; + Cmnd->device->removable = 1; + } +#endif + if(dev_ptr) + dev_ptr->scsi_dev = (void *)Cmnd->device; + } + else { +#ifdef FC_NEW_EH + Cmnd->retries = 0; /* Force retry */ +#endif + host_status = DID_BUS_BUSY; + } + Cmnd->result = ScsiResult(host_status, 0); + } + else { + if((clp[CFG_LINKDOWN_TMO].a_current)&&(binfo->fc_flag & FC_LD_TIMEOUT)) { +#ifdef FC_NEW_EH + Cmnd->retries = Cmnd->allowed; /* no more retries */ +#endif + host_status = DID_NO_CONNECT; +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) + if(lpfc_use_removable) { + Cmnd->sense_buffer[0] = 0x70; + Cmnd->sense_buffer[2] = UNIT_ATTENTION; + Cmnd->device->removable = 1; + } +#endif + if(dev_ptr) + dev_ptr->scsi_dev = (void *)Cmnd->device; + } + else { +force_retry: +#ifdef FC_NEW_EH + Cmnd->retries = 0; /* Force retry */ +#endif + host_status = DID_BUS_BUSY; + } + Cmnd->result = ScsiResult(host_status, 0); + } + fc_queue_done_cmd(p_dev_ctl, bp); + return (0); + } + + /* + * mark it as done, no longer required, but will leave for now + */ + bp->isdone=1; +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) + Cmnd->resid = bp->b_resid; +#endif + + /* + * First check if a scsi error, mid-level handles these only if DID_OK + */ + if(sp->status_validity == SC_SCSI_ERROR){ + if(sp->scsi_status==SC_CHECK_CONDITION){ + lpfc_copy_sense(dev_ptr, bp); + } + else if (sp->scsi_status == SC_RESERVATION_CONFLICT) { + host_status = DID_ERROR; + } + else if (sp->scsi_status == SC_BUSY_STATUS) { +#ifdef FC_NEW_EH + Cmnd->retries = 0; /* Force retry */ +#endif + host_status = DID_BUS_BUSY; + } + else { + host_status = DID_ERROR; + } + + if((bp->b_flags & B_ERROR)) { + if (bp->b_error == EBUSY){ + host_status = DID_OK; + sp->scsi_status = SC_QUEUE_FULL; + } else if (bp->b_error == EINVAL){ +#ifdef FC_NEW_EH + Cmnd->retries = 0; /* Force retry */ +#endif + host_status = DID_BUS_BUSY; + sp->scsi_status = 0; + } + } + + Cmnd->result = ScsiResult(host_status,sp->scsi_status); + fc_queue_done_cmd(p_dev_ctl, bp); + return (0); + } + + /* + * check error flag + */ + if((bp->b_flags & B_ERROR)) + { + switch(bp->b_error){ + case 0: + host_status = DID_OK; + sp->scsi_status = 0; + break; + case EBUSY: + host_status = DID_BUS_BUSY; + sp->scsi_status = 0; + break; + case EINVAL: +#ifdef FC_NEW_EH + Cmnd->retries = 0; /* Force retry */ +#endif + host_status = DID_BUS_BUSY; + sp->scsi_status = 0; + break; + default: +#ifdef FC_NEW_EH + host_status = DID_ERROR; +#else + host_status = DID_BUS_BUSY; +#endif + break; + } + } + + /* + * next hardware errors + */ + if(sp->status_validity == SC_ADAPTER_ERROR){ +#ifdef FC_NEW_EH + host_status = DID_ERROR; +#else + host_status = DID_BUS_BUSY; +#endif + Cmnd->result = ScsiResult(host_status,0); + fc_queue_done_cmd(p_dev_ctl, bp); + return (0); + } + + /* + * if lun0_missing feature is turned on and it's inquiry to a missing + * lun 0, then we will fake out LINUX scsi layer to allow scanning + * of other luns. + */ + if (lpfc_lun0_missing) { + if ((Cmnd->cmnd[0] == FCP_SCSI_INQUIRY) && (Cmnd->device->lun == 0)) { + uchar *buf; + buf = (uchar *)Cmnd->request_buffer; + if( *buf == 0x7f) { + /* Make lun unassigned and wrong type */ + *buf = 0x3; + } + } + } + + if(lpfc_lun_skip) { + /* If a LINUX OS patch to support, LUN skipping / no LUN 0, is not present, + * this code will fake out the LINUX scsi layer to allow it to detect + * all LUNs if there are LUN holes on a device. + */ + if (Cmnd->cmnd[0] == FCP_SCSI_INQUIRY) { + uchar *buf; + buf = (uchar *)Cmnd->request_buffer; + if(( *buf == 0x7f) || ((*buf & 0xE0) == 0x20)) { + /* Make lun unassigned and wrong type */ + *buf = 0x3; + } + } + } + + Cmnd->result = ScsiResult(host_status,sp->scsi_status); + fc_queue_done_cmd(p_dev_ctl, bp); + + return(0); +} + +/****************************************************************************** +* Function name : fc_fcp_bufunmap +* +* Description : +* +******************************************************************************/ +int fc_fcp_bufunmap(fc_dev_ctl_t * p_dev_ctl, + struct sc_buf * sp) +{ + struct buf *bp; + struct scsi_cmnd * Cmnd; + FC_BRD_INFO * binfo; + + binfo = &BINFO; + bp = (struct buf *)sp; + Cmnd = bp->cmnd; + /* unmap DMA resources used */ + if(!(sp->flags & SC_MAPPED)) + return(0); +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) + { + int rwflg; + + rwflg = Cmnd->sc_data_direction; + + if (Cmnd->use_sg) { + pci_unmap_sg(p_dev_ctl->pcidev, Cmnd->request_buffer, Cmnd->use_sg, rwflg); + } + else if ((Cmnd->request_bufflen) && (bp->av_back)) { +#if LINUX_VERSION_CODE <= LinuxVersionCode(2,4,12) + pci_unmap_single(p_dev_ctl->pcidev, (uint64_t)((ulong)(bp->av_back)), Cmnd->request_bufflen, rwflg); +#else + pci_unmap_page(p_dev_ctl->pcidev, (uint64_t)((ulong)(bp->av_back)), Cmnd->request_bufflen, rwflg); +#endif + } + } + +#endif + FCSTATCTR.fcUnMapCnt++; + sp->flags &= ~SC_MAPPED; + return(0); +} + +/****************************************************************************** +* Function name : fc_fcp_bufmap +* +* Description : Called from issue_fcp_cmd, used to map addresses in sbp to +* physical addresses for the I/O. +******************************************************************************/ +int fc_fcp_bufmap(fc_dev_ctl_t * p_dev_ctl, + struct sc_buf * sbp, + fc_buf_t * fcptr, + IOCBQ * temp, + ULP_BDE64 * bpl, + dvi_t * dev_ptr, + int pend) +{ + uint32 seg_cnt, cnt, num_bmps, i, num_bde; + int rwflg; + FC_BRD_INFO * binfo = &BINFO; + iCfgParam * clp; + struct buf * bp; + RING * rp; + IOCB * cmd; + struct scsi_cmnd * cmnd; + ULP_BDE64 * topbpl; + MATCHMAP * bmp; + MATCHMAP * last_bmp; + void * physaddr; + struct scatterlist *sgel_p; +#ifdef powerpc + struct scatterlist *sgel_p_t0; +#endif /* endif powerpc */ + + bp = (struct buf *)sbp; + /* + Linux command */ + cmnd = bp->cmnd; + if(!cmnd) + return(FCP_EXIT); + rp = &binfo->fc_ring[FC_FCP_RING]; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + cmd = &temp->iocb; + + last_bmp = fcptr->bmp; + num_bmps = 1; + num_bde = 0; + topbpl = 0; + sgel_p = 0; + + fcptr->flags |= DATA_MAPPED; + if (cmnd->use_sg) { + sbp->bufstruct.av_back = 0; + sgel_p = (struct scatterlist *)cmnd->request_buffer; +#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0) + seg_cnt = cmnd->use_sg; + rwflg = 0; +#else + rwflg = cmnd->sc_data_direction; + #ifdef powerpc /* remap to get a different set of fysadds that xclud zro */ + remapsgl: + #endif /* end if powerpc */ + seg_cnt = pci_map_sg(p_dev_ctl->pcidev, sgel_p, cmnd->use_sg, rwflg); + #ifdef powerpc /* check 4 zro phys address, then remap to get a diff 1 */ + for (sgel_p_t0=sgel_p, i=0; ibufstruct.b_bcount = cnt; + break; + } + /* Fill in continuation entry to next bpl */ + bpl->addrHigh = (uint32)putPaddrHigh(bmp->phys); + bpl->addrHigh = PCIMEM_LONG(bpl->addrHigh); + bpl->addrLow = (uint32)putPaddrLow(bmp->phys); + bpl->addrLow = PCIMEM_LONG(bpl->addrLow); + bpl->tus.f.bdeFlags = BPL64_SIZE_WORD; + num_bde++; + if (num_bmps == 1) { + cmd->un.fcpi64.bdl.bdeSize += (num_bde * sizeof(ULP_BDE64)); + } else { + topbpl->tus.f.bdeSize = (num_bde * sizeof(ULP_BDE64)); + topbpl->tus.w = PCIMEM_LONG(topbpl->tus.w); + } + topbpl = bpl; + bpl = (ULP_BDE64 * )bmp->virt; + last_bmp->fc_mptr = (void *)bmp; + last_bmp = bmp; + num_bde = 0; + num_bmps++; + } +#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0) + rwflg = 0; +#else + if(rwflg == B_WRITE) + rwflg = SCSI_DATA_WRITE; + else + rwflg = SCSI_DATA_READ; +#endif + + physaddr = (void *)((ulong)scsi_sg_dma_address(sgel_p)); + + bpl->addrLow = PCIMEM_LONG(putPaddrLow(physaddr)); + bpl->addrHigh = PCIMEM_LONG(putPaddrHigh(physaddr)); + bpl->tus.f.bdeSize = scsi_sg_dma_len(sgel_p); + cnt += bpl->tus.f.bdeSize; + if (cmd->ulpCommand == CMD_FCP_IREAD64_CR) + bpl->tus.f.bdeFlags = BUFF_USE_RCV; + else + bpl->tus.f.bdeFlags = 0; + bpl->tus.w = PCIMEM_LONG(bpl->tus.w); + bpl++; + sgel_p++; + num_bde++; + } /* end for loop */ + + } + else { + +#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0) + rwflg = 0; +#else + rwflg = cmnd->sc_data_direction; +#endif + +#if LINUX_VERSION_CODE <= LinuxVersionCode(2,4,12) + physaddr = (void *)((ulong)pci_map_single(p_dev_ctl->pcidev, + cmnd->request_buffer, cmnd->request_bufflen, rwflg)); +#else + { + struct page *page = virt_to_page((ulong)(cmnd->request_buffer)); + unsigned long offset = ((unsigned long)cmnd->request_buffer & ~PAGE_MASK); + + #ifdef powerpc + remapnsg: + #endif /* endif powerpc */ + physaddr = (void *)((ulong)pci_map_page(p_dev_ctl->pcidev, + page, offset, cmnd->request_bufflen, rwflg)); + #ifdef powerpc + if (!physaddr) { + goto remapnsg; + } + #endif /* endif remapnsg */ + } +#endif + FCSTATCTR.fcMapCnt++; + sbp->bufstruct.av_back = (void *)physaddr; + /* no scatter-gather list case */ + bpl->addrLow = PCIMEM_LONG(putPaddrLow(physaddr)); + bpl->addrHigh = PCIMEM_LONG(putPaddrHigh(physaddr)); + bpl->tus.f.bdeSize = sbp->bufstruct.b_bcount; + if (cmd->ulpCommand == CMD_FCP_IREAD64_CR) + bpl->tus.f.bdeFlags = BUFF_USE_RCV; + else + bpl->tus.f.bdeFlags = 0; + bpl->tus.w = PCIMEM_LONG(bpl->tus.w); + num_bde = 1; + bpl++; + + } + + bpl->addrHigh = 0; + bpl->addrLow = 0; + bpl->tus.w = 0; + last_bmp->fc_mptr = 0; + if (num_bmps == 1) { + cmd->un.fcpi64.bdl.bdeSize += (num_bde * sizeof(ULP_BDE64)); + } else { + topbpl->tus.f.bdeSize = (num_bde * sizeof(ULP_BDE64)); + topbpl->tus.w = PCIMEM_LONG(topbpl->tus.w); + } + cmd->ulpBdeCount = 1; + cmd->ulpLe = 1; /* Set the LE bit in the last iocb */ + + /* Queue cmd chain to last iocb entry in xmit queue */ + if (rp->fc_tx.q_first == NULL) { + rp->fc_tx.q_first = (uchar * )temp; + } else { + ((IOCBQ * )(rp->fc_tx.q_last))->q = (uchar * )temp; + } + rp->fc_tx.q_last = (uchar * )temp; + rp->fc_tx.q_cnt++; + + sbp->flags |= SC_MAPPED; + return(0); +} + +/****************************************************************************** +* Function name : local_timeout +* +* Description : Local handler for watchdog timeouts +******************************************************************************/ +void local_timeout(unsigned long data) +{ + struct watchdog *wdt = (struct watchdog *)data; + fc_dev_ctl_t * p_dev_ctl; + FC_BRD_INFO * binfo; + int skip_intr, i; + ulong siflg; + ulong iflg; + struct lpfc_dpc *ldp; + + siflg = 0; + skip_intr = 0; + iflg = 0; + LPFC_LOCK_DRIVER0; + for (i = 0; i < MAX_FC_BRDS; i++) { + if((p_dev_ctl = (fc_dev_ctl_t *)DD_CTL.p_dev[i])) { + if(p_dev_ctl->fc_ipri != 0) { + printk("LOCK 14 failure %x %x\n",(uint32)p_dev_ctl->fc_ipri, (uint32)iflg); + } + p_dev_ctl->fc_ipri = 14; + + /* Check to see if the DPC was scheduled since the last clock interrupt */ + if(p_dev_ctl->dpc_cnt == p_dev_ctl->save_dpc_cnt) { + volatile uint32 ha_copy; + void * ioa; + + binfo = &BINFO; + ioa = FC_MAP_IO(&binfo->fc_iomap_io); /* map in io registers */ + /* Read host attention register to determine interrupt source */ + ha_copy = READ_CSR_REG(binfo, FC_HA_REG(binfo, ioa)); + FC_UNMAP_MEMIO(ioa); + /* If there are any hardware interrupts to process, they better + * get done before the next clock interrupt. + */ + if(p_dev_ctl->dpc_ha_copy || (ha_copy & ~HA_LATT)) { + if(p_dev_ctl->dev_flag & FC_NEEDS_DPC) { + skip_intr = 1; + /* Local_timeout Skipping clock tick */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0756, /* ptr to msg structure */ + fc_mes0756, /* ptr to msg */ + fc_msgBlk0756.msgPreambleStr, /* begin varargs */ + p_dev_ctl->dpc_ha_copy, + ha_copy, + p_dev_ctl->dpc_cnt, + binfo->fc_ffstate); /* end varargs */ + if(wdt) + del_timer(&wdt->timer); + } + else { + p_dev_ctl->dev_flag |= FC_NEEDS_DPC; + } + } + } + p_dev_ctl->save_dpc_cnt = p_dev_ctl->dpc_cnt; + } + } + + if(skip_intr || !wdt || !wdt->timeout_id) { + fc_reset_timer(); + goto out; + } + del_timer(&wdt->timer); + + ldp = &lpfc_dpc[0]; + if (ldp->dpc_wait == NULL) { + if(wdt->func) + wdt->func(wdt); + } + else { + lpfc_timer(0); + } + +out: + for (i = 0; i < MAX_FC_BRDS; i++) { + if((p_dev_ctl = (fc_dev_ctl_t *)DD_CTL.p_dev[i])) { + p_dev_ctl->fc_ipri = 0; + } + } + LPFC_UNLOCK_DRIVER0; + + for (i = 0; i < MAX_FC_BRDS; i++) { + if((p_dev_ctl = (fc_dev_ctl_t *)DD_CTL.p_dev[i])) { + binfo = &BINFO; + ldp = &lpfc_dpc[binfo->fc_brd_no]; + if ((ldp->dpc_active == 0) && ldp->dpc_wait) + up(ldp->dpc_wait); + } + } +} + +/****************************************************************************** +* Function name : fc_reset_timer +* +* Description : +* +******************************************************************************/ +void fc_reset_timer(void) +{ + FCCLOCK_INFO * clock_info; + + clock_info = &DD_CTL.fc_clock_info; + ((struct watchdog *)(CLOCKWDT))->func = fc_timer; + ((struct watchdog *)(CLOCKWDT))->restart = 1; + ((struct watchdog *)(CLOCKWDT))->count = 0; + ((struct watchdog *)(CLOCKWDT))->stopping = 0; + /* + * add our watchdog timer routine to kernel's list + */ + ((struct watchdog *)(CLOCKWDT))->timer.expires = HZ + jiffies; + ((struct watchdog *)(CLOCKWDT))->timer.function = local_timeout; + ((struct watchdog *)(CLOCKWDT))->timer.data = (unsigned long)(CLOCKWDT); + init_timer(&((struct watchdog *)(CLOCKWDT))->timer); + add_timer(&((struct watchdog *)(CLOCKWDT))->timer); + return; +} + +/****************************************************************************** +* Function name : curtime +* +* Description : Set memory pointed to by time, with the current time (LBOLT) +* +******************************************************************************/ +void curtime(uint32 *time) +{ + *time = jiffies; +} + +/****************************************************************************** +* Function name : fc_initpci +* +* Description : Called by driver diagnostic interface to initialize dfc_info +* +******************************************************************************/ +int fc_initpci(struct dfc_info *di, + fc_dev_ctl_t *p_dev_ctl) +{ + FC_BRD_INFO * binfo; /* point to the binfo area */ + struct pci_dev *pdev; + + pdev = p_dev_ctl->pcidev; + /* + must have the pci struct + */ + if(!pdev) + return(1); + binfo = &BINFO; + + di->fc_ba.a_onmask = (ONDI_MBOX | ONDI_RMEM | ONDI_RPCI | ONDI_RCTLREG | + ONDI_IOINFO | ONDI_LNKINFO | ONDI_NODEINFO | ONDI_CFGPARAM | + ONDI_CT | ONDI_HBAAPI); + di->fc_ba.a_offmask = (OFFDI_MBOX | OFFDI_RMEM | OFFDI_WMEM | OFFDI_RPCI | + OFFDI_WPCI | OFFDI_RCTLREG | OFFDI_WCTLREG); + + if ((binfo->fc_flag & FC_SLI2) && (fc_diag_state == DDI_ONDI)) + di->fc_ba.a_onmask |= ONDI_SLI2; + else + di->fc_ba.a_onmask |= ONDI_SLI1; +#ifdef powerpc + di->fc_ba.a_onmask |= ONDI_BIG_ENDIAN; +#else + di->fc_ba.a_onmask |= ONDI_LTL_ENDIAN; +#endif + di->fc_ba.a_pci=((((uint32)pdev->device) << 16) | (uint32)(pdev->vendor)); + di->fc_ba.a_pci = SWAP_LONG(di->fc_ba.a_pci); + di->fc_ba.a_ddi = fcinstance[binfo->fc_brd_no]; + if(pdev->bus) + di->fc_ba.a_busid = (uint32)(pdev->bus->number); + else + di->fc_ba.a_busid = 0; + di->fc_ba.a_devid = (uint32)(pdev->devfn); + + bcopy((void *)lpfc_release_version, di->fc_ba.a_drvrid, 8); + decode_firmware_rev(binfo, &VPD); + bcopy((void *)fwrevision, di->fc_ba.a_fwname, 32); + + + /* setup structures for I/O mapping */ + di->fc_iomap_io = binfo->fc_iomap_io; + di->fc_iomap_mem = binfo->fc_iomap_mem; + di->fc_hmap = (char *)pdev; + return(0); +} + +/****************************************************************************** +* Function name : fc_readpci +* +* Description : Called by driver diagnostic interface to copy cnt bytes from +* PCI configuration registers, at offset, into buf. +******************************************************************************/ +int fc_readpci(struct dfc_info *di, + uint32 offset, + char *buf, + uint32 cnt) +{ + struct pci_dev *pdev; + int i; + uint32 *lp; + uint32 ldata; + + if(!di->fc_hmap) return(1); + pdev = (struct pci_dev *)di->fc_hmap; + for(i=0; i < cnt; i++){ + lp = (uint32 *)buf; + pci_read_config_dword(pdev,(u8)offset, (u32 *)buf); + ldata = *lp; + *lp = SWAP_LONG(ldata); + buf+=4; + offset+=4; + } + return(0); +} + +/****************************************************************************** +* Function name : fc_writepci +* +* Description : Called by driver diagnostic interface to write cnt bytes from +* buf into PCI configuration registers, starting at offset. +******************************************************************************/ +int fc_writepci(struct dfc_info *di, + uint32 offset, + char *buf, + uint32 cnt) +{ + struct pci_dev *pdev; + int i; + uint32 *lp; + uint32 ldata; + + if(!di->fc_hmap) return(1); + pdev = (struct pci_dev *)di->fc_hmap; + for(i=0; i < cnt; i++){ + lp = (uint32 *)buf; + ldata = *lp; + *lp = SWAP_LONG(ldata); + pci_write_config_dword(pdev,(u8)offset, *buf); + buf+=4; + offset+=4; + } + return(0); +} + +/****************************************************************************** +* Function name : copyout +* +* Description : copy from kernel-space to a user-space +* +******************************************************************************/ +int copyout(uchar *src, + uchar *dst, + unsigned long size) +{ + copy_to_user(dst,src,size); + return(0); +} + +/****************************************************************************** +* Function name : copyin +* +* Description : copy from user-space to kernel-space +* +******************************************************************************/ +int copyin(uchar *src, + uchar *dst, + unsigned long size) +{ + copy_from_user(dst,src,size); + return(0); +} + +/****************************************************************************** +* Function name : fc_getDVI +* +* Description : get a dvi ptr from a Linux scsi cmnd +* +******************************************************************************/ +_local_ dvi_t *fc_getDVI(fc_dev_ctl_t * p_dev_ctl, + int target, + fc_lun_t lun) +{ + FC_BRD_INFO * binfo; + iCfgParam * clp; + struct dev_info * dev_ptr; + struct dev_info * save_ptr; + node_t * node_ptr; + NODELIST * nlp; + int dev_index; + int report_device = 1; + + binfo = &p_dev_ctl->info; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + dev_index = INDEX(ZERO_PAN, target); + + if (dev_index >= MAX_FC_TARGETS){ + return (0); + } + + if (lun < 0) { + /* LUN address out of range */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0718, /* ptr to msg structure */ + fc_mes0718, /* ptr to msg */ + fc_msgBlk0718.msgPreambleStr, /* begin varargs */ + target, + (uint32)lun); /* end varargs */ + return (0); + } + + /* + * Find the target from the nlplist based on SCSI ID + */ + if((nlp = fc_findnode_scsid(binfo, NLP_SEARCH_MAPPED, target)) == 0) { + /* + * Device SCSI ID is not a valid FCP target + */ + + return (0); + } + + /* Allocate SCSI node structure for each open FC node */ + node_ptr = binfo->device_queue_hash[dev_index].node_ptr; + if (node_ptr == NULL) { + if (!(node_ptr = (node_t * ) fc_kmem_zalloc(sizeof(node_t)))) { + return (0); + } + + /* Initialize the node ptr structure */ + node_ptr->ap = p_dev_ctl; /* point back to adapter struct */ + node_ptr->devno = target; + node_ptr->lunlist = NULL; + node_ptr->max_lun = lpfc_max_lun; + + node_ptr->last_dev = NULL; + node_ptr->num_active_io = 0; + node_ptr->virtRptLunData = 0; + node_ptr->physRptLunData = 0; + + node_ptr->tgt_queue_depth = (u_int)clp[CFG_DFT_TGT_Q_DEPTH].a_current; + + node_ptr->nlp = nlp; + node_ptr->rpi = nlp->nlp_Rpi; + node_ptr->last_good_rpi = nlp->nlp_Rpi; + node_ptr->scsi_id = target; + nlp->nlp_targetp = (uchar * )node_ptr; + binfo->device_queue_hash[dev_index].node_ptr = node_ptr; + } + + dev_ptr = fc_find_lun(binfo, dev_index, lun); + /* device queue structure doesn't exist yet */ + if ( dev_ptr == NULL ) { + if (!(dev_ptr = (dvi_t * ) fc_kmem_zalloc(sizeof(dvi_t)))) { + return (0); + } + + /* Initialize the dev_info structure */ + dev_ptr->nodep = node_ptr; + dev_ptr->lun_id = lun; + dev_ptr->flags = 0; + dev_ptr->sense_valid = FALSE; + + /* Initialize device queues */ + dev_ptr->ABORT_BDR_fwd = NULL; + dev_ptr->ABORT_BDR_bkwd = NULL; + dev_ptr->DEVICE_WAITING_fwd = NULL; + dev_ptr->pend_head = NULL; + dev_ptr->pend_tail = NULL; + dev_ptr->pend_count = 0; + dev_ptr->clear_head = NULL; + dev_ptr->clear_count = 0; + dev_ptr->active_io_count = 0; + dev_ptr->stop_send_io = 0; + dev_ptr->ioctl_wakeup = 0; + dev_ptr->qfull_retries = lpfc_qfull_retry; + dev_ptr->first_check = FIRST_CHECK_COND | FIRST_IO; + + dev_ptr->fcp_lun_queue_depth = (u_int)clp[CFG_DFT_LUN_Q_DEPTH].a_current; + if (dev_ptr->fcp_lun_queue_depth < 1) + dev_ptr->fcp_lun_queue_depth = 1; + + dev_ptr->fcp_cur_queue_depth = dev_ptr->fcp_lun_queue_depth; + + /* init command state flags */ + dev_ptr->queue_state = ACTIVE; + dev_ptr->opened = TRUE; + dev_ptr->ioctl_wakeup = FALSE; + dev_ptr->ioctl_event = EVENT_NULL; + dev_ptr->stop_event = FALSE; + + /* + * Create fc_bufs - allocate virtual and bus lists for use with FCP + */ + if(fc_rtalloc(p_dev_ctl, dev_ptr) == 0) { + fc_kmem_free(dev_ptr, sizeof(dvi_t)); + return (0); + } + + /* Add dev_ptr to lunlist */ + if (node_ptr->lunlist == NULL) { + node_ptr->lunlist = dev_ptr; + } else { + save_ptr = node_ptr->lunlist; + while (save_ptr->next != NULL ) { + save_ptr = save_ptr->next; + } + save_ptr->next = dev_ptr; + } + dev_ptr->next = NULL; + } + + if(clp[CFG_DEVICE_REPORT].a_current + && dev_ptr!=NULL && report_device && + (dev_ptr->nodep->nlp->nlp_type & NLP_FCP_TARGET)) { + nlp = dev_ptr->nodep->nlp; + printk(KERN_INFO"!lpfc%d: Acquired FCP/SCSI Target 0x%lx LUN 0x%lx , D_ID is (0x%lx)\n", + binfo->fc_brd_no, + (ulong)target, + (ulong)lun, + (ulong)(nlp->nlp_DID)); + } + + return (dev_ptr); +} + +dvi_t * +fc_alloc_devp( +fc_dev_ctl_t * p_dev_ctl, +int target, +fc_lun_t lun) +{ + return fc_getDVI(p_dev_ctl, target, lun); +} + +/****************************************************************************** +* Function name : deviFree +* +* Description : Free a dvi_t pointer +* +******************************************************************************/ +_local_ void deviFree(fc_dev_ctl_t *p_dev_ctl, + dvi_t *dev_ptr, + node_t *node_ptr) +{ + struct dev_info *curDev, *prevDev; + fc_buf_t *curFcBuf, *tmpFcBuf; + struct sc_buf *sp; + dma_addr_t phys; + unsigned int size; + MBUF_INFO * buf_info; + MBUF_INFO bufinfo; + + /* + * First, we free up all fcbuf for this device. + */ + curFcBuf = dev_ptr->fcbuf_head; + while (curFcBuf != NULL) { + tmpFcBuf = curFcBuf->fc_fwd; + phys = (dma_addr_t)((ulong)curFcBuf->phys_adr); + size = fc_po2(sizeof(fc_buf_t)); + + buf_info = &bufinfo; + buf_info->phys = (void *)((ulong)phys); + buf_info->data_handle = 0; + buf_info->dma_handle = 0; + buf_info->flags = FC_MBUF_DMA; + buf_info->virt = (uint32 * )curFcBuf; + buf_info->size = size; + fc_free(p_dev_ctl, buf_info); + curFcBuf = tmpFcBuf; + } /* end while loop */ + while (dev_ptr->scp != NULL) { + sp = dev_ptr->scp; + dev_ptr->scp = sp->bufstruct.av_forw; + dev_ptr->scpcnt--; + fc_kmem_free((void *)sp, sizeof(struct sc_buf)); + } + + /* + * Next, we are going to remove this device-lun combination. + * But we need to make sure the link list where this dev_ptr + * belongs is not broken. + */ + + curDev = node_ptr->lunlist; + prevDev = curDev; + while (curDev != NULL) { + if (curDev == dev_ptr) + break; + else { + prevDev = curDev; + curDev = curDev->next; + } + } + + if (curDev == dev_ptr) { /* This should always pass */ + if (curDev == node_ptr->lunlist) + node_ptr->lunlist = curDev->next; + else + prevDev->next = curDev->next; + } + fc_kmem_free((void *)dev_ptr, sizeof(dvi_t)); +} +/****************************************************************************** +* Function name : fc_print +* +* Description : +* +******************************************************************************/ +int fc_print( char *str, + void *a1, + void *a2) +{ + printk((const char *)str, a1, a2); + return(1); +} /* fc_print */ + +/****************************************************************************** +* Function name : log_printf_msgblk +* +* Description : Called from common code function fc_log_printf_msg_vargs +* Note : Input string 'str' is formatted (sprintf) by caller. +******************************************************************************/ +int log_printf_msgblk(int brdno, + msgLogDef * msg, + char * str, /* String formatted by caller */ + int log_only) +{ + int ddiinst; + char * mod; + + ddiinst = fcinstance[brdno]; + mod = "lpfc"; + if (log_only) { + /* system buffer only */ + switch(msg->msgType) { + case FC_LOG_MSG_TYPE_INFO: + case FC_LOG_MSG_TYPE_WARN: + /* These LOG messages appear in LOG file only */ + printk(KERN_INFO"!%s%d:%04d:%s\n", mod, ddiinst, msg->msgNum, str); + break; + case FC_LOG_MSG_TYPE_ERR_CFG: + case FC_LOG_MSG_TYPE_ERR: + /* These LOG messages appear on the monitor and in the LOG file */ + printk(KERN_WARNING"!%s%d:%04d:%s\n", mod, ddiinst, msg->msgNum, str); + break; + case FC_LOG_MSG_TYPE_PANIC: + panic("!%s%d:%04d:%s\n", mod, ddiinst, msg->msgNum, str); + break; + default: + return(0); + } + } + else { + switch(msg->msgType) { + case FC_LOG_MSG_TYPE_INFO: + case FC_LOG_MSG_TYPE_WARN: + printk(KERN_INFO"!%s%d:%04d:%s\n", mod, ddiinst, msg->msgNum, str); + break; + case FC_LOG_MSG_TYPE_ERR_CFG: + case FC_LOG_MSG_TYPE_ERR: + printk(KERN_WARNING"!%s%d:%04d:%s\n", mod, ddiinst, msg->msgNum, str); + break; + case FC_LOG_MSG_TYPE_PANIC: + panic("!%s%d:%04d:%s\n", mod, ddiinst, msg->msgNum, str); + break; + default: + return(0); + } + } + return(1); +} /* log_printf_msgblk */ + +/****************************************************************************** +* Function name : fc_write_toio +* +******************************************************************************/ +_static_ void fc_write_toio(uint32 *src, + uint32 *dest_io, + uint32 cnt) +{ + uint32 ldata; + int i; + + for (i = 0; i < (int)cnt; i += sizeof(uint32)) { + ldata = *src++; + writel(ldata, dest_io); + dest_io++; + } + return; +} + +/****************************************************************************** +* Function name : fc_read_fromio +* +* Description : +* +******************************************************************************/ +_static_ void fc_read_fromio( uint32 *src_io, + uint32 *dest, + uint32 cnt) +{ + uint32 ldata; + int i; + + for (i = 0; i < (int)cnt; i += sizeof(uint32)) { + ldata = readl(src_io); + src_io++; + *dest++ = ldata; + } + return; +} + +/****************************************************************************** +* Function name : fc_writel +* +* Description : +* +******************************************************************************/ +_static_ void fc_writel(uint32 * src_io, + uint32 ldata) +{ + writel(ldata, src_io); + return; +} + +/****************************************************************************** +* Function name : fc_readl +* +* Description : +* +******************************************************************************/ +_static_ uint32 fc_readl(uint32 *src_io) +{ + uint32 ldata; + + ldata = readl(src_io); + return(ldata); +} + + + +#ifdef MODULE +/* + * XXX: patman I don't know why this is needed. Maybe for out of tree + * builds? +#include "lpfc.ver" + */ +#endif /* MODULE */ + +#endif /* __GENKSYMS__ */ + +#ifdef MODULE + +#ifndef EXPORT_SYMTAB +#define EXPORT_SYMTAB +#endif + +int lpfc_xmit(fc_dev_ctl_t *p_dev_ctl, struct sk_buff *skb); +int lpfc_ioctl(int cmd, void *s); + +EXPORT_SYMBOL(lpfc_xmit); +EXPORT_SYMBOL(lpfc_ioctl); + +#endif /* MODULE */ + +/****************************************************************************** +* Function name : fc_ioctl +* +* Description : ioctl interface to diagnostic utilities +* called by a special character device driver (fcLINUXdiag.c) +* fd is the board number (instance), and s is a cmninfo pointer +* +******************************************************************************/ +int fc_ioctl(int cmd, + void *s) +{ + int rc, fd; + fc_dev_ctl_t *p_dev_ctl; + struct dfccmdinfo *cp = (struct dfccmdinfo *)s; + struct cmd_input *ci = (struct cmd_input *)cp->c_datain; + + if(!cp || !ci) + return EINVAL; + fd = ci->c_brd; + if(fd > DD_CTL.num_devs) + return EINVAL; + if(!(p_dev_ctl = (fc_dev_ctl_t *)DD_CTL.p_dev[fd])) + return EINVAL; + + rc = dfc_ioctl(cp, ci); + + return(rc); +} + +/****************************************************************************** +* Function name : dfc_sleep +* +* Description : +* +******************************************************************************/ +int dfc_sleep(fc_dev_ctl_t *p_dev_ctl, + fcEvent_header *ep) +{ + switch(ep->e_mask) { + case FC_REG_LINK_EVENT: + ep->e_mode |= E_SLEEPING_MODE; + interruptible_sleep_on(&p_dev_ctl->linkwq); + if (signal_pending (current)) + return(1); + break; + case FC_REG_RSCN_EVENT: + ep->e_mode |= E_SLEEPING_MODE; + interruptible_sleep_on(&p_dev_ctl->rscnwq); + if (signal_pending (current)) + return(1); + break; + case FC_REG_CT_EVENT: + ep->e_mode |= E_SLEEPING_MODE; + interruptible_sleep_on(&p_dev_ctl->ctwq); + if (signal_pending (current)) + return(1); + break; + } + return(0); +} + +/****************************************************************************** +* Function name : dfc_wakeup +* +* Description : +* +******************************************************************************/ +int dfc_wakeup(fc_dev_ctl_t *p_dev_ctl, + fcEvent_header *ep) +{ + switch(ep->e_mask) { + case FC_REG_LINK_EVENT: + ep->e_mode &= ~E_SLEEPING_MODE; + wake_up_interruptible(&p_dev_ctl->linkwq); + break; + case FC_REG_RSCN_EVENT: + ep->e_mode &= ~E_SLEEPING_MODE; + wake_up_interruptible(&p_dev_ctl->rscnwq); + break; + case FC_REG_CT_EVENT: + ep->e_mode &= ~E_SLEEPING_MODE; + wake_up_interruptible(&p_dev_ctl->ctwq); + break; + } + return(0); +} + +/****************************************************************************** +* Function name : lpfc_xmit +* +* Description : +* +******************************************************************************/ +int lpfc_xmit(fc_dev_ctl_t *p_dev_ctl, + struct sk_buff *skb) +{ + int rc; + ulong siflg, iflg; + + siflg = 0; + LPFC_LOCK_SCSI_DONE(p_dev_ctl->host); + iflg = 0; + LPFC_LOCK_DRIVER(15); + rc = fc_xmit(p_dev_ctl, skb); + LPFC_UNLOCK_DRIVER; + LPFC_UNLOCK_SCSI_DONE(p_dev_ctl->host); + return(rc); +} + +/****************************************************************************** +* Function name : lpfc_ioctl +* +* Description : +* +******************************************************************************/ +int lpfc_ioctl(int cmd, + void *s) +{ + int i, cnt, ipri; + NETDEVICE *dev; + fc_dev_ctl_t *p_dev_ctl; + FC_BRD_INFO * binfo; + iCfgParam * clp; + struct lpfn_probe *lp; + ndd_t * p_ndd; + + cnt = 0; + switch(cmd) { + case LPFN_PROBE: +#ifndef MODULE + if(lpfc_detect_called != 1) { + lpfc_detect_called = 2; /* defer calling this till after fc_detect */ + return(1); + } +#endif /* MODULE */ + + for (i = 0; i < MAX_FC_BRDS; i++) { + if((p_dev_ctl = (fc_dev_ctl_t *)DD_CTL.p_dev[i])) { + clp = DD_CTL.p_config[i]; + binfo = &BINFO; + if(clp[CFG_NETWORK_ON].a_current == 0) + continue; + ipri = disable_lock(FC_LVL, &CMD_LOCK); + if(p_dev_ctl->ihs.lpfn_dev == 0) { + unsigned int alloc_size; + + /* ensure 32-byte alignment of the private area */ + alloc_size = sizeof(NETDEVICE) + 31; + + dev = (NETDEVICE *) lpfc_kmalloc (alloc_size, GFP_KERNEL, 0, 0); + if (dev == NULL) { + unlock_enable(ipri, &CMD_LOCK); + continue; + } + memset(dev, 0, alloc_size); +#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0) + dev->name = (char *)(dev + 1); + sprintf(dev->name, "lpfn%d", binfo->fc_brd_no); + +#else + rtnl_lock(); + strcpy(dev->name, "lpfn%d"); + if (dev_alloc_name(dev, "lpfn%d")<0) { + rtnl_unlock(); + lpfc_kfree(alloc_size, (void *)dev, (void *)((ulong)INVALID_PHYS), 0); + unlock_enable(ipri, &CMD_LOCK); + continue; + } + +#endif + dev->priv = (void *)p_dev_ctl; + p_dev_ctl->ihs.lpfn_dev = dev; + + lp = (struct lpfn_probe *)s; + p_ndd = (ndd_t * ) & (NDD); + /* Initialize the device structure. */ + dev->hard_start_xmit = lp->hard_start_xmit; + dev->get_stats = lp->get_stats; + dev->open = lp->open; + dev->stop = lp->stop; + dev->hard_header = lp->hard_header; + dev->rebuild_header = lp->rebuild_header; + dev->change_mtu = lp->change_mtu; + p_ndd->nd_receive = + (void (*)(void *, struct sk_buff *, void *))(lp->receive); + + /* Assume fc header + LLC/SNAP 24 bytes */ + dev->hard_header_len = 24; + dev->type = ARPHRD_ETHER; + dev->mtu = p_dev_ctl->ihs.lpfn_mtu; + dev->addr_len = 6; + dev->tx_queue_len = 100; + + memset(dev->broadcast, 0xFF, 6); + bcopy(p_dev_ctl->phys_addr, dev->dev_addr, 6); + + /* New-style flags */ + dev->flags = IFF_BROADCAST; + register_netdevice(dev); +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) + rtnl_unlock(); +#endif + + cnt++; + } + unlock_enable(ipri, &CMD_LOCK); + } + } + break; + case LPFN_DETACH: + for (i = 0; i < MAX_FC_BRDS; i++) { + if((p_dev_ctl = (fc_dev_ctl_t *)DD_CTL.p_dev[i])) { + clp = DD_CTL.p_config[i]; + if(clp[CFG_NETWORK_ON].a_current == 0) + continue; + ipri = disable_lock(FC_LVL, &CMD_LOCK); + if((dev=p_dev_ctl->ihs.lpfn_dev)) { + unregister_netdev(dev); + dev->priv = NULL; + p_dev_ctl->ihs.lpfn_dev = 0; + cnt++; + } + unlock_enable(ipri, &CMD_LOCK); + } + } + break; + case LPFN_DFC: + break; + default: + return(0); + } + return(cnt); +} + + +/****************************************************************************** +* Function name : lpfcdfc_init +* +* Description : Register your major, and accept a dynamic number +* +******************************************************************************/ +int lpfcdfc_init(void) +{ + int result; +#ifdef powerpc + fc_dev_ctl_t *p_dev_ctl; + MBUF_INFO *buf_info; + MBUF_INFO bufinfo; + int i; +#endif + + result = register_chrdev(lpfc_major, "lpfcdfc", &lpfc_fops); + if (result < 0) { + printk(KERN_WARNING "lpfcdfc: can't get major %d\n",lpfc_major); + return result; + } + if (lpfc_major == 0) lpfc_major = result; /* dynamic */ + +#ifdef powerpc + for(i=0; i < MAX_FC_BRDS; i++) { + p_dev_ctl = (fc_dev_ctl_t *)DD_CTL.p_dev[i]; + if(p_dev_ctl) { + buf_info = &bufinfo; + buf_info->virt = 0; + buf_info->phys = 0; + buf_info->flags = (FC_MBUF_IOCTL | FC_MBUF_UNLOCK); + buf_info->align = sizeof(void *); + buf_info->size = 64 * 1024; + buf_info->dma_handle = 0; + + fc_malloc(p_dev_ctl, buf_info); + p_dev_ctl->dfc_kernel_buf = buf_info->virt; + } + } +#endif + + return 0; +} + +/****************************************************************************** +* Function name : lpfcdiag_ioctl +* +* Description : caller must insure that cmd is the board number and arg is +* the cmdinfo pointer +* +******************************************************************************/ +int lpfcdiag_ioctl(struct inode * inode, + struct file * file, + unsigned int cmd, + unsigned long arg) +{ + return -fc_ioctl(cmd, (void *)arg); +} + +/****************************************************************************** +* Function name : lpfcdiag_open +* +* Description : +* +******************************************************************************/ +int lpfcdiag_open(struct inode * inode, + struct file * file) +{ + fc_dev_ctl_t *p_dev_ctl; + struct Scsi_Host *host; + + if(((p_dev_ctl = DD_CTL.p_dev[0])) && + ((host = p_dev_ctl->host))) { + lpfcdiag_cnt++; + } + return(0); +} + +/****************************************************************************** +* Function name : lpfcdiag_release +* +* Description : +* +******************************************************************************/ +int lpfcdiag_release(struct inode * inode, + struct file * file) +{ + fc_dev_ctl_t *p_dev_ctl; + struct Scsi_Host *host; + + if(((p_dev_ctl = DD_CTL.p_dev[0])) && + ((host = p_dev_ctl->host))) { + lpfcdiag_cnt--; + } + return(0); +} + +/****************************************************************************** +* Function name : fc_get_dds_bind +* +* Description : Called from fc_attach to setup binding parameters for adapter +******************************************************************************/ +int fc_get_dds_bind(fc_dev_ctl_t *p_dev_ctl) +{ + FC_BRD_INFO *binfo; + iCfgParam *clp; + char **arrayp; + u_int cnt; + + /* + * Check if there are any WWNN / scsid bindings + */ + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + cnt = lpfc_bind_entries; + arrayp = lpfc_fcp_bind_WWNN; + if(cnt && (*arrayp != 0)) { + fc_bind_wwnn(p_dev_ctl, arrayp, cnt); + } else { + + /* + * Check if there are any WWPN / scsid bindings + */ + arrayp = lpfc_fcp_bind_WWPN; + if(cnt && (*arrayp != 0)) { + fc_bind_wwpn(p_dev_ctl, arrayp, cnt); + } else { + + /* + * Check if there are any NPortID / scsid bindings + */ + arrayp = lpfc_fcp_bind_DID; + if(cnt && (*arrayp != 0)) { + fc_bind_did(p_dev_ctl, arrayp, cnt); + } else { + switch(clp[CFG_AUTOMAP].a_current) { + case 2: + p_dev_ctl->fcp_mapping = FCP_SEED_WWPN; + break; + case 3: + p_dev_ctl->fcp_mapping = FCP_SEED_DID; + break; + default: + p_dev_ctl->fcp_mapping = FCP_SEED_WWNN; + } + } + } + } + + clp[CFG_SCAN_DOWN].a_current = (uint32)lpfc_scandown; + if(cnt && (*arrayp != 0) && (clp[CFG_SCAN_DOWN].a_current == 2)) { + /* Scan-down is 2 with Persistent binding - ignoring scan-down */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0411, /* ptr to msg structure */ + fc_mes0411, /* ptr to msg */ + fc_msgBlk0411.msgPreambleStr, /* begin varargs */ + clp[CFG_SCAN_DOWN].a_current, + p_dev_ctl->fcp_mapping); /* end varargs */ + clp[CFG_SCAN_DOWN].a_current = 0; + } + if(clp[CFG_SCAN_DOWN].a_current > 2) { + /* Scan-down is out of range - ignoring scan-down */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0412, /* ptr to msg structure */ + fc_mes0412, /* ptr to msg */ + fc_msgBlk0412.msgPreambleStr, /* begin varargs */ + clp[CFG_SCAN_DOWN].a_current, + p_dev_ctl->fcp_mapping); /* end varargs */ + clp[CFG_SCAN_DOWN].a_current = 0; + } + return(0); +} + +/****************************************************************************** +* Function name : fc_get_dds +* +* Description : Called from fc_attach to setup configuration parameters for +* adapter +* The goal of this routine is to fill in all the a_current +* members of the CfgParam structure for all configuration +* parameters. +* Example: +* clp[CFG_XXX].a_current = (uint32)value; +* value might be a define, a global variable, clp[CFG_XXX].a_default, +* or some other enviroment specific way of initializing config parameters. +******************************************************************************/ +int fc_get_dds(fc_dev_ctl_t *p_dev_ctl, + uint32 *pio) +{ + FC_BRD_INFO *binfo; + iCfgParam *clp; + int i; + int brd; + + binfo = &BINFO; + brd = binfo->fc_brd_no; + clp = DD_CTL.p_config[brd]; + + p_dev_ctl->open_state = NORMAL_OPEN; + + /* + * Set everything to the defaults + */ + for(i=0; i < NUM_CFG_PARAM; i++) + clp[i].a_current = clp[i].a_default; + + /* Default values for I/O colaesing */ + clp[CFG_CR_DELAY].a_current = + (uint32)((ulong)fc_get_cfg_param(brd, CFG_CR_DELAY)); + clp[CFG_CR_COUNT].a_current = + (uint32)((ulong)fc_get_cfg_param(brd, CFG_CR_COUNT)); + + clp[CFG_AUTOMAP].a_current = + (uint32)((ulong)fc_get_cfg_param(brd, CFG_AUTOMAP)); + + clp[CFG_LINK_SPEED].a_current = + (uint32)((ulong)fc_get_cfg_param(brd, CFG_LINK_SPEED)); + + bcopy((uchar * )"lpfc0", (uchar *)DDS.logical_name, 6); + DDS.logical_name[4] += binfo->fc_brd_no; + DDS.logical_name[5] = 0; + + clp[CFG_INTR_ACK].a_current = (uint32)lpfc_intr_ack; + clp[CFG_IDENTIFY_SELF].a_current = 0; + clp[CFG_DEVICE_REPORT].a_current = 0; + + clp[CFG_LOG_VERBOSE].a_current = + (uint32)((ulong)fc_get_cfg_param(brd, CFG_LOG_VERBOSE)); + clp[CFG_LOG_ONLY].a_current = + (uint32)((ulong)fc_get_cfg_param(brd, CFG_LOG_ONLY)); + + /* Can NOT log verbose messages until you read VERBOSE config param */ + if((binfo->fc_flag & FC_2G_CAPABLE) == 0) { + /* This HBA is NOT 2G_CAPABLE */ + if( clp[CFG_LINK_SPEED].a_current > 1) { + /* Reset link speed to auto. 1G HBA cfg'd for 2G. */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk1303, /* ptr to msg structure */ + fc_mes1303, /* ptr to msg */ + fc_msgBlk1303.msgPreambleStr); /* begin & end varargs */ + clp[CFG_LINK_SPEED].a_current = LINK_SPEED_AUTO; + } + } + + clp[CFG_NUM_IOCBS].a_current = + (uint32)((ulong)fc_get_cfg_param(brd, CFG_NUM_IOCBS)); + + if (clp[CFG_NUM_IOCBS].a_current < LPFC_MIN_NUM_IOCBS) { + /* Num-iocbs too low, resetting */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0413, /* ptr to msg structure */ + fc_mes0413, /* ptr to msg */ + fc_msgBlk0413.msgPreambleStr, /* begin varargs */ + clp[CFG_NUM_IOCBS].a_current, + LPFC_MIN_NUM_IOCBS); /* end varargs */ + clp[CFG_NUM_IOCBS].a_current = LPFC_MIN_NUM_IOCBS; + } + if (clp[CFG_NUM_IOCBS].a_current > LPFC_MAX_NUM_IOCBS) { + /* Num-iocbs too high, resetting */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0414, /* ptr to msg structure */ + fc_mes0414, /* ptr to msg */ + fc_msgBlk0414.msgPreambleStr, /* begin varargs */ + clp[CFG_NUM_IOCBS].a_current, + LPFC_MAX_NUM_IOCBS); /* end varargs */ + clp[CFG_NUM_IOCBS].a_current = LPFC_MAX_NUM_IOCBS; + } + + clp[CFG_NUM_BUFS].a_current = + (uint32)((ulong)fc_get_cfg_param(brd, CFG_NUM_BUFS)); + + if (clp[CFG_NUM_BUFS].a_current < LPFC_MIN_NUM_BUFS) { + /* Num-bufs too low, resetting */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0415, /* ptr to msg structure */ + fc_mes0415, /* ptr to msg */ + fc_msgBlk0415.msgPreambleStr, /* begin varargs */ + clp[CFG_NUM_BUFS].a_current, + LPFC_MIN_NUM_BUFS); /* end varargs */ + clp[CFG_NUM_BUFS].a_current = LPFC_MIN_NUM_BUFS; + } + if (clp[CFG_NUM_BUFS].a_current > LPFC_MAX_NUM_BUFS) { + /* Num-bufs too high, resetting */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0416, /* ptr to msg structure */ + fc_mes0416, /* ptr to msg */ + fc_msgBlk0416.msgPreambleStr, /* begin varargs */ + clp[CFG_NUM_BUFS].a_current, + LPFC_MAX_NUM_BUFS); /* end varargs */ + clp[CFG_NUM_BUFS].a_current = LPFC_MAX_NUM_BUFS; + } + + clp[CFG_FCP_ON].a_current = 1; + clp[CFG_DFT_TGT_Q_DEPTH].a_current = + (uint32)((ulong)fc_get_cfg_param(brd, CFG_DFT_TGT_Q_DEPTH)); + clp[CFG_DFT_LUN_Q_DEPTH].a_current = + (uint32)((ulong)fc_get_cfg_param(brd, CFG_DFT_LUN_Q_DEPTH)); + if (clp[CFG_DFT_TGT_Q_DEPTH].a_current > LPFC_MAX_TGT_Q_DEPTH ) { + /* Target qdepth too high, resetting to max */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0417, /* ptr to msg structure */ + fc_mes0417, /* ptr to msg */ + fc_msgBlk0417.msgPreambleStr, /* begin varargs */ + clp[CFG_DFT_TGT_Q_DEPTH].a_current, + LPFC_MAX_TGT_Q_DEPTH); /* end varargs */ + clp[CFG_DFT_TGT_Q_DEPTH].a_current = LPFC_MAX_TGT_Q_DEPTH; + } + if (clp[CFG_DFT_LUN_Q_DEPTH].a_current > LPFC_MAX_LUN_Q_DEPTH ) { + /* Lun qdepth too high, resetting to max */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0418, /* ptr to msg structure */ + fc_mes0418, /* ptr to msg */ + fc_msgBlk0418.msgPreambleStr, /* begin varargs */ + clp[CFG_DFT_LUN_Q_DEPTH].a_current, + LPFC_MAX_LUN_Q_DEPTH); /* end varargs */ + clp[CFG_DFT_LUN_Q_DEPTH].a_current = LPFC_MAX_LUN_Q_DEPTH; + } + if (clp[CFG_DFT_LUN_Q_DEPTH].a_current == 0 ) { + /* Lun qdepth cannot be , resetting to 1 */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0419, /* ptr to msg structure */ + fc_mes0419, /* ptr to msg */ + fc_msgBlk0419.msgPreambleStr, /* begin varargs */ + clp[CFG_DFT_LUN_Q_DEPTH].a_current ); /* end varargs */ + clp[CFG_DFT_LUN_Q_DEPTH].a_current = 1; + } + + clp[CFG_DQFULL_THROTTLE_UP_TIME].a_current = + (uint32)((ulong)fc_get_cfg_param(brd, CFG_DQFULL_THROTTLE_UP_TIME)); + clp[CFG_DQFULL_THROTTLE_UP_INC].a_current = + (uint32)((ulong)fc_get_cfg_param(brd, CFG_DQFULL_THROTTLE_UP_INC)); + + clp[CFG_FIRST_CHECK].a_current = (uint32)lpfc_first_check; + clp[CFG_FCPFABRIC_TMO].a_current = + (uint32)((ulong)fc_get_cfg_param(brd, CFG_FCPFABRIC_TMO)); + if (clp[CFG_FCPFABRIC_TMO].a_current > LPFC_MAX_FABRIC_TIMEOUT) { + /* Fcpfabric_tmo too high, resetting */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0420, /* ptr to msg structure */ + fc_mes0420, /* ptr to msg */ + fc_msgBlk0420.msgPreambleStr, /* begin varargs */ + clp[CFG_FCPFABRIC_TMO].a_current, + LPFC_MAX_FABRIC_TIMEOUT); /* end varargs */ + clp[CFG_FCPFABRIC_TMO].a_current = LPFC_MAX_FABRIC_TIMEOUT; + } + + clp[CFG_FCP_CLASS].a_current = + (uint32)((ulong)fc_get_cfg_param(brd, CFG_FCP_CLASS)); + switch (clp[CFG_FCP_CLASS].a_current) { + case 2: + clp[CFG_FCP_CLASS].a_current = CLASS2; + break; + case 3: + clp[CFG_FCP_CLASS].a_current = CLASS3; + break; + default: + /* Fcp-class is illegal, resetting to default */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0421, /* ptr to msg structure */ + fc_mes0421, /* ptr to msg */ + fc_msgBlk0421.msgPreambleStr, /* begin varargs */ + clp[CFG_FCP_CLASS].a_current, + CLASS3); /* end varargs */ + clp[CFG_FCP_CLASS].a_current = CLASS3; + break; + } + + clp[CFG_USE_ADISC].a_current = + (uint32)((ulong)fc_get_cfg_param(brd, CFG_USE_ADISC)); + + clp[CFG_NO_DEVICE_DELAY].a_current = + (uint32)((ulong)fc_get_cfg_param(brd, CFG_NO_DEVICE_DELAY)); + if (clp[CFG_NO_DEVICE_DELAY].a_current > LPFC_MAX_NO_DEVICE_DELAY) { + /* No-device-delay too high, resetting to max */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0422, /* ptr to msg structure */ + fc_mes0422, /* ptr to msg */ + fc_msgBlk0422.msgPreambleStr, /* begin varargs */ + clp[CFG_NO_DEVICE_DELAY].a_current, + LPFC_MAX_NO_DEVICE_DELAY); /* end varargs */ + clp[CFG_NO_DEVICE_DELAY].a_current = LPFC_MAX_NO_DEVICE_DELAY; + } + + clp[CFG_NETWORK_ON].a_current = + (uint32)((ulong)fc_get_cfg_param(brd, CFG_NETWORK_ON)); + clp[CFG_POST_IP_BUF].a_current = + (uint32)((ulong)fc_get_cfg_param(brd, CFG_POST_IP_BUF)); + + if (clp[CFG_POST_IP_BUF].a_current < LPFC_MIN_POST_IP_BUF) { + /* Post_ip_buf too low, resetting */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0423, /* ptr to msg structure */ + fc_mes0423, /* ptr to msg */ + fc_msgBlk0423.msgPreambleStr, /* begin varargs */ + clp[CFG_POST_IP_BUF].a_current, + LPFC_MIN_POST_IP_BUF); /* end varargs */ + clp[CFG_POST_IP_BUF].a_current = LPFC_MIN_POST_IP_BUF; + } + if (clp[CFG_POST_IP_BUF].a_current > LPFC_MAX_POST_IP_BUF) { + /* Post_ip_buf too high, resetting */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0424, /* ptr to msg structure */ + fc_mes0424, /* ptr to msg */ + fc_msgBlk0424.msgPreambleStr, /* begin varargs */ + clp[CFG_POST_IP_BUF].a_current, + LPFC_MAX_POST_IP_BUF); /* end varargs */ + clp[CFG_POST_IP_BUF].a_current = LPFC_MAX_POST_IP_BUF; + } + + clp[CFG_XMT_Q_SIZE].a_current = + (uint32)((ulong)fc_get_cfg_param(brd, CFG_XMT_Q_SIZE)); + if (clp[CFG_XMT_Q_SIZE].a_current < LPFC_MIN_XMT_QUE_SIZE) { + /* Xmt-que_size too low, resetting */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0425, /* ptr to msg structure */ + fc_mes0425, /* ptr to msg */ + fc_msgBlk0425.msgPreambleStr, /* begin varargs */ + clp[CFG_XMT_Q_SIZE].a_current, + LPFC_MIN_XMT_QUE_SIZE); /* end varargs */ + clp[CFG_XMT_Q_SIZE].a_current = LPFC_MIN_XMT_QUE_SIZE; + } + if (clp[CFG_XMT_Q_SIZE].a_current > LPFC_MAX_XMT_QUE_SIZE) { + /* Xmt-que_size too high, resetting */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0426, /* ptr to msg structure */ + fc_mes0426, /* ptr to msg */ + fc_msgBlk0426.msgPreambleStr, /* begin varargs */ + clp[CFG_XMT_Q_SIZE].a_current, + LPFC_MAX_XMT_QUE_SIZE); /* end varargs */ + clp[CFG_XMT_Q_SIZE].a_current = LPFC_MAX_XMT_QUE_SIZE; + } + binfo->fc_ring[FC_IP_RING].fc_tx.q_max = clp[CFG_XMT_Q_SIZE].a_current; + + clp[CFG_IP_CLASS].a_current = (uint32)((ulong)fc_get_cfg_param(brd, CFG_IP_CLASS)); + switch (clp[CFG_IP_CLASS].a_current) { + case 2: + clp[CFG_IP_CLASS].a_current = CLASS2; + break; + case 3: + clp[CFG_IP_CLASS].a_current = CLASS3; + break; + default: + /* Ip-class is illegal, resetting */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0427, /* ptr to msg structure */ + fc_mes0427, /* ptr to msg */ + fc_msgBlk0427.msgPreambleStr, /* begin varargs */ + clp[CFG_IP_CLASS].a_current, + CLASS3); /* end varargs */ + clp[CFG_IP_CLASS].a_current = CLASS3; + break; + } + + clp[CFG_ZONE_RSCN].a_current = (uint32)lpfc_zone_rscn; + p_dev_ctl->vendor_flag = (uint32)lpfc_vendor; + + clp[CFG_HOLDIO].a_current = (uint32)((ulong)fc_get_cfg_param(brd, CFG_HOLDIO)); + clp[CFG_ACK0].a_current = (uint32)((ulong)fc_get_cfg_param(brd, CFG_ACK0)); + clp[CFG_TOPOLOGY].a_current = (uint32)((ulong)fc_get_cfg_param(brd, CFG_TOPOLOGY)); + + switch (clp[CFG_TOPOLOGY].a_current) { + case 0: + case 1: + case 2: + case 4: + case 6: + /* topology is a valid choice */ + break; + default: + /* Topology is illegal, resetting */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0428, /* ptr to msg structure */ + fc_mes0428, /* ptr to msg */ + fc_msgBlk0428.msgPreambleStr, /* begin varargs */ + clp[CFG_TOPOLOGY].a_current, + LPFC_DFT_TOPOLOGY); /* end varargs */ + clp[CFG_TOPOLOGY].a_current = LPFC_DFT_TOPOLOGY; + break; + } + + clp[CFG_NODEV_TMO].a_current = + (uint32)((ulong)fc_get_cfg_param(brd, CFG_NODEV_TMO)); + clp[CFG_DELAY_RSP_ERR].a_current = + (uint32)((ulong)fc_get_cfg_param(brd, CFG_DELAY_RSP_ERR)); + clp[CFG_CHK_COND_ERR].a_current = + (uint32)((ulong)fc_get_cfg_param(brd, CFG_CHK_COND_ERR)); + + clp[CFG_LINKDOWN_TMO].a_current = + (uint32)((ulong)fc_get_cfg_param(brd, CFG_LINKDOWN_TMO)); + if (clp[CFG_LINKDOWN_TMO].a_current > LPFC_MAX_LNKDWN_TIMEOUT) { + /* Linkdown_tmo too high, resetting */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0429, /* ptr to msg structure */ + fc_mes0429, /* ptr to msg */ + fc_msgBlk0429.msgPreambleStr, /* begin varargs */ + clp[CFG_LINKDOWN_TMO].a_current, + LPFC_MAX_LNKDWN_TIMEOUT); /* end varargs */ + clp[CFG_LINKDOWN_TMO].a_current = LPFC_MAX_LNKDWN_TIMEOUT; + } + + clp[CFG_LINK_SPEED].a_current = + (uint32)((ulong)fc_get_cfg_param(brd, CFG_LINK_SPEED)); + + p_dev_ctl->ihs.lpfn_mtu = lpfc_mtu; + if((lpfc_mtu % PAGE_SIZE) == 0) + p_dev_ctl->ihs.lpfn_rcv_buf_size = lpfc_mtu; + else { + p_dev_ctl->ihs.lpfn_rcv_buf_size = ((lpfc_mtu + PAGE_SIZE) & (PAGE_MASK)); + p_dev_ctl->ihs.lpfn_rcv_buf_size -= 16; + } + clp[CFG_NUM_NODES].a_current = clp[CFG_NUM_NODES].a_default; + + return(0); +} /* fc_get_dds */ + +/****************************************************************************** +* Function name : fc_bind_wwpn +* +******************************************************************************/ +_local_ int fc_bind_wwpn(fc_dev_ctl_t *p_dev_ctl, + char **arrayp, + u_int cnt) +{ + uchar *datap, *np; + NODELIST *nlp; + nodeh_t *hp; + NAME_TYPE pn; + int i, dev_index, entry, lpfc_num, rstatus; + unsigned int sum; + + FC_BRD_INFO * binfo = &BINFO; + + p_dev_ctl->fcp_mapping = FCP_SEED_WWPN; + np = (uchar *)&pn; + + for(entry = 0; entry < cnt; entry++) { + datap = (uchar *)arrayp[entry]; + if(datap == 0) + break; + /* Determined the number of ASC hex chars in WWNN & WWPN */ + for( i = 0; i < FC_MAX_WW_NN_PN_STRING; i++) { + if( fc_asc_to_hex( datap[i]) < 0) + break; + } + if((rstatus = fc_parse_binding_entry( p_dev_ctl, datap, np, + i, sizeof( NAME_TYPE), + FC_BIND_WW_NN_PN, &sum, entry, &lpfc_num)) > 0) { + if( rstatus == FC_SYNTAX_OK_BUT_NOT_THIS_BRD) + continue; + + /* WWPN binding entry : Syntax error code */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0430, /* ptr to msg structure */ + fc_mes0430, /* ptr to msg */ + fc_msgBlk0430.msgPreambleStr, /* begin varargs */ + entry, + rstatus); /* end varargs */ + goto out; + } + + /* Loop through all NODELIST entries and find + * the next available entry. + */ + if((nlp = (NODELIST *)fc_mem_get(binfo, MEM_NLP)) == 0) { + /* WWPN binding entry: node table full */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0432, /* ptr to msg structure */ + fc_mes0432, /* ptr to msg */ + fc_msgBlk0432.msgPreambleStr); /* begin & end varargs */ + goto out; + } + fc_bzero((void *)nlp, sizeof(NODELIST)); + nlp->sync = binfo->fc_sync; + nlp->capabilities = binfo->fc_capabilities; + + nlp->nlp_state = NLP_SEED; + nlp->nlp_type = NLP_SEED_WWPN | NLP_FCP_TARGET; + + nlp->id.nlp_sid = DEV_SID(sum); + nlp->id.nlp_pan = DEV_PAN(sum); + bcopy((uchar * )&pn, &nlp->nlp_portname, sizeof(NAME_TYPE)); + + dev_index = INDEX(nlp->id.nlp_pan, nlp->id.nlp_sid); + hp = &binfo->device_queue_hash[dev_index]; + + /* Claim SCSI ID by copying bind parameter to + * proper index in device_queue_hash. + */ + bcopy(&nlp->nlp_portname, &hp->un.dev_portname, sizeof(NAME_TYPE)); + hp->node_flag = FCP_SEED_WWPN; + + fc_nlp_bind(binfo, nlp); + + out: + np = (uchar *)&pn; + } + return (0); +} /* fc_bind_wwpn */ + +/****************************************************************************** +* Function name : fc_bind_wwnn +* +* Description : p_dev_ctl, pointer to the device control area +* +******************************************************************************/ +_local_ int fc_bind_wwnn(fc_dev_ctl_t *p_dev_ctl, + char **arrayp, + u_int cnt) +{ + uchar *datap, *np; + NODELIST *nlp; + nodeh_t *hp; + NAME_TYPE pn; + int i, dev_index, entry, lpfc_num, rstatus; + unsigned int sum; + + FC_BRD_INFO * binfo = &BINFO; + + p_dev_ctl->fcp_mapping = FCP_SEED_WWNN; + np = (uchar *)&pn; + + for(entry = 0; entry < cnt; entry++) { + datap = (uchar *)arrayp[entry]; + if(datap == 0) + break; + /* Determined the number of ASC hex chars in WWNN & WWPN */ + for( i = 0; i < FC_MAX_WW_NN_PN_STRING; i++) { + if( fc_asc_to_hex( datap[i]) < 0) + break; + } + if((rstatus = fc_parse_binding_entry( p_dev_ctl, datap, np, + i, sizeof( NAME_TYPE), + FC_BIND_WW_NN_PN, &sum, entry, &lpfc_num)) > 0) { + if( rstatus == FC_SYNTAX_OK_BUT_NOT_THIS_BRD) + continue; + + /* WWNN binding entry : Syntax error code */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0431, /* ptr to msg structure */ + fc_mes0431, /* ptr to msg */ + fc_msgBlk0431.msgPreambleStr, /* begin varargs */ + entry, + rstatus); /* end varargs */ + goto out; + } + + /* Loop through all NODELIST entries and find + * the next available entry. + */ + if((nlp = (NODELIST *)fc_mem_get(binfo, MEM_NLP)) == 0) { + /* WWNN binding entry: node table full */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0433, /* ptr to msg structure */ + fc_mes0433, /* ptr to msg */ + fc_msgBlk0433.msgPreambleStr); /* begin & end varargs */ + goto out; + } + fc_bzero((void *)nlp, sizeof(NODELIST)); + nlp->sync = binfo->fc_sync; + nlp->capabilities = binfo->fc_capabilities; + + nlp->nlp_state = NLP_SEED; + nlp->nlp_type = NLP_SEED_WWNN | NLP_FCP_TARGET; + nlp->id.nlp_sid = DEV_SID(sum); + nlp->id.nlp_pan = DEV_PAN(sum); + bcopy((uchar * )&pn, &nlp->nlp_nodename, sizeof(NAME_TYPE)); + + dev_index = INDEX(nlp->id.nlp_pan, nlp->id.nlp_sid); + hp = &binfo->device_queue_hash[dev_index]; + + /* Claim SCSI ID by copying bind parameter to + * proper index in device_queue_hash. + */ + bcopy(&nlp->nlp_nodename, &hp->un.dev_nodename, sizeof(NAME_TYPE)); + hp->node_flag = FCP_SEED_WWNN; + + fc_nlp_bind(binfo, nlp); + + out: + np = (uchar *)&pn; + } /* for loop */ + return (0); +} /* fc_bind_wwnn */ + +/****************************************************************************** +* Function name : fc_bind_did +* +* Description : p_dev_ctl, pointer to the device control area +* +******************************************************************************/ +_local_ int fc_bind_did(fc_dev_ctl_t *p_dev_ctl, + char **arrayp, + u_int cnt) +{ + uchar *datap, *np; + NODELIST *nlp; + nodeh_t *hp; + FC_BRD_INFO *binfo = &BINFO; + D_ID ndid; + int i, dev_index, entry, lpfc_num, rstatus; + unsigned int sum; + + p_dev_ctl->fcp_mapping = FCP_SEED_DID; + ndid.un.word = 0; + np = (uchar *)&ndid.un.word; + + for(entry = 0; entry < cnt; entry++) { + datap = (uchar *)arrayp[entry]; + if(datap == 0) + break; + /* Determined the number of ASC hex chars in DID */ + for( i = 0; i < FC_MAX_DID_STRING; i++) { + if( fc_asc_to_hex( datap[i]) < 0) + break; + } + if((rstatus = fc_parse_binding_entry( p_dev_ctl, datap, np, + i, sizeof(D_ID), + FC_BIND_DID, &sum, entry, &lpfc_num)) > 0) { + if( rstatus == FC_SYNTAX_OK_BUT_NOT_THIS_BRD) + continue; + + /* DID binding entry : Syntax error code */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0434, /* ptr to msg structure */ + fc_mes0434, /* ptr to msg */ + fc_msgBlk0434.msgPreambleStr, /* begin varargs */ + entry, + rstatus); /* end varargs */ + goto out; + } + + /* Loop through all NODELIST entries and find + * the next available entry. + */ + if((nlp = (NODELIST *)fc_mem_get(binfo, MEM_NLP)) == 0) { + /* DID binding entry: node table full */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0435, /* ptr to msg structure */ + fc_mes0435, /* ptr to msg */ + fc_msgBlk0435.msgPreambleStr); /* begin & end varargs */ + goto out; + } + fc_bzero((void *)nlp, sizeof(NODELIST)); + nlp->sync = binfo->fc_sync; + nlp->capabilities = binfo->fc_capabilities; + + nlp->nlp_state = NLP_SEED; + nlp->nlp_type = NLP_SEED_DID | NLP_FCP_TARGET; + nlp->id.nlp_sid = DEV_SID(sum); + nlp->id.nlp_pan = DEV_PAN(sum); + nlp->nlp_DID = SWAP_DATA(ndid.un.word); + + dev_index = INDEX(nlp->id.nlp_pan, nlp->id.nlp_sid); + hp = &binfo->device_queue_hash[dev_index]; + + /* Claim SCSI ID by copying bind parameter to + * proper index in device_queue_hash. + */ + hp->un.dev_did = nlp->nlp_DID; + hp->node_flag = FCP_SEED_DID; + + fc_nlp_bind(binfo, nlp); + + out: + + np = (uchar *)&ndid.un.word; + } + return (0); +} + +/****************************************************************************** +* Function name : fc_bufmap +* +* Description : Maps in the specified chunk of memory, bp + len, and returns +* the number of mapped segments in the scatter list. Upon return +* phys will point to a list of physical addresses and cnt will +* point to a corresponding list of sizes. Handle will point to a +* dma handle for the I/O, if needed. +* This routine is only called by the IP portion of the driver to +* get a scatter / gather list for a specific IP packet before +* starting the I/O. +******************************************************************************/ +int fc_bufmap(fc_dev_ctl_t *p_dev_ctl, + uchar *bp, + uint32 len, + void **phys, + uint32 *cnt, + void **handle) +{ + MBUF_INFO * buf_info; + MBUF_INFO bufinfo; + + buf_info = &bufinfo; + *handle = 0; + buf_info->phys = (void *)((ulong)INVALID_PHYS); + buf_info->virt = bp; + buf_info->size = len; + buf_info->flags = (FC_MBUF_PHYSONLY | FC_MBUF_DMA); + fc_malloc(p_dev_ctl, buf_info); + + if(is_invalid_phys(buf_info->phys)) + return(0); + + phys[0] = (void *) buf_info->phys; + cnt[0] = (uint32) len; + return(1); +} + +/****************************************************************************** +* Function name : fc_bufunmap +* +* Description : This is called to unmap a piece of memory, mapped by fc_bufmap, +* and to free the asociated DMA handle, if needed. +******************************************************************************/ +void fc_bufunmap(fc_dev_ctl_t *p_dev_ctl, + uchar *addr, + uchar *dmahandle, + uint32 len) +{ + MBUF_INFO * buf_info; + MBUF_INFO bufinfo; + + buf_info = &bufinfo; + buf_info->phys = (uint32 * )addr; + buf_info->flags = (FC_MBUF_PHYSONLY | FC_MBUF_DMA); + buf_info->size = len; + fc_free(p_dev_ctl, buf_info); +} + +/****************************************************************************** +* Function name : lpfc_scsi_selto_timeout +* +* Description : call back function for scsi timeout +******************************************************************************/ +void lpfc_scsi_selto_timeout(fc_dev_ctl_t *p_dev_ctl, + void *l1, + void *l2) +{ + struct buf *bp; + + bp = (struct buf *)l1; + /* Set any necessary flags for buf error */ + if((bp->b_error != EBUSY) && (bp->b_error != EINVAL)) + bp->b_error = EIO; + bp->b_flags |= B_ERROR; + fc_do_iodone(bp); +} + +/****************************************************************************** +* Function name : lpfc_copy_sense +* +* Description : call back function for scsi timeout +******************************************************************************/ +int lpfc_copy_sense(dvi_t * dev_ptr, + struct buf * bp) +{ + struct scsi_cmnd *cmnd; + int sense_cnt; + + cmnd = bp->cmnd; + if (dev_ptr->sense_length > SCSI_SENSE_BUFFERSIZE) { + sense_cnt = SCSI_SENSE_BUFFERSIZE; + } + else { + sense_cnt = dev_ptr->sense_length; + } + /* Copy sense data into SCSI buffer */ + bcopy(dev_ptr->sense, cmnd->sense_buffer, sense_cnt); + dev_ptr->sense_valid = 0; + return(0); +} + +/****************************************************************************** +* Function name : get_cmd_off_txq +* +* Description : +* +******************************************************************************/ +IOCBQ *get_cmd_off_txq(fc_dev_ctl_t *p_dev_ctl, + ushort iotag) +{ + FC_BRD_INFO * binfo = &BINFO; + IOCBQ * iocbq, *save; + RING * rp; + unsigned long iflag; + + iflag = lpfc_q_disable_lock(p_dev_ctl); + rp = &binfo->fc_ring[FC_FCP_RING]; + iocbq = (IOCBQ * )(rp->fc_tx.q_first); + save = 0; + while (iocbq) { + if(iocbq->iocb.ulpIoTag == iotag) { + if(save) + save->q = iocbq->q; + else + rp->fc_tx.q_first = (uchar *)iocbq->q; + + if(rp->fc_tx.q_last == (uchar *)iocbq) + rp->fc_tx.q_last = (uchar *)save; + + rp->fc_tx.q_cnt--; + lpfc_q_unlock_enable(p_dev_ctl, iflag); + return iocbq; + } + save = iocbq; + iocbq = (IOCBQ * )iocbq->q; + } + + lpfc_q_unlock_enable(p_dev_ctl, iflag); + return 0; +} + +/****************************************************************************** +* Function name : find_cmd_in_txpq +* +* Description : +* +******************************************************************************/ +int find_cmd_in_txpq(fc_dev_ctl_t *p_dev_ctl, + struct scsi_cmnd *cmnd) +{ + FC_BRD_INFO * binfo = &BINFO; + struct fc_buf *fcptr, *savefc; + dvi_t * dev_ptr; + IOCBQ *iocb_cmd, *iocb_cn_cmd; + struct buf *bp; + RING * rp; + struct sc_buf *sp; + int abort_stat; + unsigned long iflag; + + iflag = lpfc_q_disable_lock(p_dev_ctl); + rp = &binfo->fc_ring[FC_FCP_RING]; + fcptr = (struct fc_buf *)(rp->fc_txp.q_first); + savefc = 0; + while (fcptr) { + if(((struct buf *)(fcptr->sc_bufp))->cmnd == cmnd) { + dev_ptr = fcptr->dev_ptr; + lpfc_q_unlock_enable(p_dev_ctl, iflag); + iocb_cmd = get_cmd_off_txq(p_dev_ctl, fcptr->iotag); + iflag = lpfc_q_disable_lock(p_dev_ctl); + if (iocb_cmd) { + fc_mem_put(binfo, MEM_IOCB, (uchar * )iocb_cmd); + + lpfc_q_unlock_enable(p_dev_ctl, iflag); + while ((iocb_cn_cmd = get_cmd_off_txq(p_dev_ctl, fcptr->iotag))) { + fc_mem_put(binfo, MEM_IOCB, (uchar * )iocb_cn_cmd); + } + iflag = lpfc_q_disable_lock(p_dev_ctl); + + bp = (struct buf *)fcptr->sc_bufp; + bp->b_error = ETIMEDOUT; + bp->b_flags |= B_ERROR; + lpfc_q_unlock_enable(p_dev_ctl, iflag); + fc_do_iodone(bp); + iflag = lpfc_q_disable_lock(p_dev_ctl); + + if(savefc) { + savefc->fc_fwd = fcptr->fc_fwd; + if (fcptr->fc_fwd) + fcptr->fc_fwd->fc_bkwd = savefc; + } else { + rp->fc_txp.q_first = (uchar *)(fcptr->fc_fwd); + if (fcptr->fc_fwd) + fcptr->fc_fwd->fc_bkwd = 0; + } + + if(rp->fc_txp.q_last == (uchar *)fcptr) { + rp->fc_txp.q_last = (uchar *)savefc; + } + + rp->fc_txp.q_cnt--; + lpfc_q_unlock_enable(p_dev_ctl, iflag); + fc_enq_fcbuf(fcptr); + iflag = lpfc_q_disable_lock(p_dev_ctl); + dev_ptr->active_io_count--; + if (dev_ptr->nodep) + dev_ptr->nodep->num_active_io--; + else + panic ("abort in txp: dev_ptr->nodep is NULL\n"); + } else { + sp = (struct sc_buf *)(fcptr->sc_bufp); + sp->cmd_flag |= FLAG_ABORT; + lpfc_q_unlock_enable(p_dev_ctl, iflag); + abort_stat = fc_abort_xri(binfo, fcptr->dev_ptr, + fcptr->iotag, ABORT_TYPE_ABTS); + iflag = lpfc_q_disable_lock(p_dev_ctl); + } + lpfc_q_unlock_enable(p_dev_ctl, iflag); + return 1; + } else { + savefc = fcptr; + fcptr = (struct fc_buf *)fcptr->fc_fwd; + } + } + lpfc_q_unlock_enable(p_dev_ctl, iflag); + return 0; +} + +/****************************************************************************** +* Function name : find_cmd_in_tmolist +* +* Description : +* +******************************************************************************/ +int find_cmd_in_tmolist(fc_dev_ctl_t *p_dev_ctl, + struct scsi_cmnd *cmnd) +{ + struct buf *bp, *savebp; + + savebp = 0; + for (bp = p_dev_ctl->timeout_head; bp != NULL; ) { + if (bp->cmnd == cmnd) { + if(savebp) + savebp->av_forw = bp->av_forw; + else + p_dev_ctl->timeout_head = bp->av_forw; + + p_dev_ctl->timeout_count--; + bp->b_error = ETIMEDOUT; + bp->b_flags |= B_ERROR; + fc_do_iodone(bp); + return 1; + } else { + savebp = bp; + bp = bp->av_forw; + } + } + + return 0; +} + +/****************************************************************************** +* Function name : find_cmd_in_pendlist +* +* Description : +* +******************************************************************************/ +int find_cmd_in_pendlist(dvi_t *dev_ptr, + struct scsi_cmnd *cmnd) +{ + struct buf *bp, *savebp; + node_t * nodep; + + bp = (struct buf *)dev_ptr->pend_head; + savebp = 0; + while (bp) { + if (bp->cmnd == cmnd) { + nodep = dev_ptr->nodep; + if(savebp) + savebp->av_forw = bp->av_forw; + else + dev_ptr->pend_head = (struct sc_buf *)(bp->av_forw); + + if (dev_ptr->pend_tail == (struct sc_buf *)bp) + dev_ptr->pend_tail = (struct sc_buf *)savebp; + + dev_ptr->pend_count--; + bp->b_error = ETIMEDOUT; + bp->b_flags |= B_ERROR; + fc_do_iodone(bp); + return 1; + } else { + savebp = bp; + bp = bp->av_forw; + } + } + + return 0; +} + +/****************************************************************************** +* Function name : lpfc_find_cmd +* +* Description : +* +******************************************************************************/ +_local_ int lpfc_find_cmd(fc_dev_ctl_t *p_dev_ctl, + struct scsi_cmnd *cmnd) +{ + dvi_t * dev_ptr; + struct sc_buf * sp; + + sp = (struct sc_buf *)cmnd->host_scribble; + if(sp == 0) + return 1; + dev_ptr = sp->current_devp; + if(dev_ptr) { + if (find_cmd_in_pendlist(dev_ptr, cmnd)) + goto err1; + } + + if (find_cmd_in_txpq(p_dev_ctl, cmnd)) + goto err1; + if (find_cmd_in_tmolist(p_dev_ctl, cmnd)) + goto err1; + + return 0; + +err1: + return 1; +} + +/****************************************************************************** +* Function name : lpfc_nodev +* +* Description : +* +******************************************************************************/ +void lpfc_nodev(unsigned long l) +{ + return; +} + +/****************************************************************************** +* Function name : lpfc_scsi_add_timer +* +* Description : Copied from scsi_add_timer +******************************************************************************/ +void lpfc_scsi_add_timer(struct scsi_cmnd * SCset, + int timeout) +{ + + if( SCset->eh_timeout.function != NULL ) + { + del_timer(&SCset->eh_timeout); + } + + if(SCset->eh_timeout.data != (unsigned long) SCset) { + SCset->eh_timeout.data = (unsigned long) SCset; + SCset->eh_timeout.function = (void (*)(unsigned long))lpfc_nodev; + } + SCset->eh_timeout.expires = jiffies + timeout; + + add_timer(&SCset->eh_timeout); +} + +/****************************************************************************** +* Function name : lpfc_scsi_delete_timer() +* +* Purpose: Delete/cancel timer for a given function. +* Copied from scsi_delete_timer() +* +* Arguments: SCset - command that we are canceling timer for. +* +* Returns: Amount of time remaining before command would have timed out. +******************************************************************************/ +int lpfc_scsi_delete_timer(struct scsi_cmnd * SCset) +{ + int rtn; + + rtn = jiffies - SCset->eh_timeout.expires; + del_timer(&SCset->eh_timeout); + SCset->eh_timeout.data = (unsigned long) NULL; + SCset->eh_timeout.function = NULL; + return rtn; +} + +/****************************************************************************** +* Function name : fc_device_changed +* +* Description : +* +******************************************************************************/ +int fc_device_changed(fc_dev_ctl_t *p_dev_ctl, + struct dev_info *dev_ptr) +{ + struct scsi_device *sd; + + if(lpfc_use_removable) { + sd = (struct scsi_device *)dev_ptr->scsi_dev; + if(sd) { +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) + sd->changed = 0; + sd->removable = 0; +#else + sd->online = 1; +#endif + } + } + return(0); +} +/****************************************************************************** +* Function name : fc_bcopy +* +* Description : +* +******************************************************************************/ +void fc_bcopy(void *from, + void *to, + ulong cnt) +{ + bcopy(from, to, cnt); +} + +/****************************************************************************** +* Function name : fc_bzero +* +* Description : +* +******************************************************************************/ +void fc_bzero(void *from, + ulong cnt) +{ + memset(from,0,(size_t)cnt); +} + +/****************************************************************************** +* Function name : fc_copyout +* +* Description : +* +******************************************************************************/ +int fc_copyout(uchar *from, + uchar *to, + ulong cnt) +{ + return(copyout(from, to, cnt)); +} + +/****************************************************************************** +* Function name : fc_copyin +* +* Description : +* +******************************************************************************/ +int fc_copyin(uchar *from, + uchar *to, + ulong cnt) +{ + return(copyin(from, to, cnt)); +} + +/****************************************************************************** +* Function name : lpfc_mpdata_sync +* +* Description : +* +******************************************************************************/ +void lpfc_mpdata_sync(fc_dev_ctl_t *p_dev_ctl, + void *h, + int a, + int b, + int c) +{ +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) + if(c == 1) + c = PCI_DMA_FROMDEVICE; + else + c = PCI_DMA_TODEVICE; + if(b) + fc_pci_dma_sync_single(p_dev_ctl->pcidev, (dma_addr_t)((ulong)h), b, c); + else + fc_pci_dma_sync_single(p_dev_ctl->pcidev, (dma_addr_t)((ulong)h), 4096, c); +#endif +} + +/****************************************************************************** +* Function name : lpfc_ip_rcvsz +* +* Description : +* +******************************************************************************/ +int lpfc_ip_rcvsz(fc_dev_ctl_t *p_dev_ctl) +{ + return(p_dev_ctl->ihs.lpfn_rcv_buf_size); +} + +/****************************************************************************** +* Function name : fc_dpc_lstchk +* +* Description : Since abort, device reset, bus reset, and host reset dpc lists +* all use SCp.ptr for linking, double check to make sure +* LINUX doesn't use the same Cmnd for multiple resets / aborts. +* +* XXX patman check that this still works +******************************************************************************/ +int fc_dpc_lstchk(fc_dev_ctl_t * p_dev_ctl, + struct scsi_cmnd * Cmnd) +{ + struct scsi_cmnd * aCmnd; + struct scsi_cmnd * bCmnd; + + aCmnd = (struct scsi_cmnd *)p_dev_ctl->abort_head; + bCmnd = 0; + while(aCmnd) { + /* Check for duplicate on abort list */ + if(aCmnd == Cmnd) { + if(bCmnd == 0) { + p_dev_ctl->abort_head = (void *)SCMD_NEXT(Cmnd); + } + else { + SCMD_NEXT(bCmnd) = SCMD_NEXT(Cmnd); + } + if(Cmnd == (struct scsi_cmnd *)p_dev_ctl->abort_list) + p_dev_ctl->abort_list = (void *)bCmnd; + SCMD_NEXT(Cmnd) = 0; + return(1); + } + bCmnd = aCmnd; + aCmnd = SCMD_NEXT(aCmnd); + } + aCmnd = (struct scsi_cmnd *)p_dev_ctl->rdev_head; + bCmnd = 0; + while(aCmnd) { + /* Check for duplicate on device reset list */ + if(aCmnd == Cmnd) { + if(bCmnd == 0) { + p_dev_ctl->rdev_head = (void *)SCMD_NEXT(Cmnd); + } + else { + SCMD_NEXT(bCmnd) = SCMD_NEXT(Cmnd); + } + if(Cmnd == (struct scsi_cmnd *)p_dev_ctl->rdev_list) + p_dev_ctl->rdev_list = (void *)bCmnd; + SCMD_NEXT(Cmnd) = 0; + return(2); + } + bCmnd = aCmnd; + aCmnd = SCMD_NEXT(aCmnd); + } + aCmnd = (struct scsi_cmnd *)p_dev_ctl->rbus_head; + bCmnd = 0; + while(aCmnd) { + /* Check for duplicate on bus reset list */ + if(aCmnd == Cmnd) { + if(bCmnd == 0) { + p_dev_ctl->rbus_head = (void *)SCMD_NEXT(Cmnd); + } + else { + SCMD_NEXT(bCmnd) = SCMD_NEXT(Cmnd); + } + if(Cmnd == (struct scsi_cmnd *)p_dev_ctl->rbus_list) + p_dev_ctl->rbus_list = (void *)bCmnd; + SCMD_NEXT(Cmnd) = 0; + return(3); + } + bCmnd = aCmnd; + aCmnd = SCMD_NEXT(aCmnd); + } + aCmnd = (struct scsi_cmnd *)p_dev_ctl->rhst_head; + bCmnd = 0; + while(aCmnd) { + /* Check for duplicate on host reset list */ + if(aCmnd == Cmnd) { + if(bCmnd == 0) { + p_dev_ctl->rhst_head = (void *)SCMD_NEXT(Cmnd); + } + else { + SCMD_NEXT(bCmnd) = SCMD_NEXT(Cmnd); + } + if(Cmnd == (struct scsi_cmnd *)p_dev_ctl->rhst_list) + p_dev_ctl->rhst_list = (void *)bCmnd; + SCMD_NEXT(Cmnd) = 0; + return(4); + } + bCmnd = aCmnd; + aCmnd = SCMD_NEXT(aCmnd); + } + return(0); +} + +/****************************************************************************** +* Function name : fc_timer +* +* Description : This function will be called by the driver every second. +******************************************************************************/ +_static_ void lpfc_timer(void *p) +{ + fc_dev_ctl_t * p_dev_ctl; + FCCLOCK_INFO * clock_info; + ulong tix; + FCCLOCK * x; + int ipri; + + clock_info = &DD_CTL.fc_clock_info; + ipri = disable_lock(CLK_LVL, &CLOCK_LOCK); + + /* + *** Increment time_sample value + */ + clock_info->ticks++; + + x = clock_info->fc_clkhdr.cl_f; + + /* counter for propagating negative values */ + tix = 0; + /* If there are expired clocks */ + if (x != (FCCLOCK * ) & clock_info->fc_clkhdr) { + x->cl_tix = x->cl_tix - 1; + if (x->cl_tix <= 0) { + /* Loop thru all clock blocks */ + while (x != (FCCLOCK * ) & clock_info->fc_clkhdr) { + x->cl_tix += tix; + /* If # of ticks left > 0, break out of loop */ + if (x->cl_tix > 0) + break; + tix = x->cl_tix; + + fc_deque(x); + /* Decrement count of unexpired clocks */ + clock_info->fc_clkhdr.count--; + + unlock_enable(ipri, &CLOCK_LOCK); + + p_dev_ctl = x->cl_p_dev_ctl; + + if(p_dev_ctl) { + /* Queue clock blk to appropriate dpc to be processed */ + if(p_dev_ctl->qclk_head == NULL) { + p_dev_ctl->qclk_head = (void *)x; + p_dev_ctl->qclk_list = (void *)x; + } else { + ((FCCLOCK *)(p_dev_ctl->qclk_list))->cl_fw = x; + p_dev_ctl->qclk_list = (void *)x; + } + x->cl_fw = NULL; + } + else { + /* Call timeout routine */ + (*x->cl_func) (p_dev_ctl, x->cl_arg1, x->cl_arg2); + /* Release clock block */ + fc_clkrelb(p_dev_ctl, x); + } + + ipri = disable_lock(CLK_LVL, &CLOCK_LOCK); + + x = clock_info->fc_clkhdr.cl_f; + } + } + } + unlock_enable(ipri, &CLOCK_LOCK); + fc_reset_timer(); +} + +/****************************************************************************** +* Function name : do_fc_timer +* +* Description : +* +******************************************************************************/ +int do_fc_timer(fc_dev_ctl_t *p_dev_ctl) +{ + FCCLOCK *x; + FCCLOCK *cb; + + cb = (FCCLOCK *)p_dev_ctl->qclk_head; + while(cb) { + x = cb; + cb = cb->cl_fw; + /* Call timeout routine */ + (*x->cl_func) (p_dev_ctl, x->cl_arg1, x->cl_arg2); + /* Release clock block */ + fc_clkrelb(p_dev_ctl, x); + } + p_dev_ctl->qclk_head = 0; + p_dev_ctl->qclk_list = 0; + return(0); +} + +/****************************************************************************** +* Function name : lpfc_kmalloc +* +* Description : +* +******************************************************************************/ +void * lpfc_kmalloc(unsigned int size, + unsigned int type, + void **pphys, + fc_dev_ctl_t *p_dev_ctl) +{ + FC_BRD_INFO * binfo; + void * pcidev; + void * virt; + struct fc_mem_pool * fmp; + dma_addr_t phys; + int i, instance; + +/* printk("lpfc_kmalloc: %d %d %lx %lx\n", size, type, pphys, p_dev_ctl); +*/ + if(pphys == 0) { + virt = (void *)kmalloc(size, type); + return(virt); + } + if(p_dev_ctl == 0) { + /* lpfc_kmalloc: Bad p_dev_ctl */ + fc_log_printf_msg_vargs( 0, /* force brd 0, no p_dev_ctl */ + &fc_msgBlk1201, /* ptr to msg structure */ + fc_mes1201, /* ptr to msg */ + fc_msgBlk1201.msgPreambleStr, /* begin varargs */ + size, + type, + fc_idx_dmapool[0]); /* end varargs */ + return(0); + } + instance = p_dev_ctl->info.fc_brd_no; + pcidev = p_dev_ctl->pcidev; + binfo = &BINFO; + + if(size > FC_MAX_SEGSZ) { + /* lpfc_kmalloc: Bad size */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk1202, /* ptr to msg structure */ + fc_mes1202, /* ptr to msg */ + fc_msgBlk1202.msgPreambleStr, /* begin varargs */ + size, + type, + fc_idx_dmapool[instance]); /* end varargs */ + return(0); + } +top: + fmp = fc_mem_dmapool[instance]; + for(i=0;i<=fc_idx_dmapool[instance];i++) { + fmp = (fc_mem_dmapool[instance] + i); + if((fmp->p_virt == 0) || (fmp->p_left >= size)) + break; + } + if(i == (fc_size_dmapool[instance] - 2)) { + /* Lets make it bigger */ + fc_size_dmapool[instance] += FC_MAX_POOL; + fmp = kmalloc((sizeof(struct fc_mem_pool) * fc_size_dmapool[instance]), + GFP_ATOMIC); + if(fmp) { + fc_bzero((void *)fmp, + (sizeof(struct fc_mem_pool) * fc_size_dmapool[instance])); + fc_bcopy((void *)fc_mem_dmapool[instance], fmp, + (sizeof(struct fc_mem_pool) * (fc_size_dmapool[instance]-FC_MAX_POOL))); + kfree(fc_mem_dmapool[instance]); + fc_mem_dmapool[instance] = fmp; + goto top; + } + goto out; + } + + if(fmp->p_virt == 0) { + virt = pci_alloc_consistent(pcidev, FC_MAX_SEGSZ, &phys); + if(virt) { + fmp->p_phys = (void *)((ulong)phys); + fmp->p_virt = virt; + fmp->p_refcnt = 0; + fmp->p_left = (ushort)FC_MAX_SEGSZ; + if(i == fc_idx_dmapool[instance]) + if(i < (fc_size_dmapool[instance] - 2)) + fc_idx_dmapool[instance]++; + } + else { + /* lpfc_kmalloc: Bad virtual addr */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk1204, /* ptr to msg structure */ + fc_mes1204, /* ptr to msg */ + fc_msgBlk1204.msgPreambleStr, /* begin varargs */ + i, + size, + type, + fc_idx_dmapool[instance]); /* end varargs */ + return(0); + } + } + + if(fmp->p_left >= size) { + fmp->p_refcnt++; + virt = (void *)((uchar *)fmp->p_virt + FC_MAX_SEGSZ - fmp->p_left); + phys = (dma_addr_t)(ulong)((uchar *)fmp->p_phys + FC_MAX_SEGSZ - fmp->p_left); + *pphys = (void *)((ulong)phys); + fmp->p_left -= size; + return(virt); + } +out: + /* lpfc_kmalloc: dmapool FULL */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk1205, /* ptr to msg structure */ + fc_mes1205, /* ptr to msg */ + fc_msgBlk1205.msgPreambleStr, /* begin varargs */ + i, + size, + type, + fc_idx_dmapool[instance]); /* end varargs */ + return(0); +} + +/****************************************************************************** +* Function name : lpfc_kfree +* +* Description : +* +******************************************************************************/ +void lpfc_kfree(unsigned int size, + void *virt, + void *phys, + fc_dev_ctl_t *p_dev_ctl) +{ + FC_BRD_INFO * binfo; + struct fc_mem_pool * fmp; + void * pcidev; + int i, instance; + + if(is_invalid_phys(phys)) { + kfree(virt); + return; + } + + if(p_dev_ctl == 0) { + /* lpfc_kfree: Bad p_dev_ctl */ + fc_log_printf_msg_vargs( 0, /* force brd 0, no p_dev_ctl */ + &fc_msgBlk1206, /* ptr to msg structure */ + fc_mes1206, /* ptr to msg */ + fc_msgBlk1206.msgPreambleStr, /* begin varargs */ + size, + fc_idx_dmapool[0]); /* end varargs */ + return; + } + + instance = p_dev_ctl->info.fc_brd_no; + pcidev = p_dev_ctl->pcidev; + binfo = &BINFO; + + + for(i=0;i= fmp->p_virt) && + (virt < (void *)((uchar *)fmp->p_virt + FC_MAX_SEGSZ))) { + fmp->p_refcnt--; + if(fmp->p_refcnt == 0) { + pci_free_consistent(pcidev, FC_MAX_SEGSZ, + fmp->p_virt, (dma_addr_t)((ulong)fmp->p_phys)); + fc_bzero((void *)fmp, sizeof(struct fc_mem_pool)); + } + return; + } + } + /* lpfc_kfree: NOT in dmapool */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk1207, /* ptr to msg structure */ + fc_mes1207, /* ptr to msg */ + fc_msgBlk1207.msgPreambleStr, /* begin varargs */ + (uint32)((ulong)virt), + size, + fc_idx_dmapool[instance]); /* end varargs */ + return; +} /* lpfc_kfree */ + +MODULE_LICENSE("GPL"); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/fcLINUXlan.c 830-ivtv/drivers/scsi/lpfc/fcLINUXlan.c --- 000-virgin/drivers/scsi/lpfc/fcLINUXlan.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/fcLINUXlan.c Thu Jan 8 10:21:53 2004 @@ -0,0 +1,376 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Enterprise Fibre Channel Host Bus Adapters. * + * Refer to the README file included with this package for * + * driver version and adapter support. * + * Copyright (C) 2003 Emulex Corporation. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details, a copy of which * + * can be found in the file COPYING included with this package. * + *******************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4) +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,17) +#include +#else +#include +#endif +#include +#include +#include + +#ifdef MODULE +#include +#include "lpfc.ver" +#else +extern int lpfn_probe(void); +#endif /* MODULE */ + +/* fcLINUXlan.c IP interface network driver */ +#include "fc_os.h" +#include "fc_hw.h" +#include "fc.h" + +static int lpfn_xmit(struct sk_buff *skb, NETDEVICE *dev); +static struct enet_statistics *lpfn_get_stats(NETDEVICE *dev); + +extern int arp_find(unsigned char *haddr, struct sk_buff *skb); +extern int lpfc_xmit(fc_dev_ctl_t *p_dev_ctl, struct sk_buff *skb); +extern int lpfc_ioctl(int cmd, void *s); + +/****************************************************************************** +* Function name : lpfn_open +* +* Description : +* +******************************************************************************/ +static int lpfn_open(NETDEVICE *dev) +{ + fc_dev_ctl_t *p_dev_ctl; + FC_BRD_INFO * binfo; + + if((p_dev_ctl = (fc_dev_ctl_t *)(dev->priv)) == 0) + return(-ENODEV); + binfo = &BINFO; + p_dev_ctl->device_state = OPENED; + binfo->fc_open_count |= FC_LAN_OPEN; + + netdevice_start(dev); + netif_start_queue(dev); +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif /* MODULE */ + return 0; +} + +/****************************************************************************** +* Function name : lpfn_close +* +* Description : +* +******************************************************************************/ +static int lpfn_close(NETDEVICE *dev) +{ + fc_dev_ctl_t *p_dev_ctl; + FC_BRD_INFO * binfo; + + if((p_dev_ctl = (fc_dev_ctl_t *)(dev->priv)) == 0) + return(-ENODEV); + binfo = &BINFO; + p_dev_ctl->device_state = 0; + binfo->fc_open_count &= ~FC_LAN_OPEN; + + netdevice_stop(dev); + netif_stop_queue(dev); +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif /* MODULE */ + return 0; +} + +/****************************************************************************** +* Function name : lpfn_change_mtu +* +* Description : +* +******************************************************************************/ +int lpfn_change_mtu(NETDEVICE *dev, + int new_mtu) +{ + fc_dev_ctl_t *p_dev_ctl; + + if((p_dev_ctl = (fc_dev_ctl_t *)(dev->priv)) == 0) + return(-ENODEV); + if ((new_mtu < FC_MIN_MTU) || (new_mtu > p_dev_ctl->ihs.lpfn_mtu)) + return -EINVAL; + dev->mtu = new_mtu; + return(0); +} + + +/****************************************************************************** +* Function name : lpfn_header +* +* Description : Create the FC MAC/LLC/SNAP header for an arbitrary protocol +* layer +* saddr=NULL means use device source address +* daddr=NULL means leave destination address (eg unresolved arp) +* +******************************************************************************/ +int lpfn_header(struct sk_buff *skb, + NETDEVICE *dev, + unsigned short type, + void *daddr, + void *saddr, + unsigned len) +{ + struct fc_nethdr *fchdr; + int rc; + + if (type == ETH_P_IP || type == ETH_P_ARP) { + fchdr = (struct fc_nethdr *)skb_push(skb, sizeof(struct fc_nethdr)); + + fchdr->llc.dsap = FC_LLC_DSAP; /* DSAP */ + fchdr->llc.ssap = FC_LLC_SSAP; /* SSAP */ + fchdr->llc.ctrl = FC_LLC_CTRL; /* control field */ + fchdr->llc.prot_id[0] = 0; /* protocol id */ + fchdr->llc.prot_id[1] = 0; /* protocol id */ + fchdr->llc.prot_id[2] = 0; /* protocol id */ + fchdr->llc.type = htons(type); /* type field */ + rc = sizeof(struct fc_nethdr); + } + else { +printk("lpfn_header:Not IP or ARP: %x\n",type); + + fchdr = (struct fc_nethdr *)skb_push(skb, sizeof(struct fc_nethdr)); + rc = sizeof(struct fc_nethdr); + } + + /* Set the source and destination hardware addresses */ + if (saddr != NULL) + memcpy(fchdr->fcnet.fc_srcname.IEEE, saddr, dev->addr_len); + else + memcpy(fchdr->fcnet.fc_srcname.IEEE, dev->dev_addr, dev->addr_len); + + fchdr->fcnet.fc_srcname.nameType = NAME_IEEE; /* IEEE name */ + fchdr->fcnet.fc_srcname.IEEEextMsn = 0; + fchdr->fcnet.fc_srcname.IEEEextLsb = 0; + + + if (daddr != NULL) + { + memcpy(fchdr->fcnet.fc_destname.IEEE, daddr, dev->addr_len); + fchdr->fcnet.fc_destname.nameType = NAME_IEEE; /* IEEE name */ + fchdr->fcnet.fc_destname.IEEEextMsn = 0; + fchdr->fcnet.fc_destname.IEEEextLsb = 0; + return(rc); + } + + return(-rc); +} + +/****************************************************************************** +* Function name : lpfn_rebuild_header +* +* Description : Rebuild the FC MAC/LLC/SNAP header. +* This is called after an ARP (or in future other address +* resolution) has completed on this sk_buff. +* We now let ARP fill in the other fields. +******************************************************************************/ +int lpfn_rebuild_header(struct sk_buff *skb) +{ + struct fc_nethdr *fchdr = (struct fc_nethdr *)skb->data; + NETDEVICE *dev = skb->dev; + + if (fchdr->llc.type == htons(ETH_P_IP)) { + return arp_find(fchdr->fcnet.fc_destname.IEEE, skb); + } + + printk("%s: unable to resolve type %X addresses.\n", + dev->name, (int)fchdr->llc.type); + + memcpy(fchdr->fcnet.fc_srcname.IEEE, dev->dev_addr, dev->addr_len); + fchdr->fcnet.fc_srcname.nameType = NAME_IEEE; /* IEEE name */ + fchdr->fcnet.fc_srcname.IEEEextMsn = 0; + fchdr->fcnet.fc_srcname.IEEEextLsb = 0; + + return 0; +} + +/****************************************************************************** +* Function name : lpfn_xmit +* +* Description : +* +******************************************************************************/ +static int lpfn_xmit(struct sk_buff *skb, + NETDEVICE *dev) +{ + fc_dev_ctl_t *p_dev_ctl; + int rc; + + + p_dev_ctl = (fc_dev_ctl_t *)dev->priv; + rc=lpfc_xmit(p_dev_ctl, skb); + return rc; +} + +/****************************************************************************** +* Function name : lpfn_receive +* +* Description : +* +******************************************************************************/ +_static_ void lpfn_receive(ndd_t *p_ndd, + struct sk_buff *skb, + void *p) +{ + fc_dev_ctl_t *p_dev_ctl; + NETDEVICE *dev; + struct fc_nethdr *fchdr = (struct fc_nethdr *)skb->data; + struct ethhdr *eth; + unsigned short *sp; + + p_dev_ctl = (fc_dev_ctl_t *)p; + dev = p_dev_ctl->ihs.lpfn_dev; + skb->dev = dev; + + skb->mac.raw=fchdr->fcnet.fc_destname.IEEE; + sp = (unsigned short *)fchdr->fcnet.fc_srcname.IEEE; + *(sp - 1) = *sp; + sp++; + *(sp - 1) = *sp; + sp++; + *(sp - 1) = *sp; + + skb_pull(skb, dev->hard_header_len); + eth= skb->mac.ethernet; + + if(*eth->h_dest&1) { + if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0) + skb->pkt_type=PACKET_BROADCAST; + else + skb->pkt_type=PACKET_MULTICAST; + } + + else if(dev->flags&(IFF_PROMISC)) { + if(memcmp(eth->h_dest,dev->dev_addr, ETH_ALEN)) + skb->pkt_type=PACKET_OTHERHOST; + } + + skb->protocol = fchdr->llc.type; + + if (skb->protocol == ntohs(ETH_P_ARP)) + skb->data[1] = 0x06; + + + netif_rx(skb); +} + +/****************************************************************************** +* Function name : lpfn_get_stats +* +* Description : +* +******************************************************************************/ +static struct enet_statistics *lpfn_get_stats(NETDEVICE *dev) +{ + fc_dev_ctl_t *p_dev_ctl; + struct enet_statistics *stats; + + p_dev_ctl = (fc_dev_ctl_t *)dev->priv; + stats = &NDDSTAT.ndd_enet; + return stats; +} + +#ifdef MODULE +/****************************************************************************** +* Function name : init_module +* +* Description : +* +******************************************************************************/ +int init_module(void) +#else +/****************************************************************************** +* Function name : lpfn_probe +* +* Description : +* +******************************************************************************/ +int lpfn_probe(void) +#endif /* MODULE */ +{ + struct lpfn_probe lp; + + lp.hard_start_xmit = &lpfn_xmit; + lp.receive = &lpfn_receive; + lp.get_stats = &lpfn_get_stats; + lp.open = &lpfn_open; + lp.stop = &lpfn_close; + lp.hard_header = &lpfn_header; + lp.rebuild_header = &lpfn_rebuild_header; + lp.change_mtu = &lpfn_change_mtu; + if(lpfc_ioctl(LPFN_PROBE,(void *)&lp) == 0) + return -ENODEV; + + return 0; +} + +#ifdef MODULE +/****************************************************************************** +* Function name : cleanup_module +* +* Description : +* +******************************************************************************/ +void cleanup_module(void) +{ + lpfc_ioctl(LPFN_DETACH,0); +} +MODULE_LICENSE("GPL"); +#endif /* MODULE */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/fc_crtn.h 830-ivtv/drivers/scsi/lpfc/fc_crtn.h --- 000-virgin/drivers/scsi/lpfc/fc_crtn.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/fc_crtn.h Thu Jan 8 10:21:53 2004 @@ -0,0 +1,254 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Enterprise Fibre Channel Host Bus Adapters. * + * Refer to the README file included with this package for * + * driver version and adapter support. * + * Copyright (C) 2003 Emulex Corporation. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details, a copy of which * + * can be found in the file COPYING included with this package. * + *******************************************************************/ + +/* Module fcxmitb.c External Routine Declarations */ +_forward_ int fc_create_xri(FC_BRD_INFO *binfo, RING *rp, NODELIST *nlp); +_forward_ void fc_restartio(fc_dev_ctl_t *p_dev_ctl, NODELIST *nlp); +_forward_ IOCBQ *fc_ringtx_drain(RING *rp); +_forward_ IOCBQ *fc_ringtx_get(RING *rp); +_forward_ void fc_ringtx_put(RING *rp, IOCBQ *iocbq); +_forward_ IOCBQ *fc_ringtxp_get(RING *rp, ushort iotag); +_forward_ void fc_ringtxp_put(RING *rp, IOCBQ *iocbq); +_forward_ int fc_xmit(fc_dev_ctl_t *p_dev_ctl, fcipbuf_t *p_mbuf); +_forward_ int handle_create_xri(fc_dev_ctl_t *p_dev_ctl, RING *rp,IOCBQ *tmp); +_forward_ int handle_xmit_cmpl(fc_dev_ctl_t *p_dev_ctl, RING *rp, IOCBQ *tmp); + + + +/* Module fcelsb.c External Routine Declarations */ +_forward_ int fc_chkpadisc(FC_BRD_INFO *binfo, NODELIST *nlp, + volatile NAME_TYPE *nn, volatile NAME_TYPE *pn); +_forward_ int fc_els_cmd(FC_BRD_INFO *binfo, uint32 type, void *arg, + uint32 class, ushort iotag, NODELIST *nlp); +_forward_ int fc_els_rsp(FC_BRD_INFO *binfo, uint32 type, uint32 Xri, + uint32 class, void *iocbp, uint32 flag, NODELIST *nlp); +_forward_ void fc_snd_flogi(fc_dev_ctl_t *p_dev_ctl, void *a1, void *a2); +_forward_ int fc_initial_flogi(fc_dev_ctl_t * p_dev_ctl); +_forward_ int handle_els_event(fc_dev_ctl_t *p_dev_ctl, RING *rp, IOCBQ *temp); +_forward_ int handle_rcv_els_req(fc_dev_ctl_t *p_dev_ctl, RING *rp, IOCBQ *temp); +_forward_ int fc_process_rscn(fc_dev_ctl_t *p_dev_ctl, IOCBQ *temp, MATCHMAP *mp); +_forward_ int fc_handle_rscn(fc_dev_ctl_t *p_dev_ctl, D_ID *didp); +_forward_ int fc_issue_ct_req(FC_BRD_INFO *binfo, uint32 portid, MATCHMAP *bmp, DMATCHMAP *inmp, DMATCHMAP *outmp, uint32 tmo); +_forward_ int fc_gen_req(FC_BRD_INFO *binfo, MATCHMAP *bmp, MATCHMAP *inmp, MATCHMAP *outmp, uint32 rpi, uint32 flag, uint32 cnt, uint32 tmo); +_forward_ int fc_issue_ct_rsp(FC_BRD_INFO *binfo, uint32 tag, MATCHMAP *bmp, DMATCHMAP *inp); +_forward_ int fc_rnid_req(FC_BRD_INFO *binfo, DMATCHMAP *inp, DMATCHMAP *outp, + MATCHMAP **bmp, uint32 rpi); +_forward_ void fc_issue_ns_query(fc_dev_ctl_t *p, void *a1, void *a2); +_forward_ int fc_flush_rscn_defer(fc_dev_ctl_t *p_dev_ctl); +_forward_ int fc_abort_discovery( fc_dev_ctl_t *p_dev_ctl); +/* FDMI */ +_forward_ int fc_fdmi_cmd(fc_dev_ctl_t *p_dev_ctl, NODELIST *ndlp, int cmdcode); +_forward_ void fc_fdmi_rsp(fc_dev_ctl_t *p_dev_ctl, MATCHMAP *mp, MATCHMAP *rsp_mp); +_forward_ void fc_plogi_put(FC_BRD_INFO *binfo, IOCBQ *iocbq); +_forward_ IOCBQ * fc_plogi_get(FC_BRD_INFO *binfo); + + + +/* Module fcmboxb.c External Routine Declarations */ +_forward_ void fc_clear_la(FC_BRD_INFO *binfo, MAILBOX *mb); +_forward_ void fc_read_status(FC_BRD_INFO *binfo, MAILBOX *mb); +_forward_ void fc_read_lnk_stat(FC_BRD_INFO *binfo, MAILBOX *mb); +_forward_ void fc_config_link(fc_dev_ctl_t *p_dev_ctl, MAILBOX *mb); +_forward_ int fc_config_port(FC_BRD_INFO *binfo, MAILBOX *mb, uint32 *hbainit); +_forward_ void fc_config_ring(FC_BRD_INFO *binfo, int ring, int profile, + MAILBOX *mb); +_forward_ void fc_init_link(FC_BRD_INFO *binfo, MAILBOX *mb, + uint32 topology, uint32 linkspeed); +_forward_ MAILBOXQ *fc_mbox_get(FC_BRD_INFO *binfo); +_forward_ int fc_read_la(fc_dev_ctl_t *p_dev_ctl, MAILBOX *mb); +_forward_ void fc_mbox_put(FC_BRD_INFO *binfo, MAILBOXQ *mbq); +_forward_ void fc_read_rev(FC_BRD_INFO *binfo, MAILBOX *mb); +_forward_ int fc_read_rpi(FC_BRD_INFO *binfo, uint32 rpi,MAILBOX *mb,uint32 flg); +_forward_ int fc_read_sparam(fc_dev_ctl_t *p_dev_ctl, MAILBOX *mb); +_forward_ int fc_reg_login(FC_BRD_INFO *binfo, uint32 did, uchar *param, + MAILBOX *mb, uint32 flag); +_forward_ void fc_set_slim(FC_BRD_INFO *binfo, MAILBOX *mb, uint32 addr, + uint32 value); +_forward_ void fc_unreg_login(FC_BRD_INFO *binfo, uint32 rpi, MAILBOX *mb); +_forward_ void fc_unreg_did(FC_BRD_INFO *binfo, uint32 did, MAILBOX *mb); +_forward_ void fc_dump_mem(FC_BRD_INFO *binfo, MAILBOX *mb); + +_forward_ void fc_config_farp(FC_BRD_INFO *binfo, MAILBOX *mb); +_forward_ void fc_read_config(FC_BRD_INFO *binfo, MAILBOX *mb); + +/* Module fcmemb.c External Routine Declarations */ +_forward_ void fc_disable_tc(FC_BRD_INFO *binfo, MAILBOX *mb); +_forward_ MATCHMAP *fc_getvaddr(fc_dev_ctl_t *p_dev_ctl, RING *rp, uchar *mapbp); +_forward_ uchar *fc_mem_get(FC_BRD_INFO *binfo, uint32 seg); +_forward_ uchar *fc_mem_put(FC_BRD_INFO *binfo, uint32 seg, uchar *bp); +_forward_ int fc_free_buffer(fc_dev_ctl_t *p_dev_ctl); +_forward_ int fc_malloc_buffer(fc_dev_ctl_t *p_dev_ctl); +_forward_ void fc_mapvaddr(FC_BRD_INFO *binfo, RING *rp, MATCHMAP *mp, + uint32 *haddr, uint32 *laddr); +_forward_ int fc_runBIUdiag(FC_BRD_INFO *binfo, MAILBOX *mb, uchar *in, + uchar *out); + + +/* Module fcclockb.c External Routine Declarations */ +_forward_ void fc_clkrelb(fc_dev_ctl_t *p_dev_ctl, FCCLOCK *cb); +_forward_ int fc_clk_can(fc_dev_ctl_t *p_dev_ctl, FCCLOCK *cb); +_forward_ FCCLOCK *fc_clk_set(fc_dev_ctl_t *p_dev_ctl, ulong tix, + void (*func)(fc_dev_ctl_t*, void*, void*), void *arg1, void *arg2); +_forward_ ulong fc_clk_res(fc_dev_ctl_t *p_dev_ctl, ulong tix, FCCLOCK *cb); +_forward_ void fc_timer(void *); +_forward_ void fc_clock_deque(FCCLOCK *cb); +_forward_ void fc_clock_init(void); +_forward_ void fc_flush_clk_set(fc_dev_ctl_t *p_dev_ctl, + void (*func)(fc_dev_ctl_t*, void*, void*)); +_forward_ int fc_abort_clk_blk(fc_dev_ctl_t *p_dev_ctl, + void (*func)(fc_dev_ctl_t*, void*, void*), void *a1, void *a2); +_forward_ int fc_abort_delay_els_cmd( fc_dev_ctl_t *p_dev_ctl, uint32 did); +_forward_ void fc_q_depth_up(fc_dev_ctl_t *p_dev_ctl, void *, void *); +_forward_ void fc_establish_link_tmo(fc_dev_ctl_t *p_dev_ctl, void *, void *); +/* QFULL_RETRY */ +_forward_ void fc_qfull_retry(void *); +_forward_ void fc_reset_timer(void); + +/* Module fcrpib.c External Routine Declarations */ +_forward_ int fc_discovery(fc_dev_ctl_t *p_dev_ctl); +_forward_ ushort fc_emac_lookup(FC_BRD_INFO *binfo, uchar *addr, + NODELIST **nlpp); +_forward_ int fc_fanovery(fc_dev_ctl_t *p_dev_ctl); +_forward_ NODELIST *fc_findnode_rpi(FC_BRD_INFO *binfo, uint32 rpi); +_forward_ int fc_free_rpilist(fc_dev_ctl_t *p_dev_ctl, int keeprpi); +_forward_ void fc_freebufq(fc_dev_ctl_t *p_dev_ctl, RING *rp, IOCBQ *xmitiq); +_forward_ int fc_freenode(FC_BRD_INFO *binfo, NODELIST *nlp, int rm); +_forward_ int fc_freenode_did(FC_BRD_INFO *binfo, uint32 did, int rm); +_forward_ int fc_nlpadjust(FC_BRD_INFO *binfo); +_forward_ int fc_rpi_abortxri(FC_BRD_INFO *binfo, ushort xri); +_forward_ int fc_nlp_bind(FC_BRD_INFO *binfo, NODELIST *nlp); +_forward_ int fc_nlp_unmap(FC_BRD_INFO *binfo, NODELIST *nlp); +_forward_ int fc_nlp_map(FC_BRD_INFO *binfo, NODELIST *nlp); +_forward_ NODELIST *fc_findnode_odid(FC_BRD_INFO *binfo, uint32 order, uint32 did); +_forward_ NODELIST *fc_findnode_scsid(FC_BRD_INFO *binfo, uint32 order, uint32 scid); +_forward_ NODELIST *fc_findnode_wwpn(FC_BRD_INFO *binfo, uint32 odr, NAME_TYPE *wwp); +_forward_ NODELIST *fc_findnode_wwnn(FC_BRD_INFO *binfo, uint32 odr, NAME_TYPE *wwn); +_forward_ NODELIST *fc_findnode_oxri(FC_BRD_INFO *binfo, uint32 order, uint32 xri); +_forward_ int fc_nlp_logi(FC_BRD_INFO *binfo, NODELIST *nlp, NAME_TYPE *wwpnp, + NAME_TYPE *wwnnp); +_forward_ int fc_nlp_swapinfo(FC_BRD_INFO *binfo, NODELIST *onlp, NODELIST *nnlp); + + +/* Module fcstratb.c External Routine Declarations */ +_forward_ dvi_t *fc_fcp_abort(fc_dev_ctl_t *p, int flg, int tgt, int lun); +_forward_ int fc_assign_scsid(fc_dev_ctl_t *ap, NODELIST *nlp); +_forward_ fc_buf_t *fc_deq_fcbuf_active(RING *rp, ushort iotag); +_forward_ fc_buf_t *fc_deq_fcbuf(dvi_t *di); +_forward_ void fc_enq_abort_bdr(dvi_t *dev_ptr); +_forward_ void fc_enq_fcbuf(fc_buf_t *fcptr); +_forward_ void fc_enq_fcbuf_active(RING *rp, fc_buf_t *fcptr); +_forward_ int issue_fcp_cmd(fc_dev_ctl_t *p_dev_ctl, dvi_t *dev_ptr, + T_SCSIBUF *sbp, int pend); +_forward_ void fc_enq_wait(dvi_t *dev_ptr); +_forward_ void fc_fail_cmd(dvi_t *dev_ptr, char error, uint32 statistic); +_forward_ void fc_fail_pendq(dvi_t *dev_ptr, char error, uint32 statistic); +_forward_ int fc_failio(fc_dev_ctl_t * p_dev_ctl); +_forward_ dvi_t *fc_find_lun( FC_BRD_INFO * binfo, int hash_index, fc_lun_t lun); +_forward_ void fc_issue_cmd(fc_dev_ctl_t *ap); +_forward_ int fc_reset_dev_q_depth( fc_dev_ctl_t * p_dev_ctl); +_forward_ int fc_restart_all_devices(fc_dev_ctl_t * p_dev_ctl); +_forward_ int fc_restart_device(dvi_t * dev_ptr); +_forward_ void fc_return_standby_queue(dvi_t *dev_ptr, uchar status, + uint32 statistic); +_forward_ void re_issue_fcp_cmd(dvi_t *dev_ptr); +_forward_ void fc_polling(FC_BRD_INFO *binfo, uint32 att_bit); +_forward_ void fc_fcp_fix_txq(fc_dev_ctl_t *p_dev_ctl); + + + +/* Module fcscsib.c External Routine Declarations */ +_forward_ int fc_abort_fcp_txpq(FC_BRD_INFO *binfo, dvi_t *dev_ptr); +_forward_ int fc_abort_xri(FC_BRD_INFO *binfo, dvi_t *dev_ptr, ushort iotag, int flag); +_forward_ int fc_abort_ixri_cx(FC_BRD_INFO *binfo, ushort xri, uint32 cmd, RING *rp); +_forward_ int fc_attach(int index, uint32 *p_uio); +_forward_ int fc_cfg_init(fc_dev_ctl_t *p_dev_ctl); +_forward_ void fc_cfg_remove(fc_dev_ctl_t *p_dev_ctl); +_forward_ void fc_cmdring_timeout(fc_dev_ctl_t *p, void *a1, void *a2); +_forward_ int fc_delay_iodone(fc_dev_ctl_t *p_dev_ctl, + T_SCSIBUF * sbp); +_forward_ void fc_delay_timeout(fc_dev_ctl_t *p, void *l1, void *l2); +_forward_ void fc_nodev_timeout(fc_dev_ctl_t *p, void *l1, void *l2); +_forward_ int fc_detach(int index); +_forward_ void fc_ffcleanup(fc_dev_ctl_t *p_dev_ctl); +_forward_ void fc_free_clearq(dvi_t *dev_ptr); +_forward_ int fc_geportname(NAME_TYPE *pn1, NAME_TYPE *pn2); +_forward_ int fc_linkdown(fc_dev_ctl_t *p_dev_ctl); +_forward_ void fc_linkdown_timeout(fc_dev_ctl_t *p, void *a1, void *a2); +_forward_ void fc_mbox_timeout(fc_dev_ctl_t *p, void *a1, void *a2); +_forward_ void fc_fabric_timeout(fc_dev_ctl_t *p, void *a1, void *a2); +_forward_ int fc_nextauth(fc_dev_ctl_t *p_dev_ctl, int sndcnt); +_forward_ int fc_nextdisc(fc_dev_ctl_t *p_dev_ctl, int sndcnt); +_forward_ int fc_nextnode(fc_dev_ctl_t *p_dev_ctl, NODELIST *nlp); +_forward_ int fc_nextrscn(fc_dev_ctl_t *p_dev_ctl, int sndcnt); +_forward_ int fc_free_ct_rsp(fc_dev_ctl_t *p_dev_ctl, MATCHMAP *mlist); +_forward_ int fc_ns_cmd(fc_dev_ctl_t *p_dev_ctl, NODELIST *nlp, int cc); +_forward_ int fc_ns_rsp(fc_dev_ctl_t *p_dev_ctl, NODELIST *nslp, MATCHMAP *mp, uint32 sz); +_forward_ int fc_ct_cmd(fc_dev_ctl_t *p_dev_ctl, MATCHMAP *mp, + MATCHMAP *bmp, NODELIST *nlp); +_forward_ int fc_offline(fc_dev_ctl_t *p_dev_ctl); +_forward_ int fc_online(fc_dev_ctl_t *p_dev_ctl); +_forward_ void fc_pcimem_bcopy(uint32 *src, uint32 *dest, uint32 cnt); +_forward_ int fc_post_buffer(fc_dev_ctl_t *p_dev_ctl, RING *rp, int cnt); +_forward_ int fc_post_mbuf(fc_dev_ctl_t *p_dev_ctl, RING *rp, int cnt); +_forward_ int fc_rlip(fc_dev_ctl_t *p_dev_ctl); +_forward_ void fc_scsi_timeout(fc_dev_ctl_t *p, void *l1, void *l2); +_forward_ void fc_start(fc_dev_ctl_t *p_dev_ctl); +_forward_ void handle_fcp_event(fc_dev_ctl_t *p_dev_ctl, RING *rp,IOCBQ *temp); +_forward_ int handle_mb_cmd(fc_dev_ctl_t *p_dev_ctl, MAILBOX *mb, uint32 cmd); +_forward_ int fc_free_iocb_buf(fc_dev_ctl_t *p_dev_ctl, RING *rp, IOCBQ *tmp); +_forward_ int handle_iprcv_seq(fc_dev_ctl_t *p_dev_ctl, RING *rp, IOCBQ *temp); +_forward_ int handle_elsrcv_seq(fc_dev_ctl_t *p_dev_ctl, RING *rp, IOCBQ *temp); +_forward_ void fc_process_reglogin(fc_dev_ctl_t *p_dev_ctl, NODELIST *nlp); +_forward_ int fc_snd_scsi_req(fc_dev_ctl_t *p_dev_ctl, NAME_TYPE *wwn, + MATCHMAP *bmp, DMATCHMAP *fcpmp, DMATCHMAP *omatp, + uint32 cnt, struct dev_info *devp); +_forward_ void issue_report_lun(fc_dev_ctl_t *p_dev_ctl, void *l1, void *l2); +_forward_ int fc_parse_binding_entry( fc_dev_ctl_t *p_dev_ctl, uchar *inbuf, + uchar *outbuf, int in_size, int out_size, int bind_type, + unsigned int *sum, int entry, int *lpfc_num); + +/* + * External Routine Declarations for local print statement formatting + */ + +_forward_ int fc_asc_seq_to_hex( fc_dev_ctl_t *p_dev_ctl, + int input_bc, int output_bc, char *inp, char *outp); +_forward_ int fc_asc_to_hex( uchar c); +_forward_ int fc_is_digit( int chr); +_forward_ int fc_log_printf_msg_vargs( + int brdno, msgLogDef *msg, + void *control, ...); +_forward_ int fc_check_this_log_msg_disabled( + int brdno, msgLogDef *msg, int *log_only); + +_forward_ void fc_brdreset(fc_dev_ctl_t *p_dev_ctl); +_forward_ int fc_ffinit(fc_dev_ctl_t *p_dev_ctl); +_forward_ int issue_mb_cmd(FC_BRD_INFO *binfo, MAILBOX *mb, int flag); +_forward_ uint32 issue_iocb_cmd(FC_BRD_INFO *binfo, RING *rp, IOCBQ *iocb_cmd); +_forward_ char *decode_firmware_rev(FC_BRD_INFO *binfo, fc_vpd_t *vp); +_forward_ int dfc_fmw_rev( fc_dev_ctl_t * p_dev_ctl); +_forward_ int dfc_hba_put_event( fc_dev_ctl_t * p_dev_ctl, uint32 evcode, + uint32 evdata1, uint32 evdata2, uint32 evdata3, uint32 evdata4); +_forward_ int dfc_put_event( fc_dev_ctl_t * p_dev_ctl, uint32 evcode, + uint32 evdata0, void *evdata1, void *evdata2); +_forward_ void handle_ff_error(fc_dev_ctl_t *p_dev_ctl); +_forward_ int handle_mb_event(fc_dev_ctl_t *p_dev_ctl); +_forward_ void handle_link_event(fc_dev_ctl_t *p_dev_ctl); +_forward_ void handle_ring_event(fc_dev_ctl_t *p_dev_ctl, int ring,uint32 reg); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/fc_ertn.h 830-ivtv/drivers/scsi/lpfc/fc_ertn.h --- 000-virgin/drivers/scsi/lpfc/fc_ertn.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/fc_ertn.h Thu Jan 8 10:21:53 2004 @@ -0,0 +1,89 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Enterprise Fibre Channel Host Bus Adapters. * + * Refer to the README file included with this package for * + * driver version and adapter support. * + * Copyright (C) 2003 Emulex Corporation. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details, a copy of which * + * can be found in the file COPYING included with this package. * + *******************************************************************/ + +/* + * Begin Global Function Definitions + */ +_forward_ void fc_bcopy(void *src, void *dest, unsigned long n); +_forward_ void fc_bzero(void *src, unsigned long size ); +_forward_ int fc_copyin(uchar *src, uchar *dst, unsigned long); +_forward_ int fc_copyout(uchar *, uchar *, unsigned long); +_forward_ void lpfc_mpdata_sync(fc_dev_ctl_t *p_dev_ctl, void *h, int a, int b, int c); +_forward_ void *fc_kmem_alloc(unsigned int size); +_forward_ void fc_kmem_free(void *obj, unsigned int size); +_forward_ void curtime(uint32 *time); +_forward_ ulong dfc_disable_lock(ulong p1, Simple_lock *p2); +_forward_ void dfc_unlock_enable(ulong p1, Simple_lock *p2); +_forward_ ulong lpfc_q_disable_lock(fc_dev_ctl_t *p_dev_ctl); +_forward_ void lpfc_q_unlock_enable(fc_dev_ctl_t *p_dev_ctl, ulong p1); +_forward_ ulong lpfc_mempool_disable_lock(fc_dev_ctl_t *p_dev_ctl); +_forward_ void lpfc_mempool_unlock_enable(fc_dev_ctl_t *p_dev_ctl, ulong p1); +_forward_ int dfc_sleep(fc_dev_ctl_t *p_dev_ctl, fcEvent_header *ep); +_forward_ int dfc_wakeup(fc_dev_ctl_t *p_dev_ctl, fcEvent_header *ep); +_forward_ int lpfc_DELAYMS(fc_dev_ctl_t *p_dev_ctl, int cnt); +_forward_ int fc_fcp_bufunmap(fc_dev_ctl_t *pdev, struct sc_buf *sp); +_forward_ int fc_bufmap(fc_dev_ctl_t *p_dev_ctl, uchar *bp, uint32 len, + void **phys, uint32 *cnt, void **handle); +_forward_ void fc_bufunmap(fc_dev_ctl_t *p_dev_ctl, uchar *addr, + uchar *dmahandle, uint32 size); +_forward_ int fc_fcp_bufmap(fc_dev_ctl_t *p_dev_ctl, struct sc_buf *sbp, + fc_buf_t *fcptr, IOCBQ *temp, ULP_BDE64 *bpl, + dvi_t * dev_ptr, int pend); +_forward_ void fc_free(fc_dev_ctl_t *p_dev_ctl, MBUF_INFO *buf_info); +_forward_ int fc_get_dds(fc_dev_ctl_t *p_dev_ctl, uint32 *p_uio); +_forward_ int fc_get_dds_bind(fc_dev_ctl_t *p_dev_ctl); +_forward_ int fc_get_dds(fc_dev_ctl_t *p_dev_ctl, uint32 *p_uio); +_forward_ void lpfc_scsi_selto_timeout(fc_dev_ctl_t *p, void *l1, void *l2); +_forward_ int lpfc_copy_sense(dvi_t * dev_ptr, struct buf * bp); +_forward_ int fc_intr(struct intr *p_ihs); +_forward_ int fc_pcimap(fc_dev_ctl_t *p_dev_ctl); +_forward_ ushort fc_rdpci_cmd( fc_dev_ctl_t *p_dev_ctl); +_forward_ uint32 fc_rdpci_32( fc_dev_ctl_t *p_dev_ctl, uint32 offset); +_forward_ int fc_initpci(struct dfc_info *di, fc_dev_ctl_t *p_dev_ctl); +_forward_ int fc_readpci(struct dfc_info *di, uint32 offset, char *buf, uint32 cnt); +_forward_ int fc_writepci(struct dfc_info *di, uint32 offset, char *buf, uint32 cnt); +_forward_ uchar *fc_malloc(fc_dev_ctl_t *p_dev_ctl, MBUF_INFO *buf_info); +_forward_ int fc_memmap(fc_dev_ctl_t *p_dev_ctl); +_forward_ int fc_unmemmap(fc_dev_ctl_t *p_dev_ctl); +_forward_ int lpfc_cfg_init(fc_dev_ctl_t *p_dev_ctl); +_forward_ void fc_wrpci_cmd( fc_dev_ctl_t *p_dev_ctl, ushort cfg_value); +_forward_ int i_clear(struct intr *ihs); +_forward_ int i_init(struct intr *ihs); +_forward_ void lpfc_fcp_error( fc_buf_t * fcptr, IOCB * cmd); +_forward_ dvi_t *fc_alloc_devp(fc_dev_ctl_t *, int target, fc_lun_t lun); +_forward_ int fc_do_iodone( struct buf *bp); +_forward_ int fc_device_changed(fc_dev_ctl_t *p, struct dev_info *dp); +_forward_ int log_printf(int f, int type, int num, char *str, int brdno, + uint32 a1, uint32 a2, uint32 a3, uint32 a4); +_forward_ int log_printf_msgblk( int brdno, msgLogDef * msg, char *str, int log_only); + + +_forward_ uint32 timeout(void (*func)(ulong), struct timer_list * , uint32 ); +_forward_ int lpfc_ip_rcvsz(fc_dev_ctl_t *p_dev_ctl); +_forward_ int lpfc_kfree_skb(struct sk_buff *skb); +_forward_ struct sk_buff * lpfc_alloc_skb(unsigned int sz); +_forward_ void fc_pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t h, + size_t size, int c); +_forward_ void fc_write_toio(uint32 *src, uint32 *dest_io, uint32 cnt); +_forward_ void fc_read_fromio(uint32 *src_io, uint32 *dest, uint32 cnt); +_forward_ uint32 fc_readl(uint32 *src); +_forward_ void fc_writel(uint32 *src, uint32 value); +_forward_ int fc_print( char * str, void * arg1, void * arg2); + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/fc_hw.h 830-ivtv/drivers/scsi/lpfc/fc_hw.h --- 000-virgin/drivers/scsi/lpfc/fc_hw.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/fc_hw.h Thu Jan 8 10:21:53 2004 @@ -0,0 +1,3073 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Enterprise Fibre Channel Host Bus Adapters. * + * Refer to the README file included with this package for * + * driver version and adapter support. * + * Copyright (C) 2003 Emulex Corporation. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details, a copy of which * + * can be found in the file COPYING included with this package. * + *******************************************************************/ + +#ifndef _H_FC_HW +#define _H_FC_HW + +typedef unsigned u32bit; +typedef unsigned u16bit; +typedef unsigned u8bit; + +#define FC_MAX_TRANSFER 0x40000 /* Maximum transfer size per operation */ + +#define MAX_CONFIGURED_RINGS 4 /* # rings currently used */ + +#define IOCB_CMD_R0_ENTRIES 5 /* ELS command ring entries */ +#define IOCB_RSP_R0_ENTRIES 5 /* ELS response ring entries */ +#define IOCB_CMD_R1_ENTRIES 27 /* IP command ring entries */ +#define IOCB_RSP_R1_ENTRIES 28 /* IP response ring entries */ +#define IOCB_CMD_R2_ENTRIES 45 /* FCP command ring entries */ +#define IOCB_RSP_R2_ENTRIES 10 /* FCP response ring entries */ +#define MAX_BIOCB 120 /* max# of BIU IOCBs in shared memory */ + +#define SLI2_IOCB_CMD_R0_ENTRIES 6 /* SLI-2 ELS command ring entries */ +#define SLI2_IOCB_RSP_R0_ENTRIES 6 /* SLI-2 ELS response ring entries */ +#define SLI2_IOCB_CMD_R1_ENTRIES 24 /* SLI-2 IP command ring entries */ +#define SLI2_IOCB_RSP_R1_ENTRIES 30 /* SLI-2 IP response ring entries */ +#define SLI2_IOCB_CMD_R1XTRA_ENTRIES 18 /* SLI-2 extra FCP cmd ring entries */ +#define SLI2_IOCB_RSP_R1XTRA_ENTRIES 24 /* SLI-2 extra FCP rsp ring entries */ +#define SLI2_IOCB_CMD_R2_ENTRIES 30 /* SLI-2 FCP command ring entries */ +#define SLI2_IOCB_RSP_R2_ENTRIES 20 /* SLI-2 FCP response ring entries */ +#define SLI2_IOCB_CMD_R2XTRA_ENTRIES 22 /* SLI-2 extra FCP cmd ring entries */ +#define SLI2_IOCB_RSP_R2XTRA_ENTRIES 20 /* SLI-2 extra FCP rsp ring entries */ +#define SLI2_IOCB_CMD_R3_ENTRIES 0 /* SLI-2 FCP command ring entries */ +#define SLI2_IOCB_RSP_R3_ENTRIES 0 /* SLI-2 FCP response ring entries */ +#define MAX_SLI2_IOCB SLI2_IOCB_CMD_R0_ENTRIES + \ + SLI2_IOCB_RSP_R0_ENTRIES + \ + SLI2_IOCB_CMD_R1_ENTRIES + \ + SLI2_IOCB_RSP_R1_ENTRIES + \ + SLI2_IOCB_CMD_R2_ENTRIES + \ + SLI2_IOCB_RSP_R2_ENTRIES + \ + SLI2_IOCB_CMD_R3_ENTRIES + \ + SLI2_IOCB_RSP_R3_ENTRIES + +#define FCELSSIZE 1024 /* maximum ELS transfer size */ + +#define FC_MAXRETRY 3 /* max retries for ELS commands */ +#define FC_ELS_RING 0 /* use ring 0 for ELS commands */ +#define FC_IP_RING 1 /* use ring 1 for IP commands */ +#define FC_FCP_RING 2 /* use ring 2 for FCP initiator commands */ + +#define FF_DEF_EDTOV 2000 /* Default E_D_TOV (2000ms) */ +#define FF_DEF_ALTOV 15 /* Default AL_TIME (15ms) */ +#define FF_DEF_RATOV 2 /* Default RA_TOV (2s) */ +#define FF_DEF_ARBTOV 1900 /* Default ARB_TOV (1900ms) */ +#define MB_WAIT_PERIOD 500 /* Wait period in usec inbetween MB polls */ +#define MAX_MB_COMPLETION 1000 /* # MB_WAIT_PERIODs to wait for MB cmplt */ +#define MAX_MSG_DATA 28 /* max msg data in CMD_ADAPTER_MSG iocb */ + +#define FF_REG_AREA_SIZE 256 /* size, in bytes, of i/o register area */ +#define FF_SLIM_SIZE 4096 /* size, in bytes, of SLIM */ + +/* + * Miscellaneous stuff.... + */ +/* HBA Mgmt */ +#define FDMI_DID ((uint32)0xfffffa) +#define NameServer_DID ((uint32)0xfffffc) +#define SCR_DID ((uint32)0xfffffd) +#define Fabric_DID ((uint32)0xfffffe) +#define Bcast_DID ((uint32)0xffffff) +#define Mask_DID ((uint32)0xffffff) +#define CT_DID_MASK ((uint32)0xffff00) +#define Fabric_DID_MASK ((uint32)0xfff000) + +#define PT2PT_LocalID ((uint32)1) +#define PT2PT_RemoteID ((uint32)2) + +#define OWN_CHIP 1 /* IOCB / Mailbox is owned by Hba */ +#define OWN_HOST 0 /* IOCB / Mailbox is owned by Host */ +#define END_OF_CHAIN 0 +#define IOCB_WORD_SZ 8 /* # of words in ULP BIU XCB */ +#define MAX_RINGS 3 /* Max # of supported rings */ + +/* defines for type field in fc header */ +#define FC_ELS_DATA 0x1 +#define FC_LLC_SNAP 0x5 +#define FC_FCP_DATA 0x8 +#define FC_COMMON_TRANSPORT_ULP 0x20 + +/* defines for rctl field in fc header */ +#define FC_DEV_DATA 0x0 +#define FC_UNSOL_CTL 0x2 +#define FC_SOL_CTL 0x3 +#define FC_UNSOL_DATA 0x4 +#define FC_FCP_CMND 0x6 +#define FC_ELS_REQ 0x22 +#define FC_ELS_RSP 0x23 +#define FC_NET_HDR 0x20 /* network headers for Dfctl field */ + +/* + * Common Transport structures and definitions + * + */ + +union CtRevisionId { + /* Structure is in Big Endian format */ + struct { + u32bit Revision: 8; + u32bit InId: 24; + } bits; + uint32 word; +}; + +union CtCommandResponse { + /* Structure is in Big Endian format */ + struct { + u32bit CmdRsp: 16; + u32bit Size: 16; + } bits; + uint32 word; +}; + +typedef struct SliCtRequest { + /* Structure is in Big Endian format */ + union CtRevisionId RevisionId; + uchar FsType; + uchar FsSubType; + uchar Options; + uchar Rsrvd1; + union CtCommandResponse CommandResponse; + uchar Rsrvd2; + uchar ReasonCode; + uchar Explanation; + uchar VendorUnique; + + union { + uint32 PortID; + struct gid { + uchar PortType; /* for GID_PT requests */ + uchar DomainScope; + uchar AreaScope; + uchar Fc4Type; /* for GID_FT requests */ + } gid; + struct rft { + uint32 PortId; /* For RFT_ID requests */ +#if BIG_ENDIAN_HW + u32bit rsvd0: 16; + u32bit rsvd1: 7; + u32bit fcpReg: 1; /* Type 8 */ + u32bit rsvd2: 2; + u32bit ipReg: 1; /* Type 5 */ + u32bit rsvd3: 5; +#endif +#if LITTLE_ENDIAN_HW + u32bit rsvd0: 16; + u32bit fcpReg: 1; /* Type 8 */ + u32bit rsvd1: 7; + u32bit rsvd3: 5; + u32bit ipReg: 1; /* Type 5 */ + u32bit rsvd2: 2; +#endif + uint32 rsvd[7]; + } rft; + } un; +} SLI_CT_REQUEST, *PSLI_CT_REQUEST; + +#define SLI_CT_REVISION 1 +#define GID_REQUEST_SZ (sizeof(SLI_CT_REQUEST) - 32) +#define RFT_REQUEST_SZ (sizeof(SLI_CT_REQUEST)) + + +/* + * FsType Definitions + */ + +#define SLI_CT_MANAGEMENT_SERVICE 0xFA +#define SLI_CT_TIME_SERVICE 0xFB +#define SLI_CT_DIRECTORY_SERVICE 0xFC +#define SLI_CT_FABRIC_CONTROLLER_SERVICE 0xFD + +/* + * Directory Service Subtypes + */ + +#define SLI_CT_DIRECTORY_NAME_SERVER 0x02 + +/* + * Response Codes + */ + +#define SLI_CT_RESPONSE_FS_RJT 0x8001 +#define SLI_CT_RESPONSE_FS_ACC 0x8002 + +/* + * Reason Codes + */ + +#define SLI_CT_NO_ADDITIONAL_EXPL 0x0 +#define SLI_CT_INVALID_COMMAND 0x01 +#define SLI_CT_INVALID_VERSION 0x02 +#define SLI_CT_LOGICAL_ERROR 0x03 +#define SLI_CT_INVALID_IU_SIZE 0x04 +#define SLI_CT_LOGICAL_BUSY 0x05 +#define SLI_CT_PROTOCOL_ERROR 0x07 +#define SLI_CT_UNABLE_TO_PERFORM_REQ 0x09 +#define SLI_CT_REQ_NOT_SUPPORTED 0x0b +#define SLI_CT_HBA_INFO_NOT_REGISTERED 0x10 +#define SLI_CT_MULTIPLE_HBA_ATTR_OF_SAME_TYPE 0x11 +#define SLI_CT_INVALID_HBA_ATTR_BLOCK_LEN 0x12 +#define SLI_CT_HBA_ATTR_NOT_PRESENT 0x13 +#define SLI_CT_PORT_INFO_NOT_REGISTERED 0x20 +#define SLI_CT_MULTIPLE_PORT_ATTR_OF_SAME_TYPE 0x21 +#define SLI_CT_INVALID_PORT_ATTR_BLOCK_LEN 0x22 +#define SLI_CT_VENDOR_UNIQUE 0xff + +/* + * Name Server SLI_CT_UNABLE_TO_PERFORM_REQ Explanations + */ + +#define SLI_CT_NO_PORT_ID 0x01 +#define SLI_CT_NO_PORT_NAME 0x02 +#define SLI_CT_NO_NODE_NAME 0x03 +#define SLI_CT_NO_CLASS_OF_SERVICE 0x04 +#define SLI_CT_NO_IP_ADDRESS 0x05 +#define SLI_CT_NO_IPA 0x06 +#define SLI_CT_NO_FC4_TYPES 0x07 +#define SLI_CT_NO_SYMBOLIC_PORT_NAME 0x08 +#define SLI_CT_NO_SYMBOLIC_NODE_NAME 0x09 +#define SLI_CT_NO_PORT_TYPE 0x0A +#define SLI_CT_ACCESS_DENIED 0x10 +#define SLI_CT_INVALID_PORT_ID 0x11 +#define SLI_CT_DATABASE_EMPTY 0x12 + + + +/* + * Name Server Command Codes + */ + +#define SLI_CTNS_GA_NXT 0x0100 +#define SLI_CTNS_GPN_ID 0x0112 +#define SLI_CTNS_GNN_ID 0x0113 +#define SLI_CTNS_GCS_ID 0x0114 +#define SLI_CTNS_GFT_ID 0x0117 +#define SLI_CTNS_GSPN_ID 0x0118 +#define SLI_CTNS_GPT_ID 0x011A +#define SLI_CTNS_GID_PN 0x0121 +#define SLI_CTNS_GID_NN 0x0131 +#define SLI_CTNS_GIP_NN 0x0135 +#define SLI_CTNS_GIPA_NN 0x0136 +#define SLI_CTNS_GSNN_NN 0x0139 +#define SLI_CTNS_GNN_IP 0x0153 +#define SLI_CTNS_GIPA_IP 0x0156 +#define SLI_CTNS_GID_FT 0x0171 +#define SLI_CTNS_GID_PT 0x01A1 +#define SLI_CTNS_RPN_ID 0x0212 +#define SLI_CTNS_RNN_ID 0x0213 +#define SLI_CTNS_RCS_ID 0x0214 +#define SLI_CTNS_RFT_ID 0x0217 +#define SLI_CTNS_RSPN_ID 0x0218 +#define SLI_CTNS_RPT_ID 0x021A +#define SLI_CTNS_RIP_NN 0x0235 +#define SLI_CTNS_RIPA_NN 0x0236 +#define SLI_CTNS_RSNN_NN 0x0239 +#define SLI_CTNS_DA_ID 0x0300 + +/* + * Port Types + */ + +#define SLI_CTPT_N_PORT 0x01 +#define SLI_CTPT_NL_PORT 0x02 +#define SLI_CTPT_FNL_PORT 0x03 +#define SLI_CTPT_IP 0x04 +#define SLI_CTPT_FCP 0x08 +#define SLI_CTPT_NX_PORT 0x7F +#define SLI_CTPT_F_PORT 0x81 +#define SLI_CTPT_FL_PORT 0x82 +#define SLI_CTPT_E_PORT 0x84 + +#define SLI_CT_LAST_ENTRY 0x80000000 + +/*=====================================================================*/ + +#ifdef LP6000 +/* PCI register offsets */ +#define MEM_ADDR_OFFSET 0x10 /* SLIM base memory address */ +#define MEMH_OFFSET 0x14 /* SLIM base memory high address */ +#define REG_ADDR_OFFSET 0x18 /* REGISTER base memory address */ +#define REGH_OFFSET 0x1c /* REGISTER base memory high address */ +#define IO_ADDR_OFFSET 0x20 /* BIU I/O registers */ +#define REGIOH_OFFSET 0x24 /* REGISTER base io high address */ +#endif + +#define CMD_REG_OFFSET 0x4 /* PCI command configuration */ + +/* General PCI Register Definitions */ +/* Refer To The PCI Specification For Detailed Explanations */ + +/* Register Offsets in little endian format */ +#define PCI_VENDOR_ID_REGISTER 0x00 /* PCI Vendor ID Register*/ +#define PCI_DEVICE_ID_REGISTER 0x02 /* PCI Device ID Register*/ +#define PCI_CONFIG_ID_REGISTER 0x00 /* PCI Configuration ID Register*/ +#define PCI_COMMAND_REGISTER 0x04 /* PCI Command Register*/ +#define PCI_STATUS_REGISTER 0x06 /* PCI Status Register*/ +#define PCI_REV_ID_REGISTER 0x08 /* PCI Revision ID Register*/ +#define PCI_CLASS_CODE_REGISTER 0x09 /* PCI Class Code Register*/ +#define PCI_CACHE_LINE_REGISTER 0x0C /* PCI Cache Line Register*/ +#define PCI_LATENCY_TMR_REGISTER 0x0D /* PCI Latency Timer Register*/ +#define PCI_HEADER_TYPE_REGISTER 0x0E /* PCI Header Type Register*/ +#define PCI_BIST_REGISTER 0x0F /* PCI Built-In SelfTest Register*/ +#define PCI_BAR_0_REGISTER 0x10 /* PCI Base Address Register 0*/ +#define PCI_BAR_1_REGISTER 0x14 /* PCI Base Address Register 1*/ +#define PCI_BAR_2_REGISTER 0x18 /* PCI Base Address Register 2*/ +#define PCI_BAR_3_REGISTER 0x1C /* PCI Base Address Register 3*/ +#define PCI_BAR_4_REGISTER 0x20 /* PCI Base Address Register 4*/ +#define PCI_BAR_5_REGISTER 0x24 /* PCI Base Address Register 5*/ +#define PCI_EXPANSION_ROM 0x30 /* PCI Expansion ROM Base Register*/ +#define PCI_INTR_LINE_REGISTER 0x3C /* PCI Interrupt Line Register*/ +#define PCI_INTR_PIN_REGISTER 0x3D /* PCI Interrupt Pin Register*/ +#define PCI_MIN_GNT_REGISTER 0x3E /* PCI Min-Gnt Register*/ +#define PCI_MAX_LAT_REGISTER 0x3F /* PCI Max_Lat Register*/ +#define PCI_NODE_ADDR_REGISTER 0x40 /* PCI Node Address Register*/ + +/* PCI access methods */ +#define P_CONF_T1 1 +#define P_CONF_T2 2 + +/* max number of pci buses */ +#define MAX_PCI_BUSES 0xFF + +/* number of PCI config bytes to access */ +#define PCI_BYTE 1 +#define PCI_WORD 2 +#define PCI_DWORD 4 + +/* PCI related constants */ +#define CMD_IO_ENBL 0x0001 +#define CMD_MEM_ENBL 0x0002 +#define CMD_BUS_MASTER 0x0004 +#define CMD_MWI 0x0010 +#define CMD_PARITY_CHK 0x0040 +#define CMD_SERR_ENBL 0x0100 + +#define CMD_CFG_VALUE 0x156 /* mem enable, master, MWI, SERR, PERR */ + +/* PCI addresses */ +#define PCI_SPACE_ENABLE 0x0CF8 +#define CF1_CONFIG_ADDR_REGISTER 0x0CF8 +#define CF1_CONFIG_DATA_REGISTER 0x0CFC +#define CF2_FORWARD_REGISTER 0x0CFA +#define CF2_BASE_ADDRESS 0xC000 + +#define PCI_VENDOR_ID_EMULEX 0x10df + +#define PCI_DEVICE_ID_SUPERFLY 0xf700 +#define PCI_DEVICE_ID_DRAGONFLY 0xf800 +#define PCI_DEVICE_ID_CENTAUR 0xf900 +#define PCI_DEVICE_ID_PFLY 0xf098 +#define PCI_DEVICE_ID_PEGASUS 0xf980 +#define PCI_DEVICE_ID_TFLY 0xf0a5 +#define PCI_DEVICE_ID_THOR 0xfa00 + +#define JEDEC_ID_ADDRESS 0x0080001c +#define SUPERFLY_JEDEC_ID 0x0020 +#define DRAGONFLY_JEDEC_ID 0x0021 +#define DRAGONFLY_V2_JEDEC_ID 0x0025 +#define CENTAUR_2G_JEDEC_ID 0x0026 +#define CENTAUR_1G_JEDEC_ID 0x0028 +#define JEDEC_ID_MASK 0x0FFFF000 +#define JEDEC_ID_SHIFT 12 +#define FC_JEDEC_ID(id) ((id & JEDEC_ID_MASK) >> JEDEC_ID_SHIFT) + +#define DEFAULT_PCI_LATENCY_CLOCKS 0xf8 /* 0xF8 is a special value for + * FF11.1N6 firmware. Use + * 0x80 for pre-FF11.1N6 &N7, etc + */ +#define PCI_LATENCY_VALUE 0xf8 + +#ifdef LP6000 +typedef struct { /* BIU registers */ + uint32 hostAtt; /* See definitions for Host Attention register */ + uint32 chipAtt; /* See definitions for Chip Attention register */ + uint32 hostStatus; /* See definitions for Host Status register */ + uint32 hostControl; /* See definitions for Host Control register */ + uint32 buiConfig; /* See definitions for BIU configuration register*/ +} FF_REGS, *PFF_REGS; + +/* Host Attention Register */ + +#define HA_REG_OFFSET 0 /* Word offset from register base address */ + +#define HA_R0RE_REQ 0x00000001 /* Bit 0 */ +#define HA_R0CE_RSP 0x00000002 /* Bit 1 */ +#define HA_R0ATT 0x00000008 /* Bit 3 */ +#define HA_R1RE_REQ 0x00000010 /* Bit 4 */ +#define HA_R1CE_RSP 0x00000020 /* Bit 5 */ +#define HA_R1ATT 0x00000080 /* Bit 7 */ +#define HA_R2RE_REQ 0x00000100 /* Bit 8 */ +#define HA_R2CE_RSP 0x00000200 /* Bit 9 */ +#define HA_R2ATT 0x00000800 /* Bit 11 */ +#define HA_R3RE_REQ 0x00001000 /* Bit 12 */ +#define HA_R3CE_RSP 0x00002000 /* Bit 13 */ +#define HA_R3ATT 0x00008000 /* Bit 15 */ +#define HA_LATT 0x20000000 /* Bit 29 */ +#define HA_MBATT 0x40000000 /* Bit 30 */ +#define HA_ERATT 0x80000000 /* Bit 31 */ + + +/* Chip Attention Register */ + +#define CA_REG_OFFSET 1 /* Word offset from register base address */ + +#define CA_R0CE_REQ 0x00000001 /* Bit 0 */ +#define CA_R0RE_RSP 0x00000002 /* Bit 1 */ +#define CA_R0ATT 0x00000008 /* Bit 3 */ +#define CA_R1CE_REQ 0x00000010 /* Bit 4 */ +#define CA_R1RE_RSP 0x00000020 /* Bit 5 */ +#define CA_R1ATT 0x00000080 /* Bit 7 */ +#define CA_R2CE_REQ 0x00000100 /* Bit 8 */ +#define CA_R2RE_RSP 0x00000200 /* Bit 9 */ +#define CA_R2ATT 0x00000800 /* Bit 11 */ +#define CA_R3CE_REQ 0x00001000 /* Bit 12 */ +#define CA_R3RE_RSP 0x00002000 /* Bit 13 */ +#define CA_R3ATT 0x00008000 /* Bit 15 */ +#define CA_MBATT 0x40000000 /* Bit 30 */ + + +/* Host Status Register */ + +#define HS_REG_OFFSET 2 /* Word offset from register base address */ + +#define HS_MBRDY 0x00400000 /* Bit 22 */ +#define HS_FFRDY 0x00800000 /* Bit 23 */ +#define HS_FFER8 0x01000000 /* Bit 24 */ +#define HS_FFER7 0x02000000 /* Bit 25 */ +#define HS_FFER6 0x04000000 /* Bit 26 */ +#define HS_FFER5 0x08000000 /* Bit 27 */ +#define HS_FFER4 0x10000000 /* Bit 28 */ +#define HS_FFER3 0x20000000 /* Bit 29 */ +#define HS_FFER2 0x40000000 /* Bit 30 */ +#define HS_FFER1 0x80000000 /* Bit 31 */ +#define HS_FFERM 0xFF000000 /* Mask for error bits 31:24 */ + + +/* Host Control Register */ + +#define HC_REG_OFFSET 3 /* Word offset from register base address */ + +#define HC_MBINT_ENA 0x00000001 /* Bit 0 */ +#define HC_R0INT_ENA 0x00000002 /* Bit 1 */ +#define HC_R1INT_ENA 0x00000004 /* Bit 2 */ +#define HC_R2INT_ENA 0x00000008 /* Bit 3 */ +#define HC_R3INT_ENA 0x00000010 /* Bit 4 */ +#define HC_INITHBI 0x02000000 /* Bit 25 */ +#define HC_INITMB 0x04000000 /* Bit 26 */ +#define HC_INITFF 0x08000000 /* Bit 27 */ +#define HC_LAINT_ENA 0x20000000 /* Bit 29 */ +#define HC_ERINT_ENA 0x80000000 /* Bit 31 */ + +/* BIU Configuration Register */ + +#define BC_REG_OFFSET 4 /* Word offset from register base address */ + +#define BC_BSE 0x00000001 /* Bit 0 */ +#define BC_BSE_SWAP 0x01000000 /* Bit 0 - swapped */ + +#endif /* LP6000 */ + +/*=====================================================================*/ + +/* + * Start of FCP specific structures + */ + +/* + * Definition of FCP_RSP Packet + */ + +typedef struct _FCP_RSP { + uint32 rspRsvd1; /* FC Word 0, byte 0:3 */ + uint32 rspRsvd2; /* FC Word 1, byte 0:3 */ + + uchar rspStatus0; /* FCP_STATUS byte 0 (reserved) */ + uchar rspStatus1; /* FCP_STATUS byte 1 (reserved) */ + uchar rspStatus2; /* FCP_STATUS byte 2 field validity */ +#define RSP_LEN_VALID 0x01 /* bit 0 */ +#define SNS_LEN_VALID 0x02 /* bit 1 */ +#define RESID_OVER 0x04 /* bit 2 */ +#define RESID_UNDER 0x08 /* bit 3 */ + uchar rspStatus3; /* FCP_STATUS byte 3 SCSI status byte */ +#define SCSI_STAT_GOOD 0x00 +#define SCSI_STAT_CHECK_COND 0x02 +#define SCSI_STAT_COND_MET 0x04 +#define SCSI_STAT_BUSY 0x08 +#define SCSI_STAT_INTERMED 0x10 +#define SCSI_STAT_INTERMED_CM 0x14 +#define SCSI_STAT_RES_CNFLCT 0x18 +#define SCSI_STAT_CMD_TERM 0x22 +#define SCSI_STAT_QUE_FULL 0x28 + + uint32 rspResId; /* Residual xfer if RESID_xxxx set in fcpStatus2 */ + /* Received in Big Endian format */ + uint32 rspSnsLen; /* Length of sense data in fcpSnsInfo */ + /* Received in Big Endian format */ + uint32 rspRspLen; /* Length of FCP response data in fcpRspInfo */ + /* Received in Big Endian format */ + + uchar rspInfo0; /* FCP_RSP_INFO byte 0 (reserved) */ + uchar rspInfo1; /* FCP_RSP_INFO byte 1 (reserved) */ + uchar rspInfo2; /* FCP_RSP_INFO byte 2 (reserved) */ + uchar rspInfo3; /* FCP_RSP_INFO RSP_CODE byte 3 */ + +#define RSP_NO_FAILURE 0x00 +#define RSP_DATA_BURST_ERR 0x01 +#define RSP_CMD_FIELD_ERR 0x02 +#define RSP_RO_MISMATCH_ERR 0x03 +#define RSP_TM_NOT_SUPPORTED 0x04 /* Task mgmt function not supported */ +#define RSP_TM_NOT_COMPLETED 0x05 /* Task mgmt function not performed */ + + uint32 rspInfoRsvd; /* FCP_RSP_INFO bytes 4-7 (reserved) */ + +#define MAX_FCP_SNS 128 + uchar rspSnsInfo[MAX_FCP_SNS]; +} FCP_RSP, *PFCP_RSP; + +/* + * Definition of FCP_CMND Packet + */ + +typedef struct _FCP_CMND { + uint32 fcpLunMsl; /* most significant lun word (32 bits) */ + uint32 fcpLunLsl; /* least significant lun word (32 bits) */ + /* # of bits to shift lun id to end up in right + * payload word, little endian = 8, big = 16. + */ +#if LITTLE_ENDIAN_HW +#define FC_LUN_SHIFT 8 +#define FC_ADDR_MODE_SHIFT 0 +#endif +#if BIG_ENDIAN_HW +#define FC_LUN_SHIFT 16 +#define FC_ADDR_MODE_SHIFT 24 +#endif + + uchar fcpCntl0; /* FCP_CNTL byte 0 (reserved) */ + uchar fcpCntl1; /* FCP_CNTL byte 1 task codes */ +#define SIMPLE_Q 0x00 +#define HEAD_OF_Q 0x01 +#define ORDERED_Q 0x02 +#define ACA_Q 0x04 +#define UNTAGGED 0x05 + uchar fcpCntl2; /* FCP_CTL byte 2 task management codes */ +#define ABORT_TASK_SET 0x02 /* Bit 1 */ +#define CLEAR_TASK_SET 0x04 /* bit 2 */ +#define LUN_RESET 0x10 /* bit 4 */ +#define TARGET_RESET 0x20 /* bit 5 */ +#define CLEAR_ACA 0x40 /* bit 6 */ +#define TERMINATE_TASK 0x80 /* bit 7 */ + uchar fcpCntl3; +#define WRITE_DATA 0x01 /* Bit 0 */ +#define READ_DATA 0x02 /* Bit 1 */ + + uchar fcpCdb[16]; /* SRB cdb field is copied here */ + uint32 fcpDl; /* Total transfer length */ + +} FCP_CMND, *PFCP_CMND; + +/* SCSI INQUIRY Command Structure */ + +typedef struct inquiryDataType { + u8bit DeviceType : 5; + u8bit DeviceTypeQualifier : 3; + + u8bit DeviceTypeModifier : 7; + u8bit RemovableMedia : 1; + + uchar Versions; + uchar ResponseDataFormat; + uchar AdditionalLength; + uchar Reserved[2]; + + u8bit SoftReset : 1; + u8bit CommandQueue : 1; + u8bit Reserved2 : 1; + u8bit LinkedCommands : 1; + u8bit Synchronous : 1; + u8bit Wide16Bit : 1; + u8bit Wide32Bit : 1; + u8bit RelativeAddressing : 1; + + uchar VendorId[8]; + uchar ProductId[16]; + uchar ProductRevisionLevel[4]; + uchar VendorSpecific[20]; + uchar Reserved3[40]; +} INQUIRY_DATA_DEF; + +typedef struct _READ_CAPACITY_DATA { + ulong LogicalBlockAddress; + ulong BytesPerBlock; +} READ_CAPACITY_DATA_DEF; + +typedef struct _REPORT_LUNS_DATA { + union { + uchar cB[8]; + uint32 cL[2]; + } control; + union { + uchar eB[8]; + uint32 eL[2]; + } entry [1]; +} REPORT_LUNS_DATA_DEF; + +/* SCSI CDB command codes */ +#define FCP_SCSI_FORMAT_UNIT 0x04 +#define FCP_SCSI_INQUIRY 0x12 +#define FCP_SCSI_MODE_SELECT 0x15 +#define FCP_SCSI_MODE_SENSE 0x1A +#define FCP_SCSI_PAUSE_RESUME 0x4B +#define FCP_SCSI_PLAY_AUDIO 0x45 +#define FCP_SCSI_PLAY_AUDIO_EXT 0xA5 +#define FCP_SCSI_PLAY_AUDIO_MSF 0x47 +#define FCP_SCSI_PLAY_AUDIO_TRK_INDX 0x48 +#define FCP_SCSI_PREVENT_ALLOW_REMOVAL 0x1E +#define FCP_SCSI_READ 0x08 +#define FCP_SCSI_READ_BUFFER 0x3C +#define FCP_SCSI_READ_CAPACITY 0x25 +#define FCP_SCSI_READ_DEFECT_LIST 0x37 +#define FCP_SCSI_READ_EXTENDED 0x28 +#define FCP_SCSI_READ_HEADER 0x44 +#define FCP_SCSI_READ_LONG 0xE8 +#define FCP_SCSI_READ_SUB_CHANNEL 0x42 +#define FCP_SCSI_READ_TOC 0x43 +#define FCP_SCSI_REASSIGN_BLOCK 0x07 +#define FCP_SCSI_RECEIVE_DIAGNOSTIC_RESULTS 0x1C +#define FCP_SCSI_RELEASE_UNIT 0x17 +#define FCP_SCSI_REPORT_LUNS 0xa0 +#define FCP_SCSI_REQUEST_SENSE 0x03 +#define FCP_SCSI_RESERVE_UNIT 0x16 +#define FCP_SCSI_REZERO_UNIT 0x01 +#define FCP_SCSI_SEEK 0x0B +#define FCP_SCSI_SEEK_EXTENDED 0x2B +#define FCP_SCSI_SEND_DIAGNOSTIC 0x1D +#define FCP_SCSI_START_STOP_UNIT 0x1B +#define FCP_SCSI_TEST_UNIT_READY 0x00 +#define FCP_SCSI_VERIFY 0x2F +#define FCP_SCSI_WRITE 0x0A +#define FCP_SCSI_WRITE_AND_VERIFY 0x2E +#define FCP_SCSI_WRITE_BUFFER 0x3B +#define FCP_SCSI_WRITE_EXTENDED 0x2A +#define FCP_SCSI_WRITE_LONG 0xEA +#define FCP_SCSI_RELEASE_LUNR 0xBB +#define FCP_SCSI_RELEASE_LUNV 0xBF + +#define HPVA_SETPASSTHROUGHMODE 0x27 +#define HPVA_EXECUTEPASSTHROUGH 0x29 +#define HPVA_CREATELUN 0xE2 +#define HPVA_SETLUNSECURITYLIST 0xED +#define HPVA_SETCLOCK 0xF9 +#define HPVA_RECOVER 0xFA +#define HPVA_GENERICSERVICEOUT 0xFD + +#define DMEP_EXPORT_IN 0x85 +#define DMEP_EXPORT_OUT 0x89 + +#define MDACIOCTL_DIRECT_CMD 0x22 +#define MDACIOCTL_STOREIMAGE 0x2C +#define MDACIOCTL_WRITESIGNATURE 0xA6 +#define MDACIOCTL_SETREALTIMECLOCK 0xAC +#define MDACIOCTL_PASS_THRU_CDB 0xAD +#define MDACIOCTL_PASS_THRU_INITIATE 0xAE +#define MDACIOCTL_CREATENEWCONF 0xC0 +#define MDACIOCTL_ADDNEWCONF 0xC4 +#define MDACIOCTL_MORE 0xC6 +#define MDACIOCTL_SETPHYSDEVPARAMETER 0xC8 +#define MDACIOCTL_SETLOGDEVPARAMETER 0xCF +#define MDACIOCTL_SETCONTROLLERPARAMETER 0xD1 +#define MDACIOCTL_WRITESANMAP 0xD4 +#define MDACIOCTL_SETMACADDRESS 0xD5 + +/* + * End of FCP specific structures + */ + +#define FL_ALPA 0x00 /* AL_PA of FL_Port */ + +/* Fibre Channel Service Parameter definitions */ + +#define FC_PH_4_0 6 /* FC-PH version 4.0 */ +#define FC_PH_4_1 7 /* FC-PH version 4.1 */ +#define FC_PH_4_2 8 /* FC-PH version 4.2 */ +#define FC_PH_4_3 9 /* FC-PH version 4.3 */ + +#define FC_PH_LOW 8 /* Lowest supported FC-PH version */ +#define FC_PH_HIGH 9 /* Highest supported FC-PH version */ +#define FC_PH3 0x20 /* FC-PH-3 version */ + +#define FF_FRAME_SIZE 2048 + + +/* ==== Mailbox Commands ==== */ +#define MBX_SHUTDOWN 0x00 /* terminate testing */ +#define MBX_LOAD_SM 0x01 +#define MBX_READ_NV 0x02 +#define MBX_WRITE_NV 0x03 +#define MBX_RUN_BIU_DIAG 0x04 +#define MBX_INIT_LINK 0x05 +#define MBX_DOWN_LINK 0x06 +#define MBX_CONFIG_LINK 0x07 +#define MBX_PART_SLIM 0x08 +#define MBX_CONFIG_RING 0x09 +#define MBX_RESET_RING 0x0A +#define MBX_READ_CONFIG 0x0B +#define MBX_READ_RCONFIG 0x0C +#define MBX_READ_SPARM 0x0D +#define MBX_READ_STATUS 0x0E +#define MBX_READ_RPI 0x0F +#define MBX_READ_XRI 0x10 +#define MBX_READ_REV 0x11 +#define MBX_READ_LNK_STAT 0x12 +#define MBX_REG_LOGIN 0x13 +#define MBX_UNREG_LOGIN 0x14 +#define MBX_READ_LA 0x15 +#define MBX_CLEAR_LA 0x16 +#define MBX_DUMP_MEMORY 0x17 +#define MBX_DUMP_CONTEXT 0x18 +#define MBX_RUN_DIAGS 0x19 +#define MBX_RESTART 0x1A +#define MBX_UPDATE_CFG 0x1B +#define MBX_DOWN_LOAD 0x1C +#define MBX_DEL_LD_ENTRY 0x1D +#define MBX_RUN_PROGRAM 0x1E +#define MBX_SET_MASK 0x20 +#define MBX_SET_SLIM 0x21 +#define MBX_UNREG_D_ID 0x23 +#define MBX_CONFIG_FARP 0x25 + +#define MBX_LOAD_AREA 0x81 +#define MBX_RUN_BIU_DIAG64 0x84 +#define MBX_CONFIG_PORT 0x88 +#define MBX_READ_SPARM64 0x8D +#define MBX_READ_RPI64 0x8F +#define MBX_REG_LOGIN64 0x93 +#define MBX_READ_LA64 0x95 + +#define MBX_FLASH_WR_ULA 0x98 +#define MBX_SET_DEBUG 0x99 +#define MBX_LOAD_EXP_ROM 0x9C + +#define MBX_MAX_CMDS 0x9D +#define MBX_SLI2_CMD_MASK 0x80 + + +/* ==== IOCB Commands ==== */ + +#define CMD_RCV_SEQUENCE_CX 0x01 +#define CMD_XMIT_SEQUENCE_CR 0x02 +#define CMD_XMIT_SEQUENCE_CX 0x03 +#define CMD_XMIT_BCAST_CN 0x04 +#define CMD_XMIT_BCAST_CX 0x05 +#define CMD_QUE_RING_BUF_CN 0x06 +#define CMD_QUE_XRI_BUF_CX 0x07 +#define CMD_IOCB_CONTINUE_CN 0x08 +#define CMD_RET_XRI_BUF_CX 0x09 +#define CMD_ELS_REQUEST_CR 0x0A +#define CMD_ELS_REQUEST_CX 0x0B +#define CMD_RCV_ELS_REQ_CX 0x0D +#define CMD_ABORT_XRI_CN 0x0E +#define CMD_ABORT_XRI_CX 0x0F +#define CMD_CLOSE_XRI_CR 0x10 +#define CMD_CLOSE_XRI_CX 0x11 +#define CMD_CREATE_XRI_CR 0x12 +#define CMD_CREATE_XRI_CX 0x13 +#define CMD_GET_RPI_CN 0x14 +#define CMD_XMIT_ELS_RSP_CX 0x15 +#define CMD_GET_RPI_CR 0x16 +#define CMD_XRI_ABORTED_CX 0x17 +#define CMD_FCP_IWRITE_CR 0x18 +#define CMD_FCP_IWRITE_CX 0x19 +#define CMD_FCP_IREAD_CR 0x1A +#define CMD_FCP_IREAD_CX 0x1B +#define CMD_FCP_ICMND_CR 0x1C +#define CMD_FCP_ICMND_CX 0x1D +#define CMD_ADAPTER_MSG 0x20 +#define CMD_ADAPTER_DUMP 0x22 +#define CMD_BPL_IWRITE_CR 0x48 +#define CMD_BPL_IWRITE_CX 0x49 +#define CMD_BPL_IREAD_CR 0x4A +#define CMD_BPL_IREAD_CX 0x4B +#define CMD_BPL_ICMND_CR 0x4C +#define CMD_BPL_ICMND_CX 0x4D + +/* SLI_2 IOCB Command Set */ + +#define CMD_RCV_SEQUENCE64_CX 0x81 +#define CMD_XMIT_SEQUENCE64_CR 0x82 +#define CMD_XMIT_SEQUENCE64_CX 0x83 +#define CMD_XMIT_BCAST64_CN 0x84 +#define CMD_XMIT_BCAST64_CX 0x85 +#define CMD_QUE_RING_BUF64_CN 0x86 +#define CMD_QUE_XRI_BUF64_CX 0x87 +#define CMD_IOCB_CONTINUE64_CN 0x88 +#define CMD_RET_XRI_BUF64_CX 0x89 +#define CMD_ELS_REQUEST64_CR 0x8A +#define CMD_ELS_REQUEST64_CX 0x8B +#define CMD_RCV_ELS_REQ64_CX 0x8D +#define CMD_XMIT_ELS_RSP64_CX 0x95 +#define CMD_FCP_IWRITE64_CR 0x98 +#define CMD_FCP_IWRITE64_CX 0x99 +#define CMD_FCP_IREAD64_CR 0x9A +#define CMD_FCP_IREAD64_CX 0x9B +#define CMD_FCP_ICMND64_CR 0x9C +#define CMD_FCP_ICMND64_CX 0x9D +#define CMD_GEN_REQUEST64_CR 0xC2 +#define CMD_GEN_REQUEST64_CX 0xC3 + + +/* + * Define Status + */ +#define MBX_SUCCESS 0 +#define MBXERR_NUM_RINGS 1 +#define MBXERR_NUM_IOCBS 2 +#define MBXERR_IOCBS_EXCEEDED 3 +#define MBXERR_BAD_RING_NUMBER 4 +#define MBXERR_MASK_ENTRIES_RANGE 5 +#define MBXERR_MASKS_EXCEEDED 6 +#define MBXERR_BAD_PROFILE 7 +#define MBXERR_BAD_DEF_CLASS 8 +#define MBXERR_BAD_MAX_RESPONDER 9 +#define MBXERR_BAD_MAX_ORIGINATOR 10 +#define MBXERR_RPI_REGISTERED 11 +#define MBXERR_RPI_FULL 12 +#define MBXERR_NO_RESOURCES 13 +#define MBXERR_BAD_RCV_LENGTH 14 +#define MBXERR_DMA_ERROR 15 +#define MBXERR_ERROR 16 +#define MBX_NOT_FINISHED 255 +/* + * Error codes returned by issue_mb_cmd() + */ +#define MBX_BUSY 0xffffff /* Attempted cmd to a busy Mailbox */ +#define MBX_TIMEOUT 0xfffffe /* Max time-out expired waiting for */ +/* synch. Mailbox operation */ +/* + * flags for issue_mb_cmd() + */ +#define MBX_POLL 1 /* poll mailbox till command done, then return */ +#define MBX_SLEEP 2 /* sleep till mailbox intr cmpl wakes thread up */ +#define MBX_NOWAIT 3 /* issue command then return immediately */ + +typedef struct { +#if BIG_ENDIAN_HW + u32bit crReserved :16; + u32bit crBegin : 8; + u32bit crEnd : 8; /* Low order bit first word */ + u32bit rrReserved :16; + u32bit rrBegin : 8; + u32bit rrEnd : 8; /* Low order bit second word */ +#endif +#if LITTLE_ENDIAN_HW + u32bit crEnd : 8; /* Low order bit first word */ + u32bit crBegin : 8; + u32bit crReserved :16; + u32bit rrEnd : 8; /* Low order bit second word */ + u32bit rrBegin : 8; + u32bit rrReserved :16; +#endif +} RINGS; + + +typedef struct { +#if BIG_ENDIAN_HW + ushort offCiocb; + ushort numCiocb; + ushort offRiocb; + ushort numRiocb; +#endif +#if LITTLE_ENDIAN_HW + ushort numCiocb; + ushort offCiocb; + ushort numRiocb; + ushort offRiocb; +#endif +} RING_DEF; + + +/* + * The following F.C. frame stuctures are defined in Big Endian format. + */ + +typedef struct _NAME_TYPE { +#if BIG_ENDIAN_HW + u8bit nameType : 4; /* FC Word 0, bit 28:31 */ + u8bit IEEEextMsn : 4; /* FC Word 0, bit 24:27, bit 8:11 of IEEE ext */ +#endif +#if LITTLE_ENDIAN_HW + u8bit IEEEextMsn : 4; /* FC Word 0, bit 24:27, bit 8:11 of IEEE ext */ + u8bit nameType : 4; /* FC Word 0, bit 28:31 */ +#endif +#define NAME_IEEE 0x1 /* IEEE name - nameType */ +#define NAME_IEEE_EXT 0x2 /* IEEE extended name */ +#define NAME_FC_TYPE 0x3 /* FC native name type */ +#define NAME_IP_TYPE 0x4 /* IP address */ +#define NAME_CCITT_TYPE 0xC +#define NAME_CCITT_GR_TYPE 0xE + uchar IEEEextLsb; /* FC Word 0, bit 16:23, IEEE extended Lsb */ + uchar IEEE[6]; /* FC IEEE address */ +} NAME_TYPE; + + +typedef struct _CSP { + uchar fcphHigh; /* FC Word 0, byte 0 */ + uchar fcphLow; + uchar bbCreditMsb; + uchar bbCreditlsb; /* FC Word 0, byte 3 */ +#if BIG_ENDIAN_HW + u16bit increasingOffset : 1; /* FC Word 1, bit 31 */ + u16bit randomOffset : 1; /* FC Word 1, bit 30 */ + u16bit word1Reserved2 : 1; /* FC Word 1, bit 29 */ + u16bit fPort : 1; /* FC Word 1, bit 28 */ + u16bit altBbCredit : 1; /* FC Word 1, bit 27 */ + u16bit edtovResolution : 1; /* FC Word 1, bit 26 */ + u16bit multicast : 1; /* FC Word 1, bit 25 */ + u16bit broadcast : 1; /* FC Word 1, bit 24 */ + + u16bit huntgroup : 1; /* FC Word 1, bit 23 */ + u16bit simplex : 1; /* FC Word 1, bit 22 */ + u16bit word1Reserved1 : 3; /* FC Word 1, bit 21:19 */ + u16bit dhd : 1; /* FC Word 1, bit 18 */ + u16bit contIncSeqCnt : 1; /* FC Word 1, bit 17 */ + u16bit payloadlength : 1; /* FC Word 1, bit 16 */ +#endif +#if LITTLE_ENDIAN_HW + u16bit broadcast : 1; /* FC Word 1, bit 24 */ + u16bit multicast : 1; /* FC Word 1, bit 25 */ + u16bit edtovResolution : 1; /* FC Word 1, bit 26 */ + u16bit altBbCredit : 1; /* FC Word 1, bit 27 */ + u16bit fPort : 1; /* FC Word 1, bit 28 */ + u16bit word1Reserved2 : 1; /* FC Word 1, bit 29 */ + u16bit randomOffset : 1; /* FC Word 1, bit 30 */ + u16bit increasingOffset : 1; /* FC Word 1, bit 31 */ + + u16bit payloadlength : 1; /* FC Word 1, bit 16 */ + u16bit contIncSeqCnt : 1; /* FC Word 1, bit 17 */ + u16bit dhd : 1; /* FC Word 1, bit 18 */ + u16bit word1Reserved1 : 3; /* FC Word 1, bit 21:19 */ + u16bit simplex : 1; /* FC Word 1, bit 22 */ + u16bit huntgroup : 1; /* FC Word 1, bit 23 */ +#endif + uchar bbRcvSizeMsb; /* Upper nibble is reserved */ + + uchar bbRcvSizeLsb; /* FC Word 1, byte 3 */ + union { + struct { + uchar word2Reserved1; /* FC Word 2 byte 0 */ + + uchar totalConcurrSeq; /* FC Word 2 byte 1 */ + uchar roByCategoryMsb; /* FC Word 2 byte 2 */ + + uchar roByCategoryLsb; /* FC Word 2 byte 3 */ + } nPort; + uint32 r_a_tov; /* R_A_TOV must be in B.E. format */ + } w2; + + uint32 e_d_tov; /* E_D_TOV must be in B.E. format */ +} CSP; + + +typedef struct _CLASS_PARMS { +#if BIG_ENDIAN_HW + u8bit classValid : 1; /* FC Word 0, bit 31 */ + u8bit intermix : 1; /* FC Word 0, bit 30 */ + u8bit stackedXparent : 1; /* FC Word 0, bit 29 */ + u8bit stackedLockDown : 1; /* FC Word 0, bit 28 */ + u8bit seqDelivery : 1; /* FC Word 0, bit 27 */ + u8bit word0Reserved1 : 3; /* FC Word 0, bit 24:26 */ +#endif +#if LITTLE_ENDIAN_HW + u8bit word0Reserved1 : 3; /* FC Word 0, bit 24:26 */ + u8bit seqDelivery : 1; /* FC Word 0, bit 27 */ + u8bit stackedLockDown : 1; /* FC Word 0, bit 28 */ + u8bit stackedXparent : 1; /* FC Word 0, bit 29 */ + u8bit intermix : 1; /* FC Word 0, bit 30 */ + u8bit classValid : 1; /* FC Word 0, bit 31 */ + +#endif + uchar word0Reserved2; /* FC Word 0, bit 16:23 */ +#if BIG_ENDIAN_HW + u8bit iCtlXidReAssgn : 2; /* FC Word 0, Bit 14:15 */ + u8bit iCtlInitialPa : 2; /* FC Word 0, bit 12:13 */ + u8bit iCtlAck0capable : 1; /* FC Word 0, bit 11 */ + u8bit iCtlAckNcapable : 1; /* FC Word 0, bit 10 */ + u8bit word0Reserved3 : 2; /* FC Word 0, bit 8: 9 */ +#endif +#if LITTLE_ENDIAN_HW + u8bit word0Reserved3 : 2; /* FC Word 0, bit 8: 9 */ + u8bit iCtlAckNcapable : 1; /* FC Word 0, bit 10 */ + u8bit iCtlAck0capable : 1; /* FC Word 0, bit 11 */ + u8bit iCtlInitialPa : 2; /* FC Word 0, bit 12:13 */ + u8bit iCtlXidReAssgn : 2; /* FC Word 0, Bit 14:15 */ +#endif + uchar word0Reserved4; /* FC Word 0, bit 0: 7 */ +#if BIG_ENDIAN_HW + u8bit rCtlAck0capable : 1; /* FC Word 1, bit 31 */ + u8bit rCtlAckNcapable : 1; /* FC Word 1, bit 30 */ + u8bit rCtlXidInterlck : 1; /* FC Word 1, bit 29 */ + u8bit rCtlErrorPolicy : 2; /* FC Word 1, bit 27:28 */ + u8bit word1Reserved1 : 1; /* FC Word 1, bit 26 */ + u8bit rCtlCatPerSeq : 2; /* FC Word 1, bit 24:25 */ +#endif +#if LITTLE_ENDIAN_HW + u8bit rCtlCatPerSeq : 2; /* FC Word 1, bit 24:25 */ + u8bit word1Reserved1 : 1; /* FC Word 1, bit 26 */ + u8bit rCtlErrorPolicy : 2; /* FC Word 1, bit 27:28 */ + u8bit rCtlXidInterlck : 1; /* FC Word 1, bit 29 */ + u8bit rCtlAckNcapable : 1; /* FC Word 1, bit 30 */ + u8bit rCtlAck0capable : 1; /* FC Word 1, bit 31 */ +#endif + uchar word1Reserved2; /* FC Word 1, bit 16:23 */ + uchar rcvDataSizeMsb; /* FC Word 1, bit 8:15 */ + uchar rcvDataSizeLsb; /* FC Word 1, bit 0: 7 */ + + uchar concurrentSeqMsb; /* FC Word 2, bit 24:31 */ + uchar concurrentSeqLsb; /* FC Word 2, bit 16:23 */ + uchar EeCreditSeqMsb; /* FC Word 2, bit 8:15 */ + uchar EeCreditSeqLsb; /* FC Word 2, bit 0: 7 */ + + uchar openSeqPerXchgMsb; /* FC Word 3, bit 24:31 */ + uchar openSeqPerXchgLsb; /* FC Word 3, bit 16:23 */ + uchar word3Reserved1; /* Fc Word 3, bit 8:15 */ + uchar word3Reserved2; /* Fc Word 3, bit 0: 7 */ +} CLASS_PARMS; + + +typedef struct _SERV_PARM { /* Structure is in Big Endian format */ + CSP cmn; + NAME_TYPE portName; + NAME_TYPE nodeName; + CLASS_PARMS cls1; + CLASS_PARMS cls2; + CLASS_PARMS cls3; + CLASS_PARMS cls4; + uchar vendorVersion[16]; +} SERV_PARM, *PSERV_PARM; + + +/* + * Extended Link Service LS_COMMAND codes (Payload Word 0) + */ +#if BIG_ENDIAN_HW +#define ELS_CMD_MASK 0xffff0000 +#define ELS_RSP_MASK 0xff000000 +#define ELS_CMD_LS_RJT 0x01000000 +#define ELS_CMD_ACC 0x02000000 +#define ELS_CMD_PLOGI 0x03000000 +#define ELS_CMD_FLOGI 0x04000000 +#define ELS_CMD_LOGO 0x05000000 +#define ELS_CMD_ABTX 0x06000000 +#define ELS_CMD_RCS 0x07000000 +#define ELS_CMD_RES 0x08000000 +#define ELS_CMD_RSS 0x09000000 +#define ELS_CMD_RSI 0x0A000000 +#define ELS_CMD_ESTS 0x0B000000 +#define ELS_CMD_ESTC 0x0C000000 +#define ELS_CMD_ADVC 0x0D000000 +#define ELS_CMD_RTV 0x0E000000 +#define ELS_CMD_RLS 0x0F000000 +#define ELS_CMD_ECHO 0x10000000 +#define ELS_CMD_TEST 0x11000000 +#define ELS_CMD_RRQ 0x12000000 +#define ELS_CMD_PRLI 0x20100014 +#define ELS_CMD_PRLO 0x21100014 +#define ELS_CMD_PDISC 0x50000000 +#define ELS_CMD_FDISC 0x51000000 +#define ELS_CMD_ADISC 0x52000000 +#define ELS_CMD_FARP 0x54000000 +#define ELS_CMD_FARPR 0x55000000 +#define ELS_CMD_FAN 0x60000000 +#define ELS_CMD_RSCN 0x61040000 +#define ELS_CMD_SCR 0x62000000 +#define ELS_CMD_RNID 0x78000000 +#endif +#if LITTLE_ENDIAN_HW +#define ELS_CMD_MASK 0xffff +#define ELS_RSP_MASK 0xff +#define ELS_CMD_LS_RJT 0x01 +#define ELS_CMD_ACC 0x02 +#define ELS_CMD_PLOGI 0x03 +#define ELS_CMD_FLOGI 0x04 +#define ELS_CMD_LOGO 0x05 +#define ELS_CMD_ABTX 0x06 +#define ELS_CMD_RCS 0x07 +#define ELS_CMD_RES 0x08 +#define ELS_CMD_RSS 0x09 +#define ELS_CMD_RSI 0x0A +#define ELS_CMD_ESTS 0x0B +#define ELS_CMD_ESTC 0x0C +#define ELS_CMD_ADVC 0x0D +#define ELS_CMD_RTV 0x0E +#define ELS_CMD_RLS 0x0F +#define ELS_CMD_ECHO 0x10 +#define ELS_CMD_TEST 0x11 +#define ELS_CMD_RRQ 0x12 +#define ELS_CMD_PRLI 0x14001020 +#define ELS_CMD_PRLO 0x14001021 +#define ELS_CMD_PDISC 0x50 +#define ELS_CMD_FDISC 0x51 +#define ELS_CMD_ADISC 0x52 +#define ELS_CMD_FARP 0x54 +#define ELS_CMD_FARPR 0x55 +#define ELS_CMD_FAN 0x60 +#define ELS_CMD_RSCN 0x0461 +#define ELS_CMD_SCR 0x62 +#define ELS_CMD_RNID 0x78 +#endif + + +/* + * LS_RJT Payload Definition + */ + +typedef struct _LS_RJT { /* Structure is in Big Endian format */ + union { + uint32 lsRjtError; + struct { + uchar lsRjtRsvd0; /* FC Word 0, bit 24:31 */ + + uchar lsRjtRsnCode; /* FC Word 0, bit 16:23 */ + /* LS_RJT reason codes */ +#define LSRJT_INVALID_CMD 0x01 +#define LSRJT_LOGICAL_ERR 0x03 +#define LSRJT_LOGICAL_BSY 0x05 +#define LSRJT_PROTOCOL_ERR 0x07 +#define LSRJT_UNABLE_TPC 0x09 /* Unable to perform command */ +#define LSRJT_CMD_UNSUPPORTED 0x0B +#define LSRJT_VENDOR_UNIQUE 0xFF /* See Byte 3 */ + + uchar lsRjtRsnCodeExp; /* FC Word 0, bit 8:15 */ + /* LS_RJT reason explanation */ +#define LSEXP_NOTHING_MORE 0x00 +#define LSEXP_SPARM_OPTIONS 0x01 +#define LSEXP_SPARM_ICTL 0x03 +#define LSEXP_SPARM_RCTL 0x05 +#define LSEXP_SPARM_RCV_SIZE 0x07 +#define LSEXP_SPARM_CONCUR_SEQ 0x09 +#define LSEXP_SPARM_CREDIT 0x0B +#define LSEXP_INVALID_PNAME 0x0D +#define LSEXP_INVALID_NNAME 0x0E +#define LSEXP_INVALID_CSP 0x0F +#define LSEXP_INVALID_ASSOC_HDR 0x11 +#define LSEXP_ASSOC_HDR_REQ 0x13 +#define LSEXP_INVALID_O_SID 0x15 +#define LSEXP_INVALID_OX_RX 0x17 +#define LSEXP_CMD_IN_PROGRESS 0x19 +#define LSEXP_INVALID_NPORT_ID 0x1F +#define LSEXP_INVALID_SEQ_ID 0x21 +#define LSEXP_INVALID_XCHG 0x23 +#define LSEXP_INACTIVE_XCHG 0x25 +#define LSEXP_RQ_REQUIRED 0x27 +#define LSEXP_OUT_OF_RESOURCE 0x29 +#define LSEXP_CANT_GIVE_DATA 0x2A +#define LSEXP_REQ_UNSUPPORTED 0x2C + uchar vendorUnique; /* FC Word 0, bit 0: 7 */ + } b; + } un; +} LS_RJT; + + +/* + * N_Port Login (FLOGO/PLOGO Request) Payload Definition + */ + +typedef struct _LOGO { /* Structure is in Big Endian format */ + union { + uint32 nPortId32; /* Access nPortId as a word */ + struct { + uchar word1Reserved1; /* FC Word 1, bit 31:24 */ + uchar nPortIdByte0; /* N_port ID bit 16:23 */ + uchar nPortIdByte1; /* N_port ID bit 8:15 */ + uchar nPortIdByte2; /* N_port ID bit 0: 7 */ + } b; + } un; + NAME_TYPE portName; /* N_port name field */ +} LOGO; + + +/* + * FCP Login (PRLI Request / ACC) Payload Definition + */ + +#define PRLX_PAGE_LEN 0x10 +#define TPRLO_PAGE_LEN 0x14 + +typedef struct _PRLI { /* Structure is in Big Endian format */ + uchar prliType; /* FC Parm Word 0, bit 24:31 */ + +#define PRLI_FCP_TYPE 0x08 + uchar word0Reserved1; /* FC Parm Word 0, bit 16:23 */ + +#if BIG_ENDIAN_HW + u8bit origProcAssocV : 1; /* FC Parm Word 0, bit 15 */ + u8bit respProcAssocV : 1; /* FC Parm Word 0, bit 14 */ + u8bit estabImagePair : 1; /* FC Parm Word 0, bit 13 */ + + u8bit word0Reserved2 : 1; /* FC Parm Word 0, bit 12 */ + u8bit acceptRspCode : 4; /* FC Parm Word 0, bit 8:11, ACC ONLY */ +#endif +#if LITTLE_ENDIAN_HW + u8bit acceptRspCode : 4; /* FC Parm Word 0, bit 8:11, ACC ONLY */ + u8bit word0Reserved2 : 1; /* FC Parm Word 0, bit 12 */ + u8bit estabImagePair : 1; /* FC Parm Word 0, bit 13 */ + u8bit respProcAssocV : 1; /* FC Parm Word 0, bit 14 */ + u8bit origProcAssocV : 1; /* FC Parm Word 0, bit 15 */ +#endif +#define PRLI_REQ_EXECUTED 0x1 /* acceptRspCode */ +#define PRLI_NO_RESOURCES 0x2 +#define PRLI_INIT_INCOMPLETE 0x3 +#define PRLI_NO_SUCH_PA 0x4 +#define PRLI_PREDEF_CONFIG 0x5 +#define PRLI_PARTIAL_SUCCESS 0x6 +#define PRLI_INVALID_PAGE_CNT 0x7 + uchar word0Reserved3; /* FC Parm Word 0, bit 0:7 */ + + uint32 origProcAssoc; /* FC Parm Word 1, bit 0:31 */ + + uint32 respProcAssoc; /* FC Parm Word 2, bit 0:31 */ + + uchar word3Reserved1; /* FC Parm Word 3, bit 24:31 */ + uchar word3Reserved2; /* FC Parm Word 3, bit 16:23 */ +#if BIG_ENDIAN_HW + u16bit Word3bit15Resved : 1; /* FC Parm Word 3, bit 15 */ + u16bit Word3bit14Resved : 1; /* FC Parm Word 3, bit 14 */ + u16bit Word3bit13Resved : 1; /* FC Parm Word 3, bit 13 */ + u16bit Word3bit12Resved : 1; /* FC Parm Word 3, bit 12 */ + u16bit Word3bit11Resved : 1; /* FC Parm Word 3, bit 11 */ + u16bit Word3bit10Resved : 1; /* FC Parm Word 3, bit 10 */ + u16bit TaskRetryIdReq : 1; /* FC Parm Word 3, bit 9 */ + u16bit Retry : 1; /* FC Parm Word 3, bit 8 */ + u16bit ConfmComplAllowed : 1; /* FC Parm Word 3, bit 7 */ + u16bit dataOverLay : 1; /* FC Parm Word 3, bit 6 */ + u16bit initiatorFunc : 1; /* FC Parm Word 3, bit 5 */ + u16bit targetFunc : 1; /* FC Parm Word 3, bit 4 */ + u16bit cmdDataMixEna : 1; /* FC Parm Word 3, bit 3 */ + u16bit dataRspMixEna : 1; /* FC Parm Word 3, bit 2 */ + u16bit readXferRdyDis : 1; /* FC Parm Word 3, bit 1 */ + u16bit writeXferRdyDis : 1; /* FC Parm Word 3, bit 0 */ +#endif +#if LITTLE_ENDIAN_HW + u16bit Retry : 1; /* FC Parm Word 3, bit 8 */ + u16bit TaskRetryIdReq : 1; /* FC Parm Word 3, bit 9 */ + u16bit Word3bit10Resved : 1; /* FC Parm Word 3, bit 10 */ + u16bit Word3bit11Resved : 1; /* FC Parm Word 3, bit 11 */ + u16bit Word3bit12Resved : 1; /* FC Parm Word 3, bit 12 */ + u16bit Word3bit13Resved : 1; /* FC Parm Word 3, bit 13 */ + u16bit Word3bit14Resved : 1; /* FC Parm Word 3, bit 14 */ + u16bit Word3bit15Resved : 1; /* FC Parm Word 3, bit 15 */ + u16bit writeXferRdyDis : 1; /* FC Parm Word 3, bit 0 */ + u16bit readXferRdyDis : 1; /* FC Parm Word 3, bit 1 */ + u16bit dataRspMixEna : 1; /* FC Parm Word 3, bit 2 */ + u16bit cmdDataMixEna : 1; /* FC Parm Word 3, bit 3 */ + u16bit targetFunc : 1; /* FC Parm Word 3, bit 4 */ + u16bit initiatorFunc : 1; /* FC Parm Word 3, bit 5 */ + u16bit dataOverLay : 1; /* FC Parm Word 3, bit 6 */ + u16bit ConfmComplAllowed : 1; /* FC Parm Word 3, bit 7 */ +#endif +} PRLI; + +/* + * FCP Logout (PRLO Request / ACC) Payload Definition + */ + +typedef struct _PRLO { /* Structure is in Big Endian format */ + uchar prloType; /* FC Parm Word 0, bit 24:31 */ + +#define PRLO_FCP_TYPE 0x08 + uchar word0Reserved1; /* FC Parm Word 0, bit 16:23 */ + +#if BIG_ENDIAN_HW + u8bit origProcAssocV : 1; /* FC Parm Word 0, bit 15 */ + u8bit respProcAssocV : 1; /* FC Parm Word 0, bit 14 */ + u8bit word0Reserved2 : 2; /* FC Parm Word 0, bit 12:13 */ + u8bit acceptRspCode : 4; /* FC Parm Word 0, bit 8:11, ACC ONLY */ +#endif +#if LITTLE_ENDIAN_HW + u8bit acceptRspCode : 4; /* FC Parm Word 0, bit 8:11, ACC ONLY */ + u8bit word0Reserved2 : 2; /* FC Parm Word 0, bit 12:13 */ + u8bit respProcAssocV : 1; /* FC Parm Word 0, bit 14 */ + u8bit origProcAssocV : 1; /* FC Parm Word 0, bit 15 */ +#endif +#define PRLO_REQ_EXECUTED 0x1 /* acceptRspCode */ +#define PRLO_NO_SUCH_IMAGE 0x4 +#define PRLO_INVALID_PAGE_CNT 0x7 + + uchar word0Reserved3; /* FC Parm Word 0, bit 0:7 */ + + uint32 origProcAssoc; /* FC Parm Word 1, bit 0:31 */ + + uint32 respProcAssoc; /* FC Parm Word 2, bit 0:31 */ + + uint32 word3Reserved1; /* FC Parm Word 3, bit 0:31 */ +} PRLO; + + +typedef struct _ADISC { /* Structure is in Big Endian format */ + uint32 hardAL_PA; + NAME_TYPE portName; + NAME_TYPE nodeName; + uint32 DID; +} ADISC; + + +typedef struct _FARP { /* Structure is in Big Endian format */ + u32bit Mflags : 8; + u32bit Odid : 24; +#define FARP_NO_ACTION 0 /* FARP information enclosed, no action */ +#define FARP_MATCH_PORT 0x1 /* Match on Responder Port Name */ +#define FARP_MATCH_NODE 0x2 /* Match on Responder Node Name */ +#define FARP_MATCH_IP 0x4 /* Match on IP address, not supported */ +#define FARP_MATCH_IPV4 0x5 /* Match on IPV4 address, not supported */ +#define FARP_MATCH_IPV6 0x6 /* Match on IPV6 address, not supported */ + u32bit Rflags : 8; + u32bit Rdid : 24; +#define FARP_REQUEST_PLOGI 0x1 /* Request for PLOGI */ +#define FARP_REQUEST_FARPR 0x2 /* Request for FARP Response */ + NAME_TYPE OportName; + NAME_TYPE OnodeName; + NAME_TYPE RportName; + NAME_TYPE RnodeName; + uchar Oipaddr[16]; + uchar Ripaddr[16]; +} FARP; + +typedef struct _FAN { /* Structure is in Big Endian format */ + uint32 Fdid; + NAME_TYPE FportName; + NAME_TYPE FnodeName; +} FAN; + +typedef struct _SCR { /* Structure is in Big Endian format */ + uchar resvd1; + uchar resvd2; + uchar resvd3; + uchar Function; +#define SCR_FUNC_FABRIC 0x01 +#define SCR_FUNC_NPORT 0x02 +#define SCR_FUNC_FULL 0x03 +#define SCR_CLEAR 0xff +} SCR; + +typedef struct _RNID_TOP_DISC { + NAME_TYPE portName; + uchar resvd[8]; + uint32 unitType; +#define RNID_HBA 0x7 +#define RNID_HOST 0xa +#define RNID_DRIVER 0xd + uint32 physPort; + uint32 attachedNodes; + ushort ipVersion; +#define RNID_IPV4 0x1 +#define RNID_IPV6 0x2 + ushort UDPport; + uchar ipAddr[16]; + ushort resvd1; + ushort flags; +#define RNID_TD_SUPPORT 0x1 +#define RNID_LP_VALID 0x2 +} RNID_TOP_DISC; + +typedef struct _RNID { /* Structure is in Big Endian format */ + uchar Format; +#define RNID_TOPOLOGY_DISC 0xdf + uchar CommonLen; + uchar resvd1; + uchar SpecificLen; + NAME_TYPE portName; + NAME_TYPE nodeName; + union { + RNID_TOP_DISC topologyDisc; /* topology disc (0xdf) */ + } un; +} RNID; + +typedef struct _RRQ { /* Structure is in Big Endian format */ + uint32 SID; + ushort Oxid; + ushort Rxid; + uchar resv[32]; /* optional association hdr */ +} RRQ; + + +/* This is used for RSCN command */ +typedef struct _D_ID { /* Structure is in Big Endian format */ + union { + uint32 word; + struct { +#if BIG_ENDIAN_HW + uchar resv; + uchar domain; + uchar area; + uchar id; +#endif +#if LITTLE_ENDIAN_HW + uchar id; + uchar area; + uchar domain; + uchar resv; +#endif + } b; + } un; +} D_ID; + +/* + * Structure to define all ELS Payload types + */ + +typedef struct _ELS_PKT { /* Structure is in Big Endian format */ + uchar elsCode; /* FC Word 0, bit 24:31 */ + uchar elsByte1; + uchar elsByte2; + uchar elsByte3; + union { + LS_RJT lsRjt; /* Payload for LS_RJT ELS response */ + SERV_PARM logi; /* Payload for PLOGI/FLOGI/PDISC/ACC */ + LOGO logo; /* Payload for PLOGO/FLOGO/ACC */ + PRLI prli; /* Payload for PRLI/ACC */ + PRLO prlo; /* Payload for PRLO/ACC */ + ADISC adisc; /* Payload for ADISC/ACC */ + FARP farp; /* Payload for FARP/ACC */ + FAN fan; /* Payload for FAN */ + SCR scr; /* Payload for SCR/ACC */ + RRQ rrq; /* Payload for RRQ */ + RNID rnid; /* Payload for RNID */ + uchar pad[128-4]; /* Pad out to payload of 128 bytes */ + } un; +} ELS_PKT; + + +/* + * Begin Structure Definitions for Mailbox Commands + */ + +typedef struct { +#if BIG_ENDIAN_HW + uchar tval; + uchar tmask; + uchar rval; + uchar rmask; +#endif +#if LITTLE_ENDIAN_HW + uchar rmask; + uchar rval; + uchar tmask; + uchar tval; +#endif +} RR_REG; + +typedef struct { + uint32 bdeAddress; +#if BIG_ENDIAN_HW + u32bit bdeReserved : 4; + u32bit bdeAddrHigh : 4; + u32bit bdeSize : 24; +#endif +#if LITTLE_ENDIAN_HW + u32bit bdeSize : 24; + u32bit bdeAddrHigh : 4; + u32bit bdeReserved : 4; +#endif +} ULP_BDE; + +typedef struct ULP_BDE_64 { /* SLI-2 */ + union ULP_BDE_TUS { + uint32 w; + struct { +#if BIG_ENDIAN_HW + u32bit bdeFlags : 8; + u32bit bdeSize : 24; /* Size of buffer (in bytes) */ +#endif +#if LITTLE_ENDIAN_HW + u32bit bdeSize : 24; /* Size of buffer (in bytes) */ + u32bit bdeFlags : 8; +#endif +#define BUFF_USE_RSVD 0x01 /* bdeFlags */ +#define BUFF_USE_INTRPT 0x02 +#define BUFF_USE_CMND 0x04 /* Optional, 1=cmd/rsp 0=data buffer */ +#define BUFF_USE_RCV 0x08 /* "" "", 1=rcv buffer, 0=xmit buffer */ +#define BUFF_TYPE_32BIT 0x10 /* "" "", 1=32 bit addr 0=64 bit addr */ +#define BUFF_TYPE_SPECIAL 0x20 +#define BUFF_TYPE_BDL 0x40 /* Optional, may be set in BDL */ +#define BUFF_TYPE_INVALID 0x80 /* "" "" */ + } f; + } tus; + uint32 addrLow; + uint32 addrHigh; +} ULP_BDE64; +#define BDE64_SIZE_WORD 0 +#define BPL64_SIZE_WORD 0x40 + +typedef struct ULP_BDL { /* SLI-2 */ +#if BIG_ENDIAN_HW + u32bit bdeFlags : 8; /* BDL Flags */ + u32bit bdeSize : 24; /* Size of BDL array in host memory (bytes) */ +#endif +#if LITTLE_ENDIAN_HW + u32bit bdeSize : 24; /* Size of BDL array in host memory (bytes) */ + u32bit bdeFlags : 8; /* BDL Flags */ +#endif + uint32 addrLow; /* Address 0:31 */ + uint32 addrHigh; /* Address 32:63 */ + uint32 ulpIoTag32; /* Can be used for 32 bit I/O Tag */ +} ULP_BDL; + + +/* Structure for MB Command LOAD_SM and DOWN_LOAD */ + +typedef struct { +#if BIG_ENDIAN_HW + u32bit rsvd2 :25; + u32bit acknowledgment : 1; + u32bit version : 1; + u32bit erase_or_prog : 1; + u32bit update_flash : 1; + u32bit update_ram : 1; + u32bit method : 1; + u32bit load_cmplt : 1; +#endif +#if LITTLE_ENDIAN_HW + u32bit load_cmplt : 1; + u32bit method : 1; + u32bit update_ram : 1; + u32bit update_flash : 1; + u32bit erase_or_prog : 1; + u32bit version : 1; + u32bit acknowledgment : 1; + u32bit rsvd2 :25; +#endif + +#define DL_FROM_BDE 0 /* method */ +#define DL_FROM_SLIM 1 + + uint32 dl_to_adr_low; + uint32 dl_to_adr_high; + uint32 dl_len; + union { + uint32 dl_from_mbx_offset; + ULP_BDE dl_from_bde; + ULP_BDE64 dl_from_bde64; + } un; + +} LOAD_SM_VAR; + + +/* Structure for MB Command READ_NVPARM (02) */ + +typedef struct { + uint32 rsvd1[3]; /* Read as all one's */ + uint32 rsvd2; /* Read as all zero's */ + uint32 portname[2]; /* N_PORT name */ + uint32 nodename[2]; /* NODE name */ +#if BIG_ENDIAN_HW + u32bit pref_DID : 24; + u32bit hardAL_PA : 8; +#endif +#if LITTLE_ENDIAN_HW + u32bit hardAL_PA : 8; + u32bit pref_DID : 24; +#endif + uint32 rsvd3[21]; /* Read as all one's */ +} READ_NV_VAR; + + +/* Structure for MB Command WRITE_NVPARMS (03) */ + +typedef struct { + uint32 rsvd1[3]; /* Must be all one's */ + uint32 rsvd2; /* Must be all zero's */ + uint32 portname[2]; /* N_PORT name */ + uint32 nodename[2]; /* NODE name */ +#if BIG_ENDIAN_HW + u32bit pref_DID : 24; + u32bit hardAL_PA : 8; +#endif +#if LITTLE_ENDIAN_HW + u32bit hardAL_PA : 8; + u32bit pref_DID : 24; +#endif + uint32 rsvd3[21]; /* Must be all one's */ +} WRITE_NV_VAR; + + +/* Structure for MB Command RUN_BIU_DIAG (04) */ +/* Structure for MB Command RUN_BIU_DIAG64 (0x84) */ + +typedef struct { + uint32 rsvd1; + union { + struct { + ULP_BDE xmit_bde; + ULP_BDE rcv_bde; + } s1; + struct { + ULP_BDE64 xmit_bde64; + ULP_BDE64 rcv_bde64; + } s2; + } un; +} BIU_DIAG_VAR; + + +/* Structure for MB Command INIT_LINK (05) */ + +typedef struct { +#if BIG_ENDIAN_HW + u32bit rsvd1 : 24; + u32bit lipsr_AL_PA : 8; /* AL_PA to issue Lip Selective Reset to */ +#endif +#if LITTLE_ENDIAN_HW + u32bit lipsr_AL_PA : 8; /* AL_PA to issue Lip Selective Reset to */ + u32bit rsvd1 : 24; +#endif + +#if BIG_ENDIAN_HW + uchar fabric_AL_PA; /* If using a Fabric Assigned AL_PA */ + uchar rsvd2; + ushort link_flags; +#endif +#if LITTLE_ENDIAN_HW + ushort link_flags; + uchar rsvd2; + uchar fabric_AL_PA; /* If using a Fabric Assigned AL_PA */ +#endif +#define FLAGS_LOCAL_LB 0x01 /* link_flags (=1) ENDEC loopback */ +#define FLAGS_TOPOLOGY_MODE_LOOP_PT 0x00 /* Attempt loop then pt-pt */ +#define FLAGS_TOPOLOGY_MODE_PT_PT 0x02 /* Attempt pt-pt only */ +#define FLAGS_TOPOLOGY_MODE_LOOP 0x04 /* Attempt loop only */ +#define FLAGS_TOPOLOGY_MODE_PT_LOOP 0x06 /* Attempt pt-pt then loop */ +#define FLAGS_LIRP_LILP 0x80 /* LIRP / LILP is disabled */ + +#define FLAGS_TOPOLOGY_FAILOVER 0x0400 /* Bit 10 */ +#define FLAGS_LINK_SPEED 0x0800 /* Bit 11 */ + + uint32 link_speed; +#define LINK_SPEED_AUTO 0 /* Auto selection */ +#define LINK_SPEED_1G 1 /* 1 Gigabaud */ +#define LINK_SPEED_2G 2 /* 2 Gigabaud */ + +} INIT_LINK_VAR; + + +/* Structure for MB Command DOWN_LINK (06) */ + +typedef struct { + uint32 rsvd1; +} DOWN_LINK_VAR; + + +/* Structure for MB Command CONFIG_LINK (07) */ + +typedef struct { +#if BIG_ENDIAN_HW + u32bit cr : 1; + u32bit ci : 1; + u32bit cr_delay : 6; + u32bit cr_count : 8; + u32bit rsvd1 : 8; + u32bit MaxBBC : 8; +#endif +#if LITTLE_ENDIAN_HW + u32bit MaxBBC : 8; + u32bit rsvd1 : 8; + u32bit cr_count : 8; + u32bit cr_delay : 6; + u32bit ci : 1; + u32bit cr : 1; +#endif + uint32 myId; + uint32 rsvd2; + uint32 edtov; + uint32 arbtov; + uint32 ratov; + uint32 rttov; + uint32 altov; + uint32 crtov; + uint32 citov; +#if BIG_ENDIAN_HW + u32bit rrq_enable : 1; + u32bit rrq_immed : 1; + u32bit rsvd4 : 29; + u32bit ack0_enable : 1; +#endif +#if LITTLE_ENDIAN_HW + u32bit ack0_enable : 1; + u32bit rsvd4 : 29; + u32bit rrq_immed : 1; + u32bit rrq_enable : 1; +#endif +} CONFIG_LINK; + + +/* Structure for MB Command PART_SLIM (08) */ + +typedef struct { +#if BIG_ENDIAN_HW + u32bit unused1 : 24; + u32bit numRing : 8; +#endif +#if LITTLE_ENDIAN_HW + u32bit numRing : 8; + u32bit unused1 : 24; +#endif + RING_DEF ringdef[4]; + u32bit hbainit; +} PART_SLIM_VAR; + + +/* Structure for MB Command CONFIG_RING (09) */ + +typedef struct { +#if BIG_ENDIAN_HW + u32bit unused2 : 6; + u32bit recvSeq : 1; + u32bit recvNotify: 1; + u32bit numMask : 8; + u32bit profile : 8; + u32bit unused1 : 4; + u32bit ring : 4; +#endif +#if LITTLE_ENDIAN_HW + u32bit ring : 4; + u32bit unused1 : 4; + u32bit profile : 8; + u32bit numMask : 8; + u32bit recvNotify: 1; + u32bit recvSeq : 1; + u32bit unused2 : 6; +#endif +#if BIG_ENDIAN_HW + ushort maxRespXchg; + ushort maxOrigXchg; +#endif +#if LITTLE_ENDIAN_HW + ushort maxOrigXchg; + ushort maxRespXchg; +#endif + RR_REG rrRegs[6]; +} CONFIG_RING_VAR; + + +/* Structure for MB Command RESET_RING (10) */ + +typedef struct { + uint32 ring_no; +} RESET_RING_VAR; + + +/* Structure for MB Command READ_CONFIG (11) */ + +typedef struct { +#if BIG_ENDIAN_HW + u32bit cr : 1; + u32bit ci : 1; + u32bit cr_delay : 6; + u32bit cr_count : 8; + u32bit InitBBC : 8; + u32bit MaxBBC : 8; +#endif +#if LITTLE_ENDIAN_HW + u32bit MaxBBC : 8; + u32bit InitBBC : 8; + u32bit cr_count : 8; + u32bit cr_delay : 6; + u32bit ci : 1; + u32bit cr : 1; +#endif +#if BIG_ENDIAN_HW + u32bit topology : 8; + u32bit myDid : 24; +#endif +#if LITTLE_ENDIAN_HW + u32bit myDid : 24; + u32bit topology : 8; +#endif + /* Defines for topology (defined previously) */ +#if BIG_ENDIAN_HW + u32bit AR : 1; + u32bit IR : 1; + u32bit rsvd1 : 29; + u32bit ack0 : 1; +#endif +#if LITTLE_ENDIAN_HW + u32bit ack0 : 1; + u32bit rsvd1 : 29; + u32bit IR : 1; + u32bit AR : 1; +#endif + uint32 edtov; + uint32 arbtov; + uint32 ratov; + uint32 rttov; + uint32 altov; + uint32 lmt; +#define LMT_RESERVED 0x0 /* Not used */ +#define LMT_266_10bit 0x1 /* 265.625 Mbaud 10 bit iface */ +#define LMT_532_10bit 0x2 /* 531.25 Mbaud 10 bit iface */ +#define LMT_1063_10bit 0x3 /* 1062.5 Mbaud 20 bit iface */ +#define LMT_2125_10bit 0x8 /* 2125 Mbaud 10 bit iface */ + + uint32 rsvd2; + uint32 rsvd3; + uint32 max_xri; + uint32 max_iocb; + uint32 max_rpi; + uint32 avail_xri; + uint32 avail_iocb; + uint32 avail_rpi; + uint32 default_rpi; +} READ_CONFIG_VAR; + + +/* Structure for MB Command READ_RCONFIG (12) */ + +typedef struct { +#if BIG_ENDIAN_HW + u32bit rsvd2 : 7; + u32bit recvNotify : 1; + u32bit numMask : 8; + u32bit profile : 8; + u32bit rsvd1 : 4; + u32bit ring : 4; +#endif +#if LITTLE_ENDIAN_HW + u32bit ring : 4; + u32bit rsvd1 : 4; + u32bit profile : 8; + u32bit numMask : 8; + u32bit recvNotify : 1; + u32bit rsvd2 : 7; +#endif +#if BIG_ENDIAN_HW + ushort maxResp; + ushort maxOrig; +#endif +#if LITTLE_ENDIAN_HW + ushort maxOrig; + ushort maxResp; +#endif + RR_REG rrRegs[6]; +#if BIG_ENDIAN_HW + ushort cmdRingOffset; + ushort cmdEntryCnt; + ushort rspRingOffset; + ushort rspEntryCnt; + ushort nextCmdOffset; + ushort rsvd3; + ushort nextRspOffset; + ushort rsvd4; +#endif +#if LITTLE_ENDIAN_HW + ushort cmdEntryCnt; + ushort cmdRingOffset; + ushort rspEntryCnt; + ushort rspRingOffset; + ushort rsvd3; + ushort nextCmdOffset; + ushort rsvd4; + ushort nextRspOffset; +#endif +} READ_RCONF_VAR; + + +/* Structure for MB Command READ_SPARM (13) */ +/* Structure for MB Command READ_SPARM64 (0x8D) */ + +typedef struct { + uint32 rsvd1; + uint32 rsvd2; + union { + ULP_BDE sp; /* This BDE points to SERV_PARM structure */ + ULP_BDE64 sp64; + } un; +} READ_SPARM_VAR; + + +/* Structure for MB Command READ_STATUS (14) */ + +typedef struct { +#if BIG_ENDIAN_HW + u32bit rsvd1 : 31; + u32bit clrCounters : 1; + ushort activeXriCnt; + ushort activeRpiCnt; +#endif +#if LITTLE_ENDIAN_HW + u32bit clrCounters : 1; + u32bit rsvd1 : 31; + ushort activeRpiCnt; + ushort activeXriCnt; +#endif + uint32 xmitByteCnt; + uint32 rcvbyteCnt; + uint32 xmitFrameCnt; + uint32 rcvFrameCnt; + uint32 xmitSeqCnt; + uint32 rcvSeqCnt; + uint32 totalOrigExchanges; + uint32 totalRespExchanges; + uint32 rcvPbsyCnt; + uint32 rcvFbsyCnt; +} READ_STATUS_VAR; + + +/* Structure for MB Command READ_RPI (15) */ +/* Structure for MB Command READ_RPI64 (0x8F) */ + +typedef struct { +#if BIG_ENDIAN_HW + ushort nextRpi; + ushort reqRpi; + u32bit rsvd2 : 8; + u32bit DID : 24; +#endif +#if LITTLE_ENDIAN_HW + ushort reqRpi; + ushort nextRpi; + u32bit DID : 24; + u32bit rsvd2 : 8; +#endif + union { + ULP_BDE sp; + ULP_BDE64 sp64; + } un; + +} READ_RPI_VAR; + + +/* Structure for MB Command READ_XRI (16) */ + +typedef struct { +#if BIG_ENDIAN_HW + ushort nextXri; + ushort reqXri; + ushort rsvd1; + ushort rpi; + u32bit rsvd2 : 8; + u32bit DID : 24; + u32bit rsvd3 : 8; + u32bit SID : 24; + uint32 rsvd4; + uchar seqId; + uchar rsvd5; + ushort seqCount; + ushort oxId; + ushort rxId; + u32bit rsvd6 : 30; + u32bit si : 1; + u32bit exchOrig : 1; +#endif +#if LITTLE_ENDIAN_HW + ushort reqXri; + ushort nextXri; + ushort rpi; + ushort rsvd1; + u32bit DID : 24; + u32bit rsvd2 : 8; + u32bit SID : 24; + u32bit rsvd3 : 8; + uint32 rsvd4; + ushort seqCount; + uchar rsvd5; + uchar seqId; + ushort rxId; + ushort oxId; + u32bit exchOrig : 1; + u32bit si : 1; + u32bit rsvd6 : 30; +#endif +} READ_XRI_VAR; + + +/* Structure for MB Command READ_REV (17) */ + +typedef struct { +#if BIG_ENDIAN_HW + u32bit cv : 1; + u32bit rr : 1; + u32bit rsvd1 : 29; + u32bit rv : 1; +#endif +#if LITTLE_ENDIAN_HW + u32bit rv : 1; + u32bit rsvd1 : 29; + u32bit rr : 1; + u32bit cv : 1; +#endif + uint32 biuRev; + uint32 smRev; + union { + uint32 smFwRev; + struct { +#if BIG_ENDIAN_HW + uchar ProgType; + uchar ProgId; + u16bit ProgVer : 4; + u16bit ProgRev : 4; + u16bit ProgFixLvl : 2; + u16bit ProgDistType : 2; + u16bit DistCnt : 4; +#endif +#if LITTLE_ENDIAN_HW + u16bit DistCnt : 4; + u16bit ProgDistType : 2; + u16bit ProgFixLvl : 2; + u16bit ProgRev : 4; + u16bit ProgVer : 4; + uchar ProgId; + uchar ProgType; +#endif + } b; + } un; + uint32 endecRev; +#if BIG_ENDIAN_HW + uchar feaLevelHigh; + uchar feaLevelLow; + uchar fcphHigh; + uchar fcphLow; +#endif +#if LITTLE_ENDIAN_HW + uchar fcphLow; + uchar fcphHigh; + uchar feaLevelLow; + uchar feaLevelHigh; +#endif + uint32 postKernRev; + uint32 opFwRev; + uchar opFwName[16]; + uint32 sli1FwRev; + uchar sli1FwName[16]; + uint32 sli2FwRev; + uchar sli2FwName[16]; + uint32 rsvd2; + uint32 RandomData[7]; +} READ_REV_VAR; + +#define rxSeqRev postKernRev +#define txSeqRev opFwRev + +/* Structure for MB Command READ_LINK_STAT (18) */ + +typedef struct { + uint32 rsvd1; + uint32 linkFailureCnt; + uint32 lossSyncCnt; + + uint32 lossSignalCnt; + uint32 primSeqErrCnt; + uint32 invalidXmitWord; + uint32 crcCnt; + uint32 primSeqTimeout; + uint32 elasticOverrun; + uint32 arbTimeout; +} READ_LNK_VAR; + + +/* Structure for MB Command REG_LOGIN (19) */ +/* Structure for MB Command REG_LOGIN64 (0x93) */ + +typedef struct { +#if BIG_ENDIAN_HW + ushort rsvd1; + ushort rpi; + u32bit rsvd2 : 8; + u32bit did : 24; +#endif +#if LITTLE_ENDIAN_HW + ushort rpi; + ushort rsvd1; + u32bit did : 24; + u32bit rsvd2 : 8; +#endif + union { + ULP_BDE sp; + ULP_BDE64 sp64; + } un; + +} REG_LOGIN_VAR; + +/* Word 30 contents for REG_LOGIN */ +typedef union { + struct { +#if BIG_ENDIAN_HW + u16bit rsvd1 : 12; + u16bit class : 4; + ushort xri; +#endif +#if LITTLE_ENDIAN_HW + ushort xri; + u16bit class : 4; + u16bit rsvd1 : 12; +#endif + } f; + uint32 word; +} REG_WD30; + + +/* Structure for MB Command UNREG_LOGIN (20) */ + +typedef struct { +#if BIG_ENDIAN_HW + ushort rsvd1; + ushort rpi; +#endif +#if LITTLE_ENDIAN_HW + ushort rpi; + ushort rsvd1; +#endif +} UNREG_LOGIN_VAR; + + +/* Structure for MB Command UNREG_D_ID (0x23) */ + +typedef struct { + uint32 did; +} UNREG_D_ID_VAR; + + +/* Structure for MB Command READ_LA (21) */ +/* Structure for MB Command READ_LA64 (0x95) */ + +typedef struct { + uint32 eventTag; /* Event tag */ +#if BIG_ENDIAN_HW + u32bit rsvd1 : 22; + u32bit pb : 1; + u32bit il : 1; + u32bit attType : 8; +#endif +#if LITTLE_ENDIAN_HW + u32bit attType : 8; + u32bit il : 1; + u32bit pb : 1; + u32bit rsvd1 : 22; +#endif +#define AT_RESERVED 0x00 /* Reserved - attType */ +#define AT_LINK_UP 0x01 /* Link is up */ +#define AT_LINK_DOWN 0x02 /* Link is down */ +#if BIG_ENDIAN_HW + uchar granted_AL_PA; + uchar lipAlPs; + uchar lipType; + uchar topology; +#endif +#if LITTLE_ENDIAN_HW + uchar topology; + uchar lipType; + uchar lipAlPs; + uchar granted_AL_PA; +#endif +#define LT_PORT_INIT 0x00 /* An L_PORT initing (F7, AL_PS) - lipType */ +#define LT_PORT_ERR 0x01 /* Err @L_PORT rcv'er (F8, AL_PS) */ +#define LT_RESET_APORT 0x02 /* Lip Reset of some other port */ +#define LT_RESET_MYPORT 0x03 /* Lip Reset of my port */ +#define TOPOLOGY_PT_PT 0x01 /* Topology is pt-pt / pt-fabric */ +#define TOPOLOGY_LOOP 0x02 /* Topology is FC-AL */ + + union { + ULP_BDE lilpBde; /* This BDE points to a 128 byte buffer to */ + /* store the LILP AL_PA position map into */ + ULP_BDE64 lilpBde64; + } un; +#if BIG_ENDIAN_HW + u32bit Dlu : 1; + u32bit Dtf : 1; + u32bit Drsvd2 : 14; + u32bit DlnkSpeed : 8; + u32bit DnlPort : 4; + u32bit Dtx : 2; + u32bit Drx : 2; +#endif +#if LITTLE_ENDIAN_HW + u32bit Drx : 2; + u32bit Dtx : 2; + u32bit DnlPort : 4; + u32bit DlnkSpeed : 8; + u32bit Drsvd2 : 14; + u32bit Dtf : 1; + u32bit Dlu : 1; +#endif +#if BIG_ENDIAN_HW + u32bit Ulu : 1; + u32bit Utf : 1; + u32bit Ursvd2 : 14; + u32bit UlnkSpeed : 8; + u32bit UnlPort : 4; + u32bit Utx : 2; + u32bit Urx : 2; +#endif +#if LITTLE_ENDIAN_HW + u32bit Urx : 2; + u32bit Utx : 2; + u32bit UnlPort : 4; + u32bit UlnkSpeed : 8; + u32bit Ursvd2 : 14; + u32bit Utf : 1; + u32bit Ulu : 1; +#endif +#define LA_1GHZ_LINK 4 /* lnkSpeed */ +#define LA_2GHZ_LINK 8 /* lnkSpeed */ + +} READ_LA_VAR; + + +/* Structure for MB Command CLEAR_LA (22) */ + +typedef struct { + uint32 eventTag; /* Event tag */ + uint32 rsvd1; +} CLEAR_LA_VAR; + +/* Structure for MB Command DUMP */ + +typedef struct { +#if BIG_ENDIAN_HW + u32bit rsvd : 25 ; + u32bit ra : 1 ; + u32bit co : 1 ; + u32bit cv : 1 ; + u32bit type : 4 ; + u32bit entry_index : 16 ; + u32bit region_id : 16 ; +#endif +#if LITTLE_ENDIAN_HW + u32bit type : 4 ; + u32bit cv : 1 ; + u32bit co : 1 ; + u32bit ra : 1 ; + u32bit rsvd : 25 ; + u32bit region_id : 16 ; + u32bit entry_index : 16 ; +#endif + uint32 rsvd1; + uint32 word_cnt ; + uint32 resp_offset ; +} DUMP_VAR ; + +#define DMP_MEM_REG 0x1 +#define DMP_NV_PARAMS 0x2 + +#define DMP_REGION_VPD 0xe +#define DMP_VPD_SIZE 0x100 + +/* Structure for MB Command CONFIG_PORT (0x88) */ + +typedef struct { + uint32 pcbLen; + uint32 pcbLow; /* bit 31:0 of memory based port config block */ + uint32 pcbHigh; /* bit 63:32 of memory based port config block */ + uint32 hbainit[5]; +} CONFIG_PORT_VAR; + + +/* SLI-2 Port Control Block */ + +/* SLIM POINTER */ +#define SLIMOFF 0x30 /* WORD */ + +typedef struct _SLI2_RDSC { + uint32 cmdEntries; + uint32 cmdAddrLow; + uint32 cmdAddrHigh; + + uint32 rspEntries; + uint32 rspAddrLow; + uint32 rspAddrHigh; +} SLI2_RDSC; + +typedef struct _PCB { +#if BIG_ENDIAN_HW + u32bit type : 8; +#define TYPE_NATIVE_SLI2 0x01; + u32bit feature : 8; +#define FEATURE_INITIAL_SLI2 0x01; + u32bit rsvd : 12; + u32bit maxRing : 4; +#endif +#if LITTLE_ENDIAN_HW + u32bit maxRing : 4; + u32bit rsvd : 12; + u32bit feature : 8; +#define FEATURE_INITIAL_SLI2 0x01; + u32bit type : 8; +#define TYPE_NATIVE_SLI2 0x01; +#endif + + uint32 mailBoxSize; + uint32 mbAddrLow; + uint32 mbAddrHigh; + + uint32 hgpAddrLow; + uint32 hgpAddrHigh; + + uint32 pgpAddrLow; + uint32 pgpAddrHigh; + SLI2_RDSC rdsc[ MAX_RINGS]; +} PCB; + +typedef struct { +#if BIG_ENDIAN_HW + u32bit rsvd0 : 27; + u32bit discardFarp : 1; + u32bit IPEnable : 1; + u32bit nodeName : 1; + u32bit portName : 1; + u32bit filterEnable : 1; +#endif +#if LITTLE_ENDIAN_HW + u32bit filterEnable : 1; + u32bit portName : 1; + u32bit nodeName : 1; + u32bit IPEnable : 1; + u32bit discardFarp : 1; + u32bit rsvd : 27; +#endif + NAME_TYPE portname; + NAME_TYPE nodename; + uint32 rsvd1; + uint32 rsvd2; + uint32 rsvd3; + uint32 IPAddress; +} CONFIG_FARP_VAR; + + +/* Union of all Mailbox Command types */ + +typedef union { + uint32 varWords[31]; + LOAD_SM_VAR varLdSM; /* cmd = 1 (LOAD_SM) */ + READ_NV_VAR varRDnvp; /* cmd = 2 (READ_NVPARMS) */ + WRITE_NV_VAR varWTnvp; /* cmd = 3 (WRITE_NVPARMS) */ + BIU_DIAG_VAR varBIUdiag; /* cmd = 4 (RUN_BIU_DIAG) */ + INIT_LINK_VAR varInitLnk; /* cmd = 5 (INIT_LINK) */ + DOWN_LINK_VAR varDwnLnk; /* cmd = 6 (DOWN_LINK) */ + CONFIG_LINK varCfgLnk; /* cmd = 7 (CONFIG_LINK) */ + PART_SLIM_VAR varSlim; /* cmd = 8 (PART_SLIM) */ + CONFIG_RING_VAR varCfgRing; /* cmd = 9 (CONFIG_RING) */ + RESET_RING_VAR varRstRing; /* cmd = 10 (RESET_RING) */ + READ_CONFIG_VAR varRdConfig; /* cmd = 11 (READ_CONFIG) */ + READ_RCONF_VAR varRdRConfig; /* cmd = 12 (READ_RCONFIG) */ + READ_SPARM_VAR varRdSparm; /* cmd = 13 (READ_SPARM(64)) */ + READ_STATUS_VAR varRdStatus; /* cmd = 14 (READ_STATUS) */ + READ_RPI_VAR varRdRPI; /* cmd = 15 (READ_RPI(64)) */ + READ_XRI_VAR varRdXRI; /* cmd = 16 (READ_XRI) */ + READ_REV_VAR varRdRev; /* cmd = 17 (READ_REV) */ + READ_LNK_VAR varRdLnk; /* cmd = 18 (READ_LNK_STAT) */ + REG_LOGIN_VAR varRegLogin; /* cmd = 19 (REG_LOGIN(64)) */ + UNREG_LOGIN_VAR varUnregLogin; /* cmd = 20 (UNREG_LOGIN) */ + READ_LA_VAR varReadLA; /* cmd = 21 (READ_LA(64)) */ + CLEAR_LA_VAR varClearLA; /* cmd = 22 (CLEAR_LA) */ + DUMP_VAR varDmp ; /* Warm Start DUMP mbx cmd */ + UNREG_D_ID_VAR varUnregDID; /* cmd = 0x23 (UNREG_D_ID) */ + CONFIG_PORT_VAR varCfgPort; /* cmd = 0x88 (CONFIG_PORT) */ + CONFIG_FARP_VAR varCfgFarp; /* cmd = 0x25 (CONFIG_FARP) */ +} MAILVARIANTS; + +#define MAILBOX_CMD_WSIZE 32 + +/* + * SLI-2 specific structures + */ + +typedef struct _SLI1_DESC { + RINGS mbxCring[ 4]; + uint32 mbxUnused[ 24]; +} SLI1_DESC; + +typedef struct { + uint32 cmdPutInx; + uint32 rspGetInx; +} HGP; + +typedef struct { + uint32 cmdGetInx; + uint32 rspPutInx; +} PGP; + +typedef struct _SLI2_DESC { + HGP host[ MAX_RINGS]; + uint32 unused[ 16]; + PGP port[ MAX_RINGS]; +} SLI2_DESC; + +typedef union { + SLI1_DESC s1; + SLI2_DESC s2; +} SLI_VAR; + +typedef volatile struct { +#if BIG_ENDIAN_HW + ushort mbxStatus; + uchar mbxCommand; + u8bit mbxReserved : 6; + u8bit mbxHc : 1; + u8bit mbxOwner : 1; /* Low order bit first word */ +#endif +#if LITTLE_ENDIAN_HW + u8bit mbxOwner : 1; /* Low order bit first word */ + u8bit mbxHc : 1; + u8bit mbxReserved : 6; + uchar mbxCommand; + ushort mbxStatus; +#endif + MAILVARIANTS un; + SLI_VAR us; +} MAILBOX, *PMAILBOX; + +/* + * End Structure Definitions for Mailbox Commands + */ + + +/* + * Begin Structure Definitions for IOCB Commands + */ + +typedef struct { +#if BIG_ENDIAN_HW + uchar statAction; + uchar statRsn; + uchar statBaExp; + uchar statLocalError; +#endif +#if LITTLE_ENDIAN_HW + uchar statLocalError; + uchar statBaExp; + uchar statRsn; + uchar statAction; +#endif + /* statAction FBSY reason codes */ +#define FBSY_RSN_MASK 0xF0 /* Rsn stored in upper nibble */ +#define FBSY_FABRIC_BSY 0x10 /* F_bsy due to Fabric BSY */ +#define FBSY_NPORT_BSY 0x30 /* F_bsy due to N_port BSY */ + + /* statAction PBSY action codes */ +#define PBSY_ACTION1 0x01 /* Sequence terminated - retry */ +#define PBSY_ACTION2 0x02 /* Sequence active - retry */ + + /* statAction P/FRJT action codes */ +#define RJT_RETRYABLE 0x01 /* Retryable class of error */ +#define RJT_NO_RETRY 0x02 /* Non-Retryable class of error */ + + /* statRsn LS_RJT reason codes defined in LS_RJT structure */ + + /* statRsn P_BSY reason codes */ +#define PBSY_NPORT_BSY 0x01 /* Physical N_port BSY */ +#define PBSY_RESRCE_BSY 0x03 /* N_port resource BSY */ +#define PBSY_VU_BSY 0xFF /* See VU field for rsn */ + + /* statRsn P/F_RJT reason codes */ +#define RJT_BAD_D_ID 0x01 /* Invalid D_ID field */ +#define RJT_BAD_S_ID 0x02 /* Invalid S_ID field */ +#define RJT_UNAVAIL_TEMP 0x03 /* N_Port unavailable temp. */ +#define RJT_UNAVAIL_PERM 0x04 /* N_Port unavailable perm. */ +#define RJT_UNSUP_CLASS 0x05 /* Class not supported */ +#define RJT_DELIM_ERR 0x06 /* Delimiter usage error */ +#define RJT_UNSUP_TYPE 0x07 /* Type not supported */ +#define RJT_BAD_CONTROL 0x08 /* Invalid link conrtol */ +#define RJT_BAD_RCTL 0x09 /* R_CTL invalid */ +#define RJT_BAD_FCTL 0x0A /* F_CTL invalid */ +#define RJT_BAD_OXID 0x0B /* OX_ID invalid */ +#define RJT_BAD_RXID 0x0C /* RX_ID invalid */ +#define RJT_BAD_SEQID 0x0D /* SEQ_ID invalid */ +#define RJT_BAD_DFCTL 0x0E /* DF_CTL invalid */ +#define RJT_BAD_SEQCNT 0x0F /* SEQ_CNT invalid */ +#define RJT_BAD_PARM 0x10 /* Param. field invalid */ +#define RJT_XCHG_ERR 0x11 /* Exchange error */ +#define RJT_PROT_ERR 0x12 /* Protocol error */ +#define RJT_BAD_LENGTH 0x13 /* Invalid Length */ +#define RJT_UNEXPECTED_ACK 0x14 /* Unexpected ACK */ +#define RJT_LOGIN_REQUIRED 0x16 /* Login required */ +#define RJT_TOO_MANY_SEQ 0x17 /* Excessive sequences */ +#define RJT_XCHG_NOT_STRT 0x18 /* Exchange not started */ +#define RJT_UNSUP_SEC_HDR 0x19 /* Security hdr not supported */ +#define RJT_UNAVAIL_PATH 0x1A /* Fabric Path not available */ +#define RJT_VENDOR_UNIQUE 0xFF /* Vendor unique error */ + + /* statRsn BA_RJT reason codes */ +#define BARJT_BAD_CMD_CODE 0x01 /* Invalid command code */ +#define BARJT_LOGICAL_ERR 0x03 /* Logical error */ +#define BARJT_LOGICAL_BSY 0x05 /* Logical busy */ +#define BARJT_PROTOCOL_ERR 0x07 /* Protocol error */ +#define BARJT_VU_ERR 0xFF /* Vendor unique error */ + + /* LS_RJT reason explanation defined in LS_RJT structure */ + + /* BA_RJT reason explanation */ +#define BARJT_EXP_INVALID_ID 0x01 /* Invalid OX_ID/RX_ID */ +#define BARJT_EXP_ABORT_SEQ 0x05 /* Abort SEQ, no more info */ + + /* Localy detected errors */ +#define IOERR_SUCCESS 0x00 /* statLocalError */ +#define IOERR_MISSING_CONTINUE 0x01 +#define IOERR_SEQUENCE_TIMEOUT 0x02 +#define IOERR_INTERNAL_ERROR 0x03 +#define IOERR_INVALID_RPI 0x04 +#define IOERR_NO_XRI 0x05 +#define IOERR_ILLEGAL_COMMAND 0x06 +#define IOERR_XCHG_DROPPED 0x07 +#define IOERR_ILLEGAL_FIELD 0x08 +#define IOERR_BAD_CONTINUE 0x09 +#define IOERR_TOO_MANY_BUFFERS 0x0A +#define IOERR_RCV_BUFFER_WAITING 0x0B +#define IOERR_NO_CONNECTION 0x0C +#define IOERR_TX_DMA_FAILED 0x0D +#define IOERR_RX_DMA_FAILED 0x0E +#define IOERR_ILLEGAL_FRAME 0x0F +#define IOERR_EXTRA_DATA 0x10 +#define IOERR_NO_RESOURCES 0x11 +#define IOERR_RESERVED 0x12 +#define IOERR_ILLEGAL_LENGTH 0x13 +#define IOERR_UNSUPPORTED_FEATURE 0x14 +#define IOERR_ABORT_IN_PROGRESS 0x15 +#define IOERR_ABORT_REQUESTED 0x16 +#define IOERR_RECEIVE_BUFFER_TIMEOUT 0x17 +#define IOERR_LOOP_OPEN_FAILURE 0x18 +#define IOERR_RING_RESET 0x19 +#define IOERR_LINK_DOWN 0x1A +#define IOERR_CORRUPTED_DATA 0x1B +#define IOERR_CORRUPTED_RPI 0x1C +#define IOERR_OUT_OF_ORDER_DATA 0x1D +#define IOERR_OUT_OF_ORDER_ACK 0x1E +#define IOERR_DUP_FRAME 0x1F +#define IOERR_LINK_CONTROL_FRAME 0x20 /* ACK_N received */ +#define IOERR_BAD_HOST_ADDRESS 0x21 +#define IOERR_RCV_HDRBUF_WAITING 0x22 +#define IOERR_MISSING_HDR_BUFFER 0x23 +#define IOERR_MSEQ_CHAIN_CORRUPTED 0x24 +#define IOERR_ABORTMULT_REQUESTED 0x25 +#define IOERR_BUFFER_SHORTAGE 0x28 +} PARM_ERR; + +typedef union { + struct { +#if BIG_ENDIAN_HW + uchar Rctl; /* R_CTL field */ + uchar Type; /* TYPE field */ + uchar Dfctl; /* DF_CTL field */ + uchar Fctl; /* Bits 0-7 of IOCB word 5 */ +#endif +#if LITTLE_ENDIAN_HW + uchar Fctl; /* Bits 0-7 of IOCB word 5 */ + uchar Dfctl; /* DF_CTL field */ + uchar Type; /* TYPE field */ + uchar Rctl; /* R_CTL field */ +#endif + +#define BC 0x02 /* Broadcast Received - Fctl */ +#define SI 0x04 /* Sequence Initiative */ +#define LA 0x08 /* Ignore Link Attention state */ +#define LS 0x80 /* Last Sequence */ + } hcsw; + uint32 reserved; +} WORD5; + + +/* IOCB Command template for a generic response */ +typedef struct { + uint32 reserved[4]; + PARM_ERR perr; +} GENERIC_RSP; + + +/* IOCB Command template for XMIT / XMIT_BCAST / RCV_SEQUENCE / XMIT_ELS */ +typedef struct { + ULP_BDE xrsqbde[2]; + uint32 xrsqRo; /* Starting Relative Offset */ + WORD5 w5; /* Header control/status word */ +} XR_SEQ_FIELDS; + +/* IOCB Command template for ELS_REQUEST */ +typedef struct { + ULP_BDE elsReq; + ULP_BDE elsRsp; +#if BIG_ENDIAN_HW + u32bit word4Rsvd : 7; + u32bit fl : 1; + u32bit myID : 24; + u32bit word5Rsvd : 8; + u32bit remoteID : 24; +#endif +#if LITTLE_ENDIAN_HW + u32bit myID : 24; + u32bit fl : 1; + u32bit word4Rsvd : 7; + u32bit remoteID : 24; + u32bit word5Rsvd : 8; +#endif +} ELS_REQUEST; + +/* IOCB Command template for RCV_ELS_REQ */ +typedef struct { + ULP_BDE elsReq[2]; + uint32 parmRo; +#if BIG_ENDIAN_HW + u32bit word5Rsvd : 8; + u32bit remoteID : 24; +#endif +#if LITTLE_ENDIAN_HW + u32bit remoteID : 24; + u32bit word5Rsvd : 8; +#endif +} RCV_ELS_REQ; + +/* IOCB Command template for ABORT / CLOSE_XRI */ +typedef struct { + uint32 rsvd[3]; + uint32 abortType; +#define ABORT_TYPE_ABTX 0x00000000 +#define ABORT_TYPE_ABTS 0x00000001 + uint32 parm; +#if BIG_ENDIAN_HW + ushort abortContextTag; /* ulpContext from command to abort/close */ + ushort abortIoTag; /* ulpIoTag from command to abort/close */ +#endif +#if LITTLE_ENDIAN_HW + ushort abortIoTag; /* ulpIoTag from command to abort/close */ + ushort abortContextTag; /* ulpContext from command to abort/close */ +#endif +} AC_XRI; + +/* IOCB Command template for GET_RPI */ +typedef struct { + uint32 rsvd[4]; + uint32 parmRo; +#if BIG_ENDIAN_HW + u32bit word5Rsvd : 8; + u32bit remoteID : 24; +#endif +#if LITTLE_ENDIAN_HW + u32bit remoteID : 24; + u32bit word5Rsvd : 8; +#endif +} GET_RPI; + +/* IOCB Command template for all FCPI commands */ +typedef struct { + ULP_BDE fcpi_cmnd; /* FCP_CMND payload descriptor */ + ULP_BDE fcpi_rsp; /* Rcv buffer */ + uint32 fcpi_parm; + uint32 fcpi_XRdy; /* transfer ready for IWRITE */ +} FCPI_FIELDS; + +/* IOCB Command template for all FCPT commands */ +typedef struct { + ULP_BDE fcpt_Buffer[2]; /* FCP_CMND payload descriptor */ + uint32 fcpt_Offset; + uint32 fcpt_Length; /* transfer ready for IWRITE */ +} FCPT_FIELDS; + +/* SLI-2 IOCB structure definitions */ + +/* IOCB Command template for 64 bit XMIT / XMIT_BCAST / XMIT_ELS */ +typedef struct { + ULP_BDL bdl; + uint32 xrsqRo; /* Starting Relative Offset */ + WORD5 w5; /* Header control/status word */ +} XMT_SEQ_FIELDS64; + +/* IOCB Command template for 64 bit RCV_SEQUENCE64 */ +typedef struct { + ULP_BDE64 rcvBde; + uint32 rsvd1; + uint32 xrsqRo; /* Starting Relative Offset */ + WORD5 w5; /* Header control/status word */ +} RCV_SEQ_FIELDS64; + +/* IOCB Command template for ELS_REQUEST64 */ +typedef struct { + ULP_BDL bdl; +#if BIG_ENDIAN_HW + u32bit word4Rsvd : 7; + u32bit fl : 1; + u32bit myID : 24; + u32bit word5Rsvd : 8; + u32bit remoteID : 24; +#endif +#if LITTLE_ENDIAN_HW + u32bit myID : 24; + u32bit fl : 1; + u32bit word4Rsvd : 7; + u32bit remoteID : 24; + u32bit word5Rsvd : 8; +#endif +} ELS_REQUEST64; + +/* IOCB Command template for GEN_REQUEST64 */ +typedef struct { + ULP_BDL bdl; + uint32 xrsqRo; /* Starting Relative Offset */ + WORD5 w5; /* Header control/status word */ +} GEN_REQUEST64; + +/* IOCB Command template for RCV_ELS_REQ64 */ +typedef struct { + ULP_BDE64 elsReq; + uint32 rcvd1; + uint32 parmRo; +#if BIG_ENDIAN_HW + u32bit word5Rsvd : 8; + u32bit remoteID : 24; +#endif +#if LITTLE_ENDIAN_HW + u32bit remoteID : 24; + u32bit word5Rsvd : 8; +#endif +} RCV_ELS_REQ64; + +/* IOCB Command template for all 64 bit FCPI commands */ +typedef struct { + ULP_BDL bdl; + uint32 fcpi_parm; + uint32 fcpi_XRdy; /* transfer ready for IWRITE */ +} FCPI_FIELDS64; + +/* IOCB Command template for all 64 bit FCPT commands */ +typedef struct { + ULP_BDL bdl; + uint32 fcpt_Offset; + uint32 fcpt_Length; /* transfer ready for IWRITE */ +} FCPT_FIELDS64; + +typedef volatile struct _IOCB { /* IOCB structure */ + union { + GENERIC_RSP grsp; /* Generic response */ + XR_SEQ_FIELDS xrseq; /* XMIT / BCAST / RCV_SEQUENCE cmd */ + ULP_BDE cont[3]; /* up to 3 continuation bdes */ + ELS_REQUEST elsreq; /* ELS_REQUEST template */ + RCV_ELS_REQ rcvels; /* RCV_ELS_REQ template */ + AC_XRI acxri; /* ABORT / CLOSE_XRI template */ + GET_RPI getrpi; /* GET_RPI template */ + FCPI_FIELDS fcpi; /* FCPI template */ + FCPT_FIELDS fcpt; /* FCPT template */ + + /* SLI-2 structures */ + + ULP_BDE64 cont64[ 2]; /* up to 2 64 bit continuation bde_64s */ + ELS_REQUEST64 elsreq64; /* ELS_REQUEST template */ + GEN_REQUEST64 genreq64; /* GEN_REQUEST template */ + RCV_ELS_REQ64 rcvels64; /* RCV_ELS_REQ template */ + XMT_SEQ_FIELDS64 xseq64; /* XMIT / BCAST cmd */ + FCPI_FIELDS64 fcpi64; /* FCPI 64 bit template */ + FCPT_FIELDS64 fcpt64; /* FCPT 64 bit template */ + + uint32 ulpWord[IOCB_WORD_SZ-2]; /* generic 6 'words' */ + } un; + union { + struct { +#if BIG_ENDIAN_HW + ushort ulpContext; /* High order bits word 6 */ + ushort ulpIoTag; /* Low order bits word 6 */ +#endif +#if LITTLE_ENDIAN_HW + ushort ulpIoTag; /* Low order bits word 6 */ + ushort ulpContext; /* High order bits word 6 */ +#endif + } t1; + struct { +#if BIG_ENDIAN_HW + ushort ulpContext; /* High order bits word 6 */ + u16bit ulpIoTag1 : 2; /* Low order bits word 6 */ + u16bit ulpIoTag0 : 14; /* Low order bits word 6 */ +#endif +#if LITTLE_ENDIAN_HW + u16bit ulpIoTag0 : 14; /* Low order bits word 6 */ + u16bit ulpIoTag1 : 2; /* Low order bits word 6 */ + ushort ulpContext; /* High order bits word 6 */ +#endif + } t2; + } un1; +#define ulpContext un1.t1.ulpContext +#define ulpIoTag un1.t1.ulpIoTag +#define ulpIoTag0 un1.t2.ulpIoTag0 +#define ulpDelayXmit un1.t2.ulpIoTag1 +#define IOCB_DELAYXMIT_MSK 0x3000 +#if BIG_ENDIAN_HW + u32bit ulpRsvdByte : 8; + u32bit ulpXS : 1; + u32bit ulpFCP2Rcvy : 1; + u32bit ulpPU : 2; + u32bit ulpIr : 1; + u32bit ulpClass : 3; + u32bit ulpCommand : 8; + u32bit ulpStatus : 4; + u32bit ulpBdeCount : 2; + u32bit ulpLe : 1; + u32bit ulpOwner : 1; /* Low order bit word 7 */ +#endif +#if LITTLE_ENDIAN_HW + u32bit ulpOwner : 1; /* Low order bit word 7 */ + u32bit ulpLe : 1; + u32bit ulpBdeCount : 2; + u32bit ulpStatus : 4; + u32bit ulpCommand : 8; + u32bit ulpClass : 3; + u32bit ulpIr : 1; + u32bit ulpPU : 2; + u32bit ulpFCP2Rcvy : 1; + u32bit ulpXS : 1; + u32bit ulpRsvdByte : 8; +#endif + +#define ulpTimeout ulpRsvdByte + +#define IOCB_FCP 1 /* IOCB is used for FCP ELS cmds - ulpRsvByte */ +#define IOCB_IP 2 /* IOCB is used for IP ELS cmds */ +#define PARM_UNUSED 0 /* PU field (Word 4) not used */ +#define PARM_REL_OFF 1 /* PU field (Word 4) = R. O. */ +#define PARM_READ_CHECK 2 /* PU field (Word 4) = Data Transfer Length */ +#define CLASS1 0 /* Class 1 */ +#define CLASS2 1 /* Class 2 */ +#define CLASS3 2 /* Class 3 */ +#define CLASS_FCP_INTERMIX 7 /* FCP Data->Cls 1, all else->Cls 2 */ + +#define IOSTAT_SUCCESS 0x0 /* ulpStatus */ +#define IOSTAT_FCP_RSP_ERROR 0x1 +#define IOSTAT_REMOTE_STOP 0x2 +#define IOSTAT_LOCAL_REJECT 0x3 +#define IOSTAT_NPORT_RJT 0x4 +#define IOSTAT_FABRIC_RJT 0x5 +#define IOSTAT_NPORT_BSY 0x6 +#define IOSTAT_FABRIC_BSY 0x7 +#define IOSTAT_INTERMED_RSP 0x8 +#define IOSTAT_LS_RJT 0x9 +#define IOSTAT_BA_RJT 0xA + +} IOCB, *PIOCB; + +typedef struct { + IOCB iocb; /* iocb entry */ + uchar * q; /* ptr to next iocb entry */ + uchar * bp; /* ptr to data buffer structure */ + uchar * info; /* ptr to data information structure */ + uchar * bpl; /* ptr to data BPL structure */ + uchar * ndlp; /* ptr to the ndlp structure */ + uchar retry; /* retry counter for IOCB cmd - if needed */ + uchar rsvd1; + ushort rsvd2; +} IOCBQ; + +typedef struct { + volatile uint32 mb[MAILBOX_CMD_WSIZE]; + uchar * q; + uchar * bp; /* ptr to data buffer structure */ +} MAILBOXQ; + +/* Given a pointer to the start of the ring, and the slot number of + * the desired iocb entry, calc a pointer to that entry. + */ +#define IOCB_ENTRY(ring,slot) ((IOCB *)(((uchar *)((ulong)ring)) + (((uint32)((ulong)slot))<< 5))) + +/* + * End Structure Definitions for IOCB Commands + */ + +typedef struct { + MAILBOX mbx; + IOCB IOCBs[MAX_BIOCB]; +} SLIM; + +typedef struct { + MAILBOX mbx; + PCB pcb; + IOCB IOCBs[MAX_SLI2_IOCB]; +} SLI2_SLIM; + +/* +* FDMI +* HBA MAnagement Operations Command Codes +*/ +#define SLI_MGMT_GRHL 0x100 /* Get registered HBA list */ +#define SLI_MGMT_GHAT 0x101 /* Get HBA attributes */ +#define SLI_MGMT_GRPL 0x102 /* Get registered Port list */ +#define SLI_MGMT_GPAT 0x110 /* Get Port attributes */ +#define SLI_MGMT_RHBA 0x200 /* Register HBA */ +#define SLI_MGMT_RHAT 0x201 /* Register HBA atttributes */ +#define SLI_MGMT_RPRT 0x210 /* Register Port */ +#define SLI_MGMT_RPA 0x211 /* Register Port attributes */ +#define SLI_MGMT_DHBA 0x300 /* De-register HBA */ +#define SLI_MGMT_DPRT 0x310 /* De-register Port */ + +/* + * Management Service Subtypes + */ +#define SLI_CT_FDMI_Subtypes 0x10 + +/* + * HBA Management Service Reject Code + */ +#define REJECT_CODE 0x9 /* Unable to perform command request */ +/* + * HBA Management Service Reject Reason Code + * Please refer to the Reason Codes above + */ + +/* + * HBA Attribute Types + */ +#define NODE_NAME 0x1 +#define MANUFACTURER 0x2 +#define SERIAL_NUMBER 0x3 +#define MODEL 0x4 +#define MODEL_DESCRIPTION 0x5 +#define HARDWARE_VERSION 0x6 +#define DRIVER_VERSION 0x7 +#define OPTION_ROM_VERSION 0x8 +#define FIRMWARE_VERSION 0x9 +#define VENDOR_SPECIFIC 0xa +#define DRIVER_NAME 0xb +#define OS_NAME_VERSION 0xc +#define MAX_CT_PAYLOAD_LEN 0xd + +/* + * Port Attrubute Types + */ +#define SUPPORTED_FC4_TYPES 0x1 +#define SUPPORTED_SPEED 0x2 +#define PORT_SPEED 0x3 +#define MAX_FRAME_SIZE 0x4 +#define OS_DEVICE_NAME 0x5 + +union AttributesDef { + /* Structure is in Big Endian format */ + struct { + u32bit AttrType: 16; + u32bit AttrLen: 16; + } bits; + uint32 word; +}; + +/* + * HBA Attribute Entry (8 - 260 bytes) + */ +typedef struct +{ + union AttributesDef ad; + union { + uint32 VendorSpecific; + uint32 SupportSpeed; + uint32 PortSpeed; + uint32 MaxFrameSize; + uint32 MaxCTPayloadLen; + uchar SupportFC4Types[32]; + uchar OsDeviceName[256]; + uchar Manufacturer[64]; + uchar SerialNumber[64]; + uchar Model[256]; + uchar ModelDescription[256]; + uchar HardwareVersion[256]; + uchar DriverVersion[256]; + uchar OptionROMVersion[256]; + uchar FirmwareVersion[256]; + uchar DriverName[256]; + NAME_TYPE NodeName; + } un; +} ATTRIBUTE_ENTRY, *PATTRIBUTE_ENTRY; + + +/* + * HBA Attribute Block + */ +typedef struct +{ + uint32 EntryCnt; /* Number of HBA attribute entries */ + ATTRIBUTE_ENTRY Entry; /* Variable-length array */ +} ATTRIBUTE_BLOCK, *PATTRIBUTE_BLOCK; + + +/* + * Port Entry + */ +typedef struct +{ + NAME_TYPE PortName; +} PORT_ENTRY, *PPORT_ENTRY; + +/* + * HBA Identifier + */ +typedef struct +{ + NAME_TYPE PortName; +} HBA_IDENTIFIER, *PHBA_IDENTIFIER; + +/* + * Registered Port List Format + */ +typedef struct +{ + uint32 EntryCnt; + PORT_ENTRY pe; /* Variable-length array */ +} REG_PORT_LIST, *PREG_PORT_LIST; + +/* + * Register HBA(RHBA) + */ +typedef struct +{ + HBA_IDENTIFIER hi; + REG_PORT_LIST rpl; /* variable-length array */ +} REG_HBA, *PREG_HBA; + +/* + * Register HBA Attributes (RHAT) + */ +typedef struct +{ + NAME_TYPE HBA_PortName; + ATTRIBUTE_BLOCK ab; +} REG_HBA_ATTRIBUTE, *PREG_HBA_ATTRIBUTE; + +/* + * Register Port Attributes (RPA) + */ +typedef struct +{ + NAME_TYPE HBA_PortName; + NAME_TYPE PortName; + ATTRIBUTE_BLOCK ab; +} REG_PORT_ATTRIBUTE, *PREG_PORT_ATTRIBUTE; + +/* + * Get Registered HBA List (GRHL) Accept Payload Format + */ +typedef struct +{ + uint32 HBA__Entry_Cnt; /* Number of Registered HBA Identifiers */ + NAME_TYPE HBA_PortName; /* Variable-length array */ +} GRHL_ACC_PAYLOAD, *PGRHL_ACC_PAYLOAD; + +/* + * Get Registered Port List (GRPL) Accept Payload Format + */ +typedef struct +{ + uint32 RPL_Entry_Cnt; /* Number of Registered Port Entries */ + PORT_ENTRY Reg_Port_Entry[1]; /* Variable-length array */ +} GRPL_ACC_PAYLOAD, *PGRPL_ACC_PAYLOAD; + +/* + * Get Port Attributes (GPAT) Accept Payload Format + */ + +typedef struct +{ + ATTRIBUTE_BLOCK pab; +} GPAT_ACC_PAYLOAD, *PGPAT_ACC_PAYLOAD; +#endif /* _H_FC_HW */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/fc_os.h 830-ivtv/drivers/scsi/lpfc/fc_os.h --- 000-virgin/drivers/scsi/lpfc/fc_os.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/fc_os.h Thu Jan 8 10:21:53 2004 @@ -0,0 +1,633 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Enterprise Fibre Channel Host Bus Adapters. * + * Refer to the README file included with this package for * + * driver version and adapter support. * + * Copyright (C) 2003 Emulex Corporation. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details, a copy of which * + * can be found in the file COPYING included with this package. * + *******************************************************************/ + +#ifndef _H_FCOS +#define _H_FCOS + +#ifdef __KERNEL__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) +#endif /* __KERNEL__ */ + + +#ifdef LP6000 +#ifdef __KERNEL__ +/* From drivers/scsi */ +#include "hosts.h" + +/* The driver is comditionally compiled to utilize the old scsi error + * handling logic, or the make use of the new scsi logic (use_new_eh_code). + * To use the old error handling logic, delete the line "#define FC_NEW_EH 1". + * To use the new error handling logic, add the line "#define FC_NEW_EH 1". + * + * #define FC_NEW_EH 1 + */ + +/* Turn on new error handling for 2.4 kernel base and on */ +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,43) +#define FC_NEW_EH 1 +#endif + +#endif /* __KERNEL__ */ + +#ifndef __KERNEL__ +struct net_device_stats +{ + unsigned long rx_packets; /* total packets received */ + unsigned long tx_packets; /* total packets transmitted */ + unsigned long rx_bytes; /* total bytes received */ + unsigned long tx_bytes; /* total bytes transmitted */ + unsigned long rx_errors; /* bad packets received */ + unsigned long tx_errors; /* packet transmit problems */ + unsigned long rx_dropped; /* no space in linux buffers */ + unsigned long tx_dropped; /* no space available in linux */ + unsigned long multicast; /* multicast packets received */ + unsigned long collisions; + + /* detailed rx_errors: */ + unsigned long rx_length_errors; + unsigned long rx_over_errors; /* receiver ring buff overflow */ + unsigned long rx_crc_errors; /* recved pkt with crc error */ + unsigned long rx_frame_errors; /* recv'd frame alignment error */ + unsigned long rx_fifo_errors; /* recv'r fifo overrun */ + unsigned long rx_missed_errors; /* receiver missed packet */ + + /* detailed tx_errors */ + unsigned long tx_aborted_errors; + unsigned long tx_carrier_errors; + unsigned long tx_fifo_errors; + unsigned long tx_heartbeat_errors; + unsigned long tx_window_errors; + + /* for cslip etc */ + unsigned long rx_compressed; + unsigned long tx_compressed; +}; +#define enet_statistics net_device_stats +#endif /* __KERNEL__ */ + +typedef unsigned char uchar; +/* both ushort and ulong may be defined*/ + +#ifndef __KERNEL__ +#ifndef _SYS_TYPES_H +typedef unsigned short ushort; +typedef unsigned long ulong; +#endif +#endif /* __KERNEL__ */ + + +#define SELTO_TIMEOUT p_dev_ctl->selto_timeout + +#define _local_ static +#define _static_ +#define _forward_ extern + +typedef unsigned short uint16; +typedef unsigned int uint32; +typedef long long uint64; +#ifdef __KERNEL__ +#if LINUX_VERSION_CODE < LinuxVersionCode(2,2,18) +typedef unsigned long dma_addr_t; +#endif +#endif + +#if BITS_PER_LONG > 32 +/* These macros are for 64 bit support */ +#define putPaddrLow(addr) ((uint32) \ +(0xffffffff & (unsigned long)(addr))) +#define putPaddrHigh(addr) ((uint32) \ + (0xffffffff & (((unsigned long)(addr))>>32))) +#define getPaddr(high, low) ((unsigned long) \ + ((((unsigned long) (high)) << 32)|((unsigned long)(low)))) + +#else +/* Macro's to support 32 bit addressing */ +#define putPaddrLow(addr) ((uint32)(addr)) +#define putPaddrHigh(addr) 0 +#define getPaddr(high, low) ((uint32)(low)) +#endif + +/* Macro to get from adapter number to ddi instance */ +#define fc_brd_to_inst(brd) fcinstance[brd] + +#define DELAYMS(ms) lpfc_DELAYMS(p_dev_ctl, ms) +#define DELAYMSctx(ms) lpfc_DELAYMS(p_dev_ctl, ms) + +#define EXPORT_LINUX 1 + +#ifdef CONFIG_PPC64 +#define powerpc +#endif + +#ifdef powerpc +#define LITTLE_ENDIAN_HOST 0 /* For fc.h */ +#define BIG_ENDIAN_HW 1 /* For fc_hw.h */ +#else +#define LITTLE_ENDIAN_HOST 1 /* For fc.h */ +#define LITTLE_ENDIAN_HW 1 /* For fc_hw.h */ +#endif /* powerpc */ + +#define MACADDR_LEN 6 /* MAC network address length */ +#define FC_LVL 0 +#define CLK_LVL 0 +#define EVENT_NULL (-1) +#define DMA_READ 1 /* flag argument to D_MAP_LIST */ +#ifndef NULL /* define NULL if not defined*/ +#define NULL (0) +#endif +#define FALSE 0 +#define TRUE 1 +#define DFC_IOCTL 1 + +/* Return value for PCI interrupt routine */ +#define INTR_SUCC 1 /* Claimed interrupt, detected work to do */ +#define INTR_FAIL 0 /* Doesn't claim interrupt */ + + +#define con_print(s, a, b) \ + fc_print(s, (void *)((ulong)a), (void *)((ulong)b)) + + +/* These calls are used before, and after, access to a shared memory + * access to the adapter. + */ +#define FC_MAP_MEM(p1) (void *) (*(p1)) /* sigh */ +#define FC_MAP_IO(p1) (void *) (*(p1)) /* sigh */ +#define FC_UNMAP_MEMIO(p1) /* groan */ + +#define fc_mpdata_outcopy(p, m, d, c) fc_bcopy((m)->virt, d, c) +#define fc_mpdata_incopy(p, m, s, c) fc_bcopy(s, (m)->virt, c) +#define fc_mpdata_sync(h, a, b, c) lpfc_mpdata_sync(p_dev_ctl, h, a, b, c) + +#define DDI_DMA_SYNC_FORKERNEL 1 +#define DDI_DMA_SYNC_FORCPU 1 +#define DDI_DMA_SYNC_FORDEV 2 + +/* This call is used to wakeup someone waiting to send a SCSI + * administrative command to the drive, only one outstanding + * command can be sent to each device. + */ +#define fc_admin_wakeup(p, d, bp) + +#define lpfc_restart_device(dev_ptr) +#define lpfc_handle_fcp_error(p_pkt, p_fcptr, p_cmd) \ + lpfc_fcp_error(p_fcptr, p_cmd) +#define STAT_ABORTED 0 + +struct watchdog { + void (*func)(void *); /* completion handler */ + uint32 restart; /* restart time (in seconds) */ + uint32 count; /* time remaining */ + ulong timeout_id; + struct timer_list timer; + int stopping; +}; + +#define ntimerisset(p1) (*(p1)) +#define ntimerclear(p1) (*(p1) = 0) +#define ntimercmp(p1, p2, cmp) ((p1) cmp (p2)) + + +/* This is the dio and d_iovec structures for the d_map_* services */ +typedef struct d_iovec { + void *stub; +} *d_iovec_t; + +struct dio { + void *stub; +}; +typedef struct dio * dio_t; + +#ifdef __KERNEL__ +#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,43) +#define pci_map_single(dev, address, size, direction) virt_to_bus(address) +#define pci_unmap_single(dev, address, size, direction) +#define pci_alloc_consistent(dev, s, h) fc_pci_alloc_consistent(dev, s, h) +#define pci_free_consistent(dev, s, v, h) fc_pci_free_consistent(dev, s, v, h) +#define scsi_sg_dma_address(sc) virt_to_bus((sc)->address) +#define scsi_sg_dma_len(sc) ((sc)->length) +typedef struct wait_queue *WAIT_QUEUE; +#else +#define scsi_sg_dma_address(sc) sg_dma_address(sc) +#define scsi_sg_dma_len(sc) sg_dma_len(sc) +typedef wait_queue_head_t WAIT_QUEUE; +#endif + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,17) +#define NETDEVICE struct net_device +#else +#define NETDEVICE struct device +#endif + +#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,43) +#define netif_start_queue(dev) clear_bit(0, (void*)&dev->tbusy) +#define netif_stop_queue(dev) set_bit(0, (void*)&dev->tbusy) +#define netdevice_start(dev) dev->start = 1 +#define netdevice_stop(dev) dev->start = 0 +#define dev_kfree_skb_irq(a) dev_kfree_skb(a) +#else +#define netdevice_start(dev) +#define netdevice_stop(dev) +#endif + +#else +#define NETDEVICE void +#endif + +struct intr { + int (*handler) (struct intr *); + NETDEVICE * lpfn_dev; + int (*lpfn_handler) (void); + int lpfn_mtu; + int lpfn_rcv_buf_size; +}; +typedef struct sk_buff fcipbuf_t; + +#define fcnextpkt(x) ((x)->prev) /* FOR Now */ +#define fcnextdata(x) ((x)->next) +#define fcpktlen(x) ((x)->len) /* Assume 1 skbuff per packet */ +#define fcdata(x) ((x)->data) +#define fcdatalen(x) ((x)->len) +#define fcgethandle(x) 0 + +#define fcsetdatalen(x, l) (((x)->len) = l) +#define fcincdatalen(x, l) (((x)->len) += l) +#define fcsethandle(x, h) +#define fcfreehandle(p,x) + +#define m_getclust(a,b) lpfc_alloc_skb(p_dev_ctl->ihs.lpfn_rcv_buf_size) +#define m_getclustm(a,b,c) lpfc_alloc_skb(c) +#define m_freem(x) lpfc_kfree_skb(x); + +#define FC_RCV_BUF_SIZE lpfc_ip_rcvsz(p_dev_ctl) /* rcv buf size for IP */ + +#define enet_statistics net_device_stats +/* Structure for generic statistics */ +typedef struct ndd_genstats { + struct enet_statistics ndd_enet; + uint32 ndd_elapsed_time; /* time in seconds since last reset */ + uint32 ndd_ipackets_msw; /* packets received on interface(msw) */ + uint32 ndd_ibytes_msw; /* total # of octets received(msw) */ + uint32 ndd_recvintr_msw; /* number of receive interrupts(msw) */ + uint32 ndd_recvintr_lsw; /* number of receive interrupts(lsw) */ + uint32 ndd_opackets_msw; /* packets sent on interface(msw) */ + uint32 ndd_obytes_msw; /* total number of octets sent(msw) */ + uint32 ndd_xmitintr_msw; /* number of transmit interrupts(msw) */ + uint32 ndd_xmitintr_lsw; /* number of transmit interrupts(lsw) */ + uint32 ndd_nobufs; /* no buffers available */ + uint32 ndd_xmitque_max; /* max transmits ever queued */ + uint32 ndd_xmitque_ovf; /* number of transmit queue overflows */ + uint32 ndd_ibadpackets; /* # of bad pkts recv'd from adapter */ + uint32 ndd_xmitque_cur; /* sum of driver+adapter xmit queues */ + uint32 ndd_ifOutUcastPkts_msw; /* outbound unicast pkts requested */ + uint32 ndd_ifOutUcastPkts_lsw; /* on interface (msw and lsw) */ + uint32 ndd_ifOutMcastPkts_msw; /* outbound multicast pkts requested */ + uint32 ndd_ifOutMcastPkts_lsw; /* on interface (msw and lsw) */ + uint32 ndd_ifOutBcastPkts_msw; /* outbound broadcast pkts requested */ + uint32 ndd_ifOutBcastPkts_lsw; /* on interface (msw and lsw) */ + uint32 ndd_ifInBcastPkts_msw; /* rcv'ed broadcast pkts requested */ + uint32 ndd_ifInBcastPkts_lsw; /* on interface (msw and lsw) */ +} ndd_genstats_t; + +#define ndd_ipackets_lsw ndd_enet.rx_packets +#define ndd_opackets_lsw ndd_enet.tx_packets +#define ndd_ibytes_lsw ndd_enet.rx_bytes +#define ndd_obytes_lsw ndd_enet.tx_bytes +#define ndd_ipackets_drop ndd_enet.rx_dropped +#define ndd_opackets_drop ndd_enet.tx_dropped +#define ndd_ierrors ndd_enet.rx_errors +#define ndd_oerrors ndd_enet.tx_errors + +typedef struct ndd { + char *ndd_name; /* name, e.g. ``en0'' or ``tr0'' */ + char *ndd_alias; /* alternate name */ + uint32 ndd_flags; /* up/down, broadcast, etc. */ +#define NDD_UP (0x00000001) /* NDD is opened */ +#define NDD_BROADCAST (0x00000002) /* broadcast address valid */ +#define NDD_RUNNING (0x00000008) /* NDD is operational */ +#define NDD_SIMPLEX (0x00000010) /* can't hear own transmissions */ +#define NDD_MULTICAST (0x00000200) /* receiving all multicasts */ + void (*nd_receive)(void *, struct sk_buff *, void *); /* DLPI streams receive function */ + struct ndd_genstats ndd_genstats; /* generic network stats */ +} ndd_t; + +struct lpfn_probe { + int (*open)(NETDEVICE *dev); + int (*stop)(NETDEVICE *dev); + int (*hard_start_xmit) (struct sk_buff *skb, NETDEVICE *dev); + int (*hard_header) (struct sk_buff *skb, + NETDEVICE *dev, + unsigned short type, + void *daddr, + void *saddr, + unsigned len); + int (*rebuild_header)(struct sk_buff *skb); + void (*receive)(ndd_t *p_ndd, struct sk_buff *skb, void *p_dev_ctl); + struct net_device_stats* (*get_stats)(NETDEVICE *dev); + int (*change_mtu)(NETDEVICE *dev, int new_mtu); +}; +#define LPFN_PROBE 1 +#define LPFN_DETACH 2 +#define LPFN_DFC 3 + +struct buf { + void *av_forw; + void *av_back; + int b_bcount; /* transfer count */ + int b_error; /* expanded error field */ + int b_resid; /* words not transferred after error */ + int b_flags; /* see defines below */ +#define B_ERROR 0x0004 /* transaction aborted */ +#define B_READ 0x0040 /* read when I/O occurs */ +#define B_WRITE 0x0100 /* non-read pseudo-flag */ + struct scsi_cmnd *cmnd; + int isdone; +}; + +/* refer to the SCSI ANSI X3.131-1986 standard for information */ +struct sc_cmd { /* structure of the SCSI cmd block */ + uchar scsi_op_code; /* first byte of SCSI cmd block */ + uchar lun; /* second byte of SCSI cmd block */ + uchar scsi_bytes[14]; /* other bytes of SCSI cmd block */ +}; +#define SCSI_RELEASE_UNIT 0x17 +#define SCSI_REQUEST_SENSE 0x03 +#define SCSI_RESERVE_UNIT 0x16 + +struct scsi { + uchar scsi_length; /* byte length of scsi cmd (6,10, or 12) */ + uchar scsi_id; /* the target SCSI ID */ + uchar scsi_lun; /* which LUN on the target */ + uchar flags; /* flags for use with the physical scsi command */ +#define SC_NODISC 0x80 /* don't allow disconnections */ +#define SC_ASYNC 0x08 /* asynchronous data xfer */ + struct sc_cmd scsi_cmd; /* the actual SCSI cmd */ +}; + +struct sc_buf { + struct buf bufstruct; /* buffer structure containing request + for device -- MUST BE FIRST! */ + struct scsi scsi_command; /* the information relating strictly + to the scsi command itself */ + uint32 timeout_value; /* timeout value for the command, + in units of seconds */ + uint32 cmd_flag; +#define FLAG_ABORT 0x01 + + uchar status_validity; /* least significant bit - scsi_status + * valid, next least significant bit - + * card status valid */ + +#define SC_SCSI_ERROR 1 /* scsi status reflects error */ +#define SC_ADAPTER_ERROR 2 /* general card status reflects err */ + uchar scsi_status; /* returned SCSI Bus status */ +#define SCSI_STATUS_MASK 0x3e /* mask for useful bits */ +#define SC_GOOD_STATUS 0x00 /* target completed successfully */ +#define SC_CHECK_CONDITION 0x02 /* target is reporting an error, + * exception, or abnormal condition */ +#define SC_BUSY_STATUS 0x08 /* target is busy and cannot accept + * a command from initiator */ +#define SC_INTMD_GOOD 0x10 /* intermediate status good when using + * linked commands */ +#define SC_RESERVATION_CONFLICT 0x18 /* attempted to access a LUN which is + * reserved by another initiator */ +#define SC_COMMAND_TERMINATED 0x22 /* Command has been terminated by + * the device. */ +#define SC_QUEUE_FULL 0x28 /* Device's command queue is full */ + + uchar general_card_status; /* SCSI adapter card status byte */ +#define SC_HOST_IO_BUS_ERR 0x01 /* Host I/O Bus error condition */ +#define SC_SCSI_BUS_FAULT 0x02 /* failure of the SCSI Bus */ +#define SC_CMD_TIMEOUT 0x04 /* cmd didn't complete before timeout */ +#define SC_NO_DEVICE_RESPONSE 0x08 /* target device did not respond */ +#define SC_ADAPTER_HDW_FAILURE 0x10 /* indicating a hardware failure */ +#define SC_ADAPTER_SFW_FAILURE 0x20 /* indicating a microcode failure */ +#define SC_FUSE_OR_TERMINAL_PWR 0x40 /* indicating bad fuse or termination */ +#define SC_SCSI_BUS_RESET 0x80 /* detected external SCSI bus reset */ + + uchar adap_q_status; /* adapter's device queue status. This*/ +#define SC_DID_NOT_CLEAR_Q 0x1 /* SCSI adapter device driver has not */ + + uchar flags; /* flags to SCSI adapter driver */ +#define SC_RESUME 0x01 /* resume transaction queueing for this + * id/lun beginning with this sc_buf */ +#define SC_MAPPED 0x02 /* buffer is mapped */ + + uint32 qfull_retry_count; +struct dev_info *current_devp; +}; +#define STAT_DEV_RESET 0x0 + +#define MAX_FCP_TARGET 0xff /* max num of FCP targets supported */ +#define MAX_FCP_LUN 0xff /* max num of FCP LUNs supported */ +/* When on, if a lun is detected to be not present, or + * not ready ... device structures related to that lun + * will be freed to save memory. Remove this define + * to turn off the feature */ +#define FREE_LUN 1 + +#define INDEX(pan, target) (ushort)(((pan)<<8) | ((target) & 0x1ff)) +#define DEV_SID(x) (uchar)(x & 0xff) /* extract sid from device id */ +#define DEV_PAN(x) (uchar)((x>>8) & 0x01) /* extract pan from device id */ + +#define GET_PAYLOAD_PHYS_ADDR(x) (x->phys_adr) + +#define MAX_FCP_CMDS 4096 /* Max # of outstanding FCP cmds */ +#define MAX_FC_BRDS 16 /* Max # boards per system */ +#define MAX_FC_TARGETS 512 /* Max scsi target # per adapter */ +#define MAX_FC_BINDINGS 64 /* Max # of persistent bindings */ + +#define LPFC_LOCK_UNOWNED ((void *) -1) +#ifdef __KERNEL__ +#define cpuid smp_processor_id() +#define maxCPU NR_CPUS +#else +#define cpuid 0 +#define maxCPU 1 +#endif /* __KERNEL__ */ + +typedef struct Simple_lock { + spinlock_t *sl_lock; + int owner; +} Simple_lock; + +#define disable_lock(p1, p2) 0 +#define unlock_enable(p1, p2) + +#define LPFC_INIT_LOCK_DRIVER spin_lock_init(&lpfc_smp_lock) +#define LPFC_INIT_LOCK_DPCQ spin_lock_init(&lpfc_dpc_request_lock) + +#define LPFC_LOCK_DRIVER0 spin_lock_irqsave(&lpfc_smp_lock, iflg) +#define LPFC_LOCK_DRIVER(num) spin_lock_irqsave(&lpfc_smp_lock, iflg); \ + if(p_dev_ctl->fc_ipri != 0) { \ + printk("LOCK %d failure %x %x\n",num, \ + (uint32)p_dev_ctl->fc_ipri, (uint32)iflg); \ + } \ + p_dev_ctl->fc_ipri = num + +#define LPFC_UNLOCK_DRIVER0 spin_unlock_irqrestore(&lpfc_smp_lock, iflg) +#define LPFC_UNLOCK_DRIVER if(p_dev_ctl) p_dev_ctl->fc_ipri = 0; \ + spin_unlock_irqrestore(&lpfc_smp_lock, iflg) + +#define LPFC_LOCK_SCSI_DONE(shost) \ + spin_lock_irqsave(shost->host_lock, siflg) +#define LPFC_UNLOCK_SCSI_DONE(shost) \ + spin_unlock_irqrestore(shost->host_lock, siflg) + +#define LPFC_DPC_LOCK_Q spin_lock_irqsave(&lpfc_dpc_request_lock, siflg) +#define LPFC_DPC_UNLOCK_Q spin_unlock_irqrestore(&lpfc_dpc_request_lock, siflg) + +#define EPERM 1 /* Not super-user */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Arg list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No children */ +#ifndef EAGAIN +#define EAGAIN 11 /* Resource temporarily unavailable */ +#endif +#define ENOMEM 12 /* Not enough core */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Mount device busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Inappropriate ioctl for device */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math arg out of domain of func */ +#define ERANGE 34 /* Math result not representable */ +#ifndef ECONNABORTED +#define ECONNABORTED 103 /* Software caused connection abort */ +#endif +#ifndef ETIMEDOUT +#define ETIMEDOUT 110 /* Connection timed out */ +#endif + +#endif /* LP6000 */ + +#ifdef __KERNEL__ +#define EMULEX_REQ_QUEUE_LEN 2048 +#define EMULEX_MAX_SG(ql) (4 + ((ql) > 0) ? 7*((ql) - 1) : 0) + +#define SCMD_NEXT(scmd) ((struct scsi_cmnd *)(scmd)->SCp.ptr) + +int fc_detect(struct scsi_host_template *); +int fc_release(struct Scsi_Host *); +const char * fc_info(struct Scsi_Host *); +int fc_queuecommand(struct scsi_cmnd *, void (* done)(struct scsi_cmnd *)); +#define FC_EXTEND_TRANS_A 1 +int fc_abort(struct scsi_cmnd *); +#ifdef FC_NEW_EH +int fc_reset_bus(struct scsi_cmnd *); +int fc_reset_host(struct scsi_cmnd *); +int fc_reset_device(struct scsi_cmnd *); +#else +int lpfc_reset(struct scsi_cmnd *, unsigned int); +int fc_proc_info( char *, char **, off_t, int, int, int); +#endif + +#ifdef USE_HIMEM +#define HIGHMEM_ENTRY highmem_io:1 +#else +#define HIGHMEM_ENTRY +#endif + +#ifdef FC_NEW_EH +#define LPFC_SG_SEGMENT 64 +#define EMULEXFC { \ + name: "lpfc", \ + detect: fc_detect, \ + release: fc_release, \ + info: fc_info, \ + queuecommand: fc_queuecommand, \ + eh_abort_handler: fc_abort, \ + eh_device_reset_handler: fc_reset_device, \ + eh_bus_reset_handler: fc_reset_bus, \ + eh_host_reset_handler: fc_reset_host, \ + can_queue: EMULEX_REQ_QUEUE_LEN, \ + this_id: -1, \ + sg_tablesize: LPFC_SG_SEGMENT, \ + cmd_per_lun: 30, \ + use_clustering: DISABLE_CLUSTERING, \ + HIGHMEM_ENTRY \ +} + +#else +#define LPFC_SG_SEGMENT 32 +#define EMULEXFC { \ + next: NULL, \ + module: NULL, \ + proc_dir: NULL, \ + proc_info: fc_proc_info, \ + name: "lpfc", \ + detect: fc_detect, \ + release: fc_release, \ + info: fc_info, \ + ioctl: NULL, \ + command: NULL, \ + queuecommand: fc_queuecommand, \ + eh_strategy_handler: NULL, \ + eh_abort_handler: NULL, \ + eh_device_reset_handler:NULL, \ + eh_bus_reset_handler: NULL, \ + eh_host_reset_handler: NULL, \ + abort: fc_abort, \ + reset: lpfc_reset, \ + slave_attach: NULL, \ + can_queue: EMULEX_REQ_QUEUE_LEN, \ + sg_tablesize: LPFC_SG_SEGMENT, \ + cmd_per_lun: 30, \ + present: 0, \ + unchecked_isa_dma: 0, \ + use_clustering: DISABLE_CLUSTERING, \ + use_new_eh_code: 0, \ + emulated: 0 \ +} +#endif +#endif /* __KERNEL */ + +#endif /* _H_FCOS */ + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/fcclockb.c 830-ivtv/drivers/scsi/lpfc/fcclockb.c --- 000-virgin/drivers/scsi/lpfc/fcclockb.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/fcclockb.c Thu Jan 8 10:21:53 2004 @@ -0,0 +1,832 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Enterprise Fibre Channel Host Bus Adapters. * + * Refer to the README file included with this package for * + * driver version and adapter support. * + * Copyright (C) 2003 Emulex Corporation. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details, a copy of which * + * can be found in the file COPYING included with this package. * + *******************************************************************/ + +#include "fc_os.h" + +#include +#include +#include "fc_hw.h" +#include "fc.h" + +#include "fcdiag.h" +#include "hbaapi.h" + +#include "fc_hw.h" +#include "fc.h" + +#include "fcdiag.h" +#include "fcfgparm.h" +#include "fcmsg.h" +#include "fc_crtn.h" +#include "fc_ertn.h" + +extern fc_dd_ctl_t DD_CTL; +extern iCfgParam icfgparam[]; +/* Can be used to map driver instance number and hardware adapter number */ +extern int fcinstance[MAX_FC_BRDS]; +extern int fcinstcnt; + +_static_ FCCLOCK *fc_clkgetb(fc_dev_ctl_t *p_dev_ctl); +_static_ ulong fc_clk_rem(fc_dev_ctl_t *p_dev_ctl, FCCLOCK *cb); +_static_ int que_tin(FCLINK *blk, FCLINK *hdr); + +#include "lp6000.c" +#include "dfcdd.c" +/* +*** boolean to test if block is linked into specific queue +*** (intended for assertions) +*/ +#define inque(x,hdr) que_tin( (FCLINK *)(x), (FCLINK *)(hdr) ) + +#define FC_MAX_CLK_TIMEOUT 0xfffffff + +/***************************************************************** +*** fc_clkgetb() Get a clock block +*****************************************************************/ +_static_ FCCLOCK * +fc_clkgetb(fc_dev_ctl_t *p_dev_ctl) +{ + FC_BRD_INFO * binfo; + FCCLOCK_INFO * clock_info; + FCCLOCK * cb; + int i; + + clock_info = &DD_CTL.fc_clock_info; + + if(p_dev_ctl) { + binfo = &BINFO; + cb = (FCCLOCK * ) fc_mem_get(binfo, MEM_CLOCK); + } + else { + for(i=0;iclk_block[i]; + if(cb->cl_tix == -1) + break; + cb = 0; + } + } + + if(cb) + cb->cl_p_dev_ctl = (void *)p_dev_ctl; + + return (cb); +} + + +/***************************************************************** +*** fc_clkrelb() Release a clock block +*****************************************************************/ +_static_ void +fc_clkrelb(fc_dev_ctl_t *p_dev_ctl, FCCLOCK *cb) +{ + FC_BRD_INFO * binfo; + FCCLOCK_INFO * clock_info; + + clock_info = &DD_CTL.fc_clock_info; + + if(p_dev_ctl) { + binfo = &BINFO; + fc_mem_put(binfo, MEM_CLOCK, (uchar * )cb); + } + else { + cb->cl_tix = (uint32)-1; + } +} + + +/***************************************************************** +*** fc_clk_can() Cancel a clock request +*** fc_clk_can will cancel a previous request to fc_clk_set or +*** fc_clk_res. +*** The request must not have expired so far. A request that has been +*** cancelled cannot be reset. +*****************************************************************/ +_static_ int +fc_clk_can(fc_dev_ctl_t *p_dev_ctl, FCCLOCK *cb) +{ + FCCLOCK_INFO * clock_info; + int ipri; + + clock_info = &DD_CTL.fc_clock_info; + ipri = disable_lock(CLK_LVL, &CLOCK_LOCK); + + /* Make sure timer has not expired */ + if (!inque(cb, &clock_info->fc_clkhdr)) { + unlock_enable(ipri, &CLOCK_LOCK); + return(0); + } + + fc_clock_deque(cb); + + /* Release clock block */ + fc_clkrelb(p_dev_ctl, cb); + unlock_enable(ipri, &CLOCK_LOCK); + + return(1); +} + + +/***************************************************************** +*** fc_clk_rem() get amount of time remaining in a clock request +*** fc_clk_rem() returns the number of tix remaining in +*** a clock request generated by fc_clk_set or fc_clk_res. The timer must +*** not have expired or be cancelled. +*****************************************************************/ +_static_ ulong +fc_clk_rem(fc_dev_ctl_t *p_dev_ctl, FCCLOCK *cb) +{ + FCCLOCK_INFO * clock_info; + FCCLOCK * x; + ulong tix; + int ipri; + + clock_info = &DD_CTL.fc_clock_info; + ipri = disable_lock(CLK_LVL, &CLOCK_LOCK); + + tix = 0; + /* get top of clock queue */ + x = (FCCLOCK * ) & clock_info->fc_clkhdr; + /* + *** Add up ticks in blocks upto specified request + */ + do { + x = x->cl_fw; + if (x == (FCCLOCK * ) & clock_info->fc_clkhdr) { + unlock_enable(ipri, &CLOCK_LOCK); + return(0); + } + tix += x->cl_tix; + } while (x != cb); + + unlock_enable(ipri, &CLOCK_LOCK); + return(tix); +} + + +/***************************************************************** +*** fc_clk_res() clock reset +*** fc_clk_res() resets a clock previously assigned by fc_clk_set(). +*** That clock must not have expired. The new sec time is +*** used, measured from now. The original function/argument +*** are not changed. +*** Note: code parrallels fc_clk_can() and fc_clk_set(). +*****************************************************************/ +_static_ ulong +fc_clk_res(fc_dev_ctl_t *p_dev_ctl, ulong tix, FCCLOCK *cb) +{ + FCCLOCK_INFO * clock_info; + FCCLOCK * x; + int ipri; + + clock_info = &DD_CTL.fc_clock_info; + ipri = disable_lock(CLK_LVL, &CLOCK_LOCK); + + /* Make sure timer has not expired */ + if (!inque(cb, &clock_info->fc_clkhdr)) { + unlock_enable(ipri, &CLOCK_LOCK); + return(0); + } + if (tix <= 0) { + unlock_enable(ipri, &CLOCK_LOCK); + return(0); + } + tix++; /* round up 1 sec to account for partial first tick */ + + fc_clock_deque(cb); + + /* + *** Insert block into queue by order of amount of clock ticks, + *** each block contains difference in ticks between itself and + *** its predacessor. + */ + + /* get top of list */ + x = clock_info->fc_clkhdr.cl_f; + while (x != (FCCLOCK * ) & clock_info->fc_clkhdr) { + if (x->cl_tix >= tix) { + /* if inserting in middle of que, adjust next tix */ + x->cl_tix -= tix; + break; + } + tix -= x->cl_tix; + x = x->cl_fw; + } + + /* back up one in que */ + x = x->cl_bw; + fc_enque(cb, x); + clock_info->fc_clkhdr.count++; + cb->cl_tix = tix; + + unlock_enable(ipri, &CLOCK_LOCK); + return((ulong)1); +} + + +/***************************************************************** +*** fc_clk_set() request a clock service +*** fc_clk_set will cause specific functions to be executed at a fixed +*** time into the future. At a duration guaranteed to not be less +*** than, but potentially is longer than the given number of secs, +*** the given function is called with the given single argument. +*** Interlock is performed at a processor status level not lower +*** than the given value. The returned value is needed if the request +*** is to be cancelled or reset. +*****************************************************************/ +_static_ FCCLOCK * +fc_clk_set(fc_dev_ctl_t *p_dev_ctl, ulong tix, +void (*func)(fc_dev_ctl_t*, void*, void*), void *arg1, void *arg2) +{ + FCCLOCK_INFO * clock_info; + FCCLOCK * x; + FCCLOCK * cb; + int ipri; + + clock_info = &DD_CTL.fc_clock_info; + ipri = disable_lock(CLK_LVL, &CLOCK_LOCK); + + if (tix > FC_MAX_CLK_TIMEOUT) { + return(0); + } + tix++; /* round up 1 sec to account for partial first tick */ + + /* + *** Allocate a CLOCK block + */ + if ((cb = fc_clkgetb(p_dev_ctl)) == 0) { + unlock_enable(ipri, &CLOCK_LOCK); + return(0); + } + + /* + *** Insert block into queue by order of amount of clock ticks, + *** each block contains difference in ticks between itself and + *** its predecessor. + */ + + /* get top of list */ + x = clock_info->fc_clkhdr.cl_f; + while (x != (FCCLOCK * ) & clock_info->fc_clkhdr) { + if (x->cl_tix >= tix) { + /* if inserting in middle of que, adjust next tix */ + if (x->cl_tix > tix) { + x->cl_tix -= tix; + break; + } + /* + *** Another clock expires at same time. + *** Maintain the order of requests. + */ + for (x = x->cl_fw; + x != (FCCLOCK * ) & clock_info->fc_clkhdr; + x = x->cl_fw) { + if (x->cl_tix != 0) + break; + } + + /* I'm at end of list */ + tix = 0; + break; + } + + tix -= x->cl_tix; + x = x->cl_fw; + } + + /* back up one in que */ + x = x->cl_bw; + + /* Count the current number of unexpired clocks */ + clock_info->fc_clkhdr.count++; + fc_enque(cb, x); + cb->cl_func = (void(*)(void*, void*, void*))func; + cb->cl_arg1 = arg1; + cb->cl_arg2 = arg2; + cb->cl_tix = tix; + unlock_enable(ipri, &CLOCK_LOCK); + + return((FCCLOCK * ) cb); +} + + +/***************************************************************** +*** fc_timer +*** This function will be called by the driver every second. +*****************************************************************/ +_static_ void +fc_timer(void *p) +{ + fc_dev_ctl_t * p_dev_ctl; + FCCLOCK_INFO * clock_info; + ulong tix; + FCCLOCK * x; + int ipri; + + clock_info = &DD_CTL.fc_clock_info; + ipri = disable_lock(CLK_LVL, &CLOCK_LOCK); + + /* + *** Increment time_sample value + */ + clock_info->ticks++; + + x = clock_info->fc_clkhdr.cl_f; + + /* counter for propagating negative values */ + tix = 0; + /* If there are expired clocks */ + if (x != (FCCLOCK * ) & clock_info->fc_clkhdr) { + x->cl_tix = x->cl_tix - 1; + if (x->cl_tix <= 0) { + /* Loop thru all clock blocks */ + while (x != (FCCLOCK * ) & clock_info->fc_clkhdr) { + x->cl_tix += tix; + /* If # of ticks left > 0, break out of loop */ + if (x->cl_tix > 0) + break; + tix = x->cl_tix; + + /* Deque expired clock */ + fc_deque(x); + /* Decrement count of unexpired clocks */ + clock_info->fc_clkhdr.count--; + + unlock_enable(ipri, &CLOCK_LOCK); + + p_dev_ctl = x->cl_p_dev_ctl; + + if(p_dev_ctl) { + ipri = disable_lock(FC_LVL, &CMD_LOCK); + + /* Call timeout routine */ + (*x->cl_func) (p_dev_ctl, x->cl_arg1, x->cl_arg2); + /* Release clock block */ + fc_clkrelb(p_dev_ctl, x); + + unlock_enable(ipri, &CMD_LOCK); + } + else { + /* Call timeout routine */ + (*x->cl_func) (p_dev_ctl, x->cl_arg1, x->cl_arg2); + /* Release clock block */ + fc_clkrelb(p_dev_ctl, x); + } + + ipri = disable_lock(CLK_LVL, &CLOCK_LOCK); + + /* start over */ + x = clock_info->fc_clkhdr.cl_f; + } + } + } + unlock_enable(ipri, &CLOCK_LOCK); + fc_reset_timer(); +} + + +/***************************************************************** +*** fc_clock_deque() +*****************************************************************/ +_static_ void +fc_clock_deque(FCCLOCK *cb) +{ + FCCLOCK_INFO * clock_info; + FCCLOCK * x; + + clock_info = &DD_CTL.fc_clock_info; + /* + *** Remove the block from its present spot, but first adjust + *** tix field of any successor. + */ + if (cb->cl_fw != (FCCLOCK * ) & clock_info->fc_clkhdr) { + x = cb->cl_fw; + x->cl_tix += cb->cl_tix; + } + + /* Decrement count of unexpired clocks */ + clock_info->fc_clkhdr.count--; + + fc_deque(cb); +} + + +/***************************************************************** +*** fc_clock_init() +*****************************************************************/ +_static_ void +fc_clock_init() +{ + FCCLOCK_INFO * clock_info; + FCCLOCK * cb; + int i; + + clock_info = &DD_CTL.fc_clock_info; + + /* Initialize clock queue */ + clock_info->fc_clkhdr.cl_f = + clock_info->fc_clkhdr.cl_b = (FCCLOCK * ) & clock_info->fc_clkhdr; + clock_info->fc_clkhdr.count = 0; + + /* Initialize clock globals */ + clock_info->ticks = 0; + clock_info->Tmr_ct = 0; + + for(i=0;iclk_block[i]; + cb->cl_tix = (uint32)-1; + } +} + + +_static_ int +que_tin(FCLINK *blk, FCLINK *hdr) +{ + FCLINK * x; + + x = hdr->_f; + while (x != hdr) { + if (x == blk) { + return (1); + } + x = x->_f; + } + return(0); +} + + +_static_ void +fc_flush_clk_set( +fc_dev_ctl_t *p_dev_ctl, +void (*func)(fc_dev_ctl_t*, void*, void*)) +{ + FC_BRD_INFO * binfo; + FCCLOCK_INFO * clock_info; + FCCLOCK * x, * xmatch; + IOCBQ *iocbq; + int ipri; + + binfo = &BINFO; + clock_info = &DD_CTL.fc_clock_info; + ipri = disable_lock(CLK_LVL, &CLOCK_LOCK); + + x = clock_info->fc_clkhdr.cl_f; + + /* If there are clocks */ + while (x != (FCCLOCK * ) & clock_info->fc_clkhdr) { + if((p_dev_ctl == x->cl_p_dev_ctl) && ((void *)func == (void *)(*x->cl_func))) { + xmatch = x; + x = x->cl_fw; + + /* + *** Remove the block from its present spot, but first adjust + *** tix field of any successor. + */ + if (xmatch->cl_fw != (FCCLOCK * ) & clock_info->fc_clkhdr) { + x->cl_tix += xmatch->cl_tix; + } + + clock_info->fc_clkhdr.count--; + fc_deque(xmatch); + + if((void *)func == (void *)lpfc_scsi_selto_timeout) { + (*xmatch->cl_func) (p_dev_ctl, xmatch->cl_arg1, xmatch->cl_arg2); + } + if(func == fc_delay_timeout) { + iocbq = (IOCBQ *)xmatch->cl_arg1; + if(iocbq->bp) { + fc_mem_put(binfo, MEM_BUF, (uchar * )iocbq->bp); + } + if(iocbq->info) { + fc_mem_put(binfo, MEM_BUF, (uchar * )iocbq->info); + } + if(iocbq->bpl) { + fc_mem_put(binfo, MEM_BPL, (uchar * )iocbq->bpl); + } + fc_mem_put(binfo, MEM_IOCB, (uchar * )iocbq); + } + fc_clkrelb(p_dev_ctl, xmatch); + } + else { + x = x->cl_fw; + } + } + unlock_enable(ipri, &CLOCK_LOCK); + return; +} + +_static_ int +fc_abort_clk_blk( +fc_dev_ctl_t *p_dev_ctl, +void (*func)(fc_dev_ctl_t*, void*, void*), +void *arg1, +void *arg2) +{ + FC_BRD_INFO * binfo; + FCCLOCK_INFO * clock_info; + FCCLOCK * x, * xmatch; + IOCBQ *iocbq; + int ipri; + + binfo = &BINFO; + clock_info = &DD_CTL.fc_clock_info; + ipri = disable_lock(CLK_LVL, &CLOCK_LOCK); + + x = clock_info->fc_clkhdr.cl_f; + + /* If there are clocks */ + while (x != (FCCLOCK * ) & clock_info->fc_clkhdr) { + if((p_dev_ctl == x->cl_p_dev_ctl) && + ((void *)func == (void *)(*x->cl_func)) && + (arg1 == x->cl_arg1) && + (arg2 == x->cl_arg2)) { + xmatch = x; + x = x->cl_fw; + + /* + *** Remove the block from its present spot, but first adjust + *** tix field of any successor. + */ + if (xmatch->cl_fw != (FCCLOCK * ) & clock_info->fc_clkhdr) { + x->cl_tix += xmatch->cl_tix; + } + + clock_info->fc_clkhdr.count--; + fc_deque(xmatch); + if((void *)func == (void *)lpfc_scsi_selto_timeout) { + (*xmatch->cl_func) (p_dev_ctl, xmatch->cl_arg1, xmatch->cl_arg2); + } + if(func == fc_delay_timeout) { + iocbq = (IOCBQ *)xmatch->cl_arg1; + if(iocbq->bp) { + fc_mem_put(binfo, MEM_BUF, (uchar * )iocbq->bp); + } + if(iocbq->info) { + fc_mem_put(binfo, MEM_BUF, (uchar * )iocbq->info); + } + if(iocbq->bpl) { + fc_mem_put(binfo, MEM_BPL, (uchar * )iocbq->bpl); + } + fc_mem_put(binfo, MEM_IOCB, (uchar * )iocbq); + } + fc_clkrelb(p_dev_ctl, xmatch); + unlock_enable(ipri, &CLOCK_LOCK); + return(1); + } + else { + x = x->cl_fw; + } + } + unlock_enable(ipri, &CLOCK_LOCK); + return(0); +} + +_static_ int +fc_abort_delay_els_cmd( +fc_dev_ctl_t *p_dev_ctl, +uint32 did) +{ + FC_BRD_INFO * binfo; + FCCLOCK_INFO * clock_info; + FCCLOCK * x, * xmatch; + IOCBQ *iocbq, *saveiocbq, *next_iocbq; + int ipri; + + binfo = &BINFO; + clock_info = &DD_CTL.fc_clock_info; + ipri = disable_lock(CLK_LVL, &CLOCK_LOCK); + + x = clock_info->fc_clkhdr.cl_f; + + /* If there are clocks */ + while (x != (FCCLOCK * ) & clock_info->fc_clkhdr) { + if((p_dev_ctl == x->cl_p_dev_ctl) && + ((void *)(x->cl_func) == (void *)fc_delay_timeout)) { + xmatch = x; + x = x->cl_fw; + iocbq = (IOCBQ *)xmatch->cl_arg1; + + if((iocbq->iocb.un.elsreq.remoteID != did) && + (did != 0xffffffff)) + continue; + /* Abort delay xmit clock */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0100, /* ptr to msg structure */ + fc_mes0100, /* ptr to msg */ + fc_msgBlk0100.msgPreambleStr, /* begin varargs */ + did, + iocbq->iocb.un.elsreq.remoteID, + iocbq->iocb.ulpIoTag); /* end varargs */ + /* + *** Remove the block from its present spot, but first adjust + *** tix field of any successor. + */ + if (xmatch->cl_fw != (FCCLOCK * ) & clock_info->fc_clkhdr) { + x->cl_tix += xmatch->cl_tix; + } + + clock_info->fc_clkhdr.count--; + fc_deque(xmatch); + if(iocbq->bp) { + fc_mem_put(binfo, MEM_BUF, (uchar * )iocbq->bp); + } + if(iocbq->info) { + fc_mem_put(binfo, MEM_BUF, (uchar * )iocbq->info); + } + if(iocbq->bpl) { + fc_mem_put(binfo, MEM_BPL, (uchar * )iocbq->bpl); + } + fc_mem_put(binfo, MEM_IOCB, (uchar * )iocbq); + + fc_clkrelb(p_dev_ctl, xmatch); + + if(did != 0xffffffff) + break; + } + else { + x = x->cl_fw; + } + } + unlock_enable(ipri, &CLOCK_LOCK); + + if(binfo->fc_delayxmit) { + iocbq = binfo->fc_delayxmit; + saveiocbq = 0; + while(iocbq) { + + if((iocbq->iocb.un.elsreq.remoteID == did) || + (did == 0xffffffff)) { + + next_iocbq = (IOCBQ *)iocbq->q; + /* Abort delay xmit context */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0101, /* ptr to msg structure */ + fc_mes0101, /* ptr to msg */ + fc_msgBlk0101.msgPreambleStr, /* begin varargs */ + did, + iocbq->iocb.un.elsreq.remoteID, + iocbq->iocb.ulpIoTag); /* end varargs */ + if(saveiocbq) { + saveiocbq->q = iocbq->q; + } + else { + binfo->fc_delayxmit = (IOCBQ *)iocbq->q; + } + if(iocbq->bp) { + fc_mem_put(binfo, MEM_BUF, (uchar * )iocbq->bp); + } + if(iocbq->info) { + fc_mem_put(binfo, MEM_BUF, (uchar * )iocbq->info); + } + if(iocbq->bpl) { + fc_mem_put(binfo, MEM_BPL, (uchar * )iocbq->bpl); + } + fc_mem_put(binfo, MEM_IOCB, (uchar * )iocbq); + + if(did != 0xffffffff) + break; + iocbq = next_iocbq; + } + else { + saveiocbq = iocbq; + iocbq = (IOCBQ *)iocbq->q; + } + } + } + return(0); +} +/* DQFULL */ +/***************************************************************************** + * + * NAME: fc_q_depth_up + * FUNCTION: Increment current Q depth for LUNs + * + *****************************************************************************/ + +_static_ void +fc_q_depth_up( +fc_dev_ctl_t * p_dev_ctl, +void *n1, +void *n2) +{ + node_t *nodep; + NODELIST * ndlp; + iCfgParam * clp; + FC_BRD_INFO *binfo; + struct dev_info * dev_ptr; + + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + + if (clp[CFG_DFT_LUN_Q_DEPTH].a_current <= FC_MIN_QFULL) { + return; + } + + if(binfo->fc_ffstate != FC_READY) + goto out; + + /* + * Find the target from the nlplist based on SCSI ID + */ + ndlp = binfo->fc_nlpmap_start; + while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) { + nodep = (node_t *)ndlp->nlp_targetp; + if (nodep) { + for (dev_ptr = nodep->lunlist; dev_ptr != NULL; + dev_ptr = dev_ptr->next) { + if ((dev_ptr->stop_send_io == 0) && + (dev_ptr->fcp_cur_queue_depth < clp[CFG_DFT_LUN_Q_DEPTH].a_current)) { + dev_ptr->fcp_cur_queue_depth += (ushort)clp[CFG_DQFULL_THROTTLE_UP_INC].a_current; + if (dev_ptr->fcp_cur_queue_depth > clp[CFG_DFT_LUN_Q_DEPTH].a_current) + dev_ptr->fcp_cur_queue_depth = clp[CFG_DFT_LUN_Q_DEPTH].a_current; + } else { + /* + * Try to reset stop_send_io + */ + if (dev_ptr->stop_send_io) + dev_ptr->stop_send_io--; + } + } + } + ndlp = (NODELIST *)ndlp->nlp_listp_next; + } + +out: + fc_clk_set(p_dev_ctl, clp[CFG_DQFULL_THROTTLE_UP_TIME].a_current, fc_q_depth_up, + 0, 0); + + return; +} + +/* QFULL_RETRY */ +_static_ void +fc_qfull_retry( +void *n1) +{ + fc_buf_t * fcptr; + dvi_t * dev_ptr; + T_SCSIBUF * sbp; + struct buf * bp; + fc_dev_ctl_t * p_dev_ctl; + + fcptr = (fc_buf_t *)n1; + sbp = fcptr->sc_bufp; + dev_ptr = fcptr->dev_ptr; + bp = (struct buf *) sbp; + + if(dev_ptr->nodep) { + p_dev_ctl = dev_ptr->nodep->ap; + fc_fcp_bufunmap(p_dev_ctl, sbp); + } + /* + * Queue this command to the head of the device's + * pending queue for processing by fc_issue_cmd. + */ + if (dev_ptr->pend_head == NULL) { /* Is queue empty? */ + dev_ptr->pend_head = sbp; + dev_ptr->pend_tail = sbp; + bp->av_forw = NULL; + fc_enq_wait(dev_ptr); + } else { /* Queue not empty */ + bp->av_forw = (struct buf *) dev_ptr->pend_head; + dev_ptr->pend_head = sbp; + } + dev_ptr->pend_count++; +} + +_static_ void +fc_establish_link_tmo( +fc_dev_ctl_t * p_dev_ctl, +void *n1, +void *n2) +{ + FC_BRD_INFO * binfo; + iCfgParam * clp; + + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + /* Re-establishing Link, timer expired */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk1300, /* ptr to msg structure */ + fc_mes1300, /* ptr to msg */ + fc_msgBlk1300.msgPreambleStr, /* begin varargs */ + binfo->fc_flag, + binfo->fc_ffstate); /* end varargs */ + binfo->fc_flag &= ~FC_ESTABLISH_LINK; +} diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/fcdds.h 830-ivtv/drivers/scsi/lpfc/fcdds.h --- 000-virgin/drivers/scsi/lpfc/fcdds.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/fcdds.h Thu Jan 8 10:21:53 2004 @@ -0,0 +1,175 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Enterprise Fibre Channel Host Bus Adapters. * + * Refer to the README file included with this package for * + * driver version and adapter support. * + * Copyright (C) 2003 Emulex Corporation. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details, a copy of which * + * can be found in the file COPYING included with this package. * + *******************************************************************/ + +#ifndef _H_FCDDS +#define _H_FCDDS + +#include "fc_hw.h" + +#define LNAMESIZE 16 + +#ifndef DMA_MAXMIN_16M +#define DMA_MAXMIN_16M 0x8 +#define DMA_MAXMIN_32M 0x9 +#define DMA_MAXMIN_64M 0xa +#define DMA_MAXMIN_128M 0xb +#define DMA_MAXMIN_256M 0xc +#define DMA_MAXMIN_512M 0xd +#define DMA_MAXMIN_1G 0xe +#define DMA_MAXMIN_2G 0xf +#endif + +/****************************************************************************/ +/* This is the DDS structure for the FC device */ +/****************************************************************************/ + +typedef struct { + char logical_name[LNAMESIZE]; /* logical name in ASCII characters */ + char dev_alias[LNAMESIZE]; /* logical name in ASCII characters */ + uint32 devno; /* major/minor device number */ + + /* PCI parameters */ + int bus_id; /* for use with i_init and bus io */ + int sla; /* for use with pci_cfgrw and bus io */ + int bus_intr_lvl; /* interrupt level */ + uint64 bus_mem_addr; /* bus memory base address */ + uint64 bus_io_addr; /* I/O reg base address */ + + uint32 xmt_que_size; /* size of xmit queue for mbufs */ + uint32 num_iocbs; /* number of iocb buffers to allocate */ + uint32 num_bufs; /* number of ELS/IP buffers to allocate */ + uint32 fcpfabric_tmo; /* Extra FCP timeout for fabrics (in secs) */ + + ushort topology; /* link topology for init link */ + ushort post_ip_buf; /* number of IP buffers to post to ring 1 */ + + ushort rsvd1; + uchar ipclass; /* class to use for transmitting IP data */ + uchar fcpclass; /* class to use for transmitting FCP data */ + + uchar network_on; /* true if networking is enabled */ + uchar fcp_on; /* true if FCP access is enabled */ + uchar frame_512; /* true if 512 byte framesize is required */ + uchar use_adisc; /* Use ADISC results in FCP rediscovery */ + + uchar first_check; /* Ignore 0x2900 check condition after PLOGI */ + uchar sli; /* Service Level Interface supported */ + uchar ffnumrings; /* number of FF rings being used */ + + uchar scandown; + uchar linkdown_tmo; /* linkdown timer, seconds */ + uchar nodev_tmo; + uchar fabric_reg; /* perform RFT_ID with NameServer */ + + uchar nummask[4]; /* number of masks/rings being used */ + uchar rval[6]; /* rctl for ring, assume mask is 0xff */ + uchar tval[6]; /* type for ring, assume mask is 0xff */ + + uchar verbose; /* how much to hurl onto the console */ + uchar ack0support; /* Run with ACK0 for CLASS2 sequences */ + uchar log_only; /* console messages just logged to log file */ + uchar automap; /* assign scsi ids to all FCP devices */ + + uint32 default_tgt_queue_depth; /* max # cmds outstanding to a target */ + + uchar dds1_os; /* system dependent variable */ + uchar default_lun_queue_depth; /* max # cmds outstanding to a lun */ + uchar nodev_holdio; /* Hold I/O errors if device disappears */ + uchar zone_rscn; /* system dependent variable */ + + uchar check_cond_err; + uchar delay_rsp_err; + uchar rscn_adisc; + uchar filler1; + uchar filler2; + uchar filler3; + + uint32 dds5_os; /* system dependent variable */ +} fc_dds_t; + +/* Values for seed_base and fcp_mapping */ +#define FCP_SEED_WWPN 0x1 /* Entry scsi id is seeded for WWPN */ +#define FCP_SEED_WWNN 0x2 /* Entry scsi id is seeded for WWNN */ +#define FCP_SEED_DID 0x4 /* Entry scsi id is seeded for DID */ +#define FCP_SEED_MASK 0x7 /* mask for seeded flags */ + + + +/* Allocate space for any environment specific dds parameters */ + + + + + +/****************************************************************************/ +/* Device VPD save area */ +/****************************************************************************/ + +typedef struct fc_vpd { + uint32 status; /* vpd status value */ + uint32 length; /* number of bytes actually returned */ + struct { + uint32 rsvd1; /* Revision numbers */ + uint32 biuRev; + uint32 smRev; + uint32 smFwRev; + uint32 endecRev; + ushort rBit; + uchar fcphHigh; + uchar fcphLow; + uchar feaLevelHigh; + uchar feaLevelLow; + uint32 postKernRev; + uint32 opFwRev; + uchar opFwName[16]; + uint32 sli1FwRev; + uchar sli1FwName[16]; + uint32 sli2FwRev; + uchar sli2FwName[16]; + } rev; +} fc_vpd_t; + +/****************************************************************************/ +/* Node table information that the config routine needs */ +/****************************************************************************/ + + +/****************************************************************************/ +/* SCIOCOMPLETE results buffer structure */ +/****************************************************************************/ + +struct iorslt { + struct buf *buf_struct_ptr; + uint32 b_flags; + uint32 b_resid; + char b_error; +}; + +/****************************************************************************/ +/* Special ioctl calls for the Fibre Channel SCSI LAN device driver */ +/****************************************************************************/ + +#define SCIONODES 0x47 /* ioctl to get node table */ +#define SCIOSTRAT 0x48 /* strategy ioctl */ +#define SCIOCOMPLETE 0x49 /* I/O completion ioctl */ +#define SCIORESUMEQ 0x4a /* device resume Q ioctl */ + + +#endif /* _H_FCDDS */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/fcdiag.h 830-ivtv/drivers/scsi/lpfc/fcdiag.h --- 000-virgin/drivers/scsi/lpfc/fcdiag.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/fcdiag.h Thu Jan 8 10:21:53 2004 @@ -0,0 +1,353 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Enterprise Fibre Channel Host Bus Adapters. * + * Refer to the README file included with this package for * + * driver version and adapter support. * + * Copyright (C) 2003 Emulex Corporation. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details, a copy of which * + * can be found in the file COPYING included with this package. * + *******************************************************************/ + +#ifndef _H_FCDIAG +#define _H_FCDIAG + +#ifndef LP6000 +/* Applications using this header file should typedef the following */ +typedef unsigned int uint32; +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef void* MAILBOX; +#endif + +/* the brdinfo structure */ +typedef struct BRDINFO { + uint32 a_mem_hi; /* memory identifier for adapter access */ + uint32 a_mem_low; /* memory identifier for adapter access */ + uint32 a_flash_hi; /* memory identifier for adapter access */ + uint32 a_flash_low; /* memory identifier for adapter access */ + uint32 a_ctlreg_hi; /* memory identifier for adapter access */ + uint32 a_ctlreg_low; /* memory identifier for adapter access */ + uint32 a_intrlvl; /* interrupt level for adapter */ + uint32 a_pci; /* PCI identifier (device / vendor id) */ + uint32 a_busid; /* identifier of PCI bus adapter is on */ + uint32 a_devid; /* identifier of PCI device number */ + uchar a_rsvd1; /* reserved for future use */ + uchar a_rsvd2; /* reserved for future use */ + uchar a_siglvl; /* signal handler used by library */ + uchar a_ddi; /* identifier device driver instance number */ + uint32 a_onmask; /* mask of ONDI primatives supported */ + uint32 a_offmask; /* mask of OFFDI primatives supported */ + uchar a_drvrid[16]; /* driver version */ + uchar a_fwname[32]; /* firmware version */ +} brdinfo; + +/* bits in a_onmask */ +#define ONDI_MBOX 0x1 /* allows non-destructive mailbox commands */ +#define ONDI_IOINFO 0x2 /* supports retrieval of I/O info */ +#define ONDI_LNKINFO 0x4 /* supports retrieval of link info */ +#define ONDI_NODEINFO 0x8 /* supports retrieval of node info */ +#define ONDI_TRACEINFO 0x10 /* supports retrieval of trace info */ +#define ONDI_SETTRACE 0x20 /* supports configuration of trace info */ +#define ONDI_SLI1 0x40 /* hardware supports SLI-1 interface */ +#define ONDI_SLI2 0x80 /* hardware supports SLI-2 interface */ +#define ONDI_BIG_ENDIAN 0x100 /* DDI interface is BIG Endian */ +#define ONDI_LTL_ENDIAN 0x200 /* DDI interface is LITTLE Endian */ +#define ONDI_RMEM 0x400 /* allows reading of adapter shared memory */ +#define ONDI_RFLASH 0x800 /* allows reading of adapter flash */ +#define ONDI_RPCI 0x1000 /* allows reading of adapter pci registers */ +#define ONDI_RCTLREG 0x2000 /* allows reading of adapter cntrol registers */ +#define ONDI_CFGPARAM 0x4000 /* supports get/set configuration parameters */ +#define ONDI_CT 0x8000 /* supports passthru CT interface */ +#define ONDI_HBAAPI 0x10000 /* supports HBA API interface */ + +/* bits in a_offmask */ +#define OFFDI_MBOX 0x1 /* allows all mailbox commands */ +#define OFFDI_RMEM 0x2 /* allows reading of adapter shared memory */ +#define OFFDI_WMEM 0x4 /* allows writing of adapter shared memory */ +#define OFFDI_RFLASH 0x8 /* allows reading of adapter flash */ +#define OFFDI_WFLASH 0x10 /* allows writing of adapter flash */ +#define OFFDI_RPCI 0x20 /* allows reading of adapter pci registers */ +#define OFFDI_WPCI 0x40 /* allows writing of adapter pci registers */ +#define OFFDI_RCTLREG 0x80 /* allows reading of adapter cntrol registers */ +#define OFFDI_WCTLREG 0x100 /* allows writing of adapter cntrol registers */ +#define OFFDI_OFFLINE 0x80000000 /* if set, adapter is in offline state */ + +/* values for flag in SetDiagEnv */ +#define DDI_SHOW 0x0 +#define DDI_ONDI 0x1 +#define DDI_OFFDI 0x2 + +#define DDI_BRD_SHOW 0x10 +#define DDI_BRD_ONDI 0x11 +#define DDI_BRD_OFFDI 0x12 + +/* unused field */ +#define DDI_UNUSED 0xFFFFFFFFL /* indicate unused field of brdinfo */ + +/* the ioinfo structure */ +typedef struct IOINFO { + uint32 a_mbxCmd; /* mailbox commands issued */ + uint32 a_mboxCmpl; /* mailbox commands completed */ + uint32 a_mboxErr; /* mailbox commands completed, error status */ + uint32 a_iocbCmd; /* iocb command ring issued */ + uint32 a_iocbRsp; /* iocb rsp ring recieved */ + uint32 a_adapterIntr; /* adapter interrupt events */ + uint32 a_fcpCmd; /* FCP commands issued */ + uint32 a_fcpCmpl; /* FCP command completions recieved */ + uint32 a_fcpErr; /* FCP command completions errors */ + uint32 a_seqXmit; /* IP xmit sequences sent */ + uint32 a_seqRcv; /* IP sequences recieved */ + uint32 a_bcastXmit; /* cnt of successful xmit broadcast commands issued */ + uint32 a_bcastRcv; /* cnt of receive broadcast commands received */ + uint32 a_elsXmit; /* cnt of successful ELS request commands issued */ + uint32 a_elsRcv; /* cnt of ELS request commands received */ + uint32 a_RSCNRcv; /* cnt of RSCN commands recieved */ + uint32 a_seqXmitErr; /* cnt of unsuccessful xmit broadcast cmds issued */ + uint32 a_elsXmitErr; /* cnt of unsuccessful ELS request commands issued */ + uint32 a_elsBufPost; /* cnt of ELS buffers posted to adapter */ + uint32 a_ipBufPost; /* cnt of IP buffers posted to adapter */ + uint32 a_cnt1; /* generic counter */ + uint32 a_cnt2; /* generic counter */ + uint32 a_cnt3; /* generic counter */ + uint32 a_cnt4; /* generic counter */ + +} IOinfo; + +/* the linkinfo structure */ +typedef struct LINKINFO { + uint32 a_linkEventTag; + uint32 a_linkUp; + uint32 a_linkDown; + uint32 a_linkMulti; + uint32 a_DID; + uchar a_topology; + uchar a_linkState; + uchar a_alpa; + uchar a_alpaCnt; + uchar a_alpaMap[128]; + uchar a_wwpName[8]; + uchar a_wwnName[8]; +} LinkInfo; + +/* values for a_topology */ +#define LNK_LOOP 0x1 +#define LNK_PUBLIC_LOOP 0x2 +#define LNK_FABRIC 0x3 +#define LNK_PT2PT 0x4 + +/* values for a_linkState */ +#define LNK_DOWN 0x1 +#define LNK_UP 0x2 +#define LNK_FLOGI 0x3 +#define LNK_DISCOVERY 0x4 +#define LNK_REDISCOVERY 0x5 +#define LNK_READY 0x6 + +/* the traceinfo structure */ +typedef struct TRACEINFO { + uchar a_event; + uchar a_cmd; + ushort a_status; + uint32 a_information; +} TraceInfo; + +/* values for flag */ +#define TRC_SHOW 0x0 +#define TRC_MBOX 0x1 +#define TRC_IOCB 0x2 +#define TRC_INTR 0x4 +#define TRC_EVENT 0x8 + +/* values for a_event */ +#define TRC_MBOX_CMD 0x1 +#define TRC_MBOX_CMPL 0x2 +#define TRC_IOCB_CMD 0x3 +#define TRC_IOCB_RSP 0x4 +#define TRC_INTR_RCV 0x5 +#define TRC_EVENT1 0x6 +#define TRC_EVENT2 0x7 +#define TRC_EVENT_MASK 0x7 +#define TRC_RING0 0x0 +#define TRC_RING1 0x40 +#define TRC_RING2 0x80 +#define TRC_RING3 0xC0 +#define TRC_RING_MASK 0xC0 + +/* the cfgparam structure */ +typedef struct CFGPARAM { + uchar a_string[32]; + uint32 a_low; + uint32 a_hi; + uint32 a_default; + uint32 a_current; + ushort a_flag; + ushort a_changestate; + uchar a_help[80]; +} CfgParam; + +#define MAX_CFG_PARAM 64 + +/* values for a_flag */ +#define CFG_EXPORT 0x1 /* Export this parameter to the end user */ +#define CFG_IGNORE 0x2 /* Ignore this parameter */ +#define CFG_DEFAULT 0x8000 /* Reestablishing Link */ + +/* values for a_changestate */ +#define CFG_REBOOT 0x0 /* Changes effective after ystem reboot */ +#define CFG_DYNAMIC 0x1 /* Changes effective immediately */ +#define CFG_RESTART 0x2 /* Changes effective after driver restart */ + +/* the icfgparam structure - internal use only */ +typedef struct ICFGPARAM { + char *a_string; + uint32 a_low; + uint32 a_hi; + uint32 a_default; + uint32 a_current; + ushort a_flag; + ushort a_changestate; + char *a_help; +} iCfgParam; + + +/* the nodeinfo structure */ +typedef struct NODEINFO { + ushort a_flag; + ushort a_state; + uint32 a_did; + uchar a_wwpn[8]; + uchar a_wwnn[8]; + uint32 a_targetid; +} NodeInfo; + +#define MAX_NODES 512 + +/* Defines for a_state */ +#define NODE_UNUSED 0 /* unused NL_PORT entry */ +#define NODE_LIMBO 0x1 /* entry needs to hang around for wwpn / sid */ +#define NODE_LOGOUT 0x2 /* NL_PORT is not logged in - entry is cached */ +#define NODE_PLOGI 0x3 /* PLOGI was sent to NL_PORT */ +#define NODE_LOGIN 0x4 /* NL_PORT is logged in / login REG_LOGINed */ +#define NODE_PRLI 0x5 /* PRLI was sent to NL_PORT */ +#define NODE_ALLOC 0x6 /* NL_PORT is ready to initiate adapter I/O */ +#define NODE_SEED 0x7 /* seed scsi id bind in table */ + +/* Defines for a_flag */ +#define NODE_RPI_XRI 0x1 /* creating xri for entry */ +#define NODE_REQ_SND 0x2 /* sent ELS request for this entry */ +#define NODE_ADDR_AUTH 0x4 /* Authenticating addr for this entry */ +#define NODE_RM_ENTRY 0x8 /* Remove this entry */ +#define NODE_FARP_SND 0x10 /* sent FARP request for this entry */ +#define NODE_FABRIC 0x20 /* this entry represents the Fabric */ +#define NODE_FCP_TARGET 0x40 /* this entry is an FCP target */ +#define NODE_IP_NODE 0x80 /* this entry is an IP node */ +#define NODE_DISC_START 0x100 /* start discovery on this entry */ +#define NODE_SEED_WWPN 0x200 /* Entry scsi id is seeded for WWPN */ +#define NODE_SEED_WWNN 0x400 /* Entry scsi id is seeded for WWNN */ +#define NODE_SEED_DID 0x800 /* Entry scsi id is seeded for DID */ +#define NODE_SEED_MASK 0xe00 /* mask for seeded flags */ +#define NODE_AUTOMAP 0x1000 /* This entry was automap'ed */ +#define NODE_NS_REMOVED 0x2000 /* This entry removed from NameServer */ + +/* Defines for RegisterForEvent mask */ +#define FC_REG_LINK_EVENT 0x1 /* Register for link up / down events */ +#define FC_REG_RSCN_EVENT 0x2 /* Register for RSCN events */ +#define FC_REG_CT_EVENT 0x4 /* Register for CT request events */ +#define FC_REG_EVENT_MASK 0x3f /* event mask */ +#define FC_REG_ALL_PORTS 0x80 /* Register for all ports */ + +#define MAX_FC_EVENTS 8 /* max events user process can wait for per HBA */ +#define FC_FSTYPE_ALL 0xffff /* match on all fsTypes */ + +/* Defines for error codes */ +#define FC_ERROR_BUFFER_OVERFLOW 0xff +#define FC_ERROR_RESPONSE_TIMEOUT 0xfe +#define FC_ERROR_LINK_UNAVAILABLE 0xfd +#define FC_ERROR_INSUFFICIENT_RESOURCES 0xfc +#define FC_ERROR_EXISTING_REGISTRATION 0xfb +#define FC_ERROR_INVALID_TAG 0xfa + +/* User Library level Event structure */ +typedef struct reg_evt { + uint32 e_mask; + uint32 e_gstype; + uint32 e_pid; + uint32 e_outsz; + void (*e_func)(uint32, ...); + void * e_ctx; + void * e_out; +} RegEvent; + +/* Defines for portid for CT interface */ +#define CT_FabricCntlServer ((uint32)0xfffffd) +#define CT_NameServer ((uint32)0xfffffc) +#define CT_TimeServer ((uint32)0xfffffb) +#define CT_MgmtServer ((uint32)0xfffffa) + + +/* functions from diagnostic specification */ +uint32 InitDiagEnv(brdinfo *bi); +uint32 FreeDiagEnv(void); +uint32 SetDiagEnv(uint32 flag); +uint32 SetBrdEnv(uint32 board, uint32 flag); +uint32 GetIOinfo(uint32 board, IOinfo *ioinfo); +uint32 GetLinkInfo(uint32 board, LinkInfo *linkinfo); +uint32 GetCfgParam(uint32 board, CfgParam *cfgparam); +uint32 SetCfgParam(uint32 board, uint32 index, uint32 value); +uint32 GetNodeInfo(uint32 board, NodeInfo *nodeinfo); +int GetCTInfo(uint32 board, uint32 portid, uchar *inbuf, uint32 incnt, + uchar *outbuf, uint32 outcnt); +uint32 GetTraceInfo(uint32 board, TraceInfo *traceinfo); +uint32 SetTraceInfo(uint32 board, uint32 flag, uint32 depth); +uint32 IssueMbox(uint32 board, MAILBOX *mb, uint32 insize, uint32 outsize); +uint32 ReadMem(uint32 board, uchar *buffer, uint32 offset, uint32 count); +uint32 WriteMem(uint32 board, uchar *buffer, uint32 offset, uint32 count); +uint32 ReadFlash(uint32 board, uchar *buffer, uint32 offset, uint32 count); +uint32 WriteFlash(uint32 board, uchar *buffer, uint32 offset, uint32 count); +uint32 ReadCtlReg(uint32 board, uint32 *buffer, uint32 offset); +uint32 WriteCtlReg(uint32 board, uint32 *buffer, uint32 offset); +uint32 ReadPciCfg(uint32 board, uchar *buffer, uint32 offset, uint32 count); +uint32 WritePciCfg(uint32 board, uchar *buffer, uint32 offset, uint32 count); +uint32 ReadFcodeFlash(uint32 board, uchar *buffer, uint32 offset, uint32 count); +uint32 WriteFcodeFlash(uint32 board, uchar *buffer, uint32 offset, uint32 count); +uint32 SendElsCmd(uint32 board, uint32 opcode, uint32 did); +uint32 SendScsiCmd(uint32 board, void *wwn, void *req, uint32 sz, void *rsp, + uint32 *rsz, void *sns, uint32 *snssz); +uint32 SendScsiRead(uint32 board, void *PortWWN, uint64 l, uint32 s, + void *rsp, uint32 *rspCount, void *sns, uint32 *snsCount); +uint32 SendScsiWrite(uint32 board, void *PortWWN, uint64 l, uint32 s, + void *rsp, uint32 *rspCount, void *sns, uint32 *snsCount); +uint32 SendFcpCmd(uint32 board, void *wwn, void *req, uint32 sz, void *data, + uint32 *datasz, void *fcpRsp, uint32 *fcpRspsz); +void * RegisterForCTEvents(uint32 board, ushort type, void (*func)(uint32, ...), void *ctx, uint32 *pstat); +uint32 unRegisterForCTEvent(uint32 board, void *eventid); +uint32 RegisterForEvent(uint32 board, uint32 mask, void *type, uint32 outsz, void (*func)(uint32, ...), void *ctx); +uint32 unRegisterForEvent(uint32 board, uint32 eventid); + +#if defined(_KERNEL) || defined(__KERNEL__) +struct dfc_info { + brdinfo fc_ba; + char * fc_iomap_io; /* starting address for registers */ + char * fc_iomap_mem; /* starting address for SLIM */ + uchar * fc_hmap; /* handle for mapping memory */ + uint32 fc_refcnt; + uint32 fc_flag; +}; + +/* Define for fc_flag */ +#define DFC_STOP_IOCTL 1 /* Stop processing dfc ioctls */ +#define DFC_MBOX_ACTIVE 2 /* mailbox is active thru dfc */ + +#endif + +#endif /* _H_FCDIAG */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/fcelsb.c 830-ivtv/drivers/scsi/lpfc/fcelsb.c --- 000-virgin/drivers/scsi/lpfc/fcelsb.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/fcelsb.c Thu Jan 8 10:21:53 2004 @@ -0,0 +1,4792 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Enterprise Fibre Channel Host Bus Adapters. * + * Refer to the README file included with this package for * + * driver version and adapter support. * + * Copyright (C) 2003 Emulex Corporation. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details, a copy of which * + * can be found in the file COPYING included with this package. * + *******************************************************************/ + +#include "fc_os.h" + +#include "fc_hw.h" +#include "fc.h" + +#include "fcdiag.h" +#include "hbaapi.h" +#include "fcfgparm.h" +#include "fcmsg.h" +#include "fc_crtn.h" +#include "fc_ertn.h" /* Environment - external routine definitions */ + +extern fc_dd_ctl_t DD_CTL; +extern iCfgParam icfgparam[]; +extern char *lpfc_release_version; +extern int fc_max_els_sent; + +/* Routine Declaration - Local */ +_local_ int fc_chksparm(FC_BRD_INFO *binfo,volatile SERV_PARM *sp, uint32 cls); +_local_ int fc_els_retry(FC_BRD_INFO *binfo, RING *rp, IOCBQ *iocb, uint32 cmd, + NODELIST *nlp); +_local_ int fc_status_action(FC_BRD_INFO *binfo, IOCBQ *iocb, uint32 cmd, + NODELIST *nlp); +/* End Routine Declaration - Local */ + +/******************************************************/ +/** handle_els_event **/ +/** **/ +/** Description: Process an ELS Response Ring cmpl. **/ +/** **/ +/******************************************************/ +_static_ int +handle_els_event( +fc_dev_ctl_t *p_dev_ctl, +RING *rp, +IOCBQ *temp) +{ + IOCB * cmd; + FC_BRD_INFO * binfo; + IOCBQ * xmitiq; + volatile SERV_PARM * sp; + uint32 * lp0, * lp1; + MATCHMAP * mp, * rmp; + DMATCHMAP * drmp; + NODELIST * ndlp; + MAILBOXQ * mb; + ELS_PKT * ep; + iCfgParam * clp; + ADISC * ap; + void * ioa; + int rc; + uint32 command; + uint32 did, bumpcnt; + volatile uint32 ha_copy; + + /* Called from host_interrupt() to process ELS R0ATT */ + rc = 0; + ndlp = 0; + binfo = &BINFO; + cmd = &temp->iocb; + + /* look up xmit complete by IoTag */ + if ((xmitiq = fc_ringtxp_get(rp, cmd->ulpIoTag)) == 0) { + /* completion with missing xmit command */ + FCSTATCTR.elsStrayXmitCmpl++; + + /* Stray ELS completion */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0102, /* ptr to msg structure */ + fc_mes0102, /* ptr to msg */ + fc_msgBlk0102.msgPreambleStr, /* begin varargs */ + cmd->ulpCommand, + cmd->ulpIoTag); /* end varargs */ + + return(EIO); + } + temp->retry = xmitiq->retry; + + if(binfo->fc_ffstate < FC_READY) { + /* If we are in discovery, and a Link Event is pending, abandon + * discovery, clean up pending actions, and take the Link Event. + */ + ioa = FC_MAP_IO(&binfo->fc_iomap_io); /* map in io registers */ + /* Read host attention register to determine interrupt source */ + ha_copy = READ_CSR_REG(binfo, FC_HA_REG(binfo, ioa)); + FC_UNMAP_MEMIO(ioa); + + if(ha_copy & HA_LATT) { + /* Pending Link Event during Discovery */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0250, /* ptr to msg structure */ + fc_mes0250, /* ptr to msg */ + fc_msgBlk0250.msgPreambleStr, /* begin varargs */ + (uint32)cmd->ulpCommand, + (uint32)cmd->ulpIoTag, + (uint32)cmd->ulpStatus, + cmd->un.ulpWord[4]); /* end varargs */ + fc_abort_discovery(p_dev_ctl); + temp->retry = 0xff; + } + } + + /* Check for aborted ELS command */ + if(temp->retry == 0xff) { + + /* Aborted ELS IOCB */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0104, /* ptr to msg structure */ + fc_mes0104, /* ptr to msg */ + fc_msgBlk0104.msgPreambleStr, /* begin varargs */ + cmd->ulpCommand, + cmd->ulpIoTag); /* end varargs */ + switch (cmd->ulpCommand) { + case CMD_ELS_REQUEST_CR: + case CMD_ELS_REQUEST64_CR: + case CMD_ELS_REQUEST_CX: + case CMD_ELS_REQUEST64_CX: + mp = (MATCHMAP * )xmitiq->bp; + rmp = (MATCHMAP * )xmitiq->info; + lp0 = (uint32 * )mp->virt; + ndlp = 0; + command = *lp0; + switch (command) { + case ELS_CMD_PLOGI: + case ELS_CMD_LOGO: + case ELS_CMD_PRLI: + case ELS_CMD_PDISC: + case ELS_CMD_ADISC: + rmp->fc_mptr = (uchar *)0; + break; + } + break; + case CMD_XMIT_ELS_RSP_CX: /* Normal ELS response completion */ + case CMD_XMIT_ELS_RSP64_CX: /* Normal ELS response completion */ + mp = (MATCHMAP * )xmitiq->bp; + ndlp = (NODELIST * )xmitiq->ndlp; + break; + case CMD_GEN_REQUEST64_CX: + case CMD_GEN_REQUEST64_CR: + if(xmitiq->bpl == 0) { + /* User initiated request */ + drmp = (DMATCHMAP * )xmitiq->info; + drmp->dfc_flag = -1; + fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq); + } + else { + /* Driver initiated request */ + /* Just free resources and let timer timeout */ + fc_mem_put(binfo, MEM_BPL, (uchar * )xmitiq->bpl); + if(xmitiq->bp) { + fc_mem_put(binfo, MEM_BUF, (uchar * )xmitiq->bp); + } + if(xmitiq->info) + fc_free_ct_rsp(p_dev_ctl, (MATCHMAP *)xmitiq->info); + fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq); + } + return(0); + } + goto out2; + } + + /* ELS completion */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0105, /* ptr to msg structure */ + fc_mes0105, /* ptr to msg */ + fc_msgBlk0105.msgPreambleStr, /* begin varargs */ + (uint32)cmd->ulpCommand, + (uint32)cmd->ulpIoTag, + (uint32)cmd->ulpStatus, + cmd->un.ulpWord[4]); /* end varargs */ + + switch (cmd->ulpCommand) { + + case CMD_GEN_REQUEST64_CR: + if(xmitiq->bpl == 0) { + /* User initiated request */ + drmp = (DMATCHMAP * )xmitiq->info; + drmp->dfc_flag = -2; + } + else { + /* Driver initiated request */ + /* Just free resources and let timer timeout */ + fc_mem_put(binfo, MEM_BPL, (uchar * )xmitiq->bpl); + if(xmitiq->bp) { + fc_mem_put(binfo, MEM_BUF, (uchar * )xmitiq->bp); + } + if(xmitiq->info) + fc_free_ct_rsp(p_dev_ctl, (MATCHMAP *)xmitiq->info); + } + + break; + + case CMD_ELS_REQUEST_CR: /* Local error in ELS command */ + case CMD_ELS_REQUEST64_CR: /* Local error in ELS command */ + + FCSTATCTR.elsXmitErr++; + + /* Find out which command failed */ + mp = (MATCHMAP * )xmitiq->bp; + rmp = (MATCHMAP * )xmitiq->info; + ndlp = (NODELIST *)rmp->fc_mptr; + rmp->fc_mptr = (uchar *)0; + + lp0 = (uint32 * )mp->virt; + command = *lp0; + + if (fc_els_retry(binfo, rp, temp, command, ndlp) == 0) { + /* retry of ELS command failed */ + switch (command) { + case ELS_CMD_FLOGI: /* Fabric login */ + if (ndlp) + ndlp->nlp_flag &= ~NLP_REQ_SND; + fc_freenode_did(binfo, Fabric_DID, 1); + if (binfo->fc_ffstate == FC_FLOGI) { + binfo->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); + if (binfo->fc_topology == TOPOLOGY_LOOP) { + binfo->fc_edtov = FF_DEF_EDTOV; + binfo->fc_ratov = FF_DEF_RATOV; + if ((mb=(MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + fc_config_link(p_dev_ctl, (MAILBOX * )mb); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + binfo->fc_flag |= FC_DELAY_DISC; + } else { + /* Device Discovery completion error */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0206, /* ptr to msg structure */ + fc_mes0206, /* ptr to msg */ + fc_msgBlk0206.msgPreambleStr, /* begin varargs */ + cmd->ulpStatus, + cmd->un.ulpWord[4], + cmd->un.ulpWord[5]); /* end varargs */ + binfo->fc_ffstate = FC_ERROR; + if ((mb=(MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + fc_clear_la(binfo, (MAILBOX * )mb); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + } + } + break; + + case ELS_CMD_PLOGI: /* NPort login */ + if ((ndlp == 0) && ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, (uint32)cmd->un.elsreq.remoteID)) == 0)) { + break; + } + + /* If we are in the middle of Discovery */ + if (ndlp->nlp_action & (NLP_DO_ADDR_AUTH | NLP_DO_DISC_START | NLP_DO_RSCN)) { + /* Goto next entry */ + fc_nextnode(p_dev_ctl, ndlp); + } + + ndlp->nlp_action &= ~NLP_DO_RNID; + ndlp->nlp_flag &= ~NLP_REQ_SND; + + if((ndlp->nlp_type & (NLP_AUTOMAP | NLP_SEED_MASK)) == 0) { + fc_freenode(binfo, ndlp, 1); + } + else { + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + } + break; + + case ELS_CMD_PRLI: /* Process Log In */ + if ((ndlp == 0) && ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, (uint32)cmd->un.elsreq.remoteID)) == 0)) { + break; + } + + /* If we are in the middle of Discovery */ + if (ndlp->nlp_action & (NLP_DO_DISC_START | NLP_DO_RSCN)) { + /* Goto next entry */ + fc_nextnode(p_dev_ctl, ndlp); + } + ndlp->nlp_flag &= ~NLP_REQ_SND; + ndlp->nlp_state = NLP_LOGIN; + fc_nlp_unmap(binfo, ndlp); + break; + + case ELS_CMD_PDISC: /* Pdisc */ + case ELS_CMD_ADISC: /* Adisc */ + if ((ndlp == 0) && ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, + (uint32)cmd->un.elsreq.remoteID)) == 0)) { + break; + } + + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + + ndlp->nlp_action |= NLP_DO_DISC_START; + binfo->fc_nlp_cnt++; + fc_els_cmd(binfo, ELS_CMD_PLOGI, (void *)((ulong)cmd->un.elsreq.remoteID), (uint32)0, (ushort)0, ndlp); + break; + + case ELS_CMD_LOGO: /* Logout */ + if ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, (uint32)cmd->un.elsreq.remoteID)) == 0) { + break; + } + + /* If we are in the middle of Discovery */ + if (ndlp->nlp_action & (NLP_DO_ADDR_AUTH | NLP_DO_DISC_START | NLP_DO_RSCN)) { + /* Goto next entry */ + fc_nextnode(p_dev_ctl, ndlp); + } + + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + break; + + case ELS_CMD_FARPR: /* Farp-res */ + ep = (ELS_PKT * )lp0; + if((ndlp = fc_findnode_wwpn(binfo, NLP_SEARCH_ALL, + &ep->un.farp.RportName)) == 0) + break; + + /* If we are in the middle of Discovery */ + if (ndlp->nlp_action & NLP_DO_DISC_START) { + /* Goto next entry */ + fc_nextnode(p_dev_ctl, ndlp); + } + + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + break; + + case ELS_CMD_FARP: /* Farp-req */ + ep = (ELS_PKT * )lp0; + + if((ndlp = fc_findnode_wwpn(binfo, NLP_SEARCH_ALL, + &ep->un.farp.RportName)) == 0) + break; + + ndlp->nlp_flag &= ~NLP_FARP_SND; + ndlp->nlp_action &= ~NLP_DO_ADDR_AUTH; + break; + + case ELS_CMD_SCR: /* State Change Registration */ + break; + + case ELS_CMD_RNID: /* Receive Node Identification */ + break; + + default: + /* Unknown ELS command */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0106, /* ptr to msg structure */ + fc_mes0106, /* ptr to msg */ + fc_msgBlk0106.msgPreambleStr, /* begin varargs */ + command); /* end varargs */ + FCSTATCTR.elsCmdPktInval++; + break; + } + /* ELS command completion error */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0107, /* ptr to msg structure */ + fc_mes0107, /* ptr to msg */ + fc_msgBlk0107.msgPreambleStr, /* begin varargs */ + cmd->ulpCommand, + cmd->ulpStatus, + cmd->un.ulpWord[4], + cmd->un.ulpWord[5]); /* end varargs */ + } + else { + /* Retry in progress */ + if ((command == ELS_CMD_PLOGI) && + ((cmd->un.ulpWord[4] & 0xff) == IOERR_LOOP_OPEN_FAILURE)) { + if (ndlp->nlp_action & (NLP_DO_ADDR_AUTH | NLP_DO_DISC_START | NLP_DO_RSCN)) { + /* Goto next entry */ + fc_nextnode(p_dev_ctl, ndlp); + } + } + } + + if (xmitiq->bpl) { + fc_mem_put(binfo, MEM_BPL, (uchar * )xmitiq->bpl); + } + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + fc_mem_put(binfo, MEM_BUF, (uchar * )xmitiq->info); + break; + + case CMD_XMIT_ELS_RSP_CX: /* Normal ELS response completion */ + case CMD_XMIT_ELS_RSP64_CX: /* Normal ELS response completion */ + + ndlp = (NODELIST * )xmitiq->ndlp; + did = 0; + bumpcnt = 0; + if ((ndlp) && (ndlp->nlp_flag & NLP_SND_PLOGI)) { + ndlp->nlp_flag &= ~NLP_SND_PLOGI; + did = ndlp->nlp_DID; + if((binfo->fc_flag & FC_RSCN_MODE) || + (binfo->fc_ffstate < FC_READY)) { + binfo->fc_nlp_cnt++; + bumpcnt = 1; + } + } + mp = (MATCHMAP * )xmitiq->bp; + lp0 = (uint32 * )mp->virt; + /* get command that errored */ + command = *lp0++; + sp = (volatile SERV_PARM * )lp0; + if (cmd->ulpStatus) { + /* Error occurred sending ELS response */ + /* check to see if we should retry */ + /* ELS response completion error */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0108, /* ptr to msg structure */ + fc_mes0108, /* ptr to msg */ + fc_msgBlk0108.msgPreambleStr, /* begin varargs */ + cmd->ulpCommand, + cmd->ulpStatus, + cmd->un.ulpWord[4], + cmd->un.ulpWord[5]); /* end varargs */ + FCSTATCTR.elsXmitErr++; + + if (fc_els_retry(binfo, rp, temp, command, ndlp) == 0) { + /* No retries */ + if ((ndlp) && (ndlp->nlp_flag & NLP_RM_ENTRY) && + !(ndlp->nlp_flag & NLP_REQ_SND)) { + if (ndlp->nlp_type & NLP_FCP_TARGET) { + ndlp->nlp_flag &= ~NLP_RM_ENTRY; + ndlp->nlp_action &= ~NLP_DO_ADDR_AUTH; + if(binfo->fc_ffstate == FC_READY) { + if(!(binfo->fc_flag & FC_RSCN_MODE)) { + binfo->fc_flag |= FC_RSCN_MODE; + ndlp->nlp_action |= NLP_DO_RSCN; + ndlp->nlp_flag &= ~NLP_NODEV_TMO; + fc_nextrscn(p_dev_ctl, 1); + } + } + else { + ndlp->nlp_action |= NLP_DO_DISC_START; + fc_nextdisc(p_dev_ctl, 1); + } + } else { + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + } + } + else { + if (ndlp) { + if(!(ndlp->nlp_flag & NLP_REQ_SND)) { + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + } + } + } + } + } else { + FCSTATCTR.elsXmitCmpl++; + if(ndlp) { + /* ELS response completion */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0109, /* ptr to msg structure */ + fc_mes0109, /* ptr to msg */ + fc_msgBlk0109.msgPreambleStr, /* begin varargs */ + ndlp->nlp_DID, + ndlp->nlp_type, + ndlp->nlp_flag, + ndlp->nlp_state); /* end varargs */ + if ((ndlp->nlp_flag & NLP_REG_INP)) { + uint32 size; + MATCHMAP * bmp; + ULP_BDE64 * bpl; + + bmp = (MATCHMAP *)(xmitiq->bpl); + bpl = (ULP_BDE64 * )bmp->virt; + bpl->tus.w = PCIMEM_LONG(bpl->tus.w); + size = (uint32)bpl->tus.f.bdeSize; + if(size == (sizeof(SERV_PARM) + sizeof(uint32))) { + fc_process_reglogin(p_dev_ctl, ndlp); + } + } + + if ((ndlp->nlp_flag & NLP_RM_ENTRY) && + !(ndlp->nlp_flag & NLP_REQ_SND)) { + if (ndlp->nlp_type & NLP_FCP_TARGET) { + ndlp->nlp_flag &= ~NLP_RM_ENTRY; + ndlp->nlp_action &= ~NLP_DO_ADDR_AUTH; + if(binfo->fc_ffstate == FC_READY) { + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + if(!(binfo->fc_flag & FC_RSCN_MODE)) { + did = 0; + if(bumpcnt) + binfo->fc_nlp_cnt--; + + binfo->fc_flag |= FC_RSCN_MODE; + ndlp->nlp_action |= NLP_DO_RSCN; + ndlp->nlp_flag &= ~NLP_NODEV_TMO; + fc_nextrscn(p_dev_ctl, 1); + } + } + else { + did = 0; + if(bumpcnt) + binfo->fc_nlp_cnt--; + + ndlp->nlp_action |= NLP_DO_DISC_START; + fc_nextdisc(p_dev_ctl, 1); + } + } else { + if (ndlp->nlp_type & NLP_IP_NODE) { + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + } + else { + fc_freenode(binfo, ndlp, 1); + } + } + } + } + } + + if (xmitiq->bpl) { + fc_mem_put(binfo, MEM_BPL, (uchar * )xmitiq->bpl); + } + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + if(did && (!(ndlp->nlp_flag & NLP_NS_REMOVED))) { + fc_els_cmd(binfo, ELS_CMD_PLOGI, (void *)((ulong)did), + (uint32)0, (ushort)0, ndlp); + } + break; + + case CMD_GEN_REQUEST64_CX: + if(xmitiq->bpl == 0) { + /* User initiated request */ + drmp = (DMATCHMAP * )xmitiq->info; + fc_mpdata_sync(drmp->dfc.dma_handle, 0, 0, DDI_DMA_SYNC_FORKERNEL); + + if (cmd->ulpStatus) { + /* Error occurred sending ELS command */ + if ((cmd->un.ulpWord[4] & 0xff) == IOERR_SEQUENCE_TIMEOUT) + drmp->dfc_flag = -1; + else + drmp->dfc_flag = -2; + } + else { + drmp->dfc_flag = (int)(cmd->un.genreq64.bdl.bdeSize); + } + } + else { + /* Driver initiated request */ + if (cmd->ulpStatus == 0) { + mp = (MATCHMAP * )xmitiq->bp; + ndlp = (NODELIST *)mp->fc_mptr; + if(ndlp && (ndlp->nlp_DID == NameServer_DID)) { + fc_ns_rsp(p_dev_ctl, (NODELIST *)mp->fc_mptr, + (MATCHMAP *)xmitiq->info, + (uint32)(cmd->un.genreq64.bdl.bdeSize)); + } + /* FDMI */ + if(ndlp && (ndlp->nlp_DID == FDMI_DID)) { + fc_fdmi_rsp(p_dev_ctl, (MATCHMAP *)mp, (MATCHMAP *)xmitiq->info); + } + } + if(xmitiq->info) + fc_free_ct_rsp(p_dev_ctl, (MATCHMAP *)xmitiq->info); + fc_mem_put(binfo, MEM_BPL, (uchar * )xmitiq->bpl); + if(xmitiq->bp) { + fc_mem_put(binfo, MEM_BUF, (uchar * )xmitiq->bp); + } + } + break; + + + case CMD_ELS_REQUEST_CX: /* Normal ELS command completion */ + case CMD_ELS_REQUEST64_CX: /* Normal ELS command completion */ + + /* get command that was accepted */ + mp = (MATCHMAP * )xmitiq->bp; + lp0 = (uint32 * )mp->virt; + command = *lp0; + + /* ELS command successful, get ptr to service params */ + rmp = (MATCHMAP * )xmitiq->info; + ndlp = (NODELIST *)rmp->fc_mptr; + rmp->fc_mptr = (uchar *)0; + + lp1 = (uint32 * )rmp->virt; + fc_mpdata_sync(rmp->dma_handle, 0, 0, DDI_DMA_SYNC_FORKERNEL); + + sp = (volatile SERV_PARM * )((char *)lp1 + sizeof(uint32)); + + if (cmd->ulpStatus) { + /* Error occurred sending ELS command */ + FCSTATCTR.elsXmitErr++; + /* ELS command completion error */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0110, /* ptr to msg structure */ + fc_mes0110, /* ptr to msg */ + fc_msgBlk0110.msgPreambleStr, /* begin varargs */ + command, + cmd->ulpStatus, + cmd->un.ulpWord[4], + cmd->un.ulpWord[5]); /* end varargs */ + if ((command == ELS_CMD_FARP) || + (command == ELS_CMD_FARPR)) { + ep = (ELS_PKT * )lp0; + if((ndlp=fc_findnode_wwpn(binfo, NLP_SEARCH_ALL, &ep->un.farp.RportName))) { + ndlp->nlp_flag &= ~NLP_FARP_SND; + ndlp->nlp_action &= ~NLP_DO_ADDR_AUTH; + } + } + + /* If error occurred on ADISC/PDISC, check to see if address + * still needs to be authenticated. + */ + if ((command == ELS_CMD_ADISC) || (command == ELS_CMD_PDISC)) { + if(ndlp == 0) { + ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, + (uint32)cmd->un.elsreq.remoteID); + } + } + else { + if (command == ELS_CMD_PLOGI) { + if(ndlp == 0) { + ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, + (uint32)cmd->un.elsreq.remoteID); + } + } + } + + /* check to see if we should retry */ + if (fc_els_retry(binfo, rp, temp, command, ndlp) == 0) { + /* retry of ELS command failed */ + switch (command) { + case ELS_CMD_FLOGI: + if (ndlp) + ndlp->nlp_flag &= ~NLP_REQ_SND; + if (binfo->fc_ffstate == FC_FLOGI) { + binfo->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); + fc_freenode_did(binfo, Fabric_DID, 1); + if (binfo->fc_topology == TOPOLOGY_LOOP) { + binfo->fc_edtov = FF_DEF_EDTOV; + binfo->fc_ratov = FF_DEF_RATOV; + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + fc_config_link(p_dev_ctl, (MAILBOX * )mb); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) + != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + binfo->fc_flag |= FC_DELAY_DISC; + } else { + /* Device Discovery completion error */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0207, /* ptr to msg structure */ + fc_mes0207, /* ptr to msg */ + fc_msgBlk0207.msgPreambleStr); /* begin & end varargs */ + binfo->fc_ffstate = FC_ERROR; + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, + MEM_MBOX | MEM_PRI))) { + fc_clear_la(binfo, (MAILBOX * )mb); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) + != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + } + } + break; + + case ELS_CMD_PLOGI: + /* Cache entry in case we are in a + * LOGI collision. + */ + if ((ndlp == 0) && ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, + (uint32)cmd->un.elsreq.remoteID)) == 0)) { + break; + } + + /* If we are in the middle of Discovery */ + if (ndlp->nlp_action & (NLP_DO_ADDR_AUTH | NLP_DO_DISC_START | NLP_DO_RSCN)) { + if((ndlp->nlp_state < NLP_LOGIN) && + !(ndlp->nlp_flag & NLP_REG_INP)) { + /* Goto next entry */ + fc_nextnode(p_dev_ctl, ndlp); + } + } + + ndlp->nlp_action &= ~NLP_DO_RNID; + ndlp->nlp_flag &= ~NLP_REQ_SND; + + if((ndlp->nlp_type & (NLP_AUTOMAP | NLP_SEED_MASK)) == 0) { + fc_freenode(binfo, ndlp, 1); + } + else { + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + } + break; + + case ELS_CMD_PRLI: + if ((ndlp == 0) && ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, + (uint32)cmd->un.elsreq.remoteID)) == 0)) { + break; + } + + /* If we are in the middle of Discovery */ + if (ndlp->nlp_action & (NLP_DO_DISC_START | NLP_DO_RSCN)) { + /* Goto next entry */ + fc_nextnode(p_dev_ctl, ndlp); + } + ndlp->nlp_flag &= ~NLP_REQ_SND; + ndlp->nlp_state = NLP_LOGIN; + fc_nlp_unmap(binfo, ndlp); + break; + + case ELS_CMD_PDISC: + case ELS_CMD_ADISC: + if ((ndlp == 0) && ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, + (uint32)cmd->un.elsreq.remoteID)) == 0)) { + break; + } + + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + + ndlp->nlp_action |= NLP_DO_DISC_START; + binfo->fc_nlp_cnt++; + fc_els_cmd(binfo, ELS_CMD_PLOGI, + (void *)((ulong)cmd->un.elsreq.remoteID), + (uint32)0, (ushort)0, ndlp); + break; + + case ELS_CMD_LOGO: + if ((ndlp == 0) && ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, + (uint32)cmd->un.elsreq.remoteID)) == 0)) { + break; + } + + /* If we are in the middle of Discovery */ + if (ndlp->nlp_action & (NLP_DO_ADDR_AUTH | NLP_DO_DISC_START | NLP_DO_RSCN)) { + /* Goto next entry */ + fc_nextnode(p_dev_ctl, ndlp); + } + + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + break; + + case ELS_CMD_FARP: /* Farp-req */ + if (ndlp == 0) + break; + + ndlp->nlp_flag &= ~NLP_FARP_SND; + ndlp->nlp_action &= ~NLP_DO_ADDR_AUTH; + break; + + case ELS_CMD_FARPR: /* Farp-res */ + if (ndlp == 0) + break; + + ndlp->nlp_flag &= ~NLP_FARP_SND; + ndlp->nlp_action &= ~NLP_DO_ADDR_AUTH; + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + break; + + case ELS_CMD_SCR: /* State Change Registration */ + break; + + case ELS_CMD_RNID: /* Node Identification */ + break; + + default: + FCSTATCTR.elsCmdPktInval++; + + /* Unknown ELS command */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0111, /* ptr to msg structure */ + fc_mes0111, /* ptr to msg */ + fc_msgBlk0111.msgPreambleStr, /* begin varargs */ + command); /* end varargs */ + break; + } + } + else { + /* Retry in progress */ + if ((command == ELS_CMD_PLOGI) && + ((cmd->un.ulpWord[4] & 0xff) == IOERR_LOOP_OPEN_FAILURE)) { + if (ndlp->nlp_action & (NLP_DO_ADDR_AUTH | NLP_DO_DISC_START | NLP_DO_RSCN)) { + /* Goto next entry */ + fc_nextnode(p_dev_ctl, ndlp); + } + } + } + } else { + FCSTATCTR.elsXmitCmpl++; + + /* Process successful command completion */ + switch (command) { + case ELS_CMD_FLOGI: + /* FLOGI completes successfully */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0208, /* ptr to msg structure */ + fc_mes0208, /* ptr to msg */ + fc_msgBlk0208.msgPreambleStr, /* begin varargs */ + cmd->un.ulpWord[4], + sp->cmn.e_d_tov, + sp->cmn.w2.r_a_tov, + sp->cmn.edtovResolution); /* end varargs */ + if (ndlp) + ndlp->nlp_flag &= ~NLP_REQ_SND; + + /* register the login, REG_LOGIN */ + if (binfo->fc_ffstate == FC_FLOGI) { + /* If Common Service Parameters indicate Nport + * we are point to point, if Fport we are Fabric. + */ + if (sp->cmn.fPort) { + binfo->fc_flag |= FC_FABRIC; + if (sp->cmn.edtovResolution) { + /* E_D_TOV ticks are in nanoseconds */ + binfo->fc_edtov = (SWAP_DATA(sp->cmn.e_d_tov) + 999999) / 1000000; + } else { + /* E_D_TOV ticks are in milliseconds */ + binfo->fc_edtov = SWAP_DATA(sp->cmn.e_d_tov); + } + binfo->fc_ratov = (SWAP_DATA(sp->cmn.w2.r_a_tov) + 999) / 1000; + + if (binfo->fc_topology == TOPOLOGY_LOOP) { + binfo->fc_flag |= FC_PUBLIC_LOOP; + } else { + /* If we are a N-port connected to a Fabric, + * fixup sparam's so logins to devices on + * remote loops work. + */ + binfo->fc_sparam.cmn.altBbCredit = 1; + } + + binfo->fc_myDID = cmd->un.ulpWord[4] & Mask_DID; + + if ((ndlp == 0) && ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, + (uint32)cmd->un.elsreq.remoteID)) == 0)) { + break; + } + ndlp->nlp_type |= NLP_FABRIC; + ndlp->nlp_flag &= ~NLP_REQ_SND; + + fc_nlp_logi(binfo, ndlp, + (NAME_TYPE *)&sp->portName, (NAME_TYPE *)&sp->nodeName); + + if ((mb=(MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + fc_config_link(p_dev_ctl, (MAILBOX * )mb); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) + != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + + /* register the login with adapter */ + if (ndlp->nlp_Rpi == 0) { + fc_bcopy((void *)sp, (void *) & binfo->fc_fabparam, + sizeof(SERV_PARM)); + + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, + MEM_MBOX | MEM_PRI))) { + fc_reg_login(binfo, cmd->un.elsreq.remoteID, + (uchar * )sp, (MAILBOX * )mb, 0); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) + != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + } + + binfo->fc_flag |= FC_DELAY_DISC; + } else { + binfo->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); + binfo->fc_edtov = FF_DEF_EDTOV; + binfo->fc_ratov = FF_DEF_RATOV; + if ((rc = fc_geportname((NAME_TYPE * ) & binfo->fc_portname, + (NAME_TYPE * ) & sp->portName))) { + /* This side will initiate the PLOGI */ + binfo->fc_flag |= FC_PT2PT_PLOGI; + + /* N_Port ID cannot be 0, set our to LocalID the + * other side will be RemoteID. + */ + fc_freenode_did(binfo, 0, 1); + + /* not equal */ + if (rc == 1) + binfo->fc_myDID = PT2PT_LocalID; + rc = 0; + + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, + MEM_MBOX | MEM_PRI))) { + fc_config_link(p_dev_ctl, (MAILBOX * )mb); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) + != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + if ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, (uint32)binfo->fc_myDID)) == 0) { + if((ndlp = (NODELIST *)fc_mem_get(binfo, MEM_NLP))) { + fc_bzero((void *)ndlp, sizeof(NODELIST)); + ndlp->sync = binfo->fc_sync; + ndlp->capabilities = binfo->fc_capabilities; + ndlp->nlp_DID = binfo->fc_myDID; + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + } + else + break; + } + ndlp->nlp_DID = binfo->fc_myDID; + fc_nlp_logi(binfo, ndlp, + (NAME_TYPE *)&sp->portName, (NAME_TYPE *)&sp->nodeName); + } else { + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, + MEM_MBOX | MEM_PRI))) { + fc_config_link(p_dev_ctl, (MAILBOX * )mb); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) + != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + } + binfo->fc_flag |= FC_PT2PT; + /* Use Fabric timer as pt2pt link up timer */ + binfo->fc_fabrictmo = (2 * binfo->fc_ratov) + + ((4 * binfo->fc_edtov) / 1000) + 1; + if(FABRICTMO) { + fc_clk_res(p_dev_ctl, binfo->fc_fabrictmo, FABRICTMO); + } + else { + FABRICTMO = fc_clk_set(p_dev_ctl, binfo->fc_fabrictmo, + fc_fabric_timeout, 0, 0); + } + fc_freenode_did(binfo, Fabric_DID, 1); + + /* This is Login at init, clear la */ + if ((mb=(MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + binfo->fc_ffstate = FC_CLEAR_LA; + fc_clear_la(binfo, (MAILBOX * )mb); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) + != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + } + } else { + FCSTATCTR.elsRcvDrop++; + fc_freenode_did(binfo, Fabric_DID, 1); + } + break; + + case ELS_CMD_PLOGI: + /* PLOGI completes successfully */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0112, /* ptr to msg structure */ + fc_mes0112, /* ptr to msg */ + fc_msgBlk0112.msgPreambleStr, /* begin varargs */ + cmd->un.elsreq.remoteID, + cmd->un.ulpWord[4], + cmd->un.ulpWord[5], + binfo->fc_ffstate); /* end varargs */ + if ((ndlp == 0) && ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, + (uint32)cmd->un.elsreq.remoteID)) == 0)) { + break; + } + fc_nlp_logi(binfo, ndlp, + (NAME_TYPE *)&sp->portName, (NAME_TYPE *)&sp->nodeName); + + if (ndlp->nlp_DID != NameServer_DID) + ndlp->nlp_action &= ~NLP_DO_ADDR_AUTH; + + + ndlp->nlp_action &= ~NLP_DO_RNID; + + if (binfo->fc_flag & FC_PT2PT) { + /* Device Discovery completes */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0209, /* ptr to msg structure */ + fc_mes0209, /* ptr to msg */ + fc_msgBlk0209.msgPreambleStr); /* begin & end varargs */ + /* Fix up any changed RPIs in FCP IOCBs queued up a txq */ + fc_fcp_fix_txq(p_dev_ctl); + + binfo->fc_ffstate = FC_READY; + + binfo->fc_firstopen = 0; + if(FABRICTMO) { + fc_clk_can(p_dev_ctl, FABRICTMO); + FABRICTMO = 0; + } + ndlp->nlp_Rpi = 0; /* Keep the same rpi */ + } + + if (ndlp->nlp_Rpi) { + /* must explicitly unregister the login, UREG_LOGIN */ + /* This is so pending I/Os get returned with NO_RPI */ + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + fc_unreg_login(binfo, ndlp->nlp_Rpi, (MAILBOX * )mb); + if (issue_mb_cmd(binfo,(MAILBOX * )mb,MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + binfo->fc_nlplookup[ndlp->nlp_Rpi] = 0; + ndlp->nlp_Rpi = 0; + } + + /* register the login, REG_LOGIN */ + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + fc_reg_login(binfo, cmd->un.elsreq.remoteID, (uchar * )sp, + (MAILBOX * )mb, 0); + if (issue_mb_cmd(binfo,(MAILBOX * )mb,MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + + /* Fill in the FCP/IP class */ + { + clp = DD_CTL.p_config[binfo->fc_brd_no]; + if ( (clp[CFG_FCP_CLASS].a_current == CLASS2) && + (sp->cls2.classValid) ) { + ndlp->id.nlp_fcp_info |= CLASS2; + } else { + ndlp->id.nlp_fcp_info |= CLASS3; + } + + if ( (clp[CFG_IP_CLASS].a_current == CLASS2) && + (sp->cls2.classValid) ) { + ndlp->id.nlp_ip_info = CLASS2; + } else { + ndlp->id.nlp_ip_info = CLASS3; + } + } + + /* REG_LOGIN cmpl will goto nextnode */ + ndlp->nlp_flag &= ~NLP_REQ_SND; + ndlp->nlp_flag |= NLP_REG_INP; + break; + + case ELS_CMD_PRLI: + /* PRLI completes successfully */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0113, /* ptr to msg structure */ + fc_mes0113, /* ptr to msg */ + fc_msgBlk0113.msgPreambleStr, /* begin varargs */ + cmd->un.elsreq.remoteID, + cmd->un.ulpWord[4], + cmd->un.ulpWord[5], + binfo->fc_ffstate); /* end varargs */ + if ((ndlp == 0) && ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, + cmd->un.elsreq.remoteID)) == 0)) + break; + + ndlp->nlp_flag &= ~NLP_REQ_SND; + + /* If we are in the middle of Discovery or in pt2pt mode */ + if ((ndlp->nlp_action & (NLP_DO_DISC_START | NLP_DO_RSCN)) || + (binfo->fc_flag & FC_PT2PT)) { + int index; + node_t * node_ptr; + PRLI * npr; + + npr = (PRLI * )sp; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + if ((npr->acceptRspCode == PRLI_REQ_EXECUTED) && + (npr->prliType == PRLI_FCP_TYPE) && + (npr->targetFunc == 1)) { + + if(clp[CFG_FCP_ON].a_current) { + if (!(fc_assign_scsid(p_dev_ctl, ndlp))) { + /* No more SCSI ids available */ + fc_nextnode(p_dev_ctl, ndlp); + ndlp->nlp_state = NLP_PRLI; + fc_nlp_unmap(binfo, ndlp); + ndlp->nlp_action &= ~NLP_DO_SCSICMD; + break; + } + + if ((node_ptr = (node_t * )ndlp->nlp_targetp) == NULL) { + index = INDEX(ndlp->id.nlp_pan, ndlp->id.nlp_sid); + node_ptr = binfo->device_queue_hash[index].node_ptr; + } + /* PRLI target assigned */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0210, /* ptr to msg structure */ + fc_mes0210, /* ptr to msg */ + fc_msgBlk0210.msgPreambleStr, /* begin varargs */ + cmd->un.ulpWord[5], /* did */ + ndlp->id.nlp_pan, + ndlp->id.nlp_sid); /* end varargs */ + /* Now check for FCP-2 support */ + if(node_ptr) { + if(npr->Retry && npr->TaskRetryIdReq) + node_ptr->flags |= FC_FCP2_RECOVERY; + else + node_ptr->flags &= ~FC_FCP2_RECOVERY; + } + + } + else { + goto prlierr; + } + + /* If PRLI is successful, we have a FCP target device */ + if (((PRLI * )sp)->Retry == 1) { + ndlp->id.nlp_fcp_info |= NLP_FCP_2_DEVICE; + } + ndlp->nlp_type |= NLP_FCP_TARGET; + if((ndlp->nlp_type & NLP_SEED_MASK) == 0) { + switch(p_dev_ctl->fcp_mapping) { + case FCP_SEED_DID: + ndlp->nlp_type |= NLP_SEED_DID; + break; + case FCP_SEED_WWPN: + ndlp->nlp_type |= NLP_SEED_WWPN; + break; + case FCP_SEED_WWNN: + default: + ndlp->nlp_type |= NLP_SEED_WWNN; + break; + } + if(clp[CFG_AUTOMAP].a_current) + ndlp->nlp_type |= NLP_AUTOMAP; + } + ndlp->nlp_state = NLP_ALLOC; + fc_nlp_map(binfo, ndlp); + + /* Fix up any changed RPIs in FCP IOCBs queued up a txq */ + fc_fcp_fix_txq(p_dev_ctl); + + fc_nextnode(p_dev_ctl, ndlp); + } else { +prlierr: + ndlp->nlp_state = NLP_LOGIN; + fc_nlp_unmap(binfo, ndlp); + fc_nextnode(p_dev_ctl, ndlp); + } + } + else { + PRLI * npr; + + npr = (PRLI * )sp; + if ((npr->acceptRspCode == PRLI_REQ_EXECUTED) && + (npr->prliType == PRLI_FCP_TYPE) && + (npr->targetFunc == 1)) { + if(ndlp->nlp_type & NLP_FCP_TARGET) { + ndlp->nlp_state = NLP_ALLOC; + fc_nlp_map(binfo, ndlp); + } + else { + ndlp->nlp_state = NLP_PRLI; + fc_nlp_unmap(binfo, ndlp); + } + } + else { + ndlp->nlp_state = NLP_LOGIN; + fc_nlp_unmap(binfo, ndlp); + } + } + + ndlp->nlp_action &= ~NLP_DO_SCSICMD; + break; + + case ELS_CMD_PRLO: + /* PRLO completes successfully */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0114, /* ptr to msg structure */ + fc_mes0114, /* ptr to msg */ + fc_msgBlk0114.msgPreambleStr, /* begin varargs */ + cmd->un.elsreq.remoteID, + cmd->un.ulpWord[4], + cmd->un.ulpWord[5], + binfo->fc_ffstate); /* end varargs */ + break; + + case ELS_CMD_LOGO: + /* LOGO completes successfully */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0115, /* ptr to msg structure */ + fc_mes0115, /* ptr to msg */ + fc_msgBlk0115.msgPreambleStr, /* begin varargs */ + cmd->un.elsreq.remoteID, + cmd->un.ulpWord[4], + cmd->un.ulpWord[5], + binfo->fc_ffstate); /* end varargs */ + if ((ndlp == 0) && ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, + (uint32)cmd->un.elsreq.remoteID)) == 0)) { + break; + } + + /* If we are in the middle of Discovery */ + if (ndlp->nlp_action & (NLP_DO_ADDR_AUTH | NLP_DO_DISC_START | NLP_DO_RSCN)) { + /* Goto next entry */ + fc_nextnode(p_dev_ctl, ndlp); + } + + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + break; + + case ELS_CMD_PDISC: + /* PDISC completes successfully */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0116, /* ptr to msg structure */ + fc_mes0116, /* ptr to msg */ + fc_msgBlk0116.msgPreambleStr, /* begin varargs */ + cmd->un.elsreq.remoteID, + cmd->un.ulpWord[4], + cmd->un.ulpWord[5], + binfo->fc_ffstate); /* end varargs */ + if ((ndlp == 0) && ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, + (uint32)cmd->un.elsreq.remoteID)) == 0)) { + break; + } + + /* If we are in the middle of Address Authentication */ + if (ndlp->nlp_action & (NLP_DO_ADDR_AUTH)) { + if (fc_chkpadisc(binfo, ndlp, &sp->nodeName, + &sp->portName) == 0) { + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + ndlp->nlp_action |= NLP_DO_DISC_START; + } + /* Goto next entry */ + fc_nextnode(p_dev_ctl, ndlp); + } + ndlp->nlp_flag &= ~NLP_REQ_SND_PDISC; + break; + + case ELS_CMD_ADISC: + /* ADISC completes successfully */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0117, /* ptr to msg structure */ + fc_mes0117, /* ptr to msg */ + fc_msgBlk0117.msgPreambleStr, /* begin varargs */ + cmd->un.elsreq.remoteID, + cmd->un.ulpWord[4], + cmd->un.ulpWord[5], + binfo->fc_ffstate); /* end varargs */ + if ((ndlp == 0) && ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, + (uint32)cmd->un.elsreq.remoteID)) == 0)) { + break; + } + ndlp->nlp_flag &= ~NLP_REQ_SND_ADISC; + + /* If we are in the middle of Address Authentication */ + if (ndlp->nlp_action & (NLP_DO_ADDR_AUTH | NLP_DO_RSCN)) { + + ap = (ADISC * )sp; + if(fc_chkpadisc(binfo, ndlp, &ap->nodeName,&ap->portName) == 0) { + ndlp->nlp_action &= ~(NLP_DO_ADDR_AUTH | NLP_DO_DISC_START); + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + + + if((binfo->fc_flag & FC_RSCN_MODE) || + (binfo->fc_ffstate < FC_READY)) { + ndlp->nlp_DID = (uint32)cmd->un.elsreq.remoteID; + + + if(binfo->fc_flag & FC_RSCN_MODE) { + ndlp->nlp_action |= NLP_DO_RSCN; + binfo->fc_nlp_cnt--; + if (binfo->fc_nlp_cnt <= 0) { + binfo->fc_nlp_cnt = 0; + fc_nextrscn(p_dev_ctl, fc_max_els_sent); + } + } + else { + ndlp->nlp_action |= NLP_DO_DISC_START; + binfo->fc_nlp_cnt--; + if (binfo->fc_nlp_cnt <= 0) { + binfo->fc_nlp_cnt = 0; + fc_nextdisc(p_dev_ctl, fc_max_els_sent); + } + } + } + } + else { + fc_nextnode(p_dev_ctl, ndlp); + } + } + break; + + case ELS_CMD_FARP: + case ELS_CMD_FARPR: + /* FARP completes successfully */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0118, /* ptr to msg structure */ + fc_mes0118, /* ptr to msg */ + fc_msgBlk0118.msgPreambleStr, /* begin varargs */ + cmd->un.elsreq.remoteID, + cmd->un.ulpWord[4], + cmd->un.ulpWord[5], + command ); /* end varargs */ + ep = (ELS_PKT * )lp0; + if((ndlp = fc_findnode_wwpn(binfo, NLP_SEARCH_ALL, + &ep->un.farp.RportName)) == 0) + break; + + ndlp->nlp_flag &= ~NLP_FARP_SND; + ndlp->nlp_action &= ~NLP_DO_ADDR_AUTH; + break; + + case ELS_CMD_SCR: /* State Change Registration */ + /* SCR completes successfully */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0119, /* ptr to msg structure */ + fc_mes0119, /* ptr to msg */ + fc_msgBlk0119.msgPreambleStr, /* begin varargs */ + cmd->un.elsreq.remoteID, + cmd->un.ulpWord[4], + cmd->un.ulpWord[5], + binfo->fc_ffstate); /* end varargs */ + break; + + case ELS_CMD_RNID: /* Node Identification */ + /* RNID completes successfully */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0120, /* ptr to msg structure */ + fc_mes0120, /* ptr to msg */ + fc_msgBlk0120.msgPreambleStr, /* begin varargs */ + cmd->un.elsreq.remoteID, + cmd->un.ulpWord[4], + cmd->un.ulpWord[5], + binfo->fc_ffstate); /* end varargs */ + break; + + default: + FCSTATCTR.elsCmdPktInval++; + + /* Unknown ELS command completed */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0121, /* ptr to msg structure */ + fc_mes0121, /* ptr to msg */ + fc_msgBlk0121.msgPreambleStr, /* begin varargs */ + command); /* end varargs */ + break; + } + } + if (xmitiq->bpl) { + fc_mem_put(binfo, MEM_BPL, (uchar * )xmitiq->bpl); + } + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + fc_mem_put(binfo, MEM_BUF, (uchar * )rmp); + break; + + default: + FCSTATCTR.elsCmdIocbInval++; + + /* Unknown ELS IOCB */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0122, /* ptr to msg structure */ + fc_mes0122, /* ptr to msg */ + fc_msgBlk0122.msgPreambleStr, /* begin varargs */ + cmd->ulpCommand ); /* end varargs */ + +out2: + rc = EINVAL; + + if(xmitiq->bp) { + fc_mem_put(binfo, MEM_BUF, (uchar * )xmitiq->bp); + } + if(xmitiq->info) { + fc_mem_put(binfo, MEM_BUF, (uchar * )xmitiq->info); + } + if(xmitiq->bpl) { + fc_mem_put(binfo, MEM_BPL, (uchar * )xmitiq->bpl); + } + + break; + } /* switch(cmd->ulpCommand) */ + + fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq); + + return(rc); +} /* End handle_els_event */ + + +/**********************************************/ +/** handle_rcv_els_req **/ +/** **/ +/** Process an incoming ELS request **/ +/**********************************************/ +_static_ int +handle_rcv_els_req( +fc_dev_ctl_t *p_dev_ctl, +RING *rp, +IOCBQ *temp) +{ + IOCB * iocb; + FC_BRD_INFO * binfo; + uint32 * lp; + NODELIST * ndlp; + volatile SERV_PARM * sp; + NAME_TYPE * np; + ELS_PKT * ep; + MAILBOXQ * mb; + MATCHMAP * mp; + IOCBQ * saveq; + IOCBQ * iocbq; + uchar * bp; + uchar * bdeAddr; + iCfgParam * clp; + int i, cnt; + uint32 cmd; + uint32 did; + LS_RJT stat; + REG_WD30 wd30; + + iocb = &temp->iocb; + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + + if (binfo->fc_flag & FC_SLI2) { + /* type of ELS cmd is first 32bit word in packet */ + mp = fc_getvaddr(p_dev_ctl, rp, + (uchar * )getPaddr(iocb->un.cont64[0].addrHigh, + iocb->un.cont64[0].addrLow)); + } else { + /* type of ELS cmd is first 32bit word in packet */ + mp = fc_getvaddr(p_dev_ctl, rp, (uchar * )((ulong)iocb->un.cont[0].bdeAddress)); + } + + if (mp == 0) { + + if (binfo->fc_flag & FC_SLI2) { + bdeAddr = (uchar *)getPaddr(iocb->un.cont64[0].addrHigh, + iocb->un.cont64[0].addrLow); + } + else { + bdeAddr = (uchar *)((ulong)iocb->un.cont[0].bdeAddress); + } + FCSTATCTR.elsRcvDrop++; + + goto out; + } + + bp = mp->virt; + lp = (uint32 * )bp; + cmd = *lp++; + + /* Received ELS command */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0123, /* ptr to msg structure */ + fc_mes0123, /* ptr to msg */ + fc_msgBlk0123.msgPreambleStr, /* begin varargs */ + cmd, + iocb->un.ulpWord[5], + iocb->ulpStatus, + binfo->fc_ffstate); /* end varargs */ + if ((iocb->ulpStatus) || + ((binfo->fc_ffstate <= FC_FLOGI) && + ((cmd != ELS_CMD_FLOGI) && (cmd != ELS_CMD_ADISC) && + (cmd != ELS_CMD_FAN)))) { + if ((iocb->ulpStatus == 0) && (cmd == ELS_CMD_PLOGI)) { + /* Do this for pt2pt as well, testing with miniport driver */ + + /* Reject this request because we are in process of discovery */ + stat.un.b.lsRjtRsvd0 = 0; + stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; + stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; + stat.un.b.vendorUnique = 0; + fc_els_rsp(binfo, ELS_CMD_LS_RJT, (uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)0, (uint32)stat.un.lsRjtError, 0); + } + + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + + i = 1; + /* free resources associated with iocb and repost the ring buffers */ + if (!(binfo->fc_flag & FC_SLI2)) { + for (i = 1; i < (int)iocb->ulpBdeCount; i++) { + mp = fc_getvaddr(p_dev_ctl, rp, (uchar * )((ulong)iocb->un.cont[i].bdeAddress)); + if (mp) { + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + } + } + } + fc_post_buffer(p_dev_ctl, rp, i); + /* Drop frame if there is an error */ + FCSTATCTR.elsRcvDrop++; + return(0); + } + + /* Special case RSCN cause 2 byte payload length field is variable */ + if ((cmd & ELS_CMD_MASK) == ELS_CMD_RSCN) { + /* Received RSCN command */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0211, /* ptr to msg structure */ + fc_mes0211, /* ptr to msg */ + fc_msgBlk0211.msgPreambleStr, /* begin varargs */ + binfo->fc_flag, + binfo->fc_defer_rscn.q_cnt, + binfo->fc_rscn.q_cnt, + binfo->fc_mbox_active ); /* end varargs */ + /* ACCEPT the rscn request */ + fc_els_rsp(binfo, ELS_CMD_ACC, (uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)0, (uint32)(sizeof(uint32)), 0); + + if ((binfo->fc_flag & FC_RSCN_DISCOVERY) || + ((binfo->fc_flag & FC_RSCN_MODE) && !(binfo->fc_flag & FC_NSLOGI_TMR)) || + (binfo->fc_ffstate != FC_READY)) { + if(binfo->fc_defer_rscn.q_cnt > FC_MAX_HOLD_RSCN) { + binfo->fc_flag |= (FC_RSCN_DISCOVERY | FC_RSCN_MODE); + fc_flush_rscn_defer(p_dev_ctl); + goto dropit; + } + if(binfo->fc_flag & FC_RSCN_DISCOVERY) { + goto dropit; + } + else { + /* get an iocb buffer to copy entry into */ + if ((saveq = (IOCBQ * )fc_mem_get(binfo, MEM_IOCB | MEM_PRI)) != NULL) { + fc_bcopy((uchar *)temp, (uchar *)saveq, sizeof(IOCBQ)); + if (binfo->fc_defer_rscn.q_first) { + /* queue command to end of list */ + ((IOCBQ * )binfo->fc_defer_rscn.q_last)->q = (uchar * )saveq; + binfo->fc_defer_rscn.q_last = (uchar * )saveq; + } else { + /* add command to empty list */ + binfo->fc_defer_rscn.q_first = (uchar * )saveq; + binfo->fc_defer_rscn.q_last = (uchar * )saveq; + } + saveq->q = NULL; + *((MATCHMAP **)&saveq->iocb) = mp; + binfo->fc_defer_rscn.q_cnt++; + binfo->fc_flag |= FC_RSCN_MODE; + if (!(binfo->fc_flag & FC_SLI2)) { + i = (int)iocb->ulpBdeCount; + } + else { + i = 1; + } + fc_post_buffer(p_dev_ctl, rp, i); + return(0); + } + else + goto dropit; + } + } + + /* Make sure all outstanding Mailbox cmds (reg/unreg login) are processed + * before processing RSCN. + */ + if (binfo->fc_mbox_active) { + /* get an iocb buffer to copy entry into */ + if ((saveq = (IOCBQ * )fc_mem_get(binfo, MEM_IOCB | MEM_PRI)) != NULL) { + fc_bcopy((uchar *)temp, (uchar *)saveq, sizeof(IOCBQ)); + binfo->fc_flag |= (FC_DELAY_RSCN | FC_RSCN_MODE); + if (binfo->fc_rscn.q_first) { + /* queue command to end of list */ + ((IOCBQ * )binfo->fc_rscn.q_last)->q = (uchar * )saveq; + binfo->fc_rscn.q_last = (uchar * )saveq; + } else { + /* add command to empty list */ + binfo->fc_rscn.q_first = (uchar * )saveq; + binfo->fc_rscn.q_last = (uchar * )saveq; + } + + saveq->q = NULL; + *((MATCHMAP **)&saveq->iocb) = mp; + binfo->fc_rscn.q_cnt++; + if (!(binfo->fc_flag & FC_SLI2)) { + i = (int)iocb->ulpBdeCount; + } + else { + i = 1; + } + fc_post_buffer(p_dev_ctl, rp, i); + return(0); + } + else + goto dropit; + } + cmd &= ELS_CMD_MASK; + } + + switch (cmd) { + case ELS_CMD_PLOGI: + case ELS_CMD_FLOGI: + sp = (volatile SERV_PARM * )lp; + did = iocb->un.elsreq.remoteID; + if (cmd == ELS_CMD_FLOGI) { + FCSTATCTR.elsRcvFLOGI++; + if (binfo->fc_topology == TOPOLOGY_LOOP) { + /* We should never recieve a FLOGI in loop mode, ignore it */ + /* An FLOGI ELS command was received from DID in Loop Mode */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0124, /* ptr to msg structure */ + fc_mes0124, /* ptr to msg */ + fc_msgBlk0124.msgPreambleStr, /* begin varargs */ + cmd, + did); /* end varargs */ + break; + } + did = Fabric_DID; + if (fc_chksparm(binfo, sp, CLASS3)) { + /* For a FLOGI we accept, then if our portname is greater + * then the remote portname we initiate Nport login. + */ + int rc; + MAILBOX *tmpmb; + + rc = fc_geportname((NAME_TYPE * ) & binfo->fc_portname, + (NAME_TYPE * ) & sp->portName); + + if (rc == 2) { /* ourselves */ + /* It's ourselves, so we will just reset link */ + if ((tmpmb = (MAILBOX * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI)) == NULL) { + binfo->fc_ffstate = FC_ERROR; + return(1); + } + + binfo->fc_flag |= FC_SCSI_RLIP; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + + /* Setup and issue mailbox INITIALIZE LINK command */ + fc_linkdown(p_dev_ctl); + fc_init_link(binfo, (MAILBOX * )tmpmb, clp[CFG_TOPOLOGY].a_current, clp[CFG_LINK_SPEED].a_current); + tmpmb->un.varInitLnk.lipsr_AL_PA = 0; + if (issue_mb_cmd(binfo, (MAILBOX * )tmpmb, MBX_NOWAIT) != MBX_BUSY) + fc_mem_put(binfo, MEM_MBOX, (uchar * )tmpmb); + break; + } + + if (p_dev_ctl->fc_waitflogi) { + if (p_dev_ctl->fc_waitflogi != (FCCLOCK *)1) + fc_clk_can(p_dev_ctl, p_dev_ctl->fc_waitflogi); + p_dev_ctl->fc_waitflogi = 0; + p_dev_ctl->power_up = 1; + fc_snd_flogi(p_dev_ctl, 0, 0); + } + + fc_els_rsp(binfo, ELS_CMD_ACC, (uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)0, (uint32)sizeof(SERV_PARM), 0); + if (rc == 1) { /* greater than */ + binfo->fc_flag |= FC_PT2PT_PLOGI; + } + binfo->fc_flag |= FC_PT2PT; + /* Use Fabric timer as pt2pt link up timer */ + binfo->fc_fabrictmo = (2 * binfo->fc_ratov) + + ((4 * binfo->fc_edtov) / 1000) + 1; + if(FABRICTMO) { + fc_clk_res(p_dev_ctl, binfo->fc_fabrictmo, FABRICTMO); + } + else { + FABRICTMO = fc_clk_set(p_dev_ctl, binfo->fc_fabrictmo, + fc_fabric_timeout, 0, 0); + } + binfo->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); + } else { + /* Reject this request because invalid parameters */ + stat.un.b.lsRjtRsvd0 = 0; + stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; + stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS; + stat.un.b.vendorUnique = 0; + fc_els_rsp(binfo, ELS_CMD_LS_RJT, (uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)0, (uint32)stat.un.lsRjtError, + 0); + } + break; + } + FCSTATCTR.elsRcvPLOGI++; + + if (!(binfo->fc_flag & FC_PT2PT) && (binfo->fc_ffstate <= FC_FLOGI)) { + /* Reject this PLOGI because we are in rediscovery */ + stat.un.b.lsRjtRsvd0 = 0; + stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; + stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; + stat.un.b.vendorUnique = 0; + fc_els_rsp(binfo, ELS_CMD_LS_RJT, (uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)0, (uint32)stat.un.lsRjtError, 0); + break; + } + + if(did == NameServer_DID) + break; + + if((did & Fabric_DID_MASK) != Fabric_DID_MASK) { + /* Check to see if an existing cached entry is bad */ + ndlp = fc_findnode_wwpn(binfo, NLP_SEARCH_ALL, (NAME_TYPE *)&sp->portName); + if (ndlp && ndlp->nlp_DID && (ndlp->nlp_DID != did)) { + /* Check for a FARP generated nlplist entry */ + if (ndlp->nlp_DID == Bcast_DID) + ndlp->nlp_DID = did; + else { + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + } + } + } + + if ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, did)) == 0) { + /* This is a new node so allocate an nlplist entry and accept + * the LOGI request. + */ + if((ndlp = (NODELIST *)fc_mem_get(binfo, MEM_NLP))) { + fc_bzero((void *)ndlp, sizeof(NODELIST)); + ndlp->sync = binfo->fc_sync; + ndlp->capabilities = binfo->fc_capabilities; + ndlp->nlp_DID = did; + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + fc_nlp_logi(binfo, ndlp, + (NAME_TYPE *)&sp->portName, (NAME_TYPE *)&sp->nodeName); + } + else + break; + } + /* Received PLOGI command */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0125, /* ptr to msg structure */ + fc_mes0125, /* ptr to msg */ + fc_msgBlk0125.msgPreambleStr, /* begin varargs */ + ndlp->nlp_DID, + ndlp->nlp_state, + ndlp->nlp_flag, + ndlp->nlp_Rpi); /* end varargs */ + /* If we are pt2pt and this is the first PLOGI rcv'ed */ + if ((binfo->fc_flag & FC_PT2PT) && (binfo->fc_myDID == 0)) { + if(!(fc_chksparm(binfo, sp, CLASS3))) { + /* Reject this request because invalid parameters */ + stat.un.b.lsRjtRsvd0 = 0; + stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; + stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS; + stat.un.b.vendorUnique = 0; + fc_els_rsp(binfo, ELS_CMD_LS_RJT, (uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)0, (uint32)stat.un.lsRjtError, + ndlp); + break; + } + wd30.word = 0; + wd30.f.xri = iocb->ulpContext; + wd30.f.class = iocb->ulpClass; + + fc_freenode_did(binfo, 0, 1); + binfo->fc_myDID = iocb->un.ulpWord[4] & Mask_DID; + + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + fc_config_link(p_dev_ctl, (MAILBOX * )mb); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) + != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + if ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, binfo->fc_myDID)) == 0) { + if((ndlp = (NODELIST *)fc_mem_get(binfo, MEM_NLP))) { + fc_bzero((void *)ndlp, sizeof(NODELIST)); + ndlp->sync = binfo->fc_sync; + ndlp->capabilities = binfo->fc_capabilities; + ndlp->nlp_DID = binfo->fc_myDID; + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + } + } + if(ndlp) { + ndlp->nlp_DID = binfo->fc_myDID; + fc_nlp_logi(binfo, ndlp, &binfo->fc_portname, &binfo->fc_nodename); + if ((mb=(MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + fc_reg_login(binfo, binfo->fc_myDID, + (uchar * ) & binfo->fc_sparam, (MAILBOX * )mb, 0); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) + != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + } + /* Device Discovery completes */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0212, /* ptr to msg structure */ + fc_mes0212, /* ptr to msg */ + fc_msgBlk0212.msgPreambleStr); /* begin & end varargs */ + binfo->fc_ffstate = FC_READY; + + binfo->fc_firstopen = 0; + if(FABRICTMO) { + fc_clk_can(p_dev_ctl, FABRICTMO); + FABRICTMO = 0; + } + + /* issue mailbox command to register login with the adapter */ + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + fc_reg_login(binfo,did,(uchar * )sp, (MAILBOX * )mb, wd30.word); + if (issue_mb_cmd(binfo,(MAILBOX * )mb,MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + break; + } + + cnt = 1; + switch(ndlp->nlp_state) { + case NLP_PLOGI: + cnt = 0; + break; + + case NLP_LIMBO: + if (ndlp->nlp_flag & NLP_REQ_SND) { + cnt = 0; + break; + } + + case NLP_LOGOUT: + fc_nlp_logi(binfo, ndlp, + (NAME_TYPE *)&sp->portName, (NAME_TYPE *)&sp->nodeName); + + case NLP_LOGIN: + case NLP_PRLI: + case NLP_ALLOC: + ndlp->nlp_flag &= ~NLP_FARP_SND; + ndlp->nlp_action &= ~NLP_DO_ADDR_AUTH; + /* Keep the rpi we have and send ACC / LS_RJT */ + if (fc_chksparm(binfo, sp, CLASS3)) { + + if (ndlp->nlp_Rpi) { + fc_els_rsp(binfo, ELS_CMD_ACC, (uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)0, (uint32)(sizeof(SERV_PARM)), ndlp); + break; + } + /* no rpi so we must reglogin */ + ndlp->nlp_flag |= NLP_RCV_PLOGI; + wd30.word = 0; + wd30.f.xri = iocb->ulpContext; + wd30.f.class = iocb->ulpClass; + /* issue mailbox command to register login with the adapter */ + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + fc_reg_login(binfo,did,(uchar * )sp, (MAILBOX * )mb, wd30.word); + if (issue_mb_cmd(binfo,(MAILBOX * )mb,MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + } else { + /* Reject this request because invalid parameters */ + stat.un.b.lsRjtRsvd0 = 0; + stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; + stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS; + stat.un.b.vendorUnique = 0; + fc_els_rsp(binfo, ELS_CMD_LS_RJT, (uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)0, (uint32)stat.un.lsRjtError, + ndlp); + + if ((ndlp->nlp_state == NLP_ALLOC) && (binfo->fc_ffstate == FC_READY)) { + /* unregister existing login first */ + ndlp->nlp_flag |= NLP_UNREG_LOGO; + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + } + } + break; + } + + if(cnt) + break; + + + did = iocb->un.elsreq.remoteID; + + /* If a nlplist entry already exists, we potentially have + * a PLOGI collision. + */ + + if (!(ndlp->nlp_flag & NLP_REQ_SND)) { + /* In this case we are already logged in */ + ndlp->nlp_flag &= ~NLP_FARP_SND; + ndlp->nlp_action &= ~NLP_DO_ADDR_AUTH; + goto chkparm; + } + + FCSTATCTR.elsLogiCol++; + + /* For a PLOGI, we only accept if our portname is less + * than the remote portname. + */ + if (!(fc_geportname((NAME_TYPE * ) & binfo->fc_portname, + (NAME_TYPE * ) & sp->portName))) { +chkparm: + fc_nlp_logi(binfo, ndlp, + (NAME_TYPE *)&sp->portName, (NAME_TYPE *)&sp->nodeName); + if (fc_chksparm(binfo, sp, CLASS3)) { + /* PLOGI chkparm OK */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0126, /* ptr to msg structure */ + fc_mes0126, /* ptr to msg */ + fc_msgBlk0126.msgPreambleStr, /* begin varargs */ + ndlp->nlp_DID, + ndlp->nlp_state, + ndlp->nlp_flag, + ndlp->nlp_Rpi ); /* end varargs */ + if (ndlp->nlp_Rpi == 0) { + if (ndlp->nlp_flag & NLP_REQ_SND) { + /* Abort the current outstanding PLOGI */ + unsigned long iflag; + + iflag = lpfc_q_disable_lock(p_dev_ctl); + iocbq = (IOCBQ * )(rp->fc_txp.q_first); + while (iocbq) { + if(iocbq->iocb.un.elsreq.remoteID == ndlp->nlp_DID) { + iocbq->retry = 0xff; + } + iocbq = (IOCBQ * )iocbq->q; + } + lpfc_q_unlock_enable(p_dev_ctl, iflag); + /* In case its on fc_delay_timeout list */ + fc_abort_delay_els_cmd(p_dev_ctl, ndlp->nlp_DID); + + ndlp->nlp_flag &= ~NLP_REQ_SND; + /* The following reg_login acts as if original PLOGI cmpl */ + } + else + ndlp->nlp_flag |= NLP_RCV_PLOGI; + + wd30.word = 0; + wd30.f.xri = iocb->ulpContext; + wd30.f.class = iocb->ulpClass; + ndlp->nlp_flag |= NLP_REG_INP; + + /* issue mailbox command to register login with the adapter */ + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + fc_reg_login(binfo, did, (uchar * )sp, (MAILBOX * )mb, + wd30.word); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) + != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + } else { + fc_els_rsp(binfo, ELS_CMD_ACC, (uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)0, (uint32)(sizeof(SERV_PARM)), ndlp); + } + } else { + /* Reject this request because invalid parameters */ + stat.un.b.lsRjtRsvd0 = 0; + stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; + stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS; + stat.un.b.vendorUnique = 0; + fc_els_rsp(binfo, ELS_CMD_LS_RJT, (uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)0, (uint32)stat.un.lsRjtError, + ndlp); + + if (binfo->fc_ffstate == FC_READY) { + /* unregister existing login first */ + ndlp->nlp_flag |= NLP_UNREG_LOGO; + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + } + } + } else { + /* Reject this request because the remote node will accept ours */ + stat.un.b.lsRjtRsvd0 = 0; + stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; + stat.un.b.lsRjtRsnCodeExp = LSEXP_CMD_IN_PROGRESS; + stat.un.b.vendorUnique = 0; + fc_els_rsp(binfo, ELS_CMD_LS_RJT, (uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)0, (uint32)stat.un.lsRjtError, ndlp); + } + break; + + case ELS_CMD_LOGO: + FCSTATCTR.elsRcvLOGO++; + goto skip1; + case ELS_CMD_PRLO: + FCSTATCTR.elsRcvPRLO++; +skip1: + lp++; /* lp now points to portname */ + np = (NAME_TYPE * )lp; + did = iocb->un.elsreq.remoteID; + + if ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, did)) == 0) { + if(((ndlp = fc_findnode_wwpn(binfo, NLP_SEARCH_ALL, np)) == 0) || + (ndlp->nlp_DID == 0)) + /* ACCEPT the logout request */ + fc_els_rsp(binfo, ELS_CMD_ACC, (uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)0, (uint32)(sizeof(uint32)), 0); + break; + } + + + if (ndlp) { + if((ndlp->nlp_state >= NLP_LOGIN) || + ((!(ndlp->nlp_flag & (NLP_FARP_SND | NLP_RM_ENTRY))) && + (!(ndlp->nlp_action & (NLP_DO_ADDR_AUTH | NLP_DO_DISC_START | NLP_DO_RSCN))))) { + /* ACCEPT the logout request */ + unsigned long iflag; + + fc_els_rsp(binfo, ELS_CMD_ACC, (uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)0, (uint32)(sizeof(uint32)), ndlp); + ndlp->nlp_flag &= ~NLP_REQ_SND; + ndlp->nlp_flag |= NLP_RM_ENTRY; + + iflag = lpfc_q_disable_lock(p_dev_ctl); + iocbq = (IOCBQ * )(rp->fc_txp.q_first); + while (iocbq) { + if(iocbq->iocb.un.elsreq.remoteID == ndlp->nlp_DID) { + if(ndlp->nlp_action & (NLP_DO_ADDR_AUTH | NLP_DO_DISC_START | NLP_DO_RSCN)) { + ndlp->nlp_flag &= ~(NLP_REQ_SND_ADISC | NLP_REQ_SND_PDISC | NLP_REQ_SND); + } + iocbq->retry = 0xff; + if((binfo->fc_flag & FC_RSCN_MODE) || + (binfo->fc_ffstate < FC_READY)) { + if((ndlp->nlp_state >= NLP_PLOGI) && + (ndlp->nlp_state <= NLP_ALLOC)) { + binfo->fc_nlp_cnt--; + } + if (binfo->fc_nlp_cnt <= 0) { + binfo->fc_nlp_cnt = 0; + } + } + } + iocbq = (IOCBQ * )iocbq->q; + } + lpfc_q_unlock_enable(p_dev_ctl, iflag); + /* In case its on fc_delay_timeout list */ + fc_abort_delay_els_cmd(p_dev_ctl, ndlp->nlp_DID); + + if ((ndlp->nlp_type & NLP_FCP_TARGET) && + (ndlp->nlp_state >= NLP_LOGIN)) { + ndlp->nlp_flag |= NLP_SND_PLOGI; + } + if (ndlp->nlp_action & (NLP_DO_ADDR_AUTH | NLP_DO_DISC_START | NLP_DO_RSCN)) { + fc_nextnode(p_dev_ctl, ndlp); + } + } + else { + /* ACCEPT the logout request */ + fc_els_rsp(binfo, ELS_CMD_ACC, (uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)0, (uint32)(sizeof(uint32)), 0); + } + } + else { + /* ACCEPT the logout request */ + fc_els_rsp(binfo, ELS_CMD_ACC, (uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)0, (uint32)(sizeof(uint32)), 0); + } + break; + + case ELS_CMD_FAN: + FCSTATCTR.elsRcvFAN++; + /* FAN received */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0213, /* ptr to msg structure */ + fc_mes0213, /* ptr to msg */ + fc_msgBlk0213.msgPreambleStr, /* begin varargs */ + iocb->un.ulpWord[4], + binfo->fc_ffstate); /* end varargs */ + /* Check to see if we were waiting for FAN */ + if ((binfo->fc_ffstate != FC_FLOGI) || + (binfo->fc_topology != TOPOLOGY_LOOP) || + (!(binfo->fc_flag & FC_PUBLIC_LOOP))) + break; + + ep = (ELS_PKT * )bp; + + /* Check to make sure we haven't switched fabrics */ + if ((fc_geportname((NAME_TYPE * ) & ep->un.fan.FportName, + (NAME_TYPE * ) & binfo->fc_fabparam.portName) != 2) || + (fc_geportname((NAME_TYPE * ) & ep->un.fan.FnodeName, + (NAME_TYPE * ) & binfo->fc_fabparam.nodeName) != 2)) { + /* We switched, so we need to FLOGI again after timeout */ + break; + } + + if(FABRICTMO) { + fc_clk_can(p_dev_ctl, FABRICTMO); + FABRICTMO = 0; + } + + binfo->fc_myDID = iocb->un.ulpWord[4] & Mask_DID; + + if ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, Fabric_DID)) == 0) { + if ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, (uint32)iocb->un.elsreq.remoteID)) == 0) { + break; + } + fc_nlp_logi(binfo, ndlp, &ep->un.fan.FportName, &ep->un.fan.FnodeName); + } + ndlp->nlp_type |= NLP_FABRIC; + + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + fc_config_link(p_dev_ctl, (MAILBOX * )mb); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + + /* register the login with adapter */ + if (ndlp->nlp_Rpi == 0) { + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + fc_reg_login(binfo, iocb->un.elsreq.remoteID, + (uchar * ) & binfo->fc_fabparam, (MAILBOX * )mb, 0); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + } + + /* Since this is a FAN, we don't need to do any discovery stuff */ + fc_fanovery(p_dev_ctl); + break; + + case ELS_CMD_RSCN: + FCSTATCTR.elsRcvRSCN++; + fc_process_rscn(p_dev_ctl, temp, mp); + break; + + case ELS_CMD_ADISC: + FCSTATCTR.elsRcvADISC++; + ep = (ELS_PKT * )bp; + did = iocb->un.elsreq.remoteID; + if (((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, did)) != 0) && + (ndlp->nlp_state >= NLP_LOGIN)) { + if (fc_chkpadisc(binfo, ndlp, &ep->un.adisc.nodeName, + &ep->un.adisc.portName)) { + fc_els_rsp(binfo, ELS_CMD_ADISC, (uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)0, (uint32)sizeof(SERV_PARM), + ndlp); + } else { + /* Reject this request because invalid parameters */ + stat.un.b.lsRjtRsvd0 = 0; + stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; + stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS; + stat.un.b.vendorUnique = 0; + fc_els_rsp(binfo, ELS_CMD_LS_RJT, (uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)0, (uint32)stat.un.lsRjtError, + ndlp); + if (!(ndlp->nlp_flag & NLP_REQ_SND)) { + ndlp->nlp_flag |= NLP_UNREG_LOGO; + fc_freenode_did(binfo, did, 0); + } + } + } else { + /* Reject this request because not logged in */ + stat.un.b.lsRjtRsvd0 = 0; + stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; + stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA; + stat.un.b.vendorUnique = 0; + fc_els_rsp(binfo, ELS_CMD_LS_RJT, (uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)0, (uint32)stat.un.lsRjtError, ndlp); + if ((ndlp == 0) || (!(ndlp->nlp_flag & NLP_REQ_SND))) + fc_freenode_did(binfo, did, 0); + } + break; + + case ELS_CMD_PDISC: + FCSTATCTR.elsRcvPDISC++; + sp = (volatile SERV_PARM * )lp; + did = iocb->un.elsreq.remoteID; + if (((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, did)) != 0) && + (ndlp->nlp_state >= NLP_LOGIN)) { + if (fc_chkpadisc(binfo, ndlp, &sp->nodeName, &sp->portName)) { + fc_els_rsp(binfo, ELS_CMD_ACC, (uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)0, (uint32)sizeof(SERV_PARM), + ndlp); + } else { + /* Reject this request because invalid parameters */ + stat.un.b.lsRjtRsvd0 = 0; + stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; + stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS; + stat.un.b.vendorUnique = 0; + fc_els_rsp(binfo, ELS_CMD_LS_RJT, (uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)0, (uint32)stat.un.lsRjtError, + ndlp); + if (!(ndlp->nlp_flag & NLP_REQ_SND)) { + ndlp->nlp_flag |= NLP_UNREG_LOGO; + fc_freenode_did(binfo, did, 0); + } + } + } else { + /* Reject this request because not logged in */ + stat.un.b.lsRjtRsvd0 = 0; + stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; + stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA; + stat.un.b.vendorUnique = 0; + fc_els_rsp(binfo, ELS_CMD_LS_RJT, (uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)0, (uint32)stat.un.lsRjtError, ndlp); + if ((ndlp == 0) || (!(ndlp->nlp_flag & NLP_REQ_SND))) + fc_freenode_did(binfo, did, 0); + } + break; + + case ELS_CMD_FARPR: + FCSTATCTR.elsRcvFARPR++; + ep = (ELS_PKT * )bp; + did = iocb->un.elsreq.remoteID; + /* FARP-RSP received from DID */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0600, /* ptr to msg structure */ + fc_mes0600, /* ptr to msg */ + fc_msgBlk0600.msgPreambleStr, /* begin varargs */ + did ); /* end varargs */ + /* ACCEPT the Farp resp request */ + fc_els_rsp(binfo, ELS_CMD_ACC, (uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)0, (uint32)(sizeof(uint32)), 0); + break; + + case ELS_CMD_FARP: + FCSTATCTR.elsRcvFARP++; + ep = (ELS_PKT * )bp; + did = iocb->un.elsreq.remoteID; + /* FARP-REQ received from DID */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0601, /* ptr to msg structure */ + fc_mes0601, /* ptr to msg */ + fc_msgBlk0601.msgPreambleStr, /* begin varargs */ + did ); /* end varargs */ + if ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, did)) == 0) { + if((ndlp = (NODELIST *)fc_mem_get(binfo, MEM_NLP))) { + fc_bzero((void *)ndlp, sizeof(NODELIST)); + ndlp->sync = binfo->fc_sync; + ndlp->capabilities = binfo->fc_capabilities; + ndlp->nlp_DID = did; + fc_nlp_logi(binfo,ndlp, &ep->un.farp.OportName, &ep->un.farp.OnodeName); + ndlp->nlp_state = NLP_LIMBO; + } + else + break; + } + + /* We will only support match on WWPN or WWNN */ + if (ep->un.farp.Mflags & ~(FARP_MATCH_NODE | FARP_MATCH_PORT)) + break; + + cnt = 0; + /* If this FARP command is searching for my portname */ + if (ep->un.farp.Mflags & FARP_MATCH_PORT) { + if (fc_geportname(&ep->un.farp.RportName, &binfo->fc_portname) == 2) + cnt = 1; + else + cnt = 0; + } + + /* If this FARP command is searching for my nodename */ + if (ep->un.farp.Mflags & FARP_MATCH_NODE) { + if (fc_geportname(&ep->un.farp.RnodeName, &binfo->fc_nodename) == 2) + cnt = 1; + else + cnt = 0; + } + + if (cnt) { + if (!(binfo->fc_flag & FC_LNK_DOWN) && + (binfo->fc_ffstate >= rp->fc_xmitstate) && + !(ndlp->nlp_flag & NLP_REQ_SND) && + !(ndlp->nlp_action & NLP_DO_ADDR_AUTH)) { + /* We need to re-login to that node */ + if ((ep->un.farp.Rflags & FARP_REQUEST_PLOGI) && + !(ndlp->nlp_flag & NLP_REQ_SND)) { + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + fc_els_cmd(binfo, ELS_CMD_PLOGI, (void *)((ulong)ndlp->nlp_DID), + (uint32)0, (ushort)0, ndlp); + } + + /* We need to send FARP response to that node */ + if (ep->un.farp.Rflags & FARP_REQUEST_FARPR) { + fc_els_cmd(binfo, ELS_CMD_FARPR, (void *)((ulong)ndlp->nlp_DID), + (uint32)0, (ushort)0, ndlp); + } + } + } + break; + + case ELS_CMD_RRQ: + FCSTATCTR.elsRcvRRQ++; + ep = (ELS_PKT * )bp; + /* Get oxid / rxid from payload and internally abort it */ + if ((ep->un.rrq.SID == SWAP_DATA(binfo->fc_myDID))) { + fc_abort_ixri_cx(binfo, ep->un.rrq.Oxid, CMD_CLOSE_XRI_CX, rp); + } else { + fc_abort_ixri_cx(binfo, ep->un.rrq.Rxid, CMD_CLOSE_XRI_CX, rp); + } + /* ACCEPT the rrq request */ + fc_els_rsp(binfo, ELS_CMD_ACC, (uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)0, (uint32)(sizeof(uint32)), 0); + break; + + case ELS_CMD_PRLI: + /* ACCEPT the prli request */ + did = iocb->un.elsreq.remoteID; + if ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, did))) { + fc_els_rsp(binfo, ELS_CMD_PRLI, (uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)0, (uint32)(sizeof(uint32)), ndlp); + } + else { + stat.un.b.lsRjtRsvd0 = 0; + stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; + stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA; + stat.un.b.vendorUnique = 0; + fc_els_rsp(binfo, ELS_CMD_LS_RJT, (uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)0, (uint32)stat.un.lsRjtError, 0); + } + break; + + case ELS_CMD_RNID: + did = iocb->un.elsreq.remoteID; + ep = (ELS_PKT * )bp; + switch(ep->un.rnid.Format) { + case 0: + case RNID_TOPOLOGY_DISC: + fc_els_rsp(binfo, ELS_CMD_RNID, (uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)0, (uint32)ep->un.rnid.Format, 0); + break; + default: + /* Reject this request because format not supported */ + stat.un.b.lsRjtRsvd0 = 0; + stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; + stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA; + stat.un.b.vendorUnique = 0; + fc_els_rsp(binfo, ELS_CMD_LS_RJT, (uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)0, (uint32)stat.un.lsRjtError, 0); + } + break; + + default: + /* Unsupported ELS command, reject */ + stat.un.b.lsRjtRsvd0 = 0; + stat.un.b.lsRjtRsnCode = LSRJT_CMD_UNSUPPORTED; + stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; + stat.un.b.vendorUnique = 0; + fc_els_rsp(binfo, ELS_CMD_LS_RJT, (uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)0, (uint32)stat.un.lsRjtError, 0); + FCSTATCTR.elsCmdPktInval++; + + did = iocb->un.elsreq.remoteID; + /* Unknown ELS command received from NPORT */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0127, /* ptr to msg structure */ + fc_mes0127, /* ptr to msg */ + fc_msgBlk0127.msgPreambleStr, /* begin varargs */ + cmd, + did); /* end varargs */ + break; + } + +dropit: + + FCSTATCTR.elsRcvFrame++; + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + +out: + + i = 1; + /* free resources associated with this iocb and repost the ring buffers */ + if (!(binfo->fc_flag & FC_SLI2)) { + for (i = 1; i < (int)iocb->ulpBdeCount; i++) { + mp = fc_getvaddr(p_dev_ctl, rp, (uchar * )((ulong)iocb->un.cont[i].bdeAddress)); + if (mp) { + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + } + } + } + + fc_post_buffer(p_dev_ctl, rp, i); + + return(1); +} /* End handle_rcv_els_req */ + + +/***************************************/ +/** fc_process_rscn Process ELS **/ +/** RSCN command **/ +/***************************************/ +_static_ int +fc_process_rscn( +fc_dev_ctl_t *p_dev_ctl, +IOCBQ *temp, +MATCHMAP *mp) +{ + FC_BRD_INFO * binfo; + IOCB * iocb; + uchar * bp; + uint32 * lp; + D_ID rdid; + uint32 cmd; + int i, j, cnt; + + binfo = &BINFO; + iocb = &temp->iocb; + bp = mp->virt; + lp = (uint32 * )bp; + cmd = *lp++; + i = SWAP_DATA(cmd) & 0xffff; /* payload length */ + i -= sizeof(uint32); /* take off word 0 */ + cmd &= ELS_CMD_MASK; + + /* RSCN received */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0214, /* ptr to msg structure */ + fc_mes0214, /* ptr to msg */ + fc_msgBlk0214.msgPreambleStr, /* begin varargs */ + binfo->fc_flag, + i, + *lp, + binfo->fc_rscn_id_cnt); /* end varargs */ + cnt = 0; /* cnt will determine if we need to access NameServer */ + + /* Loop through all DIDs in the payload */ + binfo->fc_flag |= FC_RSCN_MODE; + + while (i) { + rdid.un.word = *lp++; + rdid.un.word = SWAP_DATA(rdid.un.word); + if(binfo->fc_rscn_id_cnt < FC_MAX_HOLD_RSCN) { + for(j=0;jfc_rscn_id_cnt;j++) { + if(binfo->fc_rscn_id_list[j] == rdid.un.word) { + goto skip_id; + } + } + binfo->fc_rscn_id_list[binfo->fc_rscn_id_cnt++] = rdid.un.word; + } + else { + binfo->fc_flag |= FC_RSCN_DISCOVERY; + fc_flush_rscn_defer(p_dev_ctl); + cnt = 0; + break; + } +skip_id: + cnt += (fc_handle_rscn(p_dev_ctl, &rdid)); + i -= sizeof(uint32); + } + + /* RSCN processed */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0215, /* ptr to msg structure */ + fc_mes0215, /* ptr to msg */ + fc_msgBlk0215.msgPreambleStr, /* begin varargs */ + binfo->fc_flag, + cnt, + binfo->fc_rscn_id_cnt, + binfo->fc_ffstate ); /* end varargs */ + if (cnt == 0) { + /* no need for nameserver login */ + fc_nextrscn(p_dev_ctl, fc_max_els_sent); + } + else { + if(!(binfo->fc_flag & FC_NSLOGI_TMR)) + fc_clk_set(p_dev_ctl, 1, fc_issue_ns_query, 0, 0); + binfo->fc_flag |= FC_NSLOGI_TMR; + } + return(0); +} + + +/***************************************/ +/** fc_handle_rscn Handle ELS **/ +/** RSCN command **/ +/***************************************/ +_static_ int +fc_handle_rscn( +fc_dev_ctl_t *p_dev_ctl, +D_ID *didp) +{ + FC_BRD_INFO * binfo; + NODELIST * ndlp; + NODELIST * new_ndlp; + NODELIST * callnextnode; + iCfgParam * clp; + D_ID did; + int change; + int numchange; + int ns; + + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + callnextnode = 0; + + dfc_hba_put_event(p_dev_ctl, HBA_EVENT_RSCN, binfo->fc_myDID, didp->un.word, 0, 0); + dfc_put_event(p_dev_ctl, FC_REG_RSCN_EVENT, didp->un.word, 0, 0); + + /* Is this an RSCN for me? */ + if (didp->un.word == binfo->fc_myDID) + return(0); + + /* Always query nameserver on RSCN (zoning) if CFG_ZONE_RSCN it set */ + ns = (int)clp[CFG_ZONE_RSCN].a_current; + numchange = 0; + + ndlp = binfo->fc_nlpbind_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + new_ndlp = 0; + while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) { + new_ndlp = (NODELIST *)ndlp->nlp_listp_next; + + /* Skip over FABRIC nodes and myself */ + if ((ndlp->nlp_DID == binfo->fc_myDID) || + (ndlp->nlp_type & NLP_FABRIC)) { + + ndlp = new_ndlp; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + continue; + } + + did.un.word = ndlp->nlp_DID; + change = 0; + + switch (didp->un.b.resv) { + case 0: /* Single N_Port ID effected */ + if (did.un.word == didp->un.word) { + change = 1; + } + break; + + case 1: /* Whole N_Port Area effected */ + if ((did.un.b.domain == didp->un.b.domain) && + (did.un.b.area == didp->un.b.area)) { + ns = 1; + change = 1; + } + break; + + case 2: /* Whole N_Port Domain effected */ + if (did.un.b.domain == didp->un.b.domain) { + ns = 1; + change = 1; + } + break; + + case 3: /* Whole Fabric effected */ + binfo->fc_flag |= FC_RSCN_DISCOVERY; + fc_flush_rscn_defer(p_dev_ctl); + return(0); + + default: + /* Unknown Identifier in RSCN payload */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0216, /* ptr to msg structure */ + fc_mes0216, /* ptr to msg */ + fc_msgBlk0216.msgPreambleStr, /* begin varargs */ + didp->un.word ); /* end varargs */ + break; + + } + + if (change) { + numchange++; + if((ndlp->nlp_state == NLP_ALLOC) || + (ndlp->nlp_state == NLP_LOGIN)) { + + if (ndlp->nlp_flag & NLP_REQ_SND) { + RING * rp; + IOCBQ * iocbq; + unsigned long iflag; + + /* Look through ELS ring and remove any ELS cmds in progress */ + iflag = lpfc_q_disable_lock(p_dev_ctl); + rp = &binfo->fc_ring[FC_ELS_RING]; + iocbq = (IOCBQ * )(rp->fc_txp.q_first); + while (iocbq) { + if (iocbq->iocb.un.elsreq.remoteID == ndlp->nlp_DID) { + iocbq->retry = 0xff; /* Mark for abort */ + } + iocbq = (IOCBQ * )iocbq->q; + } + lpfc_q_unlock_enable(p_dev_ctl, iflag); + /* In case its on fc_delay_timeout list */ + fc_abort_delay_els_cmd(p_dev_ctl, ndlp->nlp_DID); + + ndlp->nlp_flag &= ~NLP_REQ_SND; + } + + /* We are always using ADISC for RSCN validation */ + /* IF we are using ADISC, leave ndlp on mapped or unmapped q */ + + ndlp->nlp_flag &= ~NLP_NODEV_TMO; + + /* Mark node for authentication */ + ndlp->nlp_action |= NLP_DO_RSCN; + + } else { + + if (ndlp->nlp_flag & NLP_REQ_SND) { + if((callnextnode == 0) && (ndlp->nlp_action & NLP_DO_RSCN)) + callnextnode = ndlp; + } + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_flag &= ~NLP_NODEV_TMO; + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + + /* Mark node for authentication */ + ndlp->nlp_action |= NLP_DO_RSCN; + } + } + ndlp = new_ndlp; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + } + + /* If nothing in our node table is effected, + * we need to goto the Nameserver. + */ + if (numchange == 0) { + /* Is this a single N_Port that wasn't in our table */ + if (didp->un.b.resv == 0) { + if ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, didp->un.word)) == 0) { + if((ndlp = (NODELIST *)fc_mem_get(binfo, MEM_NLP))) { + fc_bzero((void *)ndlp, sizeof(NODELIST)); + ndlp->sync = binfo->fc_sync; + ndlp->capabilities = binfo->fc_capabilities; + ndlp->nlp_DID = didp->un.word; + } + else + return(ns); + } + ndlp->nlp_action |= NLP_DO_RSCN; + ndlp->nlp_flag &= ~NLP_NODEV_TMO; + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + } + else { + ns = 1; + } + } + + /* Is this an area or domain N_Port */ + if (didp->un.b.resv != 0) { + ns = 1; + } + + if((ns == 0) && (callnextnode)) + fc_nextnode(p_dev_ctl, callnextnode); + + /* Tell calling routine if NameServer access is required + * and return number of nodes presently being authenticated. + */ + return(ns); +} /* End fc_handle_rscn */ + + +/*************************************************/ +/** fc_chksparm Check service parameters **/ +/*************************************************/ +_local_ int +fc_chksparm( +FC_BRD_INFO *binfo, +volatile SERV_PARM *sp, +uint32 class) +{ + volatile SERV_PARM *hsp; + + hsp = &binfo->fc_sparam; + /* First check for supported version */ + + /* Next check for class validity */ + if (sp->cls1.classValid) { + if (sp->cls1.rcvDataSizeMsb > hsp->cls1.rcvDataSizeMsb) + sp->cls1.rcvDataSizeMsb = hsp->cls1.rcvDataSizeMsb; + if (sp->cls1.rcvDataSizeLsb > hsp->cls1.rcvDataSizeLsb) + sp->cls1.rcvDataSizeLsb = hsp->cls1.rcvDataSizeLsb; + } else if (class == CLASS1) { + return(0); + } + + if (sp->cls2.classValid) { + if (sp->cls2.rcvDataSizeMsb > hsp->cls2.rcvDataSizeMsb) + sp->cls2.rcvDataSizeMsb = hsp->cls2.rcvDataSizeMsb; + if (sp->cls2.rcvDataSizeLsb > hsp->cls2.rcvDataSizeLsb) + sp->cls2.rcvDataSizeLsb = hsp->cls2.rcvDataSizeLsb; + } else if (class == CLASS2) { + return(0); + } + + if (sp->cls3.classValid) { + if (sp->cls3.rcvDataSizeMsb > hsp->cls3.rcvDataSizeMsb) + sp->cls3.rcvDataSizeMsb = hsp->cls3.rcvDataSizeMsb; + if (sp->cls3.rcvDataSizeLsb > hsp->cls3.rcvDataSizeLsb) + sp->cls3.rcvDataSizeLsb = hsp->cls3.rcvDataSizeLsb; + } else if (class == CLASS3) { + return(0); + } + + if (sp->cmn.bbRcvSizeMsb > hsp->cmn.bbRcvSizeMsb) + sp->cmn.bbRcvSizeMsb = hsp->cmn.bbRcvSizeMsb; + if (sp->cmn.bbRcvSizeLsb > hsp->cmn.bbRcvSizeLsb) + sp->cmn.bbRcvSizeLsb = hsp->cmn.bbRcvSizeLsb; + + return(1); +} /* End fc_chksparm */ + + +/***************************************/ +/** fc_chkpadisc Check **/ +/** P/ADISC parameters **/ +/***************************************/ +_static_ int +fc_chkpadisc( +FC_BRD_INFO *binfo, +NODELIST *ndlp, +volatile NAME_TYPE *nn, +volatile NAME_TYPE *pn) +{ + if (fc_geportname((NAME_TYPE * )nn, &ndlp->nlp_nodename) != 2) { + return(0); + } + + if (fc_geportname((NAME_TYPE * )pn, &ndlp->nlp_portname) != 2) { + return(0); + } + + return(1); +} /* End fc_chkpadisc */ + + +/***************************************/ +/** fc_els_cmd Issue an **/ +/** ELS command **/ +/***************************************/ +_static_ int +fc_els_cmd( +FC_BRD_INFO *binfo, +uint32 elscmd, +void *arg, +uint32 retry, +ushort iotag, +NODELIST *ndlp) +{ + IOCB * icmd; + IOCBQ * temp; + RING * rp; + uchar * bp; + ULP_BDE64 * bpl; + MATCHMAP * mp, * rmp, * bmp; + MAILBOXQ * mb; + iCfgParam * clp; + union { + SERV_PARM * sp; + ADISC * ap; + FARP * fp; + fc_vpd_t * vpd; + PRLI * npr; + } un; + uint32 * lp; + ushort size; + ulong setdelay; + fc_dev_ctl_t * p_dev_ctl; + + clp = DD_CTL.p_config[binfo->fc_brd_no]; + rp = &binfo->fc_ring[FC_ELS_RING]; + p_dev_ctl = (fc_dev_ctl_t *)(binfo->fc_p_dev_ctl); + + if ((elscmd == ELS_CMD_LOGO) && (iotag == 0)) { + /* First do unreglogin for did before sending ELS LOGO request */ + if ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, (uint32)((ulong)arg))) && ndlp->nlp_Rpi) { + /* If we are in the middle of Discovery */ + if (ndlp->nlp_action & (NLP_DO_ADDR_AUTH | NLP_DO_DISC_START | NLP_DO_RSCN)) { + /* Goto next entry */ + fc_nextnode(p_dev_ctl, ndlp); + } + ndlp->nlp_flag |= NLP_UNREG_LOGO; + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + return(0); + } + } + /* Allocate buffer for command iocb */ + if ((temp = (IOCBQ * )fc_mem_get(binfo, MEM_IOCB | MEM_PRI)) == 0) { + return(1); + } + fc_bzero((void *)temp, sizeof(IOCBQ)); + icmd = &temp->iocb; + setdelay = 0; + + /* fill in BDEs for command */ + /* Allocate buffer for command payload */ + if ((mp = (MATCHMAP * )fc_mem_get(binfo, MEM_BUF | MEM_PRI)) == 0) { + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + return(1); + } + + /* Allocate buffer for response payload */ + if ((rmp = (MATCHMAP * )fc_mem_get(binfo, MEM_BUF | MEM_PRI)) == 0) { + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + return(1); + } + fc_bzero((void *)rmp->virt, sizeof(ELS_PKT)); + + if (binfo->fc_flag & FC_SLI2) { + /* Allocate buffer for Buffer ptr list */ + if ((bmp = (MATCHMAP * )fc_mem_get(binfo, MEM_BPL | MEM_PRI)) == 0) { + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + fc_mem_put(binfo, MEM_BUF, (uchar * )rmp); + return(1); + } + bpl = (ULP_BDE64 * )bmp->virt; + bpl->addrLow = PCIMEM_LONG(putPaddrLow((ulong)mp->phys)); + bpl->addrHigh = PCIMEM_LONG(putPaddrHigh((ulong)mp->phys)); + bpl->tus.f.bdeFlags = 0; + bpl++; + bpl->addrLow = PCIMEM_LONG(putPaddrLow((ulong)rmp->phys)); + bpl->addrHigh = PCIMEM_LONG(putPaddrHigh((ulong)rmp->phys)); + bpl->tus.f.bdeSize = FCELSSIZE; + bpl->tus.f.bdeFlags = BUFF_USE_RCV; + bpl->tus.w = PCIMEM_LONG(bpl->tus.w); + + bpl--; /* so we can fill in size later */ + + icmd->un.elsreq64.bdl.ulpIoTag32 = (uint32)0; + icmd->un.elsreq64.bdl.addrHigh = (uint32)putPaddrHigh(bmp->phys); + icmd->un.elsreq64.bdl.addrLow = (uint32)putPaddrLow(bmp->phys); + icmd->un.elsreq64.bdl.bdeSize = (2 * sizeof(ULP_BDE64)); + icmd->un.elsreq64.bdl.bdeFlags = BUFF_TYPE_BDL; + temp->bpl = (uchar *)bmp; + } else { + bpl = 0; + bmp = 0; + icmd->un.cont[0].bdeAddress = (uint32)putPaddrLow(mp->phys); + icmd->un.cont[1].bdeAddress = (uint32)putPaddrLow(rmp->phys); + icmd->un.cont[1].bdeSize = FCELSSIZE; + temp->bpl = 0; + } + + bp = mp->virt; + /* Save for completion so we can release these resources */ + temp->bp = (uchar * )mp; + temp->info = (uchar * )rmp; + + /* Fill in command field in payload */ + *((uint32 * )(bp)) = elscmd; /* FLOGI, PLOGI or LOGO */ + bp += sizeof(uint32); + + switch (elscmd) { + case ELS_CMD_PLOGI: /* NPort login */ + case ELS_CMD_PDISC: /* exchange parameters */ + if(ndlp && (ndlp->nlp_DID == 0)) { + ndlp->nlp_DID = (uint32)((ulong)arg); + } + case ELS_CMD_FLOGI: /* Fabric login */ + /* For LOGI request, remainder of payload is service parameters */ + fc_bcopy((void *) & binfo->fc_sparam, (void *)bp, sizeof(SERV_PARM)); + un.sp = (SERV_PARM * )bp; + + if (elscmd == ELS_CMD_FLOGI) { + un.sp->cmn.e_d_tov = 0; + un.sp->cmn.w2.r_a_tov = 0; + un.sp->cls1.classValid = 0; + un.sp->cls2.seqDelivery = 1; + un.sp->cls3.seqDelivery = 1; + if (un.sp->cmn.fcphLow < FC_PH3) + un.sp->cmn.fcphLow = FC_PH3; + if(FABRICTMO) { + fc_clk_res(p_dev_ctl, binfo->fc_fabrictmo, FABRICTMO); + } + } else { + /* Seagate drives can't handle FC_PH3 value! */ + if (un.sp->cmn.fcphLow < FC_PH_4_3) + un.sp->cmn.fcphLow = FC_PH_4_3; + } + + if (un.sp->cmn.fcphHigh < FC_PH3) + un.sp->cmn.fcphHigh = FC_PH3; + + icmd->un.elsreq.remoteID = (uint32)((ulong)arg); /* DID */ + size = (sizeof(uint32) + sizeof(SERV_PARM)); + + if (elscmd != ELS_CMD_PDISC) { + /* Allocate a nlplist entry, ELS cmpl will fill it in */ + if ((ndlp == 0) && + ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, (uint32)((ulong)arg))) == 0)) { + if((ndlp = (NODELIST *)fc_mem_get(binfo, MEM_NLP))) { + fc_bzero((void *)ndlp, sizeof(NODELIST)); + ndlp->sync = binfo->fc_sync; + ndlp->capabilities = binfo->fc_capabilities; + ndlp->nlp_DID = (uint32)((ulong)arg); + } + else { + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + fc_mem_put(binfo, MEM_BUF, (uchar * )rmp); + if (bmp) { + fc_mem_put(binfo, MEM_BPL, (uchar * )bmp); + } + return(1); + } + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + } + ndlp->nlp_flag &= ~NLP_RM_ENTRY; + ndlp->nlp_flag |= NLP_REQ_SND; + + if (elscmd == ELS_CMD_PLOGI) { + + ndlp->nlp_flag &= ~NLP_SND_PLOGI; + if (ndlp->nlp_Rpi) { + /* must explicitly unregister the login, UREG_LOGIN */ + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + fc_unreg_login(binfo, ndlp->nlp_Rpi, (MAILBOX * )mb); + if (issue_mb_cmd(binfo,(MAILBOX * )mb,MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + binfo->fc_nlplookup[ndlp->nlp_Rpi] = 0; + ndlp->nlp_Rpi = 0; + } + + /* For PLOGI requests, must make sure all outstanding Mailbox + * commands have been processed. This is to ensure UNREG_LOGINs + * complete before we try to login. + */ + if (binfo->fc_mbox_active) { + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + fc_mem_put(binfo, MEM_BUF, (uchar * )rmp); + if (bmp) { + fc_mem_put(binfo, MEM_BPL, (uchar * )bmp); + } + temp->info = (uchar *)0; + temp->bp = (uchar *)0; + temp->bpl = (uchar *)0; + fc_plogi_put(binfo, temp); + return(1); + } + + if ((ulong)arg == NameServer_DID) { + if (binfo->fc_ffstate == FC_READY) { + if(binfo->fc_flag & FC_RSCN_MODE) + ndlp->nlp_action |= NLP_DO_RSCN; + else + ndlp->nlp_action |= NLP_DO_ADDR_AUTH; + } + else + ndlp->nlp_action |= NLP_DO_ADDR_AUTH; + } + } + } + break; + + case ELS_CMD_LOGO: /* Logout */ + icmd->un.elsreq.remoteID = (uint32)((ulong)arg); /* DID */ + + *((uint32 * )(bp)) = SWAP_DATA(binfo->fc_myDID); + bp += sizeof(uint32); + + /* Last field in payload is our portname */ + fc_bcopy((void *) & binfo->fc_portname, (void *)bp, sizeof(NAME_TYPE)); + size = sizeof(uint32) + sizeof(uint32) + sizeof(NAME_TYPE); + break; + + case ELS_CMD_ADISC: + icmd->un.elsreq.remoteID = (uint32)((ulong)arg); /* DID */ + + if ((ndlp == 0) && + ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, (uint32)((ulong)arg))) == 0)) { + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + fc_mem_put(binfo, MEM_BUF, (uchar * )rmp); + if (bmp) { + fc_mem_put(binfo, MEM_BPL, (uchar * )bmp); + } + return(1); + } + ndlp->nlp_DID = (uint32)((ulong)arg); + ndlp->nlp_flag |= NLP_REQ_SND_ADISC; + un.ap = (ADISC * )(bp); + un.ap->hardAL_PA = binfo->fc_pref_ALPA; + fc_bcopy((void *) & binfo->fc_portname, (void *) & un.ap->portName, + sizeof(NAME_TYPE)); + fc_bcopy((void *) & binfo->fc_nodename, (void *) & un.ap->nodeName, + sizeof(NAME_TYPE)); + un.ap->DID = SWAP_DATA(binfo->fc_myDID); + + size = sizeof(uint32) + sizeof(ADISC); + break; + + case ELS_CMD_PRLI: /* Process login */ + icmd->un.elsreq.remoteID = (uint32)((ulong)arg); /* DID */ + if ((ndlp == 0) && + ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, (uint32)((ulong)arg))) == 0)) { + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + fc_mem_put(binfo, MEM_BUF, (uchar * )rmp); + if (bmp) { + fc_mem_put(binfo, MEM_BPL, (uchar * )bmp); + } + return(1); + } + ndlp->nlp_flag |= NLP_REQ_SND; + + /* For PRLI, remainder of payload is PRLI parameter page */ + fc_bzero((void *)bp, sizeof(PRLI)); + un.npr = (PRLI *)bp; + + /* + * If our firmware version is 3.20 or later, + * set the following bits for FC-TAPE support. + */ + if ( p_dev_ctl->vpd.rev.feaLevelHigh >= 0x02 ) { + un.npr->ConfmComplAllowed = 1; + un.npr->Retry = 1; + un.npr->TaskRetryIdReq = 1; + } + + un.npr->estabImagePair = 1; + un.npr->readXferRdyDis = 1; + if(clp[CFG_FCP_ON].a_current) { + un.npr->prliType = PRLI_FCP_TYPE; + un.npr->initiatorFunc = 1; + } + + size = sizeof(uint32) + sizeof(PRLI); + break; + + case ELS_CMD_PRLO: /* Process logout */ + /* For PRLO, remainder of payload is PRLO parameter page */ + fc_bzero((void *)bp, sizeof(PRLO)); + + icmd->un.elsreq.remoteID = (uint32)((ulong)arg); /* DID */ + size = sizeof(uint32) + sizeof(PRLO); + break; + + case ELS_CMD_SCR: /* State Change Registration */ + /* For SCR, remainder of payload is SCR parameter page */ + fc_bzero((void *)bp, sizeof(SCR)); + ((SCR * )bp)->Function = SCR_FUNC_FULL; + + icmd->un.elsreq.remoteID = (uint32)((ulong)arg); /* DID */ + size = sizeof(uint32) + sizeof(SCR); + break; + + case ELS_CMD_RNID: /* Node Identification */ + fc_bzero((void *)bp, sizeof(RNID)); + ((RNID * )bp)->Format = 0; + + icmd->un.elsreq.remoteID = (uint32)((ulong)arg); /* DID */ + size = sizeof(uint32) + sizeof(uint32); + break; + + case ELS_CMD_FARP: /* Farp */ + { + un.fp = (FARP * )(bp); + fc_bzero((void *)un.fp, sizeof(FARP)); + lp = (uint32 *)bp; + *lp++ = SWAP_DATA(binfo->fc_myDID); + un.fp->Mflags = FARP_MATCH_PORT; + un.fp->Rflags = FARP_REQUEST_PLOGI; + fc_bcopy((void *) & binfo->fc_portname, (void *) & un.fp->OportName, + sizeof(NAME_TYPE)); + fc_bcopy((void *) & binfo->fc_nodename, (void *) & un.fp->OnodeName, + sizeof(NAME_TYPE)); + switch(retry) { + case 0: + un.fp->Mflags = FARP_MATCH_PORT; + un.fp->RportName.nameType = NAME_IEEE; /* IEEE name */ + un.fp->RportName.IEEEextMsn = 0; + un.fp->RportName.IEEEextLsb = 0; + fc_bcopy(arg, (void *)un.fp->RportName.IEEE, 6); + un.fp->RnodeName.nameType = NAME_IEEE; /* IEEE name */ + un.fp->RnodeName.IEEEextMsn = 0; + un.fp->RnodeName.IEEEextLsb = 0; + fc_bcopy(arg, (void *)un.fp->RnodeName.IEEE, 6); + break; + case 1: + un.fp->Mflags = FARP_MATCH_PORT; + fc_bcopy(arg, (void *)&un.fp->RportName, sizeof(NAME_TYPE)); + retry = 0; + break; + case 2: + un.fp->Mflags = FARP_MATCH_NODE; + fc_bcopy(arg, (void *)&un.fp->RnodeName, sizeof(NAME_TYPE)); + retry = 0; + break; + } + + if((ndlp = fc_findnode_wwpn(binfo, NLP_SEARCH_ALL, &un.fp->RportName))) { + ndlp->nlp_flag |= NLP_FARP_SND; + ndlp->nlp_flag &= ~NLP_RM_ENTRY; + } + size = sizeof(uint32) + sizeof(FARP); + iotag = 0; + } + break; + + case ELS_CMD_FARPR: /* Farp response */ + { + icmd->un.elsreq.remoteID = (uint32)((ulong)arg); /* DID */ + un.fp = (FARP * )(bp); + lp = (uint32 *)bp; + *lp++ = SWAP_DATA((uint32)((ulong)arg)); + *lp++ = SWAP_DATA(binfo->fc_myDID); + un.fp->Rflags = 0; + un.fp->Mflags = (FARP_MATCH_PORT | FARP_MATCH_NODE); + + fc_bcopy((void *) & binfo->fc_portname, (void *) & un.fp->RportName, + sizeof(NAME_TYPE)); + fc_bcopy((void *) & binfo->fc_nodename, (void *) & un.fp->RnodeName, + sizeof(NAME_TYPE)); + if ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, (uint32)((ulong)arg)))) { + fc_bcopy((void *) & ndlp->nlp_portname, (void *) & un.fp->OportName, + sizeof(NAME_TYPE)); + fc_bcopy((void *) & ndlp->nlp_nodename, (void *) & un.fp->OnodeName, + sizeof(NAME_TYPE)); + } + + size = sizeof(uint32) + sizeof(FARP); + iotag = 0; + } + break; + + default: + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + fc_mem_put(binfo, MEM_BUF, (uchar * )rmp); + if (bmp) { + fc_mem_put(binfo, MEM_BPL, (uchar * )bmp); + } + /* Xmit unknown ELS command */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0128, /* ptr to msg structure */ + fc_mes0128, /* ptr to msg */ + fc_msgBlk0128.msgPreambleStr, /* begin varargs */ + elscmd); /* end varargs */ + return(1); + } + + if (binfo->fc_flag & FC_SLI2) { + icmd->ulpCommand = CMD_ELS_REQUEST64_CR; + bpl->tus.f.bdeSize = size; + bpl->tus.w = PCIMEM_LONG(bpl->tus.w); + + fc_mpdata_sync(bmp->dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV); + } else { + icmd->ulpCommand = CMD_ELS_REQUEST_CR; + icmd->un.cont[0].bdeSize = size; + } + + fc_mpdata_sync(mp->dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV); + + if (iotag) { + icmd->ulpIoTag = iotag; + } + icmd->ulpIoTag0 = (unsigned)rp->fc_iotag++; + if ((rp->fc_iotag & 0x3fff) == 0) { + rp->fc_iotag = 1; + } + + /* Fill in rest of iocb */ + icmd->ulpBdeCount = 1; + icmd->ulpLe = 1; + icmd->ulpClass = CLASS3; + icmd->ulpOwner = OWN_CHIP; + temp->retry = (uchar)retry; /* retry = uint32 */ + rmp->fc_mptr = (uchar *)ndlp; + /* Xmit ELS command to remote NPORT */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0129, /* ptr to msg structure */ + fc_mes0129, /* ptr to msg */ + fc_msgBlk0129.msgPreambleStr, /* begin varargs */ + elscmd, + icmd->un.ulpWord[5], /* did */ + icmd->ulpIoTag, + binfo->fc_ffstate); /* end varargs */ + /* + * For handleing Dump command when system panic, + * the FC_BUS_RESET needs to be checked. If FC_BUS_RESET is set, + * there is no delay for issuing ELS command. + * FC_BUS_RESET is set by the lpfc_scsi_reset(). + */ + if(icmd->ulpDelayXmit) + { + if(icmd->ulpDelayXmit == 2) { + /* Delay issue of iocb 2048 interrupt latencies */ + if(binfo->fc_delayxmit) { + IOCBQ *iop; + iop = binfo->fc_delayxmit; + while(iop->q) + iop = (IOCBQ *)iop->q; + iop->q = (uchar *)temp; + } + else { + binfo->fc_delayxmit = temp; + } + temp->q = 0; + temp->rsvd2 = 2048; + } + else { + /* Delay issue of iocb for 1 to 2 seconds */ + temp->q = 0; + + setdelay = 1; /* seconds */ + fc_clk_set(p_dev_ctl, setdelay, fc_delay_timeout, (void *)temp, ndlp); + } + } + else { + issue_iocb_cmd(binfo, rp, temp); + } + + FCSTATCTR.elsXmitFrame++; + return(0); +} /* End fc_els_cmd */ + + +/***************************************/ +/** fc_els_rsp Issue an **/ +/** ELS response **/ +/***************************************/ +_static_ int +fc_els_rsp( +FC_BRD_INFO *binfo, +uint32 elscmd, +uint32 Xri, +uint32 class, +void *iocbp, +uint32 flag, +NODELIST *ndlp) +{ + IOCB * icmd; + IOCBQ * temp; + RING * rp; + uchar * bp; + MATCHMAP * mp, * bmp; + ULP_BDE64 * bpl; + ADISC * ap; + RNID * rn; + fc_vpd_t * vpd; + PRLI * npr; + iCfgParam * clp; + fc_dev_ctl_t * p_dev_ctl; + ushort size; + + rp = &binfo->fc_ring[FC_ELS_RING]; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + p_dev_ctl = (fc_dev_ctl_t *)(binfo->fc_p_dev_ctl); + + /* Allocate buffer for command iocb */ + if ((temp = (IOCBQ * )fc_mem_get(binfo, MEM_IOCB)) == 0) { + return(1); + } + fc_bzero((void *)temp, sizeof(IOCBQ)); + icmd = &temp->iocb; + + /* fill in BDEs for command */ + /* Allocate buffer for response payload */ + if ((mp = (MATCHMAP * )fc_mem_get(binfo, MEM_BUF)) == 0) { + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + return(1); + } + + if (binfo->fc_flag & FC_SLI2) { + /* Allocate buffer for Buffer ptr list */ + if ((bmp = (MATCHMAP * )fc_mem_get(binfo, MEM_BPL)) == 0) { + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + return(1); + } + bpl = (ULP_BDE64 * )bmp->virt; + bpl->addrLow = PCIMEM_LONG(putPaddrLow((ulong)mp->phys)); + bpl->addrHigh = PCIMEM_LONG(putPaddrHigh((ulong)mp->phys)); + bpl->tus.f.bdeFlags = 0; + + icmd->un.elsreq64.bdl.ulpIoTag32 = (uint32)0; + icmd->un.elsreq64.bdl.addrHigh = (uint32)putPaddrHigh(bmp->phys); + icmd->un.elsreq64.bdl.addrLow = (uint32)putPaddrLow(bmp->phys); + icmd->un.elsreq64.bdl.bdeSize = sizeof(ULP_BDE64); + icmd->un.elsreq64.bdl.bdeFlags = BUFF_TYPE_BDL; + temp->bpl = (uchar *)bmp; + } else { + bpl = 0; + bmp = 0; + icmd->un.cont[0].bdeAddress = (uint32)putPaddrLow(mp->phys); + temp->bpl = 0; + } + + bp = mp->virt; + + /* Save for completion so we can release these resources */ + temp->bp = (uchar * )mp; + temp->ndlp = (uchar * )ndlp; + + /* Fill in command field in payload */ + *((uint32 * )(bp)) = elscmd; /* ACC or LS_RJT */ + + switch (elscmd) { + case ELS_CMD_ACC: /* Accept Response */ + /* ACCEPT will optionally contain service parameters, + * depending on flag. + */ + bp += sizeof(uint32); + if (flag >= sizeof(SERV_PARM)) { + fc_bcopy((void *) & binfo->fc_sparam, (void *)bp, sizeof(SERV_PARM)); + size = (sizeof(SERV_PARM) + sizeof(uint32)); + } else { + size = sizeof(uint32); + } + break; + + case ELS_CMD_LS_RJT: /* reject response */ + bp += sizeof(uint32); + *((uint32 * )(bp)) = flag; /* fill in error code */ + size = sizeof(uint32) + sizeof(uint32); + break; + + case ELS_CMD_ADISC: + *((uint32 * )(bp)) = ELS_CMD_ACC; + bp += sizeof(uint32); + if(ndlp) + icmd->un.elsreq.remoteID = ndlp->nlp_DID; /* DID */ + + ap = (ADISC * )(bp); + ap->hardAL_PA = binfo->fc_pref_ALPA; + fc_bcopy((void *) & binfo->fc_portname, (void *) & ap->portName, + sizeof(NAME_TYPE)); + fc_bcopy((void *) & binfo->fc_nodename, (void *) & ap->nodeName, + sizeof(NAME_TYPE)); + ap->DID = SWAP_DATA(binfo->fc_myDID); + + size = sizeof(uint32) + sizeof(ADISC); + break; + + case ELS_CMD_PRLI: + *((uint32 * )(bp)) = (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK)); + bp += sizeof(uint32); + npr = (PRLI *)bp; + if(ndlp) + icmd->un.elsreq.remoteID = ndlp->nlp_DID; /* DID */ + + /* For PRLI, remainder of payload is PRLI parameter page */ + fc_bzero((void *)bp, sizeof(PRLI)); + + vpd = &p_dev_ctl->vpd; + /* + * If our firmware version is 3.20 or later, + * set the following bits for FC-TAPE support. + */ + if ( vpd->rev.feaLevelHigh >= 0x02 ) { + npr->ConfmComplAllowed = 1; + npr->Retry = 1; + npr->TaskRetryIdReq = 1; + } + + npr->acceptRspCode = PRLI_REQ_EXECUTED; + npr->estabImagePair = 1; + npr->readXferRdyDis = 1; + npr->ConfmComplAllowed = 1; + if(clp[CFG_FCP_ON].a_current) { + npr->prliType = PRLI_FCP_TYPE; + npr->initiatorFunc = 1; + } + + size = sizeof(uint32) + sizeof(PRLI); + break; + + case ELS_CMD_RNID: + *((uint32 * )(bp)) = ELS_CMD_ACC; + bp += sizeof(uint32); + + rn = (RNID * )(bp); + fc_bzero((void *)bp, sizeof(RNID)); + rn->Format = (uchar)flag; + rn->CommonLen = (2 * sizeof(NAME_TYPE)); + fc_bcopy((void *) & binfo->fc_portname, (void *) & rn->portName, + sizeof(NAME_TYPE)); + fc_bcopy((void *) & binfo->fc_nodename, (void *) & rn->nodeName, + sizeof(NAME_TYPE)); + switch(flag) { + case 0: + rn->SpecificLen = 0; + break; + case RNID_TOPOLOGY_DISC: + rn->SpecificLen = sizeof(RNID_TOP_DISC); + fc_bcopy((void *) & binfo->fc_portname, + (void *) & rn->un.topologyDisc.portName, sizeof(NAME_TYPE)); + rn->un.topologyDisc.unitType = RNID_HBA; + rn->un.topologyDisc.physPort = 0; + rn->un.topologyDisc.attachedNodes = 0; + if(clp[CFG_NETWORK_ON].a_current) { + rn->un.topologyDisc.ipVersion = binfo->ipVersion; + rn->un.topologyDisc.UDPport = binfo->UDPport; + fc_bcopy((void *) & binfo->ipAddr[0], + (void *) & rn->un.topologyDisc.ipAddr[0], 16); + } + break; + default: + rn->CommonLen = 0; + rn->SpecificLen = 0; + break; + } + size = sizeof(uint32) + sizeof(uint32) + rn->CommonLen + rn->SpecificLen; + break; + + default: + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + if (bmp) { + fc_mem_put(binfo, MEM_BPL, (uchar * )bmp); + } + /* Xmit unknown ELS response (elsCmd> */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0130, /* ptr to msg structure */ + fc_mes0130, /* ptr to msg */ + fc_msgBlk0130.msgPreambleStr, /* begin varargs */ + elscmd ); /* end varargs */ + return(1); + } + + if (binfo->fc_flag & FC_SLI2) { + icmd->ulpCommand = CMD_XMIT_ELS_RSP64_CX; + bpl->tus.f.bdeSize = size; + bpl->tus.w = PCIMEM_LONG(bpl->tus.w); + + fc_mpdata_sync(bmp->dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV); + } else { + icmd->ulpCommand = CMD_XMIT_ELS_RSP_CX; + icmd->un.cont[0].bdeSize = size; + } + + fc_mpdata_sync(mp->dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV); + + /* If iotag is zero, assign one from global counter for board */ + if (iocbp == 0) { + temp->retry = 0; + } else { + icmd->ulpIoTag = ((IOCB *)iocbp)->ulpIoTag; + temp->retry = ((IOCBQ *)iocbp)->retry; + } + icmd->ulpIoTag0 = (unsigned)rp->fc_iotag++; + if ((rp->fc_iotag & 0x3fff) == 0) { + rp->fc_iotag = 1; + } + + /* fill in rest of iocb */ + icmd->ulpContext = (volatile ushort)Xri; + icmd->ulpBdeCount = 1; + icmd->ulpLe = 1; + icmd->ulpClass = class; + icmd->ulpOwner = OWN_CHIP; + /* Xmit ELS response to remote NPORT */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0131, /* ptr to msg structure */ + fc_mes0131, /* ptr to msg */ + fc_msgBlk0131.msgPreambleStr, /* begin varargs */ + elscmd, + icmd->un.ulpWord[5], /* did */ + icmd->ulpIoTag, + size); /* end varargs */ + issue_iocb_cmd(binfo, rp, temp); + + FCSTATCTR.elsXmitFrame++; + return(0); +} /* End fc_els_rsp */ + + +/* Retries the appropriate ELS command if necessary */ +_local_ int +fc_els_retry( +FC_BRD_INFO *binfo, +RING *rp, +IOCBQ *iocbq, +uint32 cmd, +NODELIST *ndlp) +{ + IOCB *iocb; + MATCHMAP *bmp; + + if (((binfo->fc_flag & FC_RSCN_MODE) && (binfo->fc_ffstate == FC_READY)) || + (binfo->fc_ffstate == FC_LOOP_DISC) || + (binfo->fc_ffstate == FC_NODE_DISC)) { + binfo->fc_fabrictmo = (2 * binfo->fc_ratov) + + ((4 * binfo->fc_edtov) / 1000) + 1; + if(FABRICTMO) { + fc_clk_res((fc_dev_ctl_t *)(binfo->fc_p_dev_ctl), + binfo->fc_fabrictmo, FABRICTMO); + } + else { + FABRICTMO = fc_clk_set((fc_dev_ctl_t *)(binfo->fc_p_dev_ctl), + binfo->fc_fabrictmo, fc_fabric_timeout, 0, 0); + } + } + + iocb = &iocbq->iocb; + /* Do not retry FARP/ADISC/PDISC */ + if ((cmd == ELS_CMD_FARP) || + (cmd == ELS_CMD_FARPR) || + (cmd == ELS_CMD_ADISC) || + (cmd == ELS_CMD_PDISC)) { + goto out; + } + + if (fc_status_action(binfo, iocbq, cmd, ndlp)) { + /* Indicates iocb should be retried */ + /* Retry ELS response/command */ + FCSTATCTR.elsXmitRetry++; + switch (iocb->ulpCommand) { + case CMD_ELS_REQUEST_CR: + case CMD_ELS_REQUEST64_CR: + case CMD_ELS_REQUEST_CX: + case CMD_ELS_REQUEST64_CX: + fc_els_cmd(binfo, cmd, (void *)((ulong)iocb->un.elsreq.remoteID), + (uint32)iocbq->retry, (ushort)iocb->ulpIoTag, ndlp); + break; + case CMD_XMIT_ELS_RSP_CX: + fc_els_rsp(binfo,cmd,(uint32)iocb->ulpContext, (uint32)iocb->ulpClass, + (void *)iocbq, (uint32)iocb->un.cont[0].bdeSize, ndlp); + break; + case CMD_XMIT_ELS_RSP64_CX: + bmp = (MATCHMAP *)iocbq->bpl; + if(bmp && bmp->virt) { + fc_els_rsp(binfo,cmd,(uint32)iocb->ulpContext, + (uint32)iocb->ulpClass, (void *)iocbq, + (uint32)(((ULP_BDE64 * )bmp->virt)->tus.f.bdeSize), ndlp); + } + break; + default: + goto out; + } + return(1); + } + +out: + /* ELS Retry failed */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0132, /* ptr to msg structure */ + fc_mes0132, /* ptr to msg */ + fc_msgBlk0132.msgPreambleStr, /* begin varargs */ + cmd, + iocb->un.ulpWord[4] ); /* end varargs */ + return(0); +} /* End fc_els_retry */ + + +/* Determines what action to take as result of the status + * field in the iocb. If the status indicates a retry, the iocb + * will be setup for retry and a 1 will be returned. If the status + * indicates error with no action, a 0 will be returned. + * The retry count is kept in the ls byte of the iotag. + */ +_local_ int +fc_status_action( +FC_BRD_INFO *binfo, +IOCBQ *iocbq, +uint32 cmd, +NODELIST *ndlp) +{ + uint32 class; + uchar tag; + int maxretry; + LS_RJT stat; + IOCB *iocb; + + maxretry = FC_MAXRETRY; + iocb = &iocbq->iocb; + iocb->ulpDelayXmit = 0; + + if(ndlp) { + if(ndlp->nlp_action & NLP_DO_RNID) + return(0); + if((ndlp->nlp_DID == 0) && (ndlp->nlp_type == 0)) + return(0); + } + + switch (iocb->ulpStatus) { + case IOSTAT_FCP_RSP_ERROR: + case IOSTAT_REMOTE_STOP: + break; + + case IOSTAT_LOCAL_REJECT: + if ((iocb->un.ulpWord[4] & 0xff) == IOERR_LINK_DOWN) + return(0); + + if ((iocb->un.ulpWord[4] & 0xff) == IOERR_LOOP_OPEN_FAILURE) { + if(cmd == ELS_CMD_PLOGI) { + if (iocbq->retry == 0) + iocb->ulpDelayXmit = 2; + } + goto elsretry; + } + if ((iocb->un.ulpWord[4] & 0xff) == IOERR_SEQUENCE_TIMEOUT) { + goto elsretry; + } + if ((iocb->un.ulpWord[4] & 0xff) == IOERR_NO_RESOURCES) { + if(cmd == ELS_CMD_PLOGI) + iocb->ulpDelayXmit = 1; + goto elsretry; + } + if ((iocb->un.ulpWord[4] & 0xff) == IOERR_INVALID_RPI) { + goto elsretry; + } + break; + + case IOSTAT_NPORT_RJT: + case IOSTAT_FABRIC_RJT: + /* iotag is retry count */ + if ((tag = (iocbq->retry + 1)) >= maxretry) { + FCSTATCTR.elsRetryExceeded++; + break; + } + + iocbq->retry = tag; + if (iocb->un.ulpWord[4] & RJT_UNAVAIL_TEMP) { + /* not avail temporary */ + /* Retry ELS command */ + return(1); + } + if (iocb->un.ulpWord[4] & RJT_UNSUP_CLASS) { + /* class not supported */ + if (cmd == ELS_CMD_FARP) + return(0); + if (binfo->fc_topology == TOPOLOGY_LOOP) { + /* for FC-AL retry logic goes class 3 - 2 - 1 */ + if (iocb->ulpClass == CLASS3) { + class = CLASS2; + } else { + break; + } + } else { + /* for non FC-AL retry logic goes class 1 - 2 */ + if (iocb->ulpClass == CLASS1) { + class = CLASS2; + } else { + break; + } + } + iocb->ulpClass = class; + /* Retry ELS command */ + return(1); + } + break; + + case IOSTAT_NPORT_BSY: + case IOSTAT_FABRIC_BSY: +elsretry: + tag = (iocbq->retry + 1); + /* iotag is retry count */ + if(ndlp) { + if(cmd == ELS_CMD_PLOGI) { + if((ndlp->nlp_state >= NLP_LOGIN) || + (ndlp->nlp_flag & NLP_REG_INP)) { + return(0); /* Don't retry */ + } + } + if(ndlp->nlp_flag & NLP_NODEV_TMO) { + iocbq->retry = tag; + /* Retry ELS command */ + return(1); + } + } + if(tag >= maxretry) { + FCSTATCTR.elsRetryExceeded++; + break; + } + iocbq->retry = tag; + /* Retry ELS command */ + return(1); + + case IOSTAT_LS_RJT: + stat.un.lsRjtError = SWAP_DATA(iocb->un.ulpWord[4]); + switch(stat.un.b.lsRjtRsnCode) { + case LSRJT_UNABLE_TPC: + if(stat.un.b.lsRjtRsnCodeExp == LSEXP_CMD_IN_PROGRESS) { + if(cmd == ELS_CMD_PLOGI) { + iocb->ulpDelayXmit = 1; + maxretry = 48; + } + goto elsretry; + } + if(cmd == ELS_CMD_PLOGI) { + iocb->ulpDelayXmit = 1; + + /* allow for 1sec FLOGI delay */ + maxretry = FC_MAXRETRY + 1; + goto elsretry; + } + break; + + case LSRJT_LOGICAL_BSY: + if(cmd == ELS_CMD_PLOGI) { + iocb->ulpDelayXmit = 1; + maxretry = 48; + } + goto elsretry; + } + + break; + + case IOSTAT_INTERMED_RSP: + case IOSTAT_BA_RJT: + break; + + default: + break; + } + + if((cmd == ELS_CMD_FLOGI) && (binfo->fc_topology != TOPOLOGY_LOOP)) { + iocb->ulpDelayXmit = 1; + maxretry = 48; + if ((tag = (iocbq->retry + 1)) >= maxretry) + return(0); + iocbq->retry = tag; + return(1); + } + return(0); +} /* End fc_status_action */ + + +_static_ void +fc_snd_flogi( +fc_dev_ctl_t * p_dev_ctl, +void *p1, +void *p2) +{ + FC_BRD_INFO * binfo; + RING * rp; + + binfo = &BINFO; + /* Stop the link down watchdog timer */ + rp = &binfo->fc_ring[FC_FCP_RING]; + if(RINGTMO) { + fc_clk_can(p_dev_ctl, RINGTMO); + RINGTMO = 0; + } + binfo->fc_flag &= ~(FC_LD_TIMEOUT | FC_LD_TIMER); + + /* We are either private or public loop topology */ + /* We are either Fabric or point-to-point topology */ + /* Now build FLOGI payload and issue ELS command to find out */ + fc_els_cmd(binfo, ELS_CMD_FLOGI, (void *)Fabric_DID, + (uint32)0, (ushort)0, (NODELIST *)0); + + /* + * Cancel the establish reset timer + * If we come to this point, we don't need tht timer to + * clear the FC_ESTABLISH_LINK flag. + */ + if (p_dev_ctl->fc_estabtmo) { + fc_clk_can(p_dev_ctl, p_dev_ctl->fc_estabtmo); + p_dev_ctl->fc_estabtmo = 0; + } + return; +} + +/* Wait < a second before sending intial FLOGI to start discovery */ +int +fc_initial_flogi( +fc_dev_ctl_t * p_dev_ctl) /* point to dev_ctl area */ +{ + if((p_dev_ctl->fc_waitflogi = fc_clk_set(p_dev_ctl, 0, fc_snd_flogi, 0, 0)) == 0) + fc_snd_flogi(p_dev_ctl, 0, 0); + return(0); +} + +/***************************************/ +/** fc_issue_ct_rsp Issue an **/ +/** CT rsp **/ +/***************************************/ +_static_ int +fc_issue_ct_rsp( +FC_BRD_INFO * binfo, +uint32 tag, +MATCHMAP * bmp, +DMATCHMAP * inp) +{ + IOCB * icmd; + IOCBQ * temp; + RING * rp; + fc_dev_ctl_t * p_dev_ctl; + uint32 num_entry; + + rp = &binfo->fc_ring[FC_ELS_RING]; + num_entry = (uint32)inp->dfc_flag; + inp->dfc_flag = 0; + + /* Allocate buffer for command iocb */ + if ((temp = (IOCBQ * )fc_mem_get(binfo, MEM_IOCB)) == 0) { + return(1); + } + fc_bzero((void *)temp, sizeof(IOCBQ)); + icmd = &temp->iocb; + + icmd->un.xseq64.bdl.ulpIoTag32 = (uint32)0; + icmd->un.xseq64.bdl.addrHigh = (uint32)putPaddrHigh(bmp->phys); + icmd->un.xseq64.bdl.addrLow = (uint32)putPaddrLow(bmp->phys); + icmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BDL; + icmd->un.xseq64.bdl.bdeSize = (num_entry * sizeof(ULP_BDE64)); + + /* Save for completion so we can release these resources */ + temp->bp = (uchar * )inp; + + icmd->un.xseq64.w5.hcsw.Fctl = (LS | LA); + icmd->un.xseq64.w5.hcsw.Dfctl = 0; + icmd->un.xseq64.w5.hcsw.Rctl = FC_SOL_CTL; + icmd->un.xseq64.w5.hcsw.Type = FC_COMMON_TRANSPORT_ULP; + + p_dev_ctl = (fc_dev_ctl_t *)(binfo->fc_p_dev_ctl); + fc_mpdata_sync(bmp->dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV); + + /* If iotag is zero, assign one from global counter for board */ + icmd->ulpIoTag0 = (unsigned)rp->fc_iotag++; + if ((rp->fc_iotag & 0x3fff) == 0) { + rp->fc_iotag = 1; + } + + /* Fill in rest of iocb */ + icmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX; + icmd->ulpBdeCount = 1; + icmd->ulpLe = 1; + icmd->ulpClass = CLASS3; + icmd->ulpContext = (ushort)tag; + icmd->ulpOwner = OWN_CHIP; + /* Xmit CT response on exchange */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0133, /* ptr to msg structure */ + fc_mes0133, /* ptr to msg */ + fc_msgBlk0133.msgPreambleStr, /* begin varargs */ + icmd->ulpContext, /* xid */ + icmd->ulpIoTag, + binfo->fc_ffstate ); /* end varargs */ + issue_iocb_cmd(binfo, rp, temp); + return(0); +} /* fc_issue_ct_rsp */ + +/***************************************/ +/** fc_gen_req Issue an **/ +/** GEN_REQUEST cmd **/ +/***************************************/ +_static_ int +fc_gen_req( +FC_BRD_INFO * binfo, +MATCHMAP * bmp, +MATCHMAP * inp, +MATCHMAP * outp, +uint32 rpi, +uint32 usr_flg, +uint32 num_entry, +uint32 tmo) +{ + IOCB * icmd; + IOCBQ * temp; + RING * rp; + fc_dev_ctl_t * p_dev_ctl; + + + rp = &binfo->fc_ring[FC_ELS_RING]; + + /* Allocate buffer for command iocb */ + if ((temp = (IOCBQ * )fc_mem_get(binfo, MEM_IOCB | MEM_PRI)) == 0) { + return(1); + } + fc_bzero((void *)temp, sizeof(IOCBQ)); + icmd = &temp->iocb; + + icmd->un.genreq64.bdl.ulpIoTag32 = (uint32)0; + icmd->un.genreq64.bdl.addrHigh = (uint32)putPaddrHigh(bmp->phys); + icmd->un.genreq64.bdl.addrLow = (uint32)putPaddrLow(bmp->phys); + icmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BDL; + icmd->un.genreq64.bdl.bdeSize = (num_entry * sizeof(ULP_BDE64)); + + if(usr_flg) + temp->bpl = 0; + else + temp->bpl = (uchar *)bmp; + + /* Save for completion so we can release these resources */ + temp->bp = (uchar * )inp; + temp->info = (uchar * )outp; + + /* Fill in payload, bp points to frame payload */ + icmd->ulpCommand = CMD_GEN_REQUEST64_CR; + + p_dev_ctl = (fc_dev_ctl_t *)(binfo->fc_p_dev_ctl); + fc_mpdata_sync(bmp->dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV); + + /* If iotag is zero, assign one from global counter for board */ + icmd->ulpIoTag0 = (unsigned)rp->fc_iotag++; + if ((rp->fc_iotag & 0x3fff) == 0) { + rp->fc_iotag = 1; + } + + /* Fill in rest of iocb */ + icmd->un.genreq64.w5.hcsw.Fctl = (SI | LA); + icmd->un.genreq64.w5.hcsw.Dfctl = 0; + icmd->un.genreq64.w5.hcsw.Rctl = FC_UNSOL_CTL; + icmd->un.genreq64.w5.hcsw.Type = FC_COMMON_TRANSPORT_ULP; + + if(tmo == 0) + tmo = (2 * binfo->fc_ratov); + icmd->ulpTimeout = tmo; + icmd->ulpBdeCount = 1; + icmd->ulpLe = 1; + icmd->ulpClass = CLASS3; + icmd->ulpContext = (volatile ushort)rpi; + icmd->ulpOwner = OWN_CHIP; + /* Issue GEN REQ IOCB for NPORT */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0134, /* ptr to msg structure */ + fc_mes0134, /* ptr to msg */ + fc_msgBlk0134.msgPreambleStr, /* begin varargs */ + icmd->un.ulpWord[5], /* did */ + icmd->ulpIoTag, + binfo->fc_ffstate ); /* end varargs */ + issue_iocb_cmd(binfo, rp, temp); + + FCSTATCTR.elsXmitFrame++; + return(0); +} /* End fc_gen_req */ + + +/***************************************/ +/** fc_rnid_req Issue an **/ +/** RNID REQUEST cmd **/ +/***************************************/ +_static_ int +fc_rnid_req( +FC_BRD_INFO * binfo, +DMATCHMAP * inp, +DMATCHMAP * outp, +MATCHMAP ** bmpp, +uint32 rpi) +{ + IOCB * icmd; + IOCBQ * temp; + RING * rp; + ULP_BDE64 * bpl; + MATCHMAP * bmp; + fc_dev_ctl_t * p_dev_ctl; + + + rp = &binfo->fc_ring[FC_ELS_RING]; + + /* Allocate buffer for command iocb */ + if ((temp = (IOCBQ * )fc_mem_get(binfo, MEM_IOCB | MEM_PRI)) == 0) { + return(1); + } + fc_bzero((void *)temp, sizeof(IOCBQ)); + icmd = &temp->iocb; + + if (binfo->fc_flag & FC_SLI2) { + /* Allocate buffer for Buffer ptr list */ + if ((bmp = (MATCHMAP * )fc_mem_get(binfo, MEM_BPL | MEM_PRI)) == 0) { + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + return(1); + } + *bmpp = bmp; /* to free BPL on compl */ + bpl = (ULP_BDE64 * )bmp->virt; + bpl->addrLow = PCIMEM_LONG(putPaddrLow((ulong)inp->dfc.phys)); + bpl->addrHigh = PCIMEM_LONG(putPaddrHigh((ulong)inp->dfc.phys)); + bpl->tus.f.bdeFlags = 0; + bpl++; + bpl->addrLow = PCIMEM_LONG(putPaddrLow((ulong)outp->dfc.phys)); + bpl->addrHigh = PCIMEM_LONG(putPaddrHigh((ulong)outp->dfc.phys)); + bpl->tus.f.bdeSize = (ushort)((ulong)(outp->dfc.fc_mptr)); + bpl->tus.f.bdeFlags = BUFF_USE_RCV; + bpl->tus.w = PCIMEM_LONG(bpl->tus.w); + + bpl--; /* so we can fill in size later */ + + icmd->un.genreq64.bdl.ulpIoTag32 = (uint32)0; + icmd->un.genreq64.bdl.addrHigh = (uint32)putPaddrHigh(bmp->phys); + icmd->un.genreq64.bdl.addrLow = (uint32)putPaddrLow(bmp->phys); + icmd->un.genreq64.bdl.bdeSize = (2 * sizeof(ULP_BDE64)); + icmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BDL; + temp->bpl = 0; + } else { + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + return(1); + } + + /* Save for completion so we can release these resources */ + temp->info = (uchar * )outp; + + /* Fill in payload, bp points to frame payload */ + icmd->ulpCommand = CMD_GEN_REQUEST64_CR; + bpl->tus.f.bdeSize = (ushort)((ulong)(inp->dfc.fc_mptr)); + bpl->tus.w = PCIMEM_LONG(bpl->tus.w); + + p_dev_ctl = (fc_dev_ctl_t *)(binfo->fc_p_dev_ctl); + fc_mpdata_sync(bmp->dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV); + fc_mpdata_sync(inp->dfc.dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV); + + /* If iotag is zero, assign one from global counter for board */ + icmd->ulpIoTag0 = (unsigned)rp->fc_iotag++; + if ((rp->fc_iotag & 0x3fff) == 0) { + rp->fc_iotag = 1; + } + + /* Fill in rest of iocb */ + icmd->un.genreq64.w5.hcsw.Fctl = (SI | LA); + icmd->un.genreq64.w5.hcsw.Dfctl = 0; + icmd->un.genreq64.w5.hcsw.Rctl = FC_ELS_REQ; + icmd->un.genreq64.w5.hcsw.Type = FC_ELS_DATA; + + icmd->ulpBdeCount = 1; + icmd->ulpLe = 1; + icmd->ulpClass = CLASS3; + icmd->ulpTimeout = (uchar)(rp->fc_ringtmo - 2); + icmd->ulpContext = (volatile ushort)rpi; + icmd->ulpOwner = OWN_CHIP; + /* Issue GEN REQ IOCB for RNID */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0135, /* ptr to msg structure */ + fc_mes0135, /* ptr to msg */ + fc_msgBlk0135.msgPreambleStr, /* begin varargs */ + icmd->un.ulpWord[5], /* did */ + icmd->ulpIoTag, + binfo->fc_ffstate ); /* end varargs */ + issue_iocb_cmd(binfo, rp, temp); + outp->dfc.fc_mptr = 0; + + FCSTATCTR.elsXmitFrame++; + return(0); +} /* End fc_rnid_req */ + + +/***************************************/ +/** fc_issue_ct_req Issue a **/ +/** CT request to nameserver **/ +/***************************************/ +_static_ int +fc_issue_ct_req( +FC_BRD_INFO * binfo, +uint32 portid, +MATCHMAP * bmp, +DMATCHMAP * inmp, +DMATCHMAP * outmp, +uint32 tmo) +{ + uint32 size; + NODELIST * ndlp; + + size = (uint32)outmp->dfc_flag; + /* Find nameserver entry */ + if((((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, portid))) == 0) || + (ndlp->nlp_Rpi == 0) || + (binfo->fc_flag & FC_RSCN_MODE)) { + + if ((binfo->fc_flag & FC_FABRIC) && (binfo->fc_ffstate == FC_READY)) { + if ((ndlp == 0) || ((ndlp->nlp_state < NLP_PLOGI) && !(ndlp->nlp_flag & NLP_NS_REMOVED))) { + /* We can LOGIN to the port first */ + fc_els_cmd(binfo, ELS_CMD_PLOGI, (void *)((ulong)portid), + (uint32)0, (ushort)0, ndlp); + } + return(ENODEV); + } + return(EACCES); + } + + if((fc_gen_req(binfo, bmp, (MATCHMAP *)inmp, (MATCHMAP *)outmp, + ndlp->nlp_Rpi, 1, (inmp->dfc_flag + outmp->dfc_flag), tmo))) + return(ENOMEM); + + outmp->dfc_flag = 0; + return(0); +} + +/**************************************************/ +/** **/ +/** Free any deferred RSCNs **/ +/** **/ +/**************************************************/ +_static_ int +fc_flush_rscn_defer( +fc_dev_ctl_t *p_dev_ctl) +{ + FC_BRD_INFO * binfo; + RING * rp; + IOCBQ * xmitiq; + IOCB * iocb; + MATCHMAP * mp; + int i; + + binfo = &BINFO; + rp = &binfo->fc_ring[FC_ELS_RING]; + while (binfo->fc_defer_rscn.q_first) { + xmitiq = (IOCBQ * )binfo->fc_defer_rscn.q_first; + if ((binfo->fc_defer_rscn.q_first = xmitiq->q) == 0) { + binfo->fc_defer_rscn.q_last = 0; + } + binfo->fc_defer_rscn.q_cnt--; + iocb = &xmitiq->iocb; + mp = *((MATCHMAP **)iocb); + *((MATCHMAP **)iocb) = 0; + xmitiq->q = NULL; + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + + i = 1; + /* free resources associated with this iocb and repost the ring buffers */ + if (!(binfo->fc_flag & FC_SLI2)) { + for (i = 1; i < (int)iocb->ulpBdeCount; i++) { + mp = fc_getvaddr(p_dev_ctl, rp, (uchar * )((ulong)iocb->un.cont[i].bdeAddress)); + if (mp) { + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + } + } + } + fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq); + } + return(0); +} + +/**************************************************/ +/** **/ +/** Issue a NameServer query for RSCN processing **/ +/** **/ +/**************************************************/ +_static_ void +fc_issue_ns_query( +fc_dev_ctl_t *p_dev_ctl, +void *a1, +void *a2) +{ + FC_BRD_INFO * binfo; + NODELIST * ndlp; + + binfo = &BINFO; + binfo->fc_flag &= ~FC_NSLOGI_TMR; + /* Now check with NameServer */ + if ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, NameServer_DID)) == 0) { + /* We can LOGIN to the NameServer now */ + fc_els_cmd(binfo, ELS_CMD_PLOGI, (void *)NameServer_DID, + (uint32)0, (ushort)0, ndlp); + } + else { + /* Issue GID_FT to Nameserver */ + if (fc_ns_cmd(p_dev_ctl, ndlp, SLI_CTNS_GID_FT)) { + /* error so start discovery */ + /* Done with NameServer for now, but keep logged in */ + ndlp->nlp_action &= ~NLP_DO_RSCN; + + /* Fire out PLOGIs on nodes marked for discovery */ + if ((binfo->fc_nlp_cnt <= 0) && + !(binfo->fc_flag & FC_NLP_MORE)) { + binfo->fc_nlp_cnt = 0; + fc_nextrscn(p_dev_ctl, fc_max_els_sent); + } + else { + fc_nextnode(p_dev_ctl, ndlp); + } + ndlp->nlp_action &= ~NLP_DO_ADDR_AUTH; + } + } + return; +} + +_static_ int +fc_abort_discovery( +fc_dev_ctl_t *p_dev_ctl) +{ + FC_BRD_INFO * binfo; + MAILBOXQ * mb; + + binfo = &BINFO; + + fc_linkdown(p_dev_ctl); + + /* This should turn off DELAYED ABTS for ELS timeouts */ + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX))) { + fc_set_slim(binfo, (MAILBOX * )mb, 0x052198, 0); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + + /* This is at init, clear la */ + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + fc_clear_la(binfo, (MAILBOX * )mb); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } else { + binfo->fc_ffstate = FC_ERROR; + /* Device Discovery completion error */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0217, /* ptr to msg structure */ + fc_mes0217, /* ptr to msg */ + fc_msgBlk0217.msgPreambleStr); /* begin & end varargs */ + } + if(FABRICTMO) { + fc_clk_can(p_dev_ctl, FABRICTMO); + FABRICTMO = 0; + } + return(0); +} + +#define FOURBYTES 4 + +/**************************************************/ +/** fc_fdmi_cmd **/ +/** **/ +/** Description: **/ +/** Issue Cmd to HBA Management Server **/ +/** SLI_MGMT_RHBA **/ +/** SLI_MGMT_RPRT **/ +/** SLI_MGMT_DHBA **/ +/** SLI_MGMT_DPRT **/ +/** **/ +/** Accept Payload for those 4 commands **/ +/** is 0 **/ +/** **/ +/** Returns: **/ +/** **/ +/**************************************************/ +_static_ int +fc_fdmi_cmd( +fc_dev_ctl_t *p_dev_ctl, +NODELIST *ndlp, +int cmdcode) +{ + FC_BRD_INFO * binfo; + MATCHMAP * mp, *bmp; + SLI_CT_REQUEST * CtReq; + ULP_BDE64 * bpl; + u32bit size; + PREG_HBA rh; + PPORT_ENTRY pe; + PREG_PORT_ATTRIBUTE pab; + PATTRIBUTE_BLOCK ab; + PATTRIBUTE_ENTRY ae; + uint32 id; + + binfo = &BINFO; + + /* fill in BDEs for command */ + /* Allocate buffer for command payload */ + if ((mp = (MATCHMAP * )fc_mem_get(binfo, MEM_BUF)) == 0) { + return(1); + } + + bmp = 0; + + /* Allocate buffer for Buffer ptr list */ + if ((bmp = (MATCHMAP * )fc_mem_get(binfo, MEM_BPL)) == 0) { + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + return(1); + } + /* FDMI Req */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0218, /* ptr to msg structure */ + fc_mes0218, /* ptr to msg */ + fc_msgBlk0218.msgPreambleStr, /* begin varargs */ + cmdcode, + binfo->fc_flag ); /* end varargs */ + CtReq = (SLI_CT_REQUEST * )mp->virt; + /* + * Initialize mp, 1024 bytes + */ + fc_bzero((void *)CtReq, FCELSSIZE); + + CtReq->RevisionId.bits.Revision = SLI_CT_REVISION; + CtReq->RevisionId.bits.InId = 0; + + CtReq->FsType = SLI_CT_MANAGEMENT_SERVICE; + CtReq->FsSubType = SLI_CT_FDMI_Subtypes; + size = 0; + + switch (cmdcode) { + case SLI_MGMT_RHBA : + { + fc_vpd_t * vp; + char * str; + uint32 i, j, incr; + uchar HWrev[8]; + + vp = &VPD; + + CtReq->CommandResponse.bits.CmdRsp = SWAP_DATA16(SLI_MGMT_RHBA); + CtReq->CommandResponse.bits.Size = 0; + rh = (PREG_HBA)&CtReq->un.PortID; + fc_bcopy((uchar * )&binfo->fc_sparam.portName, (uchar * )&rh->hi.PortName, + sizeof(NAME_TYPE)); + rh->rpl.EntryCnt = SWAP_DATA(1); /* One entry (port) per adapter */ + fc_bcopy((uchar * )&binfo->fc_sparam.portName, (uchar * )&rh->rpl.pe, + sizeof(NAME_TYPE)); + + /* point to the HBA attribute block */ + size = sizeof(NAME_TYPE) + FOURBYTES + sizeof(NAME_TYPE); + ab = (PATTRIBUTE_BLOCK)((uchar *)rh + size); + ab->EntryCnt = 0; + + /* Point to the begin of the first HBA attribute entry */ + /* #1 HBA attribute entry */ + size += FOURBYTES; + ae = (PATTRIBUTE_ENTRY)((uchar *)rh + size); + ae->ad.bits.AttrType = SWAP_DATA16(NODE_NAME); + ae->ad.bits.AttrLen = SWAP_DATA16(sizeof(NAME_TYPE)); + fc_bcopy((uchar * )&binfo->fc_sparam.nodeName, (uchar * )&ae->un.NodeName, + sizeof(NAME_TYPE)); + ab->EntryCnt++; + size += FOURBYTES + sizeof(NAME_TYPE); + + /* #2 HBA attribute entry */ + ae = (PATTRIBUTE_ENTRY)((uchar *)rh + size); + ae->ad.bits.AttrType = SWAP_DATA16(MANUFACTURER); + ae->ad.bits.AttrLen = SWAP_DATA16(24); + fc_bcopy("Emulex Network Systems", ae->un.Manufacturer, 22); + ab->EntryCnt++; + size += FOURBYTES + 24; + + /* #3 HBA attribute entry */ + ae = (PATTRIBUTE_ENTRY)((uchar *)rh + size); + ae->ad.bits.AttrType = SWAP_DATA16(SERIAL_NUMBER); + ae->ad.bits.AttrLen = SWAP_DATA16(32); + fc_bcopy(binfo->fc_SerialNumber, ae->un.SerialNumber, 32); + ab->EntryCnt++; + size += FOURBYTES + 32; + + /* #4 HBA attribute entry */ + id = fc_rdpci_32(p_dev_ctl, PCI_VENDOR_ID_REGISTER); + switch((id >> 16) & 0xffff) { + case PCI_DEVICE_ID_SUPERFLY: + if((vp->rev.biuRev == 1) || (vp->rev.biuRev == 2) || + (vp->rev.biuRev == 3)) { + ae = (PATTRIBUTE_ENTRY)((uchar *)rh + size); + ae->ad.bits.AttrType = SWAP_DATA16(MODEL); + ae->ad.bits.AttrLen = SWAP_DATA16(8); + fc_bcopy("LP7000", ae->un.Model, 6); + ab->EntryCnt++; + size += FOURBYTES + 8; + + /* #5 HBA attribute entry */ + ae = (PATTRIBUTE_ENTRY)((uchar *)rh + size); + ae->ad.bits.AttrType = SWAP_DATA16(MODEL_DESCRIPTION); + ae->ad.bits.AttrLen = SWAP_DATA16(64); + fc_bcopy("Emulex LightPulse LP7000 1 Gigabit PCI Fibre Channel Adapter", + ae->un.ModelDescription, 62); + ab->EntryCnt++; + size += FOURBYTES + 64; + } else { + ae = (PATTRIBUTE_ENTRY)((uchar *)rh + size); + ae->ad.bits.AttrType = SWAP_DATA16(MODEL); + ae->ad.bits.AttrLen = SWAP_DATA16(8); + fc_bcopy("LP7000E", ae->un.Model, 7); + ab->EntryCnt++; + size += FOURBYTES + 8; + + /* #5 HBA attribute entry */ + ae = (PATTRIBUTE_ENTRY)((uchar *)rh + size); + ae->ad.bits.AttrType = SWAP_DATA16(MODEL_DESCRIPTION); + ae->ad.bits.AttrLen = SWAP_DATA16(64); + fc_bcopy("Emulex LightPulse LP7000E 1 Gigabit PCI Fibre Channel Adapter", + ae->un.ModelDescription, 62); + ab->EntryCnt++; + size += FOURBYTES + 64; + } + break; + case PCI_DEVICE_ID_DRAGONFLY: + ae = (PATTRIBUTE_ENTRY)((uchar *)rh + size); + ae->ad.bits.AttrType = SWAP_DATA16(MODEL); + ae->ad.bits.AttrLen = SWAP_DATA16(8); + fc_bcopy("LP8000", ae->un.Model, 6); + ab->EntryCnt++; + size += FOURBYTES + 8; + + /* #5 HBA attribute entry */ + ae = (PATTRIBUTE_ENTRY)((uchar *)rh + size); + ae->ad.bits.AttrType = SWAP_DATA16(MODEL_DESCRIPTION); + ae->ad.bits.AttrLen = SWAP_DATA16(64); + fc_bcopy("Emulex LightPulse LP8000 1 Gigabit PCI Fibre Channel Adapter", + ae->un.ModelDescription, 62); + ab->EntryCnt++; + size += FOURBYTES + 64; + break; + case PCI_DEVICE_ID_CENTAUR: + if(FC_JEDEC_ID(vp->rev.biuRev) == CENTAUR_2G_JEDEC_ID) { + ae = (PATTRIBUTE_ENTRY)((uchar *)rh + size); + ae->ad.bits.AttrType = SWAP_DATA16(MODEL); + ae->ad.bits.AttrLen = SWAP_DATA16(8); + fc_bcopy("LP9002", ae->un.Model, 6); + ab->EntryCnt++; + size += FOURBYTES + 8; + + /* #5 HBA attribute entry */ + ae = (PATTRIBUTE_ENTRY)((uchar *)rh + size); + ae->ad.bits.AttrType = SWAP_DATA16(MODEL_DESCRIPTION); + ae->ad.bits.AttrLen = SWAP_DATA16(64); + fc_bcopy("Emulex LightPulse LP9002 2 Gigabit PCI Fibre Channel Adapter", + ae->un.ModelDescription, 62); + ab->EntryCnt++; + size += FOURBYTES + 64; + } else { + ae = (PATTRIBUTE_ENTRY)((uchar *)rh + size); + ae->ad.bits.AttrType = SWAP_DATA16(MODEL); + ae->ad.bits.AttrLen = SWAP_DATA16(8); + fc_bcopy("LP9000", ae->un.Model, 6); + ab->EntryCnt++; + size += FOURBYTES + 8; + + /* #5 HBA attribute entry */ + ae = (PATTRIBUTE_ENTRY)((uchar *)rh + size); + ae->ad.bits.AttrType = SWAP_DATA16(MODEL_DESCRIPTION); + ae->ad.bits.AttrLen = SWAP_DATA16(64); + fc_bcopy("Emulex LightPulse LP9000 1 Gigabit PCI Fibre Channel Adapter", + ae->un.ModelDescription, 62); + ab->EntryCnt++; + size += FOURBYTES + 64; + } + break; + case PCI_DEVICE_ID_PEGASUS: + ae = (PATTRIBUTE_ENTRY)((uchar *)rh + size); + ae->ad.bits.AttrType = SWAP_DATA16(MODEL); + ae->ad.bits.AttrLen = SWAP_DATA16(8); + fc_bcopy("LP9802", ae->un.Model, 6); + ab->EntryCnt++; + size += FOURBYTES + 8; + + /* #5 HBA attribute entry */ + ae = (PATTRIBUTE_ENTRY)((uchar *)rh + size); + ae->ad.bits.AttrType = SWAP_DATA16(MODEL_DESCRIPTION); + ae->ad.bits.AttrLen = SWAP_DATA16(64); + fc_bcopy("Emulex LightPulse LP9802 2 Gigabit PCI Fibre Channel Adapter", + ae->un.ModelDescription, 62); + ab->EntryCnt++; + size += FOURBYTES + 64; + break; + case PCI_DEVICE_ID_PFLY: + ae = (PATTRIBUTE_ENTRY)((uchar *)rh + size); + ae->ad.bits.AttrType = SWAP_DATA16(MODEL); + ae->ad.bits.AttrLen = SWAP_DATA16(8); + fc_bcopy("LP982", ae->un.Model, 5); + ab->EntryCnt++; + size += FOURBYTES + 8; + + /* #5 HBA attribute entry */ + ae = (PATTRIBUTE_ENTRY)((uchar *)rh + size); + ae->ad.bits.AttrType = SWAP_DATA16(MODEL_DESCRIPTION); + ae->ad.bits.AttrLen = SWAP_DATA16(64); + fc_bcopy("Emulex LightPulse LP982 2 Gigabit PCI Fibre Channel Adapter", + ae->un.ModelDescription, 62); + ab->EntryCnt++; + size += FOURBYTES + 64; + break; + } + + /* #6 HBA attribute entry */ + ae = (PATTRIBUTE_ENTRY)((uchar *)rh + size); + ae->ad.bits.AttrType = SWAP_DATA16(HARDWARE_VERSION); + ae->ad.bits.AttrLen = SWAP_DATA16(8); + /* Convert JEDEC ID to ascii for hardware version */ + incr = vp->rev.biuRev; + for(i=0;i<8;i++) { + j = (incr & 0xf); + if(j <= 9) + HWrev[7-i] = (char)((uchar)0x30 + (uchar)j); + else + HWrev[7-i] = (char)((uchar)0x61 + (uchar)(j-10)); + incr = (incr >> 4); + } + fc_bcopy((uchar *)HWrev, ae->un.HardwareVersion, 8); + ab->EntryCnt++; + size += FOURBYTES + 8; + + /* #7 HBA attribute entry */ + ae = (PATTRIBUTE_ENTRY)((uchar *)rh + size); + ae->ad.bits.AttrType = SWAP_DATA16(DRIVER_VERSION); + ae->ad.bits.AttrLen = SWAP_DATA16(16); + for (i=0; lpfc_release_version[i]; i++); + fc_bcopy((uchar *)lpfc_release_version, ae->un.DriverVersion, i); + ab->EntryCnt++; + size += FOURBYTES + 16; + + /* #8 HBA attribute entry */ + ae = (PATTRIBUTE_ENTRY)((uchar *)rh + size); + ae->ad.bits.AttrType = SWAP_DATA16(OPTION_ROM_VERSION); + ae->ad.bits.AttrLen = SWAP_DATA16(32); + fc_bcopy(binfo->fc_OptionROMVersion, ae->un.OptionROMVersion, 32); + ab->EntryCnt++; + size += FOURBYTES + 32; + + /* #9 HBA attribute entry */ + ae = (PATTRIBUTE_ENTRY)((uchar *)rh + size); + ae->ad.bits.AttrType = SWAP_DATA16(FIRMWARE_VERSION); + ae->ad.bits.AttrLen = SWAP_DATA16(32); + str = decode_firmware_rev(binfo, vp); + fc_bcopy((uchar *)str, ae->un.FirmwareVersion, 32); + ab->EntryCnt++; + size += FOURBYTES + 32; + + /* #10 HBA attribute entry */ + ae = (PATTRIBUTE_ENTRY)((uchar *)rh + size); + ae->ad.bits.AttrType = SWAP_DATA16(VENDOR_SPECIFIC); + ae->ad.bits.AttrLen = SWAP_DATA16(4); + id = SWAP_LONG(id); + id = (((SWAP_ALWAYS16(id >> 16)) << 16) | SWAP_ALWAYS16(id)); + ae->un.VendorSpecific = id; + ab->EntryCnt++; + size += FOURBYTES + 4; + + /* #11 HBA attribute entry */ + ae = (PATTRIBUTE_ENTRY)((uchar *)rh + size); + ae->ad.bits.AttrType = SWAP_DATA16(DRIVER_NAME); + ae->ad.bits.AttrLen = SWAP_DATA16(4); + fc_bcopy("lpfc", ae->un.DriverName, 4); + ab->EntryCnt++; + size += FOURBYTES + 4; + + + + ab->EntryCnt = SWAP_DATA(ab->EntryCnt); + /* Total size */ + size = GID_REQUEST_SZ - 4 + size; + } + break; + + case SLI_MGMT_RPRT : + { + fc_vpd_t * vp; + SERV_PARM * hsp; + + vp = &VPD; + + CtReq->CommandResponse.bits.CmdRsp = SWAP_DATA16(SLI_MGMT_RPRT); + CtReq->CommandResponse.bits.Size = 0; + pab = (PREG_PORT_ATTRIBUTE)&CtReq->un.PortID; + size = sizeof(NAME_TYPE) + sizeof(NAME_TYPE) + FOURBYTES; + fc_bcopy((uchar * )&binfo->fc_sparam.portName, (uchar * )&pab->HBA_PortName, + sizeof(NAME_TYPE)); + fc_bcopy((uchar * )&binfo->fc_sparam.portName, (uchar * )&pab->PortName, + sizeof(NAME_TYPE)); + pab->ab.EntryCnt = 0; + + /* #1 Port attribute entry */ + ae = (PATTRIBUTE_ENTRY)((uchar *)pab + size); + ae->ad.bits.AttrType = SWAP_DATA16(SUPPORTED_FC4_TYPES); + ae->ad.bits.AttrLen = SWAP_DATA16(8); + ae->un.SupportFC4Types[4] = 1; + pab->ab.EntryCnt++; + size += FOURBYTES + 8; + + /* #2 Port attribute entry */ + ae = (PATTRIBUTE_ENTRY)((uchar *)pab + size); + ae->ad.bits.AttrType = SWAP_DATA16(SUPPORTED_SPEED); + ae->ad.bits.AttrLen = SWAP_DATA16(4); + if(FC_JEDEC_ID(vp->rev.biuRev) == CENTAUR_2G_JEDEC_ID) + ae->un.SupportSpeed = HBA_PORTSPEED_2GBIT; + else + ae->un.SupportSpeed = HBA_PORTSPEED_1GBIT; + pab->ab.EntryCnt++; + size += FOURBYTES + 4; + + /* #3 Port attribute entry */ + ae = (PATTRIBUTE_ENTRY)((uchar *)pab + size); + ae->ad.bits.AttrType = SWAP_DATA16(PORT_SPEED); + ae->ad.bits.AttrLen = SWAP_DATA16(4); + if( binfo->fc_linkspeed == LA_2GHZ_LINK) + ae->un.PortSpeed = HBA_PORTSPEED_2GBIT; + else + ae->un.PortSpeed = HBA_PORTSPEED_1GBIT; + pab->ab.EntryCnt++; + size += FOURBYTES + 4; + + /* #4 Port attribute entry */ + ae = (PATTRIBUTE_ENTRY)((uchar *)pab + size); + ae->ad.bits.AttrType = SWAP_DATA16(MAX_FRAME_SIZE); + ae->ad.bits.AttrLen = SWAP_DATA16(4); + hsp = (SERV_PARM *)&binfo->fc_sparam; + ae->un.MaxFrameSize = (((uint32)hsp->cmn.bbRcvSizeMsb) << 8) | + (uint32)hsp->cmn.bbRcvSizeLsb; + pab->ab.EntryCnt++; + size += FOURBYTES + 4; + + /* #5 Port attribute entry */ + ae = (PATTRIBUTE_ENTRY)((uchar *)pab + size); + ae->ad.bits.AttrType = SWAP_DATA16(OS_DEVICE_NAME); + ae->ad.bits.AttrLen = SWAP_DATA16(4); + fc_bcopy("lpfc", (uchar * )&ae->un.DriverName, 4); + pab->ab.EntryCnt++; + size += FOURBYTES + 4; + + pab->ab.EntryCnt = SWAP_DATA(pab->ab.EntryCnt); + /* Total size */ + size = GID_REQUEST_SZ - 4 + size; + } + break; + + case SLI_MGMT_DHBA : + CtReq->CommandResponse.bits.CmdRsp = SWAP_DATA16(SLI_MGMT_DHBA); + CtReq->CommandResponse.bits.Size = 0; + pe = (PPORT_ENTRY)&CtReq->un.PortID; + fc_bcopy((uchar * )&binfo->fc_sparam.portName, (uchar * )&pe->PortName, + sizeof(NAME_TYPE)); + size = GID_REQUEST_SZ - 4 + sizeof(NAME_TYPE); + break; + + case SLI_MGMT_DPRT : + CtReq->CommandResponse.bits.CmdRsp = SWAP_DATA16(SLI_MGMT_DPRT); + CtReq->CommandResponse.bits.Size = 0; + pe = (PPORT_ENTRY)&CtReq->un.PortID; + fc_bcopy((uchar * )&binfo->fc_sparam.portName, (uchar * )&pe->PortName, + sizeof(NAME_TYPE)); + size = GID_REQUEST_SZ - 4 + sizeof(NAME_TYPE); + break; + } + + bpl = (ULP_BDE64 * )bmp->virt; + bpl->addrHigh = PCIMEM_LONG((uint32)putPaddrHigh(mp->phys)); + bpl->addrLow = PCIMEM_LONG((uint32)putPaddrLow(mp->phys)); + bpl->tus.f.bdeFlags = 0; + bpl->tus.f.bdeSize = size; + bpl->tus.w = PCIMEM_LONG(bpl->tus.w); + + + if(fc_ct_cmd(p_dev_ctl, mp, bmp, ndlp)) { + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + fc_mem_put(binfo, MEM_BPL, (uchar * )bmp); + } + return(0); +} /* End fc_ns_cmd */ + +/**************************************************/ +/** fc_fdmi_rsp **/ +/** **/ +/** Description: **/ +/** Process Rsp from HBA Management Server **/ +/** SLI_MGMT_RHBA **/ +/** SLI_MGMT_RPRT **/ +/** SLI_MGMT_DHBA **/ +/** SLI_MGMT_DPRT **/ +/** **/ +/** Returns: **/ +/** **/ +/**************************************************/ +_static_ void +fc_fdmi_rsp( +fc_dev_ctl_t *p_dev_ctl, +MATCHMAP *mp, +MATCHMAP *rsp_mp) + +{ + FC_BRD_INFO * binfo; + SLI_CT_REQUEST * Cmd; + SLI_CT_REQUEST * Rsp; + NODELIST * ndlp; + ushort fdmi_cmd; + ushort fdmi_rsp; + int rc; + + binfo = &BINFO; + + ndlp = (NODELIST *)mp->fc_mptr; + Cmd = (SLI_CT_REQUEST *)mp->virt; + Rsp = (SLI_CT_REQUEST *)rsp_mp->virt; + + fdmi_rsp = Rsp->CommandResponse.bits.CmdRsp; + + fdmi_cmd = Cmd->CommandResponse.bits.CmdRsp; + rc = 1; + + switch (SWAP_DATA16(fdmi_cmd)) { + case SLI_MGMT_RHBA : + rc = fc_fdmi_cmd(p_dev_ctl, ndlp, SLI_MGMT_RPRT); + break; + + case SLI_MGMT_RPRT : + break; + + case SLI_MGMT_DHBA : + rc = fc_fdmi_cmd(p_dev_ctl, ndlp, SLI_MGMT_RHBA); + break; + + case SLI_MGMT_DPRT : + rc = fc_fdmi_cmd(p_dev_ctl, ndlp, SLI_MGMT_DHBA); + break; + } + + if (rc) { + /* FDMI rsp failed */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0251, /* ptr to msg structure */ + fc_mes0251, /* ptr to msg */ + fc_msgBlk0251.msgPreambleStr, /* begin varargs */ + SWAP_DATA16(fdmi_cmd) ); /* end varargs */ + } +} /* fc_fdmi_rsp */ + + +/*****************************************************************************/ +/* + * NAME: fc_plogi_put + * + * FUNCTION: put iocb cmd onto the iocb plogi queue. + * + * EXECUTION ENVIRONMENT: process and interrupt level. + * + * NOTES: + * + * CALLED FROM: + * issue_els_cmd + * + * INPUT: + * binfo - pointer to the device info area + * iocbq - pointer to iocb queue entry + * + * RETURNS: + * NULL - command queued + */ +/*****************************************************************************/ +_static_ void +fc_plogi_put( +FC_BRD_INFO *binfo, +IOCBQ *iocbq) /* pointer to iocbq entry */ +{ + if (binfo->fc_plogi.q_first) { + /* queue command to end of list */ + ((IOCBQ * )binfo->fc_plogi.q_last)->q = (uchar * )iocbq; + binfo->fc_plogi.q_last = (uchar * )iocbq; + } else { + /* add command to empty list */ + binfo->fc_plogi.q_first = (uchar * )iocbq; + binfo->fc_plogi.q_last = (uchar * )iocbq; + } + + iocbq->q = NULL; + binfo->fc_plogi.q_cnt++; + binfo->fc_flag |= FC_DELAY_NSLOGI; + return; + +} /* End fc_plogi_put */ + + +/*****************************************************************************/ +/* + * NAME: fc_plogi_get + * + * FUNCTION: get a iocb command from iocb plogi command queue + * + * EXECUTION ENVIRONMENT: interrupt level. + * + * NOTES: + * + * CALLED FROM: + * handle_mb_event + * + * INPUT: + * binfo - pointer to the device info area + * + * RETURNS: + * NULL - no match found + * iocb pointer - pointer to a iocb command + */ +/*****************************************************************************/ +_static_ IOCBQ * +fc_plogi_get( +FC_BRD_INFO *binfo) +{ + IOCBQ * p_first = NULL; + + if (binfo->fc_plogi.q_first) { + p_first = (IOCBQ * )binfo->fc_plogi.q_first; + if ((binfo->fc_plogi.q_first = p_first->q) == 0) { + binfo->fc_plogi.q_last = 0; + binfo->fc_flag &= ~FC_DELAY_NSLOGI; + } + p_first->q = NULL; + binfo->fc_plogi.q_cnt--; + } + return(p_first); + +} /* End fc_plogi_get */ + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/fcfgparm.h 830-ivtv/drivers/scsi/lpfc/fcfgparm.h --- 000-virgin/drivers/scsi/lpfc/fcfgparm.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/fcfgparm.h Thu Jan 8 10:21:53 2004 @@ -0,0 +1,341 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Enterprise Fibre Channel Host Bus Adapters. * + * Refer to the README file included with this package for * + * driver version and adapter support. * + * Copyright (C) 2003 Emulex Corporation. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details, a copy of which * + * can be found in the file COPYING included with this package. * + *******************************************************************/ + +#ifndef _H_CFGPARAM +#define _H_CFGPARAM + +#define LPFC_DFT_POST_IP_BUF 128 +#define LPFC_MIN_POST_IP_BUF 64 +#define LPFC_MAX_POST_IP_BUF 1024 +#define LPFC_DFT_XMT_QUE_SIZE 256 +#define LPFC_MIN_XMT_QUE_SIZE 128 +#define LPFC_MAX_XMT_QUE_SIZE 10240 +#define LPFC_DFT_NUM_IOCBS 1024 +#define LPFC_MIN_NUM_IOCBS 128 +#define LPFC_MAX_NUM_IOCBS 10240 +#define LPFC_DFT_NUM_BUFS 1024 +#define LPFC_MIN_NUM_BUFS 64 +#define LPFC_MAX_NUM_BUFS 4096 +#define LPFC_DFT_NUM_NODES 510 +#define LPFC_MIN_NUM_NODES 64 +#define LPFC_MAX_NUM_NODES 4096 +#define LPFC_DFT_TOPOLOGY 0 +#define LPFC_DFT_FC_CLASS 3 + +#define LPFC_DFT_NO_DEVICE_DELAY 1 /* 1 sec */ +#define LPFC_MAX_NO_DEVICE_DELAY 30 /* 30 sec */ +#define LPFC_DFT_FABRIC_TIMEOUT 0 +#define LPFC_MAX_FABRIC_TIMEOUT 255 /* 255 sec */ +#define LPFC_DFT_LNKDWN_TIMEOUT 30 +#define LPFC_MAX_LNKDWN_TIMEOUT 255 /* 255 sec */ +#define LPFC_DFT_NODEV_TIMEOUT 0 +#define LPFC_MAX_NODEV_TIMEOUT 255 /* 255 sec */ +#define LPFC_DFT_RSCN_NS_DELAY 0 +#define LPFC_MAX_RSCN_NS_DELAY 255 /* 255 sec */ + +#define LPFC_MAX_TGT_Q_DEPTH 10240 /* max cmds allowed per tgt */ +#define LPFC_DFT_TGT_Q_DEPTH 0 /* default max cmds per tgt */ + +#define LPFC_MAX_LUN_Q_DEPTH 128 /* max cmds to allow per lun */ +#define LPFC_DFT_LUN_Q_DEPTH 30 /* default max cmds per lun */ + +#define LPFC_MAX_DQFULL_THROTTLE 1 /* Boolean (max value) */ + +#define CFG_INTR_ACK 0 /* intr-ack */ +#define CFG_LOG_VERBOSE 1 /* log-verbose */ +#define CFG_LOG_ONLY 2 /* log-only */ +#define CFG_IDENTIFY_SELF 3 /* identify-self */ +#define CFG_NUM_IOCBS 4 /* num-iocbs */ +#define CFG_NUM_BUFS 5 /* num-bufs */ +#define CFG_FCP_ON 6 /* fcp-on */ +#define CFG_DEVICE_REPORT 7 /* device-report */ +#define CFG_AUTOMAP 8 /* automap */ +#define CFG_DFT_TGT_Q_DEPTH 9 /* tgt_queue_depth */ +#define CFG_DFT_LUN_Q_DEPTH 10 /* lun_queue_depth */ +#define CFG_FIRST_CHECK 11 /* first-check */ +#define CFG_FCPFABRIC_TMO 12 /* fcpfabric-tmo */ +#define CFG_FCP_CLASS 13 /* fcp-class */ +#define CFG_USE_ADISC 14 /* use-adisc */ +#define CFG_NO_DEVICE_DELAY 15 /* no-device-delay */ +#define CFG_NETWORK_ON 16 /* network-on */ +#define CFG_POST_IP_BUF 17 /* post-ip-buf */ +#define CFG_XMT_Q_SIZE 18 /* xmt-que-size */ +#define CFG_IP_CLASS 19 /* ip-class */ +#define CFG_ACK0 20 /* ack0 */ +#define CFG_TOPOLOGY 21 /* topology */ +#define CFG_SCAN_DOWN 22 /* scan-down */ +#define CFG_LINKDOWN_TMO 23 /* linkdown-tmo */ +#define CFG_USE_LOMEM 24 /* use-lomempages */ +#define CFG_ZONE_RSCN 25 /* zone-rscn */ +#define CFG_HOLDIO 26 /* nodev-holdio */ +#define CFG_DELAY_RSP_ERR 27 /* delay-rsp-err */ +#define CFG_CHK_COND_ERR 28 /* check-cond-err */ +#define CFG_NODEV_TMO 29 /* nodev-tmo */ +#define CFG_DQFULL_THROTTLE 30 /* dqfull-throttle */ +#define CFG_LINK_SPEED 31 /* link-speed NEW_FETURE */ +#define CFG_QFULL_RSP_ERR 32 /* qfull-rsp-err */ +#define CFG_DQFULL_THROTTLE_UP_TIME 33 /* dqfull-throttle-up-time */ +#define CFG_DQFULL_THROTTLE_UP_INC 34 /* dqfull-throttle-up-inc */ +#define CFG_NUM_NODES 35 /* num-nodes */ +#define CFG_CR_DELAY 36 /* cr-delay */ +#define CFG_CR_COUNT 37 /* cr-count */ +#define NUM_CFG_PARAM 38 + +#ifdef DEF_ICFG +_static_ iCfgParam icfgparam[NUM_CFG_PARAM] = { + + /* general driver parameters */ + { "intr-ack", + 0, 1, TRUE, 0, + (ushort)0, + (ushort)CFG_DYNAMIC, + "Claim interrupt even if no work discovered" }, + + { "log-verbose", + 0, 0xffff, FALSE, 0, + (ushort)0, + (ushort)CFG_DYNAMIC, + "Verbose logging mask" }, + + { "log-only", + 0, 2, TRUE, 0, + (ushort)0, + (ushort)CFG_DYNAMIC, + "Log messages only go to system logger, not console" }, + + { "identify-self", + 0, 2, TRUE, 0, + (ushort)0, + (ushort)CFG_REBOOT, + "Driver startup will report driver version and release information" }, + + { "num-iocbs", + LPFC_MIN_NUM_IOCBS, LPFC_MAX_NUM_IOCBS, LPFC_DFT_NUM_IOCBS, 0, + (ushort)0, + (ushort)CFG_RESTART, + "Number of outstanding IOCBs driver can queue to adapter" }, + + { "num-bufs", + LPFC_MIN_NUM_BUFS, LPFC_MAX_NUM_BUFS, LPFC_DFT_NUM_BUFS, 0, + (ushort)0, + (ushort)CFG_RESTART, + "Number of buffers driver uses for ELS commands and Buffer Pointer Lists." }, + + /* FCP specific parameters */ + { "fcp-on", + 0, 1, TRUE, 0, + (ushort)0, + (ushort)CFG_REBOOT, + "Enable FCP processing" }, + + { "device-report", + 0, 1, TRUE, 0, + (ushort)0, + (ushort)CFG_RESTART, + "Driver will report FCP devices as it finds them" }, + + { "automap", + 0, 3, 2, 0, + (ushort)0, + (ushort)CFG_RESTART, + "Automatically bind FCP devices as they are discovered" }, + + { "tgt-queue-depth", + 0, LPFC_MAX_TGT_Q_DEPTH, LPFC_DFT_TGT_Q_DEPTH, 0, + (ushort)0, + (ushort)CFG_RESTART, + "Max number of FCP commands we can queue to a specific target" }, + + { "lun-queue-depth", + 0, LPFC_MAX_LUN_Q_DEPTH, LPFC_DFT_LUN_Q_DEPTH, 0, + (ushort)0, + (ushort)CFG_RESTART, + "Max number of FCP commands we can queue to a specific LUN" }, + + { "first-check", + 0, 1, + FALSE, + 0, + (ushort)0, + (ushort)CFG_DYNAMIC, + "Retry the first 29xx check condition for FCP devices during discovery" }, + + { "fcpfabric-tmo", + 0, LPFC_MAX_FABRIC_TIMEOUT, LPFC_DFT_FABRIC_TIMEOUT, 0, + (ushort)0, + (ushort)CFG_DYNAMIC, + "Extra FCP command timeout when connected to a fabric" }, + + { "fcp-class", + 2, 3, LPFC_DFT_FC_CLASS, 0, + (ushort)0, + (ushort)CFG_DYNAMIC, + "Select Fibre Channel class of service for FCP sequences" }, + + { "use-adisc", + 0, 1, FALSE, 0, + (ushort)0, + (ushort)CFG_DYNAMIC, + "Use ADISC on rediscovery to authenticate FCP devices" }, + + { "no-device-delay", + 0, LPFC_MAX_NO_DEVICE_DELAY, LPFC_DFT_NO_DEVICE_DELAY, 0, + (ushort)0, + (ushort)CFG_DYNAMIC, + "No FCP device failed I/O sec delay" }, + + /* IP specific parameters */ + { "network-on", + 0, 1, FALSE, 0, + (ushort)0, + (ushort)CFG_REBOOT, + "Enable IP processing" }, + + { "post-ip-buf", + LPFC_MIN_POST_IP_BUF, LPFC_MAX_POST_IP_BUF, LPFC_DFT_POST_IP_BUF, 0, + (ushort)0, + (ushort)CFG_RESTART, + "Number of IP buffers to post to adapter" }, + + { "xmt-que-size", + LPFC_MIN_XMT_QUE_SIZE, LPFC_MAX_XMT_QUE_SIZE, LPFC_DFT_XMT_QUE_SIZE, 0, + (ushort)0, + (ushort)CFG_RESTART, + "Number of outstanding IP cmds for an adapter" }, + + { "ip-class", + 2, 3, LPFC_DFT_FC_CLASS, 0, + (ushort)0, + (ushort)CFG_DYNAMIC, + "Select Fibre Channel class of service for IP sequences" }, + + /* Fibre Channel specific parameters */ + { "ack0", + 0, 1, FALSE, 0, + (ushort)0, + (ushort)CFG_RESTART, + "Enable ACK0 support" }, + + { "topology", + 0, 6, LPFC_DFT_TOPOLOGY, 0, + (ushort)0, + (ushort)CFG_RESTART, + "Select Fibre Channel topology" }, + + { "scan-down", + 0, 2, 2, 0, + (ushort)0, + (ushort)CFG_DYNAMIC, + "Start scanning for devices from highest ALPA to lowest" }, + + { "linkdown-tmo", + 0, LPFC_MAX_LNKDWN_TIMEOUT, LPFC_DFT_LNKDWN_TIMEOUT, 0, + (ushort)0, + (ushort)CFG_DYNAMIC, + "Seconds driver will wait before deciding link is really down" }, + + { "use-lomempages", + 0, 1, FALSE, 0, + (ushort)0, + (ushort)CFG_RESTART, + "Use low memory for adapter DMA buffers" }, + + { "zone-rscn", + 0, 1, FALSE, 0, + (ushort)0, + (ushort)CFG_DYNAMIC, + "Force RSCNs to always check NameServer for N_Port IDs" }, + + { "nodev-holdio", + 0, 1, FALSE, 0, + (ushort)0, + (ushort)CFG_DYNAMIC, + "Hold I/O errors if device disappears " }, + + { "delay-rsp-err", + 0, 1, FALSE, 0, + (ushort)0, + (ushort)CFG_DYNAMIC, + "Delay FCP error return for FCP RSP error and Check Condition" }, + + { "check-cond-err", + 0, 1, FALSE, 0, + (ushort)0, + (ushort)CFG_DYNAMIC, + "Treat special Check Conditions as a FCP error" }, + + { "nodev-tmo", + 0, LPFC_MAX_NODEV_TIMEOUT, LPFC_DFT_NODEV_TIMEOUT, 0, + (ushort)0, + (ushort)CFG_DYNAMIC, + "Seconds driver will hold I/O waiting for a device to come back" }, + + { "dqfull-throttle", + 0, 1, 1, 0, + (ushort)0, + (ushort)CFG_DYNAMIC, + "Decrement LUN throttle on a queue full condition" }, + + { "link-speed", + 0, 2, 0, 0, + (ushort)0, + (ushort)CFG_RESTART, + "Select link speed" }, + + { "qfull-rsp-err", + 0, 1, FALSE, 0, + (ushort)0, + (ushort)CFG_DYNAMIC, + "Return BUSY (default) or TERMINATED as SCSI status on a queue full condition" }, + + { "dqfull-throttle-up-time", + 0, 30, 1, 0, + (ushort)0, + (ushort)CFG_RESTART, + "When to increment the current Q depth " }, + + { "dqfull-throttle-up-inc", + 0, LPFC_MAX_LUN_Q_DEPTH, 1, 0, + (ushort)0, + (ushort)CFG_RESTART, + "Increment the current Q depth by dqfull-throttle-up-inc" }, + + { "num-nodes", + LPFC_MIN_NUM_NODES, LPFC_MAX_NUM_NODES, LPFC_DFT_NUM_NODES, 0, + (ushort)0, + (ushort)CFG_RESTART, + "Number of fibre channel nodes (NPorts) the driver will support." }, + + { "cr-delay", + 0, 63, 0, 0, + (ushort)0, + (ushort)CFG_RESTART, + "A count of milliseconds after which an interrupt response is generated" }, + + { "cr-count", + 1, 255, 0, 0, + (ushort)0, + (ushort)CFG_RESTART, + "A count of I/O completions after which an interrupt response is generated" }, + + }; +#endif /* DEF_ICFG */ + +#endif /* _H_CFGPARAM */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/fcmboxb.c 830-ivtv/drivers/scsi/lpfc/fcmboxb.c --- 000-virgin/drivers/scsi/lpfc/fcmboxb.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/fcmboxb.c Thu Jan 8 10:21:53 2004 @@ -0,0 +1,1013 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Enterprise Fibre Channel Host Bus Adapters. * + * Refer to the README file included with this package for * + * driver version and adapter support. * + * Copyright (C) 2003 Emulex Corporation. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details, a copy of which * + * can be found in the file COPYING included with this package. * + *******************************************************************/ + +#include "fc_os.h" + +#include "fc_hw.h" +#include "fc.h" + +#include "fcdiag.h" +#include "fcfgparm.h" +#include "fcmsg.h" +#include "fc_crtn.h" +#include "fc_ertn.h" + +extern fc_dd_ctl_t DD_CTL; +extern iCfgParam icfgparam[]; + +/* Routine Declaration - Local */ +/* There currently are no local routine declarations */ +/* End Routine Declaration - Local */ + + +/**********************************************/ +/** fc_restart Issue a RESTART **/ +/** mailbox command **/ +/**********************************************/ +_static_ void +fc_restart( +FC_BRD_INFO *binfo, +MAILBOX *mb, +int doit) +{ + void *ioa; + MAILBOX * mbox; + fc_dev_ctl_t *p_dev_ctl; + + fc_bzero((void *)mb, sizeof(MAILBOXQ)); + mb->mbxCommand = MBX_RESTART; + mb->mbxHc = OWN_CHIP; + mb->mbxOwner = OWN_HOST; + + if (doit) { + /* use REAL SLIM !!! */ + p_dev_ctl = (fc_dev_ctl_t *)(binfo->fc_p_dev_ctl); + binfo->fc_mboxaddr = 0; + binfo->fc_flag &= ~FC_SLI2; + + ioa = (void *)FC_MAP_MEM(&binfo->fc_iomap_mem); /* map in SLIM */ + mbox = FC_MAILBOX(binfo, ioa); + WRITE_SLIM_COPY(binfo, (uint32 *)&mb->un.varWords, (uint32 *)&mbox->un.varWords, + (MAILBOX_CMD_WSIZE - 1)); + FC_UNMAP_MEMIO(ioa); + } + return; +} /* End fc_restart */ + + +/**********************************************/ +/** fc_dump_mem Issue a DUMP MEMORY **/ +/** mailbox command **/ +/**********************************************/ +_static_ void +fc_dump_mem( +FC_BRD_INFO *binfo, +MAILBOX *mb) +{ + /* Setup to dump VPD region */ + fc_bzero((void *)mb, sizeof(MAILBOXQ)); + mb->mbxCommand = MBX_DUMP_MEMORY; + mb->un.varDmp.cv = 1; + mb->un.varDmp.type = DMP_NV_PARAMS; + mb->un.varDmp.region_id = DMP_REGION_VPD; + mb->un.varDmp.word_cnt = (DMP_VPD_SIZE / sizeof(uint32)); + + mb->un.varDmp.co = 0; + mb->un.varDmp.resp_offset = 0; + mb->mbxOwner = OWN_HOST; + return; +} /* End fc_dump_mem */ + + +/**********************************************/ +/** fc_read_nv Issue a READ NVPARAM **/ +/** mailbox command **/ +/**********************************************/ +_static_ void +fc_read_nv( +FC_BRD_INFO *binfo, +MAILBOX *mb) +{ + fc_bzero((void *)mb, sizeof(MAILBOXQ)); + mb->mbxCommand = MBX_READ_NV; + mb->mbxOwner = OWN_HOST; + return; +} /* End fc_read_nv */ + +/**********************************************/ +/** fc_read_rev Issue a READ REV **/ +/** mailbox command **/ +/**********************************************/ +_static_ void +fc_read_rev( +FC_BRD_INFO *binfo, +MAILBOX *mb) +{ + fc_bzero((void *)mb, sizeof(MAILBOXQ)); + mb->un.varRdRev.cv = 1; + mb->mbxCommand = MBX_READ_REV; + mb->mbxOwner = OWN_HOST; + return; +} /* End fc_read_rev */ + +/**********************************************/ +/** fc_runBIUdiag Issue a RUN_BIU_DIAG **/ +/** mailbox command **/ +/**********************************************/ +_static_ int +fc_runBIUdiag( +FC_BRD_INFO *binfo, +MAILBOX *mb, +uchar *in, +uchar *out) +{ + fc_bzero((void *)mb, sizeof(MAILBOXQ)); + + if (binfo->fc_flag & FC_SLI2) { + mb->mbxCommand = MBX_RUN_BIU_DIAG64; + mb->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeSize = FCELSSIZE; + mb->un.varBIUdiag.un.s2.xmit_bde64.addrHigh = (uint32)putPaddrHigh(in); + mb->un.varBIUdiag.un.s2.xmit_bde64.addrLow = (uint32)putPaddrLow(in); + mb->un.varBIUdiag.un.s2.rcv_bde64.tus.f.bdeSize = FCELSSIZE; + mb->un.varBIUdiag.un.s2.rcv_bde64.addrHigh = (uint32)putPaddrHigh(out); + mb->un.varBIUdiag.un.s2.rcv_bde64.addrLow = (uint32)putPaddrLow(out); + } else { + mb->mbxCommand = MBX_RUN_BIU_DIAG; + mb->un.varBIUdiag.un.s1.xmit_bde.bdeSize = FCELSSIZE; + mb->un.varBIUdiag.un.s1.xmit_bde.bdeAddress = (uint32)putPaddrLow(in); + mb->un.varBIUdiag.un.s1.rcv_bde.bdeSize = FCELSSIZE; + mb->un.varBIUdiag.un.s1.rcv_bde.bdeAddress = (uint32)putPaddrLow(out); + } + + mb->mbxOwner = OWN_HOST; + return(0); +} /* End fc_runBIUdiag */ + + +/**********************************************/ +/** fc_read_la Issue a READ LA **/ +/** mailbox command **/ +/**********************************************/ +_static_ int +fc_read_la( +fc_dev_ctl_t *p_dev_ctl, +MAILBOX *mb) +{ + FC_BRD_INFO * binfo; + MATCHMAP * mp; + + binfo = &BINFO; + fc_bzero((void *)mb, sizeof(MAILBOXQ)); + + if ((mp = (MATCHMAP * )fc_mem_get(binfo, MEM_BUF)) == 0) { + + if (binfo->fc_flag & FC_SLI2) + mb->mbxCommand = MBX_READ_LA64; + else + mb->mbxCommand = MBX_READ_LA; + /* READ_LA: no buffers */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0300, /* ptr to msg structure */ + fc_mes0300, /* ptr to msg */ + fc_msgBlk0300.msgPreambleStr); /* begin & end varargs */ + return(1); + } + + if (binfo->fc_flag & FC_SLI2) { + mb->mbxCommand = MBX_READ_LA64; + mb->un.varReadLA.un.lilpBde64.tus.f.bdeSize = 128; + mb->un.varReadLA.un.lilpBde64.addrHigh = (uint32)putPaddrHigh(mp->phys); + mb->un.varReadLA.un.lilpBde64.addrLow = (uint32)putPaddrLow(mp->phys); + } else { + mb->mbxCommand = MBX_READ_LA; + mb->un.varReadLA.un.lilpBde.bdeSize = 128; + mb->un.varReadLA.un.lilpBde.bdeAddress = (uint32)putPaddrLow(mp->phys); + } + + /* save address for completion */ + ((MAILBOXQ * )mb)->bp = (uchar * )mp; + + mb->mbxOwner = OWN_HOST; + return(0); +} /* End fc_read_la */ + + +/**********************************************/ +/** fc_clear_la Issue a CLEAR LA **/ +/** mailbox command **/ +/**********************************************/ +_static_ void +fc_clear_la( +FC_BRD_INFO *binfo, +MAILBOX *mb) +{ + fc_bzero((void *)mb, sizeof(MAILBOXQ)); + mb->un.varClearLA.eventTag = binfo->fc_eventTag; + mb->mbxCommand = MBX_CLEAR_LA; + mb->mbxOwner = OWN_HOST; + return; +} /* End fc_clear_la */ + + +/**********************************************/ +/** fc_read_status Issue a READ STATUS **/ +/** mailbox command **/ +/**********************************************/ +_static_ void +fc_read_status( +FC_BRD_INFO *binfo, +MAILBOX *mb) +{ + fc_bzero((void *)mb, sizeof(MAILBOXQ)); + mb->mbxCommand = MBX_READ_STATUS; + mb->mbxOwner = OWN_HOST; + return; +} /* End fc_read_status */ + +/**********************************************/ +/** fc_read_lnk_stat Issue a LINK STATUS **/ +/** mailbox command **/ +/**********************************************/ +_static_ void +fc_read_lnk_stat( +FC_BRD_INFO *binfo, +MAILBOX *mb) +{ + fc_bzero((void *)mb, sizeof(MAILBOXQ)); + mb->mbxCommand = MBX_READ_LNK_STAT; + mb->mbxOwner = OWN_HOST; + return; +} /* End fc_read_lnk_stat */ + + +/**************************************************/ +/** fc_config_ring Issue a CONFIG RING **/ +/** mailbox command **/ +/**************************************************/ +_static_ void +fc_config_ring( +FC_BRD_INFO *binfo, +int ring, +int profile, +MAILBOX *mb) +{ + int i; + int j; + + fc_bzero((void *)mb, sizeof(MAILBOXQ)); + mb->un.varCfgRing.ring = ring; + mb->un.varCfgRing.profile = profile; + mb->un.varCfgRing.maxOrigXchg = 0; + mb->un.varCfgRing.maxRespXchg = 0; + mb->un.varCfgRing.recvNotify = 1; + mb->un.varCfgRing.numMask = binfo->fc_nummask[ring]; + + j = 0; + for (i = 0; i < ring; i++) + j += binfo->fc_nummask[i]; + + for (i = 0; i < binfo->fc_nummask[ring]; i++) { + mb->un.varCfgRing.rrRegs[i].rval = binfo->fc_rval[j + i]; + if (mb->un.varCfgRing.rrRegs[i].rval != FC_ELS_REQ) /* ELS request */ + mb->un.varCfgRing.rrRegs[i].rmask = 0xff; + else + mb->un.varCfgRing.rrRegs[i].rmask = 0xfe; + mb->un.varCfgRing.rrRegs[i].tval = binfo->fc_tval[j + i]; + mb->un.varCfgRing.rrRegs[i].tmask = 0xff; + } + + mb->mbxCommand = MBX_CONFIG_RING; + mb->mbxOwner = OWN_HOST; + return; +} /* End fc_config_ring */ + + +/**************************************************/ +/** fc_config_link Issue a CONFIG LINK **/ +/** mailbox command **/ +/**************************************************/ +_static_ void +fc_config_link( +fc_dev_ctl_t *p_dev_ctl, +MAILBOX *mb) +{ + FC_BRD_INFO * binfo; + iCfgParam * clp; + + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + fc_bzero((void *)mb, sizeof(MAILBOXQ)); + + if(clp[CFG_CR_DELAY].a_current) { + mb->un.varCfgLnk.cr = 1; + mb->un.varCfgLnk.ci = 1; + mb->un.varCfgLnk.cr_delay = clp[CFG_CR_DELAY].a_current; + mb->un.varCfgLnk.cr_count = clp[CFG_CR_COUNT].a_current; + } + + mb->un.varCfgLnk.myId = binfo->fc_myDID; + mb->un.varCfgLnk.edtov = binfo->fc_edtov; + mb->un.varCfgLnk.arbtov = binfo->fc_arbtov; + mb->un.varCfgLnk.ratov = binfo->fc_ratov; + mb->un.varCfgLnk.rttov = binfo->fc_rttov; + mb->un.varCfgLnk.altov = binfo->fc_altov; + mb->un.varCfgLnk.crtov = binfo->fc_crtov; + mb->un.varCfgLnk.citov = binfo->fc_citov; + if(clp[CFG_ACK0].a_current) + mb->un.varCfgLnk.ack0_enable = 1; + + mb->mbxCommand = MBX_CONFIG_LINK; + mb->mbxOwner = OWN_HOST; + return; +} /* End fc_config_link */ + + +/**********************************************/ +/** fc_init_link Issue an INIT LINK **/ +/** mailbox command **/ +/**********************************************/ +_static_ void +fc_init_link( +FC_BRD_INFO *binfo, +MAILBOX *mb, +uint32 topology, +uint32 linkspeed) +{ + iCfgParam * clp; + fc_vpd_t * vpd; + + clp = DD_CTL.p_config[binfo->fc_brd_no]; + fc_bzero((void *)mb, sizeof(MAILBOXQ)); + + switch (topology) { + case FLAGS_TOPOLOGY_MODE_LOOP_PT: + mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_LOOP; + mb->un.varInitLnk.link_flags |= FLAGS_TOPOLOGY_FAILOVER; + break; + case FLAGS_TOPOLOGY_MODE_PT_PT: + mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_PT_PT; + break; + case FLAGS_TOPOLOGY_MODE_LOOP: + mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_LOOP; + break; + case FLAGS_TOPOLOGY_MODE_PT_LOOP: + mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_PT_PT; + mb->un.varInitLnk.link_flags |= FLAGS_TOPOLOGY_FAILOVER; + break; + } + + vpd = &((fc_dev_ctl_t *)(binfo->fc_p_dev_ctl))->vpd; + if (binfo->fc_flag & FC_2G_CAPABLE) { + if ((vpd->rev.feaLevelHigh >= 0x02) && (linkspeed > 0)) { + mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED; + mb->un.varInitLnk.link_speed = linkspeed; + } + } + + mb->mbxCommand = (volatile uchar)MBX_INIT_LINK; + mb->mbxOwner = OWN_HOST; + mb->un.varInitLnk.fabric_AL_PA = binfo->fc_pref_ALPA; + return; +} /* End fc_init_link */ + + +/**********************************************/ +/** fc_down_link Issue a DOWN LINK **/ +/** mailbox command **/ +/**********************************************/ +_static_ void +fc_down_link( +FC_BRD_INFO *binfo, +MAILBOX *mb) +{ + fc_bzero((void *)mb, sizeof(MAILBOXQ)); + + mb->mbxCommand = MBX_DOWN_LINK; + mb->mbxOwner = OWN_HOST; + return; +} + + +/**********************************************/ +/** fc_read_sparam Issue a READ SPARAM **/ +/** mailbox command **/ +/**********************************************/ +_static_ int +fc_read_sparam( +fc_dev_ctl_t *p_dev_ctl, +MAILBOX *mb) +{ + FC_BRD_INFO * binfo; + MATCHMAP * mp; + + binfo = &BINFO; + fc_bzero((void *)mb, sizeof(MAILBOXQ)); + + mb->mbxOwner = OWN_HOST; + + if ((mp = (MATCHMAP * )fc_mem_get(binfo, MEM_BUF)) == 0) { + + if (binfo->fc_flag & FC_SLI2) + mb->mbxCommand = MBX_READ_SPARM64; + else + mb->mbxCommand = MBX_READ_SPARM; + /* READ_SPARAM: no buffers */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0301, /* ptr to msg structure */ + fc_mes0301, /* ptr to msg */ + fc_msgBlk0301.msgPreambleStr); /* begin & end varargs */ + return(1); + } + + if (binfo->fc_flag & FC_SLI2) { + mb->mbxCommand = MBX_READ_SPARM64; + mb->un.varRdSparm.un.sp64.tus.f.bdeSize = sizeof(SERV_PARM); + mb->un.varRdSparm.un.sp64.addrHigh = (uint32)putPaddrHigh(mp->phys); + mb->un.varRdSparm.un.sp64.addrLow = (uint32)putPaddrLow(mp->phys); + } else { + mb->mbxCommand = MBX_READ_SPARM; + mb->un.varRdSparm.un.sp.bdeSize = sizeof(SERV_PARM); + mb->un.varRdSparm.un.sp.bdeAddress = (uint32)putPaddrLow(mp->phys); + } + + /* save address for completion */ + ((MAILBOXQ * )mb)->bp = (uchar * )mp; + + return(0); +} /* End fc_read_sparam */ + + +/**********************************************/ +/** fc_read_rpi Issue a READ RPI **/ +/** mailbox command **/ +/**********************************************/ +_static_ int +fc_read_rpi( +FC_BRD_INFO *binfo, +uint32 rpi, +MAILBOX *mb, +uint32 flag) +{ + fc_bzero((void *)mb, sizeof(MAILBOXQ)); + + mb->un.varRdRPI.reqRpi = (volatile ushort)rpi; + + if (binfo->fc_flag & FC_SLI2) { + mb->mbxCommand = MBX_READ_RPI64; + } else { + mb->mbxCommand = MBX_READ_RPI; + } + + mb->mbxOwner = OWN_HOST; + + mb->un.varWords[30] = flag; /* Set flag to issue action on cmpl */ + + return(0); +} /* End fc_read_rpi */ + + +/**********************************************/ +/** fc_read_xri Issue a READ XRI **/ +/** mailbox command **/ +/**********************************************/ +_static_ int +fc_read_xri( +FC_BRD_INFO *binfo, +uint32 xri, +MAILBOX *mb, +uint32 flag) +{ + fc_bzero((void *)mb, sizeof(MAILBOXQ)); + + mb->un.varRdXRI.reqXri = (volatile ushort)xri; + + mb->mbxCommand = MBX_READ_XRI; + mb->mbxOwner = OWN_HOST; + + mb->un.varWords[30] = flag; /* Set flag to issue action on cmpl */ + + return(0); +} /* End fc_read_xri */ + + +/**********************************************/ +/** fc_reg_login Issue a REG_LOGIN **/ +/** mailbox command **/ +/**********************************************/ +_static_ int +fc_reg_login( +FC_BRD_INFO *binfo, +uint32 did, +uchar *param, +MAILBOX *mb, +uint32 flag) +{ + uchar * sparam; + MATCHMAP * mp; + fc_dev_ctl_t *p_dev_ctl; + + fc_bzero((void *)mb, sizeof(MAILBOXQ)); + + mb->un.varRegLogin.rpi = 0; + mb->un.varRegLogin.did = did; + mb->un.varWords[30] = flag; /* Set flag to issue action on cmpl */ + + mb->mbxOwner = OWN_HOST; + + if ((mp = (MATCHMAP * )fc_mem_get(binfo, MEM_BUF)) == 0) { + + if (binfo->fc_flag & FC_SLI2) + mb->mbxCommand = MBX_REG_LOGIN64; + else + mb->mbxCommand = MBX_REG_LOGIN; + /* REG_LOGIN: no buffers */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0302, /* ptr to msg structure */ + fc_mes0302, /* ptr to msg */ + fc_msgBlk0302.msgPreambleStr, /* begin varargs */ + (uint32)did, + (uint32)flag); /* end varargs */ + return(1); + } + + sparam = mp->virt; + + /* Copy param's into a new buffer */ + fc_bcopy((void *)param, (void *)sparam, sizeof(SERV_PARM)); + + p_dev_ctl = (fc_dev_ctl_t *)(binfo->fc_p_dev_ctl); + fc_mpdata_sync(mp->dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV); + + /* save address for completion */ + ((MAILBOXQ * )mb)->bp = (uchar * )mp; + + if (binfo->fc_flag & FC_SLI2) { + mb->mbxCommand = MBX_REG_LOGIN64; + mb->un.varRegLogin.un.sp64.tus.f.bdeSize = sizeof(SERV_PARM); + mb->un.varRegLogin.un.sp64.addrHigh = (uint32)putPaddrHigh(mp->phys); + mb->un.varRegLogin.un.sp64.addrLow = (uint32)putPaddrLow(mp->phys); + } else { + mb->mbxCommand = MBX_REG_LOGIN; + mb->un.varRegLogin.un.sp.bdeSize = sizeof(SERV_PARM); + mb->un.varRegLogin.un.sp.bdeAddress = (uint32)putPaddrLow(mp->phys); + } + + return(0); +} /* End fc_reg_login */ + + +/**********************************************/ +/** fc_unreg_login Issue a UNREG_LOGIN **/ +/** mailbox command **/ +/**********************************************/ +_static_ void +fc_unreg_login( +FC_BRD_INFO *binfo, +uint32 rpi, +MAILBOX *mb) +{ + fc_bzero((void *)mb, sizeof(MAILBOXQ)); + + mb->un.varUnregLogin.rpi = (ushort)rpi; + mb->un.varUnregLogin.rsvd1 = 0; + + mb->mbxCommand = MBX_UNREG_LOGIN; + mb->mbxOwner = OWN_HOST; + return; +} /* End fc_unreg_login */ + + +/**********************************************/ +/** fc_unreg_did Issue a UNREG_DID **/ +/** mailbox command **/ +/**********************************************/ +_static_ void +fc_unreg_did( +FC_BRD_INFO *binfo, +uint32 did, +MAILBOX *mb) +{ + fc_bzero((void *)mb, sizeof(MAILBOXQ)); + + mb->un.varUnregDID.did = did; + + mb->mbxCommand = MBX_UNREG_D_ID; + mb->mbxOwner = OWN_HOST; + return; +} /* End fc_unreg_did */ + + +/**********************************************/ +/** fc_set_slim Issue a special debug mbox */ +/** command to write slim */ +/**********************************************/ +_static_ void +fc_set_slim( +FC_BRD_INFO *binfo, +MAILBOX *mb, +uint32 addr, +uint32 value) +{ + fc_bzero((void *)mb, sizeof(MAILBOXQ)); + + /* addr = 0x090597 is AUTO ABTS disable for ELS commands */ + /* addr = 0x052198 is DELAYED ABTS enable for ELS commands */ + + /* + * Always turn on DELAYED ABTS for ELS timeouts + */ + if ((addr == 0x052198) && (value == 0)) + value = 1; + + mb->un.varWords[0] = addr; + mb->un.varWords[1] = value; + + mb->mbxCommand = MBX_SET_SLIM; + mb->mbxOwner = OWN_HOST; + return; +} /* End fc_set_slim */ + + +/* Disable Traffic Cop */ +_static_ void +fc_disable_tc( +FC_BRD_INFO *binfo, +MAILBOX *mb) +{ + fc_bzero((void *)mb, sizeof(MAILBOXQ)); + mb->un.varWords[0] = 0x50797; + mb->un.varWords[1] = 0; + mb->un.varWords[2] = 0xfffffffe; + + mb->mbxCommand = MBX_SET_SLIM; + mb->mbxOwner = OWN_HOST; +} /* End fc_set_tc */ + + +/**********************************************/ +/** fc_config_port Issue a CONFIG_PORT **/ +/** mailbox command **/ +/**********************************************/ +_static_ int +fc_config_port( +FC_BRD_INFO *binfo, +MAILBOX *mb, +uint32 *hbainit) +{ + RING * rp; + fc_dev_ctl_t * p_dev_ctl; + iCfgParam * clp; + int ring_3_active; /* 4th ring */ + struct pci_dev *pdev; + + p_dev_ctl = (fc_dev_ctl_t *)(binfo->fc_p_dev_ctl); + pdev = p_dev_ctl->pcidev ; + + clp = DD_CTL.p_config[binfo->fc_brd_no]; + fc_bzero((void *)mb, sizeof(MAILBOXQ)); + + mb->mbxCommand = MBX_CONFIG_PORT; + mb->mbxOwner = OWN_HOST; + + ring_3_active = 0; /* Preset to inactive */ + + mb->un.varCfgPort.pcbLen = sizeof(PCB); + mb->un.varCfgPort.pcbLow = + (uint32)putPaddrLow( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->pcb); + mb->un.varCfgPort.pcbHigh = + (uint32)putPaddrHigh( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->pcb); + if((pdev->device == PCI_DEVICE_ID_TFLY)|| + (pdev->device == PCI_DEVICE_ID_PFLY)) + fc_bcopy((uchar*) hbainit, (uchar*) mb->un.varCfgPort.hbainit, 20); + else + fc_bcopy((uchar*) hbainit, (uchar*) mb->un.varCfgPort.hbainit, 4); + + /* Now setup pcb */ + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.type = TYPE_NATIVE_SLI2; + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.feature = FEATURE_INITIAL_SLI2; + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.maxRing = (binfo->fc_ffnumrings-1); + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.mailBoxSize = sizeof(MAILBOX); + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.mbAddrHigh = (uint32) + putPaddrHigh( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->mbx); + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.mbAddrLow = (uint32) + putPaddrLow( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->mbx); + + /* SLIM POINTER */ + if (binfo->fc_busflag & FC_HOSTPTR) { + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.hgpAddrHigh = (uint32) + putPaddrHigh( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->mbx.us.s2.host); + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.hgpAddrLow = (uint32) + putPaddrLow( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->mbx.us.s2.host); + } else { + uint32 Laddr; + + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.hgpAddrHigh = (uint32) + fc_rdpci_32((fc_dev_ctl_t *)binfo->fc_p_dev_ctl, PCI_BAR_1_REGISTER); + Laddr = fc_rdpci_32((fc_dev_ctl_t *)binfo->fc_p_dev_ctl, PCI_BAR_0_REGISTER); + Laddr &= ~0x4; + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.hgpAddrLow = (uint32)(Laddr + (SLIMOFF*4)); + } + + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.pgpAddrHigh = (uint32) + putPaddrHigh( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->mbx.us.s2.port); + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.pgpAddrLow = (uint32) + putPaddrLow( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->mbx.us.s2.port); + + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[0].cmdEntries = SLI2_IOCB_CMD_R0_ENTRIES; + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[0].rspEntries = SLI2_IOCB_RSP_R0_ENTRIES; + if(clp[CFG_NETWORK_ON].a_current == 0) { + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[1].cmdEntries = + (SLI2_IOCB_CMD_R1_ENTRIES - SLI2_IOCB_CMD_R1XTRA_ENTRIES); + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[1].rspEntries = + (SLI2_IOCB_RSP_R1_ENTRIES - SLI2_IOCB_RSP_R1XTRA_ENTRIES); + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[2].cmdEntries = + (SLI2_IOCB_CMD_R2_ENTRIES + SLI2_IOCB_CMD_R2XTRA_ENTRIES); + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[2].rspEntries = + (SLI2_IOCB_RSP_R2_ENTRIES + SLI2_IOCB_RSP_R2XTRA_ENTRIES); + } + else { + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[1].cmdEntries = SLI2_IOCB_CMD_R1_ENTRIES; + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[1].rspEntries = SLI2_IOCB_RSP_R1_ENTRIES; + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[2].cmdEntries = SLI2_IOCB_CMD_R2_ENTRIES; + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[2].rspEntries = SLI2_IOCB_RSP_R2_ENTRIES; + } + if( ring_3_active == 0) { + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[3].cmdEntries = 0; + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[3].rspEntries = 0; + } + + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[0].cmdAddrHigh = (uint32) + putPaddrHigh( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[0]); + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[0].cmdAddrLow = (uint32) + putPaddrLow( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[0]); + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[0].rspAddrHigh = (uint32) + putPaddrHigh( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[ + SLI2_IOCB_CMD_R0_ENTRIES]); + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[0].rspAddrLow = (uint32) + putPaddrLow( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[ + SLI2_IOCB_CMD_R0_ENTRIES]); + rp = &binfo->fc_ring[0]; + rp->fc_cmdringaddr = (void *) & ((SLI2_SLIM * )binfo->fc_slim2.virt)->IOCBs[0]; + rp->fc_rspringaddr = (void *) & ((SLI2_SLIM * )binfo->fc_slim2.virt)->IOCBs[ + SLI2_IOCB_CMD_R0_ENTRIES]; + + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[1].cmdAddrHigh = (uint32) + putPaddrHigh( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[ + SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES]); + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[1].cmdAddrLow = (uint32) + putPaddrLow( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[ + SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES]); + if(clp[CFG_NETWORK_ON].a_current == 0) { + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[1].rspAddrHigh = (uint32) + putPaddrHigh( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[ + SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + + SLI2_IOCB_CMD_R1_ENTRIES - SLI2_IOCB_CMD_R1XTRA_ENTRIES]); + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[1].rspAddrLow = (uint32) + putPaddrLow( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[ + SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + + SLI2_IOCB_CMD_R1_ENTRIES - SLI2_IOCB_CMD_R1XTRA_ENTRIES]); + rp = &binfo->fc_ring[1]; + rp->fc_cmdringaddr = (void *) & ((SLI2_SLIM * )binfo->fc_slim2.virt)->IOCBs[ + SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES]; + rp->fc_rspringaddr = (void *) & ((SLI2_SLIM * )binfo->fc_slim2.virt)->IOCBs[ + SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + + SLI2_IOCB_CMD_R1_ENTRIES - SLI2_IOCB_CMD_R1XTRA_ENTRIES]; + + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[2].cmdAddrHigh = (uint32) + putPaddrHigh( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[ + SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + + SLI2_IOCB_CMD_R1_ENTRIES + SLI2_IOCB_RSP_R1_ENTRIES - + SLI2_IOCB_CMD_R1XTRA_ENTRIES - SLI2_IOCB_RSP_R1XTRA_ENTRIES]); + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[2].cmdAddrLow = (uint32) + putPaddrLow( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[ + SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + + SLI2_IOCB_CMD_R1_ENTRIES + SLI2_IOCB_RSP_R1_ENTRIES - + SLI2_IOCB_CMD_R1XTRA_ENTRIES - SLI2_IOCB_RSP_R1XTRA_ENTRIES]); + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[2].rspAddrHigh = (uint32) + putPaddrHigh( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[ + SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + + SLI2_IOCB_CMD_R1_ENTRIES + SLI2_IOCB_RSP_R1_ENTRIES + + SLI2_IOCB_CMD_R2_ENTRIES + SLI2_IOCB_CMD_R2XTRA_ENTRIES - + SLI2_IOCB_CMD_R1XTRA_ENTRIES - SLI2_IOCB_RSP_R1XTRA_ENTRIES]); + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[2].rspAddrLow = (uint32) + putPaddrLow( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[ + SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + + SLI2_IOCB_CMD_R1_ENTRIES + SLI2_IOCB_RSP_R1_ENTRIES + + SLI2_IOCB_CMD_R2_ENTRIES + SLI2_IOCB_CMD_R2XTRA_ENTRIES - + SLI2_IOCB_CMD_R1XTRA_ENTRIES - SLI2_IOCB_RSP_R1XTRA_ENTRIES]); + rp = &binfo->fc_ring[2]; + rp->fc_cmdringaddr = (void *) & ((SLI2_SLIM * )binfo->fc_slim2.virt)->IOCBs[ + SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + + SLI2_IOCB_CMD_R1_ENTRIES + SLI2_IOCB_RSP_R1_ENTRIES - + SLI2_IOCB_CMD_R1XTRA_ENTRIES - SLI2_IOCB_RSP_R1XTRA_ENTRIES]; + rp->fc_rspringaddr = (void *) & ((SLI2_SLIM * )binfo->fc_slim2.virt)->IOCBs[ + SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + + SLI2_IOCB_CMD_R1_ENTRIES + SLI2_IOCB_RSP_R1_ENTRIES + + SLI2_IOCB_CMD_R2_ENTRIES + SLI2_IOCB_CMD_R2XTRA_ENTRIES - + SLI2_IOCB_CMD_R1XTRA_ENTRIES - SLI2_IOCB_RSP_R1XTRA_ENTRIES]; + } + else { + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[1].rspAddrHigh = (uint32) + putPaddrHigh( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[ + SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + + SLI2_IOCB_CMD_R1_ENTRIES]); + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[1].rspAddrLow = (uint32) + putPaddrLow( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[ + SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + + SLI2_IOCB_CMD_R1_ENTRIES]); + rp = &binfo->fc_ring[1]; + rp->fc_cmdringaddr = (void *) & ((SLI2_SLIM * )binfo->fc_slim2.virt)->IOCBs[ + SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES]; + rp->fc_rspringaddr = (void *) & ((SLI2_SLIM * )binfo->fc_slim2.virt)->IOCBs[ + SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + + SLI2_IOCB_CMD_R1_ENTRIES]; + + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[2].cmdAddrHigh = (uint32) + putPaddrHigh( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[ + SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + + SLI2_IOCB_CMD_R1_ENTRIES + SLI2_IOCB_RSP_R1_ENTRIES]); + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[2].cmdAddrLow = (uint32) + putPaddrLow( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[ + SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + + SLI2_IOCB_CMD_R1_ENTRIES + SLI2_IOCB_RSP_R1_ENTRIES]); + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[2].rspAddrHigh = (uint32) + putPaddrHigh( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[ + SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + + SLI2_IOCB_CMD_R1_ENTRIES + SLI2_IOCB_RSP_R1_ENTRIES + + SLI2_IOCB_CMD_R2_ENTRIES]); + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[2].rspAddrLow = (uint32) + putPaddrLow( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[ + SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + + SLI2_IOCB_CMD_R1_ENTRIES + SLI2_IOCB_RSP_R1_ENTRIES + + SLI2_IOCB_CMD_R2_ENTRIES]); + rp = &binfo->fc_ring[2]; + rp->fc_cmdringaddr = (void *) & ((SLI2_SLIM * )binfo->fc_slim2.virt)->IOCBs[ + SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + + SLI2_IOCB_CMD_R1_ENTRIES + SLI2_IOCB_RSP_R1_ENTRIES]; + rp->fc_rspringaddr = (void *) & ((SLI2_SLIM * )binfo->fc_slim2.virt)->IOCBs[ + SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + + SLI2_IOCB_CMD_R1_ENTRIES + SLI2_IOCB_RSP_R1_ENTRIES + + SLI2_IOCB_CMD_R2_ENTRIES]; + } + + if( ring_3_active == 0) { + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[3].cmdAddrHigh = 0; + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[3].rspAddrHigh = 0; + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[3].cmdAddrLow = 0; + ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[3].rspAddrLow = 0; + } + + fc_pcimem_bcopy((uint32 * )(&((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb), + (uint32 * )(&((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb), sizeof(PCB)); + + fc_mpdata_sync(binfo->fc_slim2.dma_handle, (off_t)0, (size_t)0, + DDI_DMA_SYNC_FORDEV); + /* Service Level Interface (SLI) 2 selected */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0405, /* ptr to msg structure */ + fc_mes0405, /* ptr to msg */ + fc_msgBlk0405.msgPreambleStr); /* begin & end varargs */ + return(0); +} /* End fc_config_port */ + +/**********************************************/ +/** fc_config_farp Issue a CONFIG FARP **/ +/** mailbox command **/ +/**********************************************/ +_static_ void +fc_config_farp( +FC_BRD_INFO *binfo, +MAILBOX *mb) +{ + fc_bzero((void *)mb, sizeof(MAILBOXQ)); + + mb->un.varCfgFarp.filterEnable = 1; + mb->un.varCfgFarp.portName = 1; + mb->un.varCfgFarp.nodeName = 1; + + fc_bcopy((uchar * )&binfo->fc_portname, (uchar *)&mb->un.varCfgFarp.portname, sizeof(NAME_TYPE)); + fc_bcopy((uchar * )&binfo->fc_portname, (uchar *)&mb->un.varCfgFarp.nodename, sizeof(NAME_TYPE)); + + mb->mbxCommand = MBX_CONFIG_FARP; + mb->mbxOwner = OWN_HOST; + return; +} + + +/**********************************************/ +/** fc_read_nv Issue a READ CONFIG **/ +/** mailbox command **/ +/**********************************************/ +_static_ void +fc_read_config( +FC_BRD_INFO *binfo, +MAILBOX *mb) +{ + fc_bzero((void *)mb, sizeof(MAILBOXQ)); + mb->mbxCommand = MBX_READ_CONFIG; + mb->mbxOwner = OWN_HOST; + return; +} /* End fc_read_config */ + +/*****************************************************************************/ +/* + * NAME: fc_mbox_put + * + * FUNCTION: put mailbox cmd onto the mailbox queue. + * + * EXECUTION ENVIRONMENT: process and interrupt level. + * + * NOTES: + * + * CALLED FROM: + * issue_mb_cmd + * + * INPUT: + * binfo - pointer to the device info area + * mbp - pointer to mailbox queue entry of mailbox cmd + * + * RETURNS: + * NULL - command queued + */ +/*****************************************************************************/ +_static_ void +fc_mbox_put( +FC_BRD_INFO *binfo, +MAILBOXQ *mbq) /* pointer to mbq entry */ +{ + if (binfo->fc_mbox.q_first) { + /* queue command to end of list */ + ((MAILBOXQ * )binfo->fc_mbox.q_last)->q = (uchar * )mbq; + binfo->fc_mbox.q_last = (uchar * )mbq; + } else { + /* add command to empty list */ + binfo->fc_mbox.q_first = (uchar * )mbq; + binfo->fc_mbox.q_last = (uchar * )mbq; + } + + mbq->q = NULL; + binfo->fc_mbox.q_cnt++; + + return; + +} /* End fc_mbox_put */ + + +/*****************************************************************************/ +/* + * NAME: fc_mbox_get + * + * FUNCTION: get a mailbox command from mailbox command queue + * + * EXECUTION ENVIRONMENT: interrupt level. + * + * NOTES: + * + * CALLED FROM: + * handle_mb_event + * + * INPUT: + * binfo - pointer to the device info area + * + * RETURNS: + * NULL - no match found + * mb pointer - pointer to a mailbox command + */ +/*****************************************************************************/ +_static_ MAILBOXQ * +fc_mbox_get( +FC_BRD_INFO *binfo) +{ + MAILBOXQ * p_first = NULL; + + if (binfo->fc_mbox.q_first) { + p_first = (MAILBOXQ * )binfo->fc_mbox.q_first; + if ((binfo->fc_mbox.q_first = p_first->q) == 0) { + binfo->fc_mbox.q_last = 0; + } + p_first->q = NULL; + binfo->fc_mbox.q_cnt--; + } + + return(p_first); + +} /* End fc_mbox_get */ + + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/fcmemb.c 830-ivtv/drivers/scsi/lpfc/fcmemb.c --- 000-virgin/drivers/scsi/lpfc/fcmemb.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/fcmemb.c Thu Jan 8 10:21:53 2004 @@ -0,0 +1,810 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Enterprise Fibre Channel Host Bus Adapters. * + * Refer to the README file included with this package for * + * driver version and adapter support. * + * Copyright (C) 2003 Emulex Corporation. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details, a copy of which * + * can be found in the file COPYING included with this package. * + *******************************************************************/ + +#include "fc_os.h" + +#include "fc_hw.h" +#include "fc.h" + +#include "fcdiag.h" +#include "fcfgparm.h" +#include "fcmsg.h" +#include "fc_crtn.h" /* Core - external routine definitions */ +#include "fc_ertn.h" /* Environment - external routine definitions */ + +extern uint32 fcPAGESIZE; +extern fc_dd_ctl_t DD_CTL; +extern iCfgParam icfgparam[]; +extern int fc_max_els_sent; + + +/* + * Define the following to Enable SANITY check logic in routines + * fc_getvaddr() and fc_mapvaddr(). + * #define FC_DBG_VADDR_SANITY_CHK + */ + +/* Routine Declaration - Local */ +/* There currently are no local routine declarations */ +/* End Routine Declaration - Local */ + +/***************************************************/ +/** fc_malloc_buffer **/ +/** **/ +/** This routine will allocate iocb/data buffer **/ +/** space and setup the buffers for all rings on **/ +/** the specified board to use. The data buffers **/ +/** can be posted to the ring with the **/ +/** fc_post_buffer routine. The iocb buffers **/ +/** are used to make a temp copy of the response **/ +/** ring iocbs. Returns 0 if not enough memory, **/ +/** Returns 1 if successful. **/ +/***************************************************/ +_static_ int +fc_malloc_buffer( +fc_dev_ctl_t *p_dev_ctl) +{ + FC_BRD_INFO * binfo = &BINFO; + iCfgParam * clp; + int i, j; + uchar * bp; + uchar * oldbp; + RING * rp; + MEMSEG * mp; + MATCHMAP * matp; + MBUF_INFO * buf_info; + MBUF_INFO bufinfo; + unsigned long iflag; + + buf_info = &bufinfo; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + + + for (i = 0; i < binfo->fc_ffnumrings; i++) { + rp = &binfo->fc_ring[i]; + rp->fc_mpon = 0; + rp->fc_mpoff = 0; + } + + if(clp[CFG_FCP_ON].a_current) { + buf_info->size = (MAX_FCP_CMDS * sizeof(void *)); + buf_info->flags = 0; + buf_info->align = sizeof(void *); + buf_info->dma_handle = 0; + + /* Create a table to relate FCP iotags to fc_buf addresses */ + fc_malloc(p_dev_ctl, buf_info); + if (buf_info->virt == NULL) { + fc_free_buffer(p_dev_ctl); + return(0); + } + binfo->fc_table = (FCPTBL * )buf_info->virt; + fc_bzero((char *)binfo->fc_table, MAX_FCP_CMDS * sizeof(void *)); + } + + /* Initialize xmit/receive buffer structure */ + /* Three buffers per response entry will initially be posted to ELS ring */ + iflag = lpfc_mempool_disable_lock(p_dev_ctl); + mp = &binfo->fc_memseg[MEM_BUF]; + mp->fc_memsize = FCELSSIZE; + if(clp[CFG_NUM_BUFS].a_current < 50) + mp->fc_numblks = 50; + else + mp->fc_numblks = (ushort)clp[CFG_NUM_BUFS].a_current; + + /* MEM_BUF is same pool as MEM_BPL */ + if (binfo->fc_sli == 2) + mp->fc_numblks += MAX_SLI2_IOCB; + + mp->fc_memflag = FC_MEM_DMA; + mp->fc_lowmem = (3 * fc_max_els_sent) + 8; + + if((2*mp->fc_lowmem) > mp->fc_numblks) + mp->fc_lowmem = (mp->fc_numblks / 2); + + /* Initialize mailbox cmd buffer structure */ + mp = &binfo->fc_memseg[MEM_MBOX]; + mp->fc_memsize = sizeof(MAILBOXQ); + mp->fc_numblks = (short)clp[CFG_NUM_NODES].a_current + 32; + mp->fc_memflag = 0; + mp->fc_lowmem = (2 * fc_max_els_sent) + 8; + + /* Initialize iocb buffer structure */ + mp = &binfo->fc_memseg[MEM_IOCB]; + mp->fc_memsize = sizeof(IOCBQ); + mp->fc_numblks = (ushort)clp[CFG_NUM_IOCBS].a_current + MIN_CLK_BLKS; + mp->fc_memflag = 0; + mp->fc_lowmem = (2 * fc_max_els_sent) + 8; + + /* Initialize iocb buffer structure */ + mp = &binfo->fc_memseg[MEM_NLP]; + mp->fc_memsize = sizeof(NODELIST); + mp->fc_numblks = (short)clp[CFG_NUM_NODES].a_current + 2; + mp->fc_memflag = 0; + mp->fc_lowmem = 0; + + + /* Allocate buffer pools for above buffer structures */ + for (j = 0; j < FC_MAX_SEG; j++) { + mp = &binfo->fc_memseg[j]; + + + mp->fc_memptr = 0; + mp->fc_endmemptr = 0; + mp->fc_memhi = 0; + mp->fc_memlo = 0; + + for (i = 0; i < mp->fc_numblks; i++) { + /* If this is a DMA buffer we need alignment on a page so we don't + * want to worry about buffers spanning page boundries when mapping + * memory for the adapter. + */ + if (mp->fc_memflag & FC_MEM_DMA) { + buf_info->size = sizeof(MATCHMAP); + buf_info->flags = 0; + buf_info->align = sizeof(void *); + buf_info->dma_handle = 0; + + fc_malloc(p_dev_ctl, buf_info); + if (buf_info->virt == NULL) { + lpfc_mempool_unlock_enable(p_dev_ctl, iflag); + fc_free_buffer(p_dev_ctl); + return(0); + } + + matp = (MATCHMAP * )buf_info->virt; + fc_bzero(matp, sizeof(MATCHMAP)); + if((ulong)matp > (ulong)(mp->fc_memhi)) + mp->fc_memhi = (uchar *)matp; + if(mp->fc_memlo == 0) + mp->fc_memlo = (uchar *)matp; + else { + if((ulong)matp < (ulong)(mp->fc_memlo)) + mp->fc_memlo = (uchar *)matp; + } + + buf_info->size = mp->fc_memsize; + buf_info->flags = FC_MBUF_DMA; + buf_info->dma_handle = 0; + + switch (mp->fc_memsize) { + case sizeof(FCP_CMND): + buf_info->align = sizeof(FCP_CMND); + break; + + case 1024: + buf_info->align = 1024; + break; + + case 2048: + buf_info->align = 2048; + break; + + case 4096: + buf_info->align = 4096; + break; + + default: + buf_info->align = sizeof(void *); + break; + } + + fc_malloc(p_dev_ctl, buf_info); + if (buf_info->virt == NULL) { + fc_free_buffer(p_dev_ctl); + return(0); + } + bp = (uchar * )buf_info->virt; + fc_bzero(bp, mp->fc_memsize); + + /* Link buffer into beginning of list. The first pointer in + * each buffer is a forward pointer to the next buffer. + */ + oldbp = mp->fc_memptr; + if(oldbp == 0) + mp->fc_endmemptr = (uchar *)matp; + mp->fc_memptr = (uchar * )matp; + matp->fc_mptr = oldbp; + matp->virt = bp; + if (buf_info->dma_handle) { + matp->dma_handle = buf_info->dma_handle; + matp->data_handle = buf_info->data_handle; + } + matp->phys = (uchar * )buf_info->phys; + } else { + buf_info->size = mp->fc_memsize; + buf_info->flags = 0; + buf_info->align = sizeof(void *); + buf_info->dma_handle = 0; + + fc_malloc(p_dev_ctl, buf_info); + if (buf_info->virt == NULL) { + lpfc_mempool_unlock_enable(p_dev_ctl, iflag); + fc_free_buffer(p_dev_ctl); + return(0); + } + bp = (uchar * )buf_info->virt; + fc_bzero(bp, mp->fc_memsize); + if((ulong)bp > (ulong)(mp->fc_memhi)) + mp->fc_memhi = (uchar *)bp; + if(mp->fc_memlo == 0) + mp->fc_memlo = (uchar *)bp; + else { + if((ulong)bp < (ulong)(mp->fc_memlo)) + mp->fc_memlo = (uchar *)bp; + } + + /* Link buffer into beginning of list. The first pointer in + * each buffer is a forward pointer to the next buffer. + */ + oldbp = mp->fc_memptr; + if(oldbp == 0) + mp->fc_endmemptr = bp; + mp->fc_memptr = bp; + *((uchar * *)bp) = oldbp; + } + } + + /* free blocks = total blocks right now */ + mp->fc_free = i; + } + + lpfc_mempool_unlock_enable(p_dev_ctl, iflag); + return(1); +} /* End fc_malloc_buffer */ + + +/***************************************************/ +/** fc_free_buffer **/ +/** **/ +/** This routine will free iocb/data buffer space */ +/***************************************************/ +_static_ int +fc_free_buffer( +fc_dev_ctl_t *p_dev_ctl) +{ + FC_BRD_INFO * binfo = &BINFO; + int j, ipri; + uchar * bp; + MEMSEG * mp; + MATCHMAP * mm; + NODELIST * ndlp; + NODELIST * ondlp; + RING * rp; + IOCBQ * iocbq, *save; + MAILBOXQ * mbox, *mbsave; + MBUF_INFO * buf_info; + MBUF_INFO bufinfo; + FCCLOCK_INFO * clock_info; + FCCLOCK * cb; + FCCLOCK * nextcb; + unsigned long iflag; + + buf_info = &bufinfo; + + /* free the mapped address match area for each ring */ + for (j = 0; j < binfo->fc_ffnumrings; j++) { + rp = &binfo->fc_ring[j]; + + /* Free everything on tx queue */ + iocbq = (IOCBQ * )(rp->fc_tx.q_first); + while (iocbq) { + save = iocbq; + iocbq = (IOCBQ * )iocbq->q; + fc_mem_put(binfo, MEM_IOCB, (uchar * )save); + } + + if (j != FC_FCP_RING) { + /* Free everything on txp queue */ + unsigned long iflag; + + iflag = lpfc_q_disable_lock(p_dev_ctl); + iocbq = (IOCBQ * )(rp->fc_txp.q_first); + while (iocbq) { + save = iocbq; + iocbq = (IOCBQ * )iocbq->q; + fc_mem_put(binfo, MEM_IOCB, (uchar * )save); + } + lpfc_q_unlock_enable(p_dev_ctl, iflag); + + while (rp->fc_mpoff) { + uchar * addr; + + addr = 0; + mm = (MATCHMAP * )(rp->fc_mpoff); + if (j == FC_IP_RING) + addr = (uchar * )(fcnextpkt((fcipbuf_t * )mm)); + else if (j == FC_ELS_RING) + addr = mm->phys; + if ((mm = fc_getvaddr(p_dev_ctl, rp, addr))) { + if (j == FC_ELS_RING) { + fc_mem_put(binfo, MEM_BUF, (uchar * )mm); + } + else if (j == FC_IP_RING) { + fcipbuf_t * mbuf; + + mbuf = (fcipbuf_t * )mm; + fcnextdata(mbuf) = 0; + fcnextpkt(mbuf) = 0; + m_freem(mbuf); + } + } + } + } + } + + /* Free any delayed ELS xmits */ + if(binfo->fc_delayxmit) { + iocbq = binfo->fc_delayxmit; + binfo->fc_delayxmit = 0; + while(iocbq) { + mm = (MATCHMAP * )iocbq->bp; + if (binfo->fc_flag & FC_SLI2) { + fc_mem_put(binfo, MEM_BPL, (uchar * )iocbq->bpl); + } + fc_mem_put(binfo, MEM_BUF, (uchar * )mm); + fc_mem_put(binfo, MEM_BUF, (uchar * )iocbq->info); + save = iocbq; + iocbq = (IOCBQ *)save->q; + fc_mem_put(binfo, MEM_IOCB, (uchar * )save); + } + } + + if (binfo->fc_table) { + buf_info->size = (MAX_FCP_CMDS * sizeof(void *)); + buf_info->virt = (uint32 * )binfo->fc_table; + buf_info->phys = 0; + buf_info->flags = 0; + buf_info->dma_handle = 0; + fc_free(p_dev_ctl, buf_info); + binfo->fc_table = 0; + } + + /* Free everything on mbox queue */ + mbox = (MAILBOXQ * )(binfo->fc_mbox.q_first); + while (mbox) { + mbsave = mbox; + mbox = (MAILBOXQ * )mbox->q; + fc_mem_put(binfo, MEM_MBOX, (uchar * )mbsave); + } + binfo->fc_mbox.q_first = 0; + binfo->fc_mbox.q_last = 0; + binfo->fc_mbox_active = 0; + + /* Free everything on iocb plogi queue */ + iocbq = (IOCBQ * )(binfo->fc_plogi.q_first); + while (iocbq) { + save = iocbq; + iocbq = (IOCBQ * )iocbq->q; + fc_mem_put(binfo, MEM_IOCB, (uchar * )save); + } + binfo->fc_plogi.q_first = 0; + binfo->fc_plogi.q_last = 0; + + /* Now cleanup unexpired clock blocks */ + clock_info = &DD_CTL.fc_clock_info; + ipri = disable_lock(FC_LVL, &CLOCK_LOCK); + + cb = clock_info->fc_clkhdr.cl_f; + while (cb != (FCCLOCK * ) & clock_info->fc_clkhdr) { + nextcb = cb->cl_fw; + if(cb->cl_p_dev_ctl == (void *)p_dev_ctl) { + fc_clock_deque(cb); + /* Release clock block */ + fc_clkrelb(p_dev_ctl, cb); + /* start over */ + } + cb = nextcb; + } + unlock_enable(ipri, &CLOCK_LOCK); + + /* Free all node table entries */ + ndlp = binfo->fc_nlpbind_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) { + ondlp = ndlp; + ndlp = (NODELIST *)ndlp->nlp_listp_next; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + fc_mem_put(binfo, MEM_NLP, (uchar * )ondlp); + } + binfo->fc_nlpbind_start = (NODELIST *)&binfo->fc_nlpbind_start; + binfo->fc_nlpbind_end = (NODELIST *)&binfo->fc_nlpbind_start; + binfo->fc_nlpmap_start = (NODELIST *)&binfo->fc_nlpmap_start; + binfo->fc_nlpmap_end = (NODELIST *)&binfo->fc_nlpmap_start; + binfo->fc_nlpunmap_start = (NODELIST *)&binfo->fc_nlpunmap_start; + binfo->fc_nlpunmap_end = (NODELIST *)&binfo->fc_nlpunmap_start; + + iflag = lpfc_mempool_disable_lock(p_dev_ctl); + /* Loop through all memory buffer pools */ + for (j = 0; j < FC_MAX_SEG; j++) { + mp = &binfo->fc_memseg[j]; + /* Free memory associated with all buffers on free buffer pool */ + while ((bp = mp->fc_memptr) != NULL) { + mp->fc_memptr = *((uchar * *)bp); + if (mp->fc_memflag & FC_MEM_DMA) { + mm = (MATCHMAP * )bp; + bp = mm->virt; + buf_info->size = mp->fc_memsize; + buf_info->virt = (uint32 * )bp; + buf_info->phys = (uint32 * )mm->phys; + buf_info->flags = FC_MBUF_DMA; + if (mm->dma_handle) { + buf_info->dma_handle = mm->dma_handle; + buf_info->data_handle = mm->data_handle; + } + fc_free(p_dev_ctl, buf_info); + + buf_info->size = sizeof(MATCHMAP); + buf_info->virt = (uint32 * )mm; + buf_info->phys = 0; + buf_info->flags = 0; + buf_info->dma_handle = 0; + fc_free(p_dev_ctl, buf_info); + } else { + buf_info->size = mp->fc_memsize; + buf_info->virt = (uint32 * )bp; + buf_info->phys = 0; + buf_info->flags = 0; + buf_info->dma_handle = 0; + fc_free(p_dev_ctl, buf_info); + } + } + mp->fc_endmemptr = NULL; + mp->fc_free = 0; + } + lpfc_mempool_unlock_enable(p_dev_ctl, iflag); + return(0); +} /* End fc_free_buffer */ + + + +/**************************************************/ +/** fc_mem_get **/ +/** **/ +/** This routine will get a free memory buffer. **/ +/** seg identifies which buffer pool to use. **/ +/** Returns the free buffer ptr or 0 for no buf **/ +/**************************************************/ +_static_ uchar * +fc_mem_get( +FC_BRD_INFO *binfo, +uint32 arg) +{ + uchar * bp; + MEMSEG * mp; + uint32 seg = arg & MEM_SEG_MASK; + int low; + fc_dev_ctl_t *p_dev_ctl; + unsigned long iflag; + + /* range check on seg argument */ + if (seg >= FC_MAX_SEG) + return((uchar * )0); + + p_dev_ctl = (fc_dev_ctl_t *)binfo->fc_p_dev_ctl; + iflag = lpfc_mempool_disable_lock(p_dev_ctl); + mp = &binfo->fc_memseg[seg]; + + if ((low = (!(arg & MEM_PRI) && (mp->fc_free <= mp->fc_lowmem)))) { + /* Memory Buffer Pool is below low water mark */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0406, /* ptr to msg structure */ + fc_mes0406, /* ptr to msg */ + fc_msgBlk0406.msgPreambleStr, /* begin varargs */ + seg, + mp->fc_lowmem, + low); /* end varargs */ + /* Low priority request and not enough buffers, so fail */ + lpfc_mempool_unlock_enable(p_dev_ctl, iflag); + return((uchar * )0); + } + + bp = mp->fc_memptr; + + if (bp) { + if(((ulong)bp > (ulong)(mp->fc_memhi)) || ((ulong)bp < (ulong)(mp->fc_memlo))) { + /* Memory Buffer Pool is corrupted */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0407, /* ptr to msg structure */ + fc_mes0407, /* ptr to msg */ + fc_msgBlk0407.msgPreambleStr, /* begin varargs */ + seg, + (ulong)bp, + (ulong)mp->fc_memhi, + (ulong)mp->fc_memlo); /* end varargs */ + mp->fc_memptr = 0; + lpfc_mempool_unlock_enable(p_dev_ctl, iflag); + return((uchar * )0); + } + + /* If a memory block exists, take it off freelist + * and return it to the user. + */ + if(mp->fc_endmemptr == bp) { + mp->fc_endmemptr = 0; + } + mp->fc_memptr = *((uchar * *)bp); + *((uchar * *)bp) = 0; + mp->fc_free--; + } else { + /* Memory Buffer Pool is out of buffers */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0409, /* ptr to msg structure */ + fc_mes0409, /* ptr to msg */ + fc_msgBlk0409.msgPreambleStr, /* begin varargs */ + seg, + mp->fc_free, + binfo->fc_mbox.q_cnt, + (ulong)(mp->fc_memhi)); /* end varargs */ + FCSTATCTR.memAllocErr++; + } + + if (seg == MEM_NLP) { + /* GET nodelist */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0927, /* ptr to msg structure */ + fc_mes0927, /* ptr to msg */ + fc_msgBlk0927.msgPreambleStr, /* begin varargs */ + (ulong)bp, + mp->fc_free); /* end varargs */ + } + + lpfc_mempool_unlock_enable(p_dev_ctl, iflag); + return(bp); +} /* End fc_mem_get */ + + +/**************************************************/ +/** fc_mem_put **/ +/** **/ +/** This routine will put a memory buffer back **/ +/** on the freelist. **/ +/** seg identifies which buffer pool to use. **/ +/**************************************************/ +_static_ uchar * +fc_mem_put( +FC_BRD_INFO *binfo, +uint32 seg, +uchar *bp) +{ + MEMSEG * mp; + uchar * oldbp; + fc_dev_ctl_t *p_dev_ctl; + unsigned long iflag; + /* range check on seg argument */ + if (seg >= FC_MAX_SEG) + return((uchar * )0); + + p_dev_ctl = (fc_dev_ctl_t *)binfo->fc_p_dev_ctl; + iflag = lpfc_mempool_disable_lock(p_dev_ctl); + mp = &binfo->fc_memseg[seg]; + + if (bp) { + + if(((ulong)bp > (ulong)(mp->fc_memhi)) || ((ulong)bp < (ulong)(mp->fc_memlo))) { + /* Memory Buffer Pool is corrupted */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0408, /* ptr to msg structure */ + fc_mes0408, /* ptr to msg */ + fc_msgBlk0408.msgPreambleStr, /* begin varargs */ + seg, + (ulong)bp, + (ulong)mp->fc_memhi, + (ulong)mp->fc_memlo); /* end varargs */ + lpfc_mempool_unlock_enable(p_dev_ctl, iflag); + return((uchar * )0); + } + /* If a memory block exists, put it on freelist + * and return it to the user. + */ + oldbp = mp->fc_memptr; + mp->fc_memptr = bp; + *((uchar * *)bp) = oldbp; + if(oldbp == 0) + mp->fc_endmemptr = bp; + mp->fc_free++; + } + + if (seg == MEM_NLP) { + /* PUT nodelist */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0928, /* ptr to msg structure */ + fc_mes0928, /* ptr to msg */ + fc_msgBlk0928.msgPreambleStr, /* begin varargs */ + (ulong)bp, + mp->fc_free); /* end varargs */ + } + + lpfc_mempool_unlock_enable(p_dev_ctl, iflag); + return(bp); +} /* End fc_mem_put */ + + +/* Look up the virtual address given a mapped address */ +_static_ MATCHMAP * +fc_getvaddr( +fc_dev_ctl_t *p_dev_ctl, +RING *rp, +uchar *mapbp) +{ + FC_BRD_INFO * binfo; + + binfo = &BINFO; + /* While there are available slots in the list */ + if (rp->fc_ringno == FC_ELS_RING) { + MATCHMAP * mp; + MATCHMAP * mpoff; + + mpoff = (MATCHMAP * )rp->fc_mpoff; + mp = 0; + + while (mpoff) { + /* Check for a match */ + if (mpoff->phys == mapbp) { + /* If we matched on the first slot */ + if (mp == 0) { + rp->fc_mpoff = mpoff->fc_mptr; + } else { + mp->fc_mptr = mpoff->fc_mptr; + } + + if (rp->fc_mpon == (uchar * )mpoff) { + rp->fc_mpon = (uchar * )mp; + } + rp->fc_bufcnt--; + mpoff->fc_mptr = 0; + + fc_mpdata_sync(mpoff->dma_handle, 0, 0, DDI_DMA_SYNC_FORKERNEL); + + /* Return entry */ + return(mpoff); + } + mp = mpoff; + mpoff = (MATCHMAP * )mpoff->fc_mptr; + } + } + + if (rp->fc_ringno == FC_IP_RING) { + fcipbuf_t * mb; + fcipbuf_t * mboff; + + mboff = (fcipbuf_t * )rp->fc_mpoff; + mb = 0; + + while (mboff) { + /* Check for a match */ + if (fcnextpkt(mboff) == (fcipbuf_t * )mapbp) { + /* If we matched on the first slot */ + if (mb == 0) { + rp->fc_mpoff = (uchar * )fcnextdata(mboff); + } else { + fcnextdata(mb) = fcnextdata(mboff); + } + + if (rp->fc_mpon == (uchar * )mboff) { + rp->fc_mpon = (uchar * )mb; + } + rp->fc_bufcnt--; + + if (fcnextpkt(mboff)) { + MBUF_INFO * buf_info; + MBUF_INFO bufinfo; + + buf_info = &bufinfo; + buf_info->dma_handle = (ulong * )fcgethandle(mboff); + if (buf_info->dma_handle) { + fc_mpdata_sync(buf_info->dma_handle, 0, 0, + DDI_DMA_SYNC_FORKERNEL); + } + buf_info->virt = 0; + buf_info->flags = (FC_MBUF_PHYSONLY | FC_MBUF_DMA); + buf_info->phys = (uint32 * )fcnextpkt(mboff); + buf_info->size = fcPAGESIZE; + fc_free(p_dev_ctl, buf_info); + } + + fcsethandle(mboff, 0); + fcnextpkt(mboff) = 0; + fcnextdata(mboff) = 0; + /* Return entry */ + return((MATCHMAP * )mboff); + } + mb = mboff; + mboff = (fcipbuf_t * )fcnextdata(mboff); + } + } + /* Cannot find virtual addr for mapped buf on ring (num) */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0410, /* ptr to msg structure */ + fc_mes0410, /* ptr to msg */ + fc_msgBlk0410.msgPreambleStr, /* begin varargs */ + rp->fc_ringno, + (ulong)mapbp, + (ulong)rp->fc_mpoff, + (ulong)rp->fc_mpon); /* end varargs */ + FCSTATCTR.noVirtPtr++; + return(0); +} /* End fc_getvaddr */ + + +/* Given a virtual address, bp, generate the physical mapped address + * and place it where addr points to. Save the address pair for lookup later. + */ +_static_ void +fc_mapvaddr( +FC_BRD_INFO *binfo, +RING *rp, +MATCHMAP *mp, +uint32 *haddr, +uint32 *laddr) +{ + fcipbuf_t * mbuf; + + switch (rp->fc_ringno) { + case FC_ELS_RING: + mp->fc_mptr = 0; + /* Update slot fc_mpon points to then bump it */ + if (rp->fc_mpoff == 0) { + rp->fc_mpoff = (uchar * )mp; + rp->fc_mpon = (uchar * )mp; + } else { + ((MATCHMAP * )(rp->fc_mpon))->fc_mptr = (uchar * )mp; + rp->fc_mpon = (uchar * )mp; + } + if (binfo->fc_flag & FC_SLI2) { + *haddr = (uint32)putPaddrHigh(mp->phys); /* return mapped address */ + *laddr = (uint32)putPaddrLow(mp->phys); /* return mapped address */ + } else { + *laddr = (uint32)putPaddrLow(mp->phys); /* return mapped address */ + } + break; + + case FC_IP_RING: + mbuf = (fcipbuf_t * )mp; + fcnextdata(mbuf) = 0; + /* Update slot fc_mpon points to then bump it */ + if (rp->fc_mpoff == 0) { + rp->fc_mpoff = (uchar * )mbuf; + rp->fc_mpon = (uchar * )mbuf; + } else { + fcnextdata((fcipbuf_t * )(rp->fc_mpon)) = mbuf; + rp->fc_mpon = (uchar * )mbuf; + } + if (binfo->fc_flag & FC_SLI2) { + *haddr = (uint32)putPaddrHigh(fcnextpkt(mbuf)); + *laddr = (uint32)putPaddrLow(fcnextpkt(mbuf)); + } else { + *laddr = (uint32)putPaddrLow(fcnextpkt(mbuf)); + } + break; + } + + rp->fc_bufcnt++; + return; +} /* End fc_mapvaddr */ + + + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/fcmsg.h 830-ivtv/drivers/scsi/lpfc/fcmsg.h --- 000-virgin/drivers/scsi/lpfc/fcmsg.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/fcmsg.h Thu Jan 8 10:21:53 2004 @@ -0,0 +1,1082 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Enterprise Fibre Channel Host Bus Adapters. * + * Refer to the README file included with this package for * + * driver version and adapter support. * + * Copyright (C) 2003 Emulex Corporation. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details, a copy of which * + * can be found in the file COPYING included with this package. * + *******************************************************************/ + +#ifndef _H_FCMSG +#define _H_FCMSG + +/* + * LOG Message Group Numbering Sequence + * + * Message Group Preamble From To + * String + * + * ELS ELx 100 199 + * DISCOVERY DIx 200 299 + * MBOX MBx 300 399 + * INIT INx 400 499 + * Unused 500 599 + * IP IPx 600 699 + * FCP FPx 700 799 + * Unused 800 899 + * NODE NDx 900 999 + * MISC MIx 1200 1299 + * LINK LKx 1300 1399 + * SLI SLx 1400 1499 + * CHK_CONDITION CKx 1500 1599 + */ + +/* + * Log Message Structure + * + * The following structure supports LOG messages only. + * Every LOG message is associated to a msgBlkLogDef structure of the + * following type. + */ + +typedef struct msgLogType { + int msgNum; /* Message number */ + char * msgStr; /* Ptr to log message */ + char * msgPreambleStr; /* Ptr to log message preamble */ + int msgOutput; /* Message output target - bitmap */ + /* + * This member controls message OUTPUT. + * + * The phase 'global controls' refers to user configurable parameters + * such as LOG_VERBOSE that control message output on a global basis. + */ + +#define FC_MSG_OPUT_GLOB_CTRL 0x0 /* Use global control */ +#define FC_MSG_OPUT_DISA 0x1 /* Override global control */ +#define FC_MSG_OPUT_FORCE 0x2 /* Override global control */ + int msgType; /* Message LOG type - bitmap */ +#define FC_LOG_MSG_TYPE_INFO 0x1 /* Maskable */ +#define FC_LOG_MSG_TYPE_WARN 0x2 /* Non-Maskable */ +#define FC_LOG_MSG_TYPE_ERR_CFG 0x4 /* Non-Maskable */ +#define FC_LOG_MSG_TYPE_ERR 0x8 /* Non-Maskable */ +#define FC_LOG_MSG_TYPE_PANIC 0x10 /* Non-Maskable */ + int msgMask; /* Message LOG mask - bitmap */ + /* + * NOTE: Only LOG messages of types MSG_TYPE_WARN & MSG_TYPE_INFO are + * maskable at the GLOBAL level. + * + * Any LOG message regardless of message type can be disabled (override verbose) + * at the msgBlkLogDef struct level my setting member msgOutput = FC_MSG_OPUT_DISA. + * The message will never be displayed regardless of verbose mask. + * + * Any LOG message regardless of message type can be enable (override verbose) + * at the msgBlkLogDef struct level my setting member msgOutput = FC_MSG_OPUT_FORCE. + * The message will always be displayed regardless of verbose mask. + */ +#define LOG_ELS 0x1 /* ELS events */ +#define LOG_DISCOVERY 0x2 /* Link discovery events */ +#define LOG_MBOX 0x4 /* Mailbox events */ +#define LOG_INIT 0x8 /* Initialization events */ +#define LOG_LINK_EVENT 0x10 /* Link events */ +#define LOG_IP 0x20 /* IP traffic history */ +#define LOG_FCP 0x40 /* FCP traffic history */ +#define LOG_NODE 0x80 /* Node table events */ +#define LOG_MISC 0x400 /* Miscellaneous events */ +#define LOG_SLI 0x800 /* SLI events */ +#define LOG_CHK_COND 0x1000 /* FCP Check condition flag */ +#define LOG_ALL_MSG 0x1fff /* LOG all messages */ + unsigned int msgLogID; /* Message LOG ID */ +#define ERRID_LOG_TIMEOUT 0xfdefefa7 /* Fibre Channel timeout */ +#define ERRID_LOG_HDW_ERR 0x1ae4fffc /* Fibre Channel hardware failure */ +#define ERRID_LOG_UNEXPECT_EVENT 0xbdb7e728 /* Fibre Channel unexpected event */ +#define ERRID_LOG_INIT 0xbe1043b8 /* Fibre Channel init failure */ +#define ERRID_LOG_NO_RESOURCE 0x474c1775 /* Fibre Channel no resources */ + } msgLogDef; + +/* + * External Declarations for LOG Messages + */ + +/* ELS LOG Messages */ +extern char fc_mes0100[]; +extern char fc_mes0101[]; +extern char fc_mes0102[]; +extern char fc_mes0103[]; +extern char fc_mes0104[]; +extern char fc_mes0105[]; +extern char fc_mes0106[]; +extern char fc_mes0107[]; +extern char fc_mes0108[]; +extern char fc_mes0109[]; +extern char fc_mes0110[]; +extern char fc_mes0111[]; +extern char fc_mes0112[]; +extern char fc_mes0113[]; +extern char fc_mes0114[]; +extern char fc_mes0115[]; +extern char fc_mes0116[]; +extern char fc_mes0117[]; +extern char fc_mes0118[]; +extern char fc_mes0119[]; +extern char fc_mes0120[]; +extern char fc_mes0121[]; +extern char fc_mes0122[]; +extern char fc_mes0123[]; +extern char fc_mes0124[]; +extern char fc_mes0125[]; +extern char fc_mes0126[]; +extern char fc_mes0127[]; +extern char fc_mes0128[]; +extern char fc_mes0129[]; +extern char fc_mes0130[]; +extern char fc_mes0131[]; +extern char fc_mes0132[]; +extern char fc_mes0133[]; +extern char fc_mes0134[]; +extern char fc_mes0135[]; +extern char fc_mes0136[]; + +/* DISCOVERY LOG Messages */ +extern char fc_mes0200[]; +extern char fc_mes0201[]; +extern char fc_mes0202[]; +extern char fc_mes0203[]; +extern char fc_mes0204[]; +extern char fc_mes0205[]; +extern char fc_mes0206[]; +extern char fc_mes0207[]; +extern char fc_mes0208[]; +extern char fc_mes0209[]; +extern char fc_mes0210[]; +extern char fc_mes0211[]; +extern char fc_mes0212[]; +extern char fc_mes0213[]; +extern char fc_mes0214[]; +extern char fc_mes0215[]; +extern char fc_mes0216[]; +extern char fc_mes0217[]; +extern char fc_mes0218[]; +extern char fc_mes0219[]; +extern char fc_mes0220[]; +extern char fc_mes0221[]; +extern char fc_mes0222[]; +extern char fc_mes0223[]; +extern char fc_mes0224[]; +extern char fc_mes0225[]; +extern char fc_mes0226[]; +extern char fc_mes0227[]; +extern char fc_mes0228[]; +extern char fc_mes0229[]; +extern char fc_mes0230[]; +extern char fc_mes0231[]; +extern char fc_mes0232[]; +extern char fc_mes0233[]; +extern char fc_mes0234[]; +extern char fc_mes0235[]; +extern char fc_mes0236[]; +extern char fc_mes0237[]; +extern char fc_mes0238[]; +extern char fc_mes0239[]; +extern char fc_mes0240[]; +extern char fc_mes0241[]; +extern char fc_mes0242[]; +extern char fc_mes0243[]; +extern char fc_mes0244[]; +extern char fc_mes0245[]; +extern char fc_mes0246[]; +extern char fc_mes0247[]; +extern char fc_mes0248[]; +extern char fc_mes0249[]; +extern char fc_mes0250[]; +extern char fc_mes0251[]; +extern char fc_mes0252[]; + +/* MAILBOX LOG Messages */ +extern char fc_mes0300[]; +extern char fc_mes0301[]; +extern char fc_mes0302[]; +extern char fc_mes0303[]; +extern char fc_mes0304[]; +extern char fc_mes0305[]; +extern char fc_mes0306[]; +extern char fc_mes0307[]; +extern char fc_mes0308[]; +extern char fc_mes0309[]; +extern char fc_mes0310[]; +extern char fc_mes0311[]; +extern char fc_mes0312[]; + +/* INIT LOG Messages */ +extern char fc_mes0400[]; +extern char fc_mes0401[]; +extern char fc_mes0402[]; +extern char fc_mes0403[]; +extern char fc_mes0404[]; +extern char fc_mes0405[]; +extern char fc_mes0406[]; +extern char fc_mes0407[]; +extern char fc_mes0408[]; +extern char fc_mes0409[]; +extern char fc_mes0410[]; +extern char fc_mes0411[]; +extern char fc_mes0412[]; +extern char fc_mes0413[]; +extern char fc_mes0414[]; +extern char fc_mes0415[]; +extern char fc_mes0416[]; +extern char fc_mes0417[]; +extern char fc_mes0418[]; +extern char fc_mes0419[]; +extern char fc_mes0420[]; +extern char fc_mes0421[]; +extern char fc_mes0422[]; +extern char fc_mes0423[]; +extern char fc_mes0424[]; +extern char fc_mes0425[]; +extern char fc_mes0426[]; +extern char fc_mes0427[]; +extern char fc_mes0428[]; +extern char fc_mes0429[]; +extern char fc_mes0430[]; +extern char fc_mes0431[]; +extern char fc_mes0432[]; +extern char fc_mes0433[]; +extern char fc_mes0434[]; +extern char fc_mes0435[]; +extern char fc_mes0436[]; +extern char fc_mes0437[]; +extern char fc_mes0438[]; +extern char fc_mes0439[]; +extern char fc_mes0440[]; +extern char fc_mes0440[]; +extern char fc_mes0441[]; +extern char fc_mes0442[]; +extern char fc_mes0443[]; +extern char fc_mes0444[]; +extern char fc_mes0445[]; +extern char fc_mes0446[]; +extern char fc_mes0447[]; +extern char fc_mes0448[]; +extern char fc_mes0449[]; +extern char fc_mes0450[]; +extern char fc_mes0451[]; +extern char fc_mes0452[]; +extern char fc_mes0453[]; +extern char fc_mes0454[]; +extern char fc_mes0455[]; +extern char fc_mes0456[]; +extern char fc_mes0457[]; +extern char fc_mes0458[]; +extern char fc_mes0459[]; +extern char fc_mes0460[]; +extern char fc_mes0461[]; + +/* UNUSED */ +/* +extern char fc_mes0500[]; +*/ + +/* IP LOG Messages */ +extern char fc_mes0600[]; +extern char fc_mes0601[]; +extern char fc_mes0602[]; +extern char fc_mes0603[]; +extern char fc_mes0604[]; +extern char fc_mes0605[]; +extern char fc_mes0606[]; +extern char fc_mes0607[]; +extern char fc_mes0608[]; + +/* FCP LOG Messages */ +extern char fc_mes0700[]; +extern char fc_mes0701[]; +extern char fc_mes0702[]; +extern char fc_mes0703[]; +extern char fc_mes0704[]; +extern char fc_mes0705[]; +extern char fc_mes0706[]; +extern char fc_mes0707[]; +extern char fc_mes0708[]; +extern char fc_mes0709[]; +extern char fc_mes0710[]; +extern char fc_mes0711[]; +extern char fc_mes0712[]; +extern char fc_mes0713[]; +extern char fc_mes0714[]; +extern char fc_mes0715[]; +extern char fc_mes0716[]; +extern char fc_mes0717[]; +extern char fc_mes0718[]; +extern char fc_mes0719[]; +extern char fc_mes0720[]; +extern char fc_mes0721[]; +extern char fc_mes0722[]; +extern char fc_mes0723[]; +extern char fc_mes0724[]; +extern char fc_mes0725[]; +extern char fc_mes0726[]; +extern char fc_mes0727[]; +extern char fc_mes0728[]; +extern char fc_mes0729[]; +extern char fc_mes0730[]; +extern char fc_mes0731[]; +extern char fc_mes0732[]; +extern char fc_mes0733[]; +extern char fc_mes0734[]; +extern char fc_mes0735[]; +extern char fc_mes0736[]; +extern char fc_mes0737[]; +extern char fc_mes0738[]; +extern char fc_mes0739[]; +extern char fc_mes0740[]; +extern char fc_mes0741[]; +extern char fc_mes0742[]; +extern char fc_mes0743[]; +extern char fc_mes0744[]; +extern char fc_mes0745[]; +extern char fc_mes0746[]; +extern char fc_mes0747[]; +extern char fc_mes0748[]; +extern char fc_mes0749[]; +extern char fc_mes0750[]; +extern char fc_mes0751[]; +extern char fc_mes0752[]; +extern char fc_mes0753[]; +extern char fc_mes0754[]; +extern char fc_mes0756[]; + +/* UNUSED */ +/* +extern char fc_mes0800[]; +*/ + +/* NODE LOG Messages */ +extern char fc_mes0900[]; +extern char fc_mes0901[]; +extern char fc_mes0902[]; +extern char fc_mes0903[]; +extern char fc_mes0904[]; +extern char fc_mes0905[]; +extern char fc_mes0906[]; +extern char fc_mes0907[]; +extern char fc_mes0908[]; +extern char fc_mes0909[]; +extern char fc_mes0910[]; +extern char fc_mes0911[]; +extern char fc_mes0912[]; +extern char fc_mes0913[]; +extern char fc_mes0914[]; +extern char fc_mes0915[]; +extern char fc_mes0916[]; +extern char fc_mes0917[]; +extern char fc_mes0918[]; +extern char fc_mes0919[]; +extern char fc_mes0920[]; +extern char fc_mes0921[]; +extern char fc_mes0922[]; +extern char fc_mes0923[]; +extern char fc_mes0924[]; +extern char fc_mes0925[]; +extern char fc_mes0926[]; +extern char fc_mes0927[]; +extern char fc_mes0928[]; + + + +/* MISC LOG messages */ +extern char fc_mes1200[]; +extern char fc_mes1201[]; +extern char fc_mes1202[]; +extern char fc_mes1203[]; +extern char fc_mes1204[]; +extern char fc_mes1205[]; +extern char fc_mes1206[]; +extern char fc_mes1207[]; +extern char fc_mes1208[]; +extern char fc_mes1209[]; +extern char fc_mes1210[]; +extern char fc_mes1211[]; +extern char fc_mes1212[]; +extern char fc_mes1213[]; + +/* LINK LOG Messages */ +extern char fc_mes1300[]; +extern char fc_mes1301[]; +extern char fc_mes1302[]; +extern char fc_mes1303[]; +extern char fc_mes1304[]; +extern char fc_mes1305[]; +extern char fc_mes1306[]; +extern char fc_mes1307[]; + +/* SLI LOG Messages */ +extern char fc_mes1400[]; +extern char fc_mes1401[]; +extern char fc_mes1402[]; + +/* CHK CONDITION LOG Messages */ +/* +extern char fc_mes1500[]; +*/ + +/* + * External Declarations for LOG Message Structure msgBlkLogDef + */ + +/* ELS LOG Message Structures */ +extern msgLogDef fc_msgBlk0100; +extern msgLogDef fc_msgBlk0101; +extern msgLogDef fc_msgBlk0102; +extern msgLogDef fc_msgBlk0103; +extern msgLogDef fc_msgBlk0104; +extern msgLogDef fc_msgBlk0105; +extern msgLogDef fc_msgBlk0106; +extern msgLogDef fc_msgBlk0107; +extern msgLogDef fc_msgBlk0108; +extern msgLogDef fc_msgBlk0109; +extern msgLogDef fc_msgBlk0110; +extern msgLogDef fc_msgBlk0111; +extern msgLogDef fc_msgBlk0112; +extern msgLogDef fc_msgBlk0113; +extern msgLogDef fc_msgBlk0114; +extern msgLogDef fc_msgBlk0115; +extern msgLogDef fc_msgBlk0116; +extern msgLogDef fc_msgBlk0117; +extern msgLogDef fc_msgBlk0118; +extern msgLogDef fc_msgBlk0119; +extern msgLogDef fc_msgBlk0120; +extern msgLogDef fc_msgBlk0121; +extern msgLogDef fc_msgBlk0122; +extern msgLogDef fc_msgBlk0123; +extern msgLogDef fc_msgBlk0124; +extern msgLogDef fc_msgBlk0125; +extern msgLogDef fc_msgBlk0126; +extern msgLogDef fc_msgBlk0127; +extern msgLogDef fc_msgBlk0128; +extern msgLogDef fc_msgBlk0129; +extern msgLogDef fc_msgBlk0130; +extern msgLogDef fc_msgBlk0131; +extern msgLogDef fc_msgBlk0132; +extern msgLogDef fc_msgBlk0133; +extern msgLogDef fc_msgBlk0134; +extern msgLogDef fc_msgBlk0135; +extern msgLogDef fc_msgBlk0136; + +/* DISCOVERY LOG Message Structures */ +extern msgLogDef fc_msgBlk0200; +extern msgLogDef fc_msgBlk0201; +extern msgLogDef fc_msgBlk0202; +extern msgLogDef fc_msgBlk0203; +extern msgLogDef fc_msgBlk0204; +extern msgLogDef fc_msgBlk0205; +extern msgLogDef fc_msgBlk0206; +extern msgLogDef fc_msgBlk0207; +extern msgLogDef fc_msgBlk0208; +extern msgLogDef fc_msgBlk0209; +extern msgLogDef fc_msgBlk0210; +extern msgLogDef fc_msgBlk0211; +extern msgLogDef fc_msgBlk0212; +extern msgLogDef fc_msgBlk0213; +extern msgLogDef fc_msgBlk0214; +extern msgLogDef fc_msgBlk0215; +extern msgLogDef fc_msgBlk0216; +extern msgLogDef fc_msgBlk0217; +extern msgLogDef fc_msgBlk0218; +extern msgLogDef fc_msgBlk0219; +extern msgLogDef fc_msgBlk0220; +extern msgLogDef fc_msgBlk0221; +extern msgLogDef fc_msgBlk0222; +extern msgLogDef fc_msgBlk0223; +extern msgLogDef fc_msgBlk0224; +extern msgLogDef fc_msgBlk0225; +extern msgLogDef fc_msgBlk0226; +extern msgLogDef fc_msgBlk0227; +extern msgLogDef fc_msgBlk0228; +extern msgLogDef fc_msgBlk0229; +extern msgLogDef fc_msgBlk0230; +extern msgLogDef fc_msgBlk0231; +extern msgLogDef fc_msgBlk0232; +extern msgLogDef fc_msgBlk0233; +extern msgLogDef fc_msgBlk0234; +extern msgLogDef fc_msgBlk0235; +extern msgLogDef fc_msgBlk0236; +extern msgLogDef fc_msgBlk0237; +extern msgLogDef fc_msgBlk0238; +extern msgLogDef fc_msgBlk0239; +extern msgLogDef fc_msgBlk0240; +extern msgLogDef fc_msgBlk0241; +extern msgLogDef fc_msgBlk0242; +extern msgLogDef fc_msgBlk0243; +extern msgLogDef fc_msgBlk0244; +extern msgLogDef fc_msgBlk0245; +extern msgLogDef fc_msgBlk0246; +extern msgLogDef fc_msgBlk0247; +extern msgLogDef fc_msgBlk0248; +extern msgLogDef fc_msgBlk0249; +extern msgLogDef fc_msgBlk0250; +extern msgLogDef fc_msgBlk0251; +extern msgLogDef fc_msgBlk0252; + +/* MAILBOX LOG Message Structures */ +extern msgLogDef fc_msgBlk0300; +extern msgLogDef fc_msgBlk0301; +extern msgLogDef fc_msgBlk0302; +extern msgLogDef fc_msgBlk0303; +extern msgLogDef fc_msgBlk0304; +extern msgLogDef fc_msgBlk0305; +extern msgLogDef fc_msgBlk0306; +extern msgLogDef fc_msgBlk0307; +extern msgLogDef fc_msgBlk0308; +extern msgLogDef fc_msgBlk0309; +extern msgLogDef fc_msgBlk0310; +extern msgLogDef fc_msgBlk0311; +extern msgLogDef fc_msgBlk0312; + +/* INIT LOG Message Structures */ +extern msgLogDef fc_msgBlk0400; +extern msgLogDef fc_msgBlk0401; +extern msgLogDef fc_msgBlk0402; +extern msgLogDef fc_msgBlk0403; +extern msgLogDef fc_msgBlk0404; +extern msgLogDef fc_msgBlk0405; +extern msgLogDef fc_msgBlk0406; +extern msgLogDef fc_msgBlk0407; +extern msgLogDef fc_msgBlk0408; +extern msgLogDef fc_msgBlk0409; +extern msgLogDef fc_msgBlk0410; +extern msgLogDef fc_msgBlk0411; +extern msgLogDef fc_msgBlk0412; +extern msgLogDef fc_msgBlk0413; +extern msgLogDef fc_msgBlk0414; +extern msgLogDef fc_msgBlk0415; +extern msgLogDef fc_msgBlk0416; +extern msgLogDef fc_msgBlk0417; +extern msgLogDef fc_msgBlk0418; +extern msgLogDef fc_msgBlk0419; +extern msgLogDef fc_msgBlk0420; +extern msgLogDef fc_msgBlk0421; +extern msgLogDef fc_msgBlk0422; +extern msgLogDef fc_msgBlk0423; +extern msgLogDef fc_msgBlk0424; +extern msgLogDef fc_msgBlk0425; +extern msgLogDef fc_msgBlk0426; +extern msgLogDef fc_msgBlk0427; +extern msgLogDef fc_msgBlk0428; +extern msgLogDef fc_msgBlk0429; +extern msgLogDef fc_msgBlk0430; +extern msgLogDef fc_msgBlk0431; +extern msgLogDef fc_msgBlk0432; +extern msgLogDef fc_msgBlk0433; +extern msgLogDef fc_msgBlk0434; +extern msgLogDef fc_msgBlk0435; +extern msgLogDef fc_msgBlk0436; +extern msgLogDef fc_msgBlk0437; +extern msgLogDef fc_msgBlk0438; +extern msgLogDef fc_msgBlk0439; +extern msgLogDef fc_msgBlk0440; +extern msgLogDef fc_msgBlk0441; +extern msgLogDef fc_msgBlk0442; +extern msgLogDef fc_msgBlk0443; +extern msgLogDef fc_msgBlk0444; +extern msgLogDef fc_msgBlk0445; +extern msgLogDef fc_msgBlk0446; +extern msgLogDef fc_msgBlk0447; +extern msgLogDef fc_msgBlk0448; +extern msgLogDef fc_msgBlk0449; +extern msgLogDef fc_msgBlk0450; +extern msgLogDef fc_msgBlk0451; +extern msgLogDef fc_msgBlk0452; +extern msgLogDef fc_msgBlk0453; +extern msgLogDef fc_msgBlk0454; +extern msgLogDef fc_msgBlk0455; +extern msgLogDef fc_msgBlk0456; +extern msgLogDef fc_msgBlk0457; +extern msgLogDef fc_msgBlk0458; +extern msgLogDef fc_msgBlk0459; +extern msgLogDef fc_msgBlk0460; +extern msgLogDef fc_msgBlk0461; + +/* UNUSED */ +/* +extern msgLogDef fc_msgBlk0500; +*/ + +/* IP LOG Message Structures */ +extern msgLogDef fc_msgBlk0600; +extern msgLogDef fc_msgBlk0601; +extern msgLogDef fc_msgBlk0602; +extern msgLogDef fc_msgBlk0603; +extern msgLogDef fc_msgBlk0604; +extern msgLogDef fc_msgBlk0605; +extern msgLogDef fc_msgBlk0606; +extern msgLogDef fc_msgBlk0607; +extern msgLogDef fc_msgBlk0608; + +/* FCP LOG Message Structures */ +extern msgLogDef fc_msgBlk0700; +extern msgLogDef fc_msgBlk0701; +extern msgLogDef fc_msgBlk0702; +extern msgLogDef fc_msgBlk0703; +extern msgLogDef fc_msgBlk0704; +extern msgLogDef fc_msgBlk0705; +extern msgLogDef fc_msgBlk0706; +extern msgLogDef fc_msgBlk0707; +extern msgLogDef fc_msgBlk0708; +extern msgLogDef fc_msgBlk0709; +extern msgLogDef fc_msgBlk0710; +extern msgLogDef fc_msgBlk0711; +extern msgLogDef fc_msgBlk0712; +extern msgLogDef fc_msgBlk0713; +extern msgLogDef fc_msgBlk0714; +extern msgLogDef fc_msgBlk0715; +extern msgLogDef fc_msgBlk0716; +extern msgLogDef fc_msgBlk0717; +extern msgLogDef fc_msgBlk0718; +extern msgLogDef fc_msgBlk0719; +extern msgLogDef fc_msgBlk0720; +extern msgLogDef fc_msgBlk0721; +extern msgLogDef fc_msgBlk0722; +extern msgLogDef fc_msgBlk0723; +extern msgLogDef fc_msgBlk0724; +extern msgLogDef fc_msgBlk0725; +extern msgLogDef fc_msgBlk0726; +extern msgLogDef fc_msgBlk0727; +extern msgLogDef fc_msgBlk0728; +extern msgLogDef fc_msgBlk0729; +extern msgLogDef fc_msgBlk0730; +extern msgLogDef fc_msgBlk0731; +extern msgLogDef fc_msgBlk0732; +extern msgLogDef fc_msgBlk0733; +extern msgLogDef fc_msgBlk0734; +extern msgLogDef fc_msgBlk0735; +extern msgLogDef fc_msgBlk0736; +extern msgLogDef fc_msgBlk0737; +extern msgLogDef fc_msgBlk0738; +extern msgLogDef fc_msgBlk0739; +extern msgLogDef fc_msgBlk0740; +extern msgLogDef fc_msgBlk0741; +extern msgLogDef fc_msgBlk0742; +extern msgLogDef fc_msgBlk0743; +extern msgLogDef fc_msgBlk0744; +extern msgLogDef fc_msgBlk0745; +extern msgLogDef fc_msgBlk0746; +extern msgLogDef fc_msgBlk0747; +extern msgLogDef fc_msgBlk0748; +extern msgLogDef fc_msgBlk0749; +extern msgLogDef fc_msgBlk0750; +extern msgLogDef fc_msgBlk0751; +extern msgLogDef fc_msgBlk0752; +extern msgLogDef fc_msgBlk0753; +extern msgLogDef fc_msgBlk0754; +extern msgLogDef fc_msgBlk0756; + +/* UNUSED */ +/* +extern msgLogDef fc_msgBlk0800; +*/ + +/* NODE LOG Message Structures */ +extern msgLogDef fc_msgBlk0900; +extern msgLogDef fc_msgBlk0901; +extern msgLogDef fc_msgBlk0902; +extern msgLogDef fc_msgBlk0903; +extern msgLogDef fc_msgBlk0904; +extern msgLogDef fc_msgBlk0905; +extern msgLogDef fc_msgBlk0906; +extern msgLogDef fc_msgBlk0907; +extern msgLogDef fc_msgBlk0908; +extern msgLogDef fc_msgBlk0909; +extern msgLogDef fc_msgBlk0910; +extern msgLogDef fc_msgBlk0911; +extern msgLogDef fc_msgBlk0912; +extern msgLogDef fc_msgBlk0913; +extern msgLogDef fc_msgBlk0914; +extern msgLogDef fc_msgBlk0915; +extern msgLogDef fc_msgBlk0916; +extern msgLogDef fc_msgBlk0917; +extern msgLogDef fc_msgBlk0918; +extern msgLogDef fc_msgBlk0919; +extern msgLogDef fc_msgBlk0920; +extern msgLogDef fc_msgBlk0921; +extern msgLogDef fc_msgBlk0922; +extern msgLogDef fc_msgBlk0923; +extern msgLogDef fc_msgBlk0924; +extern msgLogDef fc_msgBlk0925; +extern msgLogDef fc_msgBlk0926; +extern msgLogDef fc_msgBlk0927; +extern msgLogDef fc_msgBlk0928; + + + +/* MISC LOG Message Structures */ +extern msgLogDef fc_msgBlk1200; +extern msgLogDef fc_msgBlk1201; +extern msgLogDef fc_msgBlk1202; +extern msgLogDef fc_msgBlk1203; +extern msgLogDef fc_msgBlk1204; +extern msgLogDef fc_msgBlk1205; +extern msgLogDef fc_msgBlk1206; +extern msgLogDef fc_msgBlk1207; +extern msgLogDef fc_msgBlk1208; +extern msgLogDef fc_msgBlk1209; +extern msgLogDef fc_msgBlk1210; +extern msgLogDef fc_msgBlk1211; +extern msgLogDef fc_msgBlk1212; +extern msgLogDef fc_msgBlk1213; + +/* LINK LOG Message Structures */ +extern msgLogDef fc_msgBlk1300; +extern msgLogDef fc_msgBlk1301; +extern msgLogDef fc_msgBlk1302; +extern msgLogDef fc_msgBlk1303; +extern msgLogDef fc_msgBlk1304; +extern msgLogDef fc_msgBlk1305; +extern msgLogDef fc_msgBlk1306; +extern msgLogDef fc_msgBlk1307; + +/* SLI LOG Message Structures */ +extern msgLogDef fc_msgBlk1400; +extern msgLogDef fc_msgBlk1401; +extern msgLogDef fc_msgBlk1402; + +/* CHK CONDITION LOG Message Structures */ +/* +extern msgLogDef fc_msgBlk1500; +*/ + +/* + * LOG Messages Numbers + */ + +/* ELS LOG Message Numbers */ +#define FC_LOG_MSG_EL_0100 100 +#define FC_LOG_MSG_EL_0101 101 +#define FC_LOG_MSG_EL_0102 102 +#define FC_LOG_MSG_EL_0103 103 +#define FC_LOG_MSG_EL_0104 104 +#define FC_LOG_MSG_EL_0105 105 +#define FC_LOG_MSG_EL_0106 106 +#define FC_LOG_MSG_EL_0107 107 +#define FC_LOG_MSG_EL_0108 108 +#define FC_LOG_MSG_EL_0109 109 +#define FC_LOG_MSG_EL_0110 110 +#define FC_LOG_MSG_EL_0111 111 +#define FC_LOG_MSG_EL_0112 112 +#define FC_LOG_MSG_EL_0113 113 +#define FC_LOG_MSG_EL_0114 114 +#define FC_LOG_MSG_EL_0115 115 +#define FC_LOG_MSG_EL_0116 116 +#define FC_LOG_MSG_EL_0117 117 +#define FC_LOG_MSG_EL_0118 118 +#define FC_LOG_MSG_EL_0119 119 +#define FC_LOG_MSG_EL_0120 120 +#define FC_LOG_MSG_EL_0121 121 +#define FC_LOG_MSG_EL_0122 122 +#define FC_LOG_MSG_EL_0123 123 +#define FC_LOG_MSG_EL_0124 124 +#define FC_LOG_MSG_EL_0125 125 +#define FC_LOG_MSG_EL_0126 126 +#define FC_LOG_MSG_EL_0127 127 +#define FC_LOG_MSG_EL_0128 128 +#define FC_LOG_MSG_EL_0129 129 +#define FC_LOG_MSG_EL_0130 130 +#define FC_LOG_MSG_EL_0131 131 +#define FC_LOG_MSG_EL_0132 132 +#define FC_LOG_MSG_EL_0133 133 +#define FC_LOG_MSG_EL_0134 134 +#define FC_LOG_MSG_EL_0135 135 +#define FC_LOG_MSG_EL_0136 136 + +/* DISCOVERY LOG Message Numbers */ +#define FC_LOG_MSG_DI_0200 200 +#define FC_LOG_MSG_DI_0201 201 +#define FC_LOG_MSG_DI_0202 202 +#define FC_LOG_MSG_DI_0203 203 +#define FC_LOG_MSG_DI_0204 204 +#define FC_LOG_MSG_DI_0205 205 +#define FC_LOG_MSG_DI_0206 206 +#define FC_LOG_MSG_DI_0207 207 +#define FC_LOG_MSG_DI_0208 208 +#define FC_LOG_MSG_DI_0209 209 +#define FC_LOG_MSG_DI_0210 210 +#define FC_LOG_MSG_DI_0211 211 +#define FC_LOG_MSG_DI_0212 212 +#define FC_LOG_MSG_DI_0213 213 +#define FC_LOG_MSG_DI_0214 214 +#define FC_LOG_MSG_DI_0215 215 +#define FC_LOG_MSG_DI_0216 216 +#define FC_LOG_MSG_DI_0217 217 +#define FC_LOG_MSG_DI_0218 218 +#define FC_LOG_MSG_DI_0219 219 +#define FC_LOG_MSG_DI_0220 220 +#define FC_LOG_MSG_DI_0221 221 +#define FC_LOG_MSG_DI_0222 222 +#define FC_LOG_MSG_DI_0223 223 +#define FC_LOG_MSG_DI_0224 224 +#define FC_LOG_MSG_DI_0225 225 +#define FC_LOG_MSG_DI_0226 226 +#define FC_LOG_MSG_DI_0227 227 +#define FC_LOG_MSG_DI_0228 228 +#define FC_LOG_MSG_DI_0229 229 +#define FC_LOG_MSG_DI_0230 230 +#define FC_LOG_MSG_DI_0231 231 +#define FC_LOG_MSG_DI_0232 232 +#define FC_LOG_MSG_DI_0233 233 +#define FC_LOG_MSG_DI_0234 234 +#define FC_LOG_MSG_DI_0235 235 +#define FC_LOG_MSG_DI_0236 236 +#define FC_LOG_MSG_DI_0237 237 +#define FC_LOG_MSG_DI_0238 238 +#define FC_LOG_MSG_DI_0239 239 +#define FC_LOG_MSG_DI_0240 240 +#define FC_LOG_MSG_DI_0241 241 +#define FC_LOG_MSG_DI_0242 242 +#define FC_LOG_MSG_DI_0243 243 +#define FC_LOG_MSG_DI_0244 244 +#define FC_LOG_MSG_DI_0245 245 +#define FC_LOG_MSG_DI_0246 246 +#define FC_LOG_MSG_DI_0247 247 +#define FC_LOG_MSG_DI_0248 248 +#define FC_LOG_MSG_DI_0249 249 +#define FC_LOG_MSG_DI_0250 250 +#define FC_LOG_MSG_DI_0251 251 +#define FC_LOG_MSG_DI_0252 252 + +/* MAILBOX LOG Message Numbers */ +#define FC_LOG_MSG_MB_0300 300 +#define FC_LOG_MSG_MB_0301 301 +#define FC_LOG_MSG_MB_0302 302 +#define FC_LOG_MSG_MB_0303 303 +#define FC_LOG_MSG_MB_0304 304 +#define FC_LOG_MSG_MB_0305 305 +#define FC_LOG_MSG_MB_0306 306 +#define FC_LOG_MSG_MB_0307 307 +#define FC_LOG_MSG_MB_0308 308 +#define FC_LOG_MSG_MB_0309 309 +#define FC_LOG_MSG_MB_0310 310 +#define FC_LOG_MSG_MB_0311 311 +#define FC_LOG_MSG_MB_0312 312 + +/* INIT LOG Message Numbers */ +#define FC_LOG_MSG_IN_0400 400 +#define FC_LOG_MSG_IN_0401 401 +#define FC_LOG_MSG_IN_0402 402 +#define FC_LOG_MSG_IN_0403 403 +#define FC_LOG_MSG_IN_0404 404 +#define FC_LOG_MSG_IN_0405 405 +#define FC_LOG_MSG_IN_0406 406 +#define FC_LOG_MSG_IN_0407 407 +#define FC_LOG_MSG_IN_0408 408 +#define FC_LOG_MSG_IN_0409 409 +#define FC_LOG_MSG_IN_0410 410 +#define FC_LOG_MSG_IN_0411 411 +#define FC_LOG_MSG_IN_0412 412 +#define FC_LOG_MSG_IN_0413 413 +#define FC_LOG_MSG_IN_0414 414 +#define FC_LOG_MSG_IN_0415 415 +#define FC_LOG_MSG_IN_0416 416 +#define FC_LOG_MSG_IN_0417 417 +#define FC_LOG_MSG_IN_0418 418 +#define FC_LOG_MSG_IN_0419 419 +#define FC_LOG_MSG_IN_0420 420 +#define FC_LOG_MSG_IN_0421 421 +#define FC_LOG_MSG_IN_0422 422 +#define FC_LOG_MSG_IN_0423 423 +#define FC_LOG_MSG_IN_0424 424 +#define FC_LOG_MSG_IN_0425 425 +#define FC_LOG_MSG_IN_0426 426 +#define FC_LOG_MSG_IN_0427 427 +#define FC_LOG_MSG_IN_0428 428 +#define FC_LOG_MSG_IN_0429 429 +#define FC_LOG_MSG_IN_0430 430 +#define FC_LOG_MSG_IN_0431 431 +#define FC_LOG_MSG_IN_0432 432 +#define FC_LOG_MSG_IN_0433 433 +#define FC_LOG_MSG_IN_0434 434 +#define FC_LOG_MSG_IN_0435 435 +#define FC_LOG_MSG_IN_0436 436 +#define FC_LOG_MSG_IN_0437 437 +#define FC_LOG_MSG_IN_0438 438 +#define FC_LOG_MSG_IN_0439 439 +#define FC_LOG_MSG_IN_0440 440 +#define FC_LOG_MSG_IN_0441 441 +#define FC_LOG_MSG_IN_0442 442 +#define FC_LOG_MSG_IN_0443 443 +#define FC_LOG_MSG_IN_0444 444 +#define FC_LOG_MSG_IN_0445 445 +#define FC_LOG_MSG_IN_0446 446 +#define FC_LOG_MSG_IN_0447 447 +#define FC_LOG_MSG_IN_0448 448 +#define FC_LOG_MSG_IN_0449 449 +#define FC_LOG_MSG_IN_0450 450 +#define FC_LOG_MSG_IN_0451 451 +#define FC_LOG_MSG_IN_0452 452 +#define FC_LOG_MSG_IN_0453 453 +#define FC_LOG_MSG_IN_0454 454 +#define FC_LOG_MSG_IN_0455 455 +#define FC_LOG_MSG_IN_0456 456 +#define FC_LOG_MSG_IN_0457 457 +#define FC_LOG_MSG_IN_0458 458 +#define FC_LOG_MSG_IN_0459 459 +#define FC_LOG_MSG_IN_0460 460 +#define FC_LOG_MSG_IN_0461 461 + +/* UNUSED */ +/* +#define FC_LOG_MSG_IN_0500 500 +*/ + +/* IP LOG Message Numbers */ +#define FC_LOG_MSG_IP_0600 600 +#define FC_LOG_MSG_IP_0601 601 +#define FC_LOG_MSG_IP_0602 602 +#define FC_LOG_MSG_IP_0603 603 +#define FC_LOG_MSG_IP_0604 604 +#define FC_LOG_MSG_IP_0605 605 +#define FC_LOG_MSG_IP_0606 606 +#define FC_LOG_MSG_IP_0607 607 +#define FC_LOG_MSG_IP_0608 608 + +/* FCP LOG Message Numbers */ +#define FC_LOG_MSG_FP_0700 700 +#define FC_LOG_MSG_FP_0701 701 +#define FC_LOG_MSG_FP_0702 702 +#define FC_LOG_MSG_FP_0703 703 +#define FC_LOG_MSG_FP_0704 704 +#define FC_LOG_MSG_FP_0705 705 +#define FC_LOG_MSG_FP_0706 706 +#define FC_LOG_MSG_FP_0707 707 +#define FC_LOG_MSG_FP_0708 708 +#define FC_LOG_MSG_FP_0709 709 +#define FC_LOG_MSG_FP_0710 710 +#define FC_LOG_MSG_FP_0711 711 +#define FC_LOG_MSG_FP_0712 712 +#define FC_LOG_MSG_FP_0713 713 +#define FC_LOG_MSG_FP_0714 714 +#define FC_LOG_MSG_FP_0715 715 +#define FC_LOG_MSG_FP_0716 716 +#define FC_LOG_MSG_FP_0717 717 +#define FC_LOG_MSG_FP_0718 718 +#define FC_LOG_MSG_FP_0719 719 +#define FC_LOG_MSG_FP_0720 720 +#define FC_LOG_MSG_FP_0721 721 +#define FC_LOG_MSG_FP_0722 722 +#define FC_LOG_MSG_FP_0723 723 +#define FC_LOG_MSG_FP_0724 724 +#define FC_LOG_MSG_FP_0725 725 +#define FC_LOG_MSG_FP_0726 726 +#define FC_LOG_MSG_FP_0727 727 +#define FC_LOG_MSG_FP_0728 728 +#define FC_LOG_MSG_FP_0729 729 +#define FC_LOG_MSG_FP_0730 730 +#define FC_LOG_MSG_FP_0731 731 +#define FC_LOG_MSG_FP_0732 732 +#define FC_LOG_MSG_FP_0733 733 +#define FC_LOG_MSG_FP_0734 734 +#define FC_LOG_MSG_FP_0735 735 +#define FC_LOG_MSG_FP_0736 736 +#define FC_LOG_MSG_FP_0737 737 +#define FC_LOG_MSG_FP_0738 738 +#define FC_LOG_MSG_FP_0739 739 +#define FC_LOG_MSG_FP_0740 740 +#define FC_LOG_MSG_FP_0741 741 +#define FC_LOG_MSG_FP_0742 742 +#define FC_LOG_MSG_FP_0743 743 +#define FC_LOG_MSG_FP_0744 744 +#define FC_LOG_MSG_FP_0745 745 +#define FC_LOG_MSG_FP_0746 746 +#define FC_LOG_MSG_FP_0747 747 +#define FC_LOG_MSG_FP_0748 748 +#define FC_LOG_MSG_FP_0749 749 +#define FC_LOG_MSG_FP_0750 750 +#define FC_LOG_MSG_FP_0751 751 +#define FC_LOG_MSG_FP_0752 752 +#define FC_LOG_MSG_FP_0753 753 +#define FC_LOG_MSG_FP_0754 754 +#define FC_LOG_MSG_FP_0756 756 + +/* UNUSED */ +/* +#define FC_LOG_MSG_FP_0800 800 +*/ + +/* NODE LOG Message Numbers */ +#define FC_LOG_MSG_ND_0900 900 +#define FC_LOG_MSG_ND_0901 901 +#define FC_LOG_MSG_ND_0902 902 +#define FC_LOG_MSG_ND_0903 903 +#define FC_LOG_MSG_ND_0904 904 +#define FC_LOG_MSG_ND_0905 905 +#define FC_LOG_MSG_ND_0906 906 +#define FC_LOG_MSG_ND_0907 907 +#define FC_LOG_MSG_ND_0908 908 +#define FC_LOG_MSG_ND_0909 909 +#define FC_LOG_MSG_ND_0910 910 +#define FC_LOG_MSG_ND_0911 911 +#define FC_LOG_MSG_ND_0912 912 +#define FC_LOG_MSG_ND_0913 913 +#define FC_LOG_MSG_ND_0914 914 +#define FC_LOG_MSG_ND_0915 915 +#define FC_LOG_MSG_ND_0916 916 +#define FC_LOG_MSG_ND_0917 917 +#define FC_LOG_MSG_ND_0918 918 +#define FC_LOG_MSG_ND_0919 919 +#define FC_LOG_MSG_ND_0920 920 +#define FC_LOG_MSG_ND_0921 921 +#define FC_LOG_MSG_ND_0922 922 +#define FC_LOG_MSG_ND_0923 923 +#define FC_LOG_MSG_ND_0924 924 +#define FC_LOG_MSG_ND_0925 925 +#define FC_LOG_MSG_ND_0926 926 +#define FC_LOG_MSG_ND_0927 927 +#define FC_LOG_MSG_ND_0928 928 + + + +/* MISC LOG Message Numbers */ +#define FC_LOG_MSG_MI_1200 1200 +#define FC_LOG_MSG_MI_1201 1201 +#define FC_LOG_MSG_MI_1202 1202 +#define FC_LOG_MSG_MI_1203 1203 +#define FC_LOG_MSG_MI_1204 1204 +#define FC_LOG_MSG_MI_1205 1205 +#define FC_LOG_MSG_MI_1206 1206 +#define FC_LOG_MSG_MI_1207 1207 +#define FC_LOG_MSG_MI_1208 1208 +#define FC_LOG_MSG_MI_1209 1209 +#define FC_LOG_MSG_MI_1210 1210 +#define FC_LOG_MSG_MI_1211 1211 +#define FC_LOG_MSG_MI_1212 1212 +#define FC_LOG_MSG_MI_1213 1213 + +/* LINK LOG Message Numbers */ +#define FC_LOG_MSG_LK_1300 1300 +#define FC_LOG_MSG_LK_1301 1301 +#define FC_LOG_MSG_LK_1302 1302 +#define FC_LOG_MSG_LK_1303 1303 +#define FC_LOG_MSG_LK_1304 1304 +#define FC_LOG_MSG_LK_1305 1305 +#define FC_LOG_MSG_LK_1306 1306 +#define FC_LOG_MSG_LK_1307 1307 + +/* SLI LOG Message Numbers */ +#define FC_LOG_MSG_LK_1400 1400 +#define FC_LOG_MSG_LK_1401 1401 +#define FC_LOG_MSG_LK_1402 1402 + +/* CHK COMDITION LOG Message Numbers */ +/* +#define FC_LOG_MSG_LK_1500 1500 +*/ +#endif /* _H_FCMSG */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/fcmsgcom.c 830-ivtv/drivers/scsi/lpfc/fcmsgcom.c --- 000-virgin/drivers/scsi/lpfc/fcmsgcom.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/fcmsgcom.c Thu Jan 8 10:21:53 2004 @@ -0,0 +1,6231 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Enterprise Fibre Channel Host Bus Adapters. * + * Refer to the README file included with this package for * + * driver version and adapter support. * + * Copyright (C) 2003 Emulex Corporation. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details, a copy of which * + * can be found in the file COPYING included with this package. * + *******************************************************************/ + +/* +LOG Message Preamble Strings + +Preamble strings are displayed at the start of LOG messages. +The 3rd letter of the preamble string identifies the +message type as follows: + +i = Information fc_msgPreamble??i where i = Information +w = Warning fc_msgPreamble??w where w = Warning +c = Error config fc_msgPreamble??c where c = Error config +e = Error fc_msgPreamble??e where e = Error +p = Panic fc_msgPreamble??p where p = Panic +*/ + +/* ELS Log Message Preamble Strings - 100 */ +char fc_msgPreambleELi[] = "ELi:"; /* ELS Information */ +char fc_msgPreambleELw[] = "ELw:"; /* ELS Warning */ +char fc_msgPreambleELe[] = "ELe:"; /* ELS Error */ +char fc_msgPreambleELp[] = "ELp:"; /* ELS Panic */ + +/* DISCOVERY Log Message Preamble Strings - 200 */ +char fc_msgPreambleDIi[] = "DIi:"; /* Discovery Information */ +char fc_msgPreambleDIw[] = "DIw:"; /* Discovery Warning */ +char fc_msgPreambleDIe[] = "DIe:"; /* Discovery Error */ +char fc_msgPreambleDIp[] = "DIp:"; /* Discovery Panic */ + +/* MAIBOX Log Message Preamble Strings - 300 */ +char fc_msgPreambleMBi[] = "MBi:"; /* Mailbox Information */ +char fc_msgPreambleMBw[] = "MBw:"; /* Mailbox Warning */ +char fc_msgPreambleMBe[] = "MBe:"; /* Mailbox Error */ +char fc_msgPreambleMBp[] = "MBp:"; /* Mailbox Panic */ + +/* INIT Log Message Preamble Strings - 400, 500 */ +char fc_msgPreambleINi[] = "INi:"; /* INIT Information */ +char fc_msgPreambleINw[] = "INw:"; /* INIT Warning */ +char fc_msgPreambleINc[] = "INc:"; /* INIT Error Config*/ +char fc_msgPreambleINe[] = "INe:"; /* INIT Error */ +char fc_msgPreambleINp[] = "INp:"; /* INIT Panic */ + +/* IP Log Message Preamble Strings - 600 */ +char fc_msgPreambleIPi[] = "IPi:"; /* IP Information */ +char fc_msgPreambleIPw[] = "IPw:"; /* IP Warning */ +char fc_msgPreambleIPe[] = "IPe:"; /* IP Error */ +char fc_msgPreambleIPp[] = "IPp:"; /* IP Panic */ + +/* FCP Log Message Preamble Strings - 700, 800 */ +char fc_msgPreambleFPi[] = "FPi:"; /* FP Information */ +char fc_msgPreambleFPw[] = "FPw:"; /* FP Warning */ +char fc_msgPreambleFPe[] = "FPe:"; /* FP Error */ +char fc_msgPreambleFPp[] = "FPp:"; /* FP Panic */ + +/* NODE Log Message Preamble Strings - 900 */ +char fc_msgPreambleNDi[] = "NDi:"; /* Node Information */ +char fc_msgPreambleNDe[] = "NDe:"; /* Node Error */ +char fc_msgPreambleNDp[] = "NDp:"; /* Node Panic */ + + + +/* MISC Log Message Preamble Strings - 1200 */ +char fc_msgPreambleMIi[] = "MIi:"; /* MISC Information */ +char fc_msgPreambleMIw[] = "MIw:"; /* MISC Warning */ +char fc_msgPreambleMIc[] = "MIc:"; /* MISC Error Config */ +char fc_msgPreambleMIe[] = "MIe:"; /* MISC Error */ +char fc_msgPreambleMIp[] = "MIp:"; /* MISC Panic */ + +/* Link Log Message Preamble Strings - 1300 */ +char fc_msgPreambleLKi[] = "LKi:"; /* Link Information */ +char fc_msgPreambleLKw[] = "LKw:"; /* Link Warning */ +char fc_msgPreambleLKe[] = "LKe:"; /* Link Error */ +char fc_msgPreambleLKp[] = "Lkp:"; /* Link Panic */ + +/* SLI Log Message Preamble Strings - 1400 */ +char fc_msgPreambleSLe[] = "SLe:"; /* SLI Error */ + +/* CHECK CONDITION Log Message Preamble Strings - 1500 */ +char fc_msgPreambleCKi[] = "CKi:"; /* Check Condition Information */ +char fc_msgPreambleCKe[] = "CKe:"; /* Check Condition Error */ +char fc_msgPreambleCKp[] = "CKp:"; /* Check Condition Panic */ + + +/* + * Begin ELS LOG message structures + */ + +/* +msgName: fc_mes0100 +message: Abort delay xmit clock +descript: The driver is canceling the delay timer for sending an ELS + command. +data: (1) did (2) remoteID (3) ulpIoTag +severity: Warning +log: LOG_ELS verbose +module: fcclockb.c +action: None required +*/ +char fc_mes0100[] = "%sAbort delay xmit clock Data: x%x x%x x%x"; +msgLogDef fc_msgBlk0100 = { + FC_LOG_MSG_EL_0100, /* LOG message number */ + fc_mes0100, /* LOG message pointer */ + fc_msgPreambleELw, /* LOG message preamble pointer */ + FC_MSG_OPUT_GLOB_CTRL, /* LOG message output control */ + FC_LOG_MSG_TYPE_WARN, /* LOG message type */ + LOG_ELS, /* LOG message mask & group */ + ERRID_LOG_UNEXPECT_EVENT }; /* LOG message error ID */ + +/* +msgName: fc_mes0101 +message: Abort delay xmit context +descript: The driver is canceling the delay timer for sending an ELS + command. +data: (1) did (2) remoteID (3) ulpIoTag +severity: Warning +log: LOG_ELS verbose +module: fcclockb.c +action: None required +*/ +char fc_mes0101[] = "%sAbort delay xmit context Data: x%x x%x x%x"; +msgLogDef fc_msgBlk0101 = { + FC_LOG_MSG_EL_0101, + fc_mes0101, + fc_msgPreambleELw, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_WARN, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0102 +message: Stray ELS completion +descript: Received an ELS command completion without issuing a + corresponding ELS Command (based on the IOTAG field + in the CMD_ELS_REQUEST_CR IOCB). +data: (1) ulpCommand (2) ulpIoTag +severity: Error +log: Always +module: fcelsb.c +action: This error could indicate a software driver or firmware + problem. If problems persist report these errors to + Technical Support. +*/ +char fc_mes0102[] = "%sStray ELS completion Data: x%x x%x"; +msgLogDef fc_msgBlk0102 = { + FC_LOG_MSG_EL_0102, + fc_mes0102, + fc_msgPreambleELe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0103 +message: Dropping ELS rsp +descript: Dropping ELS response because there is no node table entry. +data: (1) ldata (2) ldid +severity: Error +log: Always +module: fcscsib.c +action: This error could indicate a software driver or firmware + problem. If problems persist report these errors to + Technical Support. +*/ +char fc_mes0103[] = "%sDropping ELS rsp Data: x%x x%x"; +msgLogDef fc_msgBlk0103 = { + FC_LOG_MSG_EL_0103, + fc_mes0103, + fc_msgPreambleELe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0104 +message: Aborted ELS IOCB +descript: Driver decided to abort any action taken as a result of this ELS + command completing. +data: (1) ulpCommand (2) ulpIoTag +severity: Information +log: LOG_ELS verbose +module: fcelsb.c +action: None required. +*/ +char fc_mes0104[] = "%sAborted ELS IOCB Data: x%x x%x"; +msgLogDef fc_msgBlk0104 = { + FC_LOG_MSG_EL_0104, + fc_mes0104, + fc_msgPreambleELi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0105 +message: ELS completion +descript: Adapter has notified the driver of ELS command completion. +data: (1) ulpCommand (2) ulpIoTag (3) ulpStatus (4) ulpWord[4] +severity: Information +log: LOG_ELS verbose +module: fcelsb.c +action: None required. +*/ +char fc_mes0105[] = "%sELS completion Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0105 = { + FC_LOG_MSG_EL_0105, + fc_mes0105, + fc_msgPreambleELi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0106 +message: Unknown ELS command +descript: Received an unknown ELS command completion. +data: None +severity: Error +log: Always +module: fcelsb.c +action: This error could indicate a software driver or firmware + problem. If problems persist report these errors to + Technical Support. +*/ +char fc_mes0106[] = "%sUnknown ELS command x%x"; +msgLogDef fc_msgBlk0106 = { + FC_LOG_MSG_EL_0106, + fc_mes0106, + fc_msgPreambleELe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0107 +message: ELS command completion error +descript: A driver initiated ELS command completed with an error status. +data: (1) ulpCommand (2) ulpStatus (3) ulpWord[4] (4) ulpWord[5] +severity: Information +log: LOG_ELS verbose +module: fcelsb.c +action: None required +*/ +char fc_mes0107[] = "%sELS command completion error Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0107 = { + FC_LOG_MSG_EL_0107, + fc_mes0107, + fc_msgPreambleELi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0108 +message: ELS response completion error +descript: An ELS response sent in response to a received ELS command + completed with an error status. +data: (1) ulpCommand (2) ulpStatus (3) ulpWord[4] (4) ulpWord[5] +severity: Information +log: LOG_ELS verbose +module: fcelsb.c +action: None required. +*/ +char fc_mes0108[] = "%sELS response completion error Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0108 = { + FC_LOG_MSG_EL_0108, + fc_mes0108, + fc_msgPreambleELi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0109 +message: ELS response completion +descript: An ELS response sent in response to a received ELS command + completed successfully. +data: (1) nlp_DID (2) nlp_type (3) nlp_flag (4) nlp_state +severity: Information +log: LOG_ELS verbose +module: fcelsb.c +action: None required +*/ +char fc_mes0109[] = "%sELS response completion Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0109 = { + FC_LOG_MSG_EL_0109, + fc_mes0109, + fc_msgPreambleELi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0110 +message: ELS command completion error +descript: Adapter has notified the driver of ELS command completion. +data: (1) command (2) ulpStatus (3) ulpWord[4] (4) ulpWord[5] +severity: Information +log: LOG_ELS verbose +module: fcelsb.c +action: None required +*/ +char fc_mes0110[] = "%sELS command completion error Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0110 = { + FC_LOG_MSG_EL_0110, + fc_mes0110, + fc_msgPreambleELi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0111 +message: Unknown ELS command +descript: Received an unknown ELS command completion. +data: None +severity: Error +log: Always +module: fcelsb.c +action: This error could indicate a software driver or firmware + problem. If problems persist report these errors to + Technical Support. +*/ +char fc_mes0111[] = "%sUnknown ELS command x%x"; +msgLogDef fc_msgBlk0111 = { + FC_LOG_MSG_EL_0111, + fc_mes0111, + fc_msgPreambleELe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0112 +message: PLOGI completes successfully +descript: A PLOGI to a Fibre Channel NPORT completed successfully +data: (1) remoteID (2) ulpWord[4] (3) ulpWord[5] (4) fc_ffstate +severity: Information +log: LOG_ELS verbose +module: fcelsb.c +action: None required +*/ +char fc_mes0112[] = "%sPLOGI completes successfully Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0112 = { + FC_LOG_MSG_EL_0112, + fc_mes0112, + fc_msgPreambleELi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0113 +message: PRLI completes successfully +descript: A PRLI to a FCP target completed successfully. +data: (1) remoteID (2) ulpWord[4] (3) ulpWord[5] (4) fc_ffstate +severity: Information +log: LOG_ELS & LOG_DISCOVERY verbose +module: fcelsb.c +action: None required. +*/ +char fc_mes0113[] = "%sPRLI completes successfully Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0113 = { + FC_LOG_MSG_EL_0113, + fc_mes0113, + fc_msgPreambleELi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_ELS | LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0114 +message: PRLO completes successfully +descript: A PRLO to a FCP target completed successfully. +data: (1) remoteID (2) ulpWord[4] (3) ulpWord[5] (4) fc_ffstate +severity: Information +severity: Information +log: LOG_ELS ELS & LOG_DISCOVERY verbose +module: fcelsb.c +action: None required. +*/ +char fc_mes0114[] = "%sPRLO completes successfully Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0114 = { + FC_LOG_MSG_EL_0114, + fc_mes0114, + fc_msgPreambleELi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0115 +message: LOGO completes successfully +descript: A LOGO to a FCP target completed successfully. +data: (1) remoteID (2) ulpWord[4] (3) ulpWord[5] (4) fc_ffstate +severity: Information +log: LOG_ELS ELS & LOG_DISCOVERY verbose +module: fcelsb.c +action: None required. +*/ +char fc_mes0115[] = "%sLOGO completes successfully Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0115 = { + FC_LOG_MSG_EL_0115, + fc_mes0115, + fc_msgPreambleELi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0116 +message: PDISC completes successfully +descript: A PDISC to a FCP target completed successfully. +data: (1) remoteID (2) ulpWord[4] (3) ulpWord[5] (4) fc_ffstate +severity: Information +log: LOG_ELS ELS & LOG_DISCOVERY verbose +module: fcelsb.c +action: None required. +*/ +char fc_mes0116[] = "%sPDISC completes successfully Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0116 = { + FC_LOG_MSG_EL_0116, + fc_mes0116, + fc_msgPreambleELi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0117 +message: ADISC completes successfully +descript: A ADISC to a FCP target completed successfully. +data: (1) remoteID (2) ulpWord[4] (3) ulpWord[5] (4) fc_ffstate +severity: Information +log: ELS or LOG_DISCOVERY verbose +module: fcelsb.c +action: None required. +*/ +char fc_mes0117[] = "%sADISC completes successfully Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0117 = { + FC_LOG_MSG_EL_0117, + fc_mes0117, + fc_msgPreambleELi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0118 +message: FARP completes successfully +descript: A FARP completed successfully. +data: (1) remoteID (2) ulpWord[4] (3) ulpWord[5] (4) command +severity: Information +log: LOG_ELS verbose +module: fcelsb.c +action: None required. +*/ +char fc_mes0118[] = "%sFARP completes successfully Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0118 = { + FC_LOG_MSG_EL_0118, + fc_mes0118, + fc_msgPreambleELi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0119 +message: SCR completes successfully +descript: A SCR completed successfully. +data: (1) remoteID (2) ulpWord[4] (3) ulpWord[5] (4) fc_ffstate +severity: Information +log: LOG_ELS verbose +module: fcelsb.c +action: None required. +*/ +char fc_mes0119[] = "%sSCR completes successfully Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0119 = { + FC_LOG_MSG_EL_0119, + fc_mes0119, + fc_msgPreambleELi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0120 +message: RNID completes successfully +descript: A RNID completed successfully. +data: (1) remoteID (2) ulpWord[4] (3) ulpWord[5] (4) fc_ffstate +severity: Information +log: LOG_ELS verbose +module: fcelsb.c +action: None required. +*/ +char fc_mes0120[] = "%sRNID completes successfully Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0120 = { + FC_LOG_MSG_EL_0120, + fc_mes0120, + fc_msgPreambleELi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0121 +message: Unknown ELS command completed +descript: Received an unknown ELS command completion. +data: None +severity: Error +log: Always +module: fcelsb.c +action: This error could indicate a software driver or firmware + problem. If problems persist report these errors to + Technical Support. +*/ +char fc_mes0121[] = "%sUnknown ELS command x%x completed"; +msgLogDef fc_msgBlk0121 = { + FC_LOG_MSG_EL_0121, + fc_mes0121, + fc_msgPreambleELe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0122 +message: Unknown ELS IOCB +descript: An unknown IOCB command completed in the ELS ring +data: (1) ulpCommand +severity: Error +log: Always +module: fcelsb.c +action: This error could indicate a software driver or firmware + problem. If problems persist report these errors to + Technical Support. +*/ +char fc_mes0122[] = "%sUnknown ELS IOCB Data: x%x"; +msgLogDef fc_msgBlk0122 = { + FC_LOG_MSG_EL_0122, + fc_mes0122, + fc_msgPreambleELe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0123 +message: Received ELS command +descript: An ELS command was received. +data: (1) ulpWord[5] (2) ulpStatus (3) fc_ffstate +severity: Information +log: LOG_ELS verbose +module: fcelsb.c +action: None required +*/ +char fc_mes0123[] = "%sReceived ELS command x%x Data: x%x x%x x%x"; +msgLogDef fc_msgBlk0123 = { + FC_LOG_MSG_EL_0123, + fc_mes0123, + fc_msgPreambleELi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0124 +message: An FLOGI ELS command was received from DID in Loop Mode +descript: While in Loop Mode an unknown or unsupported ELS commnad + was received. +data: None +severity: Error +log: Always +module: fcelsb.c +action: Check device DID +*/ +char fc_mes0124[] = "%sAn FLOGI ELS command x%x was received from DID x%x in Loop Mode"; +msgLogDef fc_msgBlk0124 = { + FC_LOG_MSG_EL_0124, + fc_mes0124, + fc_msgPreambleELe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0125 +message: Received PLOGI command +descript: A PLOGI command was received. +data: (1) nlp_DID (2) nlp_state (3) nlp_flag (4) nlp_Rpi +severity: Information +log: LOG_ELS verbose +module: fcelsb.c +action: None required +*/ +char fc_mes0125[] = "%sReceived PLOGI command Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0125 = { + FC_LOG_MSG_EL_0125, + fc_mes0125, + fc_msgPreambleELi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0126 +message: PLOGI chkparm OK +descript: Received a PLOGI from a remote NPORT and its Fibre Channel service + parameters match this HBA. Request can be accepted. +data: (1) nlp_DID (2) nlp_state (3) nlp_flag (4) nlp_Rpi +severity: Information +log: LOG_ELS verbose +module: fcelsb.c +action: None required +*/ +char fc_mes0126[] = "%sPLOGI chkparm OK Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0126 = { + FC_LOG_MSG_EL_0126, + fc_mes0126, + fc_msgPreambleELi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0127 +message: Unknown ELS command received from NPORT +descript: Received an unsupported ELS command from a remote NPORT. +data: None +severity: Error +log: Always +module: fcelsb.c +action: Check remote NPORT for potential problem. +*/ +char fc_mes0127[] = "%sUnknown ELS command x%x received from NPORT x%x"; +msgLogDef fc_msgBlk0127 = { + FC_LOG_MSG_EL_0127, + fc_mes0127, + fc_msgPreambleELe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0128 +message: Xmit unknown ELS command +descript: The Fibre Channel driver is attempting to send an + unsupported or unknown ELS command. +data: None +severity: Error +log: Always +module: fcelsb.c +action: This error could indicate a software driver or firmware + problem. If problems persist report these errors to + Technical Support. +*/ +char fc_mes0128[] = "%sXmit unknown ELS command x%x"; +msgLogDef fc_msgBlk0128 = { + FC_LOG_MSG_EL_0128, + fc_mes0128, + fc_msgPreambleELe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0129 +message: Xmit ELS command to remote NPORT +descript: Xmit ELS command to remote NPORT +data: (1) icmd->ulpIoTag (2) binfo->fc_ffstate +severity: Information +log: LOG_ELS verbose +module: fcelsb.c +action: None required +*/ +char fc_mes0129[] = "%sXmit ELS command x%x to remote NPORT x%x Data: x%x x%x"; +msgLogDef fc_msgBlk0129 = { + FC_LOG_MSG_EL_0129, + fc_mes0129, + fc_msgPreambleELi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0130 +message: Xmit unknown ELS response (elsCmd> +descript: The Fibre Channel driver is attempting to send an + unsupported or unknown ELS response. +data: None +severity: Error +log: Always +module: fcelsb.c +action: This error could indicate a software driver or firmware + problem. If problems persist report these errors to + Technical Support. +*/ +char fc_mes0130[] = "%sXmit unknown ELS response x%x"; +msgLogDef fc_msgBlk0130 = { + FC_LOG_MSG_EL_0130, + fc_mes0130, + fc_msgPreambleELe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0131 +message: Xmit ELS response to remote NPORT +descript: Xmit ELS response to remote NPORT +data: (1) icmd->ulpIoTag (2) size +severity: Information +log: LOG_ELS verbose +module: fcelsb.c +action: None required +*/ +char fc_mes0131[] = "%sXmit ELS response x%x to remote NPORT x%x Data: x%x x%x"; +msgLogDef fc_msgBlk0131 = { + FC_LOG_MSG_EL_0131, + fc_mes0131, + fc_msgPreambleELi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0132 +message: ELS Retry failed +descript: If an ELS command fails, it may be retried up + to 3 times. This message will be recorded if + the driver gives up retrying a specific ELS + command. +data: (1) ELS command, (2) remote PortID +severity: Information +log: LOG_ELS verbose +module: fcelsb.c +action: If the ELS command is a PRLI, and the destination + PortID is not an FCP Target, no action is required. + Otherwise, check physical connections to Fibre + Channel network and the state of the remote PortID. +*/ +char fc_mes0132[] = "%sELS Retry failed Data: x%x x%x"; +msgLogDef fc_msgBlk0132 = { + FC_LOG_MSG_EL_0132, + fc_mes0132, + fc_msgPreambleELi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0133 +message: Xmit CT response on exchange +descript: Xmit a CT response on the appropriate exchange. +data: (1) ulpIoTag (2) fc_ffstate +severity: Information +log: LOG_ELS verbose +module: fcelsb.c +action: None required +*/ +char fc_mes0133[] = "%sXmit CT response on exchange x%x Data: x%x x%x"; +msgLogDef fc_msgBlk0133 = { + FC_LOG_MSG_EL_0133, + fc_mes0133, + fc_msgPreambleELi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0134 +message: Issue GEN REQ IOCB for NPORT +descript: Issue a GEN REQ IOCB for remote NPORT. These are typically + used for CT request. +data: (1) ulpIoTag (2) fc_ffstate +severity: Information +log: LOG_ELS verbose +module: fcelsb.c +action: None required +*/ +char fc_mes0134[] = "%sIssue GEN REQ IOCB for NPORT x%x Data: x%x x%x"; +msgLogDef fc_msgBlk0134 = { + FC_LOG_MSG_EL_0134, + fc_mes0134, + fc_msgPreambleELi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0135 +message: Issue GEN REQ IOCB for RNID +descript: Issue a GEN REQ IOCB to support an ELS RNID command +data: (1) ulpWord[5] (2) ulpIoTag (3) fc_ffstate +severity: Information +log: LOG_ELS verbose +module: fcelsb.c +action: None required +*/ +char fc_mes0135[] = "%sIssue GEN REQ IOCB for RNID Data: x%x x%x x%x"; +msgLogDef fc_msgBlk0135 = { + FC_LOG_MSG_EL_0135, + fc_mes0135, + fc_msgPreambleELi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0136 +message: Delayxmit ELS command timeout +descript: The delay for issuing an ELS command has expired. The ELS + command is queued to HBA to be xmitted. +data: (1) ulpIoTag (2) retry (3) remoteID +severity: Information +log: LOG_ELS verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0136[] = "%sDelayxmit ELS command x%x timeout Data: x%x x%x x%x"; +msgLogDef fc_msgBlk0136 = { + FC_LOG_MSG_EL_0136, + fc_mes0136, + fc_msgPreambleELi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_ELS, + ERRID_LOG_TIMEOUT }; + +/* + * Begin DSCOVERY LOG Message Structures + */ + +/* +msgName: fc_mes0200 +message: Device Discovery Started +descript: Device discovery / rediscovery after FLOGI or FAN has started. +data: None +severity: Information +log: LOG_DISCOVERY verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0200[] = "%sDevice Discovery Started"; +msgLogDef fc_msgBlk0200 = { + FC_LOG_MSG_DI_0200, + fc_mes0200, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0201 +message: Device Discovery completion error +descript: This indicates an uncorrectable error was encountered + during device (re)discovery after a link up. Fibre + Channel devices will not be accessible if this message + is displayed. +data: None +severity: Error +log: Always +module: fcrpib.c +action: Reboot system. If problem persists, contact Technical + Support. Run with verbose mode on for more details. +*/ +char fc_mes0201[] = "%sDevice Discovery completion error"; +msgLogDef fc_msgBlk0201 = { + FC_LOG_MSG_DI_0201, + fc_mes0201, + fc_msgPreambleDIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0202 +message: Device Discovery Started +descript: Device discovery / rediscovery after FLOGI or FAN has started. +data: None +severity: Information +log: LOG_DISCOVERY verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0202[] = "%sDevice Discovery Started"; +msgLogDef fc_msgBlk0202 = { + FC_LOG_MSG_DI_0202, + fc_mes0202, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0203 +message: Device Discovery continues +descript: Device discovery in process +data: (1) firstndlp (2) fc_ffstate +severity: Information +log: LOG_DISCOVERY verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0203[] = "%sDevice Discovery continues Data: x%x x%x"; +msgLogDef fc_msgBlk0203 = { + FC_LOG_MSG_DI_0203, + fc_mes0203, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0204 +message: Device Discovery completion error +descript: This indicates an uncorrectable error was encountered + during device (re)discovery after a link up. Fibre + Channel devices will not be accessible if this message + is displayed. +data: None +severity: Error +log: Always +module: fcrpib.c +action: Reboot system. If problem persists, contact Technical + Support. Run with verbose mode on for more details. +*/ +char fc_mes0204[] = "%sDevice Discovery completion error"; +msgLogDef fc_msgBlk0204 = { + FC_LOG_MSG_DI_0204, + fc_mes0204, + fc_msgPreambleDIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0205 +message: Device Discovery authentication +descript: The driver has marked NPORTs in its none table that require ADISC + for authentication. +data: (1) cnt (2) cnt1 (3) cnt2 +severity: Information +log: LOG_DISCOVERY verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0205[] = "%sDevice Discovery authentication Data: x%x x%x x%x"; +msgLogDef fc_msgBlk0205 = { + FC_LOG_MSG_DI_0205, + fc_mes0205, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0206 +message: Device Discovery completion error +descript: This indicates an uncorrectable error was encountered + during device (re)discovery after a link up. Fibre + Channel devices will not be accessible if this message + is displayed. +data: (1) ulpStatus (2) ulpWord[4] (3) ulpWord[5] +severity: Error +log: Always +module: fcelsb.c +action: Reboot system. If problem persists, contact Technical + Support. Run with verbose mode on for more details. +*/ +char fc_mes0206[] = "%sDevice Discovery completion error Data: x%x x%x x%x"; +msgLogDef fc_msgBlk0206 = { + FC_LOG_MSG_DI_0206, + fc_mes0206, + fc_msgPreambleDIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0207 +message: Device Discovery completion error +descript: This indicates an uncorrectable error was encountered + during device (re)discovery after a link up. Fibre + Channel devices will not be accessible if this message + is displayed. +data: None +severity: Error +log: Always +module: fcelsb.c +action: Reboot system. If problem persists, contact Technical + Support. Run with verbose mode on for more details. +*/ +char fc_mes0207[] = "%sDevice Discovery completion error"; +msgLogDef fc_msgBlk0207 = { + FC_LOG_MSG_DI_0207, + fc_mes0207, + fc_msgPreambleDIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0208 +message: FLOGI completes successfully +descript: Fabric Login completed successfully. +data: (1) ulpWord[4] (2) e_d_tov (3) r_a_tov (4) edtovResolution +severity: Information +log: LOG_DISCOVERY verbose +module: fcelsb.c +action: None required. +*/ +char fc_mes0208[] = "%sFLOGI completes successfully Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0208 = { + FC_LOG_MSG_DI_0208, + fc_mes0208, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0209 +message: Device Discovery completes +descript: This indicates successful completion of device + (re)discovery after a link up. +data: None +severity: Information +log: LOG_DISCOVERY verbose +module: fcelsb.c +action: None required +*/ +char fc_mes0209[] = "%sDevice Discovery completes"; +msgLogDef fc_msgBlk0209 = { + FC_LOG_MSG_DI_0209, + fc_mes0209, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0210 +message: PRLI target assigned +descript: The driver has assigned a SCSI ID to the FCP target. +data: (1) ulpWord[5] (2) nlp_pan (3) nlp_sid +severity: Information +log: LOG_DISCOVERY verbose +module: fcelsb.c +action: None required +*/ +char fc_mes0210[] = "%sPRLI target assigned Data: x%x x%x x%x"; +msgLogDef fc_msgBlk0210 = { + FC_LOG_MSG_DI_0210, + fc_mes0210, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0211 +message: Received RSCN command +descript: The driver has received an RSCN command from the fabric. This + indicates a device was potentially added or removed from the + Fibre Channel network. +data: (1) fc_flag (2) defer_rscn.q_cnt (3) fc_rscn.q_cnt (4) fc_mbox_active +severity: Information +log: LOG_DISCOVERY verbose +module: fcelsb.c +action: None required +*/ +char fc_mes0211[] = "%sReceived RSCN command Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0211 = { + FC_LOG_MSG_DI_0211, + fc_mes0211, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0212 +message: Device Discovery completes +descript: This indicates successful completion of device + (re)discovery after a link up. +data: None +severity: Information +log: LOG_DISCOVERY verbose +module: fcelsb.c +action: None required +*/ +char fc_mes0212[] = "%sDevice Discovery completes"; +msgLogDef fc_msgBlk0212 = { + FC_LOG_MSG_DI_0212, + fc_mes0212, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0213 +message: FAN received +descript: A FAN ELS command was received from a Fabric. +data: (1) ulpWord[4] (2) fc_ffstate +severity: Information +log: LOG_DISCOVERY verbose +module: fcelsb.c +action: None required. +*/ +char fc_mes0213[] = "%sFAN received Data: x%x x%x"; +msgLogDef fc_msgBlk0213 = { + FC_LOG_MSG_DI_0213, + fc_mes0213, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0214 +message: RSCN received +descript: A RSCN ELS command was received from a Fabric. +data: (1) fc_flag (2) i (3) *lp (4) fc_rscn_id_cnt +severity: Information +log: LOG_DISCOVERY verbose +module: fcelsb.c +action: None required. +*/ +char fc_mes0214[] = "%sRSCN received Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0214 = { + FC_LOG_MSG_DI_0214, + fc_mes0214, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0215 +message: RSCN processed +descript: A RSCN ELS command was received from a Fabric and processed. +data: (1) fc_flag (2) cnt (3) fc_rscn_id_cnt (4) fc_ffstate +severity: Information +log: LOG_DISCOVERY verbose +module: fcelsb.c +action: None required. +*/ +char fc_mes0215[] = "%sRSCN processed Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0215 = { + FC_LOG_MSG_DI_0215, + fc_mes0215, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0216 +message: Unknown Identifier in RSCN payload +descript: Typically the identifier in the RSCN payload specifies + a domain, area or a specific NportID. If neither of + these are specified, a warning will be recorded. +data: (1) didp->un.word +severity: Error +log: Always +module: fcelsb.c +action: Potential problem with Fabric. Check with Fabric vendor. +*/ +char fc_mes0216[] = "%sUnknown Identifier in RSCN payload Data: x%x"; +msgLogDef fc_msgBlk0216 = { + FC_LOG_MSG_DI_0216, + fc_mes0216, + fc_msgPreambleDIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0217 +message: Device Discovery completion error +descript: This indicates an uncorrectable error was encountered + during device (re)discovery after a link up. Fibre + Channel devices will not be accessible if this message + is displayed. +data: None +severity: Error +log: Always +module: fcelsb.c +action: Reboot system. If problem persists, contact Technical + Support. Run with verbose mode on for more details. +*/ +char fc_mes0217[] = "%sDevice Discovery completion error"; +msgLogDef fc_msgBlk0217 = { + FC_LOG_MSG_DI_0217, + fc_mes0217, + fc_msgPreambleDIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0218 +message: FDMI Request +descript: The driver is sending an FDMI request to the fabric. +data: (1) cmdcode (2) fc_flag +severity: Information +log: LOG_DISCOVERY verbose +module: fcelsb.c +action: None required. +*/ +char fc_mes0218[] = "%sFDMI Req Data: x%x x%x"; +msgLogDef fc_msgBlk0218 = { + FC_LOG_MSG_DI_0218, + fc_mes0218, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + + +/* +msgName: fc_mes0219 +message: Issue FDMI request failed +descript: Cannot issue FDMI request to HBA. +data: (1) SLI_MGMT_DPRT +severity: Information +log: LOG_DISCOVERY verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0219[] = "%sIssue FDMI request failed Data: x%x"; +msgLogDef fc_msgBlk0219 = { + FC_LOG_MSG_DI_0219, + fc_mes0219, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0220 +message: Device Discovery completion error +descript: This indicates an uncorrectable error was encountered + during device (re)discovery after a link up. Fibre + Channel devices will not be accessible if this message + is displayed. +data: None +severity: Error +log: Always +module: fcscsib.c +action: Reboot system. If problem persists, contact Technical + Support. Run with verbose mode on for more details. +*/ +char fc_mes0220[] = "%sDevice Discovery completion error"; +msgLogDef fc_msgBlk0220 = { + FC_LOG_MSG_DI_0220, + fc_mes0220, + fc_msgPreambleDIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0221 +message: FAN timeout +descript: A link up event was received without the login bit set, + so the driver waits E_D_TOV for the Fabric to send a FAN. + If no FAN if received, a FLOGI will be sent after the timeout. +data: None +severity: Warning +log: LOG_DISCOVERY verbose +module: fcscsib.c +action: None required. The driver recovers from this condition by + issuing a FLOGI to the Fabric. +*/ +char fc_mes0221[] = "%sFAN timeout"; +msgLogDef fc_msgBlk0221 = { + FC_LOG_MSG_DI_0221, + fc_mes0221, + fc_msgPreambleDIw, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_WARN, + LOG_DISCOVERY, + ERRID_LOG_TIMEOUT }; + +/* +msgName: fc_mes0222 +message: Initial FLOGI timeout +descript: The driver is sending initial FLOGI to fabric. +data: None +severity: Error +log: Always +module: fcscsib.c +action: Check Fabric configuration. The driver recovers from this and + continues with device discovery. +*/ +char fc_mes0222[] = "%sInitial FLOGI timeout"; +msgLogDef fc_msgBlk0222 = { + FC_LOG_MSG_DI_0222, + fc_mes0222, + fc_msgPreambleDIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_DISCOVERY, + ERRID_LOG_TIMEOUT }; + +/* +msgName: fc_mes0223 +message: NameServer Registration timeout +descript: Our registration request to the Fabric was not acknowledged + within RATOV. +data: (1) fc_ns_retry (2) fc_max_ns_retry +severity: Error +log: Always +module: fcscsib.c +action: Check Fabric configuration. The driver recovers from this and + continues with device discovery. +*/ +char fc_mes0223[] = "%sNameServer Registration timeout Data: x%x x%x"; +msgLogDef fc_msgBlk0223 = { + FC_LOG_MSG_DI_0223, + fc_mes0223, + fc_msgPreambleDIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_DISCOVERY, + ERRID_LOG_TIMEOUT }; + +/* +msgName: fc_mes0224 +message: NameServer Query timeout +descript: Node authentication timeout, node Discovery timeout. A NameServer + Query to the Fabric or discovery of reported remote NPorts is not + acknowledged within R_A_TOV. +data: (1) fc_ns_retry (2) fc_max_ns_retry +severity: Error +log: Always +module: fcscsib.c +action: Check Fabric configuration. The driver recovers from this and + continues with device discovery. +*/ +char fc_mes0224[] = "%sNameServer Query timeout Data: x%x x%x"; +msgLogDef fc_msgBlk0224 = { + FC_LOG_MSG_DI_0224, + fc_mes0224, + fc_msgPreambleDIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_DISCOVERY, + ERRID_LOG_TIMEOUT }; + +/* +msgName: fc_mes0225 +message: Device Discovery completes +descript: This indicates successful completion of device + (re)discovery after a link up. +data: None +severity: Information +log: LOG_DISCOVERY verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0225[] = "%sDevice Discovery completes"; +msgLogDef fc_msgBlk0225 = { + FC_LOG_MSG_DI_0225, + fc_mes0225, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0226 +message: Device Discovery completion error +descript: This indicates an uncorrectable error was encountered + during device (re)discovery after a link up. Fibre + Channel devices will not be accessible if this message + is displayed. +data: None +severity: Error +log: Always +module: fcscsib.c +action: Reboot system. If problem persists, contact Technical + Support. Run with verbose mode on for more details. +*/ +char fc_mes0226[] = "%sDevice Discovery completion error"; +msgLogDef fc_msgBlk0226 = { + FC_LOG_MSG_DI_0226, + fc_mes0226, + fc_msgPreambleDIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0227 +message: Node Authentication timeout +descript: The driver has lost track of what NPORTs are being authenticated. +data: None +severity: Error +log: Always +module: fcscsib.c +action: None required. Driver should recover from this event. +*/ +char fc_mes0227[] = "%sNode Authentication timeout"; +msgLogDef fc_msgBlk0227 = { + FC_LOG_MSG_DI_0227, + fc_mes0227, + fc_msgPreambleDIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_DISCOVERY, + ERRID_LOG_TIMEOUT }; + +/* +msgName: fc_mes0228 +message: Node Discovery timeout +descript: The driver has lost track of what NPORTs are being discovered. +data: None +severity: Error +log: Always +module: fcscsib.c +action: None required. Driver should recover from this event. +*/ +char fc_mes0228[] = "%sNode Discovery timeout"; +msgLogDef fc_msgBlk0228 = { + FC_LOG_MSG_DI_0228, + fc_mes0228, + fc_msgPreambleDIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_DISCOVERY, + ERRID_LOG_TIMEOUT }; + +/* +msgName: fc_mes0229 +message: Node Discovery timeout +descript: The driver has lost track of what NPORTs are being discovered. +data: (1) nlp_DID (2) nlp_flag (3) nlp_state (4) nlp_type +severity: Error +log: Always +module: fcscsib.c +action: None required. Driver should recover from this event. +*/ +char fc_mes0229[] = "%sNode Discovery timeout Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0229 = { + FC_LOG_MSG_DI_0229, + fc_mes0229, + fc_msgPreambleDIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_DISCOVERY, + ERRID_LOG_TIMEOUT }; + +/* +msgName: fc_mes0230 +message: Device Discovery completion error +descript: This indicates an uncorrectable error was encountered + during device (re)discovery after a link up. Fibre + Channel devices will not be accessible if this message + is displayed. +data: None +severity: Error +log: Always +module: fcscsib.c +action: Reboot system. If problem persists, contact Technical + Support. Run with verbose mode on for more details. +*/ +char fc_mes0230[] = "%sDevice Discovery completion error"; +msgLogDef fc_msgBlk0230 = { + FC_LOG_MSG_DI_0230, + fc_mes0230, + fc_msgPreambleDIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0231 +message: RSCN timeout +descript: The driver has lost track of what NPORTs have RSCNs pending. +data: (1) fc_ns_retry (2) fc_max_ns_retry +severity: Error +log: Always +module: fcscsib.c +action: None required. Driver should recover from this event. +*/ +char fc_mes0231[] = "%sRSCN timeout Data: x%x x%x"; +msgLogDef fc_msgBlk0231 = { + FC_LOG_MSG_DI_0231, + fc_mes0231, + fc_msgPreambleDIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_DISCOVERY, + ERRID_LOG_TIMEOUT }; + +/* +msgName: fc_mes0232 +message: Node RSCN timeout +descript: The driver is cleaning up the node table entry for a node + that had a pending RSCN. +data: (1) nlp_DID (2) nlp_flag (3) nlp_state (4) nlp_type +severity: Error +log: Always +module: fcscsib.c +action: None required. Driver should recover from this event. +*/ +char fc_mes0232[] = "%sNode RSCN timeout Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0232 = { + FC_LOG_MSG_DI_0232, + fc_mes0232, + fc_msgPreambleDIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_DISCOVERY, + ERRID_LOG_TIMEOUT }; + +/* +msgName: fc_mes0233 +message: PT2PT link up timeout +descript: A PLOGI has not been received, within R_A_TOV, after a + successful FLOGI, which indicates our topology is + point-to-point with another NPort. Typically this PLOGI + is used to assign a NPortID. +data: None +severity: Warning +log: LOG_DISCOVERY verbose +module: fcscsib.c +action: None required. Driver will recover by configuring NPortID as 0. +*/ +char fc_mes0233[] = "%sPT2PT link up timeout"; +msgLogDef fc_msgBlk0233 = { + FC_LOG_MSG_DI_0233, + fc_mes0233, + fc_msgPreambleDIw, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_WARN, + LOG_DISCOVERY, + ERRID_LOG_TIMEOUT }; + +/* +msgName: fc_mes0234 +message: Device Discovery completes +descript: This indicates successful completion of device + (re)discovery after a link up. +data: None +severity: Information +log: LOG_DISCOVERY verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0234[] = "%sDevice Discovery completes"; +msgLogDef fc_msgBlk0234 = { + FC_LOG_MSG_DI_0234, + fc_mes0234, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0235 +message: Device Discovery completion error +descript: This indicates an uncorrectable error was encountered + during device (re)discovery after a link up. Fibre + Channel devices will not be accessible if this message + is displayed. +data: None +severity: Error +log: Always +module: fcscsib.c +action: Reboot system. If problem persists, contact Technical + Support. Run with verbose mode on for more details. +*/ +char fc_mes0235[] = "%sDevice Discovery completion error"; +msgLogDef fc_msgBlk0235 = { + FC_LOG_MSG_DI_0235, + fc_mes0235, + fc_msgPreambleDIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0236 +message: NameServer Req +descript: The driver is issuing a nameserver request to the fabric. +data: (1) cmdcode (2) fc_flag (3) fc_rscn_id_cnt +severity: Information +log: LOG_DISCOVERY verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0236[] = "%sNameServer Req Data: x%x x%x x%x"; +msgLogDef fc_msgBlk0236 = { + FC_LOG_MSG_DI_0236, + fc_mes0236, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0237 +message: Unknown Identifier in RSCN list +descript: A RSCN list entry contains an unknown identifier. +data: (1) rscn_did.un.word +severity: Error +log: Always +module: fcscsib.c +action: Potential problem with Fabric. Check with Fabric vendor. +*/ +char fc_mes0237[] = "%sUnknown Identifier in RSCN list Data: x%x"; +msgLogDef fc_msgBlk0237 = { + FC_LOG_MSG_DI_0237, + fc_mes0237, + fc_msgPreambleDIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0238 +message: NameServer Rsp +descript: The driver received a nameserver response. +data: (1) Did (2) nlp_flag (3) fc_flag (4) fc_rscn_id_cnt +severity: Information +log: LOG_DISCOVERY verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0238[] = "%sNameServer Rsp Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0238 = { + FC_LOG_MSG_DI_0238, + fc_mes0238, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0239 +message: NameServer Rsp +descript: The driver received a nameserver response. +data: (1) Did (2) ndlp (3) fc_flag (4) fc_rscn_id_cnt +severity: Information +log: LOG_DISCOVERY verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0239[] = "%sNameServer Rsp Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0239 = { + FC_LOG_MSG_DI_0239, + fc_mes0239, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0240 +message: NameServer Rsp Error +descript: The driver received a nameserver response containig a status error. +data: (1) CommandResponse.bits.CmdRsp (2) ReasonCode (3) Explanation + (4) fc_flag +severity: Information +log: LOG_DISCOVERY verbose +module: fcscsib.c +action: Check Fabric configuration. The driver recovers from this and + continues with device discovery. +*/ +char fc_mes0240[] = "%sNameServer Rsp Error Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0240 = { + FC_LOG_MSG_DI_0240, + fc_mes0240, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0241 +message: NameServer Rsp Error +descript: The driver received a nameserver response containing a status error. +data: (1) CommandResponse.bits.CmdRsp (2) ReasonCode (3) Explanation + (4) fc_flag +severity: Information +log: LOG_DISCOVERY verbose +module: fcscsib.c +action: Check Fabric configuration. The driver recovers from this and + continues with device discovery. +*/ +char fc_mes0241[] = "%sNameServer Rsp Error Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0241 = { + FC_LOG_MSG_DI_0241, + fc_mes0241, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0242 +message: Device Discovery nextnode +descript: The driver continuing with discovery. +data: (1) nlp_state (2) nlp_DID (3) nlp_flag (4) fc_ffstate +severity: Information +log: LOG_DISCOVERY verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0242[] = "%sDevice Discovery nextnode Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0242 = { + FC_LOG_MSG_DI_0242, + fc_mes0242, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0243 +message: Device Discovery nextdisc +descript: The driver continuing with NPORT discovery. +data: (1) fc_nlp_cnt (2) sndcnt (3) fc_mbox_active +severity: Information +log: LOG_DISCOVERY verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0243[] = "%sDevice Discovery nextdisc Data: x%x x%x x%x"; +msgLogDef fc_msgBlk0243 = { + FC_LOG_MSG_DI_0243, + fc_mes0243, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0244 +message: Device Discovery completion error +descript: This indicates an uncorrectable error was encountered + during device (re)discovery after a link up. Fibre + Channel devices will not be accessible if this message + is displayed. +data: None +severity: Error +log: Always +module: fcscsib.c +action: Reboot system. If problem persists, contact Technical + Support. Run with verbose mode on for more details. +*/ +char fc_mes0244[] = "%sDevice Discovery completion error"; +msgLogDef fc_msgBlk0244 = { + FC_LOG_MSG_DI_0244, + fc_mes0244, + fc_msgPreambleDIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0245 +message: Device Discovery next authentication +descript: The driver is continuing with NPORT authentication. +data: (1) fc_nlp_cnt (2) sndcnt (3) fc_mbox_active +severity: Information +log: LOG_DISCOVERY verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0245[] = "%sDevice Discovery next authentication Data: x%x x%x x%x"; +msgLogDef fc_msgBlk0245 = { + FC_LOG_MSG_DI_0245, + fc_mes0245, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0246 +message: Device Discovery next RSCN +descript: The driver is continuing with RSCN processing. +data: (1) fc_nlp_cnt (2) sndcnt (3) fc_mbox_active (4) fc_flag +severity: Information +log: LOG_DISCOVERY verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0246[] = "%sDevice Discovery next RSCN Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0246 = { + FC_LOG_MSG_DI_0246, + fc_mes0246, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0247 +message: Discovery RSCN +descript: The number / type of RSCNs has forced the driver to go to + the nameserver and re-discover all NPORTs. +data: (1) fc_defer_rscn.q_cnt (2) fc_flag (3) fc_rscn_disc_wdt +severity: Information +log: LOG_DISCOVERY verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0247[] = "%sDiscovery RSCN Data: x%x x%x x%x"; +msgLogDef fc_msgBlk0247 = { + FC_LOG_MSG_DI_0247, + fc_mes0247, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0248 +message: Deferred RSCN +descript: The driver has received multiple RSCNs and has deferred the + processing of the most recent RSCN. +data: (1) fc_defer_rscn.q_cnt (2) fc_flag +severity: Information +log: LOG_DISCOVERY verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0248[] = "%sDeferred RSCN Data: x%x x%x"; +msgLogDef fc_msgBlk0248 = { + FC_LOG_MSG_DI_0248, + fc_mes0248, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0249 +message: Device Discovery completes +descript: This indicates successful completion of device + (re)discovery after a link up. +data: (1) fc_flag +severity: Information +log: LOG_DISCOVERY verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0249[] = "%sDevice Discovery completes Data: x%x"; +msgLogDef fc_msgBlk0249 = { + FC_LOG_MSG_DI_0249, + fc_mes0249, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0250 +message: Pending Link Event during Discovery +descript: Received link event during discovery. Causes discovery restart. +data: (1) ulpCommand (2) ulpIoTag (3) ulpStatus (4) ulpWord[4] +severity: Warning +log: LOG_DISCOVERY verbose +module: fcelsb.c +action: None required unless problem persist. If problems persist, check + cabling. +*/ +char fc_mes0250[] = "%sPending Link Event during Discovery Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0250 = { + FC_LOG_MSG_DI_0250, + fc_mes0250, + fc_msgPreambleDIw, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_WARN, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0251 +message: FDMI rsp failed +descript: An error response was received to FDMI request +data: (1) SWAP_DATA16(fdmi_cmd) +severity: Information +log: LOG_DISCOVERY verbose +module: fcelsb.c +action: The fabric does not support FDMI, check fabric configuration. +*/ +char fc_mes0251[] = "%sFDMI rsp failed Data: x%x"; +msgLogDef fc_msgBlk0251 = { + FC_LOG_MSG_DI_0251, + fc_mes0251, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0252 +message: EXPIRED RSCN disc timer +descript: The driver timed out when processing an RSCN command from the + fabric. +data: (1) fc_flag +severity: Information +log: LOG_DISCOVERY | LOG_ELS verbose +module: fcscsib.c +action: This error could indicate a software driver or firmware + problem. If problems persist report these errors to + Technical Support. +*/ +char fc_mes0252[] = "%sEXPIRED RSCN disc timer Data: x%x"; +msgLogDef fc_msgBlk0252 = { + FC_LOG_MSG_DI_0252, + fc_mes0252, + fc_msgPreambleDIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_DISCOVERY | LOG_ELS, + ERRID_LOG_UNEXPECT_EVENT }; + +/* + * Begin MAILBOX LOG Message Structures + */ + +/* +msgName: fc_mes0300 +message: READ_LA: no buffers +descript: The driver attempted to issue READ_LA mailbox command to the HBA + but there were no buffer available. +data: None +severity: Warning +log: LOG_MBOX verbose +module: fcmboxb.c +action: This message indicates (1) a possible lack of memory resources. Try + increasing the lpfc 'num_bufs' configuration parameter to allocate + more buffers. (2) A possble driver buffer management problem. If + this problem persists, report these errors to Technical Support. +*/ +char fc_mes0300[] = "%sREAD_LA: no buffers"; +msgLogDef fc_msgBlk0300 = { + FC_LOG_MSG_MB_0300, + fc_mes0300, + fc_msgPreambleMBw, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_WARN, + LOG_MBOX, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0301 +message: READ_SPARAM: no buffers +descript: The driver attempted to issue READ_SPARAM mailbox command to the + HBA but there were no buffer available. +data: None +severity: Warning +log: LOG_MBOX verbose +module: fcmboxb.c +action: This message indicates (1) a possible lack of memory resources. Try + increasing the lpfc 'num_bufs' configuration parameter to allocate + more buffers. (2) A possble driver buffer management problem. If + this problem persists, report these errors to Technical Support. +*/ +char fc_mes0301[] = "%sREAD_SPARAM: no buffers"; +msgLogDef fc_msgBlk0301 = { + FC_LOG_MSG_MB_0301, + fc_mes0301, + fc_msgPreambleMBw, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_WARN, + LOG_MBOX, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0302 +message: REG_LOGIN: no buffers +descript: The driver attempted to issue REG_LOGIN mailbox command to the HBA + but there were no buffer available. +data: None +severity: Warning +log: LOG_MBOX verbose +module: fcmboxb.c +action: This message indicates (1) a possible lack of memory resources. Try + increasing the lpfc 'num_bufs' configuration parameter to allocate + more buffers. (2) A possble driver buffer management problem. If + this problem persists, report these errors to Technical Support. +*/ +char fc_mes0302[] = "%sREG_LOGIN: no buffers Data x%x x%x"; +msgLogDef fc_msgBlk0302 = { + FC_LOG_MSG_MB_0302, + fc_mes0302, + fc_msgPreambleMBw, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_WARN, + LOG_MBOX, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0303 +message: Adapter initialization error, mbxCmd READ_NVPARM, + mbxStatus +descript: A mailbox command failed during initialization. +data: None +severity: Error +log: Always +module: fcLINUX.c +action: This error could indicate a hardware or firmware problem. If + problems persist report these errors to Technical Support. +*/ +char fc_mes0303[] = "%sAdapter init error, mbxCmd x%x READ_NVPARM, mbxStatus x%x"; +msgLogDef fc_msgBlk0303 = { + FC_LOG_MSG_MB_0303, + fc_mes0303, + fc_msgPreambleINe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_INIT, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0304 +message: Stray Mailbox Interrupt, mbxCommand mbxStatus . +descript: Received a mailbox completion interrupt and there are no + outstanding mailbox commands. +data: None +severity: Error +log: Always +module: lp6000.c +action: This error could indicate a hardware or firmware problem. If + problems persist report these errors to Technical Support. +*/ +char fc_mes0304[] = "%sStray Mailbox Interrupt mbxCommand x%x mbxStatus x%x"; +msgLogDef fc_msgBlk0304 = { + FC_LOG_MSG_MB_0304, + fc_mes0304, + fc_msgPreambleMBe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_MBOX, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0305 +message: Mbox cmd cmpl error - RETRYing +descript: A mailbox command completed with an error status that causes the + driver to reissue the mailbox command. +data: (1) mbxCommand (2) word0 (3) fc_ffstate (4) fc_flag +severity: Information +log: LOG_MBOX verbose +module: lp6000.c +action: None required +*/ +char fc_mes0305[] = "%sMbox cmd cmpl error - RETRYing Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0305 = { + FC_LOG_MSG_MB_0305, + fc_mes0305, + fc_msgPreambleMBi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_MBOX, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0306 +message: Mbox cmd cmpl error +descript: A mailbox command completed with an error status. +data: (1) mbxCommand (2) word0 (3) ff_state (4) fc_flag +severity: Information +log: LOG_MBOX verbose +module: lp6000.c +action: None required +*/ +char fc_mes0306[] = "%sMbox cmd cmpl error Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0306 = { + FC_LOG_MSG_MB_0306, + fc_mes0306, + fc_msgPreambleMBi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_MBOX, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0307 +message: Mbox cmd cmpl +descript: A mailbox command completed.. +data: (1) mbxCommand (2) word0 (3) ff_state (4) fc_flag +severity: Information +log: LOG_MBOX verbose +module: lp6000.c +action: None required +*/ +char fc_mes0307[] = "%sMbox cmd cmpl Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0307 = { + FC_LOG_MSG_MB_0307, + fc_mes0307, + fc_msgPreambleMBi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_MBOX, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0308 +message: Mbox cmd issue - BUSY +descript: The driver attempted to issue a mailbox command while the mailbox + was busy processing the previous command. The processing of the + new command will be deferred until the mailbox becomes available. +data: (1) mbxCommand (2) ff_state (3) fc_flag (4) flag +severity: Information +log: LOG_MBOX verbose +module: lp6000.c +action: None required +*/ +char fc_mes0308[] = "%sMbox cmd issue - BUSY Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0308 = { + FC_LOG_MSG_MB_0308, + fc_mes0308, + fc_msgPreambleMBi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_MBOX, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0309 +message: Mailbox cmd issue +descript: The driver is in the process of issuing a mailbox command. +data: (1) ff_state (2) fc_flag (3) flag +severity: Information +log: LOG_MBOX verbose +module: lp6000.c +action: None required +*/ +char fc_mes0309[] = "%sMailbox cmd x%x issue Data: x%x x%x x%x"; +msgLogDef fc_msgBlk0309 = { + FC_LOG_MSG_MB_0309, + fc_mes0309, + fc_msgPreambleMBi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_MBOX, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0310 +message: Mailbox command timeout, status +descript: A Mailbox command was posted to the adapter and did + not complete within 30 seconds. +data: None +severity: Error +log: Always +module: fcscsib.c +action: This error could indicate a software driver or firmware + problem. If no I/O is going through the adapter, reboot + the system. If these problems persist, report these + errors to Technical Support. +*/ +char fc_mes0310[] = "%sMailbox command x%x timeout, status x%x"; +msgLogDef fc_msgBlk0310 = { + FC_LOG_MSG_MB_0310, + fc_mes0310, + fc_msgPreambleMBe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_MBOX, + ERRID_LOG_TIMEOUT }; + +/* +msgName: fc_mes0311 +message: REG_LOGIN cmpl +descript: REG LOGIN mailbox command completed successfully. +data: (1) nlp_DID (2) nlp_state (3) nlp_flag (4) nlp_Rpi +severity: Information +log: LOG_MBOX verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0311[] = "%sREG_LOGIN cmpl Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0311 = { + FC_LOG_MSG_MB_0311, + fc_mes0311, + fc_msgPreambleMBi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_MBOX, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0312 +message: Unknown Mailbox command completion +descript: An unsupported or illegal Mailbox command completed. +data: None +severity: Error +log: Always +module: fcscsib.c +action: This error could indicate a software driver or firmware + problem. If problems persist report these errors to + Technical Support. +*/ +char fc_mes0312[] = "%sUnknown Mailbox command x%x completion"; +msgLogDef fc_msgBlk0312 = { + FC_LOG_MSG_MB_0312, + fc_mes0312, + fc_msgPreambleMBe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_MBOX, + ERRID_LOG_UNEXPECT_EVENT }; + +/* + * Begin INIT LOG Message Structures + */ + +/* +msgName: fc_mes0400 +message: dfc_ioctl entry +descript: Entry point for processing diagnostic ioctl. +data: (1) c_cmd (2) c_arg1 (3) c_arg2 (4) c_outsz +severity: Information +log: LOG_INIT verbose +module: dfcdd.c +action: None required +*/ +char fc_mes0400[] = "%sdfc_ioctl entry Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0400 = { + FC_LOG_MSG_IN_0400, + fc_mes0400, + fc_msgPreambleINi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_INIT, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0401 +message: dfc_ioctl exit +descript: Exit point for processing diagnostic ioctl. +data: (1) rc (2) c_outsz (3) c_dataout +severity: Information +log: LOG_INIT verbose +module: dfcdd.c +action: None required +*/ +char fc_mes0401[] = "%sdfc_ioctl exit Data: x%x x%x x%x"; +msgLogDef fc_msgBlk0401 = { + FC_LOG_MSG_IN_0401, + fc_mes0401, + fc_msgPreambleINi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_INIT, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0402 +message: dfc_data_alloc +descript: Allocating data buffer to process dfc ioct. +data: (1) fc_dataout (2) fc_outsz +severity: Iniformation +log: LOG_INIT verbose +module: dfcdd.c +action: None required +*/ +char fc_mes0402[] = "%sdfc_data_alloc Data: x%x x%x"; +msgLogDef fc_msgBlk0402 = { + FC_LOG_MSG_IN_0402, + fc_mes0402, + fc_msgPreambleINi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_INIT, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0403 +message: dfc_data_free +descript: Freeing data buffer to process dfc ioct. +data: (1) fc_dataout (2) fc_outsz +severity: Information +log: LOG_INIT verbose +module: dfcdd.c +action: None required +*/ +char fc_mes0403[] = "%sdfc_data_free Data: x%x x%x"; +msgLogDef fc_msgBlk0403 = { + FC_LOG_MSG_IN_0403, + fc_mes0403, + fc_msgPreambleINi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_INIT, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0404 +message: Service Level Interface (SLI) 1 selected +descript: A PART_SLIM (SLI1) mailbox command was issued. +data: None +severity: Information +log: LOG_INIT verbose +module: fcmboxb.c +action: None required. +*/ +char fc_mes0404[] = "%sService Level Interface (SLI) 1 selected"; +msgLogDef fc_msgBlk0404 = { + FC_LOG_MSG_IN_0404, + fc_mes0404, + fc_msgPreambleINi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_INIT, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0405 +message: Service Level Interface (SLI) 2 selected +descript: A CONFIG_PORT (SLI2) mailbox command was issued. +data: None +severity: Information +log: LOG_INIT verbose +module: fcmboxb.c +action: None required. +*/ +char fc_mes0405[] = "%sService Level Interface (SLI) 2 selected"; +msgLogDef fc_msgBlk0405 = { + FC_LOG_MSG_IN_0405, + fc_mes0405, + fc_msgPreambleINi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_INIT, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0406 +message: Memory Buffer Pool is below low water mark +descript: A driver memory buffer pool is low on buffers. +data: (1) seg (2) fc_lowmem (3) low +severity: Warning +log: LOG_INIT verbose +module: fcmemb.c +action: None required. Driver will recover as buffers are returned to pool. +*/ +char fc_mes0406[] = "%sMem Buf Pool is below low water mark Data: x%x x%x x%x"; +msgLogDef fc_msgBlk0406 = { + FC_LOG_MSG_IN_0406, + fc_mes0406, + fc_msgPreambleINw, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_WARN, + LOG_INIT, + ERRID_LOG_NO_RESOURCE }; + +/* +msgName: fc_mes0407 +message: Memory Buffer Pool is corrupted +descript: The buffer address received from the pool is outside + the range of the pool and is therefore corrupt. +data: (1) seg (2) bp (3) fc_memhi (4) fc_memlo +severity: Error +log: Always +module: fcmemb.c +action: This error could indicate a software driver or firmware + problem. If problems persist report these errors to + Technical Support. +*/ +char fc_mes0407[] = "%sMemory Buffer Pool is corrupted Data x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0407 = { + FC_LOG_MSG_IN_0407, + fc_mes0407, + fc_msgPreambleINe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_INIT, + ERRID_LOG_NO_RESOURCE }; + +/* +msgName: fc_mes0408 +message: Memory Buffer Pool is corrupted +descript: The buffer address returned to the pool is outside + the range of the pool and is therefore corrupt. +data: (1) seg (2) bp (3) fc_memhi (4) fc_memlo +severity: Error +log: Always +module: fcmemb.c +action: This error could indicate a software driver or firmware + problem. If problems persist report these errors to + Technical Support. +*/ +char fc_mes0408[] = "%sMemory Buffer Pool is corrupted Data x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0408 = { + FC_LOG_MSG_IN_0408, + fc_mes0408, + fc_msgPreambleINe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_INIT, + ERRID_LOG_NO_RESOURCE }; + +/* +msgName: fc_mes0409 +message: Memory Buffer Pool is out of buffers +descript: A driver memory buffer pool is exhausted. +data: (1) seg (2) fc_free (3) fc_mbox.q_cnt (4) fc_memhi +severity: Error +log: Always +module: fcmemb.c +action: Configure more resources for that buffer pool. If + problems persist report these errors to Technical + Support. +*/ +char fc_mes0409[] = "%sMemory Buffer Pool is out of buffers Data x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0409 = { + FC_LOG_MSG_IN_0409, + fc_mes0409, + fc_msgPreambleINe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_INIT, + ERRID_LOG_NO_RESOURCE }; + +/* +msgName: fc_mes0410 +message: Cannot find virtual addr for mapped buf on ring +descript: The driver cannot find the specified buffer in its + mapping table. Thus it cannot find the virtual address + needed to access the data. +data: (1) mapbp (2) fc_mpoff (3) fc_mpon +severity: Error +log: Always +module: fcmemb.c +action: This error could indicate a software driver or firmware + problem. If problems persist report these errors to + Technical Support. +*/ +char fc_mes0410[] = "%sCannot find virtual addr for mapped buf on ring %d Data x%x x%x x%x"; +msgLogDef fc_msgBlk0410 = { + FC_LOG_MSG_IN_0410, + fc_mes0410, + fc_msgPreambleINe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_INIT, + ERRID_LOG_NO_RESOURCE }; + +/* +msgName: fc_mes0411 +message: Scan-down is 2 with Persistent binding - ignoring scan-down +descript: The configuration parameter for Scan-down conflicts with + Persistent binding parameter. +data: (1) a_current (2) fcp_mapping +severity: Error config +log: Always +module: fcLINUXfcp.c +action: Make neccessary changes to lpfc configuration file. +*/ +char fc_mes0411[] = "%sScan-down is 2 with Persistent binding - ignoring scan-down Data: x%x x%x"; +msgLogDef fc_msgBlk0411 = { + FC_LOG_MSG_IN_0411, + fc_mes0411, + fc_msgPreambleINc, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR_CFG, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0412 +message: Scan-down is out of range - ignoring scan-down +descript: The configuration parameter for Scan-down is out of range. +data: (1) clp[CFG_SCAN_DOWN].a_current (2) fcp_mapping +severity: Error +log: Always +module: fcLINUXfcp.c +action: Make neccessary changes to lpfc configuration file. +*/ +char fc_mes0412[] = "%sScan-down is out of range - ignoring scan-down Data: x%x x%x"; +msgLogDef fc_msgBlk0412 = { + FC_LOG_MSG_IN_0412, + fc_mes0412, + fc_msgPreambleINe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0413 +message: Num-iocbs too low, resetting +descript: The configuration parameter for Num-iocs is too low, resetting + parameter to default value. +data: (1) a_current (2) LPFC_MIN_NUM_IOCBS +severity: Error config +log: Always +module: fcLINUXfcp.c +action: Make neccessary changes to lpfc configuration file. +*/ +char fc_mes0413[] = "%sNum-iocbs too low, resetting Data: x%x x%x"; +msgLogDef fc_msgBlk0413 = { + FC_LOG_MSG_IN_0413, + fc_mes0413, + fc_msgPreambleINc, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR_CFG, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0414 +message: Num-iocbs too high, resetting +descript: The configuration parameter for Num-iocs is too high, resetting + parameter to default value. +data: (1) clp[CFG_NUM_IOCBS].a_current (2) LPFC_MAX_NUM_IOCBS +severity: Error config +log: Always +module: fcLINUXfcp.c +action: Make neccessary changes to lpfc configuration file. +*/ +char fc_mes0414[] = "%sNum-iocbs too high, resetting Data: x%x x%x"; +msgLogDef fc_msgBlk0414 = { + FC_LOG_MSG_IN_0414, + fc_mes0414, + fc_msgPreambleINc, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR_CFG, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0415 +message: Num-bufs too low, resetting +descript: The configuration parameter for Num-bufs is too low, resetting + parameter to default value. +data: (1) a_current (2) LPFC_MIN_NUM_BUFS +severity: Error config +log: Always +module: fcLINUXfcp.c +action: Make neccessary changes to lpfc configuration file. +*/ +char fc_mes0415[] = "%sNum-bufs too low, resetting Data: x%x x%x"; +msgLogDef fc_msgBlk0415 = { + FC_LOG_MSG_IN_0415, + fc_mes0415, + fc_msgPreambleINc, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR_CFG, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0416 +message: Num-bufs too high, resetting +descript: The configuration parameter for Num-bufs is too high, resetting + parameter to default value. +data: (1) a_current (2) LPFC_MAX_NUM_BUFS +severity: Error config +log: Always +module: fcLINUXfcp.c +action: Make neccessary changes to lpfc configuration file. +*/ +char fc_mes0416[] = "%sNum-bufs too high, resetting Data: x%x x%x"; +msgLogDef fc_msgBlk0416 = { + FC_LOG_MSG_IN_0416, + fc_mes0416, + fc_msgPreambleINc, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR_CFG, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0417 +message: Target qdepth too high, resetting to max +descript: The configuration parameter for Target queue depth is too high, + resetting parameter to default value. +data: (1) a_current (2) LPFC_MAX_TGT_Q_DEPTH +severity: Error config +log: Always +module: fcLINUXfcp.c +action: Make neccessary changes to lpfc configuration file. +*/ +char fc_mes0417[] = "%sTarget qdepth too high, resetting to max Data: x%x x%x"; +msgLogDef fc_msgBlk0417 = { + FC_LOG_MSG_IN_0417, + fc_mes0417, + fc_msgPreambleINc, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR_CFG, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0418 +message: LUN qdepth too high, resetting to max +descript: The configuration parameter for LUN queue depth is too high, + resetting parameter to maximum default value. +data: (1) a_current (2) LPFC_MAX_LUN_Q_DEPTH +severity: Error config +log: Always +module: fcLINUXfcp.c +action: Make neccessary changes to lpfc configuration file. +*/ +char fc_mes0418[] = "%sLUN qdepth too high, resetting to max Data: x%x x%x"; +msgLogDef fc_msgBlk0418 = { + FC_LOG_MSG_IN_0418, + fc_mes0418, + fc_msgPreambleINc, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR_CFG, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0419 +message: LUN qdepth cannot be , resetting to 1 +descript: The configuration parameter for LUN queue depth is set to 0. + Resetting parameter to default value of 1. +data: (1) a_current +severity: Error config +log: Always +module: fcLINUXfcp.c +action: Make neccessary changes to lpfc configuration file. +*/ +char fc_mes0419[] = "%sLUN qdepth cannot be %d, resetting to 1"; +msgLogDef fc_msgBlk0419 = { + FC_LOG_MSG_IN_0419, + fc_mes0419, + fc_msgPreambleINc, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR_CFG, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0420 +message: Fcpfabric_tmo too high, resetting +descript: The configuration parameter for Fcpfabric_tmo is too high, + resetting parameter to default value. +data: (1) a_current (2) LPFC_MAX_FABRIC_TIMEOUT +severity: Error config +log: Always +module: fcLINUXfcp.c +action: Make neccessary changes to lpfc configuration file. +*/ +char fc_mes0420[] = "%sFcpfabric_tmo too high, resetting Data: x%x x%x"; +msgLogDef fc_msgBlk0420 = { + FC_LOG_MSG_IN_0420, + fc_mes0420, + fc_msgPreambleINc, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR_CFG, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0421 +message: Fcp-class is illegal, resetting to default +descript: The configuration parameter for Fcp-class is illegal, resetting + parameter to default value. +data: (1) a_current (2) CLASS3 +severity: Error config +log: Always +module: fcLINUXfcp.c +action: Make neccessary changes to lpfc configuration file. +*/ +char fc_mes0421[] = "%sFcp-class is illegal, resetting Data: x%x x%x"; +msgLogDef fc_msgBlk0421 = { + FC_LOG_MSG_IN_0421, + fc_mes0421, + fc_msgPreambleINc, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR_CFG, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0422 +message: No-device-delay too high, resetting to max +descript: The configuration parameter for No-device-delay is too high, + resetting parameter to maximum default value. +data: (1) a_current (2) LPFC_MAX_NO_DEVICE_DELAY +severity: Error config +log: Always +module: fcLINUXfcp.c +action: Make neccessary changes to lpfc configuration file. +*/ +char fc_mes0422[] = "%sNo-device-delay too high, resetting to max Data: x%x x%x"; +msgLogDef fc_msgBlk0422 = { + FC_LOG_MSG_IN_0422, + fc_mes0422, + fc_msgPreambleINc, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR_CFG, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0423 +message: Post_ip_buf too low, resetting +descript: The configuration parameter for Post_ip_buf is too low, resetting + parameter to default value. +data: (1) a_current (2) LPFC_MIN_POST_IP_BUF +severity: Error config +log: Always +module: fcLINUXfcp.c +action: Make neccessary changes to lpfc configuration file. +*/ +char fc_mes0423[] = "%sPost_ip_buf too low, resetting Data: x%x x%x"; +msgLogDef fc_msgBlk0423 = { + FC_LOG_MSG_IN_0423, + fc_mes0423, + fc_msgPreambleINc, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR_CFG, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0424 +message: Post_ip_buf too high, resetting +descript: The configuration parameter for Post_ip_buf is too high, resetting + parameter to default value. +data: (1) a_current (2) LPFC_MAX_POST_IP_BUF +severity: Error config +log: Always +module: fcLINUXfcp.c +action: Make neccessary changes to lpfc configuration file. +*/ +char fc_mes0424[] = "%sPost_ip_buf too high, resetting Data: x%x x%x"; +msgLogDef fc_msgBlk0424 = { + FC_LOG_MSG_IN_0424, + fc_mes0424, + fc_msgPreambleINc, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR_CFG, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0425 +message: Xmt-que_size too low, resetting +descript: The configuration parameter for Xmt-que_size is too low, resetting + parameter to default value. +data: (1) a_current (2) LPFC_MIN_XMT_QUE_SIZE +severity: Error config +log: Always +module: fcLINUXcp.c +action: Make neccessary changes to lpfc configuration file. +*/ +char fc_mes0425[] = "%sXmt-que_size too low, resetting Data: x%x x%x"; +msgLogDef fc_msgBlk0425 = { + FC_LOG_MSG_IN_0425, + fc_mes0425, + fc_msgPreambleINc, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR_CFG, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0426 +message: Xmt-que_size too high, resetting +descript: The configuration parameter for Xmt-que_size is too high, resetting + parameter to default value. +data: (1) a_current (2) LPFC_MAX_XMT_QUE_SIZE +severity: Error config +log: Always +module: fcLINUXfcp.c +action: Make neccessary changes to lpfc configuration file. +*/ +char fc_mes0426[] = "%sXmt-que_size too high, resetting Data: x%x x%x"; +msgLogDef fc_msgBlk0426 = { + FC_LOG_MSG_IN_0426, + fc_mes0426, + fc_msgPreambleINc, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR_CFG, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0427 +message: Ip-class is illegal, resetting +descript: The configuration parameter for Ip-class is illegal, resetting + parameter to default value. +data: (1) a_current (2) CLASS3 +severity: Error config +log: Always +module: fcLINUXfcp.c +action: Make neccessary changes to lpfc configuration file. +*/ +char fc_mes0427[] = "%sIp-class is illegal, resetting Data: x%x x%x"; +msgLogDef fc_msgBlk0427 = { + FC_LOG_MSG_IN_0427, + fc_mes0427, + fc_msgPreambleINc, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR_CFG, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0428 +message: Topology is illegal, resetting +descript: The configuration parameter for Topology is illegal, resetting + parameter to default value. +data: (1) a_current (2) LPFC_DFT_TOPOLOGY +severity: Error config +log: Always +module: fcLINUXfcp.c +action: Make neccessary changes to lpfc configuration file. +*/ +char fc_mes0428[] = "%sTopology is illegal, resetting Data: x%x x%x"; +msgLogDef fc_msgBlk0428 = { + FC_LOG_MSG_IN_0428, + fc_mes0428, + fc_msgPreambleINc, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR_CFG, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0429 +message: Linkdown_tmo too high, resetting +descript: The configuration parameter for Linkdown_tmo is too high, resetting + parameter to default value. +data: (1) a_current (2) LPFC_MAX_LNKDWN_TIMEOUT +severity: Error config +log: Always +module: fcLINUXfcp.c +action: Make neccessary changes to lpfc configuration file. +*/ +char fc_mes0429[] = "%sLinkdown_tmo too high, resetting Data: x%x x%x"; +msgLogDef fc_msgBlk0429 = { + FC_LOG_MSG_IN_0429, + fc_mes0429, + fc_msgPreambleINc, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR_CFG, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0430 +message: WWPN binding entry : Syntax error code +descript: A syntax error occured while parsing WWPN binding + configuraion information. +data: None +detail: Binding syntax error codes + 0 FC_SYNTAX_OK + 1 FC_SYNTAX_OK_BUT_NOT_THIS_BRD + 2 FC_SYNTAX_ERR_ASC_CONVERT + 3 FC_SYNTAX_ERR_EXP_COLON + 4 FC_SYNTAX_ERR_EXP_LPFC + 5 FC_SYNTAX_ERR_INV_LPFC_NUM + 6 FC_SYNTAX_ERR_EXP_T + 7 FC_SYNTAX_ERR_INV_TARGET_NUM + 8 FC_SYNTAX_ERR_EXP_D + 9 FC_SYNTAX_ERR_INV_DEVICE_NUM + 10 FC_SYNTAX_ERR_INV_RRATIO_NUM + 11 FC_SYNTAX_ERR_EXP_NULL_TERM +severity: Error config +log: Always +module: fcLINUXfcp.c +action: Make neccessary changes to lpfc configuration file. +*/ +char fc_mes0430[] = "%sWWPN binding entry %d: Syntax error code %d"; +msgLogDef fc_msgBlk0430 = { + FC_LOG_MSG_IN_0430, + fc_mes0430, + fc_msgPreambleINc, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR_CFG, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0431 +message: WWNN binding entry : Syntax error code +descript: A syntax error occured while parsing WWNN binding + configuraion information. +data: None +detail: Binding syntax error codes + 0 FC_SYNTAX_OK + 1 FC_SYNTAX_OK_BUT_NOT_THIS_BRD + 2 FC_SYNTAX_ERR_ASC_CONVERT + 3 FC_SYNTAX_ERR_EXP_COLON + 4 FC_SYNTAX_ERR_EXP_LPFC + 5 FC_SYNTAX_ERR_INV_LPFC_NUM + 6 FC_SYNTAX_ERR_EXP_T + 7 FC_SYNTAX_ERR_INV_TARGET_NUM + 8 FC_SYNTAX_ERR_EXP_D + 9 FC_SYNTAX_ERR_INV_DEVICE_NUM + 10 FC_SYNTAX_ERR_INV_RRATIO_NUM + 11 FC_SYNTAX_ERR_EXP_NULL_TERM +severity: Error config +log: Always +module: fcLINUXfcp.c +action: Make neccessary changes to lpfc configuration file. +*/ +char fc_mes0431[] = "%sWWNN binding entry %d: Syntax error code %d"; +msgLogDef fc_msgBlk0431 = { + FC_LOG_MSG_IN_0431, + fc_mes0431, + fc_msgPreambleINc, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR_CFG, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0432 +message: WWPN binding entry: node table full +descript: More bindings entries were configured than the driver can handle. +data: None +severity: Error config +log: Always +module: fcLINUXfcp.c +action: Make neccessary changes to lpfc configuration file such that + fewer bindings are configured. +*/ +char fc_mes0432[] = "%sWWPN binding entry: node table full"; +msgLogDef fc_msgBlk0432 = { + FC_LOG_MSG_IN_0432, + fc_mes0432, + fc_msgPreambleINc, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR_CFG, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0433 +message: WWNN binding entry: node table full +descript: More bindings entries were configured than the driver can handle. +data: None +severity: Error config +log: Always +module: fcLINUXfcp.c +action: Make neccessary changes to lpfc configuration file such that + fewer bindings are configured. +*/ +char fc_mes0433[] = "%sWWNN binding entry: node table full"; +msgLogDef fc_msgBlk0433 = { + FC_LOG_MSG_IN_0433, + fc_mes0433, + fc_msgPreambleINc, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR_CFG, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0434 +message: DID binding entry : Syntax error code +descript: A syntax error occured while parsing DID binding + configuraion information. +data: None +detail: Binding syntax error codes + 0 FC_SYNTAX_OK + 1 FC_SYNTAX_OK_BUT_NOT_THIS_BRD + 2 FC_SYNTAX_ERR_ASC_CONVERT + 3 FC_SYNTAX_ERR_EXP_COLON + 4 FC_SYNTAX_ERR_EXP_LPFC + 5 FC_SYNTAX_ERR_INV_LPFC_NUM + 6 FC_SYNTAX_ERR_EXP_T + 7 FC_SYNTAX_ERR_INV_TARGET_NUM + 8 FC_SYNTAX_ERR_EXP_D + 9 FC_SYNTAX_ERR_INV_DEVICE_NUM + 10 FC_SYNTAX_ERR_INV_RRATIO_NUM + 11 FC_SYNTAX_ERR_EXP_NULL_TERM +severity: Error config +log: Always +module: fcLINUXfcp.c +action: Make neccessary changes to lpfc configuration file. +*/ +char fc_mes0434[] = "%sDID binding entry %d: Syntax error code %d"; +msgLogDef fc_msgBlk0434 = { + FC_LOG_MSG_IN_0434, + fc_mes0434, + fc_msgPreambleINc, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR_CFG, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0435 +message: DID binding entry: node table full +descript: More bindings entries were configured than the driver can handle. +data: None +severity: Error config +log: Always +module: fcLINUXfcp.c +action: Make neccessary changes to lpfc configuration file such that + fewer bindings are configured. +*/ +char fc_mes0435[] = "%sDID binding entry: node table full"; +msgLogDef fc_msgBlk0435 = { + FC_LOG_MSG_IN_0435, + fc_mes0435, + fc_msgPreambleINc, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR_CFG, + LOG_INIT, + ERRID_LOG_INIT }; +/* +msgName: fc_mes0436 +message: Adapter failed to init, timeout, status reg +descript: The adapter failed during powerup diagnostics after it was reset. +data: None +severity: Error +log: Always +module: lp6000.c +action: This error could indicate a hardware or firmware problem. If + problems persist report these errors to Technical Support. +*/ +char fc_mes0436[] = "%sAdapter failed to init, timeout, status reg x%x"; +msgLogDef fc_msgBlk0436 = { + FC_LOG_MSG_IN_0436, + fc_mes0436, + fc_msgPreambleINe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0437 +message: Adapter failed to init, chipset, status reg +descript: The adapter failed during powerup diagnostics after it was reset. +data: None +severity: Error +log: Always +module: lp6000.c +action: This error could indicate a hardware or firmware problem. If + problems persist report these errors to Technical Support. +*/ +char fc_mes0437[] = "%sAdapter failed to init, chipset, status reg x%x"; +msgLogDef fc_msgBlk0437 = { + FC_LOG_MSG_IN_0437, + fc_mes0437, + fc_msgPreambleINe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0438 +message: Adapter failed to init, chipset, status reg +descript: The adapter failed during powerup diagnostics after it was reset. +data: None +severity: Error +log: Always +module: lp6000.c +action: This error could indicate a hardware or firmware problem. If + problems persist report these errors to Technical Support. +*/ +char fc_mes0438[] = "%sAdapter failed to init, chipset, status reg x%x"; +msgLogDef fc_msgBlk0438 = { + FC_LOG_MSG_IN_0438, + fc_mes0438, + fc_msgPreambleINe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0439 +message: Adapter failed to init, mbxCmd READ_REV, mbxStatus +descript: Adapter initialization failed when issuing READ_REV mailbox command. +data: None +severity: Error +log: Always +module: lp6000.c +action: This error could indicate a hardware or firmware problem. If + problems persist report these errors to Technical Support. +*/ +char fc_mes0439[] = "%sAdapter failed to init, mbxCmd x%x READ_REV, mbxStatus x%x"; +msgLogDef fc_msgBlk0439 = { + FC_LOG_MSG_IN_0439, + fc_mes0439, + fc_msgPreambleINe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0440 +message: Adapter failed to init, mbxCmd READ_REV detected outdated firmware +descript: Outdated firmware was detected during initialization. +data: (1) read_rev_reset +severity: Error +log: Always +module: lp6000.c +action: This error could indicate a hardware or firmware problem. Update + firmware. If problems persist report these errors to Technical + Support. +*/ +char fc_mes0440[] = "%sAdapter failed to init, mbxCmd x%x READ_REV detected outdated firmware Data: x%x"; +msgLogDef fc_msgBlk0440 = { + FC_LOG_MSG_IN_0440, + fc_mes0440, + fc_msgPreambleINe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0441 +message: Adapter failed to init, mbxCmd DUMP VPD, mbxStatus +descript: Adapter initialization failed when issuing DUMP_VPD mailbox command. +data: None +severity: Error +log: Always +module: lp6000.c +action: This error could indicate a hardware or firmware problem. If + problems persist report these errors to Technical Support. +*/ +char fc_mes0441[] = "%sAdapter failed to init, mbxCmd x%x DUMP VPD, mbxStatus x%x"; +msgLogDef fc_msgBlk0441 = { + FC_LOG_MSG_IN_0441, + fc_mes0441, + fc_msgPreambleINw, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_WARN, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0442 +message: Adapter failed to init, mbxCmd CONFIG_PORT, mbxStatus +descript: Adapter initialization failed when issuing CONFIG_PORT mailbox + command. +data: 0 +severity: Error +log: Always +module: lp6000.c +action: This error could indicate a hardware or firmware problem. If + problems persist report these errors to Technical Support. +*/ +char fc_mes0442[] = "%sAdapter failed to init, mbxCmd x%x CONFIG_PORT, mbxStatus x%x Data: x%x"; +msgLogDef fc_msgBlk0442 = { + FC_LOG_MSG_IN_0442, + fc_mes0442, + fc_msgPreambleINe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0443 +message: SLI1 not supported, mbxCmd , mbxStatus +descript: The driver no longer support SLI-1 mode. +data: 0 +severity: Error +log: Always +module: lp6000.c +action: This error could indicate a driver problem. If problems persist + report these errors to Technical Support. +*/ +char fc_mes0443[] = "%sSLI1 not supported, mbxCmd x%x, mbxStatus x%x Data: x%x"; +msgLogDef fc_msgBlk0443 = { + FC_LOG_MSG_IN_0443, + fc_mes0443, + fc_msgPreambleINe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0444 +message: Adapter failed to init, no buffers for RUN_BIU_DIAG +descript: The driver attempted to issue RUN_BIU_DIAG mailbox command to + the HBA but there were no buffer available. +data: None +severity: Error +log: Always +module: lp6000.c +action: This message indicates (1) a possible lack of memory resources. + Try increasing the lpfc 'num_bufs' configuration parameter to + allocate more buffers. (2) A possble driver buffer management + problem. If this problem persists, report these errors to + Technical Support. +*/ +char fc_mes0444[] = "%sAdapter failed to init, no buffers for RUN_BIU_DIAG"; +msgLogDef fc_msgBlk0444 = { + FC_LOG_MSG_IN_0444, + fc_mes0444, + fc_msgPreambleINe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0445 +message: RUN_BIU_DIAG failed +descript: Adapter failed to init properly because a PCI bus DMA + test failed. +data: None +severity: Error +log: Always +module: lp6000.c +action: This error usually indicates a hardware problem with the + adapter. Run diagnostics. +*/ +char fc_mes0445[] = "%sRUN_BIU_DIAG failed"; +msgLogDef fc_msgBlk0445 = { + FC_LOG_MSG_IN_0445, + fc_mes0445, + fc_msgPreambleINe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0446 +message: Adapter failed to init, mbxCmd CFG_RING, mbxStatus , ring +descript: Adapter initialization failed when issuing CFG_RING mailbox command. +data: None +severity: Error +log: Always +module: lp6000.c +action: This error could indicate a hardware or firmware problem. If + problems persist report these errors to Technical Support. +*/ +char fc_mes0446[] = "%sAdapter failed to init, mbxCmd x%x CFG_RING, mbxStatus x%x, ring %d"; +msgLogDef fc_msgBlk0446 = { + FC_LOG_MSG_IN_0446, + fc_mes0446, + fc_msgPreambleINe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0447 +message: Adapter failed init, mbxCmd rubBIUdiag mbxStatus +descript: Adapter initialization failed when issuing runBIUdiag mailbox + command. +data: None +severity: Error +log: Always +module: lp6000.c +action: This error could indicate a hardware or firmware problem. If + problems persist report these errors to Technical Support. +*/ +char fc_mes0447[] = "%sAdapter failed init, mbxCmd x%x CONFIG_LINK mbxStatus x%x"; +msgLogDef fc_msgBlk0447 = { + FC_LOG_MSG_IN_0447, + fc_mes0447, + fc_msgPreambleINe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0448 +message: Adapter failed to init, mbxCmd READ_SPARM, mbxStatus +descript: Adapter initialization failed when issuing READ_SPARM mailbox + command. +data: None +severity: Error +log: Always +module: lp6000.c +action: This error could indicate a hardware or firmware problem. If + problems persist report these errors to Technical Support. +*/ +char fc_mes0448[] = "%sAdapter failed init, mbxCmd x%x READ_SPARM mbxStatus x%x"; +msgLogDef fc_msgBlk0448 = { + FC_LOG_MSG_IN_0448, + fc_mes0448, + fc_msgPreambleINe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0449 +message: WorldWide PortName Type doesn't conform to IP Profile +descript: In order to run IP, the WorldWide PortName must be of type + IEEE (NAA = 1). This message displays if the adapter WWPN + doesn't conform with the standard. +data: None +severity: Error +log: Always +module: lp6000.c +action: Turn off the network-on configuration parameter or configure + a different WWPN. +*/ +char fc_mes0449[] = "%sWorldWide PortName Type x%x doesn't conform to IP Profile"; +msgLogDef fc_msgBlk0449 = { + FC_LOG_MSG_IN_0449, + fc_mes0449, + fc_msgPreambleINe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0450 +message: Adapter failed to init, mbxCmd FARP, mbxStatus +descript: Adapter initialization failed when issuing FARP mailbox command. +data: None +severity: Warning +log: LOG_INIT verbose +module: lp6000.c +action: None required +*/ +char fc_mes0450[] = "%sAdapter failed to init, mbxCmd x%x FARP, mbxStatus x%x"; +msgLogDef fc_msgBlk0450 = { + FC_LOG_MSG_IN_0450, + fc_mes0450, + fc_msgPreambleINw, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_WARN, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0451 +message: Enable interrupt handler failed +descript: The driver attempted to register the HBA interrupt service + routine with the host operating system but failed. +data: None +severity: Error +log: Always +module: lp6000.c +action: This error could indicate a hardware or driver problem. If + problems persist report these errors to Technical Support. +*/ +char fc_mes0451[] = "%sEnable interrupt handler failed"; +msgLogDef fc_msgBlk0451 = { + FC_LOG_MSG_IN_0451, + fc_mes0451, + fc_msgPreambleINe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0452 +message: Bring Adapter offline +descript: The FC driver has received a request to bring the adapter + offline. This may occur when running lputil. +data: None +severity: Warning +log: LOG_INIT verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0452[] = "%sBring Adapter offline"; +msgLogDef fc_msgBlk0452 = { + FC_LOG_MSG_IN_0452, + fc_mes0452, + fc_msgPreambleINw, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_WARN, + LOG_INIT, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0453 +message: Adapter failed to init, mbxCmd READ_CONFIG, mbxStatus +descript: Adapter initialization failed when issuing READ_CONFIG mailbox + command. +data: None +severity: Error +log: Always +module: lp6000.c +action: This error could indicate a hardware or firmware problem. If + problems persist report these errors to Technical Support. +*/ +char fc_mes0453[] = "%sAdapter failed to init, mbxCmd x%x READ_CONFIG, mbxStatus x%x"; +msgLogDef fc_msgBlk0453 = { + FC_LOG_MSG_IN_0453, + fc_mes0453, + fc_msgPreambleINe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0454 +message: Adapter failed to init, mbxCmd INIT_LINK, mbxStatus +descript: Adapter initialization failed when issuing INIT_LINK mailbox command. +data: None +severity: Error +log: Always +module: lp6000.c +action: This error could indicate a hardware or firmware problem. If + problems persist report these errors to Technical Support. +*/ +char fc_mes0454[] = "%sAdapter failed to init, mbxCmd x%x INIT_LINK, mbxStatus x%x"; +msgLogDef fc_msgBlk0454 = { + FC_LOG_MSG_IN_0454, + fc_mes0454, + fc_msgPreambleINe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0455 +message: Vital Product +descript: Vital Product Data (VPD) contained in HBA flash. +data: (1) vpd[0] (2) vpd[1] (3) vpd[2] (4) vpd[3] +severity: Information +log: LOG_INIT verbose +module: lp6000.c +action: None required +*/ +char fc_mes0455[] = "%sVital Product Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0455 = { + FC_LOG_MSG_IN_0455, + fc_mes0455, + fc_msgPreambleINi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0457 +message: Adapter Hardware Error +descript: The driver received an interrupt indicting a possible hardware + problem. +data: (1) status (2) status1 (3) status2 +severity: Error +log: Always +module: lp6000.c +action: This error could indicate a hardware or firmware problem. If + problems persist report these errors to Technical Support. +*/ +char fc_mes0457[] = "%sAdapter Hardware Error Data: x%x x%x x%x"; +msgLogDef fc_msgBlk0457 = { + FC_LOG_MSG_IN_0457, + fc_mes0457, + fc_msgPreambleINe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_INIT, + ERRID_LOG_INIT }; + +/* +msgName: fc_mes0458 +message: Bring Adapter online +descript: The FC driver has received a request to bring the adapter + online. This may occur when running lputil. +data: None +severity: Warning +log: LOG_INIT verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0458[] = "%sBring Adapter online"; +msgLogDef fc_msgBlk0458 = { + FC_LOG_MSG_IN_0458, + fc_mes0458, + fc_msgPreambleINw, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_WARN, + LOG_INIT, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0459 +message: Bring Adapter online +descript: The FC driver has received a request to bring the adapter + online. This may occur when running lputil. +data: None +severity: Warning +log: LOG_INIT verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0459[] = "%sBring Adapter online"; +msgLogDef fc_msgBlk0459 = { + FC_LOG_MSG_IN_0459, + fc_mes0459, + fc_msgPreambleINw, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_WARN, + LOG_INIT, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0460 +message: Bring Adapter offline +descript: The FC driver has received a request to bring the adapter + offline. This may occur when running lputil. +data: None +severity: Warning +log: LOG_INIT verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0460[] = "%sBring Adapter offline"; +msgLogDef fc_msgBlk0460 = { + FC_LOG_MSG_IN_0460, + fc_mes0460, + fc_msgPreambleINw, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_WARN, + LOG_INIT, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0461 +message: Adapter failed init, mbxCmd CONFIG_LINK mbxStatus +descript: Adapter initialization failed when issuing CONFIG_LINK mailbox + command. +data: None +severity: Error +log: Always +module: lp6000.c +action: This error could indicate a hardware or firmware problem. If + problems persist report these errors to Technical Support. +*/ +char fc_mes0461[] = "%sAdapter failed init, mbxCmd x%x CONFIG_LINK mbxStatus x%x"; +msgLogDef fc_msgBlk0461 = { + FC_LOG_MSG_IN_0461, + fc_mes0461, + fc_msgPreambleINe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_INIT, + ERRID_LOG_INIT }; + +/* + * UNUSED 0500 + */ + +/* + * Begin IP LOG Message Structures + */ + +/* +msgName: fc_mes0600 +message: FARP-RSP received from DID . +descript: A FARP ELS command response was received. +data: None +severity: Information +log: LOG_IP verbose +module: fcelsb.c +action: None required +*/ +char fc_mes0600[] = "%sFARP-RSP received from DID x%x"; +msgLogDef fc_msgBlk0600 = { + FC_LOG_MSG_IP_0600, + fc_mes0600, + fc_msgPreambleIPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_IP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0601 +message: FARP-REQ received fron DID +descript: A FARP ELS command request was received. . +data: None +severity: Information +log: LOG_IP verbose +module: fcelsb.c +action: None required +*/ +char fc_mes0601[] = "%sFARP-REQ received from DID x%x"; +msgLogDef fc_msgBlk0601 = { + FC_LOG_MSG_IP_0601, + fc_mes0601, + fc_msgPreambleIPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_IP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0602 +message: IP Response Ring out of posted buffers +descript: The IP ring returned all posted buffers to the driver + and is waiting for the driver to post new buffers. This + could mean the host system is out of TCP/IP buffers. +data: (1) fc_missbufcnt (2) NoRcvBuf +severity: Warning +log: LOG_IP verbose +module: fcscsib.c +action: Try allocating more IP buffers (STREAMS buffers or mbufs) + of size 4096 and/or increasing the post-ip-buf lpfc + configuration parameter. Reboot the system. +*/ +char fc_mes0602[] = "%sIP Response Ring %d out of posted buffers Data: x%x x%x"; +msgLogDef fc_msgBlk0602 = { + FC_LOG_MSG_IP_0602, + fc_mes0602, + fc_msgPreambleIPw, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_WARN, + LOG_IP, + ERRID_LOG_NO_RESOURCE }; + +/* +msgName: fc_mes0603 +message: Rcv Ring out of posted buffers +descript: The ring returned all posted buffers to the driver + and is waiting for the driver to post new buffers. This + could mean the host system is out of ELS or CT buffers. +data: (1) fc_missbufcnt (2) NoRcvBuf +severity: Error +log: Always +module: fcscsib.c +action: Try allocating more buffers by increasing the num-buf lpfc + configuration parameter. Reboot the system. +*/ +char fc_mes0603[] = "%sRcv Ring %d out of posted buffers Data: x%x x%x"; +msgLogDef fc_msgBlk0603 = { + FC_LOG_MSG_IP_0603, + fc_mes0603, + fc_msgPreambleIPe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_IP, + ERRID_LOG_NO_RESOURCE }; + +/* +msgName: fc_mes0604 +message: Post buffer for IP ring failed +descript: The driver cannot allocate a buffer to post to the IP ring. + This usually means the host system is out of TCP/IP buffers. +data: (1) missbufcnt +severity: Error +log: Always +module: fcscsib.c +action: Try allocating more IP buffers (STREAMS buffers or mbufs) + of size 4096. Reboot the system. +*/ +char fc_mes0604[] = "%sPost buffer for IP ring %d failed Data: x%x"; +msgLogDef fc_msgBlk0604 = { + FC_LOG_MSG_IP_0604, + fc_mes0604, + fc_msgPreambleIPe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_IP, + ERRID_LOG_NO_RESOURCE }; + +/* +msgName: fc_mes0605 +message: No room on IP xmit queue +descript: The system is generating IOCB commands to be processed + faster than the adapter can process them. +data: (1) xmitnoroom +severity: Warning +log: LOG_IP verbose +module: fcxmitb.c +action: Check the state of the link. If the link is up and running, + reconfigure the xmit queue size to be larger. Note, a larger + queue size may require more system IP buffers. If the link + is down, check physical connections to Fibre Channel network. +*/ +char fc_mes0605[] = "%sNo room on IP xmit queue Data: x%x"; +msgLogDef fc_msgBlk0605 = { + FC_LOG_MSG_IP_0605, + fc_mes0605, + fc_msgPreambleIPw, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_WARN, + LOG_IP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0606 +message: Stray XmitSequence completion +descript: Received an XMIT_SEQUENCE IOCB completion without issuing + a corresponding XMIT_SEQUENCE Command (based on the IOTAG + field in the XMIT_SEQUENCE_CR iocb). +data: (1) ulpCommand (2) ulpIoTag +severity: Error +log: Always +module: fcxmitb.c +action: This error could indicate a software driver or firmware + problem. If problems persist report these errors to + Technical Support. +*/ +char fc_mes0606[] = "%sStray XmitSequence completion Data: x%x x%x"; +msgLogDef fc_msgBlk0606 = { + FC_LOG_MSG_IP_0606, + fc_mes0606, + fc_msgPreambleIPe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_IP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0607 +message: Xmit Sequence completion error +descript: A XMIT_SEQUENCE command completed with a status error + in the IOCB. +data: (1) ulpStatus (2) ulpToTag (3) ulpWord[4] (4) did +severity: Warning +log: LOG_IP verbose +module: fcxmitb.c +action: If there are many errors to one device, check physical + connections to Fibre Channel network and the state of + the remote PortID. The driver attempts to recover by + creating a new exchange to the remote device. +*/ +char fc_mes0607[] = "%sXmit Sequence completion error Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0607 = { + FC_LOG_MSG_IP_0607, + fc_mes0607, + fc_msgPreambleIPw, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_WARN, + LOG_IP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0608 +message: Stray CreateXRI completion +descript: Received a CREATE_XRI command completion without + issuing a corresponding CREATE_XRI Command (based + on the IOTAG field in the CREATE_XRI_CR iocb). +data: (1) ulpCommad (2) ulpToTag +severity: Error +log: Always +module: fcxmitb.c +action: This error could indicate a software driver or + firmware problem. If problems persist report these + errors to Technical Support. +*/ +char fc_mes0608[] = "%sStray CreateXRI completion Data: x%x x%x"; +msgLogDef fc_msgBlk0608 = { + FC_LOG_MSG_IP_0608, + fc_mes0608, + fc_msgPreambleIPe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_IP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* + * Begin FCP LOG Message Structures + */ + +/* +msgName: fc_mes0700 +message: Start nodev timer +descript: A target disappeared from the Fibre Channel network. If the + target does not return within nodev-tmo timeout all I/O to + the target will fail. +data: (1) nlp (2) nlp_flag (3) nlp_state (4) nlp_DID +severity: Information +log: LOG_FCP verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0700[] = "%sSTART nodev timer Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0700 = { + FC_LOG_MSG_FP_0700, + fc_mes0700, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0701 +message: Issue Abort Task Set I/O for LUN +descript: The SCSI layer detected that it needs to abort all I/O + to a specific device. This results in an FCP Task + Management command to abort the I/O in progress. +data: (1) did (2) sid (3) flags +severity: Information +log: LOG_FCP verbose +module: fcstratb.c +action: Check state of device in question. +*/ +char fc_mes0701[] = "%sIssue Abort Task Set I/O for LUN %d Data: x%x x%x x%x"; +msgLogDef fc_msgBlk0701 = { + FC_LOG_MSG_FP_0701, + fc_mes0701, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0702 +message: Issue Target Reset I/O +descript: The SCSI layer detected that it needs to abort all I/O + to a specific target. This results in an FCP Task + Management command to abort the I/O in progress. +data: (1) lun (2) did (3) sid (4) flags +severity: Information +log: LOG_FCP verbose +module: fcstratb.c +action: Check state of target in question. +*/ +char fc_mes0702[] = "%sIssue Target Reset I/O Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0702 = { + FC_LOG_MSG_FP_0702, + fc_mes0702, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0703 +message: Issue LUN Reset I/O for LUN +descript: The SCSI layer detected that it needs to abort all I/O + to a specific device. This results in an FCP Task + Management command to abort the I/O in progress. +data: (1) did (2) sid (3) flags +severity: Information +log: LOG_FCP verbose +module: fcstratb.c +action: Check state of device in question. +*/ +char fc_mes0703[] = "%sIssue LUN Reset I/O for LUN %d Data: x%x x%x x%x"; +msgLogDef fc_msgBlk0703 = { + FC_LOG_MSG_FP_0703, + fc_mes0703, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0704 +message: STOP nodev timer +descript: The FCP target was rediscovered and I/O can be resumed. +data: (1) ndlp (2) nlp_flag (3) nlp_state (4) nlp_DID +severity: Information +log: LOG_FCP verbose +module: fcstratb.c +action: None required +*/ +char fc_mes0704[] = "%sSTOP nodev timer Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0704 = { + FC_LOG_MSG_FP_0704, + fc_mes0704, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0705 +message: STOP nodev timer +descript: The FCP target was rediscovered and I/O can be resumed. +data: (1) ndlp (2) nlp_flag (3) nlp_state (4) nlp_DID +severity: Information +log: LOG_FCP verbose +module: fcstratb.c +action: None required +*/ +char fc_mes0705[] = "%sSTOP nodev timer Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0705 = { + FC_LOG_MSG_FP_0705, + fc_mes0705, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0706 +message: Cannot issue FCP command +descript: A valid ELS login with the FCP target no longer exists. +data: (1) did (2) sid +severity: Warning +log: LOG_FCP verbose +module: fcstratb.c +action: Check the state of the target in question. +*/ +char fc_mes0706[] = "%sCannot issue FCP command Data: x%x x%x"; +msgLogDef fc_msgBlk0706 = { + FC_LOG_MSG_FP_0706, + fc_mes0706, + fc_msgPreambleFPw, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_WARN, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0707 +message: Bad SCSI CDB length for LUN DID +descript: This error indicates a SCSI command sent to the + FC driver from the SCSI layer has an invalid length. +data: (1) cmd_cdblen (2) fcpCdb +severity: Error +log: Always +module: fcstratb.c +action: This error could indicate a host operating system SCSI + layer problem. If problems persist report these errors + to Technical Support. +*/ +char fc_mes0707[] = "%sBad SCSI CDB length for LUN %d DID x%x Data: x%x x%x"; +msgLogDef fc_msgBlk0707 = { + FC_LOG_MSG_FP_0707, + fc_mes0707, + fc_msgPreambleFPe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0708 +message: NULL sp in flush_done +descript: This error indicates a potential FC driver problem + related to a FCP command iodone +data: (1) cmnd[0] (2) serial_number (3) retries (4) result +severity: Error +log: Always +module: fcLINUXfcp.c +action: This error could indicate a driver problem. If problems + persist report these errors to Technical Support. +*/ +char fc_mes0708[] = "%sNULL sp in flush_done Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0708 = { + FC_LOG_MSG_FP_0708, + fc_mes0708, + fc_msgPreambleFPe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0709 +message: NULL sp in DPC flush_done +descript: This error indicates a potential FC driver problem + related to a FCP command iodone +data: (1) cmnd[0] (2) serial_number (3) retries (4) result +severity: Error +log: Always +module: fcLINUXfcp.c +action: This error could indicate a driver problem. If problems + persist report these errors to Technical Support. +*/ +char fc_mes0709[] = "%sNULL sp in DPC flush_done Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0709 = { + FC_LOG_MSG_FP_0709, + fc_mes0709, + fc_msgPreambleFPe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0710 +message: iodone error return +descript: This error indicates the FC driver is returning SCSI + command to the SCSI layer in error or with sense data. +data: (1) target (2) retries (3) result (4) *iptr +severity: Information +log: LOG_FCP verbose +module: fcLINUXfcp.c +action: None required +*/ +char fc_mes0710[] = "%siodone error return Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0710 = { + FC_LOG_MSG_FP_0710, + fc_mes0710, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0711 +message: iodone error return +descript: This error indicates the FC driver is returning SCSI + command to the SCSI layer in error or with sense data. +data: (1) target (2) retries (3) result (4) *iptr +severity: Information +log: LOG_FCP verbose +module: fcLINUXfcp.c +action: None required +*/ +char fc_mes0711[] = "%siodone error return Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0711 = { + FC_LOG_MSG_FP_0711, + fc_mes0711, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0712 +message: SCSI layer issued abort device +descript: The SCSI layer is requesting the driver to abort + I/O to a specific device. +data: (1) target (2) lun (3) cmnd[0] (4) serial_number +severity: Error +log: Always +module: fcLINUXfcp.c +action: Check state of device in question. +*/ +char fc_mes0712[] = "%sSCSI layer issued abort device Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0712 = { + FC_LOG_MSG_FP_0712, + fc_mes0712, + fc_msgPreambleFPe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0713 +message: SCSI layer issued target reset +descript: The SCSI layer is requesting the driver to abort + I/O to a specific target. +data: (1) target (2) lun (3) dev_index +severity: Error +log: Always +module: fcLINUXfcp.c +action: Check state of target in question. +*/ +char fc_mes0713[] = "%sSCSI layer issued target reset Data: x%x x%x x%x"; +msgLogDef fc_msgBlk0713 = { + FC_LOG_MSG_FP_0713, + fc_mes0713, + fc_msgPreambleFPe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0714 +message: SCSI layer issued Bus Reset +descript: The SCSI layer is requesting the driver to abort + all I/Os to all targets on this HBA. +data: (1) target (2) lun +severity: Error +log: Always +module: fcLINUXfcp.c +action: Check state of targets in question. +*/ +char fc_mes0714[] = "%sSCSI layer issued Bus Reset Data: x%x x%x"; +msgLogDef fc_msgBlk0714 = { + FC_LOG_MSG_FP_0714, + fc_mes0714, + fc_msgPreambleFPe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0715 +message: SCSI layer issued Host Reset +descript: The SCSI layer is requesting the driver to reset the link + on this HBA. +data: (1) target (2) lun +severity: Error +log: Always +module: fcLINUXfcp.c +action: Check state of HBA link. +*/ +char fc_mes0715[] = "%sSCSI layer issued Host Reset Data: x%x x%x"; +msgLogDef fc_msgBlk0715 = { + FC_LOG_MSG_FP_0715, + fc_mes0715, + fc_msgPreambleFPe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0716 +message: FCP residual underrun, expected , residual +descript: FCP device provided less data than was requested. +data: (1) cmnd[0] (2) underflow +severity: Information +log: LOG_FCP verbose +module: fcLINUXfcp.c +action: None required +*/ +char fc_mes0716[] = "%sFCP residual underrun, expected %d, residual %d Data: x%x x%x"; +msgLogDef fc_msgBlk0716 = { + FC_LOG_MSG_FP_0716, + fc_mes0716, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0717 +message: FCP command residual underrun converted to error +descript: The driver converts this underrun condition to an error based + on the underflow field in the SCSI cmnd. +data: (1) underflow (2) len (3) resid +severity: Information +log: LOG_FCP verbose +module: fcLINUXfcp.c +action: None required +*/ +char fc_mes0717[] = "%sFCP cmd x%x resid urun convrt'd to err Data: x%x x%x x%x"; +msgLogDef fc_msgBlk0717 = { + FC_LOG_MSG_FP_0717, + fc_mes0717, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0718 +message: LUN address out of range +descript: Invalid LUN number in the SCSI command passed to the driver. +data: (1) target (2) lun +severity: Error +log: Always +module: fcLINUXfcp.c +action: This error could indicate a host operating system SCSI + layer problem. If problems persist report these errors + to Technical Support. +*/ +char fc_mes0718[] = "%sLUN address out of range Data: x%x x%x"; +msgLogDef fc_msgBlk0718 = { + FC_LOG_MSG_FP_0718, + fc_mes0718, + fc_msgPreambleFPe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0719 +message: Waiting for REPORT LUN cmpl before issuing INQUIRY SN +descript: Waiting for REPORT LUN completion before issuing INQUIRY SN +data: (1) scsi_id (2) lun_id (3) flags +severity: Information +log: LOG_FCP verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0719[] = "%sWaiting for REPORT LUN cmpl before issuing INQUIRY SN Data: x%x x%x x%x"; +msgLogDef fc_msgBlk0719 = { + FC_LOG_MSG_FP_0719, + fc_mes0719, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0720 +message: Stray FCP completion +descript: Received an FCP command completion without issuing a + corresponding FCP Command (based on the IOTAG field + in the FCP IOCB). +data: (1) ulpCommand (2) ulpIoTag (3) ulpStatus (4) ulpWord[4] +severity: Error +log: Always +module: fcscsib.c +action: This error could indicate a software driver or firmware + problem. If problems persist report these errors to + Technical Support. +*/ +char fc_mes0720[] = "%sStray FCP completion Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0720 = { + FC_LOG_MSG_FP_0720, + fc_mes0720, + fc_msgPreambleFPe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0721 +message: INQUIRY SN cmpl +descript: An INQUIRY Serial Number (page x83) completed. This information + is saved by the driver. +data: (1) scsi_id (2) lun_id (3) statLocalError (4) cmd + WD7 +severity: Information +log: LOG_FCP verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0721[] = "%sINQUIRY SN cmpl Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0721 = { + FC_LOG_MSG_FP_0721, + fc_mes0721, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0722 +message: INQUIRY SN info +descript: This is the serial number of the device that will be saved. +data: (1) *datap (2) *datap + 3 (3) datap + 7 (4) rspResId +severity: Information +log: LOG_FCP verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0722[] = "%sINQUIRY SN info Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0722 = { + FC_LOG_MSG_FP_0722, + fc_mes0722, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0723 +message: Issue INQUIRY SN +descript: Issuing an INQUIRY Serial Number (page x83) FCP command. +data: (1) scsi_id (2) lun_id +severity: Information +log: LOG_FCP verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0723[] = "%sIssue INQUIRY SN Data: x%x x%x"; +msgLogDef fc_msgBlk0723 = { + FC_LOG_MSG_FP_0723, + fc_mes0723, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0724 +message: Issue INQUIRY Page 0 +descript: Issuing an INQUIRY (page x0) FCP command. +data: (1) scsi_id (2) lun_id +severity: Information +log: LOG_FCP verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0724[] = "%sIssue INQUIRY Page 0 Data: x%x x%x"; +msgLogDef fc_msgBlk0724 = { + FC_LOG_MSG_FP_0724, + fc_mes0724, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0725 +message: Inquiry Serial Number: invalid length +descript: An INQUIRY SN command completed with an invalid serial number length. +data: (1) sizeSN (2) j (3) scsi_id (4) lun_id +severity: Error +log: Always +module: fcscsib.c +action: Check remote NPORT for potential problem. +*/ +char fc_mes0725[] = "%sINQ Serial Number: invalid length Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0725= { + FC_LOG_MSG_FP_0725, + fc_mes0725, + fc_msgPreambleFPe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_FCP, + ERRID_LOG_HDW_ERR }; + +/* +msgName: fc_mes0726 +message: INQUIRY SN cmd failed +descript: The INQUIRY Serial Number (page x83) failed. +data: (1) ulpStatus (2) fcpi_parm (3) m_target (4) m_lun +severity: Error +log: Always +module: fcscsib.c +action: Check if target device supports this command +*/ +char fc_mes0726[] = "%sINQUIRY SN cmd failed Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0726= { + FC_LOG_MSG_FP_0726, + fc_mes0726, + fc_msgPreambleFPe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_FCP, + ERRID_LOG_HDW_ERR }; + +/* +msgName: fc_mes0727 +message: INQUIRY Page 0 cmpl +descript: An INQUIRY (page 0) completed. This information is saved by + the driver. +data: (1) scsi_id (2) lun_id (3) statLocalError (4) cmd + WD7 +severity: Information +log: LOG_FCP verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0727[] = "%sINQUIRY Page 0 cmpl Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0727 = { + FC_LOG_MSG_FP_0727, + fc_mes0727, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0728 +message: INQUIRY Page 0 cmd failed +descript: The INQUIRY (page 0) failed. +data: (1) ulpStatus (2) fcpi_parm (3) scsi_id (4) lun_id +severity: Error +log: Always +module: fcscsib.c +action: Check if target device supports this command +*/ +char fc_mes0728[] = "%sINQUIRY Page 0 cmd failed Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0728= { + FC_LOG_MSG_FP_0728, + fc_mes0728, + fc_msgPreambleFPe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_FCP, + ERRID_LOG_HDW_ERR }; + +/* +msgName: fc_mes0729 +message: FCP cmd failed on device (, ) DID +descript: The specifed device failed an FCP command. +data: (1) rspInfo3 (2) statLocalError (3) *cmd + WD6 (4) *cmd + WD7 +severity: Warning +log: LOG_FCP verbose +module: fcscsib.c +action: Check the state of the target in question. +*/ +char fc_mes0729[] = "%sFCP cmd x%x failed on device (%d, %d), DID x%x Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0729= { + FC_LOG_MSG_FP_0729, + fc_mes0729, + fc_msgPreambleFPw, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_WARN, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0730 +message: FCP command failed: RSP +descript: The FCP command failed with a response error. +data: (1) lp[2] (2) lp[3] (3) lp[4] (4) lp[5] +severity: Warning +log: LOG_FCP verbose +module: fcscsib.c +action: Check the state of the target in question. +*/ +char fc_mes0730[] = "%sFCP command failed: RSP Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0730= { + FC_LOG_MSG_FP_0730, + fc_mes0730, + fc_msgPreambleFPw, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_WARN, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0731 +message: FCP command failed: SNS +descript: The FCP command failed with sense information. +data: (1) lp[0] (2) lp[1] (3) lp[2] (4) lp[3] + (5) lp[4] (6) lp[5] (7) lp6[6] (8) lp[7] +severity: Warning +log: LOG_FCP verbose +module: fcscsib.c +action: Check the state of the target in question. +*/ +char fc_mes0731[] = "%sFCP command failed: SNS Data: x%x x%x x%x x%x x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0731= { + FC_LOG_MSG_FP_0731, + fc_mes0731, + fc_msgPreambleFPw, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_WARN, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0732 +message: Retry FCP command due to 29,00 check condition +descript: The issued FCP command got a 29,00 check condition and will + be retried by the driver. +data: (1) *lp (2) *lp+1 (3) *lp+2 (4) *lp+3 +severity: Information +log: LOG_FCP verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0732[] = "%sRetry FCP command due to 29,00 check condition Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0732 = { + FC_LOG_MSG_FP_0732, + fc_mes0732, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0733 +message: FCP Read Underrun +descript: The issued FCP command returned a Read Underrun +data: (1) *cmd + WD7 (2) ulpContext (3) rspResId (4) fcpi_parm +severity: Information +log: LOG_FCP verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0733[] = "%sFCP Read Underrun Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0733 = { + FC_LOG_MSG_FP_0733, + fc_mes0733, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0734 +message: FCP Read Check Error +descript: The issued FCP command returned a Read Check Error +data: (1) *cmd + WD7 (2) ulpContext (3) rspResId (4) fcpi_parm +severity: Error +log: Always +module: fcscsib.c +action: Check the state of the target in question. +*/ +char fc_mes0734[] = "%sFCP Read Check Error Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0734= { + FC_LOG_MSG_FP_0734, + fc_mes0734, + fc_msgPreambleFPe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_FCP, + ERRID_LOG_HDW_ERR }; + +/* +msgName: fc_mes0735 +message: FCP Read Check Error with Check Condition +descript: The issued FCP command returned a Read Check Error and a + Check condition. +data: (1) *cmd + WD7 (2) ulpContext (3) rspResId (4) fcpi_parm +severity: Error +log: Always +module: fcscsib.c +action: Check the state of the target in question. +*/ +char fc_mes0735[] = "%sFCP Read Check Error with Check Condition Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0735= { + FC_LOG_MSG_FP_0735, + fc_mes0735, + fc_msgPreambleFPe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_FCP | LOG_CHK_COND, + ERRID_LOG_HDW_ERR }; + +/* +msgName: fc_mes0736 +message: FCP QUEUE Full +descript: Received a Queue Full status from the FCP device. +data: (1) fcp_cur_queue_depth (2) active_io_count (3) flags (4) a_current +severity: Information +log: LOG_FCP verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0736[] = "%sFCP QUEUE Full Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0736 = { + FC_LOG_MSG_FP_0736, + fc_mes0736, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0737 +message: FCP error: Check condition +descript: The issued FCP command resulted in a Check Condition. +data: (1) *cmd + WD7 (2) ulpIoTag (3) ulpContext (4) statLocalError +severity: Information +log: LOG_FCP | LOG_CHK_COND verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0737[] = "%sFCP error: Check condition Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0737 = { + FC_LOG_MSG_FP_0737, + fc_mes0737, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP | LOG_CHK_COND, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0738 +message: 29,00 Check condition received +descript: The received check condition indicates the device was powered + on or reset. +data: (1) lp[0] (2) lp[1] (3) lp[2] (4) lp[3] +severity: Information +log: LOG_FCP | LOG_CHK_COND verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0738[] = "%s29,00 Check condition received Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0738 = { + FC_LOG_MSG_FP_0738, + fc_mes0738, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP | LOG_CHK_COND, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0739 +message: Check condition received ERR1 +descript: The command SCSI3_PERSISTENT_RESERVE_IN resulted in a Invalid + Command operation code check condition. +data: (1) lp[0] (2) lp[1] (3) lp[2] (4) lp[3] +severity: Information +log: LOG_FCP | LOG_CHK_COND verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0739[] = "%sCheck condition received ERR1 Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0739 = { + FC_LOG_MSG_FP_0739, + fc_mes0739, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP | LOG_CHK_COND, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0740 +message: Check condition received ERR2 +descript: The check condition meets the criteria for the configuration + parameters lpfc_check_cond_err and lpfc_delay_rsp_err. +data: (1) lp[0] (2) lp[1] (3) lp[2] (4) lp[3] +severity: Information +log: LOG_FCP | LOG_CHK_COND verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0740[] = "%sCheck condition received ERR2 Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0740 = { + FC_LOG_MSG_FP_0740, + fc_mes0740, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP | LOG_CHK_COND, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0741 +message: Check condition received +descript: The issued FCP command resulted in a Check Condition. +data: (1) lp[0] (2) lp[1] (3) lp[2] (4) lp[3] +severity: Information +log: LOG_FCP | LOG_CHK_COND verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0741[] = "%sCheck condition received Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0741 = { + FC_LOG_MSG_FP_0741, + fc_mes0741, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP | LOG_CHK_COND, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0742 +message: FCP completion error +descript: An FCP command completed with a status error in the IOCB. +data: (1) ulpStatus (2) ulpWord[4] (3) did. +severity: Information +log: LOG_FCP verbose +module: fcscsib.c +action: If there are many errors to one device, check physical + connections to Fibre Channel network and the state of the + remote PortID. +*/ +char fc_mes0742[] = "%sFCP completion error Data: x%x x%x x%x"; +msgLogDef fc_msgBlk0742 = { + FC_LOG_MSG_FP_0742, + fc_mes0742, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0743 +message: FCP completion error +descript: An FCP command completed with a status error in the IOCB. +data: (1) ulpStatus (2) ulpWord[4] (3) did. +severity: Information +log: LOG_FCP verbose +module: fcscsib.c +action: If there are many errors to one device, check physical + connections to Fibre Channel network and the state of the + remote PortID. +*/ +char fc_mes0743[] = "%sFCP completion error Data: x%x x%x x%x"; +msgLogDef fc_msgBlk0743 = { + FC_LOG_MSG_FP_0743, + fc_mes0743, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_HDW_ERR }; + +/* +msgName: fc_mes0744 +message: FCP completion error +descript: An FCP command completed with a status error in the IOCB. +data: (1) did (2) *lp (3) *(lp+2) (4) *(lp+3) +severity: Information +log: LOG_FCP verbose +module: fcscsib.c +action: If there are many errors to one device, check physical + connections to Fibre Channel network and the state of the + remote PortID. +*/ +char fc_mes0744[] = "%sFCP completion error Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0744 = { + FC_LOG_MSG_FP_0744, + fc_mes0744, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0745 +message: FCP completion error +descript: An FCP command completed with a status error in the IOCB. +data: (1) ulpStatus (2) ulpWord[4] (3) did. +severity: Information +log: LOG_FCP verbose +module: fcscsib.c +action: If there are many errors to one device, check physical + connections to Fibre Channel network and the state of the + remote PortID. +*/ +char fc_mes0745[] = "%sFCP completion error Data: x%x x%x x%x"; +msgLogDef fc_msgBlk0745 = { + FC_LOG_MSG_FP_0745, + fc_mes0745, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_HDW_ERR }; + +/* +msgName: fc_mes0746 +message: FCP completion error +descript: An FCP command completed with a status error in the IOCB. +data: (1) ulpStatus (2) ulpWord[4] (3) did. +severity: Information +log: LOG_FCP verbose +module: fcscsib.c +action: If there are many errors to one device, check physical + connections to Fibre Channel network and the state of the + remote PortID. +*/ +char fc_mes0746[] = "%sFCP completion error Data: x%x x%x x%x"; +msgLogDef fc_msgBlk0746 = { + FC_LOG_MSG_FP_0746, + fc_mes0746, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0747 +message: Cmpl Target Reset +descript: A driver initiated Target Reset completed. +data: (1) scsi_id (2) lun_id (3) statLocalError (4) *cmd + WD7 +severity: Information +log: LOG_FCP verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0747[] = "%sCmpl Target Reset Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0747 = { + FC_LOG_MSG_FP_0747, + fc_mes0747, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0748 +message: Cmpl LUN Reset +descript: A driver initiated LUN Reset completed. +data: (1) scsi_id (2) lun_id (3) statLocalError (4) *cmd + WD7 +severity: Information +log: LOG_FCP verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0748[] = "%sCmpl LUN Reset Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0748 = { + FC_LOG_MSG_FP_0748, + fc_mes0748, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0749 +message: Cmpl Abort Task Set +descript: A driver initiated Abort Task Set completed. +data: (1) scsi_id (2) lun_id (3) statLocalError (4) *cmd + WD7 +severity: Information +log: LOG_FCP verbose +module: fcscsib.c +action: None required +*/ +char fc_mes0749[] = "%sCmpl Abort Task Set Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0749 = { + FC_LOG_MSG_FP_0749, + fc_mes0749, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0750 +message: EXPIRED linkdown timer +descript: The link was down for greater than the configuration parameter + (lpfc_linkdown_tmo) seconds. All I/O associated with the devices + on this link will be failed. +data: (1) fc_ffstate +severity: Information +log: LOG_FCP | LOG_LINK_EVENT verbose +module: fcscsib.c +action: Check HBA cable/connection to Fibre Channel network. +*/ +char fc_mes0750[] = "%sEXPIRED linkdown timer Data: x%x"; +msgLogDef fc_msgBlk0750 = { + FC_LOG_MSG_FP_0750, + fc_mes0750, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP | LOG_LINK_EVENT, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0751 +message: EXPIRED nodev timer +descript: A device disappeared for greater than the configuration parameter + (lpfc_nodev_tmo) seconds. All I/O associated with this device + will be failed. +data: (1) ndlp (2) nlp_flag (3) nlp_state (4) nlp_DID +severity: Information +log: LOG_FCP verbose +module: fcscsib.c +action: Check physical connections to Fibre Channel network and the + state of the remote PortID. +*/ +char fc_mes0751[] = "%sEXPIRED nodev timer Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0751 = { + FC_LOG_MSG_FP_0751, + fc_mes0751, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0752 +message: Device disappeared, nodev timeout +descript: A device disappeared for greater than the configuration + parameter (lpfc_nodev_tmo) seconds. All I/O associated with + this device will be failed. +data: (1) did (2) sid (3) pan (4) a_current +severity: Information +log: LOG_FCP verbose +module: fcscsib.c +action: Check physical connections to Fibre Channel network and the + state of the remote PortID. +*/ +char fc_mes0752[] = "%sDevice disappeared, nodev timeout Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0752 = { + FC_LOG_MSG_FP_0752, + fc_mes0752, + fc_msgPreambleFPi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0753 +message: Inquiry Serial Number: invalid length +descript: An INQUIRY SN command completed with an invalid serial number length. +data: (1) sizeSN (2) j (3) scsi_id (4) lun_id +severity: Error +log: Always +module: fcscsib.c +action: Check state of target in question. +*/ +char fc_mes0753[] = "%sInquiry Serial Number: invalid length Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0753= { + FC_LOG_MSG_FP_0753, + fc_mes0753, + fc_msgPreambleFPe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_FCP, + ERRID_LOG_HDW_ERR }; + +/* +msgName: fc_mes0754 +message: SCSI timeout +descript: An FCP IOCB command was posted to a ring and did not complete + within ULP timeout seconds. +data: (1) did (2) sid +severity: Warning +log: LOG_FCP verbose +module: fcscsib.c +action: If no I/O is going through the adapter, reboot the system; + otherwise check the state of the target in question. +*/ +char fc_mes0754[] = "%sSCSI timeout Data: x%x x%x"; +msgLogDef fc_msgBlk0754 = { + FC_LOG_MSG_FP_0754, + fc_mes0754, + fc_msgPreambleFPw, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_WARN, + LOG_FCP, + ERRID_LOG_TIMEOUT }; + +/* +msgName: fc_mes0756 +message: Local_timeout Skipping clock tick +descript: The DPC thread has not been scheduled within several seconds +data: (1) dpc_ha_copy (2) ha_copy (3) dpc_cnt (4) fc_ffstate +severity: Warning +log: LOG_FCP verbose +module: fcLINUXfcp.c +action: Check the state of the target in question. +*/ +char fc_mes0756[] = "%sLocal_timeout Skipping clock tick Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0756= { + FC_LOG_MSG_FP_0756, + fc_mes0756, + fc_msgPreambleFPw, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_WARN, + LOG_FCP, + ERRID_LOG_UNEXPECT_EVENT }; + +/* + * UNUSED 0800 + */ + +/* + * Begin NODE LOG Message Structures + */ + +/* +msgName: fc_mes0900 +message: FIND node rpi +descript: The driver is looking up the node table entry for a remote + NPORT based on its RPI. +data: (1) ndlp (2) rpi +severity: Information +log: LOG_NODE verbose +module: fcrpib.c +action: None requird +*/ +char fc_mes0900[] = "%sFIND node rpi Data: x%x x%x"; +msgLogDef fc_msgBlk0900 = { + FC_LOG_MSG_ND_0900, + fc_mes0900, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0901 +message: Free node tbl +descript: The driver is freeing a node table entry. +data: (1) nlp_DID (2) nlp_flag (3) nlp_Rpi (4) data1 +severity: Information +log: LOG_NODE verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0901[] = "%sFree node tbl Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0901 = { + FC_LOG_MSG_ND_0901, + fc_mes0901, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0902 +message: Free node IEEE +descript: The driver freeing a node table entry. +data: (1) IEEE[2] (2) IEEE[3] (3) IEEE[4] (4) IEEE[5] +severity: Information +log: LOG_NODE verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0902[] = "%sFree node IEEE Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0902 = { + FC_LOG_MSG_ND_0902, + fc_mes0902, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0903 +message: BIND node tbl +descript: The driver is putting the node table entry on the binding list. +data: (1) nlp (2) nlp_DID (3) nlp_flag (4) data1 +severity: Information +log: LOG_NODE verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0903[] = "%sBIND node tbl Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0903= { + FC_LOG_MSG_ND_0903, + fc_mes0903, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0904 +message: UNMAP node tbl +descript: The driver is putting the node table entry on the unmapped node list. +data: (1) nlp (2) nlp_DID (3) nlp_flag (4) data1 +severity: Information +log: LOG_NODE verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0904[] = "%sUNMAP node tbl Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0904 = { + FC_LOG_MSG_ND_0904, + fc_mes0904, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0905 +message: MAP node tbl +descript: The driver is putting the node table entry on the mapped node list. +data: (1) nlp (2) nlp_DID (3) nlp_flag (4) data1 +severity: Information +log: LOG_NODE verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0905[] = "%sMAP node tbl Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0905 = { + FC_LOG_MSG_ND_0905, + fc_mes0905, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0906 +message: FIND node DID unmapped +descript: The driver is searching for a node table entry, on the + unmapped node list, based on DID. +data: (1) nlp (2) nlp_DID (3) nlp_flag (4) data1 +severity: Information +log: LOG_NODE verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0906[] = "%sFIND node DID unmapped Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0906 = { + FC_LOG_MSG_ND_0906, + fc_mes0906, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0907 +message: FIND node DID mapped +descript: The driver is searching for a node table entry, on the + mapped node list, based on DID. +data: (1) nlp (2) nlp_DID (3) nlp_flag (4) data1 +severity: Information +log: LOG_NODE verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0907[] = "%sFIND node DID mapped Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0907 = { + FC_LOG_MSG_ND_0907, + fc_mes0907, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0908 +message: FIND node DID bind +descript: The driver is searching for a node table entry, on the + binding list, based on DID. +data: (1) nlp (2) nlp_DID (3) nlp_flag (4) data1 +severity: Information +log: LOG_NODE verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0908[] = "%sFIND node DID bind Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0908 = { + FC_LOG_MSG_ND_0908, + fc_mes0908, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0909 +message: FIND node did NOT FOUND +descript: The driver was searching for a node table entry based on DID + and the entry was not found. +data: (1) order +severity: Information +log: LOG_NODE verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0909[] = "%sFIND node did x%x NOT FOUND Data: x%x"; +msgLogDef fc_msgBlk0909 = { + FC_LOG_MSG_ND_0909, + fc_mes0909, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0910 +message: FIND node scsi_id unmapped +descript: The driver is searching for a node table entry, on the + unmapped node list, based on the SCSI ID. +data: (1) nlp (2) nlp_DID (3) nlp_flag (4) data1 +severity: Information +log: LOG_NODE verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0910[] = "%sFIND node scsi_id unmapped Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0910 = { + FC_LOG_MSG_ND_0910, + fc_mes0910, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0911 +message: FIND node scsi_id mapped +descript: The driver is searching for a node table entry, on the + mapped node list, based on the SCSI ID. +data: (1) nlp (2) nlp_DID (3) nlp_flag (4) data1 +severity: Information +log: LOG_NODE verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0911[] = "%sFIND node scsi_id mapped Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0911 = { + FC_LOG_MSG_ND_0911, + fc_mes0911, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0912 +message: FIND node scsi_id bind +descript: The driver is searching for a node table entry, on the + binding list, based on the SCSI ID. +data: (1) nlp (2) nlp_DID (3) nlp_flag (4) data1 +severity: Information +log: LOG_NODE verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0912[] = "%sFIND node scsi_id bind Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0912 = { + FC_LOG_MSG_ND_0912, + fc_mes0912, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0913 +message: FIND node scsi_id NOT FOUND +descript: The driver was searching for a node table entry based on SCSI ID + and the entry was not found. +data: (1) scsid (2) order +severity: Information +log: LOG_NODE verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0913[] = "%sFIND node scsi_id NOT FOUND Data: x%x x%x"; +msgLogDef fc_msgBlk0913 = { + FC_LOG_MSG_ND_0913, + fc_mes0913, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0914 +message: FIND node wwnn unmapped +descript: The driver is searching for a node table entry, on the + unmapped port list, based on the WWNN. +data: (1) nlp (2) nlp_DID (3) nlp_flag (4) data1 +severity: Information +log: LOG_NODE verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0914[] = "%sFIND node wwnn unmapped Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0914 = { + FC_LOG_MSG_ND_0914, + fc_mes0914, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0915 +message: FIND node wwnn mapped +descript: The driver is searching for a node table entry, on the + mapped port list, based on the WWNN. +data: (1) nlp (2) nlp_DID (3) nlp_flag (4) data1 +severity: Information +log: LOG_NODE verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0915[] = "%sFIND node wwnn mapped Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0915 = { + FC_LOG_MSG_ND_0915, + fc_mes0915, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0916 +message: FIND node wwnn bind +descript: The driver is searching for a node table entry, on the + binding list, based on the WWNN. +data: (1) nlp (2) nlp_DID (3) nlp_flag (4) data1 +severity: Information +log: LOG_NODE verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0916[] = "%sFIND node wwnn bind Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0916 = { + FC_LOG_MSG_ND_0916, + fc_mes0916, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0917 +message: PUT END nodelist +descript: The driver is freeing a node table entry buffer. +data: (1) bp (2) fc_free +severity: Information +log: LOG_NODE verbose +module: fcmemb.c +action: None required +*/ +char fc_mes0917[] = "%sPUT END nodelist Data: x%x x%x"; +msgLogDef fc_msgBlk0917 = { + FC_LOG_MSG_ND_0917, + fc_mes0917, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0918 +message: FIND node wwnn NOT FOUND +descript: The driver was searching for a node table entry based on WWNN + and the entry was not found. +data: (1) order +severity: Information +log: LOG_NODE verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0918[] = "%sFIND node wwnn NOT FOUND Data: x%x"; +msgLogDef fc_msgBlk0918 = { + FC_LOG_MSG_ND_0918, + fc_mes0918, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0919 +message: FIND node wwpn unmapped +descript: The driver is searching for a node table entry, on the + unmapped port list, based on the WWPN. +data: (1) nlp (2) nlp_DID (3) nlp_flag (4) data1 +severity: Information +log: LOG_NODE verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0919[] = "%sFIND node wwpn unmapped Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0919 = { + FC_LOG_MSG_ND_0919, + fc_mes0919, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0920 +message: FIND node wwpn mapped +descript: The driver is searching for a node table entry, on the + mapped port list, based on the WWPN. +data: (1) nlp (2) nlp_DID (3) nlp_flag (4) data1 +severity: Information +log: LOG_NODE verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0920[] = "%sFIND node wwpn mapped Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0920 = { + FC_LOG_MSG_ND_0920, + fc_mes0920, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0921 +message: FIND node wwpn bind +descript: The driver is searching for a node table entry, on the + binding list, based on the WWPN. +data: (1) nlp (2) nlp_DID (3) nlp_flag (4) data1 +severity: Information +log: LOG_NODE verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0921[] = "%sFIND node wwpn bind Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0921 = { + FC_LOG_MSG_ND_0921, + fc_mes0921, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0922 +message: FIND node wwpn NOT FOUND +descript: The driver was searching for a node table entry based on WWPN + and the entry was not found. +data: (1) order +severity: Information +log: LOG_NODE verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0922[] = "%sFIND node wwpn NOT FOUND Data: x%x"; +msgLogDef fc_msgBlk0922 = { + FC_LOG_MSG_ND_0922, + fc_mes0922, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0923 +message: FIND node xri unmapped +descript: The driver is searching for a node table entry, on the + unmapped port list, based on the XRI. +data: (1) nlp (2) nlp_Xri (3) nlp_flag (4) data1 +severity: Information +log: LOG_NODE verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0923[] = "%sFIND node xri unmapped Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0923 = { + FC_LOG_MSG_ND_0923, + fc_mes0923, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0924 +message: FIND node xri mapped +descript: The driver is searching for a node table entry, on the + mapped port list, based on the XRI. +data: (1) nlp (2) nlp_Xri (3) nlp_flag (4) data1 +severity: Information +log: LOG_NODE verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0924[] = "%sFIND node xri mapped Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0924 = { + FC_LOG_MSG_ND_0924, + fc_mes0924, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0925 +message: FIND node xri bind +descript: The driver is searching for a node table entry, on the + binding list, based on the XRI. +data: (1) nlp (2) nlp_Xri (3) nlp_flag (4) data1 +severity: Information +log: LOG_NODE verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0925[] = "%sFIND node xri bind Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk0925 = { + FC_LOG_MSG_ND_0925, + fc_mes0925, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0926 +message: FIND node xri NOT FOUND +descript: The driver was searching for a node table entry based on the + XRI and the entry was not found. +data: (1) xri (2) order +severity: Information +log: LOG_NODE verbose +module: fcrpib.c +action: None required +*/ +char fc_mes0926[] = "%sFIND node xri NOT FOUND Data: x%x x%x"; +msgLogDef fc_msgBlk0926 = { + FC_LOG_MSG_ND_0926, + fc_mes0926, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0927 +message: GET nodelist +descript: The driver is allocating a buffer to hold a node table entry. +data: (1) bp (2) fc_free +severity: Information +log: LOG_NODE verbose +module: fcmemb.c +action: None required +*/ +char fc_mes0927[] = "%sGET nodelist Data: x%x x%x"; +msgLogDef fc_msgBlk0927 = { + FC_LOG_MSG_ND_0927, + fc_mes0927, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes0928 +message: PUT nodelist +descript: The driver is freeing a node table entry buffer. +data: (1) bp (2) fc_free +severity: Information +log: LOG_NODE verbose +module: fcmemb.c +action: None required +*/ +char fc_mes0928[] = "%sPUT nodelist Data: x%x x%x"; +msgLogDef fc_msgBlk0928 = { + FC_LOG_MSG_ND_0928, + fc_mes0928, + fc_msgPreambleNDi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_NODE, + ERRID_LOG_UNEXPECT_EVENT }; + + + +/* + * Begin MISC LOG message structures + */ + +/* +msgName: fc_mes1200 +message: Cannot unload driver while lpfcdiag Interface is active Data +descript: An attempt was made to unload the driver while the DFC + interface was active. +data: (1) lpfcdiag_cnt (2) instance +severity: Error +log: Always +module: fcLINUXfcp.c +action: Exit any application that uses the DFC diagnostic interface + before attempting to unload the driver. +*/ +char fc_mes1200[] = "%sCannot unload driver while lpfcdiag Interface is active Data: x%x x%x"; +msgLogDef fc_msgBlk1200 = { + FC_LOG_MSG_MI_1200, + fc_mes1200, + fc_msgPreambleMIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_MISC, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes1201 +message: lpfc_kmalloc: Bad p_dev_ctl +descript: The driver manages its own memory for internal usage. This + error indicates a problem occurred in the driver memory + management routines. This error could also indicate the host + system in low on memory resources. +data: (1) size (2) type (3) fc_idx_dmapool +severity: Error +log: Always +module: fcLINUXfcp.c +action: This error could indicate a driver or host operating system + problem. If problems persist report these errors to Technical + Support. +*/ +char fc_mes1201[] = "%slpfc_kmalloc: Bad p_dev_ctl Data: x%x x%x x%x"; +msgLogDef fc_msgBlk1201 = { + FC_LOG_MSG_MI_1201, + fc_mes1201, + fc_msgPreambleMIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_MISC, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes1202 +message: lpfc_kmalloc: Bad size +descript: The driver manages its own memory for internal usage. This + error indicates a problem occurred in the driver memory + management routines. This error could also indicate the host + system in low on memory resources. +data: (1) size (2) type (3) fc_idx_dmapool +severity: Error +log: Always +module: fcLINUXfcp.c +action: This error could indicate a driver or host operating system + problem. If problems persist report these errors to Technical + Support. +*/ +char fc_mes1202[] = "%slpfc_kmalloc: Bad size Data: x%x x%x x%x"; +msgLogDef fc_msgBlk1202 = { + FC_LOG_MSG_MI_1202, + fc_mes1202, + fc_msgPreambleMIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_MISC, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes1203 +message: lpfc_kmalloc: Virt addr failed to alloc +descript: The driver manages its own memory for internal usage. This + error indicates a problem occurred in the driver memory + management routines. This error could also indicate the host + system in low on memory resources. +data: (1) size (2) type +severity: Error +log: Always +module: fcLINUXfcp.c +action: This error could indicate a driver or host operating system + problem. If problems persist report these errors to Technical + Support. +*/ +char fc_mes1203[] = "%slpfc_kmalloc: Virt addr failed to alloc Data: x%x x%x"; +msgLogDef fc_msgBlk1203 = { + FC_LOG_MSG_MI_1203, + fc_mes1203, + fc_msgPreambleMIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_MISC, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes1204 +message: lpfc_kmalloc: Bad virtual addr +descript: The driver manages its own memory for internal usage. This + error indicates a problem occurred in the driver memory + management routines. This error could also indicate the host + system in low on memory resources. +data: (1) i (2) size ( 3) type (4) fc_idx_dmapool +severity: Error +log: Always +module: fcLINUXfcp.c +action: This error could indicate a driver or host operating system + problem. If problems persist report these errors to Technical + Support. +*/ +char fc_mes1204[] = "%slpfc_kmalloc: Bad virtual addr Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk1204 = { + FC_LOG_MSG_MI_1204, + fc_mes1204, + fc_msgPreambleMIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_MISC, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes1205 +message: lpfc_kmalloc: dmapool FULL +descript: The driver manages its own memory for internal usage. This + error indicates a problem occurred in the driver memory + management routines. This error could also indicate the host + system in low on memory resources. +data: (1) i (2) size (3) type (4) fc_idx_dmapool +severity: Error +log: Always +module: fcLINUXfcp.c +action: This error could indicate a driver or host operating system + problem. If problems persist report these errors to Technical + Support. +*/ +char fc_mes1205[] = "%slpfc_kmalloc: dmapool FULL Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk1205 = { + FC_LOG_MSG_MI_1205, + fc_mes1205, + fc_msgPreambleMIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_MISC, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes1206 +message: lpfc_kfree: Bad p_dev_ctl +descript: The driver manages its own memory for internal usage. This + error indicates a problem occurred in the driver memory + management routines. This error could also indicate the host + system in low on memory resources. +data: (1) size (2) fc_idx_dmapool +severity: Error +log: Always +module: fcLINUXfcp.c +action: This error could indicate a driver or host operating system + problem. If problems persist report these errors to Technical + Support. +*/ +char fc_mes1206[] = "%slpfc_kfree: Bad p_dev_ctl Data: x%x x%x"; +msgLogDef fc_msgBlk1206 = { + FC_LOG_MSG_MI_1206, + fc_mes1206, + fc_msgPreambleMIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_MISC, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes1207 +message: lpfc_kfree: NOT in dmapool +descript: The driver manages its own memory for internal usage. This + error indicates a problem occurred in the driver memory + management routines. This error could also indicate the host + system in low on memory resources. +data: (1) virt (2) size (3) fc_idx_dmapool +severity: Error +log: Always +module: fcLINUXfcp.c +action: This error could indicate a driver or host operating system + problem. If problems persist report these errors to Technical + Support. +*/ +char fc_mes1207[] = "%slpfc_kfree: NOT in dmapool Data: x%x x%x x%x"; +msgLogDef fc_msgBlk1207 = { + FC_LOG_MSG_MI_1207, + fc_mes1207, + fc_msgPreambleMIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_MISC, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes1208 +descript: The CT response returned more data than the user buffer could hold. +message: C_CT Request error +data: (1) dfc_flag (2) 4096 +severity: Information +log: LOG_MISC verbose +module: dfcdd.c +action: Modify user application issuing CT request to allow for a larger + response buffer. +*/ +char fc_mes1208[] = "%sC_CT Request error Data: x%x x%x"; +msgLogDef fc_msgBlk1208 = { + FC_LOG_MSG_MI_1208, + fc_mes1208, + fc_msgPreambleMIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_MISC, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes1209 +message: RNID Request error +descript: RNID sent back a response that was larger than the driver supports. +data: (1) fc_mptr (2) 4096 +severity: Information +log: LOG_MISC verbose +module: dfcdd.c +action: None required +*/ +char fc_mes1209[] = "%sRNID Request error Data: x%x x%x"; +msgLogDef fc_msgBlk1209 = { + FC_LOG_MSG_MI_1209, + fc_mes1209, + fc_msgPreambleMIi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_MISC, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes1210 +message: Convert ASC to hex. Input byte cnt < 1 +descript: ASCII string to hex conversion failed. Input byte count < 1. +data: none +severity: Error +log: Always +action: This error could indicate a software driver problem. + If problems persist report these errors to Technical Support. +*/ +char fc_mes1210[] = "%sConvert ASC to hex. Input byte cnt < 1"; +msgLogDef fc_msgBlk1210 = { + FC_LOG_MSG_MI_1210, + fc_mes1210, + fc_msgPreambleMIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_MISC, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes1211 +message: Convert ASC to hex. Input byte cnt > max +descript: ASCII string to hex conversion failed. Input byte count > max . +data: none +severity: Error +log: Always +action: This error could indicate a software driver problem. + If problems persist report these errors to Technical Support. +*/ +char fc_mes1211[] = "%sConvert ASC to hex. Input byte cnt > max %d"; +msgLogDef fc_msgBlk1211 = { + FC_LOG_MSG_MI_1211, + fc_mes1211, + fc_msgPreambleMIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_MISC, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes1212 +message: Convert ASC to hex. Output buffer to small +descript: ASCII string to hex conversion failed. The output buffer byte + size is less than 1/2 of input byte count. Every 2 input chars + (bytes) require 1 output byte. +data: none +severity: Error +log: Always +action: This error could indicate a software driver problem. + If problems persist report these errors to Technical Support. +*/ +char fc_mes1212[] = "%sConvert ASC to hex. Output buffer too small"; +msgLogDef fc_msgBlk1212 = { + FC_LOG_MSG_MI_1212, + fc_mes1212, + fc_msgPreambleMIe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_MISC, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes1213 +message: Convert ASC to hex. Input char seq not ASC hex. +descript: The ASCII hex input string contains a non-ASCII hex characters +data: none +severity: Error configuration +log: Always +action: Make neccessary changes to lpfc configuration file. +*/ +char fc_mes1213[] = "%sConvert ASC to hex. Input char seq not ASC hex."; +msgLogDef fc_msgBlk1213 = { + FC_LOG_MSG_MI_1213, + fc_mes1213, + fc_msgPreambleMIc, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR_CFG, + LOG_MISC, + ERRID_LOG_UNEXPECT_EVENT }; + +/* + * Begin LINK LOG Message Structures + */ + +/* +msgName: fc_mes1300 +message: Re-establishing Link, timer expired +descript: The driver detected a condition where it had to re-initialize + the link. +data: (1) fc_flag (2) fc_ffstate +severity: Error +log: Always +module: fcclockb.c +action: If numerous link events are occurring, check physical + connections to Fibre Channel network. +*/ +char fc_mes1300[] = "%sRe-establishing Link, timer expired Data: x%x x%x"; +msgLogDef fc_msgBlk1300 = { + FC_LOG_MSG_LK_1300, + fc_mes1300, + fc_msgPreambleLKe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_LINK_EVENT, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes1301 +message: Re-establishing Link +descript: The driver detected a condition where it had to re-initialize + the link. +data: (1) status (2) status1 (3) status2 +severity: Information +log: LOG_LINK_EVENT verbose +module: lp6000.c +action: If numerous link events are occurring, check physical + connections to Fibre Channel network. +*/ +char fc_mes1301[] = "%sRe-establishing Link Data: x%x x%x x%x"; +msgLogDef fc_msgBlk1301 = { + FC_LOG_MSG_LK_1301, + fc_mes1301, + fc_msgPreambleLKi, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_INFO, + LOG_LINK_EVENT, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes1302 +message: Reset link speed to auto. 1G node detected in loop. +descript: The driver is reinitializing the link speed to auto-detect. + This acton results if a 2G HBA is configured for a link + speed of 2G and the HBA detects a node that does NOT + support 2G link speed. All nodes on that loop will come + up with a link speed equal to 1G. +data: none +severity: Warning +log: LOG_LINK_EVENT verbose +module: lp6000.c +action: None required +*/ +char fc_mes1302[] = "%sReset link speed to auto. 1G node detected in loop."; +msgLogDef fc_msgBlk1302 = { + FC_LOG_MSG_LK_1302, + fc_mes1302, + fc_msgPreambleLKw, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_WARN, + LOG_LINK_EVENT, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes1303 +message: Reset link speed to auto. 1G HBA cfg'd for 2G. +descript: The driver is reinitializing the link speed to auto-detect. + This acton results if a 1G HBA is configured for 2G + link speed operation. All nodes on that loop will come + up with a link speed equal to 1G. +data: none +severity: Warning +log: LOG_LINK_EVENT verbose +module: fcfcp.c +action: None required +*/ +char fc_mes1303[] = "%sReset link speed to auto. 1G HBA cfg'd for 2G"; +msgLogDef fc_msgBlk1303 = { + FC_LOG_MSG_LK_1303, + fc_mes1303, + fc_msgPreambleLKw, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_WARN, + LOG_LINK_EVENT, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes1304 +message: Link Up Event received +descript: A link up event was received. It is also possible for + multiple link events to be received together. +data: (1) eventTag (2) fc_eventTag (3) granted_AL_PA (4) alpa_map[0] +detail: If multiple link events received, log (1) current event + number, (2) last event number received, (3) ALPA granted, + (4) number of entries in the loop init LILP ALPA map. + An ALPA map message is also recorded if LINK_EVENT + verbose mode is set. Each ALPA map message contains + 16 ALPAs. +severity: Error +log: Always +module: fcscsib.c +action: If numerous link events are occurring, check physical + connections to Fibre Channel network. +*/ +char fc_mes1304[] = "%sLink Up Event received Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk1304 = { + FC_LOG_MSG_LK_1304, + fc_mes1304, + fc_msgPreambleLKe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_LINK_EVENT, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes1305 +message: Link Up Event ALPA map +descript: A link up event was received. +data: (1) wd1 (2) wd2 (3) wd3 (4) wd4 +severity: Warning +log: LOG_LINK_EVENT verbose +module: fcscsib.c +action: If numerous link events are occurring, check physical + connections to Fibre Channel network. +*/ +char fc_mes1305[] = "%sLink Up Event ALPA map Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk1305 = { + FC_LOG_MSG_LK_1305, + fc_mes1305, + fc_msgPreambleLKw, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_WARN, + LOG_LINK_EVENT, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes1306 +message: Link Down Event received +descript: A link down event was received. +data: (1) eventTag (2) fc_eventTag (3) granted_AL_PA (4) alpa_map[0] +severity: Error +log: Always +module: fcscsib.c +action: If numerous link events are occurring, check physical + connections to Fibre Channel network. +*/ +char fc_mes1306[] = "%sLink Down Event received Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk1306 = { + FC_LOG_MSG_LK_1306, + fc_mes1306, + fc_msgPreambleLKe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_LINK_EVENT, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes1307 +message: SCSI Link Reset +descript: The SCSI layer has determined the link needs to be reset. + A LIP is sent to restart loop initialization. +data: None +severity: Error +log: Always +module: fcscsib.c +action: None required +*/ +char fc_mes1307[] = "%sSCSI Link Reset"; +msgLogDef fc_msgBlk1307 = { + FC_LOG_MSG_LK_1307, + fc_mes1307, + fc_msgPreambleLKe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_LINK_EVENT, + ERRID_LOG_UNEXPECT_EVENT }; + +/* + * Begin SLI LOG Message Structures + */ + +/* +msgName: fc_mes1400 +message: Unknown IOCB command +descript: Received an unknown IOCB command completion. +data: (1) ulpCommand (2) ulpStatus (3) ulpIoTag (4) ulpContext) +severity: Error +log: Always +module: lp6000.c +action: This error could indicate a software driver or firmware + problem. If these problems persist, report these errors + to Technical Support. +*/ +char fc_mes1400[] = "%sUnknown IOCB command Data: x%x x%x x%x x%x"; +msgLogDef fc_msgBlk1400 = { + FC_LOG_MSG_LK_1400, + fc_mes1400, + fc_msgPreambleSLe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_SLI, + ERRID_LOG_UNEXPECT_EVENT }; + +/* +msgName: fc_mes1401 +message: Command ring timeout +descript: An IOCB command was posted to a ring and did not complete + within a timeout based on RATOV. +data: (1) IOCB command (2) ulpCommand +severity: Error +log: Always +module: fcscsib.c +action: This error could indicate a software driver or firmware + problem. If no I/O is going through the adapter, reboot + the system. If these problems persist, report these errors + to Technical Support. +*/ +char fc_mes1401[] = "%sCommand ring %d timeout Data: x%x"; +msgLogDef fc_msgBlk1401 = { + FC_LOG_MSG_LK_1401, + fc_mes1401, + fc_msgPreambleSLe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_SLI, + ERRID_LOG_TIMEOUT }; + +/* +msgName: fc_mes1402 +message: Command ring timeout +descript: An IOCB command was posted to a ring and did not complete + within a timeout based on RATOV. +data: None +severity: Error +log: Always +module: fcscsib.c +action: This error could indicate a software driver or firmware + problem. If no I/O is going through the adapter, reboot + the system. If these problems persist, report these errors + to Technical Support. +*/ +char fc_mes1402[] = "%sCommand ring %d timeout"; +msgLogDef fc_msgBlk1402 = { + FC_LOG_MSG_LK_1402, + fc_mes1402, + fc_msgPreambleSLe, + FC_MSG_OPUT_GLOB_CTRL, + FC_LOG_MSG_TYPE_ERR, + LOG_SLI, + ERRID_LOG_TIMEOUT }; + + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/fcrpib.c 830-ivtv/drivers/scsi/lpfc/fcrpib.c --- 000-virgin/drivers/scsi/lpfc/fcrpib.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/fcrpib.c Thu Jan 8 10:21:53 2004 @@ -0,0 +1,2675 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Enterprise Fibre Channel Host Bus Adapters. * + * Refer to the README file included with this package for * + * driver version and adapter support. * + * Copyright (C) 2003 Emulex Corporation. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details, a copy of which * + * can be found in the file COPYING included with this package. * + *******************************************************************/ + +#include "fc_os.h" + +#include "fc_hw.h" +#include "fc.h" + +#include "fcdiag.h" +#include "fcfgparm.h" +#include "fcmsg.h" +#include "fc_crtn.h" +#include "fc_ertn.h" + +extern fc_dd_ctl_t DD_CTL; +extern iCfgParam icfgparam[]; +extern int fc_max_els_sent; + +/* Routine Declaration - Local */ +_local_ int fc_addrauth(fc_dev_ctl_t *p_dev_ctl); +_local_ void fc_clear_fcp_iocbq(fc_dev_ctl_t *p_dev_ctl, NODELIST *nlp); +_local_ void fc_clear_ip_iocbq(fc_dev_ctl_t *p_dev_ctl, NODELIST *nlp); +_local_ int fc_matchdid(FC_BRD_INFO *binfo, NODELIST *nlp, uint32 did); +/* End Routine Declaration - Local */ + +/* + * Array of all 126 valid AL_PA's (excluding FL_PORT AL_PA 0) + */ + +static uchar staticAlpaArray[] = +{ + 0x01, 0x02, 0x04, 0x08, 0x0F, 0x10, 0x17, 0x18, 0x1B, 0x1D, + 0x1E, 0x1F, 0x23, 0x25, 0x26, 0x27, 0x29, 0x2A, 0x2B, 0x2C, + 0x2D, 0x2E, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x39, 0x3A, + 0x3C, 0x43, 0x45, 0x46, 0x47, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x59, 0x5A, 0x5C, + 0x63, 0x65, 0x66, 0x67, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, + 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x79, 0x7A, 0x7C, 0x80, + 0x81, 0x82, 0x84, 0x88, 0x8F, 0x90, 0x97, 0x98, 0x9B, 0x9D, + 0x9E, 0x9F, 0xA3, 0xA5, 0xA6, 0xA7, 0xA9, 0xAA, 0xAB, 0xAC, + 0xAD, 0xAE, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB9, 0xBA, + 0xBC, 0xC3, 0xC5, 0xC6, 0xC7, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, + 0xCE, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD9, 0xDA, 0xDC, + 0xE0, 0xE1, 0xE2, 0xE4, 0xE8, 0xEF +}; + +int fc_fdmi_on = 0; + +_local_ int +fc_matchdid( +FC_BRD_INFO *binfo, +NODELIST *ndlp, +uint32 did) +{ + D_ID mydid; + D_ID odid; + D_ID ndid; + int zero_did; + + if (did == Bcast_DID) + return(0); + + zero_did = 0; + if (ndlp->nlp_DID == 0) { + ndlp->nlp_DID = ndlp->nlp_oldDID; + zero_did = 1; + } + + /* First check for Direct match */ + if (ndlp->nlp_DID == did) + return(1); + + /* Next check for area/domain == 0 match */ + mydid.un.word = binfo->fc_myDID; + if ((mydid.un.b.domain == 0) && (mydid.un.b.area == 0)) { + goto out; + } + + ndid.un.word = did; + odid.un.word = ndlp->nlp_DID; + if (ndid.un.b.id == odid.un.b.id) { + if ((mydid.un.b.domain == ndid.un.b.domain) && + (mydid.un.b.area == ndid.un.b.area)) { + ndid.un.word = ndlp->nlp_DID; + odid.un.word = did; + if ((ndid.un.b.domain == 0) && + (ndid.un.b.area == 0)) { + if (ndid.un.b.id) + return(1); + } + goto out; + } + + ndid.un.word = ndlp->nlp_DID; + if ((mydid.un.b.domain == ndid.un.b.domain) && + (mydid.un.b.area == ndid.un.b.area)) { + odid.un.word = ndlp->nlp_DID; + ndid.un.word = did; + if ((ndid.un.b.domain == 0) && + (ndid.un.b.area == 0)) { + if (ndid.un.b.id) + return(1); + } + } + } +out: + if(zero_did) + ndlp->nlp_DID = 0; + return(0); +} /* End fc_matchdid */ + + +/**************************************************/ +/** fc_nlpadjust **/ +/** **/ +/** This routine adjusts the timestamp in the **/ +/** nlplist when the counter wraps **/ +/**************************************************/ +_static_ int +fc_nlpadjust( +FC_BRD_INFO *binfo) +{ + NODELIST * ndlp; + NODELIST * nlphi, *nlpprev; + uint32 rpts; + + nlphi = 0; + nlpprev = 0; + rpts = 0; + ndlp = binfo->fc_nlpbind_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) { + if (ndlp->nlp_time > rpts) { + rpts = ndlp->nlp_time; + nlpprev = nlphi; + nlphi = ndlp; + } + + switch (ndlp->nlp_state) { + case NLP_LIMBO: + case NLP_LOGOUT: + ndlp->nlp_time = 1; + break; + + case NLP_ALLOC: + ndlp->nlp_time = 3; + break; + + default: + ndlp->nlp_time = 2; + break; + } + ndlp = (NODELIST *)ndlp->nlp_listp_next; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + } + + if (nlpprev) + nlpprev->nlp_time = 4; + if (nlphi) + nlphi->nlp_time = 5; + binfo->nlptimer = 6; + return(0); +} /* End fc_nlpadjust */ + + +/**************************************************/ +/** fc_findnode_rpi **/ +/** **/ +/** This routine find a node by rpi **/ +/**************************************************/ +_static_ NODELIST * +fc_findnode_rpi( +FC_BRD_INFO *binfo, +uint32 rpi) +{ + NODELIST * ndlp = 0; + + if (rpi < NLP_MAXRPI) + ndlp = binfo->fc_nlplookup[rpi]; + /* FIND node rpi */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0900, /* ptr to msg structure */ + fc_mes0900, /* ptr to msg */ + fc_msgBlk0900.msgPreambleStr, /* begin varargs */ + (ulong)ndlp, + rpi); /* end varargs */ + return(ndlp); +} /* End fc_findnode_rpi */ + + +/**************************************************/ +/** fc_freenode_did **/ +/** **/ +/** This routine will free an NODELIST entry **/ +/** associated with did. **/ +/**************************************************/ +_static_ int +fc_freenode_did( +FC_BRD_INFO *binfo, +uint32 did, +int rm) +{ + NODELIST * ndlp; + + + if(((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, did)) == 0) || + (ndlp->nlp_state == NLP_SEED)) { + /* no match found */ + return(0); + } + + fc_freenode(binfo, ndlp, rm); + if(rm == 0) { + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + } + return(1); +} /* End fc_freenode_did */ + + +/**************************************************/ +/** fc_free_rpilist **/ +/** **/ +/** This routine will free all NODELIST entries **/ +/** and associated buffers. **/ +/**************************************************/ +_static_ int +fc_free_rpilist( +fc_dev_ctl_t *p_dev_ctl, +int keeprpi) +{ + FC_BRD_INFO * binfo; + NODELIST * ndlp; + NODELIST * new_ndlp; + RING * rp; + IOCBQ * xmitiq; + iCfgParam * clp; + struct buf * bp; + T_SCSIBUF * sbp; + dvi_t * dev_ptr; + fc_buf_t * fcptr; + node_t * node_ptr; + + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + + /* if keeprpi == 0, toss everything on ELS xmitq and xmit pending queue */ + if (keeprpi == 0) { + rp = &binfo->fc_ring[FC_ELS_RING]; + /* get next command from ring xmit queue */ + while ((xmitiq = fc_ringtx_drain(rp)) != 0) { + fc_freebufq(p_dev_ctl, rp, xmitiq); + } + + /* look up xmit next compl */ + while ((xmitiq = fc_ringtxp_get(rp, 0)) != 0) { + fc_freebufq(p_dev_ctl, rp, xmitiq); + } + } + + /* Toss everything on LAN xmitq and xmit pending queue */ + rp = &binfo->fc_ring[FC_IP_RING]; + /* get next command from ring xmit queue */ + while ((xmitiq = fc_ringtx_drain(rp)) != 0) { + fc_freebufq(p_dev_ctl, rp, xmitiq); + } + + /* look up xmit next compl */ + while ((xmitiq = fc_ringtxp_get(rp, 0)) != 0) { + fc_freebufq(p_dev_ctl, rp, xmitiq); + } + + NDDSTAT.ndd_xmitque_cur = 0; + + if(clp[CFG_FCP_ON].a_current) { + int i; + + rp = &binfo->fc_ring[FC_FCP_RING]; + + for(i=0;ifc_table->fcp_array[i]) && + (fcptr = fc_deq_fcbuf_active(rp, (ushort)i))) { + dev_ptr = fcptr->dev_ptr; + + if(dev_ptr->queue_state == ACTIVE_PASSTHRU) { + node_t * map_node_ptr; + struct dev_info * map_dev_ptr; + + map_node_ptr = (node_t *)dev_ptr->pend_head; + map_dev_ptr = (struct dev_info *)dev_ptr->pend_tail; + dev_ptr->pend_head = 0; + dev_ptr->pend_tail = 0; + dev_ptr->queue_state = HALTED; + dev_ptr->active_io_count--; + if(map_dev_ptr) + map_dev_ptr->active_io_count--; + if(map_node_ptr) + map_node_ptr->num_active_io--; + + dev_ptr->ioctl_event = IOSTAT_LOCAL_REJECT; + + dev_ptr->ioctl_errno = IOERR_SEQUENCE_TIMEOUT; + dev_ptr->sense_length = 0; + dev_ptr->clear_count = 0; + continue; + } /* end ACTIVE_PASSTHRU management */ + + sbp = fcptr->sc_bufp; + bp = (struct buf *) sbp; + + + /* E_D_TOV timeout */ + bp->b_error = ETIMEDOUT; + + sbp->adap_q_status = SC_DID_NOT_CLEAR_Q; + bp->b_flags |= B_ERROR; + bp->b_resid = bp->b_bcount; + sbp->status_validity = SC_ADAPTER_ERROR; + SET_ADAPTER_STATUS(sbp, SC_CMD_TIMEOUT) + + if (fcptr->fcp_cmd.fcpCntl2) { + /* This is a task management command */ + if (bp->b_flags & B_ERROR) + dev_ptr->ioctl_errno = bp->b_error; + else + dev_ptr->ioctl_errno = 0; + + if (fcptr->fcp_cmd.fcpCntl2 == ABORT_TASK_SET) + dev_ptr->flags &= ~SCSI_ABORT_TSET; + + if (fcptr->fcp_cmd.fcpCntl2 & TARGET_RESET) + dev_ptr->flags &= ~SCSI_TARGET_RESET; + + if (fcptr->fcp_cmd.fcpCntl2 & LUN_RESET) + dev_ptr->flags &= ~SCSI_LUN_RESET; + + if (dev_ptr->ioctl_wakeup == 1) { + dev_ptr->ioctl_wakeup = 0; + + fc_admin_wakeup(p_dev_ctl, dev_ptr, sbp); + } else { + fc_do_iodone(bp); + } + } else { + fc_do_iodone(bp); + } + dev_ptr->active_io_count--; + dev_ptr->nodep->num_active_io--; + fc_enq_fcbuf(fcptr); + } + } + + fc_failio(p_dev_ctl); + + ndlp = binfo->fc_nlpmap_start; + while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) { + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + + /* Make sure pendq is empty */ + i = INDEX(ndlp->id.nlp_pan, ndlp->id.nlp_sid); + if ((node_ptr = binfo->device_queue_hash[i].node_ptr) != NULL) { + for (dev_ptr = node_ptr->lunlist; dev_ptr != NULL; + dev_ptr = dev_ptr->next) { + while ((sbp = dev_ptr->pend_head) != NULL) { + dev_ptr->pend_count--; + dev_ptr->pend_head = (T_SCSIBUF *) sbp->bufstruct.av_forw; + if (dev_ptr->pend_head == NULL) + dev_ptr->pend_tail = NULL; + else + dev_ptr->pend_head->bufstruct.av_back = NULL; + + sbp->bufstruct.b_flags |= B_ERROR; + sbp->bufstruct.b_error = EIO; + sbp->bufstruct.b_resid = sbp->bufstruct.b_bcount; + sbp->status_validity = SC_ADAPTER_ERROR; + SET_ADAPTER_STATUS(sbp, SC_NO_DEVICE_RESPONSE) + + sbp->bufstruct.av_forw = 0; + fc_do_iodone((struct buf *) sbp); + } + } + } + ndlp = binfo->fc_nlpmap_start; + } + } + + /* Put all Mapped and unmapped nodes on the bind list */ + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) { + new_ndlp = (NODELIST *)ndlp->nlp_listp_next; + + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + + ndlp = new_ndlp; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + } + + /* Put adapter into an error state and return all outstanding I/Os */ + fc_linkdown(p_dev_ctl); + + return(0); +} /* End fc_free_rpilist */ + + +/* + * Issue an ABORT_XRI_CX iocb command to abort an exchange + */ +_static_ int +fc_rpi_abortxri( +FC_BRD_INFO *binfo, +ushort xri) +{ + IOCB * icmd; + IOCBQ * temp; + RING * rp; + + /* Use IP ring so ABTS comes out after CLEAR_LA */ + rp = &binfo->fc_ring[FC_IP_RING]; + + /* Get an iocb buffer */ + if ((temp = (IOCBQ * )fc_mem_get(binfo, MEM_IOCB)) == 0) { + return(1); + } + fc_bzero((void *)temp, sizeof(IOCBQ)); + icmd = &temp->iocb; + + icmd->un.acxri.abortType = ABORT_TYPE_ABTS; + icmd->ulpContext = xri; + + /* set up an iotag */ + icmd->ulpIoTag = rp->fc_iotag++; + if (rp->fc_iotag == 0) { + rp->fc_iotag = 1; + } + + icmd->ulpLe = 1; + icmd->ulpClass = CLASS3; + icmd->ulpCommand = CMD_ABORT_XRI_CX; + icmd->ulpOwner = OWN_CHIP; + + issue_iocb_cmd(binfo, rp, temp); + + return(0); +} /* End fc_rpi_abortxri */ + + +/**************************************************/ +/** fc_freenode **/ +/** **/ +/** This routine will remove NODELIST entries **/ +/** rm determines state to leave entry at, **/ +/** either NLP_UNUSED or NLP_LOGOUT **/ +/**************************************************/ +_static_ int +fc_freenode( +FC_BRD_INFO *binfo, +NODELIST *nlp, +int rm) +{ + MAILBOXQ * mbox; + node_t * node_ptr; + uint32 data1; + + data1 = ( ((uint32)nlp->nlp_state << 24) | + ((uint32)nlp->nlp_action << 16) | + ((uint32)nlp->nlp_type << 8) | + rm ); + + /* Free node tbl */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0901, /* ptr to msg structure */ + fc_mes0901, /* ptr to msg */ + fc_msgBlk0901.msgPreambleStr, /* begin varargs */ + nlp->nlp_DID, + nlp->nlp_flag, + nlp->nlp_Rpi, + data1); /* end varargs */ + /* FREE node IEEE */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0902, /* ptr to msg structure */ + fc_mes0902, /* ptr to msg */ + fc_msgBlk0902.msgPreambleStr, /* begin varargs */ + nlp->nlp_nodename.IEEE[2], + nlp->nlp_nodename.IEEE[3], + nlp->nlp_nodename.IEEE[4], + nlp->nlp_nodename.IEEE[5]); /* end varargs */ + + + if(nlp == &binfo->fc_fcpnodev) + return(1); + + if(nlp->nlp_listp_next) { + if (nlp->nlp_flag & NLP_MAPPED) { + nlp->nlp_time = binfo->nlptimer++; + if (nlp->nlp_time == 0) { + fc_nlpadjust(binfo); + } + nlp->nlp_flag &= ~NLP_MAPPED; + binfo->fc_map_cnt--; + fc_deque(nlp); + } + else if (nlp->nlp_flag & NLP_UNMAPPED) { + nlp->nlp_time = binfo->nlptimer++; + if (nlp->nlp_time == 0) { + fc_nlpadjust(binfo); + } + nlp->nlp_flag &= ~NLP_UNMAPPED; + binfo->fc_unmap_cnt--; + fc_deque(nlp); + } + else if (nlp->nlp_flag & NLP_BIND) { + nlp->nlp_flag &= ~NLP_BIND; + binfo->fc_bind_cnt--; + fc_deque(nlp); + } + } + + /* Unregister login with firmware for this node */ + if (nlp->nlp_Rpi) { + /* Unregister login */ + if ((mbox = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + fc_unreg_login(binfo, nlp->nlp_Rpi, (MAILBOX * )mbox); + if (nlp->nlp_flag & NLP_UNREG_LOGO) { + ((MAILBOX *)mbox)->un.varWords[30] = nlp->nlp_DID; + } + if (issue_mb_cmd(binfo, (MAILBOX * )mbox, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mbox); + } + } + binfo->fc_nlplookup[nlp->nlp_Rpi] = 0; + nlp->nlp_Rpi = 0; + } + + if (nlp->nlp_DID) { + RING * rp; + IOCBQ * iocbq; + unsigned long iflag; + fc_dev_ctl_t *p_dev_ctl; + + /* Look through ELS ring and remove any ELS cmds in progress */ + p_dev_ctl = (fc_dev_ctl_t *)binfo->fc_p_dev_ctl; + iflag = lpfc_q_disable_lock(p_dev_ctl); + rp = &binfo->fc_ring[FC_ELS_RING]; + iocbq = (IOCBQ * )(rp->fc_txp.q_first); + while (iocbq) { + if (iocbq->iocb.un.elsreq.remoteID == nlp->nlp_DID) { + iocbq->retry = 0xff; /* Mark for abort */ + if((binfo->fc_flag & FC_RSCN_MODE) || + (binfo->fc_ffstate < FC_READY)) { + if((nlp->nlp_state >= NLP_PLOGI) && + (nlp->nlp_state <= NLP_PRLI)) { + nlp->nlp_action &= ~NLP_DO_RSCN; + binfo->fc_nlp_cnt--; + if ((nlp->nlp_type & NLP_IP_NODE) && nlp->nlp_bp) { + m_freem((fcipbuf_t *)nlp->nlp_bp); + nlp->nlp_bp = (uchar * )0; + } + } + } + } + iocbq = (IOCBQ * )iocbq->q; + } + lpfc_q_unlock_enable(p_dev_ctl, iflag); + /* In case its on fc_delay_timeout list */ + fc_abort_delay_els_cmd((fc_dev_ctl_t *)binfo->fc_p_dev_ctl, nlp->nlp_DID); + + nlp->nlp_oldDID = nlp->nlp_DID; /* save the old DID */ + } + + if (nlp->nlp_flag & (NLP_REQ_SND | NLP_REQ_SND_ADISC)) { + nlp->nlp_flag &= ~(NLP_REQ_SND | NLP_REQ_SND_ADISC); + /* Goto next entry */ + fc_nextnode((fc_dev_ctl_t * )(binfo->fc_p_dev_ctl), nlp); + } + + + if (nlp->nlp_type & NLP_IP_NODE) { + if (nlp->nlp_bp) { + m_freem((fcipbuf_t * )nlp->nlp_bp); + nlp->nlp_bp = 0; + } + + /* Go remove all entries for this node from the IP IOCBQ */ + fc_clear_ip_iocbq((fc_dev_ctl_t * )(binfo->fc_p_dev_ctl), nlp); + } + + if (nlp->nlp_type & NLP_FCP_TARGET) { + iCfgParam * clp; + + clp = DD_CTL.p_config[binfo->fc_brd_no]; + + /* Go remove all entries for this RPI from the FCP IOCBQ */ + fc_clear_fcp_iocbq((fc_dev_ctl_t *)binfo->fc_p_dev_ctl, nlp); + + if ((node_ptr = (node_t * )(nlp->nlp_targetp)) != NULL) { + dvi_t * dev_ptr; + + node_ptr->rpi = 0xfffe; + node_ptr->flags &= ~FC_FCP2_RECOVERY; + for (dev_ptr = node_ptr->lunlist; dev_ptr != NULL; + dev_ptr = dev_ptr->next) { + if(binfo->fc_ffstate == FC_READY){ + /* + * Cause the standby queue to drain. + */ + fc_return_standby_queue(dev_ptr, + (uchar)((binfo->fc_flag & FC_BUS_RESET) ? EIO : EFAULT), 0); + + fc_fail_pendq(dev_ptr, + (uchar)((binfo->fc_flag & FC_BUS_RESET) ? EIO : EFAULT), 0); + /* UNREG_LOGIN from freenode should abort txp I/Os */ + fc_fail_cmd(dev_ptr, (char)((binfo->fc_flag & FC_BUS_RESET) ? + EIO : EFAULT), 0); + + /* Call iodone for all the CLEARQ error bufs */ + fc_free_clearq(dev_ptr); + } + dev_ptr->queue_state = HALTED; + } + } + + /* Is this node, automapped or seeded */ + if(nlp->nlp_type & (NLP_AUTOMAP | NLP_SEED_MASK)) { + /* If FCP we need to keep entry around for the wwpn - sid mapping */ + nlp->nlp_type = (NLP_FCP_TARGET | + (nlp->nlp_type & (NLP_AUTOMAP | NLP_SEED_MASK))); + if(nlp->nlp_type & NLP_SEED_DID) { + fc_bzero((void *)&nlp->nlp_portname, sizeof(NAME_TYPE)); + fc_bzero((void *)&nlp->nlp_nodename, sizeof(NAME_TYPE)); + } + else { + nlp->nlp_DID = 0; + } + } + else { + nlp->nlp_flag = 0; + nlp->nlp_action = 0; + nlp->nlp_type = 0; + nlp->nlp_targetp = 0; + nlp->id.nlp_pan = 0; + nlp->id.nlp_sid = 0; + } + + if(node_ptr && (clp[CFG_NODEV_TMO].a_current) && + ((node_ptr->flags & FC_NODEV_TMO) == 0)) { + if(node_ptr->nodev_tmr == 0) { + /* START nodev timer */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0700, /* ptr to msg structure */ + fc_mes0700, /* ptr to msg */ + fc_msgBlk0700.msgPreambleStr, /* begin varargs */ + (ulong)nlp, + nlp->nlp_flag, + nlp->nlp_state, + nlp->nlp_DID); /* end varargs */ + + if(binfo->fc_ffstate != FC_LINK_DOWN) { + node_ptr->nodev_tmr = + fc_clk_set((fc_dev_ctl_t * )(binfo->fc_p_dev_ctl), + clp[CFG_NODEV_TMO].a_current, fc_nodev_timeout, + (void *)node_ptr, 0); + } + else { + node_ptr->nodev_tmr = + fc_clk_set((fc_dev_ctl_t * )(binfo->fc_p_dev_ctl), + (clp[CFG_NODEV_TMO].a_current + clp[CFG_LINKDOWN_TMO].a_current), + fc_nodev_timeout, (void *)node_ptr, 0); + } + } + } + } + else { + nlp->nlp_targetp = 0; + nlp->id.nlp_pan = 0; + nlp->id.nlp_sid = 0; + nlp->nlp_type = 0; + } + + nlp->nlp_Xri = 0; + nlp->nlp_action = 0; + + if (rm) { + fc_bzero((void *)nlp, sizeof(NODELIST)); + fc_mem_put(binfo, MEM_NLP, (uchar *)nlp); + } else { + if(nlp->nlp_flag & NLP_NS_REMOVED) + nlp->nlp_flag = NLP_NS_REMOVED; + else + nlp->nlp_flag = 0; + + /* Keep the entry cached */ + nlp->nlp_state = NLP_LIMBO; + /* Let the caller put it on the appropriate q at the appropriate time */ + } + return(1); +} /* End fc_freenode */ + + +/************************************************************************/ +/* */ +/* NAME: fc_clear_fcp_iocbq */ +/* */ +/* FUNCTION: Fail All FCP Commands in IOCBQ for one RPI */ +/* */ +/* This routine is called to clear out all FCP commands */ +/* in the IOCBQ for a specific SCSI FCP device RPI. */ +/* */ +/* EXECUTION ENVIRONMENT: */ +/* This routine can only be called on priority levels */ +/* equal to that of the interrupt handler. */ +/* */ +/* DATA STRUCTURES: */ +/* sc_buf - input/output request struct used between the adapter */ +/* driver and the calling SCSI device driver */ +/* */ +/* INPUTS: */ +/* NODELIST structure - pointer to device node structure */ +/* */ +/* RETURN VALUE DESCRIPTION: */ +/* none */ +/* */ +/************************************************************************/ +_local_ void +fc_clear_fcp_iocbq( +fc_dev_ctl_t *p_dev_ctl, +NODELIST *ndlp) +{ + FC_BRD_INFO * binfo; + T_SCSIBUF * sbp; + RING * rp; + IOCBQ * iocb_cmd, *next; + IOCB * icmd; + dvi_t * dev_ptr; + fc_buf_t * fcptr; + struct buf * bp; + Q tmpq; + + binfo = &BINFO; + + /* Clear out all fc_buf structures in the iocb queue for this RPI */ + rp = &binfo->fc_ring[FC_FCP_RING]; + tmpq.q_first = NULL; + + /* Get next command from ring xmit queue */ + iocb_cmd = fc_ringtx_get(rp); + + while (iocb_cmd) { + icmd = &iocb_cmd->iocb; + if ((icmd->ulpCommand != CMD_IOCB_CONTINUE_CN) && + (icmd->ulpContext == ndlp->nlp_Rpi)) { + + if ((fcptr = fc_deq_fcbuf_active(rp, icmd->ulpIoTag)) != NULL) { + dev_ptr = fcptr->dev_ptr; + /* Reject this command with error */ + if(dev_ptr && (dev_ptr->queue_state == ACTIVE_PASSTHRU)) { + node_t * map_node_ptr; + struct dev_info * map_dev_ptr; + + map_node_ptr = (node_t *)dev_ptr->pend_head; + map_dev_ptr = (struct dev_info *)dev_ptr->pend_tail; + dev_ptr->pend_head = 0; + dev_ptr->pend_tail = 0; + dev_ptr->queue_state = HALTED; + dev_ptr->active_io_count--; + if(map_dev_ptr) + map_dev_ptr->active_io_count--; + if(map_node_ptr) + map_node_ptr->num_active_io--; + + dev_ptr->ioctl_event = IOSTAT_LOCAL_REJECT; + + dev_ptr->ioctl_errno = IOERR_SEQUENCE_TIMEOUT; + dev_ptr->sense_length = 0; + dev_ptr->clear_count = 0; + while ((iocb_cmd = fc_ringtx_get(rp)) != NULL) { + icmd = &iocb_cmd->iocb; + if (icmd->ulpCommand != CMD_IOCB_CONTINUE_CN) + break; + fc_mem_put(binfo, MEM_IOCB, (uchar * )iocb_cmd); + } + continue; + } /* end ACTIVE_PASSTHRU management */ + + if (fcptr->fcp_cmd.fcpCntl2) { + + bp = (struct buf *)fcptr->sc_bufp; + + if(dev_ptr) { + /* This is a task management command */ + dev_ptr->ioctl_errno = ENXIO; + dev_ptr->active_io_count--; + dev_ptr->nodep->num_active_io--; + + if (fcptr->fcp_cmd.fcpCntl2 == ABORT_TASK_SET) + dev_ptr->flags &= ~SCSI_ABORT_TSET; + + if (fcptr->fcp_cmd.fcpCntl2 & TARGET_RESET) + dev_ptr->flags &= ~SCSI_TARGET_RESET; + + if (fcptr->fcp_cmd.fcpCntl2 & LUN_RESET) + dev_ptr->flags &= ~SCSI_LUN_RESET; + + if (fcptr->dev_ptr->ioctl_wakeup) { + fcptr->dev_ptr->ioctl_wakeup = 0; + fc_admin_wakeup(((fc_dev_ctl_t *)(binfo->fc_p_dev_ctl)), + fcptr->dev_ptr, fcptr->sc_bufp); + } + } + } else { + /* This is a regular FCP command */ + + bp = (struct buf *)fcptr->sc_bufp; + bp->b_error = ENXIO; + bp->b_resid = bp->b_bcount; + bp->b_flags |= B_ERROR; + + sbp = (T_SCSIBUF *)bp; + sbp->status_validity = SC_ADAPTER_ERROR; + SET_ADAPTER_STATUS(sbp, SC_NO_DEVICE_RESPONSE) + + dev_ptr = fcptr->dev_ptr; + if(dev_ptr) { + dev_ptr->active_io_count--; + dev_ptr->nodep->num_active_io--; + } + + fc_delay_iodone(p_dev_ctl, sbp); + } + fc_enq_fcbuf(fcptr); + } + + fc_mem_put(binfo, MEM_IOCB, (uchar * )iocb_cmd); + + while ((iocb_cmd = fc_ringtx_get(rp)) != NULL) { + icmd = &iocb_cmd->iocb; + if (icmd->ulpCommand != CMD_IOCB_CONTINUE_CN) + break; + fc_mem_put(binfo, MEM_IOCB, (uchar * )iocb_cmd); + } + } else { + /* Queue this iocb to the temporary queue */ + if (tmpq.q_first) { + ((IOCBQ * )tmpq.q_last)->q = (uchar * )iocb_cmd; + tmpq.q_last = (uchar * )iocb_cmd; + } else { + tmpq.q_first = (uchar * )iocb_cmd; + tmpq.q_last = (uchar * )iocb_cmd; + } + iocb_cmd->q = NULL; + + iocb_cmd = fc_ringtx_get(rp); + } + } + + /* Put the temporary queue back in the FCP iocb queue */ + iocb_cmd = (IOCBQ * )tmpq.q_first; + while (iocb_cmd) { + next = (IOCBQ * )iocb_cmd->q; + fc_ringtx_put(rp, iocb_cmd); + iocb_cmd = next; + } + + return; +} /* End fc_clear_fcp_iocbq */ + + +/************************************************************************/ +/* */ +/* NAME: fc_clear_ip_iocbq */ +/* */ +/* FUNCTION: Fail All IP Commands in IOCBQ for one RPI */ +/* */ +/* This routine is called to clear out all IP commands */ +/* in the IOCBQ for a specific IP device RPI. */ +/* */ +/* EXECUTION ENVIRONMENT: */ +/* This routine can only be called on priority levels */ +/* equal to that of the interrupt handler. */ +/* */ +/* INPUTS: */ +/* NODELIST structure - pointer to device node structure */ +/* */ +/* RETURN VALUE DESCRIPTION: */ +/* none */ +/* */ +/************************************************************************/ +_local_ void +fc_clear_ip_iocbq( +fc_dev_ctl_t *p_dev_ctl, +NODELIST *ndlp) +{ + FC_BRD_INFO * binfo; + RING * rp; + IOCBQ * xmitiq, *next; + IOCB * icmd; + Q tmpq; + fcipbuf_t * p_mbuf; + fcipbuf_t * m_net; + int i; + ULP_BDE64 * bpl; + MATCHMAP * bmp; + + binfo = &BINFO; + /* Clear out all commands in the iocb queue for this RPI */ + rp = &binfo->fc_ring[FC_IP_RING]; + tmpq.q_first = NULL; + + /* Get next command from ring xmit queue */ + xmitiq = fc_ringtx_drain(rp); + + while (xmitiq) { + icmd = &xmitiq->iocb; + if (((icmd->ulpCommand == CMD_XMIT_SEQUENCE_CX) || + (icmd->ulpCommand == CMD_XMIT_SEQUENCE64_CX) || + (icmd->ulpCommand == 0)) && + (ndlp == (NODELIST * )xmitiq->info)) { + + /* get mbuf ptr for xmit */ + m_net = (fcipbuf_t * )xmitiq->bp; + if (ndlp->nlp_DID == NameServer_DID) { + if (binfo->fc_flag & FC_SLI2) { + fc_mem_put(binfo, MEM_BPL, (uchar * )xmitiq->bpl); + } + fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq); + fc_mem_put(binfo, MEM_BUF, (uchar * )m_net); + goto out; + } + + /* Loop thru BDEs and unmap memory pages associated with mbuf */ + if (binfo->fc_flag & FC_SLI2) { + bmp = (MATCHMAP * )xmitiq->bpl; + bpl = (ULP_BDE64 * )bmp->virt; + while (bpl && xmitiq->iocb.un.xseq64.bdl.bdeSize) { + fc_bufunmap(p_dev_ctl, (uchar *)getPaddr(bpl->addrHigh, bpl->addrLow), 0, bpl->tus.f.bdeSize); + bpl++; + xmitiq->iocb.un.xseq64.bdl.bdeSize -= sizeof(ULP_BDE64); + } + fc_mem_put(binfo, MEM_BPL, (uchar * )bmp); + fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq); + } else { + for (i = 0; i < (int)xmitiq->iocb.ulpBdeCount; i++) { + fc_bufunmap(p_dev_ctl, (uchar *)((ulong)xmitiq->iocb.un.cont[i].bdeAddress), 0, (uint32)xmitiq->iocb.un.cont[i].bdeSize); + } + fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq); + } + + /* Take care of Continuation IOCBs for this mbuf */ + while ((xmitiq = fc_ringtx_drain(rp)) != NULL) { + icmd = &xmitiq->iocb; + if ((icmd->ulpCommand != CMD_IOCB_CONTINUE_CN) && + (icmd->ulpCommand != CMD_IOCB_CONTINUE64_CN)) + break; + /* Loop thru BDEs and unmap memory pages associated with IOCB */ + for (i = 0; i < (int)xmitiq->iocb.ulpBdeCount; i++) { + if (binfo->fc_flag & FC_SLI2) + fc_bufunmap(p_dev_ctl, (uchar *)getPaddr(xmitiq->iocb.un.cont64[i].addrHigh, xmitiq->iocb.un.cont64[i].addrLow), 0, xmitiq->iocb.un.cont64[i].tus.f.bdeSize); + else + fc_bufunmap(p_dev_ctl, (uchar *) ((ulong)xmitiq->iocb.un.cont[i].bdeAddress), 0, (uint32)xmitiq->iocb.un.cont[i].bdeSize); + } + fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq); + } + + p_mbuf = fcnextdata(m_net); + fcnextdata(m_net) = 0; + fcfreehandle(p_dev_ctl, m_net); + m_freem(m_net); + + if (p_mbuf) { + /* free mbuf */ + fcfreehandle(p_dev_ctl, p_mbuf); + m_freem(p_mbuf); + } + + } else { + /* Queue this iocb to the temporary queue */ + if (tmpq.q_first) { + ((IOCBQ * )tmpq.q_last)->q = (uchar * )xmitiq; + tmpq.q_last = (uchar * )xmitiq; + } else { + tmpq.q_first = (uchar * )xmitiq; + tmpq.q_last = (uchar * )xmitiq; + } + xmitiq->q = NULL; + + xmitiq = fc_ringtx_drain(rp); + } + } + +out: + /* Put the temporary queue back in the IP iocb queue */ + xmitiq = (IOCBQ * )tmpq.q_first; + while (xmitiq) { + next = (IOCBQ * )xmitiq->q; + fc_ringtx_put(rp, xmitiq); + xmitiq = next; + } + + return; +} /* End fc_clear_ip_iocbq */ + + +/**************************************************/ +/** fc_fanovery **/ +/** **/ +/** This routine will recover after a FAN rcvd **/ +/**************************************************/ +_static_ int +fc_fanovery( +fc_dev_ctl_t *p_dev_ctl) +{ + FC_BRD_INFO * binfo; + iCfgParam * clp; + NODELIST * ndlp; + NODELIST * firstndlp; + MAILBOXQ * mb; + int j, addrauth; + D_ID did; + + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + /* Device Discovery Started */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0200, /* ptr to msg structure */ + fc_mes0200, /* ptr to msg */ + fc_msgBlk0200.msgPreambleStr); /* begin & end varargs */ + binfo->fc_ffstate = FC_LOOP_DISC; + binfo->fc_nlp_cnt = 0; + binfo->fc_flag &= ~(FC_NLP_MORE | FC_DELAY_PLOGI); + + firstndlp = 0; + addrauth = 0; + /* Next, lets seed the nodeList with our ALPAmap */ + if (binfo->fc_topology == TOPOLOGY_LOOP) { + if (binfo->alpa_map[0]) { + for (j = 1; j <= binfo->alpa_map[0]; j++) { + if (((binfo->fc_myDID & 0xff) == binfo->alpa_map[j]) || + (binfo->alpa_map[j] == 0)) + continue; + /* Skip if the node is already in the node table */ + if ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, binfo->alpa_map[j]))) { + ndlp->nlp_DID = binfo->alpa_map[j]; + /* Mark slot for address authentication */ + ndlp->nlp_action |= NLP_DO_ADDR_AUTH; + addrauth++; + continue; + } + if((ndlp = (NODELIST *)fc_mem_get(binfo, MEM_NLP))) { + fc_bzero((void *)ndlp, sizeof(NODELIST)); + ndlp->sync = binfo->fc_sync; + ndlp->capabilities = binfo->fc_capabilities; + ndlp->nlp_DID = binfo->alpa_map[j]; + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + } + else + continue; + + ndlp->nlp_action |= NLP_DO_DISC_START; + if (firstndlp == 0) + firstndlp = ndlp; + } + } else { + /* No alpamap, so try all alpa's */ + for (j = 0; j < FC_MAXLOOP; j++) { + int index; + + if (clp[CFG_SCAN_DOWN].a_current) + index = FC_MAXLOOP - j - 1; + else + index = j; + if ((binfo->fc_myDID & 0xff) == staticAlpaArray[index]) + continue; + /* Skip if the node is already in the node table */ + if ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, staticAlpaArray[index]))) { + /* Mark slot for address authentication */ + ndlp->nlp_action |= NLP_DO_ADDR_AUTH; + ndlp->nlp_DID = staticAlpaArray[index]; + addrauth++; + continue; + } + if((ndlp = (NODELIST *)fc_mem_get(binfo, MEM_NLP))) { + fc_bzero((void *)ndlp, sizeof(NODELIST)); + ndlp->sync = binfo->fc_sync; + ndlp->capabilities = binfo->fc_capabilities; + ndlp->nlp_DID = staticAlpaArray[index]; + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + } + else + continue; + ndlp->nlp_action |= NLP_DO_DISC_START; + if (firstndlp == 0) + firstndlp = ndlp; + } + } + + /* Next mark ALL unmarked local nodes for Authentication */ + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) { + + /* Skip over Fabric nodes, myself, and nodes partially logged in */ + if ((ndlp->nlp_DID == binfo->fc_myDID) || + (ndlp->nlp_type & NLP_FABRIC) || + (ndlp->nlp_action & (NLP_DO_DISC_START | NLP_DO_ADDR_AUTH))) { + ndlp = (NODELIST *)ndlp->nlp_listp_next; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + continue; + } + + /* If it is a local node */ + did.un.word = ndlp->nlp_DID; + did.un.b.domain = 0; + did.un.b.area = 0; + if (fc_matchdid(binfo, ndlp, did.un.word)) { + /* Mark slot for address authentication */ + ndlp->nlp_action |= NLP_DO_ADDR_AUTH; + addrauth++; + } + ndlp = (NODELIST *)ndlp->nlp_listp_next; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + } + + if (addrauth) { + fc_nextauth(p_dev_ctl, fc_max_els_sent); + return(0); + } else { + if (firstndlp) { + /* We can start discovery right now */ + fc_nextdisc(p_dev_ctl, fc_max_els_sent); + return(0); + } + } + } + + /* This should turn off DELAYED ABTS for ELS timeouts */ + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX))) { + fc_set_slim(binfo, (MAILBOX * )mb, 0x052198, 0); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + + /* This is at init, clear la */ + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + binfo->fc_ffstate = FC_CLEAR_LA; + fc_clear_la(binfo, (MAILBOX * )mb); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } else { + binfo->fc_ffstate = FC_ERROR; + /* Device Discovery completion error */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0201, /* ptr to msg structure */ + fc_mes0201, /* ptr to msg */ + fc_msgBlk0201.msgPreambleStr); /* begin & end varargs */ + } + + if(FABRICTMO) { + fc_clk_can(p_dev_ctl, FABRICTMO); + FABRICTMO = 0; + } + return(0); +} /* End fc_fanovery */ + + +/**************************************************/ +/** fc_discovery **/ +/** **/ +/** This routine will find devices in network **/ +/**************************************************/ +_static_ int +fc_discovery( +fc_dev_ctl_t *p_dev_ctl) +{ + FC_BRD_INFO * binfo; + iCfgParam * clp; + NODELIST * ndlp; + NODELIST * new_ndlp; + NODELIST * firstndlp; + MAILBOXQ * mb; + int j, addrauth; + + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + /* Device Discovery Started */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0202, /* ptr to msg structure */ + fc_mes0202, /* ptr to msg */ + fc_msgBlk0202.msgPreambleStr); /* begin & end varargs */ + + binfo->fc_ffstate = FC_LOOP_DISC; + binfo->fc_nlp_cnt = 0; + binfo->fc_flag &= ~(FC_NLP_MORE | FC_DELAY_PLOGI); + + /* If this is not our first time doing discovery and we don't have + * a new myDID, then rediscovery (address authentication) is appropriate. + */ + if ((p_dev_ctl->init_eventTag) && (binfo->fc_prevDID == binfo->fc_myDID)) { + /* do rediscovery on the loop */ + addrauth = fc_addrauth(p_dev_ctl); + } else { + addrauth = 0; + p_dev_ctl->init_eventTag = 1; + /* First make sure all nodes in nlplist are free */ + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) { + new_ndlp = (NODELIST *)ndlp->nlp_listp_next; + + /* Skip over FABRIC nodes and myself */ + if ((ndlp->nlp_DID == binfo->fc_myDID) || + (ndlp->nlp_type & NLP_FABRIC)) { + ndlp = new_ndlp; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + continue; + } + + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + ndlp->nlp_action |= NLP_DO_DISC_START; + + ndlp = new_ndlp; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + } + } + binfo->fc_flag &= ~FC_SCSI_RLIP; + + /* If FCP is not enabled, go right to CLEAR_LA */ + if(!(clp[CFG_FCP_ON].a_current)) { + if (addrauth) { + /* Start authentication */ + fc_nextauth(p_dev_ctl, fc_max_els_sent); + return(0); + } + /* Nothing to discover, so goto CLEAR_LA */ + goto cla; + } + + firstndlp = 0; + + /* If FC_FABRIC is set, we need to do some NameServer stuff + * to seed the nodeList with additional entries. + */ + if (binfo->fc_flag & FC_FABRIC) { + /* We can LOGIN to the NameServer first */ + fc_els_cmd(binfo, ELS_CMD_PLOGI, (void *)NameServer_DID, + (uint32)0, (ushort)0, (NODELIST *)0); + if(fc_fdmi_on) { + /* HBA Mgmt */ + fc_els_cmd(binfo, ELS_CMD_PLOGI, (void *)FDMI_DID, + (uint32)0, (ushort)0, (NODELIST *)0); + } + return(0); + } + + /* No Fabric, just seed the nodeList with our ALPAmap */ + if (binfo->fc_topology == TOPOLOGY_LOOP) { + if (binfo->alpa_map[0]) { + for (j = 1; j <= binfo->alpa_map[0]; j++) { + if (((binfo->fc_myDID & 0xff) == binfo->alpa_map[j]) || + (binfo->alpa_map[j] == 0)) + continue; + /* Skip if the node is already marked address authentication */ + if((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, binfo->alpa_map[j]))) { + if(ndlp->nlp_action & (NLP_DO_ADDR_AUTH | NLP_DO_DISC_START)) { + ndlp->nlp_DID = binfo->alpa_map[j]; + if (firstndlp == 0) + firstndlp = ndlp; + continue; + } + } + else { + if((ndlp = (NODELIST *)fc_mem_get(binfo, MEM_NLP))) { + fc_bzero((void *)ndlp, sizeof(NODELIST)); + ndlp->sync = binfo->fc_sync; + ndlp->capabilities = binfo->fc_capabilities; + ndlp->nlp_DID = binfo->alpa_map[j]; + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + } + else + continue; + } + ndlp->nlp_action |= NLP_DO_DISC_START; + if (firstndlp == 0) + firstndlp = ndlp; + } + } else { + /* No alpamap, so try all alpa's */ + for (j = 0; j < FC_MAXLOOP; j++) { + int index; + + if (clp[CFG_SCAN_DOWN].a_current) + index = FC_MAXLOOP - j - 1; + else + index = j; + if ((binfo->fc_myDID & 0xff) == staticAlpaArray[index]) + continue; + /* Skip if the node is already marked address authentication */ + if((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, staticAlpaArray[index]))) { + if(ndlp->nlp_action & (NLP_DO_ADDR_AUTH | NLP_DO_DISC_START)) { + ndlp->nlp_DID = staticAlpaArray[index]; + if (firstndlp == 0) + firstndlp = ndlp; + continue; + } + } + else { + if((ndlp = (NODELIST *)fc_mem_get(binfo, MEM_NLP))) { + fc_bzero((void *)ndlp, sizeof(NODELIST)); + ndlp->sync = binfo->fc_sync; + ndlp->capabilities = binfo->fc_capabilities; + ndlp->nlp_DID = staticAlpaArray[index]; + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + } + else + continue; + } + ndlp->nlp_action |= NLP_DO_DISC_START; + if (firstndlp == 0) + firstndlp = ndlp; + } + } + } + /* Device Discovery continues */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0203, /* ptr to msg structure */ + fc_mes0203, /* ptr to msg */ + fc_msgBlk0203.msgPreambleStr, /* begin varargs */ + (ulong)firstndlp, + binfo->fc_ffstate); /* end varargs */ + if (addrauth) { + /* Start authentication */ + if(fc_nextauth(p_dev_ctl, fc_max_els_sent)) + return(0); + } + + if (firstndlp) { + /* We can start discovery right now */ + fc_nextdisc(p_dev_ctl, fc_max_els_sent); + return(0); + } + else { + /* Make sure no nodes are marked for discovery */ + /* go through all nodes in nlplist */ + ndlp = binfo->fc_nlpbind_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) { + if (ndlp->nlp_action & (NLP_DO_ADDR_AUTH | NLP_DO_DISC_START)) + ndlp->nlp_action &= ~(NLP_DO_ADDR_AUTH | NLP_DO_DISC_START); + ndlp = (NODELIST *)ndlp->nlp_listp_next; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + } + } + +cla: + /* This should turn off DELAYED ABTS for ELS timeouts */ + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX))) { + fc_set_slim(binfo, (MAILBOX * )mb, 0x052198, 0); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + + /* This is at init, clear la */ + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + binfo->fc_ffstate = FC_CLEAR_LA; + fc_clear_la(binfo, (MAILBOX * )mb); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } else { + binfo->fc_ffstate = FC_ERROR; + /* Device Discovery completion error */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0204, /* ptr to msg structure */ + fc_mes0204, /* ptr to msg */ + fc_msgBlk0204.msgPreambleStr); /* begin & end varargs */ + } + if(FABRICTMO) { + fc_clk_can(p_dev_ctl, FABRICTMO); + FABRICTMO = 0; + } + return(0); +} /* End fc_discovery */ + + +/**************************************************/ +/** fc_addrauth **/ +/** **/ +/** This routine will validate NODELIST entries **/ +/**************************************************/ +_local_ int +fc_addrauth( +fc_dev_ctl_t *p_dev_ctl) +{ + FC_BRD_INFO * binfo; + iCfgParam * clp; + NODELIST * ndlp; + NODELIST * new_ndlp; + int cnt; + int cnt1, cnt2; + + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + + binfo->fc_nlp_cnt = 0; + binfo->fc_flag &= ~FC_NLP_MORE; + cnt = 0; + cnt1 = 0; + cnt2 = 0; + + /* go through all nodes in nlplist */ + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) { + new_ndlp = (NODELIST *)ndlp->nlp_listp_next; + + /* Skip over Fabric nodes, myself, and nodes partially logged in */ + if ((ndlp->nlp_DID == binfo->fc_myDID) || + (ndlp->nlp_type & NLP_FABRIC)) { + ndlp = new_ndlp; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + continue; + } + + if ((ndlp->nlp_type & NLP_FCP_TARGET) && + ((!clp[CFG_USE_ADISC].a_current) || (ndlp->nlp_Rpi == 0) || + (binfo->fc_flag & FC_SCSI_RLIP))) { + /* Force regular discovery on this node */ + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + ndlp->nlp_action &= ~NLP_DO_ADDR_AUTH; + ndlp->nlp_action |= NLP_DO_DISC_START; + cnt1++; + } else { + if ((ndlp->nlp_type & NLP_IP_NODE) && (ndlp->nlp_Rpi == 0)) { + /* Force regular discovery on this node */ + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + ndlp->nlp_action &= ~NLP_DO_ADDR_AUTH; + ndlp->nlp_action |= NLP_DO_DISC_START; + cnt2++; + } else { + /* Mark slot for address authentication */ + ndlp->nlp_action |= NLP_DO_ADDR_AUTH; + cnt++; + } + } + ndlp = new_ndlp; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + } + + /* Device Discovery authentication */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0205, /* ptr to msg structure */ + fc_mes0205, /* ptr to msg */ + fc_msgBlk0205.msgPreambleStr, /* begin varargs */ + cnt, + cnt1, + cnt2); /* end varargs */ + return(cnt); +} /* End fc_addrauth */ + + +/**************************************************/ +/** fc_freebufq **/ +/** **/ +/** This routine will free a iocb cmd block and **/ +/** all associated memory. **/ +/**************************************************/ +_static_ void +fc_freebufq( +fc_dev_ctl_t *p_dev_ctl, +RING *rp, +IOCBQ *xmitiq) +{ + FC_BRD_INFO * binfo; + fcipbuf_t * p_mbuf; + fcipbuf_t * m_net; + NODELIST * ndlp; + ULP_BDE64 * bpl; + MATCHMAP * bmp; + int i; + + binfo = &BINFO; + switch (xmitiq->iocb.ulpCommand) { + case 0: + case CMD_XMIT_BCAST_CN: /* process xmit completion */ + case CMD_XMIT_BCAST_CX: + case CMD_XMIT_SEQUENCE_CX: + case CMD_XMIT_BCAST64_CN: /* process xmit completion */ + case CMD_XMIT_BCAST64_CX: + case CMD_XMIT_SEQUENCE64_CX: + /* get mbuf ptr for xmit */ + m_net = (fcipbuf_t * )xmitiq->bp; + ndlp = (NODELIST * ) xmitiq->info; + + /* Loop thru BDEs and unmap memory pages associated with mbuf */ + if (binfo->fc_flag & FC_SLI2) { + bmp = (MATCHMAP * )xmitiq->bpl; + if(bmp) { + bpl = (ULP_BDE64 * )bmp->virt; + while (bpl && xmitiq->iocb.un.xseq64.bdl.bdeSize) { + fc_bufunmap(p_dev_ctl, (uchar *)getPaddr(bpl->addrHigh, bpl->addrLow), 0, bpl->tus.f.bdeSize); + bpl++; + xmitiq->iocb.un.xseq64.bdl.bdeSize -= sizeof(ULP_BDE64); + } + fc_mem_put(binfo, MEM_BPL, (uchar * )bmp); + } + fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq); + } else { + for (i = 0; i < (int)xmitiq->iocb.ulpBdeCount; i++) { + fc_bufunmap(p_dev_ctl, (uchar *)((ulong)xmitiq->iocb.un.cont[i].bdeAddress), 0, (uint32)xmitiq->iocb.un.cont[i].bdeSize); + } + fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq); + } + + if (ndlp && (ndlp->nlp_DID == NameServer_DID)) { + fc_mem_put(binfo, MEM_BUF, (uchar * )m_net); + } else { + /* free mbuf */ + p_mbuf = fcnextdata(m_net); + fcnextdata(m_net) = 0; + fcfreehandle(p_dev_ctl, m_net); + m_freem(m_net); + if (p_mbuf) { + fcfreehandle(p_dev_ctl, p_mbuf); + m_freem(p_mbuf); + } + } + break; + + case CMD_IOCB_CONTINUE_CN: + case CMD_IOCB_CONTINUE64_CN: + /* This is valid only for the IP ring, not the ELS ring */ + if (rp->fc_ringno == FC_ELS_RING) + break; + /* Loop thru BDEs and unmap memory pages associated with IOCB */ + for (i = 0; i < (int)xmitiq->iocb.ulpBdeCount; i++) { + if (binfo->fc_flag & FC_SLI2) + fc_bufunmap(p_dev_ctl, (uchar *)getPaddr(xmitiq->iocb.un.cont64[i].addrHigh, xmitiq->iocb.un.cont64[i].addrLow), 0, xmitiq->iocb.un.cont64[i].tus.f.bdeSize); + else + fc_bufunmap(p_dev_ctl, (uchar *)((ulong)xmitiq->iocb.un.cont[i].bdeAddress), 0, (uint32)xmitiq->iocb.un.cont[i].bdeSize); + } + fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq); + break; + + case CMD_XMIT_ELS_RSP_CX: + case CMD_XMIT_ELS_RSP64_CX: + if (xmitiq->bp) { + fc_mem_put(binfo, MEM_BUF, (uchar * )xmitiq->bp); + } + if (binfo->fc_flag & FC_SLI2) { + fc_mem_put(binfo, MEM_BPL, (uchar * )xmitiq->bpl); + } + fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq); + break; + + case CMD_ELS_REQUEST_CR: + case CMD_ELS_REQUEST64_CR: + if (xmitiq->bp) { + fc_mem_put(binfo, MEM_BUF, (uchar * )xmitiq->bp); + } + if (xmitiq->info) { + fc_mem_put(binfo, MEM_BUF, (uchar * )xmitiq->info); + } + if (binfo->fc_flag & FC_SLI2) { + fc_mem_put(binfo, MEM_BPL, (uchar * )xmitiq->bpl); + } + fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq); + break; + + case CMD_QUE_RING_BUF_CN: + case CMD_QUE_RING_BUF64_CN: + /* Loop thru BDEs and return MEM_BUFs associated with IOCB */ + for (i = 0; i < (int)xmitiq->iocb.ulpBdeCount; i++) { + MATCHMAP * matp; + + if (binfo->fc_flag & FC_SLI2) + matp = fc_getvaddr(p_dev_ctl, rp, + (uchar * )getPaddr(xmitiq->iocb.un.cont64[i].addrHigh, xmitiq->iocb.un.cont64[i].addrLow)); + else + matp = fc_getvaddr(p_dev_ctl, rp, + (uchar * )((ulong)xmitiq->iocb.un.cont[i].bdeAddress)); + if (matp) { + if (rp->fc_ringno == FC_ELS_RING) { + fc_mem_put(binfo, MEM_BUF, (uchar * )matp); + } + if (rp->fc_ringno == FC_IP_RING) { + p_mbuf = (fcipbuf_t * )matp; + fcnextdata(p_mbuf) = 0; + fcnextpkt(p_mbuf) = 0; + m_freem(p_mbuf); + } + } + } + fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq); + break; + + case CMD_CREATE_XRI_CX: + case CMD_CREATE_XRI_CR: + default: + fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq); + break; + } +} /* End fc_freebufq */ + + +/**************************************************/ +/** fc_emac_lookup **/ +/** **/ +/** This routine will find an NODELIST entry **/ +/** that matches the destination MAC address. **/ +/** The XID for that entry is returned and rpi **/ +/** is updated with a ptr to the NODELIST entry. **/ +/**************************************************/ +_static_ ushort +fc_emac_lookup( +FC_BRD_INFO *binfo, +uchar *addr, +NODELIST **ndlpp) +{ + int j; + NODELIST * ndlp; + + ndlp = binfo->fc_nlpbind_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) { + + /* IF portname matches IEEE address, return NODELIST entry */ + if ((ndlp->nlp_portname.IEEE[0] == addr[0])) { + if((ndlp->nlp_state == NLP_SEED) || + ((ndlp->nlp_DID != Bcast_DID) && + ((ndlp->nlp_DID & CT_DID_MASK) == CT_DID_MASK))) { + ndlp = (NODELIST *)ndlp->nlp_listp_next; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + continue; + } + + /* check rest of bytes in address / portname */ + for (j = 1; j < NADDR_LEN; j++) { + if (ndlp->nlp_portname.IEEE[j] != addr[j]) + break; + } + /* do all NADDR_LEN bytes match? */ + if (j == NADDR_LEN) { + if ((ndlp->nlp_portname.nameType == NAME_IEEE) && + (ndlp->nlp_portname.IEEEextMsn == 0) && + (ndlp->nlp_portname.IEEEextLsb == 0)) { + *ndlpp = ndlp; + return(ndlp->nlp_Xri); + } + } + } + ndlp = (NODELIST *)ndlp->nlp_listp_next; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + } + + /* no match so return 0 */ + + *ndlpp = 0; + return(0); +} /* End fc_emac_lookup */ + + + +/* Put nlp on bind list */ +_static_ int +fc_nlp_bind( +FC_BRD_INFO *binfo, +NODELIST *nlp) +{ + NODELIST *end_nlp; + uint32 data1; + + data1 = ( ((uint32)nlp->nlp_state << 24) | + ((uint32)nlp->nlp_action << 16) | + ((uint32)nlp->nlp_type << 8) | + ((uint32)nlp->nlp_Rpi & 0xff) ); + /* BIND node tbl */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0903, /* ptr to msg structure */ + fc_mes0903, /* ptr to msg */ + fc_msgBlk0903.msgPreambleStr, /* begin varargs */ + (ulong)nlp, + nlp->nlp_DID, + nlp->nlp_flag, + data1); /* end varargs */ + /* First take it off any list its on */ + if(nlp->nlp_listp_next) { + if (nlp->nlp_flag & NLP_MAPPED) { + nlp->nlp_time = binfo->nlptimer++; + if (nlp->nlp_time == 0) { + fc_nlpadjust(binfo); + } + nlp->nlp_flag &= ~NLP_MAPPED; + binfo->fc_map_cnt--; + fc_deque(nlp); + } + else if (nlp->nlp_flag & NLP_UNMAPPED) { + nlp->nlp_time = binfo->nlptimer++; + if (nlp->nlp_time == 0) { + fc_nlpadjust(binfo); + } + nlp->nlp_flag &= ~NLP_UNMAPPED; + binfo->fc_unmap_cnt--; + fc_deque(nlp); + } + else if (nlp->nlp_flag & NLP_BIND) { + return(0); /* Already on bind list */ + } + } + + /* Put it at the begining of the bind list */ + binfo->fc_bind_cnt++; + + if(binfo->fc_nlpbind_start == (NODELIST *)&binfo->fc_nlpbind_start) { + nlp->nlp_listp_next = &binfo->fc_nlpbind_start; + binfo->fc_nlpbind_end = nlp; + } + else { + end_nlp = binfo->fc_nlpbind_start; + nlp->nlp_listp_next = end_nlp; + end_nlp->nlp_listp_prev = nlp; + } + binfo->fc_nlpbind_start = nlp;; + nlp->nlp_listp_prev = &binfo->fc_nlpbind_start; + + nlp->nlp_flag |= NLP_BIND; + + return(0); +} + +/* Put nlp on unmap list */ +_static_ int +fc_nlp_unmap( +FC_BRD_INFO *binfo, +NODELIST *nlp) +{ + NODELIST * end_nlp; + RING * rp; + IOCBQ * iocbq; + uint32 data1; + fc_dev_ctl_t * p_dev_ctl; + + data1 = ( ((uint32)nlp->nlp_state << 24) | + ((uint32)nlp->nlp_action << 16) | + ((uint32)nlp->nlp_type << 8) | + ((uint32)nlp->nlp_Rpi & 0xff) ); + /* UNMAP node tbl */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0904, /* ptr to msg structure */ + fc_mes0904, /* ptr to msg */ + fc_msgBlk0904.msgPreambleStr, /* begin varargs */ + (ulong)nlp, + nlp->nlp_DID, + nlp->nlp_flag, + data1); /* end varargs */ + /* First take it off any list its on */ + if(nlp->nlp_listp_next) { + if (nlp->nlp_flag & NLP_MAPPED) { + nlp->nlp_time = binfo->nlptimer++; + if (nlp->nlp_time == 0) { + fc_nlpadjust(binfo); + } + nlp->nlp_flag &= ~NLP_MAPPED; + binfo->fc_map_cnt--; + fc_deque(nlp); + } + else if (nlp->nlp_flag & NLP_BIND) { + nlp->nlp_time = binfo->nlptimer++; + if (nlp->nlp_time == 0) { + fc_nlpadjust(binfo); + } + nlp->nlp_flag &= ~NLP_BIND; + binfo->fc_bind_cnt--; + fc_deque(nlp); + /* If we are going from bind to unmapped, check for duplicate + * WWNN on bind list. + */ + /* Missing SP */ + p_dev_ctl = (fc_dev_ctl_t * )(binfo->fc_p_dev_ctl); + + /* Fabric nodes are always mapped by DID only */ + if((nlp->nlp_DID & Fabric_DID_MASK) == Fabric_DID_MASK) + goto out; + + switch(p_dev_ctl->fcp_mapping) { + + case FCP_SEED_DID: + break; + + case FCP_SEED_WWNN: + if((end_nlp = fc_findnode_wwnn(binfo, NLP_SEARCH_BIND, &nlp->nlp_nodename))) { + /* Found one so remove it */ + unsigned long iflag; + end_nlp->nlp_flag &= ~NLP_BIND; + binfo->fc_bind_cnt--; + fc_deque(end_nlp); + /* Look through ELS ring and remove any ELS cmds in progress for rnlp */ + iflag = lpfc_q_disable_lock(p_dev_ctl); + rp = &binfo->fc_ring[FC_ELS_RING]; + iocbq = (IOCBQ * )(rp->fc_txp.q_first); + while (iocbq) { + if ((iocbq->iocb.un.elsreq.remoteID == end_nlp->nlp_DID) || + ((end_nlp->nlp_DID == 0) && + (iocbq->iocb.un.elsreq.remoteID == end_nlp->nlp_oldDID))) { + iocbq->retry = 0xff; /* Mark for abort */ + if((binfo->fc_flag & FC_RSCN_MODE) || + (binfo->fc_ffstate < FC_READY)) { + if((end_nlp->nlp_state >= NLP_PLOGI) && + (end_nlp->nlp_state <= NLP_PRLI)) { + end_nlp->nlp_action &= ~NLP_DO_RSCN; + binfo->fc_nlp_cnt--; + if ((end_nlp->nlp_type & NLP_IP_NODE) && end_nlp->nlp_bp) { + m_freem((fcipbuf_t *)end_nlp->nlp_bp); + end_nlp->nlp_bp = (uchar * )0; + } + } + } + } + iocbq = (IOCBQ * )iocbq->q; + } + lpfc_q_unlock_enable(p_dev_ctl, iflag); + /* In case its on fc_delay_timeout list */ + fc_abort_delay_els_cmd(p_dev_ctl, end_nlp->nlp_DID); + fc_bzero((void *)end_nlp, sizeof(NODELIST)); + fc_mem_put(binfo, MEM_NLP, (uchar *)end_nlp); + } + break; + + case FCP_SEED_WWPN: + if((end_nlp = fc_findnode_wwpn(binfo, NLP_SEARCH_BIND, &nlp->nlp_portname))) { + /* Found one so remove it */ + unsigned long iflag; + end_nlp->nlp_flag &= ~NLP_BIND; + binfo->fc_bind_cnt--; + fc_deque(end_nlp); + /* Look through ELS ring and remove any ELS cmds in progress for rnlp */ + iflag = lpfc_q_disable_lock(p_dev_ctl); + rp = &binfo->fc_ring[FC_ELS_RING]; + iocbq = (IOCBQ * )(rp->fc_txp.q_first); + while (iocbq) { + if ((iocbq->iocb.un.elsreq.remoteID == end_nlp->nlp_DID) || + ((end_nlp->nlp_DID == 0) && (iocbq->iocb.un.elsreq.remoteID == end_nlp->nlp_oldDID))) { + iocbq->retry = 0xff; /* Mark for abort */ + if((binfo->fc_flag & FC_RSCN_MODE) || + (binfo->fc_ffstate < FC_READY)) { + if((end_nlp->nlp_state >= NLP_PLOGI) && + (end_nlp->nlp_state <= NLP_PRLI)) { + end_nlp->nlp_action &= ~NLP_DO_RSCN; + binfo->fc_nlp_cnt--; + if ((end_nlp->nlp_type & NLP_IP_NODE) && end_nlp->nlp_bp) { + m_freem((fcipbuf_t *)end_nlp->nlp_bp); + end_nlp->nlp_bp = (uchar * )0; + } + } + } + } + iocbq = (IOCBQ * )iocbq->q; + } + lpfc_q_unlock_enable(p_dev_ctl, iflag); + /* In case its on fc_delay_timeout list */ + fc_abort_delay_els_cmd(p_dev_ctl, end_nlp->nlp_DID); + fc_bzero((void *)end_nlp, sizeof(NODELIST)); + fc_mem_put(binfo, MEM_NLP, (uchar *)end_nlp); + } + break; + } /* switch */ + } + else if (nlp->nlp_flag & NLP_UNMAPPED) { + return(0); /* Already on unmap list */ + } + } + +out: + /* Put it on the end of the unmapped list */ + binfo->fc_unmap_cnt++; + end_nlp = binfo->fc_nlpunmap_end; + fc_enque(nlp, end_nlp); + nlp->nlp_flag |= NLP_UNMAPPED; + return(0); +} + +/* Put nlp on map list */ +_static_ int +fc_nlp_map( +FC_BRD_INFO *binfo, +NODELIST *nlp) +{ + NODELIST *end_nlp; + uint32 data1; + + data1 = ( ((uint32)nlp->nlp_state << 24) | + ((uint32)nlp->nlp_action << 16) | + ((uint32)nlp->nlp_type << 8) | + ((uint32)nlp->nlp_Rpi & 0xff) ); + /* MAP node tbl */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0905, /* ptr to msg structure */ + fc_mes0905, /* ptr to msg */ + fc_msgBlk0905.msgPreambleStr, /* begin varargs */ + (ulong)nlp, + nlp->nlp_DID, + nlp->nlp_flag, + data1); /* end varargs */ + /* First take it off any list its on */ + if(nlp->nlp_listp_next) { + if (nlp->nlp_flag & NLP_UNMAPPED) { + nlp->nlp_time = binfo->nlptimer++; + if (nlp->nlp_time == 0) { + fc_nlpadjust(binfo); + } + nlp->nlp_flag &= ~NLP_UNMAPPED; + binfo->fc_unmap_cnt--; + fc_deque(nlp); + } + else if (nlp->nlp_flag & NLP_BIND) { + nlp->nlp_time = binfo->nlptimer++; + if (nlp->nlp_time == 0) { + fc_nlpadjust(binfo); + } + nlp->nlp_flag &= ~NLP_BIND; + binfo->fc_bind_cnt--; + fc_deque(nlp); + } + else if (nlp->nlp_flag & NLP_MAPPED) { + return(0); /* Already on map list */ + } + } + + /* Put it on the end of the mapped list */ + binfo->fc_map_cnt++; + end_nlp = binfo->fc_nlpmap_end; + fc_enque(nlp, end_nlp); + nlp->nlp_flag |= NLP_MAPPED; + return(0); +} + +/**************************************************/ +/** fc_findnode_odid **/ +/** **/ +/** This routine find a node by did **/ +/**************************************************/ +_static_ NODELIST * +fc_findnode_odid( +FC_BRD_INFO *binfo, +uint32 order, +uint32 did) +{ + NODELIST * nlp; + uint32 data1; + + if(order & NLP_SEARCH_UNMAPPED) { + nlp = binfo->fc_nlpunmap_start; + while(nlp != (NODELIST *)&binfo->fc_nlpunmap_start) { + if (fc_matchdid(binfo, nlp, did)) { + + data1 = ( ((uint32)nlp->nlp_state << 24) | + ((uint32)nlp->nlp_action << 16) | + ((uint32)nlp->nlp_type << 8) | + ((uint32)nlp->nlp_Rpi & 0xff) ); + /* FIND node DID unmapped */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0906, /* ptr to msg structure */ + fc_mes0906, /* ptr to msg */ + fc_msgBlk0906.msgPreambleStr, /* begin varargs */ + (ulong)nlp, + nlp->nlp_DID, + nlp->nlp_flag, + data1); /* end varargs */ + return(nlp); + } + nlp = (NODELIST *)nlp->nlp_listp_next; + } + } + if(order & NLP_SEARCH_MAPPED) { + nlp = binfo->fc_nlpmap_start; + while(nlp != (NODELIST *)&binfo->fc_nlpmap_start) { + if (fc_matchdid(binfo, nlp, did)) { + + data1 = ( ((uint32)nlp->nlp_state << 24) | + ((uint32)nlp->nlp_action << 16) | + ((uint32)nlp->nlp_type << 8) | + ((uint32)nlp->nlp_Rpi & 0xff) ); + /* FIND node did mapped */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0907, /* ptr to msg structure */ + fc_mes0907, /* ptr to msg */ + fc_msgBlk0907.msgPreambleStr, /* begin varargs */ + (ulong)nlp, + nlp->nlp_DID, + nlp->nlp_flag, + data1); /* end varargs */ + return(nlp); + } + nlp = (NODELIST *)nlp->nlp_listp_next; + } + } + if(order & NLP_SEARCH_BIND) { + nlp = binfo->fc_nlpbind_start; + while(nlp != (NODELIST *)&binfo->fc_nlpbind_start) { + if (fc_matchdid(binfo, nlp, did)) { + + data1 = ( ((uint32)nlp->nlp_state << 24) | + ((uint32)nlp->nlp_action << 16) | + ((uint32)nlp->nlp_type << 8) | + ((uint32)nlp->nlp_Rpi & 0xff) ); + /* FIND node DID bind */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0908, /* ptr to msg structure */ + fc_mes0908, /* ptr to msg */ + fc_msgBlk0908.msgPreambleStr, /* begin varargs */ + (ulong)nlp, + nlp->nlp_DID, + nlp->nlp_flag, + data1); /* end varargs */ + return(nlp); + } + nlp = (NODELIST *)nlp->nlp_listp_next; + } + } + /* FIND node did NOT FOUND */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0909, /* ptr to msg structure */ + fc_mes0909, /* ptr to msg */ + fc_msgBlk0909.msgPreambleStr, /* begin varargs */ + did, + order); /* end varargs */ + /* no match found */ + return((NODELIST * )0); +} /* End fc_findnode_odid */ + + +/**************************************************/ +/** fc_findnode_scsid **/ +/** **/ +/** This routine find a node by scsid **/ +/**************************************************/ +_static_ NODELIST * +fc_findnode_scsid( +FC_BRD_INFO *binfo, +uint32 order, +uint32 scsid) +{ + NODELIST * nlp; + uint32 data1; + + if(order & NLP_SEARCH_UNMAPPED) { + nlp = binfo->fc_nlpunmap_start; + if(nlp == 0) { + return(0); + } + while(nlp != (NODELIST *)&binfo->fc_nlpunmap_start) { + if ((nlp->nlp_type & NLP_FCP_TARGET) && + (INDEX(nlp->id.nlp_pan, nlp->id.nlp_sid) == scsid)) { + + data1 = ( ((uint32)nlp->nlp_state << 24) | + ((uint32)nlp->nlp_action << 16) | + ((uint32)nlp->nlp_type << 8) | + ((uint32)scsid & 0xff) ); + /* FIND node scsi_id unmapped */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0910, /* ptr to msg structure */ + fc_mes0910, /* ptr to msg */ + fc_msgBlk0910.msgPreambleStr, /* begin varargs */ + (ulong)nlp, + nlp->nlp_DID, + nlp->nlp_flag, + data1); /* end varargs */ + return(nlp); + } + nlp = (NODELIST *)nlp->nlp_listp_next; + if(nlp == 0) { + return(0); + } + } + } + if(order & NLP_SEARCH_MAPPED) { + nlp = binfo->fc_nlpmap_start; + if(nlp == 0) { + return(0); + } + while(nlp != (NODELIST *)&binfo->fc_nlpmap_start) { + if ((nlp->nlp_type & NLP_FCP_TARGET) && + (INDEX(nlp->id.nlp_pan, nlp->id.nlp_sid) == scsid)) { + + data1 = ( ((uint32)nlp->nlp_state << 24) | + ((uint32)nlp->nlp_action << 16) | + ((uint32)nlp->nlp_type << 8) | + ((uint32)scsid & 0xff) ); + /* FIND node scsi_id mapped */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0911, /* ptr to msg structure */ + fc_mes0911, /* ptr to msg */ + fc_msgBlk0911.msgPreambleStr, /* begin varargs */ + (ulong)nlp, + nlp->nlp_DID, + nlp->nlp_flag, + data1); /* end varargs */ + return(nlp); + } + nlp = (NODELIST *)nlp->nlp_listp_next; + if(nlp == 0) { + return(0); + } + } + } + if(order & NLP_SEARCH_BIND) { + nlp = binfo->fc_nlpbind_start; + if(nlp == 0) { + return(0); + } + while(nlp != (NODELIST *)&binfo->fc_nlpbind_start) { + if ((nlp->nlp_type & NLP_FCP_TARGET) && + (INDEX(nlp->id.nlp_pan, nlp->id.nlp_sid) == scsid)) { + + data1 = ( ((uint32)nlp->nlp_state << 24) | + ((uint32)nlp->nlp_action << 16) | + ((uint32)nlp->nlp_type << 8) | + ((uint32)scsid & 0xff) ); + /* FIND node scsi_id bind */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0912, /* ptr to msg structure */ + fc_mes0912, /* ptr to msg */ + fc_msgBlk0912.msgPreambleStr, /* begin varargs */ + (ulong)nlp, + nlp->nlp_DID, + nlp->nlp_flag, + data1); /* end varargs */ + return(nlp); + } + nlp = (NODELIST *)nlp->nlp_listp_next; + if(nlp == 0) { + return(0); + } + } + } + /* FIND node scsi_id NOT FOUND */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0913, /* ptr to msg structure */ + fc_mes0913, /* ptr to msg */ + fc_msgBlk0913.msgPreambleStr, /* begin varargs */ + scsid, + order); /* end varargs */ + /* no match found */ + return((NODELIST * )0); +} /* End fc_findnode_scsid */ + + +/**************************************************/ +/** fc_findnode_wwnn **/ +/** **/ +/** This routine find a node by WWNN **/ +/**************************************************/ +_static_ NODELIST * +fc_findnode_wwnn( +FC_BRD_INFO *binfo, +uint32 order, +NAME_TYPE * wwnn) +{ + NODELIST * nlp; + uint32 data1; + + if(order & NLP_SEARCH_UNMAPPED) { + nlp = binfo->fc_nlpunmap_start; + while(nlp != (NODELIST *)&binfo->fc_nlpunmap_start) { + if(fc_geportname(&nlp->nlp_nodename, wwnn) == 2) { + + data1 = ( ((uint32)nlp->nlp_state << 24) | + ((uint32)nlp->nlp_action << 16) | + ((uint32)nlp->nlp_type << 8) | + ((uint32)nlp->nlp_Rpi & 0xff) ); + /* FIND node wwnn unmapped */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0914, /* ptr to msg structure */ + fc_mes0914, /* ptr to msg */ + fc_msgBlk0914.msgPreambleStr, /* begin varargs */ + (ulong)nlp, + nlp->nlp_DID, + nlp->nlp_flag, + data1); /* end varargs */ + return(nlp); + } + nlp = (NODELIST *)nlp->nlp_listp_next; + } + } + if(order & NLP_SEARCH_MAPPED) { + nlp = binfo->fc_nlpmap_start; + while(nlp != (NODELIST *)&binfo->fc_nlpmap_start) { + if(fc_geportname(&nlp->nlp_nodename, wwnn) == 2) { + + data1 = ( ((uint32)nlp->nlp_state << 24) | + ((uint32)nlp->nlp_action << 16) | + ((uint32)nlp->nlp_type << 8) | + ((uint32)nlp->nlp_Rpi & 0xff) ); + /* FIND node wwnn mapped */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0915, /* ptr to msg structure */ + fc_mes0915, /* ptr to msg */ + fc_msgBlk0915.msgPreambleStr, /* begin varargs */ + (ulong)nlp, + nlp->nlp_DID, + nlp->nlp_flag, + data1); /* end varargs */ + return(nlp); + } + nlp = (NODELIST *)nlp->nlp_listp_next; + } + } + if(order & NLP_SEARCH_BIND) { + nlp = binfo->fc_nlpbind_start; + while(nlp != (NODELIST *)&binfo->fc_nlpbind_start) { + if(fc_geportname(&nlp->nlp_nodename, wwnn) == 2) { + + data1 = ( ((uint32)nlp->nlp_state << 24) | + ((uint32)nlp->nlp_action << 16) | + ((uint32)nlp->nlp_type << 8) | + ((uint32)nlp->nlp_Rpi & 0xff) ); + /* FIND node wwnn bind */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0916, /* ptr to msg structure */ + fc_mes0916, /* ptr to msg */ + fc_msgBlk0916.msgPreambleStr, /* begin varargs */ + (ulong)nlp, + nlp->nlp_DID, + nlp->nlp_flag, + data1); /* end varargs */ + return(nlp); + } + nlp = (NODELIST *)nlp->nlp_listp_next; + } + } + /* FIND node wwnn NOT FOUND */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0918, /* ptr to msg structure */ + fc_mes0918, /* ptr to msg */ + fc_msgBlk0918.msgPreambleStr, /* begin varargs */ + order); /* end varargs */ + /* no match found */ + return((NODELIST * )0); +} /* End fc_findnode_wwnn */ + + + +/**************************************************/ +/** fc_findnode_wwpn **/ +/** **/ +/** This routine find a node by WWPN **/ +/**************************************************/ +_static_ NODELIST * +fc_findnode_wwpn( +FC_BRD_INFO *binfo, +uint32 order, +NAME_TYPE * wwpn) +{ + NODELIST * nlp; + uint32 data1; + + if(order & NLP_SEARCH_UNMAPPED) { + nlp = binfo->fc_nlpunmap_start; + while(nlp != (NODELIST *)&binfo->fc_nlpunmap_start) { + if(fc_geportname(&nlp->nlp_portname, wwpn) == 2) { + + data1 = ( ((uint32)nlp->nlp_state << 24) | + ((uint32)nlp->nlp_action << 16) | + ((uint32)nlp->nlp_type << 8) | + ((uint32)nlp->nlp_Rpi & 0xff) ); + /* FIND node wwpn unmapped */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0919, /* ptr to msg structure */ + fc_mes0919, /* ptr to msg */ + fc_msgBlk0919.msgPreambleStr, /* begin varargs */ + (ulong)nlp, + nlp->nlp_DID, + nlp->nlp_flag, + data1); /* end varargs */ + return(nlp); + } + nlp = (NODELIST *)nlp->nlp_listp_next; + } + } + if(order & NLP_SEARCH_MAPPED) { + nlp = binfo->fc_nlpmap_start; + while(nlp != (NODELIST *)&binfo->fc_nlpmap_start) { + if(fc_geportname(&nlp->nlp_portname, wwpn) == 2) { + + data1 = ( ((uint32)nlp->nlp_state << 24) | + ((uint32)nlp->nlp_action << 16) | + ((uint32)nlp->nlp_type << 8) | + ((uint32)nlp->nlp_Rpi & 0xff) ); + /* FIND node wwpn mapped */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0920, /* ptr to msg structure */ + fc_mes0920, /* ptr to msg */ + fc_msgBlk0920.msgPreambleStr, /* begin varargs */ + (ulong)nlp, + nlp->nlp_DID, + nlp->nlp_flag, + data1); /* end varargs */ + return(nlp); + } + nlp = (NODELIST *)nlp->nlp_listp_next; + } + } + if(order & NLP_SEARCH_BIND) { + nlp = binfo->fc_nlpbind_start; + while(nlp != (NODELIST *)&binfo->fc_nlpbind_start) { + if(fc_geportname(&nlp->nlp_portname, wwpn) == 2) { + + data1 = ( ((uint32)nlp->nlp_state << 24) | + ((uint32)nlp->nlp_action << 16) | + ((uint32)nlp->nlp_type << 8) | + ((uint32)nlp->nlp_Rpi & 0xff) ); + /* FIND node wwpn bind */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0921, /* ptr to msg structure */ + fc_mes0921, /* ptr to msg */ + fc_msgBlk0921.msgPreambleStr, /* begin varargs */ + (ulong)nlp, + nlp->nlp_DID, + nlp->nlp_flag, + data1); /* end varargs */ + return(nlp); + } + nlp = (NODELIST *)nlp->nlp_listp_next; + } + } + /* FIND node wwpn NOT FOUND */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0922, /* ptr to msg structure */ + fc_mes0922, /* ptr to msg */ + fc_msgBlk0922.msgPreambleStr, /* begin varargs */ + order); /* end varargs */ + /* no match found */ + return((NODELIST * )0); +} /* End fc_findnode_wwpn */ + + +/**************************************************/ +/** fc_findnode_oxri **/ +/** **/ +/** This routine find a node by OXri **/ +/**************************************************/ +_static_ NODELIST * +fc_findnode_oxri( +FC_BRD_INFO *binfo, +uint32 order, +uint32 xri) +{ + NODELIST * nlp; + uint32 data1; + + if(order & NLP_SEARCH_UNMAPPED) { + nlp = binfo->fc_nlpunmap_start; + while(nlp != (NODELIST *)&binfo->fc_nlpunmap_start) { + if (nlp->nlp_Xri == xri) { + + data1 = ( ((uint32)nlp->nlp_state << 24) | + ((uint32)nlp->nlp_action << 16) | + ((uint32)nlp->nlp_type << 8) | + ((uint32)nlp->nlp_Rpi & 0xff) ); + /* FIND node xri unmapped */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0923, /* ptr to msg structure */ + fc_mes0923, /* ptr to msg */ + fc_msgBlk0923.msgPreambleStr, /* begin varargs */ + (ulong)nlp, + nlp->nlp_Xri, + nlp->nlp_flag, + data1); /* end varargs */ + return(nlp); + } + nlp = (NODELIST *)nlp->nlp_listp_next; + } + } + if(order & NLP_SEARCH_MAPPED) { + nlp = binfo->fc_nlpmap_start; + while(nlp != (NODELIST *)&binfo->fc_nlpmap_start) { + if (nlp->nlp_Xri == xri) { + + data1 = ( ((uint32)nlp->nlp_state << 24) | + ((uint32)nlp->nlp_action << 16) | + ((uint32)nlp->nlp_type << 8) | + ((uint32)nlp->nlp_Rpi & 0xff) ); + /* FIND node xri mapped */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0924, /* ptr to msg structure */ + fc_mes0924, /* ptr to msg */ + fc_msgBlk0924.msgPreambleStr, /* begin varargs */ + (ulong)nlp, + nlp->nlp_Xri, + nlp->nlp_flag, + data1); /* end varargs */ + return(nlp); + } + nlp = (NODELIST *)nlp->nlp_listp_next; + } + } + if(order & NLP_SEARCH_BIND) { + nlp = binfo->fc_nlpbind_start; + while(nlp != (NODELIST *)&binfo->fc_nlpbind_start) { + if (nlp->nlp_Xri == xri) { + + data1 = ( ((uint32)nlp->nlp_state << 24) | + ((uint32)nlp->nlp_action << 16) | + ((uint32)nlp->nlp_type << 8) | + ((uint32)nlp->nlp_Rpi & 0xff) ); + /* FIND node xri bind */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0925, /* ptr to msg structure */ + fc_mes0925, /* ptr to msg */ + fc_msgBlk0925.msgPreambleStr, /* begin varargs */ + (ulong)nlp, + nlp->nlp_Xri, + nlp->nlp_flag, + data1); /* end varargs */ + return(nlp); + } + nlp = (NODELIST *)nlp->nlp_listp_next; + } + } + /* FIND node xri NOT FOUND */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0926, /* ptr to msg structure */ + fc_mes0926, /* ptr to msg */ + fc_msgBlk0926.msgPreambleStr, /* begin varargs */ + xri, + order); /* end varargs */ + /* no match found */ + return((NODELIST * )0); +} /* End fc_findnode_oxri */ + +/* Put nlp in PLOGI state */ +_static_ int +fc_nlp_logi( +FC_BRD_INFO *binfo, +NODELIST *nlp, +NAME_TYPE *wwpnp, +NAME_TYPE *wwnnp) +{ + fc_dev_ctl_t * p_dev_ctl; + NODELIST * rnlp; + + if (nlp->nlp_flag & NLP_UNMAPPED) { + nlp->nlp_flag &= ~NLP_UNMAPPED; + binfo->fc_unmap_cnt--; + fc_deque(nlp); + } + else if (nlp->nlp_flag & NLP_BIND) { + nlp->nlp_flag &= ~NLP_BIND; + binfo->fc_bind_cnt--; + fc_deque(nlp); + } + else if (nlp->nlp_flag & NLP_MAPPED) { + nlp->nlp_flag &= ~NLP_MAPPED; + binfo->fc_map_cnt--; + fc_deque(nlp); + } + + p_dev_ctl = (fc_dev_ctl_t * )(binfo->fc_p_dev_ctl); + + /* Fabric nodes are always mapped by DID only */ + if((nlp->nlp_DID & Fabric_DID_MASK) == Fabric_DID_MASK) + goto out; + + switch(p_dev_ctl->fcp_mapping) { + case FCP_SEED_DID: + fc_bcopy(wwpnp, &nlp->nlp_portname, sizeof(NAME_TYPE)); + fc_bcopy(wwnnp, &nlp->nlp_nodename, sizeof(NAME_TYPE)); + break; + case FCP_SEED_WWNN: + /* Check to see if this WWNN already has a binding setup */ + if(fc_geportname(&nlp->nlp_nodename, wwnnp) != 2) { + if (nlp->nlp_type & NLP_SEED_WWNN) { + /* Get a new entry to save old binding info */ + if((rnlp = (NODELIST *)fc_mem_get(binfo, MEM_NLP))) { + fc_bzero((void *)rnlp, sizeof(NODELIST)); + rnlp->nlp_state = NLP_LIMBO; + fc_nlp_swapinfo(binfo, nlp, rnlp); + fc_nlp_bind(binfo, rnlp); + } + } + /* Search for existing entry with that binding */ + if((rnlp = fc_findnode_wwnn(binfo, NLP_SEARCH_ALL, wwnnp)) && + (rnlp->nlp_type & NLP_SEED_WWNN)) { + + if (rnlp->nlp_flag & NLP_MAPPED) { + rnlp->nlp_flag &= ~NLP_MAPPED; + binfo->fc_map_cnt--; + fc_deque(rnlp); + } + else if (rnlp->nlp_flag & NLP_UNMAPPED) { + rnlp->nlp_flag &= ~NLP_UNMAPPED; + binfo->fc_unmap_cnt--; + fc_deque(rnlp); + } + else if (rnlp->nlp_flag & NLP_BIND) { + rnlp->nlp_flag &= ~NLP_BIND; + binfo->fc_bind_cnt--; + fc_deque(rnlp); + } + + /* found, so copy binding info into nlp */ + fc_nlp_swapinfo(binfo, rnlp, nlp); + if(rnlp->nlp_action || (rnlp->nlp_flag & NLP_REQ_SND)) { + fc_nlp_bind(binfo, rnlp); + } + else { + fc_freenode(binfo, rnlp, 1); + } + } + fc_bcopy(wwpnp, &nlp->nlp_portname, sizeof(NAME_TYPE)); + fc_bcopy(wwnnp, &nlp->nlp_nodename, sizeof(NAME_TYPE)); + } + else { + /* DID and WWNN match existing entry */ + fc_bcopy(wwpnp, &nlp->nlp_portname, sizeof(NAME_TYPE)); + } + break; + case FCP_SEED_WWPN: + /* Check to see if this WWPN already has a binding setup */ + if(fc_geportname(&nlp->nlp_portname, wwpnp) != 2) { + if (nlp->nlp_type & NLP_SEED_WWPN) { + /* Get a new entry to save old binding info */ + if((rnlp = (NODELIST *)fc_mem_get(binfo, MEM_NLP))) { + fc_bzero((void *)rnlp, sizeof(NODELIST)); + rnlp->nlp_state = NLP_LIMBO; + fc_nlp_swapinfo(binfo, nlp, rnlp); + fc_nlp_bind(binfo, rnlp); + } + } + /* Search for existing entry with that binding */ + if((rnlp = fc_findnode_wwpn(binfo, NLP_SEARCH_ALL, wwpnp)) && + (rnlp->nlp_type & NLP_SEED_WWPN)) { + + if (rnlp->nlp_flag & NLP_MAPPED) { + rnlp->nlp_flag &= ~NLP_MAPPED; + binfo->fc_map_cnt--; + fc_deque(rnlp); + } + else if (rnlp->nlp_flag & NLP_UNMAPPED) { + rnlp->nlp_flag &= ~NLP_UNMAPPED; + binfo->fc_unmap_cnt--; + fc_deque(rnlp); + } + else if (rnlp->nlp_flag & NLP_BIND) { + rnlp->nlp_flag &= ~NLP_BIND; + binfo->fc_bind_cnt--; + fc_deque(rnlp); + } + /* found, so copy binding info into nlp */ + fc_nlp_swapinfo(binfo, rnlp, nlp); + if(rnlp->nlp_action || (rnlp->nlp_flag & NLP_REQ_SND)) { + fc_nlp_bind(binfo, rnlp); + } + else { + fc_freenode(binfo, rnlp, 1); + } + } +out: + fc_bcopy(wwpnp, &nlp->nlp_portname, sizeof(NAME_TYPE)); + fc_bcopy(wwnnp, &nlp->nlp_nodename, sizeof(NAME_TYPE)); + } + else { + /* DID and WWPN match existing entry */ + fc_bcopy(wwnnp, &nlp->nlp_nodename, sizeof(NAME_TYPE)); + } + break; + } + + nlp->nlp_state = NLP_PLOGI; + fc_nlp_bind(binfo, nlp); + return(0); +} + +_static_ int +fc_nlp_swapinfo( +FC_BRD_INFO *binfo, +NODELIST *old_nlp, +NODELIST *new_nlp) +{ + int index; + + fc_bcopy(&old_nlp->nlp_nodename, &new_nlp->nlp_nodename, sizeof(NAME_TYPE)); + fc_bcopy(&old_nlp->nlp_portname, &new_nlp->nlp_portname, sizeof(NAME_TYPE)); + new_nlp->nlp_type = old_nlp->nlp_type; + new_nlp->id.nlp_pan = old_nlp->id.nlp_pan; + new_nlp->id.nlp_sid = old_nlp->id.nlp_sid; + new_nlp->nlp_targetp = old_nlp->nlp_targetp; + new_nlp->target_scsi_options = old_nlp->target_scsi_options; + new_nlp->capabilities = old_nlp->capabilities; + new_nlp->sync = old_nlp->sync; + + if((old_nlp->nlp_type & NLP_FCP_TARGET) && old_nlp->nlp_targetp != NULL) { + index = INDEX(new_nlp->id.nlp_pan, new_nlp->id.nlp_sid); + if(binfo->device_queue_hash[index].node_ptr && + binfo->device_queue_hash[index].node_ptr->nlp == old_nlp) { + binfo->device_queue_hash[index].node_ptr->nlp = new_nlp; + new_nlp->nlp_targetp = (uchar *)binfo->device_queue_hash[index].node_ptr; + } + } + + old_nlp->nlp_type = 0; + old_nlp->id.nlp_pan = 0; + old_nlp->id.nlp_sid = 0; + old_nlp->nlp_targetp = 0; + old_nlp->sync = binfo->fc_sync; + old_nlp->capabilities = binfo->fc_capabilities; + fc_bzero(&old_nlp->nlp_nodename, sizeof(NAME_TYPE)); + fc_bzero(&old_nlp->nlp_portname, sizeof(NAME_TYPE)); + return(0); +} + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/fcscsib.c 830-ivtv/drivers/scsi/lpfc/fcscsib.c --- 000-virgin/drivers/scsi/lpfc/fcscsib.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/fcscsib.c Thu Jan 8 10:21:53 2004 @@ -0,0 +1,7611 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Enterprise Fibre Channel Host Bus Adapters. * + * Refer to the README file included with this package for * + * driver version and adapter support. * + * Copyright (C) 2003 Emulex Corporation. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details, a copy of which * + * can be found in the file COPYING included with this package. * + *******************************************************************/ + +#include "fc_os.h" + +#include "fc_hw.h" +#include "fc.h" + +#include "fcdiag.h" +#include "hbaapi.h" +#include "fcfgparm.h" +#include "fcmsg.h" +#include "fc_crtn.h" +#include "fc_ertn.h" /* Environment - external routine definitions */ + +extern clock_t fc_ticks_per_second; +extern fc_dd_ctl_t DD_CTL; +extern iCfgParam icfgparam[]; +extern int lpfc_nethdr; +extern uint32 fcPAGESIZE; +extern uint32 fc_diag_state; +extern int fcinstance[]; + +/* Routine Declaration - Local */ +_local_ void fc_rscndisc_timeout(fc_dev_ctl_t *p_dev_ctl, void *l1, void *l2); +_local_ int fc_ring_txcnt(FC_BRD_INFO *binfo, int flag); +_local_ int fc_ring_txpcnt(FC_BRD_INFO *binfo, int flag); +/* End Routine Declaration - Local */ + +static uchar fcbroadcastaddr[MACADDR_LEN] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +_static_ int fc_max_ns_retry = 3; +_static_ int fc_inq_hbeat_tmo = 60; +_static_ int fc_inq_sn_tmo = 30; +_static_ int fc_offline_stop_io = 1; +_static_ int fc_max_els_sent = 32; + +#define INQ_LEN 0x100 + +#define RPTLUN_MIN_LEN 0x1000 +#define WD6 (IOCB_WORD_SZ-2) /* IOCB wd 6 */ +#define WD7 (IOCB_WORD_SZ-1) /* IOCB wd 7 */ +/********************************************/ +/** fc_strncmp **/ +/** **/ +/** Compare string 1 to string 2. **/ +/** Compare terminates on count N **/ +/** **/ +/** Return value: **/ +/** Less than 0 = str1 < str2 **/ +/** Zero = str1 egual str2 **/ +/** Greater than 0 = str1 > str2 **/ +/********************************************/ +_forward_ int +fc_strncmp( char *str1, + char *str2, + int cnt) +{ + int c1, c2; + int dif; + + while( cnt--) { + c1 = (int)*str1++ & 0xff; + c2 = (int)*str2++ & 0xff; + if( (c1 | c2) == 0) + return(0); /* strings equal */ + if( (dif = c1 - c2) == 0) + continue; /* chars are equal */ + if( c1 == 0) + return(-1); /* str1 < str2 */ + if( c2 == 0) + return(1); /* str1 > str2 */ + return(dif); + } + return(0); /* strings equal */ +} /* fc_strncmp */ + +/********************************************/ +/* fc_strcpy */ +/* */ +/* Copy str2 to str1. . */ +/* Str2 must be a pointer to a null */ +/* terminated string. It is the caller's */ +/* responsibility to insure that str1 is */ +/* large enough to hold str2. */ +/* */ +/* Return value: */ +/* pointer to str1 */ +/********************************************/ +_static_ char * +fc_strcpy( char *str1, /* dest */ + char *str2) /* src */ +{ + char *temp; + temp = str1; + + while( (*str1++ = *str2++) != '\0') { + continue; + } + return(temp); +} /* fc_strcpy */ + +/************************************************/ +/** fc_setup_ring **/ +/** **/ +/** After ring has been configured, this **/ +/** routine is called to initialize the ring **/ +/************************************************/ +_static_ void +fc_setup_ring( +fc_dev_ctl_t *p_dev_ctl, /* point to dev_ctl area */ +int ring) +{ + FC_BRD_INFO * binfo; + iCfgParam * clp; + RING * rp; + + binfo = &BINFO; + rp = &binfo->fc_ring[ring]; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + + /* set up the watchdog timer control structure section */ + if (!rp->fc_wdt_inited) { + if (ring == FC_FCP_RING) { + if(clp[CFG_LINKDOWN_TMO].a_current) { + rp->fc_ringtmo = clp[CFG_LINKDOWN_TMO].a_current; + } + else { + rp->fc_ringtmo = clp[CFG_LINKDOWN_TMO].a_default; + } + } else { + rp->fc_ringtmo = RING_TMO_DFT; + } + RINGTMO = 0; + rp->fc_wdt_inited = 1; + } +} /* End fc_setup_ring */ + +/************************************************************************/ +/* */ +/* NAME: fc_closewait */ +/* */ +/* FUNCTION: Adapter Driver Wait for Close Routine */ +/* This routine waits for the adapter to finish all requests */ +/* */ +/* EXECUTION ENVIRONMENT: */ +/* This routine can be called by a process. */ +/* */ +/* INPUTS: */ +/* fc_dev_ctl_t - adapter unique data structure (one per adapter) */ +/* */ +/* RETURN VALUE DESCRIPTION: none */ +/* */ +/* EXTERNAL PROCEDURES CALLED: */ +/* disable_lock lock_enable */ +/* */ +/************************************************************************/ +_static_ void +fc_closewait( +fc_dev_ctl_t *p_dev_ctl) /* point to dev_ctl area */ +{ + FC_BRD_INFO * binfo; + int ipri; + struct buf *bp, *nextbp; + + binfo = &BINFO; + + ipri = disable_lock(FC_LVL, &CMD_LOCK); + + /* wait for all operations to complete */ + while ((fc_ring_txcnt(binfo, FC_FCP_RING) + || fc_ring_txpcnt(binfo, FC_FCP_RING) + || binfo->fc_mbox.q_cnt)) { + unlock_enable(ipri, &CMD_LOCK); + DELAYMSctx(1000); /* delay 1 second */ + ipri = disable_lock(FC_LVL, &CMD_LOCK); + } + + /* Clear out timeout queue */ + for (bp = p_dev_ctl->timeout_head; bp != NULL; ) { + nextbp = bp->av_forw; + bp->b_error = ETIMEDOUT; + bp->b_flags |= B_ERROR; + bp->b_resid = bp->b_bcount; + FCSTATCTR.fcpScsiTmo++; + fc_do_iodone(bp); + bp = nextbp; + } + p_dev_ctl->timeout_head = NULL; + p_dev_ctl->timeout_count = 0; + + /* update the device state */ + binfo->fc_open_count &= ~FC_FCP_OPEN; + if (binfo->fc_open_count == 0) + p_dev_ctl->device_state = CLOSED; + + unlock_enable(ipri, &CMD_LOCK); + return; + +} /* End fc_closewait */ + + +/* + * This routine copies data from src + * then potentially swaps the destination to big endian. + * Assumes cnt is a multiple of sizeof(uint32). + */ +_static_ void +fc_pcimem_bcopy( +uint32 *src, +uint32 *dest, +uint32 cnt) +{ + uint32 ldata; + int i; + + for (i = 0; i < (int)cnt; i += sizeof(uint32)) { + ldata = *src++; + ldata = PCIMEM_LONG(ldata); + *dest++ = ldata; + } +} /* End fc_pcimem_bcopy */ + + +#define SCSI3_PERSISTENT_RESERVE_IN 0x5e + +/******************************************************/ +/** handle_fcp_event **/ +/** **/ +/** Description: Process an FCP Rsp Ring completion **/ +/** **/ +/******************************************************/ +_static_ void +handle_fcp_event( +fc_dev_ctl_t *p_dev_ctl, +RING *rp, +IOCBQ *temp) +{ + FC_BRD_INFO * binfo; + iCfgParam * clp; + IOCB * cmd; + fc_buf_t * fcptr; + struct buf * bp; + T_SCSIBUF * sbp; + FCP_RSP * fcpRsp; + uint32 * lp, i, qfull; + dvi_t * dev_ptr, * next_dev_ptr; + NODELIST * ndlp; + + /* called from host_interrupt() to process R2ATT */ + binfo = &BINFO; + cmd = &temp->iocb; + qfull = 0; + ndlp = 0; + + /* look up FCP complete by IoTag */ + if ((fcptr = fc_deq_fcbuf_active(rp, cmd->ulpIoTag)) == NULL) { + /* ERROR: completion with missing FCP command */ + if (!((cmd->ulpStatus == IOSTAT_LOCAL_REJECT) && + ((cmd->un.grsp.perr.statLocalError == IOERR_INVALID_RPI) || + (cmd->un.grsp.perr.statLocalError == IOERR_ABORT_IN_PROGRESS) || + (cmd->un.grsp.perr.statLocalError == IOERR_SEQUENCE_TIMEOUT) || + (cmd->un.grsp.perr.statLocalError == IOERR_ABORT_REQUESTED)))) { + /* Stray FCP completion */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0720, /* ptr to msg structure */ + fc_mes0720, /* ptr to msg */ + fc_msgBlk0720.msgPreambleStr, /* begin varargs */ + cmd->ulpCommand, + cmd->ulpIoTag, + cmd->ulpStatus, + cmd->un.ulpWord[4]); /* end varargs */ + } + + FCSTATCTR.fcpStrayCmpl++; + return; + } + FCSTATCTR.fcpCmpl++; + + dev_ptr = fcptr->dev_ptr; + dev_ptr->stop_send_io = 0; + + + if(dev_ptr->queue_state == ACTIVE_PASSTHRU) { + node_t * map_node_ptr; + struct dev_info * map_dev_ptr; + + map_node_ptr = (node_t *)dev_ptr->pend_head; + map_dev_ptr = (struct dev_info *)dev_ptr->pend_tail; + dev_ptr->pend_head = 0; + dev_ptr->pend_tail = 0; + dev_ptr->queue_state = HALTED; + dev_ptr->active_io_count--; + if(map_dev_ptr) + map_dev_ptr->active_io_count--; + if(map_node_ptr) + map_node_ptr->num_active_io--; + + dev_ptr->ioctl_event = cmd->ulpStatus; + dev_ptr->ioctl_errno = (uint32)cmd->un.grsp.perr.statLocalError; + fcpRsp = &fcptr->fcp_rsp; + dev_ptr->sense_length = SWAP_DATA(fcpRsp->rspSnsLen); + if(cmd->ulpCommand == CMD_FCP_IWRITE64_CX) { + if (cmd->ulpStatus == IOSTAT_SUCCESS) { + dev_ptr->clear_count = 1; + } + else { + dev_ptr->clear_count = 0; + } + } + else { + dev_ptr->clear_count = cmd->un.fcpi.fcpi_parm; + } + return; + } + + /* + * Is it a SCSI Report Lun command ? + */ + if ((fcptr->fcp_cmd.fcpCdb[0] == FCP_SCSI_REPORT_LUNS) && + (fcptr->flags & FCBUF_INTERNAL)) { + uchar *datap; + MBUF_INFO *mbufp; + node_t *nodep; + uint32 rptLunLen; + uint32 *datap32; + uint32 max, lun; + + mbufp = (MBUF_INFO *)fcptr->sc_bufp; + fcptr->sc_bufp = 0; + mbufp->size = 4096; + nodep = dev_ptr->nodep; + if(nodep == 0) { + fc_mem_put(binfo, MEM_IOCB, (uchar * )mbufp); + dev_ptr->active_io_count--; + fc_enq_fcbuf(fcptr); + return; + } + if ((cmd->ulpStatus == IOSTAT_SUCCESS) || + ((cmd->ulpStatus == IOSTAT_FCP_RSP_ERROR) && + (fcptr->fcp_rsp.rspStatus2 & RESID_UNDER) && + (fcptr->fcp_rsp.rspStatus3 == SCSI_STAT_GOOD))) { + + datap = (uchar *)mbufp->virt; + /* + * if Lun0 uses VSA, we assume others use too. + */ + if ((datap[8] & 0xc0) == 0x40) { + nodep->addr_mode = VOLUME_SET_ADDRESSING; + } + /* + * Skip retry + */ + datap32 = (uint32 *)mbufp->virt; + rptLunLen = SWAP_DATA(*datap32); + /* search for the max lun */ + max = 0; + for(i=0; i < rptLunLen; i+=8) { + datap32 += 2; + lun = (((* datap32) >> FC_LUN_SHIFT) & 0xff); + if(lun > max) + max = lun; + } + if(i) { + nodep->max_lun = max + 1; + } + + if(nodep->virtRptLunData == 0) { + if(rptLunLen > 8) { /* more than 1 lun */ + nodep->virtRptLunData = mbufp->virt; + nodep->physRptLunData = mbufp->phys; + } else { + fc_free(p_dev_ctl, mbufp); + } + } + } else { + datap = 0; + fc_free(p_dev_ctl, mbufp); + nodep->virtRptLunData = 0; + nodep->physRptLunData = 0; + } + + fc_mem_put(binfo, MEM_IOCB, (uchar * )mbufp); + + dev_ptr->active_io_count--; + nodep->num_active_io--; + fc_enq_fcbuf(fcptr); + + if ((datap == 0) && (!(nodep->flags & RETRY_RPTLUN))) { + nodep->flags |= RETRY_RPTLUN; + /* Wait a little bit for ABTSs to settle down */ + fc_clk_set(p_dev_ctl, 1, issue_report_lun, (void *)dev_ptr, 0); + } + else { + nodep->flags &= ~RETRY_RPTLUN; + nodep->rptlunstate = REPORT_LUN_COMPLETE; + } + return; + } + + + sbp = fcptr->sc_bufp; + bp = (struct buf *) sbp; + + + if (cmd->ulpStatus) { + fcpRsp = &fcptr->fcp_rsp; + { + uint32 did; + uint32 pan; + uint32 sid; + + if ((dev_ptr->nodep) && (dev_ptr->nodep->nlp)) { + ndlp = dev_ptr->nodep->nlp; + did = ndlp->nlp_DID; + pan = ndlp->id.nlp_pan; + sid = ndlp->id.nlp_sid; + if(ndlp->nlp_action & NLP_DO_RSCN) + qfull = 1; + } else { + did = 0; + pan = 0; + sid = 0; + } + /* FCP cmd failed on device (, ) DID */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0729, /* ptr to msg structure */ + fc_mes0729, /* ptr to msg */ + fc_msgBlk0729.msgPreambleStr, /* begin varargs */ + fcptr->fcp_cmd.fcpCdb[0], + FC_SCSID(pan, sid), + (uint32)(dev_ptr->lun_id), + did, + (uint32)fcpRsp->rspInfo3, + (uint32)cmd->un.grsp.perr.statLocalError, + *((uint32 *)(((uint32 *)cmd) + WD6)), /* IOCB wd 6 */ + *((uint32 *)(((uint32 *)cmd) + WD7))); /* IOCB wd 7, end varargs */ + + } + lp = (uint32 * )fcpRsp; + i = 0; + /* FCP command failed: RSP */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0730, /* ptr to msg structure */ + fc_mes0730, /* ptr to msg */ + fc_msgBlk0730.msgPreambleStr, /* begin varargs */ + lp[2], + lp[3], + lp[4], + lp[5]); /* end varargs */ + if (fcpRsp->rspStatus2 & RSP_LEN_VALID) { + i = SWAP_DATA(fcpRsp->rspRspLen); + } + if (fcpRsp->rspStatus2 & SNS_LEN_VALID) { + lp = (uint32 * )(((uchar * ) & fcpRsp->rspInfo0) + i); + /* FCP command failed: SNS */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0731, /* ptr to msg structure */ + fc_mes0731, /* ptr to msg */ + fc_msgBlk0731.msgPreambleStr, /* begin varargs */ + lp[0], + lp[1], + lp[2], + lp[3], + lp[4], + lp[5], + lp[6], + lp[7]); /* end varargs */ + if (i > sizeof(FCP_RSP)) { + cmd->ulpStatus = IOSTAT_REMOTE_STOP; + goto handle_iocb; + } + + if(binfo->fc_process_LA == 0) + goto skip4; /* link down processing */ + if (dev_ptr->first_check & FIRST_CHECK_COND) { + clp = DD_CTL.p_config[binfo->fc_brd_no]; + dev_ptr->first_check &= ~FIRST_CHECK_COND; + if((clp[CFG_FIRST_CHECK].a_current) && + (SWAP_DATA((lp[3]) & SWAP_DATA(0xFF000000)) == 0x29000000)) { + FCSTATCTR.fcpFirstCheck++; + + lp = (uint32 *)&cmd->un.ulpWord[4]; + /* Retry FCP command due to 29,00 check condition */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0732, /* ptr to msg structure */ + fc_mes0732, /* ptr to msg */ + fc_msgBlk0732.msgPreambleStr, /* begin varargs */ + *lp, + *(lp+1), + *(lp+2), + *(lp+3)); /* end varargs */ + fc_fcp_bufunmap(p_dev_ctl, sbp); + + + /* + * Queue this command to the head of the device's + * pending queue for processing by fc_issue_cmd. + */ + if (dev_ptr->pend_head == NULL) { /* Is queue empty? */ + dev_ptr->pend_head = sbp; + dev_ptr->pend_tail = sbp; + bp->av_forw = NULL; + fc_enq_wait(dev_ptr); + } else { /* Queue not empty */ + bp->av_forw = (struct buf *) dev_ptr->pend_head; + dev_ptr->pend_head = sbp; + } + dev_ptr->pend_count++; + dev_ptr->active_io_count--; + dev_ptr->nodep->num_active_io--; + fc_enq_fcbuf(fcptr); + return; + } + } + + fc_bcopy(((uchar * ) & fcpRsp->rspInfo0) + i, dev_ptr->sense, + MAX_FCP_SNS); + dev_ptr->sense_valid = 1; + dev_ptr->sense_length = SWAP_DATA(fcpRsp->rspSnsLen); + + } else { + if ((cmd->ulpStatus == IOSTAT_FCP_RSP_ERROR) && + ((((uchar)fcpRsp->rspStatus3) & SCSI_STATUS_MASK) == SCSI_STAT_QUE_FULL) && + (dev_ptr->qfull_retries > 0) && + (sbp->qfull_retry_count < dev_ptr->qfull_retries)) { + clp = DD_CTL.p_config[binfo->fc_brd_no]; + if (clp[CFG_DQFULL_THROTTLE].a_current) { + if (dev_ptr->fcp_cur_queue_depth > FC_MIN_QFULL) { + if(dev_ptr->active_io_count > FC_MIN_QFULL) + dev_ptr->fcp_cur_queue_depth = dev_ptr->active_io_count - 1; + else + dev_ptr->fcp_cur_queue_depth = FC_MIN_QFULL; + } + } + + fc_qfull_retry((void *)fcptr); + + sbp->qfull_retry_count++; + + dev_ptr->qfullcnt++; + dev_ptr->active_io_count--; + dev_ptr->nodep->num_active_io--; + fc_enq_fcbuf(fcptr); + return; + } + } + } else { + fcpRsp = &fcptr->fcp_rsp; + } + +handle_iocb: + + switch (cmd->ulpStatus) { + case IOSTAT_SUCCESS: + FCSTATCTR.fcpGood++; + break; + + case IOSTAT_FCP_RSP_ERROR: + /* ERROR: all is not well with the FCP Response */ + bp->b_error = EIO; + bp->b_flags |= B_ERROR; + + bp->b_resid = 0; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + FCSTATCTR.fcpRspErr++; + + if(binfo->fc_process_LA == 0) + goto skip4; /* link down processing */ + + + if ((fcpRsp->rspStatus2 & RESID_UNDER) || + (fcpRsp->rspStatus2 & RESID_OVER)) { + if (fcpRsp->rspStatus2 & RESID_UNDER) { + /* This is not an error! */ + bp->b_resid = SWAP_DATA(fcpRsp->rspResId); + + bp->b_error = 0; + bp->b_flags &= ~B_ERROR; + /* FCP Read Underrun */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0733, /* ptr to msg structure */ + fc_mes0733, /* ptr to msg */ + fc_msgBlk0733.msgPreambleStr, /* begin varargs */ + *((uint32 *)(((uint32 *)cmd) + WD7)), /* IOCB wd 7 */ + (uint32)cmd->ulpContext, + SWAP_DATA(fcpRsp->rspResId), + cmd->un.fcpi.fcpi_parm); /* end varargs */ + } + /* Overrun already has error set */ + } + else { + if ((bp->b_flags & B_READ) && cmd->un.fcpi.fcpi_parm) { + /* This is ALWAYS a readcheck error!! */ + + /* Give Check Condition priority over Read Check */ + if (fcpRsp->rspStatus3 != SCSI_STAT_CHECK_COND) { + bp->b_error = EIO; + bp->b_flags |= B_ERROR; + bp->b_resid = bp->b_bcount; + /* FCP Read Check Error */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0734, /* ptr to msg structure */ + fc_mes0734, /* ptr to msg */ + fc_msgBlk0734.msgPreambleStr, /* begin varargs */ + *((uint32 *)(((uint32 *)cmd) + WD7)), /* IOCB wd 7 */ + (uint32)cmd->ulpContext, + SWAP_DATA(fcpRsp->rspResId), + cmd->un.fcpi.fcpi_parm); /* end varargs */ + } + else { + /* FCP Read Check Error with Check Condition */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0735, /* ptr to msg structure */ + fc_mes0735, /* ptr to msg */ + fc_msgBlk0735.msgPreambleStr, /* begin varargs */ + *((uint32 *)(((uint32 *)cmd) + WD7)), /* IOCB wd 7 */ + (uint32)cmd->ulpContext, + SWAP_DATA(fcpRsp->rspResId), + cmd->un.fcpi.fcpi_parm); /* end varargs */ + } + } + } + + /* For QUE_FULL we will delay the iodone */ + if((((uchar) fcpRsp->rspStatus3) & SCSI_STATUS_MASK) == SCSI_STAT_QUE_FULL) { + dev_ptr->qfullcnt++; + if (clp[CFG_DQFULL_THROTTLE].a_current) { + if (dev_ptr->fcp_cur_queue_depth > FC_MIN_QFULL) { + if(dev_ptr->active_io_count > 1) + dev_ptr->fcp_cur_queue_depth = dev_ptr->active_io_count - 1; + else + dev_ptr->fcp_cur_queue_depth = 1; + } + if (dev_ptr->active_io_count > FC_MIN_QFULL) { + /* + * Try out + * stop_send_io will be decreament by 1 in fc_q_depth_up(); + */ + dev_ptr->stop_send_io = clp[CFG_NO_DEVICE_DELAY].a_current; + } + } + /* FCP QUEUE Full */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0736, /* ptr to msg structure */ + fc_mes0736, /* ptr to msg */ + fc_msgBlk0736.msgPreambleStr, /* begin varargs */ + dev_ptr->fcp_cur_queue_depth, + dev_ptr->active_io_count, + dev_ptr->flags, + clp[CFG_DQFULL_THROTTLE].a_current); /* end varargs */ + qfull = 1; + /* Set any necessary flags for buf error */ + bp->b_error = EBUSY; + bp->b_flags |= B_ERROR; + bp->b_resid = bp->b_bcount; + } + lpfc_handle_fcp_error(pkt, fcptr, cmd); + + if ((fcpRsp->rspStatus2 & RSP_LEN_VALID) && + (fcpRsp->rspInfo3 != RSP_NO_FAILURE)) { + + /* Error detected in the FCP layer */ + sbp->status_validity = SC_ADAPTER_ERROR; + + if(clp[CFG_DELAY_RSP_ERR].a_current) + qfull = clp[CFG_DELAY_RSP_ERR].a_current; + + switch (fcpRsp->rspInfo3) { + case RSP_TM_NOT_SUPPORTED: + SET_ADAPTER_STATUS(sbp, SC_NO_DEVICE_RESPONSE) + break; + + case RSP_DATA_BURST_ERR: + case RSP_CMD_FIELD_ERR: + case RSP_RO_MISMATCH_ERR: + if (fcpRsp->rspStatus3 != SCSI_STAT_GOOD) { + sbp->status_validity = SC_SCSI_ERROR; + sbp->scsi_status = fcpRsp->rspStatus3; + if ((fcpRsp->rspStatus3 == SC_CHECK_CONDITION) || + (fcpRsp->rspStatus3 == SC_COMMAND_TERMINATED)) { + sbp->adap_q_status = SC_DID_NOT_CLEAR_Q; + } + + + break; + } + + case RSP_TM_NOT_COMPLETED: + default: + SET_ADAPTER_STATUS(sbp, SC_ADAPTER_HDW_FAILURE) + break; + } + } else if (fcpRsp->rspStatus3 != SCSI_STAT_GOOD) { + /* SCSI layer detected error */ + if (fcpRsp->rspStatus3 == SCSI_STAT_CHECK_COND) { + uint32 cc; + /* FCP error: Check condition */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0737, /* ptr to msg structure */ + fc_mes0737, /* ptr to msg */ + fc_msgBlk0737.msgPreambleStr, /* begin varargs */ + *((uint32 *)(((uint32 *)cmd) + WD7)), /* IOCB wd 7 */ + (uint32)cmd->ulpIoTag, + (uint32)cmd->ulpContext, + (uint32)cmd->un.grsp.perr.statLocalError); /* end varargs */ + i = SWAP_DATA(fcpRsp->rspRspLen); + lp = (uint32 * )(((uchar * ) & fcpRsp->rspInfo0) + i); + + cc = (SWAP_DATA((lp[3]) & SWAP_DATA(0xFF000000))); + switch(cc) { + case 0x29000000: /* Power on / reset */ + i = 0; + /* 29,00 Check condition received */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0738, /* ptr to msg structure */ + fc_mes0738, /* ptr to msg */ + fc_msgBlk0738.msgPreambleStr, /* begin varargs */ + lp[0], + lp[1], + lp[2], + lp[3]); /* end varargs */ + break; + case 0x0: /* No additional sense info */ + if((lp[3]) & SWAP_DATA(0x00FF0000)) /* if ASCQ != 0 */ + goto default_chk; + case 0x44000000: /* Internal Target failure */ + case 0x25000000: /* Login Unit Not Support */ + case 0x20000000: /* Invalid Command operation code */ + if ((cc == 0x20000000) && (fcptr->fcp_cmd.fcpCdb[0] == SCSI3_PERSISTENT_RESERVE_IN)) { + /* Check condition received ERR1 */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0739, /* ptr to msg structure */ + fc_mes0739, /* ptr to msg */ + fc_msgBlk0739.msgPreambleStr, /* begin varargs */ + lp[0], + lp[1], + lp[2], + lp[3]); /* end varargs */ + goto out; + } + if(clp[CFG_CHK_COND_ERR].a_current) { + /* We want to return check cond on TUR cmd */ + if (fcptr->fcp_cmd.fcpCdb[0] == FCP_SCSI_TEST_UNIT_READY) + goto default_chk; + fc_bzero((void * )dev_ptr->sense, MAX_FCP_SNS); + dev_ptr->sense_valid = 0; + dev_ptr->sense_length = 0; + fcpRsp->rspStatus3 = SC_COMMAND_TERMINATED; + bp->b_error = EIO; + bp->b_flags |= B_ERROR; + bp->b_resid = bp->b_bcount; + sbp->status_validity = SC_ADAPTER_ERROR; + SET_ADAPTER_STATUS(sbp, SC_SCSI_BUS_RESET) + i = 0; + if(clp[CFG_DELAY_RSP_ERR].a_current) + qfull = clp[CFG_DELAY_RSP_ERR].a_current; + /* Check condition received ERR2 */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0740, /* ptr to msg structure */ + fc_mes0740, /* ptr to msg */ + fc_msgBlk0740.msgPreambleStr, /* begin varargs */ + lp[0], + lp[1], + lp[2], + lp[3]); /* end varargs */ + goto out; + } + default: + if(clp[CFG_DELAY_RSP_ERR].a_current) + qfull = clp[CFG_DELAY_RSP_ERR].a_current; +default_chk: + i = 0; + /* Check condition received */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0741, /* ptr to msg structure */ + fc_mes0741, /* ptr to msg */ + fc_msgBlk0741.msgPreambleStr, /* begin varargs */ + lp[0], + lp[1], + lp[2], + lp[3]); /* end varargs */ + break; + } + } + else { + if(clp[CFG_DELAY_RSP_ERR].a_current) + qfull = clp[CFG_DELAY_RSP_ERR].a_current; + } + + sbp->status_validity = SC_SCSI_ERROR; + sbp->scsi_status = fcpRsp->rspStatus3; + if ((fcpRsp->rspStatus3 == SC_CHECK_CONDITION) || + (fcpRsp->rspStatus3 == SC_COMMAND_TERMINATED)) { + sbp->adap_q_status = SC_DID_NOT_CLEAR_Q; + + } + } + break; + + case IOSTAT_REMOTE_STOP: + /* ERROR: ABTS/ABTX by remote N_PORT */ + FCSTATCTR.fcpRemoteStop++; + bp->b_error = EIO; + bp->b_flags |= B_ERROR; + bp->b_resid = bp->b_bcount; + sbp->status_validity = SC_SCSI_ERROR; + sbp->scsi_status = SC_COMMAND_TERMINATED; + sbp->adap_q_status = SC_DID_NOT_CLEAR_Q; + + break; + + case IOSTAT_LOCAL_REJECT: + FCSTATCTR.fcpLocalErr++; + switch (cmd->un.grsp.perr.statLocalError) { + case IOERR_SEQUENCE_TIMEOUT: + FCSTATCTR.fcpLocalTmo++; + /* E_D_TOV timeout */ + bp->b_error = ETIMEDOUT; + sbp->adap_q_status = SC_DID_NOT_CLEAR_Q; + bp->b_flags |= B_ERROR; + bp->b_resid = bp->b_bcount; + sbp->status_validity = SC_ADAPTER_ERROR; + SET_ADAPTER_STATUS(sbp, SC_CMD_TIMEOUT) + break; + + case IOERR_NO_RESOURCES: + FCSTATCTR.fcpLocalNores++; + fc_qfull_retry((void *)fcptr); + dev_ptr->active_io_count--; + dev_ptr->nodep->num_active_io--; + fc_enq_fcbuf(fcptr); + return; + case IOERR_BUFFER_SHORTAGE: + FCSTATCTR.fcpLocalBufShort++; + /* The adapter is too busy to deal with this command */ + bp->b_error = EBUSY; + bp->b_flags |= B_ERROR; + bp->b_resid = bp->b_bcount; + sbp->status_validity = 0; + break; + + case IOERR_MISSING_CONTINUE: + case IOERR_ILLEGAL_COMMAND: + case IOERR_ILLEGAL_FIELD: + case IOERR_BAD_CONTINUE: + case IOERR_TOO_MANY_BUFFERS: + case IOERR_EXTRA_DATA: + case IOERR_ILLEGAL_LENGTH: + case IOERR_UNSUPPORTED_FEATURE: + /* Let's call these driver software errors */ + qfull = 1; + FCSTATCTR.fcpLocalSfw++; + bp->b_error = EINVAL; + bp->b_flags |= B_ERROR; + bp->b_resid = bp->b_bcount; + sbp->status_validity = 0; + + { + uint32 did; + + did = 0; + if ((dev_ptr->nodep) && (dev_ptr->nodep->nlp)) + did = dev_ptr->nodep->nlp->nlp_DID; + /* FCP completion error */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0742, /* ptr to msg structure */ + fc_mes0742, /* ptr to msg */ + fc_msgBlk0742.msgPreambleStr, /* begin varargs */ + cmd->ulpStatus, + cmd->un.ulpWord[4], + did ); /* end varargs */ + } + break; + + case IOERR_TX_DMA_FAILED: + FCSTATCTR.fcpLocalTxDMA++; + goto skip2; + case IOERR_RX_DMA_FAILED: + FCSTATCTR.fcpLocalRxDMA++; + goto skip2; + case IOERR_INTERNAL_ERROR: + FCSTATCTR.fcpLocalinternal++; + goto skip2; + case IOERR_CORRUPTED_DATA: + case IOERR_CORRUPTED_RPI: + FCSTATCTR.fcpLocalCorrupt++; +skip2: + /* Let's call these adapter hardware errors */ + bp->b_error = EIO; + bp->b_flags |= B_ERROR; + bp->b_resid = bp->b_bcount; + sbp->status_validity = SC_ADAPTER_ERROR; + SET_ADAPTER_STATUS(sbp, SC_ADAPTER_HDW_FAILURE) + + { + uint32 did; + + did = 0; + if ((dev_ptr->nodep) && (dev_ptr->nodep->nlp)) + did = dev_ptr->nodep->nlp->nlp_DID; + /* FCP completion error */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0743, /* ptr to msg structure */ + fc_mes0743, /* ptr to msg */ + fc_msgBlk0743.msgPreambleStr, /* begin varargs */ + cmd->ulpStatus, + cmd->un.ulpWord[4], + did ); /* end varargs */ + } + + break; + + case IOERR_ILLEGAL_FRAME: + FCSTATCTR.fcpLocalIllFrm++; + goto skip3; + case IOERR_DUP_FRAME: + FCSTATCTR.fcpLocalDupFrm++; + goto skip3; + case IOERR_LINK_CONTROL_FRAME: + FCSTATCTR.fcpLocalLnkCtlFrm++; +skip3: + qfull = 1; + /* Let's call these device hardware errors */ + bp->b_error = EINVAL; + bp->b_flags |= B_ERROR; + bp->b_resid = bp->b_bcount; + sbp->status_validity = 0; + + { + uint32 did; + + did = 0; + if ((dev_ptr->nodep) && (dev_ptr->nodep->nlp)) + did = dev_ptr->nodep->nlp->nlp_DID; + + lp = (uint32 *)&cmd->un.ulpWord[4]; + /* FCP completion error */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0744, /* ptr to msg structure */ + fc_mes0744, /* ptr to msg */ + fc_msgBlk0744.msgPreambleStr, /* begin varargs */ + did, + *lp, + *(lp+2), + *(lp+3) ); /* end varargs */ + } + + break; + + case IOERR_LOOP_OPEN_FAILURE: + FCSTATCTR.fcpLocalLoopOpen++; + /* The device disappeared from the loop! */ + qfull = 1; + bp->b_error = EIO; + bp->b_flags |= B_ERROR; + bp->b_resid = bp->b_bcount; + sbp->status_validity = SC_ADAPTER_ERROR; + SET_ADAPTER_STATUS(sbp, SC_NO_DEVICE_RESPONSE) + if(dev_ptr->nodep && (dev_ptr->nodep->flags & FC_NODEV_TMO)) { + break; + } + if(binfo->fc_ffstate != FC_READY) { + break; + } + /* Will HALT, CLEARQ, and kick off discovery, below */ + /* Try to relogin, and if unsuccessful reject future cmds */ + if((ndlp == 0) && dev_ptr->nodep) + ndlp = fc_findnode_rpi(binfo, (uint32)dev_ptr->nodep->rpi); + + if ((ndlp) && !(ndlp->nlp_flag & (NLP_NODEV_TMO | NLP_REQ_SND))) { + ndlp->nlp_flag &= ~NLP_RM_ENTRY; + /* We are in FC_READY state */ + if (!(ndlp->nlp_action & NLP_DO_RSCN)) { + binfo->fc_flag |= FC_RSCN_MODE; + ndlp->nlp_action |= NLP_DO_RSCN; + fc_nextrscn(p_dev_ctl, 1); + } + } + break; + + case IOERR_INVALID_RPI: + FCSTATCTR.fcpLocalInvalRpi++; + goto skip4; + case IOERR_LINK_DOWN: + FCSTATCTR.fcpLocalLinkDown++; +skip4: + /* Retry these failures */ + qfull=1; + bp->b_error = EIO; + bp->b_flags |= B_ERROR; + bp->b_resid = bp->b_bcount; + sbp->status_validity = SC_ADAPTER_ERROR; + SET_ADAPTER_STATUS(sbp, SC_SCSI_BUS_RESET) + break; + + case IOERR_OUT_OF_ORDER_DATA: + case IOERR_OUT_OF_ORDER_ACK: + FCSTATCTR.fcpLocalOOO++; + /* Retry these failures */ + bp->b_error = ENXIO; + bp->b_flags |= B_ERROR; + bp->b_resid = bp->b_bcount; + sbp->status_validity = 0; + break; + + case IOERR_ABORT_IN_PROGRESS: + FCSTATCTR.fcpLocalAbtInp++; + goto skip5; + case IOERR_ABORT_REQUESTED: + FCSTATCTR.fcpLocalAbtReq++; +skip5: + /* Abort requested by us */ + if (fcptr->flags & FCBUF_ABTS) { + /* ABTS sent because of operation timeout */ + bp->b_error = ETIMEDOUT; + sbp->status_validity = SC_ADAPTER_ERROR; + SET_ADAPTER_STATUS(sbp, SC_CMD_TIMEOUT) + } else { + bp->b_error = ENXIO; + sbp->status_validity = 0; + } + bp->b_flags |= B_ERROR; + bp->b_resid = bp->b_bcount; + break; + + case IOERR_SUCCESS: + case IOERR_NO_XRI: + case IOERR_XCHG_DROPPED: + case IOERR_RCV_BUFFER_WAITING: + case IOERR_RECEIVE_BUFFER_TIMEOUT: + case IOERR_RING_RESET: + case IOERR_BAD_HOST_ADDRESS: + case IOERR_RCV_HDRBUF_WAITING: + case IOERR_MISSING_HDR_BUFFER: + case IOERR_MSEQ_CHAIN_CORRUPTED: + case IOERR_ABORTMULT_REQUESTED: + default: + FCSTATCTR.fcpLocal++; + bp->b_error = EIO; + bp->b_flags |= B_ERROR; + bp->b_resid = bp->b_bcount; + sbp->status_validity = SC_ADAPTER_ERROR; + SET_ADAPTER_STATUS(sbp, SC_NO_DEVICE_RESPONSE) + + { + uint32 did; + + did = 0; + if ((dev_ptr->nodep) && (dev_ptr->nodep->nlp)) + did = dev_ptr->nodep->nlp->nlp_DID; + /* FCP completion error */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0745, /* ptr to msg structure */ + fc_mes0745, /* ptr to msg */ + fc_msgBlk0745.msgPreambleStr, /* begin varargs */ + cmd->ulpStatus, + cmd->un.ulpWord[4], + did ); /* end varargs */ + } + break; + } + break; + + case IOSTAT_NPORT_RJT: + case IOSTAT_FABRIC_RJT: + FCSTATCTR.fcpPortRjt++; + /* The fabric or port rejected this command */ + if (cmd->un.grsp.perr.statAction == RJT_RETRYABLE) { + bp->b_error = ENXIO; + sbp->status_validity = SC_SCSI_ERROR; + sbp->scsi_status = SC_BUSY_STATUS; + } else { + bp->b_error = EIO; + sbp->status_validity = 0; + } + bp->b_flags |= B_ERROR; + bp->b_resid = bp->b_bcount; + break; + + case IOSTAT_NPORT_BSY: + case IOSTAT_FABRIC_BSY: + FCSTATCTR.fcpPortBusy++; + /* The fabric or port is too busy to deal with this command */ + bp->b_error = ENXIO; + bp->b_flags |= B_ERROR; + bp->b_resid = bp->b_bcount; + sbp->status_validity = SC_SCSI_ERROR; + sbp->scsi_status = SC_BUSY_STATUS; + break; + + case IOSTAT_INTERMED_RSP: + case IOSTAT_LS_RJT: + case IOSTAT_BA_RJT: + default: + FCSTATCTR.fcpError++; + /* ERROR: None of these errors should occur! */ + bp->b_error = EIO; + bp->b_flags |= B_ERROR; + bp->b_resid = bp->b_bcount; + sbp->status_validity = SC_ADAPTER_ERROR; + SET_ADAPTER_STATUS(sbp, SC_NO_DEVICE_RESPONSE) + + { + uint32 did; + + did = 0; + if ((dev_ptr->nodep) && (dev_ptr->nodep->nlp)) + did = dev_ptr->nodep->nlp->nlp_DID; + /* FCP completion error */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0746, /* ptr to msg structure */ + fc_mes0746, /* ptr to msg */ + fc_msgBlk0746.msgPreambleStr, /* begin varargs */ + cmd->ulpStatus, + cmd->un.ulpWord[4], + did ); /* end varargs */ + } + break; + } +out: + + if (fcptr->fcp_cmd.fcpCntl2) + { + /* This is a task management command */ + if (bp->b_flags & B_ERROR) + dev_ptr->ioctl_errno = bp->b_error; + else + dev_ptr->ioctl_errno = 0; + + + + if (fcptr->fcp_cmd.fcpCntl2 & TARGET_RESET) { + /* Cmpl Target Reset */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0747, /* ptr to msg structure */ + fc_mes0747, /* ptr to msg */ + fc_msgBlk0747.msgPreambleStr, /* begin varargs */ + (uint32)dev_ptr->nodep->scsi_id, + (uint32)dev_ptr->lun_id, + (uint32)cmd->un.grsp.perr.statLocalError, + *((uint32 *)(((uint32 *)cmd) + WD7))); /* end varargs */ + clp = DD_CTL.p_config[binfo->fc_brd_no]; + dev_ptr->flags &= ~SCSI_TARGET_RESET; + for (next_dev_ptr = dev_ptr->nodep->lunlist; next_dev_ptr != NULL; + next_dev_ptr = next_dev_ptr->next) { + + next_dev_ptr->flags &= ~SCSI_TARGET_RESET; + /* First send ABTS on any outstanding I/O in txp queue */ + fc_abort_fcp_txpq(binfo, next_dev_ptr); + fc_fail_cmd(next_dev_ptr, ENXIO, STAT_DEV_RESET); + next_dev_ptr->fcp_cur_queue_depth = + (ushort)clp[CFG_DFT_LUN_Q_DEPTH].a_current; + if (next_dev_ptr->ioctl_wakeup == 0) + fc_restart_device(next_dev_ptr); + } + } + + if (fcptr->fcp_cmd.fcpCntl2 & LUN_RESET) { + /* Cmpl LUN Reset */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0748, /* ptr to msg structure */ + fc_mes0748, /* ptr to msg */ + fc_msgBlk0748.msgPreambleStr, /* begin varargs */ + (uint32)dev_ptr->nodep->scsi_id, + (uint32)dev_ptr->lun_id, + (uint32)cmd->un.grsp.perr.statLocalError, + *((uint32 *)(((uint32 *)cmd) + WD7))); /* end varargs */ + dev_ptr->flags &= ~SCSI_LUN_RESET; + /* First send ABTS on any outstanding I/O in txp queue */ + fc_abort_fcp_txpq(binfo, dev_ptr); + fc_fail_cmd(dev_ptr, ENXIO, STAT_DEV_RESET); + if (dev_ptr->ioctl_wakeup == 0) + fc_restart_device(dev_ptr); + } + + if (fcptr->fcp_cmd.fcpCntl2 & ABORT_TASK_SET) { + /* Cmpl Abort Task Set */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0749, /* ptr to msg structure */ + fc_mes0749, /* ptr to msg */ + fc_msgBlk0749.msgPreambleStr, /* begin varargs */ + (uint32)dev_ptr->nodep->scsi_id, + (uint32)dev_ptr->lun_id, + (uint32)cmd->un.grsp.perr.statLocalError, + *((uint32 *)(((uint32 *)cmd) + WD7))); /* end varargs */ + dev_ptr->flags &= ~SCSI_ABORT_TSET; + /* First send ABTS on any outstanding I/O in txp queue */ + fc_abort_fcp_txpq(binfo, dev_ptr); + fc_fail_cmd(dev_ptr, ENXIO, STAT_DEV_RESET); + if (dev_ptr->ioctl_wakeup == 0) + fc_restart_device(dev_ptr); + } + + if (dev_ptr->ioctl_wakeup == 1) { + dev_ptr->ioctl_wakeup = 0; + fc_admin_wakeup(p_dev_ctl, dev_ptr, sbp); + } + } else { + if ((bp->b_flags & B_ERROR) && + (dev_ptr->queue_state != STOPPING)) { + /* An error has occurred, so halt the queues */ + sbp->adap_q_status = SC_DID_NOT_CLEAR_Q; + if(qfull) + fc_delay_iodone(p_dev_ctl, sbp); + else + fc_do_iodone(bp); + } else { + if(qfull) + fc_delay_iodone(p_dev_ctl, sbp); + else + fc_do_iodone(bp); + } + } + + + dev_ptr->active_io_count--; + dev_ptr->nodep->num_active_io--; + fc_enq_fcbuf(fcptr); + + + if ((dev_ptr->nodep->tgt_queue_depth) && + (dev_ptr->nodep->tgt_queue_depth == dev_ptr->nodep->num_active_io)) { + re_issue_fcp_cmd(dev_ptr->nodep->last_dev); + } + return; +} /* End handle_fcp_event */ + + +int +fc_delay_iodone( +fc_dev_ctl_t *p_dev_ctl, +T_SCSIBUF * sbp) +{ + FC_BRD_INFO * binfo; + iCfgParam * clp; + uint32 tmout; + + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + + if(clp[CFG_NO_DEVICE_DELAY].a_current) { + /* Need to set a timer so iodone can be called + * for buffer upon expiration. + */ + tmout = clp[CFG_NO_DEVICE_DELAY].a_current; + + if(fc_clk_set(p_dev_ctl, tmout, + lpfc_scsi_selto_timeout, (void *)sbp, 0) != 0) + return(1); + } + fc_do_iodone((struct buf *)sbp); + return(0); +} /* End fc_delay_iodone */ + + +/**********************************************/ +/** handle_iprcv_seq **/ +/** **/ +/**********************************************/ +_static_ int +handle_iprcv_seq( +fc_dev_ctl_t *p_dev_ctl, +RING *rp, +IOCBQ *temp) +{ + MAILBOXQ * mb; + FC_BRD_INFO * binfo; + IOCB * cmd = 0; + IOCB * savecmd; + IOCBQ * savetemp; + NETHDR * nh; + fcipbuf_t * p_mbuf, *mp, *last_mp; + ndd_t * p_ndd; + NODELIST * ndlp; + MATCHMAP * matp; + uchar * daddr; + uchar * saddr; + int count, i, la; + + binfo = &BINFO; + p_ndd = (ndd_t * ) & (NDD); + + p_mbuf = 0; + matp = (MATCHMAP *)0; /* prevent compiler warning */ + + if (++NDDSTAT.ndd_recvintr_lsw == 0) { + NDDSTAT.ndd_recvintr_msw++; + } + + mp = 0; + last_mp = 0; + count = 0; + la = 0; + + savetemp = temp; + if (binfo->fc_ffstate < FC_READY) { + if (binfo->fc_ffstate < rp->fc_xmitstate) { + goto dropout; + } + la = 1; + } + + savecmd = &temp->iocb; + while (temp) { + cmd = &temp->iocb; + if (cmd->ulpStatus) { + if ((cmd->ulpStatus == IOSTAT_LOCAL_REJECT) && + ((cmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) { + FCSTATCTR.NoRcvBuf++; + if(!(binfo->fc_flag & FC_NO_RCV_BUF)) { + /* IP Response Ring out of posted buffers */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0602, /* ptr to msg structure */ + fc_mes0602, /* ptr to msg */ + fc_msgBlk0602.msgPreambleStr, /* begin varargs */ + rp->fc_ringno, + rp->fc_missbufcnt, + FCSTATCTR.NoRcvBuf); /* end varargs */ + } + binfo->fc_flag |= FC_NO_RCV_BUF; + + fc_post_mbuf(p_dev_ctl, rp, 0); + } + else + NDDSTAT.ndd_ierrors++; +dropout: + NDDSTAT.ndd_ipackets_drop++; + fc_free_iocb_buf(p_dev_ctl, rp, savetemp); + if (p_mbuf) { + m_freem(p_mbuf); + } + return(0); + } + + if (cmd->ulpBdeCount == 0) { + temp = (IOCBQ * )temp->q; + continue; + } + for (i = 0; i < (int)cmd->ulpBdeCount; i++) { + matp = fc_getvaddr(p_dev_ctl, rp, (uchar *) + getPaddr(cmd->un.cont64[i].addrHigh, cmd->un.cont64[i].addrLow)); + if (matp == 0) { + uchar *bdeAddr; + + bdeAddr = (uchar *)getPaddr(cmd->un.cont64[0].addrHigh, + cmd->un.cont64[0].addrLow); + goto dropout; + } + + mp = (fcipbuf_t * )matp; + if (last_mp) { + fcnextdata(last_mp) = mp; + } else { + p_mbuf = mp; + } + last_mp = mp; + fcnextdata(mp) = 0; + fcsetdatalen(mp, cmd->un.cont64[i].tus.f.bdeSize); + count += cmd->un.cont64[i].tus.f.bdeSize; + } + + fc_post_mbuf(p_dev_ctl, rp, i); + cmd->ulpBdeCount = 0; + temp = (IOCBQ * )temp->q; + } + + if (p_mbuf == 0) { + goto dropout; + } + + binfo->fc_flag &= ~FC_NO_RCV_BUF; + + /* Set any IP buffer flags to indicate a recieve buffer, if needed */ + + if (++NDDSTAT.ndd_ipackets_lsw == 0) + NDDSTAT.ndd_ipackets_msw++; + + NDDSTAT.ndd_ibytes_lsw += count; + if ((int)NDDSTAT.ndd_ibytes_lsw < count) + NDDSTAT.ndd_ibytes_msw++; + nh = (NETHDR * )fcdata(p_mbuf); + + if(lpfc_nethdr == 0) { + emac_t * ep; + + /* Adjust mbuf count now */ + count -= 2; + + fcpktlen(p_mbuf) = count; /* total data in mbuf */ + fcincdatalen(p_mbuf, -2); + + fcdata(p_mbuf) += 2; + ep = (emac_t * )(fcdata(p_mbuf)); + daddr = (uchar *)ep->dest_addr; + saddr = (uchar *)ep->src_addr; + ep->llc_len = (count - sizeof(emac_t)); + } + else { + NETHDR * np; + + np = (NETHDR * )(fcdata(p_mbuf)); + daddr = np->fc_destname.IEEE; + saddr = np->fc_srcname.IEEE; + fcpktlen(p_mbuf) = count; /* total data in mbuf */ + } + + if (count < (HDR_LEN + sizeof(snaphdr_t))) + goto dropout; + + /* If this is first broadcast received from that address */ + if (savecmd->un.xrseq.w5.hcsw.Fctl & BC) { +bcst: + FCSTATCTR.frameRcvBcast++; + if (++NDDSTAT.ndd_ifInBcastPkts_lsw == 0) + NDDSTAT.ndd_ifInBcastPkts_msw++; + + fc_bcopy((char *)fcbroadcastaddr, (char *)daddr, MACADDR_LEN); + + if ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, + (uint32)savecmd->un.xrseq.xrsqRo)) == 0) { + + /* Need to cache the did / portname */ + if((ndlp = (NODELIST *)fc_mem_get(binfo, MEM_NLP))) { + fc_bzero((void *)ndlp, sizeof(NODELIST)); + ndlp->sync = binfo->fc_sync; + ndlp->capabilities = binfo->fc_capabilities; + ndlp->nlp_DID = savecmd->un.xrseq.xrsqRo; + fc_bcopy(&nh->fc_srcname, &ndlp->nlp_portname, sizeof(NAME_TYPE)); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + } + else { + goto dropout; + } + } + } else { + if ((ndlp = binfo->fc_nlplookup[savecmd->ulpIoTag]) == 0) { + if(nh->fc_destname.IEEE[0] == 0xff) { + if((nh->fc_destname.IEEE[1] == 0xff) && + (nh->fc_destname.IEEE[2] == 0xff) && + (nh->fc_destname.IEEE[3] == 0xff) && + (nh->fc_destname.IEEE[4] == 0xff) && + (nh->fc_destname.IEEE[5] == 0xff)) { + goto bcst; + } + } + /* Need to send LOGOUT for this RPI */ + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX))) { + fc_read_rpi(binfo, (uint32)savecmd->ulpIoTag, + (MAILBOX * )mb, (uint32)ELS_CMD_LOGO); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + goto dropout; + } + } + + + if(lpfc_nethdr == 0) { + fc_bcopy(ndlp->nlp_portname.IEEE, (char *)saddr, MACADDR_LEN); + } + if ((p_dev_ctl->device_state != OPENED) || + (p_ndd->nd_receive == 0)) { + goto dropout; + } + ndlp->nlp_type |= NLP_IP_NODE; + + unlock_enable(FC_LVL, &CMD_LOCK); + (*(p_ndd->nd_receive))(p_ndd, p_mbuf, p_dev_ctl); + i = disable_lock(FC_LVL, &CMD_LOCK); + + return(1); +} /* End handle_iprcv_seq */ + +/**********************************************/ +/** handle_elsrcv_seq **/ +/** **/ +/**********************************************/ +_static_ int +handle_elsrcv_seq( +fc_dev_ctl_t *p_dev_ctl, +RING *rp, +IOCBQ *temp) +{ + FC_BRD_INFO * binfo; + IOCB * cmd = 0; + IOCB * savecmd; + IOCBQ * savetemp; + MATCHMAP * p_mbuf, *last_mp; + ndd_t * p_ndd; + MATCHMAP * matp; + uint32 ctx; + int count, i, la; + + binfo = &BINFO; + p_ndd = (ndd_t * ) & (NDD); + + p_mbuf = 0; + matp = (MATCHMAP *)0; /* prevent compiler warning */ + + last_mp = 0; + count = 0; + la = 0; + + savetemp = temp; + if (binfo->fc_ffstate < FC_READY) { + goto dropout; + } + + ctx = 0; + savecmd = &temp->iocb; + while (temp) { + cmd = &temp->iocb; + if(ctx == 0) + ctx = (uint32)(cmd->ulpContext); + if (cmd->ulpStatus) { + if ((cmd->ulpStatus == IOSTAT_LOCAL_REJECT) && + ((cmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) { + FCSTATCTR.NoRcvBuf++; + if(!(binfo->fc_flag & FC_NO_RCV_BUF)) { + /* Rcv Ring out of posted buffers */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0603, /* ptr to msg structure */ + fc_mes0603, /* ptr to msg */ + fc_msgBlk0603.msgPreambleStr, /* begin varargs */ + rp->fc_ringno, + rp->fc_missbufcnt, + FCSTATCTR.NoRcvBuf); /* end varargs */ + } + binfo->fc_flag |= FC_NO_RCV_BUF; + + fc_post_buffer(p_dev_ctl, rp, 0); + } + goto dropout; + } + + if (cmd->ulpBdeCount == 0) { + temp = (IOCBQ * )temp->q; + continue; + } + for (i = 0; i < (int)cmd->ulpBdeCount; i++) { + matp = fc_getvaddr(p_dev_ctl, rp, (uchar *) + getPaddr(cmd->un.cont64[i].addrHigh, cmd->un.cont64[i].addrLow)); + if (matp == 0) { + uchar *bdeAddr; + + bdeAddr = (uchar *)getPaddr(cmd->un.cont64[0].addrHigh, + cmd->un.cont64[0].addrLow); + + goto dropout; + } + + /* Typically for Unsolicited CT requests */ + + if (last_mp) { + last_mp->fc_mptr = (void *)matp; + } else { + p_mbuf = matp; + } + last_mp = matp; + matp->fc_mptr = 0; + count += cmd->un.cont64[i].tus.f.bdeSize; + } + + fc_post_buffer(p_dev_ctl, rp, i); + cmd->ulpBdeCount = 0; + temp = (IOCBQ * )temp->q; + } + + if (p_mbuf == 0) { + goto dropout; + } + binfo->fc_flag &= ~FC_NO_RCV_BUF; + if(dfc_put_event(p_dev_ctl, FC_REG_CT_EVENT, ctx, (void *)p_mbuf, (void *)((ulong)count))) { + fc_free_iocb_buf(p_dev_ctl, rp, savetemp); + return(0); + } + +dropout: + fc_free_iocb_buf(p_dev_ctl, rp, savetemp); + while (p_mbuf) { + matp = p_mbuf; + p_mbuf = (MATCHMAP *)matp->fc_mptr; + fc_mem_put(binfo, MEM_BUF, (uchar * )matp); + } + return(0); +} /* End handle_elsrcv_seq */ + + +/**************************************************/ +/** fc_post_buffer **/ +/** **/ +/** This routine will post count buffers to the **/ +/** ring with the QUE_RING_BUF_CN command. This **/ +/** allows 3 buffers / command to be posted. **/ +/** Returns the number of buffers NOT posted. **/ +/**************************************************/ +_static_ int +fc_post_buffer( +fc_dev_ctl_t *p_dev_ctl, +RING *rp, +int cnt) +{ + IOCB * icmd; + IOCBQ * temp; + int i, j; + ushort tag; + ushort maxqbuf; + MATCHMAP * mp; + FC_BRD_INFO * binfo; + + binfo = &BINFO; + mp = 0; + if (binfo->fc_flag & FC_SLI2) + maxqbuf = 2; + else + maxqbuf = 3; + + tag = (ushort)cnt; + cnt += rp->fc_missbufcnt; + /* While there are buffers to post */ + while (cnt) { + if ((temp = (IOCBQ * )fc_mem_get(binfo, MEM_IOCB)) == 0) { + rp->fc_missbufcnt = cnt; + return(cnt); + } + fc_bzero((void *)temp, sizeof(IOCBQ)); + icmd = &temp->iocb; + + /* Max buffers can be posted per command */ + for (i = 0; i < maxqbuf; i++) { + if (cnt <= 0) + break; + + /* fill in BDEs for command */ + if ((mp = (MATCHMAP * )fc_mem_get(binfo, MEM_BUF)) == 0) { + icmd->ulpBdeCount = i; + for (j = 0; j < i; j++) { + if (binfo->fc_flag & FC_SLI2) { + mp = fc_getvaddr(p_dev_ctl, rp, + (uchar * )getPaddr(icmd->un.cont64[j].addrHigh, + icmd->un.cont64[j].addrLow)); + } + else { + mp = fc_getvaddr(p_dev_ctl, rp, + (uchar * )((ulong)icmd->un.cont[j].bdeAddress)); + } + if (mp) { + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + } + } + + rp->fc_missbufcnt = cnt + i; + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + return(cnt + i); + } + + /* map that page and save the address pair for lookup later */ + if (binfo->fc_flag & FC_SLI2) { + fc_mapvaddr(binfo, rp, mp, + (uint32 *) & icmd->un.cont64[i].addrHigh, + (uint32 *) & icmd->un.cont64[i].addrLow); + icmd->un.cont64[i].tus.f.bdeSize = FCELSSIZE; + icmd->ulpCommand = CMD_QUE_RING_BUF64_CN; + } else { + fc_mapvaddr(binfo, rp, mp, + 0, (uint32 *) & icmd->un.cont[i].bdeAddress); + icmd->un.cont[i].bdeSize = FCELSSIZE; + icmd->ulpCommand = CMD_QUE_RING_BUF_CN; + } + cnt--; + } + + icmd->ulpIoTag = tag; + icmd->ulpBdeCount = i; + icmd->ulpLe = 1; + + icmd->ulpOwner = OWN_CHIP; + + temp->bp = (uchar * )mp; /* used for delimiter between commands */ + + + FCSTATCTR.cmdQbuf++; + issue_iocb_cmd(binfo, rp, temp); + } + + rp->fc_missbufcnt = 0; + return(0); +} /* End fc_post_buffer */ + + +/**************************************************/ +/** fc_post_mbuf **/ +/** **/ +/** This routine will post count buffers to the **/ +/** ring with the QUE_RING_BUF_CN command. This **/ +/** allows 3 buffers / command to be posted. **/ +/** Returns the number of buffers NOT posted. **/ +/**************************************************/ +_static_ int +fc_post_mbuf( +fc_dev_ctl_t *p_dev_ctl, +RING *rp, +int cnt) +{ + FC_BRD_INFO * binfo; + IOCB * icmd; + IOCBQ * temp; + int i, j; + ushort tag; + ushort maxqbuf; + fcipbuf_t * mp; + + binfo = &BINFO; + mp = 0; + if (binfo->fc_flag & FC_SLI2) + maxqbuf = 2; + else + maxqbuf = 3; + + tag = (ushort)cnt; + cnt += rp->fc_missbufcnt; + /* While there are buffers to post */ + while (cnt) { + if ((temp = (IOCBQ * )fc_mem_get(binfo, MEM_IOCB)) == 0) { + rp->fc_missbufcnt = cnt; + return(cnt); + } + fc_bzero((void *)temp, sizeof(IOCBQ)); + icmd = &temp->iocb; + + /* Max buffers can be posted per command */ + for (i = 0; i < maxqbuf; i++) { + if (cnt <= 0) + break; + + /* fill in BDEs for command */ + if ((mp = (fcipbuf_t * )m_getclust(M_DONTWAIT, MT_DATA)) == 0) { + +out: + /* Post buffer for IP ring failed */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0604, /* ptr to msg structure */ + fc_mes0604, /* ptr to msg */ + fc_msgBlk0604.msgPreambleStr, /* begin varargs */ + rp->fc_ringno, + rp->fc_missbufcnt); /* end varargs */ + icmd->ulpBdeCount = i; + for (j = 0; j < i; j++) { + if (binfo->fc_flag & FC_SLI2) { + mp = (fcipbuf_t * )fc_getvaddr(p_dev_ctl, rp, + (uchar * )getPaddr(icmd->un.cont64[j].addrHigh, + icmd->un.cont64[j].addrLow)); + } + else { + mp = (fcipbuf_t * )fc_getvaddr(p_dev_ctl, rp, + (uchar * )((ulong)icmd->un.cont[j].bdeAddress)); + } + if (mp) { + fcnextdata(mp) = 0; + fcnextpkt(mp) = 0; + m_freem(mp); + } + } + + rp->fc_missbufcnt = cnt + i; + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + return(cnt + i); + } + { + MBUF_INFO * buf_info; + MBUF_INFO bufinfo; + + buf_info = &bufinfo; + buf_info->virt = (uint32 * )fcdata(mp); + buf_info->size = fcPAGESIZE; + buf_info->flags = (FC_MBUF_PHYSONLY | FC_MBUF_DMA); + buf_info->align = 0; + buf_info->dma_handle = 0; + + /* Map page of memory associated with m_data for read/write */ + fc_malloc(p_dev_ctl, buf_info); + if (buf_info->phys == NULL) { + /* mapping that page failed */ + goto out; + } + fcnextpkt(mp) = (fcipbuf_t * )buf_info->phys; + fcsethandle(mp, buf_info->dma_handle); + } + /* map that page and save the address pair for lookup later */ + if (binfo->fc_flag & FC_SLI2) { + fc_mapvaddr(binfo, rp, (MATCHMAP * )mp, + (uint32 *) & icmd->un.cont64[i].addrHigh, + (uint32 *) & icmd->un.cont64[i].addrLow); + icmd->un.cont64[i].tus.f.bdeSize = FC_RCV_BUF_SIZE; + icmd->ulpCommand = CMD_QUE_RING_BUF64_CN; + } else { + fc_mapvaddr(binfo, rp, (MATCHMAP * )mp, + 0, (uint32 *) & icmd->un.cont[i].bdeAddress); + icmd->un.cont[i].bdeSize = FC_RCV_BUF_SIZE; + icmd->ulpCommand = CMD_QUE_RING_BUF_CN; + } + cnt--; + } + + icmd->ulpIoTag = tag; + icmd->ulpBdeCount = i; + icmd->ulpLe = 1; + + icmd->ulpOwner = OWN_CHIP; + + temp->bp = (uchar * )mp; /* used for delimiter between commands */ + + FCSTATCTR.cmdQbuf++; + issue_iocb_cmd(binfo, rp, temp); + } + + rp->fc_missbufcnt = 0; + return(0); +} /* End fc_post_mbuf */ + + +_static_ int +fc_free_iocb_buf( +fc_dev_ctl_t *p_dev_ctl, +RING *rp, +IOCBQ *temp) +{ + FC_BRD_INFO * binfo; + IOCB * cmd; + int i; + MATCHMAP * mp; + + binfo = &BINFO; + while (temp) { + cmd = &temp->iocb; + for (i = 0; i < (int)cmd->ulpBdeCount; i++) { + if (binfo->fc_flag & FC_SLI2) { + mp = fc_getvaddr(p_dev_ctl, rp, (uchar * ) + getPaddr(cmd->un.cont64[i].addrHigh, cmd->un.cont64[i].addrLow)); + } + else { + mp = fc_getvaddr(p_dev_ctl, rp, (uchar * )((ulong)cmd->un.cont[i].bdeAddress)); + } + + if (mp) { + if (rp->fc_ringno == FC_ELS_RING) { + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + } + else if (rp->fc_ringno == FC_IP_RING) { + fcipbuf_t * mbuf; + + mbuf = (fcipbuf_t * )mp; + fcnextdata(mbuf) = 0; + fcnextpkt(mbuf) = 0; + m_freem(mbuf); + } + } + } + switch (rp->fc_ringno) { + case FC_ELS_RING: + fc_post_buffer(p_dev_ctl, rp, i); + break; + case FC_IP_RING: + fc_post_mbuf(p_dev_ctl, rp, i); + break; + } + temp = (IOCBQ * )temp->q; + } + return(0); +} /* End fc_free_iocb_buf */ + + +/* + * Returns 0 if pn1 < pn2 + * Returns 1 if pn1 > pn2 + * Returns 2 if pn1 = pn2 + */ +_static_ int +fc_geportname( +NAME_TYPE *pn1, +NAME_TYPE *pn2) +{ + int i; + uchar * cp1, *cp2; + + i = sizeof(NAME_TYPE); + cp1 = (uchar * )pn1; + cp2 = (uchar * )pn2; + while (i--) { + if (*cp1 < *cp2) { + return(0); + } + if (*cp1 > *cp2) { + return(1); + } + cp1++; + cp2++; + } + + return(2); /* equal */ +} /* End fc_geportname */ + + +_local_ int +fc_ring_txcnt( +FC_BRD_INFO *binfo, +int flag) +{ + int sum = 0; + + if ((binfo->fc_flag & FC_SLI2) && (FCSTATCTR.linkEvent == 0)) + return(0); + + switch (flag) { + case FC_IP_RING: + sum += binfo->fc_ring[FC_IP_RING].fc_tx.q_cnt; + sum += binfo->fc_ring[FC_ELS_RING].fc_tx.q_cnt; + break; + case FC_FCP_RING: + sum += binfo->fc_ring[FC_FCP_RING].fc_tx.q_cnt; + sum += binfo->fc_ring[FC_ELS_RING].fc_tx.q_cnt; + break; + default: + sum = 1; + break; + } + return(sum); +} /* End fc_ring_txcnt */ + + +_local_ int +fc_ring_txpcnt( +FC_BRD_INFO *binfo, +int flag) +{ + int sum = 0; + + switch (flag) { + case FC_IP_RING: + sum += binfo->fc_ring[FC_IP_RING].fc_txp.q_cnt; + sum += binfo->fc_ring[FC_ELS_RING].fc_txp.q_cnt; + break; + case FC_FCP_RING: + sum += binfo->fc_ring[FC_FCP_RING].fc_txp.q_cnt; + sum += binfo->fc_ring[FC_ELS_RING].fc_txp.q_cnt; + break; + default: + sum = 1; + break; + } + return(sum); +} /* End fc_ring_txpcnt */ + + +/*****************************************************************************/ +/* + * NAME: fc_cmdring_timeout + * + * FUNCTION: Fibre Channel driver cmd ring watchdog timer timeout routine. + * + * EXECUTION ENVIRONMENT: interrupt only + * + * CALLED FROM: + * Timer function + * + * RETURNS: + * none + */ +/*****************************************************************************/ +_static_ void +fc_cmdring_timeout( +fc_dev_ctl_t * p_dev_ctl, +void *l1, +void *l2) +{ + FC_BRD_INFO * binfo; + RING * rp; + int i; + uint32 command; + uint32 * lp0; + IOCBQ * xmitiq; + IOCBQ * save; + IOCB * icmd; + MAILBOXQ * mb; + MATCHMAP * mp; + NODELIST * ndlp; + ELS_PKT * ep; + fcipbuf_t * p_mbuf; + fcipbuf_t * m_net; + + if (!p_dev_ctl) { + return; + } + rp = (RING *)l1; + RINGTMO = 0; + + binfo = &BINFO; + if ((xmitiq = fc_ringtxp_get(rp, 0)) != NULL) { + icmd = &xmitiq->iocb; + switch (icmd->ulpCommand) { + case CMD_ELS_REQUEST_CR: + case CMD_ELS_REQUEST64_CR: + mp = (MATCHMAP * )xmitiq->bp; + lp0 = (uint32 * )mp->virt; + command = *lp0; + switch (command) { + case ELS_CMD_FLOGI: /* Fabric login */ + fc_freenode_did(binfo, Fabric_DID, 1); + if (binfo->fc_ffstate == FC_FLOGI) { + binfo->fc_flag &= ~FC_FABRIC; + if (binfo->fc_topology == TOPOLOGY_LOOP) { + binfo->fc_edtov = FF_DEF_EDTOV; + binfo->fc_ratov = FF_DEF_RATOV; + if ((mb=(MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + fc_config_link(p_dev_ctl, (MAILBOX * )mb); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) + != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + binfo->fc_flag |= FC_DELAY_DISC; + } else { + /* Device Discovery completion error */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0220, /* ptr to msg structure */ + fc_mes0220, /* ptr to msg */ + fc_msgBlk0220.msgPreambleStr); /* begin & end varargs */ + binfo->fc_ffstate = FC_ERROR; + if ((mb=(MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + fc_clear_la(binfo, (MAILBOX * )mb); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) + != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + } + } + break; + + case ELS_CMD_PLOGI: /* NPort login */ + if ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, + icmd->un.elsreq.remoteID)) == 0) + break; + + /* If we are in the middle of Discovery */ + if (ndlp->nlp_action & NLP_DO_DISC_START) { + /* Goto next entry */ + fc_nextnode(p_dev_ctl, ndlp); + } + ndlp->nlp_flag &= ~NLP_REQ_SND; + + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + break; + + case ELS_CMD_PRLI: /* Process Log In */ + if ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, + icmd->un.elsreq.remoteID)) == 0) + break; + + /* If we are in the middle of Discovery */ + if (ndlp->nlp_action & NLP_DO_DISC_START) { + /* Goto next entry */ + fc_nextnode(p_dev_ctl, ndlp); + } + ndlp->nlp_flag &= ~NLP_REQ_SND; + ndlp->nlp_state = NLP_LOGIN; + fc_nlp_unmap(binfo, ndlp); + break; + + case ELS_CMD_PDISC: /* Pdisc */ + case ELS_CMD_ADISC: /* Adisc */ + if ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, + icmd->un.elsreq.remoteID)) == 0) + break; + + /* If we are in the middle of Address Authentication */ + if (ndlp->nlp_action & (NLP_DO_ADDR_AUTH)) { + ndlp->nlp_action &= ~NLP_DO_ADDR_AUTH; + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + + ndlp->nlp_action |= NLP_DO_DISC_START; + /* Goto next entry */ + fc_nextnode(p_dev_ctl, ndlp); + } else { + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + } + break; + + case ELS_CMD_LOGO: /* Logout */ + if ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, + icmd->un.elsreq.remoteID)) == 0) + break; + + /* If we are in the middle of Discovery */ + if (ndlp->nlp_action & NLP_DO_DISC_START) { + /* Goto next entry */ + fc_nextnode(p_dev_ctl, ndlp); + } + + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + break; + + case ELS_CMD_FARP: /* Farp-req */ + case ELS_CMD_FARPR: /* Farp-res */ + ep = (ELS_PKT * )lp0; + if((ndlp = fc_findnode_wwpn(binfo, NLP_SEARCH_ALL, + &ep->un.farp.RportName)) == 0) + break; + ndlp->nlp_flag &= ~NLP_FARP_SND; + ndlp->nlp_action &= ~NLP_DO_ADDR_AUTH; + + /* Check for a FARP generated nlplist entry */ + if (ndlp->nlp_DID == Bcast_DID) { + fc_freenode(binfo, ndlp, 1); + } + break; + + case ELS_CMD_SCR: /* State Change Registration */ + break; + + default: + FCSTATCTR.elsCmdPktInval++; + break; + } + if (xmitiq->bp) { + fc_mem_put(binfo, MEM_BUF, (uchar * )xmitiq->bp); + } + if (xmitiq->info) { + fc_mem_put(binfo, MEM_BUF, (uchar * )xmitiq->info); + } + if ((binfo->fc_flag & FC_SLI2) && (xmitiq->bpl)) { + fc_mem_put(binfo, MEM_BPL, (uchar * )xmitiq->bpl); + } + break; + + case CMD_XMIT_ELS_RSP_CX: + case CMD_XMIT_ELS_RSP64_CX: + ndlp = (NODELIST * )xmitiq->ndlp; + /* No retries */ + if ((ndlp) && (ndlp->nlp_flag & NLP_RM_ENTRY) && + !(ndlp->nlp_flag & NLP_REQ_SND)) { + if (ndlp->nlp_type & NLP_FCP_TARGET) { + ndlp->nlp_flag &= ~NLP_RM_ENTRY; + ndlp->nlp_action &= ~NLP_DO_ADDR_AUTH; + if(binfo->fc_ffstate == FC_READY) { + if ((ndlp->nlp_flag & NLP_NODEV_TMO) && + (ndlp->nlp_DID != (uint32)0)) { + ndlp->nlp_flag |= NLP_NODEV_TMO; + if(!(ndlp->nlp_flag & NLP_NS_REMOVED)) { + fc_els_cmd(binfo, ELS_CMD_PLOGI, + (void *)((ulong)ndlp->nlp_DID), (uint32)0, (ushort)0, ndlp); + } + } + if(!(binfo->fc_flag & FC_RSCN_MODE)) { + binfo->fc_flag |= FC_RSCN_MODE; + ndlp->nlp_action |= NLP_DO_RSCN; + ndlp->nlp_flag &= ~NLP_NODEV_TMO; + fc_nextrscn(p_dev_ctl, 1); + } + } + else { + ndlp->nlp_action |= NLP_DO_DISC_START; + fc_nextdisc(p_dev_ctl, 1); + } + } else + fc_freenode_did(binfo, ndlp->nlp_DID, 0); + } + if (xmitiq->bp) { + fc_mem_put(binfo, MEM_BUF, (uchar * )xmitiq->bp); + } + if ((binfo->fc_flag & FC_SLI2) && (xmitiq->bpl)) { + fc_mem_put(binfo, MEM_BPL, (uchar * )xmitiq->bpl); + } + break; + + case CMD_ABORT_XRI_CN: + break; + + case CMD_CREATE_XRI_CR: + break; + + case CMD_XMIT_SEQUENCE_CX: + case CMD_XMIT_BCAST_CN: + case CMD_XMIT_SEQUENCE64_CX: + case CMD_XMIT_BCAST64_CN: + if (rp->fc_ringno != FC_IP_RING) { + break; + } + NDDSTAT.ndd_xmitque_cur--; + /* get mbuf ptr for completed xmit */ + m_net = (fcipbuf_t * )xmitiq->bp; + /* Loop through iocb chain unmap memory pages associated with mbuf */ + if (binfo->fc_flag & FC_SLI2) { + ULP_BDE64 * bpl; + MATCHMAP * bmp; + + bmp = (MATCHMAP * )xmitiq->bpl; + bpl = (ULP_BDE64 * )bmp->virt; + while (bpl && xmitiq->iocb.un.xseq64.bdl.bdeSize) { + fc_bufunmap(p_dev_ctl, (uchar *)getPaddr(bpl->addrHigh, bpl->addrLow), 0, bpl->tus.f.bdeSize); + bpl++; + xmitiq->iocb.un.xseq64.bdl.bdeSize -= sizeof(ULP_BDE64); + } + fc_mem_put(binfo, MEM_BPL, (uchar * )bmp); + fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq); + xmitiq = 0; + } else { + while (xmitiq) { + for (i = 0; i < (int)xmitiq->iocb.ulpBdeCount; i++) { + fc_bufunmap(p_dev_ctl, (uchar *)((ulong)xmitiq->iocb.un.cont[i].bdeAddress), 0, (uint32)xmitiq->iocb.un.cont[i].bdeSize); + } + save = (IOCBQ * )xmitiq->q; + fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq); + xmitiq = save; + } + } + + /* free mbuf */ + if (m_net) { + p_mbuf = fcnextdata(m_net); + fcnextdata(m_net) = 0; + fcfreehandle(p_dev_ctl, m_net); + m_freem(m_net); + if (p_mbuf) { + fcfreehandle(p_dev_ctl, p_mbuf); + m_freem(p_mbuf); + } + } + break; + + default: + break; + } + if (xmitiq) + fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq); + /* Command ring timeout */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk1401, /* ptr to msg structure */ + fc_mes1401, /* ptr to msg */ + fc_msgBlk1401.msgPreambleStr, /* begin varargs */ + rp->fc_ringno, + icmd->ulpCommand ); /* end varargs */ + } else { + /* Command ring timeout */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk1402, /* ptr to msg structure */ + fc_mes1402, /* ptr to msg */ + fc_msgBlk1402.msgPreambleStr, /* begin varargs */ + rp->fc_ringno ); /* end varargs */ + } + + if ((rp->fc_ringno == FC_IP_RING) && + (binfo->fc_flag & FC_LNK_DOWN)) { + IOCBQ * xmitiq; + + /* If linkdown, flush out tx and txp queues */ + /* get next command from ring xmit queue */ + while ((xmitiq = fc_ringtx_drain(rp)) != 0) { + fc_freebufq(p_dev_ctl, rp, xmitiq); + } + + /* look up xmit next compl */ + while ((xmitiq = fc_ringtxp_get(rp, 0)) != 0) { + fc_freebufq(p_dev_ctl, rp, xmitiq); + } + NDDSTAT.ndd_xmitque_cur = 0; + } + + return; +} /* End fc_cmdring_timeout */ + + +/*****************************************************************************/ +/* + * NAME: fc_linkdown_timeout + * + * FUNCTION: Fibre Channel driver link down watchdog timer timeout routine. + * + * EXECUTION ENVIRONMENT: interrupt only + * + * CALLED FROM: + * Timer function + * + * RETURNS: + * none + */ +/*****************************************************************************/ +_static_ void +fc_linkdown_timeout( +fc_dev_ctl_t * p_dev_ctl, +void *l1, +void *l2) +{ + FC_BRD_INFO * binfo; + iCfgParam * clp; + RING * rp; + NODELIST * ndlp; + NODELIST * new_ndlp; + + if (!p_dev_ctl) { + return; + } + + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + rp = &binfo->fc_ring[FC_FCP_RING]; + RINGTMO = 0; + + /* EXPIRED linkdown timer */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0750, /* ptr to msg structure */ + fc_mes0750, /* ptr to msg */ + fc_msgBlk0750.msgPreambleStr, /* begin varargs */ + (ulong)binfo->fc_ffstate ); /* end varargs */ + if (binfo->fc_ffstate == FC_READY) { + return; + } + + if ((binfo->fc_ffstate > FC_LINK_DOWN) && + (binfo->fc_ffstate < FC_READY)) { + + /* Set the link down watchdog timer expired flag */ + binfo->fc_flag |= FC_LD_TIMEOUT; + goto out; + } + + /* Since the link has been down for so long, call fc_freenode for all + * SCSI device and clear out all SCSI queues + */ + ndlp = binfo->fc_nlpmap_start; + while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) { + new_ndlp = (NODELIST *)ndlp->nlp_listp_next; + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + ndlp = new_ndlp; + } + + /* Set the link down watchdog timer expired flag */ + binfo->fc_flag |= FC_LD_TIMEOUT; + + if((clp[CFG_LINKDOWN_TMO].a_current) && (clp[CFG_HOLDIO].a_current == 0)) { + fc_failio(p_dev_ctl); + } + +out: + + return; +} /* End fc_linkdown_timeout */ + + +/*****************************************************************************/ +/* + * NAME: fc_mbox_timeout + * + * FUNCTION: Fibre Channel driver mailbox watchdog timer timeout routine. + * + * EXECUTION ENVIRONMENT: interrupt only + * + * CALLED FROM: + * Timer function + * + * RETURNS: + * none + */ +/*****************************************************************************/ +_static_ void +fc_mbox_timeout( +fc_dev_ctl_t * p_dev_ctl, +void *l1, +void *l2) +{ + FC_BRD_INFO * binfo; + MAILBOXQ * mbox; + MAILBOX * swpmb, *mb; + void *ioa; + volatile uint32 word0; + + if (!p_dev_ctl) { + return; + } + + binfo = &BINFO; + MBOXTMO = 0; + + binfo->fc_mbox_active = 0; + + if (binfo->fc_flag & FC_SLI2) { + fc_mpdata_sync(binfo->fc_slim2.dma_handle, 0, 0, + DDI_DMA_SYNC_FORKERNEL); + /* First copy command data */ + mb = FC_SLI2_MAILBOX(binfo); + word0 = *((volatile uint32 * )mb); + word0 = PCIMEM_LONG(word0); + } else { + /* First copy command data */ + ioa = (void *)FC_MAP_MEM(&binfo->fc_iomap_mem); /* map in SLIM */ + mb = FC_MAILBOX(binfo, ioa); + word0 = READ_SLIM_ADDR(binfo, ((volatile uint32 * )mb)); + FC_UNMAP_MEMIO(ioa); + } + swpmb = (MAILBOX * ) & word0; + + /* Mailbox command timeout, status fc_brd_no, + &fc_msgBlk0310, /* ptr to msg structure */ + fc_mes0310, /* ptr to msg */ + fc_msgBlk0310.msgPreambleStr, /* begin varargs */ + swpmb->mbxCommand, + swpmb->mbxStatus); /* end varargs */ + if ((mbox = fc_mbox_get(binfo))) { + if (issue_mb_cmd(binfo, (MAILBOX * )mbox, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mbox); + } + } + + return; +} /* End fc_mbox_timeout */ + + + +/*****************************************************************************/ +/* + * NAME: fc_fabric_timeout + * + * FUNCTION: Fibre Channel driver fabric watchdog timer timeout routine. + * + * EXECUTION ENVIRONMENT: interrupt only + * + * CALLED FROM: + * Timer function + * + * RETURNS: + * none + */ +/*****************************************************************************/ +_static_ void +fc_fabric_timeout( +fc_dev_ctl_t * p_dev_ctl, +void *l1, +void *l2) +{ + FC_BRD_INFO * binfo; + NODELIST * ndlp; + NODELIST * new_ndlp; + MAILBOXQ * mb; + iCfgParam * clp; + + if (!p_dev_ctl) { + return; + } + + binfo = &BINFO; + FABRICTMO = 0; + + /* Check for wait for FAN timeout */ + if (binfo->fc_ffstate == FC_FLOGI) { + if((binfo->fc_topology == TOPOLOGY_LOOP) && + (binfo->fc_flag & FC_PUBLIC_LOOP)) { + /* FAN timeout */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0221, /* ptr to msg structure */ + fc_mes0221, /* ptr to msg */ + fc_msgBlk0221.msgPreambleStr); /* begin & end varargs */ + } + else { + /* Initial FLOGI timeout */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0222, /* ptr to msg structure */ + fc_mes0222, /* ptr to msg */ + fc_msgBlk0222.msgPreambleStr); /* begin & end varargs */ + } + + fc_freenode_did(binfo, Fabric_DID, 1); + /* FAN timeout, so just do FLOGI instead */ + /* Now build FLOGI payload and issue ELS command */ + fc_els_cmd(binfo, ELS_CMD_FLOGI, (void *)Fabric_DID, + (uint32)0, (ushort)0, (NODELIST *)0); + goto out; + } + + /* Check for wait for NameServer Rsp timeout */ + if (binfo->fc_ffstate == FC_NS_REG) { + /* NameServer Registration timeout */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0223, /* ptr to msg structure */ + fc_mes0223, /* ptr to msg */ + fc_msgBlk0223.msgPreambleStr, /* begin varargs */ + binfo->fc_ns_retry, + fc_max_ns_retry); /* end varargs */ + if ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, NameServer_DID))) { + if(binfo->fc_ns_retry) { + if(binfo->fc_ns_retry < fc_max_ns_retry) { + /* Try it one more time */ + if (fc_ns_cmd(p_dev_ctl, ndlp, SLI_CTNS_RFT_ID) == 0) { + goto out; + } + } + binfo->fc_ns_retry = 0; + } + /* Complete discovery, then issue an INIT_LINK */ + goto ns_tmout; + } + goto out; + } + + /* Check for wait for NameServer Rsp timeout */ + if (binfo->fc_ffstate == FC_NS_QRY) { + /* NameServer Query timeout */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0224, /* ptr to msg structure */ + fc_mes0224, /* ptr to msg */ + fc_msgBlk0224.msgPreambleStr, /* begin varargs */ + binfo->fc_ns_retry, + fc_max_ns_retry); /* end varargs */ + if ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, NameServer_DID))) { + if(binfo->fc_ns_retry) { + if(binfo->fc_ns_retry < fc_max_ns_retry) { + /* Try it one more time */ + if (fc_ns_cmd(p_dev_ctl, ndlp, SLI_CTNS_GID_FT) == 0) { + goto out; + } + } + binfo->fc_ns_retry = 0; + } + +ns_tmout: + /* Complete discovery, then issue an INIT_LINK */ + /* This should turn off DELAYED ABTS for ELS timeouts */ + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX))) { + fc_set_slim(binfo, (MAILBOX * )mb, 0x052198, 0); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + + /* Nothing to authenticate, so CLEAR_LA right now */ + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + binfo->fc_ffstate = FC_CLEAR_LA; + fc_clear_la(binfo, (MAILBOX * )mb); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + /* Device Discovery completes */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0225, /* ptr to msg structure */ + fc_mes0225, /* ptr to msg */ + fc_msgBlk0225.msgPreambleStr); /* begin & end varargs */ + } else { + /* Device Discovery completion error */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0226, /* ptr to msg structure */ + fc_mes0226, /* ptr to msg */ + fc_msgBlk0226.msgPreambleStr); /* begin & end varargs */ + binfo->fc_ffstate = FC_ERROR; + } + + binfo->fc_firstopen++; + if(binfo->fc_firstopen >= fc_max_ns_retry) { + goto out; + } + + /* Get a buffer to use for the mailbox command */ + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + clp = DD_CTL.p_config[binfo->fc_brd_no]; + + /* Setup and issue mailbox INITIALIZE LINK command */ + fc_linkdown(p_dev_ctl); + fc_init_link(binfo, (MAILBOX * )mb, clp[CFG_TOPOLOGY].a_current, + clp[CFG_LINK_SPEED].a_current); + ((MAILBOX *)mb)->un.varInitLnk.lipsr_AL_PA = 0; + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) != MBX_BUSY) + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + goto out; + } + + /* Check for Node Authentication timeout */ + if (binfo->fc_ffstate == FC_LOOP_DISC) { + int disc; + + disc = 0; + /* Node Authentication timeout */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0227, /* ptr to msg structure */ + fc_mes0227, /* ptr to msg */ + fc_msgBlk0227.msgPreambleStr); /* begin & end varargs */ + ndlp = binfo->fc_nlpbind_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) { + new_ndlp = (NODELIST *)ndlp->nlp_listp_next; + + /* Clean up all nodes marked for authentication */ + if (ndlp->nlp_action & NLP_DO_ADDR_AUTH) { + ndlp->nlp_action &= ~NLP_DO_ADDR_AUTH; + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + if (ndlp->nlp_DID != NameServer_DID) { + ndlp->nlp_action |= NLP_DO_DISC_START; + disc++; + } + } + else if (ndlp->nlp_action & NLP_DO_DISC_START) { + if (ndlp->nlp_DID != NameServer_DID) { + disc++; + } + } + ndlp = new_ndlp; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + } + if(disc) { + fc_nextdisc(p_dev_ctl, fc_max_els_sent); + } + else { + goto ns_tmout; + } + goto out; + } + + /* Check for Node Discovery timeout */ + if (binfo->fc_ffstate == FC_NODE_DISC) { + /* Node Discovery timeout */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0228, /* ptr to msg structure */ + fc_mes0228, /* ptr to msg */ + fc_msgBlk0228.msgPreambleStr); /* begin & end varargs */ + ndlp = binfo->fc_nlpbind_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) { + new_ndlp = (NODELIST *)ndlp->nlp_listp_next; + + /* Clean up all nodes marked for discovery/authentication */ + if (ndlp->nlp_action & (NLP_DO_ADDR_AUTH | NLP_DO_DISC_START)) { + /* Node Discovery timeout */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0229, /* ptr to msg structure */ + fc_mes0229, /* ptr to msg */ + fc_msgBlk0229.msgPreambleStr, /* begin varargs */ + ndlp->nlp_DID, + ndlp->nlp_flag, + ndlp->nlp_state, + ndlp->nlp_type); /* end varargs */ + ndlp->nlp_flag &= ~(NLP_REQ_SND | NLP_REG_INP | NLP_REQ_SND_ADISC); + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + } + ndlp = new_ndlp; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + } + /* Nothing to discover, so CLEAR_LA right now */ + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + binfo->fc_ffstate = FC_CLEAR_LA; + fc_clear_la(binfo, (MAILBOX * )mb); + if (issue_mb_cmd(binfo, (MAILBOX * )mb,MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } else { + /* Device Discovery completion error */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0230, /* ptr to msg structure */ + fc_mes0230, /* ptr to msg */ + fc_msgBlk0230.msgPreambleStr); /* begin & end varargs */ + binfo->fc_ffstate = FC_ERROR; + } + goto out; + } + + /* Check for RSCN timeout */ + if ((binfo->fc_flag & FC_RSCN_MODE) && (binfo->fc_ffstate == FC_READY)) { + + if(binfo->fc_ns_retry) { + if ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, NameServer_DID))) { + if(binfo->fc_ns_retry < fc_max_ns_retry) { + /* Try it one more time */ + if (fc_ns_cmd(p_dev_ctl, ndlp, SLI_CTNS_GID_FT) == 0) { + goto out; + } + } + } + } + /* RSCN timeout */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0231, /* ptr to msg structure */ + fc_mes0231, /* ptr to msg */ + fc_msgBlk0231.msgPreambleStr, /* begin varargs */ + binfo->fc_ns_retry, + fc_max_ns_retry ); /* end varargs */ + ndlp = binfo->fc_nlpbind_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) { + new_ndlp = (NODELIST *)ndlp->nlp_listp_next; + + /* Clean up all nodes marked for rscn */ + if (ndlp->nlp_action & NLP_DO_RSCN) { + /* Node RSCN timeout */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0232, /* ptr to msg structure */ + fc_mes0232, /* ptr to msg */ + fc_msgBlk0232.msgPreambleStr, /* begin varargs */ + ndlp->nlp_DID, + ndlp->nlp_flag, + ndlp->nlp_state, + ndlp->nlp_type); /* end varargs */ + ndlp->nlp_flag &= ~(NLP_REQ_SND | NLP_REG_INP | NLP_REQ_SND_ADISC); + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + } + ndlp = new_ndlp; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + } + + binfo->fc_flag &= ~FC_NLP_MORE; + binfo->fc_nlp_cnt = 0; + binfo->fc_ns_retry = 0; + /* fc_nextrscn(p_dev_ctl, fc_max_els_sent); */ + fc_rlip(p_dev_ctl); + goto out; + } + + /* Check for pt2pt link up timeout */ + if ((binfo->fc_flag & FC_PT2PT) && (binfo->fc_ffstate != FC_READY)) { + /* PT2PT link up timeout */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0233, /* ptr to msg structure */ + fc_mes0233, /* ptr to msg */ + fc_msgBlk0233.msgPreambleStr); /* begin & end varargs */ + binfo->fc_ffstate = FC_LINK_UP; + binfo->fc_flag &= ~(FC_LNK_DOWN | FC_PT2PT | FC_PT2PT_PLOGI | + FC_LBIT | FC_RSCN_MODE | FC_NLP_MORE | + FC_RSCN_DISC_TMR | FC_RSCN_DISCOVERY); + + binfo->fc_myDID = 0; + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + binfo->fc_ffstate = FC_CFG_LINK; + fc_config_link(p_dev_ctl, (MAILBOX * )mb); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + goto out; + } + +out: + return; +} /* End fc_fabric_timeout */ + + +/*****************************************************************************/ +/* + * NAME: fc_delay_timeout + * + * FUNCTION: Fibre Channel driver delay watchdog timer timeout routine. + * + * EXECUTION ENVIRONMENT: interrupt only + * + * CALLED FROM: + * Timer function + * + * RETURNS: + * none + */ +/*****************************************************************************/ +_static_ void +fc_delay_timeout( +fc_dev_ctl_t * p_dev_ctl, +void *l1, +void *l2) +{ + FC_BRD_INFO * binfo; + IOCBQ * iocbq; + RING * rp; + MATCHMAP * rmp; + NODELIST * ndlp; + + binfo = &BINFO; + rp = &binfo->fc_ring[FC_ELS_RING]; + iocbq = (IOCBQ *)l1; + + if(((rmp = (MATCHMAP *)iocbq->info) != 0) && + ((ndlp = (NODELIST *)rmp->fc_mptr) != 0)) { + /* Don't send PLOGI if we are already logged in! */ + if(ndlp->nlp_state >= NLP_LOGIN) { + if(iocbq->bp) { + fc_mem_put(binfo, MEM_BUF, (uchar * )iocbq->bp); + } + if (iocbq->info) { + fc_mem_put(binfo, MEM_BUF, (uchar * )iocbq->info); + } + if (iocbq->bpl) { + fc_mem_put(binfo, MEM_BPL, (uchar * )iocbq->bpl); + } + + fc_mem_put(binfo, MEM_IOCB, (uchar * )iocbq); + return; + } + } + /* Delayxmit ELS command timeout */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0136, /* ptr to msg structure */ + fc_mes0136, /* ptr to msg */ + fc_msgBlk0136.msgPreambleStr, /* begin varargs */ + iocbq->iocb.ulpCommand, + iocbq->iocb.ulpIoTag, + iocbq->retry, + iocbq->iocb.un.elsreq.remoteID); /* end varargs */ + issue_iocb_cmd(binfo, rp, iocbq); + + if (((binfo->fc_flag & FC_RSCN_MODE) && (binfo->fc_ffstate == FC_READY)) || + (binfo->fc_ffstate == FC_LOOP_DISC) || + (binfo->fc_ffstate == FC_NODE_DISC)) { + binfo->fc_fabrictmo = (2 * binfo->fc_ratov) + + ((4 * binfo->fc_edtov) / 1000) + 1; + if(FABRICTMO) { + fc_clk_res(p_dev_ctl, binfo->fc_fabrictmo, FABRICTMO); + } + else { + FABRICTMO = fc_clk_set(p_dev_ctl, binfo->fc_fabrictmo, + fc_fabric_timeout, 0, 0); + } + } + + return; +} + +/*****************************************************************************/ +/* + * NAME: fc_nodev_timeout + * + * FUNCTION: Fibre Channel driver FCP device disappearing timeout routine. + * + * EXECUTION ENVIRONMENT: interrupt only + * + * CALLED FROM: + * Timer interrupt + * + * INPUT: + * tp - pointer to the timer structure + * + * RETURNS: + * none + */ +/*****************************************************************************/ +_static_ void +fc_nodev_timeout( +fc_dev_ctl_t * p_dev_ctl, +void * np, +void *l2) +{ + node_t * nodep; + dvi_t * dev_ptr; + FC_BRD_INFO * binfo; + iCfgParam * clp; + NODELIST * ndlp; + RING * rp; + IOCBQ * temp; + IOCBQ * nexttemp, *prevtemp; + IOCB * cmd; + unsigned long iflag; + + nodep = (node_t *)np; + binfo = &BINFO; + rp = &binfo->fc_ring[FC_FCP_RING]; + if(nodep) { + uint32 did; + uint32 pan; + uint32 sid; + uint32 rpi; + + clp = DD_CTL.p_config[p_dev_ctl->info.fc_brd_no]; + if(nodep->rpi != 0xfffe) + rpi = nodep->rpi; + else + rpi = 0; + + if((ndlp = nodep->nlp) == 0) { + /* + * Find the target from the nlplist based on SCSI ID + */ + ndlp = fc_findnode_scsid(binfo, NLP_SEARCH_MAPPED, nodep->scsi_id); + } + + if (ndlp) { + RING * rp; + IOCBQ * iocbq; + + /* EXPIRED nodev timer */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0751, /* ptr to msg structure */ + fc_mes0751, /* ptr to msg */ + fc_msgBlk0751.msgPreambleStr, /* begin varargs */ + (ulong)ndlp, + ndlp->nlp_flag, + ndlp->nlp_state, + ndlp->nlp_DID); /* end varargs */ + pan = ndlp->id.nlp_pan; + sid = ndlp->id.nlp_sid; + ndlp->nlp_flag &= ~NLP_NODEV_TMO; + did = ndlp->nlp_DID; + if(ndlp->nlp_Rpi) + rpi = ndlp->nlp_Rpi; + if(did == 0) { + if((ndlp->nlp_type & (NLP_AUTOMAP | NLP_SEED_MASK)) && + (ndlp->nlp_state == NLP_LIMBO) && ndlp->nlp_oldDID) + did = ndlp->nlp_oldDID; + + if (ndlp->nlp_flag & NLP_REQ_SND) { + /* Look through ELS ring and abort ELS cmd */ + rp = &binfo->fc_ring[FC_ELS_RING]; + iocbq = (IOCBQ * )(rp->fc_txp.q_first); + while (iocbq) { + if(iocbq->iocb.un.elsreq.remoteID == did) { + iocbq->retry = 0xff; + if((binfo->fc_flag & FC_RSCN_MODE) || + (binfo->fc_ffstate < FC_READY)) { + if((ndlp->nlp_state >= NLP_PLOGI) && + (ndlp->nlp_state <= NLP_PRLI)) { + ndlp->nlp_action &= ~NLP_DO_RSCN; + binfo->fc_nlp_cnt--; + if ((ndlp->nlp_type & NLP_IP_NODE) && ndlp->nlp_bp) { + m_freem((fcipbuf_t *)ndlp->nlp_bp); + ndlp->nlp_bp = (uchar * )0; + } + } + } + } + iocbq = (IOCBQ * )iocbq->q; + } + /* In case its on fc_delay_timeout list */ + fc_abort_delay_els_cmd(p_dev_ctl, ndlp->nlp_DID); + } + } + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + } else { + did = 0; + pan = 0; + sid = 0; + } + /* Device disappeared, nodev timeout */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0752, /* ptr to msg structure */ + fc_mes0752, /* ptr to msg */ + fc_msgBlk0752.msgPreambleStr, /* begin varargs */ + did, + sid, + pan, + clp[CFG_NODEV_TMO].a_current); /* end varargs */ + nodep->flags |= FC_NODEV_TMO; + nodep->flags &= ~FC_FCP2_RECOVERY; + nodep->nodev_tmr = 0; + for (dev_ptr = nodep->lunlist; dev_ptr != NULL; + dev_ptr = dev_ptr->next) { + + /* UNREG_LOGIN from freenode should abort txp I/Os */ + if(ndlp == 0) { + /* First send ABTS on outstanding I/Os in txp queue */ + fc_abort_fcp_txpq(binfo, dev_ptr); + } + + fc_fail_pendq(dev_ptr, ENXIO, STAT_ABORTED); + fc_fail_cmd(dev_ptr, ENXIO, STAT_ABORTED); + fc_return_standby_queue(dev_ptr, ENXIO, STAT_ABORTED); + + /* Call iodone for all the CLEARQ error bufs */ + fc_free_clearq(dev_ptr); + } + /* fail everything on txq that matches rpi */ + iflag = lpfc_q_disable_lock(p_dev_ctl); + prevtemp = 0; + temp = (IOCBQ *)rp->fc_tx.q_first; + while (temp != NULL) { + nexttemp = (IOCBQ *)temp->q; + cmd = &temp->iocb; + if(cmd->ulpContext == rpi) { + if(prevtemp) + prevtemp->q = (uchar *)nexttemp; + else + rp->fc_tx.q_first = (uchar *)nexttemp; + if(rp->fc_tx.q_last == (uchar * )temp) { + rp->fc_tx.q_last =0; + break; + } + cmd->ulpStatus = IOSTAT_LOCAL_REJECT; + cmd->un.grsp.perr.statLocalError = IOERR_INVALID_RPI; + + lpfc_q_unlock_enable(p_dev_ctl, iflag); + handle_fcp_event(p_dev_ctl, rp, temp); + iflag = lpfc_q_disable_lock(p_dev_ctl); + + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + } + else + prevtemp = temp; + + if(rp->fc_tx.q_last == (uchar * )temp) + break; + temp = nexttemp; + } + lpfc_q_unlock_enable(p_dev_ctl, iflag); + } +} + +/*****************************************************************************/ +/* + * NAME: fc_rscndisc_timeout + * + * FUNCTION: Fibre Channel driver RSCN timer timeout routine. + * + * EXECUTION ENVIRONMENT: interrupt only + * + * CALLED FROM: + * Timer function + * + * RETURNS: + * none + */ +/*****************************************************************************/ +_local_ void +fc_rscndisc_timeout( +fc_dev_ctl_t * p_dev_ctl, +void *l1, +void *l2) +{ + FC_BRD_INFO * binfo; + + binfo = &BINFO; + binfo->fc_flag |= (FC_RSCN_DISC_TMR | FC_RSCN_DISCOVERY); + /* EXPIRED RSCN disc timer */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0252, /* ptr to msg structure */ + fc_mes0252, /* ptr to msg */ + fc_msgBlk0252.msgPreambleStr, /* begin varargs */ + (ulong)binfo->fc_flag ); /* end varargs */ + fc_nextrscn(p_dev_ctl, fc_max_els_sent); +} + +_static_ int +fc_free_fcp_txq( +fc_dev_ctl_t * p_dev_ctl, +uint32 iotag) +{ + FC_BRD_INFO * binfo; + RING * rp; + IOCBQ * temp; + IOCBQ * prev_temp; + IOCB * cmd; + unsigned long iflag; + + iflag = lpfc_q_disable_lock(p_dev_ctl); + binfo = &BINFO; + rp = &binfo->fc_ring[FC_FCP_RING]; + + /* Check to see if iotag is still queued on txq */ + prev_temp = 0; + temp = (IOCBQ *)(rp->fc_tx.q_first); + while(temp) { + cmd = &temp->iocb; + if(iotag == cmd->ulpIoTag) { + /* A match so dequeue it */ + if(prev_temp) { + prev_temp->q = temp->q; + } + else { + rp->fc_tx.q_first = (uchar *)(temp->q); + } + if(rp->fc_tx.q_last == (uchar * )temp) + rp->fc_tx.q_last = (uchar * )prev_temp; + rp->fc_tx.q_cnt--; + prev_temp = temp; + temp = (IOCBQ *)(temp->q); + fc_mem_put(binfo, MEM_IOCB, (uchar * )prev_temp); + lpfc_q_unlock_enable(p_dev_ctl, iflag); + return(1); + } + prev_temp = temp; + temp = (IOCBQ *)(temp->q); + } + lpfc_q_unlock_enable(p_dev_ctl, iflag); + return(0); +} /* End fc_free_fcp_txq */ + +/*****************************************************************************/ +/* + * NAME: fc_scsi_timeout + * + * FUNCTION: Fibre Channel driver SCSI FCP timeout routine. + * + * EXECUTION ENVIRONMENT: interrupt only + * + * CALLED FROM: + * Timer interrupt + * + * INPUT: + * tp - pointer to the timer structure + * + * RETURNS: + * none + */ +/*****************************************************************************/ +_static_ void +fc_scsi_timeout( +fc_dev_ctl_t * p, +void *l1, +void *l2) +{ + fc_dev_ctl_t * p_dev_ctl; + FC_BRD_INFO * binfo; + iCfgParam * clp; + RING * rp; + fc_buf_t * fcptr, *next_fcptr; + T_SCSIBUF * sbp; + struct buf * clrptr; + dvi_t * dev_ptr; + int j, ipri, do_rlip; + uint32 now; + + curtime(&now); + + /* + * Search through all outstanding SCSI commands for any that timed out + */ + for (j = 0; j < MAX_FC_BRDS; j++) { + p_dev_ctl = DD_CTL.p_dev[j]; + if (p_dev_ctl) { + do_rlip = 0; + binfo = &BINFO; + if(binfo->fc_flag & FC_ESTABLISH_LINK) { + continue; + } + clp = DD_CTL.p_config[binfo->fc_brd_no]; + if (clp[CFG_FCP_ON].a_current) { + rp = &binfo->fc_ring[FC_FCP_RING]; + + if(((clp[CFG_LINKDOWN_TMO].a_current == 0) || + clp[CFG_HOLDIO].a_current) && (binfo->fc_ffstate != FC_READY)) { + continue; + } + + ipri = disable_lock(FC_LVL, &CMD_LOCK); + fcptr = (fc_buf_t * ) rp->fc_txp.q_first; + while (fcptr != NULL) { + next_fcptr = fcptr->fc_fwd; + + if(fcptr->dev_ptr->queue_state == ACTIVE_PASSTHRU) { + /* Don't manage PASSTRU CMD HERE */ + fc_free_fcp_txq(p_dev_ctl, fcptr->iotag); + fcptr = next_fcptr; + continue; + } /* end ACTIVE_PASSTHRU management */ + + if(ntimercmp(fcptr->timeout, now, < ) && + ntimerisset(&fcptr->timeout)) { + + { + uint32 did; + uint32 pan; + uint32 sid; + + dev_ptr = fcptr->dev_ptr; + if ((dev_ptr->nodep) && (dev_ptr->nodep->nlp)) { + did = dev_ptr->nodep->nlp->nlp_DID; + pan = dev_ptr->nodep->nlp->id.nlp_pan; + sid = dev_ptr->nodep->nlp->id.nlp_sid; + } else { + did = 0; + pan = 0; + sid = 0; + } + /* SCSI timeout */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0754, /* ptr to msg structure */ + fc_mes0754, /* ptr to msg */ + fc_msgBlk0754.msgPreambleStr, /* begin varargs */ + did, + FC_SCSID(pan, sid) ); /* end varargs */ + } + if (!(fcptr->flags & FCBUF_ABTS2)) { + /* Operation timeout, send ABTS for this exchange */ + if (fc_abort_xri(binfo, fcptr->dev_ptr, + fcptr->iotag, ABORT_TYPE_ABTS)) { + /* ABTS not sent this time, out of IOCBs */ + goto skip_rlip; + } else { + if (fcptr->flags & FCBUF_ABTS) { + /* Second ABTS sent for this command */ + fcptr->flags |= FCBUF_ABTS2; + } else { + /* First ABTS sent for this command */ + fcptr->flags |= FCBUF_ABTS; + } + } + fcptr = next_fcptr; + continue; + } + + /* Operation timeout, start loop initialization (LIP) */ + if (dev_ptr->queue_state != STOPPING) { + dev_ptr->queue_state = HALTED; + } + + do_rlip = 1; + +skip_rlip: + sbp = fcptr->sc_bufp; + fc_deq_fcbuf_active(rp, fcptr->iotag); + + sbp->bufstruct.b_error = ETIMEDOUT; + sbp->bufstruct.b_flags |= B_ERROR; + sbp->bufstruct.b_resid = sbp->bufstruct.b_bcount; + sbp->status_validity = SC_ADAPTER_ERROR; + SET_ADAPTER_STATUS(sbp, SC_CMD_TIMEOUT) + + if (fcptr->fcp_cmd.fcpCntl2) { + /* This is a task management command */ + dev_ptr->ioctl_errno = ETIMEDOUT; + + if (dev_ptr->ioctl_wakeup == 1) { + dev_ptr->ioctl_wakeup = 0; + + fc_admin_wakeup(p_dev_ctl, dev_ptr, sbp); + } + } else { + /* Don't iodone this buf until adapter cleared out */ + if(fcptr->flags & FCBUF_INTERNAL) { + if(fcptr->fcp_cmd.fcpCdb[0] != FCP_SCSI_REPORT_LUNS) { + fc_free(p_dev_ctl, (MBUF_INFO *)sbp); + } + fc_mem_put(binfo, MEM_IOCB, (uchar * )sbp); + + if((fcptr->fcp_cmd.fcpCdb[0] == FCP_SCSI_REPORT_LUNS) && + (dev_ptr->nodep) && + (dev_ptr->nodep->rptlunstate == REPORT_LUN_ONGOING)) { + dev_ptr->nodep->flags &= ~RETRY_RPTLUN; + dev_ptr->nodep->rptlunstate = REPORT_LUN_REQUIRED; + } + } + else { + if (p_dev_ctl->timeout_head == NULL) + p_dev_ctl->timeout_head = (struct buf *)sbp; + else { + clrptr = p_dev_ctl->timeout_head; + while (clrptr->av_forw) + clrptr = clrptr->av_forw; + clrptr->av_forw = (struct buf *)sbp; + } + p_dev_ctl->timeout_count++; + } + dev_ptr->active_io_count--; + dev_ptr->nodep->num_active_io--; + sbp->bufstruct.av_forw = NULL; + } + + fc_free_fcp_txq(p_dev_ctl, fcptr->iotag); + fc_enq_fcbuf(fcptr); + } + fcptr = next_fcptr; + } + unlock_enable(ipri, &CMD_LOCK); + } + + /* fix multiple init_link problem */ + if(do_rlip) { + ipri = disable_lock(FC_LVL, &CMD_LOCK); + fc_rlip(p_dev_ctl); + unlock_enable(ipri, &CMD_LOCK); + } + continue; + } + } + + SCSI_TMO = fc_clk_set(0, 5, fc_scsi_timeout, 0, 0); + return; +} /* End fc_scsi_timeout */ + +_static_ int +fc_abort_fcp_txpq( +FC_BRD_INFO *binfo, +dvi_t *dev_ptr) +{ + fc_buf_t * fcptr1, * next_fcptr; + RING * rp; + int cnt; + fc_dev_ctl_t * p_dev_ctl; + unsigned long iflag; + + p_dev_ctl = (fc_dev_ctl_t *)binfo->fc_p_dev_ctl; + iflag = lpfc_q_disable_lock(p_dev_ctl); + rp = &binfo->fc_ring[FC_FCP_RING]; + cnt = 0; + + /* send ABTS on any outstanding I/O in txp queue */ + fcptr1 = (fc_buf_t *)rp->fc_txp.q_first; + while (fcptr1 != NULL) { + next_fcptr = fcptr1->fc_fwd; + if (fcptr1->dev_ptr == dev_ptr) { + lpfc_q_unlock_enable(p_dev_ctl, iflag); + fc_abort_xri(binfo, fcptr1->dev_ptr, fcptr1->iotag, ABORT_TYPE_ABTS); + iflag = lpfc_q_disable_lock(p_dev_ctl); + cnt++; + } + fcptr1 = next_fcptr; + } + lpfc_q_unlock_enable(p_dev_ctl, iflag); + return(cnt); +} + +/* + * Issue an ABORT_XRI_CN iocb command to abort an FCP command already issued. + */ +_static_ int +fc_abort_xri( +FC_BRD_INFO *binfo, +dvi_t *dev_ptr, +ushort iotag, +int flag) +{ + IOCB * icmd; + IOCBQ * temp; + RING * rp; + + rp = &binfo->fc_ring[FC_FCP_RING]; + + if ((binfo->fc_ffstate != FC_READY) || + (dev_ptr->nodep->rpi == 0xfffe)) { + return(1); + } + + /* Get an iocb buffer */ + if ((temp = (IOCBQ * )fc_mem_get(binfo, MEM_IOCB)) == 0) { + return(1); + } + fc_bzero((void *)temp, sizeof(IOCBQ)); + icmd = &temp->iocb; + + icmd->un.acxri.abortType = flag; + icmd->un.acxri.abortContextTag = dev_ptr->nodep->rpi; + icmd->un.acxri.abortIoTag = iotag; + + /* set up an iotag using special ABTS iotags */ + icmd->ulpIoTag = (unsigned)rp->fc_bufcnt++; + if (rp->fc_bufcnt == 0) { + rp->fc_bufcnt = MAX_FCP_CMDS; + } + + icmd->ulpLe = 1; + icmd->ulpClass = (dev_ptr->nodep->nlp->id.nlp_fcp_info & 0x0f); + icmd->ulpCommand = CMD_ABORT_XRI_CN; + icmd->ulpOwner = OWN_CHIP; + + issue_iocb_cmd(binfo, rp, temp); + + return(0); +} /* End fc_abort_xri */ + + +/* + * Issue an ABORT_XRI_CX iocb command to abort an IXri. + */ +_static_ int +fc_abort_ixri_cx( +FC_BRD_INFO *binfo, +ushort xri, +uint32 cmd, +RING *rp) +{ + IOCB * icmd; + IOCBQ * temp; + NODELIST * ndlp; + + /* Get an iocb buffer */ + if ((temp = (IOCBQ * )fc_mem_get(binfo, MEM_IOCB)) == 0) { + return(1); + } + + if( (ndlp = fc_findnode_oxri(binfo, NLP_SEARCH_MAPPED | NLP_SEARCH_UNMAPPED, xri)) == 0 ) { + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + return (1); + } + + fc_bzero((void *)temp, sizeof(IOCBQ)); + icmd = &temp->iocb; + + icmd->un.acxri.abortType = ABORT_TYPE_ABTS; + icmd->ulpContext = xri; + + /* set up an iotag */ + icmd->ulpIoTag0 = (unsigned)rp->fc_iotag++; + if ((rp->fc_iotag & 0x3fff) == 0) { + rp->fc_iotag = 1; + } + + icmd->ulpLe = 1; + icmd->ulpClass = ndlp->id.nlp_ip_info; + icmd->ulpCommand = cmd; + icmd->ulpOwner = OWN_CHIP; + + issue_iocb_cmd(binfo, rp, temp); + + return(0); +} /* End fc_abort_ixri_cx */ + + +/**************************************************/ +/** handle_mb_cmd **/ +/** **/ +/** Description: Process a Mailbox Command. **/ +/** Called from host_interrupt to process MBATT **/ +/** **/ +/** Returns: **/ +/** **/ +/**************************************************/ +_static_ int +handle_mb_cmd( +fc_dev_ctl_t *p_dev_ctl, +MAILBOX *mb, +uint32 cmd) +{ + FC_BRD_INFO * binfo; + iCfgParam * clp; + MAILBOXQ * mbox; + NODELIST * ndlp; + NODELIST * new_ndlp; + struct buf *bp, *nextbp; + RING * rp; + int i; + void *ioa; + uint32 control, ldid, lrpi, ldata; + node_t * node_ptr; + + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + + /* Mailbox command completed successfully, process completion */ + switch (cmd) { + case MBX_LOAD_SM: + case MBX_READ_NV: /* a READ NVPARAMS command completed */ + case MBX_WRITE_NV: /* a WRITE NVPARAMS command completed */ + case MBX_RUN_BIU_DIAG: + case MBX_INIT_LINK: /* a LINK INIT command completed */ + case MBX_SET_SLIM: + case MBX_SET_DEBUG: + case MBX_PART_SLIM: /* a PARTITION SLIM command completed */ + case MBX_CONFIG_RING: /* a CONFIGURE RING command completed */ + case MBX_RESET_RING: + case MBX_READ_CONFIG: + case MBX_READ_RCONFIG: + case MBX_READ_STATUS: + case MBX_READ_XRI: + case MBX_READ_REV: + case MBX_UNREG_D_ID: + case MBX_READ_LNK_STAT: + case MBX_DUMP_MEMORY: + case MBX_LOAD_AREA: + break; + + case MBX_CONFIG_LINK: /* a CONFIGURE LINK command completed */ + /* Change the cmdring_timeout value for IP and ELS commands */ + rp = &binfo->fc_ring[FC_ELS_RING]; + rp->fc_ringtmo = (2 * binfo->fc_ratov) + ((4 * binfo->fc_edtov) / 1000) + 1; + rp = &binfo->fc_ring[FC_IP_RING]; + rp->fc_ringtmo = (2 * binfo->fc_ratov) + ((4 * binfo->fc_edtov) / 1000) + 1; + binfo->fc_fabrictmo = (2 * binfo->fc_ratov) + ((4 * binfo->fc_edtov) / 1000) + 1; + + if (binfo->fc_ffstate == FC_CFG_LINK) { + binfo->fc_ffstate = FC_FLOGI; + if (binfo->fc_topology == TOPOLOGY_LOOP) { + /* If we are public loop and L bit was set */ + if ((binfo->fc_flag & FC_PUBLIC_LOOP) && + !(binfo->fc_flag & FC_LBIT)) { + /* Need to wait for FAN - use fabric timer for timeout. + */ + binfo->fc_fabrictmo = ((binfo->fc_edtov) / 1000) + 1; + if(FABRICTMO) { + fc_clk_res(p_dev_ctl, binfo->fc_fabrictmo, FABRICTMO); + } + else { + FABRICTMO = fc_clk_set(p_dev_ctl, binfo->fc_fabrictmo, + fc_fabric_timeout, 0, 0); + } + break; + } + + binfo->fc_fabrictmo = (2*(binfo->fc_edtov) / 1000) + 1; + if(FABRICTMO) { + fc_clk_res(p_dev_ctl, binfo->fc_fabrictmo, FABRICTMO); + } + else { + FABRICTMO = fc_clk_set(p_dev_ctl, binfo->fc_fabrictmo, + fc_fabric_timeout, 0, 0); + } + /* For power_up == 0 see fc_ffinit */ + if(p_dev_ctl->power_up) + fc_initial_flogi(p_dev_ctl); + } + else { /* pt2pt */ + /* For power_up == 0 see fc_ffinit */ + if(p_dev_ctl->power_up) + fc_initial_flogi(p_dev_ctl); + } + } else { + if (binfo->fc_flag & FC_DELAY_DISC) { + /* Config_link is done, so start discovery */ + binfo->fc_flag &= ~FC_DELAY_DISC; + fc_discovery(p_dev_ctl); + if (binfo->fc_flag & FC_FABRIC) { + /* Register with Fabric for receiving RSCNs */ + fc_els_cmd(binfo, ELS_CMD_SCR, (void *)SCR_DID, + (uint32)0, (ushort)0, (NODELIST *)0); + } + } + } + break; + + case MBX_READ_SPARM: /* a READ SPARAM command completed */ + case MBX_READ_SPARM64: /* a READ SPARAM command completed */ + { + MATCHMAP * mp; + + mp = (MATCHMAP * )binfo->fc_mbbp; + + if(mp) { + fc_mpdata_sync(mp->dma_handle, 0, sizeof(SERV_PARM), + DDI_DMA_SYNC_FORKERNEL); + fc_mpdata_outcopy(p_dev_ctl, mp, (uchar * ) & binfo->fc_sparam, + sizeof(SERV_PARM)); + + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + + binfo->fc_mbbp = 0; + + + fc_bcopy((uchar * ) & binfo->fc_sparam.nodeName, (uchar * ) & binfo->fc_nodename, + sizeof(NAME_TYPE)); + fc_bcopy((uchar * ) & binfo->fc_sparam.portName, (uchar * ) & binfo->fc_portname, + sizeof(NAME_TYPE)); + fc_bcopy(binfo->fc_portname.IEEE, p_dev_ctl->phys_addr, 6); + } + break; + } + + case MBX_READ_RPI: + case MBX_READ_RPI64: + if (binfo->fc_flag & FC_SLI2) { + /* First copy command data */ + mb = FC_SLI2_MAILBOX(binfo); + ldata = mb->un.varWords[0]; /* get rpi */ + ldata = PCIMEM_LONG(ldata); + lrpi = ldata & 0xffff; + ldata = mb->un.varWords[1]; /* get did */ + ldata = PCIMEM_LONG(ldata); + ldid = ldata & Mask_DID; + ldata = mb->un.varWords[30]; + ldata = PCIMEM_LONG(ldata); + } else { + /* First copy command data */ + ioa = (void *)FC_MAP_MEM(&binfo->fc_iomap_mem); /* map in SLIM */ + mb = FC_MAILBOX(binfo, ioa); + ldata = READ_SLIM_ADDR(binfo, (uint32 * ) & mb->un.varWords[0]); + lrpi = ldata & 0xffff; + ldata = READ_SLIM_ADDR(binfo, (uint32 * ) & mb->un.varWords[1]); + ldid = ldata & Mask_DID; + ldata = READ_SLIM_ADDR(binfo, (uint32 * ) & mb->un.varWords[30]); + FC_UNMAP_MEMIO(ioa); + } + + if (ldata == ELS_CMD_LOGO) { + if (((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, ldid)) == 0) || + (!(ndlp->nlp_action & NLP_DO_ADDR_AUTH) && + !(ndlp->nlp_flag & (NLP_FARP_SND | NLP_REQ_SND)))) { + + if (ndlp) { + if (ndlp->nlp_Rpi) + break; /* Now we have an rpi so don't logout */ + } + fc_els_cmd(binfo, ELS_CMD_LOGO, (void *)((ulong)ldid), + (uint32)0, (ushort)0, ndlp); + } + } + break; + + case MBX_REG_LOGIN: + case MBX_REG_LOGIN64: + if (binfo->fc_mbbp) { + fc_mem_put(binfo, MEM_BUF, (uchar * )binfo->fc_mbbp); + binfo->fc_mbbp = 0; + } + + if (binfo->fc_flag & FC_SLI2) { + /* First copy command data */ + mb = FC_SLI2_MAILBOX(binfo); + ldata = mb->un.varWords[0]; /* get rpi */ + ldata = PCIMEM_LONG(ldata); + lrpi = ldata & 0xffff; + ldata = mb->un.varWords[1]; /* get did */ + ldata = PCIMEM_LONG(ldata); + ldid = ldata & Mask_DID; + ldata = mb->un.varWords[30]; + ldata = PCIMEM_LONG(ldata); + } else { + /* First copy command data */ + ioa = (void *)FC_MAP_MEM(&binfo->fc_iomap_mem); /* map in SLIM */ + mb = FC_MAILBOX(binfo, ioa); + ldata = READ_SLIM_ADDR(binfo, (uint32 * ) & mb->un.varWords[0]); + lrpi = ldata & 0xffff; + ldata = READ_SLIM_ADDR(binfo, (uint32 * ) & mb->un.varWords[1]); + ldid = ldata & Mask_DID; + ldata = READ_SLIM_ADDR(binfo, (uint32 * ) & mb->un.varWords[30]); + FC_UNMAP_MEMIO(ioa); + } + + /* Register RPI, will fill in XRI later */ + if ((ndlp=fc_findnode_odid(binfo, NLP_SEARCH_ALL, ldid))) { + ndlp->nlp_Rpi = (short)lrpi; + binfo->fc_nlplookup[lrpi] = ndlp; + ndlp->nlp_state = NLP_LOGIN; + /* REG_LOGIN cmpl */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0311, /* ptr to msg structure */ + fc_mes0311, /* ptr to msg */ + fc_msgBlk0311.msgPreambleStr, /* begin varargs */ + ndlp->nlp_DID, + ndlp->nlp_state, + ndlp->nlp_flag, + ndlp->nlp_Rpi ); /* end varargs */ + fc_nlp_unmap(binfo, ndlp); + + /* If word30 is set, send back ACC */ + if (ldata) { + REG_WD30 wd30; + + wd30.word = ldata; + + /* Wait for ACC to complete before issuing PRLI */ + fc_els_rsp(binfo, ELS_CMD_ACC, (uint32)wd30.f.xri, + (uint32)wd30.f.class, (void *)0, (uint32)sizeof(SERV_PARM), ndlp); + ndlp->nlp_flag |= NLP_REG_INP; + break; + } + + if (ndlp->nlp_DID == binfo->fc_myDID) { + ndlp->nlp_state = NLP_LOGIN; + } else { + fc_process_reglogin(p_dev_ctl, ndlp); + } + } else { + if (ldata) { + /* Dropping ELS rsp */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0103, /* ptr to msg structure */ + fc_mes0103, /* ptr to msg */ + fc_msgBlk0103.msgPreambleStr, /* begin varargs */ + ldata, + ldid ); /* end varargs */ + } + + /* Can't find NODELIST entry for this login, so unregister it */ + if ((mbox = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX))) { + fc_unreg_login(binfo, lrpi, (MAILBOX * )mbox); + if (issue_mb_cmd(binfo, (MAILBOX * )mbox, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mbox); + } + } + } + + break; + + case MBX_UNREG_LOGIN: + if (binfo->fc_flag & FC_SLI2) { + /* First copy command data */ + mb = FC_SLI2_MAILBOX(binfo); + ldata = mb->un.varWords[0]; /* get rpi */ + ldata = PCIMEM_LONG(ldata); + lrpi = ldata & 0xffff; + ldata = mb->un.varWords[30]; + ldata = PCIMEM_LONG(ldata); + } else { + /* First copy command data */ + ioa = (void *)FC_MAP_MEM(&binfo->fc_iomap_mem); /* map in SLIM */ + mb = FC_MAILBOX(binfo, ioa); + ldata = READ_SLIM_ADDR(binfo, (uint32 * ) & mb->un.varWords[0]); + lrpi = ldata & 0xffff; + ldata = READ_SLIM_ADDR(binfo, (uint32 * ) & mb->un.varWords[30]); + FC_UNMAP_MEMIO(ioa); + } + + /* If word30 is set, send back LOGO */ + if (ldata) { + fc_els_cmd(binfo, ELS_CMD_LOGO, (void *)((ulong)ldata), (uint32)0, (ushort)1, (NODELIST *)0); + } + break; + + case MBX_READ_LA: + case MBX_READ_LA64: + { + READ_LA_VAR la; + MATCHMAP * mp; + + if (binfo->fc_flag & FC_SLI2) { + /* First copy command data */ + mb = FC_SLI2_MAILBOX(binfo); + fc_pcimem_bcopy((uint32 * )((char *)mb + sizeof(uint32)), (uint32 * ) & la, + sizeof(READ_LA_VAR)); + } else { + /* First copy command data */ + ioa = (void *)FC_MAP_MEM(&binfo->fc_iomap_mem); /* map in SLIM */ + mb = FC_MAILBOX(binfo, ioa); + READ_SLIM_COPY(binfo, (uint32 * ) & la, + (uint32 * )((char *)mb + sizeof(uint32)), + (sizeof(READ_LA_VAR) / sizeof(uint32))); + FC_UNMAP_MEMIO(ioa); + } + + mp = (MATCHMAP * )binfo->fc_mbbp; + if(mp) { + fc_mpdata_sync(mp->dma_handle, 0, 128, DDI_DMA_SYNC_FORKERNEL); + fc_mpdata_outcopy(p_dev_ctl, mp, (uchar * )binfo->alpa_map, 128); + + binfo->fc_mbbp = 0; + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + } + + if (la.pb) + binfo->fc_flag |= FC_BYPASSED_MODE; + else + binfo->fc_flag &= ~FC_BYPASSED_MODE; + + if (((binfo->fc_eventTag + 1) < la.eventTag) || + (binfo->fc_eventTag == la.eventTag)) { + FCSTATCTR.LinkMultiEvent++; + if (la.attType == AT_LINK_UP) { + if (binfo->fc_eventTag != 0) { /* Pegasus */ + fc_linkdown(p_dev_ctl); + if (!(binfo->fc_flag & FC_LD_TIMER)) { + /* Start the link down watchdog timer until CLA done */ + rp = &binfo->fc_ring[FC_FCP_RING]; + RINGTMO = fc_clk_set(p_dev_ctl, rp->fc_ringtmo, + fc_linkdown_timeout, 0, 0); + if((clp[CFG_LINKDOWN_TMO].a_current == 0) || + clp[CFG_HOLDIO].a_current) { + binfo->fc_flag |= FC_LD_TIMEOUT; + } + binfo->fc_flag |= FC_LD_TIMER; + } + } + } + } + + binfo->fc_eventTag = la.eventTag; + + if (la.attType == AT_LINK_UP) { + FCSTATCTR.LinkUp++; + /* Link Up Event received */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk1304, /* ptr to msg structure */ + fc_mes1304, /* ptr to msg */ + fc_msgBlk1304.msgPreambleStr, /* begin varargs */ + la.eventTag, + binfo->fc_eventTag, + la.granted_AL_PA, + binfo->alpa_map[0] ); /* end varargs */ + if(clp[CFG_NETWORK_ON].a_current) { + /* Stop the link down watchdog timer */ + rp = &binfo->fc_ring[FC_IP_RING]; + if(RINGTMO) { + fc_clk_can(p_dev_ctl, RINGTMO); + RINGTMO = 0; + } + } + binfo->fc_ffstate = FC_LINK_UP; + binfo->fc_flag &= ~(FC_LNK_DOWN | FC_PT2PT | FC_PT2PT_PLOGI | + FC_LBIT | FC_RSCN_MODE | FC_NLP_MORE | FC_DELAY_DISC | + FC_RSCN_DISC_TMR | FC_RSCN_DISCOVERY); + binfo->fc_ns_retry = 0; + + if( la.UlnkSpeed == LA_2GHZ_LINK) + binfo->fc_linkspeed = LA_2GHZ_LINK; + else + binfo->fc_linkspeed = 0; + + if ((binfo->fc_topology = la.topology) == TOPOLOGY_LOOP) { + + if (la.il) { + binfo->fc_flag |= FC_LBIT; + fc_freenode_did(binfo, Fabric_DID, 1); + } + + binfo->fc_myDID = la.granted_AL_PA; + + dfc_hba_put_event(p_dev_ctl, HBA_EVENT_LINK_UP, binfo->fc_myDID, + la.topology, la.lipType, la.UlnkSpeed); + dfc_put_event(p_dev_ctl, FC_REG_LINK_EVENT, 0, 0, 0); + + if (binfo->fc_flag & FC_SLI2) { + i = la.un.lilpBde64.tus.f.bdeSize; + } else { + i = la.un.lilpBde.bdeSize; + } + if (i == 0) { + binfo->alpa_map[0] = 0; + } else { + if(clp[CFG_LOG_VERBOSE].a_current & DBG_LINK_EVENT) { + int numalpa, j, k; + union { + uchar pamap[16]; + struct { + uint32 wd1; + uint32 wd2; + uint32 wd3; + uint32 wd4; + } pa; + } un; + + numalpa = binfo->alpa_map[0]; + j = 0; + while (j < numalpa) { + fc_bzero(un.pamap, 16); + for (k = 1; j < numalpa; k++) { + un.pamap[k-1] = binfo->alpa_map[j+1]; + j++; + if (k == 16) + break; + } + /* Link Up Event ALPA map */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk1305, /* ptr to msg structure */ + fc_mes1305, /* ptr to msg */ + fc_msgBlk1305.msgPreambleStr, /* begin varargs */ + un.pa.wd1, + un.pa.wd2, + un.pa.wd3, + un.pa.wd4 ); /* end varargs */ + } + } + } + } else { + fc_freenode_did(binfo, Fabric_DID, 1); + + binfo->fc_myDID = binfo->fc_pref_DID; + + dfc_hba_put_event(p_dev_ctl, HBA_EVENT_LINK_UP, binfo->fc_myDID, + la.topology, la.lipType, la.UlnkSpeed); + dfc_put_event(p_dev_ctl, FC_REG_LINK_EVENT, 0, 0, 0); + } + + if ((mbox = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + /* This should turn on DELAYED ABTS for ELS timeouts */ + fc_set_slim(binfo, (MAILBOX * )mbox, 0x052198, 0x1); + /* unreg_login mailbox command could be executing, + * queue this command to be processed later. + */ + fc_mbox_put(binfo, mbox); + } + + if ((mbox = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + if(fc_read_sparam(p_dev_ctl, (MAILBOX * )mbox) == 0) { + /* set_slim mailbox command needs to execute first, + * queue this command to be processed later. + */ + fc_mbox_put(binfo, mbox); + } else { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mbox); + } + } + if ((mbox = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + binfo->fc_ffstate = FC_CFG_LINK; + fc_config_link(p_dev_ctl, (MAILBOX * )mbox); + /* read_sparam mailbox command needs to execute first, + * queue this command to be processed later. + */ + fc_mbox_put(binfo, mbox); + } + + + } /* end if link up */ + else { + FCSTATCTR.LinkDown++; + dfc_hba_put_event(p_dev_ctl, HBA_EVENT_LINK_DOWN, binfo->fc_myDID, + la.topology, la.lipType, la.UlnkSpeed); + dfc_put_event(p_dev_ctl, FC_REG_LINK_EVENT, 0, 0, 0); + /* Link Down Event received */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk1306, /* ptr to msg structure */ + fc_mes1306, /* ptr to msg */ + fc_msgBlk1306.msgPreambleStr, /* begin varargs */ + la.eventTag, + binfo->fc_eventTag, + la.granted_AL_PA, + binfo->alpa_map[0] ); /* end varargs */ + fc_linkdown(p_dev_ctl); + + if (!(binfo->fc_flag & FC_LD_TIMER)) { + /* Start the link down watchdog timer until CLA done */ + rp = &binfo->fc_ring[FC_FCP_RING]; + RINGTMO = fc_clk_set(p_dev_ctl, rp->fc_ringtmo, + fc_linkdown_timeout, 0, 0); + if((clp[CFG_LINKDOWN_TMO].a_current == 0) || + clp[CFG_HOLDIO].a_current) { + binfo->fc_flag |= FC_LD_TIMEOUT; + } + binfo->fc_flag |= FC_LD_TIMER; + } + + /* turn on Link Attention interrupts - no CLEAR_LA needed */ + binfo->fc_process_LA = 1; + ioa = (void *)FC_MAP_IO(&binfo->fc_iomap_io); /* map in io registers */ + control = READ_CSR_REG(binfo, FC_HC_REG(binfo, ioa)); + control |= HC_LAINT_ENA; + WRITE_CSR_REG(binfo, FC_HC_REG(binfo, ioa), control); + FC_UNMAP_MEMIO(ioa); + } + break; + } + + case MBX_CLEAR_LA: + /* Turn on Link Attention interrupts */ + binfo->fc_process_LA = 1; + + ioa = (void *)FC_MAP_IO(&binfo->fc_iomap_io); /* map in io registers */ + control = READ_CSR_REG(binfo, FC_HC_REG(binfo, ioa)); + control |= HC_LAINT_ENA; + WRITE_CSR_REG(binfo, FC_HC_REG(binfo, ioa), control); + FC_UNMAP_MEMIO(ioa); + + if ((!(binfo->fc_flag & FC_LNK_DOWN)) && + (binfo->fc_ffstate != FC_ERROR) && + (mb->mbxStatus != 0x1601)) { /* Link is Up */ + + if (!(binfo->fc_flag & FC_PT2PT)) { + /* Device Discovery completes */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0234, /* ptr to msg structure */ + fc_mes0234, /* ptr to msg */ + fc_msgBlk0234.msgPreambleStr); /* begin & end varargs */ + binfo->fc_nlp_cnt = 0; /* In case we need to do RSCNs */ + binfo->fc_firstopen = 0; + + /* Fix up any changed RPIs in FCP IOCBs queued up a txq */ + fc_fcp_fix_txq(p_dev_ctl); + + binfo->fc_ffstate = FC_READY; + + /* Check to see if we need to process an RSCN */ + if(binfo->fc_flag & FC_RSCN_MODE) { + fc_nextrscn(p_dev_ctl, fc_max_els_sent); + } + } + + /* Do FDMI to Register HBA and port */ + if ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, FDMI_DID))) { + if (fc_fdmi_cmd(p_dev_ctl, ndlp, SLI_MGMT_DPRT)) { + /* Issue FDMI request failed */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0219, /* ptr to msg structure */ + fc_mes0219, /* ptr to msg */ + fc_msgBlk0219.msgPreambleStr, /* begin varargs */ + SLI_MGMT_DPRT ); /* end varargs */ + } + } + + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) { + new_ndlp = (NODELIST *)ndlp->nlp_listp_next; + + /* skip myself, fabric nodes and partially logged in nodes */ + if ((ndlp->nlp_DID == binfo->fc_myDID) || + (ndlp->nlp_type & NLP_FABRIC) || + (ndlp->nlp_state != NLP_ALLOC)) + goto loop1; + + /* Allocate exchanges for all IP (non-FCP) nodes */ + if ((ndlp->nlp_Rpi) && + (ndlp->nlp_Xri == 0) && + ((ndlp->nlp_DID & CT_DID_MASK) != CT_DID_MASK) && + !(ndlp->nlp_flag & NLP_RPI_XRI) && + !(ndlp->nlp_type & NLP_FCP_TARGET)) { + ndlp->nlp_flag |= NLP_RPI_XRI; + fc_create_xri(binfo, &binfo->fc_ring[FC_ELS_RING], ndlp); + } + + if (ndlp->nlp_type & NLP_FCP_TARGET) { + int dev_index; + + dev_index = INDEX(ndlp->id.nlp_pan, ndlp->id.nlp_sid); + node_ptr = binfo->device_queue_hash[dev_index].node_ptr; + if(node_ptr) { + /* This is a new device that entered the loop */ + node_ptr->nlp = ndlp; + node_ptr->rpi = ndlp->nlp_Rpi; + node_ptr->last_good_rpi = ndlp->nlp_Rpi; + node_ptr->scsi_id = dev_index; + ndlp->nlp_targetp = (uchar *)node_ptr; + node_ptr->flags &= ~FC_NODEV_TMO; + ndlp->nlp_flag &= ~NLP_NODEV_TMO; + } + } + + if (ndlp->nlp_type & NLP_IP_NODE) { + fc_restartio(p_dev_ctl, ndlp); + } +loop1: + ndlp = new_ndlp; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + } + + /* If we are not point to point, reglogin to ourself */ + if (!(binfo->fc_flag & FC_PT2PT)) { + /* Build nlplist entry and Register login to ourself */ + if ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, binfo->fc_myDID))) { + ndlp->nlp_DID = binfo->fc_myDID; + fc_nlp_logi(binfo, ndlp, &(binfo->fc_portname), &(binfo->fc_nodename)); + } + else { + if((ndlp = (NODELIST *)fc_mem_get(binfo, MEM_NLP))) { + fc_bzero((void *)ndlp, sizeof(NODELIST)); + ndlp->sync = binfo->fc_sync; + ndlp->capabilities = binfo->fc_capabilities; + ndlp->nlp_DID = binfo->fc_myDID; + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + fc_nlp_logi(binfo, ndlp, &(binfo->fc_portname), &(binfo->fc_nodename)); + } + } + if(ndlp) { + if ((mbox = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))){ + fc_reg_login(binfo, binfo->fc_myDID, + (uchar * ) & binfo->fc_sparam, (MAILBOX * )mbox, 0); + if (issue_mb_cmd(binfo, (MAILBOX * )mbox, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mbox); + } + } + } + } else { + /* We are pt2pt no fabric */ + if (binfo->fc_flag & FC_PT2PT_PLOGI) { + /* Build nlplist entry and Register login to ourself */ + if ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, binfo->fc_myDID))) { + ndlp->nlp_DID = binfo->fc_myDID; + fc_nlp_logi(binfo, ndlp, &(binfo->fc_portname), &(binfo->fc_nodename)); + } + else { + if((ndlp = (NODELIST *)fc_mem_get(binfo, MEM_NLP))) { + fc_bzero((void *)ndlp, sizeof(NODELIST)); + ndlp->sync = binfo->fc_sync; + ndlp->capabilities = binfo->fc_capabilities; + ndlp->nlp_DID = binfo->fc_myDID; + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + fc_nlp_logi(binfo, ndlp, &(binfo->fc_portname), &(binfo->fc_nodename)); + } + } + if(ndlp) { + if ((mbox = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))){ + fc_reg_login(binfo, binfo->fc_myDID, + (uchar * ) & binfo->fc_sparam, (MAILBOX * )mbox, 0); + if (issue_mb_cmd(binfo, (MAILBOX * )mbox, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mbox); + } + } + fc_els_cmd(binfo, ELS_CMD_PLOGI, (void *)PT2PT_RemoteID, + (uint32)0, (ushort)0, (NODELIST *)0); + } + } + } + + if(binfo->fc_flag & FC_ESTABLISH_LINK) { + binfo->fc_flag &= ~FC_ESTABLISH_LINK; + } + + if(p_dev_ctl->fc_estabtmo) { + fc_clk_can(p_dev_ctl, p_dev_ctl->fc_estabtmo); + p_dev_ctl->fc_estabtmo = 0; + } + + if(((clp[CFG_LINKDOWN_TMO].a_current == 0) || + clp[CFG_HOLDIO].a_current) && + (binfo->fc_flag & FC_LD_TIMEOUT)) { + fc_failio(p_dev_ctl); + } + + /* Stop the link down watchdog timer */ + rp = &binfo->fc_ring[FC_FCP_RING]; + if(RINGTMO) { + fc_clk_can(p_dev_ctl, RINGTMO); + RINGTMO = 0; + } + binfo->fc_flag &= ~(FC_LD_TIMEOUT | FC_LD_TIMER); + + if(clp[CFG_FCP_ON].a_current) { + fc_restart_all_devices(p_dev_ctl); + + /* Call iodone for any commands that timed out previously */ + for (bp = p_dev_ctl->timeout_head; bp != NULL; ) { + nextbp = bp->av_forw; + bp->b_error = ETIMEDOUT; + bp->b_flags |= B_ERROR; + bp->b_resid = bp->b_bcount; + FCSTATCTR.fcpScsiTmo++; + fc_do_iodone(bp); + bp = nextbp; + } + p_dev_ctl->timeout_count = 0; + p_dev_ctl->timeout_head = NULL; + + /* Send down any saved FCP commands */ + fc_issue_cmd(p_dev_ctl); + } + + if (binfo->fc_deferip) { + handle_ring_event(p_dev_ctl, FC_IP_RING, + (uint32)binfo->fc_deferip); + binfo->fc_deferip = 0; + } + } + break; + + default: + /* Unknown Mailbox command completion */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0312, /* ptr to msg structure */ + fc_mes0312, /* ptr to msg */ + fc_msgBlk0312.msgPreambleStr, /* begin varargs */ + cmd ); /* end varargs */ + FCSTATCTR.mboxCmdInval++; + break; + } + + binfo->fc_mbbp = 0; + return(0); +} /* End handle_mb_cmd */ + + +/**************************************************/ +/** fc_linkdown **/ +/** **/ +/** Description: Process a Link Down event. **/ +/** Called from host_intupt to process LinkDown **/ +/** **/ +/** Returns: **/ +/** **/ +/**************************************************/ +_static_ int +fc_linkdown( +fc_dev_ctl_t *p_dev_ctl) +{ + FC_BRD_INFO * binfo; + iCfgParam * clp; + RING * rp; + NODELIST * ndlp; + NODELIST * new_ndlp; + MAILBOXQ * mb; + IOCBQ * xmitiq; + IOCBQ * iocbq; + MATCHMAP * mp; + ULP_BDE64 * addr; + + binfo = &BINFO; + binfo->fc_prevDID = binfo->fc_myDID; + binfo->fc_ffstate = FC_LINK_DOWN; + binfo->fc_flag |= FC_LNK_DOWN; + binfo->fc_flag &= ~FC_DELAY_PLOGI; + + + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + fc_unreg_did(binfo, 0xffffffff, (MAILBOX * )mb); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + + /* Free all nodes in nlplist */ + ndlp = binfo->fc_nlpbind_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) { + new_ndlp = (NODELIST *)ndlp->nlp_listp_next; + + /* Any RSCNs in progress don't matter at this point */ + ndlp->nlp_action &= ~NLP_DO_RSCN; + + if ((ndlp->nlp_type & NLP_IP_NODE) && ndlp->nlp_bp) { + m_freem((fcipbuf_t *)ndlp->nlp_bp); + ndlp->nlp_bp = (uchar * )0; + } + + /* Need to abort all exchanges, used only on IP */ + if (ndlp->nlp_Xri) { + fc_rpi_abortxri(binfo, ndlp->nlp_Xri); + ndlp->nlp_Xri = 0; + } + + /* Need to free all nodes in the process of login / registration + * as well as all Fabric nodes and myself. + */ + if ((ndlp->nlp_DID == binfo->fc_myDID) || + (!(ndlp->nlp_type & NLP_FABRIC) && ((ndlp->nlp_DID & CT_DID_MASK) == CT_DID_MASK)) || + (binfo->fc_flag & FC_PT2PT) || + (ndlp->nlp_state < NLP_ALLOC)) { + NAME_TYPE zero_pn; + + fc_bzero((void *)&zero_pn, sizeof(NAME_TYPE)); + if ((fc_geportname(&ndlp->nlp_portname, &zero_pn) == 2) && + (ndlp->nlp_state < NLP_LOGIN) && + ((ndlp->nlp_type & (NLP_AUTOMAP | NLP_SEED_MASK)) == 0)) { + fc_freenode(binfo, ndlp, 1); + } + else { + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + } + } + + /* If we are not using ADISC, free fcp nodes here to avoid excessive + * actitivity when during PLOGIs when link comes back up. + */ + clp = DD_CTL.p_config[binfo->fc_brd_no]; + if((ndlp->nlp_state == NLP_ALLOC) && + (ndlp->nlp_type & NLP_FCP_TARGET) && + ((!clp[CFG_USE_ADISC].a_current))) { + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + } + + /* Any Discovery in progress doesn't matter at this point */ + ndlp->nlp_action &= ~(NLP_DO_ADDR_AUTH | NLP_DO_DISC_START); + + ndlp = new_ndlp; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + } + + if (binfo->fc_flag & FC_PT2PT) { + binfo->fc_myDID = 0; + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + fc_config_link(p_dev_ctl, (MAILBOX * )mb); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + binfo->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI); + } + + clp = DD_CTL.p_config[binfo->fc_brd_no]; + if(clp[CFG_NETWORK_ON].a_current) { + rp = &binfo->fc_ring[FC_IP_RING]; + /* flush all xmit compls */ + while ((xmitiq = fc_ringtxp_get(rp, 0)) != 0) { + fc_freebufq(p_dev_ctl, rp, xmitiq); + } + NDDSTAT.ndd_xmitque_cur = 0; + } + + + fc_flush_clk_set(p_dev_ctl, fc_delay_timeout); + + if(FABRICTMO) { + fc_clk_can(p_dev_ctl, FABRICTMO); + FABRICTMO = 0; + } + + if(binfo->fc_rscn_disc_wdt) { + fc_clk_can(p_dev_ctl, binfo->fc_rscn_disc_wdt); + binfo->fc_rscn_disc_wdt = 0; + } + binfo->fc_flag &= ~(FC_RSCN_MODE | FC_RSCN_DISC_TMR | FC_RSCN_DISCOVERY); + binfo->fc_rscn_id_cnt = 0; + + /* Free any deferred RSCNs */ + fc_flush_rscn_defer(p_dev_ctl); + + /* Free any delayed ELS xmits */ + fc_abort_delay_els_cmd(p_dev_ctl, 0xffffffff); + + /* Look through ELS ring and remove any ELS cmds in progress */ + rp = &binfo->fc_ring[FC_ELS_RING]; + iocbq = (IOCBQ * )(rp->fc_txp.q_first); + while (iocbq) { + iocbq->retry = 0xff; /* Mark for abort */ + iocbq = (IOCBQ * )iocbq->q; + } + + if (rp->fc_tx.q_cnt) { + IOCB * icmd; + /* get next command from ring xmit queue */ + xmitiq = fc_ringtx_get(rp); + + while (xmitiq) { + icmd = &xmitiq->iocb; + if (icmd->ulpCommand == CMD_IOCB_CONTINUE_CN) { + fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq); + xmitiq = fc_ringtx_get(rp); + continue; + } + + if(xmitiq->bp) { + fc_mem_put(binfo, MEM_BUF, (uchar * )xmitiq->bp); + } + + if (binfo->fc_flag & FC_SLI2) { + + mp = (MATCHMAP *)xmitiq->bpl; + if(mp) { + addr = (ULP_BDE64 * )mp->virt; + addr++; /* goto the next one */ + + switch (icmd->ulpCommand) { + case CMD_ELS_REQUEST_CR: + case CMD_ELS_REQUEST64_CR: + case CMD_ELS_REQUEST_CX: + case CMD_ELS_REQUEST64_CX: + fc_mem_put(binfo, MEM_BUF, (uchar * )xmitiq->info); + break; + default: + if(xmitiq->info) + fc_mem_put(binfo, MEM_BUF, (uchar * )xmitiq->info); + } + fc_mem_put(binfo, MEM_BPL, (uchar * )mp); + } + } + else { + if (icmd->un.cont[1].bdeAddress) { + fc_mem_put(binfo, MEM_BUF, (uchar * )xmitiq->info); + } + } + fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq); + xmitiq = fc_ringtx_get(rp); + } + } + + return(0); +} /* End fc_linkdown */ + +/**************************************************/ +/** fc_rlip **/ +/** **/ +/** Description: **/ +/** Called to reset the link with an init_link **/ +/** **/ +/** Returns: **/ +/** **/ +/**************************************************/ +_static_ int +fc_rlip( +fc_dev_ctl_t *p_dev_ctl) +{ + FC_BRD_INFO * binfo; + iCfgParam * clp; + MAILBOX * mb; + + binfo = &BINFO; + + /* Start the Fibre Channel reset LIP process */ + if (binfo->fc_ffstate == FC_READY) { + /* Get a buffer to use for the mailbox command */ + if ((mb = (MAILBOX * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI)) == NULL) { + /* Device Discovery completion error */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0235, /* ptr to msg structure */ + fc_mes0235, /* ptr to msg */ + fc_msgBlk0235.msgPreambleStr); /* begin & end varargs */ + binfo->fc_ffstate = FC_ERROR; + return(1); + } + + binfo->fc_flag |= FC_SCSI_RLIP; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + + /* Setup and issue mailbox INITIALIZE LINK command */ + fc_linkdown(p_dev_ctl); + fc_init_link(binfo, (MAILBOX * )mb, clp[CFG_TOPOLOGY].a_current, clp[CFG_LINK_SPEED].a_current); + mb->un.varInitLnk.lipsr_AL_PA = 0; + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) != MBX_BUSY) + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + /* SCSI Link Reset */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk1307, /* ptr to msg structure */ + fc_mes1307, /* ptr to msg */ + fc_msgBlk1307.msgPreambleStr); /* begin & end varargs */ + } + return(0); +} /* End fc_rlip */ + +/**************************************************/ +/** fc_ns_cmd **/ +/** **/ +/** Description: **/ +/** Issue Cmd to NameServer **/ +/** SLI_CTNS_GID_FT **/ +/** SLI_CTNS_RFT_ID **/ +/** **/ +/** Returns: **/ +/** **/ +/**************************************************/ +_static_ int +fc_ns_cmd( +fc_dev_ctl_t *p_dev_ctl, +NODELIST *ndlp, +int cmdcode) +{ + FC_BRD_INFO * binfo; + iCfgParam * clp; + MATCHMAP * mp, *bmp; + SLI_CT_REQUEST * CtReq; + ULP_BDE64 * bpl; + + binfo = &BINFO; + + /* fill in BDEs for command */ + /* Allocate buffer for command payload */ + if ((mp = (MATCHMAP * )fc_mem_get(binfo, MEM_BUF)) == 0) { + return(1); + } + + bmp = 0; + + /* Allocate buffer for Buffer ptr list */ + if ((bmp = (MATCHMAP * )fc_mem_get(binfo, MEM_BPL)) == 0) { + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + return(1); + } + bpl = (ULP_BDE64 * )bmp->virt; + bpl->addrHigh = PCIMEM_LONG((uint32)putPaddrHigh(mp->phys)); + bpl->addrLow = PCIMEM_LONG((uint32)putPaddrLow(mp->phys)); + bpl->tus.f.bdeFlags = 0; + if (cmdcode == SLI_CTNS_GID_FT) + bpl->tus.f.bdeSize = GID_REQUEST_SZ; + else if (cmdcode == SLI_CTNS_RFT_ID) + bpl->tus.f.bdeSize = RFT_REQUEST_SZ; + else + bpl->tus.f.bdeSize = 0; + bpl->tus.w = PCIMEM_LONG(bpl->tus.w); + + CtReq = (SLI_CT_REQUEST * )mp->virt; + /* NameServer Req */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0236, /* ptr to msg structure */ + fc_mes0236, /* ptr to msg */ + fc_msgBlk0236.msgPreambleStr, /* begin varargs */ + cmdcode, + binfo->fc_flag, + binfo->fc_rscn_id_cnt); /* end varargs */ + fc_bzero((void *)CtReq, sizeof(SLI_CT_REQUEST)); + + CtReq->RevisionId.bits.Revision = SLI_CT_REVISION; + CtReq->RevisionId.bits.InId = 0; + + CtReq->FsType = SLI_CT_DIRECTORY_SERVICE; + CtReq->FsSubType = SLI_CT_DIRECTORY_NAME_SERVER; + + CtReq->CommandResponse.bits.Size = 0; + switch (cmdcode) { + case SLI_CTNS_GID_FT: + CtReq->CommandResponse.bits.CmdRsp = SWAP_DATA16(SLI_CTNS_GID_FT); + CtReq->un.gid.Fc4Type = SLI_CTPT_FCP; + if(binfo->fc_ffstate != FC_READY) + binfo->fc_ffstate = FC_NS_QRY; + break; + case SLI_CTNS_RFT_ID: + clp = DD_CTL.p_config[binfo->fc_brd_no]; + CtReq->CommandResponse.bits.CmdRsp = SWAP_DATA16(SLI_CTNS_RFT_ID); + CtReq->un.rft.PortId = SWAP_DATA(binfo->fc_myDID); + if(clp[CFG_FCP_ON].a_current) { + CtReq->un.rft.fcpReg = 1; + } + if(clp[CFG_NETWORK_ON].a_current) { + CtReq->un.rft.ipReg = 1; + } + if(binfo->fc_ffstate != FC_READY) + binfo->fc_ffstate = FC_NS_REG; + break; + } + + binfo->fc_ns_retry++; + if(FABRICTMO) { + fc_clk_can(p_dev_ctl, FABRICTMO); + } + FABRICTMO = fc_clk_set(p_dev_ctl, binfo->fc_ratov, + fc_fabric_timeout, 0, 0); + + if(fc_ct_cmd(p_dev_ctl, mp, bmp, ndlp)) { + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + fc_mem_put(binfo, MEM_BPL, (uchar * )bmp); + } + return(0); +} /* End fc_ns_cmd */ + +_static_ int +fc_free_ct_rsp( +fc_dev_ctl_t * p_dev_ctl, +MATCHMAP * mlist) +{ + FC_BRD_INFO * binfo; + MATCHMAP * mlast; + + binfo = &BINFO; + while(mlist) { + mlast = mlist; + mlist = (MATCHMAP *)mlist->fc_mptr; + + fc_mem_put(binfo, MEM_BUF, (uchar * )mlast); + } + return(0); +} + +_local_ MATCHMAP * +fc_alloc_ct_rsp( +fc_dev_ctl_t * p_dev_ctl, +ULP_BDE64 * bpl, +uint32 size, +int * entries) +{ + FC_BRD_INFO * binfo; + MATCHMAP * mlist; + MATCHMAP * mlast; + MATCHMAP * mp; + int cnt, i; + + binfo = &BINFO; + mlist = 0; + mlast = 0; + i = 0; + + while(size) { + + /* We get chucks of FCELSSIZE */ + if(size > FCELSSIZE) + cnt = FCELSSIZE; + else + cnt = size; + + /* Allocate buffer for rsp payload */ + if ((mp = (MATCHMAP * )fc_mem_get(binfo, MEM_BUF)) == 0) { + fc_free_ct_rsp(p_dev_ctl, mlist); + return(0); + } + + /* Queue it to a linked list */ + if(mlast == 0) { + mlist = mp; + mlast = mp; + } + else { + mlast->fc_mptr = (uchar *)mp; + mlast = mp; + } + mp->fc_mptr = 0; + + bpl->tus.f.bdeFlags = BUFF_USE_RCV; + + /* build buffer ptr list for IOCB */ + bpl->addrLow = PCIMEM_LONG(putPaddrLow((ulong)mp->phys)); + bpl->addrHigh = PCIMEM_LONG(putPaddrHigh((ulong)mp->phys)); + bpl->tus.f.bdeSize = (ushort)cnt; + bpl->tus.w = PCIMEM_LONG(bpl->tus.w); + bpl++; + + i++; + size -= cnt; + } + + *entries = i; + return(mlist); +} + +_static_ int +fc_ct_cmd( +fc_dev_ctl_t *p_dev_ctl, +MATCHMAP *inmp, +MATCHMAP *bmp, +NODELIST *ndlp) +{ + FC_BRD_INFO * binfo; + ULP_BDE64 * bpl; + MATCHMAP * outmp; + int cnt; + + binfo = &BINFO; + bpl = (ULP_BDE64 * )bmp->virt; + bpl++; /* Skip past ct request */ + + cnt = 0; + /* Put buffer(s) for ct rsp in bpl */ + if((outmp = fc_alloc_ct_rsp(p_dev_ctl, bpl, FC_MAX_NS_RSP, &cnt)) == 0) { + return(ENOMEM); + } + + /* save ndlp for cmpl */ + inmp->fc_mptr = (uchar *)ndlp; + + if((fc_gen_req(binfo, bmp, inmp, outmp, ndlp->nlp_Rpi, 0, (cnt+1), 0))) { + fc_free_ct_rsp(p_dev_ctl, outmp); + return(ENOMEM); + } + return(0); +} /* End fc_ct_cmd */ + + +/**************************************************/ +/** fc_ns_rsp **/ +/** **/ +/** Description: **/ +/** Process NameServer response **/ +/** **/ +/** Returns: **/ +/** **/ +/**************************************************/ +_static_ int +fc_ns_rsp( +fc_dev_ctl_t *p_dev_ctl, +NODELIST *nslp, +MATCHMAP *mp, +uint32 Size) +{ + FC_BRD_INFO * binfo; + SLI_CT_REQUEST * Response; + NODELIST * ndlp; + NODELIST * new_ndlp; + MATCHMAP * mlast; + D_ID rscn_did; + D_ID ns_did; + uint32 * tptr; + uint32 Did; + uint32 Temp; + int j, Cnt, match, new_node; + + binfo = &BINFO; + ndlp = 0; + binfo->fc_ns_retry = 0; + + binfo->fc_fabrictmo = (2 * binfo->fc_ratov) + + ((4 * binfo->fc_edtov) / 1000) + 1; + if(FABRICTMO) { + fc_clk_can(p_dev_ctl, FABRICTMO); + FABRICTMO = 0; + } + + Response = (SLI_CT_REQUEST * )mp->virt; + + if ((Response->CommandResponse.bits.CmdRsp == SWAP_DATA16(SLI_CT_RESPONSE_FS_ACC)) && + ((binfo->fc_ffstate == FC_NS_QRY) || + ((binfo->fc_ffstate == FC_READY) && (binfo->fc_flag & FC_RSCN_MODE)))) { + + tptr = (uint32 * ) & Response->un.gid.PortType; + while(mp) { + mlast = mp; + mp = (MATCHMAP *)mp->fc_mptr; + fc_mpdata_sync(mlast->dma_handle, 0, 0, DDI_DMA_SYNC_FORKERNEL); + + if(Size > FCELSSIZE) + Cnt = FCELSSIZE; + else + Cnt = Size; + Size -= Cnt; + + if(tptr == 0) + tptr = (uint32 * )mlast->virt; + else + Cnt -= 16; /* subtract length of CT header */ + + while(Cnt) { + /* Loop through entire NameServer list of DIDs */ + + /* Get next DID from NameServer List */ + Temp = *tptr++; + Did = (SWAP_DATA(Temp) & Mask_DID); + + ndlp = 0; + if ((Did) && (Did != binfo->fc_myDID)) { + new_node = 0; + ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, Did); + if(ndlp) { + ndlp->nlp_DID = Did; + /* Skip nodes already marked for discovery / rscn */ + if(ndlp->nlp_action & + (NLP_DO_ADDR_AUTH | NLP_DO_DISC_START | NLP_DO_RSCN)) + goto nsout; + } + else { + new_node = 1; + if((ndlp = (NODELIST *)fc_mem_get(binfo, MEM_NLP))) { + fc_bzero((void *)ndlp, sizeof(NODELIST)); + ndlp->sync = binfo->fc_sync; + ndlp->capabilities = binfo->fc_capabilities; + ndlp->nlp_DID = Did; + fc_nlp_bind(binfo, ndlp); + } + else + goto nsout; + } + + if ((new_node) || + (!(ndlp->nlp_flag & NLP_REQ_SND) && + (ndlp->nlp_state < NLP_ALLOC)) ) { + + if ((binfo->fc_ffstate == FC_READY) && + (binfo->fc_flag & FC_RSCN_MODE)) { + /* we are in RSCN node, so match Did from NameServer with + * with list recieved from previous RSCN commands. + * Do NOT add it to our RSCN discovery list unless we have + * a match. + */ + match = 0; + for(j=0;jfc_rscn_id_cnt;j++) { + + rscn_did.un.word = binfo->fc_rscn_id_list[j]; + ns_did.un.word = Did; + + switch (rscn_did.un.b.resv) { + case 0: /* Single N_Port ID effected */ + if (ns_did.un.word == rscn_did.un.word) { + match = 1; + } + break; + + case 1: /* Whole N_Port Area effected */ + if ((ns_did.un.b.domain == rscn_did.un.b.domain) && + (ns_did.un.b.area == rscn_did.un.b.area)) { + match = 1; + } + break; + + case 2: /* Whole N_Port Domain effected */ + if (ns_did.un.b.domain == rscn_did.un.b.domain) { + match = 1; + } + break; + + case 3: /* Whole Fabric effected */ + match = 1; + break; + + default: + /* Unknown Identifier in RSCN list */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0237, /* ptr to msg structure */ + fc_mes0237, /* ptr to msg */ + fc_msgBlk0237.msgPreambleStr, /* begin varargs */ + rscn_did.un.word); /* end varargs */ + break; + + } + if(match) + break; + } + if(match == 0) /* Skip it */ + goto nsout; + } + + /* Add it to our discovery list */ + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + if ((binfo->fc_ffstate == FC_READY) && + (binfo->fc_flag & FC_RSCN_MODE)) { + ndlp->nlp_action |= NLP_DO_RSCN; + ndlp->nlp_flag &= ~NLP_NODEV_TMO; + } + else { + ndlp->nlp_action |= NLP_DO_DISC_START; + } + } + else { + if (binfo->fc_ffstate < FC_READY) { + /* Add it to our discovery list */ + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + ndlp->nlp_action |= NLP_DO_DISC_START; + } + } + } +nsout: + + /* Mark all node table entries that are in the Nameserver */ + if(ndlp) { + ndlp->nlp_flag |= NLP_NS_NODE; + ndlp->nlp_flag &= ~NLP_NS_REMOVED; + /* NameServer Rsp */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0238, /* ptr to msg structure */ + fc_mes0238, /* ptr to msg */ + fc_msgBlk0238.msgPreambleStr, /* begin varargs */ + Did, + ndlp->nlp_flag, + binfo->fc_flag, + binfo->fc_rscn_id_cnt); /* end varargs */ + } + else { + /* NameServer Rsp */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0239, /* ptr to msg structure */ + fc_mes0239, /* ptr to msg */ + fc_msgBlk0239.msgPreambleStr, /* begin varargs */ + Did, + (ulong)ndlp, + binfo->fc_flag, + binfo->fc_rscn_id_cnt); /* end varargs */ + } + + if (Temp & SWAP_DATA(SLI_CT_LAST_ENTRY)) + goto nsout1; + Cnt -= sizeof(uint32); + } + tptr = 0; + } + +nsout1: + /* Take out all node table entries that are not in the NameServer */ + ndlp = binfo->fc_nlpbind_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) { + new_ndlp = (NODELIST *)ndlp->nlp_listp_next; + if ( (ndlp->nlp_state == NLP_LIMBO) || + (ndlp->nlp_state == NLP_SEED) || + (ndlp->nlp_DID == binfo->fc_myDID) || + (ndlp->nlp_DID == NameServer_DID) || + (ndlp->nlp_DID == FDMI_DID) || + (ndlp->nlp_type & NLP_FABRIC) || + (ndlp->nlp_flag & NLP_NS_NODE)) { + if(ndlp->nlp_flag & NLP_NS_NODE) { + ndlp->nlp_flag &= ~NLP_NS_NODE; + } else { + if(ndlp->nlp_DID != NameServer_DID) + ndlp->nlp_action &= ~(NLP_DO_ADDR_AUTH | NLP_DO_DISC_START | NLP_DO_RSCN); + } + goto loop1; + } + if ((binfo->fc_ffstate == FC_READY) && + (binfo->fc_flag & FC_RSCN_MODE) && + !(ndlp->nlp_action & NLP_DO_RSCN)) + goto loop1; + + if ((ndlp->nlp_DID != 0) && !(ndlp->nlp_flag & NLP_NODEV_TMO)) { + RING * rp; + IOCBQ * iocbq; + /* Look through ELS ring and remove any ELS cmds in progress */ + rp = &binfo->fc_ring[FC_ELS_RING]; + iocbq = (IOCBQ * )(rp->fc_txp.q_first); + while (iocbq) { + if(iocbq->iocb.un.elsreq.remoteID == ndlp->nlp_DID) { + iocbq->retry = 0xff; /* Mark for abort */ + } + iocbq = (IOCBQ * )iocbq->q; + } + /* In case its on fc_delay_timeout list */ + fc_abort_delay_els_cmd(p_dev_ctl, ndlp->nlp_DID); + + ndlp->nlp_flag &= ~(NLP_REQ_SND | NLP_REQ_SND_ADISC); + } + + ndlp->nlp_action &= ~(NLP_DO_ADDR_AUTH | NLP_DO_DISC_START | NLP_DO_RSCN); + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + ndlp->nlp_flag |= NLP_NS_REMOVED; + ndlp->nlp_type &= ~(NLP_FABRIC | NLP_IP_NODE); +loop1: + ndlp = new_ndlp; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + } + + } else if ((Response->CommandResponse.bits.CmdRsp == SWAP_DATA16(SLI_CT_RESPONSE_FS_RJT)) && + ((binfo->fc_ffstate == FC_NS_QRY) || + ((binfo->fc_ffstate == FC_READY) && (binfo->fc_flag & FC_RSCN_MODE)))) { + /* NameServer Rsp Error */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0240, /* ptr to msg structure */ + fc_mes0240, /* ptr to msg */ + fc_msgBlk0240.msgPreambleStr, /* begin varargs */ + Response->CommandResponse.bits.CmdRsp, + (uint32)Response->ReasonCode, + (uint32)Response->Explanation, + binfo->fc_flag); /* end varargs */ + goto nsout1; + + } else { + /* NameServer Rsp Error */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0241, /* ptr to msg structure */ + fc_mes0241, /* ptr to msg */ + fc_msgBlk0241.msgPreambleStr, /* begin varargs */ + Response->CommandResponse.bits.CmdRsp, + (uint32)Response->ReasonCode, + (uint32)Response->Explanation, + binfo->fc_flag); /* end varargs */ + } + + if (binfo->fc_ffstate == FC_NS_REG) { + /* Issue GID_FT to Nameserver */ + if (fc_ns_cmd(p_dev_ctl, nslp, SLI_CTNS_GID_FT)) + goto out; + } else { +out: + /* Done with NameServer for now, but leave logged in */ + + /* We can start discovery right now */ + /* Fire out PLOGIs on all nodes marked for discovery */ + binfo->fc_rscn_id_cnt = 0; + if ((binfo->fc_nlp_cnt <= 0) && !(binfo->fc_flag & FC_NLP_MORE)) { + binfo->fc_nlp_cnt = 0; + if ((binfo->fc_ffstate == FC_READY) && + (binfo->fc_flag & FC_RSCN_MODE)) { + nslp->nlp_action &= ~(NLP_DO_ADDR_AUTH | NLP_DO_RSCN); + fc_nextrscn(p_dev_ctl, fc_max_els_sent); + } + else { + nslp->nlp_action |= NLP_DO_ADDR_AUTH; + fc_nextnode(p_dev_ctl, nslp); + } + } + else { + nslp->nlp_action |= NLP_DO_ADDR_AUTH; + fc_nextnode(p_dev_ctl, nslp); + } + } + return(0); +} /* End fc_ns_rsp */ + +/**************************************************/ +/** fc_free_clearq **/ +/** **/ +/** Description: **/ +/** Called to free all clearq bufs for a device **/ +/** **/ +/** Returns: **/ +/** **/ +/**************************************************/ +_static_ void +fc_free_clearq( +dvi_t *dev_ptr) +{ + struct buf *bp, *nextbp; + FC_BRD_INFO * binfo; + + binfo = &dev_ptr->nodep->ap->info; + + /* Call iodone for all the CLEARQ error bufs */ + for (bp = dev_ptr->clear_head; bp != NULL; ) { + dev_ptr->clear_count--; + nextbp = bp->av_forw; + FCSTATCTR.fcpScsiTmo++; + fc_do_iodone(bp); + bp = nextbp; + } + dev_ptr->clear_head = NULL; + dev_ptr->flags &= ~SCSI_TQ_HALTED & ~SCSI_TQ_CLEARING; + + fc_restart_device(dev_ptr); + return; +} /* End fc_free_clearq */ + + +/****************************************************/ +/** fc_nextnode **/ +/** **/ +/** Description: **/ +/** Called during discovery or rediscovery **/ +/** **/ +/** Returns: **/ +/** **/ +/****************************************************/ +_static_ int +fc_nextnode( +fc_dev_ctl_t *p_dev_ctl, +NODELIST *ndlp) +{ + FC_BRD_INFO * binfo; + node_t * node_ptr; + dvi_t * dev_ptr; + iCfgParam * clp; + + binfo = &BINFO; + binfo->fc_fabrictmo = (2 * binfo->fc_ratov) + + ((4 * binfo->fc_edtov) / 1000) + 1; + + clp = DD_CTL.p_config[binfo->fc_brd_no]; + + /* Device Discovery nextnode */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0242, /* ptr to msg structure */ + fc_mes0242, /* ptr to msg */ + fc_msgBlk0242.msgPreambleStr, /* begin varargs */ + (uint32)ndlp->nlp_state, + ndlp->nlp_DID, + (uint32)ndlp->nlp_flag, + binfo->fc_ffstate); /* end varargs */ + if (binfo->fc_flag & FC_FABRIC) { + if (binfo->fc_ffstate < FC_NS_QRY) { + return(0); + } + if ((binfo->fc_ffstate < FC_NODE_DISC) && binfo->fc_ns_retry) { + return(0); + } + } + + if(FABRICTMO) { + fc_clk_res(p_dev_ctl, binfo->fc_fabrictmo, FABRICTMO); + } + else { + FABRICTMO = fc_clk_set(p_dev_ctl, binfo->fc_fabrictmo, + fc_fabric_timeout, 0, 0); + } + + if ((ndlp->nlp_type & NLP_FCP_TARGET) && (ndlp->nlp_state == NLP_ALLOC)) { + if(clp[CFG_FIRST_CHECK].a_current) { + /* If we are an FCP node, update first_check flag for all LUNs */ + if ((node_ptr = (node_t * )ndlp->nlp_targetp) != NULL) { + for (dev_ptr = node_ptr->lunlist; dev_ptr != NULL; + dev_ptr = dev_ptr->next) { + dev_ptr->first_check = FIRST_CHECK_COND; + fc_device_changed(p_dev_ctl, dev_ptr); + } + } + } + } + + /* Check for ADISC Address Authentication */ + if (ndlp->nlp_action & NLP_DO_ADDR_AUTH) { + ndlp->nlp_flag &= ~(NLP_REQ_SND | NLP_REQ_SND_ADISC); + ndlp->nlp_action &= ~NLP_DO_ADDR_AUTH; + + if(ndlp->nlp_DID != NameServer_DID) + binfo->fc_nlp_cnt--; + + if (binfo->fc_nlp_cnt <= 0) { + /* If no nodes left to authenticate, redo discovery on any + * new nodes. + */ + if (fc_nextauth(p_dev_ctl, fc_max_els_sent) == 0) { + binfo->fc_nlp_cnt = 0; + fc_nextdisc(p_dev_ctl, fc_max_els_sent); + } + } else { + fc_nextauth(p_dev_ctl, 1); + } + + return(0); + } + + /* Check for RSCN Discovery */ + if (ndlp->nlp_action & NLP_DO_RSCN) { + ndlp->nlp_flag &= ~(NLP_REQ_SND | NLP_REQ_SND_ADISC); + ndlp->nlp_action &= ~NLP_DO_RSCN; + binfo->fc_nlp_cnt--; + if ((ndlp->nlp_type & NLP_IP_NODE) && ndlp->nlp_bp) { + m_freem((fcipbuf_t *)ndlp->nlp_bp); + ndlp->nlp_bp = (uchar * )0; + } + + if (ndlp->nlp_type & NLP_FCP_TARGET) { + node_t * node_ptr; + dvi_t * dev_ptr; + + if ((node_ptr = (node_t * )ndlp->nlp_targetp) != NULL) { + /* restart any I/Os on this node */ + for (dev_ptr = node_ptr->lunlist; + dev_ptr != NULL; dev_ptr = dev_ptr->next) { + dev_ptr->queue_state = HALTED; + } + } + } + + if (binfo->fc_nlp_cnt <= 0) { + binfo->fc_nlp_cnt = 0; + fc_nextrscn(p_dev_ctl, fc_max_els_sent); + } else { + fc_nextrscn(p_dev_ctl, 1); + } + } + + /* Check for Address Discovery */ + if ((ndlp->nlp_action & NLP_DO_DISC_START) || + (ndlp->nlp_flag & NLP_REQ_SND)) { + ndlp->nlp_flag &= ~NLP_REQ_SND; + ndlp->nlp_action &= ~NLP_DO_DISC_START; + binfo->fc_nlp_cnt--; + + if (binfo->fc_nlp_cnt <= 0) { + binfo->fc_nlp_cnt = 0; + fc_nextdisc(p_dev_ctl, fc_max_els_sent); + } else { + fc_nextdisc(p_dev_ctl, 1); + } + } + + return(0); +} /* End fc_nextnode */ + + +/****************************************************/ +/** fc_nextdisc **/ +/** **/ +/** Description: **/ +/** Called during discovery or rediscovery **/ +/** **/ +/** Returns: **/ +/** **/ +/****************************************************/ +_static_ int +fc_nextdisc( +fc_dev_ctl_t *p_dev_ctl, +int sndcnt) +{ + FC_BRD_INFO * binfo; + MAILBOXQ * mb; + NODELIST * ndlp; + NODELIST * new_ndlp; + int cnt, skip; + uint32 did; + + binfo = &BINFO; + /* Device Discovery nextdisc */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0243, /* ptr to msg structure */ + fc_mes0243, /* ptr to msg */ + fc_msgBlk0243.msgPreambleStr, /* begin varargs */ + binfo->fc_nlp_cnt, + sndcnt, + binfo->fc_mbox_active); /* end varargs */ + binfo->fc_ffstate = FC_NODE_DISC; + binfo->fc_fabrictmo = (2 * binfo->fc_ratov) + + ((4 * binfo->fc_edtov) / 1000) + 1; + if(FABRICTMO) { + fc_clk_res(p_dev_ctl, binfo->fc_fabrictmo, FABRICTMO); + } + else { + FABRICTMO = fc_clk_set(p_dev_ctl, binfo->fc_fabrictmo, + fc_fabric_timeout, 0, 0); + } + + /* For MAXREQ requests, we must make sure all outstanding Mailbox + * commands have been processed. This is to ensure UNREG_LOGINs + * complete before we try to relogin. + */ + if (sndcnt == fc_max_els_sent) { + if (binfo->fc_mbox_active) { + binfo->fc_flag |= FC_DELAY_PLOGI; + return(fc_max_els_sent); + } + } + + cnt = 0; + skip = 0; + binfo->fc_flag &= ~FC_NLP_MORE; + + /* We can start discovery right now */ + /* Fire out PLOGIs on all nodes marked for discovery */ + ndlp = binfo->fc_nlpbind_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) { + new_ndlp = (NODELIST *)ndlp->nlp_listp_next; + + if ((ndlp->nlp_action & NLP_DO_DISC_START) && + (ndlp->nlp_DID != NameServer_DID)) { + if(!(ndlp->nlp_flag & (NLP_REQ_SND | NLP_REG_INP | NLP_RM_ENTRY))) { + binfo->fc_nlp_cnt++; + did = ndlp->nlp_DID; + if(did == 0) + did = ndlp->nlp_oldDID; + /* Start discovery for this node */ + fc_els_cmd(binfo, ELS_CMD_PLOGI, (void *)((ulong)did), + (uint32)0, (ushort)0, ndlp); + cnt++; + + if ((binfo->fc_nlp_cnt >= fc_max_els_sent) || + (cnt == sndcnt)) { + binfo->fc_flag |= FC_NLP_MORE; + return(cnt); + } + } + else + skip++; + } + ndlp = new_ndlp; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + } + + if ((binfo->fc_nlp_cnt) || skip) + return(binfo->fc_nlp_cnt); + + /* This should turn off DELAYED ABTS for ELS timeouts */ + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX))) { + fc_set_slim(binfo, (MAILBOX * )mb, 0x052198, 0); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + + /* Nothing to authenticate, so CLEAR_LA right now */ + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + binfo->fc_ffstate = FC_CLEAR_LA; + fc_clear_la(binfo, (MAILBOX * )mb); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } else { + /* Device Discovery completion error */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0244, /* ptr to msg structure */ + fc_mes0244, /* ptr to msg */ + fc_msgBlk0244.msgPreambleStr); /* begin & end varargs */ + binfo->fc_ffstate = FC_ERROR; + } + + if(FABRICTMO) { + fc_clk_can(p_dev_ctl, FABRICTMO); + FABRICTMO = 0; + } + return(0); +} /* End fc_nextdisc */ + + +/****************************************************/ +/** fc_nextauth **/ +/** **/ +/** Description: **/ +/** Called during rediscovery **/ +/** **/ +/** Returns: **/ +/** **/ +/****************************************************/ +_static_ int +fc_nextauth( +fc_dev_ctl_t *p_dev_ctl, +int sndcnt) +{ + FC_BRD_INFO * binfo; + iCfgParam * clp; + NODELIST * ndlp; + NODELIST * new_ndlp; + int cnt; + + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + /* Device Discovery next authentication */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0245, /* ptr to msg structure */ + fc_mes0245, /* ptr to msg */ + fc_msgBlk0245.msgPreambleStr, /* begin varargs */ + binfo->fc_nlp_cnt, + sndcnt, + binfo->fc_mbox_active); /* end varargs */ + cnt = 0; + binfo->fc_flag &= ~FC_NLP_MORE; + binfo->fc_fabrictmo = (2 * binfo->fc_ratov) + + ((4 * binfo->fc_edtov) / 1000) + 1; + if(FABRICTMO) { + fc_clk_res(p_dev_ctl, binfo->fc_fabrictmo, FABRICTMO); + } + else { + FABRICTMO = fc_clk_set(p_dev_ctl, binfo->fc_fabrictmo, + fc_fabric_timeout, 0, 0); + } + + /* We can start rediscovery right now */ + /* Fire out ADISC on all nodes marked for addr_auth */ + + ndlp = binfo->fc_nlpbind_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) { + new_ndlp = (NODELIST *)ndlp->nlp_listp_next; + + if (ndlp->nlp_action & NLP_DO_ADDR_AUTH) { + if (ndlp->nlp_flag & (NLP_RM_ENTRY | NLP_REQ_SND_ADISC | + NLP_REQ_SND | NLP_REG_INP)) + goto loop1; + + if ((ndlp->nlp_type & NLP_FCP_TARGET) && + ((!clp[CFG_USE_ADISC].a_current) || (ndlp->nlp_Rpi == 0))) { + /* Force regular discovery on this node */ + ndlp->nlp_action &= ~NLP_DO_ADDR_AUTH; + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + ndlp->nlp_action |= NLP_DO_DISC_START; + goto loop1; + } else { + if ((ndlp->nlp_type & NLP_IP_NODE) && (ndlp->nlp_Rpi == 0)) { + /* Force regular discovery on this node */ + ndlp->nlp_action &= ~NLP_DO_ADDR_AUTH; + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + goto loop1; + } + } + + if((ndlp->nlp_type & (NLP_FCP_TARGET | NLP_IP_NODE)) == 0) { + /* Force regular discovery on this node */ + ndlp->nlp_action &= ~NLP_DO_ADDR_AUTH; + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + ndlp->nlp_action |= NLP_DO_DISC_START; + goto loop1; + } + + binfo->fc_nlp_cnt++; + /* Start authentication */ + fc_els_cmd(binfo, ELS_CMD_ADISC, (void *)((ulong)ndlp->nlp_DID), + (uint32)0, (ushort)0, ndlp); + cnt++; + if ((binfo->fc_nlp_cnt >= fc_max_els_sent) || + (cnt == sndcnt)) { + binfo->fc_flag |= FC_NLP_MORE; + return(cnt); + } + } +loop1: + ndlp = new_ndlp; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + } + + return(binfo->fc_nlp_cnt); +} /* End fc_nextauth */ + +/****************************************************/ +/** fc_nextrscn **/ +/** **/ +/** Description: **/ +/** Called during RSCN processing **/ +/** **/ +/** Returns: **/ +/** **/ +/****************************************************/ +_static_ int +fc_nextrscn( +fc_dev_ctl_t *p_dev_ctl, +int sndcnt) +{ + FC_BRD_INFO * binfo; + iCfgParam * clp; + NODELIST * ndlp; + NODELIST * new_ndlp; + MAILBOXQ * mb; + struct buf * bp, * nextbp; + RING * rp; + IOCBQ * xmitiq; + IOCB * iocb; + MATCHMAP * mp; + int i, j, cnt; + uint32 did; + + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + /* Device Discovery next RSCN */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0246, /* ptr to msg structure */ + fc_mes0246, /* ptr to msg */ + fc_msgBlk0246.msgPreambleStr, /* begin varargs */ + binfo->fc_nlp_cnt, + sndcnt, + binfo->fc_mbox_active, + binfo->fc_flag); /* end varargs */ + cnt = 0; + if (binfo->fc_flag & FC_RSCN_DISC_TMR) + goto out; + + /* Are we waiting for a NameServer Query to complete */ + if (binfo->fc_flag & FC_NSLOGI_TMR) + return(1); + + if (binfo->fc_mbox_active) { + binfo->fc_flag |= FC_DELAY_PLOGI; + return(1); + } + + binfo->fc_flag &= ~FC_NLP_MORE; + + if(FABRICTMO) { + fc_clk_res(p_dev_ctl, binfo->fc_fabrictmo, FABRICTMO); + } + else { + FABRICTMO = fc_clk_set(p_dev_ctl, binfo->fc_fabrictmo, + fc_fabric_timeout, 0, 0); + } + + /* We can start rediscovery right now */ + /* Fire out PLOGI on all nodes marked for rscn */ + ndlp = binfo->fc_nlpbind_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) { + new_ndlp = (NODELIST *)ndlp->nlp_listp_next; + + if (ndlp->nlp_action & NLP_DO_RSCN) { + if (ndlp->nlp_flag & (NLP_RM_ENTRY | NLP_REQ_SND_ADISC | + NLP_REQ_SND | NLP_REG_INP)) + goto loop2; + + did = ndlp->nlp_DID; + if(did == 0) { + did = ndlp->nlp_oldDID; + if(did == 0) + goto loop2; + } + + binfo->fc_nlp_cnt++; + + /* We are always using ADISC for RSCN validation */ + if ((ndlp->nlp_type & NLP_FCP_TARGET) && (ndlp->nlp_Rpi == 0)) { + /* Force regular discovery on this node */ + fc_els_cmd(binfo, ELS_CMD_PLOGI, (void *)((ulong)did), + (uint32)0, (ushort)0, ndlp); + } else { + if (((ndlp->nlp_type & NLP_IP_NODE) && (ndlp->nlp_Rpi == 0)) || + ((ndlp->nlp_type & (NLP_FCP_TARGET | NLP_IP_NODE)) == 0)) { + /* Force regular discovery on this node */ + fc_els_cmd(binfo, ELS_CMD_PLOGI, (void *)((ulong)did), + (uint32)0, (ushort)0, ndlp); + } + else { + fc_els_cmd(binfo, ELS_CMD_ADISC,(void *)((ulong)did), + (uint32)0, (ushort)0, ndlp); + } + } + cnt++; + if ((binfo->fc_nlp_cnt >= fc_max_els_sent) || + (cnt == sndcnt)) { + binfo->fc_flag |= FC_NLP_MORE; + return(cnt); + } + } +loop2: + ndlp = new_ndlp; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + } + + if (binfo->fc_nlp_cnt) + return(binfo->fc_nlp_cnt); + +out: + if (binfo->fc_flag & FC_RSCN_DISCOVERY) { + /* Discovery RSCN */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0247, /* ptr to msg structure */ + fc_mes0247, /* ptr to msg */ + fc_msgBlk0247.msgPreambleStr, /* begin varargs */ + binfo->fc_defer_rscn.q_cnt, + binfo->fc_flag, + (ulong)(binfo->fc_rscn_disc_wdt)); /* end varargs */ + if(binfo->fc_rscn_disc_wdt == 0) { + binfo->fc_rscn_disc_wdt = fc_clk_set(p_dev_ctl, + ((binfo->fc_edtov / 1000) + 1), fc_rscndisc_timeout, 0, 0); + /* Free any deferred RSCNs */ + fc_flush_rscn_defer(p_dev_ctl); + return(0); + } + + if(!(binfo->fc_flag & FC_RSCN_DISC_TMR)) + return(0); + + binfo->fc_flag &= ~(FC_RSCN_DISC_TMR | FC_RSCN_DISCOVERY); + binfo->fc_rscn_disc_wdt = 0; + + /* RSCN match on all DIDs in NameServer */ + binfo->fc_rscn_id_list[0] = 0x03000000; + binfo->fc_rscn_id_cnt = 1; + + /* Free any deferred RSCNs */ + fc_flush_rscn_defer(p_dev_ctl); + + /* Authenticate all nodes in nlplist */ + ndlp = binfo->fc_nlpbind_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) { + new_ndlp = (NODELIST *)ndlp->nlp_listp_next; + + /* Skip over FABRIC nodes and myself */ + if ((ndlp->nlp_DID == binfo->fc_myDID) || + (ndlp->nlp_type & NLP_FABRIC) || + ((ndlp->nlp_DID & CT_DID_MASK) == CT_DID_MASK)) + goto loop3; + + if (ndlp->nlp_state == NLP_ALLOC) { + /* Mark node for authentication */ + ndlp->nlp_action |= NLP_DO_RSCN; + ndlp->nlp_flag &= ~NLP_NODEV_TMO; + + /* We are always using ADISC for RSCN validation */ + } +loop3: + ndlp = new_ndlp; + if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start) + ndlp = binfo->fc_nlpunmap_start; + if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + ndlp = binfo->fc_nlpmap_start; + } + + fc_issue_ns_query(p_dev_ctl, (void *)0, (void *)0); + return(0); + } + + if (binfo->fc_defer_rscn.q_first) { + uint32 * lp; + D_ID rdid; + uint32 cmd; + + /* process any deferred RSCNs */ + /* Deferred RSCN */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0248, /* ptr to msg structure */ + fc_mes0248, /* ptr to msg */ + fc_msgBlk0248.msgPreambleStr, /* begin varargs */ + binfo->fc_defer_rscn.q_cnt, + binfo->fc_flag); /* end varargs */ + binfo->fc_rscn_id_cnt = 0; + rp = &binfo->fc_ring[FC_ELS_RING]; + while (binfo->fc_defer_rscn.q_first) { + xmitiq = (IOCBQ * )binfo->fc_defer_rscn.q_first; + if ((binfo->fc_defer_rscn.q_first = xmitiq->q) == 0) { + binfo->fc_defer_rscn.q_last = 0; + } + binfo->fc_defer_rscn.q_cnt--; + iocb = &xmitiq->iocb; + mp = *((MATCHMAP **)iocb); + *((MATCHMAP **)iocb) = 0; + xmitiq->q = NULL; + + lp = (uint32 * )mp->virt; + cmd = *lp++; + i = SWAP_DATA(cmd) & 0xffff; /* payload length */ + i -= sizeof(uint32); /* take off word 0 */ + while (i) { + rdid.un.word = *lp++; + rdid.un.word = SWAP_DATA(rdid.un.word); + if(binfo->fc_rscn_id_cnt < FC_MAX_HOLD_RSCN) { + for(j=0;jfc_rscn_id_cnt;j++) { + if(binfo->fc_rscn_id_list[j] == rdid.un.word) { + goto skip_id; + } + } + binfo->fc_rscn_id_list[binfo->fc_rscn_id_cnt++] = rdid.un.word; + } + else { + binfo->fc_flag |= FC_RSCN_DISCOVERY; + goto out1; + } +skip_id: + cnt += (fc_handle_rscn(p_dev_ctl, &rdid)); + i -= sizeof(uint32); + } + +out1: + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + + i = 1; + /* free resources associated with this iocb and repost the ring buffers */ + if (!(binfo->fc_flag & FC_SLI2)) { + for (i = 1; i < (int)iocb->ulpBdeCount; i++) { + mp = fc_getvaddr(p_dev_ctl, rp, (uchar * )((ulong)iocb->un.cont[i].bdeAddress)); + if (mp) { + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + } + } + } + fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq); + if (binfo->fc_flag & FC_RSCN_DISCOVERY) + goto out; + } + if (cnt == 0) { + /* no need for nameserver login */ + fc_nextrscn(p_dev_ctl, fc_max_els_sent); + } + else + fc_issue_ns_query(p_dev_ctl, (void *)0, (void *)0); + + return(0); + } + + binfo->fc_flag &= ~FC_RSCN_MODE; + binfo->fc_rscn_id_cnt = 0; + + /* This should turn off DELAYED ABTS for ELS timeouts */ + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX))) { + fc_set_slim(binfo, (MAILBOX * )mb, 0x052198, 0); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + /* Device Discovery completes */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0249, /* ptr to msg structure */ + fc_mes0249, /* ptr to msg */ + fc_msgBlk0249.msgPreambleStr, /* begin varargs */ + binfo->fc_flag); /* end varargs */ + /* Fix up any changed RPIs in FCP IOCBs queued up a txq */ + fc_fcp_fix_txq(p_dev_ctl); + + + if(FABRICTMO) { + fc_clk_can(p_dev_ctl, FABRICTMO); + FABRICTMO = 0; + } + + if(clp[CFG_FCP_ON].a_current) { + + fc_restart_all_devices(p_dev_ctl); + + /* Call iodone for any commands that timed out previously */ + for (bp = p_dev_ctl->timeout_head; bp != NULL; ) { + nextbp = bp->av_forw; + bp->b_error = ETIMEDOUT; + bp->b_flags |= B_ERROR; + bp->b_resid = bp->b_bcount; + FCSTATCTR.fcpScsiTmo++; + fc_do_iodone(bp); + bp = nextbp; + } + p_dev_ctl->timeout_count = 0; + p_dev_ctl->timeout_head = NULL; + /* Send down any saved FCP commands */ + fc_issue_cmd(p_dev_ctl); + } + return(0); +} /* End fc_nextrscn */ + + +_static_ int +fc_online( +fc_dev_ctl_t * p_dev_ctl) +{ + FC_BRD_INFO * binfo; + int ipri; + int j; + + if(p_dev_ctl) { + ipri = disable_lock(FC_LVL, &CMD_LOCK); + binfo = &BINFO; + if (!(binfo->fc_flag & FC_OFFLINE_MODE)) { + unlock_enable(ipri, &CMD_LOCK); + return(0); + } + /* Bring Adapter online */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0458, /* ptr to msg structure */ + fc_mes0458, /* ptr to msg */ + fc_msgBlk0458.msgPreambleStr); /* begin & end varargs */ + binfo->fc_flag &= ~FC_OFFLINE_MODE; + + fc_brdreset(p_dev_ctl); + unlock_enable(ipri, &CMD_LOCK); + fc_cfg_init(p_dev_ctl); + return(0); + } + + fc_diag_state = DDI_ONDI; + + /* + * find the device in the dev_array if it is there + */ + for (j = 0; j < MAX_FC_BRDS; j++) { + p_dev_ctl = DD_CTL.p_dev[j]; + if (p_dev_ctl) { + ipri = disable_lock(FC_LVL, &CMD_LOCK); + binfo = &BINFO; + if (!(binfo->fc_flag & FC_OFFLINE_MODE)) + continue; + /* Bring Adapter online */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0459, /* ptr to msg structure */ + fc_mes0459, /* ptr to msg */ + fc_msgBlk0459.msgPreambleStr); /* begin & end varargs */ + binfo->fc_flag &= ~FC_OFFLINE_MODE; + + fc_brdreset(p_dev_ctl); + unlock_enable(ipri, &CMD_LOCK); + fc_cfg_init(p_dev_ctl); + continue; + } + } + return(0); +} /* End fc_online */ + + +_static_ int +fc_offline( +fc_dev_ctl_t * p_dev_ctl) +{ + FC_BRD_INFO * binfo; + int ipri; + int j; + + if(p_dev_ctl) { + ipri = disable_lock(FC_LVL, &CMD_LOCK); + binfo = &BINFO; + if (binfo->fc_flag & FC_OFFLINE_MODE) { + unlock_enable(ipri, &CMD_LOCK); + return(0); + } + /* Bring Adapter offline */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0460, /* ptr to msg structure */ + fc_mes0460, /* ptr to msg */ + fc_msgBlk0460.msgPreambleStr); /* begin & end varargs */ + + fc_cfg_remove(p_dev_ctl); + binfo->fc_flag |= FC_OFFLINE_MODE; + + unlock_enable(ipri, &CMD_LOCK); + return(0); + } + fc_diag_state = DDI_OFFDI; + + /* + * find the device in the dev_array if it is there + */ + for (j = 0; j < MAX_FC_BRDS; j++) { + p_dev_ctl = DD_CTL.p_dev[j]; + if (p_dev_ctl) { + ipri = disable_lock(FC_LVL, &CMD_LOCK); + binfo = &BINFO; + if (binfo->fc_flag & FC_OFFLINE_MODE) { + unlock_enable(ipri, &CMD_LOCK); + continue; + } + /* Bring Adapter offline */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0452, /* ptr to msg structure */ + fc_mes0452, /* ptr to msg */ + fc_msgBlk0452.msgPreambleStr); /* begin & end varargs */ + + fc_cfg_remove(p_dev_ctl); + binfo->fc_flag |= FC_OFFLINE_MODE; + unlock_enable(ipri, &CMD_LOCK); + continue; + } + } + return(0); +} /* End fc_offline */ + + +_static_ int +fc_attach( +int index, +uint32 *p_uio) /* pointer to driver specific structure */ +{ + fc_dev_ctl_t * p_dev_ctl; + FC_BRD_INFO * binfo; + iCfgParam * clp; + int rc, i; + + if ((p_dev_ctl = DD_CTL.p_dev[index]) == NULL) { + rc = ENOMEM; + return(rc); + } + + binfo = &BINFO; + fc_diag_state = DDI_ONDI; + + binfo->fc_brd_no = index; /* FC board number */ + binfo->fc_p_dev_ctl = (uchar * )p_dev_ctl; + binfo->nlptimer = 1; + binfo->fc_fcpnodev.nlp_Rpi = 0xfffe; + binfo->fc_nlpbind_start = (NODELIST *)&binfo->fc_nlpbind_start; + binfo->fc_nlpbind_end = (NODELIST *)&binfo->fc_nlpbind_start; + binfo->fc_nlpmap_start = (NODELIST *)&binfo->fc_nlpmap_start; + binfo->fc_nlpmap_end = (NODELIST *)&binfo->fc_nlpmap_start; + binfo->fc_nlpunmap_start = (NODELIST *)&binfo->fc_nlpunmap_start; + binfo->fc_nlpunmap_end = (NODELIST *)&binfo->fc_nlpunmap_start; + + /* Initialize current value of config parameters from default */ + clp = DD_CTL.p_config[binfo->fc_brd_no]; + for(i=0;ifc_sli = (uchar)2; + clp[CFG_ZONE_RSCN].a_current = 1; /* ALWAYS force NS login on RSCN */ + + /* config the device */ + if ((rc = fc_cfg_init(p_dev_ctl))) { + return(rc); + } + return(0); +} + + +_static_ int +fc_detach( +int index) /* device unit number */ +{ + fc_dev_ctl_t * p_dev_ctl; + FC_BRD_INFO * binfo; + + p_dev_ctl = DD_CTL.p_dev[index]; + binfo = &BINFO; + if (p_dev_ctl == 0) + return(0); + + + if (!(binfo->fc_flag & FC_OFFLINE_MODE)) { + /* Free the device resources */ + fc_cfg_remove(p_dev_ctl); + } + + /* De-register the interrupt handler */ + if (p_dev_ctl->intr_inited) { + i_clear(&IHS); + p_dev_ctl->intr_inited = 0; + } + + fc_unmemmap(p_dev_ctl); + return(0); +} + + +/*****************************************************************************/ +/* + * NAME: fc_cfg_init + * + * FUNCTION: perform CFG_INIT function. Initialize the device control + * structure and get the adapter VPD data. + * + * EXECUTION ENVIRONMENT: process only + * + * CALLED FROM: + * fc_config + * + * INPUT: + * p_dev_ctl - pointer to the dev_ctl area + * + * RETURNS: + * 0 - OK + * EEXIST - device name in use (from ns_attach) + * EINVAL - invalid parameter was passed + * EIO - permanent I/O error + */ +/*****************************************************************************/ +_static_ int +fc_cfg_init( +fc_dev_ctl_t *p_dev_ctl) /* pointer to the device control area */ +{ + int rc; /* return code */ + int i; + FC_BRD_INFO * binfo; + iCfgParam * clp; + + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + p_dev_ctl->ctl_correlator = (void * ) & DD_CTL; + + for (i = 0; i < NLP_MAXPAN; i++) { + p_dev_ctl->adapter_state[i] = CLOSED; + } + + if ((rc = fc_pcimap(p_dev_ctl))) { + return(rc); + } + + if ((rc = fc_memmap(p_dev_ctl))) { + return(rc); + } + + /* offset from beginning of SLIM */ + BINFO.fc_mboxaddr = 0; + + BINFO.fc_mbox_active = 0; + BINFO.fc_ns_retry = 0; + BINFO.fc_process_LA = 0; + BINFO.fc_edtov = FF_DEF_EDTOV; + BINFO.fc_ratov = FF_DEF_RATOV; + BINFO.fc_altov = FF_DEF_ALTOV; + BINFO.fc_arbtov = FF_DEF_ARBTOV; + + /* offset from beginning of register space */ + BINFO.fc_HAregaddr = (sizeof(uint32) * HA_REG_OFFSET); + BINFO.fc_FFregaddr = (sizeof(uint32) * CA_REG_OFFSET); + BINFO.fc_STATregaddr = (sizeof(uint32) * HS_REG_OFFSET); + BINFO.fc_HCregaddr = (sizeof(uint32) * HC_REG_OFFSET); + BINFO.fc_BCregaddr = (sizeof(uint32) * BC_REG_OFFSET); + + + /* save the dev_ctl address in the NDD correlator field */ + NDD.ndd_name = DDS.logical_name;/* point to the name contained in the dds */ + NDD.ndd_alias = DDS.dev_alias; /* point to the name contained in the dds */ + + + + binfo->fc_ring[FC_IP_RING].fc_tx.q_max = + (ushort)clp[CFG_XMT_Q_SIZE].a_current; + + p_dev_ctl->iostrat_event = EVENT_NULL; + p_dev_ctl->iostrat_head = NULL; + p_dev_ctl->iostrat_tail = NULL; + + /* + * Perform any device-specific initialization necessary at the + * CFG_INIT time. If there is any error during the device initialization, + * the CFG_INIT will fail. Also get VPD data. + */ + if ((rc = fc_ffinit(p_dev_ctl))) { + return(rc); + } + + /* Now setup physical address */ + fc_bcopy(binfo->fc_portname.IEEE, p_dev_ctl->phys_addr, 6); + + return(0); +} /* End fc_cfg_init */ + + +/*****************************************************************************/ +/* + * NAME: fc_cfg_remove + * + * FUNCTION: Remove the device resources that have been allocated during + * CFG_INIT configuration time. + * + * EXECUTION ENVIRONMENT: process only + * + * NOTES: + * + * CALLED FROM: + * fc_config + * + * INPUT: + * p_dev_ctl - address of a pointer to the dev control structure + * + * RETURNS: + * none. + */ +/*****************************************************************************/ +_static_ void +fc_cfg_remove( +fc_dev_ctl_t *p_dev_ctl) /* point to the dev_ctl area */ +{ + fc_free_rpilist(p_dev_ctl, 0); + + /* Release the watchdog timers and disable board interrupts */ + fc_ffcleanup(p_dev_ctl); + + fc_free_buffer(p_dev_ctl); /* free device buffers */ + + fc_brdreset(p_dev_ctl); + +} /* End fc_cfg_remove */ + + +/*****************************************************************************/ +/* + * NAME: fc_ffcleanup + * + * EXECUTION ENVIRONMENT: process only + * + * CALLED FROM: + * CFG_TERM + * + * INPUT: + * p_dev_ctl - pointer to the dev_ctl area. + * + * RETURNS: + * none + */ +/*****************************************************************************/ +_static_ void +fc_ffcleanup( +fc_dev_ctl_t *p_dev_ctl) /* pointer to the dev_ctl area */ +{ + int i; + RING * rp; + FC_BRD_INFO * binfo; + void *ioa; + MAILBOX * mb; + + binfo = &BINFO; + binfo->fc_process_LA = 0; + + /* Disable all but the mailbox interrupt */ + ioa = (void *)FC_MAP_IO(&binfo->fc_iomap_io); /* map in io registers */ + WRITE_CSR_REG(binfo, FC_HC_REG(binfo, ioa), HC_MBINT_ENA); + FC_UNMAP_MEMIO(ioa); + + /* Issue unreg_login command to logout all nodes */ + if (p_dev_ctl->init_eventTag) { + /* Get a buffer for mailbox command */ + if ((mb = (MAILBOX * )fc_mem_get(binfo, MEM_MBOX)) == NULL) { + } else { + fc_unreg_login(binfo, 0xffff, (MAILBOX * )mb); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) != MBX_BUSY) + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + + ioa = (void *)FC_MAP_IO(&binfo->fc_iomap_io); /* map in io registers */ + /* Clear all interrupt enable conditions */ + WRITE_CSR_REG(binfo, FC_HC_REG(binfo, ioa), 0); + FC_UNMAP_MEMIO(ioa); + + for (i = 0; i < binfo->fc_ffnumrings; i++) { + rp = &binfo->fc_ring[i]; + /* Clear the transmit watchdog timer */ + if (rp->fc_wdt_inited) { + if(RINGTMO) { + fc_clk_can(p_dev_ctl, RINGTMO); + RINGTMO = 0; + } + rp->fc_wdt_inited = 0; + } + } + + if(MBOXTMO) { + fc_clk_can(p_dev_ctl, MBOXTMO); + MBOXTMO = 0; + } + if(FABRICTMO) { + fc_clk_can(p_dev_ctl, FABRICTMO); + FABRICTMO = 0; + } + + fc_flush_rscn_defer(p_dev_ctl); + + fc_flush_clk_set(p_dev_ctl, fc_delay_timeout); + + fc_flush_clk_set(p_dev_ctl, lpfc_scsi_selto_timeout); + +} /* End fc_ffcleanup */ + + +/*****************************************************************************/ +/* + * NAME: fc_start + * + * FUNCTION: Initialize and activate the adapter. + * + * EXECUTION ENVIRONMENT: process or interrupt + * + * CALLED FROM: + * fc_config + * + * INPUT: + * p_dev_ctl - pointer to the dev_ctl area. + * + * RETURNS: + * NONE + */ +/*****************************************************************************/ + +_static_ void +fc_start( +fc_dev_ctl_t *p_dev_ctl) /* pointer to the dev_ctl area */ +{ + uint32 i, j; + FC_BRD_INFO * binfo; + iCfgParam * clp; + void * ioa; + RING * rp; + + /* Activate the adapter and allocate all the resources needed */ + + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + + /* Enable appropriate host interrupts */ + i = (uint32) (HC_MBINT_ENA | HC_ERINT_ENA); + if (binfo->fc_ffnumrings > 0) + i |= HC_R0INT_ENA; + if (binfo->fc_ffnumrings > 1) + i |= HC_R1INT_ENA; + if (binfo->fc_ffnumrings > 2) + i |= HC_R2INT_ENA; + if (binfo->fc_ffnumrings > 3) + i |= HC_R3INT_ENA; + + ioa = (void *)FC_MAP_IO(&binfo->fc_iomap_io); /* map in io registers */ + WRITE_CSR_REG(binfo, FC_HC_REG(binfo, ioa), i); + FC_UNMAP_MEMIO(ioa); + + for (i = 0; i < (uint32)binfo->fc_ffnumrings; i++) { + /* Initialize / post buffers to ring */ + fc_setup_ring(p_dev_ctl, i); + + if (i == FC_ELS_RING) { + /* Now post receive buffers to the ring */ + rp = &binfo->fc_ring[i]; + for (j = 0; j < 64; j++) + fc_post_buffer(p_dev_ctl, rp, 2); + } + } + + clp = DD_CTL.p_config[binfo->fc_brd_no]; + if(clp[CFG_NETWORK_ON].a_current) { + rp = &binfo->fc_ring[FC_IP_RING]; + i = clp[CFG_POST_IP_BUF].a_current; + while(i) { + fc_post_mbuf(p_dev_ctl, rp, 2); + i -= 2; + } + } + + /* set up the watchdog timer control structure section */ + binfo->fc_fabrictmo = FF_DEF_RATOV + 1; + +} /* End fc_start */ + + +_static_ void +fc_process_reglogin( +fc_dev_ctl_t *p_dev_ctl, /* pointer to the dev_ctl area */ +NODELIST *ndlp) +{ + node_t * node_ptr; + RING * rp; + FC_BRD_INFO * binfo; + iCfgParam * clp; + + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + + ndlp->nlp_flag &= ~NLP_REG_INP; + if (ndlp->nlp_DID == Fabric_DID) { + ndlp->nlp_flag &= ~NLP_FARP_SND; + ndlp->nlp_action &= ~NLP_DO_ADDR_AUTH; + } else { + /* If we are an FCP node, update the rpi */ + if (ndlp->nlp_type & NLP_FCP_TARGET) { + if ((node_ptr = (node_t * )ndlp->nlp_targetp) != NULL) { + node_ptr->rpi = (ushort)ndlp->nlp_Rpi; + node_ptr->last_good_rpi = (ushort)ndlp->nlp_Rpi; + node_ptr->nlp = ndlp; + node_ptr->flags &= ~FC_NODEV_TMO; + ndlp->nlp_flag &= ~NLP_NODEV_TMO; + } + else { + int dev_index; + + dev_index = INDEX(ndlp->id.nlp_pan, ndlp->id.nlp_sid); + node_ptr = binfo->device_queue_hash[dev_index].node_ptr; + if(node_ptr) { + /* This is a new device that entered the loop */ + node_ptr->nlp = ndlp; + node_ptr->rpi = (ushort)ndlp->nlp_Rpi; + node_ptr->last_good_rpi = (ushort)ndlp->nlp_Rpi; + node_ptr->scsi_id = dev_index; + ndlp->nlp_targetp = (uchar *)node_ptr; + node_ptr->flags &= ~FC_NODEV_TMO; + ndlp->nlp_flag &= ~NLP_NODEV_TMO; + } + } + } + + if((ndlp->nlp_DID & CT_DID_MASK) == CT_DID_MASK) + ndlp->nlp_state = NLP_LOGIN; + + /* HBA Mgmt */ + if(ndlp->nlp_DID == FDMI_DID) { + ndlp->nlp_state = NLP_LOGIN; + return; + } + + /* If we are a NameServer, go to next phase */ + if (ndlp->nlp_DID == NameServer_DID) { + int fabcmd; + + ndlp->nlp_state = NLP_LOGIN; + + if(binfo->fc_ffstate == FC_READY) { + fabcmd = SLI_CTNS_GID_FT; + } + else { + fabcmd = SLI_CTNS_RFT_ID; + } + + /* Issue RFT_ID / GID_FT to Nameserver */ + if (fc_ns_cmd(p_dev_ctl, ndlp, fabcmd)) { + /* error so start discovery */ + /* Done with NameServer for now, but keep logged in */ + ndlp->nlp_action &= ~NLP_DO_RSCN; + + /* Fire out PLOGIs on nodes marked for discovery */ + if ((binfo->fc_nlp_cnt <= 0) && + !(binfo->fc_flag & FC_NLP_MORE)) { + binfo->fc_nlp_cnt = 0; + if ((binfo->fc_ffstate == FC_READY) && + (binfo->fc_flag & FC_RSCN_MODE)) { + fc_nextrscn(p_dev_ctl, fc_max_els_sent); + } + else { + fc_nextnode(p_dev_ctl, ndlp); + } + } + else { + fc_nextnode(p_dev_ctl, ndlp); + } + ndlp->nlp_action &= ~NLP_DO_ADDR_AUTH; + } + return; + } + + /* If we are in the middle of Discovery */ + if ((ndlp->nlp_type & NLP_FCP_TARGET) || + (ndlp->nlp_action & NLP_DO_DISC_START) || + (ndlp->nlp_action & NLP_DO_ADDR_AUTH) || + (ndlp->nlp_action & NLP_DO_RSCN) || + (ndlp->nlp_action & NLP_DO_SCSICMD) || + (binfo->fc_flag & FC_PT2PT) || + (ndlp->nlp_portname.nameType != NAME_IEEE)) { + + ndlp->nlp_flag &= ~NLP_FARP_SND; + ndlp->nlp_action &= ~NLP_DO_ADDR_AUTH; + if((!(binfo->fc_flag & FC_PT2PT)) && (ndlp->nlp_action == 0)) { + if(binfo->fc_ffstate == FC_READY) { + ndlp->nlp_action |= NLP_DO_RSCN; + } + else { + ndlp->nlp_action |= NLP_DO_DISC_START; + } + } + if(clp[CFG_FCP_ON].a_current) { + ndlp->nlp_state = NLP_PRLI; + if((ndlp->nlp_flag & NLP_RCV_PLOGI) && + (!(ndlp->nlp_action) || (ndlp->nlp_flag & NLP_REQ_SND)) && + !(binfo->fc_flag & FC_PT2PT)) { + ndlp->nlp_state = NLP_LOGIN; + } + else { + if((ndlp->nlp_DID & Fabric_DID_MASK) != Fabric_DID_MASK) { + fc_els_cmd(binfo, ELS_CMD_PRLI, + (void *)((ulong)ndlp->nlp_DID), (uint32)0, (ushort)0, ndlp); + } + else + fc_nextnode(p_dev_ctl, ndlp); + } + } else { + /* establish a new exchange for login registration */ + if ((ndlp->nlp_Xri == 0) && + (ndlp->nlp_type & NLP_IP_NODE) && + ((ndlp->nlp_DID & CT_DID_MASK) != CT_DID_MASK) && + !(ndlp->nlp_flag & NLP_RPI_XRI)) { + ndlp->nlp_flag |= NLP_RPI_XRI; + rp = &binfo->fc_ring[FC_ELS_RING]; + fc_create_xri(binfo, rp, ndlp); + } + if(!(ndlp->nlp_flag & NLP_RCV_PLOGI)) + fc_nextnode(p_dev_ctl, ndlp); + } + } else { + ndlp->nlp_flag &= ~NLP_FARP_SND; + ndlp->nlp_action &= ~NLP_DO_ADDR_AUTH; + /* establish a new exchange for Nport login registration */ + if ((ndlp->nlp_Xri == 0) && + ((ndlp->nlp_DID & CT_DID_MASK) != CT_DID_MASK) && + !(ndlp->nlp_flag & NLP_RPI_XRI)) { + ndlp->nlp_flag |= NLP_RPI_XRI; + rp = &binfo->fc_ring[FC_ELS_RING]; + fc_create_xri(binfo, rp, ndlp); /* IP ONLY */ + } + } + ndlp->nlp_flag &= ~NLP_RCV_PLOGI; + } + return; +} + +_static_ int +fc_snd_scsi_req( +fc_dev_ctl_t *p_dev_ctl, +NAME_TYPE *wwn, +MATCHMAP *bmp, +DMATCHMAP *fcpmp, +DMATCHMAP *omatp, +uint32 count, +struct dev_info *dev_ptr) +{ + FC_BRD_INFO *binfo; + NODELIST * ndlp; + RING * rp; + IOCBQ * temp; + IOCB * cmd; + ULP_BDE64 * bpl; + FCP_CMND * inqcmnd; + fc_buf_t * fcptr; + node_t * map_node_ptr; + struct dev_info * map_dev_ptr; + uint32 did; + fc_lun_t lun; + int i; + + binfo = &BINFO; + if(((ndlp = fc_findnode_wwpn(binfo, NLP_SEARCH_ALL, wwn)) == 0) || + (!(binfo->fc_flag & FC_SLI2))) { /* MUST be SLI2 */ + return(EACCES); + } + + if(ndlp->nlp_flag & NLP_REQ_SND) { + return(ENODEV); + } + + if(ndlp->nlp_state <= NLP_LOGIN) { + if ((ndlp->nlp_DID == binfo->fc_myDID) || + (ndlp->nlp_DID & Fabric_DID_MASK)) { + return(ENODEV); + } + ndlp->nlp_action |= NLP_DO_SCSICMD; + if((ndlp->nlp_state == NLP_LOGIN) && ndlp->nlp_Rpi) { + /* Need to send PRLI */ + fc_els_cmd(binfo, ELS_CMD_PRLI, + (void *)((ulong)ndlp->nlp_DID), (uint32)0, (ushort)0, ndlp); + } + else { + /* Need to send PLOGI */ + did = ndlp->nlp_DID; + if(did == 0) { + did = ndlp->nlp_oldDID; + } + if(!(ndlp->nlp_flag & NLP_NS_REMOVED)) { + fc_els_cmd(binfo, ELS_CMD_PLOGI, + (void *)((ulong)did), (uint32)0, (ushort)0, ndlp); + } + } + return(ENODEV); + } + + inqcmnd = (FCP_CMND *)fcpmp->dfc.virt; + lun = ((inqcmnd->fcpLunMsl >> FC_LUN_SHIFT) & 0xff); + + map_node_ptr = 0; + map_dev_ptr = 0; + + if (ndlp->nlp_type & NLP_SEED_MASK) { + /* If this is a mapped target, check qdepth limits */ + i = INDEX(ndlp->id.nlp_pan, ndlp->id.nlp_sid); + if ((map_node_ptr = binfo->device_queue_hash[i].node_ptr) != NULL) { + + if (map_node_ptr->tgt_queue_depth && + (map_node_ptr->tgt_queue_depth == map_node_ptr->num_active_io)) + return(ENODEV); + + if ((map_dev_ptr = fc_find_lun(binfo, i, lun))) { + if ((map_dev_ptr->active_io_count >= map_dev_ptr->fcp_cur_queue_depth) || + (map_dev_ptr->stop_send_io)) + return(ENODEV); + } + } + } + + rp = &binfo->fc_ring[FC_FCP_RING]; + if ((temp = (IOCBQ * )fc_mem_get(binfo, MEM_IOCB)) == NULL) { + return(EACCES); + } + + fc_bzero((void *)dev_ptr, sizeof(dev_ptr)); + dev_ptr->lun_id = lun; + dev_ptr->opened = TRUE; + dev_ptr->fcp_lun_queue_depth = 1; + dev_ptr->fcp_cur_queue_depth = 1; + dev_ptr->queue_state = ACTIVE_PASSTHRU; + dev_ptr->pend_head = (T_SCSIBUF *)map_node_ptr; + dev_ptr->pend_tail = (T_SCSIBUF *)map_dev_ptr; + + fcptr = (fc_buf_t *)fcpmp->dfc.virt; + fcptr->dev_ptr = dev_ptr; + fcptr->phys_adr = (char *)fcpmp->dfc.phys; + fcptr->sc_bufp = (T_SCSIBUF *)omatp; + fcptr->flags = 0; + /* set up an iotag so we can match the completion iocb */ + for (i = 0; i < MAX_FCP_CMDS; i++) { + fcptr->iotag = rp->fc_iotag++; + if (rp->fc_iotag >= MAX_FCP_CMDS) + rp->fc_iotag = 1; + if (binfo->fc_table->fcp_array[fcptr->iotag] == 0) + break; + } + if (i >= MAX_FCP_CMDS) { + /* No more command slots available, retry later */ + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + return(EACCES); + } + + fc_bzero((void *)temp, sizeof(IOCBQ)); + cmd = &temp->iocb; + + bpl = (ULP_BDE64 * )bmp->virt; + + cmd->un.fcpi64.bdl.ulpIoTag32 = (uint32)0; + cmd->un.fcpi64.bdl.addrHigh = (uint32)putPaddrHigh(bmp->phys); + cmd->un.fcpi64.bdl.addrLow = (uint32)putPaddrLow(bmp->phys); + cmd->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BDL; + cmd->ulpBdeCount = 1; + fcptr->bmp = bmp; + temp->bpl = (uchar *)0; + + cmd->ulpContext = ndlp->nlp_Rpi; + cmd->ulpIoTag = fcptr->iotag; + /* + * if device is FCP-2 device, set the following bit that says + * to run the FC-TAPE protocol. + */ + if (ndlp->id.nlp_fcp_info & NLP_FCP_2_DEVICE) { + cmd->ulpFCP2Rcvy = 1; + } + cmd->ulpClass = (ndlp->id.nlp_fcp_info & 0x0f); + cmd->ulpOwner = OWN_CHIP; + + /* Hardcode 30 second timeout for I/O to complete */ + curtime(&fcptr->timeout); + cmd->ulpRsvdByte = fc_inq_sn_tmo; + fcptr->timeout = ((ulong)fcptr->timeout + (31 * fc_ticks_per_second)); + + switch(fcptr->fcp_cmd.fcpCntl3) { + case READ_DATA: + /* Set up for SCSI read */ + cmd->ulpCommand = CMD_FCP_IREAD64_CR; + cmd->ulpPU = PARM_READ_CHECK; + cmd->un.fcpi.fcpi_parm = count; + cmd->un.fcpi64.bdl.bdeSize = ((omatp->dfc_flag+2) * sizeof(ULP_BDE64)); + cmd->ulpBdeCount = 1; + break; + + case WRITE_DATA: + /* Set up for SCSI write */ + cmd->ulpCommand = CMD_FCP_IWRITE64_CR; + cmd->un.fcpi64.bdl.bdeSize = ((omatp->dfc_flag+2) * sizeof(ULP_BDE64)); + cmd->ulpBdeCount = 1; + break; + default: + /* Set up for SCSI command */ + cmd->ulpCommand = CMD_FCP_ICMND64_CR; + cmd->un.fcpi64.bdl.bdeSize = (2 * sizeof(ULP_BDE64)); + cmd->ulpBdeCount = 1; + break; + } + + cmd->ulpLe = 1; + /* Queue cmd chain to last iocb entry in xmit queue */ + if (rp->fc_tx.q_first == NULL) { + rp->fc_tx.q_first = (uchar * )temp; + } else { + ((IOCBQ * )(rp->fc_tx.q_last))->q = (uchar * )temp; + } + rp->fc_tx.q_last = (uchar * )temp; + rp->fc_tx.q_cnt++; + + fc_enq_fcbuf_active(rp, fcptr); + + if(map_dev_ptr) + map_dev_ptr->active_io_count++; + if(map_node_ptr) + map_node_ptr->num_active_io++; + dev_ptr->active_io_count++; + FCSTATCTR.fcpCmd++; + + issue_iocb_cmd(binfo, rp, 0); + return(0); +} + + +/****************************************************************************** +* Function name : fc_parse_binding_entry +* +* Description : Parse binding entry for WWNN & WWPN +* +* ASCII Input string example: 2000123456789abc:lpfc1t0 +* +* Return : 0 = Success +* Greater than 0 = Binding entry syntax error. SEE defs +* FC_SYNTAX_ERR_XXXXXX. +******************************************************************************/ +_static_ int +fc_parse_binding_entry( fc_dev_ctl_t *p_dev_ctl, + uchar *inbuf, uchar *outbuf, + int in_size, int out_size, + int bind_type, + unsigned int *sum, int entry, int *lpfc_num) +{ + int brd; + int c1, cvert_cnt, sumtmp; + + FC_BRD_INFO * binfo = &BINFO; + + char ds_lpfc[] = "lpfc"; + + *lpfc_num = -1; + + /* Parse 16 digit ASC hex address */ + if( bind_type == FC_BIND_DID) outbuf++; + cvert_cnt = fc_asc_seq_to_hex( p_dev_ctl, in_size, out_size, (char *)inbuf, (char *)outbuf); + if(cvert_cnt < 0) + return(FC_SYNTAX_ERR_ASC_CONVERT); + inbuf += (ulong)cvert_cnt; + + /* Parse colon */ + if(*inbuf++ != ':') + return(FC_SYNTAX_ERR_EXP_COLON); + + /* Parse lpfc */ + if(fc_strncmp( (char *)inbuf, ds_lpfc, (sizeof(ds_lpfc)-1))) + return(FC_SYNTAX_ERR_EXP_LPFC); + inbuf += sizeof(ds_lpfc)-1; + + /* Parse lpfc number */ + /* Get 1st lpfc digit */ + c1 = *inbuf++; + if(fc_is_digit(c1) == 0) + goto err_lpfc_num; + sumtmp = c1 - 0x30; + + /* Get 2nd lpfc digit */ + c1 = *inbuf; + if(fc_is_digit(c1) == 0) + goto convert_instance; + inbuf++; + sumtmp = (sumtmp * 10) + c1 - 0x30; + if((sumtmp < 0) || (sumtmp > 15)) + goto err_lpfc_num; + goto convert_instance; + +err_lpfc_num: + + return(FC_SYNTAX_ERR_INV_LPFC_NUM); + + /* Convert from ddi instance number to adapter number */ +convert_instance: + + for(brd = 0; brd < MAX_FC_BRDS; brd++) { + if(fcinstance[brd] == sumtmp) + break; + } + if(binfo->fc_brd_no != brd) { + /* Skip this entry */ + return(FC_SYNTAX_OK_BUT_NOT_THIS_BRD); + } + + + /* Parse 't' */ + if(*inbuf++ != 't') + return(FC_SYNTAX_ERR_EXP_T); + + /* Parse target number */ + /* Get 1st target digit */ + c1 = *inbuf++; + if(fc_is_digit(c1) == 0) + goto err_target_num; + sumtmp = c1 - 0x30; + + /* Get 2nd target digit */ + c1 = *inbuf; + if(fc_is_digit(c1) == 0) + goto check_for_term; + inbuf++; + sumtmp = (sumtmp * 10) + c1 - 0x30; + + /* Get 3nd target digit */ + c1 = *inbuf; + if(fc_is_digit(c1) == 0) + goto check_for_term; + inbuf++; + sumtmp = (sumtmp * 10) + c1 - 0x30; + if((sumtmp < 0) || (sumtmp > 999)) + goto err_target_num; + goto check_for_term; + +err_target_num: + return(FC_SYNTAX_ERR_INV_TARGET_NUM); + + /* Test that input string in NULL terminated - End of input */ +check_for_term: + + if(*inbuf != 0) + return(FC_SYNTAX_ERR_EXP_NULL_TERM); + + + *sum = sumtmp; + return(FC_SYNTAX_OK); /* Success */ +} /* fc_parse_binding_entry */ + +void +issue_report_lun( +fc_dev_ctl_t *pd, +void *l1, +void *l2) +{ + FC_BRD_INFO * binfo = &pd->info; + dvi_t * di = (dvi_t *)l1; + RING * rp; + fc_buf_t * fcptr; + IOCBQ * temp; + IOCB * cmd; + ULP_BDE64 * bpl; + MATCHMAP * bmp; + MBUF_INFO * mbufp; + node_t * nodep; + int i, tmo; + + rp = &binfo->fc_ring[FC_FCP_RING]; + nodep = di->nodep; + + mbufp = (MBUF_INFO * )fc_mem_get(binfo, MEM_IOCB); + if (mbufp == NULL) { + nodep->rptlunstate = REPORT_LUN_COMPLETE; + return; + } + mbufp->virt = 0; + mbufp->phys = 0; + mbufp->flags = FC_MBUF_DMA; + mbufp->align = (int)4096; + mbufp->size = 4096; + + if (nodep->virtRptLunData == 0) { + fc_malloc(pd, mbufp); + if (mbufp->phys == NULL) { + fc_mem_put(binfo, MEM_IOCB, (uchar * )mbufp); + nodep->rptlunstate = REPORT_LUN_COMPLETE; + return; + } + } else { + mbufp->phys = nodep->physRptLunData; + mbufp->virt = nodep->virtRptLunData; + } + + if ((fcptr = fc_deq_fcbuf(di)) == NULL) { + if (nodep->virtRptLunData == 0) + fc_free(pd, mbufp); + fc_mem_put(binfo, MEM_IOCB, (uchar * )mbufp); + nodep->rptlunstate = REPORT_LUN_COMPLETE; + return; + } + + if ((temp = (IOCBQ * )fc_mem_get(binfo, MEM_IOCB)) == NULL) { + if (nodep->virtRptLunData == 0) + fc_free(pd, mbufp); + fc_mem_put(binfo, MEM_IOCB, (uchar * )mbufp); + fc_enq_fcbuf(fcptr); + nodep->rptlunstate = REPORT_LUN_COMPLETE; + return; + } + + fc_bzero((void *)fcptr, sizeof(FCP_CMND) + sizeof(FCP_RSP)); + + /* + * Save the MBUF pointer. + * Buffer will be freed by handle_fcp_event(). + */ + fcptr->sc_bufp = (void *)mbufp; + + /* + * Setup SCSI command block in FCP payload + */ + fcptr->fcp_cmd.fcpCdb[0]= 0xA0; /* SCSI Report Lun Command */ + + fcptr->fcp_cmd.fcpCdb[8]= 0x10; + fcptr->fcp_cmd.fcpCntl3 = READ_DATA; + fcptr->fcp_cmd.fcpDl = SWAP_DATA(RPTLUN_MIN_LEN); + + /* + * set up an iotag so we can match the completion iocb + */ + for (i = 0; i < MAX_FCP_CMDS; i++) { + fcptr->iotag = rp->fc_iotag++; + if (rp->fc_iotag >= MAX_FCP_CMDS) + rp->fc_iotag = 1; + if (binfo->fc_table->fcp_array[fcptr->iotag] == 0) + break; + } + if (i >= MAX_FCP_CMDS) { + /* + * No more command slots available + */ + if (nodep->virtRptLunData == 0) + fc_free(pd, mbufp); + fc_mem_put(binfo, MEM_IOCB, (uchar * )mbufp); + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + fc_enq_fcbuf(fcptr); + nodep->rptlunstate = REPORT_LUN_COMPLETE; + return; + } + + fc_bzero((void *)temp, sizeof(IOCBQ)); + cmd = &temp->iocb; + temp->q = NULL; + + /* + * Allocate buffer for Buffer ptr list + */ + if ((bmp = (MATCHMAP * )fc_mem_get(binfo, MEM_BPL)) == 0) { + if (nodep->virtRptLunData == 0) + fc_free(pd, mbufp); + fc_mem_put(binfo, MEM_IOCB, (uchar * )mbufp); + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + fc_enq_fcbuf(fcptr); + nodep->rptlunstate = REPORT_LUN_COMPLETE; + return; + } + + bpl = (ULP_BDE64 * )bmp->virt; + bpl->addrHigh = PCIMEM_LONG((uint32)putPaddrHigh(GET_PAYLOAD_PHYS_ADDR(fcptr))); + bpl->addrLow = PCIMEM_LONG((uint32)putPaddrLow(GET_PAYLOAD_PHYS_ADDR(fcptr))); + bpl->tus.f.bdeSize = sizeof(FCP_CMND); + bpl->tus.f.bdeFlags = BUFF_USE_CMND; + bpl->tus.w = PCIMEM_LONG(bpl->tus.w); + bpl++; + bpl->addrHigh = PCIMEM_LONG((uint32)putPaddrHigh(GET_PAYLOAD_PHYS_ADDR(fcptr)+sizeof(FCP_CMND))); + bpl->addrLow = PCIMEM_LONG((uint32)putPaddrLow(GET_PAYLOAD_PHYS_ADDR(fcptr)+sizeof(FCP_CMND))); + bpl->tus.f.bdeSize = sizeof(FCP_RSP); + bpl->tus.f.bdeFlags = (BUFF_USE_CMND | BUFF_USE_RCV); + bpl->tus.w = PCIMEM_LONG(bpl->tus.w); + bpl++; + + cmd->un.fcpi64.bdl.ulpIoTag32 = (uint32)0; + cmd->un.fcpi64.bdl.addrHigh = (uint32)putPaddrHigh(bmp->phys); + cmd->un.fcpi64.bdl.addrLow = (uint32)putPaddrLow(bmp->phys); + cmd->un.fcpi64.bdl.bdeSize = (2 * sizeof(ULP_BDE64)); + cmd->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BDL; + cmd->ulpBdeCount = 1; + fcptr->bmp = bmp; + temp->bpl = (uchar *)0; + + cmd->ulpContext = nodep->rpi; + cmd->ulpIoTag = fcptr->iotag; + + /* + * if device is FCP-2 device, set the following bit that says + * to run the FC-TAPE protocol. + */ + if (nodep->nlp->id.nlp_fcp_info & NLP_FCP_2_DEVICE) { + cmd->ulpFCP2Rcvy = 1; + } + cmd->ulpClass = (nodep->nlp->id.nlp_fcp_info & 0x0f); + cmd->ulpOwner = OWN_CHIP; + + /* + * Hardcode 2*RATOV second timeout for I/O to complete + */ + tmo = (2 * binfo->fc_ratov); + curtime(&fcptr->timeout); + cmd->ulpRsvdByte = tmo; + tmo++; /* Make scsi timeout longer then cmd tmo */ + fcptr->timeout = ((ulong)fcptr->timeout + (tmo * fc_ticks_per_second)); + + /* + * Read Data + */ + cmd->ulpCommand = CMD_FCP_IREAD64_CR; + cmd->ulpPU = PARM_READ_CHECK; + cmd->un.fcpi.fcpi_parm = RPTLUN_MIN_LEN; + + bpl->addrHigh = PCIMEM_LONG((uint32)putPaddrHigh(mbufp->phys)); + bpl->addrLow = PCIMEM_LONG((uint32)putPaddrLow(mbufp->phys)); + bpl->tus.f.bdeSize = RPTLUN_MIN_LEN; + bpl->tus.f.bdeFlags = BUFF_USE_RCV; + bpl->tus.w = PCIMEM_LONG(bpl->tus.w); + bpl++; + + cmd->un.fcpi64.bdl.bdeSize += sizeof(ULP_BDE64); + cmd->ulpBdeCount = 1; + + cmd->ulpLe = 1; + + /* + * Queue cmd chain to last iocb entry in xmit queue + */ + if (rp->fc_tx.q_first == NULL) { + rp->fc_tx.q_first = (uchar * )temp; + } else { + ((IOCBQ * )(rp->fc_tx.q_last))->q = (uchar * )temp; + } + rp->fc_tx.q_last = (uchar * )temp; + rp->fc_tx.q_cnt++; + + fc_enq_fcbuf_active(rp, fcptr); + fcptr->flags |= FCBUF_INTERNAL; + + di->active_io_count++; + nodep->num_active_io++; + FCSTATCTR.fcpCmd++; + + issue_iocb_cmd(binfo, rp, 0); + return; +} +/****************************************/ +/* Print Format Declarations Start Here */ +/****************************************/ +_local_ int fc_sprintf_fargs( uchar *string, void *control, char *fixArgs); + +#define LENGTH_LINE 71 +#define MAX_IO_SIZE 32 * 2 /* iobuf cache size */ +#define MAX_TBUFF 18 * 2 /* temp buffer size */ + +typedef union { /* Pointer to table of arguments. */ + ulong *ip; + ulong *lip; + ulong *uip; + ulong *luip; + ulong **luipp; + uchar *cp; + uchar **csp; +} ARGLIST; + +typedef struct { + uchar *string; + long index; + int count; + uchar buf[MAX_IO_SIZE + MAX_TBUFF]; /* extra room to convert numbers */ +} PRINTBLK; + +/* + * ASCII string declarations + */ +static char dig[] = {"0123456789ABCDEF"}; +static char ds_disabled[] = "disabled"; +static char ds_enabled[] = "enabled"; +static char ds_none[] = "none"; +static char ds_null_string[] = ""; +static char ds_unknown[] = "unknown"; + +/* + * Function Declarations + */ +_local_ int add_char( PRINTBLK * io, uchar ch); +_local_ int add_string( PRINTBLK * io, uchar * string); +_local_ int fmtout( uchar *ostr, uchar *control, va_list inarg); +_local_ void print_string( PRINTBLK * io); +_local_ int long_itos( long val, uchar * cp, long base); + + +/**********************************************************/ +/** expanded_len */ +/** determine the length of the string after expanding */ +/**********************************************************/ +_local_ +int expanded_len( +uchar *sp) +{ + register int i; + uchar c; + + i = 0; + while ((c = *sp++) != 0) { + if (c < 0x1b) { + if ((c == '\r') || (c == '\n')) + break; /* stop at cr or lf */ + i++; /* double it */ + } + i++; + } + return (i); +} /* expanded_len */ + +/*************************************************/ +/** long_itos **/ +/** Convert long integer to decimal string. **/ +/** Returns the string length. **/ +/*************************************************/ +_local_ +int long_itos( +long val, /* Number to convert. */ +uchar * cp, /* Store the string here. */ +long base) /* Conversion base. */ +{ + uchar tempc[16]; + uchar *tcp; + int n=0; /* number of characters in result */ + ulong uval; /* unsigned value */ + + *(tcp=(tempc+15))=0; + if (base<0) { + /* needs signed conversion */ + base= -base; + if (val<0) { + n=1; + val = -val; + } + do { + *(--tcp)=dig[ (int)(val%base)]; + val /= base; + } while (val); + } + else { + uval=val; + do { + *(--tcp)=dig[ (int)(uval%base)]; + uval/=base; + } while(uval); + } + if (n) + *(--tcp)='-'; + n=(int)((long)&tempc[15] - (long)tcp); + fc_bcopy( tcp, cp, n+1); /* from, to, cnt */ + return(n); +} /* long_itos */ + +/****************************************/ +/** add_char **/ +/****************************************/ +_local_ +int add_char( +PRINTBLK * io, +uchar ch) +{ + int index; + + if (ch < 0x1b) { + switch (ch) { + case 0xd: /* carriage return */ + io->count = -1; /* will be incremented to 0, below */ + break; + case 0x8: /* back space */ + io->count -= 2; /* will be incremented to 1 less, below */ + break; + case 0xa: /* line feed */ + case 0x7: /* bell */ + case 0x9: /* hortizontal tab */ + case 0xe: /* shift out */ + case 0xf: /* shift in */ + io->count--; /* will be incremented to same, below */ + break; + default: + add_char(io, '^'); + ch |= 0x40; + break; + } + } + io->count++; + if (io->string != NULL) { + *io->string = ch; + *++io->string = '\0'; + return (0); + } + + index = io->index; + if( index < (MAX_IO_SIZE + MAX_TBUFF -2)) { + io->buf[index] = ch; + io->buf[++index] = '\0'; + } + return (++io->index); +} /* add_char */ + +/****************************************/ +/** add_string **/ +/****************************************/ +_local_ +int add_string( +PRINTBLK * io, +uchar * string) +{ + if (io->string != NULL) { + io->string = + (uchar *)fc_strcpy( (char *)io->string, (char *)string); /* dst, src */ + return (0); + } + return (io->index = ((long)(fc_strcpy( (char *)&io->buf[io->index], + (char *)string))) - ((long)((char *)io->buf))); /* dst, src */ +} /* add_string */ + +/*****************************************************/ +/** print_string **/ +/** takes print defn, prints data, zeroes index **/ +/*****************************************************/ +_local_ +void print_string( +PRINTBLK * io) +{ + io->index = 0; + fc_print( (char *)&io->buf[0],0,0); +} /* print_string */ + +/*VARARGS*/ +/*****************************************/ +/** fmtout **/ +/** Low-level string print routines. **/ +/*****************************************/ +_local_ +int fmtout ( +uchar *ostr, /* Output buffer, or NULL if temp */ +uchar *control, /* Control string */ +va_list inarg) /* Argument list */ +{ + short temp; /* Output channel number if string NULL. */ + int leftadj; /* Negative pararameter width specified. */ + int longflag; /* Integer is long. */ + int box = FALSE; /* not from body */ + int chr; /* control string character */ + uchar padchar; /* Pad character, typically space. */ + int width; /* Width of subfield. */ + int length; /* Length of subfield. */ + uchar *altctl; /* temp control string */ + ARGLIST altarg; + ARGLIST arg; + PRINTBLK io; + + union { /* Accumulate parameter value here. */ + uint16 tlong; + uint16 tulong; + long ltlong; + ulong ltulong; + uchar str[4]; + uint16 twds[2]; + } lw; + + union { /* Used by case %c */ + int intchar; + uchar chr[2]; + } ichar; + + arg.uip = (ulong *)inarg; + io.index = 0; + io.count = 0; + + if( (io.string = ostr) != (uchar *)NULL) + *ostr = 0; /* initialize output string to null */ + control--; + + mainloop: + altctl = NULL; + + while ((length = *++control) != 0) + { /* while more in control string */ + if (length !='%') { /* format control */ + if ((length == '\n') && box) { + fc_print( (char *)&io.buf[0],0,0); + continue; + } + if (add_char( &io, (uchar) length) >= MAX_IO_SIZE) + print_string(&io); /* write it */ + continue; + } + leftadj = (*++control == '-'); + if (leftadj) + ++control; + padchar = ' '; + width = 0; + if ((uint16)(length = (*control - '0')) <= 9) { + if (length == 0) + padchar = '0'; + width = length; + while ((uint16)(length = (*++control - '0')) <= 9 ) + width = width*10+length; + } + longflag = ( *control == 'l'); + if ( longflag) + ++control; + + chr = (int)(*control); + if( chr != 'E') { + chr |= 0x20; + } + + switch (chr) { + case 'a': + longflag = 1; + temp=16; + padchar = '0'; + length = width = 8; + goto nosign; + case 'b': + temp=2; + goto nosign; + case 'o': + temp=8; + goto nosign; + case 'u': + temp=10; + goto nosign; + case 'x': + temp=16; + goto nosign; + + case 'e': + ostr = (uchar *)va_arg(inarg, char *); + if ((chr == 'e') && + ((*(long *)ostr) == (long)NULL) && + ((*(uint16 *)&ostr[4]) == (uint16)0)) { + ostr = (uchar *)ds_unknown; + length = 7; + break; + } + temp = -1; + length = MAX_IO_SIZE -1; + fc_strcpy((char *)&io.buf[MAX_IO_SIZE], + "00-00-00-00-00-00"); /* dst, src */ + do { + long_itos((long)( ostr[++temp] + 256), lw.str, 16); + io.buf[++length] = lw.str[1]; + io.buf[++length] = lw.str[2]; + } while (++length < MAX_IO_SIZE+17); + ostr = &io.buf[MAX_IO_SIZE]; + length = 17; + break; + + case 'E': + ostr = (uchar *)va_arg(inarg, char *); + if ((chr == 'E') && + ((*(long *)ostr) == (long)NULL) && + ((*(long *)&ostr[4]) == (long)NULL)) { + ostr = (uchar *)ds_unknown; + length = 7; + break; + } + temp = -1; + length = MAX_IO_SIZE -1; + fc_strcpy( (char *)&io.buf[MAX_IO_SIZE], + "00-00-00-00-00-00-00-00"); /* dst, src */ + do { + long_itos((long)( ostr[++temp] + 256), lw.str, 16); + io.buf[++length] = lw.str[1]; + io.buf[++length] = lw.str[2]; + } while (++length < MAX_IO_SIZE+23); + ostr = &io.buf[MAX_IO_SIZE]; + length = 23; + break; + + case 'f': /* flags */ + ostr = (uchar *)ds_disabled; + length = 8; + if (va_arg(inarg, char *) != 0) { /* test value */ + ostr = (uchar *)ds_enabled; + length = 7; + } + if (chr == 'F') { + length -= 7; + ostr = (uchar *)"-"; + } + break; + + case 'i': + ostr = (uchar *)va_arg(inarg, char *); + if ((chr == 'i') && *(long *)ostr == (long)NULL) + goto putnone; + temp = 0; + length = MAX_IO_SIZE; + do { + length += long_itos((long) ostr[temp], &io.buf[length], 10); + if ( ++temp >= 4) + break; + io.buf[length] = '.'; + length++; + } while (TRUE); + ostr = &io.buf[MAX_IO_SIZE]; + length -= MAX_IO_SIZE; + break; + + case 'y': /* flags */ + if ( va_arg(inarg, char *) != 0) { /* test value */ + ostr = (uchar*)"yes"; + length = 3; + } + else { + ostr = (uchar*)"no"; + length = 2; + } + break; + + case 'c': + if (chr == 'C') { /* normal, control, or none */ + if ((length = va_arg(inarg, int)) < ' ') { + if (length == 0) { + ostr = (uchar *)ds_none; + length = 4; + } + else { + io.buf[MAX_IO_SIZE] = '^'; + io.buf[MAX_IO_SIZE+1] = ((uchar)length) + '@'; + io.buf[MAX_IO_SIZE+2] = 0; + ostr = &io.buf[MAX_IO_SIZE]; + length = 2; + } + arg.ip++; + break; + } + } /* normal, control, or none */ + + ichar.intchar = va_arg(inarg, int); + ostr = &ichar.chr[0]; + length=1; + break; + + case 'd': + temp = -10; + nosign: + if (longflag) + lw.ltulong = va_arg(inarg, ulong); + else if (temp < 0) + lw.ltlong = va_arg(inarg, long); + else + lw.ltulong = va_arg(inarg, ulong); +/* + nosign2: +*/ + length = long_itos( lw.ltlong, ostr = &io.buf[MAX_IO_SIZE], temp); + break; + + case 's': + ostr = (uchar *)va_arg(inarg, char *); /* string */ + if ((chr == 's') || (*ostr != '\0')) { + length = expanded_len(ostr); + break; + } + putnone: + ostr = (uchar *)ds_none; + length = 4; + break; + + case 't': /* tabbing */ + if ((width -= io.count) < 0) /* Spaces required to get to column. */ + width = 0; + length = 0; /* nothing other than width padding. */ + ostr = (uchar *)ds_null_string; + break; + case ' ': + width = va_arg(inarg, int); + length = 0; /* nothing other than width padding. */ + ostr = (uchar *)ds_null_string; + break; + + default: + ostr=control; + length=1; + break; + } /* switch on control */ + + if (length < 0) { /* non printing */ + if (add_string( &io, ostr) >= MAX_IO_SIZE) + print_string(&io); /* no more room, dump current buffer */ + continue; + } /* non printing */ + + + if (!leftadj && width > length) { + while (--width >= length) { + if (add_char( &io, padchar) >= MAX_IO_SIZE) + print_string(&io); /* write it */ + } + } + + if (width>length) + width -= length; + else + width = 0; + + if (length <= 1) { + if (length == 1) { + if (add_char( &io, *ostr) >= MAX_IO_SIZE) + print_string(&io); /* write it */ + } + } + else { + while ((temp = *ostr++) != 0) { + if (add_char( &io, (uchar) temp) >= MAX_IO_SIZE) + print_string(&io); /* write it */ + } + } + + while (--width >= 0) { + if (add_char( &io, padchar) >= MAX_IO_SIZE) + print_string(&io); /* write it */ + } + + } /* while more in control string */ + + if (altctl != NULL) { + control = altctl; + arg.ip = altarg.ip; + goto mainloop; + } + + if (io.index) /* anything left? */ + print_string(&io); /* write it */ + + return(io.count); +} /* fmtout */ +/*FIXARGS*/ +_local_ int +fc_sprintf_fargs( +uchar *string, /* output buffer */ +void *control, /* format string */ +char *fixArgs) /* control arguments */ +{ + return( fmtout((uchar *)string, (uchar *)control, fixArgs)); +} /* fc_sprintf_fargs */ +/*VARARGS*/ +int fc_sprintf_vargs( + void *string, /* output buffer */ + void *control, /* format string */ + ...) /* control arguments */ +{ + int iocnt; + va_list args; + va_start(args, control); + + iocnt = fmtout((uchar *)string, (uchar *)control, args); + va_end( args); + return( iocnt); +} /* fc_sprintf_vargs */ +/****************************************/ +/** fc_log_printf_msg_vargs **/ +/****************************************/ +/* +All log messages come through this routine. +All log messages are unique. +All log messages are define by a msgLogDef messages structure. +*/ +/*VARARGS*/ +_static_ int +fc_log_printf_msg_vargs( + int brdno, + msgLogDef * msg, /* Pionter to LOG msg structure */ + void * control, + ...) +{ + uchar str2[MAX_IO_SIZE + MAX_TBUFF]; /* extra room to convert numbers */ + int iocnt; + int log_only; + va_list args; + va_start(args, control); + + log_only = 0; + if( fc_check_this_log_msg_disabled( brdno, msg, &log_only)) + return(0); /* This LOG message disabled */ + + /* + If LOG message is disabled via any SW method, we SHOULD NOT get this far! + We should have taken the above return. + */ + + str2[0] = '\0'; + iocnt = fc_sprintf_fargs(str2, control, args); + va_end( args); + + return( log_printf_msgblk( brdno, msg, (char *)str2, log_only)); +} /* fc_log_printf_msg_vargs */ + +/*****************************************************/ +/** Function name : fc_check_this_log_msg_disabled **/ +/** **/ +/** Description : **/ +/** **/ +/** Return : 0 LOG message enabled **/ +/** : 1 LOG message disabled **/ +/*****************************************************/ +int fc_check_this_log_msg_disabled( int brdno, + msgLogDef *msg, + int *log_only) +{ + fc_dev_ctl_t * p_dev_ctl; + iCfgParam * clp; + int verbose; + + verbose = 0; + if( msg->msgOutput == FC_MSG_OPUT_DISA) + return(1); /* This LOG message disabled */ + + if ((p_dev_ctl = DD_CTL.p_dev[brdno])) { + clp = DD_CTL.p_config[brdno]; + if((*log_only = clp[CFG_LOG_ONLY].a_current) > 1) + return(1); /* This LOG message disabled */ + verbose = clp[CFG_LOG_VERBOSE].a_current; + } + + if( msg->msgOutput == FC_MSG_OPUT_FORCE) + return(0); /* This LOG message enabled */ + /* + * If this is a verbose message (INFO or WARN) and we are not in + * verbose mode, return 1. If it is a verbose message and the verbose + * error doesn't match our verbose mask, return 1. + */ + if( (msg->msgType == FC_LOG_MSG_TYPE_INFO) || + (msg->msgType == FC_LOG_MSG_TYPE_WARN)) { + /* LOG msg is INFO or WARN */ + if ((msg->msgMask & verbose) == 0) + return(1); /* This LOG mesaage disabled */ + } + return(0); /* This LOG message enabled */ +} /* fc_check_this_log_msg_disabled */ + +/*************************************************/ +/** fc_asc_to_hex **/ +/** Convert an ASCII hex character to hex. **/ +/** Return Hex value if success **/ +/** -1 if character not ASCII hex **/ +/*************************************************/ + +_forward_ int +fc_asc_to_hex( + uchar c) /* Character to convert */ +{ +if (c >= '0' && c <= '9') + return(c - '0'); +else if (c >= 'A' && c <= 'F') + return(c - 'A'+ 10); +else if (c >= 'a' && c <= 'f') + return(c - 'a'+ 10); +else + return(-1); +} /* fc_asc_to_hex */ + +/***************************************************/ +/** fc_asc_seq_to_hex **/ +/** **/ +/** Convert an ASCII character sequence to a **/ +/** hex number sequence **/ +/** **/ +/** return >0 Success. Return number of ASCII **/ +/** hex characters converted. **/ +/** -1 Input byte count < 1 **/ +/** -2 Input byte count > max **/ +/** -3 Output buffer to small **/ +/** -4 Input character sequence not **/ +/** ASCII hex. **/ +/***************************************************/ + +/* +This routine converts an ASCII char stream of byte into +a stream of hex bytes. The byte order of the input and +output stream are identical. The caller must deal with +SWAPPING bytes if required. + +The maximum number of ASCII hex characters that can be +convert to hex is hard coded by the LOCAL define +MAX_ASC_HEX_CHARS_INPUT. + +Two ASCII hex input characters require 1 byte of output +buffer. + +A NULL terminator at the end of an ASCII hex input string +is not required nor is it counted in the strings byte size. + +To determine the byte size of the output buffer: +(1) Add 1 to input buffer byte size if size is odd. +(2) Output buffer size = input buffer size / 2. + +Therefore an input buffer containing 10 ASC hex chars +requires an output buffer size of 5 bytes. + +An input buffer containing 11 ASC hex chars requires an +output buffer size of 6 bytes. +*/ + +_forward_ int +fc_asc_seq_to_hex( fc_dev_ctl_t *p_dev_ctl, + int input_bc, /* Number of bytes (ASC hex chars) to be converted */ + int output_bc, /* Number of bytes in hex output buffer (modulo INT) */ + char *inp, /* Pointer to ASC hex input character sequence */ + char *outp) /* Pointer to hex output buffer */ +{ +#define HEX_DIGITS_PER_BYTE 2 +#define MAX_ASC_HEX_CHARS_INPUT 32 /* Limit damage if over-write */ +#define MAX_BUF_SIZE_HEX_OUTPUT (MAX_ASC_HEX_CHARS_INPUT / HEX_DIGITS_PER_BYTE) + + FC_BRD_INFO *binfo; + int lowNib, hiNib; + int inputCharsConverted; + uchar twoHexDig; + + binfo = &BINFO; + inputCharsConverted = 0; + lowNib = -1; + hiNib = -1; + + if(input_bc < 1) { + /* Convert ASC to hex. Input byte cnt < 1. */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk1210, /* ptr to msg structure */ + fc_mes1210, /* ptr to msg */ + fc_msgBlk1210.msgPreambleStr); /* begin & end varargs */ + return(-1); + } + if(input_bc > MAX_ASC_HEX_CHARS_INPUT) { + /* Convert ASC to hex. Input byte cnt > max */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk1211, /* ptr to msg structure */ + fc_mes1211, /* ptr to msg */ + fc_msgBlk1211.msgPreambleStr, /* begin varargs */ + MAX_ASC_HEX_CHARS_INPUT); /* end varargs */ + return(-2); + } + if((output_bc * 2) < input_bc) { + /* Convert ASC to hex. Output buffer to small. */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk1212, /* ptr to msg structure */ + fc_mes1212, /* ptr to msg */ + fc_msgBlk1212.msgPreambleStr); /* begin & end varargs */ + return(-4); + } + + while( input_bc) { + twoHexDig = 0; + lowNib = -1; + hiNib = fc_asc_to_hex( *inp++); + if( --input_bc > 0) { + lowNib = fc_asc_to_hex( *inp++); + input_bc--; + } + if ((lowNib < 0) || (hiNib < 0)) { + /* Convert ASC to hex. Input char seq not ASC hex. */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk1213, /* ptr to msg structure */ + fc_mes1213, /* ptr to msg */ + fc_msgBlk1213.msgPreambleStr); /* begin & end varargs */ + return( -4); + } + if( lowNib >= 0) { + /* There were 2 digits */ + hiNib <<= 4; + twoHexDig = (hiNib | lowNib); + inputCharsConverted += 2; + } + else { + /* There was a single digit */ + twoHexDig = lowNib; + inputCharsConverted++; + } + *outp++ = twoHexDig; + } /* while */ + return(inputCharsConverted); /* ASC to hex conversion complete. Return # of chars converted */ +} /* fc_asc_seq_to_hex */ + +/********************************************/ +/** fc_is_digit **/ +/** **/ +/** Check if ASCII input value is numeric. **/ +/** **/ +/** Return 0 = input NOT numeric **/ +/** 1 = input IS numeric **/ +/********************************************/ +_forward_ int +fc_is_digit(int chr) +{ + if( (chr >= '0') && (chr <= '9')) + return(1); + return(0); +} /* fc_is_digit */ + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/fcstratb.c 830-ivtv/drivers/scsi/lpfc/fcstratb.c --- 000-virgin/drivers/scsi/lpfc/fcstratb.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/fcstratb.c Thu Jan 8 10:21:53 2004 @@ -0,0 +1,2080 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Enterprise Fibre Channel Host Bus Adapters. * + * Refer to the README file included with this package for * + * driver version and adapter support. * + * Copyright (C) 2003 Emulex Corporation. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details, a copy of which * + * can be found in the file COPYING included with this package. * + *******************************************************************/ + +#include "fc_os.h" + +#include "fc_hw.h" +#include "fc.h" + +#include "fcdiag.h" +#include "fcfgparm.h" +#include "fcmsg.h" +#include "fc_crtn.h" +#include "fc_ertn.h" + +extern fc_dd_ctl_t DD_CTL; +extern iCfgParam icfgparam[]; + + + + +/* Some timers in data structures are stored in seconds, some environments + * timeout functions work in ticks, thus some conversion is required. + * Other externs, as needed for environemt are defined here. + */ +extern uint32 fc_scsi_abort_timeout_ticks; +extern uint32 fc_ticks_per_second; + + + + +/* Routine Declaration - Local */ +_local_ void fc_deq_abort_bdr(dvi_t *dev_ptr); +_local_ void fc_deq_wait(dvi_t *dev_ptr); +/* End Routine Declaration - Local */ + +/* AlpaArray for assignment of scsid for scan-down == 2 */ +_static_ uchar AlpaArray[] = + { + 0xEF, 0xE8, 0xE4, 0xE2, 0xE1, 0xE0, 0xDC, 0xDA, 0xD9, 0xD6, + 0xD5, 0xD4, 0xD3, 0xD2, 0xD1, 0xCE, 0xCD, 0xCC, 0xCB, 0xCA, + 0xC9, 0xC7, 0xC6, 0xC5, 0xC3, 0xBC, 0xBA, 0xB9, 0xB6, 0xB5, + 0xB4, 0xB3, 0xB2, 0xB1, 0xAE, 0xAD, 0xAC, 0xAB, 0xAA, 0xA9, + 0xA7, 0xA6, 0xA5, 0xA3, 0x9F, 0x9E, 0x9D, 0x9B, 0x98, 0x97, + 0x90, 0x8F, 0x88, 0x84, 0x82, 0x81, 0x80, 0x7C, 0x7A, 0x79, + 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x6E, 0x6D, 0x6C, 0x6B, + 0x6A, 0x69, 0x67, 0x66, 0x65, 0x63, 0x5C, 0x5A, 0x59, 0x56, + 0x55, 0x54, 0x53, 0x52, 0x51, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, + 0x49, 0x47, 0x46, 0x45, 0x43, 0x3C, 0x3A, 0x39, 0x36, 0x35, + 0x34, 0x33, 0x32, 0x31, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, + 0x27, 0x26, 0x25, 0x23, 0x1F, 0x1E, 0x1D, 0x1B, 0x18, 0x17, + 0x10, 0x0F, 0x08, 0x04, 0x02, 0x01 + }; + + +_static_ dvi_t * +fc_fcp_abort( + fc_dev_ctl_t * p_dev_ctl, + int flag, + int target, + int lun) +{ + FC_BRD_INFO * binfo; + node_t * node_ptr; + dvi_t * dev_ptr; + dvi_t * xmt_devp, * devp; + RING * rp; + int i; + + binfo = &BINFO; + if(binfo->fc_flag & FC_ESTABLISH_LINK) + return(0); + + rp = &binfo->fc_ring[FC_FCP_RING]; + xmt_devp = 0; + /* Clear the queues for one or more SCSI devices + * flag will indicate perform a Target Reset, Lun Reset, or Abort Task Set + * if target = -1, all targets (bus reset). + * if lun = -1 all luns on the target. + */ + for (i = 0; i < MAX_FC_TARGETS; i++) { + if ((node_ptr = binfo->device_queue_hash[i].node_ptr) != NULL) { + if ((target != -1) && (node_ptr->scsi_id != target)) + continue; + dev_ptr = node_ptr->lunlist; + if((flag == TARGET_RESET) && + (dev_ptr != NULL)) { + if((node_ptr->rpi != 0xFFFE) && (binfo->fc_ffstate == FC_READY)) { + if(dev_ptr->flags & (SCSI_LUN_RESET | SCSI_ABORT_TSET)) { + /* check if we sent abort task set or reset lun */ + for (devp = p_dev_ctl->ABORT_BDR_head; (devp != NULL); + devp = devp->ABORT_BDR_fwd) { + if(devp == dev_ptr) + break; + } + if(devp) { + /* we found devp, its not sent yet, + * so change it to target reset. + */ + dev_ptr->flags &= ~CHK_SCSI_ABDR; + dev_ptr->flags |= SCSI_TARGET_RESET; + } + else { + /* just Q another task mgmt cmd, target reset */ + dev_ptr->flags |= SCSI_TARGET_RESET; + fc_enq_abort_bdr(dev_ptr); + } + xmt_devp = dev_ptr; + } + else if(!(dev_ptr->flags & SCSI_TARGET_RESET)) { + dev_ptr->flags |= SCSI_TARGET_RESET; + fc_enq_abort_bdr(dev_ptr); + fc_issue_cmd(p_dev_ctl); + xmt_devp = dev_ptr; + } + } + } + for (dev_ptr = node_ptr->lunlist; dev_ptr != NULL; + dev_ptr = dev_ptr->next) { + if ((lun != -1) && (dev_ptr->lun_id != lun)) + continue; + + if(flag == TARGET_RESET) { + if((node_ptr->rpi != 0xFFFE) && (binfo->fc_ffstate == FC_READY)) { + dev_ptr->flags |= SCSI_TARGET_RESET; + dev_ptr->queue_state = HALTED; + fc_fail_pendq(dev_ptr, (char) EIO, 0); + } + else { + /* First send ABTS on outstanding I/Os in txp queue */ + fc_abort_fcp_txpq(binfo, dev_ptr); + + fc_fail_pendq(dev_ptr, (char) EIO, 0); + fc_fail_cmd(dev_ptr, (char) EIO, 0); + } + } + + if((flag == LUN_RESET) && + !(dev_ptr->flags & CHK_SCSI_ABDR)) { + + if((node_ptr->rpi != 0xFFFE) && (binfo->fc_ffstate == FC_READY)) { + dev_ptr->flags |= SCSI_LUN_RESET; + fc_enq_abort_bdr(dev_ptr); + fc_issue_cmd(p_dev_ctl); + xmt_devp = dev_ptr; + dev_ptr->queue_state = HALTED; + fc_fail_pendq(dev_ptr, (char) EIO, 0); + } + else { + /* First send ABTS on outstanding I/Os in txp queue */ + fc_abort_fcp_txpq(binfo, dev_ptr); + + fc_fail_pendq(dev_ptr, (char) EIO, 0); + fc_fail_cmd(dev_ptr, (char) EIO, 0); + } + } + + if((flag == ABORT_TASK_SET) && + !(dev_ptr->flags & CHK_SCSI_ABDR)) { + + if((node_ptr->rpi != 0xFFFE) && (binfo->fc_ffstate == FC_READY)) { + dev_ptr->flags |= SCSI_ABORT_TSET; + fc_enq_abort_bdr(dev_ptr); + fc_issue_cmd(p_dev_ctl); + xmt_devp = dev_ptr; + dev_ptr->queue_state = HALTED; + fc_fail_pendq(dev_ptr, (char) EIO, 0); + } + else { + /* First send ABTS on outstanding I/Os in txp queue */ + fc_abort_fcp_txpq(binfo, dev_ptr); + + fc_fail_pendq(dev_ptr, (char) EIO, 0); + fc_fail_cmd(dev_ptr, (char) EIO, 0); + } + } + } + } + } + return(xmt_devp); +} + +_static_ int +issue_abdr( + fc_dev_ctl_t * ap, + dvi_t * dev_ptr, + RING * rp, + fc_lun_t lun) +{ + FC_BRD_INFO * binfo; + iCfgParam * clp; + fc_buf_t * fcptr; + T_SCSIBUF * sbp; + IOCB * cmd; + IOCBQ * temp; + uint32 * lp; + MATCHMAP * bmp; + ULP_BDE64 * bpl; + int i; + + binfo = &ap->info; + if ((fcptr = fc_deq_fcbuf(dev_ptr)) == NULL) { + return(EIO); + } + + if ((temp = (IOCBQ * )fc_mem_get(binfo, MEM_IOCB)) == NULL) { + fc_enq_fcbuf(fcptr); + return(EIO); + } + + { + uint32 did; + uint32 pan; + uint32 sid; + + if ((dev_ptr->nodep) && (dev_ptr->nodep->nlp)) { + did = dev_ptr->nodep->nlp->nlp_DID; + pan = dev_ptr->nodep->nlp->id.nlp_pan; + sid = dev_ptr->nodep->nlp->id.nlp_sid; + } else { + did = 0; + pan = 0; + sid = 0; + } + + if (dev_ptr->flags & SCSI_ABORT_TSET) { + /* Issue Abort Task Set I/O for LUN */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0701, /* ptr to msg structure */ + fc_mes0701, /* ptr to msg */ + fc_msgBlk0701.msgPreambleStr, /* begin varargs */ + (uint32)lun, + did, + FC_SCSID(pan, sid), + dev_ptr->flags); /* end varargs */ + } else if (dev_ptr->flags & SCSI_TARGET_RESET) { + /* Issue Target Reset I/O */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0702, /* ptr to msg structure */ + fc_mes0702, /* ptr to msg */ + fc_msgBlk0702.msgPreambleStr, /* begin varargs */ + (uint32)lun, + did, + FC_SCSID(pan, sid), + dev_ptr->flags); /* end varargs */ + } else if (dev_ptr->flags & SCSI_LUN_RESET) { + /* Issue LUN Reset I/O for LUN */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0703, /* ptr to msg structure */ + fc_mes0703, /* ptr to msg */ + fc_msgBlk0703.msgPreambleStr, /* begin varargs */ + (uint32)lun, + did, + FC_SCSID(pan, sid), + dev_ptr->flags); /* end varargs */ + } + } + + sbp = &dev_ptr->scbuf; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + + fc_bzero((void *)fcptr, sizeof(FCP_CMND) + sizeof(FCP_RSP)); + + /* shift lun id into the right payload byte */ + fcptr->fcp_cmd.fcpLunMsl = lun << FC_LUN_SHIFT; + fcptr->fcp_cmd.fcpLunLsl = 0; + if (dev_ptr->nodep->addr_mode == VOLUME_SET_ADDRESSING) { + fcptr->fcp_cmd.fcpLunMsl |= SWAP_DATA(0x40000000); + } + + fcptr->sc_bufp = sbp; + fcptr->flags = 0; + sbp->bufstruct.b_flags = 0; + sbp->bufstruct.b_error = 0; + + if (dev_ptr->flags & SCSI_ABORT_TSET) { + /* Issue an Abort Task Set task management command */ + fcptr->fcp_cmd.fcpCntl2 = ABORT_TASK_SET; + } else if (dev_ptr->flags & SCSI_TARGET_RESET) { + /* Issue a Target Reset task management command */ + fcptr->fcp_cmd.fcpCntl2 = TARGET_RESET; + } else if (dev_ptr->flags & SCSI_LUN_RESET) { + /* Issue a Lun Reset task management command */ + fcptr->fcp_cmd.fcpCntl2 = LUN_RESET; + } + + /* set up an iotag so we can match the completion iocb */ + for (i = 0; i < MAX_FCP_CMDS; i++) { + fcptr->iotag = rp->fc_iotag++; + if (rp->fc_iotag >= MAX_FCP_CMDS) + rp->fc_iotag = 1; + if (binfo->fc_table->fcp_array[fcptr->iotag] == 0) + break; + } + + if (i >= MAX_FCP_CMDS) { + /* No more command slots available, retry later */ + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + fc_enq_fcbuf(fcptr); + return(EIO); + } + + fc_bzero((void *)temp, sizeof(IOCBQ)); /* zero the iocb entry */ + cmd = &temp->iocb; + + if (binfo->fc_flag & FC_SLI2) { + /* Allocate buffer for Buffer ptr list */ + if ((bmp = (MATCHMAP * )fc_mem_get(binfo, MEM_BPL)) == 0) { + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + fc_enq_fcbuf(fcptr); + return(EIO); + } + bpl = (ULP_BDE64 * )bmp->virt; + bpl->addrHigh = PCIMEM_LONG((uint32)putPaddrHigh(GET_PAYLOAD_PHYS_ADDR(fcptr))); + bpl->addrLow = PCIMEM_LONG((uint32)putPaddrLow(GET_PAYLOAD_PHYS_ADDR(fcptr))); + bpl->tus.f.bdeSize = sizeof(FCP_CMND); + bpl->tus.f.bdeFlags = BUFF_USE_CMND; + bpl->tus.w = PCIMEM_LONG(bpl->tus.w); + + bpl++; + bpl->addrHigh = PCIMEM_LONG((uint32)putPaddrHigh(GET_PAYLOAD_PHYS_ADDR(fcptr)+sizeof(FCP_CMND))); + bpl->addrLow = PCIMEM_LONG((uint32)putPaddrLow(GET_PAYLOAD_PHYS_ADDR(fcptr)+sizeof(FCP_CMND))); + bpl->tus.f.bdeSize = sizeof(FCP_RSP); + bpl->tus.f.bdeFlags = (BUFF_USE_CMND | BUFF_USE_RCV); + bpl->tus.w = PCIMEM_LONG(bpl->tus.w); + + bpl++; + cmd->un.fcpi64.bdl.ulpIoTag32 = (uint32)0; + cmd->un.fcpi64.bdl.addrHigh = (uint32)putPaddrHigh(bmp->phys); + cmd->un.fcpi64.bdl.addrLow = (uint32)putPaddrLow(bmp->phys); + cmd->un.fcpi64.bdl.bdeSize = (2 * sizeof(ULP_BDE64)); + cmd->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BDL; + + cmd->ulpCommand = CMD_FCP_ICMND64_CR; + cmd->ulpBdeCount = 1; + fcptr->bmp = bmp; + temp->bpl = (uchar *)0; + } else { + cmd->un.fcpi.fcpi_cmnd.bdeAddress = (uint32)putPaddrLow(GET_PAYLOAD_PHYS_ADDR(fcptr)); + cmd->un.fcpi.fcpi_cmnd.bdeSize = sizeof(FCP_CMND); + cmd->un.fcpi.fcpi_rsp.bdeAddress = (uint32)(putPaddrLow((GET_PAYLOAD_PHYS_ADDR(fcptr) + sizeof(FCP_CMND)))); + cmd->un.fcpi.fcpi_rsp.bdeSize = sizeof(FCP_RSP); + cmd->ulpCommand = CMD_FCP_ICMND_CR; + cmd->ulpBdeCount = 2; + temp->bpl = (uchar *)0; + } + cmd->ulpContext = dev_ptr->nodep->rpi; + cmd->ulpIoTag = fcptr->iotag; + cmd->ulpClass = (dev_ptr->nodep->nlp->id.nlp_fcp_info & 0x0f); + cmd->ulpOwner = OWN_CHIP; + cmd->ulpLe = 1; + + /* Timeout for this command is 30 seconds */ + curtime(&fcptr->timeout); + + + /* Need to set the FCP timeout in the fcptr structure and the IOCB + * for this I/O to get the adapter to run a timer. + */ + { + uint32 time_out; + + time_out = fc_scsi_abort_timeout_ticks; + if (binfo->fc_flag & FC_FABRIC) { + time_out += (fc_ticks_per_second * + (clp[CFG_FCPFABRIC_TMO].a_current + (2 * binfo->fc_ratov))); + } + + fcptr->timeout = ((ulong)fcptr->timeout + time_out + fc_scsi_abort_timeout_ticks); + + /* Set the FCP timeout in the IOCB to get the adapter to run a timer */ + if ((time_out / fc_ticks_per_second) < 256) + cmd->ulpTimeout = time_out / fc_ticks_per_second; + + } + + lp = (uint32 * ) & fcptr->fcp_cmd; + dev_ptr->active_io_count++; + dev_ptr->nodep->num_active_io++; + + /* Queue command to last iocb entry in xmit queue */ + if (rp->fc_tx.q_first == NULL) { + rp->fc_tx.q_first = (uchar * )temp; + } else { + ((IOCBQ * )(rp->fc_tx.q_last))->q = (uchar * )temp; + } + rp->fc_tx.q_last = (uchar * )temp; + rp->fc_tx.q_cnt++; + + fc_enq_fcbuf_active(rp, fcptr); + return (0); +} + + +/************************************************************************/ +/* */ +/* NAME: fc_issue_cmd */ +/* */ +/* FUNCTION: issues a waiting FCP command, or ABORT/BDR command */ +/* */ +/* EXECUTION ENVIRONMENT: */ +/* Called by a process or the interrupt handler */ +/* */ +/* INPUTS: */ +/* ap pointer to the adapter structure */ +/* */ +/* RETURN VALUE DESCRIPTION: none */ +/* */ +/* ERROR DESCRIPTION: none */ +/* */ +/* EXTERNAL PROCEDURES CALLED: */ +/* iodone */ +/************************************************************************/ +_static_ void +fc_issue_cmd( + fc_dev_ctl_t * ap) +{ + dvi_t * dev_ptr, * requeue_ptr; + T_SCSIBUF * sbp; + int rc, requeue, exit; + FC_BRD_INFO * binfo; + RING * rp; + node_t * nodep; + + binfo = &ap->info; + if(binfo->fc_flag & FC_ESTABLISH_LINK) + return; + + rp = &binfo->fc_ring[FC_FCP_RING]; + + /* ALUN */ + /* If the abort/bdr queue is not empty we deal with it first */ + for (dev_ptr = ap->ABORT_BDR_head; (dev_ptr != NULL); + dev_ptr = ap->ABORT_BDR_head) { + + if(dev_ptr->flags & CHK_SCSI_ABDR) { + rc = issue_abdr(ap, dev_ptr, rp, dev_ptr->lun_id); + if (rc != 0) { + break; + } + } + + fc_deq_abort_bdr(dev_ptr); + } + + requeue_ptr = NULL; + exit = 0; + + /* See if there is something on the waiting queue */ + while (((dev_ptr = ap->DEVICE_WAITING_head) != NULL) + && (binfo->fc_ffstate == FC_READY) + && (dev_ptr != requeue_ptr)) { + + nodep = dev_ptr->nodep; + /* Check if a target queue depth is set */ + if (nodep->rptlunstate == REPORT_LUN_ONGOING) { + requeue = 1; + } else if (nodep->tgt_queue_depth && + (nodep->tgt_queue_depth == nodep->num_active_io)) { + if (dev_ptr->nodep->last_dev == NULL) + dev_ptr->nodep->last_dev = dev_ptr; + requeue = 1; + } else if (dev_ptr->flags & (CHK_SCSI_ABDR | SCSI_TQ_HALTED)) { + requeue = 1; + } else { + requeue = 0; + + while ((sbp = dev_ptr->pend_head) != NULL) + { + if ((dev_ptr->active_io_count >= dev_ptr->fcp_cur_queue_depth) || + (dev_ptr->stop_send_io)) { + requeue = 1; + break; + } + if ((rc = issue_fcp_cmd(ap, dev_ptr, sbp, 1))) { + if (rc & FCP_REQUEUE) { + requeue = 1; + break; + } else if (rc & FCP_EXIT) { + exit = 1; + break; + } + continue; + } + dev_ptr->pend_count--; + dev_ptr->pend_head = (T_SCSIBUF *) sbp->bufstruct.av_forw; + if (dev_ptr->pend_head == NULL) + dev_ptr->pend_tail = NULL; + else + dev_ptr->pend_head->bufstruct.av_back = NULL; + + /* Check if a target queue depth is set */ + if (nodep->tgt_queue_depth && + (nodep->tgt_queue_depth == nodep->num_active_io)) { + /* requeue I/O if max cmds to tgt are outstanding */ + if (dev_ptr->nodep->last_dev == NULL) + dev_ptr->nodep->last_dev = dev_ptr; + requeue = 1; + break; + } + } /* while pend_head */ + } + if (exit) + break; + + fc_deq_wait(dev_ptr); + + if (requeue) { + if (requeue_ptr == NULL) + requeue_ptr = dev_ptr; + fc_enq_wait(dev_ptr); + } + + } /* while wait queue */ + + if (rp->fc_tx.q_cnt) { + issue_iocb_cmd(binfo, rp, 0); + /* [SYNC] */ + if (binfo->fc_flag & FC_POLL_MODE) { + fc_polling(binfo, HA_R2ATT); + } + } + + return; + +} /* End fc_issue_cmd */ + + +/**************************************************************************/ +/* */ +/* NAME: fc_enq_fcbuf_active, fc_enq_wait, fc_enq_fcbuf, fc_enq_abort_bdr */ +/* */ +/* FUNCTION: */ +/* Utility routines to handle queuing of device structures to each */ +/* of the queues in use. */ +/* */ +/* EXECUTION ENVIRONMENT: */ +/* */ +/* RETURN VALUE DESCRIPTION: none */ +/* */ +/* ERROR DESCRIPTION: The following errno values may be returned: */ +/* none */ +/* */ +/**************************************************************************/ +_static_ void +fc_enq_fcbuf_active( +RING *rp, /* Pointer to ring for fcbufs */ +fc_buf_t *fcptr) /* Pointer to fcbuf to enqueue */ +{ + FC_BRD_INFO * binfo; + fc_dev_ctl_t *p_dev_ctl; + + binfo = (FC_BRD_INFO * )(rp->fc_binfo); + p_dev_ctl = (fc_dev_ctl_t *)(binfo->fc_p_dev_ctl); + /* Sync the FCP_CMND payload data */ + /* Use correct offset and size for syncing */ + fc_mpdata_sync(fcptr->fc_cmd_dma_handle, (off_t)fcptr->offset, + sizeof(FCP_CMND), DDI_DMA_SYNC_FORDEV); + + /* Enqueue the fcbuf on the FCP ring active queue */ + if (rp->fc_txp.q_first) { + fcptr->fc_bkwd = (fc_buf_t * )rp->fc_txp.q_last; + ((fc_buf_t * )rp->fc_txp.q_last)->fc_fwd = fcptr; + rp->fc_txp.q_last = (uchar * )fcptr; + } else { + rp->fc_txp.q_first = (uchar * )fcptr; + rp->fc_txp.q_last = (uchar * )fcptr; + fcptr->fc_bkwd = NULL; + } + + fcptr->fc_fwd = NULL; + rp->fc_txp.q_cnt++; + if(rp->fc_txp.q_cnt > rp->fc_txp.q_max) { + rp->fc_txp.q_max = rp->fc_txp.q_cnt; + } + binfo->fc_table->fcp_array[fcptr->iotag] = fcptr; +} /* End fc_enq_fcbuf_active */ + + +/* + * Name: fc_enq_wait + * Function: Place dev_ptr on the adapter's wait queue. + * Input: dvi_t *dev_ptr dev_ptr to enqueue. + * Returns: nothing. + */ +_static_ void +fc_enq_wait( +dvi_t *dev_ptr) +{ + fc_dev_ctl_t * ap; + + ap = dev_ptr->nodep->ap; + + /* Queue the dev_ptr if it is not already on the queue */ + if ((dev_ptr->DEVICE_WAITING_fwd == NULL) + && (ap->DEVICE_WAITING_tail != dev_ptr)) { + + if (ap->DEVICE_WAITING_head == NULL) { + ap->DEVICE_WAITING_head = dev_ptr; + } else { + ap->DEVICE_WAITING_tail->DEVICE_WAITING_fwd = dev_ptr; + } + ap->DEVICE_WAITING_tail = dev_ptr; + } +} /* End fc_enq_wait */ + +/* ALUN */ +/* + * Name: fc_enq_fcbuf + * Function: Place fc_buf on the device's free queue. + * Input: fc_buf_t *fcptr fc_buf to enqueue + * Returns: nothing. + */ +_static_ void +fc_enq_fcbuf( +fc_buf_t *fcptr) +{ + dvi_t * dev_ptr; + + dev_ptr = fcptr->dev_ptr; + + if (dev_ptr->fcbuf_head == NULL) { + dev_ptr->fcbuf_head = fcptr; + } else { + dev_ptr->fcbuf_tail->fc_fwd = fcptr; + } + fcptr->fc_fwd = NULL; + dev_ptr->fcbuf_tail = fcptr; + dev_ptr->numfcbufs++; + + if (dev_ptr->numfcbufs == dev_ptr->fcp_lun_queue_depth) { + if (dev_ptr->flags & SCSI_TQ_CLEARING) { + /* Call iodone for all the CLEARQ error bufs */ + fc_free_clearq(dev_ptr); + } + if (dev_ptr->queue_state == STOPPING) { + /* If we are trying to close, check to see if all done */ + } + } + + return; +} /* End fc_enq_fcbuf */ + + +/* + * Name: fc_enq_abort_bdr + * Function: Place dev_ptr on the adapter's Bus Device Reset queue. + * Input: dvi_t *dev_ptr dev_ptr to enqueue. + * Returns: nothing. + */ +_static_ void +fc_enq_abort_bdr( + dvi_t * dev_ptr) +{ + fc_dev_ctl_t * ap; + + ap = dev_ptr->nodep->ap; + + if (ap->ABORT_BDR_head == NULL) { + dev_ptr->ABORT_BDR_fwd = NULL; + dev_ptr->ABORT_BDR_bkwd = NULL; + ap->ABORT_BDR_head = dev_ptr; + ap->ABORT_BDR_tail = dev_ptr; + } else { + dev_ptr->ABORT_BDR_bkwd = ap->ABORT_BDR_tail; + dev_ptr->ABORT_BDR_fwd = NULL; + ap->ABORT_BDR_tail->ABORT_BDR_fwd = dev_ptr; + ap->ABORT_BDR_tail = dev_ptr; + } +} /* End fc_enq_abort_bdr */ + + +/**************************************************************************/ +/* */ +/* NAME: fc_deq_fcbuf_active, fc_deq_wait, fc_deq_fcbuf, fc_deq_abort_bdr */ +/* */ +/* FUNCTION: */ +/* Utility routines to handle dequeueing device structures from */ +/* each of the queues in use. */ +/* */ +/* EXECUTION ENVIRONMENT: */ +/* */ +/* ERROR DESCRIPTION: The following errno values may be returned: */ +/* none */ +/* */ +/**************************************************************************/ +_static_ fc_buf_t * +fc_deq_fcbuf_active( + RING * rp, + ushort iotag) /* tag to match I/O */ +{ + FC_BRD_INFO * binfo; + fc_dev_ctl_t * p_dev_ctl; + fc_buf_t * fcptr = NULL; + + binfo = (FC_BRD_INFO * )(rp->fc_binfo); + p_dev_ctl = (fc_dev_ctl_t *)(binfo->fc_p_dev_ctl); + /* Remove an fcbuf from the FCP ring active queue based on iotag */ + + if ((iotag < MAX_FCP_CMDS) && + (fcptr = binfo->fc_table->fcp_array[iotag])) { + + /* Remove fcbuf from list, adjust first, last and cnt */ + if (fcptr->fc_bkwd) { + fcptr->fc_bkwd->fc_fwd = fcptr->fc_fwd; + } else { + rp->fc_txp.q_first = (uchar * )fcptr->fc_fwd; + } + + if (fcptr->fc_fwd) { + fcptr->fc_fwd->fc_bkwd = fcptr->fc_bkwd; + } else { + rp->fc_txp.q_last = (uchar * )fcptr->fc_bkwd; + } + + rp->fc_txp.q_cnt--; + binfo->fc_table->fcp_array[iotag] = NULL; + } + + if (fcptr) { + if (binfo->fc_flag & FC_SLI2) { + MATCHMAP * next_bmp; + + while(fcptr->bmp) { + next_bmp = (MATCHMAP *)fcptr->bmp->fc_mptr; + fc_mem_put(binfo, MEM_BPL, (uchar *)fcptr->bmp); + fcptr->bmp = next_bmp; + } + } + fcptr->bmp = 0; + + /* Use correct offset and size for syncing */ + fc_mpdata_sync(fcptr->fc_cmd_dma_handle, + (off_t)(fcptr->offset + sizeof(FCP_CMND)), + (u_int) sizeof(FCP_RSP), DDI_DMA_SYNC_FORCPU); + + } + return(fcptr); +} /* End fc_deq_fcbuf_active */ + + +/* + * Name: fc_deq_wait + * Function: Remove a dev_ptr from the adapter's wait queue. + * Input: dvi_t *dev_ptr dev_ptr to be dequeued. + * Returns: nothing. + */ +_local_ void +fc_deq_wait( + dvi_t * dev_ptr) +{ + fc_dev_ctl_t * ap; + dvi_t *prev_ptr; + + if(dev_ptr == NULL) { + return; + } + ap = dev_ptr->nodep->ap; + if(ap->DEVICE_WAITING_head == NULL) { + return; + } + + if(dev_ptr != ap->DEVICE_WAITING_head) { + prev_ptr = ap->DEVICE_WAITING_head; + while(prev_ptr->DEVICE_WAITING_fwd != dev_ptr && + prev_ptr != ap->DEVICE_WAITING_tail) + { + prev_ptr=prev_ptr->DEVICE_WAITING_fwd; + } + if(prev_ptr->DEVICE_WAITING_fwd == dev_ptr) { + prev_ptr->DEVICE_WAITING_fwd = dev_ptr->DEVICE_WAITING_fwd; + if(ap->DEVICE_WAITING_tail == dev_ptr) { + ap->DEVICE_WAITING_tail = prev_ptr; + } + dev_ptr->DEVICE_WAITING_fwd = NULL; + } + return; + } + if (ap->DEVICE_WAITING_head == ap->DEVICE_WAITING_tail) { + ap->DEVICE_WAITING_head = NULL; + ap->DEVICE_WAITING_tail = NULL; + } else { + ap->DEVICE_WAITING_head = dev_ptr->DEVICE_WAITING_fwd; + } + dev_ptr->DEVICE_WAITING_fwd = NULL; + +} /* End fc_deq_wait */ + + +/* + * Name: fc_deq_fcbuf + * Function: Remove an fc_buf from the device's free queue. + * Input: dvi_t *dev_ptr dev_ptr with the free list. + * Returns: pointer to the fc_buf, or NULL if none exist. + */ +_static_ fc_buf_t * +fc_deq_fcbuf( + dvi_t * dev_ptr) +{ + fc_buf_t * fcptr; + + if (dev_ptr->fcbuf_head == NULL) + return(NULL); + + fcptr = dev_ptr->fcbuf_head; + if (dev_ptr->fcbuf_head == dev_ptr->fcbuf_tail) { + dev_ptr->fcbuf_head = NULL; + dev_ptr->fcbuf_tail = NULL; + } else { + dev_ptr->fcbuf_head = fcptr->fc_fwd; + } + dev_ptr->numfcbufs--; + + return(fcptr); + +} /* End fc_deq_fcbuf */ + + +/* + * Name: fc_deq_abort_bdr + * Function: Removes a dev_ptr from the adapter's abort Bus Device Reset + * queue. + * Input: dvi_t *dev_ptr dev_ptr to be removed. + * Returns: nothing. + */ +_local_ void +fc_deq_abort_bdr( +dvi_t *dev_ptr) +{ + fc_dev_ctl_t * ap; + + ap = dev_ptr->nodep->ap; + + if (ap->ABORT_BDR_head == ap->ABORT_BDR_tail) { + ap->ABORT_BDR_head = NULL; + ap->ABORT_BDR_tail = NULL; + } else if (ap->ABORT_BDR_head == dev_ptr) { + /* first one */ + ap->ABORT_BDR_head = dev_ptr->ABORT_BDR_fwd; + dev_ptr->ABORT_BDR_fwd->ABORT_BDR_bkwd = dev_ptr->ABORT_BDR_bkwd; + } else if (ap->ABORT_BDR_tail == dev_ptr) { + /* last one */ + ap->ABORT_BDR_tail = dev_ptr->ABORT_BDR_bkwd; + dev_ptr->ABORT_BDR_bkwd->ABORT_BDR_fwd = dev_ptr->ABORT_BDR_fwd; + } else { + /* in the middle */ + dev_ptr->ABORT_BDR_bkwd->ABORT_BDR_fwd = dev_ptr->ABORT_BDR_fwd; + dev_ptr->ABORT_BDR_fwd->ABORT_BDR_bkwd = dev_ptr->ABORT_BDR_bkwd; + } + dev_ptr->ABORT_BDR_fwd = NULL; + dev_ptr->ABORT_BDR_bkwd = NULL; + +} /* End fc_deq_abort_bdr */ + + +/* Assign a SCSI ID to a nodelist table entry */ +_static_ int +fc_assign_scsid( +fc_dev_ctl_t *p_dev_ctl, +NODELIST *ndlp) +{ + FC_BRD_INFO * binfo; + iCfgParam * clp; + node_t * node_ptr; + nodeh_t * hp; + NODELIST * seedndlp; + NODELIST * new_ndlp; + int dev_index, i; + + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + /* Next check to see if our binding already has a SCSI ID */ + for (dev_index = 0; dev_index < MAX_FC_TARGETS; dev_index++) { + hp = &binfo->device_queue_hash[dev_index]; + i = (hp->node_flag & FCP_SEED_MASK); + if ((i & FCP_SEED_DID) && (ndlp->nlp_DID == hp->un.dev_did)) + break; /* a match */ + else if ((i & FCP_SEED_WWPN) && + (fc_geportname(&ndlp->nlp_portname, &hp->un.dev_portname) == 2)) + break; /* a match */ + else if ((i & FCP_SEED_WWNN) && + (fc_geportname(&ndlp->nlp_nodename, &hp->un.dev_nodename) == 2)) + break; /* a match */ + } + + /* If not, assign a new SCSI ID / pan number */ + if (dev_index == MAX_FC_TARGETS) { + seedndlp = binfo->fc_nlpbind_start; + if(seedndlp == (NODELIST *)&binfo->fc_nlpbind_start) + seedndlp = binfo->fc_nlpunmap_start; + if(seedndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + seedndlp = binfo->fc_nlpmap_start; + while(seedndlp != (NODELIST *)&binfo->fc_nlpmap_start) { + new_ndlp = (NODELIST *)seedndlp->nlp_listp_next; + + if (seedndlp->nlp_type & NLP_SEED_MASK) { + if (seedndlp->nlp_type & NLP_SEED_WWNN) { + if (fc_geportname(&ndlp->nlp_nodename, + &seedndlp->nlp_nodename) == 2) { + ndlp->id.nlp_pan = seedndlp->id.nlp_pan; + ndlp->id.nlp_sid = seedndlp->id.nlp_sid; + ndlp->nlp_type |= NLP_SEED_WWNN; + if(seedndlp != ndlp) { + seedndlp->nlp_type &= ~NLP_FCP_TARGET; + fc_freenode(binfo, seedndlp, 0); + seedndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, seedndlp); + } + dev_index = INDEX(ndlp->id.nlp_pan, ndlp->id.nlp_sid); + hp = &binfo->device_queue_hash[dev_index]; + + /* Claim SCSI ID by copying bind parameter to + * proper index in device_queue_hash. + */ + if(hp->node_ptr) + ndlp->nlp_targetp = (uchar *)hp->node_ptr; + fc_bcopy(&ndlp->nlp_nodename, &hp->un.dev_nodename, + sizeof(NAME_TYPE)); + hp->node_flag &= ~FCP_SEED_MASK; + hp->node_flag |= FCP_SEED_WWNN; + goto out1; + } + } + if (seedndlp->nlp_type & NLP_SEED_WWPN) { + if (fc_geportname(&ndlp->nlp_portname, + &seedndlp->nlp_portname) == 2) { + ndlp->id.nlp_pan = seedndlp->id.nlp_pan; + ndlp->id.nlp_sid = seedndlp->id.nlp_sid; + ndlp->nlp_type |= NLP_SEED_WWPN; + if(seedndlp != ndlp) { + seedndlp->nlp_type &= ~NLP_FCP_TARGET; + fc_freenode(binfo, seedndlp, 0); + seedndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, seedndlp); + } + dev_index = INDEX(ndlp->id.nlp_pan, ndlp->id.nlp_sid); + hp = &binfo->device_queue_hash[dev_index]; + + /* Claim SCSI ID by copying bind parameter to + * proper index in device_queue_hash. + */ + if(hp->node_ptr) + ndlp->nlp_targetp = (uchar *)hp->node_ptr; + fc_bcopy(&ndlp->nlp_portname, &hp->un.dev_portname, + sizeof(NAME_TYPE)); + hp->node_flag &= ~FCP_SEED_MASK; + hp->node_flag |= FCP_SEED_WWPN; + goto out1; + } + } + if (seedndlp->nlp_type & NLP_SEED_DID) { + if (ndlp->nlp_DID == seedndlp->nlp_DID) { + ndlp->id.nlp_pan = seedndlp->id.nlp_pan; + ndlp->id.nlp_sid = seedndlp->id.nlp_sid; + ndlp->nlp_type |= NLP_SEED_DID; + if(seedndlp != ndlp) { + seedndlp->nlp_type &= ~NLP_FCP_TARGET; + fc_freenode(binfo, seedndlp, 0); + seedndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, seedndlp); + } + dev_index = INDEX(ndlp->id.nlp_pan, ndlp->id.nlp_sid); + hp = &binfo->device_queue_hash[dev_index]; + + /* Claim SCSI ID by copying bind parameter to + * proper index in device_queue_hash. + */ + if(hp->node_ptr) + ndlp->nlp_targetp = (uchar *)hp->node_ptr; + hp->un.dev_did = ndlp->nlp_DID; + hp->node_flag &= ~FCP_SEED_MASK; + hp->node_flag |= FCP_SEED_DID; + goto out1; + } + } + } + seedndlp = new_ndlp; + if(seedndlp == (NODELIST *)&binfo->fc_nlpbind_start) + seedndlp = binfo->fc_nlpunmap_start; + if(seedndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + seedndlp = binfo->fc_nlpmap_start; + } + + if(clp[CFG_AUTOMAP].a_current) { + /* Fill in nodelist entry */ + if (DEV_PAN(p_dev_ctl->sid_cnt) == NLP_MAXPAN) { + return(0); /* No more available SCSI IDs */ + } + + /* If scan-down == 2 and we are private loop, automap + * method is based on ALPA. + */ + if((clp[CFG_SCAN_DOWN].a_current == 2) && + !(binfo->fc_flag & (FC_PUBLIC_LOOP | FC_FABRIC)) && + (binfo->fc_topology == TOPOLOGY_LOOP)) { + for (i = 0; i < FC_MAXLOOP; i++) { + if(ndlp->nlp_DID == (uint32)AlpaArray[i]) + break; + } + if(i == FC_MAXLOOP) { + goto jmp_auto; + } + ndlp->id.nlp_pan = DEV_PAN(i); + ndlp->id.nlp_sid = DEV_SID(i); + } + else { + /* Check to make sure assigned scsi id does not overlap + * with a seeded value. + */ +jmp_auto: + seedndlp = binfo->fc_nlpbind_start; + if(seedndlp == (NODELIST *)&binfo->fc_nlpbind_start) + seedndlp = binfo->fc_nlpunmap_start; + if(seedndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + seedndlp = binfo->fc_nlpmap_start; + while(seedndlp != (NODELIST *)&binfo->fc_nlpmap_start) { + if ((seedndlp->nlp_state == NLP_SEED) || + (seedndlp->nlp_type & NLP_SEED_MASK)) { + if ((seedndlp->id.nlp_pan == DEV_PAN(p_dev_ctl->sid_cnt)) && + (seedndlp->id.nlp_sid == DEV_SID(p_dev_ctl->sid_cnt))) { + /* We overlap, so pick a new id and start again */ + p_dev_ctl->sid_cnt++; + goto jmp_auto; + } + } + seedndlp = (NODELIST *)seedndlp->nlp_listp_next; + if(seedndlp == (NODELIST *)&binfo->fc_nlpbind_start) + seedndlp = binfo->fc_nlpunmap_start; + if(seedndlp == (NODELIST *)&binfo->fc_nlpunmap_start) + seedndlp = binfo->fc_nlpmap_start; + } + + ndlp->id.nlp_pan = DEV_PAN(p_dev_ctl->sid_cnt); + ndlp->id.nlp_sid = DEV_SID(p_dev_ctl->sid_cnt); + p_dev_ctl->sid_cnt++; + } + ndlp->nlp_type |= NLP_AUTOMAP; + + dev_index = INDEX(ndlp->id.nlp_pan, ndlp->id.nlp_sid); + hp = &binfo->device_queue_hash[dev_index]; + + /* Claim SCSI ID by copying bind parameter to + * proper index in device_queue_hash. + */ + if(hp->node_ptr) + ndlp->nlp_targetp = (uchar *)hp->node_ptr; + switch(p_dev_ctl->fcp_mapping) { + case FCP_SEED_DID: + hp->un.dev_did = ndlp->nlp_DID; + ndlp->nlp_type |= NLP_SEED_DID; + break; + case FCP_SEED_WWPN: + fc_bcopy(&ndlp->nlp_portname, &hp->un.dev_portname, sizeof(NAME_TYPE)); + ndlp->nlp_type |= NLP_SEED_WWPN; + break; + case FCP_SEED_WWNN: + default: + fc_bcopy(&ndlp->nlp_nodename, &hp->un.dev_nodename, sizeof(NAME_TYPE)); + ndlp->nlp_type |= NLP_SEED_WWNN; + break; + } + hp->node_flag &= ~FCP_SEED_MASK; + hp->node_flag |= p_dev_ctl->fcp_mapping; + goto out1; + } + return(0); /* Cannot assign a scsi id */ + } + + /* If scan-down == 2 and we are private loop, automap + * method is based on ALPA. + */ + if((clp[CFG_SCAN_DOWN].a_current == 2) && + !(binfo->fc_flag & (FC_PUBLIC_LOOP | FC_FABRIC)) && + (binfo->fc_topology == TOPOLOGY_LOOP)) { + for (i = 0; i < FC_MAXLOOP; i++) { + if(ndlp->nlp_DID == (uint32)AlpaArray[i]) + break; + } + if(i == FC_MAXLOOP) { + goto jmp_auto; + } + ndlp->id.nlp_pan = DEV_PAN(i); + ndlp->id.nlp_sid = DEV_SID(i); + goto out1; + } + /* Copy SCSI ID for the WWN into nodelist */ + ndlp->id.nlp_pan = DEV_PAN(dev_index); + ndlp->id.nlp_sid = DEV_SID(dev_index); + + /* Update rpi for that SCSI ID's device node info */ + if ((node_ptr = (node_t * )ndlp->nlp_targetp) != NULL) { + node_ptr->rpi = ndlp->nlp_Rpi; + node_ptr->last_good_rpi = ndlp->nlp_Rpi; + node_ptr->nlp = ndlp; + node_ptr->flags &= ~FC_NODEV_TMO; + ndlp->nlp_flag &= ~NLP_NODEV_TMO; + if(node_ptr->nodev_tmr) { + /* STOP nodev timer */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0704, /* ptr to msg structure */ + fc_mes0704, /* ptr to msg */ + fc_msgBlk0704.msgPreambleStr, /* begin varargs */ + (ulong)ndlp, + ndlp->nlp_flag, + ndlp->nlp_state, + ndlp->nlp_DID); /* end varargs */ + fc_clk_can(p_dev_ctl, node_ptr->nodev_tmr); + node_ptr->nodev_tmr = 0; + } + } + else { + int dev_index; +out1: + dev_index = INDEX(ndlp->id.nlp_pan, ndlp->id.nlp_sid); + node_ptr = binfo->device_queue_hash[dev_index].node_ptr; + if(node_ptr) { + /* This is a new device that entered the loop */ + node_ptr->nlp = ndlp; + node_ptr->rpi = ndlp->nlp_Rpi; + node_ptr->last_good_rpi = ndlp->nlp_Rpi; + node_ptr->scsi_id = dev_index; + ndlp->nlp_targetp = (uchar *)node_ptr; + node_ptr->flags &= ~FC_NODEV_TMO; + ndlp->nlp_flag &= ~NLP_NODEV_TMO; + if(node_ptr->nodev_tmr) { + /* STOP nodev timer */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0705, /* ptr to msg structure */ + fc_mes0705, /* ptr to msg */ + fc_msgBlk0705.msgPreambleStr, /* begin varargs */ + (ulong)ndlp, + ndlp->nlp_flag, + ndlp->nlp_state, + ndlp->nlp_DID); /* end varargs */ + fc_clk_can(p_dev_ctl, node_ptr->nodev_tmr); + node_ptr->nodev_tmr = 0; + } + } + } + return(1); +} /* End fc_assign_scsid */ + + +/************************************************************************/ +/* */ +/* NAME: fc_fail_cmd */ +/* */ +/* FUNCTION: Fail All Pending Commands Routine */ +/* */ +/* This routine is called to clear out all pending commands */ +/* for a SCSI FCP device. */ +/* */ +/* EXECUTION ENVIRONMENT: */ +/* This routine can only be called on priority levels */ +/* equal to that of the interrupt handler. */ +/* */ +/* DATA STRUCTURES: */ +/* sc_buf - input/output request struct used between the adapter */ +/* driver and the calling SCSI device driver */ +/* */ +/* INPUTS: */ +/* dev_info structure - pointer to device information structure */ +/* */ +/* RETURN VALUE DESCRIPTION: The following are the return values: */ +/* none */ +/* */ +/************************************************************************/ +_static_ void +fc_fail_cmd( + dvi_t * dev_ptr, + char error, + uint32 statistic) +{ + T_SCSIBUF * sbp; + RING * rp; + IOCBQ * iocb_cmd, *next; + IOCB * icmd; + Q tmpq; + fc_buf_t * fcptr; + struct buf * bp; + dvi_t * next_dev_ptr; + fc_dev_ctl_t * p_dev_ctl; + FC_BRD_INFO * binfo; + iCfgParam * clp; + + p_dev_ctl = dev_ptr->nodep->ap; + binfo = &BINFO; + rp = &binfo->fc_ring[FC_FCP_RING]; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + /* First clear out all sc_buf structures in the pending queue */ + if(! clp[CFG_HOLDIO].a_current) { + if((dev_ptr->nodep) && + (dev_ptr->nodep->rptlunstate == REPORT_LUN_ONGOING)) + goto out; + sbp = dev_ptr->pend_head; + dev_ptr->pend_head = NULL; /* reset tail pointer */ + dev_ptr->pend_tail = NULL; /* reset tail pointer */ + dev_ptr->pend_count = 0; + + while (sbp != NULL) { + T_SCSIBUF *nextsbp; + + sbp->bufstruct.b_flags |= B_ERROR; /* set b_flags B_ERROR flag */ + sbp->bufstruct.b_error = error; + sbp->bufstruct.b_resid = sbp->bufstruct.b_bcount; + if (error) { + sbp->status_validity = SC_ADAPTER_ERROR; + SET_ADAPTER_STATUS(sbp,SC_NO_DEVICE_RESPONSE) + } else { + sbp->status_validity = 0; + } + + /* Point to next sc_buf in pending chain, if any */ + nextsbp = (T_SCSIBUF *) sbp->bufstruct.av_forw; + sbp->bufstruct.av_forw = 0; + fc_do_iodone((struct buf *) sbp); /* This could reque to pend_head */ + sbp = nextsbp; + } + } + +out: + /* Next clear out all fc_buf structures in the iocb queue for this device */ + tmpq.q_first = NULL; + + /* Get next command from ring xmit queue */ + iocb_cmd = fc_ringtx_get(rp); + + while (iocb_cmd) { + icmd = &iocb_cmd->iocb; + if ((icmd->ulpCommand != CMD_IOCB_CONTINUE_CN) && + (icmd->ulpContext == dev_ptr->nodep->last_good_rpi) && + (icmd->ulpIoTag < MAX_FCP_CMDS) && + (fcptr = binfo->fc_table->fcp_array[icmd->ulpIoTag]) && + (fcptr->dev_ptr == dev_ptr)) { + + if ((fcptr = fc_deq_fcbuf_active(rp, icmd->ulpIoTag)) != NULL) { + bp = (struct buf *)fcptr->sc_bufp; + + /* Reject this command with error */ + if (fcptr->fcp_cmd.fcpCntl2) { + + /* This is a task management command */ + dev_ptr->ioctl_errno = error; + if (fcptr->fcp_cmd.fcpCntl2 == ABORT_TASK_SET) + dev_ptr->flags &= ~SCSI_ABORT_TSET; + + if (fcptr->fcp_cmd.fcpCntl2 & TARGET_RESET) { + dev_ptr->flags &= ~SCSI_TARGET_RESET; + for (next_dev_ptr = dev_ptr->nodep->lunlist; + next_dev_ptr != NULL; next_dev_ptr = next_dev_ptr->next) { + next_dev_ptr->flags &= ~SCSI_TARGET_RESET; + } + } + + if (fcptr->fcp_cmd.fcpCntl2 & LUN_RESET) + dev_ptr->flags &= ~SCSI_LUN_RESET; + + if (dev_ptr->ioctl_wakeup == 1) { + dev_ptr->ioctl_wakeup = 0; + + fc_admin_wakeup(p_dev_ctl, dev_ptr, fcptr->sc_bufp); + } + else { + fc_do_iodone(bp); + } + + dev_ptr->active_io_count--; + dev_ptr->nodep->num_active_io--; + + } else { + /* This is a regular FCP command */ + bp->b_error = error; + bp->b_resid = bp->b_bcount; + bp->b_flags |= B_ERROR; + if (error) { + sbp = fcptr->sc_bufp; + sbp->status_validity = SC_ADAPTER_ERROR; + SET_ADAPTER_STATUS(sbp,SC_NO_DEVICE_RESPONSE) + } + + sbp = fcptr->sc_bufp; + + dev_ptr->active_io_count--; + dev_ptr->nodep->num_active_io--; + fc_do_iodone(bp); + } + fc_enq_fcbuf(fcptr); + } + + fc_mem_put(binfo, MEM_IOCB, (uchar * )iocb_cmd); + + while ((iocb_cmd = fc_ringtx_get(rp)) != NULL) { + icmd = &iocb_cmd->iocb; + if (icmd->ulpCommand != CMD_IOCB_CONTINUE_CN) + break; + fc_mem_put(binfo, MEM_IOCB, (uchar * )iocb_cmd); + } + } else { + /* Queue this iocb to the temporary queue */ + if (tmpq.q_first) { + ((IOCBQ * )tmpq.q_last)->q = (uchar * )iocb_cmd; + tmpq.q_last = (uchar * )iocb_cmd; + } else { + tmpq.q_first = (uchar * )iocb_cmd; + tmpq.q_last = (uchar * )iocb_cmd; + } + iocb_cmd->q = NULL; + + iocb_cmd = fc_ringtx_get(rp); + } + } + + /* Put the temporary queue back in the FCP iocb queue */ + iocb_cmd = (IOCBQ * )tmpq.q_first; + while (iocb_cmd) { + next = (IOCBQ * )iocb_cmd->q; + fc_ringtx_put(rp, iocb_cmd); + iocb_cmd = next; + } + + return; +} /* End fc_fail_cmd */ + +/* Fix up any changed RPIs in FCP IOCBs queued up a txq + * Called from CLEAR_LA after a link up. + */ +_static_ void +fc_fcp_fix_txq( + fc_dev_ctl_t * p_dev_ctl) +{ + RING * rp; + FC_BRD_INFO * binfo; + fc_buf_t * fcptr; + IOCBQ * temp; + IOCB * cmd; + dvi_t * dev_ptr; + unsigned long iflag; + + iflag = lpfc_q_disable_lock(p_dev_ctl); + binfo = &BINFO; + rp = &binfo->fc_ring[FC_FCP_RING]; + + /* Make sure all RPIs on txq are still ok */ + temp = (IOCBQ *)rp->fc_tx.q_first; + while (temp != NULL) { + cmd = &temp->iocb; + if ((fcptr = binfo->fc_table->fcp_array[cmd->ulpIoTag]) != NULL) { + dev_ptr = fcptr->dev_ptr; + if((dev_ptr) && (dev_ptr->nodep) && + (cmd->ulpContext != dev_ptr->nodep->rpi)) { + cmd->ulpContext = dev_ptr->nodep->rpi; + } + } + if(rp->fc_tx.q_last == (uchar * )temp) + break; + temp = (IOCBQ *)temp->q; + } + lpfc_q_unlock_enable(p_dev_ctl, iflag); + return; +} /* End fc_fcp_fix_txq */ + +_static_ void +fc_fail_pendq( + dvi_t * dev_ptr, + char error, + uint32 statistic) +{ + T_SCSIBUF * sbp; + RING * rp; + fc_dev_ctl_t * p_dev_ctl; + FC_BRD_INFO * binfo; + iCfgParam * clp; + + p_dev_ctl = dev_ptr->nodep->ap; + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + rp = &binfo->fc_ring[FC_FCP_RING]; + + if((dev_ptr->nodep) && + (dev_ptr->nodep->rptlunstate == REPORT_LUN_ONGOING)) + goto out; + + if(clp[CFG_HOLDIO].a_current) + goto out; + + sbp = dev_ptr->pend_head; + dev_ptr->pend_head = NULL; /* reset tail pointer */ + dev_ptr->pend_tail = NULL; /* reset tail pointer */ + dev_ptr->pend_count = 0; + + while (sbp != NULL) { + T_SCSIBUF *nextsbp; + + sbp->bufstruct.b_flags |= B_ERROR; /* set b_flags B_ERROR flag */ + sbp->bufstruct.b_error = error; + sbp->bufstruct.b_resid = sbp->bufstruct.b_bcount; + if (error) { + sbp->status_validity = SC_ADAPTER_ERROR; + SET_ADAPTER_STATUS(sbp,SC_NO_DEVICE_RESPONSE) + } else { + sbp->status_validity = 0; + } + + /* Point to next sc_buf in pending chain, if any */ + nextsbp = (T_SCSIBUF *) sbp->bufstruct.av_forw; + sbp->bufstruct.av_forw = 0; + fc_do_iodone((struct buf *) sbp); /* This could reque to pend_head */ + sbp = nextsbp; + } + +out: + return; +} /* End fc_fail_pendq */ + +/************************************************************************/ +/* */ +/* NAME:issue_fcp_cmd */ +/* */ +/* FUNCTION:Issue an FCP command to the adapter iocb queue */ +/* */ +/* EXECUTION ENVIRONMENT: */ +/* This routine always runs at interrupt level */ +/* */ +/* DATA STRUCTURES: */ +/* sc_buf- input/output request struct used between the adapter */ +/* driver and the calling SCSI device driver */ +/* */ +/* RETURN VALUE DESCRIPTION: 0 = success */ +/* 1 = continue */ +/* 2 = requeue */ +/* 4 = exit */ +/* */ +/************************************************************************/ +_static_ int +issue_fcp_cmd( + fc_dev_ctl_t * p_dev_ctl, + dvi_t * dev_ptr, + T_SCSIBUF * sbp, + int pend) +{ + FC_BRD_INFO * binfo = &BINFO; + iCfgParam * clp; + struct buf * bp; + fc_buf_t * fcptr; + int i, rc; + RING * rp; + IOCBQ * temp; + IOCB * cmd; + uint32 count, * lp; + fc_lun_t lun; + ULP_BDE64 * bpl; + MATCHMAP * bmp; + NODELIST * ndlp; + + rp = &binfo->fc_ring[FC_FCP_RING]; + bp = (struct buf *) sbp; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + + if((dev_ptr->nodep == 0) || + ((ndlp = dev_ptr->nodep->nlp) == 0)) + return(FCP_REQUEUE); + + if ( !(ndlp->capabilities & FC_CAP_AUTOSENSE) ) { + if (dev_ptr->sense_valid && + (sbp->scsi_command.scsi_cmd.scsi_op_code == SCSI_REQUEST_SENSE)) { + + /* Request sense command - use saved sense data */ + if (bp->b_bcount > (int)dev_ptr->sense_length) { + bp->b_resid = bp->b_bcount - (int)dev_ptr->sense_length; + count = dev_ptr->sense_length; + } else { + count = bp->b_bcount; + } + lp = (uint32 * )dev_ptr->sense; + lpfc_copy_sense(dev_ptr, bp); + bp->b_error = 0; + bp->b_flags &= ~B_ERROR; + + if (pend) { + dev_ptr->pend_head = (T_SCSIBUF *) bp->av_forw; + if (dev_ptr->pend_head == NULL) + dev_ptr->pend_tail = NULL; + else + dev_ptr->pend_head->bufstruct.av_back = NULL; + dev_ptr->pend_count--; + } + dev_ptr->sense_valid = 0; + + FCSTATCTR.fcpSense++; + fc_do_iodone(bp); + return(FCP_CONTINUE); + } + } + + + if(dev_ptr->queue_state != ACTIVE) { + return(FCP_REQUEUE); + } + + if(binfo->fc_process_LA == 0) { + return(FCP_REQUEUE); + } + + /* Check if device is in process of resetting */ + if (dev_ptr->flags & SCSI_DEV_RESET) { + return(FCP_REQUEUE); + } + + if (dev_ptr->nodep->rpi == 0xFFFE) { + + if(clp[CFG_HOLDIO].a_current) { + return(FCP_REQUEUE); + } + + if((clp[CFG_NODEV_TMO].a_current) && + ((dev_ptr->nodep->flags & FC_NODEV_TMO) == 0)) { + + /* Kick off first PLOGI to device */ + if (!(ndlp->nlp_flag & NLP_REQ_SND)) { + uint32 did; + + did = ndlp->nlp_DID; + if(did == (uint32)0) { + if((ndlp->nlp_type & (NLP_AUTOMAP | NLP_SEED_MASK)) && + (ndlp->nlp_state == NLP_LIMBO) && ndlp->nlp_oldDID) + did = ndlp->nlp_oldDID; + } + ndlp->nlp_flag &= ~NLP_RM_ENTRY; + if ((!(ndlp->nlp_flag & NLP_NODEV_TMO)) && + (did != (uint32)0)) { + if(!(ndlp->nlp_flag & NLP_NS_REMOVED)) { + ndlp->nlp_flag |= NLP_NODEV_TMO; + fc_els_cmd(binfo, ELS_CMD_PLOGI, (void *)((ulong)did), + (uint32)0, (ushort)0, ndlp); + } + } + } + else { + ndlp->nlp_flag |= NLP_NODEV_TMO; + } + return(FCP_REQUEUE); + } + + /* The device is not active at this time */ + bp->b_error = EIO; + bp->b_resid = bp->b_bcount; + bp->b_flags |= B_ERROR; + sbp->status_validity = SC_ADAPTER_ERROR; + SET_ADAPTER_STATUS(sbp,SC_NO_DEVICE_RESPONSE) + if (pend) { + dev_ptr->pend_head = (T_SCSIBUF *) bp->av_forw; + if (dev_ptr->pend_head == NULL) + dev_ptr->pend_tail = NULL; + else + dev_ptr->pend_head->bufstruct.av_back = NULL; + dev_ptr->pend_count--; + } + + FCSTATCTR.fcpNoDevice++; + fc_delay_iodone(p_dev_ctl, sbp); + + { + uint32 did; + uint32 pan; + uint32 sid; + + did = ndlp->nlp_DID; + pan = ndlp->id.nlp_pan; + sid = ndlp->id.nlp_sid; + + if (!(dev_ptr->flags & DONT_LOG_INVALID_RPI)) { + /* Cannot issue FCP command */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0706, /* ptr to msg structure */ + fc_mes0706, /* ptr to msg */ + fc_msgBlk0706.msgPreambleStr, /* begin varargs */ + did, + FC_SCSID(pan, sid)); /* end varargs */ + dev_ptr->flags |= DONT_LOG_INVALID_RPI; + } + } + return(FCP_CONTINUE); + } + + if (ndlp->nlp_action & NLP_DO_RSCN) { + return(FCP_REQUEUE); + } + + if ((fcptr = fc_deq_fcbuf(dev_ptr)) == NULL) { + return(FCP_REQUEUE); + } + + if ((temp = (IOCBQ * )fc_mem_get(binfo, MEM_IOCB)) == NULL) { + fc_enq_fcbuf(fcptr); + return(FCP_EXIT); + } + + fc_bzero((void *)fcptr, sizeof(FCP_CMND) + sizeof(FCP_RSP)); + + /* Copy SCSI cmd into FCP payload for xmit.*/ + lun = (uint32) sbp->scsi_command.scsi_lun; + { + int i; + fcptr->fcp_cmd.fcpCdb[0]= sbp->scsi_command.scsi_cmd.scsi_op_code; + fcptr->fcp_cmd.fcpCdb[1]= sbp->scsi_command.scsi_cmd.lun; + for(i=0; i< (sizeof(struct sc_cmd)-2); i++) + fcptr->fcp_cmd.fcpCdb[i+2]= sbp->scsi_command.scsi_cmd.scsi_bytes[i]; + fcptr->fcp_cmd.fcpCntl1 = sbp->scsi_command.flags; + } + + /* Put LUN in the FCP command using the Peripheral Addressing Method */ + fcptr->fcp_cmd.fcpLunMsl = lun << FC_LUN_SHIFT; + fcptr->fcp_cmd.fcpLunLsl = 0; + + /* + * The Logical Unit Addressing method is not supported at + * this current release. + */ + if (dev_ptr->nodep->addr_mode == VOLUME_SET_ADDRESSING) { + fcptr->fcp_cmd.fcpLunMsl |= SWAP_DATA(0x40000000); + } + + fcptr->fcp_cmd.fcpDl = SWAP_DATA(bp->b_bcount); + + fcptr->sc_bufp = sbp; + fcptr->flags = 0; + + /* set up an iotag so we can match the completion iocb */ + for (i = 0; i < MAX_FCP_CMDS; i++) { + fcptr->iotag = rp->fc_iotag++; + if (rp->fc_iotag >= MAX_FCP_CMDS) + rp->fc_iotag = 1; + if (binfo->fc_table->fcp_array[fcptr->iotag] == 0) + break; + } + if (i >= MAX_FCP_CMDS) { + /* No more command slots available, retry later */ + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + fc_enq_fcbuf(fcptr); + return(FCP_EXIT); + } + + fc_bzero((void *)temp, sizeof(IOCBQ)); /* zero the iocb entry */ + cmd = &temp->iocb; + + if (binfo->fc_flag & FC_SLI2) { + /* Allocate buffer for Buffer ptr list */ + if ((bmp = (MATCHMAP * )fc_mem_get(binfo, MEM_BPL)) == 0) { + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + fc_enq_fcbuf(fcptr); + return(FCP_EXIT); + } + bpl = (ULP_BDE64 * )bmp->virt; + bpl->addrHigh = PCIMEM_LONG((uint32)putPaddrHigh(GET_PAYLOAD_PHYS_ADDR(fcptr))); + bpl->addrLow = PCIMEM_LONG((uint32)putPaddrLow(GET_PAYLOAD_PHYS_ADDR(fcptr))); + bpl->tus.f.bdeSize = sizeof(FCP_CMND); + bpl->tus.f.bdeFlags = BUFF_USE_CMND; + bpl->tus.w = PCIMEM_LONG(bpl->tus.w); + bpl++; + bpl->addrHigh = PCIMEM_LONG((uint32)putPaddrHigh(GET_PAYLOAD_PHYS_ADDR(fcptr)+sizeof(FCP_CMND))); + bpl->addrLow = PCIMEM_LONG((uint32)putPaddrLow(GET_PAYLOAD_PHYS_ADDR(fcptr)+sizeof(FCP_CMND))); + bpl->tus.f.bdeSize = sizeof(FCP_RSP); + bpl->tus.f.bdeFlags = (BUFF_USE_CMND | BUFF_USE_RCV); + bpl->tus.w = PCIMEM_LONG(bpl->tus.w); + bpl++; + + cmd->un.fcpi64.bdl.ulpIoTag32 = (uint32)0; + cmd->un.fcpi64.bdl.addrHigh = (uint32)putPaddrHigh(bmp->phys); + cmd->un.fcpi64.bdl.addrLow = (uint32)putPaddrLow(bmp->phys); + cmd->un.fcpi64.bdl.bdeSize = (2 * sizeof(ULP_BDE64)); + cmd->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BDL; + cmd->ulpBdeCount = 1; + fcptr->bmp = bmp; + temp->bpl = (uchar *)0; + } else { + bpl = 0; + cmd->un.fcpi.fcpi_cmnd.bdeAddress = (uint32)putPaddrLow(GET_PAYLOAD_PHYS_ADDR(fcptr)); + cmd->un.fcpi.fcpi_cmnd.bdeSize = sizeof(FCP_CMND); + cmd->un.fcpi.fcpi_rsp.bdeAddress = (uint32)(putPaddrLow((GET_PAYLOAD_PHYS_ADDR(fcptr) + sizeof(FCP_CMND)))); + cmd->un.fcpi.fcpi_rsp.bdeSize = sizeof(FCP_RSP); + cmd->ulpBdeCount = 2; + fcptr->bmp = 0; + temp->bpl = (uchar *)0; + } + + cmd->ulpContext = dev_ptr->nodep->rpi; + cmd->ulpIoTag = fcptr->iotag; + /* + * if device is FCP-2 device, set the following bit that says + * to run the FC-TAPE protocol. + */ + if (ndlp->id.nlp_fcp_info & NLP_FCP_2_DEVICE) { + cmd->ulpFCP2Rcvy = 1; + } + cmd->ulpClass = (ndlp->id.nlp_fcp_info & 0x0f); + cmd->ulpOwner = OWN_CHIP; + + if (sbp->timeout_value == 0) + sbp->timeout_value = 3600; /* One hour in seconds */ + + curtime(&fcptr->timeout); + + /* Need to set the FCP timeout in the fcptr structure and the IOCB + * for this I/O to get the adapter to run a timer. + */ + { + uint32 time_out; + + if(sbp->timeout_value) + time_out = sbp->timeout_value * fc_ticks_per_second; + else + time_out = 30 * fc_ticks_per_second; + + if (binfo->fc_flag & FC_FABRIC) { + time_out += (fc_ticks_per_second * + (clp[CFG_FCPFABRIC_TMO].a_current + (2 * binfo->fc_ratov))); + } + + fcptr->timeout = ((ulong)fcptr->timeout + time_out + (300 * fc_ticks_per_second)); + + /* Set the FCP timeout in the IOCB to get the adapter to run a timer */ + if ((time_out / fc_ticks_per_second) < 256) + cmd->ulpTimeout = time_out / fc_ticks_per_second; + } + + if (bp->b_bcount == 0) { + /* Set up for SCSI command */ + if (binfo->fc_flag & FC_SLI2) + cmd->ulpCommand = CMD_FCP_ICMND64_CR; + else + cmd->ulpCommand = CMD_FCP_ICMND_CR; + + if (((fcptr->fcp_cmd.fcpCdb[0] & 0xBF) == SCSI_RESERVE_UNIT) || + ((fcptr->fcp_cmd.fcpCdb[0] & 0xBF) == SCSI_RELEASE_UNIT)) { + /* Mask off the lun field for reserve/release commands */ + fcptr->fcp_cmd.fcpCdb[1] &= 0x1f; + } + if(bpl) { + bpl->addrHigh = 0; + bpl->addrLow = 0; + bpl->tus.w = 0; + } + cmd->un.fcpi.fcpi_parm = 0; + fcptr->fcp_cmd.fcpCntl3 = 0; + + cmd->ulpLe = 1; + /* Queue cmd chain to last iocb entry in xmit queue */ + if (rp->fc_tx.q_first == NULL) { + rp->fc_tx.q_first = (uchar * )temp; + } else { + ((IOCBQ * )(rp->fc_tx.q_last))->q = (uchar * )temp; + } + rp->fc_tx.q_last = (uchar * )temp; + rp->fc_tx.q_cnt++; + + } else if (bp->b_flags & B_READ) { + /* Set up for SCSI read */ + if (binfo->fc_flag & FC_SLI2) + cmd->ulpCommand = CMD_FCP_IREAD64_CR; + else + cmd->ulpCommand = CMD_FCP_IREAD_CR; + cmd->ulpPU = PARM_READ_CHECK; + cmd->un.fcpi.fcpi_parm = bp->b_bcount; + fcptr->fcp_cmd.fcpCntl3 = READ_DATA; + if((rc = fc_fcp_bufmap(p_dev_ctl, sbp, fcptr, temp, bpl, dev_ptr, pend)) != 0) + return(rc); + } else { + /* Set up for SCSI write */ + if (binfo->fc_flag & FC_SLI2) + cmd->ulpCommand = CMD_FCP_IWRITE64_CR; + else + cmd->ulpCommand = CMD_FCP_IWRITE_CR; + fcptr->fcp_cmd.fcpCntl3 = WRITE_DATA; + if((rc = fc_fcp_bufmap(p_dev_ctl, sbp, fcptr, temp, bpl, dev_ptr, pend)) != 0) + return(rc); + } + + if(dev_ptr->nodep->flags & FC_FCP2_RECOVERY) + cmd->ulpFCP2Rcvy = 1; + + lp = (uint32 * ) & fcptr->fcp_cmd; + fc_enq_fcbuf_active(rp, fcptr); + + dev_ptr->active_io_count++; + dev_ptr->nodep->num_active_io++; + FCSTATCTR.fcpCmd++; + + return(0); +} /* End issue_fcp_cmd */ + + +_static_ int +fc_failio( + fc_dev_ctl_t * p_dev_ctl) +{ + FC_BRD_INFO * binfo; + node_t * node_ptr; + dvi_t * dev_ptr; + struct buf *bp, *nextbp; + int i; + + binfo = &BINFO; + + /* Clear the queues for one or more SCSI devices */ + for (i = 0; i < MAX_FC_TARGETS; i++) { + if ((node_ptr = binfo->device_queue_hash[i].node_ptr) != NULL) { + for (dev_ptr = node_ptr->lunlist; dev_ptr != NULL; + dev_ptr = dev_ptr->next) { + + dev_ptr->queue_state = HALTED; + fc_return_standby_queue(dev_ptr, + (uchar)((binfo->fc_flag & FC_BUS_RESET) ? EIO : EFAULT), 0); + + /* First send ABTS on outstanding I/Os in txp queue */ + fc_abort_fcp_txpq(binfo, dev_ptr); + + fc_fail_pendq(dev_ptr, (char)((binfo->fc_flag & FC_BUS_RESET) ? + EIO : EFAULT), 0); + + fc_fail_cmd(dev_ptr, (char)((binfo->fc_flag & FC_BUS_RESET) ? + EIO : EFAULT), 0); + + /* Call iodone for all the CLEARQ error bufs */ + fc_free_clearq(dev_ptr); + } + } + } + /* Call iodone for any commands that timed out previously */ + for (bp = p_dev_ctl->timeout_head; bp != NULL; ) { + nextbp = bp->av_forw; + bp->b_error = ETIMEDOUT; + bp->b_flags |= B_ERROR; + fc_do_iodone(bp); + bp = nextbp; + } + p_dev_ctl->timeout_head = NULL; + p_dev_ctl->timeout_count = 0; + return(0); +} + + +_static_ void +fc_return_standby_queue( + dvi_t * dev_ptr, + uchar status, + uint32 statistic) +{ + T_SCSIBUF * sp; + + /* It is possible to have IOs on the pending queue because + of the way the scheduler works. */ + + while ((sp = dev_ptr->standby_queue_head) != NULL) { + dev_ptr->standby_count--; + dev_ptr->standby_queue_head = (T_SCSIBUF *)sp->bufstruct.av_forw; + fc_do_iodone((struct buf *) sp); + } + dev_ptr->standby_queue_head = NULL; + dev_ptr->standby_queue_tail = NULL; +} + +/* + * Restart all devices for a given adapter. Should only be + * invoked at the conclusion of loop {re}discovery. + */ +_static_ int +fc_restart_all_devices( + fc_dev_ctl_t * p_dev_ctl) +{ + dvi_t * dev_ptr; + FC_BRD_INFO * binfo; + int i; + node_t * node_ptr; + + binfo = &BINFO; + + for (i = 0; i < MAX_FC_TARGETS; ++i) { + if ((node_ptr = binfo->device_queue_hash[i].node_ptr) != NULL) { + dev_ptr = node_ptr->lunlist; + while (dev_ptr) { + if ((dev_ptr->queue_state == RESTART_WHEN_READY) || + (dev_ptr->queue_state == HALTED)) { + fc_restart_device(dev_ptr); + } + + if (dev_ptr->nodep->rpi != 0xfffe) + dev_ptr->flags &= ~(NORPI_RESET_DONE | DONT_LOG_INVALID_RPI); + else + dev_ptr->flags &= ~DONT_LOG_INVALID_RPI; + fc_enq_wait(dev_ptr); + dev_ptr = dev_ptr->next; + } + } + } + return(0); +} /* End fc_restart_all_devices */ + +/* + * Restart a device by draining its standby queue. + */ +_static_ int +fc_restart_device( + dvi_t * dev_ptr) +{ + FC_BRD_INFO * binfo; + + binfo = &dev_ptr->nodep->ap->info; + if (binfo->fc_ffstate != FC_READY || + (dev_ptr->flags & (SCSI_TQ_CLEARING | CHK_SCSI_ABDR))) { + + dev_ptr->queue_state = RESTART_WHEN_READY; + return(0); + } + + dev_ptr->queue_state = ACTIVE; + dev_ptr->flags &= ~(SCSI_TQ_HALTED | CHK_SCSI_ABDR); + fc_return_standby_queue(dev_ptr, + (uchar)((binfo->fc_flag & FC_BUS_RESET) ? EIO : EFAULT), 0); + + return(1); +} /* End fc_restart_device */ + +/* Called to reissue fcp command if tgt throttle was reached */ +_static_ void +re_issue_fcp_cmd( + dvi_t * dev_ptr) +{ + fc_dev_ctl_t * ap; + dvi_t * next_ptr; + dvi_t * start_ptr; + T_SCSIBUF * sbp = NULL; + int rc; + FC_BRD_INFO * binfo; + RING * rp; + + if (dev_ptr == NULL) + return; + + ap = dev_ptr->nodep->ap; + binfo = &ap->info; + + rp = &binfo->fc_ring[FC_FCP_RING]; + + next_ptr = dev_ptr; + start_ptr = next_ptr->nodep->lunlist; + + if (start_ptr == NULL) + return; + + do { + + if ((sbp = next_ptr->pend_head) != NULL) + break; + + next_ptr = next_ptr->next; + if (!next_ptr) + next_ptr = start_ptr; + } while ( next_ptr != dev_ptr ); + + if (! sbp) { + next_ptr->nodep->last_dev = NULL; + return; + } + + if ((rc = issue_fcp_cmd(ap, next_ptr, sbp, 1))) { + if ((rc & FCP_REQUEUE) || (rc & FCP_EXIT)) + return; + } + next_ptr->pend_count--; + next_ptr->pend_head = (T_SCSIBUF *) sbp->bufstruct.av_forw; + if (next_ptr->pend_head == NULL) + next_ptr->pend_tail = NULL; + else + next_ptr->pend_head->bufstruct.av_back = NULL; + + if (next_ptr->pend_count == 0) + fc_deq_wait(next_ptr); + + next_ptr->nodep->last_dev = next_ptr->next; + if (next_ptr->nodep->last_dev == NULL) + next_ptr->nodep->last_dev = next_ptr->nodep->lunlist; + + if (rp->fc_tx.q_cnt) + issue_iocb_cmd(binfo, rp, 0); + + return; +} /* End re_issue_fcp_cmd */ + +/* Find a SCSI device structure for a given LUN */ +_static_ dvi_t * +fc_find_lun( +FC_BRD_INFO *binfo, +int hash_index, +fc_lun_t lun) +{ + node_t * node_ptr; + dvi_t * dev_ptr; + + if ((hash_index < 0) || (hash_index > MAX_FC_TARGETS)) + return(NULL); + + node_ptr = binfo->device_queue_hash[hash_index].node_ptr; + + if (node_ptr == NULL) { + dev_ptr = NULL; + } else { + for (dev_ptr = node_ptr->lunlist; dev_ptr != NULL; + dev_ptr = dev_ptr->next) { + + if (dev_ptr->lun_id == lun) { + /* We found the correct entry */ + break; + } + } + } + return(dev_ptr); +} /* End fc_find_lun */ + +_static_ int +fc_reset_dev_q_depth( + fc_dev_ctl_t * p_dev_ctl) +{ + dvi_t * dev_ptr; + FC_BRD_INFO * binfo; + int i; + iCfgParam * clp; + node_t * node_ptr; + + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + + for (i = 0; i < MAX_FC_TARGETS; ++i) { + if ((node_ptr = binfo->device_queue_hash[i].node_ptr) != NULL) { + dev_ptr = node_ptr->lunlist; + while (dev_ptr) { + dev_ptr->fcp_cur_queue_depth = (ushort)clp[CFG_DFT_LUN_Q_DEPTH].a_current; + dev_ptr = dev_ptr->next; + } + } + } + return(0); +} /* End fc_reset_dev_q_depth */ + + +/* [SYNC] */ +_static_ void +fc_polling( + FC_BRD_INFO *binfo, + uint32 att_bit) +{ + volatile uint32 ha_copy; + void *ioa; + fc_dev_ctl_t * p_dev_ctl; + + p_dev_ctl = (fc_dev_ctl_t *)binfo->fc_p_dev_ctl; + do { + ioa = (void *)FC_MAP_IO(&binfo->fc_iomap_io); /* map in io registers */ + ha_copy = READ_CSR_REG(binfo, FC_HA_REG(binfo, ioa)); + FC_UNMAP_MEMIO(ioa); + if (ha_copy & att_bit) + break; + } while (1); + fc_intr((struct intr *)p_dev_ctl); +} diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/fcxmitb.c 830-ivtv/drivers/scsi/lpfc/fcxmitb.c --- 000-virgin/drivers/scsi/lpfc/fcxmitb.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/fcxmitb.c Thu Jan 8 10:21:53 2004 @@ -0,0 +1,1442 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Enterprise Fibre Channel Host Bus Adapters. * + * Refer to the README file included with this package for * + * driver version and adapter support. * + * Copyright (C) 2003 Emulex Corporation. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details, a copy of which * + * can be found in the file COPYING included with this package. * + *******************************************************************/ + +#include "fc_os.h" + +#include "fc_hw.h" +#include "fc.h" + +#include "fcdiag.h" +#include "fcfgparm.h" +#include "fcmsg.h" +#include "fc_crtn.h" /* Core - external routine definitions */ +#include "fc_ertn.h" /* Environment - external routine definitions */ + +extern fc_dd_ctl_t DD_CTL; +extern iCfgParam icfgparam[]; +extern int lpfc_nethdr; + +/* Routine Declaration - Local */ +_local_ int fc_mbuf_to_iocb(fc_dev_ctl_t *p_dev_ctl, fcipbuf_t *p_mbuf); +_local_ fcipbuf_t *fc_txq_put(fc_dev_ctl_t *p_dev_ctl, RING *rp, + fcipbuf_t *p_mbuf); +/* End Routine Declaration - Local */ + +/*****************************************************************************/ +/* + * NAME: fc_ringtx_put + * + * FUNCTION: put xmit iocb onto the ring transmit queue. + * + * EXECUTION ENVIRONMENT: process and interrupt level. + * + * CALLED FROM: + * fc_els_cmd + * + * INPUT: + * binfo - pointer to the device info area + * iocbq - pointer to iocbq entry of xmit iocb + * + * RETURNS: + * none + */ +/*****************************************************************************/ +_static_ void +fc_ringtx_put( +RING *rp, +IOCBQ *iocbq) /* pointer to iocbq entry */ +{ + FC_BRD_INFO * binfo; + + binfo = (FC_BRD_INFO * )rp->fc_binfo; + if (rp->fc_tx.q_first) { + ((IOCBQ * )rp->fc_tx.q_last)->q = (uchar * )iocbq; + rp->fc_tx.q_last = (uchar * )iocbq; + } else { + rp->fc_tx.q_first = (uchar * )iocbq; + rp->fc_tx.q_last = (uchar * )iocbq; + } + + iocbq->q = NULL; + rp->fc_tx.q_cnt++; + + return; + +} /* End fc_ringtx_put */ + + +/*****************************************************************************/ +/* + * NAME: fc_ringtx_get + * + * FUNCTION: get a packet off the ring transmit queue. + * + * EXECUTION ENVIRONMENT: interrupt level. + * + * CALLED FROM: + * fc_els_cmd + * + * INPUT: + * rp - pointer to the ring to get an iocb from + * + * RETURNS: + * NULL - no iocbs found + * iocb pointer - pointer to an iocb to transmit + */ +/*****************************************************************************/ +_static_ IOCBQ * +fc_ringtx_get( +RING *rp) +{ + FC_BRD_INFO * binfo; + NODELIST * nlp; + IOCBQ * p_first = NULL; + IOCBQ * prev = NULL; + uchar * daddr; + ushort xri; + + binfo = (FC_BRD_INFO * )rp->fc_binfo; + if (rp->fc_tx.q_first) { + p_first = (IOCBQ * )rp->fc_tx.q_first; + + /* Make sure we already have a login and exchange to the remote node */ + while (p_first->iocb.ulpCommand == 0) { + if (rp->fc_ringno == FC_IP_RING) { + NETHDR * np; + + /* check to see if nlplist entry exists yet */ + np = (NETHDR * )(fcdata(((fcipbuf_t * )(p_first->bp)))); + daddr = np->fc_destname.IEEE; + if ((xri = fc_emac_lookup(binfo, daddr, &nlp))) { + /* exchange to destination already exists */ + if (binfo->fc_flag & FC_SLI2) + p_first->iocb.ulpCommand = CMD_XMIT_SEQUENCE64_CX; + else + p_first->iocb.ulpCommand = CMD_XMIT_SEQUENCE_CX; + p_first->iocb.ulpContext = xri; + p_first->info = (uchar * )nlp; + break; + } + } + + /* loop past continuation iocbs */ + while (p_first->iocb.ulpLe == 0) { + prev = p_first; + if ((p_first = (IOCBQ * )p_first->q) == 0) { + return(0); + } + } + prev = p_first; + if ((p_first = (IOCBQ * )p_first->q) == 0) { + return(0); + } + } + + /* adjust last if necessary */ + if (p_first->q == 0) { + rp->fc_tx.q_last = (uchar * )prev; + } + + /* remove iocb chain to process */ + if (prev == 0) { + rp->fc_tx.q_first = p_first->q; + } else { + prev->q = (uchar * )p_first->q; + } + + p_first->q = NULL; + rp->fc_tx.q_cnt--; + } + return(p_first); + +} /* End fc_ringtx_get */ + + +/*****************************************************************************/ +/* + * NAME: fc_ringtx_drain + * + * FUNCTION: get all packets off the ring transmit queue. + * + * EXECUTION ENVIRONMENT: interrupt level. + * + * NOTES: + * + * CALLED FROM: + * fc_els_cmd + * + * INPUT: + * binfo - pointer to the device info area + * + * RETURNS: + * NULL - no match found + * mbuf pointer - pointer to a mbuf chain which contains a packet. + */ +/*****************************************************************************/ +_static_ IOCBQ * +fc_ringtx_drain( +RING *rp) +{ + FC_BRD_INFO * binfo; + IOCBQ * p_first; + IOCBQ * prev; + + binfo = (FC_BRD_INFO * )rp->fc_binfo; + p_first = (IOCBQ * )rp->fc_tx.q_first; + if (p_first) { + prev = (IOCBQ * )p_first->q; + + /* remove iocb chain to process */ + if (prev == 0) { + rp->fc_tx.q_first = 0; + rp->fc_tx.q_last = 0; + } else { + rp->fc_tx.q_first = (uchar * )prev; + } + + p_first->q = NULL; + rp->fc_tx.q_cnt--; + } + + return(p_first); + +} /* End fc_ringtx_drain */ + + + + +/*****************************************************************************/ +/* + * NAME: fc_ringtxp_put + * + * FUNCTION: put xmit iocb onto the ring pending queue. + * + * EXECUTION ENVIRONMENT: process and interrupt level. + * + * CALLED FROM: + * fc_elsp_cmd + * + * INPUT: + * rp - pointer to the ring + * iocbq - pointer to iocbq entry of xmit iocb + * + * RETURNS: + * none + */ +/*****************************************************************************/ +_static_ void +fc_ringtxp_put( +RING *rp, +IOCBQ *iocbq) /* pointer to iocbq entry */ +{ + fc_dev_ctl_t * p_dev_ctl; + FC_BRD_INFO * binfo; + unsigned long iflag; + + binfo = (FC_BRD_INFO * )rp->fc_binfo; + p_dev_ctl = (fc_dev_ctl_t *)binfo->fc_p_dev_ctl; + + iflag = lpfc_q_disable_lock(p_dev_ctl); + if (rp->fc_txp.q_first) { + ((IOCBQ * )rp->fc_txp.q_last)->q = (uchar * )iocbq; + rp->fc_txp.q_last = (uchar * )iocbq; + } else { + rp->fc_txp.q_first = (uchar * )iocbq; + rp->fc_txp.q_last = (uchar * )iocbq; + + /* start watchdog timer on first xmit only */ + if (rp->fc_ringno != FC_FCP_RING) { + lpfc_q_unlock_enable(p_dev_ctl, iflag); + RINGTMO = fc_clk_set((fc_dev_ctl_t *)(binfo->fc_p_dev_ctl), + rp->fc_ringtmo, fc_cmdring_timeout, (void *)rp, 0); + iflag = lpfc_q_disable_lock(p_dev_ctl); + } + } + + iocbq->q = NULL; + rp->fc_txp.q_cnt++; + + lpfc_q_unlock_enable(p_dev_ctl, iflag); + return; + +} /* End fc_ringtxp_put */ + + +/*****************************************************************************/ +/* + * NAME: fc_ringtxp_get + * + * FUNCTION: get a packet off the ring pending queue. + * + * EXECUTION ENVIRONMENT: interrupt level. + * + * CALLED FROM: + * fc_els_cmd + * + * INPUT: + * rp - pointer to the ring + * + * RETURNS: + * NULL - no match found + * iocbq pointer - pointer to iocbq which matches the iotag + */ +/*****************************************************************************/ +_static_ IOCBQ * +fc_ringtxp_get( +RING *rp, +ushort iotag) /* tag to match i/o */ +{ + fc_dev_ctl_t * p_dev_ctl; + FC_BRD_INFO * binfo; + IOCBQ * iocbq; /* pointer to iocbq entry */ + IOCBQ * pq; /* pointer to previous iocbq entry */ + IOCBQ * save; /* pointer to iocb entry of chain */ + unsigned long iflag; + + binfo = (FC_BRD_INFO * )rp->fc_binfo; + p_dev_ctl = (fc_dev_ctl_t *)binfo->fc_p_dev_ctl; + pq = 0; + save = 0; + + /* Right now this just loops through the linked list looking + * for a match on iotag. This can get optimized in the future + * to have iotag just index into an array. + */ + iflag = lpfc_q_disable_lock(p_dev_ctl); + iocbq = (IOCBQ * )(rp->fc_txp.q_first); + while (iocbq) { + /* do we match on iotag */ + if ((iocbq->iocb.ulpIoTag == iotag) || (iotag == 0)) { + /* loop past continuation iocbs */ + while (iocbq->iocb.ulpLe == 0) { + rp->fc_txp.q_cnt--; + save = iocbq; + if ((iocbq = (IOCBQ * )iocbq->q) == 0) { + iocbq = save; + break; + } + } + save = iocbq; + iocbq = (IOCBQ * )iocbq->q; + + save->q = 0; /* NULL terminate iocb chain */ + + /* Remove iocbq chain from list, adjust first, last and cnt */ + if (iocbq == 0) + rp->fc_txp.q_last = (uchar * )pq; + + if (pq) { + save = (IOCBQ * )pq->q; + pq->q = (uchar * )iocbq; + } else { + save = (IOCBQ * )rp->fc_txp.q_first; + rp->fc_txp.q_first = (uchar * )iocbq; + } + rp->fc_txp.q_cnt--; + + /* stop watchdog timer */ + if(RINGTMO) { + lpfc_q_unlock_enable(p_dev_ctl, iflag); + fc_clk_can((fc_dev_ctl_t *)(binfo->fc_p_dev_ctl), RINGTMO); + iflag = lpfc_q_disable_lock(p_dev_ctl); + RINGTMO = 0; + } + + /* if xmits are still pending, restart the watchdog timer */ + if (rp->fc_txp.q_cnt > 0) { + /* start watchdog timer */ + if (rp->fc_ringno != FC_FCP_RING) { + lpfc_q_unlock_enable(p_dev_ctl, iflag); + RINGTMO = fc_clk_set((fc_dev_ctl_t *)(binfo->fc_p_dev_ctl), + rp->fc_ringtmo, fc_cmdring_timeout, (void *)rp, 0); + iflag = lpfc_q_disable_lock(p_dev_ctl); + } + } + break; + } + + pq = iocbq; + iocbq = (IOCBQ * )iocbq->q; + } + + lpfc_q_unlock_enable(p_dev_ctl, iflag); + return(save); +} /* End fc_ringtxp_get */ + + +/*****************************************************************************/ +/* + * NAME: fc_xmit + * + * FUNCTION: Fibre Channel driver output routine. + * + * EXECUTION ENVIRONMENT: process only + * + * NOTES: + * + * CALLED FROM: + * fc_output fc_intr + * + * INPUT: + * p_dev_ctl - pointer to device information. + * p_mbuf - pointer to a mbuf (chain) for outgoing packets + * + * RETURNS: + * 0 - successful + * EAGAIN - transmit queue is full + */ +/*****************************************************************************/ +int +fc_xmit( +fc_dev_ctl_t *p_dev_ctl, +fcipbuf_t *p_mbuf) +{ + fcipbuf_t * p_cur_mbuf; + fcipbuf_t * buf_tofree; + RING * rp; + FC_BRD_INFO * binfo; + iCfgParam * clp; + + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + if(clp[CFG_NETWORK_ON].a_current == 0) + return(EIO); + + rp = &binfo->fc_ring[FC_IP_RING]; + buf_tofree = fc_txq_put(p_dev_ctl, rp, p_mbuf); + if (NDDSTAT.ndd_xmitque_max < rp->fc_tx.q_cnt) { + NDDSTAT.ndd_xmitque_max = rp->fc_tx.q_cnt; + } + + /* xmit queue was totally full */ + if (buf_tofree == p_mbuf) { + while (p_mbuf) { + NDDSTAT.ndd_xmitque_ovf++; + NDDSTAT.ndd_opackets_drop++; + p_mbuf = fcnextpkt(p_mbuf); + } + + /* send the packet(s) on the xmit queue */ + issue_iocb_cmd(binfo, rp, 0); + + return(EAGAIN); + } + + /* xmit queue could not fit entire chain */ + while ((p_cur_mbuf = buf_tofree) != NULL) { + NDDSTAT.ndd_xmitque_ovf++; + NDDSTAT.ndd_opackets_drop++; + buf_tofree = fcnextpkt(buf_tofree); + fcnextpkt(p_cur_mbuf) = NULL; + m_freem(p_cur_mbuf); + } + + /* send the packet(s) on the xmit queue */ + issue_iocb_cmd(binfo, rp, 0); + + return(0); +} /* End fc_xmit */ + + +/*****************************************************************************/ +/* + * NAME: fc_txq_put + * + * FUNCTION: put packets onto the transmit queue. + * + * EXECUTION ENVIRONMENT: process and interrupt level. + * + * NOTES: + * + * CALLED FROM: + * fc_xmit + * + * INPUT: + * p_dev_ctl - pointer to the device information area + * rp - pointer to the device information area + * p_mbuf - pointer to a mbuf chain + * + * RETURNS: + * NULL - all mbufs are queued. + * mbuf pointer - point to a mbuf chain which contains packets + * that overflows the transmit queue. + */ +/*****************************************************************************/ +_local_ fcipbuf_t * +fc_txq_put( +fc_dev_ctl_t *p_dev_ctl, +RING *rp, +fcipbuf_t *p_mbuf) /* pointer to a mbuf chain */ +{ + FC_BRD_INFO * binfo; + fcipbuf_t * p_last, *p_over, *p_next; + int room; + + room = rp->fc_tx.q_max - NDDSTAT.ndd_xmitque_cur; + binfo = &BINFO; + if (room > 0) { + p_over = 0; + p_next = p_mbuf; + while (p_next) { + p_last = fcnextpkt(p_next); + fcnextpkt(p_next) = NULL; + if (fc_mbuf_to_iocb(p_dev_ctl, p_next)) { + fcnextpkt(p_next) = p_last; + p_over = p_next; + break; + } + p_next = p_last; + if ( --room <= 0) { + p_over = p_next; + break; + } + } + binfo->fc_flag &= ~FC_NO_ROOM_IP; + } else { + FCSTATCTR.xmitnoroom++; + p_over = p_mbuf; + + if(!(binfo->fc_flag & FC_NO_ROOM_IP)) { + /* No room on IP xmit queue */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0605, /* ptr to msg structure */ + fc_mes0605, /* ptr to msg */ + fc_msgBlk0605.msgPreambleStr, /* begin varargs */ + FCSTATCTR.xmitnoroom); /* end varargs */ + } + binfo->fc_flag |= FC_NO_ROOM_IP; + } + + return(p_over); + +} /* End fc_txq_put */ + + + +/*****************************************************************************/ +/* + * NAME: fc_mbuf_to_iocb + * + * FUNCTION: converts and mbuf into an iocb cmd chain and put on transmit q + * + * EXECUTION ENVIRONMENT: process and interrupt + * + * NOTES: + * + * CALLED FROM: + * + * INPUT: + * p_dev_ctl - pointer to the device information area + * p_mbuf - pointer to a packet in mbuf + * + * RETURNS: + * 0 - OK + * -1 - error occurred during transmit + */ +/*****************************************************************************/ +_local_ int +fc_mbuf_to_iocb( +fc_dev_ctl_t *p_dev_ctl, +fcipbuf_t *p_mbuf) /* pointer to the packet in mbuf */ +{ + FC_BRD_INFO * binfo; + iCfgParam * clp; + uchar * daddr; + RING * rp; + IOCBQ * temp; + IOCBQ * qhead, * qtail; + IOCB * cmd; + NODELIST * nlp; + fcipbuf_t * p_cur_mbuf; /* pointer to current packet in mbuf */ + fcipbuf_t * m_net; + ushort * sp1, * sp2; + ULP_BDE64 * bpl, * topbpl; + MATCHMAP * bmp; + MATCHMAP * bmphead, *bmptail; + MATCHMAP * savebmp; + void * handle; + emac_t * ep; + NETHDR * np; + int i, j, mapcnt; + int count, firstbuflen; + int num_iocbs, num_bdes, numble; + ushort leftover, xri; + uchar isbcast, ismcast; + + binfo = &BINFO; + rp = &binfo->fc_ring[FC_IP_RING]; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + + /* First get a temporary iocb buffers. temp will be + * used for the first iocb entry XMIT_SEQUENCE, and will + * be used for each successive IOCB_CONTINUE entry. + * qhead will be saved for the return + */ + if ((temp = (IOCBQ * )fc_mem_get(binfo, MEM_IOCB)) == 0) { + m_freem(p_mbuf); + return(0); + } + + fc_bzero((void *)temp, sizeof(IOCBQ)); /* initially zero the iocb entry */ + cmd = &temp->iocb; + mapcnt = 0; + numble = 0; + qhead = 0; + qtail = 0; + leftover = 0; + bmp = 0; + topbpl = 0; + if (binfo->fc_flag & FC_SLI2) { + bmphead = 0; + bmptail = 0; + /* Allocate buffer for Buffer ptr list */ + if ((bmp = (MATCHMAP * )fc_mem_get(binfo, MEM_BPL)) == 0) { + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + m_freem(p_mbuf); + return(0); + } + bpl = (ULP_BDE64 * )bmp->virt; + cmd->un.xseq64.bdl.ulpIoTag32 = (uint32)0; + cmd->un.xseq64.bdl.addrHigh = (uint32)putPaddrHigh(bmp->phys); + cmd->un.xseq64.bdl.addrLow = (uint32)putPaddrLow(bmp->phys); + cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BDL; + temp->bpl = (uchar *)bmp; + } + else { + bpl = 0; + bmphead = 0; + bmptail = 0; + } + + if(lpfc_nethdr == 0) { + ep = (emac_t * )(fcdata(p_mbuf)); + daddr = ep->dest_addr; + + /* We need to convert 802.3 header (14 bytes) into + * fc network header (16 bytes). Since the header is at + * the begining of the buffer, we need to allocate extra space. + */ + + count = fcpktlen(p_mbuf) + 2; /* total data in mbuf after copy */ + firstbuflen = fcdatalen(p_mbuf); + /* Assume first data buffer holds emac and LLC/SNAP at a minimun */ + if (firstbuflen < sizeof(struct fc_hdr )) { + FCSTATCTR.mbufcopy++; + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + if (bmp) { + fc_mem_put(binfo, MEM_BPL, (uchar * ) bmp); + } + m_freem(p_mbuf); + return(0); + } + + + /* Allocate a buffer big enough to hold the Fibre Channel header + * and the LLC/SNAP header. + */ + if ((m_net = (fcipbuf_t * )m_getclustm(M_DONTWAIT, MT_DATA, + (sizeof(NETHDR) + sizeof(snaphdr_t)))) == 0) { + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + if (bmp) { + fc_mem_put(binfo, MEM_BPL, (uchar * ) bmp); + } + return(EIO); + } + fcsethandle(m_net, 0); + + np = (NETHDR * )fcdata(m_net); + + /* Copy data from emac_t header to network header */ + sp1 = (ushort * ) & np->fc_destname; + *sp1++ = 0; + np->fc_destname.nameType = NAME_IEEE; /* IEEE name */ + sp2 = (ushort * )ep->dest_addr; + + if (*sp2 & SWAP_DATA16(0x8000)) /* Check for multicast */ { + ismcast = 1; + if (*sp2 != 0xffff) /* Check for broadcast */ + isbcast = 0; + else + isbcast = 1; + } else { + ismcast = 0; + isbcast = 0; + } + + /* First copy over the dest IEEE address */ + *sp1++ = *sp2++; + if (isbcast && (*sp2 != 0xffff)) + isbcast = 0; + *sp1++ = *sp2++; + if (isbcast && (*sp2 != 0xffff)) + isbcast = 0; + *sp1++ = *sp2++; + + /* Next copy over the src IEEE address */ + sp1 = (ushort * ) & np->fc_srcname; + *sp1++ = 0; + np->fc_srcname.nameType = NAME_IEEE; /* IEEE name */ + sp2 = (ushort * )binfo->fc_portname.IEEE; + *sp1++ = *sp2++; + *sp1++ = *sp2++; + *sp1++ = *sp2++; + + sp2 = (ushort * )((uchar *)ep + sizeof(emac_t)); + + /* Now Copy LLC/SNAP */ + *sp1++ = *sp2++; + *sp1++ = *sp2++; + *sp1++ = *sp2++; + *sp1++ = *sp2++; + + p_cur_mbuf = m_net; + fcsetdatalen(m_net, (sizeof(NETHDR) + sizeof(snaphdr_t))); + + fcincdatalen(p_mbuf, (-(sizeof(struct fc_hdr )))); + + fcdata(p_mbuf) += sizeof(struct fc_hdr ); + + /* Fixup mbuf chain so data is in line */ + fcnextdata(m_net) = p_mbuf; + } + else { + np = (NETHDR * )(fcdata(((fcipbuf_t * )(p_mbuf)))); + daddr = np->fc_destname.IEEE; + count = fcpktlen(p_mbuf); + p_cur_mbuf = p_mbuf; + m_net = p_mbuf; + + sp2 = (ushort * )daddr; + if (*sp2 & SWAP_DATA16(0x8000)) /* Check for multicast */ { + ismcast = 1; + if (*sp2 != 0xffff) /* Check for broadcast */ + isbcast = 0; + else + isbcast = 1; + } else { + ismcast = 0; + isbcast = 0; + } + } + + num_iocbs = 0; /* count number of iocbs needed to xmit p_mbuf */ + num_bdes = 2; /* Will change to 3 for IOCB_CONTINUE */ + nlp = 0; + + /* + * While there's data left to send and we are not at the end of + * the mbuf chain, put the data from each mbuf in the chain into + * a seperate iocb entry. + */ + while (count && p_cur_mbuf) { + if (binfo->fc_flag & FC_SLI2) { + qhead = temp; + qtail = temp; + /* Set to max number of ULP_BDE64's that fit into a bpl */ + /* Save the last BDE for a continuation ptr, if needed */ + num_bdes = ((FCELSSIZE / sizeof(ULP_BDE64)) - 1); + numble = 0; + if (bmphead == 0) { + bmphead = bmp; + bmptail = bmp; + } else { + bmptail->fc_mptr = (uchar * )bmp; + bmptail = bmp; + } + bmp->fc_mptr = 0; + } else { + if (qhead == 0) { + qhead = temp; + qtail = temp; + } else { + qtail->q = (uchar * )temp; + qtail = temp; + } + } + temp->q = 0; + /* + * copy data pointers into iocb entry + */ + for (i = 0; i < num_bdes; i++) { + /* Skip mblk's with 0 data length */ + while (p_cur_mbuf && (fcdatalen(p_cur_mbuf) == 0)) + p_cur_mbuf = fcnextdata(p_cur_mbuf); /* goto next mbuf in chain */ + + if ((count <= 0) || (p_cur_mbuf == 0)) + break; + + if (leftover == 0) { + mapcnt = fc_bufmap(p_dev_ctl, (uchar * )(fcdata(p_cur_mbuf)), + (uint32)fcdatalen(p_cur_mbuf), binfo->physaddr, binfo->cntaddr, &handle); + + /* fill in BDEs for command */ + if (mapcnt <= 0) { + cmd->ulpBdeCount = i; + goto out; + } + + /* Save dmahandle if one was returned */ + fcsethandle(p_cur_mbuf, handle); + } + + for (j = leftover; j < mapcnt; j++) { + if ((i + j - leftover) >= num_bdes) { + i = num_bdes; + leftover = j; + goto lim; + } + if (binfo->fc_flag & FC_SLI2) { + bpl->addrHigh = (uint32)putPaddrHigh(binfo->physaddr[j]); + bpl->addrHigh = PCIMEM_LONG(bpl->addrHigh); + bpl->addrLow = (uint32)putPaddrLow(binfo->physaddr[j]); + bpl->addrLow = PCIMEM_LONG(bpl->addrLow); + bpl->tus.f.bdeSize = binfo->cntaddr[j]; + bpl->tus.f.bdeFlags = BDE64_SIZE_WORD; + bpl->tus.w = PCIMEM_LONG(bpl->tus.w); + bpl++; + numble++; + } else { + cmd->un.cont[i+j-leftover].bdeAddress = (uint32)putPaddrLow(binfo->physaddr[j]); + cmd->un.cont[i+j-leftover].bdeSize = binfo->cntaddr[j]; + cmd->un.cont[i+j-leftover].bdeAddrHigh = 0; + cmd->un.cont[i+j-leftover].bdeReserved = 0; + } + } + + i = i + j - leftover - 1; + count -= fcdatalen(p_cur_mbuf); /* adjust count of data left */ + leftover = 0; + p_cur_mbuf = fcnextdata(p_cur_mbuf); /* goto next mbuf in chain */ + } + +lim: + /* Fill in rest of iocb entry, all non-zero fields */ + + cmd->ulpBdeCount = i; + + /* Setup command to use accordingly */ + if (++num_iocbs > 1) { + if (!(binfo->fc_flag & FC_SLI2)) { + cmd->ulpCommand = CMD_IOCB_CONTINUE_CN; + temp->bp = 0; + temp->info = 0; + } + } else { + /* set up an iotag so we can match the completion to an iocb/mbuf */ + cmd->ulpIoTag = rp->fc_iotag++; + if (rp->fc_iotag == 0) { + rp->fc_iotag = 1; + } + + /* Setup fibre channel header information */ + cmd->un.xrseq.w5.hcsw.Fctl = 0; + cmd->un.xrseq.w5.hcsw.Dfctl = FC_NET_HDR; /* network headers */ + cmd->un.xrseq.w5.hcsw.Rctl = FC_UNSOL_DATA; + cmd->un.xrseq.w5.hcsw.Type = FC_LLC_SNAP; + + if (isbcast) { + if (++NDDSTAT.ndd_ifOutBcastPkts_lsw == 0) + NDDSTAT.ndd_ifOutBcastPkts_msw++; + if (binfo->fc_flag & FC_SLI2) + cmd->ulpCommand = CMD_XMIT_BCAST64_CN; + else + cmd->ulpCommand = CMD_XMIT_BCAST_CN; + cmd->ulpContext = 0; + nlp = 0; + } else if (ismcast) { + if (++NDDSTAT.ndd_ifOutMcastPkts_lsw == 0) + NDDSTAT.ndd_ifOutMcastPkts_msw++; + if (binfo->fc_flag & FC_SLI2) + cmd->ulpCommand = CMD_XMIT_BCAST64_CN; + else + cmd->ulpCommand = CMD_XMIT_BCAST_CN; + cmd->ulpContext = 0; + nlp = 0; + } else { + if (++NDDSTAT.ndd_ifOutUcastPkts_lsw == 0) + NDDSTAT.ndd_ifOutUcastPkts_msw++; + + /* data from upper layer has a full MAC header on it. We + * need to match the destination address with the portname + * field in our nlp table to determine if we already have an + * exchange opened to this destination. + */ + if (((xri = fc_emac_lookup(binfo, daddr, &nlp)) != 0) && + !(nlp->nlp_action & NLP_DO_RSCN) && + (nlp->nlp_bp == 0)) { + /* exchange to destination already exists */ + if (binfo->fc_flag & FC_SLI2) + cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX; + else + cmd->ulpCommand = CMD_XMIT_SEQUENCE_CX; + cmd->ulpContext = xri; + nlp->nlp_type |= NLP_IP_NODE; + } else { /* need to wait for exchange to destination */ + FCSTATCTR.frameXmitDelay++; + cmd->ulpCommand = 0; + cmd->ulpContext = 0; + + if ((binfo->fc_flag & FC_LNK_DOWN) || + (binfo->fc_ffstate < rp->fc_xmitstate)) + goto out; + + if (nlp == 0) { + /* A partial entry doesn't even exist, so initiate + * ELS login by sending a FARP + */ + /* Add FARP code here */ + fc_els_cmd(binfo, ELS_CMD_FARP, (void *)daddr, + (uint32)0, (ushort)0, (NODELIST *)0); + } else { + if ((nlp->nlp_DID != Bcast_DID) && + !(nlp->nlp_action & NLP_DO_ADDR_AUTH) && + !(nlp->nlp_action & NLP_DO_RSCN) && + !(nlp->nlp_flag & (NLP_FARP_SND | NLP_REQ_SND | NLP_RPI_XRI))) { + /* If a cached entry exists, PLOGI first */ + if ((nlp->nlp_state == NLP_LIMBO) || + (nlp->nlp_state == NLP_LOGOUT)) { + fc_els_cmd(binfo, ELS_CMD_PLOGI, + (void *)((ulong)nlp->nlp_DID), (uint32)0, (ushort)0, nlp); + } + /* establish a new exchange */ + if ((nlp->nlp_Rpi) && (nlp->nlp_Xri == 0)) { + nlp->nlp_flag |= NLP_RPI_XRI; + fc_create_xri(binfo, &binfo->fc_ring[FC_ELS_RING], nlp); + } + } + } + + cmd = &temp->iocb; + if (binfo->fc_flag & FC_SLI2) { + while (bpl && (bpl != (ULP_BDE64 * )bmp->virt)) { + bpl--; + fc_bufunmap(p_dev_ctl, + (uchar *)getPaddr(bpl->addrHigh, bpl->addrLow), 0, bpl->tus.f.bdeSize); + } + if (bmp) { + fc_mem_put(binfo, MEM_BPL, (uchar * ) bmp); + } + } else { + for (i = 0; i < (int)cmd->ulpBdeCount; i++) { + fc_bufunmap(p_dev_ctl, (uchar *)((ulong)cmd->un.cont[i].bdeAddress), 0, (uint32)cmd->un.cont[i].bdeSize); + } + } + if(lpfc_nethdr == 0) { + /* Free Resources */ + fcnextdata(m_net) = 0; + fcfreehandle(p_dev_ctl, m_net); + m_freem(m_net); + + /* Put p_mbuf back the way it was, without NETHDR */ + fcincdatalen(p_mbuf, sizeof(struct fc_hdr )); + fcdata(p_mbuf) -= sizeof(struct fc_hdr ); + } + + fcfreehandle(p_dev_ctl, p_mbuf); + + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + + /* save buffer till ELS login completes */ + + if (nlp == 0) { + m_freem(p_mbuf); + return(0); + } + + if (nlp->nlp_bp == 0) { + nlp->nlp_bp = (uchar * )p_mbuf; + } else { + /* Only keep one mbuf chain per node "on deck" */ + p_cur_mbuf = (fcipbuf_t * )nlp->nlp_bp; + nlp->nlp_bp = (uchar * )p_mbuf; + m_freem(p_cur_mbuf); + } + return(0); + } + cmd->ulpClass = nlp->id.nlp_ip_info; + } + + num_bdes = 3; /* in case IOCB_CONTINUEs are needed */ + temp->bp = (uchar * )m_net; + temp->info = (uchar * )nlp; + } + + cmd->ulpOwner = OWN_CHIP; + + /* is this the last iocb entry we will need */ + if ((count == 0) || (p_cur_mbuf == 0)) { + temp = 0; + cmd->ulpLe = 1; + /* if so queue cmd chain to last iocb entry in xmit queue */ + if (rp->fc_tx.q_first == 0) { + rp->fc_tx.q_first = (uchar * )qhead; + rp->fc_tx.q_last = (uchar * )qtail; + } else { + ((IOCBQ * )(rp->fc_tx.q_last))->q = (uchar * )qhead; + rp->fc_tx.q_last = (uchar * )qtail; + } + rp->fc_tx.q_cnt += num_iocbs; + NDDSTAT.ndd_xmitque_cur++; + break; + } else { + cmd->ulpLe = 0; + } + + /* get another iocb entry buffer */ + if (binfo->fc_flag & FC_SLI2) { + /* Allocate buffer for Buffer ptr list */ + if ((bmp = (MATCHMAP * )fc_mem_get(binfo, MEM_BPL)) == 0) { + goto out; + } + /* Fill in continuation entry to next bpl */ + bpl->addrHigh = (uint32)putPaddrHigh(bmp->phys); + bpl->addrHigh = PCIMEM_LONG(bpl->addrHigh); + bpl->addrLow = (uint32)putPaddrLow(bmp->phys); + bpl->addrLow = PCIMEM_LONG(bpl->addrLow); + bpl->tus.f.bdeFlags = BPL64_SIZE_WORD; + numble++; + if (num_iocbs == 1) { + cmd->un.xseq64.bdl.bdeSize = (numble * sizeof(ULP_BDE64)); + } else { + topbpl->tus.f.bdeSize = (numble * sizeof(ULP_BDE64)); + topbpl->tus.w = PCIMEM_LONG(topbpl->tus.w); + } + topbpl = bpl; + bpl = (ULP_BDE64 * )bmp->virt; + leftover = 0; + } else { + if ((temp = (IOCBQ * )fc_mem_get(binfo, MEM_IOCB)) == 0) { +out: + /* no more available, so toss mbuf by freeing + * resources associated with qhead + */ + if (binfo->fc_flag & FC_SLI2) { + num_bdes = ((FCELSSIZE / sizeof(ULP_BDE64)) - 1); + bmp = bmphead; + while (bmp) { + i = 0; + bpl = (ULP_BDE64 * )bmp->virt; + while (bpl && (i < num_bdes)) { + bpl++; + i++; + fc_bufunmap(p_dev_ctl, + (uchar *)getPaddr(bpl->addrHigh, bpl->addrLow), 0, bpl->tus.f.bdeSize); + } + savebmp = (MATCHMAP * )bmp->fc_mptr; + if (bmp) { + fc_mem_put(binfo, MEM_BPL, (uchar * )bmp); + } + bmp = savebmp; + } + + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + } else { + while (qhead) { + temp = qhead; + cmd = &temp->iocb; + for (i = 0; i < (int)cmd->ulpBdeCount; i++) { + fc_bufunmap(p_dev_ctl, (uchar *)((ulong)cmd->un.cont[i].bdeAddress), 0, (uint32)cmd->un.cont[i].bdeSize); + } + qhead = (IOCBQ * )temp->q; + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + } + } + + if(lpfc_nethdr == 0) { + fcnextdata(m_net) = 0; + fcfreehandle(p_dev_ctl, m_net); + m_freem(m_net); + + /* Put p_mbuf back the way it was, without NETHDR */ + fcincdatalen(p_mbuf, sizeof(struct fc_hdr )); + fcdata(p_mbuf) -= sizeof(struct fc_hdr ); + } + + fcfreehandle(p_dev_ctl, p_mbuf); + + if (binfo->fc_flag & FC_SLI2) { + m_freem(p_mbuf); + return(0); + } + return(EIO); + } + fc_bzero((void *)temp, sizeof(IOCBQ)); + cmd = &temp->iocb; + } + } + + if (binfo->fc_flag & FC_SLI2) { + bpl->addrHigh = 0; + bpl->addrLow = 0; + bpl->tus.w = 0; + cmd->ulpBdeCount = 1; + if (num_iocbs == 1) { + cmd->un.xseq64.bdl.bdeSize = (numble * sizeof(ULP_BDE64)); + } else { + topbpl->tus.f.bdeSize = (numble * sizeof(ULP_BDE64)); + topbpl->tus.w = PCIMEM_LONG(topbpl->tus.w); + } + } + + if (temp) + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + + return(0); +} /* End fc_mbuf_to_iocb */ + + + +/**********************************************/ +/** handle_xmit_cmpl **/ +/** **/ +/** Process all transmit completions **/ +/** **/ +/**********************************************/ +_static_ int +handle_xmit_cmpl( +fc_dev_ctl_t *p_dev_ctl, +RING *rp, +IOCBQ *temp) +{ + FC_BRD_INFO * binfo; + IOCB * cmd; + IOCBQ * xmitiq; + IOCBQ * save; + NODELIST * nlp; + fcipbuf_t * p_mbuf; + fcipbuf_t * m_net; + int i, cnt; + ULP_BDE64 * bpl; + MATCHMAP * bmp; + DMATCHMAP * indmp; + + cmd = &temp->iocb; + binfo = &BINFO; + if (++NDDSTAT.ndd_xmitintr_lsw == 0) { + NDDSTAT.ndd_xmitintr_msw++; + } + + /* look up xmit compl by IoTag */ + if ((xmitiq = fc_ringtxp_get(rp, cmd->ulpIoTag)) == 0) { + FCSTATCTR.strayXmitCmpl++; + /* Stray XmitSequence completion */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0606, /* ptr to msg structure */ + fc_mes0606, /* ptr to msg */ + fc_msgBlk0606.msgPreambleStr, /* begin varargs */ + cmd->ulpCommand, + cmd->ulpIoTag); /* end varargs */ + /* completion with missing xmit command */ + return(EIO); + } + + if (rp->fc_ringno == FC_ELS_RING) { + indmp = (DMATCHMAP * )xmitiq->bp; + if (cmd->ulpStatus) { + indmp->dfc_flag = -1; + } + else { + indmp->dfc_flag = xmitiq->iocb.un.xseq64.bdl.bdeSize; + } + fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq); + return(0); + } + + + NDDSTAT.ndd_xmitque_cur--; + + /* get mbuf ptr for completed xmit */ + m_net = (fcipbuf_t * )xmitiq->bp; + + /* check for first xmit completion in sequence */ + nlp = (NODELIST * ) xmitiq->info; + + if (cmd->ulpStatus) { + uint32 did = 0; + + NDDSTAT.ndd_oerrors++; + + if (nlp) + did = nlp->nlp_DID; + /* Xmit Sequence completion error */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0607, /* ptr to msg structure */ + fc_mes0607, /* ptr to msg */ + fc_msgBlk0607.msgPreambleStr, /* begin varargs */ + cmd->ulpStatus, + cmd->ulpIoTag, + cmd->un.ulpWord[4], + did); /* end varargs */ + if (nlp && (nlp->nlp_state >= NLP_LOGIN)) { + /* If XRI in xmit sequence with status error matches XRI + * in nlplist entry, we need to create a new one. + */ + if ((nlp->nlp_Xri == cmd->ulpContext) && + !(nlp->nlp_flag & NLP_RPI_XRI)) { + /* on xmit error, exchange is aborted */ + nlp->nlp_Xri = 0; /* xri */ + /* establish a new exchange */ + if ((nlp->nlp_Rpi) && + (binfo->fc_ffstate == FC_READY)) { + nlp->nlp_flag |= NLP_RPI_XRI; + fc_create_xri(binfo, &binfo->fc_ring[FC_ELS_RING], nlp); + } + } + } + } else { + if (++NDDSTAT.ndd_opackets_lsw == 0) + NDDSTAT.ndd_opackets_msw++; + + if (m_net && + ((nlp && ((nlp->nlp_DID & CT_DID_MASK) != CT_DID_MASK)) || + (xmitiq->iocb.ulpCommand == CMD_XMIT_BCAST_CX))) { + + if(lpfc_nethdr == 0) { + p_mbuf = fcnextdata(m_net); + cnt = fcpktlen(p_mbuf); + } + else { + p_mbuf = m_net; + cnt = fcpktlen(p_mbuf) - sizeof(NETHDR); /* total data in mbuf */ + } + + NDDSTAT.ndd_obytes_lsw += cnt; + if ((int)NDDSTAT.ndd_obytes_lsw < cnt) + NDDSTAT.ndd_obytes_msw++; + } + } + + if (nlp && (nlp->nlp_DID == NameServer_DID)) { + MATCHMAP * mp; + + mp = (MATCHMAP * )m_net; + if (binfo->fc_flag & FC_SLI2) { + fc_mem_put(binfo, MEM_BPL, (uchar * )xmitiq->bpl); + } + fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq); + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + return(0); + } + + /* Loop through iocb chain and unmap memory pages associated with mbuf */ + if (binfo->fc_flag & FC_SLI2) { + MATCHMAP * savebmp; + int cnt; + + bmp = (MATCHMAP * )xmitiq->bpl; + cnt = xmitiq->iocb.un.xseq64.bdl.bdeSize; + while (bmp) { + bpl = (ULP_BDE64 * )bmp->virt; + while (bpl && cnt) { + bpl->addrHigh = PCIMEM_LONG(bpl->addrHigh); + bpl->addrLow = PCIMEM_LONG(bpl->addrLow); + bpl->tus.w = PCIMEM_LONG(bpl->tus.w); + switch (bpl->tus.f.bdeFlags) { + case BPL64_SIZE_WORD: + cnt = bpl->tus.f.bdeSize; + bpl = 0; + break; + case BDE64_SIZE_WORD: + fc_bufunmap(p_dev_ctl, (uchar *)getPaddr(bpl->addrHigh, bpl->addrLow), 0, bpl->tus.f.bdeSize); + bpl++; + cnt -= sizeof(ULP_BDE64); + break; + default: + bpl = 0; + cnt = 0; + break; + } + } + savebmp = (MATCHMAP * )bmp->fc_mptr; + fc_mem_put(binfo, MEM_BPL, (uchar * )bmp); + bmp = savebmp; + } + fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq); + } else { + while (xmitiq) { + for (i = 0; i < (int)xmitiq->iocb.ulpBdeCount; i++) { + fc_bufunmap(p_dev_ctl, (uchar *)((ulong)xmitiq->iocb.un.cont[i].bdeAddress), 0, (uint32)xmitiq->iocb.un.cont[i].bdeSize); + } + save = (IOCBQ * )xmitiq->q; + fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq); + xmitiq = save; + } + } + + /* free mbuf */ + if (m_net) { + if(lpfc_nethdr == 0) { + p_mbuf = fcnextdata(m_net); + fcnextdata(m_net) = 0; + fcfreehandle(p_dev_ctl, m_net); + m_freem(m_net); + + /* Put p_mbuf back the way it was, without NETHDR */ + fcincdatalen(p_mbuf, sizeof(struct fc_hdr )); + + fcdata(p_mbuf) -= sizeof(struct fc_hdr ); + } + else { + p_mbuf = m_net; + } + + fcfreehandle(p_dev_ctl, p_mbuf); + m_freem(p_mbuf); + } + + fc_restartio(p_dev_ctl, nlp); + + return(0); +} /* End handle_xmit_cmpl */ + + +/* + * Issue an iocb command to create an exchange with the remote + * specified by the NODELIST entry. + */ +_static_ int +fc_create_xri( +FC_BRD_INFO *binfo, +RING *rp, +NODELIST *nlp) +{ + IOCB * icmd; + IOCBQ * temp; + + /* While there are buffers to post */ + if ((temp = (IOCBQ * )fc_mem_get(binfo, MEM_IOCB)) == 0) { + return(1); + } + fc_bzero((void *)temp, sizeof(IOCBQ)); + icmd = &temp->iocb; + + /* set up an iotag so we can match the completion to an iocb/mbuf */ + icmd->ulpIoTag = rp->fc_iotag++; + if (rp->fc_iotag == 0) { + rp->fc_iotag = 1; + } + icmd->ulpContext = nlp->nlp_Rpi; + icmd->ulpLe = 1; + + icmd->ulpCommand = CMD_CREATE_XRI_CR; + icmd->ulpOwner = OWN_CHIP; + + temp->bp = (uchar * )nlp; /* used for delimiter between commands */ + + FCSTATCTR.cmdCreateXri++; + + issue_iocb_cmd(binfo, rp, temp); + return(0); +} /* End fc_create_xri */ + + +/* + * Process a create_xri command completion. + */ +_static_ int +handle_create_xri( +fc_dev_ctl_t *p_dev_ctl, +RING *rp, +IOCBQ *temp) +{ + FC_BRD_INFO * binfo; + IOCB * cmd; + NODELIST * nlp; + IOCBQ * xmitiq; + + cmd = &temp->iocb; + binfo = &BINFO; + /* look up xmit compl by IoTag */ + if ((xmitiq = fc_ringtxp_get(rp, cmd->ulpIoTag)) == 0) { + FCSTATCTR.strayXmitCmpl++; + /* Stray CreateXRI completion */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0608, /* ptr to msg structure */ + fc_mes0608, /* ptr to msg */ + fc_msgBlk0608.msgPreambleStr, /* begin varargs */ + cmd->ulpCommand, + cmd->ulpIoTag); /* end varargs */ + /* completion with missing xmit command */ + return(EIO); + } + + /* check for first xmit completion in sequence */ + nlp = (NODELIST * ) xmitiq->bp; + + if (cmd->ulpStatus) { + fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq); + + nlp->nlp_flag &= ~NLP_RPI_XRI; + + fc_freenode_did(binfo, nlp->nlp_DID, 0); + + FCSTATCTR.xriStatErr++; + return(EIO); + } + + FCSTATCTR.xriCmdCmpl++; + + nlp->nlp_Xri = cmd->ulpContext; + nlp->nlp_flag &= ~NLP_RPI_XRI; + + fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq); + + fc_restartio(p_dev_ctl, nlp); + return(0); +} /* End handle_create_xri */ + + +_static_ void +fc_restartio( +fc_dev_ctl_t *p_dev_ctl, +NODELIST *nlp) +{ + FC_BRD_INFO * binfo; + RING * rp; + fcipbuf_t * p_cur_mbuf; + fcipbuf_t * buf_tofree; + + binfo = &BINFO; + rp = &binfo->fc_ring[FC_IP_RING]; + + if (nlp) { + if ((nlp->nlp_bp) && (nlp->nlp_Xri)) { + p_cur_mbuf = (fcipbuf_t * )nlp->nlp_bp; + nlp->nlp_bp = 0; + buf_tofree = fc_txq_put(p_dev_ctl, rp, p_cur_mbuf); + while ((p_cur_mbuf = buf_tofree) != 0) { + NDDSTAT.ndd_opackets_drop++; + buf_tofree = fcnextpkt(buf_tofree); + fcnextpkt(p_cur_mbuf) = NULL; + m_freem(p_cur_mbuf); + } + } + } + + /* Is there a xmit waiting to be started */ + if (rp->fc_tx.q_first) { + /* If so, start it */ + issue_iocb_cmd(binfo, rp, 0); + } + + /* If needed */ +} /* End fc_restartio */ + + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/hbaapi.h 830-ivtv/drivers/scsi/lpfc/hbaapi.h --- 000-virgin/drivers/scsi/lpfc/hbaapi.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/hbaapi.h Thu Jan 8 10:21:53 2004 @@ -0,0 +1,311 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Enterprise Fibre Channel Host Bus Adapters. * + * Refer to the README file included with this package for * + * driver version and adapter support. * + * Copyright (C) 2003 Emulex Corporation. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details, a copy of which * + * can be found in the file COPYING included with this package. * + *******************************************************************/ + +#ifndef HBA_API_H +#define HBA_API_H + +/* Library version string */ +#define HBA_LIBVERSION 1 + +/* DLL imports for WIN32 operation */ +#define HBA_API + +/* OS specific definitions */ + + +typedef unsigned char HBA_UINT8; /* Unsigned 8 bits */ +typedef char HBA_INT8; /* Signed 8 bits */ +typedef unsigned short HBA_UINT16; /* Unsigned 16 bits */ +typedef short HBA_INT16; /* Signed 16 bits */ +typedef unsigned int HBA_UINT32; /* Unsigned 32 bits */ +typedef int HBA_INT32; /* Signed 32 bits */ +typedef void* HBA_PVOID; /* Pointer to void */ +typedef HBA_UINT32 HBA_VOID32; /* Opaque 32 bits */ +typedef long long HBA_INT64; +typedef long long HBA_UINT64; + + + +/* 4.2.1 Handle to Device */ +typedef HBA_UINT32 HBA_HANDLE; + +/* 4.2.2 Status Return Values */ +typedef HBA_UINT32 HBA_STATUS; + +#define HBA_STATUS_OK 0 +#define HBA_STATUS_ERROR 1 /* Error */ +#define HBA_STATUS_ERROR_NOT_SUPPORTED 2 /* Function not supported.*/ +#define HBA_STATUS_ERROR_INVALID_HANDLE 3 /* invalid handle */ +#define HBA_STATUS_ERROR_ARG 4 /* Bad argument */ +#define HBA_STATUS_ERROR_ILLEGAL_WWN 5 /* WWN not recognized */ +#define HBA_STATUS_ERROR_ILLEGAL_INDEX 6 /* Index not recognized */ +#define HBA_STATUS_ERROR_MORE_DATA 7 /* Larger buffer required */ +#define HBA_STATUS_ERROR_STALE_DATA 8 /* need a refresh */ + + + +/* 4.2.3 Port Operational Modes Values */ + +typedef HBA_UINT32 HBA_PORTTYPE; + +#define HBA_PORTTYPE_UNKNOWN 1 /* Unknown */ +#define HBA_PORTTYPE_OTHER 2 /* Other */ +#define HBA_PORTTYPE_NOTPRESENT 3 /* Not present */ +#define HBA_PORTTYPE_NPORT 5 /* Fabric */ +#define HBA_PORTTYPE_NLPORT 6 /* Public Loop */ +#define HBA_PORTTYPE_FLPORT 7 /* Fabric Loop Port */ +#define HBA_PORTTYPE_FPORT 8 /* Fabric Port */ +#define HBA_PORTTYPE_EPORT 9 /* Fabric expansion port */ +#define HBA_PORTTYPE_GPORT 10 /* Generic Fabric Port */ +#define HBA_PORTTYPE_LPORT 20 /* Private Loop */ +#define HBA_PORTTYPE_PTP 21 /* Point to Point */ + + +typedef HBA_UINT32 HBA_PORTSTATE; +#define HBA_PORTSTATE_UNKNOWN 1 /* Unknown */ +#define HBA_PORTSTATE_ONLINE 2 /* Operational */ +#define HBA_PORTSTATE_OFFLINE 3 /* User Offline */ +#define HBA_PORTSTATE_BYPASSED 4 /* Bypassed */ +#define HBA_PORTSTATE_DIAGNOSTICS 5 /* In diagnostics mode */ +#define HBA_PORTSTATE_LINKDOWN 6 /* Link Down */ +#define HBA_PORTSTATE_ERROR 7 /* Port Error */ +#define HBA_PORTSTATE_LOOPBACK 8 /* Loopback */ + + +typedef HBA_UINT32 HBA_PORTSPEED; +#define HBA_PORTSPEED_1GBIT 1 /* 1 GBit/sec */ +#define HBA_PORTSPEED_2GBIT 2 /* 2 GBit/sec */ +#define HBA_PORTSPEED_10GBIT 4 /* 10 GBit/sec */ + + + +/* 4.2.4 Class of Service Values - See GS-2 Spec.*/ + +typedef HBA_UINT32 HBA_COS; + + +/* 4.2.5 Fc4Types Values */ + +typedef struct HBA_fc4types { + HBA_UINT8 bits[32]; /* 32 bytes of FC-4 per GS-2 */ +} HBA_FC4TYPES, *PHBA_FC4TYPES; + +/* 4.2.6 Basic Types */ + +typedef struct HBA_wwn { + HBA_UINT8 wwn[8]; +} HBA_WWN, *PHBA_WWN; + +typedef struct HBA_ipaddress { + int ipversion; /* see enumerations in RNID */ + union + { + unsigned char ipv4address[4]; + unsigned char ipv6address[16]; + } ipaddress; +} HBA_IPADDRESS, *PHBA_IPADDRESS; + +/* 4.2.7 Adapter Attributes */ +typedef struct hba_AdapterAttributes { + char Manufacturer[64]; /*Emulex */ + char SerialNumber[64]; /* A12345 */ + char Model[256]; /* QLA2200 */ + char ModelDescription[256]; /* Agilent TachLite */ + HBA_WWN NodeWWN; + char NodeSymbolicName[256]; /* From GS-3 */ + char HardwareVersion[256]; /* Vendor use */ + char DriverVersion[256]; /* Vendor use */ + char OptionROMVersion[256]; /* Vendor use - i.e. hardware boot ROM*/ + char FirmwareVersion[256]; /* Vendor use */ + HBA_UINT32 VendorSpecificID; /* Vendor specific */ + HBA_UINT32 NumberOfPorts; + char DriverName[256]; /* Binary path and/or name of driver file. */ +} HBA_ADAPTERATTRIBUTES, *PHBA_ADAPTERATTRIBUTES; + +/* 4.2.8 Port Attributes */ +typedef struct HBA_PortAttributes { + HBA_WWN NodeWWN; + HBA_WWN PortWWN; + HBA_UINT32 PortFcId; + HBA_PORTTYPE PortType; /*PTP, Fabric, etc. */ + HBA_PORTSTATE PortState; + HBA_COS PortSupportedClassofService; + HBA_FC4TYPES PortSupportedFc4Types; + HBA_FC4TYPES PortActiveFc4Types; + char PortSymbolicName[256]; + char OSDeviceName[256]; /* \device\ScsiPort3 */ + HBA_PORTSPEED PortSupportedSpeed; + HBA_PORTSPEED PortSpeed; + HBA_UINT32 PortMaxFrameSize; + HBA_WWN FabricName; + HBA_UINT32 NumberofDiscoveredPorts; +} HBA_PORTATTRIBUTES, *PHBA_PORTATTRIBUTES; + + + +/* 4.2.9 Port Statistics */ + +typedef struct HBA_PortStatistics { + HBA_INT64 SecondsSinceLastReset; + HBA_INT64 TxFrames; + HBA_INT64 TxWords; + HBA_INT64 RxFrames; + HBA_INT64 RxWords; + HBA_INT64 LIPCount; + HBA_INT64 NOSCount; + HBA_INT64 ErrorFrames; + HBA_INT64 DumpedFrames; + HBA_INT64 LinkFailureCount; + HBA_INT64 LossOfSyncCount; + HBA_INT64 LossOfSignalCount; + HBA_INT64 PrimitiveSeqProtocolErrCount; + HBA_INT64 InvalidTxWordCount; + HBA_INT64 InvalidCRCCount; +} HBA_PORTSTATISTICS, *PHBA_PORTSTATISTICS; + + + +/* 4.2.10 FCP Attributes */ + +typedef enum HBA_fcpbindingtype { TO_D_ID, TO_WWN } HBA_FCPBINDINGTYPE; + +typedef struct HBA_ScsiId { + char OSDeviceName[256]; /* \device\ScsiPort3 */ + HBA_UINT32 ScsiBusNumber; /* Bus on the HBA */ + HBA_UINT32 ScsiTargetNumber; /* SCSI Target ID to OS */ + HBA_UINT32 ScsiOSLun; +} HBA_SCSIID, *PHBA_SCSIID; + +typedef struct HBA_FcpId { + HBA_UINT32 FcId; + HBA_WWN NodeWWN; + HBA_WWN PortWWN; + HBA_UINT64 FcpLun; +} HBA_FCPID, *PHBA_FCPID; + +typedef struct HBA_FcpScsiEntry { + HBA_SCSIID ScsiId; + HBA_FCPID FcpId; +} HBA_FCPSCSIENTRY, *PHBA_FCPSCSIENTRY; + +typedef struct HBA_FCPTargetMapping { + HBA_UINT32 NumberOfEntries; + HBA_FCPSCSIENTRY entry[1]; /* Variable length array containing mappings*/ +} HBA_FCPTARGETMAPPING, *PHBA_FCPTARGETMAPPING; + +typedef struct HBA_FCPBindingEntry { + HBA_FCPBINDINGTYPE type; + HBA_SCSIID ScsiId; + HBA_FCPID FcpId; /* WWN valid only if type is to WWN, FcpLun always valid */ + HBA_UINT32 FcId; /* valid only if type is to DID */ +} HBA_FCPBINDINGENTRY, *PHBA_FCPBINDINGENTRY; + +typedef struct HBA_FCPBinding { + HBA_UINT32 NumberOfEntries; + HBA_FCPBINDINGENTRY entry[1]; /* Variable length array */ +} HBA_FCPBINDING, *PHBA_FCPBINDING; + +/* 4.2.11 FC-3 Management Atrributes */ + +typedef enum HBA_wwntype { NODE_WWN, PORT_WWN } HBA_WWNTYPE; + +typedef struct HBA_MgmtInfo { + HBA_WWN wwn; + HBA_UINT32 unittype; + HBA_UINT32 PortId; + HBA_UINT32 NumberOfAttachedNodes; + HBA_UINT16 IPVersion; + HBA_UINT16 UDPPort; + HBA_UINT8 IPAddress[16]; + HBA_UINT16 reserved; + HBA_UINT16 TopologyDiscoveryFlags; +} HBA_MGMTINFO, *PHBA_MGMTINFO; + +#define HBA_EVENT_LIP_OCCURRED 1 +#define HBA_EVENT_LINK_UP 2 +#define HBA_EVENT_LINK_DOWN 3 +#define HBA_EVENT_LIP_RESET_OCCURRED 4 +#define HBA_EVENT_RSCN 5 +#define HBA_EVENT_PROPRIETARY 0xFFFF + +typedef struct HBA_Link_EventInfo { + HBA_UINT32 PortFcId; /* Port which this event occurred */ + HBA_UINT32 Reserved[3]; +} HBA_LINK_EVENTINFO, *PHBA_LINK_EVENTINFO; + +typedef struct HBA_RSCN_EventInfo { + HBA_UINT32 PortFcId; /* Port which this event occurred */ + HBA_UINT32 NPortPage; /* Reference FC-FS for RSCN ELS "Affected N-Port Pages"*/ + HBA_UINT32 Reserved[2]; +} HBA_RSCN_EVENTINFO, *PHBA_RSCN_EVENTINFO; + +typedef struct HBA_Pty_EventInfo { + HBA_UINT32 PtyData[4]; /* Proprietary data */ +} HBA_PTY_EVENTINFO, *PHBA_PTY_EVENTINFO; + +typedef struct HBA_EventInfo { + HBA_UINT32 EventCode; + union { + HBA_LINK_EVENTINFO Link_EventInfo; + HBA_RSCN_EVENTINFO RSCN_EventInfo; + HBA_PTY_EVENTINFO Pty_EventInfo; + } Event; +} HBA_EVENTINFO, *PHBA_EVENTINFO; + +/* Used for OSDeviceName */ +typedef struct HBA_osdn { + char drvname[32]; + HBA_UINT32 instance; + HBA_UINT32 target; + HBA_UINT32 lun; + HBA_UINT32 bus; + char flags; + char sizeSN; + char InquirySN[32]; +} HBA_OSDN; + +/* Function Prototypes */ +#if (!defined(_KERNEL) && !defined(__KERNEL__)) +uint32 GetAdapterAttributes(uint32, HBA_ADAPTERATTRIBUTES *); +uint32 GetAdapterPortAttributes(uint32, HBA_UINT32, HBA_PORTATTRIBUTES *); +uint32 GetPortStatistics(uint32, HBA_UINT32, HBA_PORTSTATISTICS *); +uint32 GetDiscoveredPortAttributes(uint32, HBA_UINT32, HBA_UINT32, HBA_PORTATTRIBUTES *); +uint32 GetPortAttributesByWWN(uint32, HBA_WWN *, HBA_PORTATTRIBUTES *); +uint32 GetPortAttributesByIndex(uint32, HBA_UINT32, HBA_UINT32, HBA_PORTATTRIBUTES *); +uint32 GetEventBuffer(uint32, PHBA_EVENTINFO, HBA_UINT32 *); +uint32 SetRNIDMgmtInfo(uint32, HBA_MGMTINFO *); +uint32 GetRNIDMgmtInfo(uint32, HBA_MGMTINFO *); +uint32 SendRNID(uint32, HBA_WWN *, HBA_WWNTYPE, void *, HBA_UINT32 *); +void ResetStatistics(uint32, HBA_UINT32); +uint32 RefreshInformation(uint32); +uint32 GetFcpTargetMapping(uint32, PHBA_FCPTARGETMAPPING); +uint32 GetFcpPersistentBinding(uint32, PHBA_FCPBINDING); +uint32 SendCTPassThru(uint32, void *, HBA_UINT32, void *, HBA_UINT32 *); +uint32 SendReportLUNs(uint32, HBA_WWN *, void *, HBA_UINT32 *, void *, + HBA_UINT32 *); +uint32 SendReadCapacity(uint32, HBA_WWN *, HBA_UINT64, void *, HBA_UINT32 *, + void *, HBA_UINT32 *); +uint32 SendScsiInquiry(uint32, HBA_WWN *, HBA_UINT64, HBA_UINT8, HBA_UINT32, + void *, HBA_UINT32 *, void *, HBA_UINT32 *); +#endif + + +#endif + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/lp6000.c 830-ivtv/drivers/scsi/lpfc/lp6000.c --- 000-virgin/drivers/scsi/lpfc/lp6000.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/lp6000.c Thu Jan 8 10:21:53 2004 @@ -0,0 +1,2696 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Enterprise Fibre Channel Host Bus Adapters. * + * Refer to the README file included with this package for * + * driver version and adapter support. * + * Copyright (C) 2003 Emulex Corporation. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details, a copy of which * + * can be found in the file COPYING included with this package. * + *******************************************************************/ + +/* Routine Declaration - Local */ +_local_ int fc_binfo_init(fc_dev_ctl_t *p_dev_ctl); +_local_ int fc_parse_vpd(fc_dev_ctl_t *p_dev_ctl, uchar *vpd); +_local_ int fc_proc_ring_event( fc_dev_ctl_t *p_dev_ctl, RING *rp, + IOCBQ *saveq); +/* End Routine Declaration - Local */ +extern uint32 fcPAGESIZE; +extern uint32 fc_diag_state; +extern int fcinstance[]; + +int fc_check_for_vpd = 1; +int fc_reset_on_attach = 0; + +extern int fc_max_els_sent; + +#define FC_MAX_VPD_SIZE 0x100 +static uint32 fc_vpd_data[FC_MAX_VPD_SIZE]; + +static uint32 fc_run_biu_test[256] = { + /* Walking ones */ + 0x80000000, 0x40000000, 0x20000000, 0x10000000, + 0x08000000, 0x04000000, 0x02000000, 0x01000000, + 0x00800000, 0x00400000, 0x00200000, 0x00100000, + 0x00080000, 0x00040000, 0x00020000, 0x00010000, + 0x00008000, 0x00004000, 0x00002000, 0x00001000, + 0x00000800, 0x00000400, 0x00000200, 0x00000100, + 0x00000080, 0x00000040, 0x00000020, 0x00000010, + 0x00000008, 0x00000004, 0x00000002, 0x00000001, + + /* Walking zeros */ + 0x7fffffff, 0xbfffffff, 0xdfffffff, 0xefffffff, + 0xf7ffffff, 0xfbffffff, 0xfdffffff, 0xfeffffff, + 0xff7fffff, 0xffbfffff, 0xffdfffff, 0xffefffff, + 0xfff7ffff, 0xfffbffff, 0xfffdffff, 0xfffeffff, + 0xffff7fff, 0xffffbfff, 0xffffdfff, 0xffffefff, + 0xfffff7ff, 0xfffffbff, 0xfffffdff, 0xfffffeff, + 0xffffff7f, 0xffffffbf, 0xffffffdf, 0xffffffef, + 0xfffffff7, 0xfffffffb, 0xfffffffd, 0xfffffffe, + + /* all zeros */ + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + + /* all ones */ + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + + /* all 5's */ + 0x55555555, 0x55555555, 0x55555555, 0x55555555, + 0x55555555, 0x55555555, 0x55555555, 0x55555555, + 0x55555555, 0x55555555, 0x55555555, 0x55555555, + 0x55555555, 0x55555555, 0x55555555, 0x55555555, + 0x55555555, 0x55555555, 0x55555555, 0x55555555, + 0x55555555, 0x55555555, 0x55555555, 0x55555555, + 0x55555555, 0x55555555, 0x55555555, 0x55555555, + 0x55555555, 0x55555555, 0x55555555, 0x55555555, + + /* all a's */ + 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, + 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, + 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, + 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, + 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, + 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, + 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, + 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, + + /* all 5a's */ + 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, + 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, + 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, + 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, + 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, + 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, + 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, + 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, + + /* all a5's */ + 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, + 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, + 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, + 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, + 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, + 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, + 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, + 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5 +}; + +extern _static_ void fc_read_nv(FC_BRD_INFO *binfo, MAILBOX *mb); +#define S(N,V) (((V)<<(N))|((V)>>(32-(N)))) +#define BYTESWAP(x) ((x<<24) | (x >> 24) | (0xFF00 & (x >> 8)) | (0xFF0000 & (x << 8))); + +/************************************************************************/ +/* */ +/* fc_swap_bcopy */ +/* */ +/************************************************************************/ +_static_ void +fc_swap_bcopy( +uint32 *src, +uint32 *dest, +uint32 cnt) +{ + uint32 ldata; + int i; + + for (i = 0; i < (int)cnt; i += sizeof(uint32)) { + ldata = *src++; + ldata = cpu_to_be32(ldata); + *dest++ = ldata; + } +} /* End fc_swap_bcopy */ + +/************************************************************************/ +/* */ +/* fc_init_hba */ +/* */ +/************************************************************************/ +uint32 +fc_init_hba( +fc_dev_ctl_t * p_dev_ctl, +MAILBOX * mb, +uint32 * pwwnn) +{ + FC_BRD_INFO * binfo; + uint32 * pText; + char licensed[56] = "key unlock for use with gnu public licensed code only\0"; + pText = (uint32 *) licensed; + fc_swap_bcopy(pText, pText, 56); + binfo = &BINFO; + /* Setup and issue mailbox READ NVPARAMS command */ + binfo->fc_ffstate = FC_INIT_NVPARAMS; + fc_read_nv(binfo, mb); + memset((void*) mb->un.varRDnvp.rsvd3, 0, sizeof(mb->un.varRDnvp.rsvd3)); + memcpy((void*) mb->un.varRDnvp.rsvd3, licensed, sizeof(licensed)); + if (issue_mb_cmd(binfo, mb, MBX_POLL) != MBX_SUCCESS) { + /* Adapter initialization error, mbxCmd READ_NVPARM, mbxStatus */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0303, /* ptr to msg structure */ + fc_mes0303, /* ptr to msg */ + fc_msgBlk0303.msgPreambleStr, /* begin varargs */ + mb->mbxCommand, + mb->mbxStatus); /* end varargs */ + return(0); + } + fc_bcopy ((uchar*)mb->un.varRDnvp.nodename, (uchar*) pwwnn, sizeof(mb->un.varRDnvp.nodename)); + return(1); +} + +/************************************************************************/ +/* */ +/* sha_initialize */ +/* */ +/************************************************************************/ +void +sha_initialize( +uint32 *HashResultPointer) +{ + HashResultPointer[0] = 0x67452301; + HashResultPointer[1] = 0xEFCDAB89; + HashResultPointer[2] = 0x98BADCFE; + HashResultPointer[3] = 0x10325476; + HashResultPointer[4] = 0xC3D2E1F0; +} +/************************************************************************/ +/* */ +/* sha_iterate */ +/* */ +/************************************************************************/ +void +sha_iterate( +uint32 *HashResultPointer, +uint32 *HashWorkingPointer) +{ + int t; + uint32 TEMP; + uint32 A, B, C, D, E; + t = 16; + do + { + HashWorkingPointer[t] = S(1,HashWorkingPointer[t-3]^HashWorkingPointer[t-8]^HashWorkingPointer[t-14]^HashWorkingPointer[t-16]); + } while (++t <= 79); + t = 0; + A = HashResultPointer[0]; + B = HashResultPointer[1]; + C = HashResultPointer[2]; + D = HashResultPointer[3]; + E = HashResultPointer[4]; + + do + { + if (t < 20) + { + TEMP = ((B & C) | ((~B) & D)) + 0x5A827999; + } else if (t < 40) { + TEMP = (B ^ C ^ D) + 0x6ED9EBA1; + } else if (t < 60) { + TEMP = ((B & C) | (B & D) | (C & D)) + 0x8F1BBCDC; + } else { + TEMP = (B ^ C ^ D) + 0xCA62C1D6; + } + TEMP += S(5,A) + E + HashWorkingPointer[t]; + E = D; + D = C; + C = S(30,B); + B = A; + A = TEMP; + } while (++t <= 79); + + HashResultPointer[0] += A; + HashResultPointer[1] += B; + HashResultPointer[2] += C; + HashResultPointer[3] += D; + HashResultPointer[4] += E; + +} +/************************************************************************/ +/* */ +/* Challenge_XOR_KEY */ +/* */ +/************************************************************************/ +void +Challenge_XOR_KEY +(uint32 *RandomChallenge, + uint32 *HashWorking) +{ + *HashWorking = (*RandomChallenge ^ *HashWorking); +} + +/************************************************************************/ +/* */ +/* fc_SHA1 */ +/* */ +/************************************************************************/ +void +fc_SHA1( +uint32 * pwwnn, +uint32 * phbainitEx, +uint32 * RandomData) +{ + int t; + uint32 HashWorking[80]; + + fc_bzero(HashWorking, sizeof(HashWorking)); + HashWorking[0] = HashWorking[78] = *pwwnn++; + HashWorking[1] = HashWorking[79] = *pwwnn; + for (t = 0; t < 7 ; t++) { + Challenge_XOR_KEY(RandomData+t,HashWorking+t); + } + sha_initialize(phbainitEx); + sha_iterate(phbainitEx, HashWorking); +} + +/************************************************************************/ +/* */ +/* fc_ffinit */ +/* */ +/************************************************************************/ +_static_ int +fc_ffinit( +fc_dev_ctl_t *p_dev_ctl) +{ + FC_BRD_INFO * binfo; + iCfgParam * clp; + fc_vpd_t * vp; + uint32 status, i, j; + uint32 read_rev_reset, hbainit = 0; + uint32 RandomData[7]; + uint32 hbainitEx[5]; + uint32 wwnn[2]; + struct pci_dev *pdev; + int ipri, flogi_sent; + MBUF_INFO bufinfo; + MBUF_INFO * buf_info; + void * ioa; + RING * rp; + MAILBOX * mb; + MATCHMAP * mp, *mp1, *mp2; + uchar * inptr, *outptr; + + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + vp = &VPD; + mb = 0; + + pdev = p_dev_ctl->pcidev ; + /* Set board state to initialization started */ + binfo->fc_ffstate = FC_INIT_START; + read_rev_reset = 0; + + if(fc_reset_on_attach) { + binfo->fc_ffstate = 0; + fc_brdreset(p_dev_ctl); + binfo->fc_ffstate = FC_INIT_START; + DELAYMS(2500); + } + +top: + ioa = (void *)FC_MAP_IO(&binfo->fc_iomap_io); /* map in io registers */ + +#if LITTLE_ENDIAN_HOST + /* For Little Endian, BIU_BSE is not supported */ +#else +#ifdef BIU_BSE + status = READ_CSR_REG(binfo, FC_BC_REG(binfo, ioa)); + WRITE_CSR_REG(binfo, FC_BC_REG(binfo, ioa), (BC_BSE_SWAP | status)); + i = READ_CSR_REG(binfo, FC_BC_REG(binfo, ioa)); +#endif +#endif + + status = READ_CSR_REG(binfo, FC_STAT_REG(binfo, ioa)); + FC_UNMAP_MEMIO(ioa); + + i = 0; + + /* Check status register to see what current state is */ + while ((status & (HS_FFRDY | HS_MBRDY)) != (HS_FFRDY | HS_MBRDY)) { + + /* Check every 100ms for 5 retries, then every 500ms for 5, then + * every 2.5 sec for 5, then reset board and every 2.5 sec for 4. + */ + if (i++ >= 20) { + /* Adapter failed to init, timeout, status reg */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0436, /* ptr to msg structure */ + fc_mes0436, /* ptr to msg */ + fc_msgBlk0436.msgPreambleStr, /* begin varargs */ + status); /* end varargs */ + binfo->fc_ffstate = FC_ERROR; + return(EIO); + } + + /* Check to see if any errors occurred during init */ + if (status & HS_FFERM) { + /* ERROR: During chipset initialization */ + /* Adapter failed to init, chipset, status reg */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0437, /* ptr to msg structure */ + fc_mes0437, /* ptr to msg */ + fc_msgBlk0437.msgPreambleStr, /* begin varargs */ + status); /* end varargs */ + binfo->fc_ffstate = FC_ERROR; + return(EIO); + } + + if (i <= 5) { + DELAYMS(100); + } + else if (i <= 10) { + DELAYMS(500); + } + else { + DELAYMS(2500); + } + + if (i == 15) { + /* Reset board and try one more time */ + binfo->fc_ffstate = 0; + fc_brdreset(p_dev_ctl); + binfo->fc_ffstate = FC_INIT_START; + } + + ioa = (void *)FC_MAP_IO(&binfo->fc_iomap_io); /* map in io registers */ + status = READ_CSR_REG(binfo, FC_STAT_REG(binfo, ioa)); + FC_UNMAP_MEMIO(ioa); + } + + /* Check to see if any errors occurred during init */ + if (status & HS_FFERM) { + /* ERROR: During chipset initialization */ + /* Adapter failed to init, chipset, status reg */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0438, /* ptr to msg structure */ + fc_mes0438, /* ptr to msg */ + fc_msgBlk0438.msgPreambleStr, /* begin varargs */ + status); /* end varargs */ + binfo->fc_ffstate = FC_ERROR; + return(EIO); + } + + ioa = (void *)FC_MAP_IO(&binfo->fc_iomap_io); /* map in io registers */ + + /* Clear all interrupt enable conditions */ + WRITE_CSR_REG(binfo, FC_HC_REG(binfo, ioa), 0); + + /* setup host attn register */ + WRITE_CSR_REG(binfo, FC_HA_REG(binfo, ioa), 0xffffffff); + + FC_UNMAP_MEMIO(ioa); + + if(read_rev_reset) + goto do_read_rev; + + fc_binfo_init(p_dev_ctl); + + /* Allocate some memory for buffers */ + if (fc_malloc_buffer(p_dev_ctl) == 0) { + binfo->fc_ffstate = FC_ERROR; + return(ENOMEM); + } + + fc_get_dds_bind(p_dev_ctl); + + /* Get a buffer which will be used repeatedly for mailbox commands */ + if ((mb = (MAILBOX * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI)) == 0) { + binfo->fc_ffstate = FC_ERROR; + fc_free_buffer(p_dev_ctl); + return(ENOMEM); + } + +do_read_rev: + if((pdev->device == PCI_DEVICE_ID_TFLY)|| + (pdev->device == PCI_DEVICE_ID_PFLY)) + hbainit = fc_init_hba(p_dev_ctl, mb, wwnn); + /* Setup and issue mailbox READ REV command */ + binfo->fc_ffstate = FC_INIT_REV; + fc_read_rev(binfo, mb); + if (issue_mb_cmd(binfo, mb, MBX_POLL) != MBX_SUCCESS) { + /* Adapter failed to init, mbxCmd READ_REV, mbxStatus */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0439, /* ptr to msg structure */ + fc_mes0439, /* ptr to msg */ + fc_msgBlk0439.msgPreambleStr, /* begin varargs */ + mb->mbxCommand, + mb->mbxStatus); /* end varargs */ + + /* If read_rev fails, give it one more chance */ + if(read_rev_reset == 0) { + binfo->fc_ffstate = 0; + fc_brdreset(p_dev_ctl); + binfo->fc_ffstate = FC_INIT_START; + + DELAYMS(2500); + DELAYMS(2500); + + read_rev_reset = 1; + goto top; + } + binfo->fc_ffstate = FC_ERROR; + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + fc_free_buffer(p_dev_ctl); + return(EIO); + } + + if(mb->un.varRdRev.rr == 0) { + + if(read_rev_reset == 0) { + binfo->fc_ffstate = 0; + fc_brdreset(p_dev_ctl); + binfo->fc_ffstate = FC_INIT_START; + + DELAYMS(2500); + DELAYMS(2500); + + read_rev_reset = 1; + goto top; + } + + vp->rev.rBit = 0; + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0440, /* ptr to msg structure */ + fc_mes0440, /* ptr to msg */ + fc_msgBlk0440.msgPreambleStr, /* begin varargs */ + mb->mbxCommand, + read_rev_reset); /* end varargs */ + } + else { + if(mb->un.varRdRev.un.b.ProgType != 2) { + if(read_rev_reset == 0) { + binfo->fc_ffstate = 0; + fc_brdreset(p_dev_ctl); + binfo->fc_ffstate = FC_INIT_START; + + DELAYMS(2500); + DELAYMS(2500); + + read_rev_reset = 1; + goto top; + } + } + vp->rev.rBit = 1; + vp->rev.sli1FwRev = mb->un.varRdRev.sli1FwRev; + fc_bcopy((uchar *)mb->un.varRdRev.sli1FwName, (uchar *)vp->rev.sli1FwName, 16); + vp->rev.sli2FwRev = mb->un.varRdRev.sli2FwRev; + fc_bcopy((uchar *)mb->un.varRdRev.sli2FwName, (uchar *)vp->rev.sli2FwName, 16); + } + + /* Save information as VPD data */ + vp->rev.biuRev = mb->un.varRdRev.biuRev; + vp->rev.smRev = mb->un.varRdRev.smRev; + vp->rev.smFwRev = mb->un.varRdRev.un.smFwRev; + vp->rev.endecRev = mb->un.varRdRev.endecRev; + vp->rev.fcphHigh = mb->un.varRdRev.fcphHigh; + vp->rev.fcphLow = mb->un.varRdRev.fcphLow; + vp->rev.feaLevelHigh = mb->un.varRdRev.feaLevelHigh; + vp->rev.feaLevelLow = mb->un.varRdRev.feaLevelLow; + vp->rev.postKernRev = mb->un.varRdRev.postKernRev; + vp->rev.opFwRev = mb->un.varRdRev.opFwRev; + if((pdev->device == PCI_DEVICE_ID_TFLY)|| + (pdev->device == PCI_DEVICE_ID_PFLY)) + fc_bcopy((uchar *)&mb->un.varWords[24], (uchar *)RandomData, sizeof(RandomData)); + + dfc_fmw_rev(p_dev_ctl); /* Save firmware rev for HBAAPI */ + + if(fc_check_for_vpd) { + /* Get adapter VPD information */ + fc_dump_mem(binfo, mb); + if (issue_mb_cmd(binfo, mb, MBX_POLL) != MBX_SUCCESS) { + /* + * Let it go through even if failed. + */ + /* Adapter failed to init, mbxCmd DUMP VPD, mbxStatus */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0441, /* ptr to msg structure */ + fc_mes0441, /* ptr to msg */ + fc_msgBlk0441.msgPreambleStr, /* begin varargs */ + mb->mbxCommand, + mb->mbxStatus); /* end varargs */ + + /* If dump_mem times out, give it one more chance */ + if((read_rev_reset == 0) && (mb->mbxStatus == 0)) { + binfo->fc_ffstate = 0; + fc_brdreset(p_dev_ctl); + binfo->fc_ffstate = FC_INIT_START; + + DELAYMS(2500); + DELAYMS(2500); + + read_rev_reset = 1; + goto top; + } + } + else { + if((mb->un.varDmp.ra == 1) && + (mb->un.varDmp.word_cnt <= FC_MAX_VPD_SIZE)) { + uint32 *lp1, *lp2; + + lp1 = (uint32 * )&mb->un.varDmp.resp_offset; + lp2 = (uint32 * )&fc_vpd_data[0]; + for(i=0;iun.varDmp.word_cnt;i++) { + status = *lp1++; + *lp2++ = SWAP_LONG(status); + } + fc_parse_vpd(p_dev_ctl, (uchar *)&fc_vpd_data[0]); + } + } + } + + /* Setup and issue mailbox CONFIG_PORT or PARTITION_SLIM command */ + binfo->fc_ffstate = FC_INIT_PARTSLIM; + if (binfo->fc_sli == 2) { + if((pdev->device == PCI_DEVICE_ID_TFLY)|| + (pdev->device == PCI_DEVICE_ID_PFLY)){ + fc_SHA1(wwnn, hbainitEx, RandomData); + fc_config_port(binfo, mb, (uint32 *) hbainitEx); + } + else + fc_config_port(binfo, mb, &hbainit); + if (issue_mb_cmd(binfo, mb, MBX_POLL) != MBX_SUCCESS) { + /* Adapter failed to init, mbxCmd CONFIG_PORT, mbxStatus */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0442, /* ptr to msg structure */ + fc_mes0442, /* ptr to msg */ + fc_msgBlk0442.msgPreambleStr, /* begin varargs */ + mb->mbxCommand, + mb->mbxStatus, + 0); /* end varargs */ + + /* If config_port fails, give it one more chance */ + if(read_rev_reset == 0) { + binfo->fc_ffstate = 0; + fc_brdreset(p_dev_ctl); + binfo->fc_ffstate = FC_INIT_START; + + DELAYMS(2500); + DELAYMS(2500); + + read_rev_reset = 1; + goto top; + } + + binfo->fc_flag &= ~FC_SLI2; + binfo->fc_mboxaddr = 0; + if (binfo->fc_slim2.virt) { + buf_info = &bufinfo; + if (binfo->fc_slim2.phys) { + buf_info->phys = (void * )binfo->fc_slim2.phys; + buf_info->data_handle = binfo->fc_slim2.data_handle; + buf_info->dma_handle = binfo->fc_slim2.dma_handle; + buf_info->flags = FC_MBUF_DMA; + } else { + buf_info->phys = 0; + buf_info->data_handle = 0; + buf_info->dma_handle = 0; + buf_info->flags = 0; + } + buf_info->size = fcPAGESIZE; + buf_info->virt = (void * )binfo->fc_slim2.virt; + fc_free(p_dev_ctl, buf_info); + binfo->fc_slim2.virt = 0; + binfo->fc_slim2.phys = 0; + binfo->fc_slim2.dma_handle = 0; + binfo->fc_slim2.data_handle = 0; + } + binfo->fc_ffstate = FC_ERROR; + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + fc_free_buffer(p_dev_ctl); + return(EIO); + } + } else { + /* SLI1 not supported, mbxCmd , mbxStatus */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0443, /* ptr to msg structure */ + fc_mes0443, /* ptr to msg */ + fc_msgBlk0443.msgPreambleStr, /* begin varargs */ + mb->mbxCommand, + mb->mbxStatus, + 0); /* end varargs */ + binfo->fc_ffstate = FC_ERROR; + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + fc_free_buffer(p_dev_ctl); + return(EIO); + } + + /* Initialize cmd/rsp ring pointers */ + for (i = 0; i < (uint32)binfo->fc_ffnumrings; i++) { + rp = &binfo->fc_ring[i]; + + rp->fc_ringno = (uchar)i; + rp->fc_xmitstate = FC_LINK_UP; + if ((i == FC_IP_RING) || (i == FC_FCP_RING)) + rp->fc_xmitstate = FC_READY; + rp->fc_binfo = (uchar * )binfo; + rp->fc_iocbhd = 0; + rp->fc_iocbtl = 0; + rp->fc_cmdidx = 0; + rp->fc_rspidx = 0; + rp->fc_iotag = 1; /* used to identify each I/O */ + if (i == FC_FCP_RING) + rp->fc_bufcnt = MAX_FCP_CMDS; /* Used for ABTS iotag */ + + /* offsets are from the beginning of SLIM */ + if (!(binfo->fc_flag & FC_SLI2)) { + /* offsets are from the beginning of SLIM */ + rp->fc_cmdringaddr = (void *)((ulong)(mb->un.varSlim.ringdef[i].offCiocb)); + rp->fc_rspringaddr = (void *)((ulong)(mb->un.varSlim.ringdef[i].offRiocb)); + + } + } + + mp1 = 0; + mp2 = 0; + /* Setup and issue mailbox RUN BIU DIAG command */ + /* setup test buffers */ + if (((mp = (MATCHMAP * )fc_mem_get(binfo, MEM_BUF | MEM_PRI)) == 0) || + ((mp1 = (MATCHMAP * )fc_mem_get(binfo, MEM_BUF | MEM_PRI)) == 0) || + ((mp2 = (MATCHMAP * )fc_mem_get(binfo, MEM_BUF | MEM_PRI)) == 0)) { + /* Adapter failed to init, no buffers for RUN_BIU_DIAG */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0444, /* ptr to msg structure */ + fc_mes0444, /* ptr to msg */ + fc_msgBlk0444.msgPreambleStr); /* begin & end varargs */ + if (mp) + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + if (mp1) + fc_mem_put(binfo, MEM_BUF, (uchar * )mp1); + binfo->fc_ffstate = FC_ERROR; + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + fc_free_buffer(p_dev_ctl); + return(ENOMEM); + } + + fc_mpdata_incopy(p_dev_ctl, mp, (uchar * ) & fc_run_biu_test[0], FCELSSIZE); + fc_mpdata_sync(mp->dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV); + inptr = mp->virt; + /* Issue mailbox command */ + fc_runBIUdiag(binfo, mb, mp->phys, mp1->phys); + if (issue_mb_cmd(binfo, mb, MBX_POLL) != MBX_SUCCESS) { + ioa = (void *)FC_MAP_IO(&binfo->fc_iomap_io); /* map in io registers */ + FC_UNMAP_MEMIO(ioa); + /* Adapter failed init, mailbox cmd runBIUdiag mbxStatus */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0447, /* ptr to msg structure */ + fc_mes0447, /* ptr to msg */ + fc_msgBlk0447.msgPreambleStr, /* begin varargs */ + mb->mbxCommand, + mb->mbxStatus); /* end varargs */ + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + fc_mem_put(binfo, MEM_BUF, (uchar * )mp1); + fc_mem_put(binfo, MEM_BUF, (uchar * )mp2); + binfo->fc_ffstate = FC_ERROR; + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + fc_free_buffer(p_dev_ctl); + return(EIO); + } + + fc_mpdata_sync(mp1->dma_handle, 0, 0, DDI_DMA_SYNC_FORKERNEL); + fc_mpdata_outcopy(p_dev_ctl, mp1, (uchar * )mp2->virt, FCELSSIZE); + outptr = (uchar * )mp2->virt; + + for (i = 0; i < FCELSSIZE; i++) { + if (*outptr++ != *inptr++) { + outptr--; + inptr--; + /* RUN_BIU_DIAG failed */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0445, /* ptr to msg structure */ + fc_mes0445, /* ptr to msg */ + fc_msgBlk0445.msgPreambleStr); /* begin & end varargs */ + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + fc_mem_put(binfo, MEM_BUF, (uchar * )mp1); + fc_mem_put(binfo, MEM_BUF, (uchar * )mp2); + binfo->fc_ffstate = FC_ERROR; + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + fc_free_buffer(p_dev_ctl); + return(EIO); + } + } + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + fc_mem_put(binfo, MEM_BUF, (uchar * )mp1); + fc_mem_put(binfo, MEM_BUF, (uchar * )mp2); + + /* Setup and issue mailbox CONFIGURE RING command */ + for (i = 0; i < (uint32)binfo->fc_ffnumrings; i++) { + binfo->fc_ffstate = FC_INIT_CFGRING; + fc_config_ring(binfo, i, 0, mb); + if (issue_mb_cmd(binfo, mb, MBX_POLL) != MBX_SUCCESS) { + /* Adapter failed to init, mbxCmd CFG_RING, mbxStatus , ring */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0446, /* ptr to msg structure */ + fc_mes0446, /* ptr to msg */ + fc_msgBlk0446.msgPreambleStr, /* begin varargs */ + mb->mbxCommand, + mb->mbxStatus, + i); /* ring num - end varargs */ + binfo->fc_ffstate = FC_ERROR; + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + fc_free_buffer(p_dev_ctl); + return(EIO); + } + } + + /* Setup link timers */ + fc_config_link(p_dev_ctl, mb); + if (issue_mb_cmd(binfo, mb, MBX_POLL) != MBX_SUCCESS) { + /* Adapter failed to init, mbxCmd CONFIG_LINK mbxStatus */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0447, /* ptr to msg structure */ + fc_mes0447, /* ptr to msg */ + fc_msgBlk0447.msgPreambleStr, /* begin varargs */ + mb->mbxCommand, + mb->mbxStatus); /* end varargs */ + binfo->fc_ffstate = FC_ERROR; + fc_ffcleanup(p_dev_ctl); + i_clear(&IHS); + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + fc_free_buffer(p_dev_ctl); + return(EIO); + } + + /* We need to get login parameters for NID */ + fc_read_sparam(p_dev_ctl, mb); + if (issue_mb_cmd(binfo, mb, MBX_POLL) != MBX_SUCCESS) { + /* Adapter failed to init, mbxCmd READ_SPARM mbxStatus */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0448, /* ptr to msg structure */ + fc_mes0448, /* ptr to msg */ + fc_msgBlk0448.msgPreambleStr, /* begin varargs */ + mb->mbxCommand, + mb->mbxStatus); /* end varargs */ + binfo->fc_ffstate = FC_ERROR; + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + fc_free_buffer(p_dev_ctl); + return(EIO); + } + + mp = (MATCHMAP * )binfo->fc_mbbp; + fc_mpdata_sync(mp->dma_handle, 0, sizeof(SERV_PARM), + DDI_DMA_SYNC_FORKERNEL); + fc_mpdata_outcopy(p_dev_ctl, mp, (uchar * ) & binfo->fc_sparam, + sizeof(SERV_PARM)); + + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + binfo->fc_mbbp = 0; + + fc_bcopy((uchar * )&binfo->fc_sparam.nodeName, (uchar * )&binfo->fc_nodename, + sizeof(NAME_TYPE)); + fc_bcopy((uchar * )&binfo->fc_sparam.portName, (uchar * )&binfo->fc_portname, + sizeof(NAME_TYPE)); + fc_bcopy(binfo->fc_portname.IEEE, p_dev_ctl->phys_addr, 6); + + /* If no serial number in VPD data, use low 6 bytes of WWNN */ + if(binfo->fc_SerialNumber[0] == 0) { + outptr = (uchar *) &binfo->fc_nodename.IEEE[0]; + for(i=0;i<12;i++) { + status = *outptr++; + j = ((status & 0xf0) >> 4); + if(j <= 9) + binfo->fc_SerialNumber[i] = (char)((uchar)0x30 + (uchar)j); + else + binfo->fc_SerialNumber[i] = (char)((uchar)0x61 + (uchar)(j-10)); + i++; + j = (status & 0xf); + if(j <= 9) + binfo->fc_SerialNumber[i] = (char)((uchar)0x30 + (uchar)j); + else + binfo->fc_SerialNumber[i] = (char)((uchar)0x61 + (uchar)(j-10)); + } + } + + if(clp[CFG_NETWORK_ON].a_current) { + if ((binfo->fc_sparam.portName.nameType != NAME_IEEE) || + (binfo->fc_sparam.portName.IEEEextMsn != 0) || + (binfo->fc_sparam.portName.IEEEextLsb != 0)) { + clp[CFG_NETWORK_ON].a_current = 0; + /* WorldWide PortName Type doesn't conform to IP Profile */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0449, /* ptr to msg structure */ + fc_mes0449, /* ptr to msg */ + fc_msgBlk0449.msgPreambleStr, /* begin varargs */ + binfo->fc_sparam.portName.nameType); /* end varargs */ + } + + fc_config_farp(binfo, mb); + if (issue_mb_cmd(binfo, mb, MBX_POLL) != MBX_SUCCESS) { + /* + * Let it go through even if failed. + */ + /* Adapter failed to init, mbxCmd FARP, mbxStatus */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0450, /* ptr to msg structure */ + fc_mes0450, /* ptr to msg */ + fc_msgBlk0450.msgPreambleStr, /* begin varargs */ + mb->mbxCommand, + mb->mbxStatus); /* end varargs */ + } + } + + if (p_dev_ctl->intr_inited != 1) { + /* Add our interrupt routine to kernel's interrupt chain & enable it */ + + + IHS.handler = fc_intr; + + if ((i_init((struct intr *) & IHS)) == INTR_FAIL) { + /* Enable interrupt handler failed */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0451, /* ptr to msg structure */ + fc_mes0451, /* ptr to msg */ + fc_msgBlk0451.msgPreambleStr); /* begin & end varargs */ + binfo->fc_ffstate = FC_ERROR; + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + fc_free_buffer(p_dev_ctl); + return(EIO); + } + p_dev_ctl->intr_inited = 1; + } + + fc_disable_tc(binfo, (MAILBOX * )mb); + if (issue_mb_cmd(binfo, mb, MBX_POLL) != MBX_SUCCESS) { + binfo->fc_ffstate = FC_ERROR; + fc_ffcleanup(p_dev_ctl); + i_clear(&IHS); + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + fc_free_buffer(p_dev_ctl); + return(EIO); + } + + fc_read_config(binfo, (MAILBOX * )mb); + if (issue_mb_cmd(binfo, mb, MBX_POLL) != MBX_SUCCESS) { + /* Adapter failed to init, mbxCmd READ_CONFIG, mbxStatus */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0453, /* ptr to msg structure */ + fc_mes0453, /* ptr to msg */ + fc_msgBlk0453.msgPreambleStr, /* begin varargs */ + mb->mbxCommand, + mb->mbxStatus); /* end varargs */ + binfo->fc_ffstate = FC_ERROR; + fc_ffcleanup(p_dev_ctl); + i_clear(&IHS); + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + fc_free_buffer(p_dev_ctl); + return(EIO); + } + + if (mb->un.varRdConfig.lmt & LMT_2125_10bit) + /* HBA is 2G capable */ + binfo->fc_flag |= FC_2G_CAPABLE; + + binfo->fc_ffstate = FC_LINK_DOWN; + binfo->fc_flag |= FC_LNK_DOWN; + + /* Activate the adapter and allocate all the resources needed for ELS */ + fc_start(p_dev_ctl); + + /* Setup and issue mailbox INITIALIZE LINK command */ + fc_init_link(binfo, mb, clp[CFG_TOPOLOGY].a_current, + clp[CFG_LINK_SPEED].a_current); + if (issue_mb_cmd(binfo, mb, MBX_NOWAIT) != MBX_SUCCESS) { + /* Adapter failed to init, mbxCmd INIT_LINK, mbxStatus */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0454, /* ptr to msg structure */ + fc_mes0454, /* ptr to msg */ + fc_msgBlk0454.msgPreambleStr, /* begin varargs */ + mb->mbxCommand, + mb->mbxStatus); /* end varargs */ + binfo->fc_ffstate = FC_ERROR; + fc_ffcleanup(p_dev_ctl); + i_clear(&IHS); + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + fc_free_buffer(p_dev_ctl); + return(EIO); + } + + + /* Enable link attention interrupt */ + ipri = disable_lock(FC_LVL, &CMD_LOCK); + ioa = (void *)FC_MAP_IO(&binfo->fc_iomap_io); /* map in io registers */ + status = READ_CSR_REG(binfo, FC_HC_REG(binfo, ioa)); + status = status | HC_LAINT_ENA; + WRITE_CSR_REG(binfo, FC_HC_REG(binfo, ioa), status); + FC_UNMAP_MEMIO(ioa); + binfo->fc_process_LA = 1; + p_dev_ctl->fc_waitflogi = (FCCLOCK *)1; + unlock_enable(ipri, &CMD_LOCK); + + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + + binfo->fc_prevDID = Mask_DID; + /* If we are point to point, don't wait for link up */ + if ((clp[CFG_TOPOLOGY].a_current == FLAGS_TOPOLOGY_MODE_PT_PT) && + (clp[CFG_FCP_ON].a_current == 0)) { + goto out; + } + + flogi_sent = 0; + i = 0; + while (binfo->fc_ffstate != FC_READY) { + /* Check every second for 20 retries. */ + if ((i++ > 20) || + ((i >= 10) && (binfo->fc_ffstate <= FC_LINK_DOWN))) { + /* The link is down, so set linkdown timeout */ + rp = &binfo->fc_ring[FC_FCP_RING]; + RINGTMO = fc_clk_set(p_dev_ctl, rp->fc_ringtmo, fc_linkdown_timeout, 0, 0); + break; + } + ipri = disable_lock(FC_LVL, &CMD_LOCK); + if((i > 1) && (binfo->fc_ffstate == FC_FLOGI) && + (flogi_sent == 0) && (p_dev_ctl->power_up == 0)) { + if(p_dev_ctl->fc_waitflogi) { + if (p_dev_ctl->fc_waitflogi != (FCCLOCK *)1) + fc_clk_can(p_dev_ctl, p_dev_ctl->fc_waitflogi); + p_dev_ctl->fc_waitflogi = 0; + } + fc_snd_flogi(p_dev_ctl, 0, 0); + flogi_sent = 1; + rp = &binfo->fc_ring[FC_ELS_RING]; + if(RINGTMO) + fc_clk_res(p_dev_ctl, 20, RINGTMO); + } + unlock_enable(ipri, &CMD_LOCK); + + DELAYMS(1000); + } + +out: + ipri = disable_lock(FC_LVL, &CMD_LOCK); + if((binfo->fc_ffstate == FC_FLOGI) && (p_dev_ctl->power_up == 0)) { + fc_snd_flogi(p_dev_ctl, 0, 0); + } + p_dev_ctl->power_up = 1; + unlock_enable(ipri, &CMD_LOCK); + + return(0); +} /* End fc_ffinit */ + +/************************************************************************/ +/* */ +/* fc_binfo_init */ +/* This routine will initialize the binfo structure */ +/* */ +/************************************************************************/ +_local_ int +fc_binfo_init( +fc_dev_ctl_t *p_dev_ctl) +{ + FC_BRD_INFO * binfo; + iCfgParam * clp; + int idx; + + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + + /* Initialize configuration parameters */ + if(binfo->fc_flag & FC_ESTABLISH_LINK) + binfo->fc_flag = FC_ESTABLISH_LINK; + else + binfo->fc_flag = 0; /* don't change nvram or tov */ + + binfo->fc_ffnumrings = MAX_CONFIGURED_RINGS - 1; /* number of rings */ + + /* Ring 0 - ELS */ + binfo->fc_nummask[0] = 4; + + binfo->fc_rval[0] = FC_ELS_REQ; /* ELS request */ + binfo->fc_tval[0] = FC_ELS_DATA; /* ELS */ + binfo->fc_rval[1] = FC_ELS_RSP; /* ELS response */ + binfo->fc_tval[1] = FC_ELS_DATA; /* ELS */ + binfo->fc_rval[2] = FC_UNSOL_CTL; /* NameServer Inquiries */ + binfo->fc_tval[2] = FC_COMMON_TRANSPORT_ULP; /* NameServer */ + binfo->fc_rval[3] = FC_SOL_CTL; /* NameServer response */ + binfo->fc_tval[3] = FC_COMMON_TRANSPORT_ULP; /* NameServer */ + if (binfo->fc_sli == 2) { + binfo->fc_ring[0].fc_numCiocb = SLI2_IOCB_CMD_R0_ENTRIES; + binfo->fc_ring[0].fc_numRiocb = SLI2_IOCB_RSP_R0_ENTRIES; + } else { + binfo->fc_ring[0].fc_numCiocb = IOCB_CMD_R0_ENTRIES; + binfo->fc_ring[0].fc_numRiocb = IOCB_RSP_R0_ENTRIES; + } + + /* Ring 1 - IP */ + if(clp[CFG_NETWORK_ON].a_current) { + binfo->fc_nummask[1] = 1; + idx = 5; + } else { + binfo->fc_nummask[1] = 0; + idx = 4; + } + binfo->fc_rval[4] = FC_UNSOL_DATA; /* Unsolicited Data */ + binfo->fc_tval[4] = FC_LLC_SNAP; /* LLC/SNAP */ + if (binfo->fc_sli == 2) { + binfo->fc_ring[1].fc_numCiocb = SLI2_IOCB_CMD_R1_ENTRIES; + binfo->fc_ring[1].fc_numRiocb = SLI2_IOCB_RSP_R1_ENTRIES; + if(clp[CFG_NETWORK_ON].a_current == 0) { + binfo->fc_ring[1].fc_numCiocb -= SLI2_IOCB_CMD_R1XTRA_ENTRIES; + binfo->fc_ring[1].fc_numRiocb -= SLI2_IOCB_RSP_R1XTRA_ENTRIES; + } + } else { + binfo->fc_ring[1].fc_numCiocb = IOCB_CMD_R1_ENTRIES; + binfo->fc_ring[1].fc_numRiocb = IOCB_RSP_R1_ENTRIES; + } + + /* Ring 2 - FCP */ + binfo->fc_nummask[2] = 0; + if (binfo->fc_sli == 2) { + binfo->fc_ring[2].fc_numCiocb = SLI2_IOCB_CMD_R2_ENTRIES; + binfo->fc_ring[2].fc_numRiocb = SLI2_IOCB_RSP_R2_ENTRIES; + if(clp[CFG_NETWORK_ON].a_current == 0) { + binfo->fc_ring[2].fc_numCiocb += SLI2_IOCB_CMD_R2XTRA_ENTRIES; + binfo->fc_ring[2].fc_numRiocb += SLI2_IOCB_RSP_R2XTRA_ENTRIES; + } + } else { + binfo->fc_ring[2].fc_numCiocb = IOCB_CMD_R2_ENTRIES; + binfo->fc_ring[2].fc_numRiocb = IOCB_RSP_R2_ENTRIES; + } + + + binfo->ipVersion = RNID_IPV4; + return(0); +} /* End fc_binfo_init */ + +/************************************************************************/ +/* */ +/* fc_parse_vpd */ +/* This routine will parse the VPD data */ +/* */ +/************************************************************************/ +_local_ int +fc_parse_vpd( +fc_dev_ctl_t *p_dev_ctl, +uchar *vpd) +{ + FC_BRD_INFO * binfo; + int finished = 0; + int index = 0; + uchar lenlo, lenhi; + unsigned char *Length; + int i, j; + + binfo = &BINFO; + /* Vital Product */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0455, /* ptr to msg structure */ + fc_mes0455, /* ptr to msg */ + fc_msgBlk0455.msgPreambleStr, /* begin varargs */ + (uint32)vpd[0], + (uint32)vpd[1], + (uint32)vpd[2], + (uint32)vpd[3]); /* end varargs */ + do { + switch (vpd[index]) { + case 0x82: + index += 1; + lenlo = vpd[index]; + index += 1; + lenhi = vpd[index]; + index += 1; + i = ((((unsigned short)lenhi) << 8) + lenlo); + index += i; + break; + case 0x90: + index += 1; + lenlo = vpd[index]; + index += 1; + lenhi = vpd[index]; + index += 1; + i = ((((unsigned short)lenhi) << 8) + lenlo); + do { + /* Look for Serial Number */ + if ((vpd[index] == 'S') && (vpd[index+1] == 'N')) { + index += 2; + Length = &vpd[index]; + index += 1; + i = *Length; + j = 0; + while(i--) { + binfo->fc_SerialNumber[j++] = vpd[index++]; + if(j == 31) + break; + } + binfo->fc_SerialNumber[j] = 0; + return(1); + } + else { + index += 2; + Length = &vpd[index]; + index += 1; + j = (int)(*Length); + index += j; + i -= (3 + j); + } + } while (i > 0); + finished = 0; + break; + case 0x78: + finished = 1; + break; + default: + return(0); + } + } while (!finished); + return(1); +} + +_static_ char fwrevision[32]; + +/* TAPE */ +_static_ char * +decode_firmware_rev( +FC_BRD_INFO *binfo, +fc_vpd_t *vp) +{ + uint32 b1, b2, b3, b4, ldata; + char c; + uint32 i, rev; + uint32 *ptr, str[4]; + + if ( vp->rev.rBit ) { + if (binfo->fc_sli == 2) + rev = vp->rev.sli2FwRev; + else + rev = vp->rev.sli1FwRev; + + b1 = (rev & 0x0000f000) >> 12; + b2 = (rev & 0x00000f00) >> 8; + b3 = (rev & 0x000000c0) >> 6; + b4 = (rev & 0x00000030) >> 4; + + switch (b4) { + case 0: + c = 'N'; + break; + case 1: + c = 'A'; + break; + case 2: + c = 'B'; + break; + case 3: + default: + c = 0; + break; + } + b4 = (rev & 0x0000000f); + + if (binfo->fc_sli == 2) { + for (i=0; i<16; i++) { + if (vp->rev.sli2FwName[i] == 0x20) { + vp->rev.sli2FwName[i] = 0; + } + } + ptr = (uint32 *)vp->rev.sli2FwName; + } else { + for (i=0; i<16; i++) { + if (vp->rev.sli1FwName[i] == 0x20) { + vp->rev.sli1FwName[i] = 0; + } + } + ptr = (uint32 *)vp->rev.sli1FwName; + } + for (i=0; i<3; i++) { + ldata = *ptr++; + ldata = SWAP_DATA(ldata); + str[i] = ldata; + } + + fwrevision[0] = (char)((int)'0' + b1); + fwrevision[1] = '.'; + fwrevision[2] = (char)((int)'0' + b2); + fwrevision[3] = (char)((int)'0' + b3); + if(c) { + fwrevision[4] = c; + fwrevision[5] = (char)((int)'0' + b4); + fwrevision[6] = 0; + } + else { + fwrevision[4] = 0; + } + } else { + rev = vp->rev.smFwRev; + + b1 = (rev & 0xff000000) >> 24; + b2 = (rev & 0x00f00000) >> 20; + b3 = (rev & 0x000f0000) >> 16; + c = (char)((rev & 0x0000ff00) >> 8); + b4 = (rev & 0x000000ff); + + fwrevision[0] = (char)((int)'0' + b1); + fwrevision[1] = '.'; + fwrevision[2] = (char)((int)'0' + b2); + fwrevision[3] = (char)((int)'0' + b3); + fwrevision[4] = c; + fwrevision[5] = (char)((int)'0' + b4); + fwrevision[6] = 0; + } + return(fwrevision); +} /* End decode_firmware_rev */ + + +/*****************************************************************************/ +/* + * NAME: fc_intr + * + * FUNCTION: Fibre Channel driver interrupt routine. + * + * EXECUTION ENVIRONMENT: interrupt only + * + * CALLED FROM: + * The FLIH + * + * INPUT: + * p_ihs - point to the interrupt structure. + * + * RETURNS: + * INTR_SUCC - our interrupt + * INTR_FAIL - not our interrupt + */ +/*****************************************************************************/ +_static_ int +fc_intr( +struct intr *p_ihs) /* This also points to device control area */ +{ + fc_dev_ctl_t * p_dev_ctl = (fc_dev_ctl_t * )p_ihs; + volatile uint32 ha_copy; + FC_BRD_INFO * binfo; + iCfgParam * clp; + fcipbuf_t * mbp; + MAILBOXQ * mb; + IOCBQ * delayiocb; + IOCBQ * temp; + IOCBQ * processiocb; + IOCBQ * endiocb; + void * ioa; + int ipri, rc; + + binfo = &BINFO; + + ipri = disable_lock(FC_LVL, &CMD_LOCK); + binfo->fc_flag |= FC_INTR_THREAD; + + ioa = (void *)FC_MAP_IO(&binfo->fc_iomap_io); /* map in io registers */ + + /* Read host attention register to determine interrupt source */ + ha_copy = READ_CSR_REG(binfo, FC_HA_REG(binfo, ioa)); + + /* Clear Attention Sources, except ERROR (to preserve status) & LATT */ + WRITE_CSR_REG(binfo, FC_HA_REG(binfo, ioa), + (ha_copy & ~HA_ERATT & ~HA_LATT)); + + FC_UNMAP_MEMIO(ioa); + + + if (ha_copy) { + rc = INTR_SUCC; + binfo->fc_flag |= FC_INTR_WORK; + } else { + clp = DD_CTL.p_config[binfo->fc_brd_no]; + if (clp[CFG_INTR_ACK].a_current && (binfo->fc_flag&FC_INTR_WORK)) { + rc = INTR_SUCC; /* Just claim the first non-working interrupt */ + binfo->fc_flag &= ~FC_INTR_WORK; + } else { + if (clp[CFG_INTR_ACK].a_current == 2) + rc = INTR_SUCC; /* Always claim the interrupt */ + else + rc = INTR_FAIL; + } + } + + if (binfo->fc_flag & FC_OFFLINE_MODE) { + binfo->fc_flag &= ~FC_INTR_THREAD; + unlock_enable(ipri, &CMD_LOCK); + return(INTR_FAIL); + } + + processiocb = 0; + if(binfo->fc_delayxmit) { + delayiocb = binfo->fc_delayxmit; + binfo->fc_delayxmit = 0; + endiocb = 0; + while(delayiocb) { + temp = delayiocb; + delayiocb = (IOCBQ *)temp->q; + temp->rsvd2--; + /* If retry == 0, process IOCB */ + if(temp->rsvd2 == 0) { + if(processiocb == 0) { + processiocb = temp; + } + else { + endiocb->q = (uchar *)temp; + } + endiocb = temp; + temp->q = 0; + } + else { + /* Make delayxmit point to first non-zero retry */ + if(binfo->fc_delayxmit == 0) + binfo->fc_delayxmit = temp; + } + } + if(processiocb) { + /* Handle any delayed IOCBs */ + endiocb = processiocb; + while(endiocb) { + temp = endiocb; + endiocb = (IOCBQ *)temp->q; + temp->q = 0; + issue_iocb_cmd(binfo, &binfo->fc_ring[FC_ELS_RING], temp); + } + } + } + + + if (ha_copy & HA_ERATT) { /* Link / board error */ + unlock_enable(ipri, &CMD_LOCK); + handle_ff_error(p_dev_ctl); + return (rc); + } else { + if (ha_copy & HA_MBATT) { /* Mailbox interrupt */ + handle_mb_event(p_dev_ctl); + if(binfo->fc_flag & FC_PENDING_RING0) { + binfo->fc_flag &= ~FC_PENDING_RING0; + ha_copy |= HA_R0ATT; /* event on ring 0 */ + } + } + + if (ha_copy & HA_LATT) { /* Link Attention interrupt */ + if (binfo->fc_process_LA) { + handle_link_event(p_dev_ctl); + } + } + + if (ha_copy & HA_R0ATT) { /* event on ring 0 */ + if(binfo->fc_mbox_active == 0) + handle_ring_event(p_dev_ctl, 0, (ha_copy & 0x0000000F)); + else + binfo->fc_flag |= FC_PENDING_RING0; + } + + if (ha_copy & HA_R1ATT) { /* event on ring 1 */ + /* This ring handles IP. Defer processing anything on this ring + * till all FCP ELS traffic settles down. + */ + if (binfo->fc_ffstate <= FC_NODE_DISC) + binfo->fc_deferip |= (uchar)((ha_copy >> 4) & 0x0000000F); + else + handle_ring_event(p_dev_ctl, 1, ((ha_copy >> 4) & 0x0000000F)); + } + + if (ha_copy & HA_R2ATT) { /* event on ring 2 */ + handle_ring_event(p_dev_ctl, 2, ((ha_copy >> 8) & 0x0000000F)); + } + + if (ha_copy & HA_R3ATT) { /* event on ring 3 */ + handle_ring_event(p_dev_ctl, 3, ((ha_copy >> 12) & 0x0000000F)); + } + } + + if((processiocb == 0) && (binfo->fc_delayxmit) && + (binfo->fc_mbox_active == 0)) { + if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX))) { + fc_read_rpi(binfo, (uint32)1, (MAILBOX * )mb, (uint32)0); + if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } + } + + binfo->fc_flag &= ~FC_INTR_THREAD; + + while (p_dev_ctl->mbufl_head != 0) { + binfo->fc_flag |= FC_INTR_WORK; + mbp = (fcipbuf_t * )p_dev_ctl->mbufl_head; + p_dev_ctl->mbufl_head = (uchar * )fcnextpkt(mbp); + fcnextpkt(mbp) = 0; + fc_xmit(p_dev_ctl, mbp); + } + p_dev_ctl->mbufl_tail = 0; + + + unlock_enable(ipri, &CMD_LOCK); + return(rc); +} /* End fc_intr */ + + + +/**************************************************/ +/** handle_ff_error **/ +/** **/ +/** Runs at Interrupt level **/ +/** **/ +/**************************************************/ +_static_ void +handle_ff_error( +fc_dev_ctl_t *p_dev_ctl) +{ + volatile uint32 status, status1, status2; + void *ioa; + FC_BRD_INFO * binfo; + iCfgParam * clp; + int ipri; + + ipri = disable_lock(FC_LVL, &CMD_LOCK); + + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + + status = p_dev_ctl->dpc_hstatus; + p_dev_ctl->dpc_hstatus = 0; + + ioa = (void *)FC_MAP_MEM(&binfo->fc_iomap_mem); /* map in SLIM */ + status1 = READ_SLIM_ADDR(binfo, ((volatile uchar * )ioa + 0xa8)); + status2 = READ_SLIM_ADDR(binfo, ((volatile uchar * )ioa + 0xac)); + FC_UNMAP_MEMIO(ioa); + + + if (status & HS_FFER6) { + + + /* Re-establishing Link */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk1301, /* ptr to msg structure */ + fc_mes1301, /* ptr to msg */ + fc_msgBlk1301.msgPreambleStr, /* begin varargs */ + status, + status1, + status2); /* end varargs */ + binfo->fc_flag |= FC_ESTABLISH_LINK; + fc_cfg_remove(p_dev_ctl); + + binfo->fc_flag |= FC_OFFLINE_MODE; + + lpfc_cfg_init(p_dev_ctl); + + unlock_enable(ipri, &CMD_LOCK); + } else { + /* Adapter Hardware Error */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0457, /* ptr to msg structure */ + fc_mes0457, /* ptr to msg */ + fc_msgBlk0457.msgPreambleStr, /* begin varargs */ + status, + status1, + status2); /* end varargs */ + if (status & HS_FFER8) { /* Chipset error 8 */ + } else if (status & HS_FFER7) { /* Chipset error 7 */ + } else if (status & HS_FFER5) { /* Chipset error 5 */ + } else if (status & HS_FFER4) { /* Chipset error 4 */ + } else if (status & HS_FFER3) { /* Chipset error 3 */ + } else if (status & HS_FFER2) { /* Chipset error 2 */ + } else if (status & HS_FFER1) { /* Chipset error 1 */ + } + + fc_free_rpilist(p_dev_ctl, 0); + + p_dev_ctl->device_state = DEAD; + binfo->fc_ffstate = FC_ERROR; + unlock_enable(ipri, &CMD_LOCK); + } + +} /* End handle_ff_error */ + + +/**************************************************/ +/** handle_link_event **/ +/** **/ +/** Description: Process a Link Attention. **/ +/** **/ +/**************************************************/ +_static_ void +handle_link_event( +fc_dev_ctl_t *p_dev_ctl) +{ + /* called from host_interrupt, to process LATT */ + MAILBOX * mb; + FC_BRD_INFO * binfo; + void *ioa; + volatile uint32 control; + + binfo = &BINFO; + FCSTATCTR.linkEvent++; + + /* Get a buffer which will be used for mailbox commands */ + if ((mb = (MAILBOX * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) { + if (fc_read_la(p_dev_ctl, mb) == 0) { + if (issue_mb_cmd(binfo, mb, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + /* Turn off Link Attention interrupts until CLEAR_LA done */ + binfo->fc_process_LA = 0; + ioa = (void *)FC_MAP_IO(&binfo->fc_iomap_io); /* map in io registers */ + control = READ_CSR_REG(binfo, FC_HC_REG(binfo, ioa)); + control &= ~HC_LAINT_ENA; + WRITE_CSR_REG(binfo, FC_HC_REG(binfo, ioa), control); + /* Clear Link Attention in HA REG */ + WRITE_CSR_REG(binfo, FC_HA_REG(binfo, ioa), + (volatile uint32)(HA_LATT)); + FC_UNMAP_MEMIO(ioa); + } + else { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mb); + } + } +} /* End handle_link_event */ + + +/**************************************************/ +/** handle_ring_event **/ +/** **/ +/** Description: Process a Ring Attention. **/ +/** **/ +/**************************************************/ +_static_ void +handle_ring_event( +fc_dev_ctl_t *p_dev_ctl, +int ring_no, +uint32 reg_mask) +{ + FC_BRD_INFO * binfo; + RING * rp; + IOCB * entry; + IOCBQ * saveq; + IOCBQ * temp; + void * ioa; + int fcpfound = 0; + uint32 * xx; + uint32 portGet; + volatile uint32 chipatt; + uint32 portRspPut; + + binfo = &BINFO; + /* called from host_interrupt() to process RxATT */ + + rp = &binfo->fc_ring[ring_no]; + temp = NULL; + fc_mpdata_sync(binfo->fc_slim2.dma_handle, 0, 0, DDI_DMA_SYNC_FORKERNEL); + + /* Gather iocb entries off response ring. + * Ensure entry is owned by the host. + */ + entry = (IOCB * )IOCB_ENTRY(rp->fc_rspringaddr, rp->fc_rspidx); + portRspPut = PCIMEM_LONG(((SLI2_SLIM * )binfo->fc_slim2.virt)->mbx.us.s2.port[ring_no].rspPutInx); + if (portRspPut >= rp->fc_numRiocb) { + return; + } + + while (rp->fc_rspidx != portRspPut) { + if((ring_no == 0) && (binfo->fc_mbox_active)) { + binfo->fc_flag |= FC_PENDING_RING0; + break; + } + /* get an iocb buffer to copy entry into */ + if ((temp = (IOCBQ * )fc_mem_get(binfo, MEM_IOCB | MEM_PRI)) == NULL) { + break; + } + + + fc_pcimem_bcopy((uint32 * )entry, (uint32 * ) & temp->iocb, sizeof(IOCB)); + temp->q = NULL; + + /* bump iocb available response index */ + if (++rp->fc_rspidx >= rp->fc_numRiocb) { + rp->fc_rspidx = 0; + } + + /* SLIM POINTER */ + if (binfo->fc_busflag & FC_HOSTPTR) { + ((SLI2_SLIM * )binfo->fc_slim2.virt)->mbx.us.s2.host[ring_no].rspGetInx = + PCIMEM_LONG(rp->fc_rspidx); + } else { + void * ioa2; + + ioa = (void *)FC_MAP_MEM(&binfo->fc_iomap_mem); /* map in SLIM */ + ioa2 = (void *)((char *)ioa + ((SLIMOFF+(ring_no*2)+1)*4)); + WRITE_SLIM_ADDR(binfo, (volatile uint32 *)ioa2, rp->fc_rspidx); + FC_UNMAP_MEMIO(ioa); + } + + /* chain all iocb entries until LE is set */ + if (rp->fc_iocbhd == NULL) { + rp->fc_iocbhd = temp; + rp->fc_iocbtl = temp; + } else { + rp->fc_iocbtl->q = (uchar * )temp; + rp->fc_iocbtl = temp; + } + + /* when LE is set, entire Command has been received */ + if (temp->iocb.ulpLe) { + saveq = rp->fc_iocbhd; + + rp->fc_iocbhd = NULL; + rp->fc_iocbtl = NULL; + + /* get a ptr to first iocb entry in chain and process it */ + xx = (uint32 * ) & saveq->iocb; + fcpfound = fc_proc_ring_event(p_dev_ctl, rp, saveq); + + /* Free up iocb buffer chain for command just processed */ + while (saveq) { + temp = saveq; + saveq = (IOCBQ * )temp->q; + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + } + + } /* Entire Command has been received */ + + entry = (IOCB * )IOCB_ENTRY(rp->fc_rspringaddr, rp->fc_rspidx); + + } /* While(entry->ulpOwner == 0) */ + + if ((temp != NULL) && (reg_mask & HA_R0RE_REQ)) { + /* At least one response entry has been freed */ + FCSTATCTR.chipRingFree++; + ioa = (void *)FC_MAP_IO(&binfo->fc_iomap_io); /* map in io registers */ + /* SET R0RE_RSP in Chip Att register */ + chipatt = ((CA_R0ATT | CA_R0RE_RSP) << (ring_no * 4)); + WRITE_CSR_REG(binfo, FC_FF_REG(binfo, ioa), chipatt); + FC_UNMAP_MEMIO(ioa); + } + + if (reg_mask != 0xffffffff) { + if (fcpfound) { + fc_issue_cmd(p_dev_ctl); + } else if (reg_mask & HA_R0CE_RSP) { + FCSTATCTR.hostRingFree++; + /* Cmd ring is available, queue any available cmds */ + portGet = issue_iocb_cmd(binfo, rp, 0); + if(portGet != PCIMEM_LONG(((SLI2_SLIM * )binfo->fc_slim2.virt)->mbx.us.s2.port[rp->fc_ringno].cmdGetInx)) { + issue_iocb_cmd(binfo, rp, 0); + } + } + FCSTATCTR.ringEvent++; + } + + return; +} /* End handle_ring_event */ + +_static_ int +fc_proc_ring_event( +fc_dev_ctl_t *p_dev_ctl, +RING *rp, +IOCBQ *saveq) +{ + FC_BRD_INFO * binfo; + NODELIST * ndlp; + IOCB * cmd; + int rc; + + binfo = &BINFO; + cmd = &saveq->iocb; + rc = 0; + FCSTATCTR.iocbRsp++; + + switch (cmd->ulpCommand) { + case CMD_FCP_ICMND_CR: + case CMD_FCP_ICMND_CX: + case CMD_FCP_IREAD_CR: + case CMD_FCP_IREAD_CX: + case CMD_FCP_IWRITE_CR: + case CMD_FCP_IWRITE_CX: + case CMD_FCP_ICMND64_CR: + case CMD_FCP_ICMND64_CX: + case CMD_FCP_IREAD64_CR: + case CMD_FCP_IREAD64_CX: + case CMD_FCP_IWRITE64_CR: + case CMD_FCP_IWRITE64_CX: + handle_fcp_event(p_dev_ctl, rp, saveq); + rc = 1; + break; + + case CMD_RCV_SEQUENCE_CX: /* received incoming frame */ + case CMD_RCV_SEQUENCE64_CX: /* received incoming frame */ + switch(rp->fc_ringno) { + case FC_ELS_RING: + handle_elsrcv_seq(p_dev_ctl, rp, saveq); + break; + case FC_IP_RING: + handle_iprcv_seq(p_dev_ctl, rp, saveq); + break; + } + break; + + case CMD_XMIT_BCAST_CN: /* process xmit completion */ + case CMD_XMIT_BCAST_CX: + case CMD_XMIT_SEQUENCE_CX: + case CMD_XMIT_SEQUENCE_CR: + case CMD_XMIT_BCAST64_CN: /* process xmit completion */ + case CMD_XMIT_BCAST64_CX: + case CMD_XMIT_SEQUENCE64_CX: + case CMD_XMIT_SEQUENCE64_CR: + handle_xmit_cmpl(p_dev_ctl, rp, saveq); + break; + + case CMD_RCV_ELS_REQ_CX: /* received an els frame */ + case CMD_RCV_ELS_REQ64_CX: /* received an els frame */ + handle_rcv_els_req(p_dev_ctl, rp, saveq); + break; + + case CMD_CREATE_XRI_CR: + case CMD_CREATE_XRI_CX: + handle_create_xri(p_dev_ctl, rp, saveq); + break; + + case CMD_ELS_REQUEST_CR: /* xmit els frame completion */ + case CMD_ELS_REQUEST_CX: + case CMD_XMIT_ELS_RSP_CX: + case CMD_ELS_REQUEST64_CR: + case CMD_ELS_REQUEST64_CX: + case CMD_XMIT_ELS_RSP64_CX: + case CMD_GEN_REQUEST64_CR: + case CMD_GEN_REQUEST64_CX: + handle_els_event(p_dev_ctl, rp, saveq); + break; + + case CMD_ABORT_XRI_CN: /* Abort fcp command */ + break; + + case CMD_ABORT_XRI_CX: /* Abort command */ + break; + + case CMD_XRI_ABORTED_CX: /* Handle ABORT condition */ + /* + * If we find an NODELIST entry that matches the aborted + * XRI, clear out the Xri field. + */ + if (((ndlp = fc_findnode_oxri(binfo, NLP_SEARCH_UNMAPPED | NLP_SEARCH_MAPPED, + cmd->ulpContext)) != NULL) && !(ndlp->nlp_flag & NLP_RPI_XRI)) { + ndlp->nlp_Xri = 0; /* xri */ + /* establish a new exchange */ + if ((ndlp->nlp_Rpi) && + ((ndlp->nlp_DID & CT_DID_MASK) != CT_DID_MASK) && + (binfo->fc_ffstate == FC_READY)) { + ndlp->nlp_flag |= NLP_RPI_XRI; + fc_create_xri(binfo, &binfo->fc_ring[FC_ELS_RING], ndlp); + } + } + break; + + case CMD_ADAPTER_MSG: + if ((binfo->fc_msgidx + MAX_MSG_DATA) <= FC_MAX_ADPTMSG) { + fc_bcopy((uchar * )cmd, &binfo->fc_adaptermsg[binfo->fc_msgidx], + MAX_MSG_DATA); + binfo->fc_msgidx += MAX_MSG_DATA; + con_print("lpfc%d: %s", binfo->fc_brd_no, binfo->fc_adaptermsg); + fc_bzero((void *)binfo->fc_adaptermsg, FC_MAX_ADPTMSG); + binfo->fc_msgidx = 0; + } else { + con_print("lpfc%d: %s\n", binfo->fc_brd_no, binfo->fc_adaptermsg); + fc_bzero(binfo->fc_adaptermsg, FC_MAX_ADPTMSG); + binfo->fc_msgidx = 0; + } + break; + + + default: + /* Unknown IOCB command */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk1400, /* ptr to msg structure */ + fc_mes1400, /* ptr to msg */ + fc_msgBlk1400.msgPreambleStr, /* begin varargs */ + cmd->ulpCommand, + cmd->ulpStatus, + cmd->ulpIoTag, + cmd->ulpContext); /* end varargs */ + break; + } /* switch(cmd->ulpCommand) */ + + return(rc); +} /* End fc_proc_ring_event */ + + +/**************************************************/ +/** handle_mb_event **/ +/** **/ +/** Description: Process a Mailbox Attention. **/ +/** Called from host_interrupt to process MBATT **/ +/** **/ +/** Returns: **/ +/** **/ +/**************************************************/ +_static_ int +handle_mb_event( +fc_dev_ctl_t *p_dev_ctl) +{ + FC_BRD_INFO * binfo; + MAILBOX * mb; + MAILBOX * swpmb; + MAILBOXQ * mbox; + IOCBQ * iocbq; + NODELIST * ndlp; + void *ioa; + uint32 control; + volatile uint32 word0; + volatile uint32 ldata; + volatile uint32 ldid; + volatile uint32 lrpi; + iCfgParam * clp; + + binfo = &BINFO; + clp = DD_CTL.p_config[binfo->fc_brd_no]; + + if (binfo->fc_flag & FC_SLI2) { + fc_mpdata_sync(binfo->fc_slim2.dma_handle, 0, 0, DDI_DMA_SYNC_FORKERNEL); + /* First copy command data */ + mb = FC_SLI2_MAILBOX(binfo); + word0 = *((volatile uint32 * )mb); + word0 = PCIMEM_LONG(word0); + } else { + /* First copy command data */ + ioa = (void *)FC_MAP_MEM(&binfo->fc_iomap_mem); /* map in SLIM */ + mb = FC_MAILBOX(binfo, ioa); + word0 = READ_SLIM_ADDR(binfo, ((volatile uint32 * )mb)); + FC_UNMAP_MEMIO(ioa); + } + + swpmb = (MAILBOX * ) & word0; + + FCSTATCTR.mboxEvent++; + + /* Sanity check to ensure the host owns the mailbox */ + if (swpmb->mbxOwner != OWN_HOST) { + int i; + + for(i=0; i<10240;i++) { + if (binfo->fc_flag & FC_SLI2) { + fc_mpdata_sync(binfo->fc_slim2.dma_handle, 0, 0, DDI_DMA_SYNC_FORKERNEL); + /* First copy command data */ + mb = FC_SLI2_MAILBOX(binfo); + word0 = *((volatile uint32 * )mb); + word0 = PCIMEM_LONG(word0); + } else { + /* First copy command data */ + ioa = (void *)FC_MAP_MEM(&binfo->fc_iomap_mem); /* map in SLIM */ + mb = FC_MAILBOX(binfo, ioa); + word0 = READ_SLIM_ADDR(binfo, ((volatile uint32 * )mb)); + FC_UNMAP_MEMIO(ioa); + } + + swpmb = (MAILBOX * ) & word0; + if (swpmb->mbxOwner == OWN_HOST) + goto out; + } + /* Stray Mailbox Interrupt, mbxCommand mbxStatus */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0304, /* ptr to msg structure */ + fc_mes0304, /* ptr to msg */ + fc_msgBlk0304.msgPreambleStr, /* begin varargs */ + swpmb->mbxCommand, + swpmb->mbxStatus); /* end varargs */ + return(1); + } + +out: + + /* stop watchdog timer */ + if(MBOXTMO) { + fc_clk_can(p_dev_ctl, MBOXTMO); + MBOXTMO = 0; + } + + if (swpmb->mbxStatus) { + if (swpmb->mbxStatus == MBXERR_NO_RESOURCES) { + FCSTATCTR.mboxStatErr++; + /* Mbox cmd cmpl error - RETRYing */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0305, /* ptr to msg structure */ + fc_mes0305, /* ptr to msg */ + fc_msgBlk0305.msgPreambleStr, /* begin varargs */ + swpmb->mbxCommand, + word0, + binfo->fc_ffstate, + binfo->fc_flag); /* end varargs */ + if ((mbox = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX))) { + if (binfo->fc_flag & FC_SLI2) { + /* First copy mbox command data */ + mb = FC_SLI2_MAILBOX(binfo); + fc_pcimem_bcopy((uint32 * )mb, (uint32 * )mbox, + (sizeof(uint32) * (MAILBOX_CMD_WSIZE))); + } else { + /* First copy mbox command data */ + ioa = (void *)FC_MAP_MEM(&binfo->fc_iomap_mem); /* map in SLIM */ + mb = FC_MAILBOX(binfo, ioa); + READ_SLIM_COPY(binfo, (uint32 *)mbox, (uint32 *)mb, + MAILBOX_CMD_WSIZE); + FC_UNMAP_MEMIO(ioa); + } + switch(((MAILBOX *)mbox)->mbxCommand) { + case MBX_READ_SPARM: + control = ((MAILBOX *)mbox)->un.varRdSparm.un.sp.bdeSize; + if(control == 0) { + fc_read_sparam(p_dev_ctl, (MAILBOX *)mbox); + } + case MBX_READ_SPARM64: + control = ((MAILBOX *)mbox)->un.varRdSparm.un.sp64.tus.f.bdeSize; + if(control == 0) { + fc_read_sparam(p_dev_ctl, (MAILBOX *)mbox); + } + case MBX_REG_LOGIN: + control = ((MAILBOX *)mbox)->un.varRegLogin.un.sp.bdeSize; + if(control == 0) { + goto mbout; + } + case MBX_REG_LOGIN64: + control = ((MAILBOX *)mbox)->un.varRegLogin.un.sp64.tus.f.bdeSize; + if(control == 0) { + goto mbout; + } + case MBX_READ_LA: + control = ((MAILBOX *)mbox)->un.varReadLA.un.lilpBde.bdeSize; + if(control == 0) { + fc_read_la(p_dev_ctl, (MAILBOX *)mbox); + } + case MBX_READ_LA64: + control = ((MAILBOX *)mbox)->un.varReadLA.un.lilpBde64.tus.f.bdeSize; + if(control == 0) { + fc_read_la(p_dev_ctl, (MAILBOX *)mbox); + } + } + ((MAILBOX *)mbox)->mbxOwner = OWN_HOST; + ((MAILBOX *)mbox)->mbxStatus = 0; + mbox->bp = (uchar * )binfo->fc_mbbp; + binfo->fc_mbox_active = 0; + if (issue_mb_cmd(binfo, (MAILBOX * )mbox, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mbox); + } + return(0); + } + } + if (!((swpmb->mbxCommand == MBX_CLEAR_LA) && + (swpmb->mbxStatus == 0x1601))) { + /* Mbox cmd cmpl error */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0306, /* ptr to msg structure */ + fc_mes0306, /* ptr to msg */ + fc_msgBlk0306.msgPreambleStr, /* begin varargs */ + swpmb->mbxCommand, + word0, + binfo->fc_ffstate, + binfo->fc_flag); /* end varargs */ + FCSTATCTR.mboxStatErr++; + switch (swpmb->mbxCommand) { + case MBX_REG_LOGIN: + case MBX_REG_LOGIN64: + if (binfo->fc_flag & FC_SLI2) { + /* First copy command data */ + mb = FC_SLI2_MAILBOX(binfo); + ldata = mb->un.varWords[1]; /* get did */ + ldata = PCIMEM_LONG(ldata); + } else { + /* First copy command data */ + ioa = (void *)FC_MAP_MEM(&binfo->fc_iomap_mem); /* map in SLIM */ + mb = FC_MAILBOX(binfo, ioa); + ldata = READ_SLIM_ADDR(binfo, &mb->un.varWords[1]); + FC_UNMAP_MEMIO(ioa); + } + + ldid = ldata & Mask_DID; + if ((ndlp=fc_findnode_odid(binfo,(NLP_SEARCH_MAPPED | NLP_SEARCH_UNMAPPED), ldid))) { + if (ndlp->nlp_action & NLP_DO_DISC_START) { + /* Goto next entry */ + fc_nextnode(p_dev_ctl, ndlp); + } + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + } + break; + + case MBX_UNREG_LOGIN: + if (binfo->fc_flag & FC_SLI2) { + /* First copy command data */ + mb = FC_SLI2_MAILBOX(binfo); + ldata = mb->un.varWords[0]; /* get rpi */ + ldata = PCIMEM_LONG(ldata); + } else { + /* First copy command data */ + ioa = (void *)FC_MAP_MEM(&binfo->fc_iomap_mem); /* map in SLIM */ + mb = FC_MAILBOX(binfo, ioa); + ldata = READ_SLIM_ADDR(binfo, &mb->un.varWords[0]); + FC_UNMAP_MEMIO(ioa); + } + + lrpi = ldata & 0xffff; + + if ((ndlp = fc_findnode_rpi(binfo, lrpi)) == 0) + break; + binfo->fc_nlplookup[ndlp->nlp_Rpi] = 0; + ndlp->nlp_Rpi = 0; + fc_freenode(binfo, ndlp, 0); + ndlp->nlp_state = NLP_LIMBO; + fc_nlp_bind(binfo, ndlp); + break; + + case MBX_READ_LA: + case MBX_READ_LA64: + case MBX_CLEAR_LA: + /* Turn on Link Attention interrupts */ + binfo->fc_process_LA = 1; + + ioa = (void *)FC_MAP_IO(&binfo->fc_iomap_io); /* map in io registers */ + control = READ_CSR_REG(binfo, FC_HC_REG(binfo, ioa)); + control |= HC_LAINT_ENA; + WRITE_CSR_REG(binfo, FC_HC_REG(binfo, ioa), control); + FC_UNMAP_MEMIO(ioa); + break; + + case MBX_INIT_LINK: + if (binfo->fc_flag & FC_SLI2) { + if ((clp[CFG_LINK_SPEED].a_current > 0) && + ((swpmb->mbxStatus == 0x0011) || (swpmb->mbxStatus == 0x0500))) { + /* Reset link speed to auto. 1G node detected in loop. */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk1302, /* ptr to msg structure */ + fc_mes1302, /* ptr to msg */ + fc_msgBlk1302.msgPreambleStr); /* begin & end varargs */ + clp[CFG_LINK_SPEED].a_current = LINK_SPEED_AUTO; + if ((mbox = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX))) { + /* First copy mbox command data */ + mb = FC_SLI2_MAILBOX(binfo); + fc_pcimem_bcopy((uint32 * )mb, (uint32 * )mbox, + (sizeof(uint32) * (MAILBOX_CMD_WSIZE))); + ((MAILBOX *)mbox)->un.varInitLnk.link_flags &= ~FLAGS_LINK_SPEED; + ((MAILBOX *)mbox)->un.varInitLnk.link_speed = 0; /* LINK_SPEED_AUTO */ + ((MAILBOX *)mbox)->mbxOwner = OWN_HOST; + ((MAILBOX *)mbox)->mbxStatus = 0; + mbox->bp = (uchar * )binfo->fc_mbbp; + binfo->fc_mbox_active = 0; + if (issue_mb_cmd(binfo, (MAILBOX * )mbox, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mbox); + } + return(0); + } + } + } + break; + } + if (binfo->fc_mbbp) { + fc_mem_put(binfo, MEM_BUF, (uchar * )binfo->fc_mbbp); + binfo->fc_mbbp = 0; + } + goto mbout; + } + } + + /* Mbox cmd cmpl */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0307, /* ptr to msg structure */ + fc_mes0307, /* ptr to msg */ + fc_msgBlk0307.msgPreambleStr, /* begin varargs */ + swpmb->mbxCommand, + word0, + binfo->fc_ffstate, + binfo->fc_flag); /* end varargs */ + + if(binfo->fc_mbox_active == 2) { + MAILBOX *mbslim; + + /* command was issued by dfc layer, so save mbox cmpl */ + if ((binfo->fc_flag & FC_SLI2) && (!(binfo->fc_flag & FC_OFFLINE_MODE))) { + /* First copy command data */ + mbslim = FC_SLI2_MAILBOX(binfo); + /* copy results back to user */ + fc_pcimem_bcopy((uint32 * )mbslim, (uint32 * )&p_dev_ctl->dfcmb, + (sizeof(uint32) * MAILBOX_CMD_WSIZE)); + } else { + /* First copy command data */ + ioa = (void *)FC_MAP_MEM(&binfo->fc_iomap_mem); /* map in SLIM */ + mbslim = FC_MAILBOX(binfo, ioa); + /* copy results back to user */ + READ_SLIM_COPY(binfo, (uint32 * )&p_dev_ctl->dfcmb, (uint32 * )mbslim, + MAILBOX_CMD_WSIZE); + FC_UNMAP_MEMIO(ioa); + } + } + else { + handle_mb_cmd(p_dev_ctl, swpmb, (uint32)swpmb->mbxCommand); + } + + +mbout: + /* Process next mailbox command if there is one */ + binfo->fc_mbox_active = 0; + if ((mbox = fc_mbox_get(binfo))) { + if (issue_mb_cmd(binfo, (MAILBOX * )mbox, MBX_NOWAIT) != MBX_BUSY) { + fc_mem_put(binfo, MEM_MBOX, (uchar * )mbox); + } + } else { + if (binfo->fc_flag & FC_DELAY_PLOGI) { + binfo->fc_flag &= ~FC_DELAY_PLOGI; + if((binfo->fc_flag & FC_RSCN_MODE) && (binfo->fc_ffstate == FC_READY)) + fc_nextrscn(p_dev_ctl, fc_max_els_sent); + else + fc_nextdisc(p_dev_ctl, fc_max_els_sent); + } + if (binfo->fc_flag & FC_DELAY_NSLOGI) { + if ((iocbq = fc_plogi_get(binfo))) { + fc_els_cmd(binfo, ELS_CMD_PLOGI, + (void *)((ulong)iocbq->iocb.un.elsreq.remoteID), + (uint32)0, (ushort)0, (NODELIST *)0); + fc_mem_put(binfo, MEM_IOCB, (uchar * )iocbq); + } + else { + binfo->fc_flag &= ~FC_DELAY_NSLOGI; + } + } + if (binfo->fc_flag & FC_DELAY_RSCN) { + IOCBQ *temp; + IOCB *iocb; + MATCHMAP *mp; + RING *rp; + int i; + + rp = &binfo->fc_ring[FC_ELS_RING]; + binfo->fc_flag &= ~FC_DELAY_RSCN; + while (binfo->fc_rscn.q_first) { + temp = (IOCBQ * )binfo->fc_rscn.q_first; + if ((binfo->fc_rscn.q_first = temp->q) == 0) { + binfo->fc_rscn.q_last = 0; + } + binfo->fc_rscn.q_cnt--; + iocb = &temp->iocb; + mp = *((MATCHMAP **)iocb); + *((MATCHMAP **)iocb) = 0; + temp->q = NULL; + fc_process_rscn(p_dev_ctl, temp, mp); + + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + + i = 1; + /* free resources associated with this iocb and repost the ring buffers */ + if (!(binfo->fc_flag & FC_SLI2)) { + for (i = 1; i < (int)iocb->ulpBdeCount; i++) { + mp = fc_getvaddr(p_dev_ctl, rp, (uchar * )((ulong)iocb->un.cont[i].bdeAddress)); + if (mp) { + fc_mem_put(binfo, MEM_BUF, (uchar * )mp); + } + } + } + fc_mem_put(binfo, MEM_IOCB, (uchar * )temp); + } + } + } + return(0); +} /* End handle_mb_event */ + + +/**********************************************************/ +/** issue_mb_cmd Issue a mailbox command. **/ +/** If the mailbox is currently busy, **/ +/** queue command to mbox queue. **/ +/**********************************************************/ +_static_ int +issue_mb_cmd( +FC_BRD_INFO *binfo, +MAILBOX *mb, +int flag) +{ + MAILBOX * mbox; + MAILBOXQ * mbq; + int i; + void *ioa; + uint32 status, evtctr; + uint32 ha_copy; + fc_dev_ctl_t *p_dev_ctl; + volatile uint32 word0, ldata; + + mbq = (MAILBOXQ * )mb; + status = MBX_SUCCESS; + + if (binfo->fc_mbox_active) { + /* Another mailbox command is still being processed, queue this + * command to be processed later. + */ + fc_mbox_put(binfo, mbq); + + /* Mbox cmd issue - BUSY */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0308, /* ptr to msg structure */ + fc_mes0308, /* ptr to msg */ + fc_msgBlk0308.msgPreambleStr, /* begin varargs */ + mb->mbxCommand, + binfo->fc_ffstate, + binfo->fc_flag, + flag); /* end varargs */ + FCSTATCTR.mboxCmdBusy++; + + return(MBX_BUSY); + } + + binfo->fc_mbox_active = 1; + p_dev_ctl = (fc_dev_ctl_t *)(binfo->fc_p_dev_ctl); + + /* Mailbox cmd issue */ + fc_log_printf_msg_vargs( binfo->fc_brd_no, + &fc_msgBlk0309, /* ptr to msg structure */ + fc_mes0309, /* ptr to msg */ + fc_msgBlk0309.msgPreambleStr, /* begin varargs */ + mb->mbxCommand, + binfo->fc_ffstate, + binfo->fc_flag, + flag); /* end varargs */ + /* If we are not polling, turn on watchdog timer */ + if (flag != MBX_POLL) { + MBOXTMO = fc_clk_set(p_dev_ctl, MBOX_TMO_DFT, fc_mbox_timeout, 0, 0); + } + + FCSTATCTR.issueMboxCmd++; + evtctr = FCSTATCTR.mboxEvent; + + /* if there is one, save buffer to release in completion */ + if (mbq->bp) { + binfo->fc_mbbp = mbq->bp; + mbq->bp = 0; + } + + /* next set own bit for the adapter and copy over command word */ + mb->mbxOwner = OWN_CHIP; + + if (binfo->fc_flag & FC_SLI2) { + /* First copy command data */ + mbox = FC_SLI2_MAILBOX(binfo); + fc_pcimem_bcopy((uint32 * )mb, (uint32 * )mbox, + (sizeof(uint32) * (MAILBOX_CMD_WSIZE))); + fc_mpdata_sync(binfo->fc_slim2.dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV); + } else { + if (mb->mbxCommand == MBX_CONFIG_PORT) { + /* copy command data into host mbox for cmpl */ + fc_pcimem_bcopy((uint32 * )mb, + (uint32 * ) & ((SLI2_SLIM * )binfo->fc_slim2.virt)->mbx, + (sizeof(uint32) * (MAILBOX_CMD_WSIZE))); + } + + /* First copy command data */ + ioa = (void *)FC_MAP_MEM(&binfo->fc_iomap_mem); /* map in SLIM */ + + mbox = FC_MAILBOX(binfo, ioa); + WRITE_SLIM_COPY(binfo, &mb->un.varWords, &mbox->un.varWords, + (MAILBOX_CMD_WSIZE - 1)); + + + /* copy over last word, with mbxOwner set */ + ldata = *((volatile uint32 * )mb); + + WRITE_SLIM_ADDR(binfo, ((volatile uint32 * )mbox), ldata); + FC_UNMAP_MEMIO(ioa); + + if (mb->mbxCommand == MBX_CONFIG_PORT) { + /* switch over to host mailbox */ + binfo->fc_mboxaddr = (uint32 *)&((SLI2_SLIM * )binfo->fc_slim2.virt)->mbx; + binfo->fc_flag |= FC_SLI2; + } + } + + + /* interrupt board to doit right away */ + ioa = (void *)FC_MAP_IO(&binfo->fc_iomap_io); /* map in io registers */ + WRITE_CSR_REG(binfo, FC_FF_REG(binfo, ioa), CA_MBATT); + FC_UNMAP_MEMIO(ioa); + + switch (flag) { + case MBX_SLEEP: + case MBX_NOWAIT: + break; + + case MBX_POLL: + i = 0; + if (binfo->fc_flag & FC_SLI2) { + fc_mpdata_sync(binfo->fc_slim2.dma_handle, 0, 0, + DDI_DMA_SYNC_FORKERNEL); + + /* First copy command data */ + mbox = FC_SLI2_MAILBOX(binfo); + word0 = *((volatile uint32 * )mbox); + word0 = PCIMEM_LONG(word0); + } else { + /* First copy command data */ + ioa = (void *)FC_MAP_MEM(&binfo->fc_iomap_mem); /* map in SLIM */ + mbox = FC_MAILBOX(binfo, ioa); + word0 = READ_SLIM_ADDR(binfo, ((volatile uint32 * )mbox)); + FC_UNMAP_MEMIO(ioa); + } + + ioa = (void *)FC_MAP_IO(&binfo->fc_iomap_io); /* map in io registers */ + ha_copy = READ_CSR_REG(binfo, FC_HA_REG(binfo, ioa)); + FC_UNMAP_MEMIO(ioa); + + /* Wait for command to complete */ + while (((word0 & OWN_CHIP) == OWN_CHIP) || !(ha_copy & HA_MBATT)) { + if (i++ >= 100) { + binfo->fc_mbox_active = 0; + return(MBX_NOT_FINISHED); + } + + /* Check if we took a mbox interrupt while we were polling */ + if(((word0 & OWN_CHIP) != OWN_CHIP) && (evtctr != FCSTATCTR.mboxEvent)) + break; + + DELAYMS(i); + + if (binfo->fc_flag & FC_SLI2) { + fc_mpdata_sync(binfo->fc_slim2.dma_handle, 0, 0, + DDI_DMA_SYNC_FORKERNEL); + + /* First copy command data */ + mbox = FC_SLI2_MAILBOX(binfo); + word0 = *((volatile uint32 * )mbox); + word0 = PCIMEM_LONG(word0); + } else { + /* First copy command data */ + ioa = (void *)FC_MAP_MEM(&binfo->fc_iomap_mem); /* map in SLIM */ + mbox = FC_MAILBOX(binfo, ioa); + word0 = READ_SLIM_ADDR(binfo, ((volatile uint32 * )mbox)); + FC_UNMAP_MEMIO(ioa); + } + ioa = (void *)FC_MAP_IO(&binfo->fc_iomap_io); /* map in io registers */ + ha_copy = READ_CSR_REG(binfo, FC_HA_REG(binfo, ioa)); + FC_UNMAP_MEMIO(ioa); + } + + if (binfo->fc_flag & FC_SLI2) { + fc_mpdata_sync(binfo->fc_slim2.dma_handle, 0, 0, + DDI_DMA_SYNC_FORKERNEL); + + /* First copy command data */ + mbox = FC_SLI2_MAILBOX(binfo); + /* copy results back to user */ + fc_pcimem_bcopy((uint32 * )mbox, (uint32 * )mb, + (sizeof(uint32) * MAILBOX_CMD_WSIZE)); + } else { + /* First copy command data */ + ioa = (void *)FC_MAP_MEM(&binfo->fc_iomap_mem); /* map in SLIM */ + mbox = FC_MAILBOX(binfo, ioa); + /* copy results back to user */ + READ_SLIM_COPY(binfo, (uint32 * )mb, (uint32 * )mbox, MAILBOX_CMD_WSIZE); + FC_UNMAP_MEMIO(ioa); + } + + ioa = (void *)FC_MAP_IO(&binfo->fc_iomap_io); /* map in io registers */ + WRITE_CSR_REG(binfo, FC_HA_REG(binfo, ioa), HA_MBATT); + FC_UNMAP_MEMIO(ioa); + + binfo->fc_mbox_active = 0; + status = mb->mbxStatus; + break; + } + return(status); +} /* End issue_mb_cmd */ + + +/* + * This routine will issue as many iocb commands from the + * ring's xmit queue to the adapter as it can. + * If iocb_cmd is specified it will be queued to the xmit queue. + */ +_static_ uint32 +issue_iocb_cmd( +FC_BRD_INFO *binfo, +RING *rp, +IOCBQ *iocb_cmd) +{ + IOCB * iocb; + IOCB * icmd; + void * ioa; + uint32 status; + uint32 * xx; + int onetime; + uint32 portCmdGet, rc; + fc_dev_ctl_t *p_dev_ctl; + + rc = PCIMEM_LONG(((SLI2_SLIM * )binfo->fc_slim2.virt)->mbx.us.s2.port[rp->fc_ringno].cmdGetInx); + onetime = 0; + if ((binfo->fc_flag & FC_LNK_DOWN) || + (binfo->fc_ffstate < rp->fc_xmitstate)) { + if (iocb_cmd) { + icmd = &iocb_cmd->iocb; + if ((icmd->ulpCommand != CMD_QUE_RING_BUF_CN) && + (icmd->ulpCommand != CMD_QUE_RING_BUF64_CN) && + (icmd->ulpCommand != CMD_CREATE_XRI_CR)) { + fc_ringtx_put(rp, iocb_cmd); + + FCSTATCTR.NoIssueIocb++; + /* If link is down, just return */ + return(rc); + } + onetime = 1; + } else { + /* If link is down, just return */ + return(rc); + } + } else { + if (iocb_cmd) { + /* Queue command to ring xmit queue */ + fc_ringtx_put(rp, iocb_cmd); + } + if((binfo->fc_process_LA == 0) && + (rp->fc_ringno == FC_FCP_RING)) { + return(rc); + } + } + + p_dev_ctl = (fc_dev_ctl_t *)(binfo->fc_p_dev_ctl); + fc_mpdata_sync(binfo->fc_slim2.dma_handle, 0, 0, DDI_DMA_SYNC_FORKERNEL); + + /* onetime should only be set for QUE_RING_BUF or CREATE_XRI + * iocbs sent with link down. + */ + + /* get the next available command iocb */ + iocb = (IOCB * )IOCB_ENTRY(rp->fc_cmdringaddr, rp->fc_cmdidx); + + portCmdGet = rc; + + if (portCmdGet >= rp->fc_numCiocb) { + if (iocb_cmd) { + /* Queue command to ring xmit queue */ + fc_ringtx_put(rp, iocb_cmd); + } + return(rc); + } + + /* bump iocb available command index */ + if (++rp->fc_cmdidx >= rp->fc_numCiocb) { + rp->fc_cmdidx = 0; + } + + /* While IOCB entries are available */ + while (rp->fc_cmdidx != portCmdGet) { + /* get next command from ring xmit queue */ + if ((onetime == 0) && ((iocb_cmd = fc_ringtx_get(rp)) == NULL)) { +out: + fc_mpdata_sync(binfo->fc_slim2.dma_handle, 0, 0, + DDI_DMA_SYNC_FORKERNEL); + fc_mpdata_sync(binfo->fc_slim2.dma_handle, 0, 0, + DDI_DMA_SYNC_FORDEV); + + /* SLIM POINTER */ + if (binfo->fc_busflag & FC_HOSTPTR) { + rp->fc_cmdidx = + (uchar)PCIMEM_LONG(((SLI2_SLIM * )binfo->fc_slim2.virt)->mbx.us.s2.host[rp->fc_ringno].cmdPutInx); + } else { + void *ioa2; + + ioa = (void *)FC_MAP_MEM(&binfo->fc_iomap_mem); /* map in SLIM */ + ioa2 = (void *)((char *)ioa +((SLIMOFF+(rp->fc_ringno*2))*4)); + rp->fc_cmdidx = (uchar)READ_SLIM_ADDR(binfo, (volatile uint32 *)ioa2); + FC_UNMAP_MEMIO(ioa); + } + + ioa = (void *)FC_MAP_IO(&binfo->fc_iomap_io); /* map in io registers */ + status = ((CA_R0ATT) << (rp->fc_ringno * 4)); + WRITE_CSR_REG(binfo, FC_FF_REG(binfo, ioa), (volatile uint32)status); + FC_UNMAP_MEMIO(ioa); + return(rc); + } + icmd = &iocb_cmd->iocb; + + xx = (uint32 * ) icmd; + /* issue iocb command to adapter */ + fc_pcimem_bcopy((uint32 * )icmd, (uint32 * )iocb, sizeof(IOCB)); + FCSTATCTR.IssueIocb++; + + if ((icmd->ulpCommand == CMD_QUE_RING_BUF_CN) || + (icmd->ulpCommand == CMD_QUE_RING_BUF64_CN) || + (rp->fc_ringno == FC_FCP_RING) || + (icmd->ulpCommand == CMD_ABORT_XRI_CX) || + (icmd->ulpCommand == CMD_ABORT_XRI_CN)) { + fc_mem_put(binfo, MEM_IOCB, (uchar * )iocb_cmd); + } else { + fc_ringtxp_put(rp, iocb_cmd); + } + + /* SLIM POINTER */ + if (binfo->fc_busflag & FC_HOSTPTR) { + ((SLI2_SLIM * )binfo->fc_slim2.virt)->mbx.us.s2.host[rp->fc_ringno].cmdPutInx = PCIMEM_LONG(rp->fc_cmdidx); + } else { + void *ioa2; + + ioa = (void *)FC_MAP_MEM(&binfo->fc_iomap_mem); /* map in SLIM */ + ioa2 = (void *)((char *)ioa +((SLIMOFF+(rp->fc_ringno*2))*4)); + WRITE_SLIM_ADDR(binfo, (volatile uint32 *)ioa2, rp->fc_cmdidx); + FC_UNMAP_MEMIO(ioa); + } + + if (onetime) { + goto out; + } + + /* get the next available command iocb */ + iocb = (IOCB * )IOCB_ENTRY(rp->fc_cmdringaddr, rp->fc_cmdidx); + + /* bump iocb available command index */ + if (++rp->fc_cmdidx >= rp->fc_numCiocb) { + rp->fc_cmdidx = 0; + } + } + + fc_mpdata_sync(binfo->fc_slim2.dma_handle, 0, 0, + DDI_DMA_SYNC_FORKERNEL); + fc_mpdata_sync(binfo->fc_slim2.dma_handle, 0, 0, + DDI_DMA_SYNC_FORDEV); + + /* SLIM POINTER */ + if (binfo->fc_busflag & FC_HOSTPTR) { + rp->fc_cmdidx = + (uchar)PCIMEM_LONG(((SLI2_SLIM * )binfo->fc_slim2.virt)->mbx.us.s2.host[rp->fc_ringno].cmdPutInx); + } else { + void *ioa2; + + ioa = (void *)FC_MAP_MEM(&binfo->fc_iomap_mem); /* map in SLIM */ + ioa2 = (void *)((char *)ioa +((SLIMOFF+(rp->fc_ringno*2))*4)); + rp->fc_cmdidx = (uchar)READ_SLIM_ADDR(binfo, (volatile uint32 *)ioa2); + FC_UNMAP_MEMIO(ioa); + } + + + /* If we get here, iocb list is full */ + /* + * Set ring 'x' to SET R0CE_REQ in Chip Att register. + * Chip will tell us when an entry is freed. + */ + ioa = (void *)FC_MAP_IO(&binfo->fc_iomap_io); /* map in io registers */ + status = ((CA_R0ATT | CA_R0CE_REQ) << (rp->fc_ringno * 4)); + WRITE_CSR_REG(binfo, FC_FF_REG(binfo, ioa), (volatile uint32)status); + FC_UNMAP_MEMIO(ioa); + + FCSTATCTR.iocbRingBusy++; + + if (onetime) { + /* Queue command to ring xmit queue */ + fc_ringtx_put(rp, iocb_cmd); + } + return(rc); +} /* End issue_iocb_cmd */ + + + + +/*****************************************************************************/ +/* + * NAME: fc_brdreset + * + * FUNCTION: hardware reset of adapter is performed + * + * EXECUTION ENVIRONMENT: process only + * + * NOTES: + * + * CALLED FROM: + * fc_cfg_init + * + * INPUT: + * p_dev_ctl - point to the dev_ctl area + * + */ +/*****************************************************************************/ +_static_ void +fc_brdreset ( +fc_dev_ctl_t *p_dev_ctl) /* point to the dev_ctl area */ +{ + uint32 word0; + ushort cfg_value, skip_post; + void *ioa; + FC_BRD_INFO * binfo; + MAILBOX * swpmb; + MAILBOX * mb; + + binfo = &BINFO; + ioa = (void *)FC_MAP_MEM(&binfo->fc_iomap_mem); /* map in SLIM */ + + + /* use REAL SLIM !!! */ + binfo->fc_mboxaddr = 0; + binfo->fc_flag &= ~FC_SLI2; + + /* Reset the board - First put restart command in mailbox */ + mb = FC_MAILBOX(binfo, ioa); + word0 = 0; + swpmb = (MAILBOX * ) & word0; + swpmb->mbxCommand = MBX_RESTART; + swpmb->mbxHc = 1; + WRITE_SLIM_ADDR(binfo, ((volatile uint32 * )mb), word0); + /* Only skip post after fc_ffinit is completed */ + if (binfo->fc_ffstate) { + skip_post = 1; + WRITE_SLIM_ADDR(binfo, (((volatile uint32 * )mb) + 1), 1); /* Skip post */ + } + else { + skip_post = 0; + } + FC_UNMAP_MEMIO(ioa); + + /* Turn off SERR, PERR in PCI cmd register */ + binfo->fc_ffstate = FC_INIT_START; + + cfg_value = fc_rdpci_cmd(p_dev_ctl); + fc_wrpci_cmd(p_dev_ctl, (ushort)(cfg_value & ~(CMD_PARITY_CHK | CMD_SERR_ENBL))); + + ioa = (void *)FC_MAP_IO(&binfo->fc_iomap_io); /* map in io registers */ + + WRITE_CSR_REG(binfo, FC_HC_REG(binfo, ioa), (volatile uint32)HC_INITFF); + DELAYMS(1); + + WRITE_CSR_REG(binfo, FC_HC_REG(binfo, ioa), (volatile uint32)0); + + FC_UNMAP_MEMIO(ioa); + + /* Restore PCI cmd register */ + fc_wrpci_cmd(p_dev_ctl, cfg_value); + + if(skip_post) { + DELAYMS(100); + } + else { + DELAYMS(2000); + } + + binfo->fc_ffstate = FC_INIT_START; + binfo->fc_eventTag = 0; + binfo->fc_myDID = 0; + binfo->fc_prevDID = 0; + p_dev_ctl->power_up = 0; + return; +} diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/lpfc.conf.c 830-ivtv/drivers/scsi/lpfc/lpfc.conf.c --- 000-virgin/drivers/scsi/lpfc/lpfc.conf.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/lpfc.conf.c Thu Jan 8 10:21:53 2004 @@ -0,0 +1,336 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Enterprise Fibre Channel Host Bus Adapters. * + * Refer to the README file included with this package for * + * driver version and adapter support. * + * Copyright (C) 2003 Emulex Corporation. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details, a copy of which * + * can be found in the file COPYING included with this package. * + *******************************************************************/ + +#include +#include "fc_os.h" +#include "fc_hw.h" +#include "fc.h" +#include "fcmsg.h" + +/* +# Verbosity: only turn this flag on if you are willing to risk being +# deluged with LOTS of information. +# You can set a bit mask to record specific types of verbose messages: +# +# LOG_ELS 0x1 ELS events +# LOG_DISCOVERY 0x2 Link discovery events +# LOG_MBOX 0x4 Mailbox events +# LOG_INIT 0x8 Initialization events +# LOG_LINK_EVENT 0x10 Link events +# LOG_IP 0x20 IP traffic history +# LOG_FCP 0x40 FCP traffic history +# LOG_NODE 0x80 Node table events +# LOG_MISC 0x400 Miscellaneous events +# LOG_SLI 0x800 SLI events +# LOG_CHK_COND 0x1000 FCP Check condition flag +# LOG_ALL_MSG 0x1fff LOG all messages +*/ +int lpfc_log_verbose =0; + +/* +# Setting log-only to 0 causes log messages to be printed on the +# console and to be logged to syslog (which may send them to the +# console again if it's configured to do so). +# Setting log-only to 1 causes log messages to go to syslog only. +*/ +int lpfc_log_only =0; + +/* +# lun-queue-depth: the default value lpfc will use to limit +# the number of outstanding commands per FCP LUN. This value is +# global, affecting each LUN recognized by the driver. +*/ +int lpfc_lun_queue_depth =30; + +/* +# lpfc_lun_skip : Is a LINUX OS parameter to support LUN skipping / no LUN +# If this is set to 1, lpfc will fake out the LINUX scsi layer to allow +# it to detect all LUNs if there are LUN holes on a device. +*/ +int lpfc_lun_skip=0; + +/* +# tgt-queue-depth: the default value lpfc will use to limit +# the number of outstanding commands per FCP target. This value is +# global, affecting each target recognized by the driver. +*/ +int lpfc_tgt_queue_depth =0; + +/* +# no-device-delay [0 or 1 to 30] - determines the length of +# the interval between deciding to fail back an I/O because there is no way +# to communicate with its particular device (e.g., due to device failure) and +# the actual fail back. A value of zero implies no delay whatsoever. +# Cautions: (1) This value is in seconds. +# (2) Setting a long delay value may permit I/O to build up, +# each with a pending timeout, which could result in the exhaustion of +# critical LINUX kernel resources. +# +# Note that this value can have an impact on the speed with which a +# system can shut down with I/Os pending and with the HBA not able to +# communicate with the loop or fabric, e.g., with a cable pulled. +*/ +int lpfc_no_device_delay =1; + +/* +# +++ Variables relating to IP networking support. +++ +*/ + +/* +# network-on: true (1) if networking is enabled, false (0) if not +*/ +int lpfc_network_on = 0; + +/* +# xmt-que-size: size of the transmit queue for mbufs (128 - 10240) +*/ +int lpfc_xmt_que_size = 256; + +/* +# +++ Variables common to both SCSI (FCP) and IP networking support. +++ +*/ + +/* +# Some disk devices have a "select ID" or "select Target" capability. +# From a protocol standpoint "select ID" usually means select the +# Fibre channel "ALPA". In the FC-AL Profile there is an "informative +# annex" which contains a table that maps a "select ID" (a number +# between 0 and 7F) to an ALPA. By default, for compatibility with +# older drivers, the lpfc driver scans its ALPA map from low ALPA +# to high ALPA. +# +# Turning on the scan-down variable (on = 1, off = 0) will +# cause the lpfc driver to use an inverted ALPA map, effectively +# scanning ALPAs from high to low as specified in the FC-AL annex. +# A value of 2, will also cause target assignment in a private loop +# environment to be based on the ALPA. Persistent bindings should NOT be +# used if scan-down is 2. +# +# (Note: This "select ID" functionality is a LOOP ONLY characteristic +# and will not work across a fabric.) +*/ +int lpfc_scandown =2; + +/* +# Determine how long the driver will wait to begin linkdown processing +# when a cable has been pulled or the link has otherwise become +# inaccessible, 1 - 255 secs. Linkdown processing includes failing back +# cmds to the target driver that have been waiting around for the link +# to come back up. There's a tradeoff here: small values of the timer +# cause the link to appear to "bounce", while large values of the +# timer can delay failover in a fault tolerant environment. Units are in +# seconds. A value of 0 means never failback cmds until the link comes up. +*/ +int lpfc_linkdown_tmo =30; + +/* +# If set, nodev-holdio will hold all I/O errors on devices that disappear +# until they come back. Default is 0, return errors with no-device-delay +*/ +int lpfc_nodev_holdio =0; + +/* +# If set, nodev-tmo will hold all I/O errors on devices that disappear +# until the timer expires. Default is 0, return errors with no-device-delay. +*/ +int lpfc_nodev_tmo =30; + +/* +# Use no-device-delay to delay FCP RSP errors and certain check conditions +*/ +int lpfc_delay_rsp_err =1; + +/* +# Treat certain check conditions as a FCP error +*/ +int lpfc_check_cond_err =1; + +/* +# num-iocbs: number of iocb buffers to allocate (128 to 10240) +*/ +int lpfc_num_iocbs = 2048; + +/* +# num-bufs: number of ELS buffers to allocate (64 to 4096) +# ELS buffers are needed to support Fibre channel Extended Link Services. +# Also used for SLI-2 FCP buffers, one per FCP command, and Mailbox commands. +*/ +int lpfc_num_bufs = 4096; + +/* +# topology: link topology for init link +# 0x0 = attempt loop mode then point-to-point +# 0x02 = attempt point-to-point mode only +# 0x04 = attempt loop mode only +# 0x06 = attempt point-to-point mode then loop +# Set point-to-point mode if you want to run as an N_Port. +# Set loop mode if you want to run as an NL_Port. +*/ +int lpfc_topology = 0; + +/* +# link-speed:link speed selection for initializing the Fibre Channel connection. +# 0 = auto select (default) +# 1 = 1 Gigabaud +# 2 = 2 Gigabaud +*/ +int lpfc_link_speed = 0; + +/* +# ip-class: FC class (2 or 3) to use for the IP protocol. +*/ +int lpfc_ip_class = 3; + +/* +# fcp-class: FC class (2 or 3) to use for the FCP protocol. +*/ +int lpfc_fcp_class = 3; + +/* +# Use ADISC for FCP rediscovery instead of PLOGI +*/ +int lpfc_use_adisc =0; + +/* +# Extra FCP timeout for fabrics +*/ +int lpfc_fcpfabric_tmo =0; + +/* +# Number of 4k STREAMS buffers to post to IP ring +*/ +int lpfc_post_ip_buf =128; + +/* +#Use dqfull-throttle-up-time to specify when to increment the current Q depth. +# This variable is in seconds. +*/ +int lpfc_dqfull_throttle_up_time =1; + +/* +# Increment the current Q depth by dqfull-throttle-up-inc +*/ +int lpfc_dqfull_throttle_up_inc =1; + +/* +# Use ACK0, instead of ACK1 for class 2 acknowledgement +*/ +int lpfc_ack0support =0; + +/* +# Vendor specific flag for vendor specifc actions. +*/ +int lpfc_vendor =0x1; + +/* +# Linux does not scan past lun 0 is it's missing. Emulex driver can +# work around this limitation if this feature is on (1). +*/ +int lpfc_lun0_missing =0; + +/* +# When a disk disapears, fiber cable being disconnected for example, +# this option will report it missing BUT removable. This allows +# Linux to re-discover the disk later on without scan, when the cable +# is re-connected in our example. +# Warning: when this option is set, statuses and timeout values on +# disk missing reported to the kernel may have an effect +# on other software packages like failover, multipath, etc... +*/ +int lpfc_use_removable =1; + +/* +# specified the maximum number of luns per target. A value of 20 means +# luns from 0 to 19 are valid. +# Default of 0 means to use driver's maximum of 256. + */ +int lpfc_max_lun =0; + +/* +# When the scsi layer passes the driver a command, the SCSI command structure +# has a field in it, sc_data_direction, to indicate if the SCSI command is a +# read or a write SCSI operation. Under some instances, this field is invalid +# and the SCSI opcode can be used to determine the type of SCSI operation. If +# wish to use the SCSI opcode, set this to 0. +# Note: For LINUX kernel revisions <= 2.4.4, this is ignored and the SCSI +# opcode is always used. +*/ +int lpfc_use_data_direction =1; + +/* +# Setup FCP persistent bindings, +# fcp-bind-WWPN binds a specific WorldWide PortName to a target id, +# fcp-bind-WWNN binds a specific WorldWide NodeName to a target id, +# fcp-bind-DID binds a specific DID to a target id. +# Only one binding method can be used. "lpfc_automap" needs to +# be changed to 0 and scan-down should NOT be set to 2 +# when one of these binding methods is used. +# WWNN, WWPN and DID are hexadecimal values. +# WWNN must be 16 digit BCD with leading 0s. +# WWPN must be 16 digit BCD with leading 0s. +# DID must be 6 digit BCD with leading 0s. +# The SCSI ID to bind to consists of two parts, the lpfc interface +# to bind to, and the target number for that interface. +# Thus lpfc0t2 specifies target 2 on interface lpfc0. +# +# Here are some examples: +# WWNN SCSI ID +# char *lpfc_fcp_bind_WWNN[]={"22000020370b8275:lpfc0t1", +# "22000020370b8998:lpfc0t2"}; +# +# WWPN SCSI ID +# char *lpfc_fcp_bind_WWPN[]={"22000020370b8275:lpfc0t1", +# "22000020370b8998:lpfc0t2"}; +# +# DID SCSI ID +# char *lpfc_fcp_bind_DID[]={"0000dc:lpfc0t1", +# "0000e0:lpfc0t2"}; +# +*/ +int lpfc_bind_entries =0; +char *lpfc_fcp_bind_WWNN[MAX_FC_BINDINGS]; +char *lpfc_fcp_bind_WWPN[MAX_FC_BINDINGS]; +char *lpfc_fcp_bind_DID[MAX_FC_BINDINGS]; + +/* +# If automap is set, SCSI IDs for all FCP nodes without +# persistent bindings will be automatically generated. +# If new FCP devices are added to the network when the system is down, +# there is no guarantee that these SCSI IDs will remain the same +# when the system is booted again. +# If one of the above fcp binding methods is specified, then automap +# devices will use the same mapping method to preserve +# SCSI IDs between link down and link up. +# If no bindings are specified above, a value of 1 will force WWNN +# binding, 2 for WWPN binding, and 3 for DID binding. +# If automap is 0, only devices with persistent bindings will be +# recognized by the system. +*/ +int lpfc_automap =2; + +/* +# Default values for I/O colaesing +# cr_delay ms or cr_count outstanding commands +*/ +int lpfc_cr_delay =0; +int lpfc_cr_count =0; + + + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/lpfc.conf.defs 830-ivtv/drivers/scsi/lpfc/lpfc.conf.defs --- 000-virgin/drivers/scsi/lpfc/lpfc.conf.defs Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/lpfc.conf.defs Thu Jan 8 10:21:53 2004 @@ -0,0 +1,3380 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Enterprise Fibre Channel Host Bus Adapters. * + * Refer to the README file included with this package for * + * driver version and adapter support. * + * Copyright (C) 2003 Emulex Corporation. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details, a copy of which * + * can be found in the file COPYING included with this package. * + *******************************************************************/ + +/* This file is to support different configurations for each HBA */ +/* HBA 0 */ +#ifdef MODULE_PARM +MODULE_PARM(lpfc0_log_verbose, "i"); +MODULE_PARM(lpfc0_log_only, "i"); +MODULE_PARM(lpfc0_lun_queue_depth, "i"); +MODULE_PARM(lpfc0_tgt_queue_depth, "i"); +MODULE_PARM(lpfc0_no_device_delay, "i"); +MODULE_PARM(lpfc0_network_on, "i"); +MODULE_PARM(lpfc0_xmt_que_size, "i"); +MODULE_PARM(lpfc0_scandown, "i"); +MODULE_PARM(lpfc0_linkdown_tmo, "i"); +MODULE_PARM(lpfc0_nodev_tmo, "i"); +MODULE_PARM(lpfc0_delay_rsp_err, "i"); +MODULE_PARM(lpfc0_nodev_holdio, "i"); +MODULE_PARM(lpfc0_check_cond_err, "i"); +MODULE_PARM(lpfc0_num_iocbs, "i"); +MODULE_PARM(lpfc0_num_bufs, "i"); +MODULE_PARM(lpfc0_topology, "i"); +MODULE_PARM(lpfc0_link_speed, "i"); +MODULE_PARM(lpfc0_ip_class, "i"); +MODULE_PARM(lpfc0_fcp_class, "i"); +MODULE_PARM(lpfc0_use_adisc, "i"); +MODULE_PARM(lpfc0_fcpfabric_tmo, "i"); +MODULE_PARM(lpfc0_post_ip_buf, "i"); +MODULE_PARM(lpfc0_dqfull_throttle_up_time, "i"); +MODULE_PARM(lpfc0_dqfull_throttle_up_inc, "i"); +MODULE_PARM(lpfc0_ack0support, "i"); +MODULE_PARM(lpfc0_automap, "i"); +MODULE_PARM(lpfc0_cr_delay, "i"); +MODULE_PARM(lpfc0_cr_count, "i"); +#endif + +static int lpfc0_log_verbose = -1; +static int lpfc0_log_only = -1; +static int lpfc0_lun_queue_depth = -1; +static int lpfc0_tgt_queue_depth = -1; +static int lpfc0_no_device_delay = -1; +static int lpfc0_network_on = -1; +static int lpfc0_xmt_que_size = -1; +static int lpfc0_scandown = -1; +static int lpfc0_linkdown_tmo = -1; +static int lpfc0_nodev_tmo = -1; +static int lpfc0_delay_rsp_err = -1; +static int lpfc0_nodev_holdio = -1; +static int lpfc0_check_cond_err = -1; +static int lpfc0_num_iocbs = -1; +static int lpfc0_num_bufs = -1; +static int lpfc0_topology = -1; +static int lpfc0_link_speed = -1; +static int lpfc0_ip_class = -1; +static int lpfc0_fcp_class = -1; +static int lpfc0_use_adisc = -1; +static int lpfc0_fcpfabric_tmo = -1; +static int lpfc0_post_ip_buf = -1; +static int lpfc0_dqfull_throttle_up_time = -1; +static int lpfc0_dqfull_throttle_up_inc = -1; +static int lpfc0_ack0support = -1; +static int lpfc0_automap = -1; +static int lpfc0_cr_delay = -1; +static int lpfc0_cr_count = -1; + +/* HBA 1 */ +#ifdef MODULE_PARM +MODULE_PARM(lpfc1_log_verbose, "i"); +MODULE_PARM(lpfc1_log_only, "i"); +MODULE_PARM(lpfc1_lun_queue_depth, "i"); +MODULE_PARM(lpfc1_tgt_queue_depth, "i"); +MODULE_PARM(lpfc1_no_device_delay, "i"); +MODULE_PARM(lpfc1_network_on, "i"); +MODULE_PARM(lpfc1_xmt_que_size, "i"); +MODULE_PARM(lpfc1_scandown, "i"); +MODULE_PARM(lpfc1_linkdown_tmo, "i"); +MODULE_PARM(lpfc1_nodev_tmo, "i"); +MODULE_PARM(lpfc1_delay_rsp_err, "i"); +MODULE_PARM(lpfc1_nodev_holdio, "i"); +MODULE_PARM(lpfc1_check_cond_err, "i"); +MODULE_PARM(lpfc1_num_iocbs, "i"); +MODULE_PARM(lpfc1_num_bufs, "i"); +MODULE_PARM(lpfc1_topology, "i"); +MODULE_PARM(lpfc1_link_speed, "i"); +MODULE_PARM(lpfc1_ip_class, "i"); +MODULE_PARM(lpfc1_fcp_class, "i"); +MODULE_PARM(lpfc1_use_adisc, "i"); +MODULE_PARM(lpfc1_fcpfabric_tmo, "i"); +MODULE_PARM(lpfc1_post_ip_buf, "i"); +MODULE_PARM(lpfc1_dqfull_throttle_up_time, "i"); +MODULE_PARM(lpfc1_dqfull_throttle_up_inc, "i"); +MODULE_PARM(lpfc1_ack0support, "i"); +MODULE_PARM(lpfc1_automap, "i"); +MODULE_PARM(lpfc1_cr_delay, "i"); +MODULE_PARM(lpfc1_cr_count, "i"); +#endif + +static int lpfc1_log_verbose = -1; +static int lpfc1_log_only = -1; +static int lpfc1_lun_queue_depth = -1; +static int lpfc1_tgt_queue_depth = -1; +static int lpfc1_no_device_delay = -1; +static int lpfc1_network_on = -1; +static int lpfc1_xmt_que_size = -1; +static int lpfc1_scandown = -1; +static int lpfc1_linkdown_tmo = -1; +static int lpfc1_nodev_tmo = -1; +static int lpfc1_delay_rsp_err = -1; +static int lpfc1_nodev_holdio = -1; +static int lpfc1_check_cond_err = -1; +static int lpfc1_num_iocbs = -1; +static int lpfc1_num_bufs = -1; +static int lpfc1_topology = -1; +static int lpfc1_link_speed = -1; +static int lpfc1_ip_class = -1; +static int lpfc1_fcp_class = -1; +static int lpfc1_use_adisc = -1; +static int lpfc1_fcpfabric_tmo = -1; +static int lpfc1_post_ip_buf = -1; +static int lpfc1_dqfull_throttle_up_time = -1; +static int lpfc1_dqfull_throttle_up_inc = -1; +static int lpfc1_ack0support = -1; +static int lpfc1_automap = -1; +static int lpfc1_cr_delay = -1; +static int lpfc1_cr_count = -1; + +/* HBA 2 */ +#ifdef MODULE_PARM +MODULE_PARM(lpfc2_log_verbose, "i"); +MODULE_PARM(lpfc2_log_only, "i"); +MODULE_PARM(lpfc2_lun_queue_depth, "i"); +MODULE_PARM(lpfc2_tgt_queue_depth, "i"); +MODULE_PARM(lpfc2_no_device_delay, "i"); +MODULE_PARM(lpfc2_network_on, "i"); +MODULE_PARM(lpfc2_xmt_que_size, "i"); +MODULE_PARM(lpfc2_scandown, "i"); +MODULE_PARM(lpfc2_linkdown_tmo, "i"); +MODULE_PARM(lpfc2_nodev_tmo, "i"); +MODULE_PARM(lpfc2_delay_rsp_err, "i"); +MODULE_PARM(lpfc2_nodev_holdio, "i"); +MODULE_PARM(lpfc2_check_cond_err, "i"); +MODULE_PARM(lpfc2_num_iocbs, "i"); +MODULE_PARM(lpfc2_num_bufs, "i"); +MODULE_PARM(lpfc2_topology, "i"); +MODULE_PARM(lpfc2_link_speed, "i"); +MODULE_PARM(lpfc2_ip_class, "i"); +MODULE_PARM(lpfc2_fcp_class, "i"); +MODULE_PARM(lpfc2_use_adisc, "i"); +MODULE_PARM(lpfc2_fcpfabric_tmo, "i"); +MODULE_PARM(lpfc2_post_ip_buf, "i"); +MODULE_PARM(lpfc2_dqfull_throttle_up_time, "i"); +MODULE_PARM(lpfc2_dqfull_throttle_up_inc, "i"); +MODULE_PARM(lpfc2_ack0support, "i"); +MODULE_PARM(lpfc2_automap, "i"); +MODULE_PARM(lpfc2_cr_delay, "i"); +MODULE_PARM(lpfc2_cr_count, "i"); +#endif + +static int lpfc2_log_verbose = -1; +static int lpfc2_log_only = -1; +static int lpfc2_lun_queue_depth = -1; +static int lpfc2_tgt_queue_depth = -1; +static int lpfc2_no_device_delay = -1; +static int lpfc2_network_on = -1; +static int lpfc2_xmt_que_size = -1; +static int lpfc2_scandown = -1; +static int lpfc2_linkdown_tmo = -1; +static int lpfc2_nodev_tmo = -1; +static int lpfc2_delay_rsp_err = -1; +static int lpfc2_nodev_holdio = -1; +static int lpfc2_check_cond_err = -1; +static int lpfc2_num_iocbs = -1; +static int lpfc2_num_bufs = -1; +static int lpfc2_topology = -1; +static int lpfc2_link_speed = -1; +static int lpfc2_ip_class = -1; +static int lpfc2_fcp_class = -1; +static int lpfc2_use_adisc = -1; +static int lpfc2_fcpfabric_tmo = -1; +static int lpfc2_post_ip_buf = -1; +static int lpfc2_dqfull_throttle_up_time = -1; +static int lpfc2_dqfull_throttle_up_inc = -1; +static int lpfc2_ack0support = -1; +static int lpfc2_automap = -1; +static int lpfc2_cr_delay = -1; +static int lpfc2_cr_count = -1; + +/* HBA 3 */ +#ifdef MODULE_PARM +MODULE_PARM(lpfc3_log_verbose, "i"); +MODULE_PARM(lpfc3_log_only, "i"); +MODULE_PARM(lpfc3_lun_queue_depth, "i"); +MODULE_PARM(lpfc3_tgt_queue_depth, "i"); +MODULE_PARM(lpfc3_no_device_delay, "i"); +MODULE_PARM(lpfc3_network_on, "i"); +MODULE_PARM(lpfc3_xmt_que_size, "i"); +MODULE_PARM(lpfc3_scandown, "i"); +MODULE_PARM(lpfc3_linkdown_tmo, "i"); +MODULE_PARM(lpfc3_nodev_tmo, "i"); +MODULE_PARM(lpfc3_delay_rsp_err, "i"); +MODULE_PARM(lpfc3_nodev_holdio, "i"); +MODULE_PARM(lpfc3_check_cond_err, "i"); +MODULE_PARM(lpfc3_num_iocbs, "i"); +MODULE_PARM(lpfc3_num_bufs, "i"); +MODULE_PARM(lpfc3_topology, "i"); +MODULE_PARM(lpfc3_link_speed, "i"); +MODULE_PARM(lpfc3_ip_class, "i"); +MODULE_PARM(lpfc3_fcp_class, "i"); +MODULE_PARM(lpfc3_use_adisc, "i"); +MODULE_PARM(lpfc3_fcpfabric_tmo, "i"); +MODULE_PARM(lpfc3_post_ip_buf, "i"); +MODULE_PARM(lpfc3_dqfull_throttle_up_time, "i"); +MODULE_PARM(lpfc3_dqfull_throttle_up_inc, "i"); +MODULE_PARM(lpfc3_ack0support, "i"); +MODULE_PARM(lpfc3_automap, "i"); +MODULE_PARM(lpfc3_cr_delay, "i"); +MODULE_PARM(lpfc3_cr_count, "i"); +#endif + +static int lpfc3_log_verbose = -1; +static int lpfc3_log_only = -1; +static int lpfc3_lun_queue_depth = -1; +static int lpfc3_tgt_queue_depth = -1; +static int lpfc3_no_device_delay = -1; +static int lpfc3_network_on = -1; +static int lpfc3_xmt_que_size = -1; +static int lpfc3_scandown = -1; +static int lpfc3_linkdown_tmo = -1; +static int lpfc3_nodev_tmo = -1; +static int lpfc3_delay_rsp_err = -1; +static int lpfc3_nodev_holdio = -1; +static int lpfc3_check_cond_err = -1; +static int lpfc3_num_iocbs = -1; +static int lpfc3_num_bufs = -1; +static int lpfc3_topology = -1; +static int lpfc3_link_speed = -1; +static int lpfc3_ip_class = -1; +static int lpfc3_fcp_class = -1; +static int lpfc3_use_adisc = -1; +static int lpfc3_fcpfabric_tmo = -1; +static int lpfc3_post_ip_buf = -1; +static int lpfc3_dqfull_throttle_up_time = -1; +static int lpfc3_dqfull_throttle_up_inc = -1; +static int lpfc3_ack0support = -1; +static int lpfc3_automap = -1; +static int lpfc3_cr_delay = -1; +static int lpfc3_cr_count = -1; + +/* HBA 4 */ +#ifdef MODULE_PARM +MODULE_PARM(lpfc4_log_verbose, "i"); +MODULE_PARM(lpfc4_log_only, "i"); +MODULE_PARM(lpfc4_lun_queue_depth, "i"); +MODULE_PARM(lpfc4_tgt_queue_depth, "i"); +MODULE_PARM(lpfc4_no_device_delay, "i"); +MODULE_PARM(lpfc4_network_on, "i"); +MODULE_PARM(lpfc4_xmt_que_size, "i"); +MODULE_PARM(lpfc4_scandown, "i"); +MODULE_PARM(lpfc4_linkdown_tmo, "i"); +MODULE_PARM(lpfc4_nodev_tmo, "i"); +MODULE_PARM(lpfc4_delay_rsp_err, "i"); +MODULE_PARM(lpfc4_nodev_holdio, "i"); +MODULE_PARM(lpfc4_check_cond_err, "i"); +MODULE_PARM(lpfc4_num_iocbs, "i"); +MODULE_PARM(lpfc4_num_bufs, "i"); +MODULE_PARM(lpfc4_topology, "i"); +MODULE_PARM(lpfc4_link_speed, "i"); +MODULE_PARM(lpfc4_ip_class, "i"); +MODULE_PARM(lpfc4_fcp_class, "i"); +MODULE_PARM(lpfc4_use_adisc, "i"); +MODULE_PARM(lpfc4_fcpfabric_tmo, "i"); +MODULE_PARM(lpfc4_post_ip_buf, "i"); +MODULE_PARM(lpfc4_dqfull_throttle_up_time, "i"); +MODULE_PARM(lpfc4_dqfull_throttle_up_inc, "i"); +MODULE_PARM(lpfc4_ack0support, "i"); +MODULE_PARM(lpfc4_automap, "i"); +MODULE_PARM(lpfc4_cr_delay, "i"); +MODULE_PARM(lpfc4_cr_count, "i"); +#endif + +static int lpfc4_log_verbose = -1; +static int lpfc4_log_only = -1; +static int lpfc4_lun_queue_depth = -1; +static int lpfc4_tgt_queue_depth = -1; +static int lpfc4_no_device_delay = -1; +static int lpfc4_network_on = -1; +static int lpfc4_xmt_que_size = -1; +static int lpfc4_scandown = -1; +static int lpfc4_linkdown_tmo = -1; +static int lpfc4_nodev_tmo = -1; +static int lpfc4_delay_rsp_err = -1; +static int lpfc4_nodev_holdio = -1; +static int lpfc4_check_cond_err = -1; +static int lpfc4_num_iocbs = -1; +static int lpfc4_num_bufs = -1; +static int lpfc4_topology = -1; +static int lpfc4_link_speed = -1; +static int lpfc4_ip_class = -1; +static int lpfc4_fcp_class = -1; +static int lpfc4_use_adisc = -1; +static int lpfc4_fcpfabric_tmo = -1; +static int lpfc4_post_ip_buf = -1; +static int lpfc4_dqfull_throttle_up_time = -1; +static int lpfc4_dqfull_throttle_up_inc = -1; +static int lpfc4_ack0support = -1; +static int lpfc4_automap = -1; +static int lpfc4_cr_delay = -1; +static int lpfc4_cr_count = -1; + +/* HBA 5 */ +#ifdef MODULE_PARM +MODULE_PARM(lpfc5_log_verbose, "i"); +MODULE_PARM(lpfc5_log_only, "i"); +MODULE_PARM(lpfc5_lun_queue_depth, "i"); +MODULE_PARM(lpfc5_tgt_queue_depth, "i"); +MODULE_PARM(lpfc5_no_device_delay, "i"); +MODULE_PARM(lpfc5_network_on, "i"); +MODULE_PARM(lpfc5_xmt_que_size, "i"); +MODULE_PARM(lpfc5_scandown, "i"); +MODULE_PARM(lpfc5_linkdown_tmo, "i"); +MODULE_PARM(lpfc5_nodev_tmo, "i"); +MODULE_PARM(lpfc5_delay_rsp_err, "i"); +MODULE_PARM(lpfc5_nodev_holdio, "i"); +MODULE_PARM(lpfc5_check_cond_err, "i"); +MODULE_PARM(lpfc5_num_iocbs, "i"); +MODULE_PARM(lpfc5_num_bufs, "i"); +MODULE_PARM(lpfc5_topology, "i"); +MODULE_PARM(lpfc5_link_speed, "i"); +MODULE_PARM(lpfc5_ip_class, "i"); +MODULE_PARM(lpfc5_fcp_class, "i"); +MODULE_PARM(lpfc5_use_adisc, "i"); +MODULE_PARM(lpfc5_fcpfabric_tmo, "i"); +MODULE_PARM(lpfc5_post_ip_buf, "i"); +MODULE_PARM(lpfc5_dqfull_throttle_up_time, "i"); +MODULE_PARM(lpfc5_dqfull_throttle_up_inc, "i"); +MODULE_PARM(lpfc5_ack0support, "i"); +MODULE_PARM(lpfc5_automap, "i"); +MODULE_PARM(lpfc5_cr_delay, "i"); +MODULE_PARM(lpfc5_cr_count, "i"); +#endif + +static int lpfc5_log_verbose = -1; +static int lpfc5_log_only = -1; +static int lpfc5_lun_queue_depth = -1; +static int lpfc5_tgt_queue_depth = -1; +static int lpfc5_no_device_delay = -1; +static int lpfc5_network_on = -1; +static int lpfc5_xmt_que_size = -1; +static int lpfc5_scandown = -1; +static int lpfc5_linkdown_tmo = -1; +static int lpfc5_nodev_tmo = -1; +static int lpfc5_delay_rsp_err = -1; +static int lpfc5_nodev_holdio = -1; +static int lpfc5_check_cond_err = -1; +static int lpfc5_num_iocbs = -1; +static int lpfc5_num_bufs = -1; +static int lpfc5_topology = -1; +static int lpfc5_link_speed = -1; +static int lpfc5_ip_class = -1; +static int lpfc5_fcp_class = -1; +static int lpfc5_use_adisc = -1; +static int lpfc5_fcpfabric_tmo = -1; +static int lpfc5_post_ip_buf = -1; +static int lpfc5_dqfull_throttle_up_time = -1; +static int lpfc5_dqfull_throttle_up_inc = -1; +static int lpfc5_ack0support = -1; +static int lpfc5_automap = -1; +static int lpfc5_cr_delay = -1; +static int lpfc5_cr_count = -1; + +/* HBA 6 */ +#ifdef MODULE_PARM +MODULE_PARM(lpfc6_log_verbose, "i"); +MODULE_PARM(lpfc6_log_only, "i"); +MODULE_PARM(lpfc6_lun_queue_depth, "i"); +MODULE_PARM(lpfc6_tgt_queue_depth, "i"); +MODULE_PARM(lpfc6_no_device_delay, "i"); +MODULE_PARM(lpfc6_network_on, "i"); +MODULE_PARM(lpfc6_xmt_que_size, "i"); +MODULE_PARM(lpfc6_scandown, "i"); +MODULE_PARM(lpfc6_linkdown_tmo, "i"); +MODULE_PARM(lpfc6_nodev_tmo, "i"); +MODULE_PARM(lpfc6_delay_rsp_err, "i"); +MODULE_PARM(lpfc6_nodev_holdio, "i"); +MODULE_PARM(lpfc6_check_cond_err, "i"); +MODULE_PARM(lpfc6_num_iocbs, "i"); +MODULE_PARM(lpfc6_num_bufs, "i"); +MODULE_PARM(lpfc6_topology, "i"); +MODULE_PARM(lpfc6_link_speed, "i"); +MODULE_PARM(lpfc6_ip_class, "i"); +MODULE_PARM(lpfc6_fcp_class, "i"); +MODULE_PARM(lpfc6_use_adisc, "i"); +MODULE_PARM(lpfc6_fcpfabric_tmo, "i"); +MODULE_PARM(lpfc6_post_ip_buf, "i"); +MODULE_PARM(lpfc6_dqfull_throttle_up_time, "i"); +MODULE_PARM(lpfc6_dqfull_throttle_up_inc, "i"); +MODULE_PARM(lpfc6_ack0support, "i"); +MODULE_PARM(lpfc6_automap, "i"); +MODULE_PARM(lpfc6_cr_delay, "i"); +MODULE_PARM(lpfc6_cr_count, "i"); +#endif + +static int lpfc6_log_verbose = -1; +static int lpfc6_log_only = -1; +static int lpfc6_lun_queue_depth = -1; +static int lpfc6_tgt_queue_depth = -1; +static int lpfc6_no_device_delay = -1; +static int lpfc6_network_on = -1; +static int lpfc6_xmt_que_size = -1; +static int lpfc6_scandown = -1; +static int lpfc6_linkdown_tmo = -1; +static int lpfc6_nodev_tmo = -1; +static int lpfc6_delay_rsp_err = -1; +static int lpfc6_nodev_holdio = -1; +static int lpfc6_check_cond_err = -1; +static int lpfc6_num_iocbs = -1; +static int lpfc6_num_bufs = -1; +static int lpfc6_topology = -1; +static int lpfc6_link_speed = -1; +static int lpfc6_ip_class = -1; +static int lpfc6_fcp_class = -1; +static int lpfc6_use_adisc = -1; +static int lpfc6_fcpfabric_tmo = -1; +static int lpfc6_post_ip_buf = -1; +static int lpfc6_dqfull_throttle_up_time = -1; +static int lpfc6_dqfull_throttle_up_inc = -1; +static int lpfc6_ack0support = -1; +static int lpfc6_automap = -1; +static int lpfc6_cr_delay = -1; +static int lpfc6_cr_count = -1; + +/* HBA 7 */ +#ifdef MODULE_PARM +MODULE_PARM(lpfc7_log_verbose, "i"); +MODULE_PARM(lpfc7_log_only, "i"); +MODULE_PARM(lpfc7_lun_queue_depth, "i"); +MODULE_PARM(lpfc7_tgt_queue_depth, "i"); +MODULE_PARM(lpfc7_no_device_delay, "i"); +MODULE_PARM(lpfc7_network_on, "i"); +MODULE_PARM(lpfc7_xmt_que_size, "i"); +MODULE_PARM(lpfc7_scandown, "i"); +MODULE_PARM(lpfc7_linkdown_tmo, "i"); +MODULE_PARM(lpfc7_nodev_tmo, "i"); +MODULE_PARM(lpfc7_delay_rsp_err, "i"); +MODULE_PARM(lpfc7_nodev_holdio, "i"); +MODULE_PARM(lpfc7_check_cond_err, "i"); +MODULE_PARM(lpfc7_num_iocbs, "i"); +MODULE_PARM(lpfc7_num_bufs, "i"); +MODULE_PARM(lpfc7_topology, "i"); +MODULE_PARM(lpfc7_link_speed, "i"); +MODULE_PARM(lpfc7_ip_class, "i"); +MODULE_PARM(lpfc7_fcp_class, "i"); +MODULE_PARM(lpfc7_use_adisc, "i"); +MODULE_PARM(lpfc7_fcpfabric_tmo, "i"); +MODULE_PARM(lpfc7_post_ip_buf, "i"); +MODULE_PARM(lpfc7_dqfull_throttle_up_time, "i"); +MODULE_PARM(lpfc7_dqfull_throttle_up_inc, "i"); +MODULE_PARM(lpfc7_ack0support, "i"); +MODULE_PARM(lpfc7_automap, "i"); +MODULE_PARM(lpfc7_cr_delay, "i"); +MODULE_PARM(lpfc7_cr_count, "i"); +#endif + +static int lpfc7_log_verbose = -1; +static int lpfc7_log_only = -1; +static int lpfc7_lun_queue_depth = -1; +static int lpfc7_tgt_queue_depth = -1; +static int lpfc7_no_device_delay = -1; +static int lpfc7_network_on = -1; +static int lpfc7_xmt_que_size = -1; +static int lpfc7_scandown = -1; +static int lpfc7_linkdown_tmo = -1; +static int lpfc7_nodev_tmo = -1; +static int lpfc7_delay_rsp_err = -1; +static int lpfc7_nodev_holdio = -1; +static int lpfc7_check_cond_err = -1; +static int lpfc7_num_iocbs = -1; +static int lpfc7_num_bufs = -1; +static int lpfc7_topology = -1; +static int lpfc7_link_speed = -1; +static int lpfc7_ip_class = -1; +static int lpfc7_fcp_class = -1; +static int lpfc7_use_adisc = -1; +static int lpfc7_fcpfabric_tmo = -1; +static int lpfc7_post_ip_buf = -1; +static int lpfc7_dqfull_throttle_up_time = -1; +static int lpfc7_dqfull_throttle_up_inc = -1; +static int lpfc7_ack0support = -1; +static int lpfc7_automap = -1; +static int lpfc7_cr_delay = -1; +static int lpfc7_cr_count = -1; + +/* HBA 8 */ +#ifdef MODULE_PARM +MODULE_PARM(lpfc8_log_verbose, "i"); +MODULE_PARM(lpfc8_log_only, "i"); +MODULE_PARM(lpfc8_lun_queue_depth, "i"); +MODULE_PARM(lpfc8_tgt_queue_depth, "i"); +MODULE_PARM(lpfc8_no_device_delay, "i"); +MODULE_PARM(lpfc8_network_on, "i"); +MODULE_PARM(lpfc8_xmt_que_size, "i"); +MODULE_PARM(lpfc8_scandown, "i"); +MODULE_PARM(lpfc8_linkdown_tmo, "i"); +MODULE_PARM(lpfc8_nodev_tmo, "i"); +MODULE_PARM(lpfc8_delay_rsp_err, "i"); +MODULE_PARM(lpfc8_nodev_holdio, "i"); +MODULE_PARM(lpfc8_check_cond_err, "i"); +MODULE_PARM(lpfc8_num_iocbs, "i"); +MODULE_PARM(lpfc8_num_bufs, "i"); +MODULE_PARM(lpfc8_topology, "i"); +MODULE_PARM(lpfc8_link_speed, "i"); +MODULE_PARM(lpfc8_ip_class, "i"); +MODULE_PARM(lpfc8_fcp_class, "i"); +MODULE_PARM(lpfc8_use_adisc, "i"); +MODULE_PARM(lpfc8_fcpfabric_tmo, "i"); +MODULE_PARM(lpfc8_post_ip_buf, "i"); +MODULE_PARM(lpfc8_dqfull_throttle_up_time, "i"); +MODULE_PARM(lpfc8_dqfull_throttle_up_inc, "i"); +MODULE_PARM(lpfc8_ack0support, "i"); +MODULE_PARM(lpfc8_automap, "i"); +MODULE_PARM(lpfc8_cr_delay, "i"); +MODULE_PARM(lpfc8_cr_count, "i"); +#endif + +static int lpfc8_log_verbose = -1; +static int lpfc8_log_only = -1; +static int lpfc8_lun_queue_depth = -1; +static int lpfc8_tgt_queue_depth = -1; +static int lpfc8_no_device_delay = -1; +static int lpfc8_network_on = -1; +static int lpfc8_xmt_que_size = -1; +static int lpfc8_scandown = -1; +static int lpfc8_linkdown_tmo = -1; +static int lpfc8_nodev_tmo = -1; +static int lpfc8_delay_rsp_err = -1; +static int lpfc8_nodev_holdio = -1; +static int lpfc8_check_cond_err = -1; +static int lpfc8_num_iocbs = -1; +static int lpfc8_num_bufs = -1; +static int lpfc8_topology = -1; +static int lpfc8_link_speed = -1; +static int lpfc8_ip_class = -1; +static int lpfc8_fcp_class = -1; +static int lpfc8_use_adisc = -1; +static int lpfc8_fcpfabric_tmo = -1; +static int lpfc8_post_ip_buf = -1; +static int lpfc8_dqfull_throttle_up_time = -1; +static int lpfc8_dqfull_throttle_up_inc = -1; +static int lpfc8_ack0support = -1; +static int lpfc8_automap = -1; +static int lpfc8_cr_delay = -1; +static int lpfc8_cr_count = -1; + +/* HBA 9 */ +#ifdef MODULE_PARM +MODULE_PARM(lpfc9_log_verbose, "i"); +MODULE_PARM(lpfc9_log_only, "i"); +MODULE_PARM(lpfc9_lun_queue_depth, "i"); +MODULE_PARM(lpfc9_tgt_queue_depth, "i"); +MODULE_PARM(lpfc9_no_device_delay, "i"); +MODULE_PARM(lpfc9_network_on, "i"); +MODULE_PARM(lpfc9_xmt_que_size, "i"); +MODULE_PARM(lpfc9_scandown, "i"); +MODULE_PARM(lpfc9_linkdown_tmo, "i"); +MODULE_PARM(lpfc9_nodev_tmo, "i"); +MODULE_PARM(lpfc9_delay_rsp_err, "i"); +MODULE_PARM(lpfc9_nodev_holdio, "i"); +MODULE_PARM(lpfc9_check_cond_err, "i"); +MODULE_PARM(lpfc9_num_iocbs, "i"); +MODULE_PARM(lpfc9_num_bufs, "i"); +MODULE_PARM(lpfc9_topology, "i"); +MODULE_PARM(lpfc9_link_speed, "i"); +MODULE_PARM(lpfc9_ip_class, "i"); +MODULE_PARM(lpfc9_fcp_class, "i"); +MODULE_PARM(lpfc9_use_adisc, "i"); +MODULE_PARM(lpfc9_fcpfabric_tmo, "i"); +MODULE_PARM(lpfc9_post_ip_buf, "i"); +MODULE_PARM(lpfc9_dqfull_throttle_up_time, "i"); +MODULE_PARM(lpfc9_dqfull_throttle_up_inc, "i"); +MODULE_PARM(lpfc9_ack0support, "i"); +MODULE_PARM(lpfc9_automap, "i"); +MODULE_PARM(lpfc9_cr_delay, "i"); +MODULE_PARM(lpfc9_cr_count, "i"); +#endif + +static int lpfc9_log_verbose = -1; +static int lpfc9_log_only = -1; +static int lpfc9_lun_queue_depth = -1; +static int lpfc9_tgt_queue_depth = -1; +static int lpfc9_no_device_delay = -1; +static int lpfc9_network_on = -1; +static int lpfc9_xmt_que_size = -1; +static int lpfc9_scandown = -1; +static int lpfc9_linkdown_tmo = -1; +static int lpfc9_nodev_tmo = -1; +static int lpfc9_delay_rsp_err = -1; +static int lpfc9_nodev_holdio = -1; +static int lpfc9_check_cond_err = -1; +static int lpfc9_num_iocbs = -1; +static int lpfc9_num_bufs = -1; +static int lpfc9_topology = -1; +static int lpfc9_link_speed = -1; +static int lpfc9_ip_class = -1; +static int lpfc9_fcp_class = -1; +static int lpfc9_use_adisc = -1; +static int lpfc9_fcpfabric_tmo = -1; +static int lpfc9_post_ip_buf = -1; +static int lpfc9_dqfull_throttle_up_time = -1; +static int lpfc9_dqfull_throttle_up_inc = -1; +static int lpfc9_ack0support = -1; +static int lpfc9_automap = -1; +static int lpfc9_cr_delay = -1; +static int lpfc9_cr_count = -1; + +/* HBA 10 */ +#ifdef MODULE_PARM +MODULE_PARM(lpfc10_log_verbose, "i"); +MODULE_PARM(lpfc10_log_only, "i"); +MODULE_PARM(lpfc10_lun_queue_depth, "i"); +MODULE_PARM(lpfc10_tgt_queue_depth, "i"); +MODULE_PARM(lpfc10_no_device_delay, "i"); +MODULE_PARM(lpfc10_network_on, "i"); +MODULE_PARM(lpfc10_xmt_que_size, "i"); +MODULE_PARM(lpfc10_scandown, "i"); +MODULE_PARM(lpfc10_linkdown_tmo, "i"); +MODULE_PARM(lpfc10_nodev_tmo, "i"); +MODULE_PARM(lpfc10_delay_rsp_err, "i"); +MODULE_PARM(lpfc10_nodev_holdio, "i"); +MODULE_PARM(lpfc10_check_cond_err, "i"); +MODULE_PARM(lpfc10_num_iocbs, "i"); +MODULE_PARM(lpfc10_num_bufs, "i"); +MODULE_PARM(lpfc10_topology, "i"); +MODULE_PARM(lpfc10_link_speed, "i"); +MODULE_PARM(lpfc10_ip_class, "i"); +MODULE_PARM(lpfc10_fcp_class, "i"); +MODULE_PARM(lpfc10_use_adisc, "i"); +MODULE_PARM(lpfc10_fcpfabric_tmo, "i"); +MODULE_PARM(lpfc10_post_ip_buf, "i"); +MODULE_PARM(lpfc10_dqfull_throttle_up_time, "i"); +MODULE_PARM(lpfc10_dqfull_throttle_up_inc, "i"); +MODULE_PARM(lpfc10_ack0support, "i"); +MODULE_PARM(lpfc10_automap, "i"); +MODULE_PARM(lpfc10_cr_delay, "i"); +MODULE_PARM(lpfc10_cr_count, "i"); +#endif + +static int lpfc10_log_verbose = -1; +static int lpfc10_log_only = -1; +static int lpfc10_lun_queue_depth = -1; +static int lpfc10_tgt_queue_depth = -1; +static int lpfc10_no_device_delay = -1; +static int lpfc10_network_on = -1; +static int lpfc10_xmt_que_size = -1; +static int lpfc10_scandown = -1; +static int lpfc10_linkdown_tmo = -1; +static int lpfc10_nodev_tmo = -1; +static int lpfc10_delay_rsp_err = -1; +static int lpfc10_nodev_holdio = -1; +static int lpfc10_check_cond_err = -1; +static int lpfc10_num_iocbs = -1; +static int lpfc10_num_bufs = -1; +static int lpfc10_topology = -1; +static int lpfc10_link_speed = -1; +static int lpfc10_ip_class = -1; +static int lpfc10_fcp_class = -1; +static int lpfc10_use_adisc = -1; +static int lpfc10_fcpfabric_tmo = -1; +static int lpfc10_post_ip_buf = -1; +static int lpfc10_dqfull_throttle_up_time = -1; +static int lpfc10_dqfull_throttle_up_inc = -1; +static int lpfc10_ack0support = -1; +static int lpfc10_automap = -1; +static int lpfc10_cr_delay = -1; +static int lpfc10_cr_count = -1; + +/* HBA 11 */ +#ifdef MODULE_PARM +MODULE_PARM(lpfc11_log_verbose, "i"); +MODULE_PARM(lpfc11_log_only, "i"); +MODULE_PARM(lpfc11_lun_queue_depth, "i"); +MODULE_PARM(lpfc11_tgt_queue_depth, "i"); +MODULE_PARM(lpfc11_no_device_delay, "i"); +MODULE_PARM(lpfc11_network_on, "i"); +MODULE_PARM(lpfc11_xmt_que_size, "i"); +MODULE_PARM(lpfc11_scandown, "i"); +MODULE_PARM(lpfc11_linkdown_tmo, "i"); +MODULE_PARM(lpfc11_nodev_tmo, "i"); +MODULE_PARM(lpfc11_delay_rsp_err, "i"); +MODULE_PARM(lpfc11_nodev_holdio, "i"); +MODULE_PARM(lpfc11_check_cond_err, "i"); +MODULE_PARM(lpfc11_num_iocbs, "i"); +MODULE_PARM(lpfc11_num_bufs, "i"); +MODULE_PARM(lpfc11_topology, "i"); +MODULE_PARM(lpfc11_link_speed, "i"); +MODULE_PARM(lpfc11_ip_class, "i"); +MODULE_PARM(lpfc11_fcp_class, "i"); +MODULE_PARM(lpfc11_use_adisc, "i"); +MODULE_PARM(lpfc11_fcpfabric_tmo, "i"); +MODULE_PARM(lpfc11_post_ip_buf, "i"); +MODULE_PARM(lpfc11_dqfull_throttle_up_time, "i"); +MODULE_PARM(lpfc11_dqfull_throttle_up_inc, "i"); +MODULE_PARM(lpfc11_ack0support, "i"); +MODULE_PARM(lpfc11_automap, "i"); +MODULE_PARM(lpfc11_cr_delay, "i"); +MODULE_PARM(lpfc11_cr_count, "i"); +#endif + +static int lpfc11_log_verbose = -1; +static int lpfc11_log_only = -1; +static int lpfc11_lun_queue_depth = -1; +static int lpfc11_tgt_queue_depth = -1; +static int lpfc11_no_device_delay = -1; +static int lpfc11_network_on = -1; +static int lpfc11_xmt_que_size = -1; +static int lpfc11_scandown = -1; +static int lpfc11_linkdown_tmo = -1; +static int lpfc11_nodev_tmo = -1; +static int lpfc11_delay_rsp_err = -1; +static int lpfc11_nodev_holdio = -1; +static int lpfc11_check_cond_err = -1; +static int lpfc11_num_iocbs = -1; +static int lpfc11_num_bufs = -1; +static int lpfc11_topology = -1; +static int lpfc11_link_speed = -1; +static int lpfc11_ip_class = -1; +static int lpfc11_fcp_class = -1; +static int lpfc11_use_adisc = -1; +static int lpfc11_fcpfabric_tmo = -1; +static int lpfc11_post_ip_buf = -1; +static int lpfc11_dqfull_throttle_up_time = -1; +static int lpfc11_dqfull_throttle_up_inc = -1; +static int lpfc11_ack0support = -1; +static int lpfc11_automap = -1; +static int lpfc11_cr_delay = -1; +static int lpfc11_cr_count = -1; + +/* HBA 12 */ +#ifdef MODULE_PARM +MODULE_PARM(lpfc12_log_verbose, "i"); +MODULE_PARM(lpfc12_log_only, "i"); +MODULE_PARM(lpfc12_lun_queue_depth, "i"); +MODULE_PARM(lpfc12_tgt_queue_depth, "i"); +MODULE_PARM(lpfc12_no_device_delay, "i"); +MODULE_PARM(lpfc12_network_on, "i"); +MODULE_PARM(lpfc12_xmt_que_size, "i"); +MODULE_PARM(lpfc12_scandown, "i"); +MODULE_PARM(lpfc12_linkdown_tmo, "i"); +MODULE_PARM(lpfc12_nodev_tmo, "i"); +MODULE_PARM(lpfc12_delay_rsp_err, "i"); +MODULE_PARM(lpfc12_nodev_holdio, "i"); +MODULE_PARM(lpfc12_check_cond_err, "i"); +MODULE_PARM(lpfc12_num_iocbs, "i"); +MODULE_PARM(lpfc12_num_bufs, "i"); +MODULE_PARM(lpfc12_topology, "i"); +MODULE_PARM(lpfc12_link_speed, "i"); +MODULE_PARM(lpfc12_ip_class, "i"); +MODULE_PARM(lpfc12_fcp_class, "i"); +MODULE_PARM(lpfc12_use_adisc, "i"); +MODULE_PARM(lpfc12_fcpfabric_tmo, "i"); +MODULE_PARM(lpfc12_post_ip_buf, "i"); +MODULE_PARM(lpfc12_dqfull_throttle_up_time, "i"); +MODULE_PARM(lpfc12_dqfull_throttle_up_inc, "i"); +MODULE_PARM(lpfc12_ack0support, "i"); +MODULE_PARM(lpfc12_automap, "i"); +MODULE_PARM(lpfc12_cr_delay, "i"); +MODULE_PARM(lpfc12_cr_count, "i"); +#endif + +static int lpfc12_log_verbose = -1; +static int lpfc12_log_only = -1; +static int lpfc12_lun_queue_depth = -1; +static int lpfc12_tgt_queue_depth = -1; +static int lpfc12_no_device_delay = -1; +static int lpfc12_network_on = -1; +static int lpfc12_xmt_que_size = -1; +static int lpfc12_scandown = -1; +static int lpfc12_linkdown_tmo = -1; +static int lpfc12_nodev_tmo = -1; +static int lpfc12_delay_rsp_err = -1; +static int lpfc12_nodev_holdio = -1; +static int lpfc12_check_cond_err = -1; +static int lpfc12_num_iocbs = -1; +static int lpfc12_num_bufs = -1; +static int lpfc12_topology = -1; +static int lpfc12_link_speed = -1; +static int lpfc12_ip_class = -1; +static int lpfc12_fcp_class = -1; +static int lpfc12_use_adisc = -1; +static int lpfc12_fcpfabric_tmo = -1; +static int lpfc12_post_ip_buf = -1; +static int lpfc12_dqfull_throttle_up_time = -1; +static int lpfc12_dqfull_throttle_up_inc = -1; +static int lpfc12_ack0support = -1; +static int lpfc12_automap = -1; +static int lpfc12_cr_delay = -1; +static int lpfc12_cr_count = -1; + +/* HBA 13 */ +#ifdef MODULE_PARM +MODULE_PARM(lpfc13_log_verbose, "i"); +MODULE_PARM(lpfc13_log_only, "i"); +MODULE_PARM(lpfc13_lun_queue_depth, "i"); +MODULE_PARM(lpfc13_tgt_queue_depth, "i"); +MODULE_PARM(lpfc13_no_device_delay, "i"); +MODULE_PARM(lpfc13_network_on, "i"); +MODULE_PARM(lpfc13_xmt_que_size, "i"); +MODULE_PARM(lpfc13_scandown, "i"); +MODULE_PARM(lpfc13_linkdown_tmo, "i"); +MODULE_PARM(lpfc13_nodev_tmo, "i"); +MODULE_PARM(lpfc13_delay_rsp_err, "i"); +MODULE_PARM(lpfc13_nodev_holdio, "i"); +MODULE_PARM(lpfc13_check_cond_err, "i"); +MODULE_PARM(lpfc13_num_iocbs, "i"); +MODULE_PARM(lpfc13_num_bufs, "i"); +MODULE_PARM(lpfc13_topology, "i"); +MODULE_PARM(lpfc13_link_speed, "i"); +MODULE_PARM(lpfc13_ip_class, "i"); +MODULE_PARM(lpfc13_fcp_class, "i"); +MODULE_PARM(lpfc13_use_adisc, "i"); +MODULE_PARM(lpfc13_fcpfabric_tmo, "i"); +MODULE_PARM(lpfc13_post_ip_buf, "i"); +MODULE_PARM(lpfc13_dqfull_throttle_up_time, "i"); +MODULE_PARM(lpfc13_dqfull_throttle_up_inc, "i"); +MODULE_PARM(lpfc13_ack0support, "i"); +MODULE_PARM(lpfc13_automap, "i"); +MODULE_PARM(lpfc13_cr_delay, "i"); +MODULE_PARM(lpfc13_cr_count, "i"); +#endif + +static int lpfc13_log_verbose = -1; +static int lpfc13_log_only = -1; +static int lpfc13_lun_queue_depth = -1; +static int lpfc13_tgt_queue_depth = -1; +static int lpfc13_no_device_delay = -1; +static int lpfc13_network_on = -1; +static int lpfc13_xmt_que_size = -1; +static int lpfc13_scandown = -1; +static int lpfc13_linkdown_tmo = -1; +static int lpfc13_nodev_tmo = -1; +static int lpfc13_delay_rsp_err = -1; +static int lpfc13_nodev_holdio = -1; +static int lpfc13_check_cond_err = -1; +static int lpfc13_num_iocbs = -1; +static int lpfc13_num_bufs = -1; +static int lpfc13_topology = -1; +static int lpfc13_link_speed = -1; +static int lpfc13_ip_class = -1; +static int lpfc13_fcp_class = -1; +static int lpfc13_use_adisc = -1; +static int lpfc13_fcpfabric_tmo = -1; +static int lpfc13_post_ip_buf = -1; +static int lpfc13_dqfull_throttle_up_time = -1; +static int lpfc13_dqfull_throttle_up_inc = -1; +static int lpfc13_ack0support = -1; +static int lpfc13_automap = -1; +static int lpfc13_cr_delay = -1; +static int lpfc13_cr_count = -1; + +/* HBA 14 */ +#ifdef MODULE_PARM +MODULE_PARM(lpfc14_log_verbose, "i"); +MODULE_PARM(lpfc14_log_only, "i"); +MODULE_PARM(lpfc14_lun_queue_depth, "i"); +MODULE_PARM(lpfc14_tgt_queue_depth, "i"); +MODULE_PARM(lpfc14_no_device_delay, "i"); +MODULE_PARM(lpfc14_network_on, "i"); +MODULE_PARM(lpfc14_xmt_que_size, "i"); +MODULE_PARM(lpfc14_scandown, "i"); +MODULE_PARM(lpfc14_linkdown_tmo, "i"); +MODULE_PARM(lpfc14_nodev_tmo, "i"); +MODULE_PARM(lpfc14_delay_rsp_err, "i"); +MODULE_PARM(lpfc14_nodev_holdio, "i"); +MODULE_PARM(lpfc14_check_cond_err, "i"); +MODULE_PARM(lpfc14_num_iocbs, "i"); +MODULE_PARM(lpfc14_num_bufs, "i"); +MODULE_PARM(lpfc14_topology, "i"); +MODULE_PARM(lpfc14_link_speed, "i"); +MODULE_PARM(lpfc14_ip_class, "i"); +MODULE_PARM(lpfc14_fcp_class, "i"); +MODULE_PARM(lpfc14_use_adisc, "i"); +MODULE_PARM(lpfc14_fcpfabric_tmo, "i"); +MODULE_PARM(lpfc14_post_ip_buf, "i"); +MODULE_PARM(lpfc14_dqfull_throttle_up_time, "i"); +MODULE_PARM(lpfc14_dqfull_throttle_up_inc, "i"); +MODULE_PARM(lpfc14_ack0support, "i"); +MODULE_PARM(lpfc14_automap, "i"); +MODULE_PARM(lpfc14_cr_delay, "i"); +MODULE_PARM(lpfc14_cr_count, "i"); +#endif + +static int lpfc14_log_verbose = -1; +static int lpfc14_log_only = -1; +static int lpfc14_lun_queue_depth = -1; +static int lpfc14_tgt_queue_depth = -1; +static int lpfc14_no_device_delay = -1; +static int lpfc14_network_on = -1; +static int lpfc14_xmt_que_size = -1; +static int lpfc14_scandown = -1; +static int lpfc14_linkdown_tmo = -1; +static int lpfc14_nodev_tmo = -1; +static int lpfc14_delay_rsp_err = -1; +static int lpfc14_nodev_holdio = -1; +static int lpfc14_check_cond_err = -1; +static int lpfc14_num_iocbs = -1; +static int lpfc14_num_bufs = -1; +static int lpfc14_topology = -1; +static int lpfc14_link_speed = -1; +static int lpfc14_ip_class = -1; +static int lpfc14_fcp_class = -1; +static int lpfc14_use_adisc = -1; +static int lpfc14_fcpfabric_tmo = -1; +static int lpfc14_post_ip_buf = -1; +static int lpfc14_dqfull_throttle_up_time = -1; +static int lpfc14_dqfull_throttle_up_inc = -1; +static int lpfc14_ack0support = -1; +static int lpfc14_automap = -1; +static int lpfc14_cr_delay = -1; +static int lpfc14_cr_count = -1; + +/* HBA 15 */ +#ifdef MODULE_PARM +MODULE_PARM(lpfc15_log_verbose, "i"); +MODULE_PARM(lpfc15_log_only, "i"); +MODULE_PARM(lpfc15_lun_queue_depth, "i"); +MODULE_PARM(lpfc15_tgt_queue_depth, "i"); +MODULE_PARM(lpfc15_no_device_delay, "i"); +MODULE_PARM(lpfc15_network_on, "i"); +MODULE_PARM(lpfc15_xmt_que_size, "i"); +MODULE_PARM(lpfc15_scandown, "i"); +MODULE_PARM(lpfc15_linkdown_tmo, "i"); +MODULE_PARM(lpfc15_nodev_tmo, "i"); +MODULE_PARM(lpfc15_delay_rsp_err, "i"); +MODULE_PARM(lpfc15_nodev_holdio, "i"); +MODULE_PARM(lpfc15_check_cond_err, "i"); +MODULE_PARM(lpfc15_num_iocbs, "i"); +MODULE_PARM(lpfc15_num_bufs, "i"); +MODULE_PARM(lpfc15_topology, "i"); +MODULE_PARM(lpfc15_link_speed, "i"); +MODULE_PARM(lpfc15_ip_class, "i"); +MODULE_PARM(lpfc15_fcp_class, "i"); +MODULE_PARM(lpfc15_use_adisc, "i"); +MODULE_PARM(lpfc15_fcpfabric_tmo, "i"); +MODULE_PARM(lpfc15_post_ip_buf, "i"); +MODULE_PARM(lpfc15_dqfull_throttle_up_time, "i"); +MODULE_PARM(lpfc15_dqfull_throttle_up_inc, "i"); +MODULE_PARM(lpfc15_ack0support, "i"); +MODULE_PARM(lpfc15_automap, "i"); +MODULE_PARM(lpfc15_cr_delay, "i"); +MODULE_PARM(lpfc15_cr_count, "i"); +#endif + +static int lpfc15_log_verbose = -1; +static int lpfc15_log_only = -1; +static int lpfc15_lun_queue_depth = -1; +static int lpfc15_tgt_queue_depth = -1; +static int lpfc15_no_device_delay = -1; +static int lpfc15_network_on = -1; +static int lpfc15_xmt_que_size = -1; +static int lpfc15_scandown = -1; +static int lpfc15_linkdown_tmo = -1; +static int lpfc15_nodev_tmo = -1; +static int lpfc15_delay_rsp_err = -1; +static int lpfc15_nodev_holdio = -1; +static int lpfc15_check_cond_err = -1; +static int lpfc15_num_iocbs = -1; +static int lpfc15_num_bufs = -1; +static int lpfc15_topology = -1; +static int lpfc15_link_speed = -1; +static int lpfc15_ip_class = -1; +static int lpfc15_fcp_class = -1; +static int lpfc15_use_adisc = -1; +static int lpfc15_fcpfabric_tmo = -1; +static int lpfc15_post_ip_buf = -1; +static int lpfc15_dqfull_throttle_up_time = -1; +static int lpfc15_dqfull_throttle_up_inc = -1; +static int lpfc15_ack0support = -1; +static int lpfc15_automap = -1; +static int lpfc15_cr_delay = -1; +static int lpfc15_cr_count = -1; + +#ifdef MODULE_PARM +MODULE_PARM(lpfc_log_verbose, "i"); +MODULE_PARM(lpfc_log_only, "i"); +MODULE_PARM(lpfc_lun_queue_depth, "i"); +MODULE_PARM(lpfc_tgt_queue_depth, "i"); +MODULE_PARM(lpfc_no_device_delay, "i"); +MODULE_PARM(lpfc_network_on, "i"); +MODULE_PARM(lpfc_xmt_que_size, "i"); +MODULE_PARM(lpfc_scandown, "i"); +MODULE_PARM(lpfc_linkdown_tmo, "i"); +MODULE_PARM(lpfc_nodev_tmo, "i"); +MODULE_PARM(lpfc_delay_rsp_err, "i"); +MODULE_PARM(lpfc_nodev_holdio, "i"); +MODULE_PARM(lpfc_check_cond_err, "i"); +MODULE_PARM(lpfc_num_iocbs, "i"); +MODULE_PARM(lpfc_num_bufs, "i"); +MODULE_PARM(lpfc_topology, "i"); +MODULE_PARM(lpfc_link_speed, "i"); +MODULE_PARM(lpfc_ip_class, "i"); +MODULE_PARM(lpfc_fcp_class, "i"); +MODULE_PARM(lpfc_use_adisc, "i"); +MODULE_PARM(lpfc_fcpfabric_tmo, "i"); +MODULE_PARM(lpfc_post_ip_buf, "i"); +MODULE_PARM(lpfc_dqfull_throttle_up_time, "i"); +MODULE_PARM(lpfc_dqfull_throttle_up_inc, "i"); +MODULE_PARM(lpfc_ack0support, "i"); +MODULE_PARM(lpfc_automap, "i"); +MODULE_PARM(lpfc_cr_delay, "i"); +MODULE_PARM(lpfc_cr_count, "i"); +#endif + +extern int lpfc_log_verbose; +extern int lpfc_log_only; +extern int lpfc_lun_queue_depth; +extern int lpfc_tgt_queue_depth; +extern int lpfc_no_device_delay; +extern int lpfc_network_on; +extern int lpfc_xmt_que_size; +extern int lpfc_scandown; +extern int lpfc_linkdown_tmo; +extern int lpfc_nodev_tmo; +extern int lpfc_delay_rsp_err; +extern int lpfc_nodev_holdio; +extern int lpfc_check_cond_err; +extern int lpfc_num_iocbs; +extern int lpfc_num_bufs; +extern int lpfc_topology; +extern int lpfc_link_speed; +extern int lpfc_ip_class; +extern int lpfc_fcp_class; +extern int lpfc_use_adisc; +extern int lpfc_fcpfabric_tmo; +extern int lpfc_post_ip_buf; +extern int lpfc_dqfull_throttle_up_time; +extern int lpfc_dqfull_throttle_up_inc; +extern int lpfc_ack0support; +extern int lpfc_automap; +extern int lpfc_cr_delay; +extern int lpfc_cr_count; + + +void * +fc_get_cfg_param( +int brd, +int param) +{ + void *value; + + value = (void *)((ulong)(-1)); + switch(brd) { + case 0: /* HBA 0 */ + switch(param) { + case CFG_LOG_VERBOSE: /* log-verbose */ + value = (void *)((ulong)lpfc_log_verbose); + if(lpfc0_log_verbose != -1) + value = (void *)((ulong)lpfc0_log_verbose); + break; + case CFG_LOG_ONLY: /* log-only */ + value = (void *)((ulong)lpfc_log_only); + if(lpfc0_log_only != -1) + value = (void *)((ulong)lpfc0_log_only); + break; + case CFG_NUM_IOCBS: /* num-iocbs */ + value = (void *)((ulong)lpfc_num_iocbs); + if(lpfc0_num_iocbs != -1) + value = (void *)((ulong)lpfc0_num_iocbs); + break; + case CFG_NUM_BUFS: /* num-bufs */ + value = (void *)((ulong)lpfc_num_bufs); + if(lpfc0_num_bufs != -1) + value = (void *)((ulong)lpfc0_num_bufs); + break; + case CFG_AUTOMAP: /* automap */ + value = (void *)((ulong)lpfc_automap); + if(lpfc0_automap != -1) + value = (void *)((ulong)lpfc0_automap); + break; + case CFG_CR_DELAY: /* cr_delay */ + value = (void *)((ulong)lpfc_cr_delay); + if(lpfc0_cr_delay != -1) + value = (void *)((ulong)lpfc0_cr_delay); + break; + case CFG_CR_COUNT: /* cr_count */ + value = (void *)((ulong)lpfc_cr_count); + if(lpfc0_cr_count != -1) + value = (void *)((ulong)lpfc0_cr_count); + break; + case CFG_DFT_TGT_Q_DEPTH: /* tgt_queue_depth */ + value = (void *)((ulong)lpfc_tgt_queue_depth); + if(lpfc0_tgt_queue_depth != -1) + value = (void *)((ulong)lpfc0_tgt_queue_depth); + break; + case CFG_DFT_LUN_Q_DEPTH: /* lun_queue_depth */ + value = (void *)((ulong)lpfc_lun_queue_depth); + if(lpfc0_lun_queue_depth != -1) + value = (void *)((ulong)lpfc0_lun_queue_depth); + break; + case CFG_FCPFABRIC_TMO: /* fcpfabric-tmo */ + value = (void *)((ulong)lpfc_fcpfabric_tmo); + if(lpfc0_fcpfabric_tmo != -1) + value = (void *)((ulong)lpfc0_fcpfabric_tmo); + break; + case CFG_FCP_CLASS: /* fcp-class */ + value = (void *)((ulong)lpfc_fcp_class); + if(lpfc0_fcp_class != -1) + value = (void *)((ulong)lpfc0_fcp_class); + break; + case CFG_USE_ADISC: /* use-adisc */ + value = (void *)((ulong)lpfc_use_adisc); + if(lpfc0_use_adisc != -1) + value = (void *)((ulong)lpfc0_use_adisc); + break; + case CFG_NO_DEVICE_DELAY: /* no-device-delay */ + value = (void *)((ulong)lpfc_no_device_delay); + if(lpfc0_no_device_delay != -1) + value = (void *)((ulong)lpfc0_no_device_delay); + break; + case CFG_NETWORK_ON: /* network-on */ + value = (void *)((ulong)lpfc_network_on); + if(lpfc0_network_on != -1) + value = (void *)((ulong)lpfc0_network_on); + break; + case CFG_POST_IP_BUF: /* post-ip-buf */ + value = (void *)((ulong)lpfc_post_ip_buf); + if(lpfc0_post_ip_buf != -1) + value = (void *)((ulong)lpfc0_post_ip_buf); + break; + case CFG_XMT_Q_SIZE: /* xmt-que-size */ + value = (void *)((ulong)lpfc_xmt_que_size); + if(lpfc0_xmt_que_size != -1) + value = (void *)((ulong)lpfc0_xmt_que_size); + break; + case CFG_IP_CLASS: /* ip-class */ + value = (void *)((ulong)lpfc_ip_class); + if(lpfc0_ip_class != -1) + value = (void *)((ulong)lpfc0_ip_class); + break; + case CFG_ACK0: /* ack0 */ + value = (void *)((ulong)lpfc_ack0support); + if(lpfc0_ack0support != -1) + value = (void *)((ulong)lpfc0_ack0support); + break; + case CFG_TOPOLOGY: /* topology */ + value = (void *)((ulong)lpfc_topology); + if(lpfc0_topology != -1) + value = (void *)((ulong)lpfc0_topology); + break; + case CFG_SCAN_DOWN: /* scan-down */ + value = (void *)((ulong)lpfc_scandown); + if(lpfc0_scandown != -1) + value = (void *)((ulong)lpfc0_scandown); + break; + case CFG_LINKDOWN_TMO: /* linkdown-tmo */ + value = (void *)((ulong)lpfc_linkdown_tmo); + if(lpfc0_linkdown_tmo != -1) + value = (void *)((ulong)lpfc0_linkdown_tmo); + break; + case CFG_HOLDIO: /* nodev-holdio */ + value = (void *)((ulong)lpfc_nodev_holdio); + if(lpfc0_nodev_holdio != -1) + value = (void *)((ulong)lpfc0_nodev_holdio); + break; + case CFG_DELAY_RSP_ERR: /* delay-rsp-err */ + value = (void *)((ulong)lpfc_delay_rsp_err); + if(lpfc0_delay_rsp_err != -1) + value = (void *)((ulong)lpfc0_delay_rsp_err); + break; + case CFG_CHK_COND_ERR: /* check-cond-err */ + value = (void *)((ulong)lpfc_check_cond_err); + if(lpfc0_check_cond_err != -1) + value = (void *)((ulong)lpfc0_check_cond_err); + break; + case CFG_NODEV_TMO: /* nodev-tmo */ + value = (void *)((ulong)lpfc_nodev_tmo); + if(lpfc0_nodev_tmo != -1) + value = (void *)((ulong)lpfc0_nodev_tmo); + break; + case CFG_LINK_SPEED: /* link-speed */ + value = (void *)((ulong)lpfc_link_speed); + if(lpfc0_link_speed != -1) + value = (void *)((ulong)lpfc0_link_speed); + break; + case CFG_DQFULL_THROTTLE_UP_TIME: /* dqfull-throttle-up-time */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_time); + if(lpfc0_dqfull_throttle_up_time != -1) + value = (void *)((ulong)lpfc0_dqfull_throttle_up_time); + break; + case CFG_DQFULL_THROTTLE_UP_INC: /* dqfull-throttle-up-inc */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_inc); + if(lpfc0_dqfull_throttle_up_inc != -1) + value = (void *)((ulong)lpfc0_dqfull_throttle_up_inc); + break; + default: + break; + } + break; + case 1: /* HBA 1 */ + switch(param) { + case CFG_LOG_VERBOSE: /* log-verbose */ + value = (void *)((ulong)lpfc_log_verbose); + if(lpfc1_log_verbose != -1) + value = (void *)((ulong)lpfc1_log_verbose); + break; + case CFG_LOG_ONLY: /* log-only */ + value = (void *)((ulong)lpfc_log_only); + if(lpfc1_log_only != -1) + value = (void *)((ulong)lpfc1_log_only); + break; + case CFG_NUM_IOCBS: /* num-iocbs */ + value = (void *)((ulong)lpfc_num_iocbs); + if(lpfc1_num_iocbs != -1) + value = (void *)((ulong)lpfc1_num_iocbs); + break; + case CFG_NUM_BUFS: /* num-bufs */ + value = (void *)((ulong)lpfc_num_bufs); + if(lpfc1_num_bufs != -1) + value = (void *)((ulong)lpfc1_num_bufs); + break; + case CFG_AUTOMAP: /* automap */ + value = (void *)((ulong)lpfc_automap); + if(lpfc1_automap != -1) + value = (void *)((ulong)lpfc1_automap); + break; + case CFG_CR_DELAY: /* cr_delay */ + value = (void *)((ulong)lpfc_cr_delay); + if(lpfc1_cr_delay != -1) + value = (void *)((ulong)lpfc1_cr_delay); + break; + case CFG_CR_COUNT: /* cr_count */ + value = (void *)((ulong)lpfc_cr_count); + if(lpfc1_cr_count != -1) + value = (void *)((ulong)lpfc1_cr_count); + break; + case CFG_DFT_TGT_Q_DEPTH: /* tgt_queue_depth */ + value = (void *)((ulong)lpfc_tgt_queue_depth); + if(lpfc1_tgt_queue_depth != -1) + value = (void *)((ulong)lpfc1_tgt_queue_depth); + break; + case CFG_DFT_LUN_Q_DEPTH: /* lun_queue_depth */ + value = (void *)((ulong)lpfc_lun_queue_depth); + if(lpfc1_lun_queue_depth != -1) + value = (void *)((ulong)lpfc1_lun_queue_depth); + break; + case CFG_FCPFABRIC_TMO: /* fcpfabric-tmo */ + value = (void *)((ulong)lpfc_fcpfabric_tmo); + if(lpfc1_fcpfabric_tmo != -1) + value = (void *)((ulong)lpfc1_fcpfabric_tmo); + break; + case CFG_FCP_CLASS: /* fcp-class */ + value = (void *)((ulong)lpfc_fcp_class); + if(lpfc1_fcp_class != -1) + value = (void *)((ulong)lpfc1_fcp_class); + break; + case CFG_USE_ADISC: /* use-adisc */ + value = (void *)((ulong)lpfc_use_adisc); + if(lpfc1_use_adisc != -1) + value = (void *)((ulong)lpfc1_use_adisc); + break; + case CFG_NO_DEVICE_DELAY: /* no-device-delay */ + value = (void *)((ulong)lpfc_no_device_delay); + if(lpfc1_no_device_delay != -1) + value = (void *)((ulong)lpfc1_no_device_delay); + break; + case CFG_NETWORK_ON: /* network-on */ + value = (void *)((ulong)lpfc_network_on); + if(lpfc1_network_on != -1) + value = (void *)((ulong)lpfc1_network_on); + break; + case CFG_POST_IP_BUF: /* post-ip-buf */ + value = (void *)((ulong)lpfc_post_ip_buf); + if(lpfc1_post_ip_buf != -1) + value = (void *)((ulong)lpfc1_post_ip_buf); + break; + case CFG_XMT_Q_SIZE: /* xmt-que-size */ + value = (void *)((ulong)lpfc_xmt_que_size); + if(lpfc1_xmt_que_size != -1) + value = (void *)((ulong)lpfc1_xmt_que_size); + break; + case CFG_IP_CLASS: /* ip-class */ + value = (void *)((ulong)lpfc_ip_class); + if(lpfc1_ip_class != -1) + value = (void *)((ulong)lpfc1_ip_class); + break; + case CFG_ACK0: /* ack0 */ + value = (void *)((ulong)lpfc_ack0support); + if(lpfc1_ack0support != -1) + value = (void *)((ulong)lpfc1_ack0support); + break; + case CFG_TOPOLOGY: /* topology */ + value = (void *)((ulong)lpfc_topology); + if(lpfc1_topology != -1) + value = (void *)((ulong)lpfc1_topology); + break; + case CFG_SCAN_DOWN: /* scan-down */ + value = (void *)((ulong)lpfc_scandown); + if(lpfc1_scandown != -1) + value = (void *)((ulong)lpfc1_scandown); + break; + case CFG_LINKDOWN_TMO: /* linkdown-tmo */ + value = (void *)((ulong)lpfc_linkdown_tmo); + if(lpfc1_linkdown_tmo != -1) + value = (void *)((ulong)lpfc1_linkdown_tmo); + break; + case CFG_HOLDIO: /* nodev-holdio */ + value = (void *)((ulong)lpfc_nodev_holdio); + if(lpfc1_nodev_holdio != -1) + value = (void *)((ulong)lpfc1_nodev_holdio); + break; + case CFG_DELAY_RSP_ERR: /* delay-rsp-err */ + value = (void *)((ulong)lpfc_delay_rsp_err); + if(lpfc1_delay_rsp_err != -1) + value = (void *)((ulong)lpfc1_delay_rsp_err); + break; + case CFG_CHK_COND_ERR: /* check-cond-err */ + value = (void *)((ulong)lpfc_check_cond_err); + if(lpfc1_check_cond_err != -1) + value = (void *)((ulong)lpfc1_check_cond_err); + break; + case CFG_NODEV_TMO: /* nodev-tmo */ + value = (void *)((ulong)lpfc_nodev_tmo); + if(lpfc1_nodev_tmo != -1) + value = (void *)((ulong)lpfc1_nodev_tmo); + break; + case CFG_LINK_SPEED: /* link-speed */ + value = (void *)((ulong)lpfc_link_speed); + if(lpfc1_link_speed != -1) + value = (void *)((ulong)lpfc1_link_speed); + break; + case CFG_DQFULL_THROTTLE_UP_TIME: /* dqfull-throttle-up-time */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_time); + if(lpfc1_dqfull_throttle_up_time != -1) + value = (void *)((ulong)lpfc1_dqfull_throttle_up_time); + break; + case CFG_DQFULL_THROTTLE_UP_INC: /* dqfull-throttle-up-inc */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_inc); + if(lpfc1_dqfull_throttle_up_inc != -1) + value = (void *)((ulong)lpfc1_dqfull_throttle_up_inc); + break; + } + break; + case 2: /* HBA 2 */ + switch(param) { + case CFG_LOG_VERBOSE: /* log-verbose */ + value = (void *)((ulong)lpfc_log_verbose); + if(lpfc2_log_verbose != -1) + value = (void *)((ulong)lpfc2_log_verbose); + break; + case CFG_LOG_ONLY: /* log-only */ + value = (void *)((ulong)lpfc_log_only); + if(lpfc2_log_only != -1) + value = (void *)((ulong)lpfc2_log_only); + break; + case CFG_NUM_IOCBS: /* num-iocbs */ + value = (void *)((ulong)lpfc_num_iocbs); + if(lpfc2_num_iocbs != -1) + value = (void *)((ulong)lpfc2_num_iocbs); + break; + case CFG_NUM_BUFS: /* num-bufs */ + value = (void *)((ulong)lpfc_num_bufs); + if(lpfc2_num_bufs != -1) + value = (void *)((ulong)lpfc2_num_bufs); + break; + case CFG_AUTOMAP: /* automap */ + value = (void *)((ulong)lpfc_automap); + if(lpfc2_automap != -1) + value = (void *)((ulong)lpfc2_automap); + break; + case CFG_CR_DELAY: /* cr_delay */ + value = (void *)((ulong)lpfc_cr_delay); + if(lpfc2_cr_delay != -1) + value = (void *)((ulong)lpfc2_cr_delay); + break; + case CFG_CR_COUNT: /* cr_count */ + value = (void *)((ulong)lpfc_cr_count); + if(lpfc2_cr_count != -1) + value = (void *)((ulong)lpfc2_cr_count); + break; + case CFG_DFT_TGT_Q_DEPTH: /* tgt_queue_depth */ + value = (void *)((ulong)lpfc_tgt_queue_depth); + if(lpfc2_tgt_queue_depth != -1) + value = (void *)((ulong)lpfc2_tgt_queue_depth); + break; + case CFG_DFT_LUN_Q_DEPTH: /* lun_queue_depth */ + value = (void *)((ulong)lpfc_lun_queue_depth); + if(lpfc2_lun_queue_depth != -1) + value = (void *)((ulong)lpfc2_lun_queue_depth); + break; + case CFG_FCPFABRIC_TMO: /* fcpfabric-tmo */ + value = (void *)((ulong)lpfc_fcpfabric_tmo); + if(lpfc2_fcpfabric_tmo != -1) + value = (void *)((ulong)lpfc2_fcpfabric_tmo); + break; + case CFG_FCP_CLASS: /* fcp-class */ + value = (void *)((ulong)lpfc_fcp_class); + if(lpfc2_fcp_class != -1) + value = (void *)((ulong)lpfc2_fcp_class); + break; + case CFG_USE_ADISC: /* use-adisc */ + value = (void *)((ulong)lpfc_use_adisc); + if(lpfc2_use_adisc != -1) + value = (void *)((ulong)lpfc2_use_adisc); + break; + case CFG_NO_DEVICE_DELAY: /* no-device-delay */ + value = (void *)((ulong)lpfc_no_device_delay); + if(lpfc2_no_device_delay != -1) + value = (void *)((ulong)lpfc2_no_device_delay); + break; + case CFG_NETWORK_ON: /* network-on */ + value = (void *)((ulong)lpfc_network_on); + if(lpfc2_network_on != -1) + value = (void *)((ulong)lpfc2_network_on); + break; + case CFG_POST_IP_BUF: /* post-ip-buf */ + value = (void *)((ulong)lpfc_post_ip_buf); + if(lpfc2_post_ip_buf != -1) + value = (void *)((ulong)lpfc2_post_ip_buf); + break; + case CFG_XMT_Q_SIZE: /* xmt-que-size */ + value = (void *)((ulong)lpfc_xmt_que_size); + if(lpfc2_xmt_que_size != -1) + value = (void *)((ulong)lpfc2_xmt_que_size); + break; + case CFG_IP_CLASS: /* ip-class */ + value = (void *)((ulong)lpfc_ip_class); + if(lpfc2_ip_class != -1) + value = (void *)((ulong)lpfc2_ip_class); + break; + case CFG_ACK0: /* ack0 */ + value = (void *)((ulong)lpfc_ack0support); + if(lpfc2_ack0support != -1) + value = (void *)((ulong)lpfc2_ack0support); + break; + case CFG_TOPOLOGY: /* topology */ + value = (void *)((ulong)lpfc_topology); + if(lpfc2_topology != -1) + value = (void *)((ulong)lpfc2_topology); + break; + case CFG_SCAN_DOWN: /* scan-down */ + value = (void *)((ulong)lpfc_scandown); + if(lpfc2_scandown != -1) + value = (void *)((ulong)lpfc2_scandown); + break; + case CFG_LINKDOWN_TMO: /* linkdown-tmo */ + value = (void *)((ulong)lpfc_linkdown_tmo); + if(lpfc2_linkdown_tmo != -1) + value = (void *)((ulong)lpfc2_linkdown_tmo); + break; + case CFG_HOLDIO: /* nodev-holdio */ + value = (void *)((ulong)lpfc_nodev_holdio); + if(lpfc2_nodev_holdio != -1) + value = (void *)((ulong)lpfc2_nodev_holdio); + break; + case CFG_DELAY_RSP_ERR: /* delay-rsp-err */ + value = (void *)((ulong)lpfc_delay_rsp_err); + if(lpfc2_delay_rsp_err != -1) + value = (void *)((ulong)lpfc2_delay_rsp_err); + break; + case CFG_CHK_COND_ERR: /* check-cond-err */ + value = (void *)((ulong)lpfc_check_cond_err); + if(lpfc2_check_cond_err != -1) + value = (void *)((ulong)lpfc2_check_cond_err); + break; + case CFG_NODEV_TMO: /* nodev-tmo */ + value = (void *)((ulong)lpfc_nodev_tmo); + if(lpfc2_nodev_tmo != -1) + value = (void *)((ulong)lpfc2_nodev_tmo); + break; + case CFG_LINK_SPEED: /* link-speed */ + value = (void *)((ulong)lpfc_link_speed); + if(lpfc2_link_speed != -1) + value = (void *)((ulong)lpfc2_link_speed); + break; + case CFG_DQFULL_THROTTLE_UP_TIME: /* dqfull-throttle-up-time */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_time); + if(lpfc2_dqfull_throttle_up_time != -1) + value = (void *)((ulong)lpfc2_dqfull_throttle_up_time); + break; + case CFG_DQFULL_THROTTLE_UP_INC: /* dqfull-throttle-up-inc */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_inc); + if(lpfc2_dqfull_throttle_up_inc != -1) + value = (void *)((ulong)lpfc2_dqfull_throttle_up_inc); + break; + } + break; + case 3: /* HBA 3 */ + switch(param) { + case CFG_LOG_VERBOSE: /* log-verbose */ + value = (void *)((ulong)lpfc_log_verbose); + if(lpfc3_log_verbose != -1) + value = (void *)((ulong)lpfc3_log_verbose); + break; + case CFG_LOG_ONLY: /* log-only */ + value = (void *)((ulong)lpfc_log_only); + if(lpfc3_log_only != -1) + value = (void *)((ulong)lpfc3_log_only); + break; + case CFG_NUM_IOCBS: /* num-iocbs */ + value = (void *)((ulong)lpfc_num_iocbs); + if(lpfc3_num_iocbs != -1) + value = (void *)((ulong)lpfc3_num_iocbs); + break; + case CFG_NUM_BUFS: /* num-bufs */ + value = (void *)((ulong)lpfc_num_bufs); + if(lpfc3_num_bufs != -1) + value = (void *)((ulong)lpfc3_num_bufs); + break; + case CFG_AUTOMAP: /* automap */ + value = (void *)((ulong)lpfc_automap); + if(lpfc3_automap != -1) + value = (void *)((ulong)lpfc3_automap); + break; + case CFG_CR_DELAY: /* cr_delay */ + value = (void *)((ulong)lpfc_cr_delay); + if(lpfc3_cr_delay != -1) + value = (void *)((ulong)lpfc3_cr_delay); + break; + case CFG_CR_COUNT: /* cr_count */ + value = (void *)((ulong)lpfc_cr_count); + if(lpfc3_cr_count != -1) + value = (void *)((ulong)lpfc3_cr_count); + break; + case CFG_DFT_TGT_Q_DEPTH: /* tgt_queue_depth */ + value = (void *)((ulong)lpfc_tgt_queue_depth); + if(lpfc3_tgt_queue_depth != -1) + value = (void *)((ulong)lpfc3_tgt_queue_depth); + break; + case CFG_DFT_LUN_Q_DEPTH: /* lun_queue_depth */ + value = (void *)((ulong)lpfc_lun_queue_depth); + if(lpfc3_lun_queue_depth != -1) + value = (void *)((ulong)lpfc3_lun_queue_depth); + break; + case CFG_FCPFABRIC_TMO: /* fcpfabric-tmo */ + value = (void *)((ulong)lpfc_fcpfabric_tmo); + if(lpfc3_fcpfabric_tmo != -1) + value = (void *)((ulong)lpfc3_fcpfabric_tmo); + break; + case CFG_FCP_CLASS: /* fcp-class */ + value = (void *)((ulong)lpfc_fcp_class); + if(lpfc3_fcp_class != -1) + value = (void *)((ulong)lpfc3_fcp_class); + break; + case CFG_USE_ADISC: /* use-adisc */ + value = (void *)((ulong)lpfc_use_adisc); + if(lpfc3_use_adisc != -1) + value = (void *)((ulong)lpfc3_use_adisc); + break; + case CFG_NO_DEVICE_DELAY: /* no-device-delay */ + value = (void *)((ulong)lpfc_no_device_delay); + if(lpfc3_no_device_delay != -1) + value = (void *)((ulong)lpfc3_no_device_delay); + break; + case CFG_NETWORK_ON: /* network-on */ + value = (void *)((ulong)lpfc_network_on); + if(lpfc3_network_on != -1) + value = (void *)((ulong)lpfc3_network_on); + break; + case CFG_POST_IP_BUF: /* post-ip-buf */ + value = (void *)((ulong)lpfc_post_ip_buf); + if(lpfc3_post_ip_buf != -1) + value = (void *)((ulong)lpfc3_post_ip_buf); + break; + case CFG_XMT_Q_SIZE: /* xmt-que-size */ + value = (void *)((ulong)lpfc_xmt_que_size); + if(lpfc3_xmt_que_size != -1) + value = (void *)((ulong)lpfc3_xmt_que_size); + break; + case CFG_IP_CLASS: /* ip-class */ + value = (void *)((ulong)lpfc_ip_class); + if(lpfc3_ip_class != -1) + value = (void *)((ulong)lpfc3_ip_class); + break; + case CFG_ACK0: /* ack0 */ + value = (void *)((ulong)lpfc_ack0support); + if(lpfc3_ack0support != -1) + value = (void *)((ulong)lpfc3_ack0support); + break; + case CFG_TOPOLOGY: /* topology */ + value = (void *)((ulong)lpfc_topology); + if(lpfc3_topology != -1) + value = (void *)((ulong)lpfc3_topology); + break; + case CFG_SCAN_DOWN: /* scan-down */ + value = (void *)((ulong)lpfc_scandown); + if(lpfc3_scandown != -1) + value = (void *)((ulong)lpfc3_scandown); + break; + case CFG_LINKDOWN_TMO: /* linkdown-tmo */ + value = (void *)((ulong)lpfc_linkdown_tmo); + if(lpfc3_linkdown_tmo != -1) + value = (void *)((ulong)lpfc3_linkdown_tmo); + break; + case CFG_HOLDIO: /* nodev-holdio */ + value = (void *)((ulong)lpfc_nodev_holdio); + if(lpfc3_nodev_holdio != -1) + value = (void *)((ulong)lpfc3_nodev_holdio); + break; + case CFG_DELAY_RSP_ERR: /* delay-rsp-err */ + value = (void *)((ulong)lpfc_delay_rsp_err); + if(lpfc3_delay_rsp_err != -1) + value = (void *)((ulong)lpfc3_delay_rsp_err); + break; + case CFG_CHK_COND_ERR: /* check-cond-err */ + value = (void *)((ulong)lpfc_check_cond_err); + if(lpfc3_check_cond_err != -1) + value = (void *)((ulong)lpfc3_check_cond_err); + break; + case CFG_NODEV_TMO: /* nodev-tmo */ + value = (void *)((ulong)lpfc_nodev_tmo); + if(lpfc3_nodev_tmo != -1) + value = (void *)((ulong)lpfc3_nodev_tmo); + break; + case CFG_LINK_SPEED: /* link-speed */ + value = (void *)((ulong)lpfc_link_speed); + if(lpfc3_link_speed != -1) + value = (void *)((ulong)lpfc3_link_speed); + break; + case CFG_DQFULL_THROTTLE_UP_TIME: /* dqfull-throttle-up-time */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_time); + if(lpfc3_dqfull_throttle_up_time != -1) + value = (void *)((ulong)lpfc3_dqfull_throttle_up_time); + break; + case CFG_DQFULL_THROTTLE_UP_INC: /* dqfull-throttle-up-inc */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_inc); + if(lpfc3_dqfull_throttle_up_inc != -1) + value = (void *)((ulong)lpfc3_dqfull_throttle_up_inc); + break; + } + break; + case 4: /* HBA 4 */ + switch(param) { + case CFG_LOG_VERBOSE: /* log-verbose */ + value = (void *)((ulong)lpfc_log_verbose); + if(lpfc4_log_verbose != -1) + value = (void *)((ulong)lpfc4_log_verbose); + break; + case CFG_LOG_ONLY: /* log-only */ + value = (void *)((ulong)lpfc_log_only); + if(lpfc4_log_only != -1) + value = (void *)((ulong)lpfc4_log_only); + break; + case CFG_NUM_IOCBS: /* num-iocbs */ + value = (void *)((ulong)lpfc_num_iocbs); + if(lpfc4_num_iocbs != -1) + value = (void *)((ulong)lpfc4_num_iocbs); + break; + case CFG_NUM_BUFS: /* num-bufs */ + value = (void *)((ulong)lpfc_num_bufs); + if(lpfc4_num_bufs != -1) + value = (void *)((ulong)lpfc4_num_bufs); + break; + case CFG_AUTOMAP: /* automap */ + value = (void *)((ulong)lpfc_automap); + if(lpfc4_automap != -1) + value = (void *)((ulong)lpfc4_automap); + break; + case CFG_CR_DELAY: /* cr_delay */ + value = (void *)((ulong)lpfc_cr_delay); + if(lpfc4_cr_delay != -1) + value = (void *)((ulong)lpfc4_cr_delay); + break; + case CFG_CR_COUNT: /* cr_count */ + value = (void *)((ulong)lpfc_cr_count); + if(lpfc4_cr_count != -1) + value = (void *)((ulong)lpfc4_cr_count); + break; + case CFG_DFT_TGT_Q_DEPTH: /* tgt_queue_depth */ + value = (void *)((ulong)lpfc_tgt_queue_depth); + if(lpfc4_tgt_queue_depth != -1) + value = (void *)((ulong)lpfc4_tgt_queue_depth); + break; + case CFG_DFT_LUN_Q_DEPTH: /* lun_queue_depth */ + value = (void *)((ulong)lpfc_lun_queue_depth); + if(lpfc4_lun_queue_depth != -1) + value = (void *)((ulong)lpfc4_lun_queue_depth); + break; + case CFG_FCPFABRIC_TMO: /* fcpfabric-tmo */ + value = (void *)((ulong)lpfc_fcpfabric_tmo); + if(lpfc4_fcpfabric_tmo != -1) + value = (void *)((ulong)lpfc4_fcpfabric_tmo); + break; + case CFG_FCP_CLASS: /* fcp-class */ + value = (void *)((ulong)lpfc_fcp_class); + if(lpfc4_fcp_class != -1) + value = (void *)((ulong)lpfc4_fcp_class); + break; + case CFG_USE_ADISC: /* use-adisc */ + value = (void *)((ulong)lpfc_use_adisc); + if(lpfc4_use_adisc != -1) + value = (void *)((ulong)lpfc4_use_adisc); + break; + case CFG_NO_DEVICE_DELAY: /* no-device-delay */ + value = (void *)((ulong)lpfc_no_device_delay); + if(lpfc4_no_device_delay != -1) + value = (void *)((ulong)lpfc4_no_device_delay); + break; + case CFG_NETWORK_ON: /* network-on */ + value = (void *)((ulong)lpfc_network_on); + if(lpfc4_network_on != -1) + value = (void *)((ulong)lpfc4_network_on); + break; + case CFG_POST_IP_BUF: /* post-ip-buf */ + value = (void *)((ulong)lpfc_post_ip_buf); + if(lpfc4_post_ip_buf != -1) + value = (void *)((ulong)lpfc4_post_ip_buf); + break; + case CFG_XMT_Q_SIZE: /* xmt-que-size */ + value = (void *)((ulong)lpfc_xmt_que_size); + if(lpfc4_xmt_que_size != -1) + value = (void *)((ulong)lpfc4_xmt_que_size); + break; + case CFG_IP_CLASS: /* ip-class */ + value = (void *)((ulong)lpfc_ip_class); + if(lpfc4_ip_class != -1) + value = (void *)((ulong)lpfc4_ip_class); + break; + case CFG_ACK0: /* ack0 */ + value = (void *)((ulong)lpfc_ack0support); + if(lpfc4_ack0support != -1) + value = (void *)((ulong)lpfc4_ack0support); + break; + case CFG_TOPOLOGY: /* topology */ + value = (void *)((ulong)lpfc_topology); + if(lpfc4_topology != -1) + value = (void *)((ulong)lpfc4_topology); + break; + case CFG_SCAN_DOWN: /* scan-down */ + value = (void *)((ulong)lpfc_scandown); + if(lpfc4_scandown != -1) + value = (void *)((ulong)lpfc4_scandown); + break; + case CFG_LINKDOWN_TMO: /* linkdown-tmo */ + value = (void *)((ulong)lpfc_linkdown_tmo); + if(lpfc4_linkdown_tmo != -1) + value = (void *)((ulong)lpfc4_linkdown_tmo); + break; + case CFG_HOLDIO: /* nodev-holdio */ + value = (void *)((ulong)lpfc_nodev_holdio); + if(lpfc4_nodev_holdio != -1) + value = (void *)((ulong)lpfc4_nodev_holdio); + break; + case CFG_DELAY_RSP_ERR: /* delay-rsp-err */ + value = (void *)((ulong)lpfc_delay_rsp_err); + if(lpfc4_delay_rsp_err != -1) + value = (void *)((ulong)lpfc4_delay_rsp_err); + break; + case CFG_CHK_COND_ERR: /* check-cond-err */ + value = (void *)((ulong)lpfc_check_cond_err); + if(lpfc4_check_cond_err != -1) + value = (void *)((ulong)lpfc4_check_cond_err); + break; + case CFG_NODEV_TMO: /* nodev-tmo */ + value = (void *)((ulong)lpfc_nodev_tmo); + if(lpfc4_nodev_tmo != -1) + value = (void *)((ulong)lpfc4_nodev_tmo); + break; + case CFG_LINK_SPEED: /* link-speed */ + value = (void *)((ulong)lpfc_link_speed); + if(lpfc4_link_speed != -1) + value = (void *)((ulong)lpfc4_link_speed); + break; + case CFG_DQFULL_THROTTLE_UP_TIME: /* dqfull-throttle-up-time */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_time); + if(lpfc4_dqfull_throttle_up_time != -1) + value = (void *)((ulong)lpfc4_dqfull_throttle_up_time); + break; + case CFG_DQFULL_THROTTLE_UP_INC: /* dqfull-throttle-up-inc */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_inc); + if(lpfc4_dqfull_throttle_up_inc != -1) + value = (void *)((ulong)lpfc4_dqfull_throttle_up_inc); + break; + } + break; + case 5: /* HBA 5 */ + switch(param) { + case CFG_LOG_VERBOSE: /* log-verbose */ + value = (void *)((ulong)lpfc_log_verbose); + if(lpfc5_log_verbose != -1) + value = (void *)((ulong)lpfc5_log_verbose); + break; + case CFG_LOG_ONLY: /* log-only */ + value = (void *)((ulong)lpfc_log_only); + if(lpfc5_log_only != -1) + value = (void *)((ulong)lpfc5_log_only); + break; + case CFG_NUM_IOCBS: /* num-iocbs */ + value = (void *)((ulong)lpfc_num_iocbs); + if(lpfc5_num_iocbs != -1) + value = (void *)((ulong)lpfc5_num_iocbs); + break; + case CFG_NUM_BUFS: /* num-bufs */ + value = (void *)((ulong)lpfc_num_bufs); + if(lpfc5_num_bufs != -1) + value = (void *)((ulong)lpfc5_num_bufs); + break; + case CFG_AUTOMAP: /* automap */ + value = (void *)((ulong)lpfc_automap); + if(lpfc5_automap != -1) + value = (void *)((ulong)lpfc5_automap); + break; + case CFG_CR_DELAY: /* cr_delay */ + value = (void *)((ulong)lpfc_cr_delay); + if(lpfc5_cr_delay != -1) + value = (void *)((ulong)lpfc5_cr_delay); + break; + case CFG_CR_COUNT: /* cr_count */ + value = (void *)((ulong)lpfc_cr_count); + if(lpfc5_cr_count != -1) + value = (void *)((ulong)lpfc5_cr_count); + break; + case CFG_DFT_TGT_Q_DEPTH: /* tgt_queue_depth */ + value = (void *)((ulong)lpfc_tgt_queue_depth); + if(lpfc5_tgt_queue_depth != -1) + value = (void *)((ulong)lpfc5_tgt_queue_depth); + break; + case CFG_DFT_LUN_Q_DEPTH: /* lun_queue_depth */ + value = (void *)((ulong)lpfc_lun_queue_depth); + if(lpfc5_lun_queue_depth != -1) + value = (void *)((ulong)lpfc5_lun_queue_depth); + break; + case CFG_FCPFABRIC_TMO: /* fcpfabric-tmo */ + value = (void *)((ulong)lpfc_fcpfabric_tmo); + if(lpfc5_fcpfabric_tmo != -1) + value = (void *)((ulong)lpfc5_fcpfabric_tmo); + break; + case CFG_FCP_CLASS: /* fcp-class */ + value = (void *)((ulong)lpfc_fcp_class); + if(lpfc5_fcp_class != -1) + value = (void *)((ulong)lpfc5_fcp_class); + break; + case CFG_USE_ADISC: /* use-adisc */ + value = (void *)((ulong)lpfc_use_adisc); + if(lpfc5_use_adisc != -1) + value = (void *)((ulong)lpfc5_use_adisc); + break; + case CFG_NO_DEVICE_DELAY: /* no-device-delay */ + value = (void *)((ulong)lpfc_no_device_delay); + if(lpfc5_no_device_delay != -1) + value = (void *)((ulong)lpfc5_no_device_delay); + break; + case CFG_NETWORK_ON: /* network-on */ + value = (void *)((ulong)lpfc_network_on); + if(lpfc5_network_on != -1) + value = (void *)((ulong)lpfc5_network_on); + break; + case CFG_POST_IP_BUF: /* post-ip-buf */ + value = (void *)((ulong)lpfc_post_ip_buf); + if(lpfc5_post_ip_buf != -1) + value = (void *)((ulong)lpfc5_post_ip_buf); + break; + case CFG_XMT_Q_SIZE: /* xmt-que-size */ + value = (void *)((ulong)lpfc_xmt_que_size); + if(lpfc5_xmt_que_size != -1) + value = (void *)((ulong)lpfc5_xmt_que_size); + break; + case CFG_IP_CLASS: /* ip-class */ + value = (void *)((ulong)lpfc_ip_class); + if(lpfc5_ip_class != -1) + value = (void *)((ulong)lpfc5_ip_class); + break; + case CFG_ACK0: /* ack0 */ + value = (void *)((ulong)lpfc_ack0support); + if(lpfc5_ack0support != -1) + value = (void *)((ulong)lpfc5_ack0support); + break; + case CFG_TOPOLOGY: /* topology */ + value = (void *)((ulong)lpfc_topology); + if(lpfc5_topology != -1) + value = (void *)((ulong)lpfc5_topology); + break; + case CFG_SCAN_DOWN: /* scan-down */ + value = (void *)((ulong)lpfc_scandown); + if(lpfc5_scandown != -1) + value = (void *)((ulong)lpfc5_scandown); + break; + case CFG_LINKDOWN_TMO: /* linkdown-tmo */ + value = (void *)((ulong)lpfc_linkdown_tmo); + if(lpfc5_linkdown_tmo != -1) + value = (void *)((ulong)lpfc5_linkdown_tmo); + break; + case CFG_HOLDIO: /* nodev-holdio */ + value = (void *)((ulong)lpfc_nodev_holdio); + if(lpfc5_nodev_holdio != -1) + value = (void *)((ulong)lpfc5_nodev_holdio); + break; + case CFG_DELAY_RSP_ERR: /* delay-rsp-err */ + value = (void *)((ulong)lpfc_delay_rsp_err); + if(lpfc5_delay_rsp_err != -1) + value = (void *)((ulong)lpfc5_delay_rsp_err); + break; + case CFG_CHK_COND_ERR: /* check-cond-err */ + value = (void *)((ulong)lpfc_check_cond_err); + if(lpfc5_check_cond_err != -1) + value = (void *)((ulong)lpfc5_check_cond_err); + break; + case CFG_NODEV_TMO: /* nodev-tmo */ + value = (void *)((ulong)lpfc_nodev_tmo); + if(lpfc5_nodev_tmo != -1) + value = (void *)((ulong)lpfc5_nodev_tmo); + break; + case CFG_LINK_SPEED: /* link-speed */ + value = (void *)((ulong)lpfc_link_speed); + if(lpfc5_link_speed != -1) + value = (void *)((ulong)lpfc5_link_speed); + break; + case CFG_DQFULL_THROTTLE_UP_TIME: /* dqfull-throttle-up-time */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_time); + if(lpfc5_dqfull_throttle_up_time != -1) + value = (void *)((ulong)lpfc5_dqfull_throttle_up_time); + break; + case CFG_DQFULL_THROTTLE_UP_INC: /* dqfull-throttle-up-inc */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_inc); + if(lpfc5_dqfull_throttle_up_inc != -1) + value = (void *)((ulong)lpfc5_dqfull_throttle_up_inc); + break; + } + break; + case 6: /* HBA 6 */ + switch(param) { + case CFG_LOG_VERBOSE: /* log-verbose */ + value = (void *)((ulong)lpfc_log_verbose); + if(lpfc6_log_verbose != -1) + value = (void *)((ulong)lpfc6_log_verbose); + break; + case CFG_LOG_ONLY: /* log-only */ + value = (void *)((ulong)lpfc_log_only); + if(lpfc6_log_only != -1) + value = (void *)((ulong)lpfc6_log_only); + break; + case CFG_NUM_IOCBS: /* num-iocbs */ + value = (void *)((ulong)lpfc_num_iocbs); + if(lpfc6_num_iocbs != -1) + value = (void *)((ulong)lpfc6_num_iocbs); + break; + case CFG_NUM_BUFS: /* num-bufs */ + value = (void *)((ulong)lpfc_num_bufs); + if(lpfc6_num_bufs != -1) + value = (void *)((ulong)lpfc6_num_bufs); + break; + case CFG_AUTOMAP: /* automap */ + value = (void *)((ulong)lpfc_automap); + if(lpfc6_automap != -1) + value = (void *)((ulong)lpfc6_automap); + break; + case CFG_CR_DELAY: /* cr_delay */ + value = (void *)((ulong)lpfc_cr_delay); + if(lpfc6_cr_delay != -1) + value = (void *)((ulong)lpfc6_cr_delay); + break; + case CFG_CR_COUNT: /* cr_count */ + value = (void *)((ulong)lpfc_cr_count); + if(lpfc6_cr_count != -1) + value = (void *)((ulong)lpfc6_cr_count); + break; + case CFG_DFT_TGT_Q_DEPTH: /* tgt_queue_depth */ + value = (void *)((ulong)lpfc_tgt_queue_depth); + if(lpfc6_tgt_queue_depth != -1) + value = (void *)((ulong)lpfc6_tgt_queue_depth); + break; + case CFG_DFT_LUN_Q_DEPTH: /* lun_queue_depth */ + value = (void *)((ulong)lpfc_lun_queue_depth); + if(lpfc6_lun_queue_depth != -1) + value = (void *)((ulong)lpfc6_lun_queue_depth); + break; + case CFG_FCPFABRIC_TMO: /* fcpfabric-tmo */ + value = (void *)((ulong)lpfc_fcpfabric_tmo); + if(lpfc6_fcpfabric_tmo != -1) + value = (void *)((ulong)lpfc6_fcpfabric_tmo); + break; + case CFG_FCP_CLASS: /* fcp-class */ + value = (void *)((ulong)lpfc_fcp_class); + if(lpfc6_fcp_class != -1) + value = (void *)((ulong)lpfc6_fcp_class); + break; + case CFG_USE_ADISC: /* use-adisc */ + value = (void *)((ulong)lpfc_use_adisc); + if(lpfc6_use_adisc != -1) + value = (void *)((ulong)lpfc6_use_adisc); + break; + case CFG_NO_DEVICE_DELAY: /* no-device-delay */ + value = (void *)((ulong)lpfc_no_device_delay); + if(lpfc6_no_device_delay != -1) + value = (void *)((ulong)lpfc6_no_device_delay); + break; + case CFG_NETWORK_ON: /* network-on */ + value = (void *)((ulong)lpfc_network_on); + if(lpfc6_network_on != -1) + value = (void *)((ulong)lpfc6_network_on); + break; + case CFG_POST_IP_BUF: /* post-ip-buf */ + value = (void *)((ulong)lpfc_post_ip_buf); + if(lpfc6_post_ip_buf != -1) + value = (void *)((ulong)lpfc6_post_ip_buf); + break; + case CFG_XMT_Q_SIZE: /* xmt-que-size */ + value = (void *)((ulong)lpfc_xmt_que_size); + if(lpfc6_xmt_que_size != -1) + value = (void *)((ulong)lpfc6_xmt_que_size); + break; + case CFG_IP_CLASS: /* ip-class */ + value = (void *)((ulong)lpfc_ip_class); + if(lpfc6_ip_class != -1) + value = (void *)((ulong)lpfc6_ip_class); + break; + case CFG_ACK0: /* ack0 */ + value = (void *)((ulong)lpfc_ack0support); + if(lpfc6_ack0support != -1) + value = (void *)((ulong)lpfc6_ack0support); + break; + case CFG_TOPOLOGY: /* topology */ + value = (void *)((ulong)lpfc_topology); + if(lpfc6_topology != -1) + value = (void *)((ulong)lpfc6_topology); + break; + case CFG_SCAN_DOWN: /* scan-down */ + value = (void *)((ulong)lpfc_scandown); + if(lpfc6_scandown != -1) + value = (void *)((ulong)lpfc6_scandown); + break; + case CFG_LINKDOWN_TMO: /* linkdown-tmo */ + value = (void *)((ulong)lpfc_linkdown_tmo); + if(lpfc6_linkdown_tmo != -1) + value = (void *)((ulong)lpfc6_linkdown_tmo); + break; + case CFG_HOLDIO: /* nodev-holdio */ + value = (void *)((ulong)lpfc_nodev_holdio); + if(lpfc6_nodev_holdio != -1) + value = (void *)((ulong)lpfc6_nodev_holdio); + break; + case CFG_DELAY_RSP_ERR: /* delay-rsp-err */ + value = (void *)((ulong)lpfc_delay_rsp_err); + if(lpfc6_delay_rsp_err != -1) + value = (void *)((ulong)lpfc6_delay_rsp_err); + break; + case CFG_CHK_COND_ERR: /* check-cond-err */ + value = (void *)((ulong)lpfc_check_cond_err); + if(lpfc6_check_cond_err != -1) + value = (void *)((ulong)lpfc6_check_cond_err); + break; + case CFG_NODEV_TMO: /* nodev-tmo */ + value = (void *)((ulong)lpfc_nodev_tmo); + if(lpfc6_nodev_tmo != -1) + value = (void *)((ulong)lpfc6_nodev_tmo); + break; + case CFG_LINK_SPEED: /* link-speed */ + value = (void *)((ulong)lpfc_link_speed); + if(lpfc6_link_speed != -1) + value = (void *)((ulong)lpfc6_link_speed); + break; + case CFG_DQFULL_THROTTLE_UP_TIME: /* dqfull-throttle-up-time */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_time); + if(lpfc6_dqfull_throttle_up_time != -1) + value = (void *)((ulong)lpfc6_dqfull_throttle_up_time); + break; + case CFG_DQFULL_THROTTLE_UP_INC: /* dqfull-throttle-up-inc */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_inc); + if(lpfc6_dqfull_throttle_up_inc != -1) + value = (void *)((ulong)lpfc6_dqfull_throttle_up_inc); + break; + } + break; + case 7: /* HBA 7 */ + switch(param) { + case CFG_LOG_VERBOSE: /* log-verbose */ + value = (void *)((ulong)lpfc_log_verbose); + if(lpfc7_log_verbose != -1) + value = (void *)((ulong)lpfc7_log_verbose); + break; + case CFG_LOG_ONLY: /* log-only */ + value = (void *)((ulong)lpfc_log_only); + if(lpfc7_log_only != -1) + value = (void *)((ulong)lpfc7_log_only); + break; + case CFG_NUM_IOCBS: /* num-iocbs */ + value = (void *)((ulong)lpfc_num_iocbs); + if(lpfc7_num_iocbs != -1) + value = (void *)((ulong)lpfc7_num_iocbs); + break; + case CFG_NUM_BUFS: /* num-bufs */ + value = (void *)((ulong)lpfc_num_bufs); + if(lpfc7_num_bufs != -1) + value = (void *)((ulong)lpfc7_num_bufs); + break; + case CFG_AUTOMAP: /* automap */ + value = (void *)((ulong)lpfc_automap); + if(lpfc7_automap != -1) + value = (void *)((ulong)lpfc7_automap); + break; + case CFG_CR_DELAY: /* cr_delay */ + value = (void *)((ulong)lpfc_cr_delay); + if(lpfc7_cr_delay != -1) + value = (void *)((ulong)lpfc7_cr_delay); + break; + case CFG_CR_COUNT: /* cr_count */ + value = (void *)((ulong)lpfc_cr_count); + if(lpfc7_cr_count != -1) + value = (void *)((ulong)lpfc7_cr_count); + break; + case CFG_DFT_TGT_Q_DEPTH: /* tgt_queue_depth */ + value = (void *)((ulong)lpfc_tgt_queue_depth); + if(lpfc7_tgt_queue_depth != -1) + value = (void *)((ulong)lpfc7_tgt_queue_depth); + break; + case CFG_DFT_LUN_Q_DEPTH: /* lun_queue_depth */ + value = (void *)((ulong)lpfc_lun_queue_depth); + if(lpfc7_lun_queue_depth != -1) + value = (void *)((ulong)lpfc7_lun_queue_depth); + break; + case CFG_FCPFABRIC_TMO: /* fcpfabric-tmo */ + value = (void *)((ulong)lpfc_fcpfabric_tmo); + if(lpfc7_fcpfabric_tmo != -1) + value = (void *)((ulong)lpfc7_fcpfabric_tmo); + break; + case CFG_FCP_CLASS: /* fcp-class */ + value = (void *)((ulong)lpfc_fcp_class); + if(lpfc7_fcp_class != -1) + value = (void *)((ulong)lpfc7_fcp_class); + break; + case CFG_USE_ADISC: /* use-adisc */ + value = (void *)((ulong)lpfc_use_adisc); + if(lpfc7_use_adisc != -1) + value = (void *)((ulong)lpfc7_use_adisc); + break; + case CFG_NO_DEVICE_DELAY: /* no-device-delay */ + value = (void *)((ulong)lpfc_no_device_delay); + if(lpfc7_no_device_delay != -1) + value = (void *)((ulong)lpfc7_no_device_delay); + break; + case CFG_NETWORK_ON: /* network-on */ + value = (void *)((ulong)lpfc_network_on); + if(lpfc7_network_on != -1) + value = (void *)((ulong)lpfc7_network_on); + break; + case CFG_POST_IP_BUF: /* post-ip-buf */ + value = (void *)((ulong)lpfc_post_ip_buf); + if(lpfc7_post_ip_buf != -1) + value = (void *)((ulong)lpfc7_post_ip_buf); + break; + case CFG_XMT_Q_SIZE: /* xmt-que-size */ + value = (void *)((ulong)lpfc_xmt_que_size); + if(lpfc7_xmt_que_size != -1) + value = (void *)((ulong)lpfc7_xmt_que_size); + break; + case CFG_IP_CLASS: /* ip-class */ + value = (void *)((ulong)lpfc_ip_class); + if(lpfc7_ip_class != -1) + value = (void *)((ulong)lpfc7_ip_class); + break; + case CFG_ACK0: /* ack0 */ + value = (void *)((ulong)lpfc_ack0support); + if(lpfc7_ack0support != -1) + value = (void *)((ulong)lpfc7_ack0support); + break; + case CFG_TOPOLOGY: /* topology */ + value = (void *)((ulong)lpfc_topology); + if(lpfc7_topology != -1) + value = (void *)((ulong)lpfc7_topology); + break; + case CFG_SCAN_DOWN: /* scan-down */ + value = (void *)((ulong)lpfc_scandown); + if(lpfc7_scandown != -1) + value = (void *)((ulong)lpfc7_scandown); + break; + case CFG_LINKDOWN_TMO: /* linkdown-tmo */ + value = (void *)((ulong)lpfc_linkdown_tmo); + if(lpfc7_linkdown_tmo != -1) + value = (void *)((ulong)lpfc7_linkdown_tmo); + break; + case CFG_HOLDIO: /* nodev-holdio */ + value = (void *)((ulong)lpfc_nodev_holdio); + if(lpfc7_nodev_holdio != -1) + value = (void *)((ulong)lpfc7_nodev_holdio); + break; + case CFG_DELAY_RSP_ERR: /* delay-rsp-err */ + value = (void *)((ulong)lpfc_delay_rsp_err); + if(lpfc7_delay_rsp_err != -1) + value = (void *)((ulong)lpfc7_delay_rsp_err); + break; + case CFG_CHK_COND_ERR: /* check-cond-err */ + value = (void *)((ulong)lpfc_check_cond_err); + if(lpfc7_check_cond_err != -1) + value = (void *)((ulong)lpfc7_check_cond_err); + break; + case CFG_NODEV_TMO: /* nodev-tmo */ + value = (void *)((ulong)lpfc_nodev_tmo); + if(lpfc7_nodev_tmo != -1) + value = (void *)((ulong)lpfc7_nodev_tmo); + break; + case CFG_LINK_SPEED: /* link-speed */ + value = (void *)((ulong)lpfc_link_speed); + if(lpfc7_link_speed != -1) + value = (void *)((ulong)lpfc7_link_speed); + break; + case CFG_DQFULL_THROTTLE_UP_TIME: /* dqfull-throttle-up-time */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_time); + if(lpfc7_dqfull_throttle_up_time != -1) + value = (void *)((ulong)lpfc7_dqfull_throttle_up_time); + break; + case CFG_DQFULL_THROTTLE_UP_INC: /* dqfull-throttle-up-inc */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_inc); + if(lpfc7_dqfull_throttle_up_inc != -1) + value = (void *)((ulong)lpfc7_dqfull_throttle_up_inc); + break; + } + break; + case 8: /* HBA 8 */ + switch(param) { + case CFG_LOG_VERBOSE: /* log-verbose */ + value = (void *)((ulong)lpfc_log_verbose); + if(lpfc8_log_verbose != -1) + value = (void *)((ulong)lpfc8_log_verbose); + break; + case CFG_LOG_ONLY: /* log-only */ + value = (void *)((ulong)lpfc_log_only); + if(lpfc8_log_only != -1) + value = (void *)((ulong)lpfc8_log_only); + break; + case CFG_NUM_IOCBS: /* num-iocbs */ + value = (void *)((ulong)lpfc_num_iocbs); + if(lpfc8_num_iocbs != -1) + value = (void *)((ulong)lpfc8_num_iocbs); + break; + case CFG_NUM_BUFS: /* num-bufs */ + value = (void *)((ulong)lpfc_num_bufs); + if(lpfc8_num_bufs != -1) + value = (void *)((ulong)lpfc8_num_bufs); + break; + case CFG_AUTOMAP: /* automap */ + value = (void *)((ulong)lpfc_automap); + if(lpfc8_automap != -1) + value = (void *)((ulong)lpfc8_automap); + break; + case CFG_CR_DELAY: /* cr_delay */ + value = (void *)((ulong)lpfc_cr_delay); + if(lpfc8_cr_delay != -1) + value = (void *)((ulong)lpfc8_cr_delay); + break; + case CFG_CR_COUNT: /* cr_count */ + value = (void *)((ulong)lpfc_cr_count); + if(lpfc8_cr_count != -1) + value = (void *)((ulong)lpfc8_cr_count); + break; + case CFG_DFT_TGT_Q_DEPTH: /* tgt_queue_depth */ + value = (void *)((ulong)lpfc_tgt_queue_depth); + if(lpfc8_tgt_queue_depth != -1) + value = (void *)((ulong)lpfc8_tgt_queue_depth); + break; + case CFG_DFT_LUN_Q_DEPTH: /* lun_queue_depth */ + value = (void *)((ulong)lpfc_lun_queue_depth); + if(lpfc8_lun_queue_depth != -1) + value = (void *)((ulong)lpfc8_lun_queue_depth); + break; + case CFG_FCPFABRIC_TMO: /* fcpfabric-tmo */ + value = (void *)((ulong)lpfc_fcpfabric_tmo); + if(lpfc8_fcpfabric_tmo != -1) + value = (void *)((ulong)lpfc8_fcpfabric_tmo); + break; + case CFG_FCP_CLASS: /* fcp-class */ + value = (void *)((ulong)lpfc_fcp_class); + if(lpfc8_fcp_class != -1) + value = (void *)((ulong)lpfc8_fcp_class); + break; + case CFG_USE_ADISC: /* use-adisc */ + value = (void *)((ulong)lpfc_use_adisc); + if(lpfc8_use_adisc != -1) + value = (void *)((ulong)lpfc8_use_adisc); + break; + case CFG_NO_DEVICE_DELAY: /* no-device-delay */ + value = (void *)((ulong)lpfc_no_device_delay); + if(lpfc8_no_device_delay != -1) + value = (void *)((ulong)lpfc8_no_device_delay); + break; + case CFG_NETWORK_ON: /* network-on */ + value = (void *)((ulong)lpfc_network_on); + if(lpfc8_network_on != -1) + value = (void *)((ulong)lpfc8_network_on); + break; + case CFG_POST_IP_BUF: /* post-ip-buf */ + value = (void *)((ulong)lpfc_post_ip_buf); + if(lpfc8_post_ip_buf != -1) + value = (void *)((ulong)lpfc8_post_ip_buf); + break; + case CFG_XMT_Q_SIZE: /* xmt-que-size */ + value = (void *)((ulong)lpfc_xmt_que_size); + if(lpfc8_xmt_que_size != -1) + value = (void *)((ulong)lpfc8_xmt_que_size); + break; + case CFG_IP_CLASS: /* ip-class */ + value = (void *)((ulong)lpfc_ip_class); + if(lpfc8_ip_class != -1) + value = (void *)((ulong)lpfc8_ip_class); + break; + case CFG_ACK0: /* ack0 */ + value = (void *)((ulong)lpfc_ack0support); + if(lpfc8_ack0support != -1) + value = (void *)((ulong)lpfc8_ack0support); + break; + case CFG_TOPOLOGY: /* topology */ + value = (void *)((ulong)lpfc_topology); + if(lpfc8_topology != -1) + value = (void *)((ulong)lpfc8_topology); + break; + case CFG_SCAN_DOWN: /* scan-down */ + value = (void *)((ulong)lpfc_scandown); + if(lpfc8_scandown != -1) + value = (void *)((ulong)lpfc8_scandown); + break; + case CFG_LINKDOWN_TMO: /* linkdown-tmo */ + value = (void *)((ulong)lpfc_linkdown_tmo); + if(lpfc8_linkdown_tmo != -1) + value = (void *)((ulong)lpfc8_linkdown_tmo); + break; + case CFG_HOLDIO: /* nodev-holdio */ + value = (void *)((ulong)lpfc_nodev_holdio); + if(lpfc8_nodev_holdio != -1) + value = (void *)((ulong)lpfc8_nodev_holdio); + break; + case CFG_DELAY_RSP_ERR: /* delay-rsp-err */ + value = (void *)((ulong)lpfc_delay_rsp_err); + if(lpfc8_delay_rsp_err != -1) + value = (void *)((ulong)lpfc8_delay_rsp_err); + break; + case CFG_CHK_COND_ERR: /* check-cond-err */ + value = (void *)((ulong)lpfc_check_cond_err); + if(lpfc8_check_cond_err != -1) + value = (void *)((ulong)lpfc8_check_cond_err); + break; + case CFG_NODEV_TMO: /* nodev-tmo */ + value = (void *)((ulong)lpfc_nodev_tmo); + if(lpfc8_nodev_tmo != -1) + value = (void *)((ulong)lpfc8_nodev_tmo); + break; + case CFG_LINK_SPEED: /* link-speed */ + value = (void *)((ulong)lpfc_link_speed); + if(lpfc8_link_speed != -1) + value = (void *)((ulong)lpfc8_link_speed); + break; + case CFG_DQFULL_THROTTLE_UP_TIME: /* dqfull-throttle-up-time */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_time); + if(lpfc8_dqfull_throttle_up_time != -1) + value = (void *)((ulong)lpfc8_dqfull_throttle_up_time); + break; + case CFG_DQFULL_THROTTLE_UP_INC: /* dqfull-throttle-up-inc */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_inc); + if(lpfc8_dqfull_throttle_up_inc != -1) + value = (void *)((ulong)lpfc8_dqfull_throttle_up_inc); + break; + } + break; + case 9: /* HBA 9 */ + switch(param) { + case CFG_LOG_VERBOSE: /* log-verbose */ + value = (void *)((ulong)lpfc_log_verbose); + if(lpfc9_log_verbose != -1) + value = (void *)((ulong)lpfc9_log_verbose); + break; + case CFG_LOG_ONLY: /* log-only */ + value = (void *)((ulong)lpfc_log_only); + if(lpfc9_log_only != -1) + value = (void *)((ulong)lpfc9_log_only); + break; + case CFG_NUM_IOCBS: /* num-iocbs */ + value = (void *)((ulong)lpfc_num_iocbs); + if(lpfc9_num_iocbs != -1) + value = (void *)((ulong)lpfc9_num_iocbs); + break; + case CFG_NUM_BUFS: /* num-bufs */ + value = (void *)((ulong)lpfc_num_bufs); + if(lpfc9_num_bufs != -1) + value = (void *)((ulong)lpfc9_num_bufs); + break; + case CFG_AUTOMAP: /* automap */ + value = (void *)((ulong)lpfc_automap); + if(lpfc9_automap != -1) + value = (void *)((ulong)lpfc9_automap); + break; + case CFG_CR_DELAY: /* cr_delay */ + value = (void *)((ulong)lpfc_cr_delay); + if(lpfc9_cr_delay != -1) + value = (void *)((ulong)lpfc9_cr_delay); + break; + case CFG_CR_COUNT: /* cr_count */ + value = (void *)((ulong)lpfc_cr_count); + if(lpfc9_cr_count != -1) + value = (void *)((ulong)lpfc9_cr_count); + break; + case CFG_DFT_TGT_Q_DEPTH: /* tgt_queue_depth */ + value = (void *)((ulong)lpfc_tgt_queue_depth); + if(lpfc9_tgt_queue_depth != -1) + value = (void *)((ulong)lpfc9_tgt_queue_depth); + break; + case CFG_DFT_LUN_Q_DEPTH: /* lun_queue_depth */ + value = (void *)((ulong)lpfc_lun_queue_depth); + if(lpfc9_lun_queue_depth != -1) + value = (void *)((ulong)lpfc9_lun_queue_depth); + break; + case CFG_FCPFABRIC_TMO: /* fcpfabric-tmo */ + value = (void *)((ulong)lpfc_fcpfabric_tmo); + if(lpfc9_fcpfabric_tmo != -1) + value = (void *)((ulong)lpfc9_fcpfabric_tmo); + break; + case CFG_FCP_CLASS: /* fcp-class */ + value = (void *)((ulong)lpfc_fcp_class); + if(lpfc9_fcp_class != -1) + value = (void *)((ulong)lpfc9_fcp_class); + break; + case CFG_USE_ADISC: /* use-adisc */ + value = (void *)((ulong)lpfc_use_adisc); + if(lpfc9_use_adisc != -1) + value = (void *)((ulong)lpfc9_use_adisc); + break; + case CFG_NO_DEVICE_DELAY: /* no-device-delay */ + value = (void *)((ulong)lpfc_no_device_delay); + if(lpfc9_no_device_delay != -1) + value = (void *)((ulong)lpfc9_no_device_delay); + break; + case CFG_NETWORK_ON: /* network-on */ + value = (void *)((ulong)lpfc_network_on); + if(lpfc9_network_on != -1) + value = (void *)((ulong)lpfc9_network_on); + break; + case CFG_POST_IP_BUF: /* post-ip-buf */ + value = (void *)((ulong)lpfc_post_ip_buf); + if(lpfc9_post_ip_buf != -1) + value = (void *)((ulong)lpfc9_post_ip_buf); + break; + case CFG_XMT_Q_SIZE: /* xmt-que-size */ + value = (void *)((ulong)lpfc_xmt_que_size); + if(lpfc9_xmt_que_size != -1) + value = (void *)((ulong)lpfc9_xmt_que_size); + break; + case CFG_IP_CLASS: /* ip-class */ + value = (void *)((ulong)lpfc_ip_class); + if(lpfc9_ip_class != -1) + value = (void *)((ulong)lpfc9_ip_class); + break; + case CFG_ACK0: /* ack0 */ + value = (void *)((ulong)lpfc_ack0support); + if(lpfc9_ack0support != -1) + value = (void *)((ulong)lpfc9_ack0support); + break; + case CFG_TOPOLOGY: /* topology */ + value = (void *)((ulong)lpfc_topology); + if(lpfc9_topology != -1) + value = (void *)((ulong)lpfc9_topology); + break; + case CFG_SCAN_DOWN: /* scan-down */ + value = (void *)((ulong)lpfc_scandown); + if(lpfc9_scandown != -1) + value = (void *)((ulong)lpfc9_scandown); + break; + case CFG_LINKDOWN_TMO: /* linkdown-tmo */ + value = (void *)((ulong)lpfc_linkdown_tmo); + if(lpfc9_linkdown_tmo != -1) + value = (void *)((ulong)lpfc9_linkdown_tmo); + break; + case CFG_HOLDIO: /* nodev-holdio */ + value = (void *)((ulong)lpfc_nodev_holdio); + if(lpfc9_nodev_holdio != -1) + value = (void *)((ulong)lpfc9_nodev_holdio); + break; + case CFG_DELAY_RSP_ERR: /* delay-rsp-err */ + value = (void *)((ulong)lpfc_delay_rsp_err); + if(lpfc9_delay_rsp_err != -1) + value = (void *)((ulong)lpfc9_delay_rsp_err); + break; + case CFG_CHK_COND_ERR: /* check-cond-err */ + value = (void *)((ulong)lpfc_check_cond_err); + if(lpfc9_check_cond_err != -1) + value = (void *)((ulong)lpfc9_check_cond_err); + break; + case CFG_NODEV_TMO: /* nodev-tmo */ + value = (void *)((ulong)lpfc_nodev_tmo); + if(lpfc9_nodev_tmo != -1) + value = (void *)((ulong)lpfc9_nodev_tmo); + break; + case CFG_LINK_SPEED: /* link-speed */ + value = (void *)((ulong)lpfc_link_speed); + if(lpfc9_link_speed != -1) + value = (void *)((ulong)lpfc9_link_speed); + break; + case CFG_DQFULL_THROTTLE_UP_TIME: /* dqfull-throttle-up-time */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_time); + if(lpfc9_dqfull_throttle_up_time != -1) + value = (void *)((ulong)lpfc9_dqfull_throttle_up_time); + break; + case CFG_DQFULL_THROTTLE_UP_INC: /* dqfull-throttle-up-inc */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_inc); + if(lpfc9_dqfull_throttle_up_inc != -1) + value = (void *)((ulong)lpfc9_dqfull_throttle_up_inc); + break; + } + break; + case 10: /* HBA 10 */ + switch(param) { + case CFG_LOG_VERBOSE: /* log-verbose */ + value = (void *)((ulong)lpfc_log_verbose); + if(lpfc10_log_verbose != -1) + value = (void *)((ulong)lpfc10_log_verbose); + break; + case CFG_LOG_ONLY: /* log-only */ + value = (void *)((ulong)lpfc_log_only); + if(lpfc10_log_only != -1) + value = (void *)((ulong)lpfc10_log_only); + break; + case CFG_NUM_IOCBS: /* num-iocbs */ + value = (void *)((ulong)lpfc_num_iocbs); + if(lpfc10_num_iocbs != -1) + value = (void *)((ulong)lpfc10_num_iocbs); + break; + case CFG_NUM_BUFS: /* num-bufs */ + value = (void *)((ulong)lpfc_num_bufs); + if(lpfc10_num_bufs != -1) + value = (void *)((ulong)lpfc10_num_bufs); + break; + case CFG_AUTOMAP: /* automap */ + value = (void *)((ulong)lpfc_automap); + if(lpfc10_automap != -1) + value = (void *)((ulong)lpfc10_automap); + break; + case CFG_CR_DELAY: /* cr_delay */ + value = (void *)((ulong)lpfc_cr_delay); + if(lpfc10_cr_delay != -1) + value = (void *)((ulong)lpfc10_cr_delay); + break; + case CFG_CR_COUNT: /* cr_count */ + value = (void *)((ulong)lpfc_cr_count); + if(lpfc10_cr_count != -1) + value = (void *)((ulong)lpfc10_cr_count); + break; + case CFG_DFT_TGT_Q_DEPTH: /* tgt_queue_depth */ + value = (void *)((ulong)lpfc_tgt_queue_depth); + if(lpfc10_tgt_queue_depth != -1) + value = (void *)((ulong)lpfc10_tgt_queue_depth); + break; + case CFG_DFT_LUN_Q_DEPTH: /* lun_queue_depth */ + value = (void *)((ulong)lpfc_lun_queue_depth); + if(lpfc10_lun_queue_depth != -1) + value = (void *)((ulong)lpfc10_lun_queue_depth); + break; + case CFG_FCPFABRIC_TMO: /* fcpfabric-tmo */ + value = (void *)((ulong)lpfc_fcpfabric_tmo); + if(lpfc10_fcpfabric_tmo != -1) + value = (void *)((ulong)lpfc10_fcpfabric_tmo); + break; + case CFG_FCP_CLASS: /* fcp-class */ + value = (void *)((ulong)lpfc_fcp_class); + if(lpfc10_fcp_class != -1) + value = (void *)((ulong)lpfc10_fcp_class); + break; + case CFG_USE_ADISC: /* use-adisc */ + value = (void *)((ulong)lpfc_use_adisc); + if(lpfc10_use_adisc != -1) + value = (void *)((ulong)lpfc10_use_adisc); + break; + case CFG_NO_DEVICE_DELAY: /* no-device-delay */ + value = (void *)((ulong)lpfc_no_device_delay); + if(lpfc10_no_device_delay != -1) + value = (void *)((ulong)lpfc10_no_device_delay); + break; + case CFG_NETWORK_ON: /* network-on */ + value = (void *)((ulong)lpfc_network_on); + if(lpfc10_network_on != -1) + value = (void *)((ulong)lpfc10_network_on); + break; + case CFG_POST_IP_BUF: /* post-ip-buf */ + value = (void *)((ulong)lpfc_post_ip_buf); + if(lpfc10_post_ip_buf != -1) + value = (void *)((ulong)lpfc10_post_ip_buf); + break; + case CFG_XMT_Q_SIZE: /* xmt-que-size */ + value = (void *)((ulong)lpfc_xmt_que_size); + if(lpfc10_xmt_que_size != -1) + value = (void *)((ulong)lpfc10_xmt_que_size); + break; + case CFG_IP_CLASS: /* ip-class */ + value = (void *)((ulong)lpfc_ip_class); + if(lpfc10_ip_class != -1) + value = (void *)((ulong)lpfc10_ip_class); + break; + case CFG_ACK0: /* ack0 */ + value = (void *)((ulong)lpfc_ack0support); + if(lpfc10_ack0support != -1) + value = (void *)((ulong)lpfc10_ack0support); + break; + case CFG_TOPOLOGY: /* topology */ + value = (void *)((ulong)lpfc_topology); + if(lpfc10_topology != -1) + value = (void *)((ulong)lpfc10_topology); + break; + case CFG_SCAN_DOWN: /* scan-down */ + value = (void *)((ulong)lpfc_scandown); + if(lpfc10_scandown != -1) + value = (void *)((ulong)lpfc10_scandown); + break; + case CFG_LINKDOWN_TMO: /* linkdown-tmo */ + value = (void *)((ulong)lpfc_linkdown_tmo); + if(lpfc10_linkdown_tmo != -1) + value = (void *)((ulong)lpfc10_linkdown_tmo); + break; + case CFG_HOLDIO: /* nodev-holdio */ + value = (void *)((ulong)lpfc_nodev_holdio); + if(lpfc10_nodev_holdio != -1) + value = (void *)((ulong)lpfc10_nodev_holdio); + break; + case CFG_DELAY_RSP_ERR: /* delay-rsp-err */ + value = (void *)((ulong)lpfc_delay_rsp_err); + if(lpfc10_delay_rsp_err != -1) + value = (void *)((ulong)lpfc10_delay_rsp_err); + break; + case CFG_CHK_COND_ERR: /* check-cond-err */ + value = (void *)((ulong)lpfc_check_cond_err); + if(lpfc10_check_cond_err != -1) + value = (void *)((ulong)lpfc10_check_cond_err); + break; + case CFG_NODEV_TMO: /* nodev-tmo */ + value = (void *)((ulong)lpfc_nodev_tmo); + if(lpfc10_nodev_tmo != -1) + value = (void *)((ulong)lpfc10_nodev_tmo); + break; + case CFG_LINK_SPEED: /* link-speed */ + value = (void *)((ulong)lpfc_link_speed); + if(lpfc10_link_speed != -1) + value = (void *)((ulong)lpfc10_link_speed); + break; + case CFG_DQFULL_THROTTLE_UP_TIME: /* dqfull-throttle-up-time */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_time); + if(lpfc10_dqfull_throttle_up_time != -1) + value = (void *)((ulong)lpfc10_dqfull_throttle_up_time); + break; + case CFG_DQFULL_THROTTLE_UP_INC: /* dqfull-throttle-up-inc */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_inc); + if(lpfc10_dqfull_throttle_up_inc != -1) + value = (void *)((ulong)lpfc10_dqfull_throttle_up_inc); + break; + } + break; + case 11: /* HBA 11 */ + switch(param) { + case CFG_LOG_VERBOSE: /* log-verbose */ + value = (void *)((ulong)lpfc_log_verbose); + if(lpfc11_log_verbose != -1) + value = (void *)((ulong)lpfc11_log_verbose); + break; + case CFG_LOG_ONLY: /* log-only */ + value = (void *)((ulong)lpfc_log_only); + if(lpfc11_log_only != -1) + value = (void *)((ulong)lpfc11_log_only); + break; + case CFG_NUM_IOCBS: /* num-iocbs */ + value = (void *)((ulong)lpfc_num_iocbs); + if(lpfc11_num_iocbs != -1) + value = (void *)((ulong)lpfc11_num_iocbs); + break; + case CFG_NUM_BUFS: /* num-bufs */ + value = (void *)((ulong)lpfc_num_bufs); + if(lpfc11_num_bufs != -1) + value = (void *)((ulong)lpfc11_num_bufs); + break; + case CFG_AUTOMAP: /* automap */ + value = (void *)((ulong)lpfc_automap); + if(lpfc11_automap != -1) + value = (void *)((ulong)lpfc11_automap); + break; + case CFG_CR_DELAY: /* cr_delay */ + value = (void *)((ulong)lpfc_cr_delay); + if(lpfc11_cr_delay != -1) + value = (void *)((ulong)lpfc11_cr_delay); + break; + case CFG_CR_COUNT: /* cr_count */ + value = (void *)((ulong)lpfc_cr_count); + if(lpfc11_cr_count != -1) + value = (void *)((ulong)lpfc11_cr_count); + break; + case CFG_DFT_TGT_Q_DEPTH: /* tgt_queue_depth */ + value = (void *)((ulong)lpfc_tgt_queue_depth); + if(lpfc11_tgt_queue_depth != -1) + value = (void *)((ulong)lpfc11_tgt_queue_depth); + break; + case CFG_DFT_LUN_Q_DEPTH: /* lun_queue_depth */ + value = (void *)((ulong)lpfc_lun_queue_depth); + if(lpfc11_lun_queue_depth != -1) + value = (void *)((ulong)lpfc11_lun_queue_depth); + break; + case CFG_FCPFABRIC_TMO: /* fcpfabric-tmo */ + value = (void *)((ulong)lpfc_fcpfabric_tmo); + if(lpfc11_fcpfabric_tmo != -1) + value = (void *)((ulong)lpfc11_fcpfabric_tmo); + break; + case CFG_FCP_CLASS: /* fcp-class */ + value = (void *)((ulong)lpfc_fcp_class); + if(lpfc11_fcp_class != -1) + value = (void *)((ulong)lpfc11_fcp_class); + break; + case CFG_USE_ADISC: /* use-adisc */ + value = (void *)((ulong)lpfc_use_adisc); + if(lpfc11_use_adisc != -1) + value = (void *)((ulong)lpfc11_use_adisc); + break; + case CFG_NO_DEVICE_DELAY: /* no-device-delay */ + value = (void *)((ulong)lpfc_no_device_delay); + if(lpfc11_no_device_delay != -1) + value = (void *)((ulong)lpfc11_no_device_delay); + break; + case CFG_NETWORK_ON: /* network-on */ + value = (void *)((ulong)lpfc_network_on); + if(lpfc11_network_on != -1) + value = (void *)((ulong)lpfc11_network_on); + break; + case CFG_POST_IP_BUF: /* post-ip-buf */ + value = (void *)((ulong)lpfc_post_ip_buf); + if(lpfc11_post_ip_buf != -1) + value = (void *)((ulong)lpfc11_post_ip_buf); + break; + case CFG_XMT_Q_SIZE: /* xmt-que-size */ + value = (void *)((ulong)lpfc_xmt_que_size); + if(lpfc11_xmt_que_size != -1) + value = (void *)((ulong)lpfc11_xmt_que_size); + break; + case CFG_IP_CLASS: /* ip-class */ + value = (void *)((ulong)lpfc_ip_class); + if(lpfc11_ip_class != -1) + value = (void *)((ulong)lpfc11_ip_class); + break; + case CFG_ACK0: /* ack0 */ + value = (void *)((ulong)lpfc_ack0support); + if(lpfc11_ack0support != -1) + value = (void *)((ulong)lpfc11_ack0support); + break; + case CFG_TOPOLOGY: /* topology */ + value = (void *)((ulong)lpfc_topology); + if(lpfc11_topology != -1) + value = (void *)((ulong)lpfc11_topology); + break; + case CFG_SCAN_DOWN: /* scan-down */ + value = (void *)((ulong)lpfc_scandown); + if(lpfc11_scandown != -1) + value = (void *)((ulong)lpfc11_scandown); + break; + case CFG_LINKDOWN_TMO: /* linkdown-tmo */ + value = (void *)((ulong)lpfc_linkdown_tmo); + if(lpfc11_linkdown_tmo != -1) + value = (void *)((ulong)lpfc11_linkdown_tmo); + break; + case CFG_HOLDIO: /* nodev-holdio */ + value = (void *)((ulong)lpfc_nodev_holdio); + if(lpfc11_nodev_holdio != -1) + value = (void *)((ulong)lpfc11_nodev_holdio); + break; + case CFG_DELAY_RSP_ERR: /* delay-rsp-err */ + value = (void *)((ulong)lpfc_delay_rsp_err); + if(lpfc11_delay_rsp_err != -1) + value = (void *)((ulong)lpfc11_delay_rsp_err); + break; + case CFG_CHK_COND_ERR: /* check-cond-err */ + value = (void *)((ulong)lpfc_check_cond_err); + if(lpfc11_check_cond_err != -1) + value = (void *)((ulong)lpfc11_check_cond_err); + break; + case CFG_NODEV_TMO: /* nodev-tmo */ + value = (void *)((ulong)lpfc_nodev_tmo); + if(lpfc11_nodev_tmo != -1) + value = (void *)((ulong)lpfc11_nodev_tmo); + break; + case CFG_LINK_SPEED: /* link-speed */ + value = (void *)((ulong)lpfc_link_speed); + if(lpfc11_link_speed != -1) + value = (void *)((ulong)lpfc11_link_speed); + break; + case CFG_DQFULL_THROTTLE_UP_TIME: /* dqfull-throttle-up-time */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_time); + if(lpfc11_dqfull_throttle_up_time != -1) + value = (void *)((ulong)lpfc11_dqfull_throttle_up_time); + break; + case CFG_DQFULL_THROTTLE_UP_INC: /* dqfull-throttle-up-inc */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_inc); + if(lpfc11_dqfull_throttle_up_inc != -1) + value = (void *)((ulong)lpfc11_dqfull_throttle_up_inc); + break; + } + break; + case 12: /* HBA 12 */ + switch(param) { + case CFG_LOG_VERBOSE: /* log-verbose */ + value = (void *)((ulong)lpfc_log_verbose); + if(lpfc12_log_verbose != -1) + value = (void *)((ulong)lpfc12_log_verbose); + break; + case CFG_LOG_ONLY: /* log-only */ + value = (void *)((ulong)lpfc_log_only); + if(lpfc12_log_only != -1) + value = (void *)((ulong)lpfc12_log_only); + break; + case CFG_NUM_IOCBS: /* num-iocbs */ + value = (void *)((ulong)lpfc_num_iocbs); + if(lpfc12_num_iocbs != -1) + value = (void *)((ulong)lpfc12_num_iocbs); + break; + case CFG_NUM_BUFS: /* num-bufs */ + value = (void *)((ulong)lpfc_num_bufs); + if(lpfc12_num_bufs != -1) + value = (void *)((ulong)lpfc12_num_bufs); + break; + case CFG_AUTOMAP: /* automap */ + value = (void *)((ulong)lpfc_automap); + if(lpfc12_automap != -1) + value = (void *)((ulong)lpfc12_automap); + break; + case CFG_CR_DELAY: /* cr_delay */ + value = (void *)((ulong)lpfc_cr_delay); + if(lpfc12_cr_delay != -1) + value = (void *)((ulong)lpfc12_cr_delay); + break; + case CFG_CR_COUNT: /* cr_count */ + value = (void *)((ulong)lpfc_cr_count); + if(lpfc12_cr_count != -1) + value = (void *)((ulong)lpfc12_cr_count); + break; + case CFG_DFT_TGT_Q_DEPTH: /* tgt_queue_depth */ + value = (void *)((ulong)lpfc_tgt_queue_depth); + if(lpfc12_tgt_queue_depth != -1) + value = (void *)((ulong)lpfc12_tgt_queue_depth); + break; + case CFG_DFT_LUN_Q_DEPTH: /* lun_queue_depth */ + value = (void *)((ulong)lpfc_lun_queue_depth); + if(lpfc12_lun_queue_depth != -1) + value = (void *)((ulong)lpfc12_lun_queue_depth); + break; + case CFG_FCPFABRIC_TMO: /* fcpfabric-tmo */ + value = (void *)((ulong)lpfc_fcpfabric_tmo); + if(lpfc12_fcpfabric_tmo != -1) + value = (void *)((ulong)lpfc12_fcpfabric_tmo); + break; + case CFG_FCP_CLASS: /* fcp-class */ + value = (void *)((ulong)lpfc_fcp_class); + if(lpfc12_fcp_class != -1) + value = (void *)((ulong)lpfc12_fcp_class); + break; + case CFG_USE_ADISC: /* use-adisc */ + value = (void *)((ulong)lpfc_use_adisc); + if(lpfc12_use_adisc != -1) + value = (void *)((ulong)lpfc12_use_adisc); + break; + case CFG_NO_DEVICE_DELAY: /* no-device-delay */ + value = (void *)((ulong)lpfc_no_device_delay); + if(lpfc12_no_device_delay != -1) + value = (void *)((ulong)lpfc12_no_device_delay); + break; + case CFG_NETWORK_ON: /* network-on */ + value = (void *)((ulong)lpfc_network_on); + if(lpfc12_network_on != -1) + value = (void *)((ulong)lpfc12_network_on); + break; + case CFG_POST_IP_BUF: /* post-ip-buf */ + value = (void *)((ulong)lpfc_post_ip_buf); + if(lpfc12_post_ip_buf != -1) + value = (void *)((ulong)lpfc12_post_ip_buf); + break; + case CFG_XMT_Q_SIZE: /* xmt-que-size */ + value = (void *)((ulong)lpfc_xmt_que_size); + if(lpfc12_xmt_que_size != -1) + value = (void *)((ulong)lpfc12_xmt_que_size); + break; + case CFG_IP_CLASS: /* ip-class */ + value = (void *)((ulong)lpfc_ip_class); + if(lpfc12_ip_class != -1) + value = (void *)((ulong)lpfc12_ip_class); + break; + case CFG_ACK0: /* ack0 */ + value = (void *)((ulong)lpfc_ack0support); + if(lpfc12_ack0support != -1) + value = (void *)((ulong)lpfc12_ack0support); + break; + case CFG_TOPOLOGY: /* topology */ + value = (void *)((ulong)lpfc_topology); + if(lpfc12_topology != -1) + value = (void *)((ulong)lpfc12_topology); + break; + case CFG_SCAN_DOWN: /* scan-down */ + value = (void *)((ulong)lpfc_scandown); + if(lpfc12_scandown != -1) + value = (void *)((ulong)lpfc12_scandown); + break; + case CFG_LINKDOWN_TMO: /* linkdown-tmo */ + value = (void *)((ulong)lpfc_linkdown_tmo); + if(lpfc12_linkdown_tmo != -1) + value = (void *)((ulong)lpfc12_linkdown_tmo); + break; + case CFG_HOLDIO: /* nodev-holdio */ + value = (void *)((ulong)lpfc_nodev_holdio); + if(lpfc12_nodev_holdio != -1) + value = (void *)((ulong)lpfc12_nodev_holdio); + break; + case CFG_DELAY_RSP_ERR: /* delay-rsp-err */ + value = (void *)((ulong)lpfc_delay_rsp_err); + if(lpfc12_delay_rsp_err != -1) + value = (void *)((ulong)lpfc12_delay_rsp_err); + break; + case CFG_CHK_COND_ERR: /* check-cond-err */ + value = (void *)((ulong)lpfc_check_cond_err); + if(lpfc12_check_cond_err != -1) + value = (void *)((ulong)lpfc12_check_cond_err); + break; + case CFG_NODEV_TMO: /* nodev-tmo */ + value = (void *)((ulong)lpfc_nodev_tmo); + if(lpfc12_nodev_tmo != -1) + value = (void *)((ulong)lpfc12_nodev_tmo); + break; + case CFG_LINK_SPEED: /* link-speed */ + value = (void *)((ulong)lpfc_link_speed); + if(lpfc12_link_speed != -1) + value = (void *)((ulong)lpfc12_link_speed); + break; + case CFG_DQFULL_THROTTLE_UP_TIME: /* dqfull-throttle-up-time */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_time); + if(lpfc12_dqfull_throttle_up_time != -1) + value = (void *)((ulong)lpfc12_dqfull_throttle_up_time); + break; + case CFG_DQFULL_THROTTLE_UP_INC: /* dqfull-throttle-up-inc */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_inc); + if(lpfc12_dqfull_throttle_up_inc != -1) + value = (void *)((ulong)lpfc12_dqfull_throttle_up_inc); + break; + } + break; + case 13: /* HBA 13 */ + switch(param) { + case CFG_LOG_VERBOSE: /* log-verbose */ + value = (void *)((ulong)lpfc_log_verbose); + if(lpfc13_log_verbose != -1) + value = (void *)((ulong)lpfc13_log_verbose); + break; + case CFG_LOG_ONLY: /* log-only */ + value = (void *)((ulong)lpfc_log_only); + if(lpfc13_log_only != -1) + value = (void *)((ulong)lpfc13_log_only); + break; + case CFG_NUM_IOCBS: /* num-iocbs */ + value = (void *)((ulong)lpfc_num_iocbs); + if(lpfc13_num_iocbs != -1) + value = (void *)((ulong)lpfc13_num_iocbs); + break; + case CFG_NUM_BUFS: /* num-bufs */ + value = (void *)((ulong)lpfc_num_bufs); + if(lpfc13_num_bufs != -1) + value = (void *)((ulong)lpfc13_num_bufs); + break; + case CFG_AUTOMAP: /* automap */ + value = (void *)((ulong)lpfc_automap); + if(lpfc13_automap != -1) + value = (void *)((ulong)lpfc13_automap); + break; + case CFG_CR_DELAY: /* cr_delay */ + value = (void *)((ulong)lpfc_cr_delay); + if(lpfc13_cr_delay != -1) + value = (void *)((ulong)lpfc13_cr_delay); + break; + case CFG_CR_COUNT: /* cr_count */ + value = (void *)((ulong)lpfc_cr_count); + if(lpfc13_cr_count != -1) + value = (void *)((ulong)lpfc13_cr_count); + break; + case CFG_DFT_TGT_Q_DEPTH: /* tgt_queue_depth */ + value = (void *)((ulong)lpfc_tgt_queue_depth); + if(lpfc13_tgt_queue_depth != -1) + value = (void *)((ulong)lpfc13_tgt_queue_depth); + break; + case CFG_DFT_LUN_Q_DEPTH: /* lun_queue_depth */ + value = (void *)((ulong)lpfc_lun_queue_depth); + if(lpfc13_lun_queue_depth != -1) + value = (void *)((ulong)lpfc13_lun_queue_depth); + break; + case CFG_FCPFABRIC_TMO: /* fcpfabric-tmo */ + value = (void *)((ulong)lpfc_fcpfabric_tmo); + if(lpfc13_fcpfabric_tmo != -1) + value = (void *)((ulong)lpfc13_fcpfabric_tmo); + break; + case CFG_FCP_CLASS: /* fcp-class */ + value = (void *)((ulong)lpfc_fcp_class); + if(lpfc13_fcp_class != -1) + value = (void *)((ulong)lpfc13_fcp_class); + break; + case CFG_USE_ADISC: /* use-adisc */ + value = (void *)((ulong)lpfc_use_adisc); + if(lpfc13_use_adisc != -1) + value = (void *)((ulong)lpfc13_use_adisc); + break; + case CFG_NO_DEVICE_DELAY: /* no-device-delay */ + value = (void *)((ulong)lpfc_no_device_delay); + if(lpfc13_no_device_delay != -1) + value = (void *)((ulong)lpfc13_no_device_delay); + break; + case CFG_NETWORK_ON: /* network-on */ + value = (void *)((ulong)lpfc_network_on); + if(lpfc13_network_on != -1) + value = (void *)((ulong)lpfc13_network_on); + break; + case CFG_POST_IP_BUF: /* post-ip-buf */ + value = (void *)((ulong)lpfc_post_ip_buf); + if(lpfc13_post_ip_buf != -1) + value = (void *)((ulong)lpfc13_post_ip_buf); + break; + case CFG_XMT_Q_SIZE: /* xmt-que-size */ + value = (void *)((ulong)lpfc_xmt_que_size); + if(lpfc13_xmt_que_size != -1) + value = (void *)((ulong)lpfc13_xmt_que_size); + break; + case CFG_IP_CLASS: /* ip-class */ + value = (void *)((ulong)lpfc_ip_class); + if(lpfc13_ip_class != -1) + value = (void *)((ulong)lpfc13_ip_class); + break; + case CFG_ACK0: /* ack0 */ + value = (void *)((ulong)lpfc_ack0support); + if(lpfc13_ack0support != -1) + value = (void *)((ulong)lpfc13_ack0support); + break; + case CFG_TOPOLOGY: /* topology */ + value = (void *)((ulong)lpfc_topology); + if(lpfc13_topology != -1) + value = (void *)((ulong)lpfc13_topology); + break; + case CFG_SCAN_DOWN: /* scan-down */ + value = (void *)((ulong)lpfc_scandown); + if(lpfc13_scandown != -1) + value = (void *)((ulong)lpfc13_scandown); + break; + case CFG_LINKDOWN_TMO: /* linkdown-tmo */ + value = (void *)((ulong)lpfc_linkdown_tmo); + if(lpfc13_linkdown_tmo != -1) + value = (void *)((ulong)lpfc13_linkdown_tmo); + break; + case CFG_HOLDIO: /* nodev-holdio */ + value = (void *)((ulong)lpfc_nodev_holdio); + if(lpfc13_nodev_holdio != -1) + value = (void *)((ulong)lpfc13_nodev_holdio); + break; + case CFG_DELAY_RSP_ERR: /* delay-rsp-err */ + value = (void *)((ulong)lpfc_delay_rsp_err); + if(lpfc13_delay_rsp_err != -1) + value = (void *)((ulong)lpfc13_delay_rsp_err); + break; + case CFG_CHK_COND_ERR: /* check-cond-err */ + value = (void *)((ulong)lpfc_check_cond_err); + if(lpfc13_check_cond_err != -1) + value = (void *)((ulong)lpfc13_check_cond_err); + break; + case CFG_NODEV_TMO: /* nodev-tmo */ + value = (void *)((ulong)lpfc_nodev_tmo); + if(lpfc13_nodev_tmo != -1) + value = (void *)((ulong)lpfc13_nodev_tmo); + break; + case CFG_LINK_SPEED: /* link-speed */ + value = (void *)((ulong)lpfc_link_speed); + if(lpfc13_link_speed != -1) + value = (void *)((ulong)lpfc13_link_speed); + break; + case CFG_DQFULL_THROTTLE_UP_TIME: /* dqfull-throttle-up-time */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_time); + if(lpfc13_dqfull_throttle_up_time != -1) + value = (void *)((ulong)lpfc13_dqfull_throttle_up_time); + break; + case CFG_DQFULL_THROTTLE_UP_INC: /* dqfull-throttle-up-inc */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_inc); + if(lpfc13_dqfull_throttle_up_inc != -1) + value = (void *)((ulong)lpfc13_dqfull_throttle_up_inc); + break; + } + break; + case 14: /* HBA 14 */ + switch(param) { + case CFG_LOG_VERBOSE: /* log-verbose */ + value = (void *)((ulong)lpfc_log_verbose); + if(lpfc14_log_verbose != -1) + value = (void *)((ulong)lpfc14_log_verbose); + break; + case CFG_LOG_ONLY: /* log-only */ + value = (void *)((ulong)lpfc_log_only); + if(lpfc14_log_only != -1) + value = (void *)((ulong)lpfc14_log_only); + break; + case CFG_NUM_IOCBS: /* num-iocbs */ + value = (void *)((ulong)lpfc_num_iocbs); + if(lpfc14_num_iocbs != -1) + value = (void *)((ulong)lpfc14_num_iocbs); + break; + case CFG_NUM_BUFS: /* num-bufs */ + value = (void *)((ulong)lpfc_num_bufs); + if(lpfc14_num_bufs != -1) + value = (void *)((ulong)lpfc14_num_bufs); + break; + case CFG_AUTOMAP: /* automap */ + value = (void *)((ulong)lpfc_automap); + if(lpfc14_automap != -1) + value = (void *)((ulong)lpfc14_automap); + break; + case CFG_CR_DELAY: /* cr_delay */ + value = (void *)((ulong)lpfc_cr_delay); + if(lpfc14_cr_delay != -1) + value = (void *)((ulong)lpfc14_cr_delay); + break; + case CFG_CR_COUNT: /* cr_count */ + value = (void *)((ulong)lpfc_cr_count); + if(lpfc14_cr_count != -1) + value = (void *)((ulong)lpfc14_cr_count); + break; + case CFG_DFT_TGT_Q_DEPTH: /* tgt_queue_depth */ + value = (void *)((ulong)lpfc_tgt_queue_depth); + if(lpfc14_tgt_queue_depth != -1) + value = (void *)((ulong)lpfc14_tgt_queue_depth); + break; + case CFG_DFT_LUN_Q_DEPTH: /* lun_queue_depth */ + value = (void *)((ulong)lpfc_lun_queue_depth); + if(lpfc14_lun_queue_depth != -1) + value = (void *)((ulong)lpfc14_lun_queue_depth); + break; + case CFG_FCPFABRIC_TMO: /* fcpfabric-tmo */ + value = (void *)((ulong)lpfc_fcpfabric_tmo); + if(lpfc14_fcpfabric_tmo != -1) + value = (void *)((ulong)lpfc14_fcpfabric_tmo); + break; + case CFG_FCP_CLASS: /* fcp-class */ + value = (void *)((ulong)lpfc_fcp_class); + if(lpfc14_fcp_class != -1) + value = (void *)((ulong)lpfc14_fcp_class); + break; + case CFG_USE_ADISC: /* use-adisc */ + value = (void *)((ulong)lpfc_use_adisc); + if(lpfc14_use_adisc != -1) + value = (void *)((ulong)lpfc14_use_adisc); + break; + case CFG_NO_DEVICE_DELAY: /* no-device-delay */ + value = (void *)((ulong)lpfc_no_device_delay); + if(lpfc14_no_device_delay != -1) + value = (void *)((ulong)lpfc14_no_device_delay); + break; + case CFG_NETWORK_ON: /* network-on */ + value = (void *)((ulong)lpfc_network_on); + if(lpfc14_network_on != -1) + value = (void *)((ulong)lpfc14_network_on); + break; + case CFG_POST_IP_BUF: /* post-ip-buf */ + value = (void *)((ulong)lpfc_post_ip_buf); + if(lpfc14_post_ip_buf != -1) + value = (void *)((ulong)lpfc14_post_ip_buf); + break; + case CFG_XMT_Q_SIZE: /* xmt-que-size */ + value = (void *)((ulong)lpfc_xmt_que_size); + if(lpfc14_xmt_que_size != -1) + value = (void *)((ulong)lpfc14_xmt_que_size); + break; + case CFG_IP_CLASS: /* ip-class */ + value = (void *)((ulong)lpfc_ip_class); + if(lpfc14_ip_class != -1) + value = (void *)((ulong)lpfc14_ip_class); + break; + case CFG_ACK0: /* ack0 */ + value = (void *)((ulong)lpfc_ack0support); + if(lpfc14_ack0support != -1) + value = (void *)((ulong)lpfc14_ack0support); + break; + case CFG_TOPOLOGY: /* topology */ + value = (void *)((ulong)lpfc_topology); + if(lpfc14_topology != -1) + value = (void *)((ulong)lpfc14_topology); + break; + case CFG_SCAN_DOWN: /* scan-down */ + value = (void *)((ulong)lpfc_scandown); + if(lpfc14_scandown != -1) + value = (void *)((ulong)lpfc14_scandown); + break; + case CFG_LINKDOWN_TMO: /* linkdown-tmo */ + value = (void *)((ulong)lpfc_linkdown_tmo); + if(lpfc14_linkdown_tmo != -1) + value = (void *)((ulong)lpfc14_linkdown_tmo); + break; + case CFG_HOLDIO: /* nodev-holdio */ + value = (void *)((ulong)lpfc_nodev_holdio); + if(lpfc14_nodev_holdio != -1) + value = (void *)((ulong)lpfc14_nodev_holdio); + break; + case CFG_DELAY_RSP_ERR: /* delay-rsp-err */ + value = (void *)((ulong)lpfc_delay_rsp_err); + if(lpfc14_delay_rsp_err != -1) + value = (void *)((ulong)lpfc14_delay_rsp_err); + break; + case CFG_CHK_COND_ERR: /* check-cond-err */ + value = (void *)((ulong)lpfc_check_cond_err); + if(lpfc14_check_cond_err != -1) + value = (void *)((ulong)lpfc14_check_cond_err); + break; + case CFG_NODEV_TMO: /* nodev-tmo */ + value = (void *)((ulong)lpfc_nodev_tmo); + if(lpfc14_nodev_tmo != -1) + value = (void *)((ulong)lpfc14_nodev_tmo); + break; + case CFG_LINK_SPEED: /* link-speed */ + value = (void *)((ulong)lpfc_link_speed); + if(lpfc14_link_speed != -1) + value = (void *)((ulong)lpfc14_link_speed); + break; + case CFG_DQFULL_THROTTLE_UP_TIME: /* dqfull-throttle-up-time */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_time); + if(lpfc14_dqfull_throttle_up_time != -1) + value = (void *)((ulong)lpfc14_dqfull_throttle_up_time); + break; + case CFG_DQFULL_THROTTLE_UP_INC: /* dqfull-throttle-up-inc */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_inc); + if(lpfc14_dqfull_throttle_up_inc != -1) + value = (void *)((ulong)lpfc14_dqfull_throttle_up_inc); + break; + } + break; + case 15: /* HBA 15 */ + switch(param) { + case CFG_LOG_VERBOSE: /* log-verbose */ + value = (void *)((ulong)lpfc_log_verbose); + if(lpfc15_log_verbose != -1) + value = (void *)((ulong)lpfc15_log_verbose); + break; + case CFG_LOG_ONLY: /* log-only */ + value = (void *)((ulong)lpfc_log_only); + if(lpfc15_log_only != -1) + value = (void *)((ulong)lpfc15_log_only); + break; + case CFG_NUM_IOCBS: /* num-iocbs */ + value = (void *)((ulong)lpfc_num_iocbs); + if(lpfc15_num_iocbs != -1) + value = (void *)((ulong)lpfc15_num_iocbs); + break; + case CFG_NUM_BUFS: /* num-bufs */ + value = (void *)((ulong)lpfc_num_bufs); + if(lpfc15_num_bufs != -1) + value = (void *)((ulong)lpfc15_num_bufs); + break; + case CFG_AUTOMAP: /* automap */ + value = (void *)((ulong)lpfc_automap); + if(lpfc15_automap != -1) + value = (void *)((ulong)lpfc15_automap); + break; + case CFG_CR_DELAY: /* cr_delay */ + value = (void *)((ulong)lpfc_cr_delay); + if(lpfc15_cr_delay != -1) + value = (void *)((ulong)lpfc15_cr_delay); + break; + case CFG_CR_COUNT: /* cr_count */ + value = (void *)((ulong)lpfc_cr_count); + if(lpfc15_cr_count != -1) + value = (void *)((ulong)lpfc15_cr_count); + break; + case CFG_DFT_TGT_Q_DEPTH: /* tgt_queue_depth */ + value = (void *)((ulong)lpfc_tgt_queue_depth); + if(lpfc15_tgt_queue_depth != -1) + value = (void *)((ulong)lpfc15_tgt_queue_depth); + break; + case CFG_DFT_LUN_Q_DEPTH: /* lun_queue_depth */ + value = (void *)((ulong)lpfc_lun_queue_depth); + if(lpfc15_lun_queue_depth != -1) + value = (void *)((ulong)lpfc15_lun_queue_depth); + break; + case CFG_FCPFABRIC_TMO: /* fcpfabric-tmo */ + value = (void *)((ulong)lpfc_fcpfabric_tmo); + if(lpfc15_fcpfabric_tmo != -1) + value = (void *)((ulong)lpfc15_fcpfabric_tmo); + break; + case CFG_FCP_CLASS: /* fcp-class */ + value = (void *)((ulong)lpfc_fcp_class); + if(lpfc15_fcp_class != -1) + value = (void *)((ulong)lpfc15_fcp_class); + break; + case CFG_USE_ADISC: /* use-adisc */ + value = (void *)((ulong)lpfc_use_adisc); + if(lpfc15_use_adisc != -1) + value = (void *)((ulong)lpfc15_use_adisc); + break; + case CFG_NO_DEVICE_DELAY: /* no-device-delay */ + value = (void *)((ulong)lpfc_no_device_delay); + if(lpfc15_no_device_delay != -1) + value = (void *)((ulong)lpfc15_no_device_delay); + break; + case CFG_NETWORK_ON: /* network-on */ + value = (void *)((ulong)lpfc_network_on); + if(lpfc15_network_on != -1) + value = (void *)((ulong)lpfc15_network_on); + break; + case CFG_POST_IP_BUF: /* post-ip-buf */ + value = (void *)((ulong)lpfc_post_ip_buf); + if(lpfc15_post_ip_buf != -1) + value = (void *)((ulong)lpfc15_post_ip_buf); + break; + case CFG_XMT_Q_SIZE: /* xmt-que-size */ + value = (void *)((ulong)lpfc_xmt_que_size); + if(lpfc15_xmt_que_size != -1) + value = (void *)((ulong)lpfc15_xmt_que_size); + break; + case CFG_IP_CLASS: /* ip-class */ + value = (void *)((ulong)lpfc_ip_class); + if(lpfc15_ip_class != -1) + value = (void *)((ulong)lpfc15_ip_class); + break; + case CFG_ACK0: /* ack0 */ + value = (void *)((ulong)lpfc_ack0support); + if(lpfc15_ack0support != -1) + value = (void *)((ulong)lpfc15_ack0support); + break; + case CFG_TOPOLOGY: /* topology */ + value = (void *)((ulong)lpfc_topology); + if(lpfc15_topology != -1) + value = (void *)((ulong)lpfc15_topology); + break; + case CFG_SCAN_DOWN: /* scan-down */ + value = (void *)((ulong)lpfc_scandown); + if(lpfc15_scandown != -1) + value = (void *)((ulong)lpfc15_scandown); + break; + case CFG_LINKDOWN_TMO: /* linkdown-tmo */ + value = (void *)((ulong)lpfc_linkdown_tmo); + if(lpfc15_linkdown_tmo != -1) + value = (void *)((ulong)lpfc15_linkdown_tmo); + break; + case CFG_HOLDIO: /* nodev-holdio */ + value = (void *)((ulong)lpfc_nodev_holdio); + if(lpfc15_nodev_holdio != -1) + value = (void *)((ulong)lpfc15_nodev_holdio); + break; + case CFG_DELAY_RSP_ERR: /* delay-rsp-err */ + value = (void *)((ulong)lpfc_delay_rsp_err); + if(lpfc15_delay_rsp_err != -1) + value = (void *)((ulong)lpfc15_delay_rsp_err); + break; + case CFG_CHK_COND_ERR: /* check-cond-err */ + value = (void *)((ulong)lpfc_check_cond_err); + if(lpfc15_check_cond_err != -1) + value = (void *)((ulong)lpfc15_check_cond_err); + break; + case CFG_NODEV_TMO: /* nodev-tmo */ + value = (void *)((ulong)lpfc_nodev_tmo); + if(lpfc15_nodev_tmo != -1) + value = (void *)((ulong)lpfc15_nodev_tmo); + break; + case CFG_LINK_SPEED: /* link-speed */ + value = (void *)((ulong)lpfc_link_speed); + if(lpfc15_link_speed != -1) + value = (void *)((ulong)lpfc15_link_speed); + break; + case CFG_DQFULL_THROTTLE_UP_TIME: /* dqfull-throttle-up-time */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_time); + if(lpfc15_dqfull_throttle_up_time != -1) + value = (void *)((ulong)lpfc15_dqfull_throttle_up_time); + break; + case CFG_DQFULL_THROTTLE_UP_INC: /* dqfull-throttle-up-inc */ + value = (void *)((ulong)lpfc_dqfull_throttle_up_inc); + if(lpfc15_dqfull_throttle_up_inc != -1) + value = (void *)((ulong)lpfc15_dqfull_throttle_up_inc); + break; + } + break; + default: + break; + } + return(value); +} + + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/lpfc/lpfc.spec 830-ivtv/drivers/scsi/lpfc/lpfc.spec --- 000-virgin/drivers/scsi/lpfc/lpfc.spec Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/lpfc/lpfc.spec Thu Jan 8 10:21:53 2004 @@ -0,0 +1,127 @@ +#******************************************************************* +# * This file is part of the Emulex Linux Device Driver for * +# * Enterprise Fibre Channel Host Bus Adapters. * +# * Refer to the README file included with this package for * +# * driver version and adapter support. * +# * Copyright (C) 2003 Emulex Corporation. * +# * www.emulex.com * +# * * +# * This program is free software; you can redistribute it and/or * +# * modify it under the terms of the GNU General Public License * +# * as published by the Free Software Foundation; either version 2 * +# * of the License, or (at your option) any later version. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU General Public License for more details, a copy of which * +# * can be found in the file COPYING included with this package. * +# ******************************************************************* +%define rel 1 +%define ver LPFC_DRIVER_VERSION +%define tarName lpfcdriver.tar + +Summary: Emulex Driver Kit for Linux +Name: lpfcdriver +Version: %ver +Release: %rel +Copyright: Emulex Corp. +Group: System Environment/Kernel +Source: %tarName +URL: http://www.emulex.com +Vendor: Emulex Corp. +Packager: Regis.Goupil +BuildRoot: /tmp/lpfc-%{ver} +Requires: kernel >= 2.2.0 +Requires: rpm >= 3.0.4 + +%description +Emulex Open Source Fibre Channel driver for Linux version %ver + +%prep + +%build +rm -rf %{buildroot} +mkdir -p %{buildroot}/lpfc-%{ver} +cd lpfc-%{ver} +find . -print | cpio -pdumv %{buildroot}/ + +%install +cd %{buildroot}/lpfc-%{ver} +tar -xf /usr/src/redhat/SOURCES/lpfc-%{ver}/lpfcdriver.tar +if [ -e /usr/src/linux-2.4/drivers/scsi ]; then dirval="linux-2.4"; \ +else if [ -e /usr/src/linux/drivers/scsi ]; then dirval="linux"; \ +else echo "Cannot find the kernel sources directory"; exit 1; fi fi +if [ -e /usr/src/$dirval/drivers/scsi/lpfc/ ]; then \ +rm -fr /usr/src/$dirval/drivers/scsi/lpfc; +fi +mkdir -p /usr/src/$dirval/drivers/scsi/lpfc; +cp * /usr/src/$dirval/drivers/scsi/lpfc; + +# post install (on client machine) section +%post +if [ -e /usr/src/linux-2.4/drivers/scsi ]; then dirval="linux-2.4"; \ +else if [ -e /usr/src/linux/drivers/scsi ]; then dirval="linux"; \ +else echo "Cannot find the kernel sources directory"; exit 1; fi fi +rm -fr lpfc-%{ver}/lpfc; +rm -fr /usr/src/$dirval/drivers/scsi/lpfc; +mkdir /usr/src/$dirval/drivers/scsi/lpfc; +cp lpfc-%{ver}/* /usr/src/$dirval/drivers/scsi/lpfc; + +echo " " +echo "The Emulex Open Source Driver has been installed on your system." +echo "Source files have been installed under a temporary directory /lpfc-%{ver}" +echo "and under /usr/src/$dirval/drivers/scsi/lpfc." +echo "Please refer to the Emulex documentation for the next step." +echo " " + +%preun +if [ -e /usr/src/linux-2.4/drivers/scsi/lpfc ]; then dirval="linux-2.4"; \ +else if [ -e /usr/src/linux/drivers/scsi/lpfc ]; then dirval="linux"; fi fi +echo " " +echo "The lpfcdriver rpm is about to be removed from your system." +echo "All the source files under /usr/src/$dirval/drivers/scsi/lpfc" +echo "and /lpfc-%{ver} will be removed." +echo " " + +%postun +if [ -e /usr/src/linux-2.4/drivers/scsi/lpfc ]; then dirval="linux-2.4"; \ +else if [ -e /usr/src/linux/drivers/scsi/lpfc ]; then dirval="linux"; fi fi +rm -fr /usr/src/$dirval/drivers/scsi/lpfc; +echo " " +echo "The Emulex Open Source Driver has been removed from your system." +echo "Remove the appropriate entry in modules.conf if this file was modified." +echo " " +rm -fr lpfc-%{ver}; + +%files +/lpfc-%{ver}/COPYING +/lpfc-%{ver}/dfcdd.c +/lpfc-%{ver}/dfc.h +/lpfc-%{ver}/fcclockb.c +/lpfc-%{ver}/fc_crtn.h +/lpfc-%{ver}/fcdds.h +/lpfc-%{ver}/fcdiag.h +/lpfc-%{ver}/fcelsb.c +/lpfc-%{ver}/fc_ertn.h +/lpfc-%{ver}/fcfgparm.h +/lpfc-%{ver}/fc.h +/lpfc-%{ver}/fc_hw.h +/lpfc-%{ver}/fcLINUXfcp.c +/lpfc-%{ver}/fcLINUXlan.c +/lpfc-%{ver}/fcmboxb.c +/lpfc-%{ver}/fcmemb.c +/lpfc-%{ver}/fcmsgcom.c +/lpfc-%{ver}/fcmsg.h +/lpfc-%{ver}/fc_os.h +/lpfc-%{ver}/fcrpib.c +/lpfc-%{ver}/fcscsib.c +/lpfc-%{ver}/fcstratb.c +/lpfc-%{ver}/fcxmitb.c +/lpfc-%{ver}/hbaapi.h +/lpfc-%{ver}/lp6000.c +/lpfc-%{ver}/lpfc.conf.c +/lpfc-%{ver}/lpfc.conf.defs +/lpfc-%{ver}/Makefile +/lpfc-%{ver}/README +/lpfc-%{ver}/lpfc.spec diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/Kconfig 830-ivtv/drivers/scsi/qla2xxx/Kconfig --- 000-virgin/drivers/scsi/qla2xxx/Kconfig Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/Kconfig Thu Jan 8 10:22:00 2004 @@ -0,0 +1,33 @@ +config SCSI_QLA2XXX + bool "QLogic ISP2xxx PCI/PCI-X Fibre Channel HBA Support" + depends on PCI && SCSI + ---help--- + These drivers support the QLogic 2xxx host adapter family of SCSI FCP + HBAs. + +config SCSI_QLA21XX + tristate "ISP2100 host adapter family support" + depends on SCSI_QLA2XXX + ---help--- + This driver supports the QLogic 21xx (ISP2100) host adapter family. + +config SCSI_QLA22XX + tristate "ISP2200 host adapter family support" + depends on SCSI_QLA2XXX + ---help--- + This driver supports the QLogic 22xx (ISP2200) host adapter family. + +config SCSI_QLA23XX + tristate "ISP23xx host adapter family support" + depends on SCSI_QLA2XXX + ---help--- + This driver supports the QLogic 23xx (ISP2300, ISP2312, and ISP2322) + host adapter family. + +config SCSI_QLA2XXX_FAILOVER_ENABLE + bool "Compile in Failover code" + depends on SCSI_QLA2XXX + ---help--- + Compile the driver with failover support. Please review the driver + documentation for further information on supported hosts and storage + types. diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/Makefile 830-ivtv/drivers/scsi/qla2xxx/Makefile --- 000-virgin/drivers/scsi/qla2xxx/Makefile Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/Makefile Thu Jan 8 10:22:00 2004 @@ -0,0 +1,18 @@ +EXTRA_CFLAGS += -g -Idrivers/scsi -DUNIQUE_FW_NAME + +qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \ + qla_dbg.o qla_sup.o qla_rscn.o qla_xioct.o qla_inioct.o + +qla2xxx-$(CONFIG_SCSI_QLA2XXX_FAILOVER_ENABLE) += qla_fo.o qla_foln.o \ + qla_cfg.o qla_cfgln.o + +qla2100-y := ql2100.o ql2100_fw.o +qla2200-y := ql2200.o ql2200_fw.o +qla2300-y := ql2300.o ql2300_fw.o #ql2322_fw.o + +host-progs := extras/qla_nvr +always := $(host-progs) + +obj-$(CONFIG_SCSI_QLA21XX) += qla2xxx.o qla2100.o +obj-$(CONFIG_SCSI_QLA22XX) += qla2xxx.o qla2200.o +obj-$(CONFIG_SCSI_QLA23XX) += qla2xxx.o qla2300.o diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/exioct.h 830-ivtv/drivers/scsi/qla2xxx/exioct.h --- 000-virgin/drivers/scsi/qla2xxx/exioct.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/exioct.h Thu Jan 8 10:22:00 2004 @@ -0,0 +1,995 @@ +/****************************************************************************** + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + ******************************************************************************/ + +/* + * File Name: exioct.h + * + * San/Device Management Ioctl Header + * File is created to adhere to Solaris requirement using 8-space tabs. + * + * !!!!! PLEASE DO NOT REMOVE THE TABS !!!!! + * !!!!! PLEASE NO SINGLE LINE COMMENTS: // !!!!! + * !!!!! PLEASE NO MORE THAN 80 CHARS PER LINE !!!!! + * + * Revision History: + * + * Rev. 0 March 1, 2000 + * YPL - Created. + * + * Rev. 1 March 2, 2000 + * RLU - Updated with latest definitions. Added more comments. + * + * Rev. 2 May 16, 2000 + * SP - Updated definitions and changed structures (March 27, 2000) + * SP - Addded structures + * + * Rev. 3 June 1, 2000 + * THL - Made major changes to include all changes talked in our meeting. + * + * Rev. 4 June 5, 2000 + * RLU - Added new definitions/structures for SDM_GET_AEN and SDM_REG_AEN + * functions. + * - Major definition/structure name changes as discussed in meetings. + * - Deleted duplicated command code and structure definitions. + * + * Rev. 4.1 June 14, 2000 + * WTR - Moved Solaris specific defines to exioctso.h. This makes it + * possible for application developers to include only exioct.h + * in their Solaris application development. + * + * Rev. 4.2 June 15, 2000 + * THL - Changed UINT16 and UINT32 back to WORD and DWORD for NT; otherwise, + * NT will get a compilation error for redefining UINT16 and UINT32. + * Added RISC_CODE/FLASH_RAM macros. + * + * Rev. 4.3 June 22, 2000 + * THL - Changed SDM_FC_ADDR according to External Ioctls document. + * Added SDM_DEF_TYPE macros. + * + * Rev. 4.4 June 22, 2000 + * THL - Moved NT specific defines to exioctnt.h. + * + * Rev. 4.5 August 15, 2000 + * SP - Rolled back some changes made by Todd R. + * Kept new status code SDM_STATUS_NO_MEMORY + * Port types fabric and tape device + * + * Rev. 4.7 Sep 6, 2000 + * YPL - Replace SDM_ with EXT_, _ISP with _CHIP. + * Add vendor specific statuses, device update, config defines. + * + * Rev. 5.0 Sep 13, 2000 + * YPL - Update version to 5, remove max defines, make port type bit. + * Change HBA_PORT_PROPERTY to have bus/target/lun defined as UINT16 + * + * Rev. 5.1 Sep 22, 2000 + * THL - Add destination address for specify scsi address or FC address. + * Remove "not support" comment and add more macros. + * + * Rev. 5.2 Sep 27, 2000 + * THL - Add new macros and structure for add and swap target device. + * Create new data structure for get port database. + * TLE - Merge changes needed for FailOver + * + * Rev. 5.3 Sep 29, 2000 + * THL - Add access mode for NVRAM. + * + * Rev. 5.4 Oct 03, 2000 + * THL - Add EXT_SC_GET_FC_STATISTICS. + * + * Rev. 5.5 Oct 18, 2000 + * THL - Remove duplicated EXT_DEF_ADDR_MODE_32 and EXT_DEF_ADDR_MODE_16. + * Reformat new data structures and defines. + * + * Rev. 5.6 Oct 19, 2000 + * RLU - Changed file name from ExIoct.h to exioct.h. + * - Added definition of EXT_RNID_DATA for API implementation. + * - Reformat some lines to conform to the format agreed + * upon in IOCTL meeting (and mentioned at beginning of + * this file). + * + * Rev. 5.7 Oct 25, 2000 + * BN - Added LUN bitmask structure and macros + * + * Rev. 5.8 Oct 25, 2000 + * BN - Added EXT_CC_DRIVER_PROP define + * + * Rev. 5.9 Oct 26, 2000 + * BN - Sync with UnixApi project + * + * Rev. 5.10 Oct 30, 2000 + * BN - Remove not needed #define for EXT_CC_DRIVER_PROP + * - Add EXT_ to IS_LUN_BIT_SET, SET_LUN_BIT, CLR_LUN_BIT + * + * Rev. 5.11 Nov 1, 2000 + * BN - Increased [1] of EXT_DEVICEDATA to [EXT_MAX_TARGET] + * TLE - Decreased [EXT_MAX_TARGET] of EXT_DEVICEDATA to [1] + * + * Rev. 5.12 Nov 7, 2000 + * RLU - Deleted EXT_DEF_MAX_LUNS define and changed all references + * to it to use EXT_MAX_LUN. + * - Changed the revision numbers for the last 2 revisions down + * to use 5.x. + * + * Rev. 5.13 Nov 14, 2000 + * WTR - Fixed pointer referencing problem in the LUN_BIT_MASK macros. + * Updated comment at bit mask definition. + * + * Rev. 5.14 Dec 6, 2000 + * THL - Added Local and LoopID to discovered port/target property. + * + * Rev. 5.15 Dec 24, 2000 + * YPL - Enhance port connection modes and driver attrib + * + * Rev. 5.16 Dec 27, 2000 + * TLE - Add BufferHandle member to _EXT_ASYNC_EVENT data structure for + * SCTP support + * + * Rev. 5.17 Jan 10, 2001 + * YPL - Add edtov, ratov & fabric name in port property + * + * Rev. 5.18 Feb 28, 2001 + * YPL - Remove SCTP fields and add fabric parameter flags in port property + * + * Rev. 5.19 Mar 08, 2001 + * YPL - Remove SCTP fields from hba port prop + * + * Rev. 5.20 June 11, 2001 + * YPL - Change to reserved fields and add fabric name field in port property + * + * Rev. 5.21 June 29, 2001 + * YPL - Merge in changes decided long time ago (use _DEF_ for defines) & + * reserved some EXT_CC for legacy ioctls, plus add RNID dataformat + * values definition + * + * Rev. 5.21 Sep 18, 2001 + * SP - Added New return status codes + * + * Rev. 5.22 Oct 23, 2001 + * SP - Change reserve fields to add fields to EXT_HBA_PORT + * Added port speeds and FC4Types fields and related definitions + * + * Rev. 5.23 Dec 04, 2001 + * RL - Added port speed value definition. + * + * Rev. 5.24 Jan 20, 2002 + * JJ - Added PCI device function bits field in EXT_CHIP structure. + * + * Rev. 5.25 Feb 04, 2002 + * JJ - Added 16 bytes CDB support. Also added SenseLength field + * in SCSI_PASSTHRU structure. + * + * Rev. 5.26 Feb 12, 2002 + * AV - Changed type size used in SCSI_PASSTHRU structure definitions + * to re-enable gcc's automatic structure padding for backward + * compatibility. + * + * Rev. 5.27 Mar 01, 2002 + * RL - Added new SC value for SCSI3 command passthru. + * + * Rev. 5.28 Dec 09, 2002 + * Sync up with NT version of exioct.h: + * TLE - Modify EXT_RNID_REQ data structure for IBM SendRNID workaround + * YPL - Add firmware state (online diagnostics) + * YPL - Add ELS PS + * YPL - Add els event, # of els buffers & size + * + * Rev. 5.29 April 21, 2003 + * RA - Defined the structure EXT_BEACON_CONTROL and subcommand code: + * EXT_SC_GET_BEACON_STATE,EXT_SC_SET_BEACON_STATE for the + * led blinking feature. + * + * Rev. 5.30 July 21, 2003 + * RL - Added new statistics fields in HBA_PORT_STAT struct. + */ + +#ifndef _EXIOCT_H +#define _EXIOCT_H + +/* + * NOTE: the following version defines must be updated each time the + * changes made may affect the backward compatibility of the + * input/output relations of the SDM IOCTL functions. + */ +#define EXT_VERSION 5 + + +/* + * OS independent General definitions + */ +#define EXT_DEF_SIGNATURE_SIZE 8 +#define EXT_DEF_WWN_NAME_SIZE 8 +#define EXT_DEF_WWP_NAME_SIZE 8 +#define EXT_DEF_SERIAL_NUM_SIZE 4 +#define EXT_DEF_PORTID_SIZE 4 +#define EXT_DEF_PORTID_SIZE_ACTUAL 3 +#define EXT_DEF_MAX_STR_SIZE 128 +#define EXT_DEF_SCSI_PASSTHRU_CDB_LENGTH 16 + +#define EXT_DEF_ADDR_MODE_32 1 +#define EXT_DEF_ADDR_MODE_64 2 + +/* + * *********************************************************************** + * X OS type definitions + * *********************************************************************** + */ +#ifdef _MSC_VER /* NT */ + +#pragma pack(1) +#include "ExIoctNT.h" + +#elif defined(linux) /* Linux */ + +#include "exioctln.h" + +#elif defined(sun) || defined(__sun) /* Solaris */ + +#include "exioctso.h" + +#endif + +/* + * *********************************************************************** + * OS dependent General configuration defines + * *********************************************************************** + */ +#define EXT_DEF_MAX_HBA EXT_DEF_MAX_HBA_OS +#define EXT_DEF_MAX_BUS EXT_DEF_MAX_BUS_OS +#define EXT_DEF_MAX_TARGET EXT_DEF_MAX_TARGET_OS +#define EXT_DEF_MAX_LUN EXT_DEF_MAX_LUN_OS + +/* + * *********************************************************************** + * Common header struct definitions for San/Device Mgmt + * *********************************************************************** + */ +typedef struct { + UINT64 Signature; /* 8 chars string */ + UINT16 AddrMode; /* 2 */ + UINT16 Version; /* 2 */ + UINT16 SubCode; /* 2 */ + UINT16 Instance; /* 2 */ + UINT32 Status; /* 4 */ + UINT32 DetailStatus; /* 4 */ + UINT32 Reserved1; /* 4 */ + UINT32 RequestLen; /* 4 */ + UINT32 ResponseLen; /* 4 */ + UINT64 RequestAdr; /* 8 */ + UINT64 ResponseAdr; /* 8 */ + UINT16 HbaSelect; /* 2 */ + UINT16 VendorSpecificStatus[11]; /* 22 */ + UINT64 VendorSpecificData; /* 8 chars string */ +} EXT_IOCTL, *PEXT_IOCTL; /* 84 / 0x54 */ + +/* + * Addressing mode used by the user application + */ +#define EXT_ADDR_MODE EXT_ADDR_MODE_OS + +/* + * Status. These macros are being used for setting Status field in + * EXT_IOCTL structure. + */ +#define EXT_STATUS_OK 0 +#define EXT_STATUS_ERR 1 +#define EXT_STATUS_BUSY 2 +#define EXT_STATUS_PENDING 3 +#define EXT_STATUS_SUSPENDED 4 +#define EXT_STATUS_RETRY_PENDING 5 +#define EXT_STATUS_INVALID_PARAM 6 +#define EXT_STATUS_DATA_OVERRUN 7 +#define EXT_STATUS_DATA_UNDERRUN 8 +#define EXT_STATUS_DEV_NOT_FOUND 9 +#define EXT_STATUS_COPY_ERR 10 +#define EXT_STATUS_MAILBOX 11 +#define EXT_STATUS_UNSUPPORTED_SUBCODE 12 +#define EXT_STATUS_UNSUPPORTED_VERSION 13 +#define EXT_STATUS_MS_NO_RESPONSE 14 +#define EXT_STATUS_SCSI_STATUS 15 +#define EXT_STATUS_BUFFER_TOO_SMALL 16 +#define EXT_STATUS_NO_MEMORY 17 +#define EXT_STATUS_UNKNOWN 18 +#define EXT_STATUS_UNKNOWN_DSTATUS 19 +#define EXT_STATUS_INVALID_REQUEST 20 + +#define EXT_STATUS_DEVICE_NOT_READY 21 +#define EXT_STATUS_DEVICE_OFFLINE 22 +#define EXT_STATUS_HBA_NOT_READY 23 +#define EXT_STATUS_HBA_QUEUE_FULL 24 + +/* + * Detail Status contains the SCSI bus status codes. + */ + +#define EXT_DSTATUS_GOOD 0x00 +#define EXT_DSTATUS_CHECK_CONDITION 0x02 +#define EXT_DSTATUS_CONDITION_MET 0x04 +#define EXT_DSTATUS_BUSY 0x08 +#define EXT_DSTATUS_INTERMEDIATE 0x10 +#define EXT_DSTATUS_INTERMEDIATE_COND_MET 0x14 +#define EXT_DSTATUS_RESERVATION_CONFLICT 0x18 +#define EXT_DSTATUS_COMMAND_TERMINATED 0x22 +#define EXT_DSTATUS_QUEUE_FULL 0x28 + +/* + * Detail Status contains the needed Response buffer space(bytes) + * when Status = EXT_STATUS_BUFFER_TOO_SMALL + */ + + +/* + * Detail Status contains one of the following codes + * when Status = EXT_STATUS_INVALID_PARAM or + * = EXT_STATUS_DEV_NOT_FOUND + */ +#define EXT_DSTATUS_NOADNL_INFO 0x00 +#define EXT_DSTATUS_HBA_INST 0x01 +#define EXT_DSTATUS_TARGET 0x02 +#define EXT_DSTATUS_LUN 0x03 +#define EXT_DSTATUS_REQUEST_LEN 0x04 +#define EXT_DSTATUS_PATH_INDEX 0x05 + +/* + * Currently supported DeviceControl / ioctl command codes + */ +#define EXT_CC_QUERY EXT_CC_QUERY_OS +#define EXT_CC_SEND_FCCT_PASSTHRU EXT_CC_SEND_FCCT_PASSTHRU_OS +#define EXT_CC_REG_AEN EXT_CC_REG_AEN_OS +#define EXT_CC_GET_AEN EXT_CC_GET_AEN_OS +#define EXT_CC_SEND_ELS_RNID EXT_CC_SEND_ELS_RNID_OS +#define EXT_CC_SEND_SCSI_PASSTHRU EXT_CC_SCSI_PASSTHRU_OS +#define EXT_CC_SEND_ELS_PASSTHRU EXT_CC_SEND_ELS_PASSTHRU_OS + +/* + * HBA port operations + */ +#define EXT_CC_GET_DATA EXT_CC_GET_DATA_OS +#define EXT_CC_SET_DATA EXT_CC_SET_DATA_OS + + +/* Reserved command codes. */ +#define EXT_CC_RESERVED0A EXT_CC_RESERVED0A_OS +#define EXT_CC_RESERVED0B EXT_CC_RESERVED0B_OS +#define EXT_CC_RESERVED0C EXT_CC_RESERVED0C_OS +#define EXT_CC_RESERVED0D EXT_CC_RESERVED0D_OS +#define EXT_CC_RESERVED0E EXT_CC_RESERVED0E_OS +#define EXT_CC_RESERVED0F EXT_CC_RESERVED0F_OS +#define EXT_CC_RESERVED0G EXT_CC_RESERVED0G_OS +#define EXT_CC_RESERVED0H EXT_CC_RESERVED0H_OS +#define EXT_CC_RESERVED0I EXT_CC_RESERVED0I_OS +#define EXT_CC_RESERVED0J EXT_CC_RESERVED0J_OS +#define EXT_CC_RESERVED0Z EXT_CC_RESERVED0Z_OS + + +/* + * *********************************************************************** + * EXT_IOCTL SubCode definition. + * These macros are being used for setting SubCode field in EXT_IOCTL + * structure. + * *********************************************************************** + */ + +/* + * Query. + * Uses with EXT_QUERY as the ioctl code. + */ +#define EXT_SC_QUERY_HBA_NODE 1 +#define EXT_SC_QUERY_HBA_PORT 2 +#define EXT_SC_QUERY_DISC_PORT 3 +#define EXT_SC_QUERY_DISC_TGT 4 +#define EXT_SC_QUERY_DISC_LUN 5 /* Currently Not Supported */ +#define EXT_SC_QUERY_DRIVER 6 +#define EXT_SC_QUERY_FW 7 +#define EXT_SC_QUERY_CHIP 8 + +/* + * Sub codes for Get Data. + * Use in combination with EXT_GET_DATA as the ioctl code + */ +/* 1 - 99 Common */ +#define EXT_SC_GET_SCSI_ADDR 1 /* Currently Not Supported */ +#define EXT_SC_GET_ERR_DETECTIONS 2 /* Currently Not Supported */ +#define EXT_SC_GET_STATISTICS 3 +#define EXT_SC_GET_BUS_MODE 4 /* Currently Not Supported */ +#define EXT_SC_GET_DR_DUMP_BUF 5 /* Currently Not Supported */ +#define EXT_SC_GET_RISC_CODE 6 /* Currently Not Supported */ +#define EXT_SC_GET_FLASH_RAM 7 /* for backward compatible */ +#define EXT_SC_GET_BEACON_STATE 8 + +/* 100 - 199 FC_INTF_TYPE */ +#define EXT_SC_GET_LINK_STATUS 101 /* Currently Not Supported */ +#define EXT_SC_GET_LOOP_ID 102 /* Currently Not Supported */ +#define EXT_SC_GET_LUN_BITMASK 103 +#define EXT_SC_GET_PORT_DATABASE 104 /* Currently Not Supported */ +#define EXT_SC_GET_PORT_DATABASE_MEM 105 /* Currently Not Supported */ +#define EXT_SC_GET_PORT_SUMMARY 106 +#define EXT_SC_GET_POSITION_MAP 107 +#define EXT_SC_GET_RETRY_CNT 108 /* Currently Not Supported */ +#define EXT_SC_GET_RNID 109 +#define EXT_SC_GET_RTIN 110 /* Currently Not Supported */ +#define EXT_SC_GET_FC_LUN_BITMASK 111 +#define EXT_SC_GET_FC_STATISTICS 112 /* for backward compatible */ + +/* 200 - 299 SCSI_INTF_TYPE */ +#define EXT_SC_GET_SEL_TIMEOUT 201 /* Currently Not Supported */ + + +/* + * Sub codes for Set Data. + * Use in combination with EXT_SET_DATA as the ioctl code + */ +/* 1 - 99 Common */ +#define EXT_SC_RST_STATISTICS 3 +#define EXT_SC_RESERVED_BC7 7 +#define EXT_SC_SET_BEACON_STATE 8 + +/* 100 - 199 FC_INTF_TYPE */ +#define EXT_SC_SET_LUN_BITMASK 103 +#define EXT_SC_SET_RNID 109 +#define EXT_SC_SET_FC_LUN_BITMASK 111 +#define EXT_SC_RESERVED_BC112 112 +#define EXT_SC_RESERVED_BC113 113 + +/* 200 - 299 SCSI_INTF_TYPE */ + +/* SCSI passthrough */ +#define EXT_SC_SEND_SCSI_PASSTHRU 0 +#define EXT_SC_SEND_FC_SCSI_PASSTHRU 1 +#define EXT_SC_SCSI3_PASSTHRU 2 + +/* Read */ + +/* Write */ + +/* Reset */ + +/* Request struct */ + + +/* + * Response struct + */ +typedef struct _EXT_HBA_NODE { + UINT8 WWNN [EXT_DEF_WWN_NAME_SIZE]; /* 8 */ + UINT8 Manufacturer [EXT_DEF_MAX_STR_SIZE]; /* 128; "QLOGIC" */ + UINT8 Model [EXT_DEF_MAX_STR_SIZE]; /* 128; "QLA2200" */ + UINT8 SerialNum [EXT_DEF_SERIAL_NUM_SIZE];/* 4; 123 */ + UINT8 DriverVersion[EXT_DEF_MAX_STR_SIZE]; /* 128; "7.4.3" */ + UINT8 FWVersion [EXT_DEF_MAX_STR_SIZE]; /* 128; "2.1.6" */ + + /* The following field is currently not supported */ + UINT8 OptRomVersion[EXT_DEF_MAX_STR_SIZE]; /* 128; "1.44" */ + + UINT16 PortCount; /* 2; 1 */ + UINT16 InterfaceType; /* 2; FC/SCSI */ + + /* The following two fields are not yet supported */ + UINT32 DriverAttr; /* 4 */ + UINT32 FWAttr; /* 4 */ + + UINT32 Reserved[8]; /* 32 */ +} EXT_HBA_NODE, *PEXT_HBA_NODE; /* 696 */ + +/* HBA node query interface type */ +#define EXT_DEF_FC_INTF_TYPE 1 +#define EXT_DEF_SCSI_INTF_TYPE 2 + +typedef struct _EXT_HBA_PORT { + UINT8 WWPN[EXT_DEF_WWN_NAME_SIZE]; /* 8 */ + UINT8 Id [EXT_DEF_PORTID_SIZE]; /* 4; 3 bytes valid Port Id. */ + UINT16 Type; /* 2; Port Type */ + UINT16 State; /* 2; Port State */ + UINT16 Mode; /* 2 */ + UINT16 DiscPortCount; /* 2 */ + UINT16 DiscPortNameType; /* 2; USE_NODE_NAME or */ + /* USE_PORT_NAME */ + UINT16 DiscTargetCount; /* 2 */ + UINT16 Bus; /* 2 */ + UINT16 Target; /* 2 */ + UINT16 Lun; /* 2 */ + /* 2 */ + UINT8 PortSupportedFC4Types; + UINT8 PortActiveFC4Types; + UINT8 FabricName[EXT_DEF_WWN_NAME_SIZE]; /* 8 */ + + /* 2*/ + UINT8 PortSupportedSpeed; + UINT8 PortSpeed; + UINT16 Unused; /* 2 */ + UINT32 Reserved[3]; /* 12 */ +} EXT_HBA_PORT, *PEXT_HBA_PORT; /* 56 */ + +/* port type */ +#define EXT_DEF_INITIATOR_DEV 1 +#define EXT_DEF_TARGET_DEV 2 +#define EXT_DEF_TAPE_DEV 4 +#define EXT_DEF_FABRIC_DEV 8 + + +/* HBA port state */ +#define EXT_DEF_HBA_OK 0 +#define EXT_DEF_HBA_SUSPENDED 1 +#define EXT_DEF_HBA_LOOP_DOWN 2 + +/* Connection mode */ +#define EXT_DEF_UNKNOWN_MODE 0 +#define EXT_DEF_P2P_MODE 1 +#define EXT_DEF_LOOP_MODE 2 +#define EXT_DEF_FL_MODE 3 +#define EXT_DEF_N_MODE 4 + +/* Valid name type for Disc. port/target */ +#define EXT_DEF_USE_NODE_NAME 1 +#define EXT_DEF_USE_PORT_NAME 2 + +/* FC4 type values */ +#define EXT_DEF_FC4_TYPE_SCSI 0x1 +#define EXT_DEF_FC4_TYPE_IP 0x2 +#define EXT_DEF_FC4_TYPE_SCTP 0x4 +#define EXT_DEF_FC4_TYPE_VI 0x8 + +/* Port Speed values */ +#define EXT_DEF_PORTSPEED_1GBIT 1 +#define EXT_DEF_PORTSPEED_2GBIT 2 +#define EXT_DEF_PORTSPEED_10GBIT 4 + +typedef struct _EXT_DISC_PORT { + UINT8 WWNN[EXT_DEF_WWN_NAME_SIZE]; /* 8 */ + UINT8 WWPN[EXT_DEF_WWN_NAME_SIZE]; /* 8 */ + UINT8 Id [EXT_DEF_PORTID_SIZE]; + /* 4; last 3 bytes used. big endian */ + + /* The following fields currently are not supported */ + UINT16 Type; /* 2; Port Type */ + UINT16 Status; /* 2; Port Status */ + UINT16 Bus; /* 2; n/a for Solaris */ + + UINT16 TargetId; /* 2 */ + UINT8 Local; /* 1; Local or Remote */ + UINT8 ReservedByte[1]; /* 1 */ + + UINT16 LoopID; /* 2; Loop ID */ + + UINT32 Reserved[7]; /* 28 */ +} EXT_DISC_PORT, *PEXT_DISC_PORT; /* 60 */ + +typedef struct _EXT_DISC_TARGET { + UINT8 WWNN[EXT_DEF_WWN_NAME_SIZE]; /* 8 */ + UINT8 WWPN[EXT_DEF_WWN_NAME_SIZE]; /* 8 */ + UINT8 Id [EXT_DEF_PORTID_SIZE]; + /* 4; last 3 bytes used. big endian */ + + /* The following fields currently are not supported */ + UINT16 Type; /* 2; Target Type */ + UINT16 Status; /* 2; Target Status*/ + UINT16 Bus; /* 2; n/a for Solaris */ + + UINT16 TargetId; /* 2 */ + + /* The following field is currently not supported */ + UINT16 LunCount; /* 2; n/a for nt */ + + UINT8 Local; /* 1; Local or Remote */ + UINT8 ReservedByte[1]; /* 1 */ + + UINT16 LoopID; /* 2; Loop ID */ + + UINT16 Reserved[13]; /* 26 */ +} EXT_DISC_TARGET, *PEXT_DISC_TARGET; /* 60 */ + +/* The following command is not supported */ +typedef struct _EXT_DISC_LUN { /* n/a for nt */ + UINT16 Id; /* 2 */ + UINT16 State; /* 2 */ + UINT16 IoCount; /* 2 */ + UINT16 Reserved[15]; /* 30 */ +} EXT_DISC_LUN, *PEXT_DISC_LUN; /* 36 */ + + +/* SCSI address */ +typedef struct _EXT_SCSI_ADDR { + UINT16 Bus; /* 2 */ + UINT16 Target; /* 2 */ + UINT16 Lun; /* 2 */ + UINT16 Padding[5]; /* 10 */ +} EXT_SCSI_ADDR, *PEXT_SCSI_ADDR; /* 16 */ + + +/* Fibre Channel address */ +typedef struct _EXT_FC_ADDR { + union { + UINT8 WWNN[EXT_DEF_WWN_NAME_SIZE]; /* 8 */ + UINT8 WWPN[EXT_DEF_WWN_NAME_SIZE]; /* 8 */ + UINT8 Id[EXT_DEF_PORTID_SIZE]; /* 4 */ + } FcAddr; + UINT16 Type; /* 2 */ + UINT16 Padding[2]; /* 2 */ +} EXT_FC_ADDR, *PEXT_FC_ADDR; /* 24 */ + +#define EXT_DEF_TYPE_WWNN 1 +#define EXT_DEF_TYPE_WWPN 2 +#define EXT_DEF_TYPE_PORTID 3 +#define EXT_DEF_TYPE_FABRIC 4 + + +/* Destination address */ +typedef struct _EXT_DEST_ADDR { + union { + UINT8 WWNN[EXT_DEF_WWN_NAME_SIZE]; /* 8 */ + UINT8 WWPN[EXT_DEF_WWN_NAME_SIZE]; /* 8 */ + UINT8 Id[EXT_DEF_PORTID_SIZE]; /* 4 */ + struct { + UINT16 Bus; /* 2 */ + UINT16 Target; /* 2 */ + } ScsiAddr; + } DestAddr; + UINT16 DestType; /* 2 */ + UINT16 Lun; /* 2 */ + UINT16 Padding[2]; /* 4 */ +} EXT_DEST_ADDR, *PEXT_DEST_ADDR; /* 16 */ + + +#define EXT_DEF_DESTTYPE_WWNN 1 +#define EXT_DEF_DESTTYPE_WWPN 2 +#define EXT_DEF_DESTTYPE_PORTID 3 +#define EXT_DEF_DESTTYPE_FABRIC 4 +#define EXT_DEF_DESTTYPE_SCSI 5 + +/* Statistic */ +#if defined(linux) /* Linux */ +typedef struct _EXT_HBA_PORT_STAT { + UINT32 ControllerErrorCount; /* 4 */ + UINT32 DeviceErrorCount; /* 4 */ + UINT32 TotalIoCount; /* 4 */ + UINT32 TotalMBytes; /* 4; MB of data processed */ + UINT32 TotalLipResets; /* 4; Total no. of LIP Reset */ + UINT32 Reserved2; /* 4 */ + UINT32 TotalLinkFailures; /* 4 */ + UINT32 TotalLossOfSync; /* 4 */ + UINT32 TotalLossOfSignals; /* 4 */ + UINT32 PrimitiveSeqProtocolErrorCount;/* 4 */ + UINT32 InvalidTransmissionWordCount; /* 4 */ + UINT32 InvalidCRCCount; /* 4 */ + uint64_t InputRequestCount; /* 8 */ + uint64_t OutputRequestCount; /* 8 */ + uint64_t ControlRequestCount; /* 8 */ + uint64_t InputMBytes; /* 8 */ + uint64_t OutputMBytes; /* 8 */ + UINT32 Reserved[6]; /* 24 */ +} EXT_HBA_PORT_STAT, *PEXT_HBA_PORT_STAT; /* 112 */ +#else +typedef struct _EXT_HBA_PORT_STAT { + UINT32 ControllerErrorCount; /* 4 */ + UINT32 DeviceErrorCount; /* 4 */ + UINT32 TotalIoCount; /* 4 */ + UINT32 TotalMBytes; /* 4; MB of data processed */ + UINT32 TotalLipResets; /* 4; Total no. of LIP Reset */ + UINT32 Reserved2; /* 4 */ + UINT32 TotalLinkFailures; /* 4 */ + UINT32 TotalLossOfSync; /* 4 */ + UINT32 TotalLossOfSignals; /* 4 */ + UINT32 PrimitiveSeqProtocolErrorCount;/* 4 */ + UINT32 InvalidTransmissionWordCount; /* 4 */ + UINT32 InvalidCRCCount; /* 4 */ + UINT64 InputRequestCount; /* 8 */ + UINT64 OutputRequestCount; /* 8 */ + UINT64 ControlRequestCount; /* 8 */ + UINT64 InputMBytes; /* 8 */ + UINT64 OutputMBytes; /* 8 */ + UINT32 Reserved[6]; /* 24 */ +} EXT_HBA_PORT_STAT, *PEXT_HBA_PORT_STAT; /* 112 */ +#endif + + +/* Driver property */ +typedef struct _EXT_DRIVER { + UINT8 Version[EXT_DEF_MAX_STR_SIZE];/* 128 */ + UINT16 NumOfBus; /* 2; Port Type */ + UINT16 TargetsPerBus; /* 2; Port Status */ + UINT16 LunsPerTarget; /* 2 */ + UINT32 MaxTransferLen; /* 4 */ + UINT32 MaxDataSegments; /* 4 */ + UINT16 DmaBitAddresses; /* 2 */ + UINT16 IoMapType; /* 2 */ + UINT32 Attrib; /* 4 */ + UINT32 InternalFlags[4]; /* 16 */ + UINT32 Reserved[8]; /* 32 */ +} EXT_DRIVER, *PEXT_DRIVER; /* 198 */ + + +/* Firmware property */ +typedef struct _EXT_FW { + UINT8 Version[EXT_DEF_MAX_STR_SIZE];/* 128 */ + UINT32 Attrib; /* 4 */ + UINT16 Reserved[33]; /* 66 */ +} EXT_FW, *PEXT_FW; /* 198 */ + + +/* ISP/Chip property */ +typedef struct _EXT_CHIP { + UINT16 VendorId; /* 2 */ + UINT16 DeviceId; /* 2 */ + UINT16 SubVendorId; /* 2 */ + UINT16 SubSystemId; /* 2 */ + UINT16 PciBusNumber; /* 2 */ + UINT16 PciSlotNumber; /* 2 */ + UINT32 IoAddr; /* 4 */ + UINT32 IoAddrLen; /* 4 */ + UINT32 MemAddr; /* 4 */ + UINT32 MemAddrLen; /* 4 */ + UINT16 ChipType; /* 2 */ + UINT16 InterruptLevel; /* 2 */ + UINT16 OutMbx[8]; /* 16 */ + UINT16 PciDevFunc; /* 2 */ + UINT16 Reserved[15]; /* 30 */ +} EXT_CHIP, *PEXT_CHIP; /* 80 */ + + +/* Request Buffer for RNID */ +typedef struct _EXT_RNID_REQ { + EXT_FC_ADDR Addr; /* 14 */ + UINT8 DataFormat; /* 1 */ + UINT8 Pad; /* 1 */ + UINT8 OptWWN[EXT_DEF_WWN_NAME_SIZE]; /* 8 */ + UINT8 OptPortId[EXT_DEF_PORTID_SIZE]; /* 4 */ + UINT32 Reserved[12]; /* 48 */ + UINT8 Pad1[3]; /* 3 */ +} EXT_RNID_REQ, *PEXT_RNID_REQ; /* 79 */ + +#define EXT_DEF_RNID_DFORMAT_NONE 0 +#define EXT_DEF_RNID_DFORMAT_TOPO_DISC 0xDF + +/* Request Buffer for Set RNID */ +typedef struct _EXT_SET_RNID_REQ { + UINT8 IPVersion[2]; + UINT8 UDPPortNumber[2]; + UINT8 IPAddress[16]; + UINT32 Reserved[16]; +} EXT_SET_RNID_REQ, *PEXT_SET_RNID_REQ; + +/* RNID definition and data struct */ +#define SEND_RNID_RSP_SIZE 72 + +typedef struct _RNID_DATA +{ + UINT8 WWN[16]; /* 16 */ + UINT32 UnitType; /* 4 */ + UINT8 PortId[4]; /* 4 */ + UINT32 NumOfAttachedNodes; /* 4 */ + UINT8 IPVersion[2]; /* 2 */ + UINT8 UDPPortNumber[2]; /* 2 */ + UINT8 IPAddress[16]; /* 16 */ + UINT16 Reserved; /* 2 */ + UINT16 TopoDiscFlags; /* 2 */ +} EXT_RNID_DATA, *PEXT_RNID_DATA; /* 52 */ + + +/* SCSI pass-through */ +typedef struct _EXT_SCSI_PASSTHRU { + EXT_SCSI_ADDR TargetAddr; + UINT8 Direction; + UINT8 CdbLength; + UINT8 Cdb[EXT_DEF_SCSI_PASSTHRU_CDB_LENGTH]; + UINT32 Reserved[14]; + UINT16 Reserved2; + UINT16 SenseLength; + UINT8 SenseData[256]; +} EXT_SCSI_PASSTHRU, *PEXT_SCSI_PASSTHRU; + +/* FC SCSI pass-through */ +typedef struct _EXT_FC_SCSI_PASSTHRU { + EXT_DEST_ADDR FCScsiAddr; + UINT8 Direction; + UINT8 CdbLength; + UINT8 Cdb[EXT_DEF_SCSI_PASSTHRU_CDB_LENGTH]; + UINT32 Reserved[14]; + UINT16 Reserved2; + UINT16 SenseLength; + UINT8 SenseData[256]; +} EXT_FC_SCSI_PASSTHRU, *PEXT_FC_SCSI_PASSTHRU; + +/* SCSI pass-through direction */ +#define EXT_DEF_SCSI_PASSTHRU_DATA_IN 1 +#define EXT_DEF_SCSI_PASSTHRU_DATA_OUT 2 + + +/* EXT_REG_AEN Request struct */ +typedef struct _EXT_REG_AEN { + UINT32 Enable; /* 4; non-0 to enable, 0 to disable. */ + UINT32 Reserved; /* 4 */ +} EXT_REG_AEN, *PEXT_REG_AEN; /* 8 */ + +/* EXT_GET_AEN Response struct */ +typedef struct _EXT_ASYNC_EVENT { + UINT32 AsyncEventCode; /* 4 */ + union { + struct { + UINT8 RSCNInfo[EXT_DEF_PORTID_SIZE_ACTUAL];/* 3, BE */ + UINT8 AddrFormat; /* 1 */ + UINT32 Rsvd_1[2]; /* 8 */ + } RSCN; + + UINT32 Reserved[3]; /* 12 */ + } Payload; +} EXT_ASYNC_EVENT, *PEXT_ASYNC_EVENT; /* 16 */ + + +/* Asynchronous Event Codes */ +#define EXT_DEF_LIP_OCCURRED 0x8010 +#define EXT_DEF_LINK_UP 0x8011 +#define EXT_DEF_LINK_DOWN 0x8012 +#define EXT_DEF_LIP_RESET 0x8013 +#define EXT_DEF_RSCN 0x8015 +#define EXT_DEF_DEVICE_UPDATE 0x8014 +#define EXT_DEF_ELS 0x8200 + +/* Required # of entries in the queue buffer allocated. */ +#define EXT_DEF_MAX_AEN_QUEUE EXT_DEF_MAX_AEN_QUEUE_OS +#define EXT_DEF_MAX_ELS_BUFS EXT_DEF_MAX_ELS_BUFS_OS +#define EXT_DEF_SIZE_ELS_BUF EXT_DEF_SIZE_ELS_BUF_OS + +/* Device type to get for EXT_SC_GET_PORT_SUMMARY */ +#define EXT_DEF_GET_KNOWN_DEVICE 0x1 +#define EXT_DEF_GET_VISIBLE_DEVICE 0x2 +#define EXT_DEF_GET_HIDDEN_DEVICE 0x4 +#define EXT_DEF_GET_FABRIC_DEVICE 0x8 +#define EXT_DEF_GET_LOOP_DEVICE 0x10 + +/* Each entry in device database */ +typedef struct _EXT_DEVICEDATAENTRY +{ + UINT8 NodeWWN[8]; /* Node World Wide Name for device */ + UINT8 PortWWN[8]; /* Port World Wide Name for device */ + UINT8 PortID[3]; /* Current PortId for device */ + UINT8 ControlFlags; /* Control flag */ + EXT_SCSI_ADDR TargetAddress; /* scsi address */ + UINT32 DeviceFlags; /* Flags for device */ + UINT16 LoopID; /* Loop ID */ + UINT16 BaseLunNumber; + UINT32 Reserved[32]; +} EXT_DEVICEDATAENTRY, *PEXT_DEVICEDATAENTRY; + +/* Device database information */ +typedef struct _EXT_DEVICEDATA +{ + UINT32 TotalDevices; /* Set to total number of device. */ + UINT32 ReturnListEntryCount; /* Set to number of device entries */ + /* returned in list. */ + + EXT_DEVICEDATAENTRY EntryList[1]; /* Variable length */ +} EXT_DEVICEDATA, *PEXT_DEVICEDATA; + + +/* Swap Target Device Data structure */ +typedef struct _EXT_SWAPTARGETDEVICE +{ + EXT_DEVICEDATAENTRY CurrentExistDevice; + EXT_DEVICEDATAENTRY NewDevice; +} EXT_SWAPTARGETDEVICE, *PEXT_SWAPTARGETDEVICE; + +/* LUN BitMask structure definition, array of 8bit bytes, + * 1 bit per lun. When bit == 1, the lun is masked. + * Most significant bit of mask[0] is lun 0. + * Least significant bit of mask[0] is lun 7. + */ +typedef struct _EXT_LUN_BIT_MASK { +#if ((EXT_DEF_MAX_LUN & 0x7) == 0) + UINT8 mask[EXT_DEF_MAX_LUN >> 3]; +#else + UINT8 mask[(EXT_DEF_MAX_LUN + 8) >> 3 ]; +#endif +} EXT_LUN_BIT_MASK, *PEXT_LUN_BIT_MASK; + +/* + * LUN mask bit manipulation macros + * + * P = Pointer to an EXT_LUN_BIT_MASK union. + * L = LUN number. + */ +#define EXT_IS_LUN_BIT_SET(P,L) \ + (((P)->mask[L/8] & (0x80 >> (L%8)))?1:0) + +#define EXT_SET_LUN_BIT(P,L) \ + ((P)->mask[L/8] |= (0x80 >> (L%8))) + +#define EXT_CLR_LUN_BIT(P,L) \ + ((P)->mask[L/8] &= ~(0x80 >> (L%8))) + +#define EXT_DEF_LUN_BITMASK_LIST_MIN_ENTRIES 1 +#define EXT_DEF_LUN_BITMASK_LIST_MAX_ENTRIES 256 + +#ifdef _WIN64 +#define EXT_DEF_LUN_BITMASK_LIST_HEADER_SIZE 32 +#else +#define EXT_DEF_LUN_BITMASK_LIST_HEADER_SIZE \ + offsetof(LUN_BITMASK_LIST_BUFFER, asBitmaskEntry) +#endif + +#define EXT_DEF_LUN_COUNT 2048 +#define EXT_DEF_LUN_BITMASK_BYTES (EXT_DEF_LUN_COUNT / 8) + +typedef struct _EXT_LUN_BITMASK_ENTRY +{ + UINT8 NodeName[EXT_DEF_WWN_NAME_SIZE]; + UINT8 PortName[EXT_DEF_WWN_NAME_SIZE]; + + UINT32 Reserved2; + UINT32 Reserved3; + UINT32 Reserved4; + UINT32 Reserved5; /* Pad to 32-byte header.*/ + + UINT8 Bitmask[EXT_DEF_LUN_BITMASK_BYTES]; +} EXT_LUN_BITMASK_ENTRY, *PEXT_LUN_BITMASK_ENTRY; + +/* Structure as it is stored in the config file.*/ +typedef struct _LUN_BITMASK_LIST +{ + UINT16 Version; /* Should be LUN_BITMASK_REGISTRY_VERSION */ + UINT16 EntryCount; /* Count of variable entries following.*/ + UINT32 Reserved1; + UINT32 Reserved2; + UINT32 Reserved3; + UINT32 Reserved4; + UINT32 Reserved5; + UINT32 Reserved6; + UINT32 Reserved7; /* Pad to 32-byte header.*/ + + EXT_LUN_BITMASK_ENTRY BitmaskEntry[1]; /* Variable-length data.*/ + +} EXT_LUN_BITMASK_LIST, *PEXT_LUN_BITMASK_LIST; + + +#define EXT_DEF_LUN_BITMASK_LIST_MIN_SIZE \ + (EXT_DEF_LUN_BITMASK_LIST_HEADER_SIZE + \ + (sizeof(EXT_DEF_LUN_BITMASK_ENTRY) * EXT_DEF_LUN_BITMASK_LIST_MIN_ENTRIES)) +#define EXT_DEF_LUN_BITMASK_LIST_MAX_SIZE \ + (EXT_DEF_LUN_BITMASK_LIST_HEADER_SIZE + \ + (sizeof(EXT_DEF_LUN_BITMASK_ENTRY) * EXT_DEF_LUN_BITMASK_LIST_MAX_ENTRIES)) + +/* Request Buffer for ELS PT*/ +#define EXT_DEF_WWPN_VALID 1 +#define EXT_DEF_WWNN_VALID 2 +#define EXT_DEF_PID_VALID 4 +typedef struct _EXT_ELS_PT_REQ { + UINT8 WWNN[EXT_DEF_WWN_NAME_SIZE]; /* 8 */ + UINT8 WWPN[EXT_DEF_WWN_NAME_SIZE]; /* 8 */ + UINT8 Id[EXT_DEF_PORTID_SIZE]; /* 4 */ + UINT16 ValidMask; /* 2 */ + UINT16 Lid; /* 2 */ + UINT16 Rxid; /* 2 */ + UINT16 AccRjt; /* 2 */ + UINT32 Reserved; /* 4 */ +} EXT_ELS_PT_REQ, *PEXT_ELS_PT_REQ; /* 32 */ + +/* LED state information */ + +#define EXT_DEF_GRN_BLINK_ON 0x01ED0017 +#define EXT_DEF_GRN_BLINK_OFF 0x01ED00FF + +typedef struct _EXT_BEACON_CONTROL { + UINT32 State; /* 4 */ + UINT32 Reserved[3]; /* 12 */ +} EXT_BEACON_CONTROL , *PEXT_BEACON_CONTROL ; /* 16 */ + +#ifdef _MSC_VER +#pragma pack() +#endif + +#endif /* _EXIOCT_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/exioctln.h 830-ivtv/drivers/scsi/qla2xxx/exioctln.h --- 000-virgin/drivers/scsi/qla2xxx/exioctln.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/exioctln.h Thu Jan 8 10:22:00 2004 @@ -0,0 +1,287 @@ +/***************************************************************************** +* QLOGIC LINUX SOFTWARE +* +* QLogic ISP2x00 device driver for Linux 2.6.x +* Copyright (C) 2003 QLogic Corporation +* (www.qlogic.com) +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2, or (at your option) any +* later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +****************************************************************************/ + +/* + * File Name: exioctln.h + + Rev 16 July 31, 2003 RL + - Added definitions for Status field in discovered target + structure. + - Updated ioctl command value assignment on PPC64 so this + file can be shared with API lib. + + Rev 15 June 03, 2003 RL + - Modified ioctl command code value assignment so it also + works on PPC64. + + Rev 14 February 25, 2003 RL + - Added EXT_CC_DRIVER_SPECIFIC ioctl command to return + some driver specific data that can be used by API library + to determine how to maintain backward compatibility + of certain features. + + Rev 13 January 31, 2003 RL + - Changed the value of EXT_DEF_USE_HBASELECT to avoid + conflicting with older implementation of FO API lib. + + Rev 12 January 20, 2003 RL + - Added EXT_DEF_USE_HBASELECT definition for use by + the SETINSTANCE command. + + Rev 11 December 10, 2002 RL + - Added EXT_CC_SEND_ELS_PASSTHRU_OS definition. + + Rev 10 October 26, 2001 RL + - Corrected MAX_HBA, MAX_TARGET and MAX_LUN values to 255. + + Rev 9 July 26, 2001 RL + - Added definition of signed types. + + Rev 8 July 05, 2001 RL + - Redefined ioctl command values. + + Rev 7 Nov 06, 2000 BN + - Added EXT_DEF_MAX_AEN_QUEUE_OS define + - Added define for handle_hba_t + + Rev 6 Oct 25, 2000 BN + - Added EXT_CC_DRIVER_PROP_OS define + + Rev 5 Oct 25, 2000 BN + - Redo the copyright header and add AEN details + + Rev 4 Oct 23, 2000 BN + - Added definition for BOOLEAN + + Rev 3 Oct 23, 2000 BN + - Added definitions for EXT_ADDR_MODE_OS + and also include of + + Rev 2 Oct 18, 2000 BN + - Enable API Exention support + + Rev 1 Original version Sep 7, 2000 BN + +*/ + + +#ifndef _EXIOCT_LN_H_ +#define _EXIOCT_LN_H_ + +#include + +#ifdef APILIB +#include +#endif + + +#define INT8 int8_t +#define INT16 int16_t +#define INT32 int32_t +#define UINT8 uint8_t +#define UINT16 uint16_t +#define UINT32 uint32_t +#define UINT64 void * +#define BOOLEAN uint8_t + +typedef struct track_instance { + int handle; +} track_instance_t; + + +#if BITS_PER_LONG <= 32 +#define EXT_ADDR_MODE_OS EXT_DEF_ADDR_MODE_32 +#else +#define EXT_ADDR_MODE_OS EXT_DEF_ADDR_MODE_64 +#endif + + +#define QLMULTIPATH_MAGIC 'y' + +#define _QLBUILD /* for exioct.h to enable include of qinsdmgt.h */ + + + +#define EXT_DEF_MAX_HBA_OS 255 /* 0 - 0xFE */ +#define EXT_DEF_MAX_BUS_OS 1 +#define EXT_DEF_MAX_TARGET_OS 255 /* 0 - 0xFE */ +#define EXT_DEF_MAX_LUN_OS 255 /* 0 - 0xFE */ + +#define EXT_DEF_MAX_AEN_QUEUE_OS 64 + +#define EXT_DEF_FC_HEADER_LEN 24 +#define EXT_DEF_ELS_RJT_LENGTH 0x08 /* 8 */ +#define EXT_DEF_ELS_RPS_ACC_LENGTH 0x40 /* 64 */ +#define EXT_DEF_ELS_RLS_ACC_LENGTH 0x1C /* 28 */ + +#define EXT_DEF_USE_HBASELECT 0x02 /* bit 1: HbaSelect field now + * used to specify destination + * HBA of each command. + * SetInstance cmd is now + * issued only once during + * API initialization. + */ + +/* target status flags */ +#define EXT_DEF_TGTSTAT_OFFLINE 0x01 +#define EXT_DEF_TGTSTAT_IN_CFG 0x02 + + +/*****************/ +/* Command codes */ +/*****************/ +#define QL_IOCTL_BASE(idx) _IOWR(QLMULTIPATH_MAGIC, idx, EXT_IOCTL) +#define QL_IOCTL_CMD(idx) QL_IOCTL_BASE(idx) + +/*************************************************************** + * These are regular/external command codes, starting from 0. + * The regular command code end index must be updated whenever + * adding new commands. + ***************************************************************/ +#define EXT_DEF_LN_REG_CC_START_IDX 0x00 /* reg cmd start index */ + +#define EXT_CC_QUERY_OS /* QUERY */ \ + QL_IOCTL_CMD(0x00) +#define EXT_CC_SEND_FCCT_PASSTHRU_OS /* FCCT_PASSTHRU */ \ + QL_IOCTL_CMD(0x01) +#define EXT_CC_REG_AEN_OS /* REG_AEN */ \ + QL_IOCTL_CMD(0x02) +#define EXT_CC_GET_AEN_OS /* GET_AEN */ \ + QL_IOCTL_CMD(0x03) +#define EXT_CC_SEND_ELS_RNID_OS /* SEND_ELS_RNID */ \ + QL_IOCTL_CMD(0x04) +#define EXT_CC_SCSI_PASSTHRU_OS /* SCSI_PASSTHRU */ \ + QL_IOCTL_CMD(0x05) + +#define EXT_CC_GET_DATA_OS /* GET_DATA */ \ + QL_IOCTL_CMD(0x06) +#define EXT_CC_SET_DATA_OS /* SET_DATA */ \ + QL_IOCTL_CMD(0x07) + +#define EXT_DEF_LN_REG_CC_END_IDX 0x07 /* reg cmd end index */ + +/***************************************** + * Following are internal command codes. + * See inioct.h. + *****************************************/ +#define EXT_DEF_LN_INT_CC_START_IDX 0x08 /* int cmd start index */ +#define EXT_CC_RESERVED0A_OS \ + QL_IOCTL_CMD(0x08) +#define EXT_CC_RESERVED0B_OS \ + QL_IOCTL_CMD(0x09) + +#define EXT_CC_RESERVED0C_OS \ + QL_IOCTL_CMD(0x0a) +#define EXT_CC_RESERVED0D_OS \ + QL_IOCTL_CMD(0x0b) + +#define EXT_CC_RESERVED0E_OS \ + QL_IOCTL_CMD(0x0c) +#define EXT_CC_RESERVED0F_OS \ + QL_IOCTL_CMD(0x0d) + +#define EXT_CC_RESERVED0G_OS \ + QL_IOCTL_CMD(0x0e) +#define EXT_CC_RESERVED0H_OS \ + QL_IOCTL_CMD(0x0f) + +#define EXT_CC_RESERVED0I_OS \ + QL_IOCTL_CMD(0x10) +#define EXT_CC_RESERVED0J_OS \ + QL_IOCTL_CMD(0x11) + +#define EXT_DEF_LN_INT_CC_END_IDX 0x11 /* supported int cmd end idx */ + +#define EXT_CC_RESERVED0Z_OS \ + QL_IOCTL_CMD(0x21) + +/********************************************************/ +/* These are additional regular/external command codes. */ +/********************************************************/ +#define EXT_DEF_LN_ADD_CC_START_IDX 0x30 /* additional cmd start index */ +#define EXT_CC_SEND_ELS_PASSTHRU_OS \ + QL_IOCTL_CMD(0x30) +#define EXT_DEF_LN_ADD_CC_END_IDX 0x30 /* additional cmd end index */ + + +/******************************************************** + * Failover ioctl command codes range from 0xc0 to 0xdf. + * See definition in qlfoln.h. + ********************************************************/ + + +/*******************************************************************/ +/* These are Linux driver implementation specific commands. Values */ +/* start from highest possible value and in decreasing order. */ +/*******************************************************************/ +#define EXT_DEF_LN_SPC_CC_START_IDX 0xff /* LN specific cmd start idx */ + +#define EXT_CC_STARTIOCTL /* STARTIOCTL */ \ + QL_IOCTL_CMD(0xff) +#define EXT_CC_SETINSTANCE /* SETINSTANCE */ \ + QL_IOCTL_CMD(0xfe) +#define EXT_CC_WWPN_TO_SCSIADDR /* WWPN_TO_SCSIADDR */ \ + QL_IOCTL_CMD(0xfd) +#define EXT_CC_DRIVER_SPECIFIC /* DRIVER_SPECIFIC */ \ + QL_IOCTL_CMD(0xfc) + +#define EXT_DEF_LN_SPC_CC_END_IDX 0xfc /* LN specific cmd end idx */ + + +/* + * Response struct definition + */ +typedef struct _EXT_LN_DRV_VERSION { + UINT8 Major; + UINT8 Minor; + UINT8 Patch; + UINT8 Beta; + UINT8 Reserved[4]; +} EXT_LN_DRV_VERSION; /* 8 */ + +typedef struct _EXT_LN_DRIVER_DATA { + EXT_LN_DRV_VERSION DrvVer; /* 8 */ + UINT32 Reserved[14]; /* 56 */ +} EXT_LN_DRIVER_DATA, *PEXT_LN_DRIVER_DATA; /* 64 */ + + + + + + +/* + * Overrides for Emacs so that we almost follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 2 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -2 + * c-argdecl-indent: 2 + * c-label-offset: -2 + * c-continued-statement-offset: 4 + * c-continued-brace-offset: 0 + * indent-tabs-mode: nil + * tab-width: 8 + * End: + */ + +#endif /* _EXIOCT_LN_H_ */ + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/extras/add_to_kernel.diff 830-ivtv/drivers/scsi/qla2xxx/extras/add_to_kernel.diff --- 000-virgin/drivers/scsi/qla2xxx/extras/add_to_kernel.diff Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/extras/add_to_kernel.diff Thu Jan 8 10:22:00 2004 @@ -0,0 +1,21 @@ +--- linux-2.6.0-test9/drivers/scsi/Kconfig.orig 2003-10-25 11:44:40.000000000 -0700 ++++ linux-2.6.0-test9/drivers/scsi/Kconfig 2003-11-04 14:18:19.072377672 -0800 +@@ -1212,6 +1212,8 @@ + To compile this driver as a module, choose M here: the + module will be called qlogicpti. + ++source "drivers/scsi/qla2xxx/Kconfig" ++ + config SCSI_SEAGATE + tristate "Seagate ST-02 and Future Domain TMC-8xx SCSI support" + depends on X86 && ISA && SCSI && BROKEN +--- linux-2.6.0-test9/drivers/scsi/Makefile.orig 2003-11-04 14:17:44.627614072 -0800 ++++ linux-2.6.0-test9/drivers/scsi/Makefile 2003-11-04 14:18:19.074377368 -0800 +@@ -74,6 +74,7 @@ + obj-$(CONFIG_SCSI_QLOGIC_ISP) += qlogicisp.o + obj-$(CONFIG_SCSI_QLOGIC_FC) += qlogicfc.o + obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o ++obj-$(CONFIG_SCSI_QLA2XXX) += qla2xxx/ + obj-$(CONFIG_SCSI_PAS16) += pas16.o + obj-$(CONFIG_SCSI_SEAGATE) += seagate.o + obj-$(CONFIG_SCSI_FD_8xx) += seagate.o diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/extras/qla_dmp.sh 830-ivtv/drivers/scsi/qla2xxx/extras/qla_dmp.sh --- 000-virgin/drivers/scsi/qla2xxx/extras/qla_dmp.sh Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/extras/qla_dmp.sh Thu Jan 8 10:22:00 2004 @@ -0,0 +1,60 @@ +#!/bin/sh +# +# QLogic ISP2x00 device driver dump reader +# Copyright (C) 2003 QLogic Corporation +# (www.qlogic.com) +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +version=1.039720 +sysfs=/sys +qstats=${sysfs}/class/scsi_host/host${1}/device/stats +qfwd=${sysfs}/class/scsi_host/host${1}/device/fw_dump +dfile=fw_dump_${1}_`eval date +%Y%m%d_%H%M%S`.txt + +# Get host number +if [ -z "${1}" ] ; then + echo "QLogic Firmware Dump Reader: ${version}" + echo "Usage:" + echo " `basename ${0}` " + exit 1 +fi + +# Verify fw_dump binary-attribute file +if ! test -f ${qfwd} ; then + echo "No firmware dump file at host ${1}!!!" + exit 1 +fi + +# Verify a firmware dump is available for the given host +#if ! test -f ${qstats} ; then +# echo "No device stats to verify firmware dump available at host ${1}!!!" +# exit 1 +#fi +#do_dump=`eval cat ${qstats} | cut -d ' ' -f5` +#if [ "${do_dump}" = "0" ] ; then +# echo "No firmware dump available at host ${1}!!!" +# exit 1 +#fi + +# Go with dump +echo 1 > ${qfwd} +cat ${qfwd} > ${dfile} +echo 0 > ${qfwd} +if ! test -s "${dfile}" ; then + echo "No firmware dump available at host ${1}!!!" + rm ${dfile} + exit 1 +fi + +echo "Firmware dumped to file ${dfile}." + +exit 0 diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/extras/qla_nvr.c 830-ivtv/drivers/scsi/qla2xxx/extras/qla_nvr.c --- 000-virgin/drivers/scsi/qla2xxx/extras/qla_nvr.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/extras/qla_nvr.c Thu Jan 8 10:22:00 2004 @@ -0,0 +1,1042 @@ +/******************************************************************************** +* QLogic ISP2x00 NVRAM parser +* Copyright (C) 2003 QLogic Corporation +* (www.qlogic.com) +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2, or (at your option) any +* later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +static char *qla_version = "1.00"; + +#define MAX_STRINGS 16 +#define MAX_PARAMS_SIZE 256 + +/* + * ISP2X00 NVRAM structure definition. + */ +typedef struct nvram { + uint8_t id[4]; + uint8_t nvram_version; + uint8_t reserved_0; + uint8_t parameter_block_version; + uint8_t reserved_1; + uint8_t firmware_options[2]; + uint8_t max_frame_length[2]; + uint8_t max_iocb_allocation[2]; + uint8_t execution_throttle[2]; + uint8_t login_retry_count; + uint8_t retry_delay; + uint8_t port_name[8]; + uint8_t hard_address[2]; + uint8_t inquiry; + uint8_t login_timeout; + uint8_t node_name[8]; + uint8_t add_fw_opt[2]; + uint8_t response_accumulation_timer; + uint8_t interrupt_delay_timer; + uint8_t special_options[2]; + uint8_t reserved_4[26]; + uint8_t host_p[2]; + uint8_t boot_node_name[8]; + uint8_t boot_lun_number; + uint8_t reset_delay; + uint8_t port_down_retry_count; + uint8_t boot_id_number; + uint8_t maximum_luns_per_target[2]; + uint8_t boot_port_name[8]; + uint8_t reserved_6[6]; + uint8_t reserved_7[50]; + uint8_t reserved_8[50]; + uint8_t reserved_9[32]; + uint8_t adapter_features[2]; + uint8_t reserved_10[6]; + uint8_t reserved_11[4]; + uint8_t subsystem_vendor_id[2]; + uint8_t reserved_12[2]; + uint8_t subsystem_device_id[2]; + uint8_t subsystem_vendor_id_2200[2]; + uint8_t subsystem_device_id_2200[2]; + uint8_t reserved_13; + uint8_t checksum; +} nvram_t; + +/* + * Parameter types. + */ +typedef enum { + BITS, + NUMBER, + STRING +} prm_t; + +typedef struct { + prm_t type; + uint8_t bits[MAX_STRINGS]; + uint8_t bytes; + char *strings[MAX_STRINGS]; +} nv_param_t; + +typedef struct { + uint8_t *addr; + nv_param_t *nvp; +} input_t; + +/* + * Global data. + */ +nvram_t nv; + +nv_param_t nv_id = { + STRING, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 4, + { + "\n; NVRAM header\n\n" + "id [\"4 characters\"] = " + } +}; +nv_param_t nv_version = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "version [0-255] = " + } +}; +nv_param_t rsv_byte = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "reserved [0-255] = " + } +}; +nv_param_t p_version = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "\n; RISC Parameter Block\n\n" + "version [0-255] = " + } +}; +nv_param_t firmware_options = { + BITS, + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }, + 2, + { + "\n; Firmware options\n\nenable hard loop ID [0-1] = ", + "enable fairness [0-1] = ", + "enable full duplex [0-1] = ", + "enable fast posting [0-1] = ", + "enable target mode [0-1] = ", + "disable initiator mode [0-1] = ", + "Enable ADISC [0-1] = ", + "Target Inquiry Data [0-1] = ", + "Enable PDBC Notify [0-1] = ", + "Non participating LIP [0-1] = ", + "Descending Search LoopID [0-1] = ", + "Acquire LoopID in LIPA [0-1] = ", + "Stop PortQ on FullStatus [0-1] = ", + "Full Login After LIP [0-1] = ", + "Node Name option [0-1] = ", + "Ext IFWCB enable bit [0-1] = " + } +}; +nv_param_t frame_payload_size = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 2, + { + "\nframe payload size [0-65535] = " + } +}; +nv_param_t max_iocb_allocation = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 2, + { + "max iocb allocation [0-65535] = " + } +}; +nv_param_t execution_throttle = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 2, + { + "execution throttle [0-65535] = " + } +}; +nv_param_t login_retry_count = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "login retry count [0-255] = " + } +}; +nv_param_t retry_delay = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "retry delay [0-255] = " + } +}; +nv_param_t port_name_0 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "\nport name 0 [0-255] = " + } +}; +nv_param_t port_name_1 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "port name 1 (must be zero) [0-255] = " + } +}; +nv_param_t port_name_2 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "port name 2 (company ID) [0-255] = " + } +}; +nv_param_t port_name_3 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "port name 3 (company ID) [0-255] = " + } +}; +nv_param_t port_name_4 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "port name 4 (company ID) [0-255] = " + } +}; +nv_param_t port_name_5 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "port name 5 (serial number) [0-255] = " + } +}; +nv_param_t port_name_6 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "port name 6 (serial number) [0-255] = " + } +}; +nv_param_t port_name_7 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "port name 7 (serial number) [0-255] = " + } +}; +nv_param_t hard_address = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 2, + { + "\nadapter hard loop ID [0-65535] = " + } +}; +nv_param_t inquiry = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "inquiry data [0-255] = " + } +}; +nv_param_t login_timeout = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "login timeout [0-255] = " + } +}; +nv_param_t node_name_0 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "\nnode name 0 [0-255] = " + } +}; +nv_param_t node_name_1 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "node name 1 [0-255] = " + } +}; +nv_param_t node_name_2 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "node name 2 [0-255] = " + } +}; +nv_param_t node_name_3 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "node name 3 [0-255] = " + } +}; +nv_param_t node_name_4 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "node name 4 [0-255] = " + } +}; +nv_param_t node_name_5 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "node name 5 [0-255] = " + } +}; +nv_param_t node_name_6 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "node name 6 [0-255] = " + } +}; +nv_param_t node_name_7 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "node name 7 [0-255] = " + } +}; +nv_param_t add_fw_opt = { + BITS, + { 4, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, }, + 2, + { + "\n; Extended Parameter\n\nOperation Mode [0-15] = ", + "Init Config Mode [0-7] = ", + "Enable Non part on LIHA failure [0-1] = ", + "Enable Class 2 [0-1] = ", + "Enable Ack0 [0-1] = ", + "Reserved [0-1] = ", + "Reserved [0-1] = ", + "Enable FC Tape [0-1] = ", + "Enable FC Confirm [0-1] = ", + "Enable Queueing [0-1] = ", + "No Logo On Link Down [0-1] = " + } +}; +nv_param_t response_accumulation_timer = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "\nResponse Accumulation Timer [0-255] = " + } +}; +nv_param_t interrupt_delay_timer = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "Interrupt Delay Timer [0-255] = " + } +}; +nv_param_t special_options = { + BITS, + { 1, 1, 2, 2, 2, 5, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, }, + 2, + { + "\n; special options\n\nenable read xfr rdy [0-1] = ", + "not re-acquire ALPA during LIFA/LIPA [0-1] = ", + "Reserved [0-3] = ", + "FCP_RSP Payload Size [0-3] = ", + "Reserved [0-3] = ", + "Reserved [0-31] = ", + "enable 50 ohm termination [0-1] = ", + "Data Rate [0-3] = " + } +}; +nv_param_t rsv_word = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 2, + { + "reserved [0-65535] = " + } +}; +nv_param_t host_p = { + BITS, + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }, + 2, + { + "\n; HOST Parameter block\n\nunused [0-1] = ", + "disable BIOS [0-1] = ", + "disable LUNs [0-1] = ", + "enable selectable boot [0-1] = ", + "disable RISC code load [0-1] = ", + "set cache line size 1 [0-1] = ", + "PCI Parity Disable [0-1] = ", + "enable extended logging [0-1] = ", + "enable 64bit addressing [0-1] = ", + "enable LIP reset [0-1] = ", + "enable LIP full login [0-1] = ", + "enable target reset [0-1] = ", + "enable database storage [0-1] = ", + "enable cache flush read [0-1] = ", + "enable database load [0-1] = ", + "unused [0-1] = " + } +}; +nv_param_t boot_node_name_0 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "\nboot node name 0 [0-255] = " + } +}; +nv_param_t boot_node_name_1 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "boot node name 1 [0-255] = " + } +}; +nv_param_t boot_node_name_2 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "boot node name 2 [0-255] = " + } +}; +nv_param_t boot_node_name_3 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "boot node name 3 [0-255] = " + } +}; +nv_param_t boot_node_name_4 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "boot node name 4 [0-255] = " + } +}; +nv_param_t boot_node_name_5 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "boot node name 5 [0-255] = " + } +}; +nv_param_t boot_node_name_6 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "boot node name 6 [0-255] = " + } +}; +nv_param_t boot_node_name_7 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "boot node name 7 [0-255] = " + } +}; +nv_param_t boot_lun_number = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "boot LUN number [0-255] = " + } +}; +nv_param_t reset_delay = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "\nreset delay [0-255] = " + } +}; +nv_param_t port_down_retry_count = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "port down retry count [0-255] = " + } +}; +nv_param_t boot_id_number = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "boot ID number [0-255] = " + } +}; +nv_param_t maximum_luns_per_target = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 2, + { + "\nmaximum LUNs per target [0-65535] = " + } +}; +nv_param_t boot_port_name_0 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "\nboot port name 0 [0-255] = " + } +}; +nv_param_t boot_port_name_1 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "boot port name 1 [0-255] = " + } +}; +nv_param_t boot_port_name_2 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "boot port name 2 [0-255] = " + } +}; +nv_param_t boot_port_name_3 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "boot port name 3 [0-255] = " + } +}; +nv_param_t boot_port_name_4 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "boot port name 4 [0-255] = " + } +}; +nv_param_t boot_port_name_5 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "boot port name 5 [0-255] = " + } +}; +nv_param_t boot_port_name_6 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "boot port name 6 [0-255] = " + } +}; +nv_param_t boot_port_name_7 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "boot port name 7 [0-255] = " + } +}; +nv_param_t adapter_features = { + BITS, + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }, + 2, + { + "\n; Adapter Features\n\nExternal GBIC [0-1] = ", + "Risc RAM Parity [0-1] = ", + "Buffer Plus Module [0-1] = ", + "Multi Chip Adapter [0-1] = ", + "unused [0-1] = ", + "unused [0-1] = ", + "unused [0-1] = ", + "unused [0-1] = ", + "unused [0-1] = ", + "unused [0-1] = ", + "unused [0-1] = ", + "unused [0-1] = ", + "unused [0-1] = ", + "unused [0-1] = ", + "unused [0-1] = ", + "unused [0-1] = " + } +}; +nv_param_t subsystem_vendor_id = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 2, + { + "\nsubsystem vendor ID [0-65535] = " + } +}; +nv_param_t subsystem_device_id = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 2, + { + "\nsubsystem device ID [0-65535] = " + } +}; +nv_param_t subsystem_vendor_id_2200 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 2, + { + "\nsubsystem vendor ID 2 [0-65535] = " + } +}; +nv_param_t subsystem_device_id_2200 = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 2, + { + "\nsubsystem device ID 2 [0-65535] = " + } +}; +nv_param_t checksum = { + NUMBER, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + 1, + { + "\nchecksum [0-255] = " + } +}; + +input_t nvram_params[] = { + { &nv.id[0], &nv_id }, + { &nv.nvram_version, &nv_version }, + { &nv.reserved_0, &rsv_byte }, + { &nv.parameter_block_version, &p_version }, + { &nv.reserved_1, &rsv_byte }, + { &nv.firmware_options[0], &firmware_options }, + { &nv.max_frame_length[0], &frame_payload_size }, + { &nv.max_iocb_allocation[0], &max_iocb_allocation }, + { &nv.execution_throttle[0], &execution_throttle }, + { &nv.login_retry_count, &login_retry_count }, + { &nv.retry_delay, &retry_delay }, + { &nv.port_name[0], &port_name_0 }, + { &nv.port_name[1], &port_name_1 }, + { &nv.port_name[2], &port_name_2 }, + { &nv.port_name[3], &port_name_3 }, + { &nv.port_name[4], &port_name_4 }, + { &nv.port_name[5], &port_name_5 }, + { &nv.port_name[6], &port_name_6 }, + { &nv.port_name[7], &port_name_7 }, + { &nv.hard_address[0], &hard_address }, + { &nv.inquiry, &inquiry }, + { &nv.login_timeout, &login_timeout }, + { &nv.node_name[0], &node_name_0 }, + { &nv.node_name[1], &node_name_1 }, + { &nv.node_name[2], &node_name_2 }, + { &nv.node_name[3], &node_name_3 }, + { &nv.node_name[4], &node_name_4 }, + { &nv.node_name[5], &node_name_5 }, + { &nv.node_name[6], &node_name_6 }, + { &nv.node_name[7], &node_name_7 }, + { &nv.add_fw_opt[0], &add_fw_opt }, + { &nv.response_accumulation_timer, &response_accumulation_timer }, + { &nv.interrupt_delay_timer, &interrupt_delay_timer }, + { &nv.special_options[0], &special_options }, + { &nv.reserved_4[0], &rsv_word }, + { &nv.reserved_4[2], &rsv_word }, + { &nv.reserved_4[4], &rsv_word }, + { &nv.reserved_4[6], &rsv_word }, + { &nv.reserved_4[8], &rsv_word }, + { &nv.reserved_4[10], &rsv_word }, + { &nv.reserved_4[12], &rsv_word }, + { &nv.reserved_4[14], &rsv_word }, + { &nv.reserved_4[16], &rsv_word }, + { &nv.reserved_4[18], &rsv_word }, + { &nv.reserved_4[20], &rsv_word }, + { &nv.reserved_4[22], &rsv_word }, + { &nv.reserved_4[24], &rsv_word }, + { &nv.host_p[0], &host_p }, + { &nv.boot_node_name[0], &boot_node_name_0 }, + { &nv.boot_node_name[1], &boot_node_name_1 }, + { &nv.boot_node_name[2], &boot_node_name_2 }, + { &nv.boot_node_name[3], &boot_node_name_3 }, + { &nv.boot_node_name[4], &boot_node_name_4 }, + { &nv.boot_node_name[5], &boot_node_name_5 }, + { &nv.boot_node_name[6], &boot_node_name_6 }, + { &nv.boot_node_name[7], &boot_node_name_7 }, + { &nv.boot_lun_number, &boot_lun_number }, + { &nv.reset_delay, &reset_delay }, + { &nv.port_down_retry_count, &port_down_retry_count }, + { &nv.boot_id_number, &boot_id_number }, + { &nv.maximum_luns_per_target[0], &maximum_luns_per_target }, + { &nv.boot_port_name[0], &boot_port_name_0 }, + { &nv.boot_port_name[1], &boot_port_name_1 }, + { &nv.boot_port_name[2], &boot_port_name_2 }, + { &nv.boot_port_name[3], &boot_port_name_3 }, + { &nv.boot_port_name[4], &boot_port_name_4 }, + { &nv.boot_port_name[5], &boot_port_name_5 }, + { &nv.boot_port_name[6], &boot_port_name_6 }, + { &nv.boot_port_name[7], &boot_port_name_7 }, + { &nv.reserved_6[0], &rsv_word }, + { &nv.reserved_6[2], &rsv_word }, + { &nv.reserved_6[4], &rsv_word }, + { &nv.reserved_7[0], &rsv_word }, /* 100 */ + { &nv.reserved_7[2], &rsv_word }, + { &nv.reserved_7[4], &rsv_word }, + { &nv.reserved_7[6], &rsv_word }, + { &nv.reserved_7[8], &rsv_word }, + { &nv.reserved_7[10], &rsv_word }, + { &nv.reserved_7[12], &rsv_word }, + { &nv.reserved_7[14], &rsv_word }, + { &nv.reserved_7[16], &rsv_word }, + { &nv.reserved_7[18], &rsv_word }, + { &nv.reserved_7[20], &rsv_word }, + { &nv.reserved_7[22], &rsv_word }, + { &nv.reserved_7[24], &rsv_word }, + { &nv.reserved_7[26], &rsv_word }, + { &nv.reserved_7[28], &rsv_word }, + { &nv.reserved_7[30], &rsv_word }, + { &nv.reserved_7[32], &rsv_word }, + { &nv.reserved_7[34], &rsv_word }, + { &nv.reserved_7[36], &rsv_word }, + { &nv.reserved_7[38], &rsv_word }, + { &nv.reserved_7[40], &rsv_word }, + { &nv.reserved_7[42], &rsv_word }, + { &nv.reserved_7[44], &rsv_word }, + { &nv.reserved_7[46], &rsv_word }, + { &nv.reserved_7[48], &rsv_word }, + { &nv.reserved_8[0], &rsv_word }, /* 150 */ + { &nv.reserved_8[2], &rsv_word }, + { &nv.reserved_8[4], &rsv_word }, + { &nv.reserved_8[6], &rsv_word }, + { &nv.reserved_8[8], &rsv_word }, + { &nv.reserved_8[10], &rsv_word }, + { &nv.reserved_8[12], &rsv_word }, + { &nv.reserved_8[14], &rsv_word }, + { &nv.reserved_8[16], &rsv_word }, + { &nv.reserved_8[18], &rsv_word }, + { &nv.reserved_8[20], &rsv_word }, + { &nv.reserved_8[22], &rsv_word }, + { &nv.reserved_8[24], &rsv_word }, + { &nv.reserved_8[26], &rsv_word }, + { &nv.reserved_8[28], &rsv_word }, + { &nv.reserved_8[30], &rsv_word }, + { &nv.reserved_8[32], &rsv_word }, + { &nv.reserved_8[34], &rsv_word }, + { &nv.reserved_8[36], &rsv_word }, + { &nv.reserved_8[38], &rsv_word }, + { &nv.reserved_8[40], &rsv_word }, + { &nv.reserved_8[42], &rsv_word }, + { &nv.reserved_8[44], &rsv_word }, + { &nv.reserved_8[46], &rsv_word }, + { &nv.reserved_8[48], &rsv_word }, + { &nv.reserved_9[0], &rsv_word }, /* 200 */ + { &nv.reserved_9[2], &rsv_word }, + { &nv.reserved_9[4], &rsv_word }, + { &nv.reserved_9[6], &rsv_word }, + { &nv.reserved_9[8], &rsv_word }, + { &nv.reserved_9[10], &rsv_word }, + { &nv.reserved_9[12], &rsv_word }, + { &nv.reserved_9[14], &rsv_word }, + { &nv.reserved_9[16], &rsv_word }, + { &nv.reserved_9[18], &rsv_word }, + { &nv.reserved_9[20], &rsv_word }, + { &nv.reserved_9[22], &rsv_word }, + { &nv.reserved_9[24], &rsv_word }, + { &nv.reserved_9[26], &rsv_word }, + { &nv.reserved_9[28], &rsv_word }, + { &nv.reserved_9[30], &rsv_word }, + { &nv.adapter_features[0], &adapter_features }, + { &nv.reserved_10[0], &rsv_word }, + { &nv.reserved_10[2], &rsv_word }, + { &nv.reserved_10[4], &rsv_word }, + { &nv.reserved_11[0], &rsv_word }, + { &nv.reserved_11[2], &rsv_word }, + { &nv.subsystem_vendor_id[0], &subsystem_vendor_id }, + { &nv.reserved_12[0], &rsv_word }, + { &nv.subsystem_device_id[0], &subsystem_device_id }, + { &nv.subsystem_vendor_id_2200[0], &subsystem_vendor_id_2200 }, + { &nv.subsystem_device_id_2200[0], &subsystem_device_id_2200 }, + { &nv.reserved_13, &rsv_byte }, + { &nv.checksum, &checksum } +}; + +/* + * Local function prototypes. + */ +static void usage(void); +static void bin2asc(void); +static void asc2bin(void); +static void get_param(input_t *); +static uint8_t calc_checksum(void); +static void dmp_param(input_t *); + +/* + * Local functions. + */ +int +main(int argc, char *argv[]) +{ + if (argc != 2) { + usage(); + exit(1); + } + + if (strcmp(argv[1], "-a") == 0) { + bin2asc(); + } else if (strcmp(argv[1], "-b") == 0) { + asc2bin(); + } else { + usage(); + exit(1); + } + + return 0; +} + +static void +usage(void) +{ + fprintf(stderr, "QLogic NVRAM Parser: %s\n", qla_version); + fprintf(stderr, "Usage:\n"); + fprintf(stderr, " qla_nvr [-a] [-b] -\n"); + fprintf(stderr, " -a -- convert raw nvram to ASCII\n"); + fprintf(stderr, " -b -- convert ASCII to raw nvram\n\n"); +} + +static void +bin2asc(void) +{ + int stat = 0; + uint32_t i; + + /* Get NVRAM data. */ + fread(&nv, sizeof(char), sizeof(nvram_t), stdin); + + if (calc_checksum() != 0) { + fprintf(stderr, "qla_nvr: NVRAM checksum error!!!\n"); + return; + } + + for (i = 0; nvram_params[i].nvp != &checksum; i++) { + if (nvram_params[i].nvp == &rsv_word || + nvram_params[i].nvp == &rsv_byte) { + if (stat == 0) { + printf("\n"); + stat++; + } + } else { + stat = 0; + } + dmp_param(&nvram_params[i]); + } +} + +static void +asc2bin(void) +{ + uint32_t i; + + memset(&nv, 0, sizeof(nvram_t)); + + for (i = 0; nvram_params[i].nvp != &checksum; i++) + get_param(&nvram_params[i]); + + /* Check for proper port name. */ + if (nv.port_name[0] != 33 || nv.port_name[2] != 0 || + nv.port_name[3] != 224 || nv.port_name[4] != 139) { + fprintf(stderr, "qla_nvr: Invalid port name!!!\n"); + return; + } + + /* calculate checksum */ + nv.checksum = ~calc_checksum() + 1; + + /* Write NVRAM data. */ + fwrite(&nv, sizeof(char), sizeof(nvram_t), stdout); +} + +static void +get_param(input_t *inp) +{ + char s[MAX_PARAMS_SIZE]; + uint32_t i; + uint32_t n = 0; + uint8_t bc = 0; + uint8_t bp = 0; + uint32_t b = 0; + + while (fgets(s, MAX_PARAMS_SIZE, stdin) != NULL) { + i = 0; + while (isspace(s[i])) + i++; + if(s[i] == ';' || s[i] == '\0') + continue; + + while (s[i++] != '=') + ; + while (isspace(s[i])) + i++; + + /* Get decimal number. */ + n = 0; + while (s[i] != '\0') { + if (inp->nvp->type == STRING) { + if (s[i] == '"') { + i++; + } else { + n |= s[i++] << (bp++ * 8); + if (bp == inp->nvp->bytes) + break; + } + } else { + n = atol(&s[i]); + break; + } + } + + /* If number or string, done. */ + if (inp->nvp->type == NUMBER || inp->nvp->type == STRING) { + break; + } + + /* Bits. */ + b |= n << bc; + bc += inp->nvp->bits[bp++]; + if (bp == inp->nvp->bytes * 8 || inp->nvp->bits[bp] == 0) { + n = b; + break; + } + } + + /* Store input data. */ + for (i = 0; i < inp->nvp->bytes; i++) { + inp->addr[i] = (uint8_t)n; + n >>= 8; + } +} + +static uint8_t +calc_checksum(void) +{ + uint32_t i; + uint8_t rval = 0; + uint8_t *nvp = (uint8_t *)&nv; + + for (i = 0; i < sizeof (nvram_t); i++) + rval += *nvp++; + + return (rval); +} + + +static void +dmp_param(input_t *inp) +{ + uint32_t i; + uint32_t n; + uint32_t x; + uint32_t b; + uint8_t bc = 0; + uint8_t bp = 0; + + /* Get number. */ + n = 0; + x = inp->nvp->bytes; + while (x != 0) { + n <<= 8; + n |= inp->addr[--x]; + } + + for (i = 0; i < MAX_STRINGS && inp->nvp->strings[i] != NULL; i++) { + /* If number, done. */ + if (inp->nvp->type == NUMBER) { + printf("%s%d\n", inp->nvp->strings[i], n); + return; + } + + /* If string, done. */ + if (inp->nvp->type == STRING) { + printf("%s\"", inp->nvp->strings[i]); + for (x = 0; x < inp->nvp->bytes; x++) { + bc = n & 0xff; + n >>= 8; + printf("%c", bc); + } + printf("\"\n"); + return; + } + + /* Make bit mask. */ + for (b = 0, x = 0; x < inp->nvp->bits[bp]; x++) + b = b << 1 | 1; + + /* Get masked data. */ + b = n >> bc & b; + bc += inp->nvp->bits[bp++]; + + /* Output string and number. */ + printf("%s%d\n", inp->nvp->strings[i], b); + + /* Test for last bit. */ + if (bp == inp->nvp->bytes * 8 || inp->nvp->bits[bp] == 0) + break; + } +} diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/inioct.h 830-ivtv/drivers/scsi/qla2xxx/inioct.h --- 000-virgin/drivers/scsi/qla2xxx/inioct.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/inioct.h Thu Jan 8 10:22:00 2004 @@ -0,0 +1,137 @@ +/****************************************************************************** + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + ******************************************************************************/ + +/* + * File Name: inioct.h + * + * San/Device Management Ioctl Header + * File is created to adhere to Solaris requirement using 8-space tabs. + * + * !!!!! PLEASE DO NOT REMOVE THE TABS !!!!! + * !!!!! PLEASE NO SINGLE LINE COMMENTS: // !!!!! + * !!!!! PLEASE NO MORE THAN 80 CHARS PER LINE !!!!! + * + * + * Revision History: + * + * Rev. 0 June 15, 2001 + * YPL - Created. + * + * Rev. 1 June 26, 2001 + * YPL - Change the loop back structure and delete cc that is not used. + * + * Rev. 2 June 29, 2001 + * YPL - Use new EXT_CC defines from exioct.h + * + * Rev. 3 July 12, 2001 + * RL - Added definitions for loopback mbx command completion codes. + * + * Rev. 4 July 12, 2001 + * RL - Added definitions for loopback mbx command completion codes. + * + * Rev. 5 October 9, 2002 + * AV - Added definition for Read Option ROM IOCTL. + * + * Rev. 6 May 27, 2003 + * RL - Modified loopback rsp buffer structure definition to add + * diagnostic Echo command support. + * + */ + +#ifndef _INIOCT_H +#define _INIOCT_H + +/* + * *********************************************************************** + * X OS type definitions + * *********************************************************************** + */ +#ifdef _MSC_VER /* NT */ +#pragma pack(1) +#endif + +/* + * *********************************************************************** + * INT_IOCTL SubCode definition. + * These macros are being used for setting SubCode field in EXT_IOCTL + * structure. + * *********************************************************************** + */ + +/* + * Currently supported DeviceControl / ioctl command codes + */ +#define INT_CC_GET_PORT_STAT_FC EXT_CC_RESERVED0A_OS +#define INT_CC_LOOPBACK EXT_CC_RESERVED0B_OS +#define INT_CC_UPDATE_OPTION_ROM EXT_CC_RESERVED0C_OS +#define INT_CC_ADD_TARGET_DEVICE EXT_CC_RESERVED0D_OS +#define INT_CC_READ_NVRAM EXT_CC_RESERVED0E_OS +#define INT_CC_UPDATE_NVRAM EXT_CC_RESERVED0F_OS +#define INT_CC_SWAP_TARGET_DEVICE EXT_CC_RESERVED0G_OS +#define INT_CC_READ_OPTION_ROM EXT_CC_RESERVED0H_OS +#define INT_CC_LEGACY_LOOPBACK EXT_CC_RESERVED0Z_OS + + + +/* NVRAM */ +#define INT_SC_NVRAM_HARDWARE 0 /* Save */ +#define INT_SC_NVRAM_DRIVER 1 /* Driver (Apply) */ +#define INT_SC_NVRAM_ALL 2 /* NVRAM/Driver (Save+Apply) */ + +/* Loopback */ +typedef struct _INT_LOOPBACK_REQ +{ + UINT16 Options; /* 2 */ + UINT32 TransferCount; /* 4 */ + UINT32 IterationCount; /* 4 */ + UINT64 BufferAddress; /* 8 */ + UINT32 BufferLength; /* 4 */ + UINT16 Reserved[9]; /* 18 */ +} INT_LOOPBACK_REQ, *PINT_LOOPBACK_REQ; /* 408 */ + +typedef struct _INT_LOOPBACK_RSP +{ + UINT64 BufferAddress; /* 8 */ + UINT32 BufferLength; /* 4 */ + UINT16 CompletionStatus; /* 2 */ + UINT16 CrcErrorCount; /* 2 */ + UINT16 DisparityErrorCount; /* 2 */ + UINT16 FrameLengthErrorCount; /* 2 */ + UINT32 IterationCountLastError; /* 4 */ + UINT8 CommandSent; /* 1 */ + UINT8 Reserved1; /* 1 */ + UINT16 Reserved2[7]; /* 16 */ +} INT_LOOPBACK_RSP, *PINT_LOOPBACK_RSP; /* 40 */ + +/* definition for interpreting CompletionStatus values */ +#define INT_DEF_LB_COMPLETE 0x4000 +#define INT_DEF_LB_ECHO_CMD_ERR 0x4005 +#define INT_DEF_LB_PARAM_ERR 0x4006 +#define INT_DEF_LB_LOOP_DOWN 0x400b +#define INT_DEF_LB_CMD_ERROR 0x400c + +/* definition for interpreting CommandSent field */ +#define INT_DEF_LB_LOOPBACK_CMD 0 +#define INT_DEF_LB_ECHO_CMD 1 + +#ifdef _MSC_VER +#pragma pack() +#endif + +#endif /* _INIOCT_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/ql2100.c 830-ivtv/drivers/scsi/qla2xxx/ql2100.c --- 000-virgin/drivers/scsi/qla2xxx/ql2100.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/ql2100.c Thu Jan 8 10:22:00 2004 @@ -0,0 +1,92 @@ +/* + * QLogic ISP2100 device driver for Linux 2.6.x + * Copyright (C) 2003 Christoph Hellwig. + * Copyright (C) 2003 QLogic Corporation (www.qlogic.com) + * + * Released under GPL v2. + */ + +#include +#include +#include + +#include "qla_os.h" +#include "qla_def.h" + +static char qla_driver_name[] = "qla2100"; + +extern unsigned char fw2100tp_version[]; +extern unsigned char fw2100tp_version_str[]; +extern unsigned short fw2100tp_addr01; +extern unsigned short fw2100tp_code01[]; +extern unsigned short fw2100tp_length01; + +static struct qla_fw_info qla_fw_tbl[] = { + { + .addressing = FW_INFO_ADDR_NORMAL, + .fwcode = &fw2100tp_code01[0], + .fwlen = &fw2100tp_length01, + .fwstart = &fw2100tp_addr01, + }, + + { FW_INFO_ADDR_NOMORE, }, +}; + +static struct qla_board_info qla_board_tbl = { + .drv_name = qla_driver_name, + + .isp_name = "ISP2100", + .fw_info = qla_fw_tbl, +}; + +static struct pci_device_id qla2100_pci_tbl[] = { + { + .vendor = PCI_VENDOR_ID_QLOGIC, + .device = PCI_DEVICE_ID_QLOGIC_ISP2100, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (unsigned long)&qla_board_tbl, + }, + + {0, 0}, +}; +MODULE_DEVICE_TABLE(pci, qla2100_pci_tbl); + +static int __devinit +qla2100_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) +{ + return qla2x00_probe_one(pdev, + (struct qla_board_info *)id->driver_data); +} + +static void __devexit +qla2100_remove_one(struct pci_dev *pdev) +{ + qla2x00_remove_one(pdev); +} + +static struct pci_driver qla2100_pci_driver = { + .name = "qla2100", + .id_table = qla2100_pci_tbl, + .probe = qla2100_probe_one, + .remove = __devexit_p(qla2100_remove_one), +}; + +static int __init +qla2100_init(void) +{ + return pci_module_init(&qla2100_pci_driver); +} + +static void __exit +qla2100_exit(void) +{ + pci_unregister_driver(&qla2100_pci_driver); +} + +module_init(qla2100_init); +module_exit(qla2100_exit); + +MODULE_AUTHOR("QLogic Corporation"); +MODULE_DESCRIPTION("QLogic ISP21xx FC-SCSI Host Bus Adapter driver"); +MODULE_LICENSE("GPL"); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/ql2100_fw.c 830-ivtv/drivers/scsi/qla2xxx/ql2100_fw.c --- 000-virgin/drivers/scsi/qla2xxx/ql2100_fw.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/ql2100_fw.c Thu Jan 8 10:22:00 2004 @@ -0,0 +1,4858 @@ +/****************************************************************************** + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + *************************************************************************/ + +/* + * Firmware Version 1.19.24 (14:02 Jul 16, 2002) + */ + +#ifdef UNIQUE_FW_NAME +unsigned short fw2100tp_version = 1*1024+19; +#else +unsigned short risc_code_version = 1*1024+19; +#endif + +#ifdef UNIQUE_FW_NAME +unsigned char fw2100tp_version_str[] = {1,19,24}; +#else +unsigned char firmware_version[] = {1,19,24}; +#endif + +#ifdef UNIQUE_FW_NAME +#define fw2100tp_VERSION_STRING "1.19.24" +#else +#define FW_VERSION_STRING "1.19.24" +#endif + +#ifdef UNIQUE_FW_NAME +unsigned short fw2100tp_addr01 = 0x1000 ; +#else +unsigned short risc_code_addr01 = 0x1000 ; +#endif + +#ifdef UNIQUE_FW_NAME +unsigned short fw2100tp_code01[] = { +#else +unsigned short risc_code01[] = { +#endif + 0x0078, 0x102d, 0x0000, 0x95f1, 0x0000, 0x0001, 0x0013, 0x0018, + 0x0017, 0x2043, 0x4f50, 0x5952, 0x4947, 0x4854, 0x2032, 0x3030, + 0x3120, 0x514c, 0x4f47, 0x4943, 0x2043, 0x4f52, 0x504f, 0x5241, + 0x5449, 0x4f4e, 0x2049, 0x5350, 0x3231, 0x3030, 0x2046, 0x6972, + 0x6d77, 0x6172, 0x6520, 0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030, + 0x312e, 0x3139, 0x2020, 0x2020, 0x2400, 0x2091, 0x2000, 0x20c1, + 0x0021, 0x2039, 0xffff, 0x2019, 0xaaaa, 0x2760, 0x2069, 0x7fff, + 0x20c1, 0x0020, 0x2c2c, 0x2d34, 0x2762, 0x236a, 0x2c24, 0x2d04, + 0x266a, 0x2562, 0xa406, 0x00c0, 0x1052, 0x20c1, 0x0021, 0x2c2c, + 0x2362, 0x2c04, 0x2562, 0xa306, 0x0040, 0x1052, 0x20c1, 0x0020, + 0x2039, 0x8fff, 0x20a1, 0xad00, 0x2708, 0x810d, 0x810d, 0x810d, + 0x810d, 0xa18c, 0x000f, 0x2001, 0x000a, 0xa112, 0xa00e, 0x21a8, + 0x41a4, 0x3400, 0x8211, 0x00c0, 0x105f, 0x2708, 0x3400, 0xa102, + 0x0040, 0x106f, 0x0048, 0x106f, 0x20a8, 0xa00e, 0x41a4, 0x20a1, + 0xa5f1, 0x2009, 0x0000, 0x20a9, 0x070f, 0x41a4, 0x3400, 0x20c9, + 0xaaff, 0x2059, 0x0000, 0x2b78, 0x7823, 0x0004, 0x2089, 0x25c7, + 0x2051, 0xa600, 0x2a70, 0x7762, 0xa786, 0x8fff, 0x0040, 0x1092, + 0x705f, 0xcd00, 0x705b, 0xccf1, 0x7067, 0x0200, 0x706b, 0x0200, + 0x0078, 0x109a, 0x705b, 0xbd01, 0x7067, 0x0100, 0x706b, 0x0100, + 0x705f, 0xbd00, 0x1078, 0x12df, 0x1078, 0x13ca, 0x1078, 0x1577, + 0x1078, 0x1ce9, 0x1078, 0x42ec, 0x1078, 0x76bf, 0x1078, 0x1355, + 0x1078, 0x2ac0, 0x1078, 0x4e93, 0x1078, 0x49a3, 0x1078, 0x594a, + 0x1078, 0x2263, 0x1078, 0x5c43, 0x1078, 0x5485, 0x1078, 0x2162, + 0x1078, 0x2240, 0x2091, 0x3009, 0x7823, 0x0000, 0x0090, 0x10cf, + 0x7820, 0xa086, 0x0002, 0x00c0, 0x10cf, 0x7823, 0x4000, 0x0068, + 0x10c7, 0x781b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x2a70, + 0x7003, 0x0000, 0x2001, 0x017f, 0x2003, 0x0000, 0x2a70, 0x7000, + 0xa08e, 0x0003, 0x00c0, 0x10ef, 0x1078, 0x365e, 0x1078, 0x2ae8, + 0x1078, 0x4ee3, 0x1078, 0x4b66, 0x2009, 0x0100, 0x2104, 0xa082, + 0x0002, 0x0048, 0x10f3, 0x1078, 0x5966, 0x0078, 0x10d6, 0x1079, + 0x10f7, 0x0078, 0x10dc, 0x1078, 0x7197, 0x0078, 0x10eb, 0x1101, + 0x1102, 0x11be, 0x10ff, 0x1246, 0x12dc, 0x12dd, 0x12de, 0x1078, + 0x1332, 0x007c, 0x127e, 0x0f7e, 0x2091, 0x8000, 0x7000, 0xa086, + 0x0001, 0x00c0, 0x1198, 0x1078, 0x3aec, 0x2079, 0x0100, 0x7844, + 0xa005, 0x00c0, 0x1198, 0x2011, 0x41dc, 0x1078, 0x5a45, 0x1078, + 0x1adf, 0x780f, 0x00ff, 0x7840, 0xa084, 0xfffb, 0x7842, 0x2011, + 0x8010, 0x73c4, 0x1078, 0x361b, 0x2001, 0xffff, 0x1078, 0x5ae6, + 0x723c, 0xc284, 0x723e, 0x2001, 0xa60c, 0x2014, 0xc2ac, 0x2202, + 0x1078, 0x6f9f, 0x2011, 0x0004, 0x1078, 0x8d1b, 0x1078, 0x489e, + 0x1078, 0x42d4, 0x0040, 0x1144, 0x7087, 0x0001, 0x70bf, 0x0000, + 0x1078, 0x3c9e, 0x0078, 0x1198, 0x1078, 0x4967, 0x0040, 0x114d, + 0x7a0c, 0xc2b4, 0x7a0e, 0x0078, 0x1159, 0x1078, 0x90a6, 0x70cc, + 0xd09c, 0x00c0, 0x1159, 0x7098, 0xa005, 0x0040, 0x1159, 0x1078, + 0x42b8, 0x70d7, 0x0000, 0x70d3, 0x0000, 0x72cc, 0x2079, 0xa652, + 0x7804, 0xd0ac, 0x0040, 0x1165, 0xc295, 0x72ce, 0xa296, 0x0004, + 0x0040, 0x1186, 0x2011, 0x0001, 0x1078, 0x8d1b, 0x7093, 0x0000, + 0x7097, 0xffff, 0x7003, 0x0002, 0x0f7f, 0x1078, 0x2677, 0x2011, + 0x0005, 0x1078, 0x70e0, 0x1078, 0x62d1, 0x0c7e, 0x2061, 0x0100, + 0x60e3, 0x0008, 0x0c7f, 0x127f, 0x0078, 0x119a, 0x7093, 0x0000, + 0x7097, 0xffff, 0x7003, 0x0002, 0x2011, 0x0005, 0x1078, 0x70e0, + 0x1078, 0x62d1, 0x0c7e, 0x2061, 0x0100, 0x60e3, 0x0008, 0x0c7f, + 0x0f7f, 0x127f, 0x007c, 0x0c7e, 0x20a9, 0x0082, 0x2009, 0x007e, + 0x017e, 0x027e, 0x037e, 0x2110, 0x027e, 0x2019, 0x0029, 0x1078, + 0x73d0, 0x027f, 0x1078, 0xa4f1, 0x037f, 0x027f, 0x017f, 0x1078, + 0x298e, 0x8108, 0x00f0, 0x11a0, 0x0c7f, 0x706f, 0x0000, 0x7070, + 0xa084, 0x00ff, 0x7072, 0x709b, 0x0000, 0x007c, 0x127e, 0x2091, + 0x8000, 0x7000, 0xa086, 0x0002, 0x00c0, 0x1244, 0x7094, 0xa086, + 0xffff, 0x0040, 0x11d1, 0x1078, 0x2677, 0x1078, 0x62d1, 0x0078, + 0x1244, 0x70cc, 0xd09c, 0x0040, 0x11fd, 0xd084, 0x0040, 0x11fd, + 0x0f7e, 0x2079, 0x0100, 0x790c, 0xc1b5, 0x790e, 0x0f7f, 0xd08c, + 0x0040, 0x11fd, 0x70d0, 0xa086, 0xffff, 0x0040, 0x11f9, 0x1078, + 0x27f7, 0x1078, 0x62d1, 0x70cc, 0xd094, 0x00c0, 0x1244, 0x2011, + 0x0001, 0x2019, 0x0000, 0x1078, 0x282f, 0x1078, 0x62d1, 0x0078, + 0x1244, 0x70d4, 0xa005, 0x00c0, 0x1244, 0x7090, 0xa005, 0x00c0, + 0x1244, 0x1078, 0x4967, 0x00c0, 0x1244, 0x2001, 0xa653, 0x2004, + 0xd0ac, 0x0040, 0x1227, 0x157e, 0x0c7e, 0x20a9, 0x007f, 0x2009, + 0x0000, 0x017e, 0x1078, 0x45c4, 0x00c0, 0x121a, 0x6000, 0xd0ec, + 0x00c0, 0x1222, 0x017f, 0x8108, 0x00f0, 0x1211, 0x0c7f, 0x157f, + 0x0078, 0x1227, 0x017f, 0x0c7f, 0x157f, 0x0078, 0x1244, 0x7003, + 0x0003, 0x7097, 0xffff, 0x2001, 0x0000, 0x1078, 0x24e8, 0x1078, + 0x3699, 0x2001, 0xa8b2, 0x2004, 0xa086, 0x0005, 0x00c0, 0x123c, + 0x2011, 0x0000, 0x1078, 0x70e0, 0x2011, 0x0000, 0x1078, 0x70ea, + 0x1078, 0x62d1, 0x1078, 0x639b, 0x127f, 0x007c, 0x017e, 0x0f7e, + 0x127e, 0x2091, 0x8000, 0x2079, 0x0100, 0x2009, 0x00f7, 0x1078, + 0x42a1, 0x7940, 0xa18c, 0x0010, 0x7942, 0x7924, 0xd1b4, 0x0040, + 0x125b, 0x7827, 0x0040, 0xd19c, 0x0040, 0x1260, 0x7827, 0x0008, + 0x007e, 0x037e, 0x157e, 0xa006, 0x1078, 0x5ae6, 0x7900, 0xa18a, + 0x0003, 0x0050, 0x1289, 0x7954, 0xd1ac, 0x00c0, 0x1289, 0x2009, + 0x00f8, 0x1078, 0x42a1, 0x7843, 0x0090, 0x7843, 0x0010, 0x20a9, + 0x09c4, 0x7820, 0xd09c, 0x00c0, 0x1281, 0x7824, 0xd0ac, 0x00c0, + 0x12ca, 0x00f0, 0x1279, 0x2001, 0x0001, 0x1078, 0x24e8, 0x0078, + 0x12d5, 0x7853, 0x0000, 0x782f, 0x0020, 0x20a9, 0x0050, 0x00e0, + 0x128f, 0x2091, 0x6000, 0x00f0, 0x128f, 0x7853, 0x0400, 0x782f, + 0x0000, 0x2009, 0x00f8, 0x1078, 0x42a1, 0x20a9, 0x000e, 0x0005, + 0x00f0, 0x129f, 0x7853, 0x1400, 0x7843, 0x0090, 0x7843, 0x0010, + 0x2019, 0x61a8, 0x7854, 0x0005, 0x0005, 0xd08c, 0x0040, 0x12b4, + 0x7824, 0xd0ac, 0x00c0, 0x12ca, 0x8319, 0x00c0, 0x12aa, 0x2009, + 0xa632, 0x2104, 0x8000, 0x200a, 0xa084, 0xfff0, 0x0040, 0x12c4, + 0x200b, 0x0000, 0x1078, 0x2588, 0x2001, 0x0001, 0x1078, 0x24e8, + 0x0078, 0x12d3, 0x2001, 0xa632, 0x2003, 0x0000, 0x7828, 0xc09d, + 0x782a, 0x7827, 0x0048, 0x7853, 0x0400, 0x157f, 0x037f, 0x007f, + 0x127f, 0x0f7f, 0x017f, 0x007c, 0x007c, 0x007c, 0x007c, 0x2a70, + 0x2061, 0xa8ad, 0x2063, 0x0001, 0x6007, 0x0013, 0x600b, 0x0018, + 0x600f, 0x0017, 0x2009, 0x0100, 0x2104, 0xa082, 0x0002, 0x0048, + 0x12f5, 0x7053, 0xffff, 0x0078, 0x12f7, 0x7053, 0x0000, 0x7057, + 0xffff, 0x706f, 0x0000, 0x7073, 0x0000, 0x1078, 0x90a6, 0x2061, + 0xa88d, 0x6003, 0x0909, 0x6007, 0x0000, 0x600b, 0x8800, 0x600f, + 0x0200, 0x6013, 0x00ff, 0x6017, 0x0003, 0x601b, 0x0000, 0x601f, + 0x07d0, 0x2061, 0xa895, 0x6003, 0x8000, 0x6007, 0x0000, 0x600b, + 0x0000, 0x600f, 0x0200, 0x6013, 0x00ff, 0x6017, 0x0000, 0x601b, + 0x0001, 0x601f, 0x0000, 0x2061, 0xa8a5, 0x6003, 0x514c, 0x6007, + 0x4f47, 0x600b, 0x4943, 0x600f, 0x2020, 0x2001, 0xa626, 0x2003, + 0x0000, 0x007c, 0x2091, 0x8000, 0x0068, 0x1334, 0x007e, 0x017e, + 0x2079, 0x0000, 0x7818, 0xd084, 0x00c0, 0x133a, 0x017f, 0x792e, + 0x007f, 0x782a, 0x007f, 0x7826, 0x3900, 0x783a, 0x7823, 0x8002, + 0x781b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x2079, 0xa600, + 0x7803, 0x0005, 0x0078, 0x1352, 0x007c, 0x2071, 0xa600, 0x715c, + 0x712e, 0x2021, 0x0001, 0xa190, 0x002d, 0xa298, 0x002d, 0x0048, + 0x136b, 0x7060, 0xa302, 0x00c8, 0x136b, 0x220a, 0x2208, 0x2310, + 0x8420, 0x0078, 0x135d, 0x200b, 0x0000, 0x74aa, 0x74ae, 0x007c, + 0x0e7e, 0x127e, 0x2091, 0x8000, 0x2071, 0xa600, 0x70ac, 0xa0ea, + 0x0010, 0x00c8, 0x137e, 0xa06e, 0x0078, 0x1388, 0x8001, 0x70ae, + 0x702c, 0x2068, 0x2d04, 0x702e, 0x206b, 0x0000, 0x6807, 0x0000, + 0x127f, 0x0e7f, 0x007c, 0x0e7e, 0x2071, 0xa600, 0x127e, 0x2091, + 0x8000, 0x70ac, 0x8001, 0x00c8, 0x1398, 0xa06e, 0x0078, 0x13a1, + 0x70ae, 0x702c, 0x2068, 0x2d04, 0x702e, 0x206b, 0x0000, 0x6807, + 0x0000, 0x127f, 0x0e7f, 0x007c, 0x0e7e, 0x127e, 0x2091, 0x8000, + 0x2071, 0xa600, 0x702c, 0x206a, 0x2d00, 0x702e, 0x70ac, 0x8000, + 0x70ae, 0x127f, 0x0e7f, 0x007c, 0x8dff, 0x0040, 0x13c0, 0x6804, + 0x6807, 0x0000, 0x007e, 0x1078, 0x13a4, 0x0d7f, 0x0078, 0x13b4, + 0x007c, 0x0e7e, 0x2071, 0xa600, 0x70ac, 0xa08a, 0x0010, 0xa00d, + 0x0e7f, 0x007c, 0x0e7e, 0x2071, 0xa8d6, 0x7007, 0x0000, 0x701b, + 0x0000, 0x701f, 0x0000, 0x2071, 0x0000, 0x7010, 0xa085, 0x8004, + 0x7012, 0x0e7f, 0x007c, 0x127e, 0x2091, 0x8000, 0x0e7e, 0x2270, + 0x700b, 0x0000, 0x2071, 0xa8d6, 0x7018, 0xa088, 0xa8df, 0x220a, + 0x8000, 0xa084, 0x0007, 0x701a, 0x7004, 0xa005, 0x00c0, 0x13f6, + 0x0f7e, 0x2079, 0x0010, 0x1078, 0x1408, 0x0f7f, 0x0e7f, 0x127f, + 0x007c, 0x0e7e, 0x2071, 0xa8d6, 0x7004, 0xa005, 0x00c0, 0x1406, + 0x0f7e, 0x2079, 0x0010, 0x1078, 0x1408, 0x0f7f, 0x0e7f, 0x007c, + 0x7000, 0x0079, 0x140b, 0x140f, 0x1479, 0x1496, 0x1496, 0x7018, + 0x711c, 0xa106, 0x00c0, 0x1417, 0x7007, 0x0000, 0x007c, 0x0d7e, + 0xa180, 0xa8df, 0x2004, 0x700a, 0x2068, 0x8108, 0xa18c, 0x0007, + 0x711e, 0x7803, 0x0026, 0x6824, 0x7832, 0x6828, 0x7836, 0x682c, + 0x783a, 0x6830, 0x783e, 0x6810, 0x700e, 0x680c, 0x7016, 0x6804, + 0x0d7f, 0xd084, 0x0040, 0x1439, 0x7007, 0x0001, 0x1078, 0x143e, + 0x007c, 0x7007, 0x0002, 0x1078, 0x1454, 0x007c, 0x017e, 0x027e, + 0x710c, 0x2011, 0x0040, 0xa182, 0x0040, 0x00c8, 0x1449, 0x2110, + 0xa006, 0x700e, 0x7212, 0x8203, 0x7822, 0x7803, 0x0020, 0x7803, + 0x0041, 0x027f, 0x017f, 0x007c, 0x017e, 0x027e, 0x137e, 0x147e, + 0x157e, 0x7014, 0x2098, 0x20a1, 0x0014, 0x7803, 0x0026, 0x710c, + 0x2011, 0x0040, 0xa182, 0x0040, 0x00c8, 0x1468, 0x2110, 0xa006, + 0x700e, 0x22a8, 0x53a6, 0x8203, 0x7822, 0x7803, 0x0020, 0x3300, + 0x7016, 0x7803, 0x0001, 0x157f, 0x147f, 0x137f, 0x027f, 0x017f, + 0x007c, 0x137e, 0x147e, 0x157e, 0x2099, 0xa6fa, 0x20a1, 0x0018, + 0x20a9, 0x0008, 0x53a3, 0x7803, 0x0020, 0x127e, 0x2091, 0x8000, + 0x7803, 0x0041, 0x7007, 0x0003, 0x7000, 0xc084, 0x7002, 0x700b, + 0xa6f5, 0x127f, 0x157f, 0x147f, 0x137f, 0x007c, 0x137e, 0x147e, + 0x157e, 0x2001, 0xa729, 0x209c, 0x20a1, 0x0014, 0x7803, 0x0026, + 0x2001, 0xa72a, 0x20ac, 0x53a6, 0x2099, 0xa72b, 0x20a1, 0x0018, + 0x20a9, 0x0008, 0x53a3, 0x7803, 0x0020, 0x127e, 0x2091, 0x8000, + 0x7803, 0x0001, 0x7007, 0x0004, 0x7000, 0xc08c, 0x7002, 0x700b, + 0xa726, 0x127f, 0x157f, 0x147f, 0x137f, 0x007c, 0x017e, 0x0e7e, + 0x2071, 0xa8d6, 0x0f7e, 0x2079, 0x0010, 0x7904, 0x7803, 0x0002, + 0xd1fc, 0x0040, 0x14d0, 0xa18c, 0x0700, 0x7004, 0x1079, 0x14d4, + 0x0f7f, 0x0e7f, 0x017f, 0x007c, 0x1408, 0x14dc, 0x1509, 0x1531, + 0x1564, 0x14da, 0x0078, 0x14da, 0xa18c, 0x0700, 0x00c0, 0x1502, + 0x137e, 0x147e, 0x157e, 0x7014, 0x20a0, 0x2099, 0x0014, 0x7803, + 0x0040, 0x7010, 0x20a8, 0x53a5, 0x3400, 0x7016, 0x157f, 0x147f, + 0x137f, 0x700c, 0xa005, 0x0040, 0x151e, 0x1078, 0x143e, 0x007c, + 0x7008, 0xa080, 0x0002, 0x2003, 0x0100, 0x7007, 0x0000, 0x1078, + 0x1408, 0x007c, 0x7008, 0xa080, 0x0002, 0x2003, 0x0200, 0x0078, + 0x14fd, 0xa18c, 0x0700, 0x00c0, 0x1514, 0x700c, 0xa005, 0x0040, + 0x151e, 0x1078, 0x1454, 0x007c, 0x7008, 0xa080, 0x0002, 0x2003, + 0x0200, 0x7007, 0x0000, 0x1078, 0x1408, 0x007c, 0x0d7e, 0x7008, + 0x2068, 0x7830, 0x6826, 0x7834, 0x682a, 0x7838, 0x682e, 0x783c, + 0x6832, 0x680b, 0x0100, 0x0d7f, 0x7007, 0x0000, 0x1078, 0x1408, + 0x007c, 0xa18c, 0x0700, 0x00c0, 0x155e, 0x137e, 0x147e, 0x157e, + 0x2001, 0xa6f8, 0x2004, 0xa080, 0x000d, 0x20a0, 0x2099, 0x0014, + 0x7803, 0x0040, 0x20a9, 0x0020, 0x53a5, 0x2001, 0xa6fa, 0x2004, + 0xd0bc, 0x0040, 0x1554, 0x2001, 0xa703, 0x2004, 0xa080, 0x000d, + 0x20a0, 0x20a9, 0x0020, 0x53a5, 0x157f, 0x147f, 0x137f, 0x7007, + 0x0000, 0x1078, 0x4f8c, 0x1078, 0x1408, 0x007c, 0x2011, 0x8003, + 0x1078, 0x361b, 0x0078, 0x1562, 0xa18c, 0x0700, 0x00c0, 0x1571, + 0x2001, 0xa728, 0x2003, 0x0100, 0x7007, 0x0000, 0x1078, 0x1408, + 0x007c, 0x2011, 0x8004, 0x1078, 0x361b, 0x0078, 0x1575, 0x127e, + 0x2091, 0x2100, 0x2079, 0x0030, 0x2071, 0xa8e7, 0x7803, 0x0004, + 0x7003, 0x0000, 0x700f, 0xa8ed, 0x7013, 0xa8ed, 0x780f, 0x0076, + 0x7803, 0x0004, 0x127f, 0x007c, 0x6934, 0xa184, 0x0007, 0x0079, + 0x1591, 0x1599, 0x15df, 0x1599, 0x1599, 0x1599, 0x15c4, 0x15a8, + 0x159d, 0xa085, 0x0001, 0x0078, 0x15f9, 0x684c, 0xd0bc, 0x0040, + 0x1599, 0x6860, 0x682e, 0x685c, 0x682a, 0x6858, 0x0078, 0x15e7, + 0xa18c, 0x00ff, 0xa186, 0x001e, 0x00c0, 0x1599, 0x684c, 0xd0bc, + 0x0040, 0x1599, 0x6860, 0x682e, 0x685c, 0x682a, 0x6804, 0x681a, + 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x206a, 0x2004, + 0x6832, 0x6858, 0x0078, 0x15ef, 0xa18c, 0x00ff, 0xa186, 0x0015, + 0x00c0, 0x1599, 0x684c, 0xd0ac, 0x0040, 0x1599, 0x6804, 0x681a, + 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x206a, 0x2004, + 0x6832, 0xa006, 0x682e, 0x682a, 0x6858, 0x0078, 0x15ef, 0x684c, + 0xd0ac, 0x0040, 0x1599, 0xa006, 0x682e, 0x682a, 0x6858, 0xa18c, + 0x000f, 0xa188, 0x206a, 0x210c, 0x6932, 0x2d08, 0x691a, 0x6826, + 0x684c, 0xc0dd, 0x684e, 0xa006, 0x680a, 0x697c, 0x6912, 0x6980, + 0x6916, 0x007c, 0x20e1, 0x0007, 0x20e1, 0x2000, 0x2001, 0x020a, + 0x2004, 0x82ff, 0x0040, 0x161c, 0xa280, 0x0004, 0x0d7e, 0x206c, + 0x684c, 0xd0dc, 0x00c0, 0x1618, 0x1078, 0x158c, 0x0040, 0x1618, + 0x0d7f, 0xa280, 0x0000, 0x2003, 0x0002, 0xa016, 0x0078, 0x161c, + 0x6808, 0x8000, 0x680a, 0x0d7f, 0x127e, 0x047e, 0x037e, 0x027e, + 0x2091, 0x2100, 0x027f, 0x037f, 0x047f, 0x7000, 0xa005, 0x00c0, + 0x1630, 0x7206, 0x2001, 0x1651, 0x007e, 0x2260, 0x0078, 0x17e0, + 0x710c, 0x220a, 0x8108, 0x230a, 0x8108, 0x240a, 0x8108, 0xa182, + 0xa908, 0x0048, 0x163d, 0x2009, 0xa8ed, 0x710e, 0x7010, 0xa102, + 0xa082, 0x0009, 0x0040, 0x1648, 0xa080, 0x001b, 0x00c0, 0x164b, + 0x2009, 0x0138, 0x200a, 0x7000, 0xa005, 0x00c0, 0x1651, 0x1078, + 0x17c1, 0x127f, 0x007c, 0x127e, 0x027e, 0x037e, 0x0c7e, 0x007e, + 0x2091, 0x2100, 0x007f, 0x047f, 0x037f, 0x027f, 0x0d7e, 0x0c7e, + 0x2460, 0x6110, 0x2168, 0x6a62, 0x6b5e, 0xa005, 0x0040, 0x16dd, + 0x6808, 0xa005, 0x0040, 0x174a, 0x7000, 0xa005, 0x00c0, 0x1672, + 0x0078, 0x16d2, 0x700c, 0x7110, 0xa106, 0x00c0, 0x1753, 0x7004, + 0xa406, 0x00c0, 0x16d2, 0x2001, 0x0005, 0x2004, 0xd08c, 0x0040, + 0x168f, 0x047e, 0x1078, 0x1913, 0x047f, 0x2460, 0x6010, 0xa080, + 0x0002, 0x2004, 0xa005, 0x0040, 0x174a, 0x0078, 0x166c, 0x2001, + 0x0207, 0x2004, 0xd09c, 0x00c0, 0x167b, 0x7804, 0xa084, 0x6000, + 0x0040, 0x16a0, 0xa086, 0x6000, 0x0040, 0x16a0, 0x0078, 0x167b, + 0x7100, 0xa186, 0x0002, 0x00c0, 0x16c0, 0x0e7e, 0x2b68, 0x6818, + 0x2060, 0x1078, 0x203f, 0x2804, 0xac70, 0x6034, 0xd09c, 0x00c0, + 0x16b5, 0x7108, 0x720c, 0x0078, 0x16b7, 0x7110, 0x7214, 0x6810, + 0xa100, 0x6812, 0x6814, 0xa201, 0x6816, 0x0e7f, 0x0078, 0x16c4, + 0xa186, 0x0001, 0x00c0, 0x16cc, 0x7820, 0x6910, 0xa100, 0x6812, + 0x7824, 0x6914, 0xa101, 0x6816, 0x7803, 0x0004, 0x7003, 0x0000, + 0x7004, 0x2060, 0x6100, 0xa18e, 0x0004, 0x00c0, 0x1753, 0x2009, + 0x0048, 0x1078, 0x775c, 0x0078, 0x1753, 0x6808, 0xa005, 0x0040, + 0x174a, 0x7000, 0xa005, 0x00c0, 0x16e7, 0x0078, 0x174a, 0x700c, + 0x7110, 0xa106, 0x00c0, 0x16f0, 0x7004, 0xa406, 0x00c0, 0x174a, + 0x2001, 0x0005, 0x2004, 0xd08c, 0x0040, 0x1704, 0x047e, 0x1078, + 0x1913, 0x047f, 0x2460, 0x6010, 0xa080, 0x0002, 0x2004, 0xa005, + 0x0040, 0x174a, 0x0078, 0x16e1, 0x2001, 0x0207, 0x2004, 0xd09c, + 0x00c0, 0x16f0, 0x2001, 0x0005, 0x2004, 0xd08c, 0x00c0, 0x16f6, + 0x7804, 0xa084, 0x6000, 0x0040, 0x171b, 0xa086, 0x6000, 0x0040, + 0x171b, 0x0078, 0x16f0, 0x7007, 0x0000, 0xa016, 0x2218, 0x7000, + 0xa08e, 0x0001, 0x0040, 0x173c, 0xa08e, 0x0002, 0x00c0, 0x174a, + 0x0c7e, 0x0e7e, 0x6818, 0x2060, 0x1078, 0x203f, 0x2804, 0xac70, + 0x6034, 0xd09c, 0x00c0, 0x1738, 0x7308, 0x720c, 0x0078, 0x173a, + 0x7310, 0x7214, 0x0e7f, 0x0c7f, 0x7820, 0xa318, 0x7824, 0xa211, + 0x6810, 0xa300, 0x6812, 0x6814, 0xa201, 0x6816, 0x7803, 0x0004, + 0x7003, 0x0000, 0x6100, 0xa18e, 0x0004, 0x00c0, 0x1753, 0x2009, + 0x0048, 0x1078, 0x775c, 0x0c7f, 0x0d7f, 0x127f, 0x007c, 0x0f7e, + 0x0e7e, 0x027e, 0x037e, 0x047e, 0x057e, 0x2071, 0xa8e7, 0x7000, + 0xa086, 0x0000, 0x0040, 0x17ba, 0x7004, 0xac06, 0x00c0, 0x17ab, + 0x2079, 0x0030, 0x7000, 0xa086, 0x0003, 0x0040, 0x17ab, 0x7804, + 0xd0fc, 0x00c0, 0x17a7, 0x20e1, 0x6000, 0x2011, 0x0032, 0x2001, + 0x0208, 0x200c, 0x2001, 0x0209, 0x2004, 0xa106, 0x00c0, 0x176f, + 0x8211, 0x00c0, 0x1777, 0x7804, 0xd0fc, 0x00c0, 0x17a7, 0x1078, + 0x1b22, 0x027e, 0x057e, 0x7803, 0x0004, 0x7804, 0xd0ac, 0x00c0, + 0x178d, 0x7803, 0x0002, 0x7803, 0x0009, 0x7003, 0x0003, 0x7007, + 0x0000, 0x057f, 0x027f, 0x2001, 0x015d, 0x2003, 0x0000, 0x2001, + 0x0160, 0x2502, 0x2001, 0x0138, 0x2202, 0x0078, 0x17ab, 0x1078, + 0x1913, 0x0078, 0x175f, 0x157e, 0x20a9, 0x0009, 0x2009, 0xa8ed, + 0x2104, 0xac06, 0x00c0, 0x17b5, 0x200a, 0xa188, 0x0003, 0x00f0, + 0x17b0, 0x157f, 0x057f, 0x047f, 0x037f, 0x027f, 0x0e7f, 0x0f7f, + 0x007c, 0x700c, 0x7110, 0xa106, 0x00c0, 0x17c9, 0x7003, 0x0000, + 0x007c, 0x2104, 0x7006, 0x2060, 0x8108, 0x211c, 0x8108, 0x2124, + 0x8108, 0xa182, 0xa908, 0x0048, 0x17d7, 0x2009, 0xa8ed, 0x7112, + 0x700c, 0xa106, 0x00c0, 0x17e0, 0x2001, 0x0138, 0x2003, 0x0008, + 0x8cff, 0x00c0, 0x17e7, 0x1078, 0x1b4d, 0x0078, 0x1854, 0x6010, + 0x2068, 0x2d58, 0x6828, 0xa406, 0x00c0, 0x17f2, 0x682c, 0xa306, + 0x0040, 0x182f, 0x601c, 0xa086, 0x0008, 0x0040, 0x182f, 0x6024, + 0xd0f4, 0x00c0, 0x181c, 0xd0d4, 0x0040, 0x1818, 0x6038, 0xa402, + 0x6034, 0xa303, 0x0040, 0x1806, 0x00c8, 0x1818, 0x643a, 0x6336, + 0x6c2a, 0x6b2e, 0x047e, 0x037e, 0x2400, 0x6c7c, 0xa402, 0x6812, + 0x2300, 0x6b80, 0xa303, 0x6816, 0x037f, 0x047f, 0x0078, 0x181c, + 0x1078, 0x9053, 0x0040, 0x17e3, 0x2001, 0xa674, 0x2004, 0xd0b4, + 0x00c0, 0x182b, 0x6018, 0x2004, 0xd0bc, 0x00c0, 0x182b, 0x6817, + 0x7fff, 0x6813, 0xffff, 0x1078, 0x208a, 0x00c0, 0x17e3, 0x0c7e, + 0x7004, 0x2060, 0x6024, 0xc0d4, 0x6026, 0x0c7f, 0x684c, 0xd0f4, + 0x0040, 0x1840, 0x6817, 0xffff, 0x6813, 0xffff, 0x0078, 0x17e3, + 0x6824, 0x2050, 0x6818, 0x2060, 0x6830, 0x2040, 0x6034, 0xa0cc, + 0x000f, 0x2009, 0x0011, 0x1078, 0x1855, 0x0040, 0x1853, 0x2009, + 0x0001, 0x1078, 0x1855, 0x2d58, 0x007c, 0x8aff, 0x0040, 0x18ec, + 0xa03e, 0x2730, 0x6850, 0xd0fc, 0x00c0, 0x1877, 0xd0f4, 0x00c0, + 0x1887, 0x0d7e, 0x2804, 0xac68, 0x2900, 0x0079, 0x1867, 0x18ce, + 0x188e, 0x188e, 0x18ce, 0x18ce, 0x18c6, 0x18ce, 0x188e, 0x18ce, + 0x1894, 0x1894, 0x18ce, 0x18ce, 0x18ce, 0x18bd, 0x1894, 0xc0fc, + 0x6852, 0x6b6c, 0x6a70, 0x6d1c, 0x6c20, 0x0d7e, 0xd99c, 0x0040, + 0x18d1, 0x2804, 0xac68, 0x6f08, 0x6e0c, 0x0078, 0x18d1, 0xc0f4, + 0x6852, 0x6b6c, 0x6a70, 0x0d7e, 0x0078, 0x18d8, 0x6b08, 0x6a0c, + 0x6d00, 0x6c04, 0x0078, 0x18d1, 0x7b0c, 0xd3bc, 0x0040, 0x18b5, + 0x7004, 0x0e7e, 0x2070, 0x701c, 0x0e7f, 0xa086, 0x0008, 0x00c0, + 0x18b5, 0x7b08, 0xa39c, 0x0fff, 0x2d20, 0x0d7f, 0x0d7e, 0x6a14, + 0x82ff, 0x00c0, 0x18b0, 0x6810, 0xa302, 0x0048, 0x18b0, 0x6b10, + 0x2011, 0x0000, 0x2468, 0x0078, 0x18b7, 0x6b10, 0x6a14, 0x6d00, + 0x6c04, 0x6f08, 0x6e0c, 0x0078, 0x18d1, 0x0d7f, 0x0d7e, 0x6834, + 0xa084, 0x00ff, 0xa086, 0x001e, 0x00c0, 0x18ce, 0x0d7f, 0x1078, + 0x2026, 0x00c0, 0x1855, 0xa00e, 0x0078, 0x18ec, 0x0d7f, 0x1078, + 0x1332, 0x7b22, 0x7a26, 0x7d32, 0x7c36, 0x7f3a, 0x7e3e, 0x7902, + 0x7000, 0x8000, 0x7002, 0x0d7f, 0x6828, 0xa300, 0x682a, 0x682c, + 0xa201, 0x682e, 0x2300, 0x6b10, 0xa302, 0x6812, 0x2200, 0x6a14, + 0xa203, 0x6816, 0x1078, 0x2026, 0x007c, 0x1078, 0x1332, 0x1078, + 0x1c97, 0x7004, 0x2060, 0x0d7e, 0x6010, 0x2068, 0x7003, 0x0000, + 0x1078, 0x1af4, 0x1078, 0x8d06, 0x0040, 0x190c, 0x6808, 0x8001, + 0x680a, 0x697c, 0x6912, 0x6980, 0x6916, 0x682b, 0xffff, 0x682f, + 0xffff, 0x6850, 0xc0bd, 0x6852, 0x0d7f, 0x1078, 0x8a01, 0x0078, + 0x1adb, 0x1078, 0x1332, 0x127e, 0x2091, 0x2100, 0x007e, 0x017e, + 0x2b68, 0x6818, 0x2060, 0x7904, 0x7803, 0x0002, 0xa184, 0x0700, + 0x00c0, 0x18ef, 0xa184, 0x0003, 0xa086, 0x0003, 0x0040, 0x1911, + 0x7000, 0x0079, 0x192b, 0x1933, 0x1935, 0x1a34, 0x1ab2, 0x1ac9, + 0x1933, 0x1933, 0x1933, 0x1078, 0x1332, 0x8001, 0x7002, 0xa184, + 0x0880, 0x00c0, 0x194a, 0x8aff, 0x0040, 0x19d4, 0x2009, 0x0001, + 0x1078, 0x1855, 0x0040, 0x1adb, 0x2009, 0x0001, 0x1078, 0x1855, + 0x0078, 0x1adb, 0x7803, 0x0004, 0x7003, 0x0000, 0xd1bc, 0x00c0, + 0x19b2, 0x027e, 0x037e, 0x017e, 0x7808, 0xd0ec, 0x00c0, 0x1962, + 0x7c20, 0x7d24, 0x7e30, 0x7f34, 0x7803, 0x0009, 0x7003, 0x0004, + 0x0078, 0x1964, 0x1078, 0x1bd7, 0x017f, 0xd194, 0x0040, 0x196b, + 0x8aff, 0x0040, 0x19a1, 0x6b28, 0x6a2c, 0x2400, 0x686e, 0xa31a, + 0x2500, 0x6872, 0xa213, 0x6b2a, 0x6a2e, 0x0c7e, 0x7004, 0x2060, + 0x6024, 0xd0f4, 0x00c0, 0x197e, 0x633a, 0x6236, 0x0c7f, 0x2400, + 0x6910, 0xa100, 0x6812, 0x2500, 0x6914, 0xa101, 0x6816, 0x037f, + 0x027f, 0x2600, 0x681e, 0x2700, 0x6822, 0x1078, 0x203f, 0x2a00, + 0x6826, 0x2c00, 0x681a, 0x2800, 0x6832, 0x6850, 0xc0fd, 0x6852, + 0x6808, 0x8001, 0x680a, 0x00c0, 0x19a7, 0x684c, 0xd0e4, 0x0040, + 0x19a7, 0x7004, 0x2060, 0x2009, 0x0048, 0x1078, 0x775c, 0x7000, + 0xa086, 0x0004, 0x0040, 0x1adb, 0x7003, 0x0000, 0x1078, 0x17c1, + 0x0078, 0x1adb, 0x057e, 0x7d0c, 0xd5bc, 0x00c0, 0x19b9, 0x1078, + 0xa57e, 0x057f, 0x1078, 0x1af4, 0x0f7e, 0x7004, 0x2078, 0x1078, + 0x4963, 0x0040, 0x19c6, 0x7824, 0xc0f5, 0x7826, 0x0f7f, 0x682b, + 0xffff, 0x682f, 0xffff, 0x6808, 0x8001, 0x680a, 0x697c, 0x6912, + 0x6980, 0x6916, 0x0078, 0x1adb, 0x7004, 0x0c7e, 0x2060, 0x6024, + 0x0c7f, 0xd0f4, 0x0040, 0x19e1, 0x6808, 0x8001, 0x680a, 0x0078, + 0x19f5, 0x684c, 0xc0f5, 0x684e, 0x7814, 0xa005, 0x00c0, 0x19f9, + 0x7003, 0x0000, 0x6808, 0x8001, 0x680a, 0x00c0, 0x19f5, 0x7004, + 0x2060, 0x2009, 0x0048, 0x1078, 0x775c, 0x1078, 0x17c1, 0x0078, + 0x1adb, 0x7814, 0x6910, 0xa102, 0x6812, 0x6914, 0xa183, 0x0000, + 0x6816, 0x7814, 0x7908, 0xa18c, 0x0fff, 0xa192, 0x0841, 0x00c8, + 0x18ef, 0xa188, 0x0007, 0x8114, 0x8214, 0x8214, 0xa10a, 0x8104, + 0x8004, 0x8004, 0xa20a, 0x810b, 0x810b, 0x810b, 0x1078, 0x1b5e, + 0x7803, 0x0004, 0x780f, 0xffff, 0x7803, 0x0001, 0x7804, 0xd0fc, + 0x0040, 0x1a1e, 0x7803, 0x0002, 0x7803, 0x0004, 0x780f, 0x0076, + 0x7004, 0x7007, 0x0000, 0x2060, 0x2009, 0x0048, 0x1078, 0x775c, + 0x1078, 0x1b92, 0x0040, 0x19f5, 0x8001, 0x7002, 0xd194, 0x0040, + 0x1a46, 0x7804, 0xd0fc, 0x00c0, 0x191b, 0x8aff, 0x0040, 0x1adb, + 0x2009, 0x0001, 0x1078, 0x1855, 0x0078, 0x1adb, 0xa184, 0x0880, + 0x00c0, 0x1a53, 0x8aff, 0x0040, 0x1adb, 0x2009, 0x0001, 0x1078, + 0x1855, 0x0078, 0x1adb, 0x7803, 0x0004, 0x7003, 0x0000, 0xd1bc, + 0x00c0, 0x1a93, 0x027e, 0x037e, 0x7808, 0xd0ec, 0x00c0, 0x1a66, + 0x7803, 0x0009, 0x7003, 0x0004, 0x0078, 0x1a68, 0x1078, 0x1bd7, + 0x6b28, 0x6a2c, 0x1078, 0x203f, 0x0d7e, 0x0f7e, 0x2d78, 0x2804, + 0xac68, 0x6034, 0xd09c, 0x00c0, 0x1a83, 0x6808, 0x2008, 0xa31a, + 0x680c, 0xa213, 0x7810, 0xa100, 0x7812, 0x690c, 0x7814, 0xa101, + 0x7816, 0x0078, 0x1a8f, 0x6810, 0x2008, 0xa31a, 0x6814, 0xa213, + 0x7810, 0xa100, 0x7812, 0x6914, 0x7814, 0xa101, 0x7816, 0x0f7f, + 0x0d7f, 0x0078, 0x196d, 0x057e, 0x7d0c, 0x1078, 0xa57e, 0x057f, + 0x1078, 0x1af4, 0x0f7e, 0x7004, 0x2078, 0x1078, 0x4963, 0x0040, + 0x1aa4, 0x7824, 0xc0f5, 0x7826, 0x0f7f, 0x682b, 0xffff, 0x682f, + 0xffff, 0x6808, 0x8001, 0x680a, 0x697c, 0x6912, 0x6980, 0x6916, + 0x0078, 0x1adb, 0x7803, 0x0004, 0x7003, 0x0000, 0x7004, 0xa00d, + 0x0040, 0x1ac5, 0x6808, 0x8001, 0x680a, 0x00c0, 0x1ac5, 0x7004, + 0x2060, 0x2009, 0x0048, 0x1078, 0x775c, 0x1078, 0x17c1, 0x0078, + 0x1adb, 0x7803, 0x0004, 0x7003, 0x0000, 0x7004, 0x2060, 0x6010, + 0xa005, 0x0040, 0x1ac5, 0x2068, 0x6808, 0x8000, 0x680a, 0x6c28, + 0x6b2c, 0x1078, 0x17e0, 0x017f, 0x007f, 0x127f, 0x007c, 0x127e, + 0x2091, 0x2100, 0x7000, 0xa086, 0x0003, 0x00c0, 0x1af2, 0x700c, + 0x7110, 0xa106, 0x0040, 0x1af2, 0x20e1, 0x9028, 0x700f, 0xa8ed, + 0x7013, 0xa8ed, 0x127f, 0x007c, 0x0c7e, 0x1078, 0x1b22, 0x20e1, + 0x9028, 0x700c, 0x7110, 0xa106, 0x0040, 0x1b19, 0x2104, 0xa005, + 0x0040, 0x1b08, 0x2060, 0x6010, 0x2060, 0x6008, 0x8001, 0x600a, + 0xa188, 0x0003, 0xa182, 0xa908, 0x0048, 0x1b10, 0x2009, 0xa8ed, + 0x7112, 0x700c, 0xa106, 0x00c0, 0x1af9, 0x2011, 0x0008, 0x0078, + 0x1af9, 0x2001, 0x015d, 0x2003, 0x0000, 0x2001, 0x0138, 0x2202, + 0x0c7f, 0x007c, 0x2001, 0x0138, 0x2014, 0x2003, 0x0000, 0x2021, + 0xb015, 0x2001, 0x0141, 0x201c, 0xd3dc, 0x00c0, 0x1b3f, 0x2001, + 0x0109, 0x201c, 0xa39c, 0x0048, 0x00c0, 0x1b3f, 0x2001, 0x0111, + 0x201c, 0x83ff, 0x00c0, 0x1b3f, 0x8421, 0x00c0, 0x1b29, 0x007c, + 0x2011, 0x0201, 0x2009, 0x003c, 0x2204, 0xa005, 0x00c0, 0x1b4c, + 0x8109, 0x00c0, 0x1b44, 0x007c, 0x007c, 0x1078, 0x1b40, 0x0040, + 0x1b55, 0x780c, 0xd0a4, 0x0040, 0x1b5b, 0x1078, 0x1af4, 0xa085, + 0x0001, 0x0078, 0x1b5d, 0x1078, 0x1b92, 0x007c, 0x0e7e, 0x2071, + 0x0200, 0x7808, 0xa084, 0xf000, 0xa10d, 0x1078, 0x1b22, 0x2019, + 0x5000, 0x8319, 0x0040, 0x1b7c, 0x2001, 0xa908, 0x2004, 0xa086, + 0x0000, 0x0040, 0x1b7c, 0x2001, 0x0021, 0xd0fc, 0x0040, 0x1b69, + 0x1078, 0x1eaa, 0x0078, 0x1b67, 0x20e1, 0x7000, 0x7324, 0x7420, + 0x7028, 0x7028, 0x7426, 0x7037, 0x0001, 0x810f, 0x712e, 0x702f, + 0x0100, 0x7037, 0x0008, 0x7326, 0x7422, 0x2001, 0x0138, 0x2202, + 0x0e7f, 0x007c, 0x027e, 0x2001, 0x015d, 0x2001, 0x0000, 0x7908, + 0xa18c, 0x0fff, 0xa182, 0x0ffd, 0x0048, 0x1ba0, 0x2009, 0x0000, + 0xa190, 0x0007, 0xa294, 0x1ff8, 0x8214, 0x8214, 0x8214, 0x2001, + 0x020a, 0x82ff, 0x0040, 0x1bb5, 0x20e1, 0x6000, 0x200c, 0x200c, + 0x200c, 0x200c, 0x8211, 0x00c0, 0x1bae, 0x20e1, 0x7000, 0x200c, + 0x200c, 0x7003, 0x0000, 0x20e1, 0x6000, 0x2001, 0x0208, 0x200c, + 0x2001, 0x0209, 0x2004, 0xa106, 0x0040, 0x1bd4, 0x1078, 0x1b40, + 0x0040, 0x1bd2, 0x7908, 0xd1ec, 0x00c0, 0x1bd4, 0x790c, 0xd1a4, + 0x0040, 0x1b97, 0x1078, 0x1af4, 0xa006, 0x027f, 0x007c, 0x7c20, + 0x7d24, 0x7e30, 0x7f34, 0x700c, 0x7110, 0xa106, 0x0040, 0x1c69, + 0x7004, 0x017e, 0x210c, 0xa106, 0x017f, 0x0040, 0x1c69, 0x0d7e, + 0x0c7e, 0x216c, 0x2d00, 0xa005, 0x0040, 0x1c67, 0x681c, 0xa086, + 0x0008, 0x0040, 0x1c67, 0x6824, 0xd0d4, 0x00c0, 0x1c67, 0x6810, + 0x2068, 0x6850, 0xd0fc, 0x0040, 0x1c29, 0x8108, 0x2104, 0x6b2c, + 0xa306, 0x00c0, 0x1c67, 0x8108, 0x2104, 0x6a28, 0xa206, 0x00c0, + 0x1c67, 0x6850, 0xc0fc, 0xc0f5, 0x6852, 0x686c, 0x7822, 0x6870, + 0x7826, 0x681c, 0x7832, 0x6820, 0x7836, 0x6818, 0x2060, 0x6034, + 0xd09c, 0x0040, 0x1c24, 0x6830, 0x2004, 0xac68, 0x6808, 0x783a, + 0x680c, 0x783e, 0x0078, 0x1c65, 0xa006, 0x783a, 0x783e, 0x0078, + 0x1c65, 0x8108, 0x2104, 0xa005, 0x00c0, 0x1c67, 0x6b2c, 0xa306, + 0x00c0, 0x1c67, 0x8108, 0x2104, 0xa005, 0x00c0, 0x1c67, 0x6a28, + 0xa206, 0x00c0, 0x1c67, 0x6850, 0xc0f5, 0x6852, 0x6830, 0x2004, + 0x6918, 0xa160, 0xa180, 0x000d, 0x2004, 0xd09c, 0x00c0, 0x1c57, + 0x6008, 0x7822, 0x686e, 0x600c, 0x7826, 0x6872, 0x6000, 0x7832, + 0x6004, 0x7836, 0xa006, 0x783a, 0x783e, 0x0078, 0x1c65, 0x6010, + 0x7822, 0x686e, 0x6014, 0x7826, 0x6872, 0x6000, 0x7832, 0x6004, + 0x7836, 0x6008, 0x783a, 0x600c, 0x783e, 0x7803, 0x0011, 0x0c7f, + 0x0d7f, 0x007c, 0x0f7e, 0x0e7e, 0x017e, 0x027e, 0x2071, 0xa8e7, + 0x2079, 0x0030, 0x2011, 0x0050, 0x7000, 0xa086, 0x0000, 0x0040, + 0x1c92, 0x8211, 0x0040, 0x1c90, 0x2001, 0x0005, 0x2004, 0xd08c, + 0x0040, 0x1c79, 0x7904, 0xa18c, 0x0780, 0x017e, 0x1078, 0x1913, + 0x017f, 0x81ff, 0x00c0, 0x1c90, 0x2011, 0x0050, 0x0078, 0x1c74, + 0xa085, 0x0001, 0x027f, 0x017f, 0x0e7f, 0x0f7f, 0x007c, 0x7803, + 0x0004, 0x2009, 0x0064, 0x7804, 0xd0ac, 0x0040, 0x1ce8, 0x8109, + 0x00c0, 0x1c9b, 0x2009, 0x0100, 0x210c, 0xa18a, 0x0003, 0x1048, + 0x1332, 0x1078, 0x1fca, 0x0e7e, 0x0f7e, 0x2071, 0xa8d6, 0x2079, + 0x0010, 0x7004, 0xa086, 0x0000, 0x0040, 0x1ce0, 0x7800, 0x007e, + 0x7820, 0x007e, 0x7830, 0x007e, 0x7834, 0x007e, 0x7838, 0x007e, + 0x783c, 0x007e, 0x7803, 0x0004, 0x7823, 0x0000, 0x0005, 0x0005, + 0x2079, 0x0030, 0x7804, 0xd0ac, 0x10c0, 0x1332, 0x2079, 0x0010, + 0x007f, 0x783e, 0x007f, 0x783a, 0x007f, 0x7836, 0x007f, 0x7832, + 0x007f, 0x7822, 0x007f, 0x7802, 0x0f7f, 0x0e7f, 0x0078, 0x1ce6, + 0x0f7f, 0x0e7f, 0x7804, 0xd0ac, 0x10c0, 0x1332, 0x1078, 0x639b, + 0x007c, 0x0e7e, 0x2071, 0xa908, 0x7003, 0x0000, 0x0e7f, 0x007c, + 0x0d7e, 0xa280, 0x0004, 0x206c, 0x694c, 0xd1dc, 0x00c0, 0x1d6b, + 0x6934, 0xa184, 0x0007, 0x0079, 0x1cfd, 0x1d05, 0x1d56, 0x1d05, + 0x1d05, 0x1d05, 0x1d3b, 0x1d18, 0x1d07, 0x1078, 0x1332, 0x684c, + 0xd0b4, 0x0040, 0x1e79, 0x6860, 0x682e, 0x6816, 0x685c, 0x682a, + 0x6812, 0x687c, 0x680a, 0x6880, 0x680e, 0x6958, 0x0078, 0x1d5e, + 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, 0x00c0, 0x1d05, 0x684c, + 0xd0b4, 0x0040, 0x1e79, 0x6860, 0x682e, 0x6816, 0x685c, 0x682a, + 0x6812, 0x687c, 0x680a, 0x6880, 0x680e, 0x6804, 0x681a, 0xa080, + 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x206a, 0x2004, 0x6832, + 0x6958, 0x0078, 0x1d67, 0xa18c, 0x00ff, 0xa186, 0x0015, 0x00c0, + 0x1d6b, 0x684c, 0xd0b4, 0x0040, 0x1e79, 0x6804, 0x681a, 0xa080, + 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x206a, 0x2004, 0x6832, + 0x6958, 0xa006, 0x682e, 0x682a, 0x0078, 0x1d67, 0x684c, 0xd0b4, + 0x0040, 0x18ed, 0x6958, 0xa006, 0x682e, 0x682a, 0x2d00, 0x681a, + 0x6834, 0xa084, 0x000f, 0xa080, 0x206a, 0x2004, 0x6832, 0x6926, + 0x684c, 0xc0dd, 0x684e, 0x0d7f, 0x007c, 0x0f7e, 0x2079, 0x0020, + 0x7804, 0xd0fc, 0x10c0, 0x1eaa, 0x0e7e, 0x0d7e, 0x2071, 0xa908, + 0x7000, 0xa005, 0x00c0, 0x1df0, 0x0c7e, 0x7206, 0xa280, 0x0004, + 0x205c, 0x7004, 0x2068, 0x7803, 0x0004, 0x6818, 0x0d7e, 0x2068, + 0x686c, 0x7812, 0x6890, 0x0f7e, 0x20e1, 0x9040, 0x2079, 0x0200, + 0x781a, 0x2079, 0x0100, 0x8004, 0x78d6, 0x0f7f, 0x0d7f, 0x2b68, + 0x6824, 0x2050, 0x6818, 0x2060, 0x6830, 0x2040, 0x6034, 0xa0cc, + 0x000f, 0x6908, 0x2001, 0x04fd, 0x2004, 0xa086, 0x0007, 0x0040, + 0x1db2, 0xa184, 0x0007, 0x0040, 0x1db2, 0x017e, 0x2009, 0x0008, + 0xa102, 0x017f, 0xa108, 0x791a, 0x7116, 0x701e, 0x680c, 0xa081, + 0x0000, 0x781e, 0x701a, 0xa006, 0x700e, 0x7012, 0x7004, 0x692c, + 0x6814, 0xa106, 0x00c0, 0x1dc9, 0x6928, 0x6810, 0xa106, 0x0040, + 0x1dd6, 0x037e, 0x047e, 0x6b14, 0x6c10, 0x1078, 0x208a, 0x047f, + 0x037f, 0x0040, 0x1dd6, 0x0c7f, 0x0078, 0x1df0, 0x8aff, 0x00c0, + 0x1dde, 0x0c7f, 0xa085, 0x0001, 0x0078, 0x1df0, 0x127e, 0x2091, + 0x8000, 0x2079, 0x0020, 0x2009, 0x0001, 0x1078, 0x1df4, 0x0040, + 0x1ded, 0x2009, 0x0001, 0x1078, 0x1df4, 0x127f, 0x0c7f, 0xa006, + 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x077e, 0x067e, 0x057e, 0x047e, + 0x037e, 0x027e, 0x8aff, 0x0040, 0x1e72, 0x700c, 0x7214, 0xa23a, + 0x7010, 0x7218, 0xa203, 0x0048, 0x1e71, 0xa705, 0x0040, 0x1e71, + 0xa03e, 0x2730, 0x6850, 0xd0fc, 0x00c0, 0x1e24, 0x0d7e, 0x2804, + 0xac68, 0x2900, 0x0079, 0x1e14, 0x1e53, 0x1e34, 0x1e34, 0x1e53, + 0x1e53, 0x1e4b, 0x1e53, 0x1e34, 0x1e53, 0x1e3a, 0x1e3a, 0x1e53, + 0x1e53, 0x1e53, 0x1e42, 0x1e3a, 0xc0fc, 0x6852, 0x6b6c, 0x6a70, + 0x6d1c, 0x6c20, 0xd99c, 0x0040, 0x1e57, 0x0d7e, 0x2804, 0xac68, + 0x6f08, 0x6e0c, 0x0078, 0x1e56, 0x6b08, 0x6a0c, 0x6d00, 0x6c04, + 0x0078, 0x1e56, 0x6b10, 0x6a14, 0x6d00, 0x6c04, 0x6f08, 0x6e0c, + 0x0078, 0x1e56, 0x0d7f, 0x0d7e, 0x6834, 0xa084, 0x00ff, 0xa086, + 0x001e, 0x00c0, 0x1e53, 0x0d7f, 0x1078, 0x2026, 0x00c0, 0x1dfa, + 0xa00e, 0x0078, 0x1e72, 0x0d7f, 0x1078, 0x1332, 0x0d7f, 0x7b22, + 0x7a26, 0x7d32, 0x7c36, 0x7f3a, 0x7e3e, 0x7902, 0x7000, 0x8000, + 0x7002, 0x6828, 0xa300, 0x682a, 0x682c, 0xa201, 0x682e, 0x700c, + 0xa300, 0x700e, 0x7010, 0xa201, 0x7012, 0x1078, 0x2026, 0x0078, + 0x1e72, 0xa006, 0x027f, 0x037f, 0x047f, 0x057f, 0x067f, 0x077f, + 0x007c, 0x1078, 0x1332, 0x027e, 0x2001, 0x0105, 0x2003, 0x0010, + 0x20e1, 0x9040, 0x7803, 0x0004, 0x7003, 0x0000, 0x7004, 0x2060, + 0x0d7e, 0x6010, 0x2068, 0x1078, 0x8d06, 0x0040, 0x1e92, 0x6850, + 0xc0bd, 0x6852, 0x0d7f, 0x0c7e, 0x1078, 0x8a01, 0x0c7f, 0x2001, + 0xa8c0, 0x2004, 0xac06, 0x00c0, 0x1ea7, 0x20e1, 0x9040, 0x1078, + 0x738a, 0x2011, 0x0000, 0x1078, 0x70ea, 0x1078, 0x639b, 0x027f, + 0x0078, 0x1f76, 0x127e, 0x2091, 0x2200, 0x007e, 0x017e, 0x0f7e, + 0x0e7e, 0x0d7e, 0x0c7e, 0x2079, 0x0020, 0x2071, 0xa908, 0x2b68, + 0x6818, 0x2060, 0x7904, 0x7803, 0x0002, 0xa184, 0x0700, 0x00c0, + 0x1e7b, 0x7000, 0x0079, 0x1ec4, 0x1f76, 0x1ec8, 0x1f43, 0x1f74, + 0x8001, 0x7002, 0xd19c, 0x00c0, 0x1edc, 0x8aff, 0x0040, 0x1efb, + 0x2009, 0x0001, 0x1078, 0x1df4, 0x0040, 0x1f76, 0x2009, 0x0001, + 0x1078, 0x1df4, 0x0078, 0x1f76, 0x7803, 0x0004, 0xd194, 0x0040, + 0x1eec, 0x6850, 0xc0fc, 0x6852, 0x8aff, 0x00c0, 0x1ef1, 0x684c, + 0xc0f5, 0x684e, 0x0078, 0x1ef1, 0x1078, 0x203f, 0x6850, 0xc0fd, + 0x6852, 0x2a00, 0x6826, 0x2c00, 0x681a, 0x2800, 0x6832, 0x7003, + 0x0000, 0x0078, 0x1f76, 0x711c, 0x81ff, 0x0040, 0x1f11, 0x7918, + 0x7922, 0x7827, 0x0000, 0x7803, 0x0001, 0x7000, 0x8000, 0x7002, + 0x700c, 0xa100, 0x700e, 0x7010, 0xa081, 0x0000, 0x7012, 0x0078, + 0x1f76, 0x0f7e, 0x027e, 0x781c, 0x007e, 0x7818, 0x007e, 0x2079, + 0x0100, 0x7a14, 0xa284, 0x0004, 0xa085, 0x0012, 0x7816, 0x037e, + 0x2019, 0x1000, 0x8319, 0x1040, 0x1332, 0x7820, 0xd0bc, 0x00c0, + 0x1f22, 0x037f, 0x79c8, 0x007f, 0xa102, 0x017f, 0x007e, 0x017e, + 0x79c4, 0x007f, 0xa103, 0x78c6, 0x007f, 0x78ca, 0xa284, 0x0004, + 0xa085, 0x0012, 0x7816, 0x027f, 0x0f7f, 0x7803, 0x0008, 0x7003, + 0x0000, 0x0078, 0x1f76, 0x8001, 0x7002, 0xd194, 0x0040, 0x1f58, + 0x7804, 0xd0fc, 0x00c0, 0x1eba, 0xd19c, 0x00c0, 0x1f72, 0x8aff, + 0x0040, 0x1f76, 0x2009, 0x0001, 0x1078, 0x1df4, 0x0078, 0x1f76, + 0x027e, 0x037e, 0x6b28, 0x6a2c, 0x1078, 0x203f, 0x0d7e, 0x2804, + 0xac68, 0x6034, 0xd09c, 0x00c0, 0x1f6b, 0x6808, 0xa31a, 0x680c, + 0xa213, 0x0078, 0x1f6f, 0x6810, 0xa31a, 0x6814, 0xa213, 0x0d7f, + 0x0078, 0x1eec, 0x0078, 0x1eec, 0x1078, 0x1332, 0x0c7f, 0x0d7f, + 0x0e7f, 0x0f7f, 0x017f, 0x007f, 0x127f, 0x007c, 0x0f7e, 0x0e7e, + 0x2071, 0xa908, 0x7000, 0xa086, 0x0000, 0x0040, 0x1fc7, 0x2079, + 0x0020, 0x017e, 0x2009, 0x0207, 0x210c, 0xd194, 0x0040, 0x1fa4, + 0x2009, 0x020c, 0x210c, 0xa184, 0x0003, 0x0040, 0x1fa4, 0x1078, + 0xa5d2, 0x2001, 0x0133, 0x2004, 0xa005, 0x1040, 0x1332, 0x20e1, + 0x9040, 0x2001, 0x020c, 0x2102, 0x2009, 0x0206, 0x2104, 0x2009, + 0x0203, 0x210c, 0xa106, 0x00c0, 0x1faf, 0x20e1, 0x9040, 0x7804, + 0xd0fc, 0x0040, 0x1f8a, 0x1078, 0x1eaa, 0x7000, 0xa086, 0x0000, + 0x00c0, 0x1f8a, 0x017f, 0x7803, 0x0004, 0x7804, 0xd0ac, 0x00c0, + 0x1fbd, 0x20e1, 0x9040, 0x7803, 0x0002, 0x7003, 0x0000, 0x0e7f, + 0x0f7f, 0x007c, 0x027e, 0x0c7e, 0x0d7e, 0x0e7e, 0x0f7e, 0x2071, + 0xa908, 0x2079, 0x0020, 0x7000, 0xa086, 0x0000, 0x0040, 0x2003, + 0x7004, 0x2060, 0x6010, 0x2068, 0x1078, 0x8d06, 0x0040, 0x1fed, + 0x6850, 0xc0b5, 0x6852, 0x680c, 0x7a1c, 0xa206, 0x00c0, 0x1fed, + 0x6808, 0x7a18, 0xa206, 0x0040, 0x2009, 0x2001, 0x0105, 0x2003, + 0x0010, 0x20e1, 0x9040, 0x7803, 0x0004, 0x7003, 0x0000, 0x7004, + 0x2060, 0x1078, 0x8a01, 0x20e1, 0x9040, 0x1078, 0x738a, 0x2011, + 0x0000, 0x1078, 0x70ea, 0x0f7f, 0x0e7f, 0x0d7f, 0x0c7f, 0x027f, + 0x007c, 0x6810, 0x6a14, 0xa205, 0x00c0, 0x1fed, 0x684c, 0xc0dc, + 0x684e, 0x2c10, 0x1078, 0x1cf0, 0x2001, 0x0105, 0x2003, 0x0010, + 0x20e1, 0x9040, 0x7803, 0x0004, 0x7003, 0x0000, 0x2069, 0xa8b1, + 0x6833, 0x0000, 0x683f, 0x0000, 0x0078, 0x2003, 0x8840, 0x2804, + 0xa005, 0x00c0, 0x203a, 0x6004, 0xa005, 0x0040, 0x203c, 0x681a, + 0x2060, 0x6034, 0xa084, 0x000f, 0xa080, 0x206a, 0x2044, 0x88ff, + 0x1040, 0x1332, 0x8a51, 0x007c, 0x2051, 0x0000, 0x007c, 0x8a50, + 0x8841, 0x2804, 0xa005, 0x00c0, 0x2059, 0x2c00, 0xad06, 0x0040, + 0x204e, 0x6000, 0xa005, 0x00c0, 0x204e, 0x2d00, 0x2060, 0x681a, + 0x6034, 0xa084, 0x000f, 0xa080, 0x207a, 0x2044, 0x88ff, 0x1040, + 0x1332, 0x007c, 0x0000, 0x0011, 0x0015, 0x0019, 0x001d, 0x0021, + 0x0025, 0x0029, 0x0000, 0x000f, 0x0015, 0x001b, 0x0021, 0x0027, + 0x0000, 0x0000, 0x0000, 0x205f, 0x205b, 0x0000, 0x0000, 0x2069, + 0x0000, 0x205f, 0x0000, 0x2066, 0x2063, 0x0000, 0x0000, 0x0000, + 0x2069, 0x2066, 0x0000, 0x2061, 0x2061, 0x0000, 0x0000, 0x2069, + 0x0000, 0x2061, 0x0000, 0x2067, 0x2067, 0x0000, 0x0000, 0x0000, + 0x2069, 0x2067, 0x0a7e, 0x097e, 0x087e, 0x6b2e, 0x6c2a, 0x6858, + 0xa055, 0x0040, 0x212d, 0x2d60, 0x6034, 0xa0cc, 0x000f, 0xa9c0, + 0x206a, 0xa986, 0x0007, 0x0040, 0x20a5, 0xa986, 0x000e, 0x0040, + 0x20a5, 0xa986, 0x000f, 0x00c0, 0x20a9, 0x605c, 0xa422, 0x6060, + 0xa31a, 0x2804, 0xa045, 0x00c0, 0x20b7, 0x0050, 0x20b1, 0x0078, + 0x212d, 0x6004, 0xa065, 0x0040, 0x212d, 0x0078, 0x2094, 0x2804, + 0xa005, 0x0040, 0x20d5, 0xac68, 0xd99c, 0x00c0, 0x20c5, 0x6808, + 0xa422, 0x680c, 0xa31b, 0x0078, 0x20c9, 0x6810, 0xa422, 0x6814, + 0xa31b, 0x0048, 0x20f4, 0x2300, 0xa405, 0x0040, 0x20db, 0x8a51, + 0x0040, 0x212d, 0x8840, 0x0078, 0x20b7, 0x6004, 0xa065, 0x0040, + 0x212d, 0x0078, 0x2094, 0x8a51, 0x0040, 0x212d, 0x8840, 0x2804, + 0xa005, 0x00c0, 0x20ee, 0x6004, 0xa065, 0x0040, 0x212d, 0x6034, + 0xa0cc, 0x000f, 0xa9c0, 0x206a, 0x2804, 0x2040, 0x2b68, 0x6850, + 0xc0fc, 0x6852, 0x0078, 0x2121, 0x8422, 0x8420, 0x831a, 0xa399, + 0x0000, 0x0d7e, 0x2b68, 0x6c6e, 0x6b72, 0x0d7f, 0xd99c, 0x00c0, + 0x210f, 0x6908, 0x2400, 0xa122, 0x690c, 0x2300, 0xa11b, 0x1048, + 0x1332, 0x6800, 0xa420, 0x6804, 0xa319, 0x0078, 0x211b, 0x6910, + 0x2400, 0xa122, 0x6914, 0x2300, 0xa11b, 0x1048, 0x1332, 0x6800, + 0xa420, 0x6804, 0xa319, 0x2b68, 0x6c1e, 0x6b22, 0x6850, 0xc0fd, + 0x6852, 0x2c00, 0x681a, 0x2800, 0x6832, 0x2a00, 0x6826, 0x007f, + 0x007f, 0x007f, 0xa006, 0x0078, 0x2132, 0x087f, 0x097f, 0x0a7f, + 0xa085, 0x0001, 0x007c, 0x2001, 0x0005, 0x2004, 0xa084, 0x0007, + 0x0079, 0x213a, 0x2142, 0x2143, 0x2146, 0x2149, 0x214e, 0x2151, + 0x2156, 0x215b, 0x007c, 0x1078, 0x1eaa, 0x007c, 0x1078, 0x1913, + 0x007c, 0x1078, 0x1913, 0x1078, 0x1eaa, 0x007c, 0x1078, 0x14be, + 0x007c, 0x1078, 0x1eaa, 0x1078, 0x14be, 0x007c, 0x1078, 0x1913, + 0x1078, 0x14be, 0x007c, 0x1078, 0x1913, 0x1078, 0x1eaa, 0x1078, + 0x14be, 0x007c, 0x127e, 0x2091, 0x2300, 0x2079, 0x0200, 0x2071, + 0xab80, 0x2069, 0xa600, 0x2009, 0x0004, 0x7912, 0x7817, 0x0004, + 0x1078, 0x251f, 0x781b, 0x0002, 0x20e1, 0x8700, 0x127f, 0x007c, + 0x127e, 0x2091, 0x2300, 0x781c, 0xa084, 0x0007, 0x0079, 0x2180, + 0x21a4, 0x2188, 0x218c, 0x2190, 0x2196, 0x219a, 0x219e, 0x21a2, + 0x1078, 0x548e, 0x0078, 0x21a4, 0x1078, 0x54da, 0x0078, 0x21a4, + 0x1078, 0x548e, 0x1078, 0x54da, 0x0078, 0x21a4, 0x1078, 0x21a6, + 0x0078, 0x21a4, 0x1078, 0x21a6, 0x0078, 0x21a4, 0x1078, 0x21a6, + 0x0078, 0x21a4, 0x1078, 0x21a6, 0x127f, 0x007c, 0x007e, 0x017e, + 0x027e, 0x1078, 0xa5d2, 0x7930, 0xa184, 0x0003, 0x0040, 0x21c9, + 0x2001, 0xa8c0, 0x2004, 0xa005, 0x0040, 0x21c5, 0x2001, 0x0133, + 0x2004, 0xa005, 0x1040, 0x1332, 0x0c7e, 0x2001, 0xa8c0, 0x2064, + 0x1078, 0x8a01, 0x0c7f, 0x0078, 0x21f2, 0x20e1, 0x9040, 0x0078, + 0x21f2, 0xa184, 0x0030, 0x0040, 0x21da, 0x6a00, 0xa286, 0x0003, + 0x00c0, 0x21d4, 0x0078, 0x21d6, 0x1078, 0x4224, 0x20e1, 0x9010, + 0x0078, 0x21f2, 0xa184, 0x00c0, 0x0040, 0x21ec, 0x0e7e, 0x037e, + 0x047e, 0x057e, 0x2071, 0xa8e7, 0x1078, 0x1af4, 0x057f, 0x047f, + 0x037f, 0x0e7f, 0x0078, 0x21f2, 0xa184, 0x0300, 0x0040, 0x21f2, + 0x20e1, 0x9020, 0x7932, 0x027f, 0x017f, 0x007f, 0x007c, 0x017e, + 0x0e7e, 0x0f7e, 0x2071, 0xa600, 0x7128, 0x2001, 0xa890, 0x2102, + 0x2001, 0xa898, 0x2102, 0xa182, 0x0211, 0x00c8, 0x220b, 0x2009, + 0x0008, 0x0078, 0x2235, 0xa182, 0x0259, 0x00c8, 0x2213, 0x2009, + 0x0007, 0x0078, 0x2235, 0xa182, 0x02c1, 0x00c8, 0x221b, 0x2009, + 0x0006, 0x0078, 0x2235, 0xa182, 0x0349, 0x00c8, 0x2223, 0x2009, + 0x0005, 0x0078, 0x2235, 0xa182, 0x0421, 0x00c8, 0x222b, 0x2009, + 0x0004, 0x0078, 0x2235, 0xa182, 0x0581, 0x00c8, 0x2233, 0x2009, + 0x0003, 0x0078, 0x2235, 0x2009, 0x0002, 0x2079, 0x0200, 0x7912, + 0x7817, 0x0004, 0x1078, 0x251f, 0x0f7f, 0x0e7f, 0x017f, 0x007c, + 0x127e, 0x2091, 0x2200, 0x2061, 0x0100, 0x2071, 0xa600, 0x6024, + 0x6026, 0x6053, 0x0030, 0x6033, 0x00ef, 0x60e7, 0x0000, 0x60eb, + 0x00ef, 0x60e3, 0x0008, 0x604b, 0xf7f7, 0x6043, 0x0000, 0x602f, + 0x0080, 0x602f, 0x0000, 0x6007, 0x0eaf, 0x600f, 0x00ff, 0x602b, + 0x002f, 0x127f, 0x007c, 0x2001, 0xa630, 0x2003, 0x0000, 0x2001, + 0xa62f, 0x2003, 0x0001, 0x007c, 0x127e, 0x2091, 0x2200, 0x007e, + 0x017e, 0x027e, 0x6124, 0xa184, 0x002c, 0x00c0, 0x227b, 0xa184, + 0x0007, 0x0079, 0x2281, 0xa195, 0x0004, 0xa284, 0x0007, 0x0079, + 0x2281, 0x22ad, 0x2289, 0x228d, 0x2291, 0x2297, 0x229b, 0x22a1, + 0x22a7, 0x1078, 0x5c56, 0x0078, 0x22ad, 0x1078, 0x5d45, 0x0078, + 0x22ad, 0x1078, 0x5d45, 0x1078, 0x5c56, 0x0078, 0x22ad, 0x1078, + 0x22b2, 0x0078, 0x22ad, 0x1078, 0x5c56, 0x1078, 0x22b2, 0x0078, + 0x22ad, 0x1078, 0x5d45, 0x1078, 0x22b2, 0x0078, 0x22ad, 0x1078, + 0x5d45, 0x1078, 0x5c56, 0x1078, 0x22b2, 0x027f, 0x017f, 0x007f, + 0x127f, 0x007c, 0x6124, 0xd1ac, 0x0040, 0x23ac, 0x017e, 0x047e, + 0x0c7e, 0x644c, 0xa486, 0xf0f0, 0x00c0, 0x22c5, 0x2061, 0x0100, + 0x644a, 0x6043, 0x0090, 0x6043, 0x0010, 0x74c6, 0xa48c, 0xff00, + 0x7034, 0xd084, 0x0040, 0x22dd, 0xa186, 0xf800, 0x00c0, 0x22dd, + 0x703c, 0xd084, 0x00c0, 0x22dd, 0xc085, 0x703e, 0x037e, 0x2418, + 0x2011, 0x8016, 0x1078, 0x361b, 0x037f, 0xa196, 0xff00, 0x0040, + 0x231f, 0x6030, 0xa084, 0x00ff, 0x810f, 0xa116, 0x0040, 0x231f, + 0x7130, 0xd184, 0x00c0, 0x231f, 0x2011, 0xa653, 0x2214, 0xd2ec, + 0x0040, 0x22fa, 0xc18d, 0x7132, 0x2011, 0xa653, 0x2214, 0xd2ac, + 0x00c0, 0x231f, 0x6240, 0xa294, 0x0010, 0x0040, 0x2306, 0x6248, + 0xa294, 0xff00, 0xa296, 0xff00, 0x0040, 0x231f, 0x7030, 0xd08c, + 0x0040, 0x2371, 0x7034, 0xd08c, 0x00c0, 0x2316, 0x2001, 0xa60c, + 0x200c, 0xd1ac, 0x00c0, 0x2371, 0xc1ad, 0x2102, 0x037e, 0x73c4, + 0x2011, 0x8013, 0x1078, 0x361b, 0x037f, 0x0078, 0x2371, 0x7034, + 0xd08c, 0x00c0, 0x232b, 0x2001, 0xa60c, 0x200c, 0xd1ac, 0x00c0, + 0x2371, 0xc1ad, 0x2102, 0x037e, 0x73c4, 0x2011, 0x8013, 0x1078, + 0x361b, 0x037f, 0x7130, 0xc185, 0x7132, 0x2011, 0xa653, 0x220c, + 0xd1a4, 0x0040, 0x2355, 0x017e, 0x2009, 0x0001, 0x2011, 0x0100, + 0x1078, 0x5bf1, 0x2019, 0x000e, 0x1078, 0xa195, 0xa484, 0x00ff, + 0xa080, 0x29c0, 0x200c, 0xa18c, 0xff00, 0x810f, 0x8127, 0xa006, + 0x2009, 0x000e, 0x1078, 0xa21d, 0x017f, 0xd1ac, 0x00c0, 0x2362, + 0x017e, 0x2009, 0x0000, 0x2019, 0x0004, 0x1078, 0x284f, 0x017f, + 0x0078, 0x2371, 0x157e, 0x20a9, 0x007f, 0x2009, 0x0000, 0x1078, + 0x45c4, 0x00c0, 0x236d, 0x1078, 0x42f8, 0x8108, 0x00f0, 0x2367, + 0x157f, 0x0c7f, 0x047f, 0x0f7e, 0x2079, 0xa8c4, 0x783c, 0xa086, + 0x0000, 0x0040, 0x2383, 0x6027, 0x0004, 0x783f, 0x0000, 0x2079, + 0x0140, 0x7803, 0x0000, 0x0f7f, 0x2011, 0x0003, 0x1078, 0x70e0, + 0x2011, 0x0002, 0x1078, 0x70ea, 0x1078, 0x6fc4, 0x037e, 0x2019, + 0x0000, 0x1078, 0x7058, 0x037f, 0x60e3, 0x0000, 0x017f, 0x2001, + 0xa600, 0x2014, 0xa296, 0x0004, 0x00c0, 0x23a4, 0xd19c, 0x00c0, + 0x23ac, 0x6228, 0xc29d, 0x622a, 0x2003, 0x0001, 0x2001, 0xa622, + 0x2003, 0x0000, 0x6027, 0x0020, 0xd194, 0x0040, 0x2490, 0x0f7e, + 0x2079, 0xa8c4, 0x783c, 0xa086, 0x0001, 0x00c0, 0x23d0, 0x017e, + 0x6027, 0x0004, 0x783f, 0x0000, 0x2079, 0x0140, 0x7803, 0x1000, + 0x7803, 0x0000, 0x2079, 0xa8b1, 0x7807, 0x0000, 0x7833, 0x0000, + 0x1078, 0x62d1, 0x1078, 0x639b, 0x017f, 0x0f7f, 0x0078, 0x2490, + 0x0f7f, 0x017e, 0x3900, 0xa082, 0xa9e3, 0x00c8, 0x23db, 0x017e, + 0x1078, 0x747a, 0x017f, 0x6220, 0xd2b4, 0x0040, 0x2446, 0x1078, + 0x5acb, 0x1078, 0x6e0f, 0x6027, 0x0004, 0x0f7e, 0x2019, 0xa8ba, + 0x2304, 0xa07d, 0x0040, 0x241c, 0x7804, 0xa086, 0x0032, 0x00c0, + 0x241c, 0x0d7e, 0x0c7e, 0x0e7e, 0x2069, 0x0140, 0x618c, 0x6288, + 0x7818, 0x608e, 0x7808, 0x608a, 0x6043, 0x0002, 0x2001, 0x0003, + 0x8001, 0x00c0, 0x2400, 0x6043, 0x0000, 0x6803, 0x1000, 0x6803, + 0x0000, 0x618e, 0x628a, 0x1078, 0x61cd, 0x1078, 0x62d1, 0x7810, + 0x2070, 0x7037, 0x0103, 0x2f60, 0x1078, 0x772d, 0x0e7f, 0x0c7f, + 0x0d7f, 0x0f7f, 0x017f, 0x007c, 0x0f7f, 0x0d7e, 0x2069, 0x0140, + 0x6804, 0xa084, 0x4000, 0x0040, 0x2429, 0x6803, 0x1000, 0x6803, + 0x0000, 0x0d7f, 0x0c7e, 0x2061, 0xa8b1, 0x6028, 0xa09a, 0x00c8, + 0x00c8, 0x2439, 0x8000, 0x602a, 0x0c7f, 0x1078, 0x6e01, 0x0078, + 0x248f, 0x2019, 0xa8ba, 0x2304, 0xa065, 0x0040, 0x2443, 0x2009, + 0x0027, 0x1078, 0x775c, 0x0c7f, 0x0078, 0x248f, 0xd2bc, 0x0040, + 0x248f, 0x1078, 0x5ad8, 0x6017, 0x0010, 0x6027, 0x0004, 0x0d7e, + 0x2069, 0x0140, 0x6804, 0xa084, 0x4000, 0x0040, 0x245b, 0x6803, + 0x1000, 0x6803, 0x0000, 0x0d7f, 0x0c7e, 0x2061, 0xa8b1, 0x6044, + 0xa09a, 0x00c8, 0x00c8, 0x247e, 0x8000, 0x6046, 0x603c, 0x0c7f, + 0xa005, 0x0040, 0x248f, 0x2009, 0x07d0, 0x1078, 0x5ad0, 0xa080, + 0x0007, 0x2004, 0xa086, 0x0006, 0x00c0, 0x247a, 0x6017, 0x0012, + 0x0078, 0x248f, 0x6017, 0x0016, 0x0078, 0x248f, 0x037e, 0x2019, + 0x0001, 0x1078, 0x7058, 0x037f, 0x2019, 0xa8c0, 0x2304, 0xa065, + 0x0040, 0x248e, 0x2009, 0x004f, 0x1078, 0x775c, 0x0c7f, 0x017f, + 0xd19c, 0x0040, 0x24e4, 0x7034, 0xd0ac, 0x00c0, 0x24c1, 0x017e, + 0x157e, 0x6027, 0x0008, 0x602f, 0x0020, 0x20a9, 0x000a, 0x00f0, + 0x249f, 0x602f, 0x0000, 0x6150, 0xa185, 0x1400, 0x6052, 0x20a9, + 0x0320, 0x00e0, 0x24a9, 0x2091, 0x6000, 0x6020, 0xd09c, 0x00c0, + 0x24b8, 0x157f, 0x6152, 0x017f, 0x6027, 0x0008, 0x0078, 0x24e4, + 0x1078, 0x2577, 0x00f0, 0x24a9, 0x157f, 0x6152, 0x017f, 0x6027, + 0x0008, 0x017e, 0x6028, 0xc09c, 0x602a, 0x2011, 0x0003, 0x1078, + 0x70e0, 0x2011, 0x0002, 0x1078, 0x70ea, 0x1078, 0x6fc4, 0x037e, + 0x2019, 0x0000, 0x1078, 0x7058, 0x037f, 0x60e3, 0x0000, 0x1078, + 0xa5ad, 0x1078, 0xa5cb, 0x2001, 0xa600, 0x2003, 0x0004, 0x6027, + 0x0008, 0x1078, 0x1246, 0x017f, 0xa18c, 0xffd0, 0x6126, 0x007c, + 0x007e, 0x017e, 0x027e, 0x0e7e, 0x0f7e, 0x127e, 0x2091, 0x8000, + 0x2071, 0xa600, 0x71bc, 0x70be, 0xa116, 0x0040, 0x2518, 0x81ff, + 0x0040, 0x2500, 0x2011, 0x8011, 0x1078, 0x361b, 0x0078, 0x2518, + 0x2011, 0x8012, 0x1078, 0x361b, 0x2001, 0xa672, 0x2004, 0xd0fc, + 0x00c0, 0x2518, 0x037e, 0x0c7e, 0x1078, 0x6f9f, 0x2061, 0x0100, + 0x2019, 0x0028, 0x2009, 0x0000, 0x1078, 0x284f, 0x0c7f, 0x037f, + 0x127f, 0x0f7f, 0x0e7f, 0x027f, 0x017f, 0x007f, 0x007c, 0x0c7e, + 0x0f7e, 0x007e, 0x027e, 0x2061, 0x0100, 0xa190, 0x253b, 0x2204, + 0x60f2, 0x2011, 0x2548, 0x6000, 0xa082, 0x0003, 0x00c8, 0x2534, + 0x2001, 0x00ff, 0x0078, 0x2535, 0x2204, 0x60ee, 0x027f, 0x007f, + 0x0f7f, 0x0c7f, 0x007c, 0x0840, 0x0840, 0x0840, 0x0580, 0x0420, + 0x0348, 0x02c0, 0x0258, 0x0210, 0x01a8, 0x01a8, 0x01a8, 0x01a8, + 0x0140, 0x00f8, 0x00d0, 0x00b0, 0x00a0, 0x2028, 0xa18c, 0x00ff, + 0x2130, 0xa094, 0xff00, 0x00c0, 0x2558, 0x81ff, 0x0040, 0x255c, + 0x1078, 0x5761, 0x0078, 0x2563, 0xa080, 0x29c0, 0x200c, 0xa18c, + 0xff00, 0x810f, 0xa006, 0x007c, 0xa080, 0x29c0, 0x200c, 0xa18c, + 0x00ff, 0x007c, 0x0c7e, 0x2061, 0xa600, 0x6030, 0x0040, 0x2573, + 0xc09d, 0x0078, 0x2574, 0xc09c, 0x6032, 0x0c7f, 0x007c, 0x007e, + 0x157e, 0x0f7e, 0x2079, 0x0100, 0x20a9, 0x000a, 0x7854, 0xd08c, + 0x00c0, 0x2584, 0x00f0, 0x257e, 0x0f7f, 0x157f, 0x007f, 0x007c, + 0x0c7e, 0x007e, 0x2061, 0x0100, 0x6030, 0x007e, 0x6048, 0x007e, + 0x60e4, 0x007e, 0x60e8, 0x007e, 0x6050, 0x007e, 0x60f0, 0x007e, + 0x60ec, 0x007e, 0x600c, 0x007e, 0x6004, 0x007e, 0x6028, 0x007e, + 0x60e0, 0x007e, 0x602f, 0x0100, 0x602f, 0x0000, 0x0005, 0x0005, + 0x0005, 0x0005, 0x602f, 0x0040, 0x602f, 0x0000, 0x007f, 0x60e2, + 0x007f, 0x602a, 0x007f, 0x6006, 0x007f, 0x600e, 0x007f, 0x60ee, + 0x007f, 0x60f2, 0x007f, 0x6052, 0x007f, 0x60ea, 0x007f, 0x60e6, + 0x007f, 0x604a, 0x007f, 0x6032, 0x007f, 0x0c7f, 0x007c, 0x25e7, + 0x25eb, 0x25ef, 0x25f5, 0x25fb, 0x2601, 0x2607, 0x260f, 0x2617, + 0x261d, 0x2623, 0x262b, 0x2633, 0x263b, 0x2643, 0x264d, 0x2657, + 0x2657, 0x2657, 0x2657, 0x2657, 0x2657, 0x2657, 0x2657, 0x2657, + 0x2657, 0x2657, 0x2657, 0x2657, 0x2657, 0x2657, 0x2657, 0x107e, + 0x007e, 0x0078, 0x2670, 0x107e, 0x007e, 0x0078, 0x2670, 0x107e, + 0x007e, 0x1078, 0x226c, 0x0078, 0x2670, 0x107e, 0x007e, 0x1078, + 0x226c, 0x0078, 0x2670, 0x107e, 0x007e, 0x1078, 0x2133, 0x0078, + 0x2670, 0x107e, 0x007e, 0x1078, 0x2133, 0x0078, 0x2670, 0x107e, + 0x007e, 0x1078, 0x226c, 0x1078, 0x2133, 0x0078, 0x2670, 0x107e, + 0x007e, 0x1078, 0x226c, 0x1078, 0x2133, 0x0078, 0x2670, 0x107e, + 0x007e, 0x1078, 0x2178, 0x0078, 0x2670, 0x107e, 0x007e, 0x1078, + 0x2178, 0x0078, 0x2670, 0x107e, 0x007e, 0x1078, 0x226c, 0x1078, + 0x2178, 0x0078, 0x2670, 0x107e, 0x007e, 0x1078, 0x226c, 0x1078, + 0x2178, 0x0078, 0x2670, 0x107e, 0x007e, 0x1078, 0x2133, 0x1078, + 0x2178, 0x0078, 0x2670, 0x107e, 0x007e, 0x1078, 0x2133, 0x1078, + 0x2178, 0x0078, 0x2670, 0x107e, 0x007e, 0x1078, 0x226c, 0x1078, + 0x2133, 0x1078, 0x2178, 0x0078, 0x2670, 0x107e, 0x007e, 0x1078, + 0x226c, 0x1078, 0x2133, 0x1078, 0x2178, 0x0078, 0x2670, 0x0005, + 0x0078, 0x2657, 0xb084, 0x003c, 0x8004, 0x8004, 0x0079, 0x2660, + 0x2670, 0x25ed, 0x25f1, 0x25f7, 0x25fd, 0x2603, 0x2609, 0x2611, + 0x2619, 0x261f, 0x2625, 0x262d, 0x2635, 0x263d, 0x2645, 0x264f, + 0x0008, 0x265a, 0x007f, 0x107f, 0x2091, 0x8001, 0x007c, 0x0c7e, + 0x027e, 0x047e, 0x2021, 0x0000, 0x1078, 0x4967, 0x00c0, 0x2772, + 0x70cc, 0xd09c, 0x0040, 0x268e, 0xd084, 0x00c0, 0x268e, 0xd0bc, + 0x00c0, 0x2772, 0x1078, 0x2776, 0x0078, 0x2772, 0xd0cc, 0x00c0, + 0x2772, 0xd094, 0x0040, 0x2698, 0x7097, 0xffff, 0x0078, 0x2772, + 0x2001, 0x010c, 0x203c, 0x7284, 0xd284, 0x0040, 0x2701, 0xd28c, + 0x00c0, 0x2701, 0x037e, 0x7394, 0xa38e, 0xffff, 0x0040, 0x26ab, + 0x83ff, 0x00c0, 0x26ad, 0x2019, 0x0001, 0x8314, 0xa2e0, 0xacc0, + 0x2c04, 0xa38c, 0x0001, 0x0040, 0x26ba, 0xa084, 0xff00, 0x8007, + 0x0078, 0x26bc, 0xa084, 0x00ff, 0xa70e, 0x0040, 0x26f6, 0xa08e, + 0x0000, 0x0040, 0x26f6, 0xa08e, 0x00ff, 0x00c0, 0x26d3, 0x7230, + 0xd284, 0x00c0, 0x26fc, 0x7284, 0xc28d, 0x7286, 0x7097, 0xffff, + 0x037f, 0x0078, 0x2701, 0x2009, 0x0000, 0x1078, 0x254d, 0x1078, + 0x455c, 0x00c0, 0x26f9, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, + 0x00c0, 0x26f0, 0x7030, 0xd08c, 0x0040, 0x26ea, 0x6000, 0xd0bc, + 0x0040, 0x26f0, 0x1078, 0x278c, 0x0040, 0x26f9, 0x0078, 0x26f6, + 0x1078, 0x28c4, 0x1078, 0x27b9, 0x0040, 0x26f9, 0x8318, 0x0078, + 0x26ad, 0x7396, 0x0078, 0x26fe, 0x7097, 0xffff, 0x037f, 0x0078, + 0x2772, 0xa780, 0x29c0, 0x203c, 0xa7bc, 0xff00, 0x873f, 0x2041, + 0x007e, 0x7094, 0xa096, 0xffff, 0x00c0, 0x2713, 0x2009, 0x0000, + 0x28a8, 0x0078, 0x271f, 0xa812, 0x0048, 0x271b, 0x2008, 0xa802, + 0x20a8, 0x0078, 0x271f, 0x7097, 0xffff, 0x0078, 0x2772, 0x2700, + 0x157e, 0x017e, 0xa106, 0x0040, 0x2766, 0xc484, 0x1078, 0x45c4, + 0x0040, 0x2730, 0x1078, 0x455c, 0x00c0, 0x276f, 0x0078, 0x2731, + 0xc485, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x2740, + 0x7030, 0xd08c, 0x0040, 0x275e, 0x6000, 0xd0bc, 0x00c0, 0x275e, + 0x7284, 0xd28c, 0x0040, 0x2756, 0x6004, 0xa084, 0x00ff, 0xa082, + 0x0006, 0x0048, 0x2766, 0xd484, 0x00c0, 0x2752, 0x1078, 0x457f, + 0x0078, 0x2754, 0x1078, 0x298e, 0x0078, 0x2766, 0x1078, 0x28c4, + 0x1078, 0x27b9, 0x0040, 0x276f, 0x0078, 0x2766, 0x1078, 0x2959, + 0x0040, 0x2766, 0x1078, 0x278c, 0x0040, 0x276f, 0x017f, 0x8108, + 0x157f, 0x00f0, 0x271f, 0x7097, 0xffff, 0x0078, 0x2772, 0x017f, + 0x157f, 0x7196, 0x047f, 0x027f, 0x0c7f, 0x007c, 0x0c7e, 0x017e, + 0x7097, 0x0001, 0x2009, 0x007e, 0x1078, 0x455c, 0x00c0, 0x2789, + 0x1078, 0x28c4, 0x1078, 0x27b9, 0x0040, 0x2789, 0x70cc, 0xc0bd, + 0x70ce, 0x017f, 0x0c7f, 0x007c, 0x017e, 0x077e, 0x0d7e, 0x0c7e, + 0x2c68, 0x2001, 0xa657, 0x2004, 0xa084, 0x00ff, 0x6842, 0x1078, + 0x76c7, 0x0040, 0x27b4, 0x2d00, 0x601a, 0x601f, 0x0001, 0x2001, + 0x0000, 0x1078, 0x44ee, 0x2001, 0x0000, 0x1078, 0x4502, 0x127e, + 0x2091, 0x8000, 0x7090, 0x8000, 0x7092, 0x127f, 0x2009, 0x0004, + 0x1078, 0x775c, 0xa085, 0x0001, 0x0c7f, 0x0d7f, 0x077f, 0x017f, + 0x007c, 0x017e, 0x077e, 0x0d7e, 0x0c7e, 0x2c68, 0x2001, 0xa657, + 0x2004, 0xa084, 0x00ff, 0x6842, 0x1078, 0x9187, 0x0040, 0x27f2, + 0x2d00, 0x601a, 0x6800, 0xc0c4, 0x6802, 0x68a0, 0xa086, 0x007e, + 0x0040, 0x27db, 0x6804, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, + 0x27db, 0x1078, 0x2880, 0x601f, 0x0001, 0x2001, 0x0000, 0x1078, + 0x44ee, 0x2001, 0x0002, 0x1078, 0x4502, 0x127e, 0x2091, 0x8000, + 0x7090, 0x8000, 0x7092, 0x127f, 0x2009, 0x0002, 0x1078, 0x775c, + 0xa085, 0x0001, 0x0c7f, 0x0d7f, 0x077f, 0x017f, 0x007c, 0x0c7e, + 0x027e, 0x2009, 0x0080, 0x1078, 0x455c, 0x00c0, 0x2805, 0x1078, + 0x2808, 0x0040, 0x2805, 0x70d3, 0xffff, 0x027f, 0x0c7f, 0x007c, + 0x017e, 0x077e, 0x0d7e, 0x0c7e, 0x2c68, 0x1078, 0x76c7, 0x0040, + 0x282a, 0x2d00, 0x601a, 0x601f, 0x0001, 0x2001, 0x0000, 0x1078, + 0x44ee, 0x2001, 0x0002, 0x1078, 0x4502, 0x127e, 0x2091, 0x8000, + 0x70d4, 0x8000, 0x70d6, 0x127f, 0x2009, 0x0002, 0x1078, 0x775c, + 0xa085, 0x0001, 0x0c7f, 0x0d7f, 0x077f, 0x017f, 0x007c, 0x0c7e, + 0x0d7e, 0x127e, 0x2091, 0x8000, 0x2009, 0x007f, 0x1078, 0x455c, + 0x00c0, 0x284b, 0x2c68, 0x1078, 0x76c7, 0x0040, 0x284b, 0x2d00, + 0x601a, 0x6312, 0x601f, 0x0001, 0x620a, 0x2009, 0x0022, 0x1078, + 0x775c, 0xa085, 0x0001, 0x127f, 0x0d7f, 0x0c7f, 0x007c, 0x0e7e, + 0x0c7e, 0x067e, 0x037e, 0x027e, 0x1078, 0x5f0e, 0x1078, 0x5eae, + 0x1078, 0x8068, 0x2130, 0x81ff, 0x0040, 0x2864, 0x20a9, 0x007e, + 0x2009, 0x0000, 0x0078, 0x2868, 0x20a9, 0x007f, 0x2009, 0x0000, + 0x017e, 0x1078, 0x45c4, 0x00c0, 0x2871, 0x1078, 0x47e9, 0x1078, + 0x42f8, 0x017f, 0x8108, 0x00f0, 0x2868, 0x86ff, 0x00c0, 0x287a, + 0x1078, 0x119b, 0x027f, 0x037f, 0x067f, 0x0c7f, 0x0e7f, 0x007c, + 0x0e7e, 0x0c7e, 0x037e, 0x027e, 0x017e, 0x6218, 0x2270, 0x72a0, + 0x027e, 0x2019, 0x0029, 0x1078, 0x5f01, 0x077e, 0x2039, 0x0000, + 0x1078, 0x5e0a, 0x2c08, 0x1078, 0x9f8b, 0x077f, 0x017f, 0x2e60, + 0x1078, 0x47e9, 0x6210, 0x6314, 0x1078, 0x42f8, 0x6212, 0x6316, + 0x017f, 0x027f, 0x037f, 0x0c7f, 0x0e7f, 0x007c, 0x0e7e, 0x007e, + 0x6018, 0xa080, 0x0028, 0x2004, 0xd0bc, 0x00c0, 0x28ba, 0x2071, + 0xa600, 0x7090, 0xa005, 0x0040, 0x28b7, 0x8001, 0x7092, 0x007f, + 0x0e7f, 0x007c, 0x2071, 0xa600, 0x70d4, 0xa005, 0x0040, 0x28b7, + 0x8001, 0x70d6, 0x0078, 0x28b7, 0x6000, 0xc08c, 0x6002, 0x007c, + 0x0f7e, 0x0e7e, 0x0c7e, 0x037e, 0x027e, 0x017e, 0x157e, 0x2178, + 0x81ff, 0x00c0, 0x28d7, 0x20a9, 0x0001, 0x0078, 0x28f2, 0x2001, + 0xa653, 0x2004, 0xd0c4, 0x0040, 0x28ee, 0xd0a4, 0x0040, 0x28ee, + 0x047e, 0x6018, 0xa080, 0x0028, 0x2024, 0xa4a4, 0x00ff, 0x8427, + 0xa006, 0x2009, 0x002d, 0x1078, 0xa21d, 0x047f, 0x20a9, 0x00ff, + 0x2011, 0x0000, 0x027e, 0xa28e, 0x007e, 0x0040, 0x2936, 0xa28e, + 0x007f, 0x0040, 0x2936, 0xa28e, 0x0080, 0x0040, 0x2936, 0xa288, + 0xa735, 0x210c, 0x81ff, 0x0040, 0x2936, 0x8fff, 0x1040, 0x2942, + 0x0c7e, 0x2160, 0x2001, 0x0001, 0x1078, 0x4972, 0x0c7f, 0x2019, + 0x0029, 0x1078, 0x5f01, 0x077e, 0x2039, 0x0000, 0x1078, 0x5e0a, + 0x0c7e, 0x027e, 0x2160, 0x6204, 0xa294, 0x00ff, 0xa286, 0x0006, + 0x00c0, 0x2926, 0x6007, 0x0404, 0x0078, 0x292b, 0x2001, 0x0004, + 0x8007, 0xa215, 0x6206, 0x027f, 0x0c7f, 0x017e, 0x2c08, 0x1078, + 0x9f8b, 0x017f, 0x077f, 0x2160, 0x1078, 0x47e9, 0x027f, 0x8210, + 0x00f0, 0x28f2, 0x157f, 0x017f, 0x027f, 0x037f, 0x0c7f, 0x0e7f, + 0x0f7f, 0x007c, 0x047e, 0x027e, 0x017e, 0x2001, 0xa653, 0x2004, + 0xd0c4, 0x0040, 0x2955, 0xd0a4, 0x0040, 0x2955, 0xa006, 0x2220, + 0x8427, 0x2009, 0x0029, 0x1078, 0xa21d, 0x017f, 0x027f, 0x047f, + 0x007c, 0x017e, 0x027e, 0x037e, 0x0c7e, 0x7284, 0x82ff, 0x0040, + 0x2987, 0xa290, 0xa653, 0x2214, 0xd2ac, 0x00c0, 0x2987, 0x2100, + 0x1078, 0x2564, 0x81ff, 0x0040, 0x2989, 0x2019, 0x0001, 0x8314, + 0xa2e0, 0xacc0, 0x2c04, 0xd384, 0x0040, 0x297b, 0xa084, 0xff00, + 0x8007, 0x0078, 0x297d, 0xa084, 0x00ff, 0xa116, 0x0040, 0x2989, + 0xa096, 0x00ff, 0x0040, 0x2987, 0x8318, 0x0078, 0x296f, 0xa085, + 0x0001, 0x0c7f, 0x037f, 0x027f, 0x017f, 0x007c, 0x017e, 0x0c7e, + 0x127e, 0x2091, 0x8000, 0x017e, 0x027e, 0x037e, 0x2110, 0x027e, + 0x2019, 0x0029, 0x1078, 0x73d0, 0x027f, 0x1078, 0xa4f1, 0x037f, + 0x027f, 0x017f, 0xa180, 0xa735, 0x2004, 0xa065, 0x0040, 0x29b7, + 0x017e, 0x0c7e, 0x1078, 0x9187, 0x017f, 0x1040, 0x1332, 0x611a, + 0x1078, 0x2880, 0x1078, 0x772d, 0x017f, 0x1078, 0x457f, 0x127f, + 0x0c7f, 0x017f, 0x007c, 0x2001, 0xa633, 0x2004, 0xd0cc, 0x007c, + 0x7eef, 0x7de8, 0x7ce4, 0x80e2, 0x7be1, 0x80e0, 0x80dc, 0x80da, + 0x7ad9, 0x80d6, 0x80d5, 0x80d4, 0x80d3, 0x80d2, 0x80d1, 0x79ce, + 0x78cd, 0x80cc, 0x80cb, 0x80ca, 0x80c9, 0x80c7, 0x80c6, 0x77c5, + 0x76c3, 0x80bc, 0x80ba, 0x75b9, 0x80b6, 0x74b5, 0x73b4, 0x72b3, + 0x80b2, 0x80b1, 0x80ae, 0x71ad, 0x80ac, 0x70ab, 0x6faa, 0x6ea9, + 0x80a7, 0x6da6, 0x6ca5, 0x6ba3, 0x6a9f, 0x699e, 0x689d, 0x809b, + 0x8098, 0x6797, 0x6690, 0x658f, 0x6488, 0x6384, 0x6282, 0x8081, + 0x8080, 0x617c, 0x607a, 0x8079, 0x5f76, 0x8075, 0x8074, 0x8073, + 0x8072, 0x8071, 0x806e, 0x5e6d, 0x806c, 0x5d6b, 0x5c6a, 0x5b69, + 0x8067, 0x5a66, 0x5965, 0x5863, 0x575c, 0x565a, 0x5559, 0x8056, + 0x8055, 0x5454, 0x5353, 0x5252, 0x5151, 0x504e, 0x4f4d, 0x804c, + 0x804b, 0x4e4a, 0x4d49, 0x8047, 0x4c46, 0x8045, 0x8043, 0x803c, + 0x803a, 0x8039, 0x8036, 0x4b35, 0x8034, 0x4a33, 0x4932, 0x4831, + 0x802e, 0x472d, 0x462c, 0x452b, 0x442a, 0x4329, 0x4227, 0x8026, + 0x8025, 0x4123, 0x401f, 0x3f1e, 0x3e1d, 0x3d1b, 0x3c18, 0x8017, + 0x8010, 0x3b0f, 0x3a08, 0x8004, 0x3902, 0x8001, 0x8000, 0x8000, + 0x3800, 0x3700, 0x3600, 0x8000, 0x3500, 0x8000, 0x8000, 0x8000, + 0x3400, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x3300, + 0x3200, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x3100, + 0x3000, 0x8000, 0x8000, 0x2f00, 0x8000, 0x2e00, 0x2d00, 0x2c00, + 0x8000, 0x8000, 0x8000, 0x2b00, 0x8000, 0x2a00, 0x2900, 0x2800, + 0x8000, 0x2700, 0x2600, 0x2500, 0x2400, 0x2300, 0x2200, 0x8000, + 0x8000, 0x2100, 0x2000, 0x1f00, 0x1e00, 0x1d00, 0x1c00, 0x8000, + 0x8000, 0x1b00, 0x1a00, 0x8000, 0x1900, 0x8000, 0x8000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x1800, 0x8000, 0x1700, 0x1600, 0x1500, + 0x8000, 0x1400, 0x1300, 0x1200, 0x1100, 0x1000, 0x0f00, 0x8000, + 0x8000, 0x0e00, 0x0d00, 0x0c00, 0x0b00, 0x0a00, 0x0900, 0x8000, + 0x8000, 0x0800, 0x0700, 0x8000, 0x0600, 0x8000, 0x8000, 0x8000, + 0x0500, 0x0400, 0x0300, 0x8000, 0x0200, 0x8000, 0x8000, 0x8000, + 0x0100, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x0000, + 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x2071, 0xa682, 0x7003, 0x0002, 0xa006, 0x7012, 0x7016, 0x703a, + 0x703e, 0x7033, 0xa692, 0x7037, 0xa692, 0x7007, 0x0001, 0x2061, + 0xa6d2, 0x6003, 0x0002, 0x007c, 0x0090, 0x2ae7, 0x0068, 0x2ae7, + 0x2071, 0xa682, 0x2b78, 0x7818, 0xd084, 0x00c0, 0x2ae7, 0x2a60, + 0x7820, 0xa08e, 0x0069, 0x00c0, 0x2bd7, 0x0079, 0x2b6b, 0x007c, + 0x2071, 0xa682, 0x7004, 0x0079, 0x2aed, 0x2af1, 0x2af2, 0x2afc, + 0x2b0e, 0x007c, 0x0090, 0x2afb, 0x0068, 0x2afb, 0x2b78, 0x7818, + 0xd084, 0x0040, 0x2b1a, 0x007c, 0x2b78, 0x2061, 0xa6d2, 0x6008, + 0xa08e, 0x0100, 0x0040, 0x2b09, 0xa086, 0x0200, 0x0040, 0x2bcf, + 0x007c, 0x7014, 0x2068, 0x2a60, 0x7018, 0x007a, 0x7010, 0x2068, + 0x6834, 0xa086, 0x0103, 0x0040, 0x2b16, 0x007c, 0x2a60, 0x2b78, + 0x7018, 0x007a, 0x2a60, 0x7820, 0xa08a, 0x0040, 0x00c8, 0x2b23, + 0x61bc, 0x0079, 0x2b2b, 0x2100, 0xa08a, 0x003f, 0x00c8, 0x2bcb, + 0x61bc, 0x0079, 0x2b6b, 0x2bad, 0x2bdf, 0x2be7, 0x2beb, 0x2bf3, + 0x2bf9, 0x2bfd, 0x2c09, 0x2c0d, 0x2c17, 0x2c1b, 0x2bcb, 0x2bcb, + 0x2bcb, 0x2c1f, 0x2bcb, 0x2c2f, 0x2c46, 0x2c5d, 0x2cdd, 0x2ce2, + 0x2d0f, 0x2d69, 0x2d7a, 0x2d98, 0x2dd9, 0x2de3, 0x2df0, 0x2e03, + 0x2e22, 0x2e2b, 0x2e68, 0x2e6e, 0x2bcb, 0x2e8a, 0x2bcb, 0x2bcb, + 0x2bcb, 0x2bcb, 0x2bcb, 0x2e91, 0x2e9b, 0x2bcb, 0x2bcb, 0x2bcb, + 0x2bcb, 0x2bcb, 0x2bcb, 0x2bcb, 0x2bcb, 0x2ea3, 0x2bcb, 0x2bcb, + 0x2bcb, 0x2bcb, 0x2bcb, 0x2eb5, 0x2ece, 0x2bcb, 0x2bcb, 0x2bcb, + 0x2bcb, 0x2bcb, 0x2bcb, 0x2ee0, 0x2f37, 0x2f95, 0x2fa9, 0x2bcb, + 0x2bcb, 0x2bcb, 0x398e, 0x2bcb, 0x2bcb, 0x2bcb, 0x2bcb, 0x2bcb, + 0x2bcb, 0x2bcb, 0x2bcb, 0x2c17, 0x2c1b, 0x2fc0, 0x2bcb, 0x2fcd, + 0x3a26, 0x3a83, 0x2bcb, 0x2bcb, 0x2bcb, 0x2bcb, 0x2bcb, 0x2bcb, + 0x2bcb, 0x2bcb, 0x2bcb, 0x301a, 0x314f, 0x316b, 0x3177, 0x31da, + 0x3233, 0x323e, 0x327d, 0x328c, 0x329b, 0x329e, 0x2fd1, 0x32c2, + 0x331e, 0x332b, 0x343c, 0x356f, 0x3599, 0x36a6, 0x2bcb, 0x36b6, + 0x36f0, 0x37bf, 0x2bcb, 0x2bcb, 0x2bcb, 0x2bcb, 0x3827, 0x3843, + 0x38bd, 0x3977, 0x713c, 0x0078, 0x2bad, 0x2021, 0x4000, 0x1078, + 0x35f5, 0x127e, 0x2091, 0x8000, 0x0068, 0x2bba, 0x7818, 0xd084, + 0x0040, 0x2bbd, 0x127f, 0x0078, 0x2bb1, 0x7c22, 0x7926, 0x7a2a, + 0x7b2e, 0x781b, 0x0001, 0x2091, 0x4080, 0x7007, 0x0001, 0x2091, + 0x5000, 0x127f, 0x007c, 0x2021, 0x4001, 0x0078, 0x2baf, 0x2021, + 0x4002, 0x0078, 0x2baf, 0x2021, 0x4003, 0x0078, 0x2baf, 0x2021, + 0x4005, 0x0078, 0x2baf, 0x2021, 0x4006, 0x0078, 0x2baf, 0xa02e, + 0x2520, 0x7b28, 0x7a2c, 0x7824, 0x7930, 0x0078, 0x3604, 0x7823, + 0x0004, 0x7824, 0x007a, 0xa02e, 0x2520, 0x7b28, 0x7a2c, 0x7824, + 0x7930, 0x0078, 0x3608, 0x7924, 0x7828, 0x2114, 0x200a, 0x0078, + 0x2bad, 0x7924, 0x2114, 0x0078, 0x2bad, 0x2099, 0x0009, 0x20a1, + 0x0009, 0x20a9, 0x0007, 0x53a3, 0x7924, 0x7a28, 0x7b2c, 0x0078, + 0x2bad, 0x7824, 0x2060, 0x0078, 0x2c21, 0x2009, 0x0001, 0x2011, + 0x0013, 0x2019, 0x0018, 0x783b, 0x0017, 0x0078, 0x2bad, 0x7d38, + 0x7c3c, 0x0078, 0x2be1, 0x7d38, 0x7c3c, 0x0078, 0x2bed, 0x2061, + 0x1000, 0x610c, 0xa006, 0x2c14, 0xa200, 0x8c60, 0x8109, 0x00c0, + 0x2c23, 0x2010, 0xa005, 0x0040, 0x2bad, 0x0078, 0x2bd3, 0x2069, + 0xa652, 0x7824, 0x7930, 0xa11a, 0x00c8, 0x2bdb, 0x8019, 0x0040, + 0x2bdb, 0x684a, 0x6942, 0x782c, 0x6852, 0x7828, 0x6856, 0xa006, + 0x685a, 0x685e, 0x1078, 0x4eae, 0x0078, 0x2bad, 0x2069, 0xa652, + 0x7824, 0x7934, 0xa11a, 0x00c8, 0x2bdb, 0x8019, 0x0040, 0x2bdb, + 0x684e, 0x6946, 0x782c, 0x6862, 0x7828, 0x6866, 0xa006, 0x686a, + 0x686e, 0x1078, 0x4a3e, 0x0078, 0x2bad, 0xa02e, 0x2520, 0x81ff, + 0x00c0, 0x2bd7, 0x7924, 0x7b28, 0x7a2c, 0x20a9, 0x0005, 0x20a1, + 0xa689, 0x41a1, 0x1078, 0x35ba, 0x0040, 0x2bd7, 0x2009, 0x0020, + 0x1078, 0x3604, 0x701b, 0x2c75, 0x007c, 0x6834, 0x2008, 0xa084, + 0x00ff, 0xa096, 0x0011, 0x0040, 0x2c85, 0xa096, 0x0019, 0x0040, + 0x2c85, 0xa096, 0x0015, 0x00c0, 0x2bd7, 0x810f, 0xa18c, 0x00ff, + 0x0040, 0x2bd7, 0x710e, 0x700c, 0x8001, 0x0040, 0x2cb6, 0x700e, + 0x1078, 0x35ba, 0x0040, 0x2bd7, 0x2009, 0x0020, 0x2061, 0xa6d2, + 0x6224, 0x6328, 0x642c, 0x6530, 0xa290, 0x0040, 0xa399, 0x0000, + 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x1078, 0x3604, 0x701b, 0x2ca9, + 0x007c, 0x6834, 0xa084, 0x00ff, 0xa096, 0x0002, 0x0040, 0x2cb4, + 0xa096, 0x000a, 0x00c0, 0x2bd7, 0x0078, 0x2c8b, 0x7010, 0x2068, + 0x6838, 0xc0fd, 0x683a, 0x1078, 0x4431, 0x00c0, 0x2cc4, 0x7007, + 0x0003, 0x701b, 0x2cc6, 0x007c, 0x1078, 0x4b51, 0x127e, 0x2091, + 0x8000, 0x20a9, 0x0005, 0x2099, 0xa689, 0x530a, 0x2100, 0xa210, + 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0xad80, 0x000d, + 0x2009, 0x0020, 0x127f, 0x0078, 0x3608, 0x61a4, 0x7824, 0x60a6, + 0x0078, 0x2bad, 0x2091, 0x8000, 0x7823, 0x4000, 0x7827, 0x4953, + 0x782b, 0x5020, 0x782f, 0x2020, 0x2009, 0x017f, 0x2104, 0x7832, + 0x3f00, 0x7836, 0x2061, 0x0100, 0x6200, 0x2061, 0x0200, 0x603c, + 0x8007, 0xa205, 0x783a, 0x2009, 0x04fd, 0x2104, 0x783e, 0x781b, + 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x2071, 0x0010, 0x20c1, + 0x00f0, 0xa08a, 0x0003, 0x00c8, 0x0427, 0x0078, 0x0423, 0x81ff, + 0x00c0, 0x2bd7, 0x7924, 0x810f, 0xa18c, 0x00ff, 0x1078, 0x45c4, + 0x00c0, 0x2bdb, 0x7e38, 0xa684, 0x3fff, 0xa082, 0x4000, 0x0048, + 0x2d23, 0x0078, 0x2bdb, 0x7c28, 0x7d2c, 0x1078, 0x47a4, 0xd28c, + 0x00c0, 0x2d2e, 0x1078, 0x4736, 0x0078, 0x2d30, 0x1078, 0x4772, + 0x00c0, 0x2d5a, 0x2061, 0xad00, 0x127e, 0x2091, 0x8000, 0x6000, + 0xa086, 0x0000, 0x0040, 0x2d48, 0x6010, 0xa06d, 0x0040, 0x2d48, + 0x683c, 0xa406, 0x00c0, 0x2d48, 0x6840, 0xa506, 0x0040, 0x2d53, + 0x127f, 0xace0, 0x0010, 0x2001, 0xa616, 0x2004, 0xac02, 0x00c8, + 0x2bd7, 0x0078, 0x2d34, 0x1078, 0x8a01, 0x127f, 0x0040, 0x2bd7, + 0x0078, 0x2bad, 0xa00e, 0x2001, 0x0005, 0x1078, 0x4b51, 0x127e, + 0x2091, 0x8000, 0x1078, 0x8f85, 0x1078, 0x4a73, 0x127f, 0x0078, + 0x2bad, 0x81ff, 0x00c0, 0x2bd7, 0x1078, 0x35d2, 0x0040, 0x2bdb, + 0x1078, 0x4673, 0x0040, 0x2bd7, 0x1078, 0x47b2, 0x0040, 0x2bd7, + 0x0078, 0x2bad, 0x81ff, 0x00c0, 0x2bd7, 0x1078, 0x35e4, 0x0040, + 0x2bdb, 0x1078, 0x482f, 0x0040, 0x2bd7, 0x2019, 0x0005, 0x1078, + 0x47d3, 0x0040, 0x2bd7, 0x7828, 0xa08a, 0x1000, 0x00c8, 0x2bdb, + 0x8003, 0x800b, 0x810b, 0xa108, 0x1078, 0x5a52, 0x0078, 0x2bad, + 0x127e, 0x2091, 0x8000, 0x81ff, 0x0040, 0x2da2, 0x2009, 0x0001, + 0x0078, 0x2dd3, 0x2029, 0x00ff, 0x6450, 0x2400, 0xa506, 0x0040, + 0x2dcd, 0x2508, 0x1078, 0x45c4, 0x00c0, 0x2dcd, 0x1078, 0x482f, + 0x00c0, 0x2db8, 0x2009, 0x0002, 0x62ac, 0x2518, 0x0078, 0x2dd3, + 0x2019, 0x0004, 0x1078, 0x47d3, 0x00c0, 0x2dc2, 0x2009, 0x0006, + 0x0078, 0x2dd3, 0x7824, 0xa08a, 0x1000, 0x00c8, 0x2dd6, 0x8003, + 0x800b, 0x810b, 0xa108, 0x1078, 0x5a52, 0x8529, 0x00c8, 0x2da5, + 0x127f, 0x0078, 0x2bad, 0x127f, 0x0078, 0x2bd7, 0x127f, 0x0078, + 0x2bdb, 0x1078, 0x35d2, 0x0040, 0x2bdb, 0x1078, 0x46e7, 0x1078, + 0x47a4, 0x0078, 0x2bad, 0x81ff, 0x00c0, 0x2bd7, 0x1078, 0x35d2, + 0x0040, 0x2bdb, 0x1078, 0x46d6, 0x1078, 0x47a4, 0x0078, 0x2bad, + 0x81ff, 0x00c0, 0x2bd7, 0x1078, 0x35d2, 0x0040, 0x2bdb, 0x1078, + 0x4775, 0x0040, 0x2bd7, 0x1078, 0x4484, 0x1078, 0x472f, 0x1078, + 0x47a4, 0x0078, 0x2bad, 0x1078, 0x35d2, 0x0040, 0x2bdb, 0x1078, + 0x4673, 0x0040, 0x2bd7, 0x62a0, 0x2019, 0x0005, 0x0c7e, 0x1078, + 0x47e9, 0x0c7f, 0x1078, 0x5f01, 0x077e, 0x2039, 0x0000, 0x1078, + 0x5e0a, 0x2009, 0x0000, 0x1078, 0x9f8b, 0x077f, 0x1078, 0x47a4, + 0x0078, 0x2bad, 0x1078, 0x35d2, 0x0040, 0x2bdb, 0x1078, 0x47a4, + 0x2208, 0x0078, 0x2bad, 0x157e, 0x0d7e, 0x0e7e, 0x2069, 0xa714, + 0x6810, 0x6914, 0xa10a, 0x00c8, 0x2e37, 0x2009, 0x0000, 0x6816, + 0x2011, 0x0000, 0x2019, 0x0000, 0x20a9, 0x00ff, 0x2069, 0xa735, + 0x2d04, 0xa075, 0x0040, 0x2e4c, 0x704c, 0x1078, 0x2e56, 0xa210, + 0x7080, 0x1078, 0x2e56, 0xa318, 0x8d68, 0x00f0, 0x2e40, 0x2300, + 0xa218, 0x0e7f, 0x0d7f, 0x157f, 0x0078, 0x2bad, 0x0f7e, 0x017e, + 0xa07d, 0x0040, 0x2e65, 0x2001, 0x0000, 0x8000, 0x2f0c, 0x81ff, + 0x0040, 0x2e65, 0x2178, 0x0078, 0x2e5d, 0x017f, 0x0f7f, 0x007c, + 0x2069, 0xa714, 0x6910, 0x62a8, 0x0078, 0x2bad, 0x81ff, 0x00c0, + 0x2bd7, 0x6150, 0xa190, 0x29c0, 0x2214, 0xa294, 0x00ff, 0x6070, + 0xa084, 0xff00, 0xa215, 0x636c, 0x67cc, 0xd79c, 0x0040, 0x2e84, + 0x2031, 0x0001, 0x0078, 0x2e86, 0x2031, 0x0000, 0x7e3a, 0x7f3e, + 0x0078, 0x2bad, 0x6140, 0x6244, 0x2019, 0xa8a2, 0x231c, 0x0078, + 0x2bad, 0x127e, 0x2091, 0x8000, 0x6134, 0x6338, 0xa006, 0x2010, + 0x127f, 0x0078, 0x2bad, 0x1078, 0x35e4, 0x0040, 0x2bdb, 0x6244, + 0x6338, 0x0078, 0x2bad, 0x6140, 0x6244, 0x7824, 0x6042, 0x7b28, + 0x6346, 0x2069, 0xa652, 0x831f, 0xa305, 0x6816, 0x782c, 0x2069, + 0xa8a2, 0x2d1c, 0x206a, 0x0078, 0x2bad, 0x017e, 0x127e, 0x2091, + 0x8000, 0x7824, 0x6036, 0xd094, 0x0040, 0x2ec8, 0x7828, 0xa085, + 0x0001, 0x2009, 0xa8ab, 0x200a, 0x2001, 0xffff, 0x1078, 0x5ae6, + 0x782c, 0x603a, 0x127f, 0x017f, 0x0078, 0x2bad, 0x1078, 0x35e4, + 0x0040, 0x2bdb, 0x7828, 0xa00d, 0x0040, 0x2bdb, 0x782c, 0xa005, + 0x0040, 0x2bdb, 0x6244, 0x6146, 0x6338, 0x603a, 0x0078, 0x2bad, + 0x2001, 0xa600, 0x2004, 0xa086, 0x0003, 0x00c0, 0x2bd7, 0x0c7e, + 0x2061, 0x0100, 0x7924, 0x810f, 0xa18c, 0x00ff, 0xa196, 0x00ff, + 0x00c0, 0x2ef7, 0x6030, 0xa085, 0xff00, 0x0078, 0x2f06, 0xa182, + 0x007f, 0x00c8, 0x2f30, 0xa188, 0x29c0, 0x210c, 0xa18c, 0x00ff, + 0x6030, 0xa116, 0x0040, 0x2f30, 0x810f, 0xa105, 0x127e, 0x2091, + 0x8000, 0x007e, 0x1078, 0x76c7, 0x007f, 0x0040, 0x2f2c, 0x601a, + 0x600b, 0xbc09, 0x601f, 0x0001, 0x1078, 0x35ba, 0x0040, 0x2f33, + 0x6837, 0x0000, 0x7007, 0x0003, 0x6833, 0x0000, 0x6838, 0xc0fd, + 0x683a, 0x701b, 0x2f8e, 0x2d00, 0x6012, 0x2009, 0x0032, 0x1078, + 0x775c, 0x127f, 0x0c7f, 0x007c, 0x127f, 0x0c7f, 0x0078, 0x2bd7, + 0x0c7f, 0x0078, 0x2bdb, 0x1078, 0x772d, 0x0078, 0x2f2c, 0x2001, + 0xa600, 0x2004, 0xa086, 0x0003, 0x00c0, 0x2bd7, 0x0c7e, 0x2061, + 0x0100, 0x7924, 0x810f, 0xa18c, 0x00ff, 0xa196, 0x00ff, 0x00c0, + 0x2f4e, 0x6030, 0xa085, 0xff00, 0x0078, 0x2f5d, 0xa182, 0x007f, + 0x00c8, 0x2f87, 0xa188, 0x29c0, 0x210c, 0xa18c, 0x00ff, 0x6030, + 0xa116, 0x0040, 0x2f87, 0x810f, 0xa105, 0x127e, 0x2091, 0x8000, + 0x007e, 0x1078, 0x76c7, 0x007f, 0x0040, 0x2f83, 0x601a, 0x600b, + 0xbc05, 0x601f, 0x0001, 0x1078, 0x35ba, 0x0040, 0x2f8a, 0x6837, + 0x0000, 0x7007, 0x0003, 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, + 0x701b, 0x2f8e, 0x2d00, 0x6012, 0x2009, 0x0032, 0x1078, 0x775c, + 0x127f, 0x0c7f, 0x007c, 0x127f, 0x0c7f, 0x0078, 0x2bd7, 0x0c7f, + 0x0078, 0x2bdb, 0x1078, 0x772d, 0x0078, 0x2f83, 0x6830, 0xa086, + 0x0100, 0x0040, 0x2bd7, 0x0078, 0x2bad, 0x2061, 0xa933, 0x127e, + 0x2091, 0x8000, 0x6000, 0xd084, 0x0040, 0x2fa6, 0x6104, 0x6208, + 0x2019, 0xa612, 0x231c, 0x127f, 0x0078, 0x2bad, 0x127f, 0x0078, + 0x2bdb, 0x81ff, 0x00c0, 0x2bd7, 0x127e, 0x2091, 0x8000, 0x6248, + 0x6064, 0xa202, 0x0048, 0x2fbd, 0xa085, 0x0001, 0x1078, 0x256a, + 0x1078, 0x3c9e, 0x127f, 0x0078, 0x2bad, 0x127f, 0x0078, 0x2bdb, + 0x127e, 0x2091, 0x8000, 0x20a9, 0x0012, 0x2001, 0xa640, 0x20a0, + 0xa006, 0x40a4, 0x127f, 0x0078, 0x2bad, 0x7d38, 0x7c3c, 0x0078, + 0x2c5f, 0x7824, 0xa09c, 0x00ff, 0xa39a, 0x0003, 0x00c8, 0x2bd7, + 0x6250, 0xa084, 0xff00, 0x8007, 0xa206, 0x00c0, 0x2fe9, 0x2001, + 0xa640, 0x2009, 0x000c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0078, + 0x3608, 0x81ff, 0x00c0, 0x2bd7, 0x1078, 0x35e4, 0x0040, 0x2bdb, + 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x2bd7, 0x0c7e, + 0x1078, 0x35ba, 0x0c7f, 0x0040, 0x2bd7, 0x6837, 0x0000, 0x6838, + 0xc0fd, 0x683a, 0x1078, 0x8e4a, 0x0040, 0x2bd7, 0x7007, 0x0003, + 0x701b, 0x300b, 0x007c, 0x6830, 0xa086, 0x0100, 0x0040, 0x2bd7, + 0xad80, 0x000e, 0x2009, 0x000c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, + 0x0078, 0x3608, 0x1078, 0x35ba, 0x0040, 0x2bd7, 0x1078, 0x42dd, + 0x2009, 0x001c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x1078, 0x3604, + 0x701b, 0x302b, 0x007c, 0xade8, 0x000d, 0x6800, 0xa005, 0x0040, + 0x2bdb, 0x6804, 0xd0ac, 0x0040, 0x3038, 0xd0a4, 0x0040, 0x2bdb, + 0xd094, 0x0040, 0x3043, 0x0c7e, 0x2061, 0x0100, 0x6104, 0xa18c, + 0xffdf, 0x6106, 0x0c7f, 0xd08c, 0x0040, 0x304e, 0x0c7e, 0x2061, + 0x0100, 0x6104, 0xa18d, 0x0010, 0x6106, 0x0c7f, 0x2009, 0x0100, + 0x210c, 0xa18a, 0x0002, 0x0048, 0x3063, 0xd084, 0x0040, 0x3063, + 0x6a28, 0xa28a, 0x007f, 0x00c8, 0x2bdb, 0xa288, 0x29c0, 0x210c, + 0xa18c, 0x00ff, 0x6156, 0xd0dc, 0x0040, 0x306c, 0x6828, 0xa08a, + 0x007f, 0x00c8, 0x2bdb, 0x6052, 0x6808, 0xa08a, 0x0100, 0x0048, + 0x2bdb, 0xa08a, 0x0841, 0x00c8, 0x2bdb, 0xa084, 0x0007, 0x00c0, + 0x2bdb, 0x680c, 0xa005, 0x0040, 0x2bdb, 0x6810, 0xa005, 0x0040, + 0x2bdb, 0x6848, 0x6940, 0xa10a, 0x00c8, 0x2bdb, 0x8001, 0x0040, + 0x2bdb, 0x684c, 0x6944, 0xa10a, 0x00c8, 0x2bdb, 0x8001, 0x0040, + 0x2bdb, 0x6804, 0xd0fc, 0x0040, 0x30c2, 0x1078, 0x35ba, 0x0040, + 0x2bd7, 0x2009, 0x0014, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0xa290, + 0x0038, 0xa399, 0x0000, 0x1078, 0x3604, 0x701b, 0x30a8, 0x007c, + 0xade8, 0x000d, 0x20a9, 0x0014, 0x2d98, 0x2069, 0xa66e, 0x2da0, + 0x53a3, 0x7010, 0xa0e8, 0x000d, 0x2001, 0xa672, 0x200c, 0xd1e4, + 0x0040, 0x30c2, 0x0c7e, 0x2061, 0x0100, 0x6004, 0xa085, 0x0b00, + 0x6006, 0x0c7f, 0x20a9, 0x001c, 0x2d98, 0x2069, 0xa652, 0x2da0, + 0x53a3, 0x6814, 0xa08c, 0x00ff, 0x6142, 0x8007, 0xa084, 0x00ff, + 0x6046, 0x1078, 0x4eae, 0x1078, 0x49ce, 0x1078, 0x4a3e, 0x6000, + 0xa086, 0x0000, 0x00c0, 0x314d, 0x6808, 0x602a, 0x1078, 0x21f7, + 0x6818, 0x691c, 0x6a20, 0x6b24, 0x8007, 0x810f, 0x8217, 0x831f, + 0x6016, 0x611a, 0x621e, 0x6322, 0x6c04, 0xd4f4, 0x0040, 0x30fa, + 0x6830, 0x6934, 0x6a38, 0x6b3c, 0x8007, 0x810f, 0x8217, 0x831f, + 0x0078, 0x30fc, 0xa084, 0xf0ff, 0x6006, 0x610a, 0x620e, 0x6312, + 0x1078, 0x5b19, 0x6904, 0xd1fc, 0x0040, 0x312f, 0x0c7e, 0x2009, + 0x0000, 0x20a9, 0x0001, 0x6b70, 0xd384, 0x0040, 0x312c, 0x0078, + 0x3116, 0x839d, 0x00c8, 0x312c, 0x3508, 0x8109, 0x1078, 0x5480, + 0x6878, 0x6016, 0x6874, 0x2008, 0xa084, 0xff00, 0x8007, 0x600a, + 0xa184, 0x00ff, 0x6006, 0x8108, 0x00c0, 0x312a, 0x6003, 0x0003, + 0x0078, 0x312c, 0x6003, 0x0001, 0x00f0, 0x3111, 0x0c7f, 0x0c7e, + 0x2061, 0x0100, 0x602f, 0x0040, 0x602f, 0x0000, 0x0c7f, 0x1078, + 0x3819, 0x0040, 0x313d, 0x1078, 0x256a, 0x60c0, 0xa005, 0x0040, + 0x3149, 0x6003, 0x0001, 0x2091, 0x301d, 0x1078, 0x4224, 0x0078, + 0x314d, 0x6003, 0x0004, 0x2091, 0x301d, 0x0078, 0x2bad, 0x6000, + 0xa086, 0x0000, 0x0040, 0x2bd7, 0x2069, 0xa652, 0x7830, 0x6842, + 0x7834, 0x6846, 0x6804, 0xd0fc, 0x0040, 0x3162, 0x2009, 0x0030, + 0x0078, 0x3164, 0x2009, 0x001c, 0x2d00, 0x7a2c, 0x7b28, 0x7c3c, + 0x7d38, 0x0078, 0x3608, 0xa006, 0x1078, 0x256a, 0x81ff, 0x00c0, + 0x2bd7, 0x1078, 0x42dd, 0x1078, 0x4224, 0x0078, 0x2bad, 0x81ff, + 0x00c0, 0x2bd7, 0x6184, 0x81ff, 0x0040, 0x3191, 0x703f, 0x0000, + 0x2001, 0xacc0, 0x2009, 0x0040, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, + 0x127e, 0x2091, 0x8000, 0x1078, 0x3608, 0x701b, 0x2baa, 0x127f, + 0x007c, 0x703f, 0x0001, 0x0d7e, 0x2069, 0xacc0, 0x20a9, 0x0040, + 0x20a1, 0xacc0, 0x2019, 0xffff, 0x43a4, 0x6550, 0xa588, 0x29c0, + 0x210c, 0xa18c, 0x00ff, 0x216a, 0xa00e, 0x2011, 0x0002, 0x2100, + 0xa506, 0x0040, 0x31c3, 0x1078, 0x45c4, 0x00c0, 0x31c3, 0x6014, + 0x821c, 0x0048, 0x31bb, 0xa398, 0xacc0, 0xa085, 0xff00, 0x8007, + 0x201a, 0x0078, 0x31c2, 0xa398, 0xacc0, 0x2324, 0xa4a4, 0xff00, + 0xa405, 0x201a, 0x8210, 0x8108, 0xa182, 0x0080, 0x00c8, 0x31ca, + 0x0078, 0x31a7, 0x8201, 0x8007, 0x2d0c, 0xa105, 0x206a, 0x0d7f, + 0x20a9, 0x0040, 0x20a1, 0xacc0, 0x2099, 0xacc0, 0x1078, 0x4281, + 0x0078, 0x3180, 0x1078, 0x35e4, 0x0040, 0x2bdb, 0x0c7e, 0x1078, + 0x35ba, 0x0c7f, 0x00c0, 0x31e8, 0x2009, 0x0002, 0x0078, 0x2bd7, + 0x2001, 0xa653, 0x2004, 0xd0b4, 0x0040, 0x320f, 0x6000, 0xd08c, + 0x00c0, 0x320f, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, + 0x320f, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x1078, 0x8e9e, + 0x00c0, 0x3206, 0x2009, 0x0003, 0x0078, 0x2bd7, 0x7007, 0x0003, + 0x701b, 0x320b, 0x007c, 0x1078, 0x35e4, 0x0040, 0x2bdb, 0x20a9, + 0x002b, 0x2c98, 0xade8, 0x0002, 0x2da0, 0x53a3, 0x20a9, 0x0004, + 0xac80, 0x0006, 0x2098, 0xad80, 0x0006, 0x20a0, 0x1078, 0x4281, + 0x20a9, 0x0004, 0xac80, 0x000a, 0x2098, 0xad80, 0x000a, 0x20a0, + 0x1078, 0x4281, 0x2d00, 0x2009, 0x002b, 0x7a2c, 0x7b28, 0x7c3c, + 0x7d38, 0x0078, 0x3608, 0x81ff, 0x00c0, 0x2bd7, 0x1078, 0x35d2, + 0x0040, 0x2bdb, 0x1078, 0x47bd, 0x0078, 0x2bad, 0x81ff, 0x00c0, + 0x2bd7, 0x7828, 0xa08a, 0x1000, 0x00c8, 0x2bdb, 0x1078, 0x35e4, + 0x0040, 0x2bdb, 0x1078, 0x482f, 0x0040, 0x2bd7, 0x2019, 0x0004, + 0x1078, 0x47d3, 0x7924, 0x810f, 0x7a28, 0x1078, 0x3259, 0x0078, + 0x2bad, 0xa186, 0x00ff, 0x0040, 0x3261, 0x1078, 0x3271, 0x0078, + 0x3270, 0x2029, 0x007e, 0x2061, 0xa600, 0x6450, 0x2400, 0xa506, + 0x0040, 0x326d, 0x2508, 0x1078, 0x3271, 0x8529, 0x00c8, 0x3266, + 0x007c, 0x1078, 0x45c4, 0x00c0, 0x327c, 0x2200, 0x8003, 0x800b, + 0x810b, 0xa108, 0x1078, 0x5a52, 0x007c, 0x81ff, 0x00c0, 0x2bd7, + 0x1078, 0x35d2, 0x0040, 0x2bdb, 0x1078, 0x4673, 0x0040, 0x2bd7, + 0x1078, 0x47c8, 0x0078, 0x2bad, 0x81ff, 0x00c0, 0x2bd7, 0x1078, + 0x35d2, 0x0040, 0x2bdb, 0x1078, 0x4673, 0x0040, 0x2bd7, 0x1078, + 0x47b2, 0x0078, 0x2bad, 0x6100, 0x0078, 0x2bad, 0x1078, 0x35e4, + 0x0040, 0x2bdb, 0x2001, 0xa600, 0x2004, 0xa086, 0x0003, 0x00c0, + 0x2bd7, 0x0d7e, 0xace8, 0x000a, 0x7924, 0xd184, 0x0040, 0x32b2, + 0xace8, 0x0006, 0x680c, 0x8007, 0x783e, 0x6808, 0x8007, 0x783a, + 0x6b04, 0x831f, 0x6a00, 0x8217, 0x0d7f, 0x6100, 0xa18c, 0x0200, + 0x0078, 0x2bad, 0xa006, 0x1078, 0x256a, 0x7824, 0xa084, 0x00ff, + 0xa086, 0x00ff, 0x0040, 0x32cf, 0x81ff, 0x00c0, 0x2bd7, 0x1078, + 0x42dd, 0x7828, 0xa08a, 0x1000, 0x00c8, 0x2bdb, 0x7924, 0xa18c, + 0xff00, 0x810f, 0xa186, 0x00ff, 0x0040, 0x32e5, 0xa182, 0x007f, + 0x00c8, 0x2bdb, 0x2100, 0x1078, 0x2564, 0x027e, 0x0c7e, 0x127e, + 0x2091, 0x8000, 0x2061, 0xa8c4, 0x601b, 0x0000, 0x601f, 0x0000, + 0x2011, 0x0003, 0x1078, 0x70e0, 0x2011, 0x0002, 0x1078, 0x70ea, + 0x1078, 0x6fc4, 0x037e, 0x2019, 0x0000, 0x1078, 0x7058, 0x037f, + 0x2061, 0x0100, 0x6030, 0xa084, 0x00ff, 0x810f, 0xa105, 0x604a, + 0x6043, 0x0090, 0x6043, 0x0010, 0x2009, 0x002d, 0x2011, 0x4259, + 0x1078, 0x5add, 0x7924, 0xa18c, 0xff00, 0x810f, 0x7a28, 0x1078, + 0x3259, 0x127f, 0x0c7f, 0x027f, 0x0078, 0x2bad, 0x7924, 0xa18c, + 0xff00, 0x810f, 0x0c7e, 0x1078, 0x455c, 0x2c08, 0x0c7f, 0x00c0, + 0x2bdb, 0x0078, 0x2bad, 0x81ff, 0x0040, 0x3332, 0x2009, 0x0001, + 0x0078, 0x2bd7, 0x60cc, 0xd09c, 0x00c0, 0x333a, 0x2009, 0x0005, + 0x0078, 0x2bd7, 0x1078, 0x35ba, 0x00c0, 0x3342, 0x2009, 0x0002, + 0x0078, 0x2bd7, 0x7924, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x1078, + 0x3604, 0x701b, 0x334c, 0x007c, 0x2009, 0x0080, 0x1078, 0x45c4, + 0x00c0, 0x3359, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x0040, + 0x335d, 0x2021, 0x400a, 0x0078, 0x2baf, 0x0d7e, 0xade8, 0x000d, + 0x6900, 0x6a08, 0x6b0c, 0x6c10, 0x6d14, 0x6e18, 0x6820, 0xa0be, + 0x0100, 0x0040, 0x33d0, 0xa0be, 0x0112, 0x0040, 0x33d0, 0xa0be, + 0x0113, 0x0040, 0x33d0, 0xa0be, 0x0114, 0x0040, 0x33d0, 0xa0be, + 0x0117, 0x0040, 0x33d0, 0xa0be, 0x011a, 0x0040, 0x33d0, 0xa0be, + 0x0121, 0x0040, 0x33c6, 0xa0be, 0x0131, 0x0040, 0x33c6, 0xa0be, + 0x0171, 0x0040, 0x33d0, 0xa0be, 0x0173, 0x0040, 0x33d0, 0xa0be, + 0x01a1, 0x00c0, 0x3398, 0x6830, 0x8007, 0x6832, 0x0078, 0x33d6, + 0xa0be, 0x0212, 0x0040, 0x33cc, 0xa0be, 0x0213, 0x0040, 0x33cc, + 0xa0be, 0x0214, 0x0040, 0x33be, 0xa0be, 0x0217, 0x0040, 0x33b8, + 0xa0be, 0x021a, 0x00c0, 0x33b1, 0x6838, 0x8007, 0x683a, 0x0078, + 0x33d0, 0xa0be, 0x0300, 0x0040, 0x33d0, 0x0d7f, 0x0078, 0x2bdb, + 0xad80, 0x0010, 0x20a9, 0x0007, 0x1078, 0x3418, 0xad80, 0x000e, + 0x20a9, 0x0001, 0x1078, 0x3418, 0x0078, 0x33d0, 0xad80, 0x000c, + 0x1078, 0x3426, 0x0078, 0x33d6, 0xad80, 0x000e, 0x1078, 0x3426, + 0xad80, 0x000c, 0x20a9, 0x0001, 0x1078, 0x3418, 0x0c7e, 0x1078, + 0x35ba, 0x0040, 0x3409, 0x6838, 0xc0fd, 0x683a, 0x6837, 0x0119, + 0x6853, 0x0000, 0x684f, 0x0020, 0x685b, 0x0001, 0x810b, 0x697e, + 0x6883, 0x0000, 0x6a86, 0x6b8a, 0x6c8e, 0x6d92, 0x6996, 0x689b, + 0x0000, 0x0c7f, 0x0d7f, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, + 0x6823, 0x0000, 0x6804, 0x2068, 0x1078, 0x8e66, 0x00c0, 0x3404, + 0x2009, 0x0003, 0x0078, 0x2bd7, 0x7007, 0x0003, 0x701b, 0x340f, + 0x007c, 0x0c7f, 0x0d7f, 0x2009, 0x0002, 0x0078, 0x2bd7, 0x6820, + 0xa086, 0x8001, 0x00c0, 0x2bad, 0x2009, 0x0004, 0x0078, 0x2bd7, + 0x017e, 0x2008, 0x2044, 0x8000, 0x204c, 0x8000, 0x290a, 0x8108, + 0x280a, 0x8108, 0x00f0, 0x341a, 0x017f, 0x007c, 0x017e, 0x0a7e, + 0x0b7e, 0x2008, 0x2044, 0x8000, 0x204c, 0x8000, 0x2054, 0x8000, + 0x205c, 0x2b0a, 0x8108, 0x2a0a, 0x8108, 0x290a, 0x8108, 0x280a, + 0x0b7f, 0x0a7f, 0x017f, 0x007c, 0x81ff, 0x0040, 0x3443, 0x2009, + 0x0001, 0x0078, 0x2bd7, 0x60cc, 0xd09c, 0x00c0, 0x344b, 0x2009, + 0x0005, 0x0078, 0x2bd7, 0x7924, 0x2140, 0xa18c, 0xff00, 0x810f, + 0xa182, 0x0080, 0x0048, 0x2bdb, 0xa182, 0x00ff, 0x00c8, 0x2bdb, + 0x7a2c, 0x7b28, 0x606c, 0xa306, 0x00c0, 0x3466, 0x6070, 0xa24e, + 0x0040, 0x2bdb, 0xa9cc, 0xff00, 0x0040, 0x2bdb, 0x0c7e, 0x1078, + 0x350f, 0x2c68, 0x0c7f, 0x0040, 0x349e, 0xa0c6, 0x4000, 0x00c0, + 0x3484, 0x0c7e, 0x007e, 0x2d60, 0x2009, 0x0000, 0x1078, 0x489b, + 0x00c0, 0x347b, 0xc185, 0x6000, 0xd0bc, 0x0040, 0x3480, 0xc18d, + 0x007f, 0x0c7f, 0x0078, 0x349b, 0xa0c6, 0x4007, 0x00c0, 0x348b, + 0x2408, 0x0078, 0x349b, 0xa0c6, 0x4008, 0x00c0, 0x3493, 0x2708, + 0x2610, 0x0078, 0x349b, 0xa0c6, 0x4009, 0x00c0, 0x3499, 0x0078, + 0x349b, 0x2001, 0x4006, 0x2020, 0x0078, 0x2baf, 0x2d00, 0x7022, + 0x017e, 0x0b7e, 0x0c7e, 0x0e7e, 0x2c70, 0x1078, 0x76c7, 0x0040, + 0x34e4, 0x2d00, 0x601a, 0x2001, 0xa657, 0x2004, 0xa084, 0x00ff, + 0x6842, 0x2e58, 0x0e7f, 0x0e7e, 0x0c7e, 0x1078, 0x35ba, 0x0c7f, + 0x2b70, 0x00c0, 0x34c5, 0x1078, 0x772d, 0x0e7f, 0x0c7f, 0x0b7f, + 0x017f, 0x2009, 0x0002, 0x0078, 0x2bd7, 0x6837, 0x0000, 0x2d00, + 0x6012, 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x127e, 0x2091, + 0x8000, 0x1078, 0x2880, 0x127f, 0x601f, 0x0001, 0x2001, 0x0000, + 0x1078, 0x44ee, 0x2001, 0x0002, 0x1078, 0x4502, 0x2009, 0x0002, + 0x1078, 0x775c, 0xa085, 0x0001, 0x0e7f, 0x0c7f, 0x0b7f, 0x017f, + 0x00c0, 0x34ee, 0x2009, 0x0003, 0x0078, 0x2bd7, 0x7007, 0x0003, + 0x701b, 0x34f3, 0x007c, 0x6830, 0xa086, 0x0100, 0x7020, 0x2060, + 0x00c0, 0x3501, 0x2009, 0x0004, 0x6204, 0xa294, 0x00ff, 0x0078, + 0x2bd7, 0x2009, 0x0000, 0x1078, 0x489b, 0x00c0, 0x3508, 0xc185, + 0x6000, 0xd0bc, 0x0040, 0x350d, 0xc18d, 0x0078, 0x2bad, 0x0e7e, + 0x0d7e, 0x2029, 0x0000, 0x2021, 0x0080, 0x20a9, 0x007f, 0x2071, + 0xa7b5, 0x2e04, 0xa005, 0x00c0, 0x3524, 0x2100, 0xa406, 0x00c0, + 0x3555, 0x2428, 0x0078, 0x3555, 0x2068, 0x6f10, 0x2700, 0xa306, + 0x00c0, 0x3546, 0x6e14, 0x2600, 0xa206, 0x00c0, 0x3546, 0x2400, + 0xa106, 0x00c0, 0x3542, 0x2d60, 0xd884, 0x0040, 0x356a, 0x6004, + 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x356a, 0x2001, 0x4000, + 0x0078, 0x356b, 0x2001, 0x4007, 0x0078, 0x356b, 0x2400, 0xa106, + 0x00c0, 0x3555, 0x6e14, 0x87ff, 0x00c0, 0x3551, 0x86ff, 0x0040, + 0x3521, 0x2001, 0x4008, 0x0078, 0x356b, 0x8420, 0x8e70, 0x00f0, + 0x3519, 0x85ff, 0x00c0, 0x3564, 0x2001, 0x4009, 0x0078, 0x356b, + 0x2001, 0x0001, 0x0078, 0x356b, 0x1078, 0x455c, 0x00c0, 0x3560, + 0x6312, 0x6216, 0xa006, 0xa005, 0x0d7f, 0x0e7f, 0x007c, 0x81ff, + 0x00c0, 0x2bd7, 0x1078, 0x35ba, 0x0040, 0x2bd7, 0x6837, 0x0000, + 0x6838, 0xc0fd, 0x683a, 0x7824, 0xa005, 0x0040, 0x2bdb, 0xa096, + 0x00ff, 0x0040, 0x3587, 0xa092, 0x0004, 0x00c8, 0x2bdb, 0x2010, + 0x2d18, 0x1078, 0x282f, 0x0040, 0x2bd7, 0x7007, 0x0003, 0x701b, + 0x3592, 0x007c, 0x6830, 0xa086, 0x0100, 0x0040, 0x2bd7, 0x0078, + 0x2bad, 0x7924, 0xa18c, 0xff00, 0x810f, 0xa182, 0x0080, 0x0048, + 0x2bdb, 0xa182, 0x00ff, 0x00c8, 0x2bdb, 0x127e, 0x2091, 0x8000, + 0x1078, 0x8d4b, 0x00c0, 0x35b7, 0xa190, 0xa735, 0x2204, 0xa065, + 0x0040, 0x35b7, 0x1078, 0x42f8, 0x127f, 0x0078, 0x2bad, 0x127f, + 0x0078, 0x2bd7, 0x1078, 0x138b, 0x0040, 0x35d1, 0xa006, 0x6802, + 0x7010, 0xa005, 0x00c0, 0x35c9, 0x2d00, 0x7012, 0x7016, 0x0078, + 0x35cf, 0x7014, 0x6802, 0x2060, 0x2d00, 0x6006, 0x7016, 0xad80, + 0x000d, 0x007c, 0x7924, 0x810f, 0xa18c, 0x00ff, 0x1078, 0x45c4, + 0x00c0, 0x35e1, 0x7e28, 0xa684, 0x3fff, 0xa082, 0x4000, 0x0048, + 0x35e2, 0xa066, 0x8cff, 0x007c, 0x7e24, 0x860f, 0xa18c, 0x00ff, + 0x1078, 0x45c4, 0x00c0, 0x35f2, 0xa6b4, 0x00ff, 0xa682, 0x4000, + 0x0048, 0x35f3, 0xa066, 0x8cff, 0x007c, 0x017e, 0x7110, 0x81ff, + 0x0040, 0x3600, 0x2168, 0x6904, 0x1078, 0x13a4, 0x0078, 0x35f7, + 0x7112, 0x7116, 0x017f, 0x007c, 0x2031, 0x0001, 0x0078, 0x360a, + 0x2031, 0x0000, 0x2061, 0xa6d2, 0x6606, 0x6112, 0x600e, 0x6226, + 0x632a, 0x642e, 0x6532, 0x2c10, 0x1078, 0x13db, 0x7007, 0x0002, + 0x701b, 0x2bad, 0x007c, 0x0f7e, 0x127e, 0x2091, 0x8000, 0x2079, + 0x0000, 0x2001, 0xa690, 0x2004, 0xa005, 0x00c0, 0x3636, 0x0068, + 0x3636, 0x7818, 0xd084, 0x00c0, 0x3636, 0x7a22, 0x7b26, 0x7c2a, + 0x781b, 0x0001, 0x2091, 0x4080, 0x0078, 0x365b, 0x017e, 0x0c7e, + 0x0e7e, 0x2071, 0xa682, 0x7138, 0xa182, 0x0008, 0x0048, 0x3644, + 0x7030, 0x2060, 0x0078, 0x3655, 0x7030, 0xa0e0, 0x0008, 0xac82, + 0xa6d2, 0x0048, 0x364d, 0x2061, 0xa692, 0x2c00, 0x7032, 0x81ff, + 0x00c0, 0x3653, 0x7036, 0x8108, 0x713a, 0x2262, 0x6306, 0x640a, + 0x0e7f, 0x0c7f, 0x017f, 0x127f, 0x0f7f, 0x007c, 0x0e7e, 0x2071, + 0xa682, 0x7038, 0xa005, 0x0040, 0x3697, 0x127e, 0x2091, 0x8000, + 0x0068, 0x3696, 0x0f7e, 0x2079, 0x0000, 0x7818, 0xd084, 0x00c0, + 0x3695, 0x0c7e, 0x7034, 0x2060, 0x2c04, 0x7822, 0x6004, 0x7826, + 0x6008, 0x782a, 0x781b, 0x0001, 0x2091, 0x4080, 0x7038, 0x8001, + 0x703a, 0xa005, 0x00c0, 0x368b, 0x7033, 0xa692, 0x7037, 0xa692, + 0x0c7f, 0x0078, 0x3695, 0xac80, 0x0008, 0xa0fa, 0xa6d2, 0x0048, + 0x3693, 0x2001, 0xa692, 0x7036, 0x0c7f, 0x0f7f, 0x127f, 0x0e7f, + 0x007c, 0x027e, 0x2001, 0xa653, 0x2004, 0xd0c4, 0x0040, 0x36a4, + 0x2011, 0x8014, 0x1078, 0x361b, 0x027f, 0x007c, 0x81ff, 0x00c0, + 0x2bd7, 0x127e, 0x2091, 0x8000, 0x6030, 0xc08d, 0xc085, 0xc0ac, + 0x6032, 0x1078, 0x4224, 0x127f, 0x0078, 0x2bad, 0x81ff, 0x00c0, + 0x2bd7, 0x6000, 0xa086, 0x0003, 0x00c0, 0x2bd7, 0x2001, 0xa653, + 0x2004, 0xd0ac, 0x00c0, 0x2bd7, 0x1078, 0x35e4, 0x0040, 0x2bdb, + 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x36d3, 0x7828, + 0xa005, 0x0040, 0x2bad, 0x0c7e, 0x1078, 0x35ba, 0x0c7f, 0x0040, + 0x2bd7, 0x6837, 0x0000, 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, + 0x1078, 0x8f12, 0x0040, 0x2bd7, 0x7007, 0x0003, 0x701b, 0x36e9, + 0x007c, 0x6830, 0xa086, 0x0100, 0x0040, 0x2bd7, 0x0078, 0x2bad, + 0x2001, 0xa600, 0x2004, 0xa086, 0x0003, 0x00c0, 0x2bd7, 0x7f24, + 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x1078, 0x35ba, 0x0040, 0x2bd7, + 0x2009, 0x0000, 0x2031, 0x0000, 0x7023, 0x0000, 0x702f, 0x0000, + 0xad80, 0x0005, 0x7026, 0x20a0, 0x1078, 0x45c4, 0x00c0, 0x376d, + 0x6004, 0xa0c4, 0x00ff, 0xa8c6, 0x0006, 0x0040, 0x371d, 0xa0c4, + 0xff00, 0xa8c6, 0x0600, 0x00c0, 0x376d, 0x2001, 0xa653, 0x2004, + 0xd0ac, 0x00c0, 0x372a, 0x1078, 0x489b, 0x00c0, 0x372a, 0xd79c, + 0x0040, 0x376d, 0xd794, 0x00c0, 0x3730, 0xd784, 0x0040, 0x373c, + 0xac80, 0x0006, 0x2098, 0x3400, 0x20a9, 0x0004, 0x53a3, 0x1078, + 0x3426, 0xd794, 0x0040, 0x3745, 0xac80, 0x000a, 0x2098, 0x3400, + 0x20a9, 0x0004, 0x53a3, 0x1078, 0x3426, 0x21a2, 0xd794, 0x0040, + 0x3765, 0xac80, 0x0000, 0x2098, 0x94a0, 0x20a9, 0x0002, 0x53a3, + 0xac80, 0x0003, 0x20a6, 0x94a0, 0xac80, 0x0004, 0x2098, 0x3400, + 0x20a9, 0x0002, 0x53a3, 0x1078, 0x3418, 0xac80, 0x0026, 0x2098, + 0x20a9, 0x0002, 0x53a3, 0x0078, 0x3766, 0x94a0, 0xd794, 0x0040, + 0x376b, 0xa6b0, 0x000b, 0xa6b0, 0x0005, 0x8108, 0xd78c, 0x0040, + 0x3777, 0xa186, 0x0100, 0x0040, 0x3788, 0x0078, 0x377b, 0xa186, + 0x007e, 0x0040, 0x3788, 0xd794, 0x0040, 0x3782, 0xa686, 0x0020, + 0x0078, 0x3784, 0xa686, 0x0028, 0x0040, 0x3791, 0x0078, 0x370c, + 0x86ff, 0x00c0, 0x378f, 0x7120, 0x810b, 0x0078, 0x2bad, 0x702f, + 0x0001, 0x711e, 0x7020, 0xa600, 0x7022, 0x772a, 0x2061, 0xa6d2, + 0x6007, 0x0000, 0x6612, 0x7024, 0x600e, 0x6226, 0x632a, 0x642e, + 0x6532, 0x2c10, 0x1078, 0x13db, 0x7007, 0x0002, 0x701b, 0x37a9, + 0x007c, 0x702c, 0xa005, 0x00c0, 0x37bb, 0x711c, 0x7024, 0x20a0, + 0x7728, 0x2031, 0x0000, 0x2061, 0xa6d2, 0x6224, 0x6328, 0x642c, + 0x6530, 0x0078, 0x370c, 0x7120, 0x810b, 0x0078, 0x2bad, 0x2029, + 0x007e, 0x7924, 0x7a28, 0x7b2c, 0x7c38, 0xa184, 0xff00, 0x8007, + 0xa0e2, 0x0020, 0x0048, 0x2bdb, 0xa502, 0x0048, 0x2bdb, 0xa184, + 0x00ff, 0xa0e2, 0x0020, 0x0048, 0x2bdb, 0xa502, 0x0048, 0x2bdb, + 0xa284, 0xff00, 0x8007, 0xa0e2, 0x0020, 0x0048, 0x2bdb, 0xa502, + 0x0048, 0x2bdb, 0xa284, 0x00ff, 0xa0e2, 0x0020, 0x0048, 0x2bdb, + 0xa502, 0x0048, 0x2bdb, 0xa384, 0xff00, 0x8007, 0xa0e2, 0x0020, + 0x0048, 0x2bdb, 0xa502, 0x0048, 0x2bdb, 0xa384, 0x00ff, 0xa0e2, + 0x0020, 0x0048, 0x2bdb, 0xa502, 0x0048, 0x2bdb, 0xa484, 0xff00, + 0x8007, 0xa0e2, 0x0020, 0x0048, 0x2bdb, 0xa502, 0x0048, 0x2bdb, + 0xa484, 0x00ff, 0xa0e2, 0x0020, 0x0048, 0x2bdb, 0xa502, 0x0048, + 0x2bdb, 0x2061, 0xa8a5, 0x6102, 0x6206, 0x630a, 0x640e, 0x0078, + 0x2bad, 0x007e, 0x2001, 0xa653, 0x2004, 0xd0cc, 0x007f, 0x007c, + 0x007e, 0x2001, 0xa672, 0x2004, 0xd0bc, 0x007f, 0x007c, 0x6164, + 0x7a24, 0x6300, 0x82ff, 0x00c0, 0x3830, 0x7926, 0x0078, 0x2bad, + 0x83ff, 0x00c0, 0x2bdb, 0x2001, 0xfff0, 0xa200, 0x00c8, 0x2bdb, + 0x2019, 0xffff, 0x6068, 0xa302, 0xa200, 0x0048, 0x2bdb, 0x7926, + 0x6266, 0x0078, 0x2bad, 0x2001, 0xa600, 0x2004, 0xa086, 0x0003, + 0x00c0, 0x2bd7, 0x7c28, 0x7d24, 0x7e38, 0x7f2c, 0x1078, 0x35ba, + 0x0040, 0x2bd7, 0x2009, 0x0000, 0x2019, 0x0000, 0x7023, 0x0000, + 0x702f, 0x0000, 0xad80, 0x0003, 0x7026, 0x20a0, 0xa1e0, 0xa735, + 0x2c64, 0x8cff, 0x0040, 0x387d, 0x6004, 0xa084, 0x00ff, 0xa086, + 0x0006, 0x0040, 0x3872, 0x6004, 0xa084, 0xff00, 0xa086, 0x0600, + 0x00c0, 0x387d, 0x6014, 0x20a2, 0x94a0, 0x6010, 0x8007, 0xa105, + 0x8007, 0x20a2, 0x94a0, 0xa398, 0x0002, 0x8108, 0xa182, 0x00ff, + 0x0040, 0x3888, 0xa386, 0x002a, 0x0040, 0x3891, 0x0078, 0x385e, + 0x83ff, 0x00c0, 0x388f, 0x7120, 0x810c, 0x0078, 0x2bad, 0x702f, + 0x0001, 0x711e, 0x7020, 0xa300, 0x7022, 0x2061, 0xa6d2, 0x6007, + 0x0000, 0x6312, 0x7024, 0x600e, 0x6426, 0x652a, 0x662e, 0x6732, + 0x2c10, 0x1078, 0x13db, 0x7007, 0x0002, 0x701b, 0x38a8, 0x007c, + 0x702c, 0xa005, 0x00c0, 0x38b9, 0x711c, 0x7024, 0x20a0, 0x2019, + 0x0000, 0x2061, 0xa6d2, 0x6424, 0x6528, 0x662c, 0x6730, 0x0078, + 0x385e, 0x7120, 0x810c, 0x0078, 0x2bad, 0x81ff, 0x00c0, 0x2bd7, + 0x60cc, 0xd09c, 0x0040, 0x2bd7, 0x1078, 0x35ba, 0x0040, 0x2bd7, + 0x7924, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x1078, 0x3604, 0x701b, + 0x38d2, 0x007c, 0x0d7e, 0xade8, 0x000d, 0x6828, 0xa0be, 0x7000, + 0x0040, 0x38e5, 0xa0be, 0x7100, 0x0040, 0x38e5, 0xa0be, 0x7200, + 0x0040, 0x38e5, 0x0d7f, 0x0078, 0x2bdb, 0x6820, 0x6924, 0x1078, + 0x254d, 0x00c0, 0x3910, 0x1078, 0x455c, 0x00c0, 0x3910, 0x7122, + 0x6612, 0x6516, 0x6e18, 0x0c7e, 0x1078, 0x35ba, 0x0040, 0x3910, + 0x1078, 0x35ba, 0x0040, 0x3910, 0x0c7f, 0x0d7f, 0x6837, 0x0000, + 0x6838, 0xc0fd, 0x683a, 0x6823, 0x0000, 0x6804, 0x2068, 0x1078, + 0x8e82, 0x0040, 0x2bd7, 0x7007, 0x0003, 0x701b, 0x3913, 0x007c, + 0x0d7f, 0x0078, 0x2bd7, 0x7120, 0x1078, 0x298e, 0x6820, 0xa086, + 0x8001, 0x0040, 0x2bd7, 0x2d00, 0x701e, 0x6804, 0xa080, 0x0002, + 0x007e, 0x20a9, 0x002a, 0x2098, 0x20a0, 0x1078, 0x4281, 0x007f, + 0xade8, 0x000d, 0x6a08, 0x6b0c, 0x6c10, 0x6d14, 0x2061, 0xa6d2, + 0x6007, 0x0000, 0x6e00, 0x6f28, 0xa7c6, 0x7000, 0x00c0, 0x393a, + 0x0078, 0x393e, 0xa7c6, 0x7100, 0x00c0, 0x3946, 0xa6c2, 0x0004, + 0x0048, 0x2bdb, 0x2009, 0x0004, 0x0078, 0x3608, 0xa7c6, 0x7200, + 0x00c0, 0x2bdb, 0xa6c2, 0x0054, 0x0048, 0x2bdb, 0x600e, 0x6013, + 0x002a, 0x6226, 0x632a, 0x642e, 0x6532, 0x2c10, 0x1078, 0x13db, + 0x7007, 0x0002, 0x701b, 0x395d, 0x007c, 0x701c, 0x2068, 0x6804, + 0xa080, 0x0001, 0x2004, 0xa080, 0x0002, 0x007e, 0x20a9, 0x002a, + 0x2098, 0x20a0, 0x1078, 0x4281, 0x007f, 0x2009, 0x002a, 0x2061, + 0xa6d2, 0x6224, 0x6328, 0x642c, 0x6530, 0x0078, 0x3608, 0x81ff, + 0x00c0, 0x2bd7, 0x792c, 0x2001, 0xa89d, 0x2102, 0x1078, 0x35d2, + 0x0040, 0x2bdb, 0x1078, 0x4673, 0x0040, 0x2bd7, 0x127e, 0x2091, + 0x8000, 0x1078, 0x47de, 0x127f, 0x0078, 0x2bad, 0x7824, 0xd08c, + 0x00c0, 0x3995, 0xd084, 0x0040, 0x31da, 0x1078, 0x35e4, 0x0040, + 0x2bdb, 0x0c7e, 0x1078, 0x35ba, 0x0c7f, 0x00c0, 0x39a3, 0x2009, + 0x0002, 0x0078, 0x2bd7, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, + 0x0040, 0x39b0, 0xa08e, 0x0004, 0x0040, 0x39b0, 0xa08e, 0x0005, + 0x00c0, 0x39dd, 0x7824, 0xd08c, 0x0040, 0x39bb, 0x6000, 0xc08c, + 0x6002, 0x0078, 0x39c5, 0x2001, 0xa653, 0x2004, 0xd0b4, 0x0040, + 0x320f, 0x6000, 0xd08c, 0x00c0, 0x320f, 0x6837, 0x0000, 0x6838, + 0xc0fd, 0x683a, 0x1078, 0x8e9e, 0x00c0, 0x39d2, 0x2009, 0x0003, + 0x0078, 0x2bd7, 0x7007, 0x0003, 0x701b, 0x39d7, 0x007c, 0x1078, + 0x35e4, 0x0040, 0x2bdb, 0x0078, 0x320f, 0x2009, 0xa62f, 0x210c, + 0x81ff, 0x0040, 0x39e7, 0x2009, 0x0001, 0x0078, 0x2bd7, 0x2001, + 0xa600, 0x2004, 0xa086, 0x0003, 0x0040, 0x39f2, 0x2009, 0x0007, + 0x0078, 0x2bd7, 0x2001, 0xa653, 0x2004, 0xd0ac, 0x0040, 0x39fc, + 0x2009, 0x0008, 0x0078, 0x2bd7, 0x609c, 0xd0a4, 0x00c0, 0x3a03, + 0xd0ac, 0x00c0, 0x320f, 0x6837, 0x0000, 0x6833, 0x0000, 0x6838, + 0xc0fd, 0x683a, 0x1078, 0x8f12, 0x00c0, 0x3a12, 0x2009, 0x0003, + 0x0078, 0x2bd7, 0x7007, 0x0003, 0x701b, 0x3a17, 0x007c, 0x6830, + 0xa086, 0x0100, 0x00c0, 0x3a20, 0x2009, 0x0004, 0x0078, 0x2bd7, + 0x1078, 0x35e4, 0x0040, 0x2bdb, 0x0078, 0x39b2, 0x81ff, 0x2009, + 0x0001, 0x00c0, 0x2bd7, 0x6000, 0xa086, 0x0003, 0x2009, 0x0007, + 0x00c0, 0x2bd7, 0x2001, 0xa653, 0x2004, 0xd0ac, 0x2009, 0x0008, + 0x00c0, 0x2bd7, 0x1078, 0x35e4, 0x0040, 0x2bdb, 0x6004, 0xa084, + 0x00ff, 0xa086, 0x0006, 0x2009, 0x0009, 0x00c0, 0x2bd7, 0x0c7e, + 0x1078, 0x35ba, 0x0c7f, 0x2009, 0x0002, 0x0040, 0x2bd7, 0x6837, + 0x0000, 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x7928, 0xa194, + 0xff00, 0xa18c, 0x00ff, 0xa006, 0x82ff, 0x00c0, 0x3a65, 0xc0ed, + 0x6952, 0x792c, 0x6956, 0x0078, 0x3a6e, 0xa28e, 0x0100, 0x00c0, + 0x2bdb, 0xc0e5, 0x6853, 0x0000, 0x6857, 0x0000, 0x683e, 0x1078, + 0x90bd, 0x2009, 0x0003, 0x0040, 0x2bd7, 0x7007, 0x0003, 0x701b, + 0x3a7a, 0x007c, 0x6830, 0xa086, 0x0100, 0x2009, 0x0004, 0x0040, + 0x2bd7, 0x0078, 0x2bad, 0x81ff, 0x2009, 0x0001, 0x00c0, 0x2bd7, + 0x6000, 0xa086, 0x0003, 0x2009, 0x0007, 0x00c0, 0x2bd7, 0x1078, + 0x35e4, 0x0040, 0x2bdb, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, + 0x2009, 0x0009, 0x00c0, 0x2bd7, 0x0c7e, 0x1078, 0x35ba, 0x0c7f, + 0x2009, 0x0002, 0x0040, 0x2bd7, 0xad80, 0x000f, 0x2009, 0x0008, + 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x1078, 0x3604, 0x701b, 0x3ab1, + 0x007c, 0x0d7e, 0xade8, 0x000f, 0x6800, 0xa086, 0x0500, 0x00c0, + 0x3ac4, 0x6804, 0xa005, 0x00c0, 0x3ac4, 0x6808, 0xa084, 0xff00, + 0x00c0, 0x3ac4, 0x0078, 0x3ac7, 0x0d7f, 0x00c0, 0x2bdb, 0x0d7f, + 0x6837, 0x0000, 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x0c7e, + 0x1078, 0x35e4, 0x00c0, 0x3ad7, 0x0c7f, 0x0078, 0x2bdb, 0x1078, + 0x9119, 0x2009, 0x0003, 0x0c7f, 0x0040, 0x2bd7, 0x7007, 0x0003, + 0x701b, 0x3ae3, 0x007c, 0x6830, 0xa086, 0x0100, 0x2009, 0x0004, + 0x0040, 0x2bd7, 0x0078, 0x2bad, 0x127e, 0x0c7e, 0x0e7e, 0x2061, + 0x0100, 0x2071, 0xa600, 0x6044, 0xd0a4, 0x00c0, 0x3b15, 0xd084, + 0x0040, 0x3afe, 0x1078, 0x3c75, 0x0078, 0x3b11, 0xd08c, 0x0040, + 0x3b05, 0x1078, 0x3b8c, 0x0078, 0x3b11, 0xd094, 0x0040, 0x3b0c, + 0x1078, 0x3b60, 0x0078, 0x3b11, 0xd09c, 0x0040, 0x3b11, 0x1078, + 0x3b1f, 0x0e7f, 0x0c7f, 0x127f, 0x007c, 0x017e, 0x6128, 0xd19c, + 0x00c0, 0x3b1c, 0xc19d, 0x612a, 0x017f, 0x0078, 0x3b11, 0x624c, + 0xa286, 0xf0f0, 0x00c0, 0x3b30, 0x6048, 0xa086, 0xf0f0, 0x0040, + 0x3b30, 0x624a, 0x6043, 0x0090, 0x6043, 0x0010, 0x0078, 0x3b5f, + 0xa294, 0xff00, 0xa296, 0xf700, 0x0040, 0x3b45, 0x7134, 0xd1a4, + 0x00c0, 0x3b45, 0x6240, 0xa294, 0x0010, 0x0040, 0x3b45, 0x2009, + 0x00f7, 0x1078, 0x42a1, 0x0078, 0x3b5f, 0x6043, 0x0040, 0x6043, + 0x0000, 0x7077, 0x0000, 0x708f, 0x0001, 0x70b3, 0x0000, 0x70cf, + 0x0000, 0x2009, 0xacc0, 0x200b, 0x0000, 0x7087, 0x0000, 0x707b, + 0x000f, 0x2009, 0x000f, 0x2011, 0x41d5, 0x1078, 0x5add, 0x007c, + 0x157e, 0x7078, 0xa005, 0x00c0, 0x3b8a, 0x2011, 0x41d5, 0x1078, + 0x5a45, 0x6040, 0xa094, 0x0010, 0xa285, 0x0020, 0x6042, 0x20a9, + 0x00c8, 0x6044, 0xd08c, 0x00c0, 0x3b83, 0x00f0, 0x3b71, 0x6242, + 0x708b, 0x0000, 0x6040, 0xa094, 0x0010, 0xa285, 0x0080, 0x6042, + 0x6242, 0x0078, 0x3b8a, 0x6242, 0x708b, 0x0000, 0x707f, 0x0000, + 0x0078, 0x3b8a, 0x157f, 0x007c, 0x707c, 0xa08a, 0x0003, 0x00c8, + 0x3b95, 0x1079, 0x3b98, 0x0078, 0x3b97, 0x1078, 0x1332, 0x007c, + 0x3b9b, 0x3bea, 0x3c74, 0x0f7e, 0x707f, 0x0001, 0x20e1, 0xa000, + 0x20e1, 0x8700, 0x1078, 0x21f7, 0x20e1, 0x9080, 0x20e1, 0x4000, + 0x2079, 0xab00, 0x207b, 0x2200, 0x7807, 0x00ef, 0x780b, 0x0000, + 0x780f, 0x00ef, 0x7813, 0x0138, 0x7817, 0x0000, 0x781b, 0x0000, + 0x781f, 0x0000, 0x7823, 0xffff, 0x7827, 0xffff, 0x782b, 0x0000, + 0x782f, 0x0000, 0x2079, 0xab0c, 0x207b, 0x1101, 0x7807, 0x0000, + 0x2099, 0xa605, 0x20a1, 0xab0e, 0x20a9, 0x0004, 0x53a3, 0x2079, + 0xab12, 0x207b, 0x0000, 0x7807, 0x0000, 0x2099, 0xab00, 0x20a1, + 0x020b, 0x20a9, 0x0014, 0x53a6, 0x60c3, 0x000c, 0x600f, 0x0000, + 0x1078, 0x420b, 0x0f7f, 0x7083, 0x0000, 0x6043, 0x0008, 0x6043, + 0x0000, 0x007c, 0x0d7e, 0x7080, 0x7083, 0x0000, 0xa025, 0x0040, + 0x3c5e, 0x6020, 0xd0b4, 0x00c0, 0x3c5c, 0x718c, 0x81ff, 0x0040, + 0x3c4b, 0xa486, 0x000c, 0x00c0, 0x3c56, 0xa480, 0x0018, 0x8004, + 0x20a8, 0x2011, 0xab80, 0x2019, 0xab00, 0x220c, 0x2304, 0xa106, + 0x00c0, 0x3c22, 0x8210, 0x8318, 0x00f0, 0x3c05, 0x6043, 0x0004, + 0x608b, 0xbc94, 0x608f, 0xf0f0, 0x6043, 0x0006, 0x707f, 0x0002, + 0x708b, 0x0002, 0x2009, 0x07d0, 0x2011, 0x41dc, 0x1078, 0x5add, + 0x0078, 0x3c5c, 0x2069, 0xab80, 0x6930, 0xa18e, 0x1101, 0x00c0, + 0x3c56, 0x6834, 0xa005, 0x00c0, 0x3c56, 0x6900, 0xa18c, 0x00ff, + 0x00c0, 0x3c36, 0x6804, 0xa005, 0x0040, 0x3c4b, 0x2011, 0xab8e, + 0x2019, 0xa605, 0x20a9, 0x0004, 0x220c, 0x2304, 0xa102, 0x0048, + 0x3c49, 0x00c0, 0x3c56, 0x8210, 0x8318, 0x00f0, 0x3c3c, 0x0078, + 0x3c56, 0x708f, 0x0000, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, + 0xab80, 0x20a1, 0x020b, 0x20a9, 0x0014, 0x53a6, 0x6043, 0x0008, + 0x6043, 0x0000, 0x0078, 0x3c5e, 0x0d7f, 0x007c, 0x6020, 0xd0b4, + 0x00c0, 0x3c5c, 0x60c3, 0x000c, 0x2011, 0xa8bb, 0x2013, 0x0000, + 0x7083, 0x0000, 0x20e1, 0x9080, 0x60a3, 0x0056, 0x60a7, 0x9575, + 0x1078, 0x6e06, 0x0078, 0x3c5c, 0x007c, 0x7088, 0xa08a, 0x001d, + 0x00c8, 0x3c7e, 0x1079, 0x3c81, 0x0078, 0x3c80, 0x1078, 0x1332, + 0x007c, 0x3cab, 0x3cba, 0x3ce9, 0x3d02, 0x3d2e, 0x3d5a, 0x3d86, + 0x3dbc, 0x3de8, 0x3e10, 0x3e53, 0x3e7d, 0x3e9f, 0x3eb5, 0x3edb, + 0x3eee, 0x3ef7, 0x3f2b, 0x3f57, 0x3f83, 0x3faf, 0x3fe5, 0x4030, + 0x405f, 0x4081, 0x40c3, 0x40e9, 0x4102, 0x4103, 0x0c7e, 0x2061, + 0xa600, 0x6003, 0x0007, 0x2061, 0x0100, 0x6004, 0xa084, 0xfff9, + 0x6006, 0x0c7f, 0x007c, 0x608b, 0xbc94, 0x608f, 0xf0f0, 0x6043, + 0x0002, 0x708b, 0x0001, 0x2009, 0x07d0, 0x2011, 0x41dc, 0x1078, + 0x5add, 0x007c, 0x0f7e, 0x7080, 0xa086, 0x0014, 0x00c0, 0x3ce7, + 0x6043, 0x0000, 0x6020, 0xd0b4, 0x00c0, 0x3ce7, 0x2079, 0xab80, + 0x7a30, 0xa296, 0x1102, 0x00c0, 0x3ce5, 0x7834, 0xa005, 0x00c0, + 0x3ce5, 0x7a38, 0xd2fc, 0x0040, 0x3cdb, 0x70b0, 0xa005, 0x00c0, + 0x3cdb, 0x70b3, 0x0001, 0x2011, 0x41dc, 0x1078, 0x5a45, 0x708b, + 0x0010, 0x1078, 0x3ef7, 0x0078, 0x3ce7, 0x1078, 0x4224, 0x0f7f, + 0x007c, 0x708b, 0x0003, 0x6043, 0x0004, 0x2011, 0x41dc, 0x1078, + 0x5a45, 0x1078, 0x4289, 0x20a3, 0x1102, 0x20a3, 0x0000, 0x20a9, + 0x000a, 0x20a3, 0x0000, 0x00f0, 0x3cf9, 0x60c3, 0x0014, 0x1078, + 0x420b, 0x007c, 0x0f7e, 0x7080, 0xa005, 0x0040, 0x3d2c, 0x2011, + 0x41dc, 0x1078, 0x5a45, 0xa086, 0x0014, 0x00c0, 0x3d2a, 0x2079, + 0xab80, 0x7a30, 0xa296, 0x1102, 0x00c0, 0x3d2a, 0x7834, 0xa005, + 0x00c0, 0x3d2a, 0x7a38, 0xd2fc, 0x0040, 0x3d24, 0x70b0, 0xa005, + 0x00c0, 0x3d24, 0x70b3, 0x0001, 0x708b, 0x0004, 0x1078, 0x3d2e, + 0x0078, 0x3d2c, 0x1078, 0x4224, 0x0f7f, 0x007c, 0x708b, 0x0005, + 0x1078, 0x4289, 0x20a3, 0x1103, 0x20a3, 0x0000, 0x3430, 0x2011, + 0xab8e, 0x1078, 0x42d4, 0x00c0, 0x3d4c, 0x7074, 0xa005, 0x00c0, + 0x3d4c, 0x7150, 0xa186, 0xffff, 0x0040, 0x3d4c, 0x1078, 0x419d, + 0x0040, 0x3d4c, 0x1078, 0x42b8, 0x20a9, 0x0008, 0x2298, 0x26a0, + 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, + 0x420b, 0x007c, 0x0f7e, 0x7080, 0xa005, 0x0040, 0x3d84, 0x2011, + 0x41dc, 0x1078, 0x5a45, 0xa086, 0x0014, 0x00c0, 0x3d82, 0x2079, + 0xab80, 0x7a30, 0xa296, 0x1103, 0x00c0, 0x3d82, 0x7834, 0xa005, + 0x00c0, 0x3d82, 0x7a38, 0xd2fc, 0x0040, 0x3d7c, 0x70b0, 0xa005, + 0x00c0, 0x3d7c, 0x70b3, 0x0001, 0x708b, 0x0006, 0x1078, 0x3d86, + 0x0078, 0x3d84, 0x1078, 0x4224, 0x0f7f, 0x007c, 0x708b, 0x0007, + 0x1078, 0x4289, 0x20a3, 0x1104, 0x20a3, 0x0000, 0x3430, 0x2011, + 0xab8e, 0x1078, 0x42d4, 0x00c0, 0x3dae, 0x7074, 0xa005, 0x00c0, + 0x3dae, 0x7154, 0xa186, 0xffff, 0x0040, 0x3dae, 0xa180, 0x29c0, + 0x200c, 0xa18c, 0xff00, 0x810f, 0x1078, 0x419d, 0x0040, 0x3dae, + 0x1078, 0x3820, 0x0040, 0x3dae, 0x1078, 0x256a, 0x20a9, 0x0008, + 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, + 0x0014, 0x1078, 0x420b, 0x007c, 0x0f7e, 0x7080, 0xa005, 0x0040, + 0x3de6, 0x2011, 0x41dc, 0x1078, 0x5a45, 0xa086, 0x0014, 0x00c0, + 0x3de4, 0x2079, 0xab80, 0x7a30, 0xa296, 0x1104, 0x00c0, 0x3de4, + 0x7834, 0xa005, 0x00c0, 0x3de4, 0x7a38, 0xd2fc, 0x0040, 0x3dde, + 0x70b0, 0xa005, 0x00c0, 0x3dde, 0x70b3, 0x0001, 0x708b, 0x0008, + 0x1078, 0x3de8, 0x0078, 0x3de6, 0x1078, 0x4224, 0x0f7f, 0x007c, + 0x708b, 0x0009, 0x1078, 0x4289, 0x20a3, 0x1105, 0x20a3, 0x0100, + 0x3430, 0x1078, 0x42d4, 0x00c0, 0x3e01, 0x7074, 0xa005, 0x00c0, + 0x3e01, 0x1078, 0x4104, 0x00c0, 0x3e0b, 0xa085, 0x0001, 0x1078, + 0x256a, 0x20a9, 0x0008, 0x2099, 0xab8e, 0x26a0, 0x53a6, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x420b, 0x007c, + 0x0f7e, 0x7080, 0xa005, 0x0040, 0x3e51, 0x2011, 0x41dc, 0x1078, + 0x5a45, 0xa086, 0x0014, 0x00c0, 0x3e4f, 0x2079, 0xab80, 0x7a30, + 0xa296, 0x1105, 0x00c0, 0x3e4f, 0x7834, 0x2011, 0x0100, 0xa21e, + 0x00c0, 0x3e3a, 0x7a38, 0xd2fc, 0x0040, 0x3e34, 0x70b0, 0xa005, + 0x00c0, 0x3e34, 0x70b3, 0x0001, 0x708b, 0x000a, 0x1078, 0x3e53, + 0x0078, 0x3e51, 0xa005, 0x00c0, 0x3e4f, 0x7a38, 0xd2fc, 0x0040, + 0x3e47, 0x70b0, 0xa005, 0x00c0, 0x3e47, 0x70b3, 0x0001, 0x7087, + 0x0000, 0x708b, 0x000e, 0x1078, 0x3edb, 0x0078, 0x3e51, 0x1078, + 0x4224, 0x0f7f, 0x007c, 0x708b, 0x000b, 0x2011, 0xab0e, 0x22a0, + 0x20a9, 0x0040, 0x2019, 0xffff, 0x43a4, 0x20a9, 0x0002, 0x2009, + 0x0000, 0x41a4, 0x1078, 0x4289, 0x20a3, 0x1106, 0x20a3, 0x0000, + 0x1078, 0x42d4, 0x0040, 0x3e70, 0x2013, 0x0000, 0x0078, 0x3e74, + 0x6030, 0xa085, 0x0100, 0x2012, 0x2298, 0x20a9, 0x0042, 0x53a6, + 0x60c3, 0x0084, 0x1078, 0x420b, 0x007c, 0x0f7e, 0x7080, 0xa005, + 0x0040, 0x3e9d, 0x2011, 0x41dc, 0x1078, 0x5a45, 0xa086, 0x0084, + 0x00c0, 0x3e9b, 0x2079, 0xab80, 0x7a30, 0xa296, 0x1106, 0x00c0, + 0x3e9b, 0x7834, 0xa005, 0x00c0, 0x3e9b, 0x708b, 0x000c, 0x1078, + 0x3e9f, 0x0078, 0x3e9d, 0x1078, 0x4224, 0x0f7f, 0x007c, 0x708b, + 0x000d, 0x1078, 0x4289, 0x20a3, 0x1107, 0x20a3, 0x0000, 0x2099, + 0xab8e, 0x20a9, 0x0040, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x60c3, 0x0084, 0x1078, 0x420b, 0x007c, 0x0f7e, 0x7080, 0xa005, + 0x0040, 0x3ed9, 0x2011, 0x41dc, 0x1078, 0x5a45, 0xa086, 0x0084, + 0x00c0, 0x3ed7, 0x2079, 0xab80, 0x7a30, 0xa296, 0x1107, 0x00c0, + 0x3ed7, 0x7834, 0xa005, 0x00c0, 0x3ed7, 0x7087, 0x0001, 0x1078, + 0x427b, 0x708b, 0x000e, 0x1078, 0x3edb, 0x0078, 0x3ed9, 0x1078, + 0x4224, 0x0f7f, 0x007c, 0x708b, 0x000f, 0x7083, 0x0000, 0x608b, + 0xbc85, 0x608f, 0xb5b5, 0x6043, 0x0005, 0x6043, 0x0004, 0x2009, + 0x07d0, 0x2011, 0x41dc, 0x1078, 0x5a38, 0x007c, 0x7080, 0xa005, + 0x0040, 0x3ef6, 0x2011, 0x41dc, 0x1078, 0x5a45, 0x007c, 0x708b, + 0x0011, 0x1078, 0x42d4, 0x00c0, 0x3f14, 0x716c, 0x81ff, 0x0040, + 0x3f14, 0x2009, 0x0000, 0x7070, 0xa084, 0x00ff, 0x1078, 0x254d, + 0xa186, 0x007e, 0x0040, 0x3f14, 0xa186, 0x0080, 0x0040, 0x3f14, + 0x2011, 0xab8e, 0x1078, 0x419d, 0x20e1, 0x9080, 0x20e1, 0x4000, + 0x2099, 0xab80, 0x20a1, 0x020b, 0x7480, 0xa480, 0x0018, 0xa080, + 0x0007, 0xa084, 0x03f8, 0x8004, 0x20a8, 0x53a6, 0x60c3, 0x0014, + 0x1078, 0x420b, 0x007c, 0x0f7e, 0x7080, 0xa005, 0x0040, 0x3f55, + 0x2011, 0x41dc, 0x1078, 0x5a45, 0xa086, 0x0014, 0x00c0, 0x3f53, + 0x2079, 0xab80, 0x7a30, 0xa296, 0x1103, 0x00c0, 0x3f53, 0x7834, + 0xa005, 0x00c0, 0x3f53, 0x7a38, 0xd2fc, 0x0040, 0x3f4d, 0x70b0, + 0xa005, 0x00c0, 0x3f4d, 0x70b3, 0x0001, 0x708b, 0x0012, 0x1078, + 0x3f57, 0x0078, 0x3f55, 0x1078, 0x4224, 0x0f7f, 0x007c, 0x708b, + 0x0013, 0x1078, 0x4295, 0x20a3, 0x1103, 0x20a3, 0x0000, 0x3430, + 0x2011, 0xab8e, 0x1078, 0x42d4, 0x00c0, 0x3f75, 0x7074, 0xa005, + 0x00c0, 0x3f75, 0x7150, 0xa186, 0xffff, 0x0040, 0x3f75, 0x1078, + 0x419d, 0x0040, 0x3f75, 0x1078, 0x42b8, 0x20a9, 0x0008, 0x2298, + 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, + 0x1078, 0x420b, 0x007c, 0x0f7e, 0x7080, 0xa005, 0x0040, 0x3fad, + 0x2011, 0x41dc, 0x1078, 0x5a45, 0xa086, 0x0014, 0x00c0, 0x3fab, + 0x2079, 0xab80, 0x7a30, 0xa296, 0x1104, 0x00c0, 0x3fab, 0x7834, + 0xa005, 0x00c0, 0x3fab, 0x7a38, 0xd2fc, 0x0040, 0x3fa5, 0x70b0, + 0xa005, 0x00c0, 0x3fa5, 0x70b3, 0x0001, 0x708b, 0x0014, 0x1078, + 0x3faf, 0x0078, 0x3fad, 0x1078, 0x4224, 0x0f7f, 0x007c, 0x708b, + 0x0015, 0x1078, 0x4295, 0x20a3, 0x1104, 0x20a3, 0x0000, 0x3430, + 0x2011, 0xab8e, 0x1078, 0x42d4, 0x00c0, 0x3fd7, 0x7074, 0xa005, + 0x00c0, 0x3fd7, 0x7154, 0xa186, 0xffff, 0x0040, 0x3fd7, 0xa180, + 0x29c0, 0x200c, 0xa18c, 0xff00, 0x810f, 0x1078, 0x419d, 0x0040, + 0x3fd7, 0x1078, 0x3820, 0x0040, 0x3fd7, 0x1078, 0x256a, 0x20a9, + 0x0008, 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x60c3, 0x0014, 0x1078, 0x420b, 0x007c, 0x0f7e, 0x7080, 0xa005, + 0x0040, 0x402e, 0x2011, 0x41dc, 0x1078, 0x5a45, 0xa086, 0x0014, + 0x00c0, 0x402c, 0x2079, 0xab80, 0x7a30, 0xa296, 0x1105, 0x00c0, + 0x402c, 0x7834, 0x2011, 0x0100, 0xa21e, 0x00c0, 0x400b, 0x7a38, + 0xd2fc, 0x0040, 0x4009, 0x70b0, 0xa005, 0x00c0, 0x4009, 0x70b3, + 0x0001, 0x0078, 0x401a, 0xa005, 0x00c0, 0x402c, 0x7a38, 0xd2fc, + 0x0040, 0x4018, 0x70b0, 0xa005, 0x00c0, 0x4018, 0x70b3, 0x0001, + 0x7087, 0x0000, 0x7a38, 0xd2f4, 0x0040, 0x4026, 0x2001, 0xa674, + 0x2004, 0xd0a4, 0x00c0, 0x4026, 0x70cf, 0x0008, 0x708b, 0x0016, + 0x1078, 0x4030, 0x0078, 0x402e, 0x1078, 0x4224, 0x0f7f, 0x007c, + 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0xab80, 0x20a1, 0x020b, + 0x20a9, 0x000e, 0x53a6, 0x3430, 0x2011, 0xab8e, 0x708b, 0x0017, + 0x1078, 0x42d4, 0x00c0, 0x4050, 0x7074, 0xa005, 0x00c0, 0x4050, + 0x1078, 0x4104, 0x00c0, 0x405a, 0xa085, 0x0001, 0x1078, 0x256a, + 0x20a9, 0x0008, 0x2099, 0xab8e, 0x26a0, 0x53a6, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x420b, 0x007c, 0x0f7e, + 0x7080, 0xa005, 0x0040, 0x407f, 0x2011, 0x41dc, 0x1078, 0x5a45, + 0xa086, 0x0084, 0x00c0, 0x407d, 0x2079, 0xab80, 0x7a30, 0xa296, + 0x1106, 0x00c0, 0x407d, 0x7834, 0xa005, 0x00c0, 0x407d, 0x708b, + 0x0018, 0x1078, 0x4081, 0x0078, 0x407f, 0x1078, 0x4224, 0x0f7f, + 0x007c, 0x708b, 0x0019, 0x1078, 0x4295, 0x20a3, 0x1106, 0x20a3, + 0x0000, 0x3430, 0x2099, 0xab8e, 0x2039, 0xab0e, 0x27a0, 0x20a9, + 0x0040, 0x53a3, 0x1078, 0x42d4, 0x00c0, 0x40b5, 0x2728, 0x2514, + 0x8207, 0xa084, 0x00ff, 0x8000, 0x2018, 0xa294, 0x00ff, 0x8007, + 0xa205, 0x202a, 0x6030, 0x2310, 0x8214, 0xa2a0, 0xab0e, 0x2414, + 0xa38c, 0x0001, 0x0040, 0x40b0, 0xa294, 0xff00, 0x0078, 0x40b3, + 0xa294, 0x00ff, 0x8007, 0xa215, 0x2222, 0x2798, 0x26a0, 0x20a9, + 0x0040, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0084, + 0x1078, 0x420b, 0x007c, 0x0f7e, 0x7080, 0xa005, 0x0040, 0x40e7, + 0x2011, 0x41dc, 0x1078, 0x5a45, 0xa086, 0x0084, 0x00c0, 0x40e5, + 0x2079, 0xab80, 0x7a30, 0xa296, 0x1107, 0x00c0, 0x40e5, 0x7834, + 0xa005, 0x00c0, 0x40e5, 0x7087, 0x0001, 0x1078, 0x427b, 0x708b, + 0x001a, 0x1078, 0x40e9, 0x0078, 0x40e7, 0x1078, 0x4224, 0x0f7f, + 0x007c, 0x708b, 0x001b, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, + 0xab80, 0x20a1, 0x020b, 0x7480, 0xa480, 0x0018, 0xa080, 0x0007, + 0xa084, 0x03f8, 0x8004, 0x20a8, 0x53a6, 0x60c3, 0x0084, 0x1078, + 0x420b, 0x007c, 0x007c, 0x007c, 0x087e, 0x097e, 0x2029, 0xa653, + 0x252c, 0x20a9, 0x0008, 0x2041, 0xab0e, 0x28a0, 0x2099, 0xab8e, + 0x53a3, 0x20a9, 0x0008, 0x2011, 0x0007, 0xd5d4, 0x0040, 0x411a, + 0x2011, 0x0000, 0x2800, 0xa200, 0x200c, 0xa1a6, 0xffff, 0x00c0, + 0x412c, 0xd5d4, 0x0040, 0x4127, 0x8210, 0x0078, 0x4128, 0x8211, + 0x00f0, 0x411a, 0x0078, 0x4194, 0x82ff, 0x00c0, 0x413e, 0xd5d4, + 0x0040, 0x4138, 0xa1a6, 0x3fff, 0x0040, 0x4124, 0x0078, 0x413c, + 0xa1a6, 0x3fff, 0x0040, 0x4194, 0xa18d, 0xc000, 0x20a9, 0x0010, + 0x2019, 0x0001, 0xd5d4, 0x0040, 0x4147, 0x2019, 0x0010, 0x2120, + 0xd5d4, 0x0040, 0x414e, 0x8423, 0x0078, 0x414f, 0x8424, 0x00c8, + 0x415c, 0xd5d4, 0x0040, 0x4157, 0x8319, 0x0078, 0x4158, 0x8318, + 0x00f0, 0x4148, 0x0078, 0x4194, 0x23a8, 0x2021, 0x0001, 0x8426, + 0x8425, 0x00f0, 0x4160, 0x2328, 0x8529, 0xa2be, 0x0007, 0x0040, + 0x4174, 0x007e, 0x2039, 0x0007, 0x2200, 0xa73a, 0x007f, 0x27a8, + 0xa5a8, 0x0010, 0x00f0, 0x4170, 0x7552, 0xa5c8, 0x29c0, 0x292c, + 0xa5ac, 0x00ff, 0x6532, 0x60e7, 0x0000, 0x65ea, 0x706f, 0x0000, + 0x7572, 0x2018, 0x2304, 0xa405, 0x201a, 0x7077, 0x0001, 0x26a0, + 0x2898, 0x20a9, 0x0008, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0xa085, 0x0001, 0x0078, 0x419a, 0xa006, 0x0078, 0x419a, 0xa006, + 0x1078, 0x1332, 0x097f, 0x087f, 0x007c, 0x2118, 0x2021, 0x0000, + 0x2001, 0x0007, 0xa39a, 0x0010, 0x0048, 0x41aa, 0x8420, 0x8001, + 0x0078, 0x41a2, 0x2118, 0x84ff, 0x0040, 0x41b3, 0xa39a, 0x0010, + 0x8421, 0x00c0, 0x41ae, 0x2021, 0x0001, 0x83ff, 0x0040, 0x41bc, + 0x8423, 0x8319, 0x00c0, 0x41b8, 0xa238, 0x2704, 0xa42c, 0x00c0, + 0x41d4, 0xa405, 0x203a, 0x7152, 0xa1a0, 0x29c0, 0x242c, 0xa5ac, + 0x00ff, 0x6532, 0x60e7, 0x0000, 0x65ea, 0x706f, 0x0000, 0x7572, + 0x7077, 0x0001, 0xa084, 0x0000, 0x007c, 0x0e7e, 0x2071, 0xa600, + 0x707b, 0x0000, 0x0e7f, 0x007c, 0x0e7e, 0x0f7e, 0x2001, 0x0002, + 0x1078, 0x5ae6, 0x2079, 0x0100, 0x2071, 0x0140, 0x1078, 0x6e0f, + 0x7004, 0xa084, 0x4000, 0x0040, 0x41f1, 0x7003, 0x1000, 0x7003, + 0x0000, 0x127e, 0x2091, 0x8000, 0x2071, 0xa622, 0x2073, 0x0000, + 0x7840, 0x027e, 0x017e, 0x2009, 0x00f7, 0x1078, 0x42a1, 0x017f, + 0xa094, 0x0010, 0xa285, 0x0080, 0x7842, 0x7a42, 0x027f, 0x127f, + 0x0f7f, 0x0e7f, 0x007c, 0x127e, 0x2091, 0x8000, 0x2011, 0xa8bb, + 0x2013, 0x0000, 0x7083, 0x0000, 0x127f, 0x20e1, 0x9080, 0x60a3, + 0x0056, 0x60a7, 0x9575, 0x1078, 0x6e06, 0x2009, 0x07d0, 0x2011, + 0x41dc, 0x1078, 0x5add, 0x007c, 0x017e, 0x027e, 0x0c7e, 0x127e, + 0x2091, 0x8000, 0x2011, 0x0003, 0x1078, 0x70e0, 0x2011, 0x0002, + 0x1078, 0x70ea, 0x1078, 0x6fc4, 0x037e, 0x2019, 0x0000, 0x1078, + 0x7058, 0x037f, 0x2009, 0x00f7, 0x1078, 0x42a1, 0x2061, 0xa8c4, + 0x601b, 0x0000, 0x601f, 0x0000, 0x2061, 0xa600, 0x6003, 0x0001, + 0x2061, 0x0100, 0x6043, 0x0090, 0x6043, 0x0010, 0x2009, 0x002d, + 0x2011, 0x4259, 0x1078, 0x5a38, 0x127f, 0x0c7f, 0x027f, 0x017f, + 0x007c, 0x0e7e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2001, 0x0001, + 0x1078, 0x5ae6, 0x2071, 0x0100, 0x1078, 0x6e0f, 0x2071, 0x0140, + 0x7004, 0xa084, 0x4000, 0x0040, 0x4271, 0x7003, 0x1000, 0x7003, + 0x0000, 0x2001, 0x0001, 0x1078, 0x24e8, 0x1078, 0x4224, 0x127f, + 0x007f, 0x0e7f, 0x007c, 0x20a9, 0x0040, 0x20a1, 0xacc0, 0x2099, + 0xab8e, 0x3304, 0x8007, 0x20a2, 0x9398, 0x94a0, 0x00f0, 0x4281, + 0x007c, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0xab00, 0x20a1, + 0x020b, 0x20a9, 0x000c, 0x53a6, 0x007c, 0x20e1, 0x9080, 0x20e1, + 0x4000, 0x2099, 0xab80, 0x20a1, 0x020b, 0x20a9, 0x000c, 0x53a6, + 0x007c, 0x0c7e, 0x007e, 0x2061, 0x0100, 0x810f, 0x2001, 0xa62f, + 0x2004, 0xa005, 0x00c0, 0x42b2, 0x6030, 0xa084, 0x00ff, 0xa105, + 0x0078, 0x42b4, 0xa185, 0x00f7, 0x604a, 0x007f, 0x0c7f, 0x007c, + 0x017e, 0x047e, 0x2001, 0xa653, 0x2004, 0xd0a4, 0x0040, 0x42cb, + 0xa006, 0x2020, 0x2009, 0x002a, 0x1078, 0xa21d, 0x2001, 0xa60c, + 0x200c, 0xc195, 0x2102, 0x2019, 0x002a, 0x2009, 0x0000, 0x1078, + 0x284f, 0x047f, 0x017f, 0x007c, 0x007e, 0x2001, 0xa60c, 0x2004, + 0xd09c, 0x0040, 0x42db, 0x007f, 0x007c, 0x007e, 0x017e, 0x127e, + 0x2091, 0x8000, 0x2001, 0x0101, 0x200c, 0xa18d, 0x0006, 0x2102, + 0x127f, 0x017f, 0x007f, 0x007c, 0x157e, 0x20a9, 0x00ff, 0x2009, + 0xa735, 0xa006, 0x200a, 0x8108, 0x00f0, 0x42f2, 0x157f, 0x007c, + 0x0d7e, 0x037e, 0x157e, 0x137e, 0x147e, 0x2069, 0xa652, 0xa006, + 0x6002, 0x6007, 0x0707, 0x600a, 0x600e, 0x6012, 0xa198, 0x29c0, + 0x231c, 0xa39c, 0x00ff, 0x6316, 0x20a9, 0x0004, 0xac98, 0x0006, + 0x23a0, 0x40a4, 0x20a9, 0x0004, 0xac98, 0x000a, 0x23a0, 0x40a4, + 0x603e, 0x6042, 0x604e, 0x6052, 0x6056, 0x605a, 0x605e, 0x6062, + 0x6066, 0x606a, 0x606e, 0x6072, 0x6076, 0x607a, 0x607e, 0x6082, + 0x6086, 0x608a, 0x608e, 0x6092, 0x6096, 0x609a, 0x609e, 0x60ae, + 0x61a2, 0x0d7e, 0x60a4, 0xa06d, 0x0040, 0x4338, 0x1078, 0x13a4, + 0x60a7, 0x0000, 0x60a8, 0xa06d, 0x0040, 0x4340, 0x1078, 0x13a4, + 0x60ab, 0x0000, 0x0d7f, 0xa006, 0x604a, 0x6810, 0x603a, 0x680c, + 0x6046, 0x6814, 0xa084, 0x00ff, 0x6042, 0x147f, 0x137f, 0x157f, + 0x037f, 0x0d7f, 0x007c, 0x127e, 0x2091, 0x8000, 0x6944, 0x6e48, + 0xa684, 0x3fff, 0xa082, 0x4000, 0x00c8, 0x4424, 0xa18c, 0xff00, + 0x810f, 0xa182, 0x00ff, 0x00c8, 0x442a, 0x2001, 0xa60c, 0x2004, + 0xa084, 0x0003, 0x0040, 0x4385, 0x2001, 0xa60c, 0x2004, 0xd084, + 0x00c0, 0x4405, 0xa188, 0xa735, 0x2104, 0xa065, 0x0040, 0x4405, + 0x6004, 0xa084, 0x00ff, 0xa08e, 0x0006, 0x00c0, 0x4405, 0x6000, + 0xd0c4, 0x0040, 0x4405, 0x0078, 0x4392, 0xa188, 0xa735, 0x2104, + 0xa065, 0x0040, 0x43e9, 0x6004, 0xa084, 0x00ff, 0xa08e, 0x0006, + 0x00c0, 0x43ef, 0x60a4, 0xa00d, 0x0040, 0x439a, 0x1078, 0x4817, + 0x0040, 0x43e3, 0x60a8, 0xa00d, 0x0040, 0x43b4, 0x1078, 0x486a, + 0x00c0, 0x43b4, 0x694c, 0xd1fc, 0x00c0, 0x43aa, 0x1078, 0x44df, + 0x0078, 0x43de, 0x1078, 0x4484, 0x694c, 0xd1ec, 0x00c0, 0x43de, + 0x1078, 0x46d6, 0x0078, 0x43de, 0x694c, 0xa184, 0xa000, 0x0040, + 0x43ce, 0xd1ec, 0x0040, 0x43c7, 0xd1fc, 0x0040, 0x43c3, 0x1078, + 0x46e7, 0x0078, 0x43ca, 0x1078, 0x46e7, 0x0078, 0x43ce, 0xd1fc, + 0x0040, 0x43ce, 0x1078, 0x4484, 0x0078, 0x43de, 0x6050, 0xa00d, + 0x0040, 0x43d9, 0x2d00, 0x200a, 0x6803, 0x0000, 0x6052, 0x0078, + 0x43de, 0x2d00, 0x6052, 0x604e, 0x6803, 0x0000, 0x1078, 0x5da9, + 0xa006, 0x127f, 0x007c, 0x2001, 0x0005, 0x2009, 0x0000, 0x0078, + 0x442e, 0x2001, 0x0028, 0x2009, 0x0000, 0x0078, 0x442e, 0xa082, + 0x0006, 0x00c8, 0x4405, 0x60a0, 0xd0bc, 0x00c0, 0x4401, 0x6100, + 0xd1fc, 0x0040, 0x4392, 0x2001, 0x0029, 0x2009, 0x1000, 0x0078, + 0x442e, 0x2001, 0x0028, 0x0078, 0x4420, 0x2009, 0xa60c, 0x210c, + 0xd18c, 0x0040, 0x440f, 0x2001, 0x0004, 0x0078, 0x4420, 0xd184, + 0x0040, 0x4416, 0x2001, 0x0004, 0x0078, 0x4420, 0x2001, 0x0029, + 0x6100, 0xd1fc, 0x0040, 0x4420, 0x2009, 0x1000, 0x0078, 0x442e, + 0x2009, 0x0000, 0x0078, 0x442e, 0x2001, 0x0029, 0x2009, 0x0000, + 0x0078, 0x442e, 0x2001, 0x0029, 0x2009, 0x0000, 0xa005, 0x127f, + 0x007c, 0x6944, 0x6e48, 0xa684, 0x3fff, 0xa082, 0x4000, 0x00c8, + 0x447e, 0xa18c, 0xff00, 0x810f, 0xa182, 0x00ff, 0x00c8, 0x4464, + 0xa188, 0xa735, 0x2104, 0xa065, 0x0040, 0x4464, 0x6004, 0xa084, + 0x00ff, 0xa08e, 0x0006, 0x00c0, 0x446a, 0x684c, 0xd0ec, 0x0040, + 0x4457, 0x1078, 0x46e7, 0x1078, 0x4484, 0x0078, 0x445f, 0x1078, + 0x4484, 0x684c, 0xd0fc, 0x0040, 0x445f, 0x1078, 0x46d6, 0x1078, + 0x472f, 0xa006, 0x0078, 0x4482, 0x2001, 0x0028, 0x2009, 0x0000, + 0x0078, 0x4482, 0xa082, 0x0006, 0x00c8, 0x4478, 0x6100, 0xd1fc, + 0x0040, 0x444d, 0x2001, 0x0029, 0x2009, 0x1000, 0x0078, 0x4482, + 0x2001, 0x0029, 0x2009, 0x0000, 0x0078, 0x4482, 0x2001, 0x0029, + 0x2009, 0x0000, 0xa005, 0x007c, 0x127e, 0x2091, 0x8000, 0x6050, + 0xa00d, 0x0040, 0x4492, 0x2d00, 0x200a, 0x6803, 0x0000, 0x6052, + 0x127f, 0x007c, 0x2d00, 0x6052, 0x604e, 0x6803, 0x0000, 0x0078, + 0x4490, 0x127e, 0x2091, 0x8000, 0x604c, 0xa005, 0x0040, 0x44af, + 0x0e7e, 0x2071, 0xa8b1, 0x7004, 0xa086, 0x0002, 0x0040, 0x44b6, + 0x0e7f, 0x604c, 0x6802, 0x2d00, 0x604e, 0x127f, 0x007c, 0x2d00, + 0x6052, 0x604e, 0x6803, 0x0000, 0x0078, 0x44ad, 0x701c, 0xac06, + 0x00c0, 0x44a8, 0x604c, 0x2070, 0x7000, 0x6802, 0x2d00, 0x7002, + 0x0e7f, 0x127f, 0x007c, 0x127e, 0x2091, 0x8000, 0x604c, 0xa06d, + 0x0040, 0x44d1, 0x6800, 0xa005, 0x00c0, 0x44cf, 0x6052, 0x604e, + 0xad05, 0x127f, 0x007c, 0x604c, 0xa06d, 0x0040, 0x44de, 0x6800, + 0xa005, 0x00c0, 0x44dc, 0x6052, 0x604e, 0xad05, 0x007c, 0x6803, + 0x0000, 0x6084, 0xa00d, 0x0040, 0x44e9, 0x2d00, 0x200a, 0x6086, + 0x007c, 0x2d00, 0x6086, 0x6082, 0x0078, 0x44e8, 0x127e, 0x0c7e, + 0x027e, 0x2091, 0x8000, 0x6218, 0x2260, 0x6200, 0xa005, 0x0040, + 0x44fc, 0xc285, 0x0078, 0x44fd, 0xc284, 0x6202, 0x027f, 0x0c7f, + 0x127f, 0x007c, 0x127e, 0x0c7e, 0x2091, 0x8000, 0x6218, 0x2260, + 0x6204, 0x007e, 0xa086, 0x0006, 0x00c0, 0x4521, 0x609c, 0xd0ac, + 0x0040, 0x4521, 0x2001, 0xa653, 0x2004, 0xd0a4, 0x0040, 0x4521, + 0xa284, 0xff00, 0x8007, 0xa086, 0x0007, 0x00c0, 0x4521, 0x2011, + 0x0600, 0x007f, 0xa294, 0xff00, 0xa215, 0x6206, 0x007e, 0xa086, + 0x0006, 0x00c0, 0x4531, 0x6290, 0x82ff, 0x00c0, 0x4531, 0x1078, + 0x1332, 0x007f, 0x0c7f, 0x127f, 0x007c, 0x127e, 0x0c7e, 0x2091, + 0x8000, 0x6218, 0x2260, 0x6204, 0x007e, 0xa086, 0x0006, 0x00c0, + 0x4553, 0x609c, 0xd0a4, 0x0040, 0x4553, 0x2001, 0xa653, 0x2004, + 0xd0ac, 0x00c0, 0x4553, 0xa284, 0x00ff, 0xa086, 0x0007, 0x00c0, + 0x4553, 0x2011, 0x0006, 0x007f, 0xa294, 0x00ff, 0x8007, 0xa215, + 0x6206, 0x0c7f, 0x127f, 0x007c, 0x027e, 0xa182, 0x00ff, 0x0048, + 0x4565, 0xa085, 0x0001, 0x0078, 0x457d, 0xa190, 0xa735, 0x2204, + 0xa065, 0x00c0, 0x457c, 0x017e, 0x0d7e, 0x1078, 0x1370, 0x2d60, + 0x0d7f, 0x017f, 0x0040, 0x4561, 0x2c00, 0x2012, 0x60a7, 0x0000, + 0x60ab, 0x0000, 0x1078, 0x42f8, 0xa006, 0x027f, 0x007c, 0x127e, + 0x2091, 0x8000, 0x027e, 0xa182, 0x00ff, 0x0048, 0x458b, 0xa085, + 0x0001, 0x0078, 0x45c1, 0x0d7e, 0xa190, 0xa735, 0x2204, 0xa06d, + 0x0040, 0x45bf, 0x2013, 0x0000, 0x0d7e, 0x0c7e, 0x2d60, 0x60a4, + 0xa06d, 0x0040, 0x459d, 0x1078, 0x13a4, 0x60a8, 0xa06d, 0x0040, + 0x45a3, 0x1078, 0x13a4, 0x0c7f, 0x0d7f, 0x0d7e, 0x0c7e, 0x68ac, + 0x2060, 0x8cff, 0x0040, 0x45bb, 0x600c, 0x007e, 0x6010, 0x2068, + 0x1078, 0x8d06, 0x0040, 0x45b6, 0x1078, 0x13b4, 0x1078, 0x772d, + 0x0c7f, 0x0078, 0x45a9, 0x0c7f, 0x0d7f, 0x1078, 0x13a4, 0x0d7f, + 0xa006, 0x027f, 0x127f, 0x007c, 0x017e, 0xa182, 0x00ff, 0x0048, + 0x45cd, 0xa085, 0x0001, 0x0078, 0x45d4, 0xa188, 0xa735, 0x2104, + 0xa065, 0x0040, 0x45c9, 0xa006, 0x017f, 0x007c, 0x0d7e, 0x157e, + 0x137e, 0x147e, 0x600b, 0x0000, 0x600f, 0x0000, 0x6000, 0xc08c, + 0x6002, 0x2069, 0xab8e, 0x6808, 0x605e, 0x6810, 0x6062, 0x6138, + 0xa10a, 0x0048, 0x45ec, 0x603a, 0x6814, 0x6066, 0x2099, 0xab96, + 0xac88, 0x000a, 0x21a0, 0x20a9, 0x0004, 0x53a3, 0x2099, 0xab9a, + 0xac88, 0x0006, 0x21a0, 0x20a9, 0x0004, 0x53a3, 0x2069, 0xabae, + 0x6808, 0x606a, 0x690c, 0x616e, 0x6810, 0x6072, 0x6818, 0x6076, + 0x60a0, 0xa086, 0x007e, 0x00c0, 0x4611, 0x2069, 0xab8e, 0x690c, + 0x616e, 0xa182, 0x0211, 0x00c8, 0x4619, 0x2009, 0x0008, 0x0078, + 0x4643, 0xa182, 0x0259, 0x00c8, 0x4621, 0x2009, 0x0007, 0x0078, + 0x4643, 0xa182, 0x02c1, 0x00c8, 0x4629, 0x2009, 0x0006, 0x0078, + 0x4643, 0xa182, 0x0349, 0x00c8, 0x4631, 0x2009, 0x0005, 0x0078, + 0x4643, 0xa182, 0x0421, 0x00c8, 0x4639, 0x2009, 0x0004, 0x0078, + 0x4643, 0xa182, 0x0581, 0x00c8, 0x4641, 0x2009, 0x0003, 0x0078, + 0x4643, 0x2009, 0x0002, 0x6192, 0x147f, 0x137f, 0x157f, 0x0d7f, + 0x007c, 0x017e, 0x027e, 0x0e7e, 0x2071, 0xab8d, 0x2e04, 0x6896, + 0x2071, 0xab8e, 0x7004, 0x689a, 0x701c, 0x689e, 0x6a00, 0x2009, + 0xa672, 0x210c, 0xd0bc, 0x0040, 0x4663, 0xd1ec, 0x0040, 0x4663, + 0xc2ad, 0x0078, 0x4664, 0xc2ac, 0xd0c4, 0x0040, 0x466d, 0xd1e4, + 0x0040, 0x466d, 0xc2bd, 0x0078, 0x466e, 0xc2bc, 0x6a02, 0x0e7f, + 0x027f, 0x017f, 0x007c, 0x0d7e, 0x127e, 0x2091, 0x8000, 0x60a4, + 0xa06d, 0x0040, 0x4697, 0x6900, 0x81ff, 0x00c0, 0x46ab, 0x6a04, + 0xa282, 0x0010, 0x00c8, 0x46b0, 0xad88, 0x0004, 0x20a9, 0x0010, + 0x2104, 0xa086, 0xffff, 0x0040, 0x4692, 0x8108, 0x00f0, 0x4688, + 0x1078, 0x1332, 0x260a, 0x8210, 0x6a06, 0x0078, 0x46ab, 0x1078, + 0x138b, 0x0040, 0x46b0, 0x2d00, 0x60a6, 0x6803, 0x0000, 0xad88, + 0x0004, 0x20a9, 0x0010, 0x200b, 0xffff, 0x8108, 0x00f0, 0x46a3, + 0x6807, 0x0001, 0x6e12, 0xa085, 0x0001, 0x127f, 0x0d7f, 0x007c, + 0xa006, 0x0078, 0x46ad, 0x127e, 0x2091, 0x8000, 0x0d7e, 0x60a4, + 0xa00d, 0x0040, 0x46d3, 0x2168, 0x6800, 0xa005, 0x00c0, 0x46cf, + 0x1078, 0x4817, 0x00c0, 0x46d3, 0x200b, 0xffff, 0x6804, 0xa08a, + 0x0002, 0x0048, 0x46cf, 0x8001, 0x6806, 0x0078, 0x46d3, 0x1078, + 0x13a4, 0x60a7, 0x0000, 0x0d7f, 0x127f, 0x007c, 0x127e, 0x2091, + 0x8000, 0x1078, 0x487f, 0x0078, 0x46df, 0x1078, 0x4484, 0x1078, + 0x4775, 0x00c0, 0x46dd, 0x1078, 0x472f, 0x127f, 0x007c, 0x0d7e, + 0x127e, 0x2091, 0x8000, 0x60a8, 0xa06d, 0x0040, 0x470b, 0x6950, + 0x81ff, 0x00c0, 0x471f, 0x6a54, 0xa282, 0x0010, 0x00c8, 0x472c, + 0xad88, 0x0018, 0x20a9, 0x0010, 0x2104, 0xa086, 0xffff, 0x0040, + 0x4706, 0x8108, 0x00f0, 0x46fc, 0x1078, 0x1332, 0x260a, 0x8210, + 0x6a56, 0x0078, 0x471f, 0x1078, 0x138b, 0x0040, 0x472c, 0x2d00, + 0x60aa, 0x6853, 0x0000, 0xad88, 0x0018, 0x20a9, 0x0010, 0x200b, + 0xffff, 0x8108, 0x00f0, 0x4717, 0x6857, 0x0001, 0x6e62, 0x0078, + 0x4723, 0x1078, 0x44df, 0x1078, 0x4739, 0x00c0, 0x4721, 0xa085, + 0x0001, 0x127f, 0x0d7f, 0x007c, 0xa006, 0x0078, 0x4729, 0x127e, + 0x2091, 0x8000, 0x1078, 0x5da9, 0x127f, 0x007c, 0xa01e, 0x0078, + 0x473b, 0x2019, 0x0001, 0xa00e, 0x127e, 0x2091, 0x8000, 0x604c, + 0x2068, 0x6000, 0xd0dc, 0x00c0, 0x4759, 0x8dff, 0x0040, 0x4770, + 0x83ff, 0x0040, 0x4751, 0x6848, 0xa606, 0x0040, 0x475e, 0x0078, + 0x4759, 0x683c, 0xa406, 0x00c0, 0x4759, 0x6840, 0xa506, 0x0040, + 0x475e, 0x2d08, 0x6800, 0x2068, 0x0078, 0x4745, 0x1078, 0x7233, + 0x6a00, 0x604c, 0xad06, 0x00c0, 0x4768, 0x624e, 0x0078, 0x476b, + 0xa180, 0x0000, 0x2202, 0x82ff, 0x00c0, 0x4770, 0x6152, 0x8dff, + 0x127f, 0x007c, 0xa01e, 0x0078, 0x4777, 0x2019, 0x0001, 0xa00e, + 0x6080, 0x2068, 0x8dff, 0x0040, 0x47a3, 0x83ff, 0x0040, 0x4786, + 0x6848, 0xa606, 0x0040, 0x4793, 0x0078, 0x478e, 0x683c, 0xa406, + 0x00c0, 0x478e, 0x6840, 0xa506, 0x0040, 0x4793, 0x2d08, 0x6800, + 0x2068, 0x0078, 0x477a, 0x6a00, 0x6080, 0xad06, 0x00c0, 0x479b, + 0x6282, 0x0078, 0x479e, 0xa180, 0x0000, 0x2202, 0x82ff, 0x00c0, + 0x47a3, 0x6186, 0x8dff, 0x007c, 0xa016, 0x1078, 0x4810, 0x00c0, + 0x47ab, 0x2011, 0x0001, 0x1078, 0x4863, 0x00c0, 0x47b1, 0xa295, + 0x0002, 0x007c, 0x1078, 0x489b, 0x0040, 0x47ba, 0x1078, 0x8dca, + 0x0078, 0x47bc, 0xa085, 0x0001, 0x007c, 0x1078, 0x489b, 0x0040, + 0x47c5, 0x1078, 0x8d62, 0x0078, 0x47c7, 0xa085, 0x0001, 0x007c, + 0x1078, 0x489b, 0x0040, 0x47d0, 0x1078, 0x8dac, 0x0078, 0x47d2, + 0xa085, 0x0001, 0x007c, 0x1078, 0x489b, 0x0040, 0x47db, 0x1078, + 0x8d7e, 0x0078, 0x47dd, 0xa085, 0x0001, 0x007c, 0x1078, 0x489b, + 0x0040, 0x47e6, 0x1078, 0x8de8, 0x0078, 0x47e8, 0xa085, 0x0001, + 0x007c, 0x127e, 0x007e, 0x0d7e, 0x2091, 0x8000, 0x6080, 0xa06d, + 0x0040, 0x4808, 0x6800, 0x007e, 0x6837, 0x0103, 0x6b4a, 0x6847, + 0x0000, 0x1078, 0x8f7d, 0x007e, 0x6000, 0xd0fc, 0x0040, 0x4802, + 0x1078, 0xa4ed, 0x007f, 0x1078, 0x4a73, 0x007f, 0x0078, 0x47ef, + 0x6083, 0x0000, 0x6087, 0x0000, 0x0d7f, 0x007f, 0x127f, 0x007c, + 0x60a4, 0xa00d, 0x00c0, 0x4817, 0xa085, 0x0001, 0x007c, 0x0e7e, + 0x2170, 0x7000, 0xa005, 0x00c0, 0x482c, 0x20a9, 0x0010, 0xae88, + 0x0004, 0x2104, 0xa606, 0x0040, 0x482c, 0x8108, 0x00f0, 0x4821, + 0xa085, 0x0001, 0x0078, 0x482d, 0xa006, 0x0e7f, 0x007c, 0x0d7e, + 0x127e, 0x2091, 0x8000, 0x60a4, 0xa06d, 0x00c0, 0x483d, 0x1078, + 0x138b, 0x0040, 0x484f, 0x2d00, 0x60a6, 0x6803, 0x0001, 0x6807, + 0x0000, 0xad88, 0x0004, 0x20a9, 0x0010, 0x200b, 0xffff, 0x8108, + 0x00f0, 0x4845, 0xa085, 0x0001, 0x127f, 0x0d7f, 0x007c, 0xa006, + 0x0078, 0x484c, 0x0d7e, 0x127e, 0x2091, 0x8000, 0x60a4, 0xa06d, + 0x0040, 0x4860, 0x60a7, 0x0000, 0x1078, 0x13a4, 0xa085, 0x0001, + 0x127f, 0x0d7f, 0x007c, 0x60a8, 0xa00d, 0x00c0, 0x486a, 0xa085, + 0x0001, 0x007c, 0x0e7e, 0x2170, 0x7050, 0xa005, 0x00c0, 0x487d, + 0x20a9, 0x0010, 0xae88, 0x0018, 0x2104, 0xa606, 0x0040, 0x487d, + 0x8108, 0x00f0, 0x4874, 0xa085, 0x0001, 0x0e7f, 0x007c, 0x127e, + 0x2091, 0x8000, 0x1078, 0x4863, 0x00c0, 0x4899, 0x200b, 0xffff, + 0x0d7e, 0x60a8, 0x2068, 0x6854, 0xa08a, 0x0002, 0x0048, 0x4894, + 0x8001, 0x6856, 0x0078, 0x4898, 0x1078, 0x13a4, 0x60ab, 0x0000, + 0x0d7f, 0x127f, 0x007c, 0x609c, 0xd0a4, 0x007c, 0x0f7e, 0x71b0, + 0x81ff, 0x00c0, 0x48b9, 0x71cc, 0xd19c, 0x0040, 0x48b9, 0x2001, + 0x007e, 0xa080, 0xa735, 0x2004, 0xa07d, 0x0040, 0x48b9, 0x7804, + 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x48b9, 0x7800, 0xc0ed, + 0x7802, 0x2079, 0xa652, 0x7804, 0xd0a4, 0x0040, 0x48df, 0x157e, + 0x0c7e, 0x20a9, 0x007f, 0x2009, 0x0000, 0x017e, 0x1078, 0x45c4, + 0x00c0, 0x48d9, 0x6004, 0xa084, 0xff00, 0x8007, 0xa096, 0x0004, + 0x0040, 0x48d6, 0xa086, 0x0006, 0x00c0, 0x48d9, 0x6000, 0xc0ed, + 0x6002, 0x017f, 0x8108, 0x00f0, 0x48c5, 0x0c7f, 0x157f, 0x1078, + 0x4967, 0x0040, 0x48e8, 0x2001, 0xa8a1, 0x200c, 0x0078, 0x48f0, + 0x2079, 0xa652, 0x7804, 0xd0a4, 0x0040, 0x48f4, 0x2009, 0x07d0, + 0x2011, 0x48f6, 0x1078, 0x5add, 0x0f7f, 0x007c, 0x2011, 0x48f6, + 0x1078, 0x5a45, 0x1078, 0x4967, 0x0040, 0x491e, 0x2001, 0xa7b3, + 0x2004, 0xa080, 0x0000, 0x200c, 0xc1ec, 0x2102, 0x2001, 0xa653, + 0x2004, 0xd0a4, 0x0040, 0x4912, 0x2009, 0x07d0, 0x2011, 0x48f6, + 0x1078, 0x5add, 0x0e7e, 0x2071, 0xa600, 0x706f, 0x0000, 0x7073, + 0x0000, 0x1078, 0x2677, 0x0e7f, 0x0078, 0x4956, 0x157e, 0x0c7e, + 0x20a9, 0x007f, 0x2009, 0x0000, 0x017e, 0x1078, 0x45c4, 0x00c0, + 0x4950, 0x6000, 0xd0ec, 0x0040, 0x4950, 0x047e, 0x62a0, 0xa294, + 0x00ff, 0x8227, 0xa006, 0x2009, 0x0029, 0x1078, 0xa21d, 0x6000, + 0xc0e5, 0xc0ec, 0x6002, 0x6004, 0xa084, 0x00ff, 0xa085, 0x0700, + 0x6006, 0x2019, 0x0029, 0x1078, 0x5f01, 0x077e, 0x2039, 0x0000, + 0x1078, 0x5e0a, 0x2009, 0x0000, 0x1078, 0x9f8b, 0x077f, 0x047f, + 0x017f, 0x8108, 0x00f0, 0x4924, 0x0c7f, 0x157f, 0x007c, 0x0c7e, + 0x6018, 0x2060, 0x6000, 0xc0ec, 0x6002, 0x0c7f, 0x007c, 0x7818, + 0x2004, 0xd0ac, 0x007c, 0x7818, 0x2004, 0xd0bc, 0x007c, 0x0f7e, + 0x2001, 0xa7b3, 0x2004, 0xa07d, 0x0040, 0x4970, 0x7800, 0xd0ec, + 0x0f7f, 0x007c, 0x127e, 0x027e, 0x2091, 0x8000, 0x007e, 0x62a0, + 0xa290, 0xa735, 0x2204, 0xac06, 0x10c0, 0x1332, 0x007f, 0x6200, + 0xa005, 0x0040, 0x4986, 0xc2fd, 0x0078, 0x4987, 0xc2fc, 0x6202, + 0x027f, 0x127f, 0x007c, 0x2011, 0xa633, 0x2204, 0xd0cc, 0x0040, + 0x4998, 0x2001, 0xa89f, 0x200c, 0x2011, 0x4999, 0x1078, 0x5add, + 0x007c, 0x2011, 0x4999, 0x1078, 0x5a45, 0x2011, 0xa633, 0x2204, + 0xc0cc, 0x2012, 0x007c, 0x2071, 0xa714, 0x7003, 0x0001, 0x7007, + 0x0000, 0x7013, 0x0000, 0x7017, 0x0000, 0x701b, 0x0000, 0x701f, + 0x0000, 0x700b, 0x0000, 0x704b, 0x0001, 0x704f, 0x0000, 0x705b, + 0x0020, 0x705f, 0x0040, 0x707f, 0x0000, 0x2071, 0xa87d, 0x7003, + 0xa714, 0x7007, 0x0000, 0x700b, 0x0000, 0x700f, 0xa85d, 0x7013, + 0x0020, 0x7017, 0x0040, 0x7037, 0x0000, 0x007c, 0x017e, 0x0e7e, + 0x2071, 0xa835, 0xa00e, 0x7186, 0x718a, 0x7097, 0x0001, 0x2001, + 0xa653, 0x2004, 0xd0fc, 0x00c0, 0x49e8, 0x2001, 0xa653, 0x2004, + 0xa00e, 0xd09c, 0x0040, 0x49e5, 0x8108, 0x7102, 0x0078, 0x4a3b, + 0x2001, 0xa672, 0x200c, 0xa184, 0x000f, 0x2009, 0xa673, 0x210c, + 0x0079, 0x49f2, 0x49dd, 0x4a13, 0x4a1b, 0x4a26, 0x4a2c, 0x49dd, + 0x49dd, 0x49dd, 0x4a02, 0x49dd, 0x49dd, 0x49dd, 0x49dd, 0x49dd, + 0x49dd, 0x49dd, 0x7003, 0x0004, 0x137e, 0x147e, 0x157e, 0x2099, + 0xa676, 0x20a1, 0xa886, 0x20a9, 0x0004, 0x53a3, 0x157f, 0x147f, + 0x137f, 0x0078, 0x4a3b, 0x708f, 0x0005, 0x7007, 0x0122, 0x2001, + 0x0002, 0x0078, 0x4a21, 0x708f, 0x0002, 0x7007, 0x0121, 0x2001, + 0x0003, 0x7002, 0x7097, 0x0001, 0x0078, 0x4a38, 0x7007, 0x0122, + 0x2001, 0x0002, 0x0078, 0x4a30, 0x7007, 0x0121, 0x2001, 0x0003, + 0x7002, 0xa006, 0x7096, 0x708e, 0xa184, 0xff00, 0x8007, 0x709a, + 0xa184, 0x00ff, 0x7092, 0x0e7f, 0x017f, 0x007c, 0x0e7e, 0x2071, + 0xa714, 0x684c, 0xa005, 0x00c0, 0x4a4c, 0x7028, 0xc085, 0x702a, + 0xa085, 0x0001, 0x0078, 0x4a71, 0x6a60, 0x7236, 0x6b64, 0x733a, + 0x6868, 0x703e, 0x7076, 0x686c, 0x7042, 0x707a, 0x684c, 0x702e, + 0x6844, 0x7032, 0x2009, 0x000d, 0x200a, 0x700b, 0x0000, 0x8007, + 0x8006, 0x8006, 0xa08c, 0x003f, 0xa084, 0xffc0, 0xa210, 0x2100, + 0xa319, 0x726e, 0x7372, 0x7028, 0xc084, 0x702a, 0x7007, 0x0001, + 0xa006, 0x0e7f, 0x007c, 0x0e7e, 0x027e, 0x6838, 0xd0fc, 0x00c0, + 0x4ac9, 0x6804, 0xa00d, 0x0040, 0x4a8f, 0x0d7e, 0x2071, 0xa600, + 0xa016, 0x702c, 0x2168, 0x6904, 0x206a, 0x8210, 0x2d00, 0x81ff, + 0x00c0, 0x4a82, 0x702e, 0x70ac, 0xa200, 0x70ae, 0x0d7f, 0x2071, + 0xa714, 0x701c, 0xa005, 0x00c0, 0x4adb, 0x0068, 0x4ad9, 0x2071, + 0xa835, 0x7200, 0x82ff, 0x0040, 0x4ad9, 0x6934, 0xa186, 0x0103, + 0x00c0, 0x4aec, 0x6948, 0x6844, 0xa105, 0x00c0, 0x4acc, 0x2009, + 0x8020, 0x2200, 0x0079, 0x4aac, 0x4ad9, 0x4ab1, 0x4b09, 0x4b17, + 0x4ad9, 0x2071, 0x0000, 0x7018, 0xd084, 0x00c0, 0x4ad9, 0x7122, + 0x683c, 0x7026, 0x6840, 0x702a, 0x701b, 0x0001, 0x2091, 0x4080, + 0x2071, 0xa600, 0x702c, 0x206a, 0x2d00, 0x702e, 0x70ac, 0x8000, + 0x70ae, 0x027f, 0x0e7f, 0x007c, 0x6844, 0xa086, 0x0100, 0x00c0, + 0x4ad9, 0x6868, 0xa005, 0x00c0, 0x4ad9, 0x2009, 0x8020, 0x0078, + 0x4aa9, 0x2071, 0xa714, 0x2d08, 0x206b, 0x0000, 0x7010, 0x8000, + 0x7012, 0x7018, 0xa06d, 0x711a, 0x0040, 0x4ae9, 0x6902, 0x0078, + 0x4aea, 0x711e, 0x0078, 0x4ac9, 0xa18c, 0x00ff, 0xa186, 0x0017, + 0x0040, 0x4afa, 0xa186, 0x001e, 0x0040, 0x4afa, 0xa18e, 0x001f, + 0x00c0, 0x4ad9, 0x684c, 0xd0cc, 0x0040, 0x4ad9, 0x6850, 0xa084, + 0x00ff, 0xa086, 0x0001, 0x00c0, 0x4ad9, 0x2009, 0x8021, 0x0078, + 0x4aa9, 0x7084, 0x8008, 0xa092, 0x001e, 0x00c8, 0x4ad9, 0x7186, + 0xae90, 0x0003, 0xa210, 0x683c, 0x2012, 0x0078, 0x4b27, 0x7084, + 0x8008, 0xa092, 0x000f, 0x00c8, 0x4ad9, 0x7186, 0xae90, 0x0003, + 0x8003, 0xa210, 0x683c, 0x2012, 0x8210, 0x6840, 0x2012, 0x7088, + 0xa10a, 0x0048, 0x4ac0, 0x718c, 0x7084, 0xa10a, 0x0048, 0x4ac0, + 0x2071, 0x0000, 0x7018, 0xd084, 0x00c0, 0x4ac0, 0x2071, 0xa835, + 0x7000, 0xa086, 0x0002, 0x00c0, 0x4b47, 0x1078, 0x4dc3, 0x2071, + 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0078, 0x4ac0, 0x1078, + 0x4dee, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0078, + 0x4ac0, 0x007e, 0x684c, 0x007e, 0x6837, 0x0103, 0x20a9, 0x001c, + 0xad80, 0x0011, 0x20a0, 0x2001, 0x0000, 0x40a4, 0x007f, 0xa084, + 0x00ff, 0x684e, 0x007f, 0x684a, 0x6952, 0x007c, 0x2071, 0xa714, + 0x7004, 0x0079, 0x4b6b, 0x4b75, 0x4b86, 0x4d94, 0x4d95, 0x4dbc, + 0x4dc2, 0x4b76, 0x4d82, 0x4d23, 0x4da5, 0x007c, 0x127e, 0x2091, + 0x8000, 0x0068, 0x4b85, 0x2009, 0x000d, 0x7030, 0x200a, 0x2091, + 0x4080, 0x7007, 0x0001, 0x700b, 0x0000, 0x127f, 0x2069, 0xa8c4, + 0x6844, 0xa005, 0x0050, 0x4bae, 0x00c0, 0x4bae, 0x127e, 0x2091, + 0x8000, 0x2069, 0x0000, 0x6934, 0x2001, 0xa720, 0x2004, 0xa10a, + 0x0040, 0x4ba9, 0x0068, 0x4bad, 0x2069, 0x0000, 0x6818, 0xd084, + 0x00c0, 0x4bad, 0x2009, 0x8040, 0x6922, 0x681b, 0x0001, 0x2091, + 0x4080, 0x2069, 0xa8c4, 0x6847, 0xffff, 0x127f, 0x2069, 0xa600, + 0x6848, 0x6964, 0xa102, 0x2069, 0xa835, 0x688a, 0x6984, 0x701c, + 0xa06d, 0x0040, 0x4bc0, 0x81ff, 0x0040, 0x4c08, 0x0078, 0x4bd6, + 0x81ff, 0x0040, 0x4cda, 0x2071, 0xa835, 0x7184, 0x7088, 0xa10a, + 0x00c8, 0x4bd6, 0x7190, 0x2071, 0xa8c4, 0x7040, 0xa005, 0x0040, + 0x4bd6, 0x00d0, 0x4cda, 0x7142, 0x0078, 0x4cda, 0x2071, 0xa835, + 0x718c, 0x127e, 0x2091, 0x8000, 0x7084, 0xa10a, 0x0048, 0x4cf7, + 0x0068, 0x4c8c, 0x2071, 0x0000, 0x7018, 0xd084, 0x00c0, 0x4c8c, + 0x2001, 0xffff, 0x2071, 0xa8c4, 0x7042, 0x2071, 0xa835, 0x7000, + 0xa086, 0x0002, 0x00c0, 0x4bfe, 0x1078, 0x4dc3, 0x2071, 0x0000, + 0x701b, 0x0001, 0x2091, 0x4080, 0x0078, 0x4c8c, 0x1078, 0x4dee, + 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0078, 0x4c8c, + 0x2071, 0xa835, 0x7000, 0xa005, 0x0040, 0x4cb9, 0x6934, 0xa186, + 0x0103, 0x00c0, 0x4c8f, 0x684c, 0xd0bc, 0x00c0, 0x4cb9, 0x6948, + 0x6844, 0xa105, 0x00c0, 0x4cac, 0x2009, 0x8020, 0x2071, 0xa835, + 0x7000, 0x0079, 0x4c23, 0x4cb9, 0x4c71, 0x4c49, 0x4c5b, 0x4c28, + 0x137e, 0x147e, 0x157e, 0x2099, 0xa676, 0x20a1, 0xa886, 0x20a9, + 0x0004, 0x53a3, 0x157f, 0x147f, 0x137f, 0x2071, 0xa87d, 0xad80, + 0x000f, 0x700e, 0x7013, 0x0002, 0x7007, 0x0002, 0x700b, 0x0000, + 0x2e10, 0x1078, 0x13db, 0x2071, 0xa714, 0x7007, 0x0009, 0x0078, + 0x4cda, 0x7084, 0x8008, 0xa092, 0x001e, 0x00c8, 0x4cda, 0xae90, + 0x0003, 0xa210, 0x683c, 0x2012, 0x7186, 0x2071, 0xa714, 0x1078, + 0x4e4c, 0x0078, 0x4cda, 0x7084, 0x8008, 0xa092, 0x000f, 0x00c8, + 0x4cda, 0xae90, 0x0003, 0x8003, 0xa210, 0x683c, 0x2012, 0x8210, + 0x6840, 0x2012, 0x7186, 0x2071, 0xa714, 0x1078, 0x4e4c, 0x0078, + 0x4cda, 0x127e, 0x2091, 0x8000, 0x0068, 0x4c8c, 0x2071, 0x0000, + 0x7018, 0xd084, 0x00c0, 0x4c8c, 0x7122, 0x683c, 0x7026, 0x6840, + 0x702a, 0x701b, 0x0001, 0x2091, 0x4080, 0x127f, 0x2071, 0xa714, + 0x1078, 0x4e4c, 0x0078, 0x4cda, 0x127f, 0x0078, 0x4cda, 0xa18c, + 0x00ff, 0xa186, 0x0017, 0x0040, 0x4c9d, 0xa186, 0x001e, 0x0040, + 0x4c9d, 0xa18e, 0x001f, 0x00c0, 0x4cb9, 0x684c, 0xd0cc, 0x0040, + 0x4cb9, 0x6850, 0xa084, 0x00ff, 0xa086, 0x0001, 0x00c0, 0x4cb9, + 0x2009, 0x8021, 0x0078, 0x4c1e, 0x6844, 0xa086, 0x0100, 0x00c0, + 0x4cb9, 0x6868, 0xa005, 0x00c0, 0x4cb9, 0x2009, 0x8020, 0x0078, + 0x4c1e, 0x2071, 0xa714, 0x1078, 0x4e60, 0x0040, 0x4cda, 0x2071, + 0xa714, 0x700f, 0x0001, 0x6934, 0xa184, 0x00ff, 0xa086, 0x0003, + 0x00c0, 0x4cd1, 0x810f, 0xa18c, 0x00ff, 0x8101, 0x0040, 0x4cd1, + 0x710e, 0x7007, 0x0003, 0x1078, 0x4e80, 0x7050, 0xa086, 0x0100, + 0x0040, 0x4d95, 0x127e, 0x2091, 0x8000, 0x2071, 0xa714, 0x7008, + 0xa086, 0x0001, 0x00c0, 0x4cf5, 0x0068, 0x4cf5, 0x2009, 0x000d, + 0x7030, 0x200a, 0x2091, 0x4080, 0x700b, 0x0000, 0x7004, 0xa086, + 0x0006, 0x00c0, 0x4cf5, 0x7007, 0x0001, 0x127f, 0x007c, 0x2071, + 0xa714, 0x1078, 0x4e60, 0x0040, 0x4d20, 0x2071, 0xa835, 0x7084, + 0x700a, 0x20a9, 0x0020, 0x2099, 0xa836, 0x20a1, 0xa85d, 0x53a3, + 0x7087, 0x0000, 0x2071, 0xa714, 0x2069, 0xa87d, 0x706c, 0x6826, + 0x7070, 0x682a, 0x7074, 0x682e, 0x7078, 0x6832, 0x2d10, 0x1078, + 0x13db, 0x7007, 0x0008, 0x2001, 0xffff, 0x2071, 0xa8c4, 0x7042, + 0x127f, 0x0078, 0x4cda, 0x2069, 0xa87d, 0x6808, 0xa08e, 0x0000, + 0x0040, 0x4d81, 0xa08e, 0x0200, 0x0040, 0x4d7f, 0xa08e, 0x0100, + 0x00c0, 0x4d81, 0x127e, 0x2091, 0x8000, 0x0068, 0x4d7c, 0x2069, + 0x0000, 0x6818, 0xd084, 0x00c0, 0x4d7c, 0x702c, 0x7130, 0x8108, + 0xa102, 0x0048, 0x4d4a, 0xa00e, 0x7034, 0x706e, 0x7038, 0x7072, + 0x0078, 0x4d54, 0x706c, 0xa080, 0x0040, 0x706e, 0x00c8, 0x4d54, + 0x7070, 0xa081, 0x0000, 0x7072, 0x7132, 0x6936, 0x700b, 0x0000, + 0x2001, 0xa85a, 0x2004, 0xa005, 0x00c0, 0x4d73, 0x6934, 0x2069, + 0xa835, 0x689c, 0x699e, 0x2069, 0xa8c4, 0xa102, 0x00c0, 0x4d6c, + 0x6844, 0xa005, 0x00d0, 0x4d7a, 0x2001, 0xa85b, 0x200c, 0x810d, + 0x6946, 0x0078, 0x4d7a, 0x2009, 0x8040, 0x6922, 0x681b, 0x0001, + 0x2091, 0x4080, 0x7007, 0x0001, 0x127f, 0x0078, 0x4d81, 0x7007, + 0x0005, 0x007c, 0x701c, 0xa06d, 0x0040, 0x4d93, 0x1078, 0x4e60, + 0x0040, 0x4d93, 0x7007, 0x0003, 0x1078, 0x4e80, 0x7050, 0xa086, + 0x0100, 0x0040, 0x4d95, 0x007c, 0x007c, 0x7050, 0xa09e, 0x0100, + 0x00c0, 0x4d9e, 0x7007, 0x0004, 0x0078, 0x4dbc, 0xa086, 0x0200, + 0x00c0, 0x4da4, 0x7007, 0x0005, 0x007c, 0x2001, 0xa87f, 0x2004, + 0xa08e, 0x0100, 0x00c0, 0x4db1, 0x7007, 0x0001, 0x1078, 0x4e4c, + 0x007c, 0xa08e, 0x0000, 0x0040, 0x4db0, 0xa08e, 0x0200, 0x00c0, + 0x4db0, 0x7007, 0x0005, 0x007c, 0x1078, 0x4e16, 0x7006, 0x1078, + 0x4e4c, 0x007c, 0x007c, 0x0e7e, 0x157e, 0x2071, 0xa835, 0x7184, + 0x81ff, 0x0040, 0x4deb, 0xa006, 0x7086, 0xae80, 0x0003, 0x2071, + 0x0000, 0x21a8, 0x2014, 0x7226, 0x8000, 0x0070, 0x4de8, 0x2014, + 0x722a, 0x8000, 0x0070, 0x4de8, 0x2014, 0x722e, 0x8000, 0x0070, + 0x4de8, 0x2014, 0x723a, 0x8000, 0x0070, 0x4de8, 0x2014, 0x723e, + 0xa180, 0x8030, 0x7022, 0x157f, 0x0e7f, 0x007c, 0x0e7e, 0x157e, + 0x2071, 0xa835, 0x7184, 0x81ff, 0x0040, 0x4e13, 0xa006, 0x7086, + 0xae80, 0x0003, 0x2071, 0x0000, 0x21a8, 0x2014, 0x7226, 0x8000, + 0x2014, 0x722a, 0x8000, 0x0070, 0x4e0c, 0x2014, 0x723a, 0x8000, + 0x2014, 0x723e, 0x0078, 0x4e10, 0x2001, 0x8020, 0x0078, 0x4e12, + 0x2001, 0x8042, 0x7022, 0x157f, 0x0e7f, 0x007c, 0x702c, 0x7130, + 0x8108, 0xa102, 0x0048, 0x4e23, 0xa00e, 0x7034, 0x706e, 0x7038, + 0x7072, 0x0078, 0x4e2d, 0x706c, 0xa080, 0x0040, 0x706e, 0x00c8, + 0x4e2d, 0x7070, 0xa081, 0x0000, 0x7072, 0x7132, 0x700c, 0x8001, + 0x700e, 0x00c0, 0x4e43, 0x127e, 0x2091, 0x8000, 0x0068, 0x4e46, + 0x2001, 0x000d, 0x2102, 0x2091, 0x4080, 0x2001, 0x0001, 0x700b, + 0x0000, 0x127f, 0x007c, 0x2001, 0x0007, 0x007c, 0x2001, 0x0006, + 0x700b, 0x0001, 0x127f, 0x007c, 0x701c, 0xa06d, 0x0040, 0x4e5f, + 0x127e, 0x2091, 0x8000, 0x7010, 0x8001, 0x7012, 0x2d04, 0x701e, + 0xa005, 0x00c0, 0x4e5c, 0x701a, 0x127f, 0x1078, 0x13a4, 0x007c, + 0x2019, 0x000d, 0x2304, 0x230c, 0xa10e, 0x0040, 0x4e6f, 0x2304, + 0x230c, 0xa10e, 0x0040, 0x4e6f, 0xa006, 0x0078, 0x4e7f, 0x732c, + 0x8319, 0x7130, 0xa102, 0x00c0, 0x4e79, 0x2300, 0xa005, 0x0078, + 0x4e7f, 0x0048, 0x4e7e, 0xa302, 0x0078, 0x4e7f, 0x8002, 0x007c, + 0x2d00, 0x7026, 0xa080, 0x000d, 0x7056, 0x7053, 0x0000, 0x127e, + 0x2091, 0x8000, 0x2009, 0xa8d6, 0x2104, 0xc08d, 0x200a, 0x127f, + 0x1078, 0x13f9, 0x007c, 0x2071, 0xa6e2, 0x7003, 0x0000, 0x7007, + 0x0000, 0x700f, 0x0000, 0x702b, 0x0001, 0x704f, 0x0000, 0x7053, + 0x0001, 0x705f, 0x0020, 0x7063, 0x0040, 0x7083, 0x0000, 0x708b, + 0x0000, 0x708f, 0x0001, 0x70bf, 0x0000, 0x007c, 0x0e7e, 0x2071, + 0xa6e2, 0x6848, 0xa005, 0x00c0, 0x4ebc, 0x7028, 0xc085, 0x702a, + 0xa085, 0x0001, 0x0078, 0x4ee1, 0x6a50, 0x7236, 0x6b54, 0x733a, + 0x6858, 0x703e, 0x707a, 0x685c, 0x7042, 0x707e, 0x6848, 0x702e, + 0x6840, 0x7032, 0x2009, 0x000c, 0x200a, 0x8007, 0x8006, 0x8006, + 0xa08c, 0x003f, 0xa084, 0xffc0, 0xa210, 0x2100, 0xa319, 0x7272, + 0x7376, 0x7028, 0xc084, 0x702a, 0x7007, 0x0001, 0x700f, 0x0000, + 0xa006, 0x0e7f, 0x007c, 0x2b78, 0x2071, 0xa6e2, 0x7004, 0x1079, + 0x4f41, 0x700c, 0x0079, 0x4eec, 0x4ef1, 0x4ee6, 0x4ee6, 0x4ee6, + 0x4ee6, 0x007c, 0x700c, 0x0079, 0x4ef5, 0x4efa, 0x4f3f, 0x4f3f, + 0x4f40, 0x4f40, 0x7830, 0x7930, 0xa106, 0x0040, 0x4f04, 0x7830, + 0x7930, 0xa106, 0x00c0, 0x4f2a, 0x7030, 0xa10a, 0x0040, 0x4f2a, + 0x00c8, 0x4f0c, 0x712c, 0xa10a, 0xa18a, 0x0002, 0x00c8, 0x4f2b, + 0x1078, 0x1370, 0x0040, 0x4f2a, 0x2d00, 0x705a, 0x7063, 0x0040, + 0x2001, 0x0003, 0x7057, 0x0000, 0x127e, 0x007e, 0x2091, 0x8000, + 0x2009, 0xa8d6, 0x2104, 0xc085, 0x200a, 0x007f, 0x700e, 0x127f, + 0x1078, 0x13f9, 0x007c, 0x1078, 0x1370, 0x0040, 0x4f2a, 0x2d00, + 0x705a, 0x1078, 0x1370, 0x00c0, 0x4f37, 0x0078, 0x4f16, 0x2d00, + 0x7086, 0x7063, 0x0080, 0x2001, 0x0004, 0x0078, 0x4f1a, 0x007c, + 0x007c, 0x4f52, 0x4f53, 0x4f8a, 0x4f8b, 0x4f3f, 0x4fc1, 0x4fc6, + 0x4ffd, 0x4ffe, 0x5019, 0x501a, 0x501b, 0x501c, 0x501d, 0x501e, + 0x509e, 0x50c8, 0x007c, 0x700c, 0x0079, 0x4f56, 0x4f5b, 0x4f5e, + 0x4f6e, 0x4f89, 0x4f89, 0x1078, 0x4ef2, 0x007c, 0x127e, 0x8001, + 0x700e, 0x7058, 0x007e, 0x1078, 0x5464, 0x0040, 0x4f6b, 0x2091, + 0x8000, 0x1078, 0x4ef2, 0x0d7f, 0x0078, 0x4f77, 0x127e, 0x8001, + 0x700e, 0x1078, 0x5464, 0x7058, 0x2068, 0x7084, 0x705a, 0x6803, + 0x0000, 0x6807, 0x0000, 0x6834, 0xa084, 0x00ff, 0xa08a, 0x0020, + 0x00c8, 0x4f86, 0x1079, 0x4fa1, 0x127f, 0x007c, 0x127f, 0x1078, + 0x501f, 0x007c, 0x007c, 0x007c, 0x0e7e, 0x2071, 0xa6e2, 0x700c, + 0x0079, 0x4f92, 0x4f97, 0x4f97, 0x4f97, 0x4f99, 0x4f9d, 0x0e7f, + 0x007c, 0x700f, 0x0001, 0x0078, 0x4f9f, 0x700f, 0x0002, 0x0e7f, + 0x007c, 0x501f, 0x501f, 0x503b, 0x501f, 0x5171, 0x501f, 0x501f, + 0x501f, 0x501f, 0x501f, 0x503b, 0x51bb, 0x5208, 0x5261, 0x5277, + 0x501f, 0x501f, 0x5057, 0x503b, 0x501f, 0x501f, 0x5078, 0x5338, + 0x5356, 0x501f, 0x5057, 0x501f, 0x501f, 0x501f, 0x501f, 0x506d, + 0x5356, 0x7020, 0x2068, 0x1078, 0x13a4, 0x007c, 0x700c, 0x0079, + 0x4fc9, 0x4fce, 0x4fd1, 0x4fe1, 0x4ffc, 0x4ffc, 0x1078, 0x4ef2, + 0x007c, 0x127e, 0x8001, 0x700e, 0x7058, 0x007e, 0x1078, 0x5464, + 0x0040, 0x4fde, 0x2091, 0x8000, 0x1078, 0x4ef2, 0x0d7f, 0x0078, + 0x4fea, 0x127e, 0x8001, 0x700e, 0x1078, 0x5464, 0x7058, 0x2068, + 0x7084, 0x705a, 0x6803, 0x0000, 0x6807, 0x0000, 0x6834, 0xa084, + 0x00ff, 0xa08a, 0x001a, 0x00c8, 0x4ff9, 0x1079, 0x4fff, 0x127f, + 0x007c, 0x127f, 0x1078, 0x501f, 0x007c, 0x007c, 0x007c, 0x501f, + 0x503b, 0x515b, 0x501f, 0x503b, 0x501f, 0x503b, 0x503b, 0x501f, + 0x503b, 0x515b, 0x503b, 0x503b, 0x503b, 0x503b, 0x503b, 0x501f, + 0x503b, 0x515b, 0x501f, 0x501f, 0x503b, 0x501f, 0x501f, 0x501f, + 0x503b, 0x007c, 0x007c, 0x007c, 0x007c, 0x007c, 0x007c, 0x7007, + 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0d5, 0x683a, 0x127e, 0x2091, + 0x8000, 0x1078, 0x4a73, 0x127f, 0x007c, 0x7007, 0x0001, 0x6838, + 0xa084, 0x00ff, 0xc0e5, 0x683a, 0x127e, 0x2091, 0x8000, 0x1078, + 0x4a73, 0x127f, 0x007c, 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, + 0xc0ed, 0x683a, 0x127e, 0x2091, 0x8000, 0x1078, 0x4a73, 0x127f, + 0x007c, 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0dd, 0x683a, + 0x127e, 0x2091, 0x8000, 0x1078, 0x4a73, 0x127f, 0x007c, 0x6834, + 0x8007, 0xa084, 0x00ff, 0x0040, 0x502d, 0x8001, 0x00c0, 0x5064, + 0x7007, 0x0001, 0x0078, 0x513a, 0x7007, 0x0006, 0x7012, 0x2d00, + 0x7016, 0x701a, 0x704b, 0x513a, 0x007c, 0x684c, 0xa084, 0x00c0, + 0xa086, 0x00c0, 0x00c0, 0x5078, 0x7007, 0x0001, 0x0078, 0x5373, + 0x2d00, 0x7016, 0x701a, 0x20a9, 0x0004, 0xa080, 0x0024, 0x2098, + 0x20a1, 0xa70d, 0x53a3, 0x6858, 0x7012, 0xa082, 0x0401, 0x00c8, + 0x5049, 0x6884, 0xa08a, 0x0002, 0x00c8, 0x5049, 0x82ff, 0x00c0, + 0x509a, 0x6888, 0x698c, 0xa105, 0x0040, 0x509a, 0x2001, 0x510a, + 0x0078, 0x509d, 0xa280, 0x5100, 0x2004, 0x70c6, 0x7010, 0xa015, + 0x0040, 0x50e8, 0x1078, 0x1370, 0x00c0, 0x50a9, 0x7007, 0x000f, + 0x007c, 0x2d00, 0x7022, 0x70c4, 0x2060, 0x6000, 0x6836, 0x6004, + 0xad00, 0x7096, 0x6008, 0xa20a, 0x00c8, 0x50b8, 0xa00e, 0x2200, + 0x7112, 0x620c, 0x8003, 0x800b, 0xa296, 0x0004, 0x0040, 0x50c1, + 0xa108, 0x719a, 0x810b, 0x719e, 0xae90, 0x0022, 0x1078, 0x13db, + 0x7090, 0xa08e, 0x0100, 0x0040, 0x50dc, 0xa086, 0x0200, 0x0040, + 0x50d4, 0x7007, 0x0010, 0x007c, 0x7020, 0x2068, 0x1078, 0x13a4, + 0x7014, 0x2068, 0x0078, 0x5049, 0x7020, 0x2068, 0x7018, 0x6802, + 0x6807, 0x0000, 0x2d08, 0x2068, 0x6906, 0x711a, 0x0078, 0x509e, + 0x7014, 0x2068, 0x7007, 0x0001, 0x6884, 0xa005, 0x00c0, 0x50f7, + 0x6888, 0x698c, 0xa105, 0x0040, 0x50f7, 0x1078, 0x510e, 0x6834, + 0xa084, 0x00ff, 0xa086, 0x001e, 0x0040, 0x5373, 0x0078, 0x513a, + 0x5102, 0x5106, 0x0002, 0x0011, 0x0007, 0x0004, 0x000a, 0x000f, + 0x0005, 0x0006, 0x000a, 0x0011, 0x0005, 0x0004, 0x0f7e, 0x0e7e, + 0x0c7e, 0x077e, 0x067e, 0x6f88, 0x6e8c, 0x6804, 0x2060, 0xacf0, + 0x0021, 0xacf8, 0x0027, 0x2009, 0x0005, 0x700c, 0x7816, 0x7008, + 0x7812, 0x7004, 0x7806, 0x7000, 0x7802, 0x7e0e, 0x7f0a, 0x8109, + 0x0040, 0x5130, 0xaef2, 0x0004, 0xaffa, 0x0006, 0x0078, 0x511d, + 0x6004, 0xa065, 0x00c0, 0x5117, 0x067f, 0x077f, 0x0c7f, 0x0e7f, + 0x0f7f, 0x007c, 0x2009, 0xa62f, 0x210c, 0x81ff, 0x00c0, 0x5155, + 0x6838, 0xa084, 0x00ff, 0x683a, 0x1078, 0x4353, 0x00c0, 0x5149, + 0x007c, 0x1078, 0x4b51, 0x127e, 0x2091, 0x8000, 0x1078, 0x8f7d, + 0x1078, 0x4a73, 0x127f, 0x0078, 0x5148, 0x2001, 0x0028, 0x2009, + 0x0000, 0x0078, 0x5149, 0x7018, 0x6802, 0x2d08, 0x2068, 0x6906, + 0x711a, 0x7010, 0x8001, 0x7012, 0x0040, 0x516a, 0x7007, 0x0006, + 0x0078, 0x5170, 0x7014, 0x2068, 0x7007, 0x0001, 0x7048, 0x107a, + 0x007c, 0x7007, 0x0001, 0x6944, 0x810f, 0xa18c, 0x00ff, 0x6848, + 0xa084, 0x00ff, 0x20a9, 0x0001, 0xa096, 0x0001, 0x0040, 0x519a, + 0x2009, 0x0000, 0x20a9, 0x00ff, 0xa096, 0x0002, 0x0040, 0x519a, + 0xa005, 0x00c0, 0x51ad, 0x6944, 0x810f, 0xa18c, 0x00ff, 0x1078, + 0x45c4, 0x00c0, 0x51ad, 0x067e, 0x6e50, 0x1078, 0x46b3, 0x067f, + 0x0078, 0x51ad, 0x047e, 0x2011, 0xa60c, 0x2224, 0xc484, 0xc48c, + 0x2412, 0x047f, 0x0c7e, 0x1078, 0x45c4, 0x00c0, 0x51a9, 0x1078, + 0x4852, 0x8108, 0x00f0, 0x51a3, 0x0c7f, 0x684c, 0xd084, 0x00c0, + 0x51b4, 0x1078, 0x13a4, 0x007c, 0x127e, 0x2091, 0x8000, 0x1078, + 0x4a73, 0x127f, 0x007c, 0x127e, 0x2091, 0x8000, 0x7007, 0x0001, + 0x2001, 0xa653, 0x2004, 0xd0a4, 0x0040, 0x51ff, 0x2061, 0xa933, + 0x6100, 0xd184, 0x0040, 0x51df, 0x6858, 0xa084, 0x00ff, 0x00c0, + 0x5202, 0x6000, 0xd084, 0x0040, 0x51ff, 0x6004, 0xa005, 0x00c0, + 0x5205, 0x6003, 0x0000, 0x600b, 0x0000, 0x0078, 0x51fc, 0x2011, + 0x0001, 0x6860, 0xa005, 0x00c0, 0x51e7, 0x2001, 0x001e, 0x8000, + 0x6016, 0x6858, 0xa084, 0x00ff, 0x0040, 0x51ff, 0x6006, 0x6858, + 0x8007, 0xa084, 0x00ff, 0x0040, 0x51ff, 0x600a, 0x6858, 0x8000, + 0x00c0, 0x51fb, 0xc28d, 0x6202, 0x127f, 0x0078, 0x5453, 0x127f, + 0x0078, 0x544b, 0x127f, 0x0078, 0x5443, 0x127f, 0x0078, 0x5447, + 0x127e, 0x2091, 0x8000, 0x7007, 0x0001, 0x2001, 0xa653, 0x2004, + 0xd0a4, 0x0040, 0x525e, 0x2061, 0xa933, 0x6000, 0xd084, 0x0040, + 0x525e, 0x6204, 0x6308, 0xd08c, 0x00c0, 0x5250, 0x6c48, 0xa484, + 0x0003, 0x0040, 0x5236, 0x6958, 0xa18c, 0x00ff, 0x8001, 0x00c0, + 0x522f, 0x2100, 0xa210, 0x0048, 0x525b, 0x0078, 0x5236, 0x8001, + 0x00c0, 0x525b, 0x2100, 0xa212, 0x0048, 0x525b, 0xa484, 0x000c, + 0x0040, 0x5250, 0x6958, 0x810f, 0xa18c, 0x00ff, 0xa082, 0x0004, + 0x00c0, 0x5248, 0x2100, 0xa318, 0x0048, 0x525b, 0x0078, 0x5250, + 0xa082, 0x0004, 0x00c0, 0x525b, 0x2100, 0xa31a, 0x0048, 0x525b, + 0x6860, 0xa005, 0x0040, 0x5256, 0x8000, 0x6016, 0x6206, 0x630a, + 0x127f, 0x0078, 0x5453, 0x127f, 0x0078, 0x544f, 0x127f, 0x0078, + 0x544b, 0x127e, 0x2091, 0x8000, 0x7007, 0x0001, 0x2061, 0xa933, + 0x6300, 0xd38c, 0x00c0, 0x5271, 0x6308, 0x8318, 0x0048, 0x5274, + 0x630a, 0x127f, 0x0078, 0x5461, 0x127f, 0x0078, 0x544f, 0x127e, + 0x0c7e, 0x2091, 0x8000, 0x7007, 0x0001, 0x684c, 0xd0ac, 0x0040, + 0x528b, 0x0c7e, 0x2061, 0xa933, 0x6000, 0xa084, 0xfcff, 0x6002, + 0x0c7f, 0x0078, 0x52ba, 0x6858, 0xa005, 0x0040, 0x52d1, 0x685c, + 0xa065, 0x0040, 0x52cd, 0x2001, 0xa62f, 0x2004, 0xa005, 0x0040, + 0x529d, 0x1078, 0x8ec6, 0x0078, 0x52ab, 0x6013, 0x0400, 0x6037, + 0x0000, 0x694c, 0xd1a4, 0x0040, 0x52a7, 0x6950, 0x6136, 0x2009, + 0x0041, 0x1078, 0x775c, 0x6958, 0xa18c, 0xff00, 0xa186, 0x2000, + 0x00c0, 0x52ba, 0x027e, 0x2009, 0x0000, 0x2011, 0xfdff, 0x1078, + 0x5bf1, 0x027f, 0x684c, 0xd0c4, 0x0040, 0x52c9, 0x2061, 0xa933, + 0x6000, 0xd08c, 0x00c0, 0x52c9, 0x6008, 0x8000, 0x0048, 0x52cd, + 0x600a, 0x0c7f, 0x127f, 0x0078, 0x5453, 0x0c7f, 0x127f, 0x0078, + 0x544b, 0x6954, 0xa186, 0x0045, 0x0040, 0x5306, 0xa186, 0x002a, + 0x00c0, 0x52e1, 0x2001, 0xa60c, 0x200c, 0xc194, 0x2102, 0x0078, + 0x52ba, 0xa186, 0x0020, 0x0040, 0x52fa, 0xa186, 0x0029, 0x0040, + 0x52ed, 0xa186, 0x002d, 0x00c0, 0x52cd, 0x6944, 0xa18c, 0xff00, + 0x810f, 0x1078, 0x45c4, 0x00c0, 0x52ba, 0x6000, 0xc0e4, 0x6002, + 0x0078, 0x52ba, 0x685c, 0xa065, 0x0040, 0x52cd, 0x6007, 0x0024, + 0x2001, 0xa8a3, 0x2004, 0x6016, 0x0078, 0x52ba, 0x685c, 0xa065, + 0x0040, 0x52cd, 0x0e7e, 0x6860, 0xa075, 0x2001, 0xa62f, 0x2004, + 0xa005, 0x0040, 0x531e, 0x1078, 0x8ec6, 0x8eff, 0x0040, 0x531b, + 0x2e60, 0x1078, 0x8ec6, 0x0e7f, 0x0078, 0x52ba, 0x6024, 0xc0dc, + 0xc0d5, 0x6026, 0x2e60, 0x6007, 0x003a, 0x6870, 0xa005, 0x0040, + 0x532f, 0x6007, 0x003b, 0x6874, 0x602a, 0x6878, 0x6012, 0x6003, + 0x0001, 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x0e7f, 0x0078, 0x52ba, + 0x2061, 0xa933, 0x6000, 0xd084, 0x0040, 0x5352, 0xd08c, 0x00c0, + 0x5461, 0x2091, 0x8000, 0x6204, 0x8210, 0x0048, 0x534c, 0x6206, + 0x2091, 0x8001, 0x0078, 0x5461, 0x2091, 0x8001, 0x6853, 0x0016, + 0x0078, 0x545a, 0x6853, 0x0007, 0x0078, 0x545a, 0x6834, 0x8007, + 0xa084, 0x00ff, 0x00c0, 0x5360, 0x1078, 0x502d, 0x0078, 0x5372, + 0x2030, 0x8001, 0x00c0, 0x536a, 0x7007, 0x0001, 0x1078, 0x5373, + 0x0078, 0x5372, 0x7007, 0x0006, 0x7012, 0x2d00, 0x7016, 0x701a, + 0x704b, 0x5373, 0x007c, 0x0e7e, 0x127e, 0x2091, 0x8000, 0xa03e, + 0x2009, 0xa62f, 0x210c, 0x81ff, 0x00c0, 0x53ff, 0x2009, 0xa60c, + 0x210c, 0xd194, 0x00c0, 0x5431, 0x6848, 0x2070, 0xae82, 0xad00, + 0x0048, 0x53ef, 0x2001, 0xa616, 0x2004, 0xae02, 0x00c8, 0x53ef, + 0x2061, 0xa933, 0x6100, 0xa184, 0x0301, 0xa086, 0x0001, 0x00c0, + 0x53d2, 0x711c, 0xa186, 0x0006, 0x00c0, 0x53da, 0x7018, 0xa005, + 0x0040, 0x53ff, 0x2004, 0xd0e4, 0x00c0, 0x542b, 0x7024, 0xd0dc, + 0x00c0, 0x5435, 0x6853, 0x0000, 0x6803, 0x0000, 0x2d08, 0x7010, + 0xa005, 0x00c0, 0x53be, 0x7112, 0x684c, 0xd0f4, 0x00c0, 0x5439, + 0x2e60, 0x1078, 0x5b27, 0x127f, 0x0e7f, 0x007c, 0x2068, 0x6800, + 0xa005, 0x00c0, 0x53be, 0x6902, 0x2168, 0x684c, 0xd0f4, 0x00c0, + 0x5439, 0x127f, 0x0e7f, 0x007c, 0x127f, 0x0e7f, 0x6853, 0x0006, + 0x0078, 0x545a, 0xd184, 0x0040, 0x53cc, 0xd1c4, 0x00c0, 0x53f3, + 0x0078, 0x53f7, 0x6944, 0xa18c, 0xff00, 0x810f, 0x1078, 0x45c4, + 0x00c0, 0x542b, 0x6000, 0xd0e4, 0x00c0, 0x542b, 0x711c, 0xa186, + 0x0007, 0x00c0, 0x53ef, 0x6853, 0x0002, 0x0078, 0x542d, 0x6853, + 0x0008, 0x0078, 0x542d, 0x6853, 0x000e, 0x0078, 0x542d, 0x6853, + 0x0017, 0x0078, 0x542d, 0x6853, 0x0035, 0x0078, 0x542d, 0x2001, + 0xa672, 0x2004, 0xd0fc, 0x0040, 0x5427, 0x6848, 0x2070, 0xae82, + 0xad00, 0x0048, 0x5427, 0x6058, 0xae02, 0x00c8, 0x5427, 0x711c, + 0xa186, 0x0006, 0x00c0, 0x5427, 0x7018, 0xa005, 0x0040, 0x5427, + 0x2004, 0xd0bc, 0x0040, 0x5427, 0x2039, 0x0001, 0x7000, 0xa086, + 0x0007, 0x00c0, 0x537e, 0x7003, 0x0002, 0x0078, 0x537e, 0x6853, + 0x0028, 0x0078, 0x542d, 0x6853, 0x0029, 0x127f, 0x0e7f, 0x0078, + 0x545a, 0x6853, 0x002a, 0x0078, 0x542d, 0x6853, 0x0045, 0x0078, + 0x542d, 0x2e60, 0x2019, 0x0002, 0x6017, 0x0014, 0x1078, 0x9dc7, + 0x127f, 0x0e7f, 0x007c, 0x2009, 0x003e, 0x0078, 0x5455, 0x2009, + 0x0004, 0x0078, 0x5455, 0x2009, 0x0006, 0x0078, 0x5455, 0x2009, + 0x0016, 0x0078, 0x5455, 0x2009, 0x0001, 0x6854, 0xa084, 0xff00, + 0xa105, 0x6856, 0x2091, 0x8000, 0x1078, 0x4a73, 0x2091, 0x8001, + 0x007c, 0x1078, 0x13a4, 0x007c, 0x702c, 0x7130, 0x8108, 0xa102, + 0x0048, 0x5471, 0xa00e, 0x7034, 0x7072, 0x7038, 0x7076, 0x0078, + 0x547d, 0x7070, 0xa080, 0x0040, 0x7072, 0x00c8, 0x547d, 0x7074, + 0xa081, 0x0000, 0x7076, 0xa085, 0x0001, 0x7932, 0x7132, 0x007c, + 0x0d7e, 0x1078, 0x5b1e, 0x0d7f, 0x007c, 0x0d7e, 0x2011, 0x0004, + 0x2204, 0xa085, 0x8002, 0x2012, 0x0d7f, 0x007c, 0x20e1, 0x0002, + 0x3d08, 0x20e1, 0x2000, 0x3d00, 0xa084, 0x7000, 0x0040, 0x549c, + 0xa086, 0x1000, 0x00c0, 0x54d3, 0x20e1, 0x0000, 0x3d00, 0xa094, + 0xff00, 0x8217, 0xa084, 0xf000, 0xa086, 0x3000, 0x00c0, 0x54b7, + 0xa184, 0xff00, 0x8007, 0xa086, 0x0008, 0x00c0, 0x54d3, 0x1078, + 0x29bb, 0x00c0, 0x54d3, 0x1078, 0x56b2, 0x0078, 0x54ce, 0x20e1, + 0x0004, 0x3d60, 0xd1bc, 0x00c0, 0x54be, 0x3e60, 0xac84, 0x000f, + 0x00c0, 0x54d3, 0xac82, 0xad00, 0x0048, 0x54d3, 0x6858, 0xac02, + 0x00c8, 0x54d3, 0x2009, 0x0047, 0x1078, 0x775c, 0x7a1c, 0xd284, + 0x00c0, 0x548e, 0x007c, 0xa016, 0x1078, 0x15fa, 0x0078, 0x54ce, + 0x0078, 0x54d3, 0x781c, 0xd08c, 0x0040, 0x5502, 0x157e, 0x137e, + 0x147e, 0x20e1, 0x3000, 0x3d20, 0x3e28, 0xa584, 0x0076, 0x00c0, + 0x5518, 0xa484, 0x7000, 0xa086, 0x1000, 0x00c0, 0x5507, 0x1078, + 0x554e, 0x0040, 0x5518, 0x20e1, 0x3000, 0x7828, 0x7828, 0x1078, + 0x556c, 0x147f, 0x137f, 0x157f, 0x2009, 0xa8b9, 0x2104, 0xa005, + 0x00c0, 0x5503, 0x007c, 0x1078, 0x62d1, 0x0078, 0x5502, 0xa484, + 0x7000, 0x00c0, 0x5518, 0x1078, 0x554e, 0x0040, 0x552c, 0x7000, + 0xa084, 0xff00, 0xa086, 0x8100, 0x0040, 0x54f3, 0x0078, 0x552c, + 0x1078, 0xa54f, 0xd5a4, 0x0040, 0x5528, 0x047e, 0x1078, 0x1b22, + 0x047f, 0x20e1, 0x9010, 0x2001, 0x0138, 0x2202, 0x0078, 0x5530, + 0x1078, 0x554e, 0x6883, 0x0000, 0x20e1, 0x3000, 0x7828, 0x7828, + 0x1078, 0x5537, 0x147f, 0x137f, 0x157f, 0x0078, 0x5502, 0x2001, + 0xa60e, 0x2004, 0xd08c, 0x0040, 0x554d, 0x2001, 0xa600, 0x2004, + 0xa086, 0x0003, 0x00c0, 0x554d, 0x027e, 0x037e, 0x2011, 0x8048, + 0x2518, 0x1078, 0x361b, 0x037f, 0x027f, 0x007c, 0xa484, 0x01ff, + 0x6882, 0xa005, 0x0040, 0x5560, 0xa080, 0x001f, 0xa084, 0x03f8, + 0x80ac, 0x20e1, 0x1000, 0x2ea0, 0x2099, 0x020a, 0x53a5, 0x007c, + 0x20a9, 0x000c, 0x20e1, 0x1000, 0x2ea0, 0x2099, 0x020a, 0x53a5, + 0xa085, 0x0001, 0x0078, 0x555f, 0x7000, 0xa084, 0xff00, 0xa08c, + 0xf000, 0x8007, 0xa196, 0x0000, 0x00c0, 0x5579, 0x0078, 0x57ba, + 0x007c, 0xa196, 0x2000, 0x00c0, 0x558a, 0x6900, 0xa18e, 0x0001, + 0x00c0, 0x5586, 0x1078, 0x3aec, 0x0078, 0x5578, 0x1078, 0x5592, + 0x0078, 0x5578, 0xa196, 0x8000, 0x00c0, 0x5578, 0x1078, 0x5871, + 0x0078, 0x5578, 0x0c7e, 0x7110, 0xa18c, 0xff00, 0x810f, 0xa196, + 0x0001, 0x0040, 0x559f, 0xa196, 0x0023, 0x00c0, 0x56aa, 0xa08e, + 0x0023, 0x00c0, 0x55d4, 0x1078, 0x591d, 0x0040, 0x56aa, 0x7124, + 0x610a, 0x7030, 0xa08e, 0x0200, 0x00c0, 0x55b8, 0x7034, 0xa005, + 0x00c0, 0x56aa, 0x2009, 0x0015, 0x1078, 0x775c, 0x0078, 0x56aa, + 0xa08e, 0x0214, 0x0040, 0x55c0, 0xa08e, 0x0210, 0x00c0, 0x55c6, + 0x2009, 0x0015, 0x1078, 0x775c, 0x0078, 0x56aa, 0xa08e, 0x0100, + 0x00c0, 0x56aa, 0x7034, 0xa005, 0x00c0, 0x56aa, 0x2009, 0x0016, + 0x1078, 0x775c, 0x0078, 0x56aa, 0xa08e, 0x0022, 0x00c0, 0x56aa, + 0x7030, 0xa08e, 0x0300, 0x00c0, 0x55e5, 0x7034, 0xa005, 0x00c0, + 0x56aa, 0x2009, 0x0017, 0x0078, 0x5676, 0xa08e, 0x0500, 0x00c0, + 0x55f1, 0x7034, 0xa005, 0x00c0, 0x56aa, 0x2009, 0x0018, 0x0078, + 0x5676, 0xa08e, 0x2010, 0x00c0, 0x55f9, 0x2009, 0x0019, 0x0078, + 0x5676, 0xa08e, 0x2110, 0x00c0, 0x5601, 0x2009, 0x001a, 0x0078, + 0x5676, 0xa08e, 0x5200, 0x00c0, 0x560d, 0x7034, 0xa005, 0x00c0, + 0x56aa, 0x2009, 0x001b, 0x0078, 0x5676, 0xa08e, 0x5000, 0x00c0, + 0x5619, 0x7034, 0xa005, 0x00c0, 0x56aa, 0x2009, 0x001c, 0x0078, + 0x5676, 0xa08e, 0x1300, 0x00c0, 0x5621, 0x2009, 0x0034, 0x0078, + 0x5676, 0xa08e, 0x1200, 0x00c0, 0x562d, 0x7034, 0xa005, 0x00c0, + 0x56aa, 0x2009, 0x0024, 0x0078, 0x5676, 0xa08c, 0xff00, 0xa18e, + 0x2400, 0x00c0, 0x5637, 0x2009, 0x002d, 0x0078, 0x5676, 0xa08c, + 0xff00, 0xa18e, 0x5300, 0x00c0, 0x5641, 0x2009, 0x002a, 0x0078, + 0x5676, 0xa08e, 0x0f00, 0x00c0, 0x5649, 0x2009, 0x0020, 0x0078, + 0x5676, 0xa08e, 0x5300, 0x00c0, 0x564f, 0x0078, 0x566c, 0xa08e, + 0x6104, 0x00c0, 0x566c, 0x2011, 0xab8d, 0x8208, 0x2204, 0xa082, + 0x0004, 0x20a8, 0x95ac, 0x95ac, 0x2011, 0x8015, 0x211c, 0x8108, + 0x047e, 0x2124, 0x1078, 0x361b, 0x047f, 0x8108, 0x00f0, 0x565c, + 0x2009, 0x0023, 0x0078, 0x5676, 0xa08e, 0x6000, 0x00c0, 0x5674, + 0x2009, 0x003f, 0x0078, 0x5676, 0x2009, 0x001d, 0x017e, 0x2011, + 0xab83, 0x2204, 0x8211, 0x220c, 0x1078, 0x254d, 0x00c0, 0x56ac, + 0x1078, 0x455c, 0x00c0, 0x56ac, 0x6612, 0x6516, 0x86ff, 0x0040, + 0x569c, 0x017f, 0x017e, 0xa186, 0x0017, 0x00c0, 0x569c, 0x686c, + 0xa606, 0x00c0, 0x569c, 0x6870, 0xa506, 0xa084, 0xff00, 0x00c0, + 0x569c, 0x6000, 0xc0f5, 0x6002, 0x0c7e, 0x1078, 0x76c7, 0x0040, + 0x56af, 0x017f, 0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0x017f, + 0x1078, 0x775c, 0x0c7f, 0x007c, 0x017f, 0x0078, 0x56aa, 0x0c7f, + 0x0078, 0x56ac, 0x0c7e, 0x1078, 0x570f, 0x00c0, 0x570d, 0xa28e, + 0x0033, 0x00c0, 0x56de, 0x1078, 0x591d, 0x0040, 0x570d, 0x7124, + 0x610a, 0x7030, 0xa08e, 0x0200, 0x00c0, 0x56d0, 0x7034, 0xa005, + 0x00c0, 0x570d, 0x2009, 0x0015, 0x1078, 0x775c, 0x0078, 0x570d, + 0xa08e, 0x0100, 0x00c0, 0x570d, 0x7034, 0xa005, 0x00c0, 0x570d, + 0x2009, 0x0016, 0x1078, 0x775c, 0x0078, 0x570d, 0xa28e, 0x0032, + 0x00c0, 0x570d, 0x7030, 0xa08e, 0x1400, 0x00c0, 0x570d, 0x2009, + 0x0038, 0x017e, 0x2011, 0xab83, 0x2204, 0x8211, 0x220c, 0x1078, + 0x254d, 0x00c0, 0x570c, 0x1078, 0x455c, 0x00c0, 0x570c, 0x6612, + 0x6516, 0x0c7e, 0x1078, 0x76c7, 0x0040, 0x570b, 0x017f, 0x611a, + 0x601f, 0x0004, 0x7120, 0x610a, 0x017f, 0x1078, 0x775c, 0x1078, + 0x62d1, 0x0078, 0x570d, 0x0c7f, 0x017f, 0x0c7f, 0x007c, 0x0f7e, + 0x0d7e, 0x027e, 0x017e, 0x137e, 0x147e, 0x157e, 0x3c00, 0x007e, + 0x2079, 0x0030, 0x2069, 0x0200, 0x1078, 0x1c6a, 0x00c0, 0x5750, + 0x1078, 0x1b40, 0x0040, 0x575d, 0x7908, 0xa18c, 0x1fff, 0xa182, + 0x0011, 0x00c8, 0x575a, 0x20a9, 0x000c, 0x20e1, 0x0000, 0x2ea0, + 0x2099, 0x020a, 0x53a5, 0x20e1, 0x2000, 0x2001, 0x020a, 0x2004, + 0x7a0c, 0x7808, 0xa080, 0x0007, 0xa084, 0x1ff8, 0xa08a, 0x0140, + 0x10c8, 0x1332, 0x80ac, 0x20e1, 0x6000, 0x2099, 0x020a, 0x53a5, + 0x20e1, 0x7000, 0x6828, 0x6828, 0x7803, 0x0004, 0xa294, 0x0070, + 0x007f, 0x20e0, 0x157f, 0x147f, 0x137f, 0x017f, 0x027f, 0x0d7f, + 0x0f7f, 0x007c, 0xa016, 0x1078, 0x15fa, 0xa085, 0x0001, 0x0078, + 0x5750, 0x047e, 0x0e7e, 0x0d7e, 0x2028, 0x2130, 0xa696, 0x00ff, + 0x00c0, 0x5782, 0xa596, 0xfffd, 0x00c0, 0x5772, 0x2009, 0x007f, + 0x0078, 0x57b5, 0xa596, 0xfffe, 0x00c0, 0x577a, 0x2009, 0x007e, + 0x0078, 0x57b5, 0xa596, 0xfffc, 0x00c0, 0x5782, 0x2009, 0x0080, + 0x0078, 0x57b5, 0x2011, 0x0000, 0x2021, 0x0081, 0x20a9, 0x007e, + 0x2071, 0xa7b6, 0x2e1c, 0x83ff, 0x00c0, 0x5794, 0x82ff, 0x00c0, + 0x57a9, 0x2410, 0x0078, 0x57a9, 0x2368, 0x6f10, 0x007e, 0x2100, + 0xa706, 0x007f, 0x6b14, 0x00c0, 0x57a3, 0xa346, 0x00c0, 0x57a3, + 0x2408, 0x0078, 0x57b5, 0x87ff, 0x00c0, 0x57a9, 0x83ff, 0x0040, + 0x578e, 0x8420, 0x8e70, 0x00f0, 0x578a, 0x82ff, 0x00c0, 0x57b4, + 0xa085, 0x0001, 0x0078, 0x57b6, 0x2208, 0xa006, 0x0d7f, 0x0e7f, + 0x047f, 0x007c, 0xa084, 0x0007, 0x0079, 0x57bf, 0x007c, 0x57c7, + 0x57c7, 0x57c7, 0x5933, 0x57c7, 0x57c8, 0x57e1, 0x5858, 0x007c, + 0x7110, 0xd1bc, 0x0040, 0x57e0, 0x7120, 0x2160, 0xac8c, 0x000f, + 0x00c0, 0x57e0, 0xac8a, 0xad00, 0x0048, 0x57e0, 0x6858, 0xac02, + 0x00c8, 0x57e0, 0x7124, 0x610a, 0x2009, 0x0046, 0x1078, 0x775c, + 0x007c, 0x0c7e, 0xa484, 0x01ff, 0x0040, 0x5833, 0x7110, 0xd1bc, + 0x00c0, 0x5833, 0x2011, 0xab83, 0x2204, 0x8211, 0x220c, 0x1078, + 0x254d, 0x00c0, 0x5833, 0x1078, 0x455c, 0x00c0, 0x5833, 0x6612, + 0x6516, 0x6000, 0xd0ec, 0x00c0, 0x5833, 0x6204, 0xa294, 0xff00, + 0x8217, 0xa286, 0x0006, 0x00c0, 0x5818, 0x0c7e, 0x1078, 0x76c7, + 0x017f, 0x0040, 0x5835, 0x611a, 0x601f, 0x0006, 0x7120, 0x610a, + 0x7130, 0x6122, 0x2009, 0x0044, 0x1078, 0x775c, 0x0078, 0x5833, + 0x0c7e, 0x1078, 0x76c7, 0x017f, 0x0040, 0x5833, 0x611a, 0x601f, + 0x0004, 0x7120, 0x610a, 0xa286, 0x0004, 0x00c0, 0x582b, 0x6007, + 0x0005, 0x0078, 0x582d, 0x6007, 0x0001, 0x6003, 0x0001, 0x1078, + 0x5dd7, 0x1078, 0x62d1, 0x0c7f, 0x007c, 0x2001, 0xa60d, 0x2004, + 0xd0ec, 0x0040, 0x583f, 0x2011, 0x8049, 0x1078, 0x361b, 0x0c7e, + 0x1078, 0x9187, 0x017f, 0x0040, 0x5833, 0x611a, 0x601f, 0x0006, + 0x7120, 0x610a, 0x7130, 0x6122, 0x6013, 0x0300, 0x6003, 0x0001, + 0x6007, 0x0041, 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x0078, 0x5833, + 0x7110, 0xd1bc, 0x0040, 0x5870, 0x7020, 0x2060, 0xac84, 0x000f, + 0x00c0, 0x5870, 0xac82, 0xad00, 0x0048, 0x5870, 0x6858, 0xac02, + 0x00c8, 0x5870, 0x7124, 0x610a, 0x2009, 0x0045, 0x1078, 0x775c, + 0x007c, 0x007e, 0x1078, 0x29bb, 0x007f, 0x00c0, 0x5887, 0x7110, + 0xa18c, 0xff00, 0x810f, 0xa18e, 0x0000, 0x00c0, 0x5887, 0xa084, + 0x000f, 0xa08a, 0x0006, 0x00c8, 0x5887, 0x1079, 0x5888, 0x007c, + 0x588e, 0x588f, 0x588e, 0x588e, 0x58ff, 0x590e, 0x007c, 0x7110, + 0xd1bc, 0x0040, 0x5897, 0x702c, 0xd084, 0x0040, 0x58fe, 0x700c, + 0x7108, 0x1078, 0x254d, 0x00c0, 0x58fe, 0x1078, 0x455c, 0x00c0, + 0x58fe, 0x6612, 0x6516, 0x6204, 0x7110, 0xd1bc, 0x0040, 0x58c9, + 0xa28c, 0x00ff, 0xa186, 0x0004, 0x0040, 0x58b2, 0xa186, 0x0006, + 0x00c0, 0x58ef, 0x0c7e, 0x1078, 0x591d, 0x0c7f, 0x0040, 0x58fe, + 0x0c7e, 0x1078, 0x76c7, 0x017f, 0x0040, 0x58fe, 0x611a, 0x601f, + 0x0002, 0x7120, 0x610a, 0x2009, 0x0088, 0x1078, 0x775c, 0x0078, + 0x58fe, 0xa28c, 0x00ff, 0xa186, 0x0006, 0x0040, 0x58de, 0xa186, + 0x0004, 0x0040, 0x58de, 0xa294, 0xff00, 0x8217, 0xa286, 0x0004, + 0x0040, 0x58de, 0xa286, 0x0006, 0x00c0, 0x58ef, 0x0c7e, 0x1078, + 0x76c7, 0x017f, 0x0040, 0x58fe, 0x611a, 0x601f, 0x0005, 0x7120, + 0x610a, 0x2009, 0x0088, 0x1078, 0x775c, 0x0078, 0x58fe, 0x0c7e, + 0x1078, 0x76c7, 0x017f, 0x0040, 0x58fe, 0x611a, 0x601f, 0x0004, + 0x7120, 0x610a, 0x2009, 0x0001, 0x1078, 0x775c, 0x007c, 0x7110, + 0xd1bc, 0x0040, 0x590d, 0x1078, 0x591d, 0x0040, 0x590d, 0x7124, + 0x610a, 0x2009, 0x0089, 0x1078, 0x775c, 0x007c, 0x7110, 0xd1bc, + 0x0040, 0x591c, 0x1078, 0x591d, 0x0040, 0x591c, 0x7124, 0x610a, + 0x2009, 0x008a, 0x1078, 0x775c, 0x007c, 0x7020, 0x2060, 0xac84, + 0x000f, 0x00c0, 0x5930, 0xac82, 0xad00, 0x0048, 0x5930, 0x2001, + 0xa616, 0x2004, 0xac02, 0x00c8, 0x5930, 0xa085, 0x0001, 0x007c, + 0xa006, 0x0078, 0x592f, 0x7110, 0xd1bc, 0x00c0, 0x5949, 0x7024, + 0x2060, 0xac84, 0x000f, 0x00c0, 0x5949, 0xac82, 0xad00, 0x0048, + 0x5949, 0x6858, 0xac02, 0x00c8, 0x5949, 0x2009, 0x0051, 0x1078, + 0x775c, 0x007c, 0x2071, 0xa8c4, 0x7003, 0x0003, 0x700f, 0x0361, + 0xa006, 0x701a, 0x7012, 0x7017, 0xad00, 0x7007, 0x0000, 0x7026, + 0x702b, 0x6e1c, 0x7032, 0x7037, 0x6e70, 0x703b, 0x0002, 0x703f, + 0x0000, 0x7043, 0xffff, 0x7047, 0xffff, 0x007c, 0x2071, 0xa8c4, + 0x00e0, 0x5a32, 0x2091, 0x6000, 0x700c, 0x8001, 0x700e, 0x00c0, + 0x59de, 0x700f, 0x0361, 0x7007, 0x0001, 0x127e, 0x2091, 0x8000, + 0x7138, 0x8109, 0x713a, 0x00c0, 0x59dc, 0x703b, 0x0002, 0x2009, + 0x0100, 0x2104, 0xa082, 0x0003, 0x00c8, 0x59dc, 0x703c, 0xa086, + 0x0001, 0x00c0, 0x59b9, 0x0d7e, 0x2069, 0x0140, 0x6804, 0xa084, + 0x4000, 0x0040, 0x5997, 0x6803, 0x1000, 0x0078, 0x599e, 0x6804, + 0xa084, 0x1000, 0x0040, 0x599e, 0x6803, 0x0100, 0x6803, 0x0000, + 0x703f, 0x0000, 0x2069, 0xa8b1, 0x6804, 0xa082, 0x0006, 0x00c0, + 0x59ab, 0x6807, 0x0000, 0x6830, 0xa082, 0x0003, 0x00c0, 0x59b2, + 0x6833, 0x0000, 0x1078, 0x62d1, 0x1078, 0x639b, 0x0d7f, 0x0078, + 0x59dc, 0x0d7e, 0x2069, 0xa600, 0x6948, 0x6864, 0xa102, 0x00c8, + 0x59db, 0x2069, 0xa8b1, 0x6804, 0xa086, 0x0000, 0x00c0, 0x59db, + 0x6830, 0xa086, 0x0000, 0x00c0, 0x59db, 0x703f, 0x0001, 0x6807, + 0x0006, 0x6833, 0x0003, 0x2069, 0x0100, 0x6830, 0x689e, 0x2069, + 0x0140, 0x6803, 0x0600, 0x0d7f, 0x0078, 0x59e1, 0x127e, 0x2091, + 0x8000, 0x7024, 0xa00d, 0x0040, 0x59f9, 0x7020, 0x8001, 0x7022, + 0x00c0, 0x59f9, 0x7023, 0x0009, 0x8109, 0x7126, 0xa186, 0x03e8, + 0x00c0, 0x59f4, 0x7028, 0x107a, 0x81ff, 0x00c0, 0x59f9, 0x7028, + 0x107a, 0x7030, 0xa00d, 0x0040, 0x5a10, 0x702c, 0x8001, 0x702e, + 0x00c0, 0x5a10, 0x702f, 0x0009, 0x8109, 0x7132, 0x0040, 0x5a0e, + 0xa184, 0x007f, 0x1040, 0x6ea2, 0x0078, 0x5a10, 0x7034, 0x107a, + 0x7040, 0xa005, 0x0040, 0x5a18, 0x0050, 0x5a18, 0x8001, 0x7042, + 0x7044, 0xa005, 0x0040, 0x5a20, 0x0050, 0x5a20, 0x8001, 0x7046, + 0x7018, 0xa00d, 0x0040, 0x5a31, 0x7008, 0x8001, 0x700a, 0x00c0, + 0x5a31, 0x700b, 0x0009, 0x8109, 0x711a, 0x00c0, 0x5a31, 0x701c, + 0x107a, 0x127f, 0x7004, 0x0079, 0x5a35, 0x5a5c, 0x5a5d, 0x5a79, + 0x0e7e, 0x2071, 0xa8c4, 0x7018, 0xa005, 0x00c0, 0x5a43, 0x711a, + 0x721e, 0x700b, 0x0009, 0x0e7f, 0x007c, 0x0e7e, 0x007e, 0x2071, + 0xa8c4, 0x701c, 0xa206, 0x00c0, 0x5a4f, 0x701a, 0x701e, 0x007f, + 0x0e7f, 0x007c, 0x0e7e, 0x2071, 0xa8c4, 0x6088, 0xa102, 0x0048, + 0x5a5a, 0x618a, 0x0e7f, 0x007c, 0x007c, 0x7110, 0x1078, 0x45c4, + 0x00c0, 0x5a6f, 0x6088, 0x8001, 0x0048, 0x5a6f, 0x608a, 0x00c0, + 0x5a6f, 0x127e, 0x2091, 0x8000, 0x1078, 0x62d1, 0x127f, 0x8108, + 0xa182, 0x00ff, 0x0048, 0x5a77, 0xa00e, 0x7007, 0x0002, 0x7112, + 0x007c, 0x7014, 0x2060, 0x127e, 0x2091, 0x8000, 0x603c, 0xa005, + 0x0040, 0x5a88, 0x8001, 0x603e, 0x00c0, 0x5a88, 0x1078, 0x8f9c, + 0x6014, 0xa005, 0x0040, 0x5ab2, 0x8001, 0x6016, 0x00c0, 0x5ab2, + 0x611c, 0xa186, 0x0003, 0x0040, 0x5a99, 0xa186, 0x0006, 0x00c0, + 0x5ab0, 0x6010, 0x2068, 0x6854, 0xa08a, 0x199a, 0x0048, 0x5ab0, + 0xa082, 0x1999, 0x6856, 0xa08a, 0x199a, 0x0048, 0x5aa9, 0x2001, + 0x1999, 0x8003, 0x800b, 0x810b, 0xa108, 0x6116, 0x0078, 0x5ab2, + 0x1078, 0x8abe, 0x127f, 0xac88, 0x0010, 0x7116, 0x2001, 0xcd00, + 0xa102, 0x0048, 0x5abf, 0x7017, 0xad00, 0x7007, 0x0000, 0x007c, + 0x0e7e, 0x2071, 0xa8c4, 0x7027, 0x07d0, 0x7023, 0x0009, 0x703b, + 0x0002, 0x0e7f, 0x007c, 0x2001, 0xa8cd, 0x2003, 0x0000, 0x007c, + 0x0e7e, 0x2071, 0xa8c4, 0x7132, 0x702f, 0x0009, 0x0e7f, 0x007c, + 0x2011, 0xa8d0, 0x2013, 0x0000, 0x007c, 0x0e7e, 0x2071, 0xa8c4, + 0x711a, 0x721e, 0x700b, 0x0009, 0x0e7f, 0x007c, 0x027e, 0x0e7e, + 0x0f7e, 0x2079, 0xa600, 0x7a34, 0xd294, 0x0040, 0x5b15, 0x2071, + 0xa8ac, 0x2e14, 0xa0fe, 0x0000, 0x0040, 0x5b02, 0xa0fe, 0x0001, + 0x0040, 0x5b06, 0xa0fe, 0x0002, 0x00c0, 0x5b11, 0xa292, 0x0085, + 0x0078, 0x5b08, 0xa292, 0x0005, 0x0078, 0x5b08, 0xa292, 0x0002, + 0x2272, 0x0040, 0x5b0d, 0x00c8, 0x5b15, 0x2011, 0x8037, 0x1078, + 0x361b, 0x2011, 0xa8ab, 0x2204, 0x2072, 0x0f7f, 0x0e7f, 0x027f, + 0x007c, 0x0c7e, 0x2061, 0xa933, 0x0c7f, 0x007c, 0xa184, 0x000f, + 0x8003, 0x8003, 0x8003, 0xa080, 0xa933, 0x2060, 0x007c, 0x6854, + 0xa08a, 0x199a, 0x0048, 0x5b2e, 0x2001, 0x1999, 0xa005, 0x00c0, + 0x5b3d, 0x0c7e, 0x2061, 0xa933, 0x6014, 0x0c7f, 0xa005, 0x00c0, + 0x5b42, 0x2001, 0x001e, 0x0078, 0x5b42, 0xa08e, 0xffff, 0x00c0, + 0x5b42, 0xa006, 0x8003, 0x800b, 0x810b, 0xa108, 0x6116, 0x684c, + 0xa08c, 0x00c0, 0xa18e, 0x00c0, 0x0040, 0x5b9e, 0xd0b4, 0x00c0, + 0x5b59, 0xd0bc, 0x00c0, 0x5b8b, 0x2009, 0x0006, 0x1078, 0x5bc3, + 0x007c, 0xd0fc, 0x0040, 0x5b64, 0xa084, 0x0003, 0x0040, 0x5b64, + 0xa086, 0x0003, 0x00c0, 0x5bbc, 0x6024, 0xd0d4, 0x0040, 0x5b6e, + 0xc0d4, 0x6026, 0x6860, 0x602a, 0x685c, 0x602e, 0x2009, 0xa674, + 0x2104, 0xd084, 0x0040, 0x5b83, 0x6118, 0xa188, 0x0027, 0x2104, + 0xd08c, 0x00c0, 0x5b83, 0x87ff, 0x00c0, 0x5b82, 0x2009, 0x0042, + 0x1078, 0x775c, 0x007c, 0x87ff, 0x00c0, 0x5b8a, 0x2009, 0x0043, + 0x1078, 0x775c, 0x007c, 0xd0fc, 0x0040, 0x5b96, 0xa084, 0x0003, + 0x0040, 0x5b96, 0xa086, 0x0003, 0x00c0, 0x5bbc, 0x87ff, 0x00c0, + 0x5b9d, 0x2009, 0x0042, 0x1078, 0x775c, 0x007c, 0xd0fc, 0x0040, + 0x5baf, 0xa084, 0x0003, 0xa08e, 0x0002, 0x0040, 0x5bb3, 0x87ff, + 0x00c0, 0x5bae, 0x2009, 0x0041, 0x1078, 0x775c, 0x007c, 0x1078, + 0x5bc1, 0x0078, 0x5bae, 0x87ff, 0x00c0, 0x5bae, 0x2009, 0x0043, + 0x1078, 0x775c, 0x0078, 0x5bae, 0x2009, 0x0004, 0x1078, 0x5bc3, + 0x007c, 0x2009, 0x0001, 0x0d7e, 0x6010, 0xa0ec, 0xf000, 0x0040, + 0x5bef, 0x2068, 0x6952, 0x6800, 0x6012, 0xa186, 0x0001, 0x00c0, + 0x5be5, 0x694c, 0xa18c, 0x8100, 0xa18e, 0x8100, 0x00c0, 0x5be5, + 0x0c7e, 0x2061, 0xa933, 0x6200, 0xd28c, 0x00c0, 0x5be4, 0x6204, + 0x8210, 0x0048, 0x5be4, 0x6206, 0x0c7f, 0x1078, 0x4a73, 0x6010, + 0xa06d, 0x077e, 0x2039, 0x0000, 0x10c0, 0x5b27, 0x077f, 0x0d7f, + 0x007c, 0x157e, 0x0c7e, 0x2061, 0xa933, 0x6000, 0x81ff, 0x0040, + 0x5bfc, 0xa205, 0x0078, 0x5bfd, 0xa204, 0x6002, 0x0c7f, 0x157f, + 0x007c, 0x6800, 0xd08c, 0x00c0, 0x5c0d, 0x6808, 0xa005, 0x0040, + 0x5c0d, 0x8001, 0x680a, 0xa085, 0x0001, 0x007c, 0x20a9, 0x0010, + 0xa006, 0x8004, 0x8086, 0x818e, 0x00c8, 0x5c17, 0xa200, 0x00f0, + 0x5c12, 0x8086, 0x818e, 0x007c, 0x157e, 0x20a9, 0x0010, 0xa005, + 0x0040, 0x5c3d, 0xa11a, 0x00c8, 0x5c3d, 0x8213, 0x818d, 0x0048, + 0x5c30, 0xa11a, 0x00c8, 0x5c31, 0x00f0, 0x5c25, 0x0078, 0x5c35, + 0xa11a, 0x2308, 0x8210, 0x00f0, 0x5c25, 0x007e, 0x3200, 0xa084, + 0xf7ff, 0x2080, 0x007f, 0x157f, 0x007c, 0x007e, 0x3200, 0xa085, + 0x0800, 0x0078, 0x5c39, 0x127e, 0x2091, 0x2200, 0x2079, 0xa8b1, + 0x127f, 0x0d7e, 0x2069, 0xa8b1, 0x6803, 0x0005, 0x2069, 0x0004, + 0x2d04, 0xa085, 0x8001, 0x206a, 0x0d7f, 0x007c, 0x0c7e, 0x6027, + 0x0001, 0x7804, 0xa084, 0x0007, 0x0079, 0x5c5e, 0x5c68, 0x5c8d, + 0x5ce8, 0x5c6e, 0x5c8d, 0x5c68, 0x5c66, 0x5c66, 0x1078, 0x1332, + 0x1078, 0x5acb, 0x1078, 0x62d1, 0x0c7f, 0x007c, 0x62c0, 0x82ff, + 0x00c0, 0x5c74, 0x0c7f, 0x007c, 0x2011, 0x41dc, 0x1078, 0x5a45, + 0x7828, 0xa092, 0x00c8, 0x00c8, 0x5c83, 0x8000, 0x782a, 0x1078, + 0x421b, 0x0078, 0x5c72, 0x1078, 0x41dc, 0x7807, 0x0003, 0x7827, + 0x0000, 0x782b, 0x0000, 0x0078, 0x5c72, 0x1078, 0x5acb, 0x3c00, + 0x007e, 0x2011, 0x0209, 0x20e1, 0x4000, 0x2214, 0x007f, 0x20e0, + 0x82ff, 0x0040, 0x5cab, 0x62c0, 0x82ff, 0x00c0, 0x5cab, 0x782b, + 0x0000, 0x7824, 0xa065, 0x1040, 0x1332, 0x2009, 0x0013, 0x1078, + 0x775c, 0x0c7f, 0x007c, 0x3900, 0xa082, 0xa9e3, 0x00c8, 0x5cb2, + 0x1078, 0x747a, 0x0c7e, 0x7824, 0xa065, 0x1040, 0x1332, 0x7804, + 0xa086, 0x0004, 0x0040, 0x5d2d, 0x7828, 0xa092, 0x2710, 0x00c8, + 0x5cc8, 0x8000, 0x782a, 0x0c7f, 0x1078, 0x6e01, 0x0078, 0x5ca9, + 0x6104, 0xa186, 0x0003, 0x00c0, 0x5cdf, 0x0e7e, 0x2071, 0xa600, + 0x70d8, 0x0e7f, 0xd08c, 0x0040, 0x5cdf, 0x0c7e, 0x0e7e, 0x2061, + 0x0100, 0x2071, 0xa600, 0x1078, 0x4224, 0x0e7f, 0x0c7f, 0x1078, + 0xa5c4, 0x2009, 0x0014, 0x1078, 0x775c, 0x0c7f, 0x0078, 0x5ca9, + 0x2001, 0xa8cd, 0x2003, 0x0000, 0x62c0, 0x82ff, 0x00c0, 0x5cfc, + 0x782b, 0x0000, 0x7824, 0xa065, 0x1040, 0x1332, 0x2009, 0x0013, + 0x1078, 0x77b3, 0x0c7f, 0x007c, 0x0c7e, 0x0d7e, 0x3900, 0xa082, + 0xa9e3, 0x00c8, 0x5d05, 0x1078, 0x747a, 0x7824, 0xa005, 0x1040, + 0x1332, 0x781c, 0xa06d, 0x1040, 0x1332, 0x6800, 0xc0dc, 0x6802, + 0x7924, 0x2160, 0x1078, 0x772d, 0x693c, 0x81ff, 0x1040, 0x1332, + 0x8109, 0x693e, 0x6854, 0xa015, 0x0040, 0x5d21, 0x7a1e, 0x0078, + 0x5d23, 0x7918, 0x791e, 0x7807, 0x0000, 0x7827, 0x0000, 0x0d7f, + 0x0c7f, 0x1078, 0x62d1, 0x0078, 0x5cfa, 0x6104, 0xa186, 0x0002, + 0x0040, 0x5d38, 0xa186, 0x0004, 0x0040, 0x5d38, 0x0078, 0x5cbc, + 0x7808, 0xac06, 0x0040, 0x5cbc, 0x1078, 0x61cd, 0x1078, 0x5dd7, + 0x0c7f, 0x1078, 0x62d1, 0x0078, 0x5ca9, 0x0c7e, 0x6027, 0x0002, + 0x62c8, 0x82ff, 0x00c0, 0x5d61, 0x62c4, 0x82ff, 0x00c0, 0x5d61, + 0x793c, 0xa1e5, 0x0000, 0x0040, 0x5d5b, 0x2009, 0x0049, 0x1078, + 0x775c, 0x0c7f, 0x007c, 0x2011, 0xa8d0, 0x2013, 0x0000, 0x0078, + 0x5d59, 0x3908, 0xa192, 0xa9e3, 0x00c8, 0x5d68, 0x1078, 0x747a, + 0x6017, 0x0010, 0x793c, 0x81ff, 0x0040, 0x5d5b, 0x7944, 0xa192, + 0x7530, 0x00c8, 0x5d85, 0x8108, 0x7946, 0x793c, 0xa188, 0x0007, + 0x210c, 0xa18e, 0x0006, 0x00c0, 0x5d81, 0x6017, 0x0012, 0x0078, + 0x5d59, 0x6017, 0x0016, 0x0078, 0x5d59, 0x7848, 0xc085, 0x784a, + 0x0078, 0x5d59, 0x007e, 0x017e, 0x0c7e, 0x127e, 0x2091, 0x8000, + 0x600f, 0x0000, 0x2c08, 0x2061, 0xa8b1, 0x6020, 0x8000, 0x6022, + 0x6010, 0xa005, 0x0040, 0x5da5, 0xa080, 0x0003, 0x2102, 0x6112, + 0x127f, 0x0c7f, 0x017f, 0x007f, 0x007c, 0x6116, 0x6112, 0x0078, + 0x5da0, 0x0d7e, 0x2069, 0xa8b1, 0x6000, 0xd0d4, 0x0040, 0x5dbe, + 0x6820, 0x8000, 0x6822, 0xa086, 0x0001, 0x00c0, 0x5db9, 0x2c00, + 0x681e, 0x6804, 0xa084, 0x0007, 0x0079, 0x62d9, 0xc0d5, 0x6002, + 0x6818, 0xa005, 0x0040, 0x5dd0, 0x6056, 0x605b, 0x0000, 0x007e, + 0x2c00, 0x681a, 0x0d7f, 0x685a, 0x2069, 0xa8b1, 0x0078, 0x5db0, + 0x6056, 0x605a, 0x2c00, 0x681a, 0x681e, 0x0078, 0x5db0, 0x007e, + 0x017e, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x600f, 0x0000, 0x2c08, + 0x2061, 0xa8b1, 0x6020, 0x8000, 0x6022, 0x6008, 0xa005, 0x0040, + 0x5df2, 0xa080, 0x0003, 0x2102, 0x610a, 0x127f, 0x0c7f, 0x017f, + 0x007f, 0x007c, 0x610e, 0x610a, 0x0078, 0x5ded, 0x0c7e, 0x600f, + 0x0000, 0x2c08, 0x2061, 0xa8b1, 0x6034, 0xa005, 0x0040, 0x5e06, + 0xa080, 0x0003, 0x2102, 0x6136, 0x0c7f, 0x007c, 0x613a, 0x6136, + 0x0078, 0x5e04, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x057e, + 0x037e, 0x027e, 0x017e, 0x007e, 0x127e, 0xa02e, 0x2071, 0xa8b1, + 0x7638, 0x2660, 0x2678, 0x2091, 0x8000, 0x8cff, 0x0040, 0x5e8c, + 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, 0x00c0, 0x5e87, 0x87ff, + 0x0040, 0x5e2e, 0x6020, 0xa106, 0x00c0, 0x5e87, 0x703c, 0xac06, + 0x00c0, 0x5e44, 0x037e, 0x2019, 0x0001, 0x1078, 0x7058, 0x7033, + 0x0000, 0x703f, 0x0000, 0x7043, 0x0000, 0x7047, 0x0000, 0x704b, + 0x0000, 0x037f, 0x2029, 0x0001, 0x7038, 0xac36, 0x00c0, 0x5e4a, + 0x660c, 0x763a, 0x7034, 0xac36, 0x00c0, 0x5e58, 0x2c00, 0xaf36, + 0x0040, 0x5e56, 0x2f00, 0x7036, 0x0078, 0x5e58, 0x7037, 0x0000, + 0x660c, 0x067e, 0x2c00, 0xaf06, 0x0040, 0x5e61, 0x7e0e, 0x0078, + 0x5e62, 0x2678, 0x600f, 0x0000, 0x1078, 0x8d06, 0x0040, 0x5e82, + 0x6010, 0x2068, 0x601c, 0xa086, 0x0003, 0x00c0, 0x5e9d, 0x6837, + 0x0103, 0x6b4a, 0x6847, 0x0000, 0x017e, 0x037e, 0x077e, 0x1078, + 0x8f7d, 0x1078, 0xa4e2, 0x1078, 0x4a73, 0x077f, 0x037f, 0x017f, + 0x1078, 0x8eb9, 0x1078, 0x8ec6, 0x0c7f, 0x0078, 0x5e1d, 0x2c78, + 0x600c, 0x2060, 0x0078, 0x5e1d, 0x85ff, 0x0040, 0x5e91, 0x1078, + 0x639b, 0x127f, 0x007f, 0x017f, 0x027f, 0x037f, 0x057f, 0x067f, + 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x601c, 0xa086, 0x0006, + 0x00c0, 0x5e6f, 0x017e, 0x037e, 0x077e, 0x1078, 0xa4e2, 0x1078, + 0xa1ca, 0x077f, 0x037f, 0x017f, 0x0078, 0x5e82, 0x007e, 0x067e, + 0x0c7e, 0x0d7e, 0x0f7e, 0x2031, 0x0000, 0x127e, 0x2091, 0x8000, + 0x2079, 0xa8b1, 0x7838, 0xa065, 0x0040, 0x5eef, 0x600c, 0x007e, + 0x600f, 0x0000, 0x783c, 0xac06, 0x00c0, 0x5ed6, 0x037e, 0x2019, + 0x0001, 0x1078, 0x7058, 0x7833, 0x0000, 0x783f, 0x0000, 0x7843, + 0x0000, 0x7847, 0x0000, 0x784b, 0x0000, 0x037f, 0x1078, 0x8d06, + 0x0040, 0x5eea, 0x6010, 0x2068, 0x601c, 0xa086, 0x0003, 0x00c0, + 0x5ef8, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x4a73, + 0x1078, 0x8eb9, 0x1078, 0x8ec6, 0x007f, 0x0078, 0x5ebb, 0x7e3a, + 0x7e36, 0x127f, 0x0f7f, 0x0d7f, 0x0c7f, 0x067f, 0x007f, 0x007c, + 0x601c, 0xa086, 0x0006, 0x00c0, 0x5ee1, 0x1078, 0xa1ca, 0x0078, + 0x5eea, 0x017e, 0x027e, 0x087e, 0x2041, 0x0000, 0x1078, 0x5f1b, + 0x1078, 0x5fdb, 0x087f, 0x027f, 0x017f, 0x007c, 0x0f7e, 0x127e, + 0x2079, 0xa8b1, 0x2091, 0x8000, 0x1078, 0x6076, 0x1078, 0x60ec, + 0x127f, 0x0f7f, 0x007c, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, + 0x017e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2071, 0xa8b1, 0x7614, + 0x2660, 0x2678, 0x8cff, 0x0040, 0x5fb5, 0x6018, 0xa080, 0x0028, + 0x2004, 0xa206, 0x00c0, 0x5fb0, 0x88ff, 0x0040, 0x5f3b, 0x6020, + 0xa106, 0x00c0, 0x5fb0, 0x7024, 0xac06, 0x00c0, 0x5f6b, 0x2069, + 0x0100, 0x68c0, 0xa005, 0x0040, 0x5f66, 0x1078, 0x5acb, 0x1078, + 0x6e0f, 0x68c3, 0x0000, 0x1078, 0x7378, 0x7027, 0x0000, 0x037e, + 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0040, 0x5f5b, 0x6803, + 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0040, + 0x5f63, 0x6827, 0x0001, 0x037f, 0x0078, 0x5f6b, 0x6003, 0x0009, + 0x630a, 0x0078, 0x5fb0, 0x7014, 0xac36, 0x00c0, 0x5f71, 0x660c, + 0x7616, 0x7010, 0xac36, 0x00c0, 0x5f7f, 0x2c00, 0xaf36, 0x0040, + 0x5f7d, 0x2f00, 0x7012, 0x0078, 0x5f7f, 0x7013, 0x0000, 0x660c, + 0x067e, 0x2c00, 0xaf06, 0x0040, 0x5f88, 0x7e0e, 0x0078, 0x5f89, + 0x2678, 0x600f, 0x0000, 0x6010, 0x2068, 0x1078, 0x8d06, 0x0040, + 0x5fa9, 0x601c, 0xa086, 0x0003, 0x00c0, 0x5fbe, 0x6837, 0x0103, + 0x6b4a, 0x6847, 0x0000, 0x017e, 0x037e, 0x087e, 0x1078, 0x8f7d, + 0x1078, 0xa4e2, 0x1078, 0x4a73, 0x087f, 0x037f, 0x017f, 0x1078, + 0x8eb9, 0x1078, 0x8ec6, 0x1078, 0x7233, 0x0c7f, 0x0078, 0x5f2a, + 0x2c78, 0x600c, 0x2060, 0x0078, 0x5f2a, 0x127f, 0x007f, 0x017f, + 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x601c, 0xa086, + 0x0006, 0x00c0, 0x5fcf, 0x017e, 0x037e, 0x087e, 0x1078, 0xa4e2, + 0x1078, 0xa1ca, 0x087f, 0x037f, 0x017f, 0x0078, 0x5fa9, 0x601c, + 0xa086, 0x0002, 0x00c0, 0x5fa9, 0x6004, 0xa086, 0x0085, 0x0040, + 0x5f96, 0x0078, 0x5fa9, 0x0c7e, 0x007e, 0x127e, 0x2091, 0x8000, + 0xa280, 0xa735, 0x2004, 0xa065, 0x0040, 0x6072, 0x0f7e, 0x0e7e, + 0x0d7e, 0x067e, 0x2071, 0xa8b1, 0x6654, 0x7018, 0xac06, 0x00c0, + 0x5ff2, 0x761a, 0x701c, 0xac06, 0x00c0, 0x5ffe, 0x86ff, 0x00c0, + 0x5ffd, 0x7018, 0x701e, 0x0078, 0x5ffe, 0x761e, 0x6058, 0xa07d, + 0x0040, 0x6003, 0x7e56, 0xa6ed, 0x0000, 0x0040, 0x6009, 0x2f00, + 0x685a, 0x6057, 0x0000, 0x605b, 0x0000, 0x6000, 0xc0d4, 0xc0dc, + 0x6002, 0x1078, 0x44d3, 0x0040, 0x606e, 0x7624, 0x86ff, 0x0040, + 0x605c, 0xa680, 0x0004, 0x2004, 0xad06, 0x00c0, 0x605c, 0x0d7e, + 0x2069, 0x0100, 0x68c0, 0xa005, 0x0040, 0x6053, 0x1078, 0x5acb, + 0x1078, 0x6e0f, 0x68c3, 0x0000, 0x1078, 0x7378, 0x7027, 0x0000, + 0x037e, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0040, 0x603c, + 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, + 0x0040, 0x6044, 0x6827, 0x0001, 0x037f, 0x0d7f, 0x0c7e, 0x603c, + 0xa005, 0x0040, 0x604d, 0x8001, 0x603e, 0x2660, 0x1078, 0x8ec6, + 0x0c7f, 0x0078, 0x605c, 0x0d7f, 0x0c7e, 0x2660, 0x6003, 0x0009, + 0x630a, 0x0c7f, 0x0078, 0x6011, 0x8dff, 0x0040, 0x606a, 0x6837, + 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x8f7d, 0x1078, 0xa4e2, + 0x1078, 0x4a73, 0x1078, 0x7233, 0x0078, 0x6011, 0x067f, 0x0d7f, + 0x0e7f, 0x0f7f, 0x127f, 0x007f, 0x0c7f, 0x007c, 0x007e, 0x067e, + 0x0c7e, 0x0d7e, 0x2031, 0x0000, 0x7814, 0xa065, 0x0040, 0x60d0, + 0x600c, 0x007e, 0x600f, 0x0000, 0x7824, 0xac06, 0x00c0, 0x60b5, + 0x2069, 0x0100, 0x68c0, 0xa005, 0x0040, 0x60af, 0x1078, 0x5acb, + 0x1078, 0x6e0f, 0x68c3, 0x0000, 0x1078, 0x7378, 0x7827, 0x0000, + 0x037e, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0040, 0x60a4, + 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, + 0x0040, 0x60ac, 0x6827, 0x0001, 0x037f, 0x0078, 0x60b5, 0x6003, + 0x0009, 0x630a, 0x2c30, 0x0078, 0x60cd, 0x6010, 0x2068, 0x1078, + 0x8d06, 0x0040, 0x60c9, 0x601c, 0xa086, 0x0003, 0x00c0, 0x60d7, + 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x4a73, 0x1078, + 0x8eb9, 0x1078, 0x8ec6, 0x1078, 0x7233, 0x007f, 0x0078, 0x607d, + 0x7e16, 0x7e12, 0x0d7f, 0x0c7f, 0x067f, 0x007f, 0x007c, 0x601c, + 0xa086, 0x0006, 0x00c0, 0x60e0, 0x1078, 0xa1ca, 0x0078, 0x60c9, + 0x601c, 0xa086, 0x0002, 0x00c0, 0x60c9, 0x6004, 0xa086, 0x0085, + 0x0040, 0x60c0, 0x0078, 0x60c9, 0x007e, 0x067e, 0x0c7e, 0x0d7e, + 0x7818, 0xa065, 0x0040, 0x615a, 0x6054, 0x007e, 0x6057, 0x0000, + 0x605b, 0x0000, 0x6000, 0xc0d4, 0xc0dc, 0x6002, 0x1078, 0x44d3, + 0x0040, 0x6157, 0x7e24, 0x86ff, 0x0040, 0x6149, 0xa680, 0x0004, + 0x2004, 0xad06, 0x00c0, 0x6149, 0x0d7e, 0x2069, 0x0100, 0x68c0, + 0xa005, 0x0040, 0x6140, 0x1078, 0x5acb, 0x1078, 0x6e0f, 0x68c3, + 0x0000, 0x1078, 0x7378, 0x7827, 0x0000, 0x037e, 0x2069, 0x0140, + 0x6b04, 0xa384, 0x1000, 0x0040, 0x6129, 0x6803, 0x0100, 0x6803, + 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0040, 0x6131, 0x6827, + 0x0001, 0x037f, 0x0d7f, 0x0c7e, 0x603c, 0xa005, 0x0040, 0x613a, + 0x8001, 0x603e, 0x2660, 0x1078, 0x8ec6, 0x0c7f, 0x0078, 0x6149, + 0x0d7f, 0x0c7e, 0x2660, 0x6003, 0x0009, 0x630a, 0x0c7f, 0x0078, + 0x60fe, 0x8dff, 0x0040, 0x6153, 0x6837, 0x0103, 0x6b4a, 0x6847, + 0x0000, 0x1078, 0x4a73, 0x1078, 0x7233, 0x0078, 0x60fe, 0x007f, + 0x0078, 0x60f1, 0x781e, 0x781a, 0x0d7f, 0x0c7f, 0x067f, 0x007f, + 0x007c, 0x0e7e, 0x0d7e, 0x067e, 0x6000, 0xd0dc, 0x0040, 0x6181, + 0x604c, 0xa06d, 0x0040, 0x6181, 0x6848, 0xa606, 0x00c0, 0x6181, + 0x2071, 0xa8b1, 0x7024, 0xa035, 0x0040, 0x6181, 0xa080, 0x0004, + 0x2004, 0xad06, 0x00c0, 0x6181, 0x6000, 0xc0dc, 0x6002, 0x1078, + 0x6185, 0x067f, 0x0d7f, 0x0e7f, 0x007c, 0x0f7e, 0x2079, 0x0100, + 0x78c0, 0xa005, 0x00c0, 0x6194, 0x0c7e, 0x2660, 0x6003, 0x0009, + 0x630a, 0x0c7f, 0x0078, 0x61cb, 0x1078, 0x6e0f, 0x78c3, 0x0000, + 0x1078, 0x7378, 0x7027, 0x0000, 0x037e, 0x2079, 0x0140, 0x7b04, + 0xa384, 0x1000, 0x0040, 0x61a8, 0x7803, 0x0100, 0x7803, 0x0000, + 0x2079, 0x0100, 0x7824, 0xd084, 0x0040, 0x61b0, 0x7827, 0x0001, + 0x1078, 0x7378, 0x037f, 0x1078, 0x44d3, 0x0c7e, 0x603c, 0xa005, + 0x0040, 0x61bc, 0x8001, 0x603e, 0x2660, 0x1078, 0x772d, 0x0c7f, + 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x8f7d, 0x1078, + 0x4a73, 0x1078, 0x7233, 0x0f7f, 0x007c, 0x0e7e, 0x0c7e, 0x2071, + 0xa8b1, 0x7004, 0xa084, 0x0007, 0x0079, 0x61d6, 0x61e0, 0x61e3, + 0x61fc, 0x6218, 0x6262, 0x61e0, 0x61e0, 0x61de, 0x1078, 0x1332, + 0x0c7f, 0x0e7f, 0x007c, 0x7024, 0xa065, 0x0040, 0x61f1, 0x7020, + 0x8001, 0x7022, 0x600c, 0xa015, 0x0040, 0x61f8, 0x7216, 0x600f, + 0x0000, 0x7007, 0x0000, 0x7027, 0x0000, 0x0c7f, 0x0e7f, 0x007c, + 0x7216, 0x7212, 0x0078, 0x61f1, 0x6018, 0x2060, 0x1078, 0x44d3, + 0x6000, 0xc0dc, 0x6002, 0x7020, 0x8001, 0x7022, 0x0040, 0x620d, + 0x6054, 0xa015, 0x0040, 0x6214, 0x721e, 0x7007, 0x0000, 0x7027, + 0x0000, 0x0c7f, 0x0e7f, 0x007c, 0x7218, 0x721e, 0x0078, 0x620d, + 0x7024, 0xa065, 0x0040, 0x625f, 0x700c, 0xac06, 0x00c0, 0x622f, + 0x1078, 0x7233, 0x600c, 0xa015, 0x0040, 0x622b, 0x720e, 0x600f, + 0x0000, 0x0078, 0x625d, 0x720e, 0x720a, 0x0078, 0x625d, 0x7014, + 0xac06, 0x00c0, 0x6242, 0x1078, 0x7233, 0x600c, 0xa015, 0x0040, + 0x623e, 0x7216, 0x600f, 0x0000, 0x0078, 0x625d, 0x7216, 0x7212, + 0x0078, 0x625d, 0x601c, 0xa086, 0x0003, 0x00c0, 0x625d, 0x6018, + 0x2060, 0x1078, 0x44d3, 0x6000, 0xc0dc, 0x6002, 0x1078, 0x7233, + 0x701c, 0xa065, 0x0040, 0x625d, 0x6054, 0xa015, 0x0040, 0x625b, + 0x721e, 0x0078, 0x625d, 0x7218, 0x721e, 0x7027, 0x0000, 0x0c7f, + 0x0e7f, 0x007c, 0x7024, 0xa065, 0x0040, 0x626f, 0x1078, 0x7233, + 0x600c, 0xa015, 0x0040, 0x6276, 0x720e, 0x600f, 0x0000, 0x1078, + 0x7378, 0x7027, 0x0000, 0x0c7f, 0x0e7f, 0x007c, 0x720e, 0x720a, + 0x0078, 0x626f, 0x0d7e, 0x2069, 0xa8b1, 0x6830, 0xa084, 0x0003, + 0x0079, 0x6282, 0x6288, 0x628a, 0x62b4, 0x6288, 0x1078, 0x1332, + 0x0d7f, 0x007c, 0x0c7e, 0x6840, 0xa086, 0x0001, 0x0040, 0x62aa, + 0x683c, 0xa065, 0x0040, 0x629b, 0x600c, 0xa015, 0x0040, 0x62a6, + 0x6a3a, 0x600f, 0x0000, 0x6833, 0x0000, 0x683f, 0x0000, 0x2011, + 0xa8d0, 0x2013, 0x0000, 0x0c7f, 0x0d7f, 0x007c, 0x683a, 0x6836, + 0x0078, 0x629b, 0x6843, 0x0000, 0x6838, 0xa065, 0x0040, 0x629b, + 0x6003, 0x0003, 0x0078, 0x629b, 0x0c7e, 0x6843, 0x0000, 0x6847, + 0x0000, 0x684b, 0x0000, 0x683c, 0xa065, 0x0040, 0x62ce, 0x600c, + 0xa015, 0x0040, 0x62ca, 0x6a3a, 0x600f, 0x0000, 0x683f, 0x0000, + 0x0078, 0x62ce, 0x683f, 0x0000, 0x683a, 0x6836, 0x0c7f, 0x0d7f, + 0x007c, 0x0d7e, 0x2069, 0xa8b1, 0x6804, 0xa084, 0x0007, 0x0079, + 0x62d9, 0x62e3, 0x638a, 0x638a, 0x638a, 0x638a, 0x638c, 0x638a, + 0x62e1, 0x1078, 0x1332, 0x6820, 0xa005, 0x00c0, 0x62e9, 0x0d7f, + 0x007c, 0x0c7e, 0x680c, 0xa065, 0x0040, 0x62f8, 0x6807, 0x0004, + 0x6826, 0x682b, 0x0000, 0x1078, 0x63d4, 0x0c7f, 0x0d7f, 0x007c, + 0x6814, 0xa065, 0x0040, 0x6306, 0x6807, 0x0001, 0x6826, 0x682b, + 0x0000, 0x1078, 0x63d4, 0x0c7f, 0x0d7f, 0x007c, 0x0e7e, 0x037e, + 0x6a1c, 0xa2f5, 0x0000, 0x0040, 0x6385, 0x704c, 0xa00d, 0x0040, + 0x6315, 0x7088, 0xa005, 0x0040, 0x632d, 0x7054, 0xa075, 0x0040, + 0x631e, 0xa20e, 0x0040, 0x6385, 0x0078, 0x6323, 0x6818, 0xa20e, + 0x0040, 0x6385, 0x2070, 0x704c, 0xa00d, 0x0040, 0x6315, 0x7088, + 0xa005, 0x00c0, 0x6315, 0x2e00, 0x681e, 0x733c, 0x7038, 0xa302, + 0x00c8, 0x6315, 0x1078, 0x76fc, 0x0040, 0x6385, 0x8318, 0x733e, + 0x6112, 0x2e10, 0x621a, 0xa180, 0x0014, 0x2004, 0xa084, 0x00ff, + 0x6032, 0xa180, 0x0014, 0x2003, 0x0000, 0xa180, 0x0015, 0x2004, + 0xa08a, 0x199a, 0x0048, 0x634e, 0x2001, 0x1999, 0x8003, 0x801b, + 0x831b, 0xa318, 0x6316, 0x037f, 0x0f7e, 0x2c78, 0x71a0, 0xd1bc, + 0x0040, 0x6367, 0x7100, 0xd1f4, 0x0040, 0x6363, 0x7114, 0xa18c, + 0x00ff, 0x0078, 0x636c, 0x2009, 0x0000, 0x0078, 0x636c, 0xa1e0, + 0x29c0, 0x2c0c, 0xa18c, 0x00ff, 0x2061, 0x0100, 0x619a, 0x1078, + 0x6965, 0x7300, 0xc3dd, 0x7302, 0x6807, 0x0002, 0x2f18, 0x6b26, + 0x682b, 0x0000, 0x781f, 0x0003, 0x7803, 0x0001, 0x7807, 0x0040, + 0x0f7f, 0x0e7f, 0x0c7f, 0x0d7f, 0x007c, 0x037f, 0x0e7f, 0x0c7f, + 0x0078, 0x6383, 0x0d7f, 0x007c, 0x0c7e, 0x680c, 0xa065, 0x0040, + 0x6398, 0x6807, 0x0004, 0x6826, 0x682b, 0x0000, 0x1078, 0x63d4, + 0x0c7f, 0x0d7f, 0x007c, 0x0f7e, 0x0d7e, 0x2069, 0xa8b1, 0x6830, + 0xa086, 0x0000, 0x00c0, 0x63bb, 0x6838, 0xa07d, 0x0040, 0x63bb, + 0x6833, 0x0001, 0x683e, 0x6847, 0x0000, 0x684b, 0x0000, 0x127e, + 0x0f7e, 0x2091, 0x2200, 0x027f, 0x1078, 0x1d6d, 0x00c0, 0x63be, + 0x127f, 0x1078, 0x6cb3, 0x0d7f, 0x0f7f, 0x007c, 0x127f, 0x6843, + 0x0000, 0x7803, 0x0002, 0x780c, 0xa015, 0x0040, 0x63d0, 0x6a3a, + 0x780f, 0x0000, 0x6833, 0x0000, 0x683f, 0x0000, 0x0078, 0x63bb, + 0x683a, 0x6836, 0x0078, 0x63ca, 0x601c, 0xa084, 0x000f, 0x1079, + 0x63da, 0x007c, 0x63e3, 0x63e8, 0x6809, 0x6922, 0x63e8, 0x6809, + 0x6922, 0x63e3, 0x63e8, 0x1078, 0x61cd, 0x1078, 0x62d1, 0x007c, + 0x157e, 0x137e, 0x147e, 0x0c7e, 0x0f7e, 0x6004, 0xa08a, 0x0044, + 0x10c8, 0x1332, 0x6118, 0x2178, 0x79a0, 0xd1bc, 0x0040, 0x6405, + 0x7900, 0xd1f4, 0x0040, 0x6401, 0x7914, 0xa18c, 0x00ff, 0x0078, + 0x640a, 0x2009, 0x0000, 0x0078, 0x640a, 0xa1f8, 0x29c0, 0x2f0c, + 0xa18c, 0x00ff, 0x2c78, 0x2061, 0x0100, 0x619a, 0xa08a, 0x0040, + 0x00c8, 0x645c, 0x1079, 0x641a, 0x0f7f, 0x0c7f, 0x147f, 0x137f, + 0x157f, 0x007c, 0x64c2, 0x650a, 0x6532, 0x65cd, 0x65fd, 0x6605, + 0x662c, 0x663d, 0x664e, 0x6656, 0x666e, 0x6656, 0x66d9, 0x663d, + 0x66fa, 0x6702, 0x664e, 0x6702, 0x6713, 0x645a, 0x645a, 0x645a, + 0x645a, 0x645a, 0x645a, 0x645a, 0x645a, 0x645a, 0x645a, 0x645a, + 0x6eef, 0x6f14, 0x6f29, 0x6f4c, 0x6f6d, 0x662c, 0x645a, 0x662c, + 0x6656, 0x645a, 0x6532, 0x65cd, 0x645a, 0x749c, 0x6656, 0x645a, + 0x74bc, 0x6656, 0x645a, 0x645a, 0x64bd, 0x646b, 0x645a, 0x74e1, + 0x7558, 0x7640, 0x645a, 0x7651, 0x6626, 0x766d, 0x645a, 0x6f82, + 0x645a, 0x645a, 0x1078, 0x1332, 0x2100, 0x1079, 0x6465, 0x0f7f, + 0x0c7f, 0x147f, 0x137f, 0x157f, 0x007c, 0x6469, 0x6469, 0x6469, + 0x649f, 0x1078, 0x1332, 0x0d7e, 0x20a1, 0x020b, 0x1078, 0x6731, + 0x7810, 0x2068, 0x20a3, 0x2414, 0x20a3, 0x0018, 0x20a3, 0x0800, + 0x683c, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x6850, 0x20a2, 0x6854, 0x20a2, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x60c3, 0x0018, 0x1078, 0x6dfb, 0x0d7f, 0x007c, + 0x0d7e, 0x7818, 0x2068, 0x68a0, 0xa082, 0x007e, 0x0048, 0x649c, + 0xa085, 0x0001, 0x0d7f, 0x007c, 0xa006, 0x0078, 0x649a, 0x0d7e, + 0x20a1, 0x020b, 0x1078, 0x6731, 0x20a3, 0x0500, 0x20a3, 0x0000, + 0x7810, 0xa0e8, 0x000f, 0x6808, 0x20a2, 0x680c, 0x20a2, 0x6810, + 0x20a2, 0x6814, 0x20a2, 0x6818, 0x20a2, 0x681c, 0x20a2, 0x60c3, + 0x0010, 0x1078, 0x6dfb, 0x0d7f, 0x007c, 0x6030, 0x609a, 0x1078, + 0x6dfb, 0x007c, 0x20a1, 0x020b, 0x1078, 0x6731, 0x20a3, 0x5200, + 0x20a3, 0x0000, 0x0d7e, 0x2069, 0xa652, 0x6804, 0xd084, 0x0040, + 0x64dc, 0x6828, 0x20a3, 0x0000, 0x017e, 0x1078, 0x2564, 0x21a2, + 0x017f, 0x0d7f, 0x0078, 0x64e1, 0x0d7f, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x20a9, 0x0004, 0x2099, 0xa605, 0x53a6, 0x20a9, 0x0004, + 0x2099, 0xa601, 0x53a6, 0x7818, 0xa080, 0x0028, 0x2004, 0xa082, + 0x007f, 0x0048, 0x64fb, 0x2001, 0xa61b, 0x20a6, 0x2001, 0xa61c, + 0x20a6, 0x0078, 0x6501, 0x20a3, 0x0000, 0x6030, 0xa084, 0x00ff, + 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x001c, 0x1078, + 0x6dfb, 0x007c, 0x20a1, 0x020b, 0x1078, 0x6731, 0x20a3, 0x0500, + 0x20a3, 0x0000, 0x7818, 0xa080, 0x0028, 0x2004, 0xa082, 0x007f, + 0x0048, 0x6522, 0x2001, 0xa61b, 0x20a6, 0x2001, 0xa61c, 0x20a6, + 0x0078, 0x6528, 0x20a3, 0x0000, 0x6030, 0xa084, 0x00ff, 0x20a2, + 0x20a9, 0x0004, 0x2099, 0xa605, 0x53a6, 0x60c3, 0x0010, 0x1078, + 0x6dfb, 0x007c, 0x20a1, 0x020b, 0x1078, 0x6731, 0x0c7e, 0x7818, + 0x2060, 0x2001, 0x0000, 0x1078, 0x4972, 0x0c7f, 0x7818, 0xa080, + 0x0028, 0x2004, 0xa086, 0x007e, 0x00c0, 0x654d, 0x20a3, 0x0400, + 0x620c, 0xc2b4, 0x620e, 0x0078, 0x654f, 0x20a3, 0x0300, 0x20a3, + 0x0000, 0x7818, 0xa080, 0x0028, 0x2004, 0xa086, 0x007e, 0x00c0, + 0x659c, 0x2099, 0xa88d, 0x33a6, 0x9398, 0x33a6, 0x9398, 0x3304, + 0xa084, 0x3fff, 0x20a2, 0x9398, 0x33a6, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a9, 0x0004, 0x2099, + 0xa605, 0x53a6, 0x20a9, 0x0004, 0x2099, 0xa601, 0x53a6, 0x20a9, + 0x0010, 0x20a3, 0x0000, 0x00f0, 0x6579, 0x2099, 0xa895, 0x3304, + 0xc0dd, 0x20a2, 0x2001, 0xa672, 0x2004, 0xd0e4, 0x0040, 0x6594, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x9398, 0x9398, 0x9398, 0x33a6, + 0x20a9, 0x0004, 0x0078, 0x6596, 0x20a9, 0x0007, 0x20a3, 0x0000, + 0x00f0, 0x6596, 0x0078, 0x65bc, 0x2099, 0xa88d, 0x20a9, 0x0008, + 0x53a6, 0x20a9, 0x0004, 0x2099, 0xa605, 0x53a6, 0x20a9, 0x0004, + 0x2099, 0xa601, 0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x00f0, + 0x65ad, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x00f0, 0x65b3, 0x2099, + 0xa895, 0x20a9, 0x0008, 0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000, + 0x00f0, 0x65be, 0x20a9, 0x000a, 0x20a3, 0x0000, 0x00f0, 0x65c4, + 0x60c3, 0x0074, 0x1078, 0x6dfb, 0x007c, 0x20a1, 0x020b, 0x1078, + 0x6731, 0x20a3, 0x2010, 0x20a3, 0x0014, 0x20a3, 0x0800, 0x20a3, + 0x2000, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x0f7e, + 0x2079, 0xa652, 0x7904, 0x0f7f, 0xd1ac, 0x00c0, 0x65e9, 0xa085, + 0x0020, 0xd1a4, 0x0040, 0x65ee, 0xa085, 0x0010, 0xa085, 0x0002, + 0x0d7e, 0x0078, 0x66b7, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x60c3, 0x0014, 0x1078, 0x6dfb, 0x007c, 0x20a1, 0x020b, 0x1078, + 0x6731, 0x20a3, 0x5000, 0x0078, 0x654f, 0x20a1, 0x020b, 0x1078, + 0x6731, 0x20a3, 0x2110, 0x20a3, 0x0014, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x60c3, 0x0014, 0x1078, 0x6dfb, 0x007c, 0x20a1, 0x020b, + 0x1078, 0x67b9, 0x0078, 0x6630, 0x20a1, 0x020b, 0x1078, 0x67c2, + 0x20a3, 0x0200, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x60c3, 0x0004, 0x1078, 0x6dfb, 0x007c, 0x20a1, 0x020b, 0x1078, + 0x67c2, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0003, 0x20a3, + 0x2a00, 0x60c3, 0x0008, 0x1078, 0x6dfb, 0x007c, 0x20a1, 0x020b, + 0x1078, 0x67c2, 0x20a3, 0x0200, 0x0078, 0x654f, 0x20a1, 0x020b, + 0x1078, 0x67c2, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x7828, 0xa005, + 0x0040, 0x6665, 0x20a2, 0x0078, 0x6667, 0x20a3, 0x0003, 0x7810, + 0x20a2, 0x60c3, 0x0008, 0x1078, 0x6dfb, 0x007c, 0x0d7e, 0x20a1, + 0x020b, 0x1078, 0x67c2, 0x20a3, 0x0210, 0x20a3, 0x0014, 0x20a3, + 0x0800, 0x7818, 0x2068, 0x6894, 0xa086, 0x0014, 0x00c0, 0x6694, + 0x6998, 0xa184, 0xc000, 0x00c0, 0x6690, 0xd1ec, 0x0040, 0x668c, + 0x20a3, 0x2100, 0x0078, 0x6696, 0x20a3, 0x0100, 0x0078, 0x6696, + 0x20a3, 0x0400, 0x0078, 0x6696, 0x20a3, 0x0700, 0xa006, 0x20a2, + 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x0f7e, 0x2079, 0xa652, 0x7904, + 0x0f7f, 0xd1ac, 0x00c0, 0x66a6, 0xa085, 0x0020, 0xd1a4, 0x0040, + 0x66ab, 0xa085, 0x0010, 0x2009, 0xa674, 0x210c, 0xd184, 0x0040, + 0x66b5, 0x699c, 0xd18c, 0x0040, 0x66b7, 0xa085, 0x0002, 0x027e, + 0x2009, 0xa672, 0x210c, 0xd1e4, 0x0040, 0x66c5, 0xc0c5, 0xa094, + 0x0030, 0xa296, 0x0010, 0x0040, 0x66cf, 0xd1ec, 0x0040, 0x66cf, + 0xa094, 0x0030, 0xa296, 0x0010, 0x0040, 0x66cf, 0xc0bd, 0x027f, + 0x20a2, 0x20a2, 0x20a2, 0x60c3, 0x0014, 0x1078, 0x6dfb, 0x0d7f, + 0x007c, 0x20a1, 0x020b, 0x1078, 0x67c2, 0x20a3, 0x0210, 0x20a3, + 0x0014, 0x20a3, 0x0000, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, + 0x6dfb, 0x007c, 0x20a1, 0x020b, 0x1078, 0x67c2, 0x20a3, 0x0200, + 0x0078, 0x64c8, 0x20a1, 0x020b, 0x1078, 0x67c2, 0x20a3, 0x0100, + 0x20a3, 0x0000, 0x20a3, 0x0003, 0x20a3, 0x2a00, 0x60c3, 0x0008, + 0x1078, 0x6dfb, 0x007c, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x20a1, + 0x020b, 0x1078, 0x67c2, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, + 0x000b, 0x20a3, 0x0000, 0x60c3, 0x0008, 0x1078, 0x6dfb, 0x007c, + 0x027e, 0x037e, 0x047e, 0x2019, 0x3200, 0x2021, 0x0800, 0x0078, + 0x6738, 0x027e, 0x037e, 0x047e, 0x2019, 0x2200, 0x2021, 0x0100, + 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2014, + 0xa286, 0x007e, 0x00c0, 0x674b, 0xa385, 0x00ff, 0x20a2, 0x20a3, + 0xfffe, 0x0078, 0x6780, 0xa286, 0x007f, 0x00c0, 0x6757, 0x0d7e, + 0xa385, 0x00ff, 0x20a2, 0x20a3, 0xfffd, 0x0078, 0x676e, 0xd2bc, + 0x0040, 0x6776, 0xa286, 0x0080, 0x0d7e, 0x00c0, 0x6766, 0xa385, + 0x00ff, 0x20a2, 0x20a3, 0xfffc, 0x0078, 0x676e, 0xa2e8, 0xa735, + 0x2d6c, 0x6810, 0xa305, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa61b, + 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x6784, 0x0d7e, 0xa2e8, + 0xa735, 0x2d6c, 0x6810, 0xa305, 0x20a2, 0x6814, 0x20a2, 0x0d7f, + 0x20a3, 0x0000, 0x6230, 0x22a2, 0xa485, 0x0029, 0x20a2, 0x047f, + 0x037f, 0x20a3, 0x0000, 0x1078, 0x6dea, 0x22a2, 0x20a3, 0x0000, + 0x2fa2, 0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f, + 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x20a3, 0x02ff, + 0x2011, 0xfffc, 0x22a2, 0x0d7e, 0x2069, 0xa61b, 0x2da6, 0x8d68, + 0x2da6, 0x0d7f, 0x20a3, 0x2029, 0x20a3, 0x0000, 0x0078, 0x678b, + 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0xfc02, 0x20a3, 0x0000, + 0x007c, 0x027e, 0x037e, 0x047e, 0x2019, 0x3300, 0x2021, 0x0800, + 0x0078, 0x67c9, 0x027e, 0x037e, 0x047e, 0x2019, 0x2300, 0x2021, + 0x0100, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, + 0x2004, 0xa092, 0x007e, 0x0048, 0x67e6, 0x0d7e, 0xa0e8, 0xa735, + 0x2d6c, 0x6810, 0xa305, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa61b, + 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x67f4, 0x0d7e, 0xa0e8, + 0xa735, 0x2d6c, 0x6810, 0xa305, 0x20a2, 0x6814, 0x20a2, 0x0d7f, + 0x20a3, 0x0000, 0x6230, 0x22a2, 0xa485, 0x0098, 0x20a2, 0x20a3, + 0x0000, 0x047f, 0x037f, 0x1078, 0x6dea, 0x22a2, 0x20a3, 0x0000, + 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f, + 0x007c, 0x0c7e, 0x0f7e, 0x6004, 0xa08a, 0x0085, 0x1048, 0x1332, + 0xa08a, 0x008c, 0x10c8, 0x1332, 0x6118, 0x2178, 0x79a0, 0xd1bc, + 0x0040, 0x6827, 0x7900, 0xd1f4, 0x0040, 0x6823, 0x7914, 0xa18c, + 0x00ff, 0x0078, 0x682c, 0x2009, 0x0000, 0x0078, 0x682c, 0xa1f8, + 0x29c0, 0x2f0c, 0xa18c, 0x00ff, 0x2c78, 0x2061, 0x0100, 0x619a, + 0xa082, 0x0085, 0x1079, 0x6837, 0x0f7f, 0x0c7f, 0x007c, 0x6840, + 0x684b, 0x6866, 0x683e, 0x683e, 0x683e, 0x6840, 0x1078, 0x1332, + 0x147e, 0x20a1, 0x020b, 0x1078, 0x6879, 0x60c3, 0x0000, 0x1078, + 0x6dfb, 0x147f, 0x007c, 0x147e, 0x20a1, 0x020b, 0x1078, 0x68ad, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808, 0x20a2, 0x7810, 0x20a2, + 0x20a3, 0x0000, 0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x60c3, 0x000c, 0x1078, 0x6dfb, 0x147f, 0x007c, 0x147e, 0x20a1, + 0x020b, 0x1078, 0x68ee, 0x20a3, 0x0003, 0x20a3, 0x0300, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0004, 0x1078, 0x6dfb, 0x147f, + 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, + 0x0028, 0x2004, 0xa092, 0x007e, 0x0048, 0x6898, 0x0d7e, 0xa0e8, + 0xa735, 0x2d6c, 0x6810, 0xa085, 0x8100, 0x20a2, 0x6814, 0x20a2, + 0x2069, 0xa61b, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x68a7, + 0x0d7e, 0xa0e8, 0xa735, 0x2d6c, 0x6810, 0xa085, 0x8100, 0x20a2, + 0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, + 0x0009, 0x20a3, 0x0000, 0x0078, 0x678b, 0x027e, 0x20e1, 0x9080, + 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0xa092, 0x007e, + 0x0048, 0x68cc, 0x0d7e, 0xa0e8, 0xa735, 0x2d6c, 0x6810, 0xa085, + 0x8400, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa61b, 0x2da6, 0x8d68, + 0x2da6, 0x0d7f, 0x0078, 0x68db, 0x0d7e, 0xa0e8, 0xa735, 0x2d6c, + 0x6810, 0xa085, 0x8400, 0x20a2, 0x6814, 0x20a2, 0x0d7f, 0x20a3, + 0x0000, 0x6230, 0x22a2, 0x20a3, 0x0099, 0x20a3, 0x0000, 0x1078, + 0x6dea, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x7a10, 0x22a2, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f, 0x007c, 0x027e, 0x20e1, + 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0xa092, + 0x007e, 0x0048, 0x690d, 0x0d7e, 0xa0e8, 0xa735, 0x2d6c, 0x6810, + 0xa085, 0x8500, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa61b, 0x2da6, + 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x691c, 0x0d7e, 0xa0e8, 0xa735, + 0x2d6c, 0x6810, 0xa085, 0x8500, 0x20a2, 0x6814, 0x20a2, 0x0d7f, + 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, 0x0099, 0x20a3, 0x0000, + 0x0078, 0x68df, 0x0c7e, 0x0f7e, 0x2c78, 0x7804, 0xa08a, 0x0040, + 0x1048, 0x1332, 0xa08a, 0x0053, 0x10c8, 0x1332, 0x7918, 0x2160, + 0x61a0, 0xd1bc, 0x0040, 0x6941, 0x6100, 0xd1f4, 0x0040, 0x693d, + 0x6114, 0xa18c, 0x00ff, 0x0078, 0x6946, 0x2009, 0x0000, 0x0078, + 0x6946, 0xa1e0, 0x29c0, 0x2c0c, 0xa18c, 0x00ff, 0x2061, 0x0100, + 0x619a, 0xa082, 0x0040, 0x1079, 0x6950, 0x0f7f, 0x0c7f, 0x007c, + 0x6965, 0x6a73, 0x6a14, 0x6c27, 0x6963, 0x6963, 0x6963, 0x6963, + 0x6963, 0x6963, 0x6963, 0x714c, 0x715d, 0x716e, 0x717f, 0x6963, + 0x767e, 0x6963, 0x713b, 0x1078, 0x1332, 0x0d7e, 0x157e, 0x147e, + 0x780b, 0xffff, 0x20a1, 0x020b, 0x1078, 0x69d0, 0x7910, 0x2168, + 0x6948, 0x7922, 0x21a2, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x694c, + 0xa184, 0x000f, 0x00c0, 0x6980, 0x2001, 0x0005, 0x0078, 0x698a, + 0xd184, 0x0040, 0x6987, 0x2001, 0x0004, 0x0078, 0x698a, 0xa084, + 0x0006, 0x8004, 0x017e, 0x2008, 0x7830, 0xa084, 0x00ff, 0x8007, + 0xa105, 0x017f, 0x20a2, 0xd1ac, 0x0040, 0x699a, 0x20a3, 0x0002, + 0x0078, 0x69a6, 0xd1b4, 0x0040, 0x69a1, 0x20a3, 0x0001, 0x0078, + 0x69a6, 0x20a3, 0x0000, 0x2230, 0x0078, 0x69a8, 0x6a80, 0x6e7c, + 0x20a9, 0x0008, 0xad80, 0x0017, 0x200c, 0x810f, 0x21a2, 0x8000, + 0x00f0, 0x69ac, 0x22a2, 0x26a2, 0x60c3, 0x0020, 0x20e1, 0x9080, + 0x6014, 0xa084, 0x0004, 0xa085, 0x0009, 0x6016, 0x2001, 0xa8cd, + 0x2003, 0x07d0, 0x2001, 0xa8cc, 0x2003, 0x0009, 0x2001, 0xa8d2, + 0x2003, 0x0002, 0x1078, 0x158c, 0x147f, 0x157f, 0x0d7f, 0x007c, + 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7a18, 0xa280, 0x0023, 0x2014, + 0x8210, 0xa294, 0x00ff, 0x2202, 0x8217, 0x7818, 0xa080, 0x0028, + 0x2004, 0xd0bc, 0x0040, 0x69f6, 0x0d7e, 0xa0e8, 0xa735, 0x2d6c, + 0x6810, 0xa085, 0x0600, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa61b, + 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x6a05, 0x0d7e, 0xa0e8, + 0xa735, 0x2d6c, 0x6810, 0xa085, 0x0600, 0x20a2, 0x6814, 0x20a2, + 0x0d7f, 0x20a3, 0x0000, 0x6130, 0x21a2, 0x20a3, 0x0829, 0x20a3, + 0x0000, 0x22a2, 0x20a3, 0x0000, 0x2fa2, 0x20a3, 0xffff, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x007c, 0x0d7e, 0x157e, 0x137e, 0x147e, + 0x20a1, 0x020b, 0x1078, 0x6a34, 0x7810, 0x2068, 0x6860, 0x20a2, + 0x685c, 0x20a2, 0x6880, 0x20a2, 0x687c, 0x20a2, 0xa006, 0x20a2, + 0x20a2, 0x20a2, 0x20a2, 0x60c3, 0x000c, 0x1078, 0x6dfb, 0x147f, + 0x137f, 0x157f, 0x0d7f, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, + 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, 0x6a52, + 0x0d7e, 0xa0e8, 0xa735, 0x2d6c, 0x6810, 0xa085, 0x0500, 0x20a2, + 0x6814, 0x20a2, 0x2069, 0xa61b, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, + 0x0078, 0x6a61, 0x0d7e, 0xa0e8, 0xa735, 0x2d6c, 0x6810, 0xa085, + 0x0500, 0x20a2, 0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000, 0x6230, + 0x22a2, 0x20a3, 0x0889, 0x20a3, 0x0000, 0x1078, 0x6dea, 0x22a2, + 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x027f, 0x007c, 0x0d7e, 0x157e, 0x137e, 0x147e, 0x7810, + 0xa0ec, 0xf000, 0x0040, 0x6a8b, 0xa06d, 0x1078, 0x495f, 0x0040, + 0x6a8b, 0x684c, 0xa084, 0x2020, 0xa086, 0x2020, 0x00c0, 0x6a8b, + 0x7824, 0xc0cd, 0x7826, 0x20a1, 0x020b, 0x1078, 0x6be0, 0xa016, + 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x7810, 0xa084, 0xf000, + 0x00c0, 0x6aa2, 0x7810, 0xa084, 0x0700, 0x8007, 0x1079, 0x6aaa, + 0x0078, 0x6aa5, 0xa006, 0x1079, 0x6aaa, 0x147f, 0x137f, 0x157f, + 0x0d7f, 0x007c, 0x6ab4, 0x6b4c, 0x6b57, 0x6b81, 0x6b95, 0x6bb1, + 0x6bbc, 0x6ab2, 0x1078, 0x1332, 0x017e, 0x037e, 0x694c, 0xa18c, + 0x0003, 0x0040, 0x6abf, 0xa186, 0x0003, 0x00c0, 0x6ace, 0x6b78, + 0x7824, 0xd0cc, 0x0040, 0x6ac5, 0xc3e5, 0x23a2, 0x6868, 0x20a2, + 0x6864, 0x20a2, 0x037f, 0x017f, 0x0078, 0x6b8c, 0xa186, 0x0001, + 0x10c0, 0x1332, 0x6b78, 0x7824, 0xd0cc, 0x0040, 0x6ad8, 0xc3e5, + 0x23a2, 0x6868, 0x20a2, 0x6864, 0x20a2, 0x22a2, 0x6874, 0x20a2, + 0x22a2, 0x687c, 0x20a2, 0x2009, 0x0018, 0xa384, 0x0300, 0x0040, + 0x6b46, 0xd3c4, 0x0040, 0x6aee, 0x687c, 0xa108, 0xd3cc, 0x0040, + 0x6af3, 0x6874, 0xa108, 0x157e, 0x20a9, 0x000d, 0xad80, 0x0020, + 0x201c, 0x831f, 0x23a2, 0x8000, 0x00f0, 0x6af8, 0x157f, 0x22a2, + 0x22a2, 0x22a2, 0xa184, 0x0003, 0x0040, 0x6b46, 0x20a1, 0x020b, + 0x20e1, 0x9080, 0x20e1, 0x4000, 0x007e, 0x7818, 0xa080, 0x0028, + 0x2004, 0xd0bc, 0x0040, 0x6b26, 0x0d7e, 0xa0e8, 0xa735, 0x2d6c, + 0x6810, 0xa085, 0x0700, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa61b, + 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x6b35, 0x0d7e, 0xa0e8, + 0xa735, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, 0x6814, 0x20a2, + 0x0d7f, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x007f, 0x7b24, 0xd3cc, + 0x0040, 0x6b3e, 0x20a3, 0x0889, 0x0078, 0x6b40, 0x20a3, 0x0898, + 0x20a2, 0x1078, 0x6dea, 0x22a2, 0x20a3, 0x0000, 0x61c2, 0x037f, + 0x017f, 0x1078, 0x6dfb, 0x007c, 0x2011, 0x0008, 0x7824, 0xd0cc, + 0x0040, 0x6b53, 0xc2e5, 0x22a2, 0xa016, 0x0078, 0x6b8a, 0x2011, + 0x0302, 0x7824, 0xd0cc, 0x0040, 0x6b5e, 0xc2e5, 0x22a2, 0xa016, + 0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x0012, 0x22a2, 0x20a3, 0x0008, + 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x7000, 0x20a3, 0x0500, + 0x22a2, 0x20a3, 0x000a, 0x22a2, 0x22a2, 0x20a3, 0x2500, 0x22a2, + 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0032, 0x1078, 0x6dfb, + 0x007c, 0x2011, 0x0028, 0x7824, 0xd0cc, 0x0040, 0x6b88, 0xc2e5, + 0x22a2, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, + 0x60c3, 0x0018, 0x1078, 0x6dfb, 0x007c, 0x2011, 0x0100, 0x7824, + 0xd0cc, 0x0040, 0x6b9c, 0xc2e5, 0x22a2, 0xa016, 0x22a2, 0x22a2, + 0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x0008, 0x22a2, 0x7834, 0xa084, + 0x00ff, 0x20a2, 0x22a2, 0x22a2, 0x60c3, 0x0020, 0x1078, 0x6dfb, + 0x007c, 0x2011, 0x0008, 0x7824, 0xd0cc, 0x0040, 0x6bb8, 0xc2e5, + 0x22a2, 0xa016, 0x0078, 0x6b8a, 0x037e, 0x7b10, 0xa384, 0xff00, + 0x7812, 0xa384, 0x00ff, 0x8001, 0x00c0, 0x6bcf, 0x7824, 0xd0cc, + 0x0040, 0x6bcb, 0xc2e5, 0x22a2, 0x037f, 0x0078, 0x6b8a, 0x047e, + 0x2021, 0x0800, 0x007e, 0x7824, 0xd0cc, 0x007f, 0x0040, 0x6bd9, + 0xc4e5, 0x24a2, 0x047f, 0x22a2, 0x20a2, 0x037f, 0x0078, 0x6b8c, + 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, + 0x2004, 0xd0bc, 0x0040, 0x6bfe, 0x0d7e, 0xa0e8, 0xa735, 0x2d6c, + 0x6810, 0xa085, 0x0700, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa61b, + 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x6c0d, 0x0d7e, 0xa0e8, + 0xa735, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, 0x6814, 0x20a2, + 0x0d7f, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x7824, 0xd0cc, 0x0040, + 0x6c15, 0x20a3, 0x0889, 0x0078, 0x6c17, 0x20a3, 0x0898, 0x20a3, + 0x0000, 0x1078, 0x6dea, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, + 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f, 0x007c, 0x0d7e, + 0x157e, 0x137e, 0x147e, 0x017e, 0x037e, 0x7810, 0xa084, 0x0700, + 0x8007, 0x1079, 0x6c3a, 0x037f, 0x017f, 0x147f, 0x137f, 0x157f, + 0x0d7f, 0x007c, 0x6c42, 0x6c42, 0x6c44, 0x6c42, 0x6c42, 0x6c42, + 0x6c69, 0x6c42, 0x1078, 0x1332, 0x7910, 0xa18c, 0xf8ff, 0xa18d, + 0x0600, 0x7912, 0x20a1, 0x020b, 0x2009, 0x0003, 0x1078, 0x6c73, + 0x0d7e, 0x2069, 0xa652, 0x6804, 0xd0bc, 0x0040, 0x6c5e, 0x682c, + 0xa084, 0x00ff, 0x8007, 0x20a2, 0x0078, 0x6c60, 0x20a3, 0x3f00, + 0x0d7f, 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0001, 0x1078, 0x6dfb, + 0x007c, 0x20a1, 0x020b, 0x2009, 0x0003, 0x1078, 0x6c73, 0x20a3, + 0x7f00, 0x0078, 0x6c61, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, + 0x7818, 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, 0x6c91, 0x0d7e, + 0xa0e8, 0xa735, 0x2d6c, 0x6810, 0xa085, 0x0100, 0x20a2, 0x6814, + 0x20a2, 0x2069, 0xa61b, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, + 0x6ca0, 0x0d7e, 0xa0e8, 0xa735, 0x2d6c, 0x6810, 0xa085, 0x0100, + 0x20a2, 0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000, 0x6230, 0x22a2, + 0x20a3, 0x0888, 0xa18d, 0x0008, 0x21a2, 0x1078, 0x6dea, 0x22a2, + 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x027f, 0x007c, 0x0e7e, 0x0d7e, 0x0c7e, 0x057e, 0x047e, + 0x037e, 0x2061, 0x0100, 0x2071, 0xa600, 0x6130, 0x7818, 0x2068, + 0x68a0, 0x2028, 0xd0bc, 0x00c0, 0x6cca, 0x6910, 0x6a14, 0x6430, + 0x0078, 0x6cce, 0x6910, 0x6a14, 0x736c, 0x7470, 0x781c, 0xa086, + 0x0006, 0x0040, 0x6d2d, 0xd5bc, 0x0040, 0x6cde, 0xa185, 0x0100, + 0x6062, 0x6266, 0x636a, 0x646e, 0x0078, 0x6ce5, 0xa185, 0x0100, + 0x6062, 0x6266, 0x606b, 0x0000, 0x646e, 0x6073, 0x0809, 0x6077, + 0x0008, 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e, 0x8007, 0x607a, + 0x607f, 0x0000, 0x2f00, 0x6082, 0x7808, 0x6086, 0x7810, 0x2070, + 0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6, 0x7008, 0x60ca, + 0x686c, 0x60ce, 0x60ab, 0x0036, 0x60af, 0x95d5, 0x60d7, 0x0000, + 0xa582, 0x0080, 0x0048, 0x6d17, 0x6a00, 0xd2f4, 0x0040, 0x6d15, + 0x6a14, 0xa294, 0x00ff, 0x0078, 0x6d17, 0x2011, 0x0000, 0x629e, + 0x6017, 0x0016, 0x2009, 0x07d0, 0x60c4, 0xa084, 0xfff0, 0xa005, + 0x0040, 0x6d24, 0x2009, 0x1b58, 0x1078, 0x5ad0, 0x037f, 0x047f, + 0x057f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, 0x7810, 0x2070, 0x704c, + 0xa084, 0x0003, 0xa086, 0x0002, 0x0040, 0x6d85, 0xd5bc, 0x0040, + 0x6d41, 0xa185, 0x0100, 0x6062, 0x6266, 0x636a, 0x646e, 0x0078, + 0x6d48, 0xa185, 0x0100, 0x6062, 0x6266, 0x606b, 0x0000, 0x646e, + 0x6073, 0x0880, 0x6077, 0x0008, 0x688c, 0x8000, 0xa084, 0x00ff, + 0x688e, 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6086, 0x7808, + 0x6082, 0x7060, 0x608a, 0x705c, 0x608e, 0x7080, 0x60c6, 0x707c, + 0x60ca, 0x707c, 0x792c, 0xa108, 0x792e, 0x7080, 0x7928, 0xa109, + 0x792a, 0x686c, 0x60ce, 0x60ab, 0x0036, 0x60af, 0x95d5, 0x60d7, + 0x0000, 0xa582, 0x0080, 0x0048, 0x6d80, 0x6a00, 0xd2f4, 0x0040, + 0x6d7e, 0x6a14, 0xa294, 0x00ff, 0x0078, 0x6d80, 0x2011, 0x0000, + 0x629e, 0x6017, 0x0012, 0x0078, 0x6d1a, 0xd5bc, 0x0040, 0x6d90, + 0xa185, 0x0700, 0x6062, 0x6266, 0x636a, 0x646e, 0x0078, 0x6d97, + 0xa185, 0x0700, 0x6062, 0x6266, 0x606b, 0x0000, 0x646e, 0x1078, + 0x495f, 0x0040, 0x6dad, 0x0d7e, 0x7810, 0xa06d, 0x684c, 0x0d7f, + 0xa084, 0x2020, 0xa086, 0x2020, 0x00c0, 0x6dad, 0x7824, 0xc0cd, + 0x7826, 0x6073, 0x0889, 0x0078, 0x6daf, 0x6073, 0x0898, 0x6077, + 0x0000, 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e, 0x8007, 0x607a, + 0x607f, 0x0000, 0x2f00, 0x6086, 0x7808, 0x6082, 0x7014, 0x608a, + 0x7010, 0x608e, 0x700c, 0x60c6, 0x7008, 0x60ca, 0x686c, 0x60ce, + 0x60ab, 0x0036, 0x60af, 0x95d5, 0x60d7, 0x0000, 0xa582, 0x0080, + 0x0048, 0x6ddd, 0x6a00, 0xd2f4, 0x0040, 0x6ddb, 0x6a14, 0xa294, + 0x00ff, 0x0078, 0x6ddd, 0x2011, 0x0000, 0x629e, 0x7824, 0xd0cc, + 0x0040, 0x6de6, 0x6017, 0x0016, 0x0078, 0x6d1a, 0x6017, 0x0012, + 0x0078, 0x6d1a, 0x7a18, 0xa280, 0x0023, 0x2014, 0x8210, 0xa294, + 0x00ff, 0x2202, 0x8217, 0x007c, 0x0d7e, 0x2069, 0xa8b1, 0x6843, + 0x0001, 0x0d7f, 0x007c, 0x20e1, 0x9080, 0x60a3, 0x0056, 0x60a7, + 0x9575, 0x1078, 0x6e06, 0x1078, 0x5ac0, 0x007c, 0x007e, 0x6014, + 0xa084, 0x0004, 0xa085, 0x0009, 0x6016, 0x007f, 0x007c, 0x007e, + 0x0c7e, 0x2061, 0x0100, 0x6014, 0xa084, 0x0004, 0xa085, 0x0008, + 0x6016, 0x0c7f, 0x007f, 0x007c, 0x0c7e, 0x0d7e, 0x017e, 0x027e, + 0x2061, 0x0100, 0x2069, 0x0140, 0x6904, 0xa194, 0x4000, 0x0040, + 0x6e59, 0x1078, 0x6e0f, 0x6803, 0x1000, 0x6803, 0x0000, 0x0c7e, + 0x2061, 0xa8b1, 0x6128, 0xa192, 0x00c8, 0x00c8, 0x6e44, 0x8108, + 0x612a, 0x6124, 0x0c7f, 0x81ff, 0x0040, 0x6e54, 0x1078, 0x5ac0, + 0x1078, 0x6e06, 0x0078, 0x6e54, 0x6124, 0xa1e5, 0x0000, 0x0040, + 0x6e51, 0x1078, 0xa5c4, 0x1078, 0x5acb, 0x2009, 0x0014, 0x1078, + 0x775c, 0x0c7f, 0x0078, 0x6e54, 0x027f, 0x017f, 0x0d7f, 0x0c7f, + 0x007c, 0x2001, 0xa8cd, 0x2004, 0xa005, 0x00c0, 0x6e54, 0x0c7e, + 0x2061, 0xa8b1, 0x6128, 0xa192, 0x0003, 0x00c8, 0x6e44, 0x8108, + 0x612a, 0x0c7f, 0x1078, 0x5ac0, 0x1078, 0x4224, 0x0078, 0x6e54, + 0x0c7e, 0x0d7e, 0x0e7e, 0x017e, 0x027e, 0x1078, 0x5ad8, 0x2071, + 0xa8b1, 0x713c, 0x81ff, 0x0040, 0x6e9a, 0x2061, 0x0100, 0x2069, + 0x0140, 0x6904, 0xa194, 0x4000, 0x0040, 0x6ea0, 0x6803, 0x1000, + 0x6803, 0x0000, 0x037e, 0x2019, 0x0001, 0x1078, 0x7058, 0x037f, + 0x713c, 0x2160, 0x1078, 0xa5c4, 0x2009, 0x004a, 0x1078, 0x775c, + 0x0078, 0x6e9a, 0x027f, 0x017f, 0x0e7f, 0x0d7f, 0x0c7f, 0x007c, + 0x0078, 0x6e8a, 0x0e7e, 0x2071, 0xa8b1, 0x7048, 0xd084, 0x0040, + 0x6ebc, 0x713c, 0x81ff, 0x0040, 0x6ebc, 0x2071, 0x0100, 0xa188, + 0x0007, 0x210c, 0xa18e, 0x0006, 0x00c0, 0x6eba, 0x7017, 0x0012, + 0x0078, 0x6ebc, 0x7017, 0x0016, 0x0e7f, 0x007c, 0x0e7e, 0x0d7e, + 0x0c7e, 0x067e, 0x057e, 0x047e, 0x007e, 0x127e, 0x2091, 0x8000, + 0x6018, 0x2068, 0x6ca0, 0x2071, 0xa8b1, 0x7018, 0x2068, 0x8dff, + 0x0040, 0x6ee6, 0x68a0, 0xa406, 0x0040, 0x6eda, 0x6854, 0x2068, + 0x0078, 0x6ecf, 0x6010, 0x2060, 0x643c, 0x6540, 0x6648, 0x2d60, + 0x1078, 0x4736, 0x0040, 0x6ee6, 0xa085, 0x0001, 0x127f, 0x007f, + 0x047f, 0x057f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, 0x20a1, + 0x020b, 0x1078, 0x6731, 0x20a3, 0x1200, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x781c, 0xa086, 0x0004, 0x00c0, 0x6f01, 0x6098, 0x0078, + 0x6f02, 0x6030, 0x20a2, 0x7834, 0x20a2, 0x7838, 0x20a2, 0x20a9, + 0x0010, 0xa006, 0x20a2, 0x00f0, 0x6f0a, 0x20a2, 0x20a2, 0x60c3, + 0x002c, 0x1078, 0x6dfb, 0x007c, 0x157e, 0x147e, 0x20a1, 0x020b, + 0x1078, 0x6731, 0x20a3, 0x0f00, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x7808, 0x20a2, 0x60c3, 0x0008, 0x1078, 0x6dfb, 0x147f, 0x157f, + 0x007c, 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, 0x67c2, 0x20a3, + 0x0200, 0x20a3, 0x0000, 0x20a9, 0x0006, 0x2011, 0xa640, 0x2019, + 0xa641, 0x23a6, 0x22a6, 0xa398, 0x0002, 0xa290, 0x0002, 0x00f0, + 0x6f39, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x001c, 0x1078, + 0x6dfb, 0x147f, 0x157f, 0x007c, 0x157e, 0x147e, 0x017e, 0x027e, + 0x20a1, 0x020b, 0x1078, 0x6799, 0x1078, 0x67b0, 0x7810, 0xa080, + 0x0000, 0x2004, 0xa080, 0x0015, 0x2098, 0x7808, 0xa088, 0x0002, + 0x21a8, 0x53a6, 0xa080, 0x0004, 0x8003, 0x60c2, 0x1078, 0x6dfb, + 0x027f, 0x017f, 0x147f, 0x157f, 0x007c, 0x157e, 0x147e, 0x20a1, + 0x020b, 0x1078, 0x6731, 0x20a3, 0x6200, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x7808, 0x20a2, 0x60c3, 0x0008, 0x1078, 0x6dfb, 0x147f, + 0x157f, 0x007c, 0x157e, 0x147e, 0x017e, 0x027e, 0x20a1, 0x020b, + 0x1078, 0x6731, 0x7810, 0xa080, 0x0000, 0x2004, 0xa080, 0x0017, + 0x2098, 0x7808, 0xa088, 0x0002, 0x21a8, 0x53a6, 0x8003, 0x60c2, + 0x1078, 0x6dfb, 0x027f, 0x017f, 0x147f, 0x157f, 0x007c, 0x0e7e, + 0x0c7e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2071, 0xa8b1, 0x700c, + 0x2060, 0x8cff, 0x0040, 0x6fbb, 0x1078, 0x8f00, 0x00c0, 0x6fb2, + 0x1078, 0x7c83, 0x600c, 0x007e, 0x1078, 0x772d, 0x1078, 0x7233, + 0x0c7f, 0x0078, 0x6fa9, 0x700f, 0x0000, 0x700b, 0x0000, 0x127f, + 0x007f, 0x0c7f, 0x0e7f, 0x007c, 0x127e, 0x157e, 0x0f7e, 0x0e7e, + 0x0d7e, 0x0c7e, 0x027e, 0x017e, 0x007e, 0x2091, 0x8000, 0x2069, + 0x0100, 0x2079, 0x0140, 0x2071, 0xa8b1, 0x7024, 0x2060, 0x8cff, + 0x0040, 0x7014, 0x1078, 0x6e0f, 0x68c3, 0x0000, 0x1078, 0x5acb, + 0x2009, 0x0013, 0x1078, 0x775c, 0x20a9, 0x01f4, 0x6824, 0xd094, + 0x0040, 0x6ff7, 0x6827, 0x0004, 0x7804, 0xa084, 0x4000, 0x0040, + 0x7009, 0x7803, 0x1000, 0x7803, 0x0000, 0x0078, 0x7009, 0xd084, + 0x0040, 0x6ffe, 0x6827, 0x0001, 0x0078, 0x7000, 0x00f0, 0x6fe6, + 0x7804, 0xa084, 0x1000, 0x0040, 0x7009, 0x7803, 0x0100, 0x7803, + 0x0000, 0x6824, 0x007f, 0x017f, 0x027f, 0x0c7f, 0x0d7f, 0x0e7f, + 0x0f7f, 0x157f, 0x127f, 0x007c, 0x2001, 0xa600, 0x2004, 0xa096, + 0x0001, 0x0040, 0x704e, 0xa096, 0x0004, 0x0040, 0x704e, 0x1078, + 0x5acb, 0x6817, 0x0008, 0x68c3, 0x0000, 0x2011, 0x41dc, 0x1078, + 0x5a45, 0x20a9, 0x01f4, 0x6824, 0xd094, 0x0040, 0x703c, 0x6827, + 0x0004, 0x7804, 0xa084, 0x4000, 0x0040, 0x704e, 0x7803, 0x1000, + 0x7803, 0x0000, 0x0078, 0x704e, 0xd084, 0x0040, 0x7043, 0x6827, + 0x0001, 0x0078, 0x7045, 0x00f0, 0x702b, 0x7804, 0xa084, 0x1000, + 0x0040, 0x704e, 0x7803, 0x0100, 0x7803, 0x0000, 0x007f, 0x017f, + 0x027f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x157f, 0x127f, 0x007c, + 0x127e, 0x157e, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x027e, 0x017e, + 0x007e, 0x2091, 0x8000, 0x2069, 0x0100, 0x2079, 0x0140, 0x2071, + 0xa8b1, 0x703c, 0x2060, 0x8cff, 0x0040, 0x70d6, 0x68af, 0x95f5, + 0x6817, 0x0010, 0x2009, 0x00fa, 0x8109, 0x00c0, 0x7074, 0x68c7, + 0x0000, 0x68cb, 0x0008, 0x1078, 0x5ad8, 0x1078, 0x1f7e, 0x047e, + 0x057e, 0x2009, 0x017f, 0x212c, 0x200b, 0x00a5, 0x2021, 0x0169, + 0x2404, 0xa084, 0x000f, 0xa086, 0x0004, 0x00c0, 0x70a5, 0x68c7, + 0x0000, 0x68cb, 0x0008, 0x0e7e, 0x0f7e, 0x2079, 0x0020, 0x2071, + 0xa908, 0x6814, 0xa084, 0x0004, 0xa085, 0x0012, 0x6816, 0x7803, + 0x0008, 0x7003, 0x0000, 0x0f7f, 0x0e7f, 0x250a, 0x057f, 0x047f, + 0xa39d, 0x0000, 0x00c0, 0x70b0, 0x2009, 0x0049, 0x1078, 0x775c, + 0x20a9, 0x03e8, 0x6824, 0xd094, 0x0040, 0x70c3, 0x6827, 0x0004, + 0x7804, 0xa084, 0x4000, 0x0040, 0x70d5, 0x7803, 0x1000, 0x7803, + 0x0000, 0x0078, 0x70d5, 0xd08c, 0x0040, 0x70ca, 0x6827, 0x0002, + 0x0078, 0x70cc, 0x00f0, 0x70b2, 0x7804, 0xa084, 0x1000, 0x0040, + 0x70d5, 0x7803, 0x0100, 0x7803, 0x0000, 0x6824, 0x007f, 0x017f, + 0x027f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x157f, 0x127f, 0x007c, + 0x0d7e, 0x127e, 0x2091, 0x8000, 0x2069, 0xa8b1, 0x6a06, 0x127f, + 0x0d7f, 0x007c, 0x0d7e, 0x127e, 0x2091, 0x8000, 0x2069, 0xa8b1, + 0x6a32, 0x127f, 0x0d7f, 0x007c, 0x0f7e, 0x0e7e, 0x0c7e, 0x067e, + 0x007e, 0x127e, 0x2071, 0xa8b1, 0x7614, 0x2660, 0x2678, 0x2091, + 0x8000, 0x8cff, 0x0040, 0x7134, 0x601c, 0xa206, 0x00c0, 0x712f, + 0x7014, 0xac36, 0x00c0, 0x710e, 0x660c, 0x7616, 0x7010, 0xac36, + 0x00c0, 0x711c, 0x2c00, 0xaf36, 0x0040, 0x711a, 0x2f00, 0x7012, + 0x0078, 0x711c, 0x7013, 0x0000, 0x660c, 0x067e, 0x2c00, 0xaf06, + 0x0040, 0x7125, 0x7e0e, 0x0078, 0x7126, 0x2678, 0x600f, 0x0000, + 0x1078, 0x8ec6, 0x1078, 0x7233, 0x0c7f, 0x0078, 0x7101, 0x2c78, + 0x600c, 0x2060, 0x0078, 0x7101, 0x127f, 0x007f, 0x067f, 0x0c7f, + 0x0e7f, 0x0f7f, 0x007c, 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, + 0x69d0, 0x7810, 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, + 0x20a3, 0x1000, 0x0078, 0x718e, 0x157e, 0x147e, 0x20a1, 0x020b, + 0x1078, 0x69d0, 0x7810, 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, + 0x20a2, 0x20a3, 0x4000, 0x0078, 0x718e, 0x157e, 0x147e, 0x20a1, + 0x020b, 0x1078, 0x69d0, 0x7810, 0x20a2, 0xa006, 0x20a2, 0x20a2, + 0x20a2, 0x20a2, 0x20a3, 0x2000, 0x0078, 0x718e, 0x157e, 0x147e, + 0x20a1, 0x020b, 0x1078, 0x69d0, 0x7810, 0x20a2, 0xa006, 0x20a2, + 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x0400, 0x0078, 0x718e, 0x157e, + 0x147e, 0x20a1, 0x020b, 0x1078, 0x69d0, 0x7810, 0x20a2, 0xa006, + 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x0200, 0x1078, 0x723e, + 0x60c3, 0x0020, 0x1078, 0x6dfb, 0x147f, 0x157f, 0x007c, 0x127e, + 0x0c7e, 0x2091, 0x8000, 0x2061, 0x0100, 0x6120, 0xd1b4, 0x00c0, + 0x71a6, 0xd1bc, 0x00c0, 0x71f0, 0x0078, 0x7230, 0x2009, 0x017f, + 0x200b, 0x00a1, 0x157e, 0x007e, 0x0d7e, 0x2069, 0x0140, 0x20a9, + 0x001e, 0x2009, 0x0169, 0x6804, 0xa084, 0x4000, 0x0040, 0x71e7, + 0x6020, 0xd0b4, 0x0040, 0x71e7, 0x6024, 0xd094, 0x00c0, 0x71e7, + 0x2104, 0xa084, 0x000f, 0xa086, 0x0004, 0x00c0, 0x71e7, 0x00f0, + 0x71b3, 0x027e, 0x6198, 0xa18c, 0x00ff, 0x8107, 0x6130, 0xa18c, + 0x00ff, 0xa10d, 0x6088, 0x628c, 0x618e, 0x608b, 0xbc91, 0x6043, + 0x0001, 0x6043, 0x0000, 0x608a, 0x628e, 0x6024, 0xd094, 0x00c0, + 0x71e6, 0x6a04, 0xa294, 0x4000, 0x00c0, 0x71dd, 0x027f, 0x0d7f, + 0x007f, 0x157f, 0x2009, 0x017f, 0x200b, 0x0000, 0x0078, 0x7230, + 0x2009, 0x017f, 0x200b, 0x00a1, 0x157e, 0x007e, 0x0d7e, 0x2069, + 0x0140, 0x20a9, 0x001e, 0x2009, 0x0169, 0x6804, 0xa084, 0x4000, + 0x0040, 0x7229, 0x6020, 0xd0bc, 0x0040, 0x7229, 0x2104, 0xa084, + 0x000f, 0xa086, 0x0004, 0x00c0, 0x7229, 0x00f0, 0x71fd, 0x027e, + 0x6164, 0xa18c, 0x00ff, 0x8107, 0x6130, 0xa18c, 0x00ff, 0xa10d, + 0x6088, 0x628c, 0x608b, 0xbc91, 0x618e, 0x6043, 0x0001, 0x6043, + 0x0000, 0x608a, 0x628e, 0x6a04, 0xa294, 0x4000, 0x00c0, 0x7223, + 0x027f, 0x0d7f, 0x007f, 0x157f, 0x2009, 0x017f, 0x200b, 0x0000, + 0x0c7f, 0x127f, 0x007c, 0x0e7e, 0x2071, 0xa8b1, 0x7020, 0xa005, + 0x0040, 0x723c, 0x8001, 0x7022, 0x0e7f, 0x007c, 0x20a9, 0x0008, + 0x20a2, 0x00f0, 0x7240, 0x20a2, 0x20a2, 0x007c, 0x0f7e, 0x0e7e, + 0x0d7e, 0x0c7e, 0x077e, 0x067e, 0x007e, 0x127e, 0x2091, 0x8000, + 0x2071, 0xa8b1, 0x7614, 0x2660, 0x2678, 0x2039, 0x0001, 0x87ff, + 0x0040, 0x72e2, 0x8cff, 0x0040, 0x72e2, 0x601c, 0xa086, 0x0006, + 0x00c0, 0x72dd, 0x88ff, 0x0040, 0x726d, 0x2800, 0xac06, 0x00c0, + 0x72dd, 0x2039, 0x0000, 0x0078, 0x7278, 0x6018, 0xa206, 0x00c0, + 0x72dd, 0x85ff, 0x0040, 0x7278, 0x6020, 0xa106, 0x00c0, 0x72dd, + 0x7024, 0xac06, 0x00c0, 0x72a8, 0x2069, 0x0100, 0x68c0, 0xa005, + 0x0040, 0x72a3, 0x1078, 0x5acb, 0x6817, 0x0008, 0x68c3, 0x0000, + 0x1078, 0x7378, 0x7027, 0x0000, 0x037e, 0x2069, 0x0140, 0x6b04, + 0xa384, 0x1000, 0x0040, 0x7298, 0x6803, 0x0100, 0x6803, 0x0000, + 0x2069, 0x0100, 0x6824, 0xd084, 0x0040, 0x72a0, 0x6827, 0x0001, + 0x037f, 0x0078, 0x72a8, 0x6003, 0x0009, 0x630a, 0x0078, 0x72dd, + 0x7014, 0xac36, 0x00c0, 0x72ae, 0x660c, 0x7616, 0x7010, 0xac36, + 0x00c0, 0x72bc, 0x2c00, 0xaf36, 0x0040, 0x72ba, 0x2f00, 0x7012, + 0x0078, 0x72bc, 0x7013, 0x0000, 0x660c, 0x067e, 0x2c00, 0xaf06, + 0x0040, 0x72c5, 0x7e0e, 0x0078, 0x72c6, 0x2678, 0x89ff, 0x00c0, + 0x72d5, 0x600f, 0x0000, 0x6010, 0x2068, 0x1078, 0x8d06, 0x0040, + 0x72d3, 0x1078, 0xa1ca, 0x1078, 0x8ec6, 0x1078, 0x7233, 0x88ff, + 0x00c0, 0x72ec, 0x0c7f, 0x0078, 0x7257, 0x2c78, 0x600c, 0x2060, + 0x0078, 0x7257, 0xa006, 0x127f, 0x007f, 0x067f, 0x077f, 0x0c7f, + 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x6017, 0x0000, 0x0c7f, 0xa8c5, + 0x0001, 0x0078, 0x72e3, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, + 0x027e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2071, 0xa8b1, 0x7638, + 0x2660, 0x2678, 0x8cff, 0x0040, 0x7367, 0x601c, 0xa086, 0x0006, + 0x00c0, 0x7362, 0x87ff, 0x0040, 0x7313, 0x2700, 0xac06, 0x00c0, + 0x7362, 0x0078, 0x731e, 0x6018, 0xa206, 0x00c0, 0x7362, 0x85ff, + 0x0040, 0x731e, 0x6020, 0xa106, 0x00c0, 0x7362, 0x703c, 0xac06, + 0x00c0, 0x7332, 0x037e, 0x2019, 0x0001, 0x1078, 0x7058, 0x7033, + 0x0000, 0x703f, 0x0000, 0x7043, 0x0000, 0x7047, 0x0000, 0x704b, + 0x0000, 0x037f, 0x7038, 0xac36, 0x00c0, 0x7338, 0x660c, 0x763a, + 0x7034, 0xac36, 0x00c0, 0x7346, 0x2c00, 0xaf36, 0x0040, 0x7344, + 0x2f00, 0x7036, 0x0078, 0x7346, 0x7037, 0x0000, 0x660c, 0x067e, + 0x2c00, 0xaf06, 0x0040, 0x734f, 0x7e0e, 0x0078, 0x7350, 0x2678, + 0x600f, 0x0000, 0x6010, 0x2068, 0x1078, 0x8d06, 0x0040, 0x735a, + 0x1078, 0xa1ca, 0x1078, 0x8ec6, 0x87ff, 0x00c0, 0x7371, 0x0c7f, + 0x0078, 0x7302, 0x2c78, 0x600c, 0x2060, 0x0078, 0x7302, 0xa006, + 0x127f, 0x007f, 0x027f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, + 0x007c, 0x6017, 0x0000, 0x0c7f, 0xa7bd, 0x0001, 0x0078, 0x7368, + 0x0e7e, 0x2071, 0xa8b1, 0x2001, 0xa600, 0x2004, 0xa086, 0x0002, + 0x00c0, 0x7386, 0x7007, 0x0005, 0x0078, 0x7388, 0x7007, 0x0000, + 0x0e7f, 0x007c, 0x0f7e, 0x0e7e, 0x0c7e, 0x067e, 0x027e, 0x007e, + 0x127e, 0x2091, 0x8000, 0x2071, 0xa8b1, 0x2c10, 0x7638, 0x2660, + 0x2678, 0x8cff, 0x0040, 0x73c8, 0x2200, 0xac06, 0x00c0, 0x73c3, + 0x7038, 0xac36, 0x00c0, 0x73a6, 0x660c, 0x763a, 0x7034, 0xac36, + 0x00c0, 0x73b4, 0x2c00, 0xaf36, 0x0040, 0x73b2, 0x2f00, 0x7036, + 0x0078, 0x73b4, 0x7037, 0x0000, 0x660c, 0x2c00, 0xaf06, 0x0040, + 0x73bc, 0x7e0e, 0x0078, 0x73bd, 0x2678, 0x600f, 0x0000, 0xa085, + 0x0001, 0x0078, 0x73c8, 0x2c78, 0x600c, 0x2060, 0x0078, 0x7399, + 0x127f, 0x007f, 0x027f, 0x067f, 0x0c7f, 0x0e7f, 0x0f7f, 0x007c, + 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x007e, 0x127e, 0x2091, + 0x8000, 0x2071, 0xa8b1, 0x760c, 0x2660, 0x2678, 0x8cff, 0x0040, + 0x7469, 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, 0x00c0, 0x7464, + 0x7024, 0xac06, 0x00c0, 0x740f, 0x2069, 0x0100, 0x68c0, 0xa005, + 0x0040, 0x743d, 0x1078, 0x6e0f, 0x68c3, 0x0000, 0x1078, 0x7378, + 0x7027, 0x0000, 0x037e, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, + 0x0040, 0x7406, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, + 0x6824, 0xd084, 0x0040, 0x740e, 0x6827, 0x0001, 0x037f, 0x700c, + 0xac36, 0x00c0, 0x7415, 0x660c, 0x760e, 0x7008, 0xac36, 0x00c0, + 0x7423, 0x2c00, 0xaf36, 0x0040, 0x7421, 0x2f00, 0x700a, 0x0078, + 0x7423, 0x700b, 0x0000, 0x660c, 0x067e, 0x2c00, 0xaf06, 0x0040, + 0x742c, 0x7e0e, 0x0078, 0x742d, 0x2678, 0x600f, 0x0000, 0x1078, + 0x8eec, 0x00c0, 0x7441, 0x1078, 0x28a6, 0x1078, 0x8f00, 0x00c0, + 0x745d, 0x1078, 0x7c83, 0x0078, 0x745d, 0x1078, 0x7378, 0x0078, + 0x740f, 0x1078, 0x8f00, 0x00c0, 0x7449, 0x1078, 0x7c83, 0x0078, + 0x745d, 0x6010, 0x2068, 0x1078, 0x8d06, 0x0040, 0x745d, 0x601c, + 0xa086, 0x0003, 0x00c0, 0x7471, 0x6837, 0x0103, 0x6b4a, 0x6847, + 0x0000, 0x1078, 0x4a73, 0x1078, 0x8eb9, 0x1078, 0x8ec6, 0x1078, + 0x7233, 0x0c7f, 0x0078, 0x73de, 0x2c78, 0x600c, 0x2060, 0x0078, + 0x73de, 0x127f, 0x007f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, + 0x007c, 0x601c, 0xa086, 0x0006, 0x00c0, 0x745d, 0x1078, 0xa1ca, + 0x0078, 0x745d, 0x037e, 0x157e, 0x137e, 0x147e, 0x3908, 0xa006, + 0xa190, 0x0020, 0x221c, 0xa39e, 0x2676, 0x00c0, 0x748b, 0x8210, + 0x8000, 0x0078, 0x7482, 0xa005, 0x0040, 0x7497, 0x20a9, 0x0020, + 0x2198, 0x8211, 0xa282, 0x0020, 0x20c8, 0x20a0, 0x53a3, 0x147f, + 0x137f, 0x157f, 0x037f, 0x007c, 0x0d7e, 0x20a1, 0x020b, 0x1078, + 0x67c2, 0x20a3, 0x0200, 0x20a3, 0x0014, 0x60c3, 0x0014, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x2099, 0xa8a5, 0x20a9, 0x0004, 0x53a6, + 0x20a3, 0x0004, 0x20a3, 0x7878, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x1078, 0x6dfb, 0x0d7f, 0x007c, 0x20a1, 0x020b, 0x1078, 0x67c2, + 0x20a3, 0x0214, 0x20a3, 0x0018, 0x20a3, 0x0800, 0x7810, 0xa084, + 0xff00, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x7810, 0xa084, 0x00ff, 0x20a2, 0x7828, 0x20a2, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0018, 0x1078, 0x6dfb, + 0x007c, 0x0d7e, 0x017e, 0x2f68, 0x2009, 0x0035, 0x1078, 0x91bc, + 0x00c0, 0x7551, 0x20a1, 0x020b, 0x1078, 0x6731, 0x20a3, 0x1300, + 0x20a3, 0x0000, 0x7828, 0x2068, 0x681c, 0xa086, 0x0003, 0x0040, + 0x752d, 0x7818, 0xa080, 0x0028, 0x2014, 0xa286, 0x007e, 0x00c0, + 0x7507, 0x20a3, 0x00ff, 0x20a3, 0xfffe, 0x0078, 0x7542, 0xa286, + 0x007f, 0x00c0, 0x7511, 0x20a3, 0x00ff, 0x20a3, 0xfffd, 0x0078, + 0x7542, 0xd2bc, 0x0040, 0x7527, 0xa286, 0x0080, 0x00c0, 0x751e, + 0x20a3, 0x00ff, 0x20a3, 0xfffc, 0x0078, 0x7542, 0xa2e8, 0xa735, + 0x2d6c, 0x6810, 0x20a2, 0x6814, 0x20a2, 0x0078, 0x7542, 0x20a3, + 0x0000, 0x6098, 0x20a2, 0x0078, 0x7542, 0x7818, 0xa080, 0x0028, + 0x2004, 0xa082, 0x007e, 0x0048, 0x753e, 0x0d7e, 0x2069, 0xa61b, + 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x7542, 0x20a3, 0x0000, + 0x6030, 0x20a2, 0x7834, 0x20a2, 0x7838, 0x20a2, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x60c3, 0x000c, 0x1078, 0x6dfb, 0x017f, 0x0d7f, + 0x007c, 0x7817, 0x0001, 0x7803, 0x0006, 0x017f, 0x0d7f, 0x007c, + 0x0d7e, 0x027e, 0x7928, 0x2168, 0x691c, 0xa186, 0x0006, 0x0040, + 0x757a, 0xa186, 0x0003, 0x0040, 0x75d5, 0xa186, 0x0005, 0x0040, + 0x75b8, 0xa186, 0x0004, 0x0040, 0x75a8, 0xa186, 0x0008, 0x0040, + 0x75c2, 0x7807, 0x0037, 0x7813, 0x1700, 0x1078, 0x7640, 0x027f, + 0x0d7f, 0x007c, 0x1078, 0x75fd, 0x2009, 0x4000, 0x6800, 0x0079, + 0x7581, 0x7594, 0x75a2, 0x7596, 0x75a2, 0x759d, 0x7594, 0x7594, + 0x75a2, 0x75a2, 0x75a2, 0x75a2, 0x7594, 0x7594, 0x7594, 0x7594, + 0x7594, 0x75a2, 0x7594, 0x75a2, 0x1078, 0x1332, 0x6824, 0xd0e4, + 0x0040, 0x759d, 0xd0cc, 0x0040, 0x75a0, 0xa00e, 0x0078, 0x75a2, + 0x2009, 0x2000, 0x6828, 0x20a2, 0x682c, 0x20a2, 0x0078, 0x75f3, + 0x1078, 0x75fd, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x2009, 0x4000, + 0x6a00, 0xa286, 0x0002, 0x00c0, 0x75b6, 0xa00e, 0x0078, 0x75f3, + 0x1078, 0x75fd, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x2009, 0x4000, + 0x0078, 0x75f3, 0x1078, 0x75fd, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x2009, 0x4000, 0xa286, 0x0005, 0x0040, 0x75d2, 0xa286, 0x0002, + 0x00c0, 0x75d3, 0xa00e, 0x0078, 0x75f3, 0x1078, 0x75fd, 0x6810, + 0x2068, 0x697c, 0x6810, 0xa112, 0x6980, 0x6814, 0xa103, 0x20a2, + 0x22a2, 0x7928, 0xa180, 0x0000, 0x2004, 0xa08e, 0x0002, 0x0040, + 0x75f1, 0xa08e, 0x0004, 0x0040, 0x75f1, 0x2009, 0x4000, 0x0078, + 0x75f3, 0x2009, 0x0000, 0x21a2, 0x20a3, 0x0000, 0x60c3, 0x0018, + 0x1078, 0x6dfb, 0x027f, 0x0d7f, 0x007c, 0x037e, 0x047e, 0x057e, + 0x067e, 0x20a1, 0x020b, 0x1078, 0x67c2, 0xa006, 0x20a3, 0x0200, + 0x20a2, 0x7934, 0x21a2, 0x7938, 0x21a2, 0x7818, 0xa080, 0x0028, + 0x2004, 0xa092, 0x007e, 0x0048, 0x7623, 0x0d7e, 0x2069, 0xa61b, + 0x2d2c, 0x8d68, 0x2d34, 0xa0e8, 0xa735, 0x2d6c, 0x6b10, 0x6c14, + 0x0d7f, 0x0078, 0x7629, 0x2019, 0x0000, 0x6498, 0x2029, 0x0000, + 0x6630, 0x7828, 0xa080, 0x0007, 0x2004, 0xa086, 0x0003, 0x00c0, + 0x7637, 0x25a2, 0x26a2, 0x23a2, 0x24a2, 0x0078, 0x763b, 0x23a2, + 0x24a2, 0x25a2, 0x26a2, 0x067f, 0x057f, 0x047f, 0x037f, 0x007c, + 0x20a1, 0x020b, 0x1078, 0x67c2, 0x20a3, 0x0100, 0x20a3, 0x0000, + 0x20a3, 0x0009, 0x7810, 0x20a2, 0x60c3, 0x0008, 0x1078, 0x6dfb, + 0x007c, 0x20a1, 0x020b, 0x1078, 0x6728, 0x20a3, 0x1400, 0x20a3, + 0x0000, 0x7834, 0x20a2, 0x7838, 0x20a2, 0x7828, 0x20a2, 0x782c, + 0x20a2, 0x7830, 0xa084, 0x00ff, 0x8007, 0x20a2, 0x20a3, 0x0000, + 0x60c3, 0x0010, 0x1078, 0x6dfb, 0x007c, 0x20a1, 0x020b, 0x1078, + 0x67b9, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x7828, 0x20a2, 0x7810, + 0x20a2, 0x60c3, 0x0008, 0x1078, 0x6dfb, 0x007c, 0x147e, 0x20a1, + 0x020b, 0x1078, 0x7689, 0x60c3, 0x0000, 0x1078, 0x6dfb, 0x147f, + 0x007c, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, + 0x2004, 0xd0bc, 0x0040, 0x76a6, 0x0d7e, 0xa0e8, 0xa735, 0x2d6c, + 0x6810, 0xa085, 0x0300, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa61b, + 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x76ae, 0x20a3, 0x0300, + 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, 0x0819, + 0x20a3, 0x0000, 0x1078, 0x6dea, 0x22a2, 0x20a3, 0x0000, 0x2fa2, + 0x7a08, 0x22a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x007c, 0x2061, + 0xad00, 0x2a70, 0x7064, 0x704a, 0x704f, 0xad00, 0x007c, 0x0e7e, + 0x127e, 0x2071, 0xa600, 0x2091, 0x8000, 0x7548, 0xa582, 0x0010, + 0x0048, 0x76f9, 0x704c, 0x2060, 0x6000, 0xa086, 0x0000, 0x0040, + 0x76e5, 0xace0, 0x0010, 0x7058, 0xac02, 0x00c8, 0x76e1, 0x0078, + 0x76d4, 0x2061, 0xad00, 0x0078, 0x76d4, 0x6003, 0x0008, 0x8529, + 0x754a, 0xaca8, 0x0010, 0x7058, 0xa502, 0x00c8, 0x76f5, 0x754e, + 0xa085, 0x0001, 0x127f, 0x0e7f, 0x007c, 0x704f, 0xad00, 0x0078, + 0x76f0, 0xa006, 0x0078, 0x76f2, 0x0e7e, 0x2071, 0xa600, 0x7548, + 0xa582, 0x0010, 0x0048, 0x772a, 0x704c, 0x2060, 0x6000, 0xa086, + 0x0000, 0x0040, 0x7717, 0xace0, 0x0010, 0x7058, 0xac02, 0x00c8, + 0x7713, 0x0078, 0x7706, 0x2061, 0xad00, 0x0078, 0x7706, 0x6003, + 0x0008, 0x8529, 0x754a, 0xaca8, 0x0010, 0x7058, 0xa502, 0x00c8, + 0x7726, 0x754e, 0xa085, 0x0001, 0x0e7f, 0x007c, 0x704f, 0xad00, + 0x0078, 0x7722, 0xa006, 0x0078, 0x7724, 0xac82, 0xad00, 0x1048, + 0x1332, 0x2001, 0xa616, 0x2004, 0xac02, 0x10c8, 0x1332, 0xa006, + 0x6006, 0x600a, 0x600e, 0x6012, 0x6016, 0x601a, 0x601f, 0x0000, + 0x6003, 0x0000, 0x6022, 0x6026, 0x602a, 0x602e, 0x6032, 0x6036, + 0x603a, 0x603e, 0x2061, 0xa600, 0x6048, 0x8000, 0x604a, 0xa086, + 0x0001, 0x0040, 0x7754, 0x007c, 0x127e, 0x2091, 0x8000, 0x1078, + 0x62d1, 0x127f, 0x0078, 0x7753, 0x601c, 0xa084, 0x000f, 0x0079, + 0x7761, 0x776a, 0x777b, 0x7797, 0x77b3, 0x920e, 0x922a, 0x9246, + 0x776a, 0x777b, 0xa186, 0x0013, 0x00c0, 0x7773, 0x1078, 0x61cd, + 0x1078, 0x62d1, 0x007c, 0xa18e, 0x0047, 0x00c0, 0x777a, 0xa016, + 0x1078, 0x15fa, 0x007c, 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8, + 0x1332, 0x1079, 0x7785, 0x067f, 0x007c, 0x7795, 0x7b00, 0x7cb2, + 0x7795, 0x7d36, 0x77cf, 0x7795, 0x7795, 0x7a92, 0x80f6, 0x7795, + 0x7795, 0x7795, 0x7795, 0x7795, 0x7795, 0x1078, 0x1332, 0x067e, + 0x6000, 0xa0b2, 0x0010, 0x10c8, 0x1332, 0x1079, 0x77a1, 0x067f, + 0x007c, 0x77b1, 0x87c3, 0x77b1, 0x77b1, 0x77b1, 0x77b1, 0x77b1, + 0x77b1, 0x8766, 0x8951, 0x77b1, 0x87f3, 0x8879, 0x87f3, 0x8879, + 0x77b1, 0x1078, 0x1332, 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8, + 0x1332, 0x1079, 0x77bd, 0x067f, 0x007c, 0x77cd, 0x813d, 0x820e, + 0x8368, 0x84e4, 0x77cd, 0x77cd, 0x77cd, 0x8116, 0x870e, 0x8712, + 0x77cd, 0x77cd, 0x77cd, 0x77cd, 0x8742, 0x1078, 0x1332, 0xa1b6, + 0x0015, 0x00c0, 0x77d7, 0x1078, 0x772d, 0x0078, 0x77dd, 0xa1b6, + 0x0016, 0x10c0, 0x1332, 0x1078, 0x772d, 0x007c, 0x20a9, 0x000e, + 0x2e98, 0x6010, 0x20a0, 0x53a3, 0x20a9, 0x0006, 0x3310, 0x3420, + 0x9398, 0x94a0, 0x3318, 0x3428, 0x222e, 0x2326, 0xa290, 0x0002, + 0xa5a8, 0x0002, 0xa398, 0x0002, 0xa4a0, 0x0002, 0x00f0, 0x77ec, + 0x0e7e, 0x1078, 0x8d06, 0x0040, 0x7803, 0x6010, 0x2070, 0x7007, + 0x0000, 0x7037, 0x0103, 0x0e7f, 0x1078, 0x772d, 0x007c, 0x0d7e, + 0x037e, 0x7330, 0xa386, 0x0200, 0x00c0, 0x7814, 0x6018, 0x2068, + 0x6813, 0x00ff, 0x6817, 0xfffd, 0x6010, 0xa005, 0x0040, 0x781e, + 0x2068, 0x6807, 0x0000, 0x6837, 0x0103, 0x6b32, 0x1078, 0x772d, + 0x037f, 0x0d7f, 0x007c, 0x017e, 0x20a9, 0x002a, 0xae80, 0x000c, + 0x2098, 0x6010, 0xa080, 0x0002, 0x20a0, 0x53a3, 0x20a9, 0x002a, + 0x6010, 0xa080, 0x0001, 0x2004, 0xa080, 0x0002, 0x20a0, 0x53a3, + 0x0e7e, 0x6010, 0x2004, 0x2070, 0x7037, 0x0103, 0x0e7f, 0x1078, + 0x772d, 0x017f, 0x007c, 0x0e7e, 0x0d7e, 0x603f, 0x0000, 0x2c68, + 0x017e, 0x2009, 0x0035, 0x1078, 0x91bc, 0x017f, 0x00c0, 0x785f, + 0x027e, 0x6228, 0x2268, 0x027f, 0x2071, 0xab8c, 0x6b1c, 0xa386, + 0x0003, 0x0040, 0x7863, 0xa386, 0x0006, 0x0040, 0x7867, 0x1078, + 0x772d, 0x0078, 0x7869, 0x1078, 0x786c, 0x0078, 0x7869, 0x1078, + 0x7938, 0x0d7f, 0x0e7f, 0x007c, 0x0f7e, 0x6810, 0x2078, 0xa186, + 0x0015, 0x0040, 0x791d, 0xa18e, 0x0016, 0x00c0, 0x7936, 0x700c, + 0xa08c, 0xff00, 0xa186, 0x1700, 0x0040, 0x7882, 0xa186, 0x0300, + 0x00c0, 0x78f8, 0x8fff, 0x00c0, 0x788c, 0x6800, 0xa086, 0x000f, + 0x0040, 0x78db, 0x0078, 0x7934, 0x6808, 0xa086, 0xffff, 0x00c0, + 0x7921, 0x784c, 0xa084, 0x0060, 0xa086, 0x0020, 0x00c0, 0x78a2, + 0x797c, 0x7810, 0xa106, 0x00c0, 0x7921, 0x7980, 0x7814, 0xa106, + 0x00c0, 0x7921, 0x1078, 0x8eb9, 0x6830, 0x7852, 0x784c, 0xc0dc, + 0xc0f4, 0xc0d4, 0x784e, 0x027e, 0xa00e, 0x6a14, 0x2001, 0x000a, + 0x1078, 0x5c1c, 0x7854, 0xa20a, 0x0048, 0x78b7, 0x8011, 0x7a56, + 0x82ff, 0x027f, 0x00c0, 0x78c3, 0x0c7e, 0x2d60, 0x1078, 0x8ae0, + 0x0c7f, 0x0078, 0x7934, 0x0c7e, 0x0d7e, 0x2f68, 0x6838, 0xd0fc, + 0x00c0, 0x78ce, 0x1078, 0x4353, 0x0078, 0x78d0, 0x1078, 0x4431, + 0x0d7f, 0x0c7f, 0x00c0, 0x7921, 0x0c7e, 0x2d60, 0x1078, 0x772d, + 0x0c7f, 0x0078, 0x7934, 0x0c7e, 0x1078, 0x9187, 0x0040, 0x78f1, + 0x6013, 0x0000, 0x6818, 0x601a, 0x601f, 0x0003, 0x6904, 0x0c7e, + 0x2d60, 0x1078, 0x772d, 0x0c7f, 0x1078, 0x775c, 0x0c7f, 0x0078, + 0x7934, 0x2001, 0xa8a4, 0x2004, 0x683e, 0x0c7f, 0x0078, 0x7934, + 0x7008, 0xa086, 0x000b, 0x00c0, 0x7912, 0x6018, 0x200c, 0xc1bc, + 0x2102, 0x0c7e, 0x2d60, 0x7853, 0x0003, 0x6007, 0x0085, 0x6003, + 0x000b, 0x601f, 0x0002, 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x0c7f, + 0x0078, 0x7934, 0x700c, 0xa086, 0x2a00, 0x00c0, 0x7921, 0x2001, + 0xa8a4, 0x2004, 0x683e, 0x0078, 0x7934, 0x1078, 0x7953, 0x0078, + 0x7936, 0x8fff, 0x1040, 0x1332, 0x0c7e, 0x0d7e, 0x2d60, 0x2f68, + 0x6837, 0x0103, 0x684b, 0x0003, 0x1078, 0x89cf, 0x1078, 0x8eb9, + 0x1078, 0x8ec6, 0x0d7f, 0x0c7f, 0x1078, 0x772d, 0x0f7f, 0x007c, + 0xa186, 0x0015, 0x00c0, 0x7942, 0x2001, 0xa8a4, 0x2004, 0x683e, + 0x0078, 0x7950, 0xa18e, 0x0016, 0x00c0, 0x7952, 0x0c7e, 0x2d00, + 0x2060, 0x1078, 0xa495, 0x1078, 0x5bc1, 0x1078, 0x772d, 0x0c7f, + 0x1078, 0x772d, 0x007c, 0x027e, 0x037e, 0x047e, 0x7228, 0x7c80, + 0x7b7c, 0xd2f4, 0x0040, 0x7962, 0x2001, 0xa8a4, 0x2004, 0x683e, + 0x0078, 0x79c6, 0x0c7e, 0x2d60, 0x1078, 0x89f3, 0x0c7f, 0x6804, + 0xa086, 0x0050, 0x00c0, 0x797a, 0x0c7e, 0x2d00, 0x2060, 0x6003, + 0x0001, 0x6007, 0x0050, 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x0c7f, + 0x0078, 0x79c6, 0x6800, 0xa086, 0x000f, 0x0040, 0x799c, 0x8fff, + 0x1040, 0x1332, 0x6824, 0xd0dc, 0x00c0, 0x799c, 0x6800, 0xa086, + 0x0004, 0x00c0, 0x79a1, 0x784c, 0xd0ac, 0x0040, 0x79a1, 0x784c, + 0xc0dc, 0xc0f4, 0x784e, 0x7850, 0xc0f4, 0xc0fc, 0x7852, 0x2001, + 0x0001, 0x682e, 0x0078, 0x79c0, 0x2001, 0x0007, 0x682e, 0x0078, + 0x79c0, 0x784c, 0xd0b4, 0x00c0, 0x79ae, 0xd0ac, 0x0040, 0x799c, + 0x784c, 0xd0f4, 0x00c0, 0x799c, 0x0078, 0x798f, 0xd2ec, 0x00c0, + 0x799c, 0x7024, 0xa306, 0x00c0, 0x79b9, 0x7020, 0xa406, 0x0040, + 0x799c, 0x7020, 0x6836, 0x7024, 0x683a, 0x2001, 0x0005, 0x682e, + 0x1078, 0x8ff0, 0x1078, 0x62d1, 0x0078, 0x79c8, 0x1078, 0x772d, + 0x047f, 0x037f, 0x027f, 0x007c, 0x0e7e, 0x0d7e, 0x027e, 0x6034, + 0x2068, 0x6a1c, 0xa286, 0x0007, 0x0040, 0x7a35, 0xa286, 0x0002, + 0x0040, 0x7a35, 0xa286, 0x0000, 0x0040, 0x7a35, 0x6808, 0x6338, + 0xa306, 0x00c0, 0x7a35, 0x2071, 0xab8c, 0xa186, 0x0015, 0x0040, + 0x7a2f, 0xa18e, 0x0016, 0x00c0, 0x7a02, 0x6030, 0xa084, 0x00ff, + 0xa086, 0x0001, 0x00c0, 0x7a02, 0x700c, 0xa086, 0x2a00, 0x00c0, + 0x7a02, 0x6034, 0xa080, 0x0009, 0x200c, 0xc1dd, 0xc1f5, 0x2102, + 0x0078, 0x7a2f, 0x0c7e, 0x6034, 0x2060, 0x6104, 0xa186, 0x004b, + 0x0040, 0x7a22, 0xa186, 0x004c, 0x0040, 0x7a22, 0xa186, 0x004d, + 0x0040, 0x7a22, 0xa186, 0x004e, 0x0040, 0x7a22, 0xa186, 0x0052, + 0x0040, 0x7a22, 0x6010, 0x2068, 0x1078, 0x8d06, 0x1040, 0x1332, + 0x6853, 0x0003, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, + 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x0c7f, 0x0078, 0x7a35, 0x6034, + 0x2068, 0x2001, 0xa8a4, 0x2004, 0x683e, 0x1078, 0x772d, 0x027f, + 0x0d7f, 0x0e7f, 0x007c, 0x0d7e, 0x20a9, 0x000e, 0x2e98, 0x6010, + 0x20a0, 0x53a3, 0xa1b6, 0x0015, 0x00c0, 0x7a73, 0x6018, 0x2068, + 0x157e, 0x037e, 0x027e, 0xae90, 0x000c, 0xa290, 0x0004, 0x20a9, + 0x0004, 0xad98, 0x000a, 0x1078, 0x80de, 0x027f, 0x037f, 0x157f, + 0x00c0, 0x7a76, 0x157e, 0x037e, 0x027e, 0xae90, 0x000c, 0xa290, + 0x0008, 0x20a9, 0x0004, 0xad98, 0x0006, 0x1078, 0x80de, 0x027f, + 0x037f, 0x157f, 0x00c0, 0x7a76, 0x7038, 0x680a, 0x703c, 0x680e, + 0x6800, 0xc08d, 0x6802, 0x0d7f, 0x0078, 0x77f8, 0x1078, 0x2880, + 0x0c7e, 0x1078, 0x76c7, 0x2f00, 0x601a, 0x6013, 0x0000, 0x601f, + 0x0001, 0x6007, 0x0001, 0x6003, 0x0001, 0x2001, 0x0007, 0x1078, + 0x4502, 0x1078, 0x4535, 0x1078, 0x5dd7, 0x1078, 0x62d1, 0x0c7f, + 0x0078, 0x7a73, 0x2100, 0xa1b2, 0x0044, 0x10c8, 0x1332, 0xa1b2, + 0x0040, 0x00c8, 0x7af7, 0x0079, 0x7a9d, 0x7aeb, 0x7adf, 0x7aeb, + 0x7aeb, 0x7aeb, 0x7aeb, 0x7add, 0x7add, 0x7add, 0x7add, 0x7add, + 0x7add, 0x7add, 0x7add, 0x7add, 0x7add, 0x7add, 0x7add, 0x7add, + 0x7add, 0x7add, 0x7add, 0x7add, 0x7add, 0x7add, 0x7add, 0x7add, + 0x7add, 0x7add, 0x7add, 0x7add, 0x7aeb, 0x7add, 0x7aeb, 0x7aeb, + 0x7add, 0x7add, 0x7add, 0x7add, 0x7add, 0x7aeb, 0x7add, 0x7add, + 0x7add, 0x7add, 0x7add, 0x7add, 0x7add, 0x7add, 0x7add, 0x7aeb, + 0x7aeb, 0x7add, 0x7add, 0x7add, 0x7add, 0x7add, 0x7add, 0x7add, + 0x7add, 0x7add, 0x7aeb, 0x7add, 0x7add, 0x1078, 0x1332, 0x6003, + 0x0001, 0x6106, 0x1078, 0x5dd7, 0x127e, 0x2091, 0x8000, 0x1078, + 0x62d1, 0x127f, 0x007c, 0x6003, 0x0001, 0x6106, 0x1078, 0x5dd7, + 0x127e, 0x2091, 0x8000, 0x1078, 0x62d1, 0x127f, 0x007c, 0x2600, + 0x0079, 0x7afa, 0x7afe, 0x7afe, 0x7afe, 0x7aeb, 0x1078, 0x1332, + 0x6004, 0xa0b2, 0x0044, 0x10c8, 0x1332, 0xa1b6, 0x0013, 0x00c0, + 0x7b10, 0xa0b2, 0x0040, 0x00c8, 0x7c79, 0x2008, 0x0079, 0x7bbf, + 0xa1b6, 0x0027, 0x00c0, 0x7b7c, 0x1078, 0x61cd, 0x6004, 0x1078, + 0x8eec, 0x0040, 0x7b2d, 0x1078, 0x8f00, 0x0040, 0x7b74, 0xa08e, + 0x0021, 0x0040, 0x7b78, 0xa08e, 0x0022, 0x0040, 0x7b74, 0xa08e, + 0x003d, 0x0040, 0x7b78, 0x0078, 0x7b6f, 0x1078, 0x28a6, 0x2001, + 0x0007, 0x1078, 0x4502, 0x6018, 0xa080, 0x0028, 0x200c, 0x1078, + 0x7c83, 0xa186, 0x007e, 0x00c0, 0x7b42, 0x2001, 0xa633, 0x2014, + 0xc285, 0x2202, 0x017e, 0x027e, 0x037e, 0x2110, 0x027e, 0x2019, + 0x0028, 0x1078, 0x73d0, 0x027f, 0x1078, 0xa4f1, 0x037f, 0x027f, + 0x017f, 0x017e, 0x027e, 0x037e, 0x2110, 0x2019, 0x0028, 0x1078, + 0x5f01, 0x077e, 0x2039, 0x0000, 0x1078, 0x5e0a, 0x0c7e, 0x6018, + 0xa065, 0x0040, 0x7b65, 0x1078, 0x47e9, 0x0c7f, 0x2c08, 0x1078, + 0x9f8b, 0x077f, 0x037f, 0x027f, 0x017f, 0x1078, 0x457f, 0x1078, + 0x772d, 0x1078, 0x62d1, 0x007c, 0x1078, 0x7c83, 0x0078, 0x7b6f, + 0x1078, 0x7ca6, 0x0078, 0x7b6f, 0xa186, 0x0014, 0x00c0, 0x7b73, + 0x1078, 0x61cd, 0x1078, 0x2880, 0x1078, 0x8eec, 0x00c0, 0x7b9b, + 0x1078, 0x28a6, 0x6018, 0xa080, 0x0028, 0x200c, 0x1078, 0x7c83, + 0xa186, 0x007e, 0x00c0, 0x7b99, 0x2001, 0xa633, 0x200c, 0xc185, + 0x2102, 0x0078, 0x7b6f, 0x1078, 0x8f00, 0x00c0, 0x7ba3, 0x1078, + 0x7c83, 0x0078, 0x7b6f, 0x6004, 0xa08e, 0x0032, 0x00c0, 0x7bb4, + 0x0e7e, 0x0f7e, 0x2071, 0xa682, 0x2079, 0x0000, 0x1078, 0x2bd7, + 0x0f7f, 0x0e7f, 0x0078, 0x7b6f, 0x6004, 0xa08e, 0x0021, 0x0040, + 0x7b9f, 0xa08e, 0x0022, 0x1040, 0x7c83, 0x0078, 0x7b6f, 0x7c01, + 0x7c03, 0x7c07, 0x7c0b, 0x7c0f, 0x7c13, 0x7bff, 0x7bff, 0x7bff, + 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, + 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, + 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7c17, 0x7c29, 0x7bff, + 0x7c2b, 0x7c29, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7c29, + 0x7c29, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, + 0x7bff, 0x7c5c, 0x7c29, 0x7bff, 0x7c23, 0x7bff, 0x7bff, 0x7bff, + 0x7c25, 0x7bff, 0x7bff, 0x7bff, 0x7c29, 0x7bff, 0x7bff, 0x1078, + 0x1332, 0x0078, 0x7c29, 0x2001, 0x000b, 0x0078, 0x7c36, 0x2001, + 0x0003, 0x0078, 0x7c36, 0x2001, 0x0005, 0x0078, 0x7c36, 0x2001, + 0x0001, 0x0078, 0x7c36, 0x2001, 0x0009, 0x0078, 0x7c36, 0x1078, + 0x61cd, 0x6003, 0x0005, 0x2001, 0xa8a4, 0x2004, 0x603e, 0x1078, + 0x62d1, 0x0078, 0x7c35, 0x0078, 0x7c29, 0x0078, 0x7c29, 0x1078, + 0x4502, 0x0078, 0x7c6e, 0x1078, 0x61cd, 0x6003, 0x0004, 0x2001, + 0xa8a2, 0x2004, 0x6016, 0x1078, 0x62d1, 0x007c, 0x1078, 0x4502, + 0x1078, 0x61cd, 0x2001, 0xa8a4, 0x2004, 0x603e, 0x6003, 0x0002, + 0x037e, 0x2019, 0xa65d, 0x2304, 0xa084, 0xff00, 0x00c0, 0x7c4d, + 0x2019, 0xa8a2, 0x231c, 0x0078, 0x7c56, 0x8007, 0xa09a, 0x0004, + 0x0048, 0x7c48, 0x8003, 0x801b, 0x831b, 0xa318, 0x6316, 0x037f, + 0x1078, 0x62d1, 0x0078, 0x7c35, 0x0e7e, 0x0f7e, 0x2071, 0xa682, + 0x2079, 0x0000, 0x1078, 0x2bd7, 0x0f7f, 0x0e7f, 0x1078, 0x61cd, + 0x1078, 0x772d, 0x1078, 0x62d1, 0x0078, 0x7c35, 0x1078, 0x61cd, + 0x6003, 0x0002, 0x2001, 0xa8a2, 0x2004, 0x6016, 0x1078, 0x62d1, + 0x007c, 0x2600, 0x2008, 0x0079, 0x7c7d, 0x7c81, 0x7c81, 0x7c81, + 0x7c6e, 0x1078, 0x1332, 0x0e7e, 0x1078, 0x8d06, 0x0040, 0x7c9f, + 0x6010, 0x2070, 0x7038, 0xd0fc, 0x0040, 0x7c9f, 0x7007, 0x0000, + 0x017e, 0x6004, 0xa08e, 0x0021, 0x0040, 0x7ca1, 0xa08e, 0x003d, + 0x0040, 0x7ca1, 0x017f, 0x7037, 0x0103, 0x7033, 0x0100, 0x0e7f, + 0x007c, 0x017f, 0x1078, 0x7ca6, 0x0078, 0x7c9f, 0x0e7e, 0xacf0, + 0x0004, 0x2e74, 0x7000, 0x2070, 0x7037, 0x0103, 0x7023, 0x8001, + 0x0e7f, 0x007c, 0x0d7e, 0x6618, 0x2668, 0x6804, 0xa084, 0x00ff, + 0x0d7f, 0xa0b2, 0x000c, 0x10c8, 0x1332, 0x6604, 0xa6b6, 0x0043, + 0x00c0, 0x7cc6, 0x1078, 0x9134, 0x0078, 0x7d25, 0x6604, 0xa6b6, + 0x0033, 0x00c0, 0x7ccf, 0x1078, 0x90d8, 0x0078, 0x7d25, 0x6604, + 0xa6b6, 0x0028, 0x00c0, 0x7cd8, 0x1078, 0x8f2f, 0x0078, 0x7d25, + 0x6604, 0xa6b6, 0x0029, 0x00c0, 0x7ce1, 0x1078, 0x8f49, 0x0078, + 0x7d25, 0x6604, 0xa6b6, 0x001f, 0x00c0, 0x7cea, 0x1078, 0x77de, + 0x0078, 0x7d25, 0x6604, 0xa6b6, 0x0000, 0x00c0, 0x7cf3, 0x1078, + 0x7a3b, 0x0078, 0x7d25, 0x6604, 0xa6b6, 0x0022, 0x00c0, 0x7cfc, + 0x1078, 0x7807, 0x0078, 0x7d25, 0x6604, 0xa6b6, 0x0035, 0x00c0, + 0x7d05, 0x1078, 0x7843, 0x0078, 0x7d25, 0x6604, 0xa6b6, 0x0039, + 0x00c0, 0x7d0e, 0x1078, 0x79cc, 0x0078, 0x7d25, 0x6604, 0xa6b6, + 0x003d, 0x00c0, 0x7d17, 0x1078, 0x7823, 0x0078, 0x7d25, 0xa1b6, + 0x0015, 0x00c0, 0x7d1f, 0x1079, 0x7d2a, 0x0078, 0x7d25, 0xa1b6, + 0x0016, 0x00c0, 0x7d26, 0x1079, 0x7e7f, 0x007c, 0x1078, 0x7773, + 0x0078, 0x7d25, 0x7d4e, 0x7d51, 0x7d4e, 0x7d9c, 0x7d4e, 0x7e13, + 0x7e8b, 0x7d4e, 0x7d4e, 0x7e57, 0x7d4e, 0x7e6d, 0xa1b6, 0x0048, + 0x0040, 0x7d42, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x1078, + 0x15fa, 0x007c, 0x0e7e, 0xacf0, 0x0004, 0x2e74, 0x7000, 0x2070, + 0x7037, 0x0103, 0x0e7f, 0x1078, 0x772d, 0x007c, 0x0005, 0x0005, + 0x007c, 0x0e7e, 0x2071, 0xa600, 0x7080, 0xa086, 0x0074, 0x00c0, + 0x7d85, 0x1078, 0x9f5f, 0x00c0, 0x7d77, 0x0d7e, 0x6018, 0x2068, + 0x7030, 0xd08c, 0x0040, 0x7d6a, 0x6800, 0xd0bc, 0x0040, 0x7d6a, + 0xc0c5, 0x6802, 0x1078, 0x7d89, 0x0d7f, 0x2001, 0x0006, 0x1078, + 0x4502, 0x1078, 0x28a6, 0x1078, 0x772d, 0x0078, 0x7d87, 0x2001, + 0x000a, 0x1078, 0x4502, 0x1078, 0x28a6, 0x6003, 0x0001, 0x6007, + 0x0001, 0x1078, 0x5dd7, 0x0078, 0x7d87, 0x1078, 0x7dff, 0x0e7f, + 0x007c, 0x6800, 0xd084, 0x0040, 0x7d9b, 0x2001, 0x0000, 0x1078, + 0x44ee, 0x2069, 0xa652, 0x6804, 0xd0a4, 0x0040, 0x7d9b, 0x2001, + 0x0006, 0x1078, 0x4535, 0x007c, 0x0d7e, 0x2011, 0xa620, 0x2204, + 0xa086, 0x0074, 0x00c0, 0x7dfb, 0x6018, 0x2068, 0x6aa0, 0xa286, + 0x007e, 0x00c0, 0x7daf, 0x1078, 0x7f9b, 0x0078, 0x7dfd, 0x1078, + 0x7f91, 0x6018, 0x2068, 0xa080, 0x0028, 0x2014, 0xa286, 0x0080, + 0x00c0, 0x7dd3, 0x6813, 0x00ff, 0x6817, 0xfffc, 0x6010, 0xa005, + 0x0040, 0x7dc9, 0x2068, 0x6807, 0x0000, 0x6837, 0x0103, 0x6833, + 0x0200, 0x2001, 0x0006, 0x1078, 0x4502, 0x1078, 0x28a6, 0x1078, + 0x772d, 0x0078, 0x7dfd, 0x0e7e, 0x2071, 0xa633, 0x2e04, 0xd09c, + 0x0040, 0x7dee, 0x2071, 0xab80, 0x7108, 0x720c, 0xa18c, 0x00ff, + 0x00c0, 0x7de6, 0xa284, 0xff00, 0x0040, 0x7dee, 0x6018, 0x2070, + 0x70a0, 0xd0bc, 0x00c0, 0x7dee, 0x7112, 0x7216, 0x0e7f, 0x2001, + 0x0004, 0x1078, 0x4502, 0x6003, 0x0001, 0x6007, 0x0003, 0x1078, + 0x5dd7, 0x0078, 0x7dfd, 0x1078, 0x7dff, 0x0d7f, 0x007c, 0x2001, + 0x0007, 0x1078, 0x4502, 0x2001, 0xa600, 0x2004, 0xa086, 0x0003, + 0x00c0, 0x7e0e, 0x2001, 0x0007, 0x1078, 0x4535, 0x1078, 0x28a6, + 0x1078, 0x772d, 0x007c, 0x0e7e, 0x2071, 0xa600, 0x7080, 0xa086, + 0x0014, 0x00c0, 0x7e51, 0x7000, 0xa086, 0x0003, 0x00c0, 0x7e26, + 0x6010, 0xa005, 0x00c0, 0x7e26, 0x1078, 0x3699, 0x0d7e, 0x6018, + 0x2068, 0x1078, 0x4649, 0x1078, 0x7d89, 0x0d7f, 0x1078, 0x8043, + 0x00c0, 0x7e51, 0x0d7e, 0x6018, 0x2068, 0x6890, 0x0d7f, 0xa005, + 0x0040, 0x7e51, 0x2001, 0x0006, 0x1078, 0x4502, 0x0e7e, 0x6010, + 0xa005, 0x0040, 0x7e4a, 0x2070, 0x7007, 0x0000, 0x7037, 0x0103, + 0x7033, 0x0200, 0x0e7f, 0x1078, 0x28a6, 0x1078, 0x772d, 0x0078, + 0x7e55, 0x1078, 0x7c83, 0x1078, 0x7dff, 0x0e7f, 0x007c, 0x2011, + 0xa620, 0x2204, 0xa086, 0x0014, 0x00c0, 0x7e6a, 0x2001, 0x0002, + 0x1078, 0x4502, 0x6003, 0x0001, 0x6007, 0x0001, 0x1078, 0x5dd7, + 0x0078, 0x7e6c, 0x1078, 0x7dff, 0x007c, 0x2011, 0xa620, 0x2204, + 0xa086, 0x0004, 0x00c0, 0x7e7c, 0x2001, 0x0007, 0x1078, 0x4502, + 0x1078, 0x772d, 0x0078, 0x7e7e, 0x1078, 0x7dff, 0x007c, 0x7d4e, + 0x7e97, 0x7d4e, 0x7ed2, 0x7d4e, 0x7f44, 0x7e8b, 0x7d4e, 0x7d4e, + 0x7f59, 0x7d4e, 0x7f6c, 0x6604, 0xa686, 0x0003, 0x0040, 0x7e13, + 0xa6b6, 0x001e, 0x00c0, 0x7e96, 0x1078, 0x772d, 0x007c, 0x0d7e, + 0x0c7e, 0x1078, 0x7f7f, 0x00c0, 0x7ead, 0x2001, 0x0000, 0x1078, + 0x44ee, 0x2001, 0x0002, 0x1078, 0x4502, 0x6003, 0x0001, 0x6007, + 0x0002, 0x1078, 0x5dd7, 0x0078, 0x7ecf, 0x2009, 0xab8e, 0x2104, + 0xa086, 0x0009, 0x00c0, 0x7ec2, 0x6018, 0x2068, 0x6840, 0xa084, + 0x00ff, 0xa005, 0x0040, 0x7ecd, 0x8001, 0x6842, 0x6017, 0x000a, + 0x0078, 0x7ecf, 0x2009, 0xab8f, 0x2104, 0xa084, 0xff00, 0xa086, + 0x1900, 0x00c0, 0x7ecd, 0x0078, 0x7ea1, 0x1078, 0x7dff, 0x0c7f, + 0x0d7f, 0x007c, 0x1078, 0x7f8e, 0x00c0, 0x7ee6, 0x2001, 0x0000, + 0x1078, 0x44ee, 0x2001, 0x0002, 0x1078, 0x4502, 0x6003, 0x0001, + 0x6007, 0x0002, 0x1078, 0x5dd7, 0x0078, 0x7f12, 0x1078, 0x7c83, + 0x2009, 0xab8e, 0x2134, 0xa6b4, 0x00ff, 0xa686, 0x0005, 0x0040, + 0x7f13, 0xa686, 0x000b, 0x0040, 0x7f10, 0x2009, 0xab8f, 0x2104, + 0xa084, 0xff00, 0x00c0, 0x7f00, 0xa686, 0x0009, 0x0040, 0x7f13, + 0xa086, 0x1900, 0x00c0, 0x7f10, 0xa686, 0x0009, 0x0040, 0x7f13, + 0x2001, 0x0004, 0x1078, 0x4502, 0x1078, 0x772d, 0x0078, 0x7f12, + 0x1078, 0x7dff, 0x007c, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x8d06, + 0x0040, 0x7f21, 0x6838, 0xd0fc, 0x0040, 0x7f21, 0x0d7f, 0x0078, + 0x7f10, 0x6018, 0x2068, 0x6840, 0xa084, 0x00ff, 0xa005, 0x0040, + 0x7f32, 0x8001, 0x6842, 0x6017, 0x000a, 0x6007, 0x0016, 0x0d7f, + 0x0078, 0x7f12, 0x68a0, 0xa086, 0x007e, 0x00c0, 0x7f3f, 0x0e7e, + 0x2071, 0xa600, 0x1078, 0x42b8, 0x0e7f, 0x0078, 0x7f41, 0x1078, + 0x2880, 0x0d7f, 0x0078, 0x7f10, 0x1078, 0x7f8e, 0x00c0, 0x7f54, + 0x2001, 0x0004, 0x1078, 0x4502, 0x6003, 0x0001, 0x6007, 0x0003, + 0x1078, 0x5dd7, 0x0078, 0x7f58, 0x1078, 0x7c83, 0x1078, 0x7dff, + 0x007c, 0x1078, 0x7f8e, 0x00c0, 0x7f69, 0x2001, 0x0008, 0x1078, + 0x4502, 0x6003, 0x0001, 0x6007, 0x0005, 0x1078, 0x5dd7, 0x0078, + 0x7f6b, 0x1078, 0x7dff, 0x007c, 0x1078, 0x7f8e, 0x00c0, 0x7f7c, + 0x2001, 0x000a, 0x1078, 0x4502, 0x6003, 0x0001, 0x6007, 0x0001, + 0x1078, 0x5dd7, 0x0078, 0x7f7e, 0x1078, 0x7dff, 0x007c, 0x2009, + 0xab8e, 0x2104, 0xa086, 0x0003, 0x00c0, 0x7f8d, 0x2009, 0xab8f, + 0x2104, 0xa084, 0xff00, 0xa086, 0x2a00, 0x007c, 0xa085, 0x0001, + 0x007c, 0x0c7e, 0x017e, 0xac88, 0x0006, 0x2164, 0x1078, 0x45d6, + 0x017f, 0x0c7f, 0x007c, 0x0f7e, 0x0e7e, 0x0d7e, 0x037e, 0x017e, + 0x6018, 0x2068, 0x2071, 0xa633, 0x2e04, 0xa085, 0x0003, 0x2072, + 0x1078, 0x8014, 0x0040, 0x7fd9, 0x2009, 0xa633, 0x2104, 0xc0cd, + 0x200a, 0x2001, 0xa653, 0x2004, 0xd0a4, 0x0040, 0x7fc2, 0xa006, + 0x2020, 0x2009, 0x002a, 0x1078, 0xa21d, 0x2001, 0xa60c, 0x200c, + 0xc195, 0x2102, 0x2019, 0x002a, 0x2009, 0x0001, 0x1078, 0x284f, + 0x2071, 0xa600, 0x1078, 0x2677, 0x0c7e, 0x157e, 0x20a9, 0x0081, + 0x2009, 0x007f, 0x1078, 0x298e, 0x8108, 0x00f0, 0x7fd2, 0x157f, + 0x0c7f, 0x1078, 0x7f91, 0x6813, 0x00ff, 0x6817, 0xfffe, 0x2071, + 0xab80, 0x2079, 0x0100, 0x2e04, 0xa084, 0x00ff, 0x2069, 0xa61b, + 0x206a, 0x78e6, 0x007e, 0x8e70, 0x2e04, 0x2069, 0xa61c, 0x206a, + 0x78ea, 0xa084, 0xff00, 0x017f, 0xa105, 0x2009, 0xa626, 0x200a, + 0x2069, 0xab8e, 0x2071, 0xa89e, 0x6810, 0x2072, 0x6814, 0x7006, + 0x6818, 0x700a, 0x681c, 0x700e, 0x1078, 0x906e, 0x2001, 0x0006, + 0x1078, 0x4502, 0x1078, 0x28a6, 0x1078, 0x772d, 0x017f, 0x037f, + 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x027e, 0x037e, 0x0e7e, 0x157e, + 0x2019, 0xa626, 0x231c, 0x83ff, 0x0040, 0x803e, 0x2071, 0xab80, + 0x2e14, 0xa294, 0x00ff, 0x7004, 0xa084, 0xff00, 0xa205, 0xa306, + 0x00c0, 0x803e, 0x2011, 0xab96, 0xad98, 0x000a, 0x20a9, 0x0004, + 0x1078, 0x80de, 0x00c0, 0x803e, 0x2011, 0xab9a, 0xad98, 0x0006, + 0x20a9, 0x0004, 0x1078, 0x80de, 0x00c0, 0x803e, 0x157f, 0x0e7f, + 0x037f, 0x027f, 0x007c, 0x0e7e, 0x2071, 0xab8c, 0x7004, 0xa086, + 0x0014, 0x00c0, 0x8066, 0x7008, 0xa086, 0x0800, 0x00c0, 0x8066, + 0x700c, 0xd0ec, 0x0040, 0x8064, 0xa084, 0x0f00, 0xa086, 0x0100, + 0x00c0, 0x8064, 0x7024, 0xd0a4, 0x00c0, 0x8061, 0xd0ac, 0x0040, + 0x8064, 0xa006, 0x0078, 0x8066, 0xa085, 0x0001, 0x0e7f, 0x007c, + 0x0e7e, 0x0d7e, 0x0c7e, 0x077e, 0x057e, 0x047e, 0x027e, 0x007e, + 0x127e, 0x2091, 0x8000, 0x2029, 0xa8ba, 0x252c, 0x2021, 0xa8c0, + 0x2424, 0x2061, 0xad00, 0x2071, 0xa600, 0x7248, 0x7064, 0xa202, + 0x00c8, 0x80cc, 0x1078, 0xa242, 0x0040, 0x80c4, 0x671c, 0xa786, + 0x0001, 0x0040, 0x80c4, 0xa786, 0x0007, 0x0040, 0x80c4, 0x2500, + 0xac06, 0x0040, 0x80c4, 0x2400, 0xac06, 0x0040, 0x80c4, 0x0c7e, + 0x6000, 0xa086, 0x0004, 0x00c0, 0x809f, 0x1078, 0x1757, 0xa786, + 0x0008, 0x00c0, 0x80ae, 0x1078, 0x8f00, 0x00c0, 0x80ae, 0x0c7f, + 0x1078, 0x7c83, 0x1078, 0x8ec6, 0x0078, 0x80c4, 0x6010, 0x2068, + 0x1078, 0x8d06, 0x0040, 0x80c1, 0xa786, 0x0003, 0x00c0, 0x80d6, + 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x4a73, 0x1078, + 0x8eb9, 0x1078, 0x8ec6, 0x0c7f, 0xace0, 0x0010, 0x7058, 0xac02, + 0x00c8, 0x80cc, 0x0078, 0x807d, 0x127f, 0x007f, 0x027f, 0x047f, + 0x057f, 0x077f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, 0xa786, 0x0006, + 0x00c0, 0x80b8, 0x1078, 0xa1ca, 0x0078, 0x80c1, 0x220c, 0x2304, + 0xa106, 0x00c0, 0x80e9, 0x8210, 0x8318, 0x00f0, 0x80de, 0xa006, + 0x007c, 0x2304, 0xa102, 0x0048, 0x80f1, 0x2001, 0x0001, 0x0078, + 0x80f3, 0x2001, 0x0000, 0xa18d, 0x0001, 0x007c, 0x6004, 0xa08a, + 0x0044, 0x10c8, 0x1332, 0x1078, 0x8eec, 0x0040, 0x8105, 0x1078, + 0x8f00, 0x0040, 0x8112, 0x0078, 0x810b, 0x1078, 0x28a6, 0x1078, + 0x8f00, 0x0040, 0x8112, 0x1078, 0x61cd, 0x1078, 0x772d, 0x1078, + 0x62d1, 0x007c, 0x1078, 0x7c83, 0x0078, 0x810b, 0xa182, 0x0040, + 0x0079, 0x811a, 0x812d, 0x812d, 0x812d, 0x812d, 0x812d, 0x812d, + 0x812d, 0x812d, 0x812d, 0x812d, 0x812d, 0x812f, 0x812f, 0x812f, + 0x812f, 0x812d, 0x812d, 0x812d, 0x812f, 0x1078, 0x1332, 0x600b, + 0xffff, 0x6003, 0x0001, 0x6106, 0x1078, 0x5d8a, 0x127e, 0x2091, + 0x8000, 0x1078, 0x62d1, 0x127f, 0x007c, 0xa186, 0x0013, 0x00c0, + 0x8146, 0x6004, 0xa082, 0x0040, 0x0079, 0x81d1, 0xa186, 0x0027, + 0x00c0, 0x8168, 0x1078, 0x61cd, 0x1078, 0x2880, 0x0d7e, 0x6110, + 0x2168, 0x1078, 0x8d06, 0x0040, 0x8162, 0x6837, 0x0103, 0x684b, + 0x0029, 0x6847, 0x0000, 0x694c, 0xc1c5, 0x694e, 0x1078, 0x4a73, + 0x1078, 0x8eb9, 0x0d7f, 0x1078, 0x772d, 0x1078, 0x62d1, 0x007c, + 0xa186, 0x0014, 0x00c0, 0x8171, 0x6004, 0xa082, 0x0040, 0x0079, + 0x8199, 0xa186, 0x0046, 0x0040, 0x817d, 0xa186, 0x0045, 0x0040, + 0x817d, 0xa186, 0x0047, 0x10c0, 0x1332, 0x2001, 0x0109, 0x2004, + 0xd084, 0x0040, 0x8196, 0x127e, 0x2091, 0x2200, 0x007e, 0x017e, + 0x027e, 0x1078, 0x5c56, 0x027f, 0x017f, 0x007f, 0x127f, 0x6000, + 0xa086, 0x0002, 0x00c0, 0x8196, 0x0078, 0x820e, 0x1078, 0x7773, + 0x007c, 0x81ae, 0x81ac, 0x81ac, 0x81ac, 0x81ac, 0x81ac, 0x81ac, + 0x81ac, 0x81ac, 0x81ac, 0x81ac, 0x81ca, 0x81ca, 0x81ca, 0x81ca, + 0x81ac, 0x81ca, 0x81ac, 0x81ca, 0x1078, 0x1332, 0x1078, 0x61cd, + 0x0d7e, 0x6110, 0x2168, 0x1078, 0x8d06, 0x0040, 0x81c4, 0x6837, + 0x0103, 0x684b, 0x0006, 0x6847, 0x0000, 0x6850, 0xc0ec, 0x6852, + 0x1078, 0x4a73, 0x1078, 0x8eb9, 0x0d7f, 0x1078, 0x772d, 0x1078, + 0x62d1, 0x007c, 0x1078, 0x61cd, 0x1078, 0x772d, 0x1078, 0x62d1, + 0x007c, 0x81e6, 0x81e4, 0x81e4, 0x81e4, 0x81e4, 0x81e4, 0x81e4, + 0x81e4, 0x81e4, 0x81e4, 0x81e4, 0x81f8, 0x81f8, 0x81f8, 0x81f8, + 0x81e4, 0x8207, 0x81e4, 0x81f8, 0x1078, 0x1332, 0x1078, 0x61cd, + 0x2001, 0xa8a4, 0x2004, 0x603e, 0x6003, 0x0002, 0x1078, 0x62d1, + 0x6010, 0xa088, 0x0013, 0x2104, 0xa085, 0x0400, 0x200a, 0x007c, + 0x1078, 0x61cd, 0x2001, 0xa8a2, 0x2004, 0x6016, 0x2001, 0xa8a4, + 0x2004, 0x603e, 0x6003, 0x000f, 0x1078, 0x62d1, 0x007c, 0x1078, + 0x61cd, 0x1078, 0x772d, 0x1078, 0x62d1, 0x007c, 0xa182, 0x0040, + 0x0079, 0x8212, 0x8225, 0x8225, 0x8225, 0x8225, 0x8225, 0x8227, + 0x8327, 0x8359, 0x8225, 0x8225, 0x8225, 0x8225, 0x8225, 0x8225, + 0x8225, 0x8225, 0x8225, 0x8225, 0x8225, 0x1078, 0x1332, 0x0e7e, + 0x0d7e, 0x603f, 0x0000, 0x2071, 0xab80, 0x7124, 0x610a, 0x2071, + 0xab8c, 0x6110, 0x2168, 0x7614, 0xa6b4, 0x0fff, 0x86ff, 0x0040, + 0x82e9, 0xa68c, 0x0c00, 0x0040, 0x825e, 0x0f7e, 0x2c78, 0x1078, + 0x4963, 0x0f7f, 0x0040, 0x825a, 0x684c, 0xd0ac, 0x0040, 0x825a, + 0x6024, 0xd0dc, 0x00c0, 0x825a, 0x6850, 0xd0bc, 0x00c0, 0x825a, + 0x7318, 0x6814, 0xa306, 0x00c0, 0x8301, 0x731c, 0x6810, 0xa306, + 0x00c0, 0x8301, 0x7318, 0x6b62, 0x731c, 0x6b5e, 0xa68c, 0x00ff, + 0xa186, 0x0002, 0x0040, 0x8291, 0xa186, 0x0028, 0x00c0, 0x826e, + 0x1078, 0x8eda, 0x684b, 0x001c, 0x0078, 0x8293, 0xd6dc, 0x0040, + 0x828a, 0x684b, 0x0015, 0x684c, 0xd0ac, 0x0040, 0x8288, 0x6914, + 0x6a10, 0x2100, 0xa205, 0x0040, 0x8288, 0x7018, 0xa106, 0x00c0, + 0x8285, 0x701c, 0xa206, 0x0040, 0x8288, 0x6962, 0x6a5e, 0xc6dc, + 0x0078, 0x8293, 0xd6d4, 0x0040, 0x8291, 0x684b, 0x0007, 0x0078, + 0x8293, 0x684b, 0x0000, 0x6837, 0x0103, 0x6e46, 0xa01e, 0xd6c4, + 0x0040, 0x82bc, 0xa686, 0x0100, 0x00c0, 0x82a7, 0x2001, 0xab99, + 0x2004, 0xa005, 0x00c0, 0x82a7, 0xc6c4, 0x0078, 0x8236, 0x7328, + 0x732c, 0x6b56, 0x83ff, 0x0040, 0x82bc, 0xa38a, 0x0009, 0x0048, + 0x82b3, 0x2019, 0x0008, 0x037e, 0x2308, 0x2019, 0xab98, 0xad90, + 0x0019, 0x1078, 0x89e2, 0x037f, 0xd6cc, 0x0040, 0x8317, 0x7124, + 0x695a, 0x81ff, 0x0040, 0x8317, 0xa192, 0x0021, 0x00c8, 0x82d5, + 0x2071, 0xab98, 0x831c, 0x2300, 0xae18, 0xad90, 0x001d, 0x1078, + 0x89e2, 0x1078, 0x91f4, 0x0078, 0x8317, 0x6838, 0xd0fc, 0x0040, + 0x82de, 0x2009, 0x0020, 0x695a, 0x0078, 0x82c8, 0x0f7e, 0x2d78, + 0x1078, 0x897a, 0x0f7f, 0x1078, 0x91f4, 0x1078, 0x89cf, 0x0078, + 0x8319, 0x0f7e, 0x2c78, 0x1078, 0x4963, 0x0f7f, 0x0040, 0x8307, + 0x684c, 0xd0ac, 0x0040, 0x8307, 0x6024, 0xd0dc, 0x00c0, 0x8307, + 0x6850, 0xd0bc, 0x00c0, 0x8307, 0x6810, 0x6914, 0xa105, 0x0040, + 0x8307, 0x1078, 0x8fbf, 0x0d7f, 0x0e7f, 0x0078, 0x8326, 0x684b, + 0x0000, 0x6837, 0x0103, 0x6e46, 0x684c, 0xd0ac, 0x0040, 0x8317, + 0x6810, 0x6914, 0xa115, 0x0040, 0x8317, 0x1078, 0x84d5, 0x1078, + 0x4a73, 0x6218, 0x2268, 0x6a3c, 0x8211, 0x6a3e, 0x1078, 0x8f89, + 0x0d7f, 0x0e7f, 0x00c0, 0x8326, 0x1078, 0x772d, 0x007c, 0x0f7e, + 0x6003, 0x0003, 0x2079, 0xab8c, 0x7c04, 0x7b00, 0x7e0c, 0x7d08, + 0x6010, 0x2078, 0x784c, 0xd0ac, 0x0040, 0x833e, 0x6003, 0x0002, + 0x0f7f, 0x007c, 0x2130, 0x2228, 0x0078, 0x834a, 0x2400, 0x797c, + 0xa10a, 0x2300, 0x7a80, 0xa213, 0x2600, 0xa102, 0x2500, 0xa203, + 0x0048, 0x833a, 0x7c12, 0x7b16, 0x7e0a, 0x7d0e, 0x0f7f, 0x603f, + 0x0000, 0x2c10, 0x1078, 0x1cf0, 0x1078, 0x5df6, 0x1078, 0x639b, + 0x007c, 0x2001, 0xa8a4, 0x2004, 0x603e, 0x6003, 0x0004, 0x6110, + 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x1078, 0x15fa, 0x007c, + 0xa182, 0x0040, 0x0079, 0x836c, 0x837f, 0x837f, 0x837f, 0x837f, + 0x837f, 0x8381, 0x8424, 0x837f, 0x837f, 0x843a, 0x84ab, 0x837f, + 0x837f, 0x837f, 0x837f, 0x84ba, 0x837f, 0x837f, 0x837f, 0x1078, + 0x1332, 0x077e, 0x0f7e, 0x0e7e, 0x0d7e, 0x2071, 0xab8c, 0x6110, + 0x2178, 0x7614, 0xa6b4, 0x0fff, 0x7e46, 0x7f4c, 0xc7e5, 0x7f4e, + 0x6218, 0x2268, 0x6a3c, 0x8211, 0x6a3e, 0x86ff, 0x0040, 0x841f, + 0xa694, 0xff00, 0xa284, 0x0c00, 0x0040, 0x83a2, 0x7018, 0x7862, + 0x701c, 0x785e, 0xa284, 0x0300, 0x0040, 0x841f, 0x1078, 0x138b, + 0x1040, 0x1332, 0x2d00, 0x784a, 0x7f4c, 0xc7cd, 0x7f4e, 0x6837, + 0x0103, 0x7838, 0x683a, 0x783c, 0x683e, 0x7840, 0x6842, 0x6e46, + 0xa68c, 0x0c00, 0x0040, 0x83c0, 0x7318, 0x6b62, 0x731c, 0x6b5e, + 0xa68c, 0x00ff, 0xa186, 0x0002, 0x0040, 0x83dc, 0xa186, 0x0028, + 0x00c0, 0x83ce, 0x684b, 0x001c, 0x0078, 0x83de, 0xd6dc, 0x0040, + 0x83d5, 0x684b, 0x0015, 0x0078, 0x83de, 0xd6d4, 0x0040, 0x83dc, + 0x684b, 0x0007, 0x0078, 0x83de, 0x684b, 0x0000, 0x6f4e, 0x7850, + 0x6852, 0x7854, 0x6856, 0xa01e, 0xd6c4, 0x0040, 0x83fc, 0x7328, + 0x732c, 0x6b56, 0x83ff, 0x0040, 0x83fc, 0xa38a, 0x0009, 0x0048, + 0x83f3, 0x2019, 0x0008, 0x037e, 0x2308, 0x2019, 0xab98, 0xad90, + 0x0019, 0x1078, 0x89e2, 0x037f, 0xd6cc, 0x0040, 0x841f, 0x7124, + 0x695a, 0x81ff, 0x0040, 0x841f, 0xa192, 0x0021, 0x00c8, 0x8413, + 0x2071, 0xab98, 0x831c, 0x2300, 0xae18, 0xad90, 0x001d, 0x1078, + 0x89e2, 0x0078, 0x841f, 0x7838, 0xd0fc, 0x0040, 0x841c, 0x2009, + 0x0020, 0x695a, 0x0078, 0x8408, 0x2d78, 0x1078, 0x897a, 0x0d7f, + 0x0e7f, 0x0f7f, 0x077f, 0x007c, 0x0f7e, 0x6003, 0x0003, 0x2079, + 0xab8c, 0x7c04, 0x7b00, 0x7e0c, 0x7d08, 0x6010, 0x2078, 0x7c12, + 0x7b16, 0x7e0a, 0x7d0e, 0x0f7f, 0x2c10, 0x1078, 0x1cf0, 0x1078, + 0x6df4, 0x007c, 0x0d7e, 0x0f7e, 0x2c78, 0x1078, 0x4963, 0x0f7f, + 0x0040, 0x8446, 0x2001, 0xa8a4, 0x2004, 0x603e, 0x6003, 0x0002, + 0x1078, 0x627a, 0x1078, 0x639b, 0x6110, 0x2168, 0x694c, 0xd1e4, + 0x0040, 0x84a9, 0xd1cc, 0x0040, 0x8480, 0x6948, 0x6838, 0xd0fc, + 0x0040, 0x8478, 0x017e, 0x684c, 0x007e, 0x6850, 0x007e, 0xad90, + 0x000d, 0xa198, 0x000d, 0x2009, 0x0020, 0x157e, 0x21a8, 0x2304, + 0x2012, 0x8318, 0x8210, 0x00f0, 0x8467, 0x157f, 0x007f, 0x6852, + 0x007f, 0x684e, 0x017f, 0x2168, 0x1078, 0x13b4, 0x0078, 0x84a3, + 0x017e, 0x1078, 0x13b4, 0x0d7f, 0x1078, 0x89cf, 0x0078, 0x84a3, + 0x6837, 0x0103, 0x6944, 0xa184, 0x00ff, 0xa0b6, 0x0002, 0x0040, + 0x849f, 0xa086, 0x0028, 0x00c0, 0x8491, 0x684b, 0x001c, 0x0078, + 0x84a1, 0xd1dc, 0x0040, 0x8498, 0x684b, 0x0015, 0x0078, 0x84a1, + 0xd1d4, 0x0040, 0x849f, 0x684b, 0x0007, 0x0078, 0x84a1, 0x684b, + 0x0000, 0x1078, 0x4a73, 0x1078, 0x8f89, 0x00c0, 0x84a9, 0x1078, + 0x772d, 0x0d7f, 0x007c, 0x2019, 0x0001, 0x1078, 0x7058, 0x6003, + 0x0002, 0x2001, 0xa8a4, 0x2004, 0x603e, 0x1078, 0x627a, 0x1078, + 0x639b, 0x007c, 0x1078, 0x627a, 0x1078, 0x2880, 0x0d7e, 0x6110, + 0x2168, 0x1078, 0x8d06, 0x0040, 0x84cf, 0x6837, 0x0103, 0x684b, + 0x0029, 0x6847, 0x0000, 0x1078, 0x4a73, 0x1078, 0x8eb9, 0x0d7f, + 0x1078, 0x772d, 0x1078, 0x639b, 0x007c, 0x684b, 0x0015, 0xd1fc, + 0x0040, 0x84e1, 0x684b, 0x0007, 0x8002, 0x8000, 0x810a, 0xa189, + 0x0000, 0x6962, 0x685e, 0x007c, 0xa182, 0x0040, 0x0079, 0x84e8, + 0x84fb, 0x84fb, 0x84fb, 0x84fb, 0x84fb, 0x84fd, 0x84fb, 0x85d0, + 0x85dc, 0x84fb, 0x84fb, 0x84fb, 0x84fb, 0x84fb, 0x84fb, 0x84fb, + 0x84fb, 0x84fb, 0x84fb, 0x1078, 0x1332, 0x077e, 0x0f7e, 0x0e7e, + 0x0d7e, 0x2071, 0xab8c, 0x6110, 0x2178, 0x7614, 0xa6b4, 0x0fff, + 0x0f7e, 0x2c78, 0x1078, 0x4963, 0x0f7f, 0x0040, 0x851b, 0xa684, + 0x00ff, 0x00c0, 0x851b, 0x6024, 0xd0f4, 0x0040, 0x851b, 0x1078, + 0x8fbf, 0x0078, 0x85cb, 0x7e46, 0x7f4c, 0xc7e5, 0x7f4e, 0x6218, + 0x2268, 0x6a3c, 0x8211, 0x6a3e, 0x86ff, 0x0040, 0x85c0, 0xa694, + 0xff00, 0xa284, 0x0c00, 0x0040, 0x8531, 0x7018, 0x7862, 0x701c, + 0x785e, 0xa284, 0x0300, 0x0040, 0x85bd, 0xa686, 0x0100, 0x00c0, + 0x8543, 0x2001, 0xab99, 0x2004, 0xa005, 0x00c0, 0x8543, 0xc6c4, + 0x7e46, 0x0078, 0x8524, 0x1078, 0x138b, 0x1040, 0x1332, 0x2d00, + 0x784a, 0x7f4c, 0xa7bd, 0x0200, 0x7f4e, 0x6837, 0x0103, 0x7838, + 0x683a, 0x783c, 0x683e, 0x7840, 0x6842, 0x6e46, 0xa68c, 0x0c00, + 0x0040, 0x855e, 0x7318, 0x6b62, 0x731c, 0x6b5e, 0xa68c, 0x00ff, + 0xa186, 0x0002, 0x0040, 0x857a, 0xa186, 0x0028, 0x00c0, 0x856c, + 0x684b, 0x001c, 0x0078, 0x857c, 0xd6dc, 0x0040, 0x8573, 0x684b, + 0x0015, 0x0078, 0x857c, 0xd6d4, 0x0040, 0x857a, 0x684b, 0x0007, + 0x0078, 0x857c, 0x684b, 0x0000, 0x6f4e, 0x7850, 0x6852, 0x7854, + 0x6856, 0xa01e, 0xd6c4, 0x0040, 0x859a, 0x7328, 0x732c, 0x6b56, + 0x83ff, 0x0040, 0x859a, 0xa38a, 0x0009, 0x0048, 0x8591, 0x2019, + 0x0008, 0x037e, 0x2308, 0x2019, 0xab98, 0xad90, 0x0019, 0x1078, + 0x89e2, 0x037f, 0xd6cc, 0x0040, 0x85bd, 0x7124, 0x695a, 0x81ff, + 0x0040, 0x85bd, 0xa192, 0x0021, 0x00c8, 0x85b1, 0x2071, 0xab98, + 0x831c, 0x2300, 0xae18, 0xad90, 0x001d, 0x1078, 0x89e2, 0x0078, + 0x85bd, 0x7838, 0xd0fc, 0x0040, 0x85ba, 0x2009, 0x0020, 0x695a, + 0x0078, 0x85a6, 0x2d78, 0x1078, 0x897a, 0xd6dc, 0x00c0, 0x85c3, + 0xa006, 0x0078, 0x85c9, 0x2001, 0x0001, 0x2071, 0xab8c, 0x7218, + 0x731c, 0x1078, 0x1653, 0x0d7f, 0x0e7f, 0x0f7f, 0x077f, 0x007c, + 0x2001, 0xa8a4, 0x2004, 0x603e, 0x20e1, 0x0005, 0x3d18, 0x3e20, + 0x2c10, 0x1078, 0x15fa, 0x007c, 0x2001, 0xa8a4, 0x2004, 0x603e, + 0x0d7e, 0x6003, 0x0002, 0x6110, 0x2168, 0x694c, 0xd1e4, 0x0040, + 0x870c, 0x603f, 0x0000, 0x0f7e, 0x2c78, 0x1078, 0x4963, 0x0f7f, + 0x0040, 0x8622, 0x6814, 0x6910, 0xa115, 0x0040, 0x8622, 0x6a60, + 0xa206, 0x00c0, 0x85ff, 0x685c, 0xa106, 0x0040, 0x8622, 0x684c, + 0xc0e4, 0x684e, 0x6847, 0x0000, 0x6863, 0x0000, 0x685f, 0x0000, + 0x6024, 0xd0f4, 0x00c0, 0x8617, 0x697c, 0x6810, 0xa102, 0x603a, + 0x6980, 0x6814, 0xa103, 0x6036, 0x6024, 0xc0f5, 0x6026, 0x0d7e, + 0x6018, 0x2068, 0x683c, 0x8000, 0x683e, 0x0d7f, 0x1078, 0x8fbf, + 0x0078, 0x870c, 0x694c, 0xd1cc, 0x0040, 0x86d1, 0x6948, 0x6838, + 0xd0fc, 0x0040, 0x8689, 0x017e, 0x684c, 0x007e, 0x6850, 0x007e, + 0x0f7e, 0x2178, 0x7944, 0xa184, 0x00ff, 0xa0b6, 0x0002, 0x0040, + 0x865c, 0xa086, 0x0028, 0x00c0, 0x8643, 0x684b, 0x001c, 0x784b, + 0x001c, 0x0078, 0x8667, 0xd1dc, 0x0040, 0x8653, 0x684b, 0x0015, + 0x784b, 0x0015, 0x1078, 0x916c, 0x0040, 0x8651, 0x7944, 0xc1dc, + 0x7946, 0x0078, 0x8667, 0xd1d4, 0x0040, 0x865c, 0x684b, 0x0007, + 0x784b, 0x0007, 0x0078, 0x8667, 0x684c, 0xd0ac, 0x0040, 0x8667, + 0x6810, 0x6914, 0xa115, 0x0040, 0x8667, 0x1078, 0x84d5, 0x6848, + 0x784a, 0x6860, 0x7862, 0x685c, 0x785e, 0xad90, 0x000d, 0xaf98, + 0x000d, 0x2009, 0x0020, 0x157e, 0x21a8, 0x2304, 0x2012, 0x8318, + 0x8210, 0x00f0, 0x8675, 0x157f, 0x0f7f, 0x007f, 0x6852, 0x007f, + 0x684e, 0x1078, 0x91f4, 0x017f, 0x2168, 0x1078, 0x13b4, 0x0078, + 0x8706, 0x017e, 0x0f7e, 0x2178, 0x7944, 0xa184, 0x00ff, 0xa0b6, + 0x0002, 0x0040, 0x86b6, 0xa086, 0x0028, 0x00c0, 0x869d, 0x684b, + 0x001c, 0x784b, 0x001c, 0x0078, 0x86c1, 0xd1dc, 0x0040, 0x86ad, + 0x684b, 0x0015, 0x784b, 0x0015, 0x1078, 0x916c, 0x0040, 0x86ab, + 0x7944, 0xc1dc, 0x7946, 0x0078, 0x86c1, 0xd1d4, 0x0040, 0x86b6, + 0x684b, 0x0007, 0x784b, 0x0007, 0x0078, 0x86c1, 0x684c, 0xd0ac, + 0x0040, 0x86c1, 0x6810, 0x6914, 0xa115, 0x0040, 0x86c1, 0x1078, + 0x84d5, 0x6860, 0x7862, 0x685c, 0x785e, 0x684c, 0x784e, 0x0f7f, + 0x1078, 0x13b4, 0x0d7f, 0x1078, 0x91f4, 0x1078, 0x89cf, 0x0078, + 0x8706, 0x6837, 0x0103, 0x6944, 0xa184, 0x00ff, 0xa0b6, 0x0002, + 0x0040, 0x86f7, 0xa086, 0x0028, 0x00c0, 0x86e2, 0x684b, 0x001c, + 0x0078, 0x8704, 0xd1dc, 0x0040, 0x86f0, 0x684b, 0x0015, 0x1078, + 0x916c, 0x0040, 0x86ee, 0x6944, 0xc1dc, 0x6946, 0x0078, 0x8704, + 0xd1d4, 0x0040, 0x86f7, 0x684b, 0x0007, 0x0078, 0x8704, 0x684b, + 0x0000, 0x684c, 0xd0ac, 0x0040, 0x8704, 0x6810, 0x6914, 0xa115, + 0x0040, 0x8704, 0x1078, 0x84d5, 0x1078, 0x4a73, 0x1078, 0x8f89, + 0x00c0, 0x870c, 0x1078, 0x772d, 0x0d7f, 0x007c, 0x1078, 0x61cd, + 0x0078, 0x8714, 0x1078, 0x627a, 0x1078, 0x8d06, 0x0040, 0x8733, + 0x0d7e, 0x6110, 0x2168, 0x6837, 0x0103, 0x2009, 0xa60c, 0x210c, + 0xd18c, 0x00c0, 0x873e, 0xd184, 0x00c0, 0x873a, 0x6108, 0x694a, + 0xa18e, 0x0029, 0x00c0, 0x872e, 0x1078, 0xa4e2, 0x6847, 0x0000, + 0x1078, 0x4a73, 0x0d7f, 0x1078, 0x772d, 0x1078, 0x62d1, 0x1078, + 0x639b, 0x007c, 0x684b, 0x0004, 0x0078, 0x872e, 0x684b, 0x0004, + 0x0078, 0x872e, 0xa182, 0x0040, 0x0079, 0x8746, 0x8759, 0x8759, + 0x8759, 0x8759, 0x8759, 0x875b, 0x8759, 0x875e, 0x8759, 0x8759, + 0x8759, 0x8759, 0x8759, 0x8759, 0x8759, 0x8759, 0x8759, 0x8759, + 0x8759, 0x1078, 0x1332, 0x1078, 0x772d, 0x007c, 0x007e, 0x027e, + 0xa016, 0x1078, 0x15fa, 0x027f, 0x007f, 0x007c, 0xa182, 0x0085, + 0x0079, 0x876a, 0x8773, 0x8771, 0x8771, 0x877f, 0x8771, 0x8771, + 0x8771, 0x1078, 0x1332, 0x6003, 0x0001, 0x6106, 0x1078, 0x5d8a, + 0x127e, 0x2091, 0x8000, 0x1078, 0x62d1, 0x127f, 0x007c, 0x027e, + 0x057e, 0x0d7e, 0x0e7e, 0x2071, 0xab80, 0x7224, 0x6212, 0x7220, + 0x1078, 0x8cf2, 0x0040, 0x87a4, 0x2268, 0x6800, 0xa086, 0x0000, + 0x0040, 0x87a4, 0x6018, 0x6d18, 0xa52e, 0x00c0, 0x87a4, 0x0c7e, + 0x2d60, 0x1078, 0x89f3, 0x0c7f, 0x0040, 0x87a4, 0x6803, 0x0002, + 0x6007, 0x0086, 0x0078, 0x87a6, 0x6007, 0x0087, 0x6003, 0x0001, + 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x0f7e, 0x2278, 0x1078, 0x4963, + 0x0f7f, 0x0040, 0x87be, 0x6824, 0xd0ec, 0x0040, 0x87be, 0x0c7e, + 0x2260, 0x603f, 0x0000, 0x1078, 0x8fbf, 0x0c7f, 0x0e7f, 0x0d7f, + 0x057f, 0x027f, 0x007c, 0xa186, 0x0013, 0x00c0, 0x87d4, 0x6004, + 0xa08a, 0x0085, 0x1048, 0x1332, 0xa08a, 0x008c, 0x10c8, 0x1332, + 0xa082, 0x0085, 0x0079, 0x87e3, 0xa186, 0x0027, 0x0040, 0x87dc, + 0xa186, 0x0014, 0x10c0, 0x1332, 0x1078, 0x61cd, 0x1078, 0x8ec6, + 0x1078, 0x62d1, 0x007c, 0x87ea, 0x87ec, 0x87ec, 0x87ea, 0x87ea, + 0x87ea, 0x87ea, 0x1078, 0x1332, 0x1078, 0x61cd, 0x1078, 0x8ec6, + 0x1078, 0x62d1, 0x007c, 0xa186, 0x0013, 0x00c0, 0x87fd, 0x6004, + 0xa082, 0x0085, 0x2008, 0x0078, 0x8838, 0xa186, 0x0027, 0x00c0, + 0x8820, 0x1078, 0x61cd, 0x1078, 0x2880, 0x0d7e, 0x6010, 0x2068, + 0x1078, 0x8d06, 0x0040, 0x8816, 0x6837, 0x0103, 0x6847, 0x0000, + 0x684b, 0x0029, 0x1078, 0x4a73, 0x1078, 0x8eb9, 0x0d7f, 0x1078, + 0x772d, 0x1078, 0x62d1, 0x007c, 0x1078, 0x7773, 0x0078, 0x881b, + 0xa186, 0x0014, 0x00c0, 0x881c, 0x1078, 0x61cd, 0x0d7e, 0x6010, + 0x2068, 0x1078, 0x8d06, 0x0040, 0x8816, 0x6837, 0x0103, 0x6847, + 0x0000, 0x684b, 0x0006, 0x6850, 0xc0ec, 0x6852, 0x0078, 0x8812, + 0x0079, 0x883a, 0x8843, 0x8841, 0x8841, 0x8841, 0x8841, 0x8841, + 0x885e, 0x1078, 0x1332, 0x1078, 0x61cd, 0x6030, 0xa08c, 0xff00, + 0x810f, 0xa186, 0x0039, 0x0040, 0x8851, 0xa186, 0x0035, 0x00c0, + 0x8855, 0x2001, 0xa8a2, 0x0078, 0x8857, 0x2001, 0xa8a3, 0x2004, + 0x6016, 0x6003, 0x000c, 0x1078, 0x62d1, 0x007c, 0x1078, 0x61cd, + 0x6030, 0xa08c, 0xff00, 0x810f, 0xa186, 0x0039, 0x0040, 0x886c, + 0xa186, 0x0035, 0x00c0, 0x8870, 0x2001, 0xa8a2, 0x0078, 0x8872, + 0x2001, 0xa8a3, 0x2004, 0x6016, 0x6003, 0x000e, 0x1078, 0x62d1, + 0x007c, 0xa182, 0x008c, 0x00c8, 0x8883, 0xa182, 0x0085, 0x0048, + 0x8883, 0x0079, 0x8886, 0x1078, 0x7773, 0x007c, 0x888d, 0x888d, + 0x888d, 0x888d, 0x888f, 0x88ec, 0x888d, 0x1078, 0x1332, 0x0f7e, + 0x2c78, 0x1078, 0x4963, 0x0f7f, 0x0040, 0x88a2, 0x6030, 0xa08c, + 0xff00, 0x810f, 0xa186, 0x0039, 0x0040, 0x8903, 0xa186, 0x0035, + 0x0040, 0x8903, 0x0d7e, 0x1078, 0x8d06, 0x00c0, 0x88ab, 0x1078, + 0x8eb9, 0x0078, 0x88ce, 0x6010, 0x2068, 0x684c, 0xd0e4, 0x00c0, + 0x88b3, 0x1078, 0x8eb9, 0x6837, 0x0103, 0x6850, 0xd0b4, 0x0040, + 0x88bf, 0x684b, 0x0006, 0xc0ec, 0x6852, 0x0078, 0x88ca, 0xd0bc, + 0x0040, 0x88c6, 0x684b, 0x0002, 0x0078, 0x88ca, 0x684b, 0x0005, + 0x1078, 0x8f85, 0x6847, 0x0000, 0x1078, 0x4a73, 0x2c68, 0x1078, + 0x76c7, 0x0040, 0x88e7, 0x6003, 0x0001, 0x6007, 0x001e, 0x2009, + 0xab8e, 0x210c, 0x6136, 0x2009, 0xab8f, 0x210c, 0x613a, 0x6918, + 0x611a, 0x6920, 0x6122, 0x601f, 0x0001, 0x1078, 0x5d8a, 0x2d60, + 0x1078, 0x772d, 0x0d7f, 0x007c, 0x0f7e, 0x2c78, 0x1078, 0x4963, + 0x0f7f, 0x0040, 0x8929, 0x6030, 0xa08c, 0xff00, 0x810f, 0xa186, + 0x0035, 0x0040, 0x8903, 0xa186, 0x001e, 0x0040, 0x8903, 0xa186, + 0x0039, 0x00c0, 0x8929, 0x0d7e, 0x2c68, 0x1078, 0x91bc, 0x00c0, + 0x894d, 0x1078, 0x76c7, 0x0040, 0x8926, 0x6106, 0x6003, 0x0001, + 0x601f, 0x0001, 0x6918, 0x611a, 0x6928, 0x612a, 0x692c, 0x612e, + 0x6930, 0xa18c, 0x00ff, 0x6132, 0x6934, 0x6136, 0x6938, 0x613a, + 0x6920, 0x6122, 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x2d60, 0x0078, + 0x894d, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x8d06, 0x0040, 0x894d, + 0x6837, 0x0103, 0x6850, 0xd0b4, 0x0040, 0x893c, 0xc0ec, 0x6852, + 0x684b, 0x0006, 0x0078, 0x8947, 0xd0bc, 0x0040, 0x8943, 0x684b, + 0x0002, 0x0078, 0x8947, 0x684b, 0x0005, 0x1078, 0x8f85, 0x6847, + 0x0000, 0x1078, 0x4a73, 0x1078, 0x8eb9, 0x0d7f, 0x1078, 0x772d, + 0x007c, 0x017e, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x8d06, 0x0040, + 0x8961, 0x6837, 0x0103, 0x684b, 0x0028, 0x6847, 0x0000, 0x1078, + 0x4a73, 0x0d7f, 0x017f, 0xa186, 0x0013, 0x0040, 0x8973, 0xa186, + 0x0014, 0x0040, 0x8973, 0xa186, 0x0027, 0x0040, 0x8973, 0x1078, + 0x7773, 0x0078, 0x8979, 0x1078, 0x61cd, 0x1078, 0x8ec6, 0x1078, + 0x62d1, 0x007c, 0x057e, 0x067e, 0x0d7e, 0x0f7e, 0x2029, 0x0001, + 0xa182, 0x0101, 0x00c8, 0x8986, 0x0078, 0x8988, 0x2009, 0x0100, + 0x2130, 0x2069, 0xab98, 0x831c, 0x2300, 0xad18, 0x2009, 0x0020, + 0xaf90, 0x001d, 0x1078, 0x89e2, 0xa6b2, 0x0020, 0x7804, 0xa06d, + 0x0040, 0x899c, 0x1078, 0x13b4, 0x1078, 0x138b, 0x0040, 0x89c6, + 0x8528, 0x6837, 0x0110, 0x683b, 0x0000, 0x2d20, 0x7c06, 0xa68a, + 0x003d, 0x00c8, 0x89b2, 0x2608, 0xad90, 0x000f, 0x1078, 0x89e2, + 0x0078, 0x89c6, 0xa6b2, 0x003c, 0x2009, 0x003c, 0x2d78, 0xad90, + 0x000f, 0x1078, 0x89e2, 0x0078, 0x899c, 0x0f7f, 0x852f, 0xa5ad, + 0x0003, 0x7d36, 0xa5ac, 0x0000, 0x0078, 0x89cb, 0x0f7f, 0x852f, + 0xa5ad, 0x0003, 0x7d36, 0x0d7f, 0x067f, 0x057f, 0x007c, 0x0f7e, + 0x8dff, 0x0040, 0x89e0, 0x6804, 0xa07d, 0x0040, 0x89de, 0x6807, + 0x0000, 0x1078, 0x4a73, 0x2f68, 0x0078, 0x89d3, 0x1078, 0x4a73, + 0x0f7f, 0x007c, 0x157e, 0xa184, 0x0001, 0x0040, 0x89e8, 0x8108, + 0x810c, 0x21a8, 0x2304, 0x8007, 0x2012, 0x8318, 0x8210, 0x00f0, + 0x89ea, 0x157f, 0x007c, 0x067e, 0x127e, 0x2091, 0x8000, 0x2031, + 0x0001, 0x601c, 0xa084, 0x000f, 0x1079, 0x8a0f, 0x127f, 0x067f, + 0x007c, 0x127e, 0x2091, 0x8000, 0x067e, 0x2031, 0x0000, 0x601c, + 0xa084, 0x000f, 0x1079, 0x8a0f, 0x067f, 0x127f, 0x007c, 0x8a29, + 0x8a17, 0x8a24, 0x8a45, 0x8a17, 0x8a24, 0x8a45, 0x8a24, 0x1078, + 0x1332, 0x037e, 0x2019, 0x0010, 0x1078, 0x9dc7, 0x601f, 0x0006, + 0x6003, 0x0007, 0x037f, 0x007c, 0xa006, 0x007c, 0xa085, 0x0001, + 0x007c, 0x0d7e, 0x86ff, 0x00c0, 0x8a40, 0x6010, 0x2068, 0x1078, + 0x8d06, 0x0040, 0x8a42, 0xa00e, 0x2001, 0x0005, 0x1078, 0x4b51, + 0x1078, 0x8f85, 0x1078, 0x4a73, 0x1078, 0x772d, 0xa085, 0x0001, + 0x0d7f, 0x007c, 0xa006, 0x0078, 0x8a40, 0x6000, 0xa08a, 0x0010, + 0x10c8, 0x1332, 0x1079, 0x8a4d, 0x007c, 0x8a5d, 0x8a82, 0x8a5f, + 0x8aa5, 0x8a7e, 0x8a5d, 0x8a24, 0x8a29, 0x8a29, 0x8a24, 0x8a24, + 0x8a24, 0x8a24, 0x8a24, 0x8a24, 0x8a24, 0x1078, 0x1332, 0x86ff, + 0x00c0, 0x8a7b, 0x601c, 0xa086, 0x0006, 0x0040, 0x8a7b, 0x0d7e, + 0x6010, 0x2068, 0x1078, 0x8d06, 0x0040, 0x8a70, 0x1078, 0x8f85, + 0x0d7f, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x1078, + 0x5d8a, 0x1078, 0x62d1, 0xa085, 0x0001, 0x007c, 0x1078, 0x1757, + 0x0078, 0x8a5f, 0x0e7e, 0x2071, 0xa8b1, 0x7024, 0xac06, 0x00c0, + 0x8a8b, 0x1078, 0x6fc4, 0x601c, 0xa084, 0x000f, 0xa086, 0x0006, + 0x00c0, 0x8a9d, 0x087e, 0x097e, 0x2049, 0x0001, 0x2c40, 0x1078, + 0x7246, 0x097f, 0x087f, 0x0078, 0x8a9f, 0x1078, 0x6ebe, 0x0e7f, + 0x00c0, 0x8a5f, 0x1078, 0x8a24, 0x007c, 0x037e, 0x0e7e, 0x2071, + 0xa8b1, 0x703c, 0xac06, 0x00c0, 0x8ab5, 0x2019, 0x0000, 0x1078, + 0x7058, 0x0e7f, 0x037f, 0x0078, 0x8a5f, 0x1078, 0x738a, 0x0e7f, + 0x037f, 0x00c0, 0x8a5f, 0x1078, 0x8a24, 0x007c, 0x0c7e, 0x601c, + 0xa084, 0x000f, 0x1079, 0x8ac6, 0x0c7f, 0x007c, 0x8ad5, 0x8b47, + 0x8c7f, 0x8ae0, 0x8ec6, 0x8ad5, 0x9db8, 0x772d, 0x8b47, 0x1078, + 0x8f00, 0x00c0, 0x8ad5, 0x1078, 0x7c83, 0x007c, 0x1078, 0x61cd, + 0x1078, 0x62d1, 0x1078, 0x772d, 0x007c, 0x6017, 0x0001, 0x007c, + 0x1078, 0x8d06, 0x0040, 0x8ae8, 0x6010, 0xa080, 0x0019, 0x2c02, + 0x6000, 0xa08a, 0x0010, 0x10c8, 0x1332, 0x1079, 0x8af0, 0x007c, + 0x8b00, 0x8b02, 0x8b24, 0x8b36, 0x8b43, 0x8b00, 0x8ad5, 0x8ad5, + 0x8ad5, 0x8b36, 0x8b36, 0x8b00, 0x8b00, 0x8b00, 0x8b00, 0x8b40, + 0x1078, 0x1332, 0x0e7e, 0x6010, 0x2070, 0x7050, 0xc0b5, 0x7052, + 0x2071, 0xa8b1, 0x7024, 0xac06, 0x0040, 0x8b20, 0x1078, 0x6ebe, + 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x2001, 0xa8a3, + 0x2004, 0x6016, 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x0e7f, 0x007c, + 0x6017, 0x0001, 0x0078, 0x8b1e, 0x0d7e, 0x6010, 0x2068, 0x6850, + 0xc0b5, 0x6852, 0x0d7f, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, + 0x0002, 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x007c, 0x0d7e, 0x6017, + 0x0001, 0x6010, 0x2068, 0x6850, 0xc0b5, 0x6852, 0x0d7f, 0x007c, + 0x1078, 0x772d, 0x007c, 0x1078, 0x1757, 0x0078, 0x8b24, 0x6000, + 0xa08a, 0x0010, 0x10c8, 0x1332, 0x1079, 0x8b4f, 0x007c, 0x8b5f, + 0x8add, 0x8b61, 0x8b5f, 0x8b61, 0x8b61, 0x8ad6, 0x8b5f, 0x8acf, + 0x8acf, 0x8b5f, 0x8b5f, 0x8b5f, 0x8b5f, 0x8b5f, 0x8b5f, 0x1078, + 0x1332, 0x0d7e, 0x6018, 0x2068, 0x6804, 0xa084, 0x00ff, 0x0d7f, + 0xa08a, 0x000c, 0x10c8, 0x1332, 0x1079, 0x8b6f, 0x007c, 0x8b7b, + 0x8c23, 0x8b7d, 0x8bbd, 0x8b7d, 0x8bbd, 0x8b7d, 0x8b8a, 0x8b7b, + 0x8bbd, 0x8b7b, 0x8ba7, 0x1078, 0x1332, 0x6004, 0xa08e, 0x0016, + 0x0040, 0x8bb8, 0xa08e, 0x0004, 0x0040, 0x8bb8, 0xa08e, 0x0002, + 0x0040, 0x8bb8, 0x6004, 0x1078, 0x8f00, 0x0040, 0x8c3e, 0xa08e, + 0x0021, 0x0040, 0x8c42, 0xa08e, 0x0022, 0x0040, 0x8c3e, 0xa08e, + 0x003d, 0x0040, 0x8c42, 0xa08e, 0x0039, 0x0040, 0x8c46, 0xa08e, + 0x0035, 0x0040, 0x8c46, 0xa08e, 0x001e, 0x0040, 0x8bba, 0xa08e, + 0x0001, 0x00c0, 0x8bb6, 0x0d7e, 0x6018, 0x2068, 0x6804, 0xa084, + 0x00ff, 0x0d7f, 0xa086, 0x0006, 0x0040, 0x8bb8, 0x1078, 0x2880, + 0x1078, 0x7c83, 0x1078, 0x8ec6, 0x007c, 0x0c7e, 0x0d7e, 0x6104, + 0xa186, 0x0016, 0x0040, 0x8c13, 0xa186, 0x0002, 0x00c0, 0x8be6, + 0x6018, 0x2068, 0x68a0, 0xd0bc, 0x00c0, 0x8c6a, 0x6840, 0xa084, + 0x00ff, 0xa005, 0x0040, 0x8be6, 0x8001, 0x6842, 0x6013, 0x0000, + 0x601f, 0x0007, 0x6017, 0x0398, 0x1078, 0x76c7, 0x0040, 0x8be6, + 0x2d00, 0x601a, 0x601f, 0x0001, 0x0078, 0x8c13, 0x0d7f, 0x0c7f, + 0x6004, 0xa08e, 0x0002, 0x00c0, 0x8c04, 0x6018, 0xa080, 0x0028, + 0x2004, 0xa086, 0x007e, 0x00c0, 0x8c04, 0x2009, 0xa633, 0x2104, + 0xc085, 0x200a, 0x0e7e, 0x2071, 0xa600, 0x1078, 0x42b8, 0x0e7f, + 0x1078, 0x7c83, 0x0078, 0x8c08, 0x1078, 0x7c83, 0x1078, 0x2880, + 0x0e7e, 0x127e, 0x2091, 0x8000, 0x1078, 0x28a6, 0x127f, 0x0e7f, + 0x1078, 0x8ec6, 0x007c, 0x2001, 0x0002, 0x1078, 0x4502, 0x6003, + 0x0001, 0x6007, 0x0002, 0x1078, 0x5dd7, 0x1078, 0x62d1, 0x0d7f, + 0x0c7f, 0x0078, 0x8c12, 0x0c7e, 0x0d7e, 0x6104, 0xa186, 0x0016, + 0x0040, 0x8c13, 0x6018, 0x2068, 0x6840, 0xa084, 0x00ff, 0xa005, + 0x0040, 0x8be6, 0x8001, 0x6842, 0x6003, 0x0001, 0x1078, 0x5dd7, + 0x1078, 0x62d1, 0x0d7f, 0x0c7f, 0x0078, 0x8c12, 0x1078, 0x7c83, + 0x0078, 0x8bba, 0x1078, 0x7ca6, 0x0078, 0x8bba, 0x0d7e, 0x2c68, + 0x6104, 0x1078, 0x91bc, 0x0d7f, 0x0040, 0x8c52, 0x1078, 0x772d, + 0x0078, 0x8c69, 0x6004, 0x8007, 0x6130, 0xa18c, 0x00ff, 0xa105, + 0x6032, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x6038, + 0x600a, 0x2001, 0xa8a3, 0x2004, 0x6016, 0x1078, 0x5d8a, 0x1078, + 0x62d1, 0x007c, 0x0d7f, 0x0c7f, 0x1078, 0x7c83, 0x1078, 0x2880, + 0x0e7e, 0x127e, 0x2091, 0x8000, 0x1078, 0x28a6, 0x6013, 0x0000, + 0x601f, 0x0007, 0x6017, 0x0398, 0x127f, 0x0e7f, 0x007c, 0x6000, + 0xa08a, 0x0010, 0x10c8, 0x1332, 0x1079, 0x8c87, 0x007c, 0x8c97, + 0x8c97, 0x8c97, 0x8c97, 0x8c97, 0x8c97, 0x8c97, 0x8c97, 0x8c97, + 0x8ad5, 0x8c97, 0x8add, 0x8c99, 0x8add, 0x8ca7, 0x8c97, 0x1078, + 0x1332, 0x6004, 0xa086, 0x008b, 0x0040, 0x8ca7, 0x6007, 0x008b, + 0x6003, 0x000d, 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x007c, 0x1078, + 0x8eb9, 0x1078, 0x8d06, 0x0040, 0x8cdf, 0x1078, 0x2880, 0x0d7e, + 0x1078, 0x8d06, 0x0040, 0x8cc1, 0x6010, 0x2068, 0x6837, 0x0103, + 0x684b, 0x0006, 0x6847, 0x0000, 0x6850, 0xc0ed, 0x6852, 0x1078, + 0x4a73, 0x2c68, 0x1078, 0x76c7, 0x0040, 0x8ccf, 0x6818, 0x601a, + 0x0c7e, 0x2d60, 0x1078, 0x8ec6, 0x0c7f, 0x0078, 0x8cd0, 0x2d60, + 0x0d7f, 0x6013, 0x0000, 0x601f, 0x0001, 0x6007, 0x0001, 0x6003, + 0x0001, 0x1078, 0x5dd7, 0x1078, 0x62d1, 0x0078, 0x8cf1, 0x6030, + 0xa08c, 0xff00, 0x810f, 0xa186, 0x0039, 0x0040, 0x8ceb, 0xa186, + 0x0035, 0x00c0, 0x8cef, 0x1078, 0x2880, 0x0078, 0x8cc1, 0x1078, + 0x8ec6, 0x007c, 0xa284, 0x000f, 0x00c0, 0x8d03, 0xa282, 0xad00, + 0x0048, 0x8d03, 0x2001, 0xa616, 0x2004, 0xa202, 0x00c8, 0x8d03, + 0xa085, 0x0001, 0x007c, 0xa006, 0x0078, 0x8d02, 0x027e, 0x0e7e, + 0x2071, 0xa600, 0x6210, 0x705c, 0xa202, 0x0048, 0x8d18, 0x7060, + 0xa202, 0x00c8, 0x8d18, 0xa085, 0x0001, 0x0e7f, 0x027f, 0x007c, + 0xa006, 0x0078, 0x8d15, 0x0e7e, 0x0c7e, 0x037e, 0x007e, 0x127e, + 0x2091, 0x8000, 0x2061, 0xad00, 0x2071, 0xa600, 0x7348, 0x7064, + 0xa302, 0x00c8, 0x8d45, 0x601c, 0xa206, 0x00c0, 0x8d3d, 0x1078, + 0x902b, 0x0040, 0x8d3d, 0x1078, 0x8f00, 0x00c0, 0x8d39, 0x1078, + 0x7c83, 0x0c7e, 0x1078, 0x772d, 0x0c7f, 0xace0, 0x0010, 0x7058, + 0xac02, 0x00c8, 0x8d45, 0x0078, 0x8d26, 0x127f, 0x007f, 0x037f, + 0x0c7f, 0x0e7f, 0x007c, 0x0e7e, 0x0c7e, 0x017e, 0xa188, 0xa735, + 0x210c, 0x81ff, 0x0040, 0x8d59, 0x2061, 0xa9b3, 0x611a, 0x1078, + 0x2880, 0xa006, 0x0078, 0x8d5e, 0xa085, 0x0001, 0x017f, 0x0c7f, + 0x0e7f, 0x007c, 0x0c7e, 0x057e, 0x127e, 0x2091, 0x8000, 0x0c7e, + 0x1078, 0x76c7, 0x057f, 0x0040, 0x8d7b, 0x6612, 0x651a, 0x601f, + 0x0003, 0x2009, 0x004b, 0x1078, 0x775c, 0xa085, 0x0001, 0x127f, + 0x057f, 0x0c7f, 0x007c, 0xa006, 0x0078, 0x8d77, 0x0c7e, 0x057e, + 0x127e, 0x2091, 0x8000, 0x62a0, 0x0c7e, 0x1078, 0x76c7, 0x057f, + 0x0040, 0x8da9, 0x6013, 0x0000, 0x651a, 0x601f, 0x0003, 0x0c7e, + 0x2560, 0x1078, 0x47e9, 0x0c7f, 0x1078, 0x5f01, 0x077e, 0x2039, + 0x0000, 0x1078, 0x5e0a, 0x2c08, 0x1078, 0x9f8b, 0x077f, 0x2009, + 0x004c, 0x1078, 0x775c, 0xa085, 0x0001, 0x127f, 0x057f, 0x0c7f, + 0x007c, 0xa006, 0x0078, 0x8da5, 0x0f7e, 0x0c7e, 0x047e, 0x0c7e, + 0x1078, 0x76c7, 0x2c78, 0x0c7f, 0x0040, 0x8dc6, 0x7e12, 0x2c00, + 0x781a, 0x781f, 0x0003, 0x2021, 0x0005, 0x1078, 0x8e11, 0x2f60, + 0x2009, 0x004d, 0x1078, 0x775c, 0xa085, 0x0001, 0x047f, 0x0c7f, + 0x0f7f, 0x007c, 0x0f7e, 0x0c7e, 0x047e, 0x0c7e, 0x1078, 0x76c7, + 0x2c78, 0x0c7f, 0x0040, 0x8de4, 0x7e12, 0x2c00, 0x781a, 0x781f, + 0x0003, 0x2021, 0x0005, 0x1078, 0x8e11, 0x2f60, 0x2009, 0x004e, + 0x1078, 0x775c, 0xa085, 0x0001, 0x047f, 0x0c7f, 0x0f7f, 0x007c, + 0x0f7e, 0x0c7e, 0x047e, 0x0c7e, 0x1078, 0x76c7, 0x2c78, 0x0c7f, + 0x0040, 0x8e0d, 0x7e12, 0x2c00, 0x781a, 0x781f, 0x0003, 0x2021, + 0x0004, 0x1078, 0x8e11, 0x2001, 0xa89d, 0x2004, 0xd0fc, 0x0040, + 0x8e06, 0x2f60, 0x1078, 0x772d, 0x0078, 0x8e0b, 0x2f60, 0x2009, + 0x0052, 0x1078, 0x775c, 0xa085, 0x0001, 0x047f, 0x0c7f, 0x0f7f, + 0x007c, 0x097e, 0x077e, 0x127e, 0x2091, 0x8000, 0x1078, 0x4775, + 0x0040, 0x8e1e, 0x2001, 0x8e16, 0x0078, 0x8e24, 0x1078, 0x4739, + 0x0040, 0x8e2d, 0x2001, 0x8e1e, 0x007e, 0xa00e, 0x2400, 0x1078, + 0x4b51, 0x1078, 0x4a73, 0x007f, 0x007a, 0x2418, 0x1078, 0x6161, + 0x62a0, 0x087e, 0x2041, 0x0001, 0x2039, 0x0001, 0x2608, 0x1078, + 0x5f1b, 0x087f, 0x1078, 0x5e0a, 0x2f08, 0x2648, 0x1078, 0x9f8b, + 0x613c, 0x81ff, 0x1040, 0x5fdb, 0x1078, 0x62d1, 0x127f, 0x077f, + 0x097f, 0x007c, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x0c7e, 0x1078, + 0x76c7, 0x017f, 0x0040, 0x8e63, 0x660a, 0x611a, 0x601f, 0x0001, + 0x2d00, 0x6012, 0x2009, 0x001f, 0x1078, 0x775c, 0xa085, 0x0001, + 0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078, 0x8e60, 0x0c7e, 0x127e, + 0x2091, 0x8000, 0x0c7e, 0x1078, 0x76c7, 0x017f, 0x0040, 0x8e7f, + 0x660a, 0x611a, 0x601f, 0x0008, 0x2d00, 0x6012, 0x2009, 0x0021, + 0x1078, 0x775c, 0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006, + 0x0078, 0x8e7c, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x0c7e, 0x1078, + 0x76c7, 0x017f, 0x0040, 0x8e9b, 0x660a, 0x611a, 0x601f, 0x0001, + 0x2d00, 0x6012, 0x2009, 0x003d, 0x1078, 0x775c, 0xa085, 0x0001, + 0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078, 0x8e98, 0x0c7e, 0x127e, + 0x2091, 0x8000, 0x0c7e, 0x1078, 0x76c7, 0x017f, 0x0040, 0x8eb6, + 0x611a, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x0000, 0x1078, + 0x775c, 0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078, + 0x8eb3, 0x027e, 0x0d7e, 0x6218, 0x2268, 0x6a3c, 0x82ff, 0x0040, + 0x8ec3, 0x8211, 0x6a3e, 0x0d7f, 0x027f, 0x007c, 0x007e, 0x6000, + 0xa086, 0x0000, 0x0040, 0x8ed8, 0x6013, 0x0000, 0x601f, 0x0007, + 0x2001, 0xa8a3, 0x2004, 0x6016, 0x1078, 0xa495, 0x603f, 0x0000, + 0x007f, 0x007c, 0x067e, 0x0c7e, 0x0d7e, 0x2031, 0xa653, 0x2634, + 0xd6e4, 0x0040, 0x8ee8, 0x6618, 0x2660, 0x6e48, 0x1078, 0x46e7, + 0x0d7f, 0x0c7f, 0x067f, 0x007c, 0x007e, 0x017e, 0x6004, 0xa08e, + 0x0002, 0x0040, 0x8efd, 0xa08e, 0x0003, 0x0040, 0x8efd, 0xa08e, + 0x0004, 0x0040, 0x8efd, 0xa085, 0x0001, 0x017f, 0x007f, 0x007c, + 0x007e, 0x0d7e, 0x6010, 0xa06d, 0x0040, 0x8f0d, 0x6838, 0xd0fc, + 0x0040, 0x8f0d, 0xa006, 0x0078, 0x8f0f, 0xa085, 0x0001, 0x0d7f, + 0x007f, 0x007c, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x0c7e, 0x1078, + 0x76c7, 0x017f, 0x0040, 0x8f2c, 0x611a, 0x601f, 0x0001, 0x2d00, + 0x6012, 0x1078, 0x2880, 0x2009, 0x0028, 0x1078, 0x775c, 0xa085, + 0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078, 0x8f29, 0xa186, + 0x0015, 0x00c0, 0x8f44, 0x2011, 0xa620, 0x2204, 0xa086, 0x0074, + 0x00c0, 0x8f44, 0x1078, 0x7f91, 0x6003, 0x0001, 0x6007, 0x0029, + 0x1078, 0x5dd7, 0x0078, 0x8f48, 0x1078, 0x7c83, 0x1078, 0x772d, + 0x007c, 0xa186, 0x0016, 0x00c0, 0x8f53, 0x2001, 0x0004, 0x1078, + 0x4502, 0x0078, 0x8f74, 0xa186, 0x0015, 0x00c0, 0x8f78, 0x2011, + 0xa620, 0x2204, 0xa086, 0x0014, 0x00c0, 0x8f78, 0x0d7e, 0x6018, + 0x2068, 0x1078, 0x4649, 0x0d7f, 0x1078, 0x8043, 0x00c0, 0x8f78, + 0x0d7e, 0x6018, 0x2068, 0x6890, 0x0d7f, 0xa005, 0x0040, 0x8f78, + 0x2001, 0x0006, 0x1078, 0x4502, 0x1078, 0x77f8, 0x0078, 0x8f7c, + 0x1078, 0x7c83, 0x1078, 0x772d, 0x007c, 0x6848, 0xa086, 0x0005, + 0x00c0, 0x8f84, 0x1078, 0x8f85, 0x007c, 0x6850, 0xc0ad, 0x6852, + 0x007c, 0x0e7e, 0x2071, 0xab8c, 0x7014, 0xd0e4, 0x0040, 0x8f9a, + 0x6013, 0x0000, 0x6003, 0x0001, 0x6007, 0x0050, 0x1078, 0x5d8a, + 0x1078, 0x62d1, 0x0e7f, 0x007c, 0x0c7e, 0x0f7e, 0x2c78, 0x1078, + 0x4963, 0x0f7f, 0x0040, 0x8fa9, 0x601c, 0xa084, 0x000f, 0x1079, + 0x8fab, 0x0c7f, 0x007c, 0x8ad5, 0x8fb6, 0x8fb9, 0x8fbc, 0xa25d, + 0xa279, 0xa27c, 0x8ad5, 0x8ad5, 0x1078, 0x1332, 0x0005, 0x0005, + 0x007c, 0x0005, 0x0005, 0x007c, 0x1078, 0x8fbf, 0x007c, 0x0f7e, + 0x2c78, 0x1078, 0x4963, 0x0040, 0x8fee, 0x1078, 0x76c7, 0x00c0, + 0x8fcf, 0x2001, 0xa8a4, 0x2004, 0x783e, 0x0078, 0x8fee, 0x7818, + 0x601a, 0x781c, 0xa086, 0x0003, 0x0040, 0x8fdc, 0x7808, 0x6036, + 0x2f00, 0x603a, 0x0078, 0x8fe0, 0x7808, 0x603a, 0x2f00, 0x6036, + 0x602a, 0x601f, 0x0001, 0x6007, 0x0035, 0x6003, 0x0001, 0x7920, + 0x6122, 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x2f60, 0x0f7f, 0x007c, + 0x017e, 0x0f7e, 0x682c, 0x6032, 0xa08e, 0x0001, 0x0040, 0x9001, + 0xa086, 0x0005, 0x0040, 0x9005, 0xa006, 0x602a, 0x602e, 0x0078, + 0x9016, 0x6824, 0xc0f4, 0xc0d5, 0x6826, 0x6810, 0x2078, 0x787c, + 0x6938, 0xa102, 0x7880, 0x6934, 0xa103, 0x00c8, 0x8ffc, 0x6834, + 0x602a, 0x6838, 0xa084, 0xfffc, 0x683a, 0x602e, 0x2d00, 0x6036, + 0x6808, 0x603a, 0x6918, 0x611a, 0x6920, 0x6122, 0x601f, 0x0001, + 0x6007, 0x0039, 0x6003, 0x0001, 0x1078, 0x5d8a, 0x6803, 0x0002, + 0x0f7f, 0x017f, 0x007c, 0x007e, 0x017e, 0x6004, 0xa08e, 0x0034, + 0x0040, 0x9050, 0xa08e, 0x0035, 0x0040, 0x9050, 0xa08e, 0x0036, + 0x0040, 0x9050, 0xa08e, 0x0037, 0x0040, 0x9050, 0xa08e, 0x0038, + 0x0040, 0x9050, 0xa08e, 0x0039, 0x0040, 0x9050, 0xa08e, 0x003a, + 0x0040, 0x9050, 0xa08e, 0x003b, 0x0040, 0x9050, 0xa085, 0x0001, + 0x017f, 0x007f, 0x007c, 0x0f7e, 0x2c78, 0x1078, 0x4963, 0x00c0, + 0x905d, 0xa085, 0x0001, 0x0078, 0x906c, 0x6024, 0xd0f4, 0x00c0, + 0x906b, 0xc0f5, 0x6026, 0x6010, 0x2078, 0x7828, 0x603a, 0x782c, + 0x6036, 0x1078, 0x1757, 0xa006, 0x0f7f, 0x007c, 0x007e, 0x017e, + 0x027e, 0x037e, 0x0e7e, 0x2001, 0xa89e, 0x200c, 0x8000, 0x2014, + 0x2001, 0x0032, 0x1078, 0x5c1c, 0x2001, 0xa8a2, 0x82ff, 0x00c0, + 0x9083, 0x2011, 0x0014, 0x2202, 0x2001, 0xa8a0, 0x200c, 0x8000, + 0x2014, 0x2071, 0xa88d, 0x711a, 0x721e, 0x2001, 0x0064, 0x1078, + 0x5c1c, 0x2001, 0xa8a3, 0x82ff, 0x00c0, 0x9098, 0x2011, 0x0014, + 0x2202, 0x2009, 0xa8a4, 0xa280, 0x000a, 0x200a, 0x1078, 0x498b, + 0x0e7f, 0x037f, 0x027f, 0x017f, 0x007f, 0x007c, 0x007e, 0x0e7e, + 0x2001, 0xa8a2, 0x2003, 0x0028, 0x2001, 0xa8a3, 0x2003, 0x0014, + 0x2071, 0xa88d, 0x701b, 0x0000, 0x701f, 0x07d0, 0x2001, 0xa8a4, + 0x2003, 0x001e, 0x0e7f, 0x007f, 0x007c, 0x0c7e, 0x127e, 0x2091, + 0x8000, 0x0c7e, 0x1078, 0x76c7, 0x017f, 0x0040, 0x90d5, 0x611a, + 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x0033, 0x1078, 0x775c, + 0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078, 0x90d2, + 0x0d7e, 0x0e7e, 0x0f7e, 0x2071, 0xa600, 0xa186, 0x0015, 0x00c0, + 0x9107, 0x7080, 0xa086, 0x0018, 0x00c0, 0x9107, 0x6010, 0x2068, + 0x6a3c, 0xd2e4, 0x00c0, 0x90fb, 0x2c78, 0x1078, 0x6490, 0x0040, + 0x910f, 0x706c, 0x6a50, 0xa206, 0x00c0, 0x9103, 0x7070, 0x6a54, + 0xa206, 0x00c0, 0x9103, 0x6218, 0xa290, 0x0028, 0x2214, 0x2009, + 0x0000, 0x1078, 0x28c8, 0x1078, 0x77f8, 0x0078, 0x910b, 0x1078, + 0x7c83, 0x1078, 0x772d, 0x0f7f, 0x0e7f, 0x0d7f, 0x007c, 0x7050, + 0xa080, 0x29c0, 0x2004, 0x6a54, 0xa206, 0x0040, 0x90fb, 0x0078, + 0x9103, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x0c7e, 0x1078, 0x76c7, + 0x017f, 0x0040, 0x9131, 0x611a, 0x601f, 0x0001, 0x2d00, 0x6012, + 0x2009, 0x0043, 0x1078, 0x775c, 0xa085, 0x0001, 0x127f, 0x0c7f, + 0x007c, 0xa006, 0x0078, 0x912e, 0x0d7e, 0x0e7e, 0x0f7e, 0x2071, + 0xa600, 0xa186, 0x0015, 0x00c0, 0x915a, 0x7080, 0xa086, 0x0004, + 0x00c0, 0x915a, 0x6010, 0xa0e8, 0x000f, 0x2c78, 0x1078, 0x6490, + 0x0040, 0x9162, 0x706c, 0x6a08, 0xa206, 0x00c0, 0x9156, 0x7070, + 0x6a0c, 0xa206, 0x00c0, 0x9156, 0x1078, 0x2880, 0x1078, 0x77f8, + 0x0078, 0x915e, 0x1078, 0x7c83, 0x1078, 0x772d, 0x0f7f, 0x0e7f, + 0x0d7f, 0x007c, 0x7050, 0xa080, 0x29c0, 0x2004, 0x6a0c, 0xa206, + 0x0040, 0x9154, 0x0078, 0x9156, 0x017e, 0x027e, 0x684c, 0xd0ac, + 0x0040, 0x9184, 0x6914, 0x6a10, 0x2100, 0xa205, 0x0040, 0x9184, + 0x6860, 0xa106, 0x00c0, 0x9180, 0x685c, 0xa206, 0x0040, 0x9184, + 0x6962, 0x6a5e, 0xa085, 0x0001, 0x027f, 0x017f, 0x007c, 0x0e7e, + 0x127e, 0x2071, 0xa600, 0x2091, 0x8000, 0x7548, 0xa582, 0x0001, + 0x0048, 0x91b9, 0x704c, 0x2060, 0x6000, 0xa086, 0x0000, 0x0040, + 0x91a5, 0xace0, 0x0010, 0x7058, 0xac02, 0x00c8, 0x91a1, 0x0078, + 0x9194, 0x2061, 0xad00, 0x0078, 0x9194, 0x6003, 0x0008, 0x8529, + 0x754a, 0xaca8, 0x0010, 0x7058, 0xa502, 0x00c8, 0x91b5, 0x754e, + 0xa085, 0x0001, 0x127f, 0x0e7f, 0x007c, 0x704f, 0xad00, 0x0078, + 0x91b0, 0xa006, 0x0078, 0x91b2, 0x0c7e, 0x027e, 0x017e, 0xa186, + 0x0035, 0x0040, 0x91c6, 0x6a34, 0x0078, 0x91c7, 0x6a28, 0x1078, + 0x8cf2, 0x0040, 0x91f0, 0x2260, 0x611c, 0xa186, 0x0003, 0x0040, + 0x91d5, 0xa186, 0x0006, 0x00c0, 0x91ec, 0x6834, 0xa206, 0x0040, + 0x91e4, 0x6838, 0xa206, 0x00c0, 0x91ec, 0x6108, 0x6834, 0xa106, + 0x00c0, 0x91ec, 0x0078, 0x91e9, 0x6008, 0x6938, 0xa106, 0x00c0, + 0x91ec, 0x6018, 0x6918, 0xa106, 0x017f, 0x027f, 0x0c7f, 0x007c, + 0xa085, 0x0001, 0x0078, 0x91ec, 0x6944, 0xd1cc, 0x0040, 0x920d, + 0xa18c, 0x00ff, 0xa18e, 0x0002, 0x00c0, 0x920d, 0xad88, 0x001e, + 0x210c, 0xa18c, 0x0f00, 0x810f, 0xa18e, 0x0001, 0x00c0, 0x920d, + 0x6810, 0x6914, 0xa115, 0x10c0, 0x84d5, 0x007c, 0x067e, 0x6000, + 0xa0b2, 0x0010, 0x10c8, 0x1332, 0x1079, 0x9218, 0x067f, 0x007c, + 0x9228, 0x96df, 0x97fb, 0x9228, 0x9228, 0x9228, 0x9228, 0x9228, + 0x9262, 0x988e, 0x9228, 0x9228, 0x9228, 0x9228, 0x9228, 0x9228, + 0x1078, 0x1332, 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8, 0x1332, + 0x1079, 0x9234, 0x067f, 0x007c, 0x9244, 0x9d53, 0x9244, 0x9244, + 0x9244, 0x9244, 0x9244, 0x9244, 0x9d11, 0x9da1, 0x9244, 0xa3b0, + 0xa3e4, 0xa3b0, 0xa3e4, 0x9244, 0x1078, 0x1332, 0x067e, 0x6000, + 0xa0b2, 0x0010, 0x10c8, 0x1332, 0x1079, 0x9250, 0x067f, 0x007c, + 0x9260, 0x99eb, 0x9ac7, 0x9af5, 0x9b70, 0x9260, 0x9c76, 0x9c1e, + 0x989a, 0x9ce5, 0x9cfb, 0x9260, 0x9260, 0x9260, 0x9260, 0x9260, + 0x1078, 0x1332, 0xa1b2, 0x0044, 0x10c8, 0x1332, 0x2100, 0x0079, + 0x9269, 0x92a9, 0x9498, 0x92a9, 0x92a9, 0x92a9, 0x94a0, 0x92a9, + 0x92a9, 0x92a9, 0x92a9, 0x92a9, 0x92a9, 0x92a9, 0x92a9, 0x92a9, + 0x92a9, 0x92a9, 0x92a9, 0x92a9, 0x92a9, 0x92a9, 0x92a9, 0x92a9, + 0x92ab, 0x9311, 0x9320, 0x9377, 0x9396, 0x9415, 0x9485, 0x92a9, + 0x92a9, 0x94a4, 0x92a9, 0x92a9, 0x94b7, 0x94c2, 0x92a9, 0x92a9, + 0x92a9, 0x92a9, 0x92a9, 0x94fa, 0x92a9, 0x92a9, 0x9509, 0x92a9, + 0x92a9, 0x92a9, 0x92a9, 0x92a9, 0x92a9, 0x9522, 0x92a9, 0x92a9, + 0x92a9, 0x95af, 0x92a9, 0x92a9, 0x92a9, 0x92a9, 0x92a9, 0x92a9, + 0x9629, 0x1078, 0x1332, 0x1078, 0x4967, 0x00c0, 0x92bb, 0x2001, + 0xa633, 0x2004, 0xd0cc, 0x00c0, 0x92bb, 0xa084, 0x0009, 0xa086, + 0x0008, 0x00c0, 0x92c3, 0x6007, 0x0009, 0x602b, 0x0009, 0x6013, + 0x0000, 0x0078, 0x9493, 0x1078, 0x4957, 0x0e7e, 0x0c7e, 0x037e, + 0x027e, 0x017e, 0x6218, 0x2270, 0x72a0, 0x027e, 0x2019, 0x0029, + 0x1078, 0x5f01, 0x077e, 0x2039, 0x0000, 0x1078, 0x5e0a, 0x2c08, + 0x1078, 0x9f8b, 0x077f, 0x017f, 0x2e60, 0x1078, 0x47e9, 0x017f, + 0x027f, 0x037f, 0x0c7f, 0x0e7f, 0x6618, 0x0c7e, 0x2660, 0x1078, + 0x45d6, 0x0c7f, 0xa6b0, 0x0001, 0x2634, 0xa684, 0x00ff, 0xa082, + 0x0006, 0x0048, 0x9303, 0x1078, 0x9ebf, 0x00c0, 0x9371, 0x1078, + 0x9e50, 0x00c0, 0x92ff, 0x6007, 0x0008, 0x0078, 0x9493, 0x6007, + 0x0009, 0x0078, 0x9493, 0x1078, 0xa09f, 0x0040, 0x930d, 0x1078, + 0x9ebf, 0x0040, 0x92f7, 0x0078, 0x9371, 0x6013, 0x1900, 0x0078, + 0x92ff, 0x1078, 0x29bb, 0x00c0, 0x9664, 0x6106, 0x1078, 0x9e05, + 0x6007, 0x0006, 0x0078, 0x9493, 0x6007, 0x0007, 0x0078, 0x9493, + 0x1078, 0xa41c, 0x00c0, 0x9664, 0x1078, 0x29bb, 0x00c0, 0x9664, + 0x0d7e, 0x6618, 0x2668, 0x6e04, 0xa684, 0x00ff, 0xa082, 0x0006, + 0x00c8, 0x9336, 0x2001, 0x0001, 0x1078, 0x44ee, 0xa6b4, 0xff00, + 0x8637, 0xa686, 0x0006, 0x0040, 0x9353, 0xa686, 0x0004, 0x0040, + 0x9353, 0x6e04, 0xa6b4, 0x00ff, 0xa686, 0x0006, 0x0040, 0x9353, + 0xa686, 0x0004, 0x0040, 0x9353, 0xa686, 0x0005, 0x0040, 0x9353, + 0x0d7f, 0x0078, 0x9371, 0x1078, 0x9f25, 0x00c0, 0x936c, 0xa686, + 0x0006, 0x00c0, 0x9365, 0x027e, 0x6218, 0xa290, 0x0028, 0x2214, + 0x2009, 0x0000, 0x1078, 0x28c8, 0x027f, 0x1078, 0x4649, 0x6007, + 0x000a, 0x0d7f, 0x0078, 0x9493, 0x6007, 0x000b, 0x0d7f, 0x0078, + 0x9493, 0x1078, 0x2880, 0x6007, 0x0001, 0x0078, 0x9493, 0x1078, + 0xa41c, 0x00c0, 0x9664, 0x1078, 0x29bb, 0x00c0, 0x9664, 0x6618, + 0x0d7e, 0x2668, 0x6e04, 0x0d7f, 0xa686, 0x0707, 0x0040, 0x9371, + 0x027e, 0x6218, 0xa290, 0x0028, 0x2214, 0x2009, 0x0000, 0x1078, + 0x28c8, 0x027f, 0x6007, 0x000c, 0x0078, 0x9493, 0x1078, 0x4967, + 0x00c0, 0x93a3, 0x2001, 0xa633, 0x2004, 0xa084, 0x0009, 0xa086, + 0x0008, 0x00c0, 0x93ab, 0x6007, 0x0009, 0x602b, 0x0009, 0x6013, + 0x0000, 0x0078, 0x9493, 0x1078, 0x4957, 0x6618, 0xa6b0, 0x0001, + 0x2634, 0xa684, 0x00ff, 0xa082, 0x0006, 0x0048, 0x93ef, 0xa6b4, + 0xff00, 0x8637, 0xa686, 0x0004, 0x0040, 0x93c2, 0xa686, 0x0006, + 0x00c0, 0x9371, 0x1078, 0x9f34, 0x00c0, 0x93ca, 0x6007, 0x000e, + 0x0078, 0x9493, 0x047e, 0x6418, 0xa4a0, 0x0028, 0x2424, 0xa4a4, + 0x00ff, 0x8427, 0x047e, 0x1078, 0x2880, 0x047f, 0x017e, 0xa006, + 0x2009, 0xa653, 0x210c, 0xd1a4, 0x0040, 0x93e9, 0x2009, 0x0029, + 0x1078, 0xa21d, 0x6018, 0x0d7e, 0x2068, 0x6800, 0xc0e5, 0x6802, + 0x0d7f, 0x017f, 0x047f, 0x6007, 0x0001, 0x0078, 0x9493, 0x2001, + 0x0001, 0x1078, 0x44ee, 0x157e, 0x017e, 0x027e, 0x037e, 0x20a9, + 0x0004, 0x2019, 0xa605, 0x2011, 0xab90, 0x1078, 0x80de, 0x037f, + 0x027f, 0x017f, 0x157f, 0xa005, 0x0040, 0x940f, 0xa6b4, 0xff00, + 0x8637, 0xa686, 0x0006, 0x0040, 0x93c2, 0x0078, 0x9371, 0x6013, + 0x1900, 0x6007, 0x0009, 0x0078, 0x9493, 0x1078, 0x4967, 0x00c0, + 0x9422, 0x2001, 0xa633, 0x2004, 0xa084, 0x0009, 0xa086, 0x0008, + 0x00c0, 0x942a, 0x6007, 0x0009, 0x602b, 0x0009, 0x6013, 0x0000, + 0x0078, 0x9493, 0x1078, 0x4957, 0x6618, 0xa6b0, 0x0001, 0x2634, + 0xa684, 0x00ff, 0xa082, 0x0006, 0x0048, 0x9472, 0xa6b4, 0xff00, + 0x8637, 0xa686, 0x0004, 0x0040, 0x9441, 0xa686, 0x0006, 0x00c0, + 0x9371, 0x1078, 0x9f5f, 0x00c0, 0x944d, 0x1078, 0x9e50, 0x00c0, + 0x944d, 0x6007, 0x0010, 0x0078, 0x9493, 0x047e, 0x6418, 0xa4a0, + 0x0028, 0x2424, 0xa4a4, 0x00ff, 0x8427, 0x047e, 0x1078, 0x2880, + 0x047f, 0x017e, 0xa006, 0x2009, 0xa653, 0x210c, 0xd1a4, 0x0040, + 0x946c, 0x2009, 0x0029, 0x1078, 0xa21d, 0x6018, 0x0d7e, 0x2068, + 0x6800, 0xc0e5, 0x6802, 0x0d7f, 0x017f, 0x047f, 0x6007, 0x0001, + 0x0078, 0x9493, 0x1078, 0xa09f, 0x0040, 0x947f, 0xa6b4, 0xff00, + 0x8637, 0xa686, 0x0006, 0x0040, 0x9441, 0x0078, 0x9371, 0x6013, + 0x1900, 0x6007, 0x0009, 0x0078, 0x9493, 0x1078, 0x29bb, 0x00c0, + 0x9664, 0x1078, 0xa41c, 0x00c0, 0x9664, 0x1078, 0x9667, 0x00c0, + 0x9371, 0x6007, 0x0012, 0x6003, 0x0001, 0x1078, 0x5dd7, 0x007c, + 0x6007, 0x0001, 0x6003, 0x0001, 0x1078, 0x5dd7, 0x0078, 0x9497, + 0x6007, 0x0005, 0x0078, 0x949a, 0x1078, 0xa41c, 0x00c0, 0x9664, + 0x1078, 0x29bb, 0x00c0, 0x9664, 0x1078, 0x9667, 0x00c0, 0x9371, + 0x6007, 0x0020, 0x6003, 0x0001, 0x1078, 0x5dd7, 0x007c, 0x1078, + 0x29bb, 0x00c0, 0x9664, 0x6007, 0x0023, 0x6003, 0x0001, 0x1078, + 0x5dd7, 0x007c, 0x1078, 0xa41c, 0x00c0, 0x9664, 0x1078, 0x29bb, + 0x00c0, 0x9664, 0x1078, 0x9667, 0x00c0, 0x9371, 0x017e, 0x027e, + 0x2011, 0xab90, 0x2214, 0x2c08, 0xa006, 0x1078, 0xa1e6, 0x00c0, + 0x94e9, 0x2160, 0x6007, 0x0026, 0x6013, 0x1700, 0x2011, 0xab89, + 0x2214, 0xa296, 0xffff, 0x00c0, 0x94f3, 0x6007, 0x0025, 0x0078, + 0x94f3, 0x6004, 0xa086, 0x0024, 0x00c0, 0x94f0, 0x1078, 0x772d, + 0x2160, 0x6007, 0x0025, 0x6003, 0x0001, 0x1078, 0x5dd7, 0x027f, + 0x017f, 0x007c, 0x1078, 0x29bb, 0x00c0, 0x9664, 0x6106, 0x1078, + 0x9687, 0x6007, 0x002b, 0x0078, 0x9493, 0x6007, 0x002c, 0x0078, + 0x9493, 0x1078, 0xa41c, 0x00c0, 0x9664, 0x1078, 0x29bb, 0x00c0, + 0x9664, 0x1078, 0x9667, 0x00c0, 0x9371, 0x6106, 0x1078, 0x968c, + 0x00c0, 0x951e, 0x6007, 0x002e, 0x0078, 0x9493, 0x6007, 0x002f, + 0x0078, 0x9493, 0x1078, 0x29bb, 0x00c0, 0x9664, 0x0e7e, 0x0d7e, + 0x0c7e, 0x6018, 0xa080, 0x0001, 0x200c, 0xa184, 0x00ff, 0xa086, + 0x0006, 0x0040, 0x953f, 0xa184, 0xff00, 0x8007, 0xa086, 0x0006, + 0x0040, 0x953f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0078, 0x9498, 0x2001, + 0xa672, 0x2004, 0xd0e4, 0x0040, 0x95ab, 0x2071, 0xab8c, 0x7010, + 0x6036, 0x7014, 0x603a, 0x7108, 0x720c, 0x2001, 0xa653, 0x2004, + 0xd0a4, 0x0040, 0x955d, 0x6018, 0x2068, 0x6810, 0xa106, 0x00c0, + 0x955d, 0x6814, 0xa206, 0x0040, 0x9581, 0x2001, 0xa653, 0x2004, + 0xd0ac, 0x00c0, 0x959f, 0x2069, 0xa600, 0x6870, 0xa206, 0x00c0, + 0x959f, 0x686c, 0xa106, 0x00c0, 0x959f, 0x7210, 0x1078, 0x8cf2, + 0x0040, 0x95a5, 0x1078, 0xa28e, 0x0040, 0x95a5, 0x622a, 0x6007, + 0x0036, 0x6003, 0x0001, 0x1078, 0x5d8a, 0x0c7f, 0x0d7f, 0x0e7f, + 0x007c, 0x7214, 0xa286, 0xffff, 0x0040, 0x9593, 0x1078, 0x8cf2, + 0x0040, 0x95a5, 0xa280, 0x0002, 0x2004, 0x7110, 0xa106, 0x00c0, + 0x95a5, 0x0078, 0x956e, 0x7210, 0x2c08, 0xa085, 0x0001, 0x1078, + 0xa1e6, 0x2c10, 0x2160, 0x0040, 0x95a5, 0x0078, 0x956e, 0x6007, + 0x0037, 0x6013, 0x1500, 0x0078, 0x9579, 0x6007, 0x0037, 0x6013, + 0x1700, 0x0078, 0x9579, 0x6007, 0x0012, 0x0078, 0x9579, 0x1078, + 0x29bb, 0x00c0, 0x9664, 0x6018, 0xa080, 0x0001, 0x2004, 0xa084, + 0xff00, 0x8007, 0xa086, 0x0006, 0x00c0, 0x9498, 0x0e7e, 0x0d7e, + 0x0c7e, 0x2001, 0xa672, 0x2004, 0xd0e4, 0x0040, 0x9621, 0x2069, + 0xa600, 0x2071, 0xab8c, 0x7008, 0x6036, 0x720c, 0x623a, 0xa286, + 0xffff, 0x00c0, 0x95de, 0x7208, 0x0c7e, 0x2c08, 0xa085, 0x0001, + 0x1078, 0xa1e6, 0x2c10, 0x0c7f, 0x0040, 0x9615, 0x1078, 0x8cf2, + 0x0040, 0x9615, 0x0c7e, 0x027e, 0x2260, 0x1078, 0x89f3, 0x027f, + 0x0c7f, 0x7118, 0xa18c, 0xff00, 0x810f, 0xa186, 0x0001, 0x0040, + 0x95ff, 0xa186, 0x0005, 0x0040, 0x95f9, 0xa186, 0x0007, 0x00c0, + 0x9609, 0xa280, 0x0004, 0x2004, 0xa005, 0x0040, 0x9609, 0x057e, + 0x7510, 0x7614, 0x1078, 0xa2a3, 0x057f, 0x0c7f, 0x0d7f, 0x0e7f, + 0x007c, 0x6007, 0x003b, 0x602b, 0x0009, 0x6013, 0x2a00, 0x6003, + 0x0001, 0x1078, 0x5d8a, 0x0078, 0x9605, 0x6007, 0x003b, 0x602b, + 0x0009, 0x6013, 0x1700, 0x6003, 0x0001, 0x1078, 0x5d8a, 0x0078, + 0x9605, 0x6007, 0x003b, 0x602b, 0x000b, 0x6013, 0x0000, 0x0078, + 0x9579, 0x0e7e, 0x027e, 0x1078, 0x4967, 0x0040, 0x965e, 0x1078, + 0x4957, 0x1078, 0xa4a9, 0x00c0, 0x965c, 0x2071, 0xa600, 0x70cc, + 0xc085, 0x70ce, 0x0f7e, 0x2079, 0x0100, 0x7298, 0xa284, 0x00ff, + 0x706e, 0x78e6, 0xa284, 0xff00, 0x7270, 0xa205, 0x7072, 0x78ea, + 0x0f7f, 0x70d7, 0x0000, 0x2001, 0xa653, 0x2004, 0xd0a4, 0x0040, + 0x9655, 0x2011, 0xa8ca, 0x2013, 0x07d0, 0xd0ac, 0x00c0, 0x965e, + 0x1078, 0x2677, 0x0078, 0x965e, 0x1078, 0xa4d9, 0x027f, 0x0e7f, + 0x1078, 0x772d, 0x0078, 0x9497, 0x1078, 0x772d, 0x007c, 0x0d7e, + 0x067e, 0x6618, 0x2668, 0x6e04, 0xa6b4, 0xff00, 0x8637, 0xa686, + 0x0006, 0x0040, 0x9684, 0xa686, 0x0004, 0x0040, 0x9684, 0x6e04, + 0xa6b4, 0x00ff, 0xa686, 0x0006, 0x0040, 0x9684, 0xa686, 0x0004, + 0x0040, 0x9684, 0xa085, 0x0001, 0x067f, 0x0d7f, 0x007c, 0x0d7e, + 0x1078, 0x96bb, 0x0d7f, 0x007c, 0x0d7e, 0x1078, 0x96ca, 0x00c0, + 0x96b4, 0x680c, 0xa08c, 0xff00, 0x6820, 0xa084, 0x00ff, 0xa115, + 0x6212, 0x6824, 0x602a, 0xd1e4, 0x0040, 0x96a2, 0x2009, 0x0001, + 0x0078, 0x96b0, 0xd1ec, 0x0040, 0x96b4, 0x6920, 0xa18c, 0x00ff, + 0x6824, 0x1078, 0x254d, 0x00c0, 0x96b4, 0x2110, 0x2009, 0x0000, + 0x1078, 0x28c8, 0x0078, 0x96b8, 0xa085, 0x0001, 0x0078, 0x96b9, + 0xa006, 0x0d7f, 0x007c, 0x2069, 0xab8d, 0x6800, 0xa082, 0x0010, + 0x00c8, 0x96c8, 0x6013, 0x0000, 0xa085, 0x0001, 0x0078, 0x96c9, + 0xa006, 0x007c, 0x6013, 0x0000, 0x2069, 0xab8c, 0x6808, 0xa084, + 0xff00, 0xa086, 0x0800, 0x00c0, 0x96de, 0x6800, 0xa084, 0x00ff, + 0xa08e, 0x0014, 0x0040, 0x96de, 0xa08e, 0x0010, 0x007c, 0x6004, + 0xa0b2, 0x0044, 0x10c8, 0x1332, 0xa1b6, 0x0013, 0x00c0, 0x96eb, + 0x2008, 0x0079, 0x96fe, 0xa1b6, 0x0027, 0x0040, 0x96f3, 0xa1b6, + 0x0014, 0x10c0, 0x1332, 0x2001, 0x0007, 0x1078, 0x4535, 0x1078, + 0x61cd, 0x1078, 0x8ec6, 0x1078, 0x62d1, 0x007c, 0x973e, 0x9740, + 0x973e, 0x973e, 0x973e, 0x9740, 0x974c, 0x97d6, 0x9799, 0x97d6, + 0x97ad, 0x97d6, 0x974c, 0x97d6, 0x97ce, 0x97d6, 0x97ce, 0x97d6, + 0x97d6, 0x973e, 0x973e, 0x973e, 0x973e, 0x973e, 0x973e, 0x973e, + 0x973e, 0x973e, 0x973e, 0x973e, 0x9740, 0x973e, 0x97d6, 0x973e, + 0x973e, 0x97d6, 0x973e, 0x97d6, 0x97d6, 0x973e, 0x973e, 0x973e, + 0x973e, 0x97d6, 0x97d6, 0x973e, 0x97d6, 0x97d6, 0x973e, 0x973e, + 0x973e, 0x973e, 0x973e, 0x9740, 0x97d6, 0x97d6, 0x973e, 0x973e, + 0x97d6, 0x97d6, 0x973e, 0x973e, 0x973e, 0x973e, 0x1078, 0x1332, + 0x1078, 0x61cd, 0x2001, 0xa8a2, 0x2004, 0x6016, 0x6003, 0x0002, + 0x1078, 0x62d1, 0x0078, 0x97dc, 0x0f7e, 0x2079, 0xa652, 0x7804, + 0x0f7f, 0xd0ac, 0x00c0, 0x97d6, 0x2001, 0x0000, 0x1078, 0x44ee, + 0x6018, 0xa080, 0x0004, 0x2004, 0xa086, 0x00ff, 0x0040, 0x97d6, + 0x0c7e, 0x6018, 0x2060, 0x6000, 0xd0f4, 0x00c0, 0x9770, 0x6010, + 0xa005, 0x0040, 0x9770, 0x0c7f, 0x1078, 0x3699, 0x0078, 0x97d6, + 0x0c7f, 0x2001, 0xa600, 0x2004, 0xa086, 0x0002, 0x00c0, 0x977f, + 0x0f7e, 0x2079, 0xa600, 0x7890, 0x8000, 0x7892, 0x0f7f, 0x2001, + 0x0002, 0x1078, 0x4502, 0x1078, 0x61cd, 0x601f, 0x0001, 0x6003, + 0x0001, 0x6007, 0x0002, 0x1078, 0x5dd7, 0x1078, 0x62d1, 0x0c7e, + 0x6118, 0x2160, 0x2009, 0x0001, 0x1078, 0x5a52, 0x0c7f, 0x0078, + 0x97dc, 0x6618, 0x0d7e, 0x2668, 0x6e04, 0x0d7f, 0xa6b4, 0xff00, + 0x8637, 0xa686, 0x0006, 0x0040, 0x97d6, 0xa686, 0x0004, 0x0040, + 0x97d6, 0x2001, 0x0004, 0x0078, 0x97d4, 0x2001, 0xa600, 0x2004, + 0xa086, 0x0003, 0x00c0, 0x97b6, 0x1078, 0x3699, 0x2001, 0x0006, + 0x1078, 0x97dd, 0x6618, 0x0d7e, 0x2668, 0x6e04, 0x0d7f, 0xa6b4, + 0xff00, 0x8637, 0xa686, 0x0006, 0x0040, 0x97d6, 0x2001, 0x0006, + 0x0078, 0x97d4, 0x2001, 0x0004, 0x0078, 0x97d4, 0x2001, 0x0006, + 0x1078, 0x97dd, 0x0078, 0x97d6, 0x1078, 0x4535, 0x1078, 0x61cd, + 0x1078, 0x772d, 0x1078, 0x62d1, 0x007c, 0x017e, 0x0d7e, 0x6118, + 0x2168, 0x6900, 0xd184, 0x0040, 0x97f8, 0x6104, 0xa18e, 0x000a, + 0x00c0, 0x97f0, 0x699c, 0xd1a4, 0x00c0, 0x97f0, 0x2001, 0x0007, + 0x1078, 0x4502, 0x2001, 0x0000, 0x1078, 0x44ee, 0x1078, 0x28a6, + 0x0d7f, 0x017f, 0x007c, 0x0d7e, 0x6618, 0x2668, 0x6804, 0xa084, + 0xff00, 0x8007, 0x0d7f, 0xa0b2, 0x000c, 0x10c8, 0x1332, 0xa1b6, + 0x0015, 0x00c0, 0x980f, 0x1079, 0x9816, 0x0078, 0x9815, 0xa1b6, + 0x0016, 0x10c0, 0x1332, 0x1079, 0x9822, 0x007c, 0x7d4e, 0x7d4e, + 0x7d4e, 0x7d4e, 0x7d4e, 0x7d4e, 0x9877, 0x982e, 0x7d4e, 0x7d4e, + 0x7d4e, 0x7d4e, 0x7d4e, 0x7d4e, 0x7d4e, 0x7d4e, 0x7d4e, 0x7d4e, + 0x9877, 0x987f, 0x7d4e, 0x7d4e, 0x7d4e, 0x7d4e, 0x0f7e, 0x2079, + 0xa652, 0x7804, 0xd0ac, 0x00c0, 0x9855, 0x6018, 0xa07d, 0x0040, + 0x9855, 0x7800, 0xd0f4, 0x00c0, 0x9841, 0x7810, 0xa005, 0x00c0, + 0x9855, 0x2001, 0x0000, 0x1078, 0x44ee, 0x2001, 0x0002, 0x1078, + 0x4502, 0x601f, 0x0001, 0x6003, 0x0001, 0x6007, 0x0002, 0x1078, + 0x5dd7, 0x1078, 0x62d1, 0x0078, 0x9875, 0x2011, 0xab83, 0x2204, + 0x8211, 0x220c, 0x1078, 0x254d, 0x00c0, 0x9875, 0x0c7e, 0x1078, + 0x45c4, 0x0040, 0x9868, 0x0c7f, 0x1078, 0x772d, 0x0078, 0x9875, + 0x6010, 0x007e, 0x6014, 0x007e, 0x1078, 0x42f8, 0x007f, 0x6016, + 0x007f, 0x6012, 0x0c7f, 0x1078, 0x772d, 0x0f7f, 0x007c, 0x6604, + 0xa6b6, 0x001e, 0x00c0, 0x987e, 0x1078, 0x772d, 0x007c, 0x1078, + 0x7f8e, 0x00c0, 0x988b, 0x6003, 0x0001, 0x6007, 0x0001, 0x1078, + 0x5dd7, 0x0078, 0x988d, 0x1078, 0x772d, 0x007c, 0x6004, 0xa08a, + 0x0044, 0x10c8, 0x1332, 0x1078, 0x61cd, 0x1078, 0x8ec6, 0x1078, + 0x62d1, 0x007c, 0xa182, 0x0040, 0x0079, 0x989e, 0x98b1, 0x98b1, + 0x98b1, 0x98b1, 0x98b3, 0x98b1, 0x98b1, 0x98b1, 0x98b1, 0x98b1, + 0x98b1, 0x98b1, 0x98b1, 0x98b1, 0x98b1, 0x98b1, 0x98b1, 0x98b1, + 0x98b1, 0x1078, 0x1332, 0x0d7e, 0x0e7e, 0x0f7e, 0x157e, 0x047e, + 0x027e, 0x6218, 0xa280, 0x002b, 0x2004, 0xa005, 0x0040, 0x98c4, + 0x2021, 0x0000, 0x1078, 0xa472, 0x6106, 0x2071, 0xab80, 0x7444, + 0xa4a4, 0xff00, 0x0040, 0x991b, 0xa486, 0x2000, 0x00c0, 0x98d6, + 0x2009, 0x0001, 0x2011, 0x0200, 0x1078, 0x5bf1, 0x1078, 0x138b, + 0x1040, 0x1332, 0x6003, 0x0007, 0x2d00, 0x6837, 0x010d, 0x6803, + 0x0000, 0x683b, 0x0000, 0x6c5a, 0x2c00, 0x685e, 0x6008, 0x68b2, + 0x6018, 0x2078, 0x78a0, 0x8007, 0x7130, 0x694a, 0x017e, 0xa084, + 0xff00, 0x6846, 0x684f, 0x0000, 0x6857, 0x0036, 0x1078, 0x4a73, + 0x017f, 0xa486, 0x2000, 0x00c0, 0x9903, 0x2019, 0x0017, 0x1078, + 0xa195, 0x0078, 0x997d, 0xa486, 0x0400, 0x00c0, 0x990d, 0x2019, + 0x0002, 0x1078, 0xa146, 0x0078, 0x997d, 0xa486, 0x0200, 0x00c0, + 0x9913, 0x1078, 0xa12b, 0xa486, 0x1000, 0x00c0, 0x9919, 0x1078, + 0xa17a, 0x0078, 0x997d, 0x2069, 0xa933, 0x6a00, 0xd284, 0x0040, + 0x99e7, 0xa284, 0x0300, 0x00c0, 0x99df, 0x6804, 0xa005, 0x0040, + 0x99c5, 0x2d78, 0x6003, 0x0007, 0x1078, 0x1370, 0x0040, 0x9984, + 0x7800, 0xd08c, 0x00c0, 0x9937, 0x7804, 0x8001, 0x7806, 0x6013, + 0x0000, 0x6803, 0x0000, 0x6837, 0x0116, 0x683b, 0x0000, 0x6008, + 0x68b2, 0x2c00, 0x684a, 0x6018, 0x2078, 0x78a0, 0x8007, 0x7130, + 0x6986, 0x6846, 0x7928, 0x698a, 0x792c, 0x698e, 0x7930, 0x6992, + 0x7934, 0x6996, 0x6853, 0x003d, 0x7244, 0xa294, 0x0003, 0xa286, + 0x0002, 0x00c0, 0x995f, 0x684f, 0x0040, 0x0078, 0x9969, 0xa286, + 0x0001, 0x00c0, 0x9967, 0x684f, 0x0080, 0x0078, 0x9969, 0x684f, + 0x0000, 0x20a9, 0x000a, 0x2001, 0xab90, 0xad90, 0x0015, 0x200c, + 0x810f, 0x2112, 0x8000, 0x8210, 0x00f0, 0x996f, 0x200c, 0x6982, + 0x8000, 0x200c, 0x697e, 0x1078, 0x4a73, 0x027f, 0x047f, 0x157f, + 0x0f7f, 0x0e7f, 0x0d7f, 0x007c, 0x2001, 0xa60e, 0x2004, 0xd084, + 0x0040, 0x998e, 0x1078, 0x138b, 0x00c0, 0x9930, 0x6013, 0x0100, + 0x6003, 0x0001, 0x6007, 0x0041, 0x1078, 0x5d8a, 0x1078, 0x62d1, + 0x0078, 0x997d, 0x2069, 0xab92, 0x2d04, 0xa084, 0xff00, 0xa086, + 0x1200, 0x00c0, 0x99b9, 0x2069, 0xab80, 0x686c, 0xa084, 0x00ff, + 0x017e, 0x6110, 0xa18c, 0x0700, 0xa10d, 0x6112, 0x017f, 0x6003, + 0x0001, 0x6007, 0x0043, 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x0078, + 0x997d, 0x6013, 0x0200, 0x6003, 0x0001, 0x6007, 0x0041, 0x1078, + 0x5d8a, 0x1078, 0x62d1, 0x0078, 0x997d, 0x2001, 0xa60d, 0x2004, + 0xd0ec, 0x0040, 0x99cf, 0x2011, 0x8049, 0x1078, 0x361b, 0x6013, + 0x0300, 0x0078, 0x99d5, 0x6013, 0x0100, 0x6003, 0x0001, 0x6007, + 0x0041, 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x0078, 0x997d, 0x6013, + 0x0500, 0x0078, 0x99d5, 0x6013, 0x0600, 0x0078, 0x999a, 0x6013, + 0x0200, 0x0078, 0x999a, 0xa186, 0x0013, 0x00c0, 0x99fd, 0x6004, + 0xa08a, 0x0040, 0x1048, 0x1332, 0xa08a, 0x0053, 0x10c8, 0x1332, + 0xa082, 0x0040, 0x2008, 0x0079, 0x9a82, 0xa186, 0x0051, 0x0040, + 0x9a0a, 0xa186, 0x0047, 0x00c0, 0x9a23, 0x6004, 0xa086, 0x0041, + 0x0040, 0x9a31, 0x2001, 0x0109, 0x2004, 0xd084, 0x0040, 0x9a31, + 0x127e, 0x2091, 0x2200, 0x007e, 0x017e, 0x027e, 0x1078, 0x5c56, + 0x027f, 0x017f, 0x007f, 0x127f, 0x6000, 0xa086, 0x0002, 0x00c0, + 0x9a31, 0x0078, 0x9ac7, 0xa186, 0x0027, 0x0040, 0x9a2b, 0xa186, + 0x0014, 0x10c0, 0x1332, 0x6004, 0xa082, 0x0040, 0x2008, 0x0079, + 0x9a34, 0x1078, 0x7773, 0x007c, 0x9a47, 0x9a49, 0x9a49, 0x9a71, + 0x9a47, 0x9a47, 0x9a47, 0x9a47, 0x9a47, 0x9a47, 0x9a47, 0x9a47, + 0x9a47, 0x9a47, 0x9a47, 0x9a47, 0x9a47, 0x9a47, 0x9a47, 0x1078, + 0x1332, 0x1078, 0x61cd, 0x1078, 0x62d1, 0x037e, 0x0d7e, 0x6010, + 0xa06d, 0x0040, 0x9a6e, 0xad84, 0xf000, 0x0040, 0x9a6e, 0x6003, + 0x0002, 0x6018, 0x2004, 0xd0bc, 0x00c0, 0x9a6e, 0x2019, 0x0004, + 0x1078, 0xa1ca, 0x6013, 0x0000, 0x6014, 0xa005, 0x00c0, 0x9a6c, + 0x2001, 0xa8a3, 0x2004, 0x6016, 0x6003, 0x0007, 0x0d7f, 0x037f, + 0x007c, 0x0d7e, 0x1078, 0x61cd, 0x1078, 0x62d1, 0x1078, 0x8d06, + 0x0040, 0x9a7e, 0x6010, 0x2068, 0x1078, 0x13a4, 0x1078, 0x8ec6, + 0x0d7f, 0x007c, 0x9a95, 0x9ab4, 0x9a9e, 0x9ac1, 0x9a95, 0x9a95, + 0x9a95, 0x9a95, 0x9a95, 0x9a95, 0x9a95, 0x9a95, 0x9a95, 0x9a95, + 0x9a95, 0x9a95, 0x9a95, 0x9a95, 0x9a95, 0x1078, 0x1332, 0x6010, + 0xa088, 0x0013, 0x2104, 0xa085, 0x0400, 0x200a, 0x1078, 0x61cd, + 0x6010, 0xa080, 0x0013, 0x2004, 0xd0b4, 0x0040, 0x9aaf, 0x6003, + 0x0007, 0x2009, 0x0043, 0x1078, 0x775c, 0x0078, 0x9ab1, 0x6003, + 0x0002, 0x1078, 0x62d1, 0x007c, 0x1078, 0x61cd, 0x1078, 0xa423, + 0x00c0, 0x9abe, 0x1078, 0x5bc1, 0x1078, 0x772d, 0x1078, 0x62d1, + 0x007c, 0x1078, 0x61cd, 0x2009, 0x0041, 0x0078, 0x9c1e, 0xa182, + 0x0040, 0x0079, 0x9acb, 0x9ade, 0x9ae0, 0x9ade, 0x9ade, 0x9ade, + 0x9ade, 0x9ade, 0x9ae1, 0x9ade, 0x9ade, 0x9ade, 0x9ade, 0x9ade, + 0x9ade, 0x9ade, 0x9ade, 0x9ade, 0x9aec, 0x9ade, 0x1078, 0x1332, + 0x007c, 0x6003, 0x0004, 0x6110, 0x20e1, 0x0005, 0x3d18, 0x3e20, + 0x2c10, 0x1078, 0x15fa, 0x007c, 0x0d7e, 0x1078, 0x5bc1, 0x0d7f, + 0x1078, 0xa495, 0x1078, 0x772d, 0x007c, 0xa182, 0x0040, 0x0079, + 0x9af9, 0x9b0c, 0x9b0c, 0x9b0c, 0x9b0c, 0x9b0c, 0x9b0c, 0x9b0c, + 0x9b0e, 0x9b0c, 0x9b11, 0x9b3c, 0x9b0c, 0x9b0c, 0x9b0c, 0x9b0c, + 0x9b3c, 0x9b0c, 0x9b0c, 0x9b0c, 0x1078, 0x1332, 0x1078, 0x7773, + 0x007c, 0x1078, 0x627a, 0x1078, 0x639b, 0x6010, 0x0d7e, 0x2068, + 0x684c, 0xd0fc, 0x0040, 0x9b27, 0xa08c, 0x0003, 0xa18e, 0x0002, + 0x0040, 0x9b2f, 0x2009, 0x0041, 0x0d7f, 0x0078, 0x9c1e, 0x6003, + 0x0007, 0x6017, 0x0000, 0x1078, 0x5bc1, 0x0d7f, 0x007c, 0x1078, + 0xa423, 0x0040, 0x9b35, 0x0d7f, 0x007c, 0x1078, 0x5bc1, 0x1078, + 0x772d, 0x0d7f, 0x0078, 0x9b2e, 0x037e, 0x1078, 0x627a, 0x1078, + 0x639b, 0x6010, 0x0d7e, 0x2068, 0x6018, 0x2004, 0xd0bc, 0x0040, + 0x9b5c, 0x684c, 0xa084, 0x0003, 0xa086, 0x0002, 0x0040, 0x9b58, + 0x687c, 0x632c, 0xa31a, 0x632e, 0x6880, 0x6328, 0xa31b, 0x632a, + 0x6003, 0x0002, 0x0078, 0x9b6d, 0x2019, 0x0004, 0x1078, 0xa1ca, + 0x6014, 0xa005, 0x00c0, 0x9b69, 0x2001, 0xa8a3, 0x2004, 0x8003, + 0x6016, 0x6013, 0x0000, 0x6003, 0x0007, 0x0d7f, 0x037f, 0x007c, + 0xa186, 0x0013, 0x00c0, 0x9b7e, 0x6004, 0xa086, 0x0042, 0x10c0, + 0x1332, 0x1078, 0x61cd, 0x1078, 0x62d1, 0x007c, 0xa186, 0x0027, + 0x0040, 0x9b86, 0xa186, 0x0014, 0x00c0, 0x9b96, 0x6004, 0xa086, + 0x0042, 0x10c0, 0x1332, 0x2001, 0x0007, 0x1078, 0x4535, 0x1078, + 0x61cd, 0x1078, 0x8ec6, 0x1078, 0x62d1, 0x007c, 0xa182, 0x0040, + 0x0079, 0x9b9a, 0x9bad, 0x9bad, 0x9bad, 0x9bad, 0x9bad, 0x9bad, + 0x9bad, 0x9baf, 0x9bbb, 0x9bad, 0x9bad, 0x9bad, 0x9bad, 0x9bad, + 0x9bad, 0x9bad, 0x9bad, 0x9bad, 0x9bad, 0x1078, 0x1332, 0x037e, + 0x047e, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x1078, 0x15fa, + 0x047f, 0x037f, 0x007c, 0x6010, 0x0d7e, 0x2068, 0x6810, 0x6a14, + 0x6118, 0x210c, 0xd1bc, 0x0040, 0x9bda, 0x6124, 0xd1f4, 0x00c0, + 0x9bda, 0x007e, 0x047e, 0x057e, 0x6c7c, 0xa422, 0x6d80, 0x2200, + 0xa52b, 0x602c, 0xa420, 0x642e, 0x6028, 0xa529, 0x652a, 0x057f, + 0x047f, 0x007f, 0xa20d, 0x00c0, 0x9bee, 0x684c, 0xd0fc, 0x0040, + 0x9be6, 0x2009, 0x0041, 0x0d7f, 0x0078, 0x9c1e, 0x6003, 0x0007, + 0x6017, 0x0000, 0x1078, 0x5bc1, 0x0d7f, 0x007c, 0x007e, 0x0f7e, + 0x2c78, 0x1078, 0x4963, 0x0f7f, 0x007f, 0x0040, 0x9bfb, 0x6003, + 0x0002, 0x0d7f, 0x007c, 0x2009, 0xa60d, 0x210c, 0xd19c, 0x0040, + 0x9c05, 0x6003, 0x0007, 0x0078, 0x9c07, 0x6003, 0x0006, 0x1078, + 0x9c0d, 0x1078, 0x5bc3, 0x0d7f, 0x007c, 0xd2fc, 0x0040, 0x9c19, + 0x8002, 0x8000, 0x8212, 0xa291, 0x0000, 0x2009, 0x0009, 0x0078, + 0x9c1b, 0x2009, 0x0015, 0x6a6a, 0x6866, 0x007c, 0xa182, 0x0040, + 0x0048, 0x9c24, 0x0079, 0x9c31, 0xa186, 0x0013, 0x0040, 0x9c2c, + 0xa186, 0x0014, 0x10c0, 0x1332, 0x6024, 0xd0dc, 0x1040, 0x1332, + 0x007c, 0x9c44, 0x9c4b, 0x9c57, 0x9c63, 0x9c44, 0x9c44, 0x9c44, + 0x9c72, 0x9c44, 0x9c46, 0x9c46, 0x9c44, 0x9c44, 0x9c44, 0x9c44, + 0x9c44, 0x9c44, 0x9c44, 0x9c44, 0x1078, 0x1332, 0x6024, 0xd0dc, + 0x1040, 0x1332, 0x007c, 0x6003, 0x0001, 0x6106, 0x1078, 0x5d8a, + 0x127e, 0x2091, 0x8000, 0x1078, 0x62d1, 0x127f, 0x007c, 0x6003, + 0x0001, 0x6106, 0x1078, 0x5d8a, 0x127e, 0x2091, 0x8000, 0x1078, + 0x62d1, 0x127f, 0x007c, 0x6003, 0x0003, 0x6106, 0x2c10, 0x1078, + 0x1cf0, 0x127e, 0x2091, 0x8000, 0x1078, 0x5df6, 0x1078, 0x639b, + 0x127f, 0x007c, 0xa016, 0x1078, 0x15fa, 0x007c, 0x127e, 0x2091, + 0x8000, 0x037e, 0x0d7e, 0xa182, 0x0040, 0x1079, 0x9c83, 0x0d7f, + 0x037f, 0x127f, 0x007c, 0x9c93, 0x9c95, 0x9caa, 0x9cc9, 0x9c93, + 0x9c93, 0x9c93, 0x9ce1, 0x9c93, 0x9c93, 0x9c93, 0x9c93, 0x9c93, + 0x9c93, 0x9c93, 0x9c93, 0x1078, 0x1332, 0x6010, 0x2068, 0x684c, + 0xd0fc, 0x0040, 0x9cbf, 0xa09c, 0x0003, 0xa39e, 0x0003, 0x0040, + 0x9cbf, 0x6003, 0x0001, 0x6106, 0x1078, 0x5d8a, 0x1078, 0x62d1, + 0x0078, 0x9ce4, 0x6010, 0x2068, 0x684c, 0xd0fc, 0x0040, 0x9cbf, + 0xa09c, 0x0003, 0xa39e, 0x0003, 0x0040, 0x9cbf, 0x6003, 0x0001, + 0x6106, 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x0078, 0x9ce4, 0x6013, + 0x0000, 0x6017, 0x0000, 0x2019, 0x0004, 0x1078, 0xa1ca, 0x0078, + 0x9ce4, 0x6010, 0x2068, 0x684c, 0xd0fc, 0x0040, 0x9cbf, 0xa09c, + 0x0003, 0xa39e, 0x0003, 0x0040, 0x9cbf, 0x6003, 0x0003, 0x6106, + 0x2c10, 0x1078, 0x1cf0, 0x1078, 0x5df6, 0x1078, 0x639b, 0x0078, + 0x9ce4, 0xa016, 0x1078, 0x15fa, 0x007c, 0x1078, 0x61cd, 0x6110, + 0x81ff, 0x0040, 0x9cf6, 0x0d7e, 0x2168, 0x1078, 0xa4e2, 0x037e, + 0x2019, 0x0029, 0x1078, 0xa1ca, 0x037f, 0x0d7f, 0x1078, 0x8ec6, + 0x1078, 0x62d1, 0x007c, 0x1078, 0x627a, 0x6110, 0x81ff, 0x0040, + 0x9d0c, 0x0d7e, 0x2168, 0x1078, 0xa4e2, 0x037e, 0x2019, 0x0029, + 0x1078, 0xa1ca, 0x037f, 0x0d7f, 0x1078, 0x8ec6, 0x1078, 0x639b, + 0x007c, 0xa182, 0x0085, 0x0079, 0x9d15, 0x9d1e, 0x9d1c, 0x9d1c, + 0x9d2a, 0x9d1c, 0x9d1c, 0x9d1c, 0x1078, 0x1332, 0x6003, 0x000b, + 0x6106, 0x1078, 0x5d8a, 0x127e, 0x2091, 0x8000, 0x1078, 0x62d1, + 0x127f, 0x007c, 0x027e, 0x0e7e, 0x1078, 0xa41c, 0x0040, 0x9d34, + 0x1078, 0x772d, 0x0078, 0x9d50, 0x2071, 0xab80, 0x7224, 0x6212, + 0x7220, 0x1078, 0xa069, 0x0040, 0x9d41, 0x6007, 0x0086, 0x0078, + 0x9d4a, 0x6007, 0x0087, 0x7224, 0xa296, 0xffff, 0x00c0, 0x9d4a, + 0x6007, 0x0086, 0x6003, 0x0001, 0x1078, 0x5d8a, 0x1078, 0x62d1, + 0x0e7f, 0x027f, 0x007c, 0xa186, 0x0013, 0x00c0, 0x9d64, 0x6004, + 0xa08a, 0x0085, 0x1048, 0x1332, 0xa08a, 0x008c, 0x10c8, 0x1332, + 0xa082, 0x0085, 0x0079, 0x9d7b, 0xa186, 0x0027, 0x0040, 0x9d70, + 0xa186, 0x0014, 0x0040, 0x9d70, 0x1078, 0x7773, 0x0078, 0x9d7a, + 0x2001, 0x0007, 0x1078, 0x4535, 0x1078, 0x61cd, 0x1078, 0x8ec6, + 0x1078, 0x62d1, 0x007c, 0x9d82, 0x9d84, 0x9d84, 0x9d82, 0x9d82, + 0x9d82, 0x9d82, 0x1078, 0x1332, 0x1078, 0x61cd, 0x1078, 0x8ec6, + 0x1078, 0x62d1, 0x007c, 0xa182, 0x0085, 0x1048, 0x1332, 0xa182, + 0x008c, 0x10c8, 0x1332, 0xa182, 0x0085, 0x0079, 0x9d97, 0x9d9e, + 0x9d9e, 0x9d9e, 0x9da0, 0x9d9e, 0x9d9e, 0x9d9e, 0x1078, 0x1332, + 0x007c, 0xa186, 0x0013, 0x0040, 0x9db1, 0xa186, 0x0014, 0x0040, + 0x9db1, 0xa186, 0x0027, 0x0040, 0x9db1, 0x1078, 0x7773, 0x0078, + 0x9db7, 0x1078, 0x61cd, 0x1078, 0x8ec6, 0x1078, 0x62d1, 0x007c, + 0x037e, 0x1078, 0xa495, 0x603f, 0x0000, 0x2019, 0x000b, 0x1078, + 0x9dc7, 0x601f, 0x0006, 0x6003, 0x0007, 0x037f, 0x007c, 0x127e, + 0x037e, 0x2091, 0x8000, 0x087e, 0x2c40, 0x097e, 0x2049, 0x0000, + 0x1078, 0x7246, 0x097f, 0x087f, 0x00c0, 0x9e02, 0x077e, 0x2c38, + 0x1078, 0x72f3, 0x077f, 0x00c0, 0x9e02, 0x6000, 0xa086, 0x0000, + 0x0040, 0x9e02, 0x601c, 0xa086, 0x0007, 0x0040, 0x9e02, 0x0d7e, + 0x6000, 0xa086, 0x0004, 0x00c0, 0x9df3, 0x1078, 0xa495, 0x601f, + 0x0007, 0x1078, 0x1757, 0x6010, 0x2068, 0x1078, 0x8d06, 0x0040, + 0x9dfb, 0x1078, 0xa1ca, 0x0d7f, 0x6013, 0x0000, 0x1078, 0xa495, + 0x601f, 0x0007, 0x037f, 0x127f, 0x007c, 0x0f7e, 0x0c7e, 0x037e, + 0x157e, 0x2079, 0xab80, 0x7938, 0x783c, 0x1078, 0x254d, 0x00c0, + 0x9e49, 0x017e, 0x0c7e, 0x1078, 0x45c4, 0x00c0, 0x9e49, 0x017f, + 0x027f, 0x027e, 0x017e, 0x2019, 0x0029, 0x1078, 0x73d0, 0x1078, + 0x5f01, 0x077e, 0x2039, 0x0000, 0x1078, 0x5e0a, 0x077f, 0x017f, + 0x077e, 0x2039, 0x0000, 0x1078, 0x9f8b, 0x077f, 0x1078, 0x47e9, + 0x027e, 0x6204, 0xa294, 0xff00, 0x8217, 0xa286, 0x0006, 0x0040, + 0x9e3d, 0xa286, 0x0004, 0x00c0, 0x9e40, 0x62a0, 0x1078, 0x2942, + 0x027f, 0x017f, 0x1078, 0x42f8, 0x6612, 0x6516, 0xa006, 0x0078, + 0x9e4b, 0x0c7f, 0x017f, 0x157f, 0x037f, 0x0c7f, 0x0f7f, 0x007c, + 0x0c7e, 0x0d7e, 0x0e7e, 0x017e, 0x2009, 0xa620, 0x2104, 0xa086, + 0x0074, 0x00c0, 0x9eb3, 0x2069, 0xab8e, 0x690c, 0xa182, 0x0100, + 0x0048, 0x9ea3, 0x6908, 0xa184, 0x8000, 0x0040, 0x9eaf, 0x6018, + 0x2070, 0x7010, 0xa084, 0x00ff, 0x0040, 0x9e72, 0x7000, 0xd0f4, + 0x0040, 0x9e76, 0xa184, 0x0800, 0x0040, 0x9eaf, 0x6910, 0xa18a, + 0x0001, 0x0048, 0x9ea7, 0x6914, 0x2069, 0xabae, 0x6904, 0x81ff, + 0x00c0, 0x9e9b, 0x690c, 0xa182, 0x0100, 0x0048, 0x9ea3, 0x6908, + 0x81ff, 0x00c0, 0x9e9f, 0x6910, 0xa18a, 0x0001, 0x0048, 0x9ea7, + 0x6918, 0xa18a, 0x0001, 0x0048, 0x9eaf, 0x0078, 0x9eb9, 0x6013, + 0x0100, 0x0078, 0x9eb5, 0x6013, 0x0300, 0x0078, 0x9eb5, 0x6013, + 0x0500, 0x0078, 0x9eb5, 0x6013, 0x0700, 0x0078, 0x9eb5, 0x6013, + 0x0900, 0x0078, 0x9eb5, 0x6013, 0x0b00, 0x0078, 0x9eb5, 0x6013, + 0x0f00, 0x0078, 0x9eb5, 0x6013, 0x2d00, 0xa085, 0x0001, 0x0078, + 0x9eba, 0xa006, 0x017f, 0x0e7f, 0x0d7f, 0x0c7f, 0x007c, 0x0c7e, + 0x0d7e, 0x027e, 0x037e, 0x157e, 0x6218, 0x2268, 0x6b04, 0xa394, + 0x00ff, 0xa286, 0x0006, 0x0040, 0x9ee3, 0xa286, 0x0004, 0x0040, + 0x9ee3, 0xa394, 0xff00, 0x8217, 0xa286, 0x0006, 0x0040, 0x9ee3, + 0xa286, 0x0004, 0x0040, 0x9ee3, 0x0c7e, 0x2d60, 0x1078, 0x45d6, + 0x0c7f, 0x0078, 0x9f1e, 0x2011, 0xab96, 0xad98, 0x000a, 0x20a9, + 0x0004, 0x1078, 0x80de, 0x00c0, 0x9f1f, 0x2011, 0xab9a, 0xad98, + 0x0006, 0x20a9, 0x0004, 0x1078, 0x80de, 0x00c0, 0x9f1f, 0x047e, + 0x017e, 0x6aa0, 0xa294, 0x00ff, 0x8227, 0xa006, 0x2009, 0xa653, + 0x210c, 0xd1a4, 0x0040, 0x9f0b, 0x2009, 0x0029, 0x1078, 0xa21d, + 0x6800, 0xc0e5, 0x6802, 0x2019, 0x0029, 0x1078, 0x5f01, 0x077e, + 0x2039, 0x0000, 0x1078, 0x5e0a, 0x2c08, 0x1078, 0x9f8b, 0x077f, + 0x2001, 0x0007, 0x1078, 0x4535, 0x017f, 0x047f, 0xa006, 0x157f, + 0x037f, 0x027f, 0x0d7f, 0x0c7f, 0x007c, 0x0d7e, 0x2069, 0xab8e, + 0x6800, 0xa086, 0x0800, 0x0040, 0x9f31, 0x6013, 0x0000, 0x0078, + 0x9f32, 0xa006, 0x0d7f, 0x007c, 0x0c7e, 0x0f7e, 0x017e, 0x027e, + 0x037e, 0x157e, 0x2079, 0xab8c, 0x7930, 0x7834, 0x1078, 0x254d, + 0x00c0, 0x9f58, 0x1078, 0x45c4, 0x00c0, 0x9f58, 0x2011, 0xab90, + 0xac98, 0x000a, 0x20a9, 0x0004, 0x1078, 0x80de, 0x00c0, 0x9f58, + 0x2011, 0xab94, 0xac98, 0x0006, 0x20a9, 0x0004, 0x1078, 0x80de, + 0x157f, 0x037f, 0x027f, 0x017f, 0x0f7f, 0x0c7f, 0x007c, 0x0c7e, + 0x007e, 0x017e, 0x027e, 0x037e, 0x157e, 0x2011, 0xab83, 0x2204, + 0x8211, 0x220c, 0x1078, 0x254d, 0x00c0, 0x9f84, 0x1078, 0x45c4, + 0x00c0, 0x9f84, 0x2011, 0xab96, 0xac98, 0x000a, 0x20a9, 0x0004, + 0x1078, 0x80de, 0x00c0, 0x9f84, 0x2011, 0xab9a, 0xac98, 0x0006, + 0x20a9, 0x0004, 0x1078, 0x80de, 0x157f, 0x037f, 0x027f, 0x017f, + 0x007f, 0x0c7f, 0x007c, 0x0e7e, 0x0c7e, 0x087e, 0x077e, 0x067e, + 0x057e, 0x047e, 0x027e, 0x127e, 0x2091, 0x8000, 0x2740, 0x2029, + 0xa8ba, 0x252c, 0x2021, 0xa8c0, 0x2424, 0x2061, 0xad00, 0x2071, + 0xa600, 0x7648, 0x7064, 0x81ff, 0x0040, 0x9fb2, 0x007e, 0xa186, + 0xa9b3, 0x007f, 0x0040, 0x9fb2, 0x8001, 0xa602, 0x00c8, 0xa01c, + 0x0078, 0x9fb5, 0xa606, 0x0040, 0xa01c, 0x2100, 0xac06, 0x0040, + 0xa012, 0x1078, 0xa242, 0x0040, 0xa012, 0x671c, 0xa786, 0x0001, + 0x0040, 0xa037, 0xa786, 0x0004, 0x0040, 0xa037, 0xa786, 0x0007, + 0x0040, 0xa012, 0x2500, 0xac06, 0x0040, 0xa012, 0x2400, 0xac06, + 0x0040, 0xa012, 0x1078, 0xa256, 0x00c0, 0xa012, 0x88ff, 0x0040, + 0x9fdd, 0x6020, 0xa906, 0x00c0, 0xa012, 0x0d7e, 0x6000, 0xa086, + 0x0004, 0x00c0, 0x9fe7, 0x017e, 0x1078, 0x1757, 0x017f, 0xa786, + 0x0008, 0x00c0, 0x9ff6, 0x1078, 0x8f00, 0x00c0, 0x9ff6, 0x1078, + 0x7c83, 0x0d7f, 0x1078, 0x8ec6, 0x0078, 0xa012, 0x6010, 0x2068, + 0x1078, 0x8d06, 0x0040, 0xa00f, 0xa786, 0x0003, 0x00c0, 0xa026, + 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0xa4e2, 0x017e, + 0x1078, 0x8f7d, 0x1078, 0x4a73, 0x017f, 0x1078, 0x8eb9, 0x0d7f, + 0x1078, 0x8ec6, 0xace0, 0x0010, 0x2001, 0xa616, 0x2004, 0xac02, + 0x00c8, 0xa01c, 0x0078, 0x9f9f, 0x127f, 0x027f, 0x047f, 0x057f, + 0x067f, 0x077f, 0x087f, 0x0c7f, 0x0e7f, 0x007c, 0xa786, 0x0006, + 0x00c0, 0xa000, 0xa386, 0x0005, 0x0040, 0xa034, 0x1078, 0xa4e2, + 0x1078, 0xa1ca, 0x0078, 0xa00f, 0x0d7f, 0x0078, 0xa012, 0x1078, + 0xa256, 0x00c0, 0xa012, 0x81ff, 0x0040, 0xa012, 0xa180, 0x0001, + 0x2004, 0xa086, 0x0018, 0x0040, 0xa04c, 0xa180, 0x0001, 0x2004, + 0xa086, 0x002d, 0x00c0, 0xa012, 0x6000, 0xa086, 0x0002, 0x00c0, + 0xa012, 0x1078, 0x8eec, 0x0040, 0xa05d, 0x1078, 0x8f00, 0x00c0, + 0xa012, 0x1078, 0x7c83, 0x0078, 0xa065, 0x1078, 0x28a6, 0x1078, + 0x8f00, 0x00c0, 0xa065, 0x1078, 0x7c83, 0x1078, 0x8ec6, 0x0078, + 0xa012, 0x0c7e, 0x0e7e, 0x017e, 0x2c08, 0x2170, 0xa006, 0x1078, + 0xa1e6, 0x017f, 0x0040, 0xa079, 0x601c, 0xa084, 0x000f, 0x1079, + 0xa07c, 0x0e7f, 0x0c7f, 0x007c, 0xa084, 0xa084, 0xa084, 0xa084, + 0xa084, 0xa084, 0xa086, 0xa084, 0xa006, 0x007c, 0x047e, 0x017e, + 0x7018, 0xa080, 0x0028, 0x2024, 0xa4a4, 0x00ff, 0x8427, 0x2c00, + 0x2009, 0x0020, 0x1078, 0xa21d, 0x017f, 0x047f, 0x037e, 0x2019, + 0x0002, 0x1078, 0x9dc7, 0x037f, 0xa085, 0x0001, 0x007c, 0x2001, + 0x0001, 0x1078, 0x44ee, 0x157e, 0x017e, 0x027e, 0x037e, 0x20a9, + 0x0004, 0x2019, 0xa605, 0x2011, 0xab96, 0x1078, 0x80de, 0x037f, + 0x027f, 0x017f, 0x157f, 0xa005, 0x007c, 0x0f7e, 0x0e7e, 0x0c7e, + 0x087e, 0x077e, 0x067e, 0x027e, 0x127e, 0x2091, 0x8000, 0x2740, + 0x2061, 0xad00, 0x2079, 0x0001, 0x8fff, 0x0040, 0xa11d, 0x2071, + 0xa600, 0x7648, 0x7064, 0x8001, 0xa602, 0x00c8, 0xa11d, 0x88ff, + 0x0040, 0xa0d8, 0x2800, 0xac06, 0x00c0, 0xa113, 0x2079, 0x0000, + 0x1078, 0xa242, 0x0040, 0xa113, 0x2400, 0xac06, 0x0040, 0xa113, + 0x671c, 0xa786, 0x0006, 0x00c0, 0xa113, 0xa786, 0x0007, 0x0040, + 0xa113, 0x88ff, 0x00c0, 0xa0f7, 0x6018, 0xa206, 0x00c0, 0xa113, + 0x85ff, 0x0040, 0xa0f7, 0x6020, 0xa106, 0x00c0, 0xa113, 0x0d7e, + 0x6000, 0xa086, 0x0004, 0x00c0, 0xa103, 0x1078, 0xa495, 0x601f, + 0x0007, 0x1078, 0x1757, 0x6010, 0x2068, 0x1078, 0x8d06, 0x0040, + 0xa10d, 0x047e, 0x1078, 0xa1ca, 0x047f, 0x0d7f, 0x1078, 0x8ec6, + 0x88ff, 0x00c0, 0xa127, 0xace0, 0x0010, 0x2001, 0xa616, 0x2004, + 0xac02, 0x00c8, 0xa11d, 0x0078, 0xa0c4, 0xa006, 0x127f, 0x027f, + 0x067f, 0x077f, 0x087f, 0x0c7f, 0x0e7f, 0x0f7f, 0x007c, 0xa8c5, + 0x0001, 0x0078, 0xa11e, 0x077e, 0x057e, 0x087e, 0x2041, 0x0000, + 0x2029, 0x0001, 0x2c20, 0x2019, 0x0002, 0x6218, 0x097e, 0x2049, + 0x0000, 0x1078, 0x7246, 0x097f, 0x087f, 0x2039, 0x0000, 0x1078, + 0x72f3, 0x1078, 0xa0b5, 0x057f, 0x077f, 0x007c, 0x027e, 0x047e, + 0x057e, 0x077e, 0x0c7e, 0x157e, 0x2c20, 0x2128, 0x20a9, 0x007f, + 0x2009, 0x0000, 0x017e, 0x037e, 0x1078, 0x45c4, 0x00c0, 0xa16e, + 0x2c10, 0x057e, 0x087e, 0x2041, 0x0000, 0x2508, 0x2029, 0x0001, + 0x097e, 0x2049, 0x0000, 0x1078, 0x7246, 0x097f, 0x087f, 0x2039, + 0x0000, 0x1078, 0x72f3, 0x1078, 0xa0b5, 0x057f, 0x037f, 0x017f, + 0x8108, 0x00f0, 0xa152, 0x157f, 0x0c7f, 0x077f, 0x057f, 0x047f, + 0x027f, 0x007c, 0x077e, 0x057e, 0x6218, 0x087e, 0x2041, 0x0000, + 0x2029, 0x0001, 0x2019, 0x0048, 0x097e, 0x2049, 0x0000, 0x1078, + 0x7246, 0x097f, 0x087f, 0x2039, 0x0000, 0x1078, 0x72f3, 0x2c20, + 0x1078, 0xa0b5, 0x057f, 0x077f, 0x007c, 0x027e, 0x047e, 0x057e, + 0x077e, 0x0c7e, 0x157e, 0x2c20, 0x20a9, 0x007f, 0x2009, 0x0000, + 0x017e, 0x037e, 0x1078, 0x45c4, 0x00c0, 0xa1be, 0x2c10, 0x087e, + 0x2041, 0x0000, 0x2828, 0x047e, 0x2021, 0x0001, 0x1078, 0xa472, + 0x047f, 0x097e, 0x2049, 0x0000, 0x1078, 0x7246, 0x097f, 0x087f, + 0x2039, 0x0000, 0x1078, 0x72f3, 0x1078, 0xa0b5, 0x037f, 0x017f, + 0x8108, 0x00f0, 0xa1a0, 0x157f, 0x0c7f, 0x077f, 0x057f, 0x047f, + 0x027f, 0x007c, 0x017e, 0x0f7e, 0xad82, 0xcd00, 0x0048, 0xa1e3, + 0xad82, 0xffff, 0x00c8, 0xa1e3, 0x6800, 0xa07d, 0x0040, 0xa1e0, + 0x6803, 0x0000, 0x6b52, 0x1078, 0x4a73, 0x2f68, 0x0078, 0xa1d4, + 0x6b52, 0x1078, 0x4a73, 0x0f7f, 0x017f, 0x007c, 0x0e7e, 0x047e, + 0x037e, 0x2061, 0xad00, 0xa005, 0x00c0, 0xa1f6, 0x2071, 0xa600, + 0x7448, 0x7064, 0x8001, 0xa402, 0x00c8, 0xa218, 0x2100, 0xac06, + 0x0040, 0xa20a, 0x6000, 0xa086, 0x0000, 0x0040, 0xa20a, 0x6008, + 0xa206, 0x00c0, 0xa20a, 0x6018, 0xa1a0, 0x0006, 0x2424, 0xa406, + 0x0040, 0xa214, 0xace0, 0x0010, 0x2001, 0xa616, 0x2004, 0xac02, + 0x00c8, 0xa218, 0x0078, 0xa1f6, 0xa085, 0x0001, 0x0078, 0xa219, + 0xa006, 0x037f, 0x047f, 0x0e7f, 0x007c, 0x0d7e, 0x007e, 0x1078, + 0x138b, 0x007f, 0x1040, 0x1332, 0x6837, 0x010d, 0x685e, 0x027e, + 0x2010, 0x1078, 0x8cf2, 0x2001, 0x0000, 0x0040, 0xa233, 0x2200, + 0xa080, 0x0008, 0x2004, 0x027f, 0x684a, 0x6956, 0x6c46, 0x684f, + 0x0000, 0xa006, 0x68b2, 0x6802, 0x683a, 0x685a, 0x1078, 0x4a73, + 0x0d7f, 0x007c, 0x6700, 0xa786, 0x0000, 0x0040, 0xa255, 0xa786, + 0x0001, 0x0040, 0xa255, 0xa786, 0x000a, 0x0040, 0xa255, 0xa786, + 0x0009, 0x0040, 0xa255, 0xa085, 0x0001, 0x007c, 0x0e7e, 0x6018, + 0x2070, 0x70a0, 0xa206, 0x0e7f, 0x007c, 0x017e, 0x6004, 0xa08e, + 0x001e, 0x00c0, 0xa277, 0x8007, 0x6130, 0xa18c, 0x00ff, 0xa105, + 0x6032, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0005, 0x2001, + 0xa8a3, 0x2004, 0x6016, 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x017f, + 0x007c, 0x0005, 0x0005, 0x007c, 0x6024, 0xd0e4, 0x0040, 0xa28d, + 0xd0cc, 0x0040, 0xa287, 0x1078, 0x8fbf, 0x0078, 0xa28d, 0x1078, + 0xa495, 0x1078, 0x5bc1, 0x1078, 0x772d, 0x007c, 0xa280, 0x0007, + 0x2004, 0xa084, 0x000f, 0x0079, 0xa295, 0xa29e, 0xa29e, 0xa29e, + 0xa2a0, 0xa29e, 0xa2a0, 0xa2a0, 0xa29e, 0xa2a0, 0xa006, 0x007c, + 0xa085, 0x0001, 0x007c, 0xa280, 0x0007, 0x2004, 0xa084, 0x000f, + 0x0079, 0xa2aa, 0xa2b3, 0xa2b3, 0xa2b3, 0xa2b3, 0xa2b3, 0xa2b3, + 0xa2be, 0xa2b3, 0xa2b3, 0x6007, 0x003b, 0x602b, 0x0009, 0x6013, + 0x2a00, 0x6003, 0x0001, 0x1078, 0x5d8a, 0x007c, 0x0c7e, 0x2260, + 0x1078, 0xa495, 0x603f, 0x0000, 0x6024, 0xc0f4, 0xc0cc, 0x6026, + 0x0c7f, 0x0d7e, 0x2268, 0xa186, 0x0007, 0x00c0, 0xa31f, 0x6810, + 0xa005, 0x0040, 0xa2dc, 0xa080, 0x0013, 0x2004, 0xd0fc, 0x00c0, + 0xa2dc, 0x0d7f, 0x0078, 0xa2b3, 0x6007, 0x003a, 0x6003, 0x0001, + 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x0c7e, 0x2d60, 0x6100, 0xa186, + 0x0002, 0x00c0, 0xa3ad, 0x6010, 0xa005, 0x00c0, 0xa2f6, 0x6000, + 0xa086, 0x0007, 0x10c0, 0x1332, 0x0078, 0xa3ad, 0xa08c, 0xf000, + 0x00c0, 0xa302, 0x0078, 0xa302, 0x2068, 0x6800, 0xa005, 0x00c0, + 0xa2fc, 0x2d00, 0xa080, 0x0013, 0x2004, 0xa084, 0x0003, 0xa086, + 0x0002, 0x00c0, 0xa31b, 0x6010, 0x2068, 0x684c, 0xc0dc, 0xc0f4, + 0x684e, 0x6850, 0xc0f4, 0xc0fc, 0x6852, 0x2009, 0x0043, 0x1078, + 0x9c1e, 0x0078, 0xa3ad, 0x2009, 0x0041, 0x0078, 0xa3a7, 0xa186, + 0x0005, 0x00c0, 0xa366, 0x6810, 0xa080, 0x0013, 0x2004, 0xd0bc, + 0x00c0, 0xa32d, 0x0d7f, 0x0078, 0xa2b3, 0xd0b4, 0x0040, 0xa335, + 0xd0fc, 0x1040, 0x1332, 0x0078, 0xa2cf, 0x6007, 0x003a, 0x6003, + 0x0001, 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x0c7e, 0x2d60, 0x6100, + 0xa186, 0x0002, 0x0040, 0xa348, 0xa186, 0x0004, 0x00c0, 0xa3ad, + 0x2071, 0xa8e7, 0x7000, 0xa086, 0x0003, 0x00c0, 0xa355, 0x7004, + 0xac06, 0x00c0, 0xa355, 0x7003, 0x0000, 0x6810, 0xa080, 0x0013, + 0x200c, 0xc1f4, 0xc1dc, 0x2102, 0x8000, 0x200c, 0xc1f4, 0xc1fc, + 0xc1bc, 0x2102, 0x2009, 0x0042, 0x0078, 0xa3a7, 0x037e, 0x0d7e, + 0x0d7e, 0x1078, 0x138b, 0x037f, 0x1040, 0x1332, 0x6837, 0x010d, + 0x6803, 0x0000, 0x683b, 0x0000, 0x685b, 0x0000, 0x6b5e, 0x6857, + 0x0045, 0x2c00, 0x6862, 0x6034, 0x6872, 0x2360, 0x6024, 0xc0dd, + 0x6026, 0x6018, 0xa080, 0x0028, 0x2004, 0xa084, 0x00ff, 0x8007, + 0x6320, 0x6b4a, 0x6846, 0x684f, 0x0000, 0x6d6a, 0x6e66, 0x686f, + 0x0001, 0x1078, 0x4a73, 0x2019, 0x0045, 0x6008, 0x2068, 0x1078, + 0x9dc7, 0x2d00, 0x600a, 0x601f, 0x0006, 0x6003, 0x0007, 0x6017, + 0x0000, 0x603f, 0x0000, 0x0d7f, 0x037f, 0x0078, 0xa3ae, 0x603f, + 0x0000, 0x6003, 0x0007, 0x1078, 0x9c1e, 0x0c7f, 0x0d7f, 0x007c, + 0xa186, 0x0013, 0x00c0, 0xa3ba, 0x6004, 0xa082, 0x0085, 0x2008, + 0x0079, 0xa3d4, 0xa186, 0x0027, 0x00c0, 0xa3cd, 0x1078, 0x61cd, + 0x037e, 0x0d7e, 0x6010, 0x2068, 0x2019, 0x0004, 0x1078, 0xa1ca, + 0x0d7f, 0x037f, 0x1078, 0x62d1, 0x007c, 0xa186, 0x0014, 0x0040, + 0xa3be, 0x1078, 0x7773, 0x007c, 0xa3dd, 0xa3db, 0xa3db, 0xa3db, + 0xa3db, 0xa3db, 0xa3dd, 0x1078, 0x1332, 0x1078, 0x61cd, 0x6003, + 0x000c, 0x1078, 0x62d1, 0x007c, 0xa182, 0x008c, 0x00c8, 0xa3ee, + 0xa182, 0x0085, 0x0048, 0xa3ee, 0x0079, 0xa3f1, 0x1078, 0x7773, + 0x007c, 0xa3f8, 0xa3f8, 0xa3f8, 0xa3f8, 0xa3fa, 0xa419, 0xa3f8, + 0x1078, 0x1332, 0x0d7e, 0x2c68, 0x1078, 0x76c7, 0x0040, 0xa414, + 0x6003, 0x0001, 0x6007, 0x001e, 0x2009, 0xab8e, 0x210c, 0x6136, + 0x2009, 0xab8f, 0x210c, 0x613a, 0x600b, 0xffff, 0x6918, 0x611a, + 0x601f, 0x0004, 0x1078, 0x5d8a, 0x2d60, 0x1078, 0x772d, 0x0d7f, + 0x007c, 0x1078, 0x772d, 0x007c, 0x0e7e, 0x6018, 0x2070, 0x7000, + 0xd0ec, 0x0e7f, 0x007c, 0x6010, 0xa08c, 0xf000, 0x0040, 0xa471, + 0xa080, 0x0013, 0x200c, 0xd1ec, 0x0040, 0xa471, 0x2001, 0xa672, + 0x2004, 0xd0ec, 0x0040, 0xa471, 0x6003, 0x0002, 0x6024, 0xc0e5, + 0x6026, 0xd1ac, 0x0040, 0xa44f, 0x0f7e, 0x2c78, 0x1078, 0x495f, + 0x0f7f, 0x0040, 0xa44f, 0x2001, 0xa8a4, 0x2004, 0x603e, 0x2009, + 0xa672, 0x210c, 0xd1f4, 0x00c0, 0xa46f, 0x0078, 0xa461, 0x2009, + 0xa672, 0x210c, 0xd1f4, 0x0040, 0xa45b, 0x6024, 0xc0e4, 0x6026, + 0xa006, 0x0078, 0xa471, 0x2001, 0xa8a4, 0x200c, 0x8103, 0xa100, + 0x603e, 0x6018, 0xa088, 0x002b, 0x2104, 0xa005, 0x0040, 0xa46c, + 0xa088, 0x0003, 0x0078, 0xa464, 0x2c0a, 0x600f, 0x0000, 0xa085, + 0x0001, 0x007c, 0x017e, 0x0c7e, 0x0e7e, 0x6120, 0xa2f0, 0x002b, + 0x2e04, 0x2060, 0x8cff, 0x0040, 0xa491, 0x84ff, 0x00c0, 0xa484, + 0x6020, 0xa106, 0x00c0, 0xa48c, 0x600c, 0x2072, 0x1078, 0x5bc1, + 0x1078, 0x772d, 0x0078, 0xa48e, 0xacf0, 0x0003, 0x2e64, 0x0078, + 0xa47a, 0x0e7f, 0x0c7f, 0x017f, 0x007c, 0x0d7e, 0x6018, 0xa0e8, + 0x002b, 0x2d04, 0xa005, 0x0040, 0xa4a7, 0xac06, 0x0040, 0xa4a5, + 0x2d04, 0xa0e8, 0x0003, 0x0078, 0xa499, 0x600c, 0x206a, 0x0d7f, + 0x007c, 0x027e, 0x037e, 0x157e, 0x2011, 0xa626, 0x2204, 0xa084, + 0x00ff, 0x2019, 0xab8e, 0x2334, 0xa636, 0x00c0, 0xa4d5, 0x8318, + 0x2334, 0x2204, 0xa084, 0xff00, 0xa636, 0x00c0, 0xa4d5, 0x2011, + 0xab90, 0x6018, 0xa098, 0x000a, 0x20a9, 0x0004, 0x1078, 0x80de, + 0x00c0, 0xa4d5, 0x2011, 0xab94, 0x6018, 0xa098, 0x0006, 0x20a9, + 0x0004, 0x1078, 0x80de, 0x00c0, 0xa4d5, 0x157f, 0x037f, 0x027f, + 0x007c, 0x0e7e, 0x2071, 0xa600, 0x1078, 0x42b8, 0x1078, 0x2677, + 0x0e7f, 0x007c, 0x0e7e, 0x6018, 0x2070, 0x7000, 0xd0fc, 0x0040, + 0xa4eb, 0x1078, 0xa4ed, 0x0e7f, 0x007c, 0x6850, 0xc0e5, 0x6852, + 0x007c, 0x0e7e, 0x0c7e, 0x077e, 0x067e, 0x057e, 0x047e, 0x027e, + 0x017e, 0x127e, 0x2091, 0x8000, 0x2029, 0xa8ba, 0x252c, 0x2021, + 0xa8c0, 0x2424, 0x2061, 0xad00, 0x2071, 0xa600, 0x7648, 0x7064, + 0xa606, 0x0040, 0xa545, 0x671c, 0xa786, 0x0001, 0x0040, 0xa514, + 0xa786, 0x0008, 0x00c0, 0xa53b, 0x2500, 0xac06, 0x0040, 0xa53b, + 0x2400, 0xac06, 0x0040, 0xa53b, 0x1078, 0xa242, 0x0040, 0xa53b, + 0x1078, 0xa256, 0x00c0, 0xa53b, 0x6000, 0xa086, 0x0004, 0x00c0, + 0xa52d, 0x017e, 0x1078, 0x1757, 0x017f, 0x1078, 0x8eec, 0x00c0, + 0xa533, 0x1078, 0x28a6, 0x1078, 0x8f00, 0x00c0, 0xa539, 0x1078, + 0x7c83, 0x1078, 0x8ec6, 0xace0, 0x0010, 0x2001, 0xa616, 0x2004, + 0xac02, 0x00c8, 0xa545, 0x0078, 0xa504, 0x127f, 0x017f, 0x027f, + 0x047f, 0x057f, 0x067f, 0x077f, 0x0c7f, 0x0e7f, 0x007c, 0x127e, + 0x007e, 0x0e7e, 0x017e, 0x2091, 0x8000, 0x2071, 0xa640, 0xd5a4, + 0x0040, 0xa55d, 0x7034, 0x8000, 0x7036, 0xd5b4, 0x0040, 0xa563, + 0x7030, 0x8000, 0x7032, 0xd5ac, 0x0040, 0xa579, 0x2500, 0xa084, + 0x0007, 0xa08e, 0x0003, 0x0040, 0xa579, 0xa08e, 0x0004, 0x0040, + 0xa579, 0xa08e, 0x0005, 0x0040, 0xa579, 0x2071, 0xa64a, 0x1078, + 0xa5ba, 0x017f, 0x0e7f, 0x007f, 0x127f, 0x007c, 0x127e, 0x007e, + 0x0e7e, 0x017e, 0x2091, 0x8000, 0x2071, 0xa640, 0xd5a4, 0x0040, + 0xa58c, 0x7034, 0x8000, 0x7036, 0xd5b4, 0x0040, 0xa592, 0x7030, + 0x8000, 0x7032, 0xd5ac, 0x0040, 0xa5a8, 0x2500, 0xa084, 0x0007, + 0xa08e, 0x0003, 0x0040, 0xa5a8, 0xa08e, 0x0004, 0x0040, 0xa5a8, + 0xa08e, 0x0005, 0x0040, 0xa5a8, 0x2071, 0xa64a, 0x1078, 0xa5ba, + 0x017f, 0x0e7f, 0x007f, 0x127f, 0x007c, 0x127e, 0x007e, 0x0e7e, + 0x2091, 0x8000, 0x2071, 0xa642, 0x1078, 0xa5ba, 0x0e7f, 0x007f, + 0x127f, 0x007c, 0x2e04, 0x8000, 0x2072, 0x00c8, 0xa5c3, 0x8e70, + 0x2e04, 0x8000, 0x2072, 0x007c, 0x0e7e, 0x2071, 0xa640, 0x1078, + 0xa5ba, 0x0e7f, 0x007c, 0x0e7e, 0x2071, 0xa644, 0x1078, 0xa5ba, + 0x0e7f, 0x007c, 0x127e, 0x007e, 0x0e7e, 0x2091, 0x8000, 0x2071, + 0xa640, 0x7044, 0x8000, 0x7046, 0x0e7f, 0x007f, 0x127f, 0x007c, + 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, + 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000, + 0xa50c +}; +#ifdef UNIQUE_FW_NAME +unsigned short fw2100tp_length01 = 0x95f1; +#else +unsigned short risc_code_length01 = 0x95f1; +#endif + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/ql2200.c 830-ivtv/drivers/scsi/qla2xxx/ql2200.c --- 000-virgin/drivers/scsi/qla2xxx/ql2200.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/ql2200.c Thu Jan 8 10:22:00 2004 @@ -0,0 +1,92 @@ +/* + * QLogic ISP2200 device driver for Linux 2.6.x + * Copyright (C) 2003 Christoph Hellwig. + * Copyright (C) 2003 QLogic Corporation (www.qlogic.com) + * + * Released under GPL v2. + */ + +#include +#include +#include + +#include "qla_os.h" +#include "qla_def.h" + +static char qla_driver_name[] = "qla2200"; + +extern unsigned char fw2200tp_version[]; +extern unsigned char fw2200tp_version_str[]; +extern unsigned short fw2200tp_addr01; +extern unsigned short fw2200tp_code01[]; +extern unsigned short fw2200tp_length01; + +static struct qla_fw_info qla_fw_tbl[] = { + { + .addressing = FW_INFO_ADDR_NORMAL, + .fwcode = &fw2200tp_code01[0], + .fwlen = &fw2200tp_length01, + .fwstart = &fw2200tp_addr01, + }, + + { FW_INFO_ADDR_NOMORE, }, +}; + +static struct qla_board_info qla_board_tbl = { + .drv_name = qla_driver_name, + + .isp_name = "ISP2200", + .fw_info = qla_fw_tbl, +}; + +static struct pci_device_id qla2200_pci_tbl[] = { + { + .vendor = PCI_VENDOR_ID_QLOGIC, + .device = PCI_DEVICE_ID_QLOGIC_ISP2200, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (unsigned long)&qla_board_tbl, + }, + + {0, 0}, +}; +MODULE_DEVICE_TABLE(pci, qla2200_pci_tbl); + +static int __devinit +qla2200_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) +{ + return qla2x00_probe_one(pdev, + (struct qla_board_info *)id->driver_data); +} + +static void __devexit +qla2200_remove_one(struct pci_dev *pdev) +{ + qla2x00_remove_one(pdev); +} + +static struct pci_driver qla2200_pci_driver = { + .name = "qla2200", + .id_table = qla2200_pci_tbl, + .probe = qla2200_probe_one, + .remove = __devexit_p(qla2200_remove_one), +}; + +static int __init +qla2200_init(void) +{ + return pci_module_init(&qla2200_pci_driver); +} + +static void __exit +qla2200_exit(void) +{ + pci_unregister_driver(&qla2200_pci_driver); +} + +module_init(qla2200_init); +module_exit(qla2200_exit); + +MODULE_AUTHOR("QLogic Corporation"); +MODULE_DESCRIPTION("QLogic ISP22xx FC-SCSI Host Bus Adapter driver"); +MODULE_LICENSE("GPL"); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/ql2200_fw.c 830-ivtv/drivers/scsi/qla2xxx/ql2200_fw.c --- 000-virgin/drivers/scsi/qla2xxx/ql2200_fw.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/ql2200_fw.c Thu Jan 8 10:22:00 2004 @@ -0,0 +1,5321 @@ +/****************************************************************************** + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + *************************************************************************/ + +/* + * Firmware Version 2.02.06 (08:46 Jun 26, 2003) + */ + +#ifdef UNIQUE_FW_NAME +unsigned short fw2200tp_version = 2*1024+2; +#else +unsigned short risc_code_version = 2*1024+2; +#endif + +#ifdef UNIQUE_FW_NAME +unsigned char fw2200tp_version_str[] = {2,2,6}; +#else +unsigned char firmware_version[] = {2,2,6}; +#endif + +#ifdef UNIQUE_FW_NAME +#define fw2200tp_VERSION_STRING "2.02.06" +#else +#define FW_VERSION_STRING "2.02.06" +#endif + +#ifdef UNIQUE_FW_NAME +unsigned short fw2200tp_addr01 = 0x1000 ; +#else +unsigned short risc_code_addr01 = 0x1000 ; +#endif + +#ifdef UNIQUE_FW_NAME +unsigned short fw2200tp_code01[] = { +#else +unsigned short risc_code01[] = { +#endif + 0x0470, 0x0000, 0x0000, 0xa46f, 0x0000, 0x0002, 0x0002, 0x0006, + 0x0017, 0x2043, 0x4f50, 0x5952, 0x4947, 0x4854, 0x2032, 0x3030, + 0x3120, 0x514c, 0x4f47, 0x4943, 0x2043, 0x4f52, 0x504f, 0x5241, + 0x5449, 0x4f4e, 0x2049, 0x5350, 0x3232, 0x3030, 0x2046, 0x6972, + 0x6d77, 0x6172, 0x6520, 0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030, + 0x322e, 0x3032, 0x2e30, 0x3620, 0x2020, 0x2020, 0x2400, 0x20c1, + 0x0005, 0x2001, 0x017f, 0x2003, 0x0000, 0x20c9, 0xbaff, 0x2091, + 0x2000, 0x2059, 0x0000, 0x2b78, 0x7823, 0x0004, 0x2089, 0x296a, + 0x2051, 0xb500, 0x2a70, 0x2029, 0xed00, 0x2031, 0xffff, 0x2039, + 0xece9, 0x2021, 0x0200, 0x0804, 0x1468, 0x20a1, 0xb46f, 0xa00e, + 0x20a9, 0x0891, 0x41a4, 0x3400, 0x7562, 0x7666, 0x775e, 0x746a, + 0x746e, 0x20a1, 0xbd00, 0x7164, 0x810d, 0x810d, 0x810d, 0x810d, + 0xa18c, 0x000f, 0x2001, 0x000b, 0xa112, 0xa00e, 0x21a8, 0x41a4, + 0x3400, 0x8211, 0x1dd8, 0x7164, 0x3400, 0xa102, 0x0120, 0x0218, + 0x20a8, 0xa00e, 0x41a4, 0x3800, 0xd08c, 0x01d8, 0x2009, 0xb500, + 0x810d, 0x810d, 0x810d, 0x810d, 0xa18c, 0x000f, 0x2001, 0x0001, + 0xa112, 0x20a1, 0x1000, 0xa00e, 0x21a8, 0x41a4, 0x8211, 0x1de0, + 0x2009, 0xb500, 0x3400, 0xa102, 0x0120, 0x0218, 0x20a8, 0xa00e, + 0x41a4, 0x080c, 0x1411, 0x080c, 0x1632, 0x080c, 0x17cf, 0x080c, + 0x1fa2, 0x080c, 0x4bff, 0x080c, 0x85bf, 0x080c, 0x15bb, 0x080c, + 0x2ec4, 0x080c, 0x5d8a, 0x080c, 0x5341, 0x080c, 0x68ce, 0x080c, + 0x2510, 0x080c, 0x6b61, 0x080c, 0x63bb, 0x080c, 0x23ca, 0x080c, + 0x24de, 0x2091, 0x3009, 0x7823, 0x0000, 0x1004, 0x10c5, 0x7820, + 0xa086, 0x0002, 0x1150, 0x7823, 0x4000, 0x0e04, 0x10bd, 0x781b, + 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x2a70, 0x7003, 0x0000, + 0x2a70, 0x7000, 0xa08e, 0x0003, 0x1158, 0x080c, 0x3f08, 0x080c, + 0x2eeb, 0x080c, 0x5dd8, 0x080c, 0x54f0, 0x080c, 0x68f9, 0x0c80, + 0x000b, 0x0c98, 0x10e4, 0x10e5, 0x1210, 0x10e2, 0x12dd, 0x140e, + 0x140f, 0x1410, 0x080c, 0x1515, 0x0005, 0x0126, 0x00f6, 0x2091, + 0x8000, 0x7000, 0xa086, 0x0001, 0x1904, 0x11ed, 0x080c, 0x1588, + 0x080c, 0x5acf, 0x0150, 0x080c, 0x5af5, 0x15c0, 0x2079, 0x0100, + 0x7828, 0xa085, 0x1800, 0x782a, 0x0488, 0x080c, 0x5a07, 0x7000, + 0xa086, 0x0001, 0x1904, 0x11ed, 0x708c, 0xa086, 0x0028, 0x1904, + 0x11ed, 0x2001, 0x0161, 0x2003, 0x0001, 0x2079, 0x0100, 0x7827, + 0xffff, 0x7a28, 0xa295, 0x1e2f, 0x7a2a, 0x2011, 0x59a2, 0x080c, + 0x699c, 0x2011, 0x5995, 0x080c, 0x6a5c, 0x2011, 0x59e4, 0x080c, + 0x699c, 0x2011, 0x4adc, 0x080c, 0x699c, 0x2011, 0x8030, 0x2019, + 0x0000, 0x708b, 0x0000, 0x080c, 0x1de9, 0x00e8, 0x080c, 0x448f, + 0x2079, 0x0100, 0x7844, 0xa005, 0x1904, 0x11ed, 0x2011, 0x4adc, + 0x080c, 0x699c, 0x2011, 0x59e4, 0x080c, 0x699c, 0x080c, 0x1de9, + 0x2001, 0xb78d, 0x2004, 0x780e, 0x7840, 0xa084, 0xfffb, 0x7842, + 0x2011, 0x8010, 0x73cc, 0x080c, 0x3ecc, 0x723c, 0xc284, 0x723e, + 0x2001, 0xb50c, 0x200c, 0xc1ac, 0x2102, 0x080c, 0x7f35, 0x2011, + 0x0004, 0x080c, 0x9c60, 0x080c, 0x524d, 0x080c, 0x5acf, 0x0158, + 0x080c, 0x4be8, 0x0140, 0x708b, 0x0001, 0x70c7, 0x0000, 0x080c, + 0x462c, 0x0804, 0x11ed, 0x080c, 0x5309, 0x0120, 0x7a0c, 0xc2b4, + 0x7a0e, 0x0060, 0x7073, 0x0000, 0x080c, 0xa008, 0x70d4, 0xd09c, + 0x1128, 0x70a0, 0xa005, 0x0110, 0x080c, 0x4bc6, 0x70df, 0x0000, + 0x70db, 0x0000, 0x72d4, 0x080c, 0x5acf, 0x1178, 0x2011, 0x0000, + 0x0016, 0x080c, 0x28eb, 0x2019, 0xb78f, 0x211a, 0x001e, 0x7053, + 0xffff, 0x7057, 0x00ef, 0x7077, 0x0000, 0x2079, 0xb552, 0x7804, + 0xd0ac, 0x0108, 0xc295, 0x72d6, 0x080c, 0x5acf, 0x0118, 0xa296, + 0x0004, 0x0548, 0x2011, 0x0001, 0x080c, 0x9c60, 0x709b, 0x0000, + 0x709f, 0xffff, 0x7003, 0x0002, 0x2079, 0x0100, 0x7827, 0x0003, + 0x7828, 0xa085, 0x0003, 0x782a, 0x00fe, 0x080c, 0x2ab8, 0x2011, + 0x0005, 0x080c, 0x8075, 0x080c, 0x7173, 0x080c, 0x5acf, 0x0148, + 0x00c6, 0x2061, 0x0100, 0x0016, 0x080c, 0x28eb, 0x61e2, 0x001e, + 0x00ce, 0x012e, 0x0420, 0x709b, 0x0000, 0x709f, 0xffff, 0x7003, + 0x0002, 0x00f6, 0x2079, 0x0100, 0x7827, 0x0003, 0x7828, 0xa085, + 0x0003, 0x782a, 0x00fe, 0x2011, 0x0005, 0x080c, 0x8075, 0x080c, + 0x7173, 0x080c, 0x5acf, 0x0148, 0x00c6, 0x2061, 0x0100, 0x0016, + 0x080c, 0x28eb, 0x61e2, 0x001e, 0x00ce, 0x00fe, 0x012e, 0x0005, + 0x00c6, 0x080c, 0x5acf, 0x1118, 0x20a9, 0x0100, 0x0010, 0x20a9, + 0x0082, 0x080c, 0x5acf, 0x1118, 0x2009, 0x0000, 0x0010, 0x2009, + 0x007e, 0x080c, 0x2d97, 0x8108, 0x1f04, 0x1201, 0x00ce, 0x7073, + 0x0000, 0x7074, 0xa084, 0x00ff, 0x7076, 0x70a3, 0x0000, 0x0005, + 0x0126, 0x2091, 0x8000, 0x7000, 0xa086, 0x0002, 0x1904, 0x12db, + 0x709c, 0xa086, 0xffff, 0x0130, 0x080c, 0x2ab8, 0x080c, 0x7173, + 0x0804, 0x12db, 0x70d4, 0xd0ac, 0x1110, 0xd09c, 0x0540, 0xd084, + 0x0530, 0x0006, 0x0016, 0x2001, 0x0103, 0x2009, 0xb78d, 0x210c, + 0x2102, 0x001e, 0x000e, 0xd08c, 0x01d0, 0x70d8, 0xa086, 0xffff, + 0x0190, 0x080c, 0x2c17, 0x080c, 0x7173, 0x70d4, 0xd094, 0x1904, + 0x12db, 0x2011, 0x0001, 0x2019, 0x0000, 0x080c, 0x2c4f, 0x080c, + 0x7173, 0x0804, 0x12db, 0x70dc, 0xa005, 0x1904, 0x12db, 0x7098, + 0xa005, 0x1904, 0x12db, 0x70d4, 0xd0a4, 0x0118, 0xd0b4, 0x0904, + 0x12db, 0x080c, 0x5309, 0x1904, 0x12db, 0x2001, 0xb553, 0x2004, + 0xd0ac, 0x01c8, 0x0156, 0x00c6, 0x20a9, 0x007f, 0x2009, 0x0000, + 0x0016, 0x080c, 0x4fa9, 0x1118, 0x6000, 0xd0ec, 0x1138, 0x001e, + 0x8108, 0x1f04, 0x1268, 0x00ce, 0x015e, 0x0028, 0x001e, 0x00ce, + 0x015e, 0x0804, 0x12db, 0x0006, 0x0016, 0x2001, 0x0103, 0x2009, + 0xb78d, 0x210c, 0x2102, 0x001e, 0x000e, 0x71a8, 0x81ff, 0x11b0, + 0xa006, 0x2009, 0x0200, 0x20a9, 0x0002, 0x20a1, 0xb7de, 0x40a1, + 0x2009, 0x0700, 0x20a9, 0x0002, 0x20a1, 0xb7ce, 0x40a1, 0x7070, + 0x8007, 0x7174, 0x810f, 0x20a9, 0x0002, 0x40a1, 0x20a1, 0xb7d2, + 0x2009, 0x0000, 0x080c, 0x14fb, 0x2001, 0x0000, 0x810f, 0x20a9, + 0x0002, 0x40a1, 0x7030, 0xc08c, 0x7032, 0x7003, 0x0003, 0x709f, + 0xffff, 0x080c, 0x1581, 0xa006, 0x080c, 0x27c3, 0x080c, 0x3f3e, + 0x00f6, 0x2079, 0x0100, 0x080c, 0x5af5, 0x0150, 0x080c, 0x5acf, + 0x7828, 0x0118, 0xa084, 0xe1ff, 0x0010, 0xa084, 0xffdf, 0x782a, + 0x00fe, 0x2001, 0xb7e1, 0x2004, 0xa086, 0x0005, 0x1120, 0x2011, + 0x0000, 0x080c, 0x8075, 0x2011, 0x0000, 0x080c, 0x807f, 0x080c, + 0x7173, 0x080c, 0x7230, 0x012e, 0x0005, 0x0016, 0x0046, 0x00f6, + 0x0126, 0x2091, 0x8000, 0x2079, 0x0100, 0x2009, 0xb534, 0x2104, + 0xa005, 0x1110, 0x080c, 0x2917, 0x2009, 0x00f7, 0x080c, 0x4baf, + 0x7940, 0xa18c, 0x0010, 0x7942, 0x7924, 0xd1b4, 0x0110, 0x7827, + 0x0040, 0xd19c, 0x0110, 0x7827, 0x0008, 0x0006, 0x0036, 0x0156, + 0x7954, 0xd1ac, 0x1904, 0x134b, 0x080c, 0x5ae1, 0x0158, 0x080c, + 0x5af5, 0x1128, 0x2001, 0xb79e, 0x2003, 0x0000, 0x0070, 0x080c, + 0x5ad7, 0x0dc0, 0x2001, 0xb79e, 0x2003, 0xaaaa, 0x2001, 0xb79f, + 0x2003, 0x0001, 0x080c, 0x5a07, 0x0058, 0x080c, 0x5acf, 0x0140, + 0x2009, 0x00f8, 0x080c, 0x4baf, 0x7843, 0x0090, 0x7843, 0x0010, + 0x20a9, 0x09c4, 0x7820, 0xd09c, 0x1138, 0x080c, 0x5acf, 0x0138, + 0x7824, 0xd0ac, 0x1904, 0x13f5, 0x1f04, 0x132a, 0x0070, 0x7824, + 0x080c, 0x5aeb, 0x0118, 0xd0ac, 0x1904, 0x13f5, 0xa084, 0x1800, + 0x0d98, 0x7003, 0x0001, 0x0804, 0x13f5, 0x2001, 0x0001, 0x080c, + 0x27c3, 0x0804, 0x1404, 0x7850, 0xa084, 0x0180, 0x7852, 0x782f, + 0x0020, 0x20a9, 0x0046, 0x1d04, 0x1353, 0x080c, 0x6a44, 0x1f04, + 0x1353, 0x7850, 0xa084, 0x0180, 0xa085, 0x0400, 0x7852, 0x782f, + 0x0000, 0x080c, 0x5ae1, 0x0158, 0x080c, 0x5af5, 0x1128, 0x2001, + 0xb79e, 0x2003, 0x0000, 0x0070, 0x080c, 0x5ad7, 0x0dc0, 0x2001, + 0xb79e, 0x2003, 0xaaaa, 0x2001, 0xb79f, 0x2003, 0x0001, 0x080c, + 0x5a07, 0x0020, 0x2009, 0x00f8, 0x080c, 0x4baf, 0x20a9, 0x000e, + 0xe000, 0x1f04, 0x1380, 0x7850, 0xa084, 0x0180, 0xa085, 0x1400, + 0x7852, 0x080c, 0x5acf, 0x0120, 0x7843, 0x0090, 0x7843, 0x0010, + 0x2021, 0xe678, 0x2019, 0xea60, 0x7820, 0xd09c, 0x1558, 0x080c, + 0x5acf, 0x05d8, 0x7824, 0xd0ac, 0x1904, 0x13f5, 0x080c, 0x5af5, + 0x1508, 0x0046, 0x2021, 0x0190, 0x8421, 0x1df0, 0x004e, 0x8421, + 0x11c8, 0x7827, 0x0048, 0x20a9, 0x01f4, 0x1d04, 0x13ad, 0x080c, + 0x6a44, 0x1f04, 0x13ad, 0x7824, 0xa084, 0x0068, 0x15c8, 0x2001, + 0xb79e, 0x2003, 0xaaaa, 0x2001, 0xb79f, 0x2003, 0x0001, 0x7003, + 0x0001, 0x0498, 0x1d04, 0x13c6, 0x080c, 0x6a44, 0x8319, 0x1960, + 0x2009, 0xb534, 0x2104, 0x8000, 0x200a, 0xa084, 0xfff0, 0x0120, + 0x200b, 0x0000, 0x080c, 0x2917, 0x00d8, 0x080c, 0x5ae1, 0x1140, + 0xa4a2, 0x0064, 0x1128, 0x080c, 0x5aa6, 0x7003, 0x0001, 0x00a8, + 0x7827, 0x1800, 0xe000, 0xe000, 0x7824, 0x080c, 0x5aeb, 0x0110, + 0xd0ac, 0x1158, 0xa084, 0x1800, 0x09a8, 0x7003, 0x0001, 0x0028, + 0x2001, 0x0001, 0x080c, 0x27c3, 0x0048, 0x2001, 0xb534, 0x2003, + 0x0000, 0x7827, 0x0048, 0x7828, 0xc09d, 0x782a, 0x7850, 0xa084, + 0x0180, 0xa085, 0x0400, 0x7852, 0x015e, 0x003e, 0x000e, 0x080c, + 0x1558, 0x012e, 0x00fe, 0x004e, 0x001e, 0x0005, 0x0005, 0x0005, + 0x0005, 0x2a70, 0x2061, 0xb7c1, 0x2063, 0x0002, 0x6007, 0x0002, + 0x600b, 0x0006, 0x600f, 0x0017, 0x2001, 0xb79e, 0x2003, 0x0000, + 0x708b, 0x0000, 0x2009, 0x0100, 0x2104, 0xa082, 0x0002, 0x0218, + 0x7053, 0xffff, 0x0010, 0x7053, 0x0000, 0x705b, 0xffff, 0x7073, + 0x0000, 0x7077, 0x0000, 0x080c, 0xa008, 0x2061, 0xb78e, 0x6003, + 0x0909, 0x6007, 0x0000, 0x600b, 0x8800, 0x600f, 0x0200, 0x6013, + 0x00ff, 0x6017, 0x000f, 0x601b, 0x0000, 0x601f, 0x07d0, 0x2061, + 0xb796, 0x6003, 0x8000, 0x6007, 0x0000, 0x600b, 0x0000, 0x600f, + 0x0200, 0x6013, 0x00ff, 0x6017, 0x0000, 0x601b, 0x0001, 0x601f, + 0x0000, 0x2061, 0xb7b9, 0x6003, 0x514c, 0x6007, 0x4f47, 0x600b, + 0x4943, 0x600f, 0x2020, 0x2001, 0xb528, 0x2003, 0x0000, 0x0005, + 0x04a0, 0x2011, 0x0000, 0x81ff, 0x0570, 0xa186, 0x0001, 0x1148, + 0x2031, 0x8fff, 0x2039, 0xd501, 0x2021, 0x0100, 0x2029, 0xd500, + 0x00e8, 0xa186, 0x0002, 0x1118, 0x2011, 0x0000, 0x00b8, 0xa186, + 0x0005, 0x1118, 0x2011, 0x0001, 0x0088, 0xa186, 0x0009, 0x1118, + 0x2011, 0x0002, 0x0058, 0xa186, 0x000a, 0x1118, 0x2011, 0x0002, + 0x0028, 0xa186, 0x0055, 0x1110, 0x2011, 0x0003, 0x3800, 0xa084, + 0xfffc, 0xa205, 0x20c0, 0x0804, 0x104d, 0xa00e, 0x2011, 0x0003, + 0x2019, 0x14a4, 0x0804, 0x14f5, 0x2019, 0xaaaa, 0x2061, 0xffff, + 0x2c14, 0x2362, 0xe000, 0xe000, 0x2c04, 0xa306, 0x2262, 0x1110, + 0xc1b5, 0xc1a5, 0x2011, 0x0000, 0x2019, 0x14b7, 0x04f0, 0x2019, + 0xaaaa, 0x2061, 0xffff, 0x2c14, 0x2362, 0xe000, 0xe000, 0x2c1c, + 0x2061, 0x7fff, 0xe000, 0xe000, 0x2c04, 0x2061, 0xffff, 0x2262, + 0xa306, 0x0110, 0xc18d, 0x0008, 0xc185, 0x2011, 0x0002, 0x2019, + 0x14d2, 0x0418, 0x2061, 0xffff, 0x2019, 0xaaaa, 0x2c14, 0x2362, + 0xe000, 0xe000, 0x2c04, 0x2262, 0xa306, 0x1180, 0x2c14, 0x2362, + 0xe000, 0xe000, 0x2c1c, 0x2061, 0x7fff, 0x2c04, 0x2061, 0xffff, + 0x2262, 0xa306, 0x1110, 0xc195, 0x0008, 0xc19d, 0x2011, 0x0001, + 0x2019, 0x14f3, 0x0010, 0x0804, 0x1469, 0x3800, 0xa084, 0xfffc, + 0xa205, 0x20c0, 0x0837, 0x2011, 0x0000, 0x080c, 0x4fa9, 0x1178, + 0x6004, 0xa0c4, 0x00ff, 0xa8c6, 0x0006, 0x0128, 0xa0c4, 0xff00, + 0xa8c6, 0x0600, 0x1120, 0xa186, 0x0080, 0x0108, 0x8210, 0x8108, + 0xa186, 0x0100, 0x1d50, 0x2208, 0x0005, 0x2091, 0x8000, 0x0e04, + 0x1517, 0x0006, 0x0016, 0x2079, 0x0000, 0x7818, 0xd084, 0x1de8, + 0x001e, 0x792e, 0x000e, 0x782a, 0x000e, 0x7826, 0x3900, 0x783a, + 0x7823, 0x8002, 0x781b, 0x0001, 0x2091, 0x5000, 0x0126, 0x0156, + 0x0146, 0x20a9, 0x0010, 0x20a1, 0xb90c, 0x2091, 0x2000, 0x40a1, + 0x20a9, 0x0010, 0x2091, 0x2200, 0x40a1, 0x20a9, 0x0010, 0x2091, + 0x2400, 0x40a1, 0x20a9, 0x0010, 0x2091, 0x2600, 0x40a1, 0x20a9, + 0x0010, 0x2091, 0x2800, 0x40a1, 0x014e, 0x015e, 0x012e, 0x2079, + 0xb500, 0x7803, 0x0005, 0x2091, 0x4080, 0x04c9, 0x0cf8, 0x0005, + 0x0006, 0x080c, 0x15a3, 0x1518, 0x00f6, 0x2079, 0xb524, 0x2f04, + 0x8000, 0x207a, 0xa082, 0x000f, 0x0258, 0xa006, 0x207a, 0x2079, + 0xb526, 0x2f04, 0xa084, 0x0001, 0xa086, 0x0001, 0x207a, 0x0070, + 0x2079, 0xb526, 0x2f7c, 0x8fff, 0x1128, 0x2001, 0x0c03, 0x2003, + 0x0040, 0x0020, 0x2001, 0x0c03, 0x2003, 0x00c0, 0x00fe, 0x000e, + 0x0005, 0x0409, 0x1120, 0x2001, 0x0c03, 0x2003, 0x0080, 0x0005, + 0x00d1, 0x1120, 0x2001, 0x0c03, 0x2003, 0x0040, 0x0005, 0x0006, + 0x0091, 0x1178, 0x2001, 0x0c03, 0x2003, 0x0040, 0x2009, 0x0fff, + 0x00a1, 0x2001, 0x0c03, 0x2003, 0x0080, 0x2009, 0x0fff, 0x0069, + 0x0c88, 0x000e, 0x0005, 0x00c6, 0x2061, 0x0c00, 0x2c04, 0xa084, + 0x00ff, 0xa086, 0x00aa, 0x00ce, 0x0005, 0x0156, 0x0126, 0xa18c, + 0x0fff, 0x21a8, 0x1d04, 0x15b2, 0x2091, 0x6000, 0x1f04, 0x15b2, + 0x012e, 0x015e, 0x0005, 0x2071, 0xb500, 0x7160, 0x712e, 0x2021, + 0x0001, 0xa190, 0x0030, 0xa298, 0x0030, 0x0240, 0x7064, 0xa302, + 0x1228, 0x220a, 0x2208, 0x2310, 0x8420, 0x0ca8, 0x3800, 0xd08c, + 0x0148, 0x7064, 0xa086, 0xb500, 0x0128, 0x7067, 0xb500, 0x2011, + 0x1000, 0x0c48, 0x200b, 0x0000, 0x74b2, 0x74b6, 0x0005, 0x00e6, + 0x0126, 0x2091, 0x8000, 0x2071, 0xb500, 0x70b4, 0xa0ea, 0x0010, + 0x0268, 0x8001, 0x70b6, 0x702c, 0x2068, 0x2d04, 0x702e, 0x206b, + 0x0000, 0x6807, 0x0000, 0x012e, 0x00ee, 0x0005, 0xa06e, 0x0cd8, + 0x00e6, 0x2071, 0xb500, 0x0126, 0x2091, 0x8000, 0x70b4, 0x8001, + 0x0260, 0x70b6, 0x702c, 0x2068, 0x2d04, 0x702e, 0x206b, 0x0000, + 0x6807, 0x0000, 0x012e, 0x00ee, 0x0005, 0xa06e, 0x0cd8, 0x00e6, + 0x0126, 0x2091, 0x8000, 0x2071, 0xb500, 0x702c, 0x206a, 0x2d00, + 0x702e, 0x70b4, 0x8000, 0x70b6, 0x012e, 0x00ee, 0x0005, 0x8dff, + 0x0138, 0x6804, 0x6807, 0x0000, 0x0006, 0x0c49, 0x00de, 0x0cb8, + 0x0005, 0x00e6, 0x2071, 0xb500, 0x70b4, 0xa08a, 0x0010, 0xa00d, + 0x00ee, 0x0005, 0x00e6, 0x2071, 0xb812, 0x7007, 0x0000, 0x701b, + 0x0000, 0x701f, 0x0000, 0x2071, 0x0000, 0x7010, 0xa085, 0x8004, + 0x7012, 0x00ee, 0x0005, 0x0126, 0x2091, 0x8000, 0x00e6, 0x2270, + 0x700b, 0x0000, 0x2071, 0xb812, 0x7018, 0xa088, 0xb81b, 0x220a, + 0x8000, 0xa084, 0x0007, 0x701a, 0x7004, 0xa005, 0x1128, 0x00f6, + 0x2079, 0x0010, 0x0089, 0x00fe, 0x00ee, 0x012e, 0x0005, 0x00e6, + 0x2071, 0xb812, 0x7004, 0xa005, 0x1128, 0x00f6, 0x2079, 0x0010, + 0x0019, 0x00fe, 0x00ee, 0x0005, 0x7000, 0x0002, 0x1672, 0x16d6, + 0x16f3, 0x16f3, 0x7018, 0x711c, 0xa106, 0x1118, 0x7007, 0x0000, + 0x0005, 0x00d6, 0xa180, 0xb81b, 0x2004, 0x700a, 0x2068, 0x8108, + 0xa18c, 0x0007, 0x711e, 0x7803, 0x0026, 0x6824, 0x7832, 0x6828, + 0x7836, 0x682c, 0x783a, 0x6830, 0x783e, 0x6810, 0x700e, 0x680c, + 0x7016, 0x6804, 0x00de, 0xd084, 0x0120, 0x7007, 0x0001, 0x0029, + 0x0005, 0x7007, 0x0002, 0x00b1, 0x0005, 0x0016, 0x0026, 0x710c, + 0x2011, 0x0040, 0xa182, 0x0040, 0x1210, 0x2110, 0xa006, 0x700e, + 0x7212, 0x8203, 0x7822, 0x7803, 0x0020, 0x7803, 0x0041, 0x002e, + 0x001e, 0x0005, 0x0016, 0x0026, 0x0136, 0x0146, 0x0156, 0x7014, + 0x2098, 0x20a1, 0x0014, 0x7803, 0x0026, 0x710c, 0x2011, 0x0040, + 0xa182, 0x0040, 0x1210, 0x2110, 0xa006, 0x700e, 0x22a8, 0x53a6, + 0x8203, 0x7822, 0x7803, 0x0020, 0x3300, 0x7016, 0x7803, 0x0001, + 0x015e, 0x014e, 0x013e, 0x002e, 0x001e, 0x0005, 0x0136, 0x0146, + 0x0156, 0x2099, 0xb5fa, 0x20a1, 0x0018, 0x20a9, 0x0008, 0x53a3, + 0x7803, 0x0020, 0x0126, 0x2091, 0x8000, 0x7803, 0x0041, 0x7007, + 0x0003, 0x7000, 0xc084, 0x7002, 0x700b, 0xb5f5, 0x012e, 0x015e, + 0x014e, 0x013e, 0x0005, 0x0136, 0x0146, 0x0156, 0x2001, 0xb629, + 0x209c, 0x20a1, 0x0014, 0x7803, 0x0026, 0x2001, 0xb62a, 0x20ac, + 0x53a6, 0x2099, 0xb62b, 0x20a1, 0x0018, 0x20a9, 0x0008, 0x53a3, + 0x7803, 0x0020, 0x0126, 0x2091, 0x8000, 0x7803, 0x0001, 0x7007, + 0x0004, 0x7000, 0xc08c, 0x7002, 0x700b, 0xb626, 0x012e, 0x015e, + 0x014e, 0x013e, 0x0005, 0x0016, 0x00e6, 0x2071, 0xb812, 0x00f6, + 0x2079, 0x0010, 0x7904, 0x7803, 0x0002, 0xd1fc, 0x0120, 0xa18c, + 0x0700, 0x7004, 0x0023, 0x00fe, 0x00ee, 0x001e, 0x0005, 0x166c, + 0x1736, 0x1764, 0x178e, 0x17be, 0x1735, 0x0cf8, 0xa18c, 0x0700, + 0x1528, 0x0136, 0x0146, 0x0156, 0x7014, 0x20a0, 0x2099, 0x0014, + 0x7803, 0x0040, 0x7010, 0x20a8, 0x53a5, 0x3400, 0x7016, 0x015e, + 0x014e, 0x013e, 0x700c, 0xa005, 0x0570, 0x7830, 0x7832, 0x7834, + 0x7836, 0x080c, 0x169d, 0x0005, 0x7008, 0xa080, 0x0002, 0x2003, + 0x0100, 0x7007, 0x0000, 0x080c, 0x166c, 0x0005, 0x7008, 0xa080, + 0x0002, 0x2003, 0x0200, 0x0ca8, 0xa18c, 0x0700, 0x1150, 0x700c, + 0xa005, 0x0188, 0x7830, 0x7832, 0x7834, 0x7836, 0x080c, 0x16b2, + 0x0005, 0x7008, 0xa080, 0x0002, 0x2003, 0x0200, 0x7007, 0x0000, + 0x080c, 0x166c, 0x0005, 0x00d6, 0x7008, 0x2068, 0x7830, 0x6826, + 0x7834, 0x682a, 0x7838, 0x682e, 0x783c, 0x6832, 0x680b, 0x0100, + 0x00de, 0x7007, 0x0000, 0x080c, 0x166c, 0x0005, 0xa18c, 0x0700, + 0x1540, 0x0136, 0x0146, 0x0156, 0x2001, 0xb5f8, 0x2004, 0xa080, + 0x000d, 0x20a0, 0x2099, 0x0014, 0x7803, 0x0040, 0x20a9, 0x0020, + 0x53a5, 0x2001, 0xb5fa, 0x2004, 0xd0bc, 0x0148, 0x2001, 0xb603, + 0x2004, 0xa080, 0x000d, 0x20a0, 0x20a9, 0x0020, 0x53a5, 0x015e, + 0x014e, 0x013e, 0x7007, 0x0000, 0x080c, 0x5e6f, 0x080c, 0x166c, + 0x0005, 0x2011, 0x8003, 0x080c, 0x3ecc, 0x0cf8, 0xa18c, 0x0700, + 0x1148, 0x2001, 0xb628, 0x2003, 0x0100, 0x7007, 0x0000, 0x080c, + 0x166c, 0x0005, 0x2011, 0x8004, 0x080c, 0x3ecc, 0x0cf8, 0x0126, + 0x2091, 0x2200, 0x2079, 0x0030, 0x2071, 0xb823, 0x7003, 0x0000, + 0x700f, 0xb82f, 0x7013, 0xb82f, 0x780f, 0x00f6, 0x7803, 0x0004, + 0x012e, 0x0005, 0x6934, 0xa184, 0x0007, 0x0002, 0x17ee, 0x182c, + 0x17ee, 0x17ee, 0x17ee, 0x1814, 0x17fb, 0x17f2, 0xa085, 0x0001, + 0x0804, 0x1846, 0x684c, 0xd0bc, 0x0dc8, 0x6860, 0x682e, 0x685c, + 0x682a, 0x6858, 0x04c8, 0xa18c, 0x00ff, 0xa186, 0x001e, 0x1d70, + 0x684c, 0xd0bc, 0x0d58, 0x6860, 0x682e, 0x685c, 0x682a, 0x6804, + 0x681a, 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x22e5, + 0x2005, 0x6832, 0x6858, 0x0440, 0xa18c, 0x00ff, 0xa186, 0x0015, + 0x19a8, 0x684c, 0xd0ac, 0x0990, 0x6804, 0x681a, 0xa080, 0x000d, + 0x2004, 0xa084, 0x000f, 0xa080, 0x22e5, 0x2005, 0x6832, 0xa006, + 0x682e, 0x682a, 0x6858, 0x0080, 0x684c, 0xd0ac, 0x0904, 0x17ee, + 0xa006, 0x682e, 0x682a, 0x6858, 0xa18c, 0x000f, 0xa188, 0x22e5, + 0x210d, 0x6932, 0x2d08, 0x691a, 0x6826, 0x684c, 0xc0dd, 0x684e, + 0xa006, 0x680a, 0x697c, 0x6912, 0x6980, 0x6916, 0x0005, 0x684c, + 0xd0ac, 0x090c, 0x1515, 0x6833, 0x22e2, 0x2d08, 0x691a, 0x6858, + 0x8001, 0x6826, 0x684c, 0xc0dd, 0x684e, 0xa006, 0x680a, 0x682e, + 0x682a, 0x697c, 0x6912, 0x6980, 0x6916, 0x0005, 0x20e1, 0x0007, + 0x20e1, 0x2000, 0x2001, 0x020a, 0x2004, 0x82ff, 0x01e8, 0xa280, + 0x0004, 0x00d6, 0x206c, 0x684c, 0xd0dc, 0x1190, 0xa280, 0x0007, + 0x2004, 0xa086, 0x000a, 0x1110, 0x0891, 0x0010, 0x080c, 0x17e2, + 0x0138, 0x00de, 0xa280, 0x0000, 0x2003, 0x0002, 0xa016, 0x0020, + 0x6808, 0x8000, 0x680a, 0x00de, 0x0126, 0x0046, 0x0036, 0x0026, + 0x2091, 0x2200, 0x002e, 0x003e, 0x004e, 0x7000, 0xa005, 0x01d0, + 0x710c, 0x220a, 0x8108, 0x230a, 0x8108, 0x240a, 0x8108, 0xa182, + 0xb84a, 0x0210, 0x2009, 0xb82f, 0x710e, 0x7010, 0xa102, 0xa082, + 0x0009, 0x0118, 0xa080, 0x001b, 0x1118, 0x2009, 0x0138, 0x200a, + 0x012e, 0x0005, 0x7206, 0x2001, 0x18a8, 0x0006, 0x2260, 0x0804, + 0x19d5, 0x0126, 0x0026, 0x0036, 0x00c6, 0x0006, 0x2091, 0x2200, + 0x000e, 0x004e, 0x003e, 0x002e, 0x00d6, 0x00c6, 0x2460, 0x6110, + 0x2168, 0x6a62, 0x6b5e, 0xa005, 0x0904, 0x190a, 0x6808, 0xa005, + 0x0904, 0x1941, 0x7000, 0xa005, 0x1108, 0x0488, 0x700c, 0x7110, + 0xa106, 0x1904, 0x1949, 0x7004, 0xa406, 0x1548, 0x2001, 0x0005, + 0x2004, 0xd08c, 0x0168, 0x0046, 0x080c, 0x1b06, 0x004e, 0x2460, + 0x6010, 0xa080, 0x0002, 0x2004, 0xa005, 0x0904, 0x1941, 0x0c10, + 0x2001, 0x0207, 0x2004, 0xd09c, 0x1d48, 0x7804, 0xa084, 0x6000, + 0x0120, 0xa086, 0x6000, 0x0108, 0x0c08, 0x7818, 0x6812, 0x781c, + 0x6816, 0x7803, 0x0004, 0x7003, 0x0000, 0x7004, 0x2060, 0x6100, + 0xa18e, 0x0004, 0x1904, 0x1949, 0x2009, 0x0048, 0x080c, 0x864c, + 0x0804, 0x1949, 0x6808, 0xa005, 0x05a0, 0x7000, 0xa005, 0x0588, + 0x700c, 0x7110, 0xa106, 0x1118, 0x7004, 0xa406, 0x1550, 0x2001, + 0x0005, 0x2004, 0xd08c, 0x0160, 0x0046, 0x080c, 0x1b06, 0x004e, + 0x2460, 0x6010, 0xa080, 0x0002, 0x2004, 0xa005, 0x01d0, 0x0c28, + 0x2001, 0x0207, 0x2004, 0xd09c, 0x1d50, 0x2001, 0x0005, 0x2004, + 0xd08c, 0x1d50, 0x7804, 0xa084, 0x6000, 0x0118, 0xa086, 0x6000, + 0x19f0, 0x7818, 0x6812, 0x781c, 0x6816, 0x7803, 0x0004, 0x7003, + 0x0000, 0x6100, 0xa18e, 0x0004, 0x1120, 0x2009, 0x0048, 0x080c, + 0x864c, 0x00ce, 0x00de, 0x012e, 0x0005, 0x00f6, 0x00e6, 0x0026, + 0x0036, 0x0046, 0x0056, 0x2071, 0xb823, 0x7000, 0xa086, 0x0000, + 0x0904, 0x19b3, 0x7004, 0xac06, 0x1904, 0x19a5, 0x2079, 0x0030, + 0x7000, 0xa086, 0x0003, 0x0904, 0x19a5, 0x7804, 0xd0fc, 0x15c8, + 0x20e1, 0x6000, 0x2011, 0x0032, 0x2001, 0x0208, 0x200c, 0x2001, + 0x0209, 0x2004, 0xa106, 0x1d88, 0x8211, 0x1db0, 0x7804, 0xd0fc, + 0x1540, 0x080c, 0x1e6e, 0x0026, 0x0056, 0x7803, 0x0004, 0x7804, + 0xd0ac, 0x1de8, 0x7803, 0x0002, 0x7803, 0x0009, 0x7003, 0x0003, + 0x7007, 0x0000, 0x005e, 0x002e, 0x2001, 0x015d, 0x2003, 0x0000, + 0x080c, 0x5acf, 0x1138, 0x0066, 0x2031, 0x0001, 0x080c, 0x5b51, + 0x006e, 0x0058, 0x2001, 0x0160, 0x2502, 0x2001, 0x0138, 0x2202, + 0x0020, 0x080c, 0x1b06, 0x0804, 0x1955, 0x0156, 0x20a9, 0x0009, + 0x2009, 0xb82f, 0x2104, 0xac06, 0x1108, 0x200a, 0xa188, 0x0003, + 0x1f04, 0x19aa, 0x015e, 0x005e, 0x004e, 0x003e, 0x002e, 0x00ee, + 0x00fe, 0x0005, 0x700c, 0x7110, 0xa106, 0x0904, 0x1a49, 0x2104, + 0x7006, 0x2060, 0x8108, 0x211c, 0x8108, 0x2124, 0x8108, 0xa182, + 0xb84a, 0x0210, 0x2009, 0xb82f, 0x7112, 0x700c, 0xa106, 0x1128, + 0x080c, 0x28eb, 0x2001, 0x0138, 0x2102, 0x8cff, 0x0598, 0x6010, + 0x2068, 0x2d58, 0x6828, 0xa406, 0x1590, 0x682c, 0xa306, 0x1578, + 0x7004, 0x2060, 0x6020, 0xc0d4, 0x6022, 0x684c, 0xd0f4, 0x0128, + 0x6817, 0xffff, 0x6813, 0xffff, 0x00e8, 0x6850, 0xd0f4, 0x1130, + 0x7803, 0x0004, 0x6810, 0x781a, 0x6814, 0x781e, 0x6824, 0x2050, + 0x6818, 0x2060, 0x6830, 0x2040, 0x6034, 0xa0cc, 0x000f, 0x2009, + 0x0011, 0x080c, 0x1a4c, 0x0120, 0x2009, 0x0001, 0x080c, 0x1a4c, + 0x2d58, 0x0005, 0x080c, 0x1ddd, 0x0904, 0x19ba, 0x0cd0, 0x6020, + 0xd0f4, 0x11e0, 0xd0d4, 0x01b8, 0x6038, 0xa402, 0x6034, 0xa303, + 0x0108, 0x1288, 0x643a, 0x6336, 0x6c2a, 0x6b2e, 0x0046, 0x0036, + 0x2400, 0x6c7c, 0xa402, 0x6812, 0x2300, 0x6b80, 0xa303, 0x6816, + 0x003e, 0x004e, 0x0018, 0x080c, 0x9f9a, 0x09e0, 0x601c, 0xa08e, + 0x0008, 0x0904, 0x19e0, 0xa08e, 0x000a, 0x0904, 0x19e0, 0x2001, + 0xb574, 0x2004, 0xd0b4, 0x1140, 0x6018, 0x2004, 0xd0bc, 0x1120, + 0x6817, 0x7fff, 0x6813, 0xffff, 0x080c, 0x2305, 0x1918, 0x0804, + 0x19e0, 0x7003, 0x0000, 0x0005, 0x8aff, 0x0904, 0x1ae0, 0xa03e, + 0x2730, 0xc9fc, 0x6850, 0xd0fc, 0x11b8, 0xd0f4, 0x1528, 0x00d6, + 0x2805, 0xac68, 0x2900, 0x0002, 0x1a9e, 0x1a82, 0x1a82, 0x1a9e, + 0x1a9e, 0x1a96, 0x1a9e, 0x1a82, 0x1a9e, 0x1a87, 0x1a87, 0x1a9e, + 0x1a9e, 0x1a9e, 0x1a8e, 0x1a87, 0x7803, 0x0004, 0xc0fc, 0x6852, + 0x6b6c, 0x6a70, 0x6d1c, 0x6c20, 0x00d6, 0xd99c, 0x0550, 0x2805, + 0xac68, 0x6f08, 0x6e0c, 0x0430, 0xc0f4, 0x6852, 0x6b6c, 0x6a70, + 0x00d6, 0x0468, 0x6b08, 0x6a0c, 0x6d00, 0x6c04, 0x00d0, 0x6b10, + 0x6a14, 0x6d00, 0x6c04, 0x6f08, 0x6e0c, 0x00a0, 0x00de, 0x00d6, + 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, 0x1140, 0x00de, 0x080c, + 0x22a7, 0x1904, 0x1a4c, 0xa00e, 0x0804, 0x1ae0, 0x00de, 0x080c, + 0x1515, 0xc9fd, 0x7b22, 0x7a26, 0x7d32, 0x7c36, 0x7f3a, 0x7e3e, + 0x7316, 0x721a, 0x751e, 0x7422, 0x7726, 0x762a, 0x7902, 0x7100, + 0x8108, 0x7102, 0x00de, 0x6828, 0xa300, 0x682a, 0x682c, 0xa201, + 0x682e, 0x8109, 0x2d08, 0x1500, 0xd9fc, 0x0160, 0xc9fc, 0x080c, + 0x22a7, 0x01e8, 0x2805, 0xac68, 0x6800, 0xa506, 0x11c0, 0x6804, + 0xa406, 0x00a8, 0xc9fc, 0x080c, 0x22a7, 0x0188, 0x2805, 0xac68, + 0x6800, 0xa506, 0x1160, 0x6804, 0xa406, 0x1148, 0x6808, 0xa706, + 0x1130, 0x680c, 0xa606, 0x0018, 0xc9fc, 0x080c, 0x22a7, 0x2168, + 0x0005, 0x080c, 0x1515, 0x080c, 0x1f55, 0x7004, 0x2060, 0x00d6, + 0x6010, 0x2068, 0x7003, 0x0000, 0x080c, 0x1dfe, 0x080c, 0x9c5a, + 0x0170, 0x6808, 0x8001, 0x680a, 0x697c, 0x6912, 0x6980, 0x6916, + 0x682b, 0xffff, 0x682f, 0xffff, 0x6850, 0xc0bd, 0x6852, 0x00de, + 0x080c, 0x992a, 0x0804, 0x1d2b, 0x080c, 0x1515, 0x0126, 0x2091, + 0x2200, 0x0006, 0x0016, 0x2b68, 0x6818, 0x2060, 0x7904, 0x7803, + 0x0002, 0xa184, 0x0700, 0x1978, 0xa184, 0x0003, 0xa086, 0x0003, + 0x0d58, 0x7000, 0x0002, 0x1b23, 0x1b29, 0x1c3a, 0x1d06, 0x1d1a, + 0x1b23, 0x1b23, 0x1b23, 0x7804, 0xd09c, 0x1904, 0x1d2b, 0x080c, + 0x1515, 0x8001, 0x7002, 0xd1bc, 0x11a0, 0xd19c, 0x1904, 0x1bbe, + 0xd1dc, 0x1178, 0x8aff, 0x0904, 0x1bbe, 0x2009, 0x0001, 0x080c, + 0x1a4c, 0x0904, 0x1d2b, 0x2009, 0x0001, 0x080c, 0x1a4c, 0x0804, + 0x1d2b, 0x7803, 0x0004, 0x7003, 0x0000, 0xd1bc, 0x1904, 0x1b9e, + 0x0026, 0x0036, 0x7c20, 0x7d24, 0x7e30, 0x7f34, 0x7818, 0x6812, + 0x781c, 0x6816, 0x2001, 0x0201, 0x2004, 0xa005, 0x0140, 0x7808, + 0xd0ec, 0x1128, 0x7803, 0x0009, 0x7003, 0x0004, 0x0010, 0x080c, + 0x1d2f, 0x6b28, 0x6a2c, 0x2400, 0x686e, 0xa31a, 0x2500, 0x6872, + 0xa213, 0x6b2a, 0x6a2e, 0x00c6, 0x7004, 0x2060, 0x6020, 0xd0f4, + 0x1110, 0x633a, 0x6236, 0x00ce, 0x003e, 0x002e, 0x6e1e, 0x6f22, + 0x2500, 0xa405, 0x0128, 0x080c, 0x22bd, 0x6850, 0xc0fd, 0x6852, + 0x2a00, 0x6826, 0x2c00, 0x681a, 0x2800, 0x6832, 0x6808, 0x8001, + 0x680a, 0x1148, 0x684c, 0xd0e4, 0x0130, 0x7004, 0x2060, 0x2009, + 0x0048, 0x080c, 0x864c, 0x7000, 0xa086, 0x0004, 0x0904, 0x1d2b, + 0x7003, 0x0000, 0x080c, 0x19ba, 0x0804, 0x1d2b, 0x0056, 0x7d0c, + 0xd5bc, 0x1110, 0x080c, 0xb407, 0x005e, 0x080c, 0x1dfe, 0x00f6, + 0x7004, 0x2078, 0x080c, 0x5305, 0x0118, 0x7820, 0xc0f5, 0x7822, + 0x00fe, 0x682b, 0xffff, 0x682f, 0xffff, 0x6808, 0x8001, 0x680a, + 0x697c, 0x791a, 0x6980, 0x791e, 0x0804, 0x1d2b, 0x7004, 0x00c6, + 0x2060, 0x6020, 0x00ce, 0xd0f4, 0x0120, 0x6808, 0x8001, 0x680a, + 0x04c0, 0x7818, 0x6812, 0x7a1c, 0x6a16, 0xd19c, 0x0160, 0xa205, + 0x0150, 0x7004, 0xa080, 0x0007, 0x2004, 0xa084, 0xfffd, 0xa086, + 0x0008, 0x1904, 0x1b41, 0x684c, 0xc0f5, 0x684e, 0x7814, 0xa005, + 0x1520, 0x7003, 0x0000, 0x6808, 0x8001, 0x680a, 0x01a0, 0x7004, + 0x2060, 0x601c, 0xa086, 0x000a, 0x11a0, 0x0156, 0x20a9, 0x0009, + 0x2009, 0xb82f, 0x2104, 0xac06, 0x1108, 0x200a, 0xa188, 0x0003, + 0x1f04, 0x1bf2, 0x015e, 0x7004, 0x2060, 0x2009, 0x0048, 0x080c, + 0x864c, 0x080c, 0x19ba, 0x0804, 0x1d2b, 0x7818, 0x6812, 0x781c, + 0x6816, 0x7814, 0x7908, 0xa18c, 0x0fff, 0xa192, 0x0841, 0x1a04, + 0x1ae3, 0xa188, 0x0007, 0x8114, 0x8214, 0x8214, 0xa10a, 0x8104, + 0x8004, 0x8004, 0xa20a, 0x810b, 0x810b, 0x810b, 0x080c, 0x1e99, + 0x7803, 0x0004, 0x780f, 0xffff, 0x7803, 0x0001, 0x7804, 0xd0fc, + 0x0de8, 0x7803, 0x0002, 0x7803, 0x0004, 0x780f, 0x00f6, 0x7004, + 0x7007, 0x0000, 0x2060, 0x2009, 0x0048, 0x080c, 0x864c, 0x080c, + 0x1eef, 0x0838, 0x8001, 0x7002, 0xd194, 0x01b0, 0x7804, 0xd0fc, + 0x1904, 0x1cd6, 0xd09c, 0x0138, 0x7804, 0xd0fc, 0x1904, 0x1cd6, + 0xd09c, 0x1904, 0x1cda, 0x8aff, 0x0904, 0x1d2b, 0x2009, 0x0001, + 0x080c, 0x1a4c, 0x0804, 0x1d2b, 0xa184, 0x0888, 0x1148, 0x8aff, + 0x0904, 0x1d2b, 0x2009, 0x0001, 0x080c, 0x1a4c, 0x0804, 0x1d2b, + 0x7818, 0x6812, 0x7a1c, 0x6a16, 0xa205, 0x0904, 0x1bdb, 0x7803, + 0x0004, 0x7003, 0x0000, 0xd1bc, 0x1904, 0x1cb8, 0x6834, 0xa084, + 0x00ff, 0xa086, 0x0029, 0x1118, 0xd19c, 0x1904, 0x1bdb, 0x0026, + 0x0036, 0x7c20, 0x7d24, 0x7e30, 0x7f34, 0x7818, 0x6812, 0x781c, + 0x6816, 0x2001, 0x0201, 0x2004, 0xa005, 0x0140, 0x7808, 0xd0ec, + 0x1128, 0x7803, 0x0009, 0x7003, 0x0004, 0x0020, 0x0016, 0x080c, + 0x1d2f, 0x001e, 0x6b28, 0x6a2c, 0x080c, 0x22bd, 0x00d6, 0x2805, + 0xac68, 0x6034, 0xd09c, 0x1128, 0x6808, 0xa31a, 0x680c, 0xa213, + 0x0020, 0x6810, 0xa31a, 0x6814, 0xa213, 0x00de, 0xd194, 0x0904, + 0x1b63, 0x2a00, 0x6826, 0x2c00, 0x681a, 0x2800, 0x6832, 0x6808, + 0x8001, 0x680a, 0x6b2a, 0x6a2e, 0x003e, 0x002e, 0x0804, 0x1c01, + 0x0056, 0x7d0c, 0x080c, 0xb407, 0x005e, 0x080c, 0x1dfe, 0x00f6, + 0x7004, 0x2078, 0x080c, 0x5305, 0x0118, 0x7820, 0xc0f5, 0x7822, + 0x00fe, 0x682b, 0xffff, 0x682f, 0xffff, 0x6808, 0x8001, 0x680a, + 0x697c, 0x791a, 0x6980, 0x791e, 0x0804, 0x1d2b, 0x7804, 0xd09c, + 0x0904, 0x1b0e, 0x7c20, 0x7824, 0xa405, 0x1904, 0x1b0e, 0x7818, + 0x6812, 0x7c1c, 0x6c16, 0xa405, 0x1120, 0x7803, 0x0002, 0x0804, + 0x1bdb, 0x751c, 0x7420, 0x7724, 0x7628, 0x7014, 0xa528, 0x7018, + 0xa421, 0xa7b9, 0x0000, 0xa6b1, 0x0000, 0x7830, 0xa506, 0x1150, + 0x7834, 0xa406, 0x1138, 0x7838, 0xa706, 0x1120, 0x783c, 0xa606, + 0x0904, 0x1b0e, 0x7803, 0x0002, 0x0804, 0x1c67, 0x7803, 0x0004, + 0x7003, 0x0000, 0x7004, 0xa00d, 0x0150, 0x6808, 0x8001, 0x680a, + 0x1130, 0x7004, 0x2060, 0x2009, 0x0048, 0x080c, 0x864c, 0x080c, + 0x19ba, 0x0088, 0x7803, 0x0004, 0x7003, 0x0000, 0x7004, 0x2060, + 0x6010, 0xa005, 0x0da0, 0x2068, 0x6808, 0x8000, 0x680a, 0x6c28, + 0x6b2c, 0x080c, 0x19d5, 0x001e, 0x000e, 0x012e, 0x0005, 0x700c, + 0x7110, 0xa106, 0x0904, 0x1dd1, 0x7004, 0x0016, 0x210c, 0xa106, + 0x001e, 0x0904, 0x1dd1, 0x00d6, 0x00c6, 0x216c, 0x2d00, 0xa005, + 0x0904, 0x1dcf, 0x681c, 0xa086, 0x0008, 0x0904, 0x1dcf, 0x6820, + 0xd0d4, 0x1904, 0x1dcf, 0x6810, 0x2068, 0x6850, 0xd0fc, 0x05a8, + 0x8108, 0x2104, 0x6b2c, 0xa306, 0x1904, 0x1dcf, 0x8108, 0x2104, + 0x6a28, 0xa206, 0x1904, 0x1dcf, 0x6850, 0xc0fc, 0xc0f5, 0x6852, + 0x686c, 0x7822, 0x7016, 0x6870, 0x7826, 0x701a, 0x681c, 0x7832, + 0x701e, 0x6820, 0x7836, 0x7022, 0x6818, 0x2060, 0x6034, 0xd09c, + 0x0168, 0x6830, 0x2005, 0x00d6, 0xac68, 0x6808, 0x783a, 0x7026, + 0x680c, 0x783e, 0x702a, 0x00de, 0x0804, 0x1dc9, 0xa006, 0x783a, + 0x783e, 0x7026, 0x702a, 0x0804, 0x1dc9, 0x8108, 0x2104, 0xa005, + 0x1904, 0x1dcf, 0x6b2c, 0xa306, 0x1904, 0x1dcf, 0x8108, 0x2104, + 0xa005, 0x15e8, 0x6a28, 0xa206, 0x15d0, 0x6850, 0xc0f5, 0x6852, + 0x6830, 0x2005, 0x6918, 0xa160, 0xa180, 0x000d, 0x2004, 0xd09c, + 0x11a0, 0x6008, 0x7822, 0x7016, 0x686e, 0x600c, 0x7826, 0x701a, + 0x6872, 0x6000, 0x7832, 0x701e, 0x6004, 0x7836, 0x7022, 0xa006, + 0x783a, 0x783e, 0x7026, 0x702a, 0x00a0, 0x6010, 0x7822, 0x7016, + 0x686e, 0x6014, 0x7826, 0x701a, 0x6872, 0x6000, 0x7832, 0x701e, + 0x6004, 0x7836, 0x7022, 0x6008, 0x783a, 0x7026, 0x600c, 0x783e, + 0x702a, 0x6810, 0x781a, 0x6814, 0x781e, 0x7803, 0x0011, 0x00ce, + 0x00de, 0x0005, 0x2011, 0x0201, 0x2009, 0x003c, 0x2204, 0xa005, + 0x1118, 0x8109, 0x1dd8, 0x0005, 0x0005, 0x0ca1, 0x0118, 0x780c, + 0xd0a4, 0x0120, 0x00d9, 0xa085, 0x0001, 0x0010, 0x080c, 0x1eef, + 0x0005, 0x0126, 0x2091, 0x2200, 0x7000, 0xa086, 0x0003, 0x1160, + 0x700c, 0x7110, 0xa106, 0x0140, 0x080c, 0x295c, 0x20e1, 0x9028, + 0x700f, 0xb82f, 0x7013, 0xb82f, 0x012e, 0x0005, 0x00c6, 0x080c, + 0x5acf, 0x11b8, 0x2001, 0x0160, 0x2003, 0x0000, 0x2001, 0x0138, + 0x2003, 0x0000, 0x2011, 0x00c8, 0xe000, 0xe000, 0x8211, 0x1de0, + 0x04b1, 0x0066, 0x2031, 0x0000, 0x080c, 0x5b51, 0x006e, 0x00ce, + 0x0005, 0x080c, 0x1e6e, 0x080c, 0x295c, 0x20e1, 0x9028, 0x700c, + 0x7110, 0xa106, 0x01c0, 0x2104, 0xa005, 0x0130, 0x2060, 0x6010, + 0x2060, 0x6008, 0x8001, 0x600a, 0xa188, 0x0003, 0xa182, 0xb84a, + 0x0210, 0x2009, 0xb82f, 0x7112, 0x700c, 0xa106, 0x1d40, 0x080c, + 0x28eb, 0x2110, 0x0c20, 0x2001, 0x015d, 0x2003, 0x0000, 0x2001, + 0x0160, 0x2502, 0x2001, 0x0138, 0x2202, 0x00ce, 0x0005, 0x080c, + 0x295c, 0x20e1, 0x9028, 0x2001, 0x015d, 0x2003, 0x0000, 0x00e6, + 0x00c6, 0x0016, 0x2071, 0xb823, 0x700c, 0x7110, 0xa106, 0x0190, + 0x2104, 0xa005, 0x0130, 0x2060, 0x6010, 0x2060, 0x6008, 0x8001, + 0x600a, 0xa188, 0x0003, 0xa182, 0xb84a, 0x0210, 0x2009, 0xb82f, + 0x7112, 0x0c50, 0x001e, 0x00ce, 0x00ee, 0x0005, 0x2001, 0x0138, + 0x2014, 0x2003, 0x0000, 0x2001, 0x0160, 0x202c, 0x2003, 0x0000, + 0x080c, 0x5acf, 0x1148, 0x2021, 0x0002, 0x1d04, 0x1e7d, 0x2091, + 0x6000, 0x8421, 0x1dd0, 0x0005, 0x2021, 0xb015, 0x2001, 0x0141, + 0x201c, 0xd3dc, 0x1168, 0x2001, 0x0109, 0x201c, 0xa39c, 0x0048, + 0x1138, 0x2001, 0x0111, 0x201c, 0x83ff, 0x1110, 0x8421, 0x1d70, + 0x0005, 0x00e6, 0x2071, 0x0200, 0x7808, 0xa084, 0xf000, 0xa10d, + 0x0869, 0x2001, 0x0105, 0x2004, 0xa084, 0x0003, 0x1130, 0x2001, + 0xb84a, 0x2004, 0xa086, 0x0000, 0x0548, 0xa026, 0x2019, 0xf000, + 0x8319, 0x1148, 0x2001, 0x012b, 0x2003, 0x95f5, 0x2001, 0x0129, + 0x2003, 0x95f5, 0x00d8, 0x2001, 0x0105, 0x2004, 0xa084, 0x0003, + 0x1130, 0x2001, 0xb84a, 0x2004, 0xa086, 0x0000, 0x0178, 0x2001, + 0x0132, 0x2004, 0xa436, 0x0110, 0x2020, 0x0c00, 0x2001, 0x0021, + 0x2004, 0xd0fc, 0x09e8, 0x080c, 0x214a, 0x08c0, 0x20e1, 0x7000, + 0x7324, 0x7420, 0x7028, 0x7028, 0x7426, 0x7037, 0x0001, 0x810f, + 0x712e, 0x702f, 0x0100, 0x7037, 0x0008, 0x7326, 0x7422, 0x2001, + 0x0160, 0x2502, 0x2001, 0x0138, 0x2202, 0x00ee, 0x0005, 0x0026, + 0x2001, 0x015d, 0x2003, 0x0000, 0x7908, 0xa18c, 0x0fff, 0xa182, + 0x0ffd, 0x0210, 0x2009, 0x0000, 0xa190, 0x0007, 0xa294, 0x1ff8, + 0x8214, 0x8214, 0x8214, 0x2001, 0x020a, 0x82ff, 0x0140, 0x20e1, + 0x6000, 0x200c, 0x200c, 0x200c, 0x200c, 0x8211, 0x1dd0, 0x20e1, + 0x7000, 0x200c, 0x200c, 0x7003, 0x0000, 0x20e1, 0x6000, 0x2001, + 0x0208, 0x200c, 0x2001, 0x0209, 0x2004, 0xa106, 0x0158, 0x080c, + 0x1dd2, 0x0130, 0x7908, 0xd1ec, 0x1128, 0x790c, 0xd1a4, 0x0960, + 0x080c, 0x1dfe, 0xa006, 0x002e, 0x0005, 0x00f6, 0x00e6, 0x0016, + 0x0026, 0x2071, 0xb823, 0x2079, 0x0030, 0x2011, 0x0050, 0x7000, + 0xa086, 0x0000, 0x01a8, 0x8211, 0x0188, 0x2001, 0x0005, 0x2004, + 0xd08c, 0x0dc8, 0x7904, 0xa18c, 0x0780, 0x0016, 0x080c, 0x1b06, + 0x001e, 0x81ff, 0x1118, 0x2011, 0x0050, 0x0c48, 0xa085, 0x0001, + 0x002e, 0x001e, 0x00ee, 0x00fe, 0x0005, 0x7803, 0x0004, 0x2009, + 0x0064, 0x7804, 0xd0ac, 0x0904, 0x1fa1, 0x8109, 0x1dd0, 0x2009, + 0x0100, 0x210c, 0xa18a, 0x0003, 0x0a0c, 0x1515, 0x080c, 0x2251, + 0x00e6, 0x00f6, 0x2071, 0xb812, 0x2079, 0x0010, 0x7004, 0xa086, + 0x0000, 0x0538, 0x7800, 0x0006, 0x7820, 0x0006, 0x7830, 0x0006, + 0x7834, 0x0006, 0x7838, 0x0006, 0x783c, 0x0006, 0x7803, 0x0004, + 0xe000, 0xe000, 0x2079, 0x0030, 0x7804, 0xd0ac, 0x190c, 0x1515, + 0x2079, 0x0010, 0x000e, 0x783e, 0x000e, 0x783a, 0x000e, 0x7836, + 0x000e, 0x7832, 0x000e, 0x7822, 0x000e, 0x7802, 0x00fe, 0x00ee, + 0x0030, 0x00fe, 0x00ee, 0x7804, 0xd0ac, 0x190c, 0x1515, 0x080c, + 0x7230, 0x0005, 0x00e6, 0x2071, 0xb84a, 0x7003, 0x0000, 0x00ee, + 0x0005, 0x00d6, 0xa280, 0x0004, 0x206c, 0x694c, 0xd1dc, 0x1904, + 0x201f, 0x6934, 0xa184, 0x0007, 0x0002, 0x1fbd, 0x200a, 0x1fbd, + 0x1fbd, 0x1fbd, 0x1ff1, 0x1fd0, 0x1fbf, 0x080c, 0x1515, 0x684c, + 0xd0b4, 0x0904, 0x2107, 0x6860, 0x682e, 0x6816, 0x685c, 0x682a, + 0x6812, 0x687c, 0x680a, 0x6880, 0x680e, 0x6958, 0x0804, 0x2012, + 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, 0x1d38, 0x684c, 0xd0b4, + 0x0904, 0x2107, 0x6860, 0x682e, 0x6816, 0x685c, 0x682a, 0x6812, + 0x687c, 0x680a, 0x6880, 0x680e, 0x6804, 0x681a, 0xa080, 0x000d, + 0x2004, 0xa084, 0x000f, 0xa080, 0x22e5, 0x2005, 0x6832, 0x6958, + 0x0450, 0xa18c, 0x00ff, 0xa186, 0x0015, 0x1548, 0x684c, 0xd0b4, + 0x0904, 0x2107, 0x6804, 0x681a, 0xa080, 0x000d, 0x2004, 0xa084, + 0x000f, 0xa080, 0x22e5, 0x2005, 0x6832, 0x6958, 0xa006, 0x682e, + 0x682a, 0x0088, 0x684c, 0xd0b4, 0x0904, 0x1ae1, 0x6958, 0xa006, + 0x682e, 0x682a, 0x2d00, 0x681a, 0x6834, 0xa084, 0x000f, 0xa080, + 0x22e5, 0x2005, 0x6832, 0x6926, 0x684c, 0xc0dd, 0x684e, 0x00de, + 0x0005, 0x00f6, 0x2079, 0x0020, 0x7804, 0xd0fc, 0x190c, 0x214a, + 0x00e6, 0x00d6, 0x2071, 0xb84a, 0x7000, 0xa005, 0x1904, 0x2087, + 0x00c6, 0x7206, 0xa280, 0x0004, 0x205c, 0x7004, 0x2068, 0x7803, + 0x0004, 0x6818, 0x00d6, 0x2068, 0x686c, 0x7812, 0x6890, 0x00f6, + 0x20e1, 0x9040, 0x2079, 0x0200, 0x781a, 0x2079, 0x0100, 0x8004, + 0x78d6, 0x00fe, 0x00de, 0x2b68, 0x6824, 0x2050, 0x6818, 0x2060, + 0x6830, 0x2040, 0x6034, 0xa0cc, 0x000f, 0x6908, 0x791a, 0x7116, + 0x680c, 0x781e, 0x701a, 0xa006, 0x700e, 0x7012, 0x7004, 0x692c, + 0x6814, 0xa106, 0x1120, 0x6928, 0x6810, 0xa106, 0x0158, 0x0036, + 0x0046, 0x6b14, 0x6c10, 0x080c, 0x2305, 0x004e, 0x003e, 0x0110, + 0x00ce, 0x00a8, 0x8aff, 0x1120, 0x00ce, 0xa085, 0x0001, 0x0078, + 0x0126, 0x2091, 0x8000, 0x2079, 0x0020, 0x2009, 0x0001, 0x0059, + 0x0118, 0x2009, 0x0001, 0x0039, 0x012e, 0x00ce, 0xa006, 0x00de, + 0x00ee, 0x00fe, 0x0005, 0x0076, 0x0066, 0x0056, 0x0046, 0x0036, + 0x0026, 0x8aff, 0x0904, 0x2100, 0x700c, 0x7214, 0xa23a, 0x7010, + 0x7218, 0xa203, 0x0a04, 0x20ff, 0xa705, 0x0904, 0x20ff, 0xa03e, + 0x2730, 0x6850, 0xd0fc, 0x11a8, 0x00d6, 0x2805, 0xac68, 0x2900, + 0x0002, 0x20e2, 0x20c7, 0x20c7, 0x20e2, 0x20e2, 0x20db, 0x20e2, + 0x20c7, 0x20e2, 0x20cc, 0x20cc, 0x20e2, 0x20e2, 0x20e2, 0x20d3, + 0x20cc, 0xc0fc, 0x6852, 0x6b6c, 0x6a70, 0x6d1c, 0x6c20, 0xd99c, + 0x0528, 0x00d6, 0x2805, 0xac68, 0x6f08, 0x6e0c, 0x00f0, 0x6b08, + 0x6a0c, 0x6d00, 0x6c04, 0x00c8, 0x6b10, 0x6a14, 0x6d00, 0x6c04, + 0x6f08, 0x6e0c, 0x0090, 0x00de, 0x00d6, 0x6834, 0xa084, 0x00ff, + 0xa086, 0x001e, 0x1138, 0x00de, 0x080c, 0x22a7, 0x1904, 0x2091, + 0xa00e, 0x00f0, 0x00de, 0x080c, 0x1515, 0x00de, 0x7b22, 0x7a26, + 0x7d32, 0x7c36, 0x7f3a, 0x7e3e, 0x7902, 0x7000, 0x8000, 0x7002, + 0x6828, 0xa300, 0x682a, 0x682c, 0xa201, 0x682e, 0x700c, 0xa300, + 0x700e, 0x7010, 0xa201, 0x7012, 0x080c, 0x22a7, 0x0008, 0xa006, + 0x002e, 0x003e, 0x004e, 0x005e, 0x006e, 0x007e, 0x0005, 0x080c, + 0x1515, 0x0026, 0x2001, 0x0105, 0x2003, 0x0010, 0x20e1, 0x9040, + 0x7803, 0x0004, 0x7003, 0x0000, 0x7004, 0x2060, 0x00d6, 0x6010, + 0x2068, 0x080c, 0x9c5a, 0x0118, 0x6850, 0xc0bd, 0x6852, 0x601c, + 0xa086, 0x0006, 0x1180, 0x2061, 0x0100, 0x62c8, 0x2001, 0x00fa, + 0x8001, 0x1df0, 0x60c8, 0xa206, 0x1dc0, 0x60c4, 0x686a, 0x60c8, + 0x6866, 0x7004, 0x2060, 0x00de, 0x00c6, 0x080c, 0x992a, 0x00ce, + 0x2001, 0xb7ef, 0x2004, 0xac06, 0x1150, 0x20e1, 0x9040, 0x080c, + 0x825d, 0x2011, 0x0000, 0x080c, 0x807f, 0x080c, 0x7230, 0x002e, + 0x0804, 0x2204, 0x0126, 0x2091, 0x2400, 0x0006, 0x0016, 0x00f6, + 0x00e6, 0x00d6, 0x00c6, 0x2079, 0x0020, 0x2071, 0xb84a, 0x2b68, + 0x6818, 0x2060, 0x7904, 0x7803, 0x0002, 0xa184, 0x0700, 0x1904, + 0x2109, 0x7000, 0x0002, 0x2204, 0x2167, 0x21d7, 0x2202, 0x8001, + 0x7002, 0xd19c, 0x1170, 0x8aff, 0x05d0, 0x2009, 0x0001, 0x080c, + 0x208b, 0x0904, 0x2204, 0x2009, 0x0001, 0x080c, 0x208b, 0x0804, + 0x2204, 0x7803, 0x0004, 0xd194, 0x0148, 0x6850, 0xc0fc, 0x6852, + 0x8aff, 0x11d8, 0x684c, 0xc0f5, 0x684e, 0x00b8, 0x0026, 0x0036, + 0x6b28, 0x6a2c, 0x7820, 0x686e, 0xa31a, 0x7824, 0x6872, 0xa213, + 0x7830, 0x681e, 0x7834, 0x6822, 0x6b2a, 0x6a2e, 0x003e, 0x002e, + 0x080c, 0x22bd, 0x6850, 0xc0fd, 0x6852, 0x2a00, 0x6826, 0x2c00, + 0x681a, 0x2800, 0x6832, 0x7003, 0x0000, 0x0804, 0x2204, 0x00f6, + 0x0026, 0x781c, 0x0006, 0x7818, 0x0006, 0x2079, 0x0100, 0x7a14, + 0xa284, 0x0184, 0xa085, 0x0012, 0x7816, 0x0036, 0x2019, 0x1000, + 0x8319, 0x090c, 0x1515, 0x7820, 0xd0bc, 0x1dd0, 0x003e, 0x79c8, + 0x000e, 0xa102, 0x001e, 0x0006, 0x0016, 0x79c4, 0x000e, 0xa103, + 0x78c6, 0x000e, 0x78ca, 0xa284, 0x0184, 0xa085, 0x0012, 0x7816, + 0x002e, 0x00fe, 0x7803, 0x0008, 0x7003, 0x0000, 0x0468, 0x8001, + 0x7002, 0xd194, 0x0168, 0x7804, 0xd0fc, 0x1904, 0x215a, 0xd19c, + 0x11f8, 0x8aff, 0x0508, 0x2009, 0x0001, 0x080c, 0x208b, 0x00e0, + 0x0026, 0x0036, 0x6b28, 0x6a2c, 0x080c, 0x22bd, 0x00d6, 0x2805, + 0xac68, 0x6034, 0xd09c, 0x1128, 0x6808, 0xa31a, 0x680c, 0xa213, + 0x0020, 0x6810, 0xa31a, 0x6814, 0xa213, 0x00de, 0x0804, 0x218a, + 0x0804, 0x2186, 0x080c, 0x1515, 0x00ce, 0x00de, 0x00ee, 0x00fe, + 0x001e, 0x000e, 0x012e, 0x0005, 0x00f6, 0x00e6, 0x2071, 0xb84a, + 0x7000, 0xa086, 0x0000, 0x05d0, 0x2079, 0x0020, 0x0016, 0x2009, + 0x0207, 0x210c, 0xd194, 0x0198, 0x2009, 0x020c, 0x210c, 0xa184, + 0x0003, 0x0168, 0x080c, 0xb450, 0x2001, 0x0133, 0x2004, 0xa005, + 0x090c, 0x1515, 0x20e1, 0x9040, 0x2001, 0x020c, 0x2102, 0x2009, + 0x0206, 0x2104, 0x2009, 0x0203, 0x210c, 0xa106, 0x1110, 0x20e1, + 0x9040, 0x7804, 0xd0fc, 0x09d8, 0x080c, 0x214a, 0x7000, 0xa086, + 0x0000, 0x19a8, 0x001e, 0x7803, 0x0004, 0x7804, 0xd0ac, 0x1de8, + 0x20e1, 0x9040, 0x7803, 0x0002, 0x7003, 0x0000, 0x00ee, 0x00fe, + 0x0005, 0x0026, 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x2071, 0xb84a, + 0x2079, 0x0020, 0x7000, 0xa086, 0x0000, 0x0540, 0x7004, 0x2060, + 0x6010, 0x2068, 0x080c, 0x9c5a, 0x0158, 0x6850, 0xc0b5, 0x6852, + 0x680c, 0x7a1c, 0xa206, 0x1120, 0x6808, 0x7a18, 0xa206, 0x01e0, + 0x2001, 0x0105, 0x2003, 0x0010, 0x20e1, 0x9040, 0x7803, 0x0004, + 0x7003, 0x0000, 0x7004, 0x2060, 0x080c, 0x992a, 0x20e1, 0x9040, + 0x080c, 0x825d, 0x2011, 0x0000, 0x080c, 0x807f, 0x00fe, 0x00ee, + 0x00de, 0x00ce, 0x002e, 0x0005, 0x6810, 0x6a14, 0xa205, 0x1d00, + 0x684c, 0xc0dc, 0x684e, 0x2c10, 0x080c, 0x1fa9, 0x2001, 0x0105, + 0x2003, 0x0010, 0x20e1, 0x9040, 0x7803, 0x0004, 0x7003, 0x0000, + 0x2069, 0xb7e0, 0x6833, 0x0000, 0x683f, 0x0000, 0x08f8, 0x8840, + 0x2805, 0xa005, 0x1170, 0x6004, 0xa005, 0x0168, 0x681a, 0x2060, + 0x6034, 0xa084, 0x000f, 0xa080, 0x22e5, 0x2045, 0x88ff, 0x090c, + 0x1515, 0x8a51, 0x0005, 0x2050, 0x0005, 0x8a50, 0x8841, 0x2805, + 0xa005, 0x1190, 0x2c00, 0xad06, 0x0120, 0x6000, 0xa005, 0x1108, + 0x2d00, 0x2060, 0x681a, 0x6034, 0xa084, 0x000f, 0xa080, 0x22f5, + 0x2045, 0x88ff, 0x090c, 0x1515, 0x0005, 0x0000, 0x0011, 0x0015, + 0x0019, 0x001d, 0x0021, 0x0025, 0x0029, 0x0000, 0x000f, 0x0015, + 0x001b, 0x0021, 0x0027, 0x0000, 0x0000, 0x0000, 0x22da, 0x22d6, + 0x0000, 0x0000, 0x22e4, 0x0000, 0x22da, 0x0000, 0x22e1, 0x22de, + 0x0000, 0x0000, 0x0000, 0x22e4, 0x22e1, 0x0000, 0x22dc, 0x22dc, + 0x0000, 0x0000, 0x22e4, 0x0000, 0x22dc, 0x0000, 0x22e2, 0x22e2, + 0x0000, 0x0000, 0x0000, 0x22e4, 0x22e2, 0x00a6, 0x0096, 0x0086, + 0x6b2e, 0x6c2a, 0x6858, 0xa055, 0x0904, 0x2396, 0x2d60, 0x6034, + 0xa0cc, 0x000f, 0xa9c0, 0x22e5, 0xa986, 0x0007, 0x0130, 0xa986, + 0x000e, 0x0118, 0xa986, 0x000f, 0x1120, 0x605c, 0xa422, 0x6060, + 0xa31b, 0x2805, 0xa045, 0x1140, 0x0310, 0x0804, 0x2396, 0x6004, + 0xa065, 0x0904, 0x2396, 0x0c18, 0x2805, 0xa005, 0x01a8, 0xac68, + 0xd99c, 0x1128, 0x6808, 0xa422, 0x680c, 0xa31b, 0x0020, 0x6810, + 0xa422, 0x6814, 0xa31b, 0x0620, 0x2300, 0xa405, 0x0150, 0x8a51, + 0x0904, 0x2396, 0x8840, 0x0c40, 0x6004, 0xa065, 0x0904, 0x2396, + 0x0830, 0x8a51, 0x0904, 0x2396, 0x8840, 0x2805, 0xa005, 0x1158, + 0x6004, 0xa065, 0x0904, 0x2396, 0x6034, 0xa0cc, 0x000f, 0xa9c0, + 0x22e5, 0x2805, 0x2040, 0x2b68, 0x6850, 0xc0fc, 0x6852, 0x0458, + 0x8422, 0x8420, 0x831a, 0xa399, 0x0000, 0x00d6, 0x2b68, 0x6c6e, + 0x6b72, 0x00de, 0xd99c, 0x1168, 0x6908, 0x2400, 0xa122, 0x690c, + 0x2300, 0xa11b, 0x0a0c, 0x1515, 0x6800, 0xa420, 0x6804, 0xa319, + 0x0060, 0x6910, 0x2400, 0xa122, 0x6914, 0x2300, 0xa11b, 0x0a0c, + 0x1515, 0x6800, 0xa420, 0x6804, 0xa319, 0x2b68, 0x6c1e, 0x6b22, + 0x6850, 0xc0fd, 0x6852, 0x2c00, 0x681a, 0x2800, 0x6832, 0x2a00, + 0x6826, 0x000e, 0x000e, 0x000e, 0xa006, 0x0028, 0x008e, 0x009e, + 0x00ae, 0xa085, 0x0001, 0x0005, 0x2001, 0x0005, 0x2004, 0xa084, + 0x0007, 0x0002, 0x23aa, 0x23ab, 0x23ae, 0x23b1, 0x23b6, 0x23b9, + 0x23be, 0x23c3, 0x0005, 0x080c, 0x214a, 0x0005, 0x080c, 0x1b06, + 0x0005, 0x080c, 0x1b06, 0x080c, 0x214a, 0x0005, 0x080c, 0x171b, + 0x0005, 0x080c, 0x214a, 0x080c, 0x171b, 0x0005, 0x080c, 0x1b06, + 0x080c, 0x171b, 0x0005, 0x080c, 0x1b06, 0x080c, 0x214a, 0x080c, + 0x171b, 0x0005, 0x0126, 0x2091, 0x2600, 0x2079, 0x0200, 0x2071, + 0xbb80, 0x2069, 0xb500, 0x080c, 0x24c0, 0x080c, 0x24b0, 0x2009, + 0x0004, 0x7912, 0x7817, 0x0004, 0x080c, 0x27f8, 0x781b, 0x0002, + 0x20e1, 0x9080, 0x20e1, 0x4000, 0x20a9, 0x0080, 0x782f, 0x0000, + 0x1f04, 0x23e6, 0x20e1, 0x9080, 0x783b, 0x001f, 0x20e1, 0x8700, + 0x012e, 0x0005, 0x0126, 0x2091, 0x2600, 0x781c, 0xd0a4, 0x190c, + 0x24ad, 0xa084, 0x0007, 0x0002, 0x2416, 0x2404, 0x2407, 0x240a, + 0x240f, 0x2411, 0x2413, 0x2415, 0x080c, 0x63c4, 0x0078, 0x080c, + 0x6403, 0x0060, 0x080c, 0x63c4, 0x080c, 0x6403, 0x0038, 0x0041, + 0x0028, 0x0031, 0x0018, 0x0021, 0x0008, 0x0011, 0x012e, 0x0005, + 0x0006, 0x0016, 0x0026, 0x080c, 0xb450, 0x7930, 0xa184, 0x0003, + 0x01b0, 0x2001, 0xb7ef, 0x2004, 0xa005, 0x0170, 0x2001, 0x0133, + 0x2004, 0xa005, 0x090c, 0x1515, 0x00c6, 0x2001, 0xb7ef, 0x2064, + 0x080c, 0x992a, 0x00ce, 0x04b8, 0x20e1, 0x9040, 0x04a0, 0xa184, + 0x0030, 0x01e0, 0x6a00, 0xa286, 0x0003, 0x1108, 0x00a0, 0x080c, + 0x5acf, 0x1178, 0x2001, 0xb79f, 0x2003, 0x0001, 0x2001, 0xb500, + 0x2003, 0x0001, 0xa085, 0x0001, 0x080c, 0x5b13, 0x080c, 0x5a07, + 0x0010, 0x080c, 0x4b1f, 0x080c, 0x24b0, 0x00a8, 0xa184, 0x00c0, + 0x0168, 0x00e6, 0x0036, 0x0046, 0x0056, 0x2071, 0xb823, 0x080c, + 0x1dfe, 0x005e, 0x004e, 0x003e, 0x00ee, 0x0028, 0xa184, 0x0300, + 0x0110, 0x20e1, 0x9020, 0x7932, 0x002e, 0x001e, 0x000e, 0x0005, + 0x0016, 0x00e6, 0x00f6, 0x2071, 0xb500, 0x7128, 0x2001, 0xb791, + 0x2102, 0x2001, 0xb799, 0x2102, 0xa182, 0x0211, 0x1218, 0x2009, + 0x0008, 0x0400, 0xa182, 0x0259, 0x1218, 0x2009, 0x0007, 0x00d0, + 0xa182, 0x02c1, 0x1218, 0x2009, 0x0006, 0x00a0, 0xa182, 0x0349, + 0x1218, 0x2009, 0x0005, 0x0070, 0xa182, 0x0421, 0x1218, 0x2009, + 0x0004, 0x0040, 0xa182, 0x0581, 0x1218, 0x2009, 0x0003, 0x0010, + 0x2009, 0x0002, 0x2079, 0x0200, 0x7912, 0x7817, 0x0004, 0x080c, + 0x27f8, 0x00fe, 0x00ee, 0x001e, 0x0005, 0x7938, 0x080c, 0x1515, + 0x00e6, 0x0026, 0x2071, 0x0200, 0x20e1, 0x1000, 0x7220, 0x7028, + 0x7020, 0xa206, 0x0de0, 0x20e1, 0x9010, 0x002e, 0x00ee, 0x0005, + 0x20e1, 0xa000, 0x7837, 0x0001, 0x782f, 0x0000, 0x782f, 0x0000, + 0x782f, 0x0000, 0x782f, 0x0000, 0x7837, 0x0005, 0x20a9, 0x0210, + 0x7830, 0xd0bc, 0x1110, 0x1f04, 0x24d0, 0x7837, 0x0001, 0x7837, + 0x0000, 0xe000, 0xe000, 0x20e1, 0xa000, 0x0005, 0x0126, 0x2091, + 0x2800, 0x2061, 0x0100, 0x2071, 0xb500, 0x6024, 0x6026, 0x6053, + 0x0030, 0x080c, 0x2837, 0x6050, 0xa084, 0xfe7f, 0x6052, 0x2009, + 0x00ef, 0x6132, 0x6136, 0x080c, 0x2847, 0x60e7, 0x0000, 0x61ea, + 0x60e3, 0x0008, 0x604b, 0xf7f7, 0x6043, 0x0000, 0x602f, 0x0080, + 0x602f, 0x0000, 0x6007, 0x0e9f, 0x601b, 0x001e, 0x600f, 0x00ff, + 0x2001, 0xb78d, 0x2003, 0x00ff, 0x602b, 0x002f, 0x012e, 0x0005, + 0x2001, 0xb532, 0x2003, 0x0000, 0x2001, 0xb531, 0x2003, 0x0001, + 0x0005, 0x0126, 0x2091, 0x2800, 0x0006, 0x0016, 0x0026, 0x6124, + 0xa184, 0x1e2c, 0x1118, 0xa184, 0x0007, 0x002a, 0xa195, 0x0004, + 0xa284, 0x0007, 0x0002, 0x254d, 0x2533, 0x2536, 0x2539, 0x253e, + 0x2540, 0x2544, 0x2548, 0x080c, 0x6b74, 0x00b8, 0x080c, 0x6c4f, + 0x00a0, 0x080c, 0x6c4f, 0x080c, 0x6b74, 0x0078, 0x0099, 0x0068, + 0x080c, 0x6b74, 0x0079, 0x0048, 0x080c, 0x6c4f, 0x0059, 0x0028, + 0x080c, 0x6c4f, 0x080c, 0x6b74, 0x0029, 0x002e, 0x001e, 0x000e, + 0x012e, 0x0005, 0x6124, 0x6028, 0xd09c, 0x0118, 0xd19c, 0x1904, + 0x2766, 0x080c, 0x5acf, 0x0578, 0x7000, 0xa086, 0x0003, 0x0198, + 0x6024, 0xa084, 0x1800, 0x0178, 0x080c, 0x5af5, 0x0118, 0x080c, + 0x5ae1, 0x1148, 0x6027, 0x0020, 0x6043, 0x0000, 0x2001, 0xb79e, + 0x2003, 0xaaaa, 0x0458, 0x080c, 0x5af5, 0x15d0, 0x6024, 0xa084, + 0x1800, 0x1108, 0x04a8, 0x2001, 0xb79e, 0x2003, 0xaaaa, 0x2001, + 0xb79f, 0x2003, 0x0001, 0x2001, 0xb500, 0x2003, 0x0001, 0x080c, + 0x5a07, 0x0804, 0x2766, 0xd1ac, 0x1518, 0x6024, 0xd0dc, 0x1170, + 0xd0e4, 0x1188, 0xd0d4, 0x11a0, 0xd0cc, 0x0130, 0x708c, 0xa086, + 0x0028, 0x1110, 0x080c, 0x5c5e, 0x0804, 0x2766, 0x2001, 0xb79f, + 0x2003, 0x0000, 0x0048, 0x2001, 0xb79f, 0x2003, 0x0002, 0x0020, + 0x080c, 0x5bd1, 0x0804, 0x2766, 0x080c, 0x5d03, 0x0804, 0x2766, + 0xd1ac, 0x0904, 0x26ae, 0x080c, 0x5acf, 0x11d8, 0x6027, 0x0020, + 0x0006, 0x0026, 0x0036, 0x080c, 0x5aeb, 0x1170, 0x2001, 0xb79f, + 0x2003, 0x0001, 0x2001, 0xb500, 0x2003, 0x0001, 0x080c, 0x5a07, + 0x003e, 0x002e, 0x000e, 0x0005, 0x003e, 0x002e, 0x000e, 0x080c, + 0x5aa6, 0x0016, 0x0046, 0x00c6, 0x644c, 0xa486, 0xf0f0, 0x1138, + 0x2061, 0x0100, 0x644a, 0x6043, 0x0090, 0x6043, 0x0010, 0x74ce, + 0xa48c, 0xff00, 0x7034, 0xd084, 0x0178, 0xa186, 0xf800, 0x1160, + 0x703c, 0xd084, 0x1148, 0xc085, 0x703e, 0x0036, 0x2418, 0x2011, + 0x8016, 0x080c, 0x3ecc, 0x003e, 0xa196, 0xff00, 0x05b8, 0x7054, + 0xa084, 0x00ff, 0x810f, 0xa116, 0x0588, 0x7130, 0xd184, 0x1570, + 0x2011, 0xb553, 0x2214, 0xd2ec, 0x0138, 0xc18d, 0x7132, 0x2011, + 0xb553, 0x2214, 0xd2ac, 0x1510, 0x6240, 0xa294, 0x0010, 0x0130, + 0x6248, 0xa294, 0xff00, 0xa296, 0xff00, 0x01c0, 0x7030, 0xd08c, + 0x0904, 0x267b, 0x7034, 0xd08c, 0x1140, 0x2001, 0xb50c, 0x200c, + 0xd1ac, 0x1904, 0x267b, 0xc1ad, 0x2102, 0x0036, 0x73cc, 0x2011, + 0x8013, 0x080c, 0x3ecc, 0x003e, 0x0804, 0x267b, 0x7034, 0xd08c, + 0x1140, 0x2001, 0xb50c, 0x200c, 0xd1ac, 0x1904, 0x267b, 0xc1ad, + 0x2102, 0x0036, 0x73cc, 0x2011, 0x8013, 0x080c, 0x3ecc, 0x003e, + 0x7130, 0xc185, 0x7132, 0x2011, 0xb553, 0x220c, 0xd1a4, 0x01d0, + 0x0016, 0x2009, 0x0001, 0x2011, 0x0100, 0x080c, 0x6b1a, 0x2019, + 0x000e, 0x080c, 0xb065, 0xa484, 0x00ff, 0xa080, 0x2dc4, 0x200d, + 0xa18c, 0xff00, 0x810f, 0x8127, 0xa006, 0x2009, 0x000e, 0x080c, + 0xb0e8, 0x001e, 0xd1ac, 0x1148, 0x0016, 0x2009, 0x0000, 0x2019, + 0x0004, 0x080c, 0x2c6f, 0x001e, 0x0070, 0x0156, 0x20a9, 0x007f, + 0x2009, 0x0000, 0x080c, 0x4fa9, 0x1110, 0x080c, 0x4c0b, 0x8108, + 0x1f04, 0x2672, 0x015e, 0x00ce, 0x004e, 0x2011, 0x0003, 0x080c, + 0x8075, 0x2011, 0x0002, 0x080c, 0x807f, 0x080c, 0x7f59, 0x0036, + 0x2019, 0x0000, 0x080c, 0x7fe4, 0x003e, 0x60e3, 0x0000, 0x001e, + 0x2001, 0xb500, 0x2014, 0xa296, 0x0004, 0x1128, 0xd19c, 0x11b0, + 0x6228, 0xc29d, 0x622a, 0x2003, 0x0001, 0x2001, 0xb523, 0x2003, + 0x0000, 0x6027, 0x0020, 0x080c, 0x5af5, 0x1140, 0x0016, 0x2009, + 0x07d0, 0x2011, 0x59e4, 0x080c, 0x6a22, 0x001e, 0xd194, 0x0904, + 0x2766, 0x0016, 0x6220, 0xd2b4, 0x0904, 0x2717, 0x080c, 0x6a10, + 0x080c, 0x7d7a, 0x6027, 0x0004, 0x00f6, 0x2019, 0xb7e9, 0x2304, + 0xa07d, 0x0570, 0x7804, 0xa086, 0x0032, 0x1550, 0x00d6, 0x00c6, + 0x00e6, 0x2069, 0x0140, 0x618c, 0x6288, 0x7818, 0x608e, 0x7808, + 0x608a, 0x6043, 0x0002, 0x2001, 0x0003, 0x8001, 0x1df0, 0x6043, + 0x0000, 0x6803, 0x1000, 0x6803, 0x0000, 0x618e, 0x628a, 0x080c, + 0x7090, 0x080c, 0x7173, 0x7810, 0x2070, 0x7037, 0x0103, 0x2f60, + 0x080c, 0x861d, 0x00ee, 0x00ce, 0x00de, 0x00fe, 0x001e, 0x0005, + 0x00fe, 0x00d6, 0x2069, 0x0140, 0x6804, 0xa084, 0x4000, 0x0120, + 0x6803, 0x1000, 0x6803, 0x0000, 0x00de, 0x00c6, 0x2061, 0xb7e0, + 0x6028, 0xa09a, 0x00c8, 0x1238, 0x8000, 0x602a, 0x00ce, 0x080c, + 0x7d6d, 0x0804, 0x2765, 0x2019, 0xb7e9, 0x2304, 0xa065, 0x0120, + 0x2009, 0x0027, 0x080c, 0x864c, 0x00ce, 0x0804, 0x2765, 0xd2bc, + 0x0904, 0x2765, 0x080c, 0x6a1d, 0x6014, 0xa084, 0x0184, 0xa085, + 0x0010, 0x6016, 0x6027, 0x0004, 0x00d6, 0x2069, 0x0140, 0x6804, + 0xa084, 0x4000, 0x0120, 0x6803, 0x1000, 0x6803, 0x0000, 0x00de, + 0x00c6, 0x2061, 0xb7e0, 0x6044, 0xa09a, 0x00c8, 0x12f0, 0x8000, + 0x6046, 0x603c, 0x00ce, 0xa005, 0x0540, 0x2009, 0x07d0, 0x080c, + 0x6a15, 0xa080, 0x0007, 0x2004, 0xa086, 0x0006, 0x1138, 0x6114, + 0xa18c, 0x0184, 0xa18d, 0x0012, 0x6116, 0x00b8, 0x6114, 0xa18c, + 0x0184, 0xa18d, 0x0016, 0x6116, 0x0080, 0x0036, 0x2019, 0x0001, + 0x080c, 0x7fe4, 0x003e, 0x2019, 0xb7ef, 0x2304, 0xa065, 0x0120, + 0x2009, 0x004f, 0x080c, 0x864c, 0x00ce, 0x001e, 0xd19c, 0x0904, + 0x27bf, 0x7034, 0xd0ac, 0x1560, 0x0016, 0x0156, 0x6027, 0x0008, + 0x602f, 0x0020, 0x20a9, 0x0006, 0x1d04, 0x2774, 0x2091, 0x6000, + 0x1f04, 0x2774, 0x602f, 0x0000, 0x6150, 0xa185, 0x1400, 0x6052, + 0x20a9, 0x0366, 0x1d04, 0x2782, 0x2091, 0x6000, 0x6020, 0xd09c, + 0x1130, 0x015e, 0x6152, 0x001e, 0x6027, 0x0008, 0x0480, 0x080c, + 0x2907, 0x1f04, 0x2782, 0x015e, 0x6152, 0x001e, 0x6027, 0x0008, + 0x0016, 0x6028, 0xc09c, 0x602a, 0x2011, 0x0003, 0x080c, 0x8075, + 0x2011, 0x0002, 0x080c, 0x807f, 0x080c, 0x7f59, 0x0036, 0x2019, + 0x0000, 0x080c, 0x7fe4, 0x003e, 0x60e3, 0x0000, 0x080c, 0xb42f, + 0x080c, 0xb44a, 0xa085, 0x0001, 0x080c, 0x5b13, 0x2001, 0xb500, + 0x2003, 0x0004, 0x6027, 0x0008, 0x080c, 0x12dd, 0x001e, 0xa18c, + 0xffd0, 0x6126, 0x0005, 0x0006, 0x0016, 0x0026, 0x00e6, 0x00f6, + 0x0126, 0x2091, 0x8000, 0x2071, 0xb500, 0x71c4, 0x70c6, 0xa116, + 0x0500, 0x81ff, 0x0128, 0x2011, 0x8011, 0x080c, 0x3ecc, 0x00c8, + 0x2011, 0x8012, 0x080c, 0x3ecc, 0x2001, 0xb572, 0x2004, 0xd0fc, + 0x1180, 0x0036, 0x00c6, 0x080c, 0x2892, 0x080c, 0x7f35, 0x2061, + 0x0100, 0x2019, 0x0028, 0x2009, 0x0000, 0x080c, 0x2c6f, 0x00ce, + 0x003e, 0x012e, 0x00fe, 0x00ee, 0x002e, 0x001e, 0x000e, 0x0005, + 0x00c6, 0x00f6, 0x0006, 0x0026, 0x2061, 0x0100, 0xa190, 0x280b, + 0x2205, 0x60f2, 0x2011, 0x2818, 0x2205, 0x60ee, 0x002e, 0x000e, + 0x00fe, 0x00ce, 0x0005, 0x0840, 0x0840, 0x0840, 0x0580, 0x0420, + 0x0348, 0x02c0, 0x0258, 0x0210, 0x01a8, 0x01a8, 0x01a8, 0x01a8, + 0x0140, 0x00f8, 0x00d0, 0x00b0, 0x00a0, 0x2028, 0xa18c, 0x00ff, + 0x2130, 0xa094, 0xff00, 0x1110, 0x81ff, 0x0118, 0x080c, 0x66b1, + 0x0038, 0xa080, 0x2dc4, 0x200d, 0xa18c, 0xff00, 0x810f, 0xa006, + 0x0005, 0xa080, 0x2dc4, 0x200d, 0xa18c, 0x00ff, 0x0005, 0x00d6, + 0x2069, 0x0140, 0x2001, 0xb515, 0x2003, 0x00ef, 0x20a9, 0x0010, + 0xa006, 0x6852, 0x6856, 0x1f04, 0x2842, 0x00de, 0x0005, 0x0006, + 0x00d6, 0x0026, 0x2069, 0x0140, 0x2001, 0xb515, 0x2102, 0x8114, + 0x8214, 0x8214, 0x8214, 0x20a9, 0x0010, 0x6853, 0x0000, 0xa006, + 0x82ff, 0x1128, 0xa184, 0x000f, 0xa080, 0xb45e, 0x2005, 0x6856, + 0x8211, 0x1f04, 0x2857, 0x002e, 0x00de, 0x000e, 0x0005, 0x00c6, + 0x2061, 0xb500, 0x6030, 0x0110, 0xc09d, 0x0008, 0xc09c, 0x6032, + 0x00ce, 0x0005, 0x0156, 0x00d6, 0x0026, 0x0016, 0x0006, 0x2069, + 0x0140, 0x6980, 0xa116, 0x0180, 0xa112, 0x1230, 0x8212, 0x8210, + 0x22a8, 0x2001, 0x0402, 0x0018, 0x22a8, 0x2001, 0x0404, 0x680e, + 0x1f04, 0x2887, 0x680f, 0x0000, 0x000e, 0x001e, 0x002e, 0x00de, + 0x015e, 0x0005, 0x2001, 0xb553, 0x2004, 0xd0c4, 0x0150, 0xd0a4, + 0x0140, 0xa006, 0x0046, 0x2020, 0x2009, 0x002e, 0x080c, 0xb0e8, + 0x004e, 0x0005, 0x00f6, 0x0016, 0x0026, 0x2079, 0x0140, 0x78c4, + 0xd0dc, 0x0548, 0xa084, 0x0700, 0xa08e, 0x0300, 0x1520, 0x2011, + 0x0000, 0x2009, 0x0002, 0x2300, 0xa080, 0x0020, 0x2018, 0x2300, + 0x080c, 0x6b40, 0x2011, 0x0030, 0x2200, 0x8007, 0xa085, 0x004c, + 0x78c2, 0x2009, 0x0204, 0x210c, 0x2200, 0xa100, 0x2009, 0x0138, + 0x200a, 0x080c, 0x5acf, 0x1118, 0x2009, 0xb78f, 0x200a, 0x002e, + 0x001e, 0x00fe, 0x0005, 0x78c3, 0x0000, 0x0cc8, 0x0126, 0x2091, + 0x2800, 0x0006, 0x0016, 0x0026, 0x2001, 0x0170, 0x200c, 0x8000, + 0x2014, 0xa184, 0x0003, 0x0110, 0x0804, 0x1b04, 0x002e, 0x001e, + 0x000e, 0x012e, 0x0005, 0x0006, 0x2001, 0x0100, 0x2004, 0xa082, + 0x0005, 0x000e, 0x0268, 0x2001, 0x0170, 0x200c, 0xa18c, 0x00ff, + 0xa18e, 0x004c, 0x1128, 0x200c, 0xa18c, 0xff00, 0x810f, 0x0010, + 0x2009, 0x0000, 0x2001, 0x0204, 0x2004, 0xa108, 0x0005, 0x0006, + 0x0156, 0x00f6, 0x2079, 0x0100, 0x20a9, 0x000a, 0x7854, 0xd08c, + 0x1110, 0x1f04, 0x290e, 0x00fe, 0x015e, 0x000e, 0x0005, 0x0016, + 0x00c6, 0x0006, 0x2061, 0x0100, 0x6030, 0x0006, 0x6048, 0x0006, + 0x60e4, 0x0006, 0x60e8, 0x0006, 0x6050, 0x0006, 0x60f0, 0x0006, + 0x60ec, 0x0006, 0x600c, 0x0006, 0x6004, 0x0006, 0x6028, 0x0006, + 0x60e0, 0x0006, 0x602f, 0x0100, 0x602f, 0x0000, 0xe000, 0xe000, + 0xe000, 0xe000, 0x602f, 0x0040, 0x602f, 0x0000, 0x000e, 0x60e2, + 0x000e, 0x602a, 0x000e, 0x6006, 0x000e, 0x600e, 0x000e, 0x60ee, + 0x000e, 0x60f2, 0x000e, 0x6052, 0x000e, 0x60ea, 0x000e, 0x60e6, + 0x000e, 0x604a, 0x000e, 0x6032, 0x6036, 0x2008, 0x080c, 0x2847, + 0x000e, 0x00ce, 0x001e, 0x0005, 0x2009, 0x0171, 0x2104, 0xd0dc, + 0x0140, 0x2009, 0x0170, 0x2104, 0x200b, 0x0080, 0xe000, 0xe000, + 0x200a, 0x0005, 0x29fa, 0x29fe, 0x2a02, 0x2a08, 0x2a0e, 0x2a14, + 0x2a1a, 0x2a22, 0x2a2a, 0x2a30, 0x2a36, 0x2a3e, 0x2a46, 0x2a4e, + 0x2a56, 0x2a60, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, + 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, + 0x2aad, 0x2aad, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, + 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, + 0x2a6a, 0x2a6a, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, + 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, + 0x2aad, 0x2aad, 0x2a6c, 0x2a6c, 0x2a72, 0x2a72, 0x2a79, 0x2a79, + 0x2a80, 0x2a80, 0x2a89, 0x2a89, 0x2a90, 0x2a90, 0x2a99, 0x2a99, + 0x2aa2, 0x2aa2, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, + 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, + 0x2aad, 0x2aad, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, + 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, + 0x2a6a, 0x2a6a, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, + 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, + 0x2aad, 0x2aad, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, + 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, + 0x2a6a, 0x2a6a, 0x0106, 0x0006, 0x0804, 0x2ab5, 0x0106, 0x0006, + 0x0804, 0x2ab5, 0x0106, 0x0006, 0x080c, 0x2519, 0x0804, 0x2ab5, + 0x0106, 0x0006, 0x080c, 0x2519, 0x0804, 0x2ab5, 0x0106, 0x0006, + 0x080c, 0x239c, 0x0804, 0x2ab5, 0x0106, 0x0006, 0x080c, 0x239c, + 0x0804, 0x2ab5, 0x0106, 0x0006, 0x080c, 0x2519, 0x080c, 0x239c, + 0x0804, 0x2ab5, 0x0106, 0x0006, 0x080c, 0x2519, 0x080c, 0x239c, + 0x0804, 0x2ab5, 0x0106, 0x0006, 0x080c, 0x23f2, 0x0804, 0x2ab5, + 0x0106, 0x0006, 0x080c, 0x23f2, 0x0804, 0x2ab5, 0x0106, 0x0006, + 0x080c, 0x2519, 0x080c, 0x23f2, 0x0804, 0x2ab5, 0x0106, 0x0006, + 0x080c, 0x2519, 0x080c, 0x23f2, 0x0804, 0x2ab5, 0x0106, 0x0006, + 0x080c, 0x239c, 0x080c, 0x23f2, 0x0804, 0x2ab5, 0x0106, 0x0006, + 0x080c, 0x239c, 0x080c, 0x23f2, 0x0804, 0x2ab5, 0x0106, 0x0006, + 0x080c, 0x2519, 0x080c, 0x239c, 0x080c, 0x23f2, 0x0804, 0x2ab5, + 0x0106, 0x0006, 0x080c, 0x2519, 0x080c, 0x239c, 0x080c, 0x23f2, + 0x0804, 0x2ab5, 0xe000, 0x0cf0, 0x0106, 0x0006, 0x080c, 0x28d6, + 0x0804, 0x2ab5, 0x0106, 0x0006, 0x080c, 0x28d6, 0x080c, 0x2519, + 0x04e0, 0x0106, 0x0006, 0x080c, 0x28d6, 0x080c, 0x239c, 0x04a8, + 0x0106, 0x0006, 0x080c, 0x28d6, 0x080c, 0x2519, 0x080c, 0x239c, + 0x0460, 0x0106, 0x0006, 0x080c, 0x28d6, 0x080c, 0x23f2, 0x0428, + 0x0106, 0x0006, 0x080c, 0x28d6, 0x080c, 0x2519, 0x080c, 0x23f2, + 0x00e0, 0x0106, 0x0006, 0x080c, 0x28d6, 0x080c, 0x239c, 0x080c, + 0x23f2, 0x0098, 0x0106, 0x0006, 0x080c, 0x28d6, 0x080c, 0x2519, + 0x080c, 0x239c, 0x080c, 0x23f2, 0x0040, 0x20d1, 0x0000, 0x20d1, + 0x0001, 0x20d1, 0x0000, 0x080c, 0x1515, 0x000e, 0x010e, 0x000d, + 0x00c6, 0x0026, 0x0046, 0x2021, 0x0000, 0x080c, 0x5309, 0x1904, + 0x2b95, 0x72d4, 0x2001, 0xb79e, 0x2004, 0xa005, 0x1110, 0xd29c, + 0x0148, 0xd284, 0x1138, 0xd2bc, 0x1904, 0x2b95, 0x080c, 0x2b99, + 0x0804, 0x2b95, 0xd2cc, 0x1904, 0x2b95, 0x080c, 0x5acf, 0x1120, + 0x709f, 0xffff, 0x0804, 0x2b95, 0xd294, 0x0120, 0x709f, 0xffff, + 0x0804, 0x2b95, 0x2001, 0xb515, 0x203c, 0x7288, 0xd284, 0x0904, + 0x2b37, 0xd28c, 0x1904, 0x2b37, 0x0036, 0x739c, 0xa38e, 0xffff, + 0x1110, 0x2019, 0x0001, 0x8314, 0xa2e0, 0xbcc0, 0x2c04, 0xa38c, + 0x0001, 0x0120, 0xa084, 0xff00, 0x8007, 0x0010, 0xa084, 0x00ff, + 0xa70e, 0x0560, 0xa08e, 0x0000, 0x0548, 0xa08e, 0x00ff, 0x1150, + 0x7230, 0xd284, 0x1538, 0x7288, 0xc28d, 0x728a, 0x709f, 0xffff, + 0x003e, 0x0428, 0x2009, 0x0000, 0x080c, 0x281d, 0x080c, 0x4f4d, + 0x11b8, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x1150, 0x7030, + 0xd08c, 0x0118, 0x6000, 0xd0bc, 0x0120, 0x080c, 0x2bac, 0x0140, + 0x0028, 0x080c, 0x2cdd, 0x080c, 0x2bda, 0x0110, 0x8318, 0x0818, + 0x739e, 0x0010, 0x709f, 0xffff, 0x003e, 0x0804, 0x2b95, 0xa780, + 0x2dc4, 0x203d, 0xa7bc, 0xff00, 0x873f, 0x2041, 0x007e, 0x709c, + 0xa096, 0xffff, 0x1120, 0x2009, 0x0000, 0x28a8, 0x0050, 0xa812, + 0x0220, 0x2008, 0xa802, 0x20a8, 0x0020, 0x709f, 0xffff, 0x0804, + 0x2b95, 0x2700, 0x0156, 0x0016, 0xa106, 0x05a0, 0xc484, 0x080c, + 0x4fa9, 0x0120, 0x080c, 0x4f4d, 0x15a8, 0x0008, 0xc485, 0x6004, + 0xa084, 0x00ff, 0xa086, 0x0006, 0x1130, 0x7030, 0xd08c, 0x01e8, + 0x6000, 0xd0bc, 0x11d0, 0x7288, 0xd28c, 0x0188, 0x6004, 0xa084, + 0x00ff, 0xa082, 0x0006, 0x02b0, 0xd484, 0x1118, 0x080c, 0x4f6c, + 0x0028, 0x080c, 0x2d6a, 0x0170, 0x080c, 0x2d97, 0x0058, 0x080c, + 0x2cdd, 0x080c, 0x2bda, 0x0170, 0x0028, 0x080c, 0x2d6a, 0x0110, + 0x0419, 0x0140, 0x001e, 0x8108, 0x015e, 0x1f04, 0x2b51, 0x709f, + 0xffff, 0x0018, 0x001e, 0x015e, 0x719e, 0x004e, 0x002e, 0x00ce, + 0x0005, 0x00c6, 0x0016, 0x709f, 0x0001, 0x2009, 0x007e, 0x080c, + 0x4f4d, 0x1138, 0x080c, 0x2cdd, 0x04a9, 0x0118, 0x70d4, 0xc0bd, + 0x70d6, 0x001e, 0x00ce, 0x0005, 0x0016, 0x0076, 0x00d6, 0x00c6, + 0x2c68, 0x2001, 0xb557, 0x2004, 0xa084, 0x00ff, 0x6842, 0x080c, + 0x9ed6, 0x01d8, 0x2d00, 0x601a, 0x080c, 0xa027, 0x601f, 0x0001, + 0x2001, 0x0000, 0x080c, 0x4eeb, 0x2001, 0x0000, 0x080c, 0x4efd, + 0x0126, 0x2091, 0x8000, 0x7098, 0x8000, 0x709a, 0x012e, 0x2009, + 0x0004, 0x080c, 0x864c, 0xa085, 0x0001, 0x00ce, 0x00de, 0x007e, + 0x001e, 0x0005, 0x0016, 0x0076, 0x00d6, 0x00c6, 0x2c68, 0x2001, + 0xb557, 0x2004, 0xa084, 0x00ff, 0x6842, 0x080c, 0x9ed6, 0x0550, + 0x2d00, 0x601a, 0x6800, 0xc0c4, 0x6802, 0x68a0, 0xa086, 0x007e, + 0x0140, 0x6804, 0xa084, 0x00ff, 0xa086, 0x0006, 0x1110, 0x080c, + 0x2c9c, 0x080c, 0xa027, 0x601f, 0x0001, 0x2001, 0x0000, 0x080c, + 0x4eeb, 0x2001, 0x0002, 0x080c, 0x4efd, 0x0126, 0x2091, 0x8000, + 0x7098, 0x8000, 0x709a, 0x012e, 0x2009, 0x0002, 0x080c, 0x864c, + 0xa085, 0x0001, 0x00ce, 0x00de, 0x007e, 0x001e, 0x0005, 0x00c6, + 0x0026, 0x2009, 0x0080, 0x080c, 0x4f4d, 0x1120, 0x0031, 0x0110, + 0x70db, 0xffff, 0x002e, 0x00ce, 0x0005, 0x0016, 0x0076, 0x00d6, + 0x00c6, 0x2c68, 0x080c, 0x85c7, 0x01e8, 0x2d00, 0x601a, 0x080c, + 0xa027, 0x601f, 0x0001, 0x2001, 0x0000, 0x080c, 0x4eeb, 0x2001, + 0x0002, 0x080c, 0x4efd, 0x0126, 0x2091, 0x8000, 0x080c, 0x2c9c, + 0x70dc, 0x8000, 0x70de, 0x012e, 0x2009, 0x0002, 0x080c, 0x864c, + 0xa085, 0x0001, 0x00ce, 0x00de, 0x007e, 0x001e, 0x0005, 0x00c6, + 0x00d6, 0x0126, 0x2091, 0x8000, 0x2009, 0x007f, 0x080c, 0x4f4d, + 0x1190, 0x2c68, 0x080c, 0x85c7, 0x0170, 0x2d00, 0x601a, 0x6312, + 0x601f, 0x0001, 0x620a, 0x080c, 0xa027, 0x2009, 0x0022, 0x080c, + 0x864c, 0xa085, 0x0001, 0x012e, 0x00de, 0x00ce, 0x0005, 0x00e6, + 0x00c6, 0x0066, 0x0036, 0x0026, 0x080c, 0x6e01, 0x080c, 0x6da4, + 0x080c, 0x906f, 0x2130, 0x81ff, 0x0128, 0x20a9, 0x007e, 0x2009, + 0x0000, 0x0020, 0x20a9, 0x007f, 0x2009, 0x0000, 0x0016, 0x080c, + 0x4fa9, 0x1120, 0x080c, 0x51aa, 0x080c, 0x4c0b, 0x001e, 0x8108, + 0x1f04, 0x2c86, 0x86ff, 0x1110, 0x080c, 0x11f0, 0x002e, 0x003e, + 0x006e, 0x00ce, 0x00ee, 0x0005, 0x00e6, 0x00c6, 0x0036, 0x0026, + 0x0016, 0x6218, 0x2270, 0x72a0, 0x0026, 0x2019, 0x0029, 0x080c, + 0x6df5, 0x0076, 0x2039, 0x0000, 0x080c, 0x6d02, 0x2c08, 0x080c, + 0xae82, 0x007e, 0x001e, 0x2e60, 0x080c, 0x51aa, 0x6210, 0x6314, + 0x080c, 0x4c0b, 0x6212, 0x6316, 0x001e, 0x002e, 0x003e, 0x00ce, + 0x00ee, 0x0005, 0x00e6, 0x0006, 0x6018, 0xa080, 0x0028, 0x2004, + 0xa086, 0x0080, 0x0150, 0x2071, 0xb500, 0x7098, 0xa005, 0x0110, + 0x8001, 0x709a, 0x000e, 0x00ee, 0x0005, 0x2071, 0xb500, 0x70dc, + 0xa005, 0x0dc0, 0x8001, 0x70de, 0x0ca8, 0x6000, 0xc08c, 0x6002, + 0x0005, 0x00f6, 0x00e6, 0x00c6, 0x0036, 0x0026, 0x0016, 0x0156, + 0x2178, 0x81ff, 0x1118, 0x20a9, 0x0001, 0x0098, 0x2001, 0xb553, + 0x2004, 0xd0c4, 0x0150, 0xd0a4, 0x0140, 0xa006, 0x0046, 0x2020, + 0x2009, 0x002d, 0x080c, 0xb0e8, 0x004e, 0x20a9, 0x00ff, 0x2011, + 0x0000, 0x0026, 0xa28e, 0x007e, 0x0904, 0x2d49, 0xa28e, 0x007f, + 0x0904, 0x2d49, 0xa28e, 0x0080, 0x05e0, 0xa288, 0xb635, 0x210c, + 0x81ff, 0x05b8, 0x8fff, 0x1148, 0x2001, 0xb7be, 0x0006, 0x2003, + 0x0001, 0x04d9, 0x000e, 0x2003, 0x0000, 0x00c6, 0x2160, 0x2001, + 0x0001, 0x080c, 0x5313, 0x00ce, 0x2019, 0x0029, 0x080c, 0x6df5, + 0x0076, 0x2039, 0x0000, 0x080c, 0x6d02, 0x00c6, 0x0026, 0x2160, + 0x6204, 0xa294, 0x00ff, 0xa286, 0x0006, 0x1118, 0x6007, 0x0404, + 0x0028, 0x2001, 0x0004, 0x8007, 0xa215, 0x6206, 0x002e, 0x00ce, + 0x0016, 0x2c08, 0x080c, 0xae82, 0x001e, 0x007e, 0x2160, 0x080c, + 0x51aa, 0x002e, 0x8210, 0x1f04, 0x2d01, 0x015e, 0x001e, 0x002e, + 0x003e, 0x00ce, 0x00ee, 0x00fe, 0x0005, 0x0046, 0x0026, 0x0016, + 0x2001, 0xb553, 0x2004, 0xd0c4, 0x0148, 0xd0a4, 0x0138, 0xa006, + 0x2220, 0x8427, 0x2009, 0x0029, 0x080c, 0xb0e8, 0x001e, 0x002e, + 0x004e, 0x0005, 0x0016, 0x0026, 0x0036, 0x00c6, 0x7288, 0x82ff, + 0x01f8, 0x2011, 0xb553, 0x2214, 0xd2ac, 0x11d0, 0x2100, 0x080c, + 0x2831, 0x81ff, 0x01b8, 0x2019, 0x0001, 0x8314, 0xa2e0, 0xbcc0, + 0x2c04, 0xd384, 0x0120, 0xa084, 0xff00, 0x8007, 0x0010, 0xa084, + 0x00ff, 0xa116, 0x0138, 0xa096, 0x00ff, 0x0110, 0x8318, 0x0c68, + 0xa085, 0x0001, 0x00ce, 0x003e, 0x002e, 0x001e, 0x0005, 0x0016, + 0x00c6, 0x0126, 0x2091, 0x8000, 0x0016, 0x0026, 0x0036, 0x2110, + 0x0026, 0x2019, 0x0029, 0x080c, 0x8299, 0x002e, 0x080c, 0xb38d, + 0x003e, 0x002e, 0x001e, 0xa180, 0xb635, 0x2004, 0xa065, 0x0158, + 0x0016, 0x00c6, 0x2061, 0xb8f4, 0x001e, 0x611a, 0x080c, 0x2c9c, + 0x001e, 0x080c, 0x4f6c, 0x012e, 0x00ce, 0x001e, 0x0005, 0x2001, + 0xb535, 0x2004, 0xd0cc, 0x0005, 0x7eef, 0x7de8, 0x7ce4, 0x80e2, + 0x7be1, 0x80e0, 0x80dc, 0x80da, 0x7ad9, 0x80d6, 0x80d5, 0x80d4, + 0x80d3, 0x80d2, 0x80d1, 0x79ce, 0x78cd, 0x80cc, 0x80cb, 0x80ca, + 0x80c9, 0x80c7, 0x80c6, 0x77c5, 0x76c3, 0x80bc, 0x80ba, 0x75b9, + 0x80b6, 0x74b5, 0x73b4, 0x72b3, 0x80b2, 0x80b1, 0x80ae, 0x71ad, + 0x80ac, 0x70ab, 0x6faa, 0x6ea9, 0x80a7, 0x6da6, 0x6ca5, 0x6ba3, + 0x6a9f, 0x699e, 0x689d, 0x809b, 0x8098, 0x6797, 0x6690, 0x658f, + 0x6488, 0x6384, 0x6282, 0x8081, 0x8080, 0x617c, 0x607a, 0x8079, + 0x5f76, 0x8075, 0x8074, 0x8073, 0x8072, 0x8071, 0x806e, 0x5e6d, + 0x806c, 0x5d6b, 0x5c6a, 0x5b69, 0x8067, 0x5a66, 0x5965, 0x5863, + 0x575c, 0x565a, 0x5559, 0x8056, 0x8055, 0x5454, 0x5353, 0x5252, + 0x5151, 0x504e, 0x4f4d, 0x804c, 0x804b, 0x4e4a, 0x4d49, 0x8047, + 0x4c46, 0x8045, 0x8043, 0x803c, 0x803a, 0x8039, 0x8036, 0x4b35, + 0x8034, 0x4a33, 0x4932, 0x4831, 0x802e, 0x472d, 0x462c, 0x452b, + 0x442a, 0x4329, 0x4227, 0x8026, 0x8025, 0x4123, 0x401f, 0x3f1e, + 0x3e1d, 0x3d1b, 0x3c18, 0x8017, 0x8010, 0x3b0f, 0x3a08, 0x8004, + 0x3902, 0x8001, 0x8000, 0x8000, 0x3800, 0x3700, 0x3600, 0x8000, + 0x3500, 0x8000, 0x8000, 0x8000, 0x3400, 0x8000, 0x8000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x3300, 0x3200, 0x8000, 0x8000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x3100, 0x3000, 0x8000, 0x8000, 0x2f00, + 0x8000, 0x2e00, 0x2d00, 0x2c00, 0x8000, 0x8000, 0x8000, 0x2b00, + 0x8000, 0x2a00, 0x2900, 0x2800, 0x8000, 0x2700, 0x2600, 0x2500, + 0x2400, 0x2300, 0x2200, 0x8000, 0x8000, 0x2100, 0x2000, 0x1f00, + 0x1e00, 0x1d00, 0x1c00, 0x8000, 0x8000, 0x1b00, 0x1a00, 0x8000, + 0x1900, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x1800, + 0x8000, 0x1700, 0x1600, 0x1500, 0x8000, 0x1400, 0x1300, 0x1200, + 0x1100, 0x1000, 0x0f00, 0x8000, 0x8000, 0x0e00, 0x0d00, 0x0c00, + 0x0b00, 0x0a00, 0x0900, 0x8000, 0x8000, 0x0800, 0x0700, 0x8000, + 0x0600, 0x8000, 0x8000, 0x8000, 0x0500, 0x0400, 0x0300, 0x8000, + 0x0200, 0x8000, 0x8000, 0x8000, 0x0100, 0x8000, 0x8000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x0000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x8000, 0x2071, 0xb582, 0x7003, 0x0002, + 0xa006, 0x7012, 0x7016, 0x703a, 0x703e, 0x7033, 0xb592, 0x7037, + 0xb592, 0x7007, 0x0001, 0x2061, 0xb5d2, 0x6003, 0x0002, 0x0005, + 0x1004, 0x2eea, 0x0e04, 0x2eea, 0x2071, 0xb582, 0x2b78, 0x7818, + 0xd084, 0x1140, 0x2a60, 0x7820, 0xa08e, 0x0069, 0x1904, 0x2fcf, + 0x0804, 0x2f68, 0x0005, 0x2071, 0xb582, 0x7004, 0x0002, 0x2ef3, + 0x2ef4, 0x2efd, 0x2f0e, 0x0005, 0x1004, 0x2efc, 0x0e04, 0x2efc, + 0x2b78, 0x7818, 0xd084, 0x01e8, 0x0005, 0x2b78, 0x2061, 0xb5d2, + 0x6008, 0xa08e, 0x0100, 0x0128, 0xa086, 0x0200, 0x0904, 0x2fc9, + 0x0005, 0x7014, 0x2068, 0x2a60, 0x7018, 0x0807, 0x7010, 0x2068, + 0x6834, 0xa086, 0x0103, 0x0108, 0x0005, 0x2a60, 0x2b78, 0x7018, + 0x0807, 0x2a60, 0x7820, 0xa08a, 0x0040, 0x1210, 0x61c4, 0x0042, + 0x2100, 0xa08a, 0x003f, 0x1a04, 0x2fc6, 0x61c4, 0x0804, 0x2f68, + 0x2faa, 0x2fd5, 0x2fdd, 0x2fe1, 0x2fe9, 0x2fef, 0x2ff3, 0x2fff, + 0x3002, 0x300c, 0x300f, 0x2fc6, 0x2fc6, 0x2fc6, 0x3012, 0x2fc6, + 0x3021, 0x3038, 0x304f, 0x30c9, 0x30ce, 0x30f7, 0x3148, 0x3159, + 0x3178, 0x31b0, 0x31ba, 0x31c7, 0x31da, 0x31fb, 0x3204, 0x323a, + 0x3240, 0x2fc6, 0x3269, 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6, + 0x3270, 0x327a, 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6, + 0x2fc6, 0x2fc6, 0x3282, 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6, + 0x3294, 0x329e, 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6, + 0x0002, 0x32c8, 0x331c, 0x3377, 0x3391, 0x2fc6, 0x33c2, 0x37f5, + 0x4233, 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6, + 0x2fc6, 0x300c, 0x300f, 0x37f7, 0x2fc6, 0x3804, 0x42cc, 0x4327, + 0x438b, 0x2fc6, 0x43ee, 0x4418, 0x4437, 0x4469, 0x2fc6, 0x2fc6, + 0x2fc6, 0x3808, 0x39ad, 0x39c7, 0x39e5, 0x3a46, 0x3aa6, 0x3ab1, + 0x3ae9, 0x3af8, 0x3b07, 0x3b0a, 0x3b2d, 0x3b79, 0x3bef, 0x3bfc, + 0x3cfd, 0x3e23, 0x3e4c, 0x3f4a, 0x3f6c, 0x3f78, 0x3fb1, 0x4075, + 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6, 0x40dd, 0x40f8, 0x416a, 0x421c, + 0x713c, 0x0000, 0x2021, 0x4000, 0x080c, 0x3ea9, 0x0126, 0x2091, + 0x8000, 0x0e04, 0x2fb6, 0x7818, 0xd084, 0x0110, 0x012e, 0x0cb0, + 0x7c22, 0x7926, 0x7a2a, 0x7b2e, 0x781b, 0x0001, 0x2091, 0x4080, + 0x7007, 0x0001, 0x2091, 0x5000, 0x012e, 0x0005, 0x2021, 0x4001, + 0x0c18, 0x2021, 0x4002, 0x0c00, 0x2021, 0x4003, 0x08e8, 0x2021, + 0x4005, 0x08d0, 0x2021, 0x4006, 0x08b8, 0xa02e, 0x2520, 0x7b28, + 0x7a2c, 0x7824, 0x7930, 0x0804, 0x3eb6, 0x7823, 0x0004, 0x7824, + 0x0807, 0xa02e, 0x2520, 0x7b28, 0x7a2c, 0x7824, 0x7930, 0x0804, + 0x3eb9, 0x7924, 0x7828, 0x2114, 0x200a, 0x0804, 0x2faa, 0x7924, + 0x2114, 0x0804, 0x2faa, 0x2099, 0x0009, 0x20a1, 0x0009, 0x20a9, + 0x0007, 0x53a3, 0x7924, 0x7a28, 0x7b2c, 0x0804, 0x2faa, 0x7824, + 0x2060, 0x0090, 0x2009, 0x0002, 0x2011, 0x0002, 0x2019, 0x0006, + 0x783b, 0x0017, 0x0804, 0x2faa, 0x7d38, 0x7c3c, 0x0840, 0x7d38, + 0x7c3c, 0x0888, 0x2061, 0x1000, 0xe10c, 0xa006, 0x2c15, 0xa200, + 0x8c60, 0x8109, 0x1dd8, 0x2010, 0xa005, 0x0904, 0x2faa, 0x0804, + 0x2fcc, 0x2069, 0xb552, 0x7824, 0x7930, 0xa11a, 0x1a04, 0x2fd2, + 0x8019, 0x0904, 0x2fd2, 0x684a, 0x6942, 0x782c, 0x6852, 0x7828, + 0x6856, 0xa006, 0x685a, 0x685e, 0x080c, 0x5da5, 0x0804, 0x2faa, + 0x2069, 0xb552, 0x7824, 0x7934, 0xa11a, 0x1a04, 0x2fd2, 0x8019, + 0x0904, 0x2fd2, 0x684e, 0x6946, 0x782c, 0x6862, 0x7828, 0x6866, + 0xa006, 0x686a, 0x686e, 0x080c, 0x53d5, 0x0804, 0x2faa, 0xa02e, + 0x2520, 0x81ff, 0x1904, 0x2fcf, 0x7924, 0x7b28, 0x7a2c, 0x20a9, + 0x0005, 0x20a1, 0xb589, 0x41a1, 0x080c, 0x3e75, 0x0904, 0x2fcf, + 0x2009, 0x0020, 0x080c, 0x3eb6, 0x701b, 0x3067, 0x0005, 0x6834, + 0x2008, 0xa084, 0x00ff, 0xa096, 0x0011, 0x0138, 0xa096, 0x0019, + 0x0120, 0xa096, 0x0015, 0x1904, 0x2fcf, 0x810f, 0xa18c, 0x00ff, + 0x0904, 0x2fcf, 0x710e, 0x700c, 0x8001, 0x0528, 0x700e, 0x080c, + 0x3e75, 0x0904, 0x2fcf, 0x2009, 0x0020, 0x2061, 0xb5d2, 0x6224, + 0x6328, 0x642c, 0x6530, 0xa290, 0x0040, 0xa399, 0x0000, 0xa4a1, + 0x0000, 0xa5a9, 0x0000, 0x080c, 0x3eb6, 0x701b, 0x3098, 0x0005, + 0x6834, 0xa084, 0x00ff, 0xa096, 0x0002, 0x0120, 0xa096, 0x000a, + 0x1904, 0x2fcf, 0x08c0, 0x7010, 0x2068, 0x6838, 0xc0fd, 0x683a, + 0x080c, 0x4e49, 0x1128, 0x7007, 0x0003, 0x701b, 0x30b2, 0x0005, + 0x080c, 0x54db, 0x0126, 0x2091, 0x8000, 0x20a9, 0x0005, 0x2099, + 0xb589, 0x530a, 0x2100, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, + 0xa5a9, 0x0000, 0xad80, 0x000d, 0x2009, 0x0020, 0x012e, 0x0804, + 0x3eb9, 0x61ac, 0x7824, 0x60ae, 0x0804, 0x2faa, 0x2091, 0x8000, + 0x7823, 0x4000, 0x7827, 0x4953, 0x782b, 0x5020, 0x782f, 0x2020, + 0x2009, 0x017f, 0x2104, 0x7832, 0x3f00, 0x7836, 0x2061, 0x0100, + 0x6200, 0x2061, 0x0200, 0x603c, 0x8007, 0xa205, 0x783a, 0x2009, + 0x04fd, 0x2104, 0x783e, 0x781b, 0x0001, 0x2091, 0x5000, 0x2091, + 0x4080, 0x2071, 0x0010, 0x20c1, 0x00f0, 0x0804, 0x0427, 0x81ff, + 0x1904, 0x2fcf, 0x7924, 0x810f, 0xa18c, 0x00ff, 0x080c, 0x4fa9, + 0x1904, 0x2fd2, 0x7e38, 0xa684, 0x3fff, 0xa082, 0x4000, 0x0210, + 0x0804, 0x2fd2, 0x7c28, 0x7d2c, 0x080c, 0x5171, 0xd28c, 0x1118, + 0x080c, 0x511a, 0x0010, 0x080c, 0x514a, 0x1518, 0x2061, 0xbd00, + 0x0126, 0x2091, 0x8000, 0x6000, 0xa086, 0x0000, 0x0148, 0x6010, + 0xa06d, 0x0130, 0x683c, 0xa406, 0x1118, 0x6840, 0xa506, 0x0150, + 0x012e, 0xace0, 0x0018, 0x2001, 0xb517, 0x2004, 0xac02, 0x1a04, + 0x2fcf, 0x0c30, 0x080c, 0x992a, 0x012e, 0x0904, 0x2fcf, 0x0804, + 0x2faa, 0xa00e, 0x2001, 0x0005, 0x080c, 0x54db, 0x0126, 0x2091, + 0x8000, 0x080c, 0x9ed2, 0x080c, 0x5408, 0x012e, 0x0804, 0x2faa, + 0x81ff, 0x1904, 0x2fcf, 0x080c, 0x3e8a, 0x0904, 0x2fd2, 0x080c, + 0x506f, 0x0904, 0x2fcf, 0x080c, 0x517d, 0x0904, 0x2fcf, 0x0804, + 0x2faa, 0x81ff, 0x1904, 0x2fcf, 0x080c, 0x3e9a, 0x0904, 0x2fd2, + 0x080c, 0x51e9, 0x0904, 0x2fcf, 0x2019, 0x0005, 0x7924, 0x080c, + 0x5198, 0x0904, 0x2fcf, 0x7828, 0xa08a, 0x1000, 0x1a04, 0x2fd2, + 0x8003, 0x800b, 0x810b, 0xa108, 0x080c, 0x69a8, 0x0804, 0x2faa, + 0x0126, 0x2091, 0x8000, 0x81ff, 0x0118, 0x2009, 0x0001, 0x0450, + 0x2029, 0x00ff, 0x6450, 0x2400, 0xa506, 0x01f8, 0x2508, 0x080c, + 0x4fa9, 0x11d8, 0x080c, 0x51e9, 0x1128, 0x2009, 0x0002, 0x62b4, + 0x2518, 0x00c0, 0x2019, 0x0004, 0xa00e, 0x080c, 0x5198, 0x1118, + 0x2009, 0x0006, 0x0078, 0x7824, 0xa08a, 0x1000, 0x1270, 0x8003, + 0x800b, 0x810b, 0xa108, 0x080c, 0x69a8, 0x8529, 0x1ae0, 0x012e, + 0x0804, 0x2faa, 0x012e, 0x0804, 0x2fcf, 0x012e, 0x0804, 0x2fd2, + 0x080c, 0x3e8a, 0x0904, 0x2fd2, 0x080c, 0x50d5, 0x080c, 0x5171, + 0x0804, 0x2faa, 0x81ff, 0x1904, 0x2fcf, 0x080c, 0x3e8a, 0x0904, + 0x2fd2, 0x080c, 0x50c6, 0x080c, 0x5171, 0x0804, 0x2faa, 0x81ff, + 0x1904, 0x2fcf, 0x080c, 0x3e8a, 0x0904, 0x2fd2, 0x080c, 0x514c, + 0x0904, 0x2fcf, 0x080c, 0x4e8d, 0x080c, 0x5113, 0x080c, 0x5171, + 0x0804, 0x2faa, 0x080c, 0x3e8a, 0x0904, 0x2fd2, 0x080c, 0x506f, + 0x0904, 0x2fcf, 0x62a0, 0x2019, 0x0005, 0x00c6, 0x080c, 0x51aa, + 0x2061, 0x0000, 0x080c, 0x6df5, 0x0076, 0x2039, 0x0000, 0x080c, + 0x6d02, 0x2009, 0x0000, 0x080c, 0xae82, 0x007e, 0x00ce, 0x080c, + 0x5171, 0x0804, 0x2faa, 0x080c, 0x3e8a, 0x0904, 0x2fd2, 0x080c, + 0x5171, 0x2208, 0x0804, 0x2faa, 0x0156, 0x00d6, 0x00e6, 0x2069, + 0xb614, 0x6810, 0x6914, 0xa10a, 0x1210, 0x2009, 0x0000, 0x6816, + 0x2011, 0x0000, 0x2019, 0x0000, 0x20a9, 0x007e, 0x2069, 0xb635, + 0x2d04, 0xa075, 0x0130, 0x704c, 0x0071, 0xa210, 0x7080, 0x0059, + 0xa318, 0x8d68, 0x1f04, 0x3218, 0x2300, 0xa218, 0x00ee, 0x00de, + 0x015e, 0x0804, 0x2faa, 0x00f6, 0x0016, 0xa07d, 0x0140, 0x2001, + 0x0000, 0x8000, 0x2f0c, 0x81ff, 0x0110, 0x2178, 0x0cd0, 0x001e, + 0x00fe, 0x0005, 0x2069, 0xb614, 0x6910, 0x62b0, 0x0804, 0x2faa, + 0x81ff, 0x1904, 0x2fcf, 0x6150, 0xa190, 0x2dc4, 0x2215, 0xa294, + 0x00ff, 0x6370, 0x83ff, 0x0108, 0x6274, 0x67d4, 0xd79c, 0x0118, + 0x2031, 0x0001, 0x0090, 0xd7ac, 0x0118, 0x2031, 0x0003, 0x0068, + 0xd7a4, 0x0118, 0x2031, 0x0002, 0x0040, 0x080c, 0x5acf, 0x1118, + 0x2031, 0x0004, 0x0010, 0x2031, 0x0000, 0x7e3a, 0x7f3e, 0x0804, + 0x2faa, 0x6140, 0x6244, 0x2019, 0xb7b6, 0x231c, 0x0804, 0x2faa, + 0x0126, 0x2091, 0x8000, 0x6134, 0xa006, 0x2010, 0x6338, 0x012e, + 0x0804, 0x2faa, 0x080c, 0x3e9a, 0x0904, 0x2fd2, 0x6244, 0x6338, + 0x0804, 0x2faa, 0x6140, 0x6244, 0x7824, 0x6042, 0x7b28, 0x6346, + 0x2069, 0xb552, 0x831f, 0xa305, 0x6816, 0x782c, 0x2069, 0xb7b6, + 0x2d1c, 0x206a, 0x0804, 0x2faa, 0x0126, 0x2091, 0x8000, 0x7824, + 0x6036, 0x782c, 0x603a, 0x012e, 0x0804, 0x2faa, 0x7838, 0xa005, + 0x01a8, 0x7828, 0xa025, 0x0904, 0x2fd2, 0x782c, 0xa02d, 0x0904, + 0x2fd2, 0xa00e, 0x080c, 0x4fa9, 0x1120, 0x6244, 0x6338, 0x6446, + 0x653a, 0xa186, 0x00ff, 0x0190, 0x8108, 0x0ca0, 0x080c, 0x3e9a, + 0x0904, 0x2fd2, 0x7828, 0xa00d, 0x0904, 0x2fd2, 0x782c, 0xa005, + 0x0904, 0x2fd2, 0x6244, 0x6146, 0x6338, 0x603a, 0x0804, 0x2faa, + 0x2001, 0xb500, 0x2004, 0xa086, 0x0003, 0x1904, 0x2fcf, 0x00c6, + 0x2061, 0x0100, 0x7924, 0x810f, 0xa18c, 0x00ff, 0xa196, 0x00ff, + 0x1130, 0x2001, 0xb515, 0x2004, 0xa085, 0xff00, 0x0078, 0xa182, + 0x007f, 0x16a0, 0xa188, 0x2dc4, 0x210d, 0xa18c, 0x00ff, 0x2001, + 0xb515, 0x2004, 0xa116, 0x0550, 0x810f, 0xa105, 0x0126, 0x2091, + 0x8000, 0x0006, 0x080c, 0x85c7, 0x000e, 0x01e0, 0x601a, 0x600b, + 0xbc09, 0x601f, 0x0001, 0x080c, 0x3e75, 0x01d8, 0x6837, 0x0000, + 0x7007, 0x0003, 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x701b, + 0x3370, 0x2d00, 0x6012, 0x2009, 0x0032, 0x080c, 0x864c, 0x012e, + 0x00ce, 0x0005, 0x012e, 0x00ce, 0x0804, 0x2fcf, 0x00ce, 0x0804, + 0x2fd2, 0x080c, 0x861d, 0x0cb0, 0x2001, 0xb500, 0x2004, 0xa086, + 0x0003, 0x1904, 0x2fcf, 0x00c6, 0x2061, 0x0100, 0x7924, 0x810f, + 0xa18c, 0x00ff, 0xa196, 0x00ff, 0x1130, 0x2001, 0xb515, 0x2004, + 0xa085, 0xff00, 0x0078, 0xa182, 0x007f, 0x16a0, 0xa188, 0x2dc4, + 0x210d, 0xa18c, 0x00ff, 0x2001, 0xb515, 0x2004, 0xa116, 0x0550, + 0x810f, 0xa105, 0x0126, 0x2091, 0x8000, 0x0006, 0x080c, 0x85c7, + 0x000e, 0x01e0, 0x601a, 0x600b, 0xbc05, 0x601f, 0x0001, 0x080c, + 0x3e75, 0x01d8, 0x6837, 0x0000, 0x7007, 0x0003, 0x6833, 0x0000, + 0x6838, 0xc0fd, 0x683a, 0x701b, 0x3370, 0x2d00, 0x6012, 0x2009, + 0x0032, 0x080c, 0x864c, 0x012e, 0x00ce, 0x0005, 0x012e, 0x00ce, + 0x0804, 0x2fcf, 0x00ce, 0x0804, 0x2fd2, 0x080c, 0x861d, 0x0cb0, + 0x6830, 0xa086, 0x0100, 0x0904, 0x2fcf, 0x0804, 0x2faa, 0x2061, + 0xb874, 0x0126, 0x2091, 0x8000, 0x6000, 0xd084, 0x0178, 0x6104, + 0x6208, 0x2a60, 0x6068, 0x783a, 0x60b4, 0x783e, 0x60b0, 0x2019, + 0x0072, 0x201a, 0x6348, 0x012e, 0x0804, 0x2faa, 0xa00e, 0x2110, + 0x0c80, 0x81ff, 0x1904, 0x2fcf, 0x080c, 0x5acf, 0x0904, 0x2fcf, + 0x0126, 0x2091, 0x8000, 0x6248, 0x6068, 0xa202, 0x0248, 0xa085, + 0x0001, 0x080c, 0x2867, 0x080c, 0x462c, 0x012e, 0x0804, 0x2faa, + 0x012e, 0x0804, 0x2fd2, 0x0006, 0x0016, 0x00c6, 0x00e6, 0x2001, + 0xb7bf, 0x2070, 0x2061, 0xb552, 0x6008, 0x2072, 0x2009, 0x0000, + 0x2011, 0x1000, 0x080c, 0x6b40, 0x7206, 0x00ee, 0x00ce, 0x001e, + 0x000e, 0x0005, 0x0126, 0x2091, 0x8000, 0x7824, 0xa084, 0x0007, + 0x0002, 0x33d4, 0x33dd, 0x33e4, 0x33d1, 0x33d1, 0x33d1, 0x33d1, + 0x33d1, 0x012e, 0x0804, 0x2fd2, 0x2009, 0x0114, 0x2104, 0xa085, + 0x0800, 0x200a, 0x080c, 0x354f, 0x0070, 0x2009, 0x010b, 0x200b, + 0x0010, 0x080c, 0x354f, 0x0038, 0x81ff, 0x0128, 0x012e, 0x2021, + 0x400b, 0x0804, 0x2fac, 0x0086, 0x0096, 0x00a6, 0x00b6, 0x00c6, + 0x00d6, 0x00e6, 0x00f6, 0x080c, 0x33ab, 0x2009, 0x0101, 0x210c, + 0x0016, 0x2001, 0x0138, 0x200c, 0x2003, 0x0001, 0x0016, 0x2001, + 0x007a, 0x2034, 0x2001, 0x007b, 0x202c, 0xa006, 0x2048, 0x2050, + 0x2058, 0x080c, 0x379a, 0x080c, 0x36fe, 0xa03e, 0x2720, 0x00f6, + 0x00e6, 0x00c6, 0x2d60, 0x2071, 0xb84a, 0x2079, 0x0020, 0x00d6, + 0x2069, 0x0000, 0x6824, 0xd0b4, 0x0140, 0x2001, 0x007d, 0x2004, + 0x783e, 0x2001, 0x007c, 0x2004, 0x783a, 0x00de, 0x2011, 0x0001, + 0x080c, 0x36aa, 0x080c, 0x36aa, 0x00ce, 0x00ee, 0x00fe, 0x080c, + 0x35f5, 0x080c, 0x36d2, 0x080c, 0x364f, 0x080c, 0x35b4, 0x080c, + 0x35e5, 0x00f6, 0x2079, 0x0100, 0x7824, 0xd094, 0x0530, 0x7814, + 0xa084, 0x0184, 0xa085, 0x0010, 0x7816, 0x2079, 0x0140, 0x080c, + 0x352d, 0x1110, 0x00fe, 0x0430, 0x7804, 0xd0dc, 0x0dc0, 0x2079, + 0x0100, 0x7827, 0x0086, 0x7814, 0xa084, 0x0184, 0xa085, 0x0032, + 0x7816, 0x080c, 0x352d, 0x1110, 0x00fe, 0x00a0, 0x7824, 0xd0bc, + 0x0dc0, 0x7827, 0x0080, 0xa026, 0x7c16, 0x7824, 0xd0ac, 0x0130, + 0x8b58, 0x080c, 0x3537, 0x00fe, 0x0804, 0x34f7, 0x00fe, 0x080c, + 0x352d, 0x1150, 0x8948, 0x2001, 0x007a, 0x2602, 0x2001, 0x007b, + 0x2502, 0x080c, 0x3537, 0x0088, 0x87ff, 0x0140, 0x2001, 0x0201, + 0x2004, 0xa005, 0x1904, 0x3431, 0x8739, 0x0038, 0x2001, 0xb823, + 0x2004, 0xa086, 0x0000, 0x1904, 0x3431, 0x2001, 0x0033, 0x2003, + 0x00f6, 0x8631, 0x1208, 0x8529, 0x2500, 0xa605, 0x0904, 0x34f7, + 0x7824, 0xd0bc, 0x0128, 0x2900, 0xaa05, 0xab05, 0x1904, 0x34f7, + 0x6033, 0x000d, 0x2001, 0x0030, 0x2003, 0x0004, 0x7824, 0xd0ac, + 0x1148, 0x2001, 0xb823, 0x2003, 0x0003, 0x2001, 0x0030, 0x2003, + 0x0009, 0x0040, 0x6027, 0x0001, 0x2001, 0x0075, 0x2004, 0xa005, + 0x0108, 0x6026, 0x2c00, 0x601a, 0x20e1, 0x9040, 0x2d00, 0x681a, + 0x6833, 0x000d, 0x7824, 0xd0a4, 0x1180, 0x6827, 0x0000, 0x00c6, + 0x20a9, 0x0004, 0x2061, 0x0020, 0x6003, 0x0008, 0x2001, 0x0203, + 0x2004, 0x1f04, 0x34cc, 0x00ce, 0x0040, 0x6827, 0x0001, 0x2001, + 0x0074, 0x2004, 0xa005, 0x0108, 0x6826, 0x00f6, 0x00c6, 0x2079, + 0x0100, 0x2061, 0x0020, 0x7827, 0x0002, 0x2001, 0x0072, 0x2004, + 0xa084, 0xfff8, 0x601a, 0x0006, 0x2001, 0x0073, 0x2004, 0x601e, + 0x78c6, 0x000e, 0x78ca, 0x00ce, 0x00fe, 0x0804, 0x340f, 0x2061, + 0x0100, 0x6027, 0x0002, 0x001e, 0x61e2, 0x001e, 0x6106, 0x7824, + 0xa084, 0x0003, 0xa086, 0x0002, 0x0188, 0x20e1, 0x9028, 0x6050, + 0xa084, 0xf7ef, 0x6052, 0x602f, 0x0000, 0x602c, 0xc0ac, 0x602e, + 0x604b, 0xf7f7, 0x6043, 0x0090, 0x6043, 0x0010, 0x2908, 0x2a10, + 0x2b18, 0x2b00, 0xaa05, 0xa905, 0x00fe, 0x00ee, 0x00de, 0x00ce, + 0x00be, 0x00ae, 0x009e, 0x008e, 0x1118, 0x012e, 0x0804, 0x2faa, + 0x012e, 0x2021, 0x400c, 0x0804, 0x2fac, 0xa085, 0x0001, 0x1d04, + 0x3536, 0x2091, 0x6000, 0x8420, 0xa486, 0x0064, 0x0005, 0x2001, + 0x0105, 0x2003, 0x0010, 0x2001, 0x0030, 0x2003, 0x0004, 0x2001, + 0x0020, 0x2003, 0x0004, 0x2001, 0xb823, 0x2003, 0x0000, 0x2001, + 0xb84a, 0x2003, 0x0000, 0x20e1, 0xf000, 0xa026, 0x0005, 0x00f6, + 0x2079, 0x0100, 0x2001, 0xb515, 0x200c, 0x7932, 0x7936, 0x080c, + 0x2847, 0x7850, 0xa084, 0x0980, 0xa085, 0x0030, 0x7852, 0x2019, + 0x01f4, 0x8319, 0x1df0, 0xa084, 0x0980, 0x7852, 0x782c, 0xc0ad, + 0x782e, 0x20a9, 0x0046, 0x1d04, 0x356b, 0x2091, 0x6000, 0x1f04, + 0x356b, 0x7850, 0xa085, 0x0400, 0x7852, 0x2001, 0x0009, 0x2004, + 0xa084, 0x0003, 0xa086, 0x0001, 0x1118, 0x782c, 0xc0ac, 0x782e, + 0x784b, 0xf7f7, 0x7843, 0x0090, 0x7843, 0x0010, 0x20a9, 0x000e, + 0xe000, 0x1f04, 0x3588, 0x7850, 0xa085, 0x1400, 0x7852, 0x2019, + 0x61a8, 0x7854, 0xe000, 0xe000, 0xd08c, 0x1110, 0x8319, 0x1dc8, + 0x7827, 0x0048, 0x7850, 0xa085, 0x0400, 0x7852, 0x7843, 0x0040, + 0x2019, 0x01f4, 0xe000, 0xe000, 0x8319, 0x1de0, 0x2001, 0x0140, + 0x2003, 0x0100, 0x7827, 0x0020, 0x7843, 0x0000, 0x2003, 0x0000, + 0x7827, 0x0048, 0x00fe, 0x0005, 0x7824, 0xd0ac, 0x11c8, 0x00f6, + 0x00e6, 0x2071, 0xb823, 0x2079, 0x0030, 0x2001, 0x0201, 0x2004, + 0xa005, 0x0160, 0x7000, 0xa086, 0x0000, 0x1140, 0x0051, 0xd0bc, + 0x0108, 0x8738, 0x7003, 0x0003, 0x7803, 0x0019, 0x00ee, 0x00fe, + 0x0005, 0x780c, 0xa08c, 0x0070, 0x0178, 0x2009, 0x007a, 0x260a, + 0x2009, 0x007b, 0x250a, 0xd0b4, 0x0108, 0x8a50, 0xd0ac, 0x0108, + 0x8948, 0xd0a4, 0x0108, 0x8b58, 0x0005, 0x00f6, 0x2079, 0x0200, + 0x781c, 0xd084, 0x0140, 0x20e1, 0x0007, 0x20e1, 0x2000, 0x2001, + 0x020a, 0x2004, 0x0ca8, 0x00fe, 0x0005, 0x00e6, 0x2071, 0x0100, + 0x2001, 0xb7c0, 0x2004, 0x70e2, 0x2009, 0xb515, 0x210c, 0x716e, + 0x7063, 0x0100, 0x7166, 0x719e, 0x706b, 0x0000, 0x7073, 0x0809, + 0x7077, 0x0008, 0x7078, 0xa080, 0x0100, 0x707a, 0x7080, 0x8000, + 0x7082, 0x7087, 0xaaaa, 0xa006, 0x708a, 0x708e, 0x707e, 0x70d6, + 0x70ab, 0x0036, 0x70af, 0x95d5, 0x7027, 0x0080, 0x7014, 0xa084, + 0x0184, 0xa085, 0x0032, 0x7016, 0x080c, 0x36d2, 0x080c, 0x352d, + 0x1110, 0x8421, 0x0028, 0x7024, 0xd0bc, 0x0db0, 0x7027, 0x0080, + 0x00f6, 0x00e6, 0x2071, 0xb823, 0x2079, 0x0030, 0x00d6, 0x2069, + 0x0000, 0x6824, 0xd0b4, 0x0120, 0x683c, 0x783e, 0x6838, 0x783a, + 0x00de, 0x2011, 0x0011, 0x080c, 0x36aa, 0x2011, 0x0001, 0x080c, + 0x36aa, 0x00ee, 0x00fe, 0x7017, 0x0000, 0x00ee, 0x0005, 0x00f6, + 0x00e6, 0x2071, 0xb823, 0x2079, 0x0030, 0x7904, 0xd1fc, 0x0904, + 0x36a7, 0x7803, 0x0002, 0xa026, 0xd19c, 0x1904, 0x36a3, 0x7000, + 0x0002, 0x36a7, 0x3665, 0x3689, 0x36a3, 0xd1bc, 0x1150, 0xd1dc, + 0x1150, 0x8001, 0x7002, 0x2011, 0x0001, 0x04e1, 0x05c0, 0x04d1, + 0x04b0, 0x780f, 0x0000, 0x7820, 0x7924, 0x7803, 0x0004, 0x7822, + 0x7926, 0x2001, 0x0201, 0x200c, 0x81ff, 0x0de8, 0x080c, 0x35d1, + 0x2009, 0x0001, 0x7808, 0xd0ec, 0x0110, 0x2009, 0x0011, 0x7902, + 0x00f0, 0x8001, 0x7002, 0xa184, 0x0880, 0x1138, 0x7804, 0xd0fc, + 0x1940, 0x2011, 0x0001, 0x00b1, 0x0090, 0x6030, 0xa092, 0x0004, + 0xa086, 0x0009, 0x1120, 0x6000, 0x601a, 0x2011, 0x0025, 0x6232, + 0xd1dc, 0x1988, 0x0870, 0x7803, 0x0004, 0x7003, 0x0000, 0x00ee, + 0x00fe, 0x0005, 0x6024, 0xa005, 0x0520, 0x8001, 0x6026, 0x6018, + 0x6130, 0xa140, 0x2804, 0x7832, 0x8840, 0x2804, 0x7836, 0x8840, + 0x2804, 0x7822, 0x8840, 0x2804, 0x7826, 0x8840, 0x7a02, 0x7000, + 0x8000, 0x7002, 0x6018, 0xa802, 0xa08a, 0x0029, 0x1138, 0x6018, + 0xa080, 0x0001, 0x2004, 0x601a, 0x2001, 0x000d, 0x6032, 0xa085, + 0x0001, 0x0005, 0x00f6, 0x00e6, 0x00c6, 0x2071, 0xb84a, 0x2079, + 0x0020, 0x7904, 0xd1fc, 0x01f0, 0x7803, 0x0002, 0x2d60, 0xa026, + 0x7000, 0x0002, 0x36fa, 0x36e5, 0x36f1, 0x8001, 0x7002, 0xd19c, + 0x1188, 0x2011, 0x0001, 0x080c, 0x36aa, 0x0160, 0x080c, 0x36aa, + 0x0048, 0x8001, 0x7002, 0x7804, 0xd0fc, 0x1d30, 0x2011, 0x0001, + 0x080c, 0x36aa, 0x00ce, 0x00ee, 0x00fe, 0x0005, 0x00f6, 0x00e6, + 0x00c6, 0x2061, 0x0200, 0x2001, 0xb7c0, 0x2004, 0x601a, 0x2061, + 0x0100, 0x2001, 0xb7bf, 0x2004, 0x60ce, 0x6004, 0xc0ac, 0xa085, + 0x0200, 0x6006, 0x2001, 0x0074, 0x2004, 0xa005, 0x01f8, 0x2038, + 0x2001, 0x0076, 0x2024, 0x2001, 0x0077, 0x201c, 0x080c, 0x3e75, + 0x6833, 0x000d, 0x6f26, 0x2d00, 0x681a, 0xa78a, 0x0007, 0x0220, + 0x2138, 0x2009, 0x0007, 0x0010, 0x2708, 0xa03e, 0x6818, 0xa080, + 0x000d, 0x04b1, 0x1d90, 0x2d00, 0x681a, 0x0088, 0x080c, 0x3e75, + 0x6833, 0x000d, 0x2070, 0x6827, 0x0001, 0x2d00, 0x681a, 0x2001, + 0x0076, 0x2004, 0x2072, 0x2001, 0x0077, 0x2004, 0x7006, 0x2061, + 0x0020, 0x2079, 0x0100, 0x2001, 0xb7bf, 0x2004, 0x6012, 0x20e1, + 0x9040, 0x2001, 0x0072, 0x2004, 0xa084, 0xfff8, 0x700a, 0x601a, + 0x0006, 0x2001, 0x0073, 0x2004, 0x700e, 0x601e, 0x78c6, 0x000e, + 0x78ca, 0xa006, 0x603a, 0x603e, 0x00ce, 0x00ee, 0x00fe, 0x0005, + 0x00e6, 0x2071, 0x0010, 0x20a0, 0x2099, 0x0014, 0x7003, 0x0026, + 0x7432, 0x7336, 0xa006, 0x703a, 0x703e, 0x810b, 0x810b, 0x21a8, + 0x810b, 0x7122, 0x7003, 0x0041, 0x7004, 0xd0fc, 0x0de8, 0x7003, + 0x0002, 0x7003, 0x0040, 0x53a5, 0x7430, 0x7334, 0x87ff, 0x0180, + 0x00c6, 0x00d6, 0x2d60, 0x00c6, 0x080c, 0x3e75, 0x00ce, 0x6018, + 0x2070, 0x2d00, 0x7006, 0x601a, 0x00de, 0x00ce, 0xa085, 0x0001, + 0x00ee, 0x0005, 0x00e6, 0x2001, 0x0075, 0x2004, 0xa005, 0x0508, + 0x2038, 0x2001, 0x0078, 0x2024, 0x2001, 0x0079, 0x201c, 0x080c, + 0x3e75, 0x2d60, 0x6833, 0x000d, 0x6f26, 0x2d00, 0x681a, 0xa78a, + 0x0007, 0x0220, 0x2138, 0x2009, 0x0007, 0x0010, 0x2708, 0xa03e, + 0x6818, 0xa080, 0x000d, 0x080c, 0x3768, 0x1d88, 0x2d00, 0x681a, + 0x00e0, 0x080c, 0x3e75, 0x2d60, 0x6033, 0x000d, 0x2070, 0x6027, + 0x0001, 0x2c00, 0x601a, 0x2001, 0x0078, 0x2004, 0x2072, 0x2001, + 0x0079, 0x2004, 0x7006, 0x2001, 0x0072, 0x2004, 0xa084, 0xfff8, + 0x700a, 0x2001, 0x0073, 0x2004, 0x700e, 0x2001, 0x0030, 0x2003, + 0x0004, 0x7824, 0xd0ac, 0x1178, 0x2001, 0x0101, 0x200c, 0xc1ed, + 0x2102, 0x6027, 0x0000, 0x2001, 0xb823, 0x2003, 0x0003, 0x2001, + 0x0030, 0x2003, 0x0009, 0x00ee, 0x0005, 0x0804, 0x2faa, 0x0126, + 0x2091, 0x8000, 0x20a9, 0x0012, 0x2001, 0xb540, 0x20a0, 0xa006, + 0x40a4, 0x012e, 0x0804, 0x2faa, 0x7d38, 0x7c3c, 0x0804, 0x3051, + 0x080c, 0x3e75, 0x0904, 0x2fcf, 0x080c, 0x5acf, 0x0110, 0x080c, + 0x4bf0, 0x2009, 0x001c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x080c, + 0x3eb6, 0x701b, 0x381c, 0x0005, 0xade8, 0x000d, 0x6800, 0xa005, + 0x0904, 0x2fd2, 0x6804, 0xd0ac, 0x0118, 0xd0a4, 0x0904, 0x2fd2, + 0xd094, 0x00c6, 0x2061, 0x0100, 0x6104, 0x0138, 0x6200, 0xa292, + 0x0005, 0x0218, 0xa18c, 0xffdf, 0x0010, 0xa18d, 0x0020, 0x6106, + 0x00ce, 0xd08c, 0x00c6, 0x2061, 0x0100, 0x6104, 0x0118, 0xa18d, + 0x0010, 0x0010, 0xa18c, 0xffef, 0x6106, 0x00ce, 0x2009, 0x0100, + 0x210c, 0xa18a, 0x0002, 0x0268, 0xd084, 0x0158, 0x6a28, 0xa28a, + 0x007f, 0x1a04, 0x2fd2, 0xa288, 0x2dc4, 0x210d, 0xa18c, 0x00ff, + 0x615a, 0xd0dc, 0x0130, 0x6828, 0xa08a, 0x007f, 0x1a04, 0x2fd2, + 0x6052, 0x6808, 0xa08a, 0x0100, 0x0a04, 0x2fd2, 0xa08a, 0x0841, + 0x1a04, 0x2fd2, 0xa084, 0x0007, 0x1904, 0x2fd2, 0x680c, 0xa005, + 0x0904, 0x2fd2, 0x6810, 0xa005, 0x0904, 0x2fd2, 0x6848, 0x6940, + 0xa10a, 0x1a04, 0x2fd2, 0x8001, 0x0904, 0x2fd2, 0x684c, 0x6944, + 0xa10a, 0x1a04, 0x2fd2, 0x8001, 0x0904, 0x2fd2, 0x6804, 0xd0fc, + 0x0560, 0x080c, 0x3e75, 0x0904, 0x2fcf, 0x2009, 0x0014, 0x7a2c, + 0x7b28, 0x7c3c, 0x7d38, 0xa290, 0x0038, 0xa399, 0x0000, 0x080c, + 0x3eb6, 0x701b, 0x389c, 0x0005, 0xade8, 0x000d, 0x20a9, 0x0014, + 0x2d98, 0x2069, 0xb56e, 0x2da0, 0x53a3, 0x7010, 0xa0e8, 0x000d, + 0x2001, 0xb572, 0x200c, 0xd1e4, 0x0140, 0x00c6, 0x2061, 0x0100, + 0x6004, 0xa085, 0x0b00, 0x6006, 0x00ce, 0x2009, 0xb7b1, 0x200b, + 0x0000, 0x2001, 0xb574, 0x2004, 0xd0ac, 0x0158, 0x7824, 0x200a, + 0x2009, 0x017f, 0x200a, 0x3200, 0xa084, 0x003f, 0xa085, 0x3020, + 0x2090, 0x20a9, 0x001c, 0x2d98, 0x2069, 0xb552, 0x2da0, 0x53a3, + 0x6814, 0xa08c, 0x00ff, 0x6142, 0x8007, 0xa084, 0x00ff, 0x6046, + 0x080c, 0x5da5, 0x080c, 0x536c, 0x080c, 0x53d5, 0x6000, 0xa086, + 0x0000, 0x1904, 0x3997, 0x6808, 0x602a, 0x080c, 0x2470, 0x0006, + 0x2001, 0x0100, 0x2004, 0xa082, 0x0005, 0x000e, 0x0268, 0x2009, + 0x0170, 0x200b, 0x0080, 0xe000, 0xe000, 0x200b, 0x0000, 0x0036, + 0x6b08, 0x080c, 0x28a2, 0x003e, 0x6818, 0x691c, 0x6a20, 0x6b24, + 0x8007, 0x810f, 0x8217, 0x831f, 0x6016, 0x611a, 0x621e, 0x6322, + 0x6c04, 0xd4f4, 0x0148, 0x6830, 0x6934, 0x6a38, 0x6b3c, 0x8007, + 0x810f, 0x8217, 0x831f, 0x0010, 0xa084, 0xf0ff, 0x6006, 0x610a, + 0x620e, 0x6312, 0x8007, 0x810f, 0x8217, 0x831f, 0x20a9, 0x0004, + 0x20a1, 0xb7c6, 0x40a1, 0x080c, 0x6a68, 0x6904, 0xd1fc, 0x0520, + 0x00c6, 0x2009, 0x0000, 0x20a9, 0x0001, 0x6b70, 0xd384, 0x01c8, + 0x0020, 0x839d, 0x12b0, 0x3508, 0x8109, 0x080c, 0x635c, 0x6878, + 0x6016, 0x6874, 0x2008, 0xa084, 0xff00, 0x8007, 0x600a, 0xa184, + 0x00ff, 0x6006, 0x8108, 0x1118, 0x6003, 0x0003, 0x0010, 0x6003, + 0x0001, 0x1f04, 0x3931, 0x00ce, 0x2069, 0xb552, 0x2001, 0xb79e, + 0x6a80, 0xa294, 0x0030, 0xa28e, 0x0000, 0x0170, 0xa28e, 0x0010, + 0x0118, 0xa28e, 0x0020, 0x0140, 0x2003, 0xaaaa, 0x080c, 0x28eb, + 0x2001, 0xb78f, 0x2102, 0x0008, 0x2102, 0x00c6, 0x2061, 0x0100, + 0x602f, 0x0040, 0x602f, 0x0000, 0x00ce, 0x080c, 0x5acf, 0x0128, + 0x080c, 0x40cf, 0x0110, 0x080c, 0x2867, 0x60c8, 0xa005, 0x01d0, + 0x6003, 0x0001, 0x2009, 0x397d, 0x00e0, 0x080c, 0x5acf, 0x1178, + 0x2011, 0x59a2, 0x080c, 0x699c, 0x2011, 0x5995, 0x080c, 0x6a5c, + 0x2001, 0xb79f, 0x2003, 0x0000, 0x080c, 0x5a07, 0x0040, 0x080c, + 0x4b1f, 0x0028, 0x6003, 0x0004, 0x2009, 0x3997, 0x0010, 0x0804, + 0x2faa, 0x2001, 0x0100, 0x2004, 0xa082, 0x0005, 0x0258, 0x2001, + 0x0170, 0x2004, 0xa084, 0x00ff, 0xa086, 0x004c, 0x1118, 0x2091, + 0x309d, 0x0817, 0x2091, 0x301d, 0x0817, 0x6000, 0xa086, 0x0000, + 0x0904, 0x2fcf, 0x2069, 0xb552, 0x7830, 0x6842, 0x7834, 0x6846, + 0x6804, 0xd0fc, 0x0118, 0x2009, 0x0030, 0x0010, 0x2009, 0x001c, + 0x2d00, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0804, 0x3eb9, 0xa006, + 0x080c, 0x2867, 0x81ff, 0x1904, 0x2fcf, 0x080c, 0x5acf, 0x1178, + 0x2001, 0xb79f, 0x2003, 0x0001, 0x2001, 0xb500, 0x2003, 0x0001, + 0xa085, 0x0001, 0x080c, 0x5b13, 0x080c, 0x5a07, 0x0020, 0x080c, + 0x4bf0, 0x080c, 0x4b1f, 0x0804, 0x2faa, 0x81ff, 0x1904, 0x2fcf, + 0x080c, 0x5acf, 0x1110, 0x0804, 0x2fcf, 0x6188, 0x81ff, 0x0198, + 0x703f, 0x0000, 0x2001, 0xbcc0, 0x2009, 0x0040, 0x7a2c, 0x7b28, + 0x7c3c, 0x7d38, 0x0126, 0x2091, 0x8000, 0x080c, 0x3eb9, 0x701b, + 0x2fa8, 0x012e, 0x0005, 0x703f, 0x0001, 0x00d6, 0x2069, 0xbcc0, + 0x20a9, 0x0040, 0x20a1, 0xbcc0, 0x2019, 0xffff, 0x43a4, 0x6550, + 0xa588, 0x2dc4, 0x210d, 0xa18c, 0x00ff, 0x216a, 0xa00e, 0x2011, + 0x0002, 0x2100, 0xa506, 0x01a8, 0x080c, 0x4fa9, 0x1190, 0x6014, + 0x821c, 0x0238, 0xa398, 0xbcc0, 0xa085, 0xff00, 0x8007, 0x201a, + 0x0038, 0xa398, 0xbcc0, 0x2324, 0xa4a4, 0xff00, 0xa405, 0x201a, + 0x8210, 0x8108, 0xa182, 0x0080, 0x1208, 0x0c18, 0x8201, 0x8007, + 0x2d0c, 0xa105, 0x206a, 0x00de, 0x20a9, 0x0040, 0x20a1, 0xbcc0, + 0x2099, 0xbcc0, 0x080c, 0x4b8f, 0x0804, 0x39f2, 0x080c, 0x3e9a, + 0x0904, 0x2fd2, 0x00c6, 0x080c, 0x3e75, 0x00ce, 0x1120, 0x2009, + 0x0002, 0x0804, 0x2fcf, 0x2001, 0xb553, 0x2004, 0xd0b4, 0x0550, + 0x7824, 0xa084, 0xff00, 0xa08e, 0x7e00, 0x0520, 0xa08e, 0x7f00, + 0x0508, 0xa08e, 0x8000, 0x01f0, 0x6000, 0xd08c, 0x11d8, 0x6004, + 0xa084, 0x00ff, 0xa086, 0x0006, 0x11a8, 0x6837, 0x0000, 0x6838, + 0xc0fd, 0x683a, 0x080c, 0x9dda, 0x1120, 0x2009, 0x0003, 0x0804, + 0x2fcf, 0x7007, 0x0003, 0x701b, 0x3a7e, 0x0005, 0x080c, 0x3e9a, + 0x0904, 0x2fd2, 0x20a9, 0x002b, 0x2c98, 0xade8, 0x0002, 0x2da0, + 0x53a3, 0x20a9, 0x0004, 0xac80, 0x0006, 0x2098, 0xad80, 0x0006, + 0x20a0, 0x080c, 0x4b8f, 0x20a9, 0x0004, 0xac80, 0x000a, 0x2098, + 0xad80, 0x000a, 0x20a0, 0x080c, 0x4b8f, 0x2d00, 0x2009, 0x002b, + 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0804, 0x3eb9, 0x81ff, 0x1904, + 0x2fcf, 0x080c, 0x3e8a, 0x0904, 0x2fd2, 0x080c, 0x5186, 0x0804, + 0x2faa, 0x81ff, 0x1904, 0x2fcf, 0x7828, 0xa08a, 0x1000, 0x1a04, + 0x2fd2, 0x080c, 0x3e9a, 0x0904, 0x2fd2, 0x080c, 0x51e9, 0x0904, + 0x2fcf, 0x2019, 0x0004, 0xa00e, 0x080c, 0x5198, 0x7924, 0x810f, + 0x7a28, 0x0011, 0x0804, 0x2faa, 0xa186, 0x00ff, 0x0110, 0x0071, + 0x0060, 0x2029, 0x007e, 0x2061, 0xb500, 0x6450, 0x2400, 0xa506, + 0x0110, 0x2508, 0x0019, 0x8529, 0x1ec8, 0x0005, 0x080c, 0x4fa9, + 0x1138, 0x2200, 0x8003, 0x800b, 0x810b, 0xa108, 0x080c, 0x69a8, + 0x0005, 0x81ff, 0x1904, 0x2fcf, 0x080c, 0x3e8a, 0x0904, 0x2fd2, + 0x080c, 0x506f, 0x0904, 0x2fcf, 0x080c, 0x518f, 0x0804, 0x2faa, + 0x81ff, 0x1904, 0x2fcf, 0x080c, 0x3e8a, 0x0904, 0x2fd2, 0x080c, + 0x506f, 0x0904, 0x2fcf, 0x080c, 0x517d, 0x0804, 0x2faa, 0x6100, + 0x0804, 0x2faa, 0x080c, 0x3e9a, 0x0904, 0x2fd2, 0x2001, 0xb500, + 0x2004, 0xa086, 0x0003, 0x1904, 0x2fcf, 0x00d6, 0xace8, 0x000a, + 0x7924, 0xd184, 0x0110, 0xace8, 0x0006, 0x680c, 0x8007, 0x783e, + 0x6808, 0x8007, 0x783a, 0x6b04, 0x831f, 0x6a00, 0x8217, 0x00de, + 0x6100, 0xa18c, 0x0200, 0x0804, 0x2faa, 0x7824, 0xa09c, 0x0003, + 0xd0b4, 0x1160, 0xa39a, 0x0003, 0x1a04, 0x2fcf, 0x6250, 0xa294, + 0x00ff, 0xa084, 0xff00, 0x8007, 0xa206, 0x1150, 0x2001, 0xb540, + 0x2009, 0x000c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0804, 0x3eb9, + 0x81ff, 0x1904, 0x2fcf, 0x080c, 0x3e9a, 0x0904, 0x2fd2, 0x6004, + 0xa084, 0x00ff, 0xa086, 0x0006, 0x1904, 0x2fcf, 0x00c6, 0x080c, + 0x3e75, 0x00ce, 0x0904, 0x2fcf, 0x6837, 0x0000, 0x6838, 0xc0fd, + 0x683a, 0x080c, 0x9d86, 0x0904, 0x2fcf, 0x7007, 0x0003, 0x701b, + 0x3b6a, 0x0005, 0x6830, 0xa086, 0x0100, 0x0904, 0x2fcf, 0xad80, + 0x000e, 0x2009, 0x000c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0804, + 0x3eb9, 0xa006, 0x080c, 0x2867, 0x7824, 0xa084, 0x00ff, 0xa086, + 0x00ff, 0x0118, 0x81ff, 0x1904, 0x2fcf, 0x080c, 0x5acf, 0x0110, + 0x080c, 0x4bf0, 0x7828, 0xa08a, 0x1000, 0x1a04, 0x2fd2, 0x7924, + 0xa18c, 0xff00, 0x810f, 0xa186, 0x00ff, 0x0138, 0xa182, 0x007f, + 0x1a04, 0x2fd2, 0x2100, 0x080c, 0x2831, 0x0026, 0x00c6, 0x0126, + 0x2091, 0x8000, 0x2061, 0xb7f3, 0x601b, 0x0000, 0x601f, 0x0000, + 0x080c, 0x5acf, 0x1178, 0x2001, 0xb79f, 0x2003, 0x0001, 0x2001, + 0xb500, 0x2003, 0x0001, 0xa085, 0x0001, 0x080c, 0x5b13, 0x080c, + 0x5a07, 0x0420, 0x2011, 0x0003, 0x080c, 0x8075, 0x2011, 0x0002, + 0x080c, 0x807f, 0x080c, 0x7f59, 0x0036, 0x2019, 0x0000, 0x080c, + 0x7fe4, 0x003e, 0x2061, 0x0100, 0x2001, 0xb515, 0x2004, 0xa084, + 0x00ff, 0x810f, 0xa105, 0x604a, 0x6043, 0x0090, 0x6043, 0x0010, + 0x2009, 0x002d, 0x2011, 0x4b54, 0x080c, 0x6a22, 0x7924, 0xa18c, + 0xff00, 0x810f, 0x080c, 0x5acf, 0x1110, 0x2009, 0x00ff, 0x7a28, + 0x080c, 0x3acc, 0x012e, 0x00ce, 0x002e, 0x0804, 0x2faa, 0x7924, + 0xa18c, 0xff00, 0x810f, 0x00c6, 0x080c, 0x4f4d, 0x2c08, 0x00ce, + 0x1904, 0x2fd2, 0x0804, 0x2faa, 0x81ff, 0x0120, 0x2009, 0x0001, + 0x0804, 0x2fcf, 0x60d4, 0xd0ac, 0x1130, 0xd09c, 0x1120, 0x2009, + 0x0005, 0x0804, 0x2fcf, 0x080c, 0x3e75, 0x1120, 0x2009, 0x0002, + 0x0804, 0x2fcf, 0x7924, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x080c, + 0x3eb6, 0x701b, 0x3c1c, 0x0005, 0x2009, 0x0080, 0x080c, 0x4fa9, + 0x1130, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x0120, 0x2021, + 0x400a, 0x0804, 0x2fac, 0x00d6, 0xade8, 0x000d, 0x6900, 0x6a08, + 0x6b0c, 0x6c10, 0x6d14, 0x6e18, 0x6820, 0xa0be, 0x0100, 0x0904, + 0x3c93, 0xa0be, 0x0112, 0x0904, 0x3c93, 0xa0be, 0x0113, 0x0904, + 0x3c93, 0xa0be, 0x0114, 0x0904, 0x3c93, 0xa0be, 0x0117, 0x0904, + 0x3c93, 0xa0be, 0x011a, 0x0904, 0x3c93, 0xa0be, 0x011c, 0x0904, + 0x3c93, 0xa0be, 0x0121, 0x05b0, 0xa0be, 0x0131, 0x0598, 0xa0be, + 0x0171, 0x05c8, 0xa0be, 0x0173, 0x05b0, 0xa0be, 0x01a1, 0x1120, + 0x6830, 0x8007, 0x6832, 0x04a8, 0xa0be, 0x0212, 0x0540, 0xa0be, + 0x0213, 0x0528, 0xa0be, 0x0214, 0x01b0, 0xa0be, 0x0217, 0x0168, + 0xa0be, 0x021a, 0x1120, 0x6838, 0x8007, 0x683a, 0x00e0, 0xa0be, + 0x0300, 0x01c8, 0x00de, 0x0804, 0x2fd2, 0xad80, 0x0010, 0x20a9, + 0x0007, 0x080c, 0x3cd9, 0xad80, 0x000e, 0x20a9, 0x0001, 0x080c, + 0x3cd9, 0x0048, 0xad80, 0x000c, 0x080c, 0x3ce7, 0x0050, 0xad80, + 0x000e, 0x080c, 0x3ce7, 0xad80, 0x000c, 0x20a9, 0x0001, 0x080c, + 0x3cd9, 0x00c6, 0x080c, 0x3e75, 0x0568, 0x6838, 0xc0fd, 0x683a, + 0x6837, 0x0119, 0x6853, 0x0000, 0x684f, 0x0020, 0x685b, 0x0001, + 0x810b, 0x697e, 0x6883, 0x0000, 0x6a86, 0x6b8a, 0x6c8e, 0x6d92, + 0x6996, 0x689b, 0x0000, 0x00ce, 0x00de, 0x6837, 0x0000, 0x6838, + 0xc0fd, 0x683a, 0x6823, 0x0000, 0x6804, 0x2068, 0x080c, 0x9da2, + 0x1120, 0x2009, 0x0003, 0x0804, 0x2fcf, 0x7007, 0x0003, 0x701b, + 0x3cd0, 0x0005, 0x00ce, 0x00de, 0x2009, 0x0002, 0x0804, 0x2fcf, + 0x6820, 0xa086, 0x8001, 0x1904, 0x2faa, 0x2009, 0x0004, 0x0804, + 0x2fcf, 0x0016, 0x2008, 0x2044, 0x8000, 0x204c, 0x8000, 0x290a, + 0x8108, 0x280a, 0x8108, 0x1f04, 0x3cdb, 0x001e, 0x0005, 0x0016, + 0x00a6, 0x00b6, 0x2008, 0x2044, 0x8000, 0x204c, 0x8000, 0x2054, + 0x8000, 0x205c, 0x2b0a, 0x8108, 0x2a0a, 0x8108, 0x290a, 0x8108, + 0x280a, 0x00be, 0x00ae, 0x001e, 0x0005, 0x81ff, 0x0120, 0x2009, + 0x0001, 0x0804, 0x2fcf, 0x60d4, 0xd0ac, 0x1130, 0xd09c, 0x1120, + 0x2009, 0x0005, 0x0804, 0x2fcf, 0x7924, 0x2140, 0xa18c, 0xff00, + 0x810f, 0x60d4, 0xd0ac, 0x1120, 0xa182, 0x0080, 0x0a04, 0x2fd2, + 0xa182, 0x00ff, 0x1a04, 0x2fd2, 0x7a2c, 0x7b28, 0x6070, 0xa306, + 0x1140, 0x6074, 0xa24e, 0x0904, 0x2fd2, 0xa9cc, 0xff00, 0x0904, + 0x2fd2, 0x00c6, 0x080c, 0x3dc5, 0x2c68, 0x00ce, 0x0530, 0xa0c6, + 0x4000, 0x1178, 0x00c6, 0x0006, 0x2d60, 0xa00e, 0x080c, 0x524a, + 0x1108, 0xc185, 0x6000, 0xd0bc, 0x0108, 0xc18d, 0x000e, 0x00ce, + 0x0088, 0xa0c6, 0x4007, 0x1110, 0x2408, 0x0060, 0xa0c6, 0x4008, + 0x1118, 0x2708, 0x2610, 0x0030, 0xa0c6, 0x4009, 0x1108, 0x0010, + 0x2001, 0x4006, 0x2020, 0x0804, 0x2fac, 0x2d00, 0x7022, 0x0016, + 0x00b6, 0x00c6, 0x00e6, 0x2c70, 0x080c, 0x85c7, 0x05d8, 0x2d00, + 0x601a, 0x080c, 0xa027, 0x2e58, 0x00ee, 0x00e6, 0x00c6, 0x080c, + 0x3e75, 0x00ce, 0x2b70, 0x1150, 0x080c, 0x861d, 0x00ee, 0x00ce, + 0x00be, 0x001e, 0x2009, 0x0002, 0x0804, 0x2fcf, 0x6837, 0x0000, + 0x683b, 0x0000, 0x2d00, 0x6012, 0x6833, 0x0000, 0x6838, 0xc0fd, + 0xd88c, 0x0108, 0xc0f5, 0x683a, 0x0126, 0x2091, 0x8000, 0x080c, + 0x2c9c, 0x012e, 0x601f, 0x0001, 0x2001, 0x0000, 0x080c, 0x4eeb, + 0x2001, 0x0002, 0x080c, 0x4efd, 0x2009, 0x0002, 0x080c, 0x864c, + 0xa085, 0x0001, 0x00ee, 0x00ce, 0x00be, 0x001e, 0x1120, 0x2009, + 0x0003, 0x0804, 0x2fcf, 0x7007, 0x0003, 0x701b, 0x3da8, 0x0005, + 0x6830, 0xa086, 0x0100, 0x7020, 0x2060, 0x1138, 0x2009, 0x0004, + 0x6204, 0xa294, 0x00ff, 0x0804, 0x2fcf, 0x2009, 0x0000, 0x6838, + 0xd0f4, 0x1904, 0x2faa, 0x080c, 0x524a, 0x1108, 0xc185, 0x6000, + 0xd0bc, 0x0108, 0xc18d, 0x0804, 0x2faa, 0x00e6, 0x00d6, 0xa02e, + 0x2001, 0xb535, 0x2004, 0xd0ac, 0x0130, 0xa026, 0x20a9, 0x00ff, + 0x2071, 0xb635, 0x0030, 0x2021, 0x0080, 0x20a9, 0x007f, 0x2071, + 0xb6b5, 0x2e04, 0xa005, 0x1130, 0x2100, 0xa406, 0x1570, 0x2428, + 0xc5fd, 0x0458, 0x2068, 0x6f10, 0x2700, 0xa306, 0x11b0, 0x6e14, + 0x2600, 0xa206, 0x1190, 0x2400, 0xa106, 0x1160, 0x2d60, 0xd884, + 0x0568, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x1538, 0x2001, + 0x4000, 0x0428, 0x2001, 0x4007, 0x0410, 0x2400, 0xa106, 0x1168, + 0x6e14, 0x87ff, 0x1138, 0x86ff, 0x09d0, 0x2001, 0xb535, 0x2004, + 0xd0ac, 0x19a8, 0x2001, 0x4008, 0x0090, 0x8420, 0x8e70, 0x1f04, + 0x3dd9, 0x85ff, 0x1130, 0x2001, 0x4009, 0x0048, 0x2001, 0x0001, + 0x0030, 0x080c, 0x4f4d, 0x1dd0, 0x6312, 0x6216, 0xa006, 0xa005, + 0x00de, 0x00ee, 0x0005, 0x81ff, 0x1904, 0x2fcf, 0x080c, 0x3e75, + 0x0904, 0x2fcf, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x7824, + 0xa005, 0x0904, 0x2fd2, 0xa096, 0x00ff, 0x0120, 0xa092, 0x0004, + 0x1a04, 0x2fd2, 0x2010, 0x2d18, 0x080c, 0x2c4f, 0x0904, 0x2fcf, + 0x7007, 0x0003, 0x701b, 0x3e45, 0x0005, 0x6830, 0xa086, 0x0100, + 0x0904, 0x2fcf, 0x0804, 0x2faa, 0x7924, 0xa18c, 0xff00, 0x810f, + 0x60d4, 0xd0ac, 0x1120, 0xa182, 0x0080, 0x0a04, 0x2fd2, 0xa182, + 0x00ff, 0x1a04, 0x2fd2, 0x0126, 0x2091, 0x8000, 0x080c, 0x9c8a, + 0x1188, 0xa190, 0xb635, 0x2204, 0xa065, 0x0160, 0x080c, 0x4c0b, + 0x2001, 0xb535, 0x2004, 0xd0ac, 0x0110, 0x6017, 0x0000, 0x012e, + 0x0804, 0x2faa, 0x012e, 0x0804, 0x2fcf, 0x080c, 0x15f8, 0x0188, + 0xa006, 0x6802, 0x7010, 0xa005, 0x1120, 0x2d00, 0x7012, 0x7016, + 0x0030, 0x7014, 0x6802, 0x2060, 0x2d00, 0x6006, 0x7016, 0xad80, + 0x000d, 0x0005, 0x7924, 0x810f, 0xa18c, 0x00ff, 0x080c, 0x4fa9, + 0x1130, 0x7e28, 0xa684, 0x3fff, 0xa082, 0x4000, 0x0208, 0xa066, + 0x8cff, 0x0005, 0x7e24, 0x860f, 0xa18c, 0x00ff, 0x080c, 0x4fa9, + 0x1128, 0xa6b4, 0x00ff, 0xa682, 0x4000, 0x0208, 0xa066, 0x8cff, + 0x0005, 0x0016, 0x7110, 0x81ff, 0x0128, 0x2168, 0x6904, 0x080c, + 0x160f, 0x0cc8, 0x7112, 0x7116, 0x001e, 0x0005, 0x2031, 0x0001, + 0x0010, 0x2031, 0x0000, 0x2061, 0xb5d2, 0x6606, 0x6112, 0x600e, + 0x6226, 0x632a, 0x642e, 0x6532, 0x2c10, 0x080c, 0x1643, 0x7007, + 0x0002, 0x701b, 0x2faa, 0x0005, 0x00f6, 0x0126, 0x2091, 0x8000, + 0x2079, 0x0000, 0x2001, 0xb590, 0x2004, 0xa005, 0x1168, 0x0e04, + 0x3ee4, 0x7818, 0xd084, 0x1140, 0x7a22, 0x7b26, 0x7c2a, 0x781b, + 0x0001, 0x2091, 0x4080, 0x0408, 0x0016, 0x00c6, 0x00e6, 0x2071, + 0xb582, 0x7138, 0xa182, 0x0010, 0x0218, 0x7030, 0x2060, 0x0078, + 0x7030, 0xa0e0, 0x0004, 0xac82, 0xb5d2, 0x0210, 0x2061, 0xb592, + 0x2c00, 0x7032, 0x81ff, 0x1108, 0x7036, 0x8108, 0x713a, 0x2262, + 0x6306, 0x640a, 0x00ee, 0x00ce, 0x001e, 0x012e, 0x00fe, 0x0005, + 0x00e6, 0x2071, 0xb582, 0x7038, 0xa005, 0x0570, 0x0126, 0x2091, + 0x8000, 0x0e04, 0x3f3b, 0x00f6, 0x2079, 0x0000, 0x7818, 0xd084, + 0x1508, 0x00c6, 0x7034, 0x2060, 0x2c04, 0x7822, 0x6004, 0x7826, + 0x6008, 0x782a, 0x781b, 0x0001, 0x2091, 0x4080, 0x7038, 0x8001, + 0x703a, 0xa005, 0x1130, 0x7033, 0xb592, 0x7037, 0xb592, 0x00ce, + 0x0048, 0xac80, 0x0004, 0xa0fa, 0xb5d2, 0x0210, 0x2001, 0xb592, + 0x7036, 0x00ce, 0x00fe, 0x012e, 0x00ee, 0x0005, 0x0026, 0x2001, + 0xb553, 0x2004, 0xd0c4, 0x0120, 0x2011, 0x8014, 0x080c, 0x3ecc, + 0x002e, 0x0005, 0x81ff, 0x1904, 0x2fcf, 0x0126, 0x2091, 0x8000, + 0x6030, 0xc08d, 0xc085, 0xc0ac, 0x6032, 0x080c, 0x5acf, 0x1178, + 0x2001, 0xb79f, 0x2003, 0x0001, 0x2001, 0xb500, 0x2003, 0x0001, + 0xa085, 0x0001, 0x080c, 0x5b13, 0x080c, 0x5a07, 0x0010, 0x080c, + 0x4b1f, 0x012e, 0x0804, 0x2faa, 0x7824, 0x2008, 0xa18c, 0xfffd, + 0x1128, 0x61e0, 0xa10d, 0x61e2, 0x0804, 0x2faa, 0x0804, 0x2fd2, + 0x81ff, 0x1904, 0x2fcf, 0x6000, 0xa086, 0x0003, 0x1904, 0x2fcf, + 0x2001, 0xb553, 0x2004, 0xd0ac, 0x1904, 0x2fcf, 0x080c, 0x3e9a, + 0x0904, 0x2fd2, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x1120, + 0x7828, 0xa005, 0x0904, 0x2faa, 0x00c6, 0x080c, 0x3e75, 0x00ce, + 0x0904, 0x2fcf, 0x6837, 0x0000, 0x6833, 0x0000, 0x6838, 0xc0fd, + 0x683a, 0x080c, 0x9e6b, 0x0904, 0x2fcf, 0x7007, 0x0003, 0x701b, + 0x3faa, 0x0005, 0x6830, 0xa086, 0x0100, 0x0904, 0x2fcf, 0x0804, + 0x2faa, 0x2001, 0xb500, 0x2004, 0xa086, 0x0003, 0x1904, 0x2fcf, + 0x7f24, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x080c, 0x3e75, 0x0904, + 0x2fcf, 0x2009, 0x0000, 0x2031, 0x0000, 0x7023, 0x0000, 0x702f, + 0x0000, 0xad80, 0x0005, 0x7026, 0x20a0, 0x080c, 0x4fa9, 0x1904, + 0x4024, 0x6004, 0xa0c4, 0x00ff, 0xa8c6, 0x0006, 0x0130, 0xa0c4, + 0xff00, 0xa8c6, 0x0600, 0x1904, 0x4024, 0x2001, 0xb553, 0x2004, + 0xd0ac, 0x1128, 0x080c, 0x524a, 0x1110, 0xd79c, 0x05e8, 0xd794, + 0x1110, 0xd784, 0x0158, 0xac80, 0x0006, 0x2098, 0x3400, 0x20a9, + 0x0004, 0x53a3, 0x080c, 0x3ce7, 0xd794, 0x0148, 0xac80, 0x000a, + 0x2098, 0x3400, 0x20a9, 0x0004, 0x53a3, 0x080c, 0x3ce7, 0x21a2, + 0xd794, 0x01d8, 0xac80, 0x0000, 0x2098, 0x94a0, 0x20a9, 0x0002, + 0x53a3, 0xac80, 0x0003, 0x20a6, 0x94a0, 0xac80, 0x0004, 0x2098, + 0x3400, 0x20a9, 0x0002, 0x53a3, 0x080c, 0x3cd9, 0xac80, 0x0026, + 0x2098, 0x20a9, 0x0002, 0x53a3, 0x0008, 0x94a0, 0xd794, 0x0110, + 0xa6b0, 0x000b, 0xa6b0, 0x0005, 0x8108, 0x2001, 0xb535, 0x2004, + 0xd0ac, 0x0118, 0xa186, 0x0100, 0x0040, 0xd78c, 0x0120, 0xa186, + 0x0100, 0x0170, 0x0018, 0xa186, 0x007e, 0x0150, 0xd794, 0x0118, + 0xa686, 0x0020, 0x0010, 0xa686, 0x0028, 0x0150, 0x0804, 0x3fcd, + 0x86ff, 0x1120, 0x7120, 0x810b, 0x0804, 0x2faa, 0x702f, 0x0001, + 0x711e, 0x7020, 0xa600, 0x7022, 0x772a, 0x2061, 0xb5d2, 0x6007, + 0x0000, 0x6612, 0x7024, 0x600e, 0x6226, 0x632a, 0x642e, 0x6532, + 0x2c10, 0x080c, 0x1643, 0x7007, 0x0002, 0x701b, 0x4060, 0x0005, + 0x702c, 0xa005, 0x1170, 0x711c, 0x7024, 0x20a0, 0x7728, 0x2031, + 0x0000, 0x2061, 0xb5d2, 0x6224, 0x6328, 0x642c, 0x6530, 0x0804, + 0x3fcd, 0x7120, 0x810b, 0x0804, 0x2faa, 0x2029, 0x007e, 0x7924, + 0x7a28, 0x7b2c, 0x7c38, 0xa184, 0xff00, 0x8007, 0xa0e2, 0x0020, + 0x0a04, 0x2fd2, 0xa502, 0x0a04, 0x2fd2, 0xa184, 0x00ff, 0xa0e2, + 0x0020, 0x0a04, 0x2fd2, 0xa502, 0x0a04, 0x2fd2, 0xa284, 0xff00, + 0x8007, 0xa0e2, 0x0020, 0x0a04, 0x2fd2, 0xa502, 0x0a04, 0x2fd2, + 0xa284, 0x00ff, 0xa0e2, 0x0020, 0x0a04, 0x2fd2, 0xa502, 0x0a04, + 0x2fd2, 0xa384, 0xff00, 0x8007, 0xa0e2, 0x0020, 0x0a04, 0x2fd2, + 0xa502, 0x0a04, 0x2fd2, 0xa384, 0x00ff, 0xa0e2, 0x0020, 0x0a04, + 0x2fd2, 0xa502, 0x0a04, 0x2fd2, 0xa484, 0xff00, 0x8007, 0xa0e2, + 0x0020, 0x0a04, 0x2fd2, 0xa502, 0x0a04, 0x2fd2, 0xa484, 0x00ff, + 0xa0e2, 0x0020, 0x0a04, 0x2fd2, 0xa502, 0x0a04, 0x2fd2, 0x2061, + 0xb7b9, 0x6102, 0x6206, 0x630a, 0x640e, 0x0804, 0x2faa, 0x0006, + 0x2001, 0xb553, 0x2004, 0xd0cc, 0x000e, 0x0005, 0x0006, 0x2001, + 0xb572, 0x2004, 0xd0bc, 0x000e, 0x0005, 0x6168, 0x7a24, 0x6300, + 0x82ff, 0x1118, 0x7926, 0x0804, 0x2faa, 0x83ff, 0x1904, 0x2fd2, + 0x2001, 0xfff0, 0xa200, 0x1a04, 0x2fd2, 0x2019, 0xffff, 0x606c, + 0xa302, 0xa200, 0x0a04, 0x2fd2, 0x7926, 0x626a, 0x0804, 0x2faa, + 0x2001, 0xb500, 0x2004, 0xa086, 0x0003, 0x1904, 0x2fcf, 0x7c28, + 0x7d24, 0x7e38, 0x7f2c, 0x080c, 0x3e75, 0x0904, 0x2fcf, 0x2009, + 0x0000, 0x2019, 0x0000, 0x7023, 0x0000, 0x702f, 0x0000, 0xad80, + 0x0003, 0x7026, 0x20a0, 0xa1e0, 0xb635, 0x2c64, 0x8cff, 0x01b8, + 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x0130, 0x6004, 0xa084, + 0xff00, 0xa086, 0x0600, 0x1158, 0x6014, 0x20a2, 0x94a0, 0x6010, + 0x8007, 0xa105, 0x8007, 0x20a2, 0x94a0, 0xa398, 0x0002, 0x8108, + 0xa182, 0x00ff, 0x0120, 0xa386, 0x002a, 0x0148, 0x08e0, 0x83ff, + 0x1120, 0x7120, 0x810c, 0x0804, 0x2faa, 0x702f, 0x0001, 0x711e, + 0x7020, 0xa300, 0x7022, 0x2061, 0xb5d2, 0x6007, 0x0000, 0x6312, + 0x7024, 0x600e, 0x6426, 0x652a, 0x662e, 0x6732, 0x2c10, 0x080c, + 0x1643, 0x7007, 0x0002, 0x701b, 0x4156, 0x0005, 0x702c, 0xa005, + 0x1168, 0x711c, 0x7024, 0x20a0, 0x2019, 0x0000, 0x2061, 0xb5d2, + 0x6424, 0x6528, 0x662c, 0x6730, 0x0804, 0x4113, 0x7120, 0x810c, + 0x0804, 0x2faa, 0x81ff, 0x1904, 0x2fcf, 0x60d4, 0xd0ac, 0x1118, + 0xd09c, 0x0904, 0x2fcf, 0x080c, 0x3e75, 0x0904, 0x2fcf, 0x7924, + 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x080c, 0x3eb6, 0x701b, 0x4181, + 0x0005, 0x00d6, 0xade8, 0x000d, 0x6828, 0xa0be, 0x7000, 0x0148, + 0xa0be, 0x7100, 0x0130, 0xa0be, 0x7200, 0x0118, 0x00de, 0x0804, + 0x2fd2, 0x6820, 0x6924, 0x080c, 0x281d, 0x1510, 0x080c, 0x4f4d, + 0x11f8, 0x7122, 0x6612, 0x6516, 0x6e18, 0x00c6, 0x080c, 0x3e75, + 0x01b8, 0x080c, 0x3e75, 0x01a0, 0x00ce, 0x00de, 0x6837, 0x0000, + 0x6838, 0xc0fd, 0x683a, 0x6823, 0x0000, 0x6804, 0x2068, 0x080c, + 0x9dbe, 0x0904, 0x2fcf, 0x7007, 0x0003, 0x701b, 0x41bb, 0x0005, + 0x00de, 0x0804, 0x2fcf, 0x7120, 0x080c, 0x2d97, 0x6820, 0xa086, + 0x8001, 0x0904, 0x2fcf, 0x2d00, 0x701e, 0x6804, 0xa080, 0x0002, + 0x0006, 0x20a9, 0x002a, 0x2098, 0x20a0, 0x080c, 0x4b8f, 0x000e, + 0xade8, 0x000d, 0x6a08, 0x6b0c, 0x6c10, 0x6d14, 0x2061, 0xb5d2, + 0x6007, 0x0000, 0x6e00, 0x6f28, 0xa7c6, 0x7000, 0x1108, 0x0018, + 0xa7c6, 0x7100, 0x1140, 0xa6c2, 0x0004, 0x0a04, 0x2fd2, 0x2009, + 0x0004, 0x0804, 0x3eb9, 0xa7c6, 0x7200, 0x1904, 0x2fd2, 0xa6c2, + 0x0054, 0x0a04, 0x2fd2, 0x600e, 0x6013, 0x002a, 0x6226, 0x632a, + 0x642e, 0x6532, 0x2c10, 0x080c, 0x1643, 0x7007, 0x0002, 0x701b, + 0x4202, 0x0005, 0x701c, 0x2068, 0x6804, 0xa080, 0x0001, 0x2004, + 0xa080, 0x0002, 0x0006, 0x20a9, 0x002a, 0x2098, 0x20a0, 0x080c, + 0x4b8f, 0x000e, 0x2009, 0x002a, 0x2061, 0xb5d2, 0x6224, 0x6328, + 0x642c, 0x6530, 0x0804, 0x3eb9, 0x81ff, 0x1904, 0x2fcf, 0x792c, + 0x2001, 0xb7a0, 0x2102, 0x080c, 0x3e8a, 0x0904, 0x2fd2, 0x080c, + 0x506f, 0x0904, 0x2fcf, 0x0126, 0x2091, 0x8000, 0x080c, 0x51a1, + 0x012e, 0x0804, 0x2faa, 0x7824, 0xd08c, 0x1118, 0xd084, 0x0904, + 0x3a46, 0x080c, 0x3e9a, 0x0904, 0x2fd2, 0x00c6, 0x080c, 0x3e75, + 0x00ce, 0x1120, 0x2009, 0x0002, 0x0804, 0x2fcf, 0x6004, 0xa084, + 0x00ff, 0xa086, 0x0006, 0x0128, 0xa08e, 0x0004, 0x0110, 0xa08e, + 0x0005, 0x15b8, 0x7824, 0xd08c, 0x0120, 0x6000, 0xc08c, 0x6002, + 0x0030, 0x2001, 0xb553, 0x2004, 0xd0b4, 0x0904, 0x3a82, 0x7824, + 0xa084, 0xff00, 0xa08e, 0x7e00, 0x0904, 0x3a82, 0xa08e, 0x7f00, + 0x0904, 0x3a82, 0xa08e, 0x8000, 0x0904, 0x3a82, 0x6000, 0xd08c, + 0x1904, 0x3a82, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x080c, + 0x9dda, 0x1120, 0x2009, 0x0003, 0x0804, 0x2fcf, 0x7007, 0x0003, + 0x701b, 0x4283, 0x0005, 0x080c, 0x3e9a, 0x0904, 0x2fd2, 0x0804, + 0x3a82, 0x2009, 0xb531, 0x210c, 0x81ff, 0x0120, 0x2009, 0x0001, + 0x0804, 0x2fcf, 0x2001, 0xb500, 0x2004, 0xa086, 0x0003, 0x0120, + 0x2009, 0x0007, 0x0804, 0x2fcf, 0x2001, 0xb553, 0x2004, 0xd0ac, + 0x0120, 0x2009, 0x0008, 0x0804, 0x2fcf, 0x609c, 0xd0a4, 0x1118, + 0xd0ac, 0x1904, 0x3a82, 0x6837, 0x0000, 0x6833, 0x0000, 0x6838, + 0xc0fd, 0x683a, 0x080c, 0x9e6b, 0x1120, 0x2009, 0x0003, 0x0804, + 0x2fcf, 0x7007, 0x0003, 0x701b, 0x42be, 0x0005, 0x6830, 0xa086, + 0x0100, 0x1120, 0x2009, 0x0004, 0x0804, 0x2fcf, 0x080c, 0x3e9a, + 0x0904, 0x2fd2, 0x0804, 0x4252, 0x81ff, 0x2009, 0x0001, 0x1904, + 0x2fcf, 0x6000, 0xa086, 0x0003, 0x2009, 0x0007, 0x1904, 0x2fcf, + 0x2001, 0xb553, 0x2004, 0xd0ac, 0x2009, 0x0008, 0x1904, 0x2fcf, + 0x080c, 0x3e9a, 0x0904, 0x2fd2, 0x6004, 0xa084, 0x00ff, 0xa086, + 0x0006, 0x2009, 0x0009, 0x1904, 0x2fcf, 0x00c6, 0x080c, 0x3e75, + 0x00ce, 0x2009, 0x0002, 0x0904, 0x2fcf, 0x6837, 0x0000, 0x6833, + 0x0000, 0x6838, 0xc0fd, 0x683a, 0x7928, 0xa194, 0xff00, 0xa18c, + 0x00ff, 0xa006, 0x82ff, 0x1128, 0xc0ed, 0x6952, 0x792c, 0x6956, + 0x0048, 0xa28e, 0x0100, 0x1904, 0x2fd2, 0xc0e5, 0x6853, 0x0000, + 0x6857, 0x0000, 0x683e, 0x080c, 0xa028, 0x2009, 0x0003, 0x0904, + 0x2fcf, 0x7007, 0x0003, 0x701b, 0x431e, 0x0005, 0x6830, 0xa086, + 0x0100, 0x2009, 0x0004, 0x0904, 0x2fcf, 0x0804, 0x2faa, 0x81ff, + 0x2009, 0x0001, 0x1904, 0x2fcf, 0x6000, 0xa086, 0x0003, 0x2009, + 0x0007, 0x1904, 0x2fcf, 0x080c, 0x3e9a, 0x0904, 0x2fd2, 0x6004, + 0xa084, 0x00ff, 0xa086, 0x0006, 0x2009, 0x0009, 0x1904, 0x2fcf, + 0x00c6, 0x080c, 0x3e75, 0x00ce, 0x2009, 0x0002, 0x0904, 0x2fcf, + 0xad80, 0x000f, 0x2009, 0x0008, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, + 0x080c, 0x3eb6, 0x701b, 0x4355, 0x0005, 0x00d6, 0xade8, 0x000f, + 0x6800, 0xa086, 0x0500, 0x1140, 0x6804, 0xa005, 0x1128, 0x6808, + 0xa084, 0xff00, 0x1108, 0x0018, 0x00de, 0x1904, 0x2fd2, 0x00de, + 0x6837, 0x0000, 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x00c6, + 0x080c, 0x3e9a, 0x1118, 0x00ce, 0x0804, 0x2fd2, 0x080c, 0xa077, + 0x2009, 0x0003, 0x00ce, 0x0904, 0x2fcf, 0x7007, 0x0003, 0x701b, + 0x4382, 0x0005, 0x6830, 0xa086, 0x0100, 0x2009, 0x0004, 0x0904, + 0x2fcf, 0x0804, 0x2faa, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804, + 0x2fcf, 0x6000, 0xa086, 0x0003, 0x0120, 0x2009, 0x0007, 0x0804, + 0x2fcf, 0x7e24, 0x860f, 0xa18c, 0x00ff, 0xa6b4, 0x00ff, 0x080c, + 0x4fa9, 0x1904, 0x2fd2, 0xa186, 0x007f, 0x0150, 0x6004, 0xa084, + 0x00ff, 0xa086, 0x0006, 0x0120, 0x2009, 0x0009, 0x0804, 0x2fcf, + 0x00c6, 0x080c, 0x3e75, 0x00ce, 0x1120, 0x2009, 0x0002, 0x0804, + 0x2fcf, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x2001, 0x0100, + 0x8007, 0x680a, 0x080c, 0x9df5, 0x1120, 0x2009, 0x0003, 0x0804, + 0x2fcf, 0x7007, 0x0003, 0x701b, 0x43ce, 0x0005, 0x6808, 0x8007, + 0xa086, 0x0100, 0x1120, 0x2009, 0x0004, 0x0804, 0x2fcf, 0x68b0, + 0x6836, 0x6810, 0x8007, 0xa084, 0x00ff, 0x800c, 0x6814, 0x8007, + 0xa084, 0x00ff, 0x8004, 0xa080, 0x0002, 0xa108, 0xad80, 0x0004, + 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0804, 0x3eb9, 0x080c, 0x3e75, + 0x1120, 0x2009, 0x0002, 0x0804, 0x2fcf, 0x7924, 0xa194, 0xff00, + 0xa18c, 0x00ff, 0x8217, 0x82ff, 0x0110, 0x0804, 0x2fd2, 0x2009, + 0x001a, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x080c, 0x3eb6, 0x701b, + 0x440a, 0x0005, 0x2001, 0xb52a, 0x2003, 0x0001, 0xad80, 0x000d, + 0x2098, 0x20a9, 0x001a, 0x20a1, 0xb7c6, 0x53a3, 0x0804, 0x2faa, + 0x080c, 0x3e75, 0x1120, 0x2009, 0x0002, 0x0804, 0x2fcf, 0x7924, + 0xa194, 0xff00, 0xa18c, 0x00ff, 0x8217, 0x82ff, 0x0110, 0x0804, + 0x2fd2, 0x2099, 0xb7c6, 0x20a0, 0x20a9, 0x001a, 0x53a3, 0x2009, + 0x001a, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0804, 0x3eb9, 0x7824, + 0xa08a, 0x1000, 0x1a04, 0x2fd2, 0x0126, 0x2091, 0x8000, 0x8003, + 0x800b, 0x810b, 0xa108, 0x00c6, 0x2061, 0xb7f3, 0x6142, 0x00ce, + 0x012e, 0x0804, 0x2faa, 0x00c6, 0x080c, 0x5acf, 0x1188, 0x2001, + 0xb79f, 0x2003, 0x0001, 0x2001, 0xb500, 0x2003, 0x0001, 0xa085, + 0x0001, 0x080c, 0x5b13, 0x080c, 0x5a07, 0x080c, 0x1515, 0x0038, + 0x2061, 0xb500, 0x6030, 0xc09d, 0x6032, 0x080c, 0x4b1f, 0x00ce, + 0x0005, 0x0126, 0x2091, 0x8000, 0x00c6, 0x2061, 0xb7f3, 0x7924, + 0x6152, 0x614e, 0x6057, 0x0000, 0x604b, 0x0009, 0x7838, 0x606a, + 0x783c, 0x6066, 0x7828, 0x6062, 0x782c, 0x605e, 0x2061, 0xb7a1, + 0x2001, 0xb808, 0x600e, 0x6013, 0x0001, 0x6017, 0x0002, 0x6007, + 0x0000, 0x6037, 0x0000, 0x00ce, 0x012e, 0x0804, 0x2faa, 0x0126, + 0x00c6, 0x00e6, 0x2061, 0x0100, 0x2071, 0xb500, 0x6044, 0xd0a4, + 0x11b0, 0xd084, 0x0118, 0x080c, 0x4606, 0x0068, 0xd08c, 0x0118, + 0x080c, 0x4527, 0x0040, 0xd094, 0x0118, 0x080c, 0x44f8, 0x0018, + 0xd09c, 0x0108, 0x0061, 0x00ee, 0x00ce, 0x012e, 0x0005, 0x0016, + 0x6128, 0xd19c, 0x1110, 0xc19d, 0x612a, 0x001e, 0x0ca0, 0x624c, + 0xa286, 0xf0f0, 0x1150, 0x6048, 0xa086, 0xf0f0, 0x0130, 0x624a, + 0x6043, 0x0090, 0x6043, 0x0010, 0x0490, 0xa294, 0xff00, 0xa296, + 0xf700, 0x0178, 0x7134, 0xd1a4, 0x1160, 0x6240, 0xa295, 0x0100, + 0x6242, 0xa294, 0x0010, 0x0128, 0x2009, 0x00f7, 0x080c, 0x4baf, + 0x00f0, 0x6040, 0xa084, 0x0010, 0xa085, 0x0140, 0x6042, 0x6043, + 0x0000, 0x707b, 0x0000, 0x7097, 0x0001, 0x70bb, 0x0000, 0x70d7, + 0x0000, 0x2009, 0xbcc0, 0x200b, 0x0000, 0x708b, 0x0000, 0x707f, + 0x000a, 0x2009, 0x000a, 0x2011, 0x4ad5, 0x080c, 0x6a22, 0x0005, + 0x0156, 0x2001, 0xb574, 0x2004, 0xd08c, 0x0110, 0x7053, 0xffff, + 0x707c, 0xa005, 0x1510, 0x2011, 0x4ad5, 0x080c, 0x699c, 0x6040, + 0xa094, 0x0010, 0xa285, 0x0020, 0x6042, 0x20a9, 0x00c8, 0x6044, + 0xd08c, 0x1168, 0x1f04, 0x450f, 0x6242, 0x708f, 0x0000, 0x6040, + 0xa094, 0x0010, 0xa285, 0x0080, 0x6042, 0x6242, 0x0030, 0x6242, + 0x708f, 0x0000, 0x7083, 0x0000, 0x0000, 0x015e, 0x0005, 0x7080, + 0xa08a, 0x0003, 0x1210, 0x0023, 0x0010, 0x080c, 0x1515, 0x0005, + 0x4533, 0x4583, 0x4605, 0x00f6, 0x7083, 0x0001, 0x20e1, 0xa000, + 0xe000, 0x20e1, 0x8700, 0x080c, 0x2470, 0x20e1, 0x9080, 0x20e1, + 0x4000, 0x2079, 0xbb00, 0x207b, 0x2200, 0x7807, 0x00ef, 0x780b, + 0x0000, 0x780f, 0x00ef, 0x7813, 0x0138, 0x7817, 0x0000, 0x781b, + 0x0000, 0x781f, 0x0000, 0x7823, 0xffff, 0x7827, 0xffff, 0x782b, + 0x0000, 0x782f, 0x0000, 0x2079, 0xbb0c, 0x207b, 0x1101, 0x7807, + 0x0000, 0x2099, 0xb505, 0x20a1, 0xbb0e, 0x20a9, 0x0004, 0x53a3, + 0x2079, 0xbb12, 0x207b, 0x0000, 0x7807, 0x0000, 0x2099, 0xbb00, + 0x20a1, 0x020b, 0x20a9, 0x0014, 0x53a6, 0x60c3, 0x000c, 0x600f, + 0x0000, 0x080c, 0x4b06, 0x00fe, 0x7087, 0x0000, 0x6043, 0x0008, + 0x6043, 0x0000, 0x0005, 0x00d6, 0x7084, 0x7087, 0x0000, 0xa025, + 0x0904, 0x45ed, 0x6020, 0xd0b4, 0x1904, 0x45eb, 0x7194, 0x81ff, + 0x0904, 0x45db, 0xa486, 0x000c, 0x1904, 0x45e6, 0xa480, 0x0018, + 0x8004, 0x20a8, 0x2011, 0xbb80, 0x2019, 0xbb00, 0x220c, 0x2304, + 0xa106, 0x11b8, 0x8210, 0x8318, 0x1f04, 0x459e, 0x6043, 0x0004, + 0x608b, 0xbc94, 0x608f, 0xf0f0, 0x6043, 0x0006, 0x7083, 0x0002, + 0x708f, 0x0002, 0x2009, 0x07d0, 0x2011, 0x4adc, 0x080c, 0x6a22, + 0x0490, 0x2069, 0xbb80, 0x6930, 0xa18e, 0x1101, 0x1538, 0x6834, + 0xa005, 0x1520, 0x6900, 0xa18c, 0x00ff, 0x1118, 0x6804, 0xa005, + 0x0190, 0x2011, 0xbb8e, 0x2019, 0xb505, 0x20a9, 0x0004, 0x220c, + 0x2304, 0xa102, 0x0230, 0x1190, 0x8210, 0x8318, 0x1f04, 0x45cf, + 0x0068, 0x7097, 0x0000, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, + 0xbb80, 0x20a1, 0x020b, 0x20a9, 0x0014, 0x53a6, 0x6043, 0x0008, + 0x6043, 0x0000, 0x0010, 0x00de, 0x0005, 0x6040, 0xa085, 0x0100, + 0x6042, 0x6020, 0xd0b4, 0x1db8, 0x60c3, 0x000c, 0x2011, 0xb7ea, + 0x2013, 0x0000, 0x7087, 0x0000, 0x20e1, 0x9080, 0x60a3, 0x0056, + 0x60a7, 0x9575, 0x080c, 0x7d71, 0x0c30, 0x0005, 0x708c, 0xa08a, + 0x001d, 0x1210, 0x0023, 0x0010, 0x080c, 0x1515, 0x0005, 0x4639, + 0x4648, 0x4670, 0x4689, 0x46ad, 0x46d5, 0x46f9, 0x472a, 0x474e, + 0x4776, 0x47ad, 0x47d5, 0x47f1, 0x4807, 0x4827, 0x483a, 0x4842, + 0x4872, 0x4896, 0x48be, 0x48e2, 0x4913, 0x4950, 0x497f, 0x499b, + 0x49da, 0x49fa, 0x4a13, 0x4a14, 0x00c6, 0x2061, 0xb500, 0x6003, + 0x0007, 0x2061, 0x0100, 0x6004, 0xa084, 0xfff9, 0x6006, 0x00ce, + 0x0005, 0x608b, 0xbc94, 0x608f, 0xf0f0, 0x6043, 0x0002, 0x708f, + 0x0001, 0x2009, 0x07d0, 0x2011, 0x4adc, 0x080c, 0x6a22, 0x0005, + 0x00f6, 0x7084, 0xa086, 0x0014, 0x1508, 0x6043, 0x0000, 0x6020, + 0xd0b4, 0x11e0, 0x2079, 0xbb80, 0x7a30, 0xa296, 0x1102, 0x11a0, + 0x7834, 0xa005, 0x1188, 0x7a38, 0xd2fc, 0x0128, 0x70b8, 0xa005, + 0x1110, 0x70bb, 0x0001, 0x2011, 0x4adc, 0x080c, 0x699c, 0x708f, + 0x0010, 0x080c, 0x4842, 0x0010, 0x080c, 0x4b1f, 0x00fe, 0x0005, + 0x708f, 0x0003, 0x6043, 0x0004, 0x2011, 0x4adc, 0x080c, 0x699c, + 0x080c, 0x4b97, 0x20a3, 0x1102, 0x20a3, 0x0000, 0x20a9, 0x000a, + 0x20a3, 0x0000, 0x1f04, 0x4680, 0x60c3, 0x0014, 0x080c, 0x4b06, + 0x0005, 0x00f6, 0x7084, 0xa005, 0x01f0, 0x2011, 0x4adc, 0x080c, + 0x699c, 0xa086, 0x0014, 0x11a8, 0x2079, 0xbb80, 0x7a30, 0xa296, + 0x1102, 0x1178, 0x7834, 0xa005, 0x1160, 0x7a38, 0xd2fc, 0x0128, + 0x70b8, 0xa005, 0x1110, 0x70bb, 0x0001, 0x708f, 0x0004, 0x0029, + 0x0010, 0x080c, 0x4b1f, 0x00fe, 0x0005, 0x708f, 0x0005, 0x080c, + 0x4b97, 0x20a3, 0x1103, 0x20a3, 0x0000, 0x3430, 0x2011, 0xbb8e, + 0x080c, 0x4be8, 0x1160, 0x7078, 0xa005, 0x1148, 0x7150, 0xa186, + 0xffff, 0x0128, 0x080c, 0x4aa0, 0x0110, 0x080c, 0x4bc6, 0x20a9, + 0x0008, 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x60c3, 0x0014, 0x080c, 0x4b06, 0x0005, 0x00f6, 0x7084, 0xa005, + 0x01f0, 0x2011, 0x4adc, 0x080c, 0x699c, 0xa086, 0x0014, 0x11a8, + 0x2079, 0xbb80, 0x7a30, 0xa296, 0x1103, 0x1178, 0x7834, 0xa005, + 0x1160, 0x7a38, 0xd2fc, 0x0128, 0x70b8, 0xa005, 0x1110, 0x70bb, + 0x0001, 0x708f, 0x0006, 0x0029, 0x0010, 0x080c, 0x4b1f, 0x00fe, + 0x0005, 0x708f, 0x0007, 0x080c, 0x4b97, 0x20a3, 0x1104, 0x20a3, + 0x0000, 0x3430, 0x2011, 0xbb8e, 0x080c, 0x4be8, 0x11a8, 0x7078, + 0xa005, 0x1190, 0x7158, 0xa186, 0xffff, 0x0170, 0xa180, 0x2dc4, + 0x200d, 0xa18c, 0xff00, 0x810f, 0x080c, 0x4aa0, 0x0128, 0x080c, + 0x40d6, 0x0110, 0x080c, 0x2867, 0x20a9, 0x0008, 0x2298, 0x26a0, + 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x080c, + 0x4b06, 0x0005, 0x00f6, 0x7084, 0xa005, 0x01f0, 0x2011, 0x4adc, + 0x080c, 0x699c, 0xa086, 0x0014, 0x11a8, 0x2079, 0xbb80, 0x7a30, + 0xa296, 0x1104, 0x1178, 0x7834, 0xa005, 0x1160, 0x7a38, 0xd2fc, + 0x0128, 0x70b8, 0xa005, 0x1110, 0x70bb, 0x0001, 0x708f, 0x0008, + 0x0029, 0x0010, 0x080c, 0x4b1f, 0x00fe, 0x0005, 0x708f, 0x0009, + 0x080c, 0x4b97, 0x20a3, 0x1105, 0x20a3, 0x0100, 0x3430, 0x080c, + 0x4be8, 0x1150, 0x7078, 0xa005, 0x1138, 0x080c, 0x4a15, 0x1170, + 0xa085, 0x0001, 0x080c, 0x2867, 0x20a9, 0x0008, 0x2099, 0xbb8e, + 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, + 0x080c, 0x4b06, 0x0010, 0x080c, 0x462c, 0x0005, 0x00f6, 0x7084, + 0xa005, 0x0588, 0x2011, 0x4adc, 0x080c, 0x699c, 0xa086, 0x0014, + 0x1540, 0x2079, 0xbb80, 0x7a30, 0xa296, 0x1105, 0x1510, 0x7834, + 0x2011, 0x0100, 0xa21e, 0x1160, 0x7a38, 0xd2fc, 0x0128, 0x70b8, + 0xa005, 0x1110, 0x70bb, 0x0001, 0x708f, 0x000a, 0x00b1, 0x0098, + 0xa005, 0x1178, 0x7a38, 0xd2fc, 0x0128, 0x70b8, 0xa005, 0x1110, + 0x70bb, 0x0001, 0x708b, 0x0000, 0x708f, 0x000e, 0x080c, 0x4827, + 0x0010, 0x080c, 0x4b1f, 0x00fe, 0x0005, 0x708f, 0x000b, 0x2011, + 0xbb0e, 0x22a0, 0x20a9, 0x0040, 0x2019, 0xffff, 0x43a4, 0x20a9, + 0x0002, 0x2009, 0x0000, 0x41a4, 0x080c, 0x4b97, 0x20a3, 0x1106, + 0x20a3, 0x0000, 0x080c, 0x4be8, 0x0118, 0x2013, 0x0000, 0x0020, + 0x7054, 0xa085, 0x0100, 0x2012, 0x2298, 0x20a9, 0x0042, 0x53a6, + 0x60c3, 0x0084, 0x080c, 0x4b06, 0x0005, 0x00f6, 0x7084, 0xa005, + 0x01b0, 0x2011, 0x4adc, 0x080c, 0x699c, 0xa086, 0x0084, 0x1168, + 0x2079, 0xbb80, 0x7a30, 0xa296, 0x1106, 0x1138, 0x7834, 0xa005, + 0x1120, 0x708f, 0x000c, 0x0029, 0x0010, 0x080c, 0x4b1f, 0x00fe, + 0x0005, 0x708f, 0x000d, 0x080c, 0x4b97, 0x20a3, 0x1107, 0x20a3, + 0x0000, 0x2099, 0xbb8e, 0x20a9, 0x0040, 0x53a6, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x60c3, 0x0084, 0x080c, 0x4b06, 0x0005, 0x00f6, + 0x7084, 0xa005, 0x01d0, 0x2011, 0x4adc, 0x080c, 0x699c, 0xa086, + 0x0084, 0x1188, 0x2079, 0xbb80, 0x7a30, 0xa296, 0x1107, 0x1158, + 0x7834, 0xa005, 0x1140, 0x708b, 0x0001, 0x080c, 0x4b89, 0x708f, + 0x000e, 0x0029, 0x0010, 0x080c, 0x4b1f, 0x00fe, 0x0005, 0x708f, + 0x000f, 0x7087, 0x0000, 0x608b, 0xbc85, 0x608f, 0xb5b5, 0x6043, + 0x0005, 0x6043, 0x0004, 0x2009, 0x07d0, 0x2011, 0x4adc, 0x080c, + 0x6990, 0x0005, 0x7084, 0xa005, 0x0120, 0x2011, 0x4adc, 0x080c, + 0x699c, 0x0005, 0x708f, 0x0011, 0x080c, 0x4be8, 0x11a0, 0x7170, + 0x81ff, 0x0188, 0x2009, 0x0000, 0x7074, 0xa084, 0x00ff, 0x080c, + 0x281d, 0xa186, 0x007e, 0x0138, 0xa186, 0x0080, 0x0120, 0x2011, + 0xbb8e, 0x080c, 0x4aa0, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, + 0xbb80, 0x20a1, 0x020b, 0x7484, 0xa480, 0x0018, 0xa080, 0x0007, + 0xa084, 0x03f8, 0x8004, 0x20a8, 0x53a6, 0x60c3, 0x0014, 0x080c, + 0x4b06, 0x0005, 0x00f6, 0x7084, 0xa005, 0x01f0, 0x2011, 0x4adc, + 0x080c, 0x699c, 0xa086, 0x0014, 0x11a8, 0x2079, 0xbb80, 0x7a30, + 0xa296, 0x1103, 0x1178, 0x7834, 0xa005, 0x1160, 0x7a38, 0xd2fc, + 0x0128, 0x70b8, 0xa005, 0x1110, 0x70bb, 0x0001, 0x708f, 0x0012, + 0x0029, 0x0010, 0x080c, 0x4b1f, 0x00fe, 0x0005, 0x708f, 0x0013, + 0x080c, 0x4ba3, 0x20a3, 0x1103, 0x20a3, 0x0000, 0x3430, 0x2011, + 0xbb8e, 0x080c, 0x4be8, 0x1160, 0x7078, 0xa005, 0x1148, 0x7150, + 0xa186, 0xffff, 0x0128, 0x080c, 0x4aa0, 0x0110, 0x080c, 0x4bc6, + 0x20a9, 0x0008, 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x60c3, 0x0014, 0x080c, 0x4b06, 0x0005, 0x00f6, 0x7084, + 0xa005, 0x01f0, 0x2011, 0x4adc, 0x080c, 0x699c, 0xa086, 0x0014, + 0x11a8, 0x2079, 0xbb80, 0x7a30, 0xa296, 0x1104, 0x1178, 0x7834, + 0xa005, 0x1160, 0x7a38, 0xd2fc, 0x0128, 0x70b8, 0xa005, 0x1110, + 0x70bb, 0x0001, 0x708f, 0x0014, 0x0029, 0x0010, 0x080c, 0x4b1f, + 0x00fe, 0x0005, 0x708f, 0x0015, 0x080c, 0x4ba3, 0x20a3, 0x1104, + 0x20a3, 0x0000, 0x3430, 0x2011, 0xbb8e, 0x080c, 0x4be8, 0x11a8, + 0x7078, 0xa005, 0x1190, 0x7158, 0xa186, 0xffff, 0x0170, 0xa180, + 0x2dc4, 0x200d, 0xa18c, 0xff00, 0x810f, 0x080c, 0x4aa0, 0x0128, + 0x080c, 0x40d6, 0x0110, 0x080c, 0x2867, 0x20a9, 0x0008, 0x2298, + 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, + 0x080c, 0x4b06, 0x0005, 0x00f6, 0x7084, 0xa005, 0x05b8, 0x2011, + 0x4adc, 0x080c, 0x699c, 0xa086, 0x0014, 0x1570, 0x2079, 0xbb80, + 0x7a30, 0xa296, 0x1105, 0x1540, 0x7834, 0x2011, 0x0100, 0xa21e, + 0x1148, 0x7a38, 0xd2fc, 0x0128, 0x70b8, 0xa005, 0x1110, 0x70bb, + 0x0001, 0x0060, 0xa005, 0x11c0, 0x7a38, 0xd2fc, 0x0128, 0x70b8, + 0xa005, 0x1110, 0x70bb, 0x0001, 0x708b, 0x0000, 0x7a38, 0xd2f4, + 0x0138, 0x2001, 0xb574, 0x2004, 0xd0a4, 0x1110, 0x70d7, 0x0008, + 0x708f, 0x0016, 0x0029, 0x0010, 0x080c, 0x4b1f, 0x00fe, 0x0005, + 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0xbb80, 0x20a1, 0x020b, + 0x20a9, 0x000e, 0x53a6, 0x3430, 0x2011, 0xbb8e, 0x708f, 0x0017, + 0x080c, 0x4be8, 0x1150, 0x7078, 0xa005, 0x1138, 0x080c, 0x4a15, + 0x1170, 0xa085, 0x0001, 0x080c, 0x2867, 0x20a9, 0x0008, 0x2099, + 0xbb8e, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, + 0x0014, 0x080c, 0x4b06, 0x0010, 0x080c, 0x462c, 0x0005, 0x00f6, + 0x7084, 0xa005, 0x01b0, 0x2011, 0x4adc, 0x080c, 0x699c, 0xa086, + 0x0084, 0x1168, 0x2079, 0xbb80, 0x7a30, 0xa296, 0x1106, 0x1138, + 0x7834, 0xa005, 0x1120, 0x708f, 0x0018, 0x0029, 0x0010, 0x080c, + 0x4b1f, 0x00fe, 0x0005, 0x708f, 0x0019, 0x080c, 0x4ba3, 0x20a3, + 0x1106, 0x20a3, 0x0000, 0x3430, 0x2099, 0xbb8e, 0x2039, 0xbb0e, + 0x27a0, 0x20a9, 0x0040, 0x53a3, 0x080c, 0x4be8, 0x11e8, 0x2728, + 0x2514, 0x8207, 0xa084, 0x00ff, 0x8000, 0x2018, 0xa294, 0x00ff, + 0x8007, 0xa205, 0x202a, 0x7054, 0x2310, 0x8214, 0xa2a0, 0xbb0e, + 0x2414, 0xa38c, 0x0001, 0x0118, 0xa294, 0xff00, 0x0018, 0xa294, + 0x00ff, 0x8007, 0xa215, 0x2222, 0x2798, 0x26a0, 0x20a9, 0x0040, + 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0084, 0x080c, + 0x4b06, 0x0005, 0x00f6, 0x7084, 0xa005, 0x01d0, 0x2011, 0x4adc, + 0x080c, 0x699c, 0xa086, 0x0084, 0x1188, 0x2079, 0xbb80, 0x7a30, + 0xa296, 0x1107, 0x1158, 0x7834, 0xa005, 0x1140, 0x708b, 0x0001, + 0x080c, 0x4b89, 0x708f, 0x001a, 0x0029, 0x0010, 0x080c, 0x4b1f, + 0x00fe, 0x0005, 0x708f, 0x001b, 0x20e1, 0x9080, 0x20e1, 0x4000, + 0x2099, 0xbb80, 0x20a1, 0x020b, 0x7484, 0xa480, 0x0018, 0xa080, + 0x0007, 0xa084, 0x03f8, 0x8004, 0x20a8, 0x53a6, 0x60c3, 0x0084, + 0x080c, 0x4b06, 0x0005, 0x0005, 0x0005, 0x0086, 0x0096, 0x2029, + 0xb553, 0x252c, 0x20a9, 0x0008, 0x2041, 0xbb0e, 0x28a0, 0x2099, + 0xbb8e, 0x53a3, 0x20a9, 0x0008, 0x2011, 0x0007, 0xd5d4, 0x0110, + 0x2011, 0x0000, 0x2800, 0xa200, 0x200c, 0xa1a6, 0xffff, 0x1148, + 0xd5d4, 0x0110, 0x8210, 0x0008, 0x8211, 0x1f04, 0x4a2a, 0x0804, + 0x4a98, 0x82ff, 0x1160, 0xd5d4, 0x0120, 0xa1a6, 0x3fff, 0x0d90, + 0x0020, 0xa1a6, 0x3fff, 0x0904, 0x4a98, 0xa18d, 0xc000, 0x20a9, + 0x0010, 0x2019, 0x0001, 0xd5d4, 0x0110, 0x2019, 0x0010, 0x2120, + 0xd5d4, 0x0110, 0x8423, 0x0008, 0x8424, 0x1240, 0xd5d4, 0x0110, + 0x8319, 0x0008, 0x8318, 0x1f04, 0x4a50, 0x04d0, 0x23a8, 0x2021, + 0x0001, 0x8426, 0x8425, 0x1f04, 0x4a62, 0x2328, 0x8529, 0xa2be, + 0x0007, 0x0158, 0x0006, 0x2039, 0x0007, 0x2200, 0xa73a, 0x000e, + 0x27a8, 0xa5a8, 0x0010, 0x1f04, 0x4a71, 0x7552, 0xa5c8, 0x2dc4, + 0x292d, 0xa5ac, 0x00ff, 0x7576, 0x6532, 0x6536, 0x0016, 0x2508, + 0x080c, 0x2847, 0x001e, 0x60e7, 0x0000, 0x65ea, 0x2018, 0x2304, + 0xa405, 0x201a, 0x707b, 0x0001, 0x26a0, 0x2898, 0x20a9, 0x0008, + 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0xa085, 0x0001, 0x0028, + 0xa006, 0x0018, 0xa006, 0x080c, 0x1515, 0x009e, 0x008e, 0x0005, + 0x2118, 0x2021, 0x0000, 0x2001, 0x0007, 0xa39a, 0x0010, 0x0218, + 0x8420, 0x8001, 0x0cd0, 0x2118, 0x84ff, 0x0120, 0xa39a, 0x0010, + 0x8421, 0x1de0, 0x2021, 0x0001, 0x83ff, 0x0118, 0x8423, 0x8319, + 0x1de8, 0xa238, 0x2704, 0xa42c, 0x11b8, 0xa405, 0x203a, 0x7152, + 0xa1a0, 0x2dc4, 0x242d, 0xa5ac, 0x00ff, 0x7576, 0x6532, 0x6536, + 0x0016, 0x2508, 0x080c, 0x2847, 0x001e, 0x60e7, 0x0000, 0x65ea, + 0x707b, 0x0001, 0xa084, 0x0000, 0x0005, 0x00e6, 0x2071, 0xb500, + 0x707f, 0x0000, 0x00ee, 0x0005, 0x00e6, 0x00f6, 0x2079, 0x0100, + 0x2071, 0x0140, 0x080c, 0x7d7a, 0x7004, 0xa084, 0x4000, 0x0120, + 0x7003, 0x1000, 0x7003, 0x0000, 0x0126, 0x2091, 0x8000, 0x2071, + 0xb523, 0x2073, 0x0000, 0x7840, 0x0026, 0x0016, 0x2009, 0x00f7, + 0x080c, 0x4baf, 0x001e, 0xa094, 0x0010, 0xa285, 0x0080, 0x7842, + 0x7a42, 0x002e, 0x012e, 0x00fe, 0x00ee, 0x0005, 0x0126, 0x2091, + 0x8000, 0x2011, 0xb7ea, 0x2013, 0x0000, 0x7087, 0x0000, 0x012e, + 0x20e1, 0x9080, 0x60a3, 0x0056, 0x60a7, 0x9575, 0x080c, 0x7d71, + 0x2009, 0x07d0, 0x2011, 0x4adc, 0x080c, 0x6a22, 0x0005, 0x0016, + 0x0026, 0x00c6, 0x0126, 0x2091, 0x8000, 0x2011, 0x0003, 0x080c, + 0x8075, 0x2011, 0x0002, 0x080c, 0x807f, 0x080c, 0x7f59, 0x0036, + 0x2019, 0x0000, 0x080c, 0x7fe4, 0x003e, 0x2009, 0x00f7, 0x080c, + 0x4baf, 0x2061, 0xb7f3, 0x601b, 0x0000, 0x601f, 0x0000, 0x2061, + 0xb500, 0x6003, 0x0001, 0x2061, 0x0100, 0x6043, 0x0090, 0x6043, + 0x0010, 0x2009, 0x002d, 0x2011, 0x4b54, 0x080c, 0x6990, 0x012e, + 0x00ce, 0x002e, 0x001e, 0x0005, 0x00e6, 0x0006, 0x0126, 0x2091, + 0x8000, 0x2071, 0x0100, 0x080c, 0x7d7a, 0x2071, 0x0140, 0x7004, + 0xa084, 0x4000, 0x0120, 0x7003, 0x1000, 0x7003, 0x0000, 0x080c, + 0x5ad7, 0x01a8, 0x080c, 0x5af5, 0x1190, 0x2001, 0xb79e, 0x2003, + 0xaaaa, 0x0016, 0x080c, 0x28eb, 0x2001, 0xb78f, 0x2102, 0x001e, + 0x2001, 0xb79f, 0x2003, 0x0000, 0x080c, 0x5a07, 0x0030, 0x2001, + 0x0001, 0x080c, 0x27c3, 0x080c, 0x4b1f, 0x012e, 0x000e, 0x00ee, + 0x0005, 0x20a9, 0x0040, 0x20a1, 0xbcc0, 0x2099, 0xbb8e, 0x3304, + 0x8007, 0x20a2, 0x9398, 0x94a0, 0x1f04, 0x4b8f, 0x0005, 0x20e1, + 0x9080, 0x20e1, 0x4000, 0x2099, 0xbb00, 0x20a1, 0x020b, 0x20a9, + 0x000c, 0x53a6, 0x0005, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, + 0xbb80, 0x20a1, 0x020b, 0x20a9, 0x000c, 0x53a6, 0x0005, 0x00c6, + 0x0006, 0x2061, 0x0100, 0x810f, 0x2001, 0xb531, 0x2004, 0xa005, + 0x1138, 0x2001, 0xb515, 0x2004, 0xa084, 0x00ff, 0xa105, 0x0010, + 0xa185, 0x00f7, 0x604a, 0x000e, 0x00ce, 0x0005, 0x0016, 0x0046, + 0x2001, 0xb553, 0x2004, 0xd0a4, 0x0158, 0xa006, 0x2020, 0x2009, + 0x002a, 0x080c, 0xb0e8, 0x2001, 0xb50c, 0x200c, 0xc195, 0x2102, + 0x2019, 0x002a, 0x2009, 0x0000, 0x080c, 0x2c6f, 0x004e, 0x001e, + 0x0005, 0x080c, 0x4b1f, 0x708f, 0x0000, 0x7087, 0x0000, 0x0005, + 0x0006, 0x2001, 0xb50c, 0x2004, 0xd09c, 0x0100, 0x000e, 0x0005, + 0x0006, 0x0016, 0x0126, 0x2091, 0x8000, 0x2001, 0x0101, 0x200c, + 0xa18d, 0x0006, 0x2102, 0x012e, 0x001e, 0x000e, 0x0005, 0x0156, + 0x20a9, 0x00ff, 0x2009, 0xb635, 0xa006, 0x200a, 0x8108, 0x1f04, + 0x4c05, 0x015e, 0x0005, 0x00d6, 0x0036, 0x0156, 0x0136, 0x0146, + 0x2069, 0xb552, 0xa006, 0x6002, 0x6007, 0x0707, 0x600a, 0x600e, + 0x6012, 0xa198, 0x2dc4, 0x231d, 0xa39c, 0x00ff, 0x6316, 0x20a9, + 0x0004, 0xac98, 0x0006, 0x23a0, 0x40a4, 0x20a9, 0x0004, 0xac98, + 0x000a, 0x23a0, 0x40a4, 0x603e, 0x6042, 0x604e, 0x6052, 0x6056, + 0x605a, 0x605e, 0x6062, 0x6066, 0x606a, 0x606e, 0x6072, 0x6076, + 0x607a, 0x607e, 0x6082, 0x6086, 0x608a, 0x608e, 0x6092, 0x6096, + 0x609a, 0x609e, 0x60ae, 0x61a2, 0x00d6, 0x60a4, 0xa06d, 0x0110, + 0x080c, 0x160f, 0x60a7, 0x0000, 0x60a8, 0xa06d, 0x0110, 0x080c, + 0x160f, 0x60ab, 0x0000, 0x00de, 0xa006, 0x604a, 0x6810, 0x603a, + 0x680c, 0x6046, 0x6814, 0xa084, 0x00ff, 0x6042, 0x014e, 0x013e, + 0x015e, 0x003e, 0x00de, 0x0005, 0x0126, 0x2091, 0x8000, 0x6944, + 0x6e48, 0xa684, 0x3fff, 0xa082, 0x4000, 0x1a04, 0x4d1a, 0xa18c, + 0xff00, 0x810f, 0xa182, 0x00ff, 0x1a04, 0x4d1f, 0x2001, 0xb50c, + 0x2004, 0xa084, 0x0003, 0x01c0, 0x2001, 0xb50c, 0x2004, 0xd084, + 0x1904, 0x4d02, 0xa188, 0xb635, 0x2104, 0xa065, 0x0904, 0x4d02, + 0x6004, 0xa084, 0x00ff, 0xa08e, 0x0006, 0x1904, 0x4d02, 0x6000, + 0xd0c4, 0x0904, 0x4d02, 0x0068, 0xa188, 0xb635, 0x2104, 0xa065, + 0x0904, 0x4ce6, 0x6004, 0xa084, 0x00ff, 0xa08e, 0x0006, 0x1904, + 0x4ceb, 0x60a4, 0xa00d, 0x0118, 0x080c, 0x51d4, 0x05d0, 0x60a8, + 0xa00d, 0x0188, 0x080c, 0x521f, 0x1170, 0x694c, 0xd1fc, 0x1118, + 0x080c, 0x4ede, 0x0448, 0x080c, 0x4e8d, 0x694c, 0xd1ec, 0x1520, + 0x080c, 0x50c6, 0x0408, 0x694c, 0xa184, 0xa000, 0x0178, 0xd1ec, + 0x0140, 0xd1fc, 0x0118, 0x080c, 0x50d5, 0x0028, 0x080c, 0x50d5, + 0x0028, 0xd1fc, 0x0118, 0x080c, 0x4e8d, 0x0070, 0x6050, 0xa00d, + 0x0130, 0x2d00, 0x200a, 0x6803, 0x0000, 0x6052, 0x0028, 0x2d00, + 0x6052, 0x604e, 0x6803, 0x0000, 0x080c, 0x6caa, 0xa006, 0x012e, + 0x0005, 0x2001, 0x0005, 0x2009, 0x0000, 0x04e8, 0x2001, 0x0028, + 0x2009, 0x0000, 0x04c0, 0xa082, 0x0006, 0x12a0, 0x2001, 0xb535, + 0x2004, 0xd0ac, 0x1160, 0x60a0, 0xd0bc, 0x1148, 0x6100, 0xd1fc, + 0x0904, 0x4ca1, 0x2001, 0x0029, 0x2009, 0x1000, 0x0420, 0x2001, + 0x0028, 0x00a8, 0x2009, 0xb50c, 0x210c, 0xd18c, 0x0118, 0x2001, + 0x0004, 0x0068, 0xd184, 0x0118, 0x2001, 0x0004, 0x0040, 0x2001, + 0x0029, 0x6100, 0xd1fc, 0x0118, 0x2009, 0x1000, 0x0060, 0x2009, + 0x0000, 0x0048, 0x2001, 0x0029, 0x2009, 0x0000, 0x0020, 0x2001, + 0x0029, 0x2009, 0x0000, 0xa005, 0x012e, 0x0005, 0x00e6, 0x0126, + 0x2091, 0x8000, 0x6844, 0x8007, 0xa084, 0x00ff, 0x2008, 0xa182, + 0x00ff, 0x1a04, 0x4d79, 0xa188, 0xb635, 0x2104, 0xa065, 0x01c0, + 0x6004, 0xa084, 0x00ff, 0xa08e, 0x0006, 0x11a8, 0x2c70, 0x080c, + 0x85c7, 0x05e8, 0x2e00, 0x601a, 0x2d00, 0x6012, 0x600b, 0xffff, + 0x601f, 0x000a, 0x2009, 0x0003, 0x080c, 0x864c, 0xa006, 0x0460, + 0x2001, 0x0028, 0x0440, 0xa082, 0x0006, 0x1298, 0x2001, 0xb535, + 0x2004, 0xd0ac, 0x1158, 0x60a0, 0xd0bc, 0x1140, 0x6100, 0xd1fc, + 0x09e8, 0x2001, 0x0029, 0x2009, 0x1000, 0x00a8, 0x2001, 0x0028, + 0x0090, 0x2009, 0xb50c, 0x210c, 0xd18c, 0x0118, 0x2001, 0x0004, + 0x0050, 0xd184, 0x0118, 0x2001, 0x0004, 0x0028, 0x2001, 0x0029, + 0x0010, 0x2001, 0x0029, 0xa005, 0x012e, 0x00ee, 0x0005, 0x2001, + 0x002c, 0x0cc8, 0x00f6, 0x00e6, 0x0126, 0x2091, 0x8000, 0x2011, + 0x0000, 0x2079, 0xb500, 0x6944, 0xa18c, 0xff00, 0x810f, 0xa182, + 0x00ff, 0x1a04, 0x4e44, 0x080c, 0x4fa9, 0x11a0, 0x6004, 0xa084, + 0x00ff, 0xa082, 0x0006, 0x1270, 0x6864, 0xa0c6, 0x006f, 0x0150, + 0x2001, 0xb535, 0x2004, 0xd0ac, 0x1904, 0x4e2d, 0x60a0, 0xd0bc, + 0x1904, 0x4e2d, 0x6864, 0xa0c6, 0x006f, 0x0118, 0x2008, 0x0804, + 0x4df6, 0x6968, 0x2140, 0xa18c, 0xff00, 0x810f, 0x78d4, 0xd0ac, + 0x1118, 0xa182, 0x0080, 0x06d0, 0xa182, 0x00ff, 0x16b8, 0x6a70, + 0x6b6c, 0x7870, 0xa306, 0x1160, 0x7874, 0xa24e, 0x1118, 0x2208, + 0x2310, 0x0460, 0xa9cc, 0xff00, 0x1118, 0x2208, 0x2310, 0x0430, + 0x080c, 0x3dc5, 0x2c70, 0x0550, 0x2009, 0x0000, 0x2011, 0x0000, + 0xa0c6, 0x4000, 0x1160, 0x0006, 0x2e60, 0x080c, 0x524a, 0x1108, + 0xc185, 0x7000, 0xd0bc, 0x0108, 0xc18d, 0x000e, 0x0088, 0xa0c6, + 0x4007, 0x1110, 0x2408, 0x0060, 0xa0c6, 0x4008, 0x1118, 0x2708, + 0x2610, 0x0030, 0xa0c6, 0x4009, 0x1108, 0x0010, 0x2001, 0x4006, + 0x6866, 0x696a, 0x6a6e, 0x2001, 0x0030, 0x0450, 0x080c, 0x85c7, + 0x1138, 0x2001, 0x4005, 0x2009, 0x0003, 0x2011, 0x0000, 0x0c80, + 0x2e00, 0x601a, 0x080c, 0xa027, 0x2d00, 0x6012, 0x601f, 0x0001, + 0x6838, 0xd88c, 0x0108, 0xc0f5, 0x683a, 0x0126, 0x2091, 0x8000, + 0x080c, 0x2c9c, 0x012e, 0x2001, 0x0000, 0x080c, 0x4eeb, 0x2001, + 0x0002, 0x080c, 0x4efd, 0x2009, 0x0002, 0x080c, 0x864c, 0xa006, + 0xa005, 0x012e, 0x00ee, 0x00fe, 0x0005, 0x2001, 0x0028, 0x2009, + 0x0000, 0x0cb0, 0x2009, 0xb50c, 0x210c, 0xd18c, 0x0118, 0x2001, + 0x0004, 0x0038, 0xd184, 0x0118, 0x2001, 0x0004, 0x0010, 0x2001, + 0x0029, 0x2009, 0x0000, 0x0c20, 0x2001, 0x0029, 0x2009, 0x0000, + 0x08f8, 0x6944, 0x6e48, 0xa684, 0x3fff, 0xa082, 0x4000, 0x16b8, + 0xa18c, 0xff00, 0x810f, 0xa182, 0x00ff, 0x12e0, 0xa188, 0xb635, + 0x2104, 0xa065, 0x01b8, 0x6004, 0xa084, 0x00ff, 0xa08e, 0x0006, + 0x11b0, 0x684c, 0xd0ec, 0x0120, 0x080c, 0x50d5, 0x0431, 0x0030, + 0x0421, 0x684c, 0xd0fc, 0x0110, 0x080c, 0x50c6, 0x080c, 0x5113, + 0xa006, 0x00c8, 0x2001, 0x0028, 0x2009, 0x0000, 0x00a0, 0xa082, + 0x0006, 0x1240, 0x6100, 0xd1fc, 0x0d20, 0x2001, 0x0029, 0x2009, + 0x1000, 0x0048, 0x2001, 0x0029, 0x2009, 0x0000, 0x0020, 0x2001, + 0x0029, 0x2009, 0x0000, 0xa005, 0x0005, 0x0126, 0x2091, 0x8000, + 0x6050, 0xa00d, 0x0138, 0x2d00, 0x200a, 0x6803, 0x0000, 0x6052, + 0x012e, 0x0005, 0x2d00, 0x6052, 0x604e, 0x6803, 0x0000, 0x0cc0, + 0x0126, 0x2091, 0x8000, 0x604c, 0xa005, 0x0170, 0x00e6, 0x2071, + 0xb7e0, 0x7004, 0xa086, 0x0002, 0x0168, 0x00ee, 0x604c, 0x6802, + 0x2d00, 0x604e, 0x012e, 0x0005, 0x2d00, 0x6052, 0x604e, 0x6803, + 0x0000, 0x0cc0, 0x701c, 0xac06, 0x1d80, 0x604c, 0x2070, 0x7000, + 0x6802, 0x2d00, 0x7002, 0x00ee, 0x012e, 0x0005, 0x0126, 0x2091, + 0x8000, 0x604c, 0xa06d, 0x0130, 0x6800, 0xa005, 0x1108, 0x6052, + 0x604e, 0xad05, 0x012e, 0x0005, 0x604c, 0xa06d, 0x0130, 0x6800, + 0xa005, 0x1108, 0x6052, 0x604e, 0xad05, 0x0005, 0x6803, 0x0000, + 0x6084, 0xa00d, 0x0120, 0x2d00, 0x200a, 0x6086, 0x0005, 0x2d00, + 0x6086, 0x6082, 0x0cd8, 0x0126, 0x00c6, 0x0026, 0x2091, 0x8000, + 0x6218, 0x2260, 0x6200, 0xa005, 0x0110, 0xc285, 0x0008, 0xc284, + 0x6202, 0x002e, 0x00ce, 0x012e, 0x0005, 0x0126, 0x00c6, 0x2091, + 0x8000, 0x6218, 0x2260, 0x6204, 0x0006, 0xa086, 0x0006, 0x1180, + 0x609c, 0xd0ac, 0x0168, 0x2001, 0xb553, 0x2004, 0xd0a4, 0x0140, + 0xa284, 0xff00, 0x8007, 0xa086, 0x0007, 0x1110, 0x2011, 0x0600, + 0x000e, 0xa294, 0xff00, 0xa215, 0x6206, 0x0006, 0xa086, 0x0006, + 0x1128, 0x6290, 0x82ff, 0x1110, 0x080c, 0x1515, 0x000e, 0x00ce, + 0x012e, 0x0005, 0x0126, 0x00c6, 0x2091, 0x8000, 0x6218, 0x2260, + 0x6204, 0x0006, 0xa086, 0x0006, 0x1178, 0x609c, 0xd0a4, 0x0160, + 0x2001, 0xb553, 0x2004, 0xd0ac, 0x1138, 0xa284, 0x00ff, 0xa086, + 0x0007, 0x1110, 0x2011, 0x0006, 0x000e, 0xa294, 0x00ff, 0x8007, + 0xa215, 0x6206, 0x00ce, 0x012e, 0x0005, 0x0026, 0xa182, 0x00ff, + 0x0218, 0xa085, 0x0001, 0x00b0, 0xa190, 0xb635, 0x2204, 0xa065, + 0x1180, 0x0016, 0x00d6, 0x080c, 0x15df, 0x2d60, 0x00de, 0x001e, + 0x0d80, 0x2c00, 0x2012, 0x60a7, 0x0000, 0x60ab, 0x0000, 0x080c, + 0x4c0b, 0xa006, 0x002e, 0x0005, 0x0126, 0x2091, 0x8000, 0x0026, + 0xa182, 0x00ff, 0x0218, 0xa085, 0x0001, 0x0480, 0x00d6, 0xa190, + 0xb635, 0x2204, 0xa06d, 0x0540, 0x2013, 0x0000, 0x00d6, 0x00c6, + 0x2d60, 0x60a4, 0xa06d, 0x0110, 0x080c, 0x160f, 0x60a8, 0xa06d, + 0x0110, 0x080c, 0x160f, 0x00ce, 0x00de, 0x00d6, 0x00c6, 0x68ac, + 0x2060, 0x8cff, 0x0168, 0x600c, 0x0006, 0x6010, 0x2068, 0x080c, + 0x9c5a, 0x0110, 0x080c, 0x161f, 0x080c, 0x861d, 0x00ce, 0x0c88, + 0x00ce, 0x00de, 0x080c, 0x160f, 0x00de, 0xa006, 0x002e, 0x012e, + 0x0005, 0x0016, 0xa182, 0x00ff, 0x0218, 0xa085, 0x0001, 0x0030, + 0xa188, 0xb635, 0x2104, 0xa065, 0x0dc0, 0xa006, 0x001e, 0x0005, + 0x00d6, 0x0156, 0x0136, 0x0146, 0x600b, 0x0000, 0x600f, 0x0000, + 0x6000, 0xc08c, 0x6002, 0x080c, 0x5acf, 0x1558, 0x60a0, 0xa086, + 0x007e, 0x2069, 0xbb90, 0x0130, 0x2001, 0xb535, 0x2004, 0xd0ac, + 0x1500, 0x0098, 0x2d04, 0xd0e4, 0x01e0, 0x00d6, 0x2069, 0xbb8e, + 0x00c6, 0x2061, 0xb7b2, 0x6810, 0x2062, 0x6814, 0x6006, 0x6818, + 0x600a, 0x681c, 0x600e, 0x00ce, 0x00de, 0x8d69, 0x2d04, 0x2069, + 0x0140, 0xa005, 0x1110, 0x2001, 0x0001, 0x6886, 0x2069, 0xb500, + 0x68a6, 0x2069, 0xbb8e, 0x6808, 0x605e, 0x6810, 0x6062, 0x6138, + 0xa10a, 0x0208, 0x603a, 0x6814, 0x6066, 0x2099, 0xbb96, 0xac88, + 0x000a, 0x21a0, 0x20a9, 0x0004, 0x53a3, 0x2099, 0xbb9a, 0xac88, + 0x0006, 0x21a0, 0x20a9, 0x0004, 0x53a3, 0x2069, 0xbbae, 0x6808, + 0x606a, 0x690c, 0x616e, 0x6810, 0x6072, 0x6818, 0x6076, 0x60a0, + 0xa086, 0x007e, 0x1120, 0x2069, 0xbb8e, 0x690c, 0x616e, 0xa182, + 0x0211, 0x1218, 0x2009, 0x0008, 0x0400, 0xa182, 0x0259, 0x1218, + 0x2009, 0x0007, 0x00d0, 0xa182, 0x02c1, 0x1218, 0x2009, 0x0006, + 0x00a0, 0xa182, 0x0349, 0x1218, 0x2009, 0x0005, 0x0070, 0xa182, + 0x0421, 0x1218, 0x2009, 0x0004, 0x0040, 0xa182, 0x0581, 0x1218, + 0x2009, 0x0003, 0x0010, 0x2009, 0x0002, 0x6192, 0x014e, 0x013e, + 0x015e, 0x00de, 0x0005, 0x0016, 0x0026, 0x00e6, 0x2071, 0xbb8d, + 0x2e04, 0x6896, 0x2071, 0xbb8e, 0x7004, 0x689a, 0x701c, 0x689e, + 0x6a00, 0x2009, 0xb572, 0x210c, 0xd0bc, 0x0120, 0xd1ec, 0x0110, + 0xc2ad, 0x0008, 0xc2ac, 0xd0c4, 0x0120, 0xd1e4, 0x0110, 0xc2bd, + 0x0008, 0xc2bc, 0x6a02, 0x00ee, 0x002e, 0x001e, 0x0005, 0x00d6, + 0x0126, 0x2091, 0x8000, 0x60a4, 0xa06d, 0x01c0, 0x6900, 0x81ff, + 0x1540, 0x6a04, 0xa282, 0x0010, 0x1648, 0xad88, 0x0004, 0x20a9, + 0x0010, 0x2104, 0xa086, 0xffff, 0x0128, 0x8108, 0x1f04, 0x5081, + 0x080c, 0x1515, 0x260a, 0x8210, 0x6a06, 0x0098, 0x080c, 0x15f8, + 0x01a8, 0x2d00, 0x60a6, 0x6803, 0x0000, 0xad88, 0x0004, 0x20a9, + 0x0010, 0x200b, 0xffff, 0x8108, 0x1f04, 0x5099, 0x6807, 0x0001, + 0x6e12, 0xa085, 0x0001, 0x012e, 0x00de, 0x0005, 0xa006, 0x0cd8, + 0x0126, 0x2091, 0x8000, 0x00d6, 0x60a4, 0xa00d, 0x01a0, 0x2168, + 0x6800, 0xa005, 0x1160, 0x080c, 0x51d4, 0x1168, 0x200b, 0xffff, + 0x6804, 0xa08a, 0x0002, 0x0218, 0x8001, 0x6806, 0x0020, 0x080c, + 0x160f, 0x60a7, 0x0000, 0x00de, 0x012e, 0x0005, 0x0126, 0x2091, + 0x8000, 0x080c, 0x5232, 0x0010, 0x080c, 0x4e8d, 0x080c, 0x514c, + 0x1dd8, 0x080c, 0x5113, 0x012e, 0x0005, 0x00d6, 0x0126, 0x2091, + 0x8000, 0x60a8, 0xa06d, 0x01c0, 0x6950, 0x81ff, 0x1540, 0x6a54, + 0xa282, 0x0010, 0x1670, 0xad88, 0x0018, 0x20a9, 0x0010, 0x2104, + 0xa086, 0xffff, 0x0128, 0x8108, 0x1f04, 0x50e7, 0x080c, 0x1515, + 0x260a, 0x8210, 0x6a56, 0x0098, 0x080c, 0x15f8, 0x01d0, 0x2d00, + 0x60aa, 0x6853, 0x0000, 0xad88, 0x0018, 0x20a9, 0x0010, 0x200b, + 0xffff, 0x8108, 0x1f04, 0x50ff, 0x6857, 0x0001, 0x6e62, 0x0010, + 0x080c, 0x4ede, 0x0089, 0x1de0, 0xa085, 0x0001, 0x012e, 0x00de, + 0x0005, 0xa006, 0x0cd8, 0x0126, 0x2091, 0x8000, 0x080c, 0x6caa, + 0x012e, 0x0005, 0xa01e, 0x0010, 0x2019, 0x0001, 0xa00e, 0x0126, + 0x2091, 0x8000, 0x604c, 0x2068, 0x6000, 0xd0dc, 0x1170, 0x8dff, + 0x01f8, 0x83ff, 0x0120, 0x6848, 0xa606, 0x0158, 0x0030, 0x683c, + 0xa406, 0x1118, 0x6840, 0xa506, 0x0120, 0x2d08, 0x6800, 0x2068, + 0x0c70, 0x080c, 0x811e, 0x6a00, 0x604c, 0xad06, 0x1110, 0x624e, + 0x0018, 0xa180, 0x0000, 0x2202, 0x82ff, 0x1110, 0x6152, 0x8dff, + 0x012e, 0x0005, 0xa01e, 0x0010, 0x2019, 0x0001, 0xa00e, 0x6080, + 0x2068, 0x8dff, 0x01e8, 0x83ff, 0x0120, 0x6848, 0xa606, 0x0158, + 0x0030, 0x683c, 0xa406, 0x1118, 0x6840, 0xa506, 0x0120, 0x2d08, + 0x6800, 0x2068, 0x0c70, 0x6a00, 0x6080, 0xad06, 0x1110, 0x6282, + 0x0018, 0xa180, 0x0000, 0x2202, 0x82ff, 0x1110, 0x6186, 0x8dff, + 0x0005, 0xa016, 0x080c, 0x51ce, 0x1110, 0x2011, 0x0001, 0x080c, + 0x5219, 0x1110, 0xa295, 0x0002, 0x0005, 0x080c, 0x524a, 0x0118, + 0x080c, 0x9d0f, 0x0010, 0xa085, 0x0001, 0x0005, 0x080c, 0x524a, + 0x0118, 0x080c, 0x9c9f, 0x0010, 0xa085, 0x0001, 0x0005, 0x080c, + 0x524a, 0x0118, 0x080c, 0x9cf2, 0x0010, 0xa085, 0x0001, 0x0005, + 0x080c, 0x524a, 0x0118, 0x080c, 0x9cbb, 0x0010, 0xa085, 0x0001, + 0x0005, 0x080c, 0x524a, 0x0118, 0x080c, 0x9d2b, 0x0010, 0xa085, + 0x0001, 0x0005, 0x0126, 0x0006, 0x00d6, 0x2091, 0x8000, 0x6080, + 0xa06d, 0x01a0, 0x6800, 0x0006, 0x6837, 0x0103, 0x6b4a, 0x6847, + 0x0000, 0x080c, 0x9ecc, 0x0006, 0x6000, 0xd0fc, 0x0110, 0x080c, + 0xb389, 0x000e, 0x080c, 0x5408, 0x000e, 0x0c50, 0x6083, 0x0000, + 0x6087, 0x0000, 0x00de, 0x000e, 0x012e, 0x0005, 0x60a4, 0xa00d, + 0x1118, 0xa085, 0x0001, 0x0005, 0x00e6, 0x2170, 0x7000, 0xa005, + 0x1168, 0x20a9, 0x0010, 0xae88, 0x0004, 0x2104, 0xa606, 0x0130, + 0x8108, 0x1f04, 0x51dd, 0xa085, 0x0001, 0x0008, 0xa006, 0x00ee, + 0x0005, 0x00d6, 0x0126, 0x2091, 0x8000, 0x60a4, 0xa06d, 0x1128, + 0x080c, 0x15f8, 0x01a0, 0x2d00, 0x60a6, 0x6803, 0x0001, 0x6807, + 0x0000, 0xad88, 0x0004, 0x20a9, 0x0010, 0x200b, 0xffff, 0x8108, + 0x1f04, 0x51fd, 0xa085, 0x0001, 0x012e, 0x00de, 0x0005, 0xa006, + 0x0cd8, 0x00d6, 0x0126, 0x2091, 0x8000, 0x60a4, 0xa06d, 0x0130, + 0x60a7, 0x0000, 0x080c, 0x160f, 0xa085, 0x0001, 0x012e, 0x00de, + 0x0005, 0x60a8, 0xa00d, 0x1118, 0xa085, 0x0001, 0x0005, 0x00e6, + 0x2170, 0x7050, 0xa005, 0x1160, 0x20a9, 0x0010, 0xae88, 0x0018, + 0x2104, 0xa606, 0x0128, 0x8108, 0x1f04, 0x5228, 0xa085, 0x0001, + 0x00ee, 0x0005, 0x0126, 0x2091, 0x8000, 0x0c19, 0x1188, 0x200b, + 0xffff, 0x00d6, 0x60a8, 0x2068, 0x6854, 0xa08a, 0x0002, 0x0218, + 0x8001, 0x6856, 0x0020, 0x080c, 0x160f, 0x60ab, 0x0000, 0x00de, + 0x012e, 0x0005, 0x609c, 0xd0a4, 0x0005, 0x00f6, 0x080c, 0x5acf, + 0x01b0, 0x71b8, 0x81ff, 0x1198, 0x71d4, 0xd19c, 0x0180, 0x2001, + 0x007e, 0xa080, 0xb635, 0x2004, 0xa07d, 0x0148, 0x7804, 0xa084, + 0x00ff, 0xa086, 0x0006, 0x1118, 0x7800, 0xc0ed, 0x7802, 0x2079, + 0xb552, 0x7804, 0xd0a4, 0x01e8, 0x0156, 0x00c6, 0x20a9, 0x007f, + 0x2009, 0x0000, 0x0016, 0x080c, 0x4fa9, 0x1168, 0x6004, 0xa084, + 0xff00, 0x8007, 0xa096, 0x0004, 0x0118, 0xa086, 0x0006, 0x1118, + 0x6000, 0xc0ed, 0x6002, 0x001e, 0x8108, 0x1f04, 0x5272, 0x00ce, + 0x015e, 0x080c, 0x5309, 0x0120, 0x2001, 0xb7b5, 0x200c, 0x0038, + 0x2079, 0xb552, 0x7804, 0xd0a4, 0x0130, 0x2009, 0x07d0, 0x2011, + 0x529d, 0x080c, 0x6a22, 0x00fe, 0x0005, 0x2011, 0x529d, 0x080c, + 0x699c, 0x080c, 0x5309, 0x01f0, 0x2001, 0xb6b3, 0x2004, 0xa080, + 0x0000, 0x200c, 0xc1ec, 0x2102, 0x2001, 0xb553, 0x2004, 0xd0a4, + 0x0130, 0x2009, 0x07d0, 0x2011, 0x529d, 0x080c, 0x6a22, 0x00e6, + 0x2071, 0xb500, 0x7073, 0x0000, 0x7077, 0x0000, 0x080c, 0x2ab8, + 0x00ee, 0x04b0, 0x0156, 0x00c6, 0x20a9, 0x007f, 0x2009, 0x0000, + 0x0016, 0x080c, 0x4fa9, 0x1530, 0x6000, 0xd0ec, 0x0518, 0x0046, + 0x62a0, 0xa294, 0x00ff, 0x8227, 0xa006, 0x2009, 0x0029, 0x080c, + 0xb0e8, 0x6000, 0xc0e5, 0xc0ec, 0x6002, 0x6004, 0xa084, 0x00ff, + 0xa085, 0x0700, 0x6006, 0x2019, 0x0029, 0x080c, 0x6df5, 0x0076, + 0x2039, 0x0000, 0x080c, 0x6d02, 0x2009, 0x0000, 0x080c, 0xae82, + 0x007e, 0x004e, 0x001e, 0x8108, 0x1f04, 0x52c8, 0x00ce, 0x015e, + 0x0005, 0x00c6, 0x6018, 0x2060, 0x6000, 0xc0ec, 0x6002, 0x00ce, + 0x0005, 0x7818, 0x2004, 0xd0ac, 0x0005, 0x7818, 0x2004, 0xd0bc, + 0x0005, 0x00f6, 0x2001, 0xb6b3, 0x2004, 0xa07d, 0x0110, 0x7800, + 0xd0ec, 0x00fe, 0x0005, 0x0126, 0x0026, 0x2091, 0x8000, 0x0006, + 0x62a0, 0xa290, 0xb635, 0x2204, 0xac06, 0x190c, 0x1515, 0x000e, + 0x6200, 0xa005, 0x0110, 0xc2fd, 0x0008, 0xc2fc, 0x6202, 0x002e, + 0x012e, 0x0005, 0x2011, 0xb535, 0x2204, 0xd0cc, 0x0138, 0x2001, + 0xb7b3, 0x200c, 0x2011, 0x5337, 0x080c, 0x6a22, 0x0005, 0x2011, + 0x5337, 0x080c, 0x699c, 0x2011, 0xb535, 0x2204, 0xc0cc, 0x2012, + 0x0005, 0x2071, 0xb614, 0x7003, 0x0001, 0x7007, 0x0000, 0x7013, + 0x0000, 0x7017, 0x0000, 0x701b, 0x0000, 0x701f, 0x0000, 0x700b, + 0x0000, 0x704b, 0x0001, 0x704f, 0x0000, 0x705b, 0x0020, 0x705f, + 0x0040, 0x707f, 0x0000, 0x2071, 0xb77d, 0x7003, 0xb614, 0x7007, + 0x0000, 0x700b, 0x0000, 0x700f, 0xb75d, 0x7013, 0x0020, 0x7017, + 0x0040, 0x7037, 0x0000, 0x0005, 0x0016, 0x00e6, 0x2071, 0xb735, + 0xa00e, 0x7186, 0x718a, 0x7097, 0x0001, 0x2001, 0xb553, 0x2004, + 0xd0fc, 0x1150, 0x2001, 0xb553, 0x2004, 0xa00e, 0xd09c, 0x0108, + 0x8108, 0x7102, 0x0804, 0x53d2, 0x2001, 0xb572, 0x200c, 0xa184, + 0x000f, 0x2009, 0xb573, 0x210c, 0x0002, 0x537a, 0x53ad, 0x53b4, + 0x53be, 0x53c3, 0x537a, 0x537a, 0x537a, 0x539d, 0x537a, 0x537a, + 0x537a, 0x537a, 0x537a, 0x537a, 0x537a, 0x7003, 0x0004, 0x0136, + 0x0146, 0x0156, 0x2099, 0xb576, 0x20a1, 0xb786, 0x20a9, 0x0004, + 0x53a3, 0x015e, 0x014e, 0x013e, 0x0428, 0x708f, 0x0005, 0x7007, + 0x0122, 0x2001, 0x0002, 0x0030, 0x708f, 0x0002, 0x7007, 0x0121, + 0x2001, 0x0003, 0x7002, 0x7097, 0x0001, 0x0088, 0x7007, 0x0122, + 0x2001, 0x0002, 0x0020, 0x7007, 0x0121, 0x2001, 0x0003, 0x7002, + 0xa006, 0x7096, 0x708e, 0xa184, 0xff00, 0x8007, 0x709a, 0xa184, + 0x00ff, 0x7092, 0x00ee, 0x001e, 0x0005, 0x00e6, 0x2071, 0xb614, + 0x684c, 0xa005, 0x1130, 0x7028, 0xc085, 0x702a, 0xa085, 0x0001, + 0x0428, 0x6a60, 0x7236, 0x6b64, 0x733a, 0x6868, 0x703e, 0x7076, + 0x686c, 0x7042, 0x707a, 0x684c, 0x702e, 0x6844, 0x7032, 0x2009, + 0x000d, 0x200a, 0x700b, 0x0000, 0x8007, 0x8006, 0x8006, 0xa08c, + 0x003f, 0xa084, 0xffc0, 0xa210, 0x2100, 0xa319, 0x726e, 0x7372, + 0x7028, 0xc084, 0x702a, 0x7007, 0x0001, 0xa006, 0x00ee, 0x0005, + 0x0156, 0x00e6, 0x0026, 0x6838, 0xd0fc, 0x1904, 0x5461, 0x6804, + 0xa00d, 0x0188, 0x00d6, 0x2071, 0xb500, 0xa016, 0x702c, 0x2168, + 0x6904, 0x206a, 0x8210, 0x2d00, 0x81ff, 0x1dc8, 0x702e, 0x70b4, + 0xa200, 0x70b6, 0x00de, 0x2071, 0xb614, 0x701c, 0xa005, 0x1904, + 0x5471, 0x20a9, 0x0032, 0x0f04, 0x546f, 0x0e04, 0x542b, 0x2071, + 0xb735, 0x7200, 0x82ff, 0x05d8, 0x6934, 0xa186, 0x0103, 0x1904, + 0x547f, 0x6948, 0x6844, 0xa105, 0x1540, 0x2009, 0x8020, 0x2200, + 0x0002, 0x546f, 0x5446, 0x5497, 0x54a3, 0x546f, 0x2071, 0x0000, + 0x20a9, 0x0032, 0x0f04, 0x546f, 0x7018, 0xd084, 0x1dd8, 0x7122, + 0x683c, 0x7026, 0x6840, 0x702a, 0x701b, 0x0001, 0x2091, 0x4080, + 0x2071, 0xb500, 0x702c, 0x206a, 0x2d00, 0x702e, 0x70b4, 0x8000, + 0x70b6, 0x002e, 0x00ee, 0x015e, 0x0005, 0x6844, 0xa086, 0x0100, + 0x1130, 0x6868, 0xa005, 0x1118, 0x2009, 0x8020, 0x0880, 0x2071, + 0xb614, 0x2d08, 0x206b, 0x0000, 0x7010, 0x8000, 0x7012, 0x7018, + 0xa06d, 0x711a, 0x0110, 0x6902, 0x0008, 0x711e, 0x0c10, 0xa18c, + 0x00ff, 0xa186, 0x0017, 0x0130, 0xa186, 0x001e, 0x0118, 0xa18e, + 0x001f, 0x1d28, 0x684c, 0xd0cc, 0x0d10, 0x6850, 0xa084, 0x00ff, + 0xa086, 0x0001, 0x19e0, 0x2009, 0x8021, 0x0804, 0x543f, 0x7084, + 0x8008, 0xa092, 0x001e, 0x1a98, 0x7186, 0xae90, 0x0003, 0xa210, + 0x683c, 0x2012, 0x0078, 0x7084, 0x8008, 0xa092, 0x000f, 0x1a38, + 0x7186, 0xae90, 0x0003, 0x8003, 0xa210, 0x683c, 0x2012, 0x8210, + 0x6840, 0x2012, 0x7088, 0xa10a, 0x0a04, 0x5458, 0x718c, 0x7084, + 0xa10a, 0x0a04, 0x5458, 0x2071, 0x0000, 0x7018, 0xd084, 0x1904, + 0x5458, 0x2071, 0xb735, 0x7000, 0xa086, 0x0002, 0x1150, 0x080c, + 0x5722, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0804, + 0x5458, 0x080c, 0x574c, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, + 0x4080, 0x0804, 0x5458, 0x0006, 0x684c, 0x0006, 0x6837, 0x0103, + 0x20a9, 0x001c, 0xad80, 0x0011, 0x20a0, 0x2001, 0x0000, 0x40a4, + 0x000e, 0xa084, 0x00ff, 0x684e, 0x000e, 0x684a, 0x6952, 0x0005, + 0x2071, 0xb614, 0x7004, 0x0002, 0x54fe, 0x550f, 0x570d, 0x570e, + 0x571b, 0x5721, 0x54ff, 0x56fe, 0x5694, 0x56ea, 0x0005, 0x0126, + 0x2091, 0x8000, 0x0e04, 0x550e, 0x2009, 0x000d, 0x7030, 0x200a, + 0x2091, 0x4080, 0x7007, 0x0001, 0x700b, 0x0000, 0x012e, 0x2069, + 0xb7f3, 0x683c, 0xa005, 0x03f8, 0x11f0, 0x0126, 0x2091, 0x8000, + 0x2069, 0x0000, 0x6934, 0x2001, 0xb620, 0x2004, 0xa10a, 0x0170, + 0x0e04, 0x5532, 0x2069, 0x0000, 0x6818, 0xd084, 0x1158, 0x2009, + 0x8040, 0x6922, 0x681b, 0x0001, 0x2091, 0x4080, 0x2069, 0xb7f3, + 0x683f, 0xffff, 0x012e, 0x2069, 0xb500, 0x6848, 0x6968, 0xa102, + 0x2069, 0xb735, 0x688a, 0x6984, 0x701c, 0xa06d, 0x0120, 0x81ff, + 0x0904, 0x5588, 0x00a0, 0x81ff, 0x0904, 0x564e, 0x2071, 0xb735, + 0x7184, 0x7088, 0xa10a, 0x1258, 0x7190, 0x2071, 0xb7f3, 0x7038, + 0xa005, 0x0128, 0x1b04, 0x564e, 0x713a, 0x0804, 0x564e, 0x2071, + 0xb735, 0x718c, 0x0126, 0x2091, 0x8000, 0x7084, 0xa10a, 0x0a04, + 0x5669, 0x0e04, 0x560a, 0x2071, 0x0000, 0x7018, 0xd084, 0x1904, + 0x560a, 0x2001, 0xffff, 0x2071, 0xb7f3, 0x703a, 0x2071, 0xb735, + 0x7000, 0xa086, 0x0002, 0x1150, 0x080c, 0x5722, 0x2071, 0x0000, + 0x701b, 0x0001, 0x2091, 0x4080, 0x0804, 0x560a, 0x080c, 0x574c, + 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0804, 0x560a, + 0x2071, 0xb735, 0x7000, 0xa005, 0x0904, 0x5630, 0x6934, 0xa186, + 0x0103, 0x1904, 0x560d, 0x684c, 0xd0bc, 0x1904, 0x5630, 0x6948, + 0x6844, 0xa105, 0x1904, 0x5625, 0x2009, 0x8020, 0x2071, 0xb735, + 0x7000, 0x0002, 0x5630, 0x55f0, 0x55c8, 0x55da, 0x55a7, 0x0136, + 0x0146, 0x0156, 0x2099, 0xb576, 0x20a1, 0xb786, 0x20a9, 0x0004, + 0x53a3, 0x015e, 0x014e, 0x013e, 0x2071, 0xb77d, 0xad80, 0x000f, + 0x700e, 0x7013, 0x0002, 0x7007, 0x0002, 0x700b, 0x0000, 0x2e10, + 0x080c, 0x1643, 0x2071, 0xb614, 0x7007, 0x0009, 0x0804, 0x564e, + 0x7084, 0x8008, 0xa092, 0x001e, 0x1a04, 0x564e, 0xae90, 0x0003, + 0xa210, 0x683c, 0x2012, 0x7186, 0x2071, 0xb614, 0x080c, 0x57a3, + 0x0804, 0x564e, 0x7084, 0x8008, 0xa092, 0x000f, 0x1a04, 0x564e, + 0xae90, 0x0003, 0x8003, 0xa210, 0x683c, 0x2012, 0x8210, 0x6840, + 0x2012, 0x7186, 0x2071, 0xb614, 0x080c, 0x57a3, 0x0804, 0x564e, + 0x0126, 0x2091, 0x8000, 0x0e04, 0x560a, 0x2071, 0x0000, 0x7018, + 0xd084, 0x1180, 0x7122, 0x683c, 0x7026, 0x6840, 0x702a, 0x701b, + 0x0001, 0x2091, 0x4080, 0x012e, 0x2071, 0xb614, 0x080c, 0x57a3, + 0x0804, 0x564e, 0x012e, 0x0804, 0x564e, 0xa18c, 0x00ff, 0xa186, + 0x0017, 0x0130, 0xa186, 0x001e, 0x0118, 0xa18e, 0x001f, 0x11c0, + 0x684c, 0xd0cc, 0x01a8, 0x6850, 0xa084, 0x00ff, 0xa086, 0x0001, + 0x1178, 0x2009, 0x8021, 0x0804, 0x559e, 0x6844, 0xa086, 0x0100, + 0x1138, 0x6868, 0xa005, 0x1120, 0x2009, 0x8020, 0x0804, 0x559e, + 0x2071, 0xb614, 0x080c, 0x57b5, 0x01c8, 0x2071, 0xb614, 0x700f, + 0x0001, 0x6934, 0xa184, 0x00ff, 0xa086, 0x0003, 0x1130, 0x810f, + 0xa18c, 0x00ff, 0x8101, 0x0108, 0x710e, 0x7007, 0x0003, 0x080c, + 0x57ce, 0x7050, 0xa086, 0x0100, 0x0904, 0x570e, 0x0126, 0x2091, + 0x8000, 0x2071, 0xb614, 0x7008, 0xa086, 0x0001, 0x1180, 0x0e04, + 0x5667, 0x2009, 0x000d, 0x7030, 0x200a, 0x2091, 0x4080, 0x700b, + 0x0000, 0x7004, 0xa086, 0x0006, 0x1110, 0x7007, 0x0001, 0x012e, + 0x0005, 0x2071, 0xb614, 0x080c, 0x57b5, 0x0518, 0x2071, 0xb735, + 0x7084, 0x700a, 0x20a9, 0x0020, 0x2099, 0xb736, 0x20a1, 0xb75d, + 0x53a3, 0x7087, 0x0000, 0x2071, 0xb614, 0x2069, 0xb77d, 0x706c, + 0x6826, 0x7070, 0x682a, 0x7074, 0x682e, 0x7078, 0x6832, 0x2d10, + 0x080c, 0x1643, 0x7007, 0x0008, 0x2001, 0xffff, 0x2071, 0xb7f3, + 0x703a, 0x012e, 0x0804, 0x564e, 0x2069, 0xb77d, 0x6808, 0xa08e, + 0x0000, 0x0904, 0x56e9, 0xa08e, 0x0200, 0x0904, 0x56e7, 0xa08e, + 0x0100, 0x1904, 0x56e9, 0x0126, 0x2091, 0x8000, 0x0e04, 0x56e5, + 0x2069, 0x0000, 0x6818, 0xd084, 0x15c0, 0x702c, 0x7130, 0x8108, + 0xa102, 0x0230, 0xa00e, 0x7034, 0x706e, 0x7038, 0x7072, 0x0048, + 0x706c, 0xa080, 0x0040, 0x706e, 0x1220, 0x7070, 0xa081, 0x0000, + 0x7072, 0x7132, 0x6936, 0x700b, 0x0000, 0x2001, 0xb75a, 0x2004, + 0xa005, 0x1190, 0x6934, 0x2069, 0xb735, 0x689c, 0x699e, 0x2069, + 0xb7f3, 0xa102, 0x1118, 0x683c, 0xa005, 0x1368, 0x2001, 0xb75b, + 0x200c, 0x810d, 0x693e, 0x0038, 0x2009, 0x8040, 0x6922, 0x681b, + 0x0001, 0x2091, 0x4080, 0x7007, 0x0001, 0x012e, 0x0010, 0x7007, + 0x0005, 0x0005, 0x2001, 0xb77f, 0x2004, 0xa08e, 0x0100, 0x1128, + 0x7007, 0x0001, 0x080c, 0x57a3, 0x0005, 0xa08e, 0x0000, 0x0de0, + 0xa08e, 0x0200, 0x1dc8, 0x7007, 0x0005, 0x0005, 0x701c, 0xa06d, + 0x0158, 0x080c, 0x57b5, 0x0140, 0x7007, 0x0003, 0x080c, 0x57ce, + 0x7050, 0xa086, 0x0100, 0x0110, 0x0005, 0x0005, 0x7050, 0xa09e, + 0x0100, 0x1118, 0x7007, 0x0004, 0x0030, 0xa086, 0x0200, 0x1110, + 0x7007, 0x0005, 0x0005, 0x080c, 0x5771, 0x7006, 0x080c, 0x57a3, + 0x0005, 0x0005, 0x00e6, 0x0156, 0x2071, 0xb735, 0x7184, 0x81ff, + 0x0500, 0xa006, 0x7086, 0xae80, 0x0003, 0x2071, 0x0000, 0x21a8, + 0x2014, 0x7226, 0x8000, 0x0f04, 0x5746, 0x2014, 0x722a, 0x8000, + 0x0f04, 0x5746, 0x2014, 0x722e, 0x8000, 0x0f04, 0x5746, 0x2014, + 0x723a, 0x8000, 0x0f04, 0x5746, 0x2014, 0x723e, 0xa180, 0x8030, + 0x7022, 0x015e, 0x00ee, 0x0005, 0x00e6, 0x0156, 0x2071, 0xb735, + 0x7184, 0x81ff, 0x01d8, 0xa006, 0x7086, 0xae80, 0x0003, 0x2071, + 0x0000, 0x21a8, 0x2014, 0x7226, 0x8000, 0x2014, 0x722a, 0x8000, + 0x0f04, 0x5768, 0x2014, 0x723a, 0x8000, 0x2014, 0x723e, 0x0018, + 0x2001, 0x8020, 0x0010, 0x2001, 0x8042, 0x7022, 0x015e, 0x00ee, + 0x0005, 0x702c, 0x7130, 0x8108, 0xa102, 0x0230, 0xa00e, 0x7034, + 0x706e, 0x7038, 0x7072, 0x0048, 0x706c, 0xa080, 0x0040, 0x706e, + 0x1220, 0x7070, 0xa081, 0x0000, 0x7072, 0x7132, 0x700c, 0x8001, + 0x700e, 0x1180, 0x0126, 0x2091, 0x8000, 0x0e04, 0x579d, 0x2001, + 0x000d, 0x2102, 0x2091, 0x4080, 0x2001, 0x0001, 0x700b, 0x0000, + 0x012e, 0x0005, 0x2001, 0x0007, 0x0005, 0x2001, 0x0006, 0x700b, + 0x0001, 0x012e, 0x0005, 0x701c, 0xa06d, 0x0170, 0x0126, 0x2091, + 0x8000, 0x7010, 0x8001, 0x7012, 0x2d04, 0x701e, 0xa005, 0x1108, + 0x701a, 0x012e, 0x080c, 0x160f, 0x0005, 0x2019, 0x000d, 0x2304, + 0x230c, 0xa10e, 0x0130, 0x2304, 0x230c, 0xa10e, 0x0110, 0xa006, + 0x0060, 0x732c, 0x8319, 0x7130, 0xa102, 0x1118, 0x2300, 0xa005, + 0x0020, 0x0210, 0xa302, 0x0008, 0x8002, 0x0005, 0x2d00, 0x7026, + 0xa080, 0x000d, 0x7056, 0x7053, 0x0000, 0x0126, 0x2091, 0x8000, + 0x2009, 0xb812, 0x2104, 0xc08d, 0x200a, 0x012e, 0x080c, 0x165f, + 0x0005, 0x708c, 0xa08a, 0x0029, 0x1220, 0xa082, 0x001d, 0x0033, + 0x0010, 0x080c, 0x1515, 0x6027, 0x1e00, 0x0005, 0x58dc, 0x5857, + 0x586f, 0x58ac, 0x58cd, 0x5907, 0x5919, 0x586f, 0x58f3, 0x57fb, + 0x5829, 0x57fa, 0x0005, 0x00d6, 0x2069, 0x0200, 0x6804, 0xa005, + 0x1180, 0x6808, 0xa005, 0x1518, 0x708f, 0x0028, 0x2069, 0xb7c5, + 0x2d04, 0x7002, 0x080c, 0x5bd1, 0x6028, 0xa085, 0x0600, 0x602a, + 0x00b0, 0x708f, 0x0028, 0x2069, 0xb7c5, 0x2d04, 0x7002, 0x6028, + 0xa085, 0x0600, 0x602a, 0x00e6, 0x0036, 0x0046, 0x0056, 0x2071, + 0xb823, 0x080c, 0x1dfe, 0x005e, 0x004e, 0x003e, 0x00ee, 0x00de, + 0x0005, 0x00d6, 0x2069, 0x0200, 0x6804, 0xa005, 0x1180, 0x6808, + 0xa005, 0x1518, 0x708f, 0x0028, 0x2069, 0xb7c5, 0x2d04, 0x7002, + 0x080c, 0x5c5e, 0x6028, 0xa085, 0x0600, 0x602a, 0x00b0, 0x708f, + 0x0028, 0x2069, 0xb7c5, 0x2d04, 0x7002, 0x6028, 0xa085, 0x0600, + 0x602a, 0x00e6, 0x0036, 0x0046, 0x0056, 0x2071, 0xb823, 0x080c, + 0x1dfe, 0x005e, 0x004e, 0x003e, 0x00ee, 0x00de, 0x0005, 0x6803, + 0x0090, 0x6124, 0xd1e4, 0x1190, 0x080c, 0x5984, 0xd1d4, 0x1160, + 0xd1dc, 0x1138, 0xd1cc, 0x0150, 0x708f, 0x0020, 0x080c, 0x5984, + 0x0028, 0x708f, 0x001d, 0x0010, 0x708f, 0x001f, 0x0005, 0x6803, + 0x0088, 0x6124, 0xd1cc, 0x1590, 0xd1dc, 0x1568, 0xd1e4, 0x1540, + 0xa184, 0x1e00, 0x1580, 0x60e3, 0x0001, 0x600c, 0xc0b4, 0x600e, + 0x080c, 0x5aff, 0x080c, 0x24b0, 0x0156, 0x6803, 0x0100, 0x20a9, + 0x0014, 0x6804, 0xd0dc, 0x1118, 0x1f04, 0x5889, 0x0048, 0x20a9, + 0x0014, 0x6803, 0x0080, 0x6804, 0xd0d4, 0x1130, 0x1f04, 0x5893, + 0x080c, 0x5b20, 0x015e, 0x0078, 0x015e, 0x708f, 0x0028, 0x0058, + 0x708f, 0x001e, 0x0040, 0x708f, 0x001d, 0x0028, 0x708f, 0x0020, + 0x0010, 0x708f, 0x001f, 0x0005, 0x60e3, 0x0001, 0x600c, 0xc0b4, + 0x600e, 0x080c, 0x5aff, 0x080c, 0x24b0, 0x6803, 0x0080, 0x6124, + 0xd1d4, 0x1180, 0xd1dc, 0x1158, 0xd1e4, 0x1130, 0xa184, 0x1e00, + 0x1158, 0x708f, 0x0028, 0x0040, 0x708f, 0x001e, 0x0028, 0x708f, + 0x001d, 0x0010, 0x708f, 0x001f, 0x0005, 0x6803, 0x00a0, 0x6124, + 0xd1dc, 0x1138, 0xd1e4, 0x0138, 0x080c, 0x1e47, 0x708f, 0x001e, + 0x0010, 0x708f, 0x001d, 0x0005, 0x080c, 0x59f6, 0x6124, 0xd1dc, + 0x1188, 0x080c, 0x5984, 0x0016, 0x080c, 0x1e47, 0x001e, 0xd1d4, + 0x1128, 0xd1e4, 0x0138, 0x708f, 0x001e, 0x0020, 0x708f, 0x001f, + 0x080c, 0x5984, 0x0005, 0x6803, 0x00a0, 0x6124, 0xd1d4, 0x1160, + 0xd1cc, 0x1150, 0xd1dc, 0x1128, 0xd1e4, 0x0140, 0x708f, 0x001e, + 0x0028, 0x708f, 0x001d, 0x0010, 0x708f, 0x0021, 0x0005, 0x080c, + 0x59f6, 0x6124, 0xd1d4, 0x1150, 0xd1dc, 0x1128, 0xd1e4, 0x0140, + 0x708f, 0x001e, 0x0028, 0x708f, 0x001d, 0x0010, 0x708f, 0x001f, + 0x0005, 0x6803, 0x0090, 0x6124, 0xd1d4, 0x1178, 0xd1cc, 0x1150, + 0xd1dc, 0x1128, 0xd1e4, 0x0158, 0x708f, 0x001e, 0x0040, 0x708f, + 0x001d, 0x0028, 0x708f, 0x0020, 0x0010, 0x708f, 0x001f, 0x0005, + 0x0016, 0x00c6, 0x00d6, 0x00e6, 0x0126, 0x2061, 0x0100, 0x2069, + 0x0140, 0x2071, 0xb500, 0x2091, 0x8000, 0x080c, 0x5acf, 0x11e8, + 0x2001, 0xb50c, 0x200c, 0xd1b4, 0x01c0, 0xc1b4, 0x2102, 0x6027, + 0x0200, 0xe000, 0xe000, 0x6024, 0xd0cc, 0x0158, 0x6803, 0x00a0, + 0x2001, 0xb79f, 0x2003, 0x0001, 0x2001, 0xb500, 0x2003, 0x0001, + 0x0428, 0x6028, 0xc0cd, 0x602a, 0x0408, 0x080c, 0x5aeb, 0x0150, + 0x080c, 0x5ae1, 0x1138, 0x2001, 0x0001, 0x080c, 0x27c3, 0x080c, + 0x5aa6, 0x00a0, 0x080c, 0x59f3, 0x0178, 0x2001, 0x0001, 0x080c, + 0x27c3, 0x708c, 0xa086, 0x001e, 0x0120, 0x708c, 0xa086, 0x0022, + 0x1118, 0x708f, 0x0025, 0x0010, 0x708f, 0x0021, 0x012e, 0x00ee, + 0x00de, 0x00ce, 0x001e, 0x0005, 0x0026, 0x2011, 0x5995, 0x080c, + 0x6a5c, 0x002e, 0x0016, 0x0026, 0x2009, 0x0064, 0x2011, 0x5995, + 0x080c, 0x6a53, 0x002e, 0x001e, 0x0005, 0x00e6, 0x00f6, 0x0016, + 0x080c, 0x7d7a, 0x2071, 0xb500, 0x080c, 0x5930, 0x001e, 0x00fe, + 0x00ee, 0x0005, 0x0016, 0x0026, 0x0036, 0x00c6, 0x00d6, 0x00e6, + 0x00f6, 0x0126, 0x080c, 0x7d7a, 0x2061, 0x0100, 0x2069, 0x0140, + 0x2071, 0xb500, 0x2091, 0x8000, 0x6028, 0xc09c, 0x602a, 0x2011, + 0x0003, 0x080c, 0x8075, 0x2011, 0x0002, 0x080c, 0x807f, 0x080c, + 0x7f59, 0x080c, 0x6a10, 0x0036, 0x2019, 0x0000, 0x080c, 0x7fe4, + 0x003e, 0x60e3, 0x0000, 0x080c, 0xb42f, 0x080c, 0xb44a, 0x2001, + 0xb500, 0x2003, 0x0004, 0x6027, 0x0008, 0x080c, 0x12dd, 0x2001, + 0x0001, 0x080c, 0x27c3, 0x012e, 0x00fe, 0x00ee, 0x00de, 0x00ce, + 0x003e, 0x002e, 0x001e, 0x0005, 0x2001, 0xb500, 0x2004, 0xa086, + 0x0004, 0x0140, 0x2001, 0xb79e, 0x2003, 0xaaaa, 0x2001, 0xb79f, + 0x2003, 0x0000, 0x0005, 0x6020, 0xd09c, 0x0005, 0x6800, 0xa086, + 0x00c0, 0x0160, 0x6803, 0x00c0, 0x0156, 0x20a9, 0x002d, 0x1d04, + 0x59ff, 0x2091, 0x6000, 0x1f04, 0x59ff, 0x015e, 0x0005, 0x00c6, + 0x00d6, 0x00e6, 0x2061, 0x0100, 0x2069, 0x0140, 0x2071, 0xb500, + 0x2001, 0xb79f, 0x200c, 0xa186, 0x0000, 0x0158, 0xa186, 0x0001, + 0x0158, 0xa186, 0x0002, 0x0158, 0xa186, 0x0003, 0x0158, 0x0804, + 0x5a94, 0x708f, 0x0022, 0x0040, 0x708f, 0x0021, 0x0028, 0x708f, + 0x0023, 0x0020, 0x708f, 0x0024, 0x6043, 0x0000, 0x60e3, 0x0000, + 0x6887, 0x0001, 0x2001, 0x0001, 0x080c, 0x2872, 0x0026, 0x2011, + 0x0003, 0x080c, 0x8075, 0x2011, 0x0002, 0x080c, 0x807f, 0x080c, + 0x7f59, 0x0036, 0x2019, 0x0000, 0x080c, 0x7fe4, 0x003e, 0x002e, + 0x7000, 0xa08e, 0x0004, 0x0118, 0x602b, 0x0028, 0x0010, 0x602b, + 0x0020, 0x0156, 0x0126, 0x2091, 0x8000, 0x20a9, 0x0005, 0x6024, + 0xd0ac, 0x0120, 0x012e, 0x015e, 0x0804, 0x5aa2, 0x6800, 0xa084, + 0x00a0, 0xc0bd, 0x6802, 0x6904, 0xd1d4, 0x1130, 0x6803, 0x0100, + 0x1f04, 0x5a57, 0x080c, 0x5b20, 0x012e, 0x015e, 0x080c, 0x5ae1, + 0x01a8, 0x6044, 0xa005, 0x0168, 0x6050, 0x0006, 0xa085, 0x0020, + 0x6052, 0x080c, 0x5b20, 0xa006, 0x8001, 0x1df0, 0x000e, 0x6052, + 0x0028, 0x6804, 0xd0d4, 0x1110, 0x080c, 0x5b20, 0x0016, 0x0026, + 0x2009, 0x00c8, 0x2011, 0x59a2, 0x080c, 0x6a22, 0x002e, 0x001e, + 0x2001, 0xb79f, 0x2003, 0x0004, 0x080c, 0x57e1, 0x080c, 0x5ae1, + 0x0148, 0x6804, 0xd0d4, 0x1130, 0xd0dc, 0x1100, 0x2001, 0xb79f, + 0x2003, 0x0000, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x00c6, 0x00d6, + 0x00e6, 0x2061, 0x0100, 0x2069, 0x0140, 0x2071, 0xb500, 0x2001, + 0xb79e, 0x2003, 0x0000, 0x2001, 0xb78f, 0x2003, 0x0000, 0x708f, + 0x0000, 0x60e3, 0x0000, 0x6887, 0x0000, 0x2001, 0x0000, 0x080c, + 0x2872, 0x6803, 0x0000, 0x6043, 0x0090, 0x6043, 0x0010, 0x6027, + 0xffff, 0x602b, 0x182f, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x0006, + 0x2001, 0xb79e, 0x2004, 0xa086, 0xaaaa, 0x000e, 0x0005, 0x0006, + 0x2001, 0xb572, 0x2004, 0xa084, 0x0030, 0xa086, 0x0000, 0x000e, + 0x0005, 0x0006, 0x2001, 0xb572, 0x2004, 0xa084, 0x0030, 0xa086, + 0x0030, 0x000e, 0x0005, 0x0006, 0x2001, 0xb572, 0x2004, 0xa084, + 0x0030, 0xa086, 0x0010, 0x000e, 0x0005, 0x0006, 0x2001, 0xb572, + 0x2004, 0xa084, 0x0030, 0xa086, 0x0020, 0x000e, 0x0005, 0x2001, + 0xb50c, 0x2004, 0xd0a4, 0x0170, 0x080c, 0x2892, 0x0036, 0x0016, + 0x2009, 0x0000, 0x2019, 0x0028, 0x080c, 0x2c6f, 0x001e, 0x003e, + 0xa006, 0x0009, 0x0005, 0x00e6, 0x2071, 0xb50c, 0x2e04, 0x0118, + 0xa085, 0x0010, 0x0010, 0xa084, 0xffef, 0x2072, 0x00ee, 0x0005, + 0x6050, 0x0006, 0x60f0, 0x0006, 0x60ec, 0x0006, 0x600c, 0x0006, + 0x6004, 0x0006, 0x6028, 0x0006, 0x602f, 0x0100, 0x602f, 0x0000, + 0x602f, 0x0040, 0x602f, 0x0000, 0x000e, 0x602a, 0x000e, 0x6006, + 0x000e, 0x600e, 0x000e, 0x60ee, 0x000e, 0x60f2, 0x60e3, 0x0000, + 0x6887, 0x0001, 0x2001, 0x0001, 0x080c, 0x2872, 0x6800, 0xa084, + 0x00a0, 0xc0bd, 0x6802, 0x6803, 0x00a0, 0x000e, 0x6052, 0x6050, + 0x0005, 0x0156, 0x0016, 0x0026, 0x0036, 0x00c6, 0x00d6, 0x00e6, + 0x2061, 0x0100, 0x2069, 0x0140, 0x2071, 0xb500, 0x6020, 0xa084, + 0x0080, 0x0138, 0x2001, 0xb50c, 0x200c, 0xc1bd, 0x2102, 0x0804, + 0x5bc9, 0x2001, 0xb50c, 0x200c, 0xc1bc, 0x2102, 0x6028, 0xa084, + 0xe1ff, 0x602a, 0x6027, 0x0200, 0x6803, 0x0090, 0x20a9, 0x0384, + 0x6024, 0xd0cc, 0x1508, 0x1d04, 0x5b78, 0x2091, 0x6000, 0x1f04, + 0x5b78, 0x2011, 0x0003, 0x080c, 0x8075, 0x2011, 0x0002, 0x080c, + 0x807f, 0x080c, 0x7f59, 0x2019, 0x0000, 0x080c, 0x7fe4, 0x6803, + 0x00a0, 0x2001, 0xb79f, 0x2003, 0x0001, 0x2001, 0xb500, 0x2003, + 0x0001, 0xa085, 0x0001, 0x0468, 0x86ff, 0x1120, 0x080c, 0x1e47, + 0x080c, 0x24b0, 0x60e3, 0x0000, 0x2001, 0xb78f, 0x2004, 0x080c, + 0x2872, 0x60e2, 0x6803, 0x0080, 0x20a9, 0x0384, 0x6027, 0x1e00, + 0x2009, 0x1e00, 0xe000, 0x6024, 0xa10c, 0x0138, 0x1d04, 0x5bae, + 0x2091, 0x6000, 0x1f04, 0x5bae, 0x0820, 0x6028, 0xa085, 0x1e00, + 0x602a, 0x70a4, 0xa005, 0x1118, 0x6887, 0x0001, 0x0008, 0x6886, + 0xa006, 0x00ee, 0x00de, 0x00ce, 0x003e, 0x002e, 0x001e, 0x015e, + 0x0005, 0x0156, 0x0016, 0x0026, 0x0036, 0x00c6, 0x00d6, 0x00e6, + 0x2061, 0x0100, 0x2071, 0xb500, 0x2069, 0x0140, 0x6020, 0xa084, + 0x00c0, 0x0120, 0x6884, 0xa005, 0x1904, 0x5c25, 0x6803, 0x0088, + 0x60e3, 0x0000, 0x6887, 0x0000, 0x2001, 0x0000, 0x080c, 0x2872, + 0x2069, 0x0200, 0x6804, 0xa005, 0x1118, 0x6808, 0xa005, 0x01c0, + 0x6028, 0xa084, 0xfbff, 0x602a, 0x6027, 0x0400, 0x2069, 0xb7c5, + 0x7000, 0x206a, 0x708f, 0x0026, 0x7003, 0x0001, 0x20a9, 0x0002, + 0x1d04, 0x5c08, 0x2091, 0x6000, 0x1f04, 0x5c08, 0x0804, 0x5c56, + 0x2069, 0x0140, 0x20a9, 0x0384, 0x6027, 0x1e00, 0x2009, 0x1e00, + 0xe000, 0x6024, 0xa10c, 0x0520, 0xa084, 0x1a00, 0x1508, 0x1d04, + 0x5c14, 0x2091, 0x6000, 0x1f04, 0x5c14, 0x2011, 0x0003, 0x080c, + 0x8075, 0x2011, 0x0002, 0x080c, 0x807f, 0x080c, 0x7f59, 0x2019, + 0x0000, 0x080c, 0x7fe4, 0x6803, 0x00a0, 0x2001, 0xb79f, 0x2003, + 0x0001, 0x2001, 0xb500, 0x2003, 0x0001, 0xa085, 0x0001, 0x00b0, + 0x080c, 0x24b0, 0x6803, 0x0080, 0x2069, 0x0140, 0x60e3, 0x0000, + 0x70a4, 0xa005, 0x1118, 0x6887, 0x0001, 0x0008, 0x6886, 0x2001, + 0xb78f, 0x2004, 0x080c, 0x2872, 0x60e2, 0xa006, 0x00ee, 0x00de, + 0x00ce, 0x003e, 0x002e, 0x001e, 0x015e, 0x0005, 0x0156, 0x0016, + 0x0026, 0x0036, 0x00c6, 0x00d6, 0x00e6, 0x2061, 0x0100, 0x2071, + 0xb500, 0x6020, 0xa084, 0x00c0, 0x01e0, 0x2011, 0x0003, 0x080c, + 0x8075, 0x2011, 0x0002, 0x080c, 0x807f, 0x080c, 0x7f59, 0x2019, + 0x0000, 0x080c, 0x7fe4, 0x2069, 0x0140, 0x6803, 0x00a0, 0x2001, + 0xb79f, 0x2003, 0x0001, 0x2001, 0xb500, 0x2003, 0x0001, 0x0804, + 0x5cfb, 0x2001, 0xb50c, 0x200c, 0xd1b4, 0x1160, 0xc1b5, 0x2102, + 0x080c, 0x598a, 0x2069, 0x0140, 0x080c, 0x24b0, 0x6803, 0x0080, + 0x60e3, 0x0000, 0x2069, 0x0200, 0x6804, 0xa005, 0x1118, 0x6808, + 0xa005, 0x01c0, 0x6028, 0xa084, 0xfdff, 0x602a, 0x6027, 0x0200, + 0x2069, 0xb7c5, 0x7000, 0x206a, 0x708f, 0x0027, 0x7003, 0x0001, + 0x20a9, 0x0002, 0x1d04, 0x5cb2, 0x2091, 0x6000, 0x1f04, 0x5cb2, + 0x0804, 0x5cfb, 0x6027, 0x1e00, 0x2009, 0x1e00, 0xe000, 0x6024, + 0xa10c, 0x01c8, 0xa084, 0x1c00, 0x11b0, 0x1d04, 0x5cba, 0x0006, + 0x0016, 0x00c6, 0x00d6, 0x00e6, 0x080c, 0x68f9, 0x00ee, 0x00de, + 0x00ce, 0x001e, 0x000e, 0x00e6, 0x2071, 0xb7f3, 0x7018, 0x00ee, + 0xa005, 0x1d00, 0x0500, 0x0026, 0x2011, 0x59a2, 0x080c, 0x699c, + 0x2011, 0x5995, 0x080c, 0x6a5c, 0x002e, 0x2069, 0x0140, 0x60e3, + 0x0000, 0x70a4, 0xa005, 0x1118, 0x6887, 0x0001, 0x0008, 0x6886, + 0x2001, 0xb78f, 0x2004, 0x080c, 0x2872, 0x60e2, 0x2001, 0xb50c, + 0x200c, 0xc1b4, 0x2102, 0x00ee, 0x00de, 0x00ce, 0x003e, 0x002e, + 0x001e, 0x015e, 0x0005, 0x0156, 0x0016, 0x0026, 0x0036, 0x0046, + 0x00c6, 0x00e6, 0x2061, 0x0100, 0x2071, 0xb500, 0x7130, 0xd184, + 0x1180, 0x2011, 0xb553, 0x2214, 0xd2ec, 0x0138, 0xc18d, 0x7132, + 0x2011, 0xb553, 0x2214, 0xd2ac, 0x1120, 0x7030, 0xd08c, 0x0904, + 0x5d68, 0x7130, 0xc185, 0x7132, 0x2011, 0xb553, 0x220c, 0xd1a4, + 0x0530, 0x0016, 0x2019, 0x000e, 0x080c, 0xb065, 0x0156, 0x20a9, + 0x007f, 0x2009, 0x0000, 0xa186, 0x007e, 0x01a0, 0xa186, 0x0080, + 0x0188, 0x080c, 0x4fa9, 0x1170, 0x8127, 0xa006, 0x0016, 0x2009, + 0x000e, 0x080c, 0xb0e8, 0x2009, 0x0001, 0x2011, 0x0100, 0x080c, + 0x6b1a, 0x001e, 0x8108, 0x1f04, 0x5d33, 0x015e, 0x001e, 0xd1ac, + 0x1148, 0x0016, 0x2009, 0x0000, 0x2019, 0x0004, 0x080c, 0x2c6f, + 0x001e, 0x0070, 0x0156, 0x20a9, 0x007f, 0x2009, 0x0000, 0x080c, + 0x4fa9, 0x1110, 0x080c, 0x4c0b, 0x8108, 0x1f04, 0x5d5f, 0x015e, + 0x080c, 0x1e47, 0x2011, 0x0003, 0x080c, 0x8075, 0x2011, 0x0002, + 0x080c, 0x807f, 0x080c, 0x7f59, 0x0036, 0x2019, 0x0000, 0x080c, + 0x7fe4, 0x003e, 0x60e3, 0x0000, 0x2001, 0xb500, 0x2003, 0x0001, + 0x080c, 0x5a07, 0x00ee, 0x00ce, 0x004e, 0x003e, 0x002e, 0x001e, + 0x015e, 0x0005, 0x2071, 0xb5e2, 0x7003, 0x0000, 0x7007, 0x0000, + 0x700f, 0x0000, 0x702b, 0x0001, 0x704f, 0x0000, 0x7053, 0x0001, + 0x705f, 0x0020, 0x7063, 0x0040, 0x7083, 0x0000, 0x708b, 0x0000, + 0x708f, 0x0001, 0x70bf, 0x0000, 0x0005, 0x00e6, 0x2071, 0xb5e2, + 0x6848, 0xa005, 0x1130, 0x7028, 0xc085, 0x702a, 0xa085, 0x0001, + 0x0428, 0x6a50, 0x7236, 0x6b54, 0x733a, 0x6858, 0x703e, 0x707a, + 0x685c, 0x7042, 0x707e, 0x6848, 0x702e, 0x6840, 0x7032, 0x2009, + 0x000c, 0x200a, 0x8007, 0x8006, 0x8006, 0xa08c, 0x003f, 0xa084, + 0xffc0, 0xa210, 0x2100, 0xa319, 0x7272, 0x7376, 0x7028, 0xc084, + 0x702a, 0x7007, 0x0001, 0x700f, 0x0000, 0xa006, 0x00ee, 0x0005, + 0x2b78, 0x2071, 0xb5e2, 0x7004, 0x0043, 0x700c, 0x0002, 0x5de4, + 0x5ddb, 0x5ddb, 0x5ddb, 0x5ddb, 0x0005, 0x5e3a, 0x5e3b, 0x5e6d, + 0x5e6e, 0x5e38, 0x5ebc, 0x5ec1, 0x5ef2, 0x5ef3, 0x5f0e, 0x5f0f, + 0x5f10, 0x5f11, 0x5f12, 0x5f13, 0x5fc9, 0x5ff0, 0x700c, 0x0002, + 0x5dfd, 0x5e38, 0x5e38, 0x5e39, 0x5e39, 0x7830, 0x7930, 0xa106, + 0x0120, 0x7830, 0x7930, 0xa106, 0x1510, 0x7030, 0xa10a, 0x01f8, + 0x1210, 0x712c, 0xa10a, 0xa18a, 0x0002, 0x12d0, 0x080c, 0x15df, + 0x01b0, 0x2d00, 0x705a, 0x7063, 0x0040, 0x2001, 0x0003, 0x7057, + 0x0000, 0x0126, 0x0006, 0x2091, 0x8000, 0x2009, 0xb812, 0x2104, + 0xc085, 0x200a, 0x000e, 0x700e, 0x012e, 0x080c, 0x165f, 0x0005, + 0x080c, 0x15df, 0x0de0, 0x2d00, 0x705a, 0x080c, 0x15df, 0x1108, + 0x0c10, 0x2d00, 0x7086, 0x7063, 0x0080, 0x2001, 0x0004, 0x08f8, + 0x0005, 0x0005, 0x0005, 0x700c, 0x0002, 0x5e42, 0x5e45, 0x5e53, + 0x5e6c, 0x5e6c, 0x080c, 0x5df6, 0x0005, 0x0126, 0x8001, 0x700e, + 0x7058, 0x0006, 0x080c, 0x6343, 0x0120, 0x2091, 0x8000, 0x080c, + 0x5df6, 0x00de, 0x0048, 0x0126, 0x8001, 0x700e, 0x080c, 0x6343, + 0x7058, 0x2068, 0x7084, 0x705a, 0x6803, 0x0000, 0x6807, 0x0000, + 0x6834, 0xa084, 0x00ff, 0xa08a, 0x003a, 0x1218, 0x00db, 0x012e, + 0x0005, 0x012e, 0x080c, 0x5f14, 0x0005, 0x0005, 0x0005, 0x00e6, + 0x2071, 0xb5e2, 0x700c, 0x0002, 0x5e79, 0x5e79, 0x5e79, 0x5e7b, + 0x5e7e, 0x00ee, 0x0005, 0x700f, 0x0001, 0x0010, 0x700f, 0x0002, + 0x00ee, 0x0005, 0x5f14, 0x5f14, 0x5f30, 0x5f14, 0x60ad, 0x5f14, + 0x5f14, 0x5f14, 0x5f14, 0x5f14, 0x5f30, 0x60ef, 0x6132, 0x617b, + 0x618f, 0x5f14, 0x5f14, 0x5f4c, 0x5f30, 0x5f14, 0x5f14, 0x5fa6, + 0x623b, 0x6256, 0x5f14, 0x5f4c, 0x5f14, 0x5f14, 0x5f14, 0x5f14, + 0x5f9c, 0x6256, 0x5f14, 0x5f14, 0x5f14, 0x5f14, 0x5f14, 0x5f14, + 0x5f14, 0x5f14, 0x5f14, 0x5f60, 0x5f14, 0x5f14, 0x5f14, 0x5f14, + 0x5f14, 0x5f14, 0x5f14, 0x5f14, 0x5f14, 0x6361, 0x5f14, 0x5f14, + 0x5f14, 0x5f14, 0x5f14, 0x5f75, 0x7020, 0x2068, 0x080c, 0x160f, + 0x0005, 0x700c, 0x0002, 0x5ec8, 0x5ecb, 0x5ed9, 0x5ef1, 0x5ef1, + 0x080c, 0x5df6, 0x0005, 0x0126, 0x8001, 0x700e, 0x7058, 0x0006, + 0x080c, 0x6343, 0x0120, 0x2091, 0x8000, 0x080c, 0x5df6, 0x00de, + 0x0048, 0x0126, 0x8001, 0x700e, 0x080c, 0x6343, 0x7058, 0x2068, + 0x7084, 0x705a, 0x6803, 0x0000, 0x6807, 0x0000, 0x6834, 0xa084, + 0x00ff, 0xa08a, 0x001a, 0x1218, 0x003b, 0x012e, 0x0005, 0x012e, + 0x0419, 0x0005, 0x0005, 0x0005, 0x5f14, 0x5f30, 0x6099, 0x5f14, + 0x5f30, 0x5f14, 0x5f30, 0x5f30, 0x5f14, 0x5f30, 0x6099, 0x5f30, + 0x5f30, 0x5f30, 0x5f30, 0x5f30, 0x5f14, 0x5f30, 0x6099, 0x5f14, + 0x5f14, 0x5f30, 0x5f14, 0x5f14, 0x5f14, 0x5f30, 0x0005, 0x0005, + 0x0005, 0x0005, 0x0005, 0x0005, 0x7007, 0x0001, 0x6838, 0xa084, + 0x00ff, 0xc0d5, 0x683a, 0x0126, 0x2091, 0x8000, 0x080c, 0x5408, + 0x012e, 0x0005, 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0e5, + 0x683a, 0x0126, 0x2091, 0x8000, 0x080c, 0x5408, 0x012e, 0x0005, + 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0ed, 0x683a, 0x0126, + 0x2091, 0x8000, 0x080c, 0x5408, 0x012e, 0x0005, 0x7007, 0x0001, + 0x6838, 0xa084, 0x00ff, 0xc0dd, 0x683a, 0x0126, 0x2091, 0x8000, + 0x080c, 0x5408, 0x012e, 0x0005, 0x6834, 0x8007, 0xa084, 0x00ff, + 0x0988, 0x8001, 0x1120, 0x7007, 0x0001, 0x0804, 0x6059, 0x7007, + 0x0006, 0x7012, 0x2d00, 0x7016, 0x701a, 0x704b, 0x6059, 0x0005, + 0x6834, 0x8007, 0xa084, 0x00ff, 0x0904, 0x5f22, 0x8001, 0x1120, + 0x7007, 0x0001, 0x0804, 0x6076, 0x7007, 0x0006, 0x7012, 0x2d00, + 0x7016, 0x701a, 0x704b, 0x6076, 0x0005, 0x6834, 0x8007, 0xa084, + 0x00ff, 0xa086, 0x0001, 0x1904, 0x5f22, 0x7007, 0x0001, 0x2009, + 0xb531, 0x210c, 0x81ff, 0x11a8, 0x6838, 0xa084, 0x00ff, 0x683a, + 0x6853, 0x0000, 0x080c, 0x4d82, 0x1108, 0x0005, 0x0126, 0x2091, + 0x8000, 0x6837, 0x0139, 0x684a, 0x6952, 0x080c, 0x5408, 0x012e, + 0x0ca0, 0x2001, 0x0028, 0x0c90, 0x684c, 0xa084, 0x00c0, 0xa086, + 0x00c0, 0x1120, 0x7007, 0x0001, 0x0804, 0x626e, 0x2d00, 0x7016, + 0x701a, 0x20a9, 0x0004, 0xa080, 0x0024, 0x2098, 0x20a1, 0xb60d, + 0x53a3, 0x6858, 0x7012, 0xa082, 0x0401, 0x1a04, 0x5f3e, 0x6a84, + 0xa28a, 0x0002, 0x1a04, 0x5f3e, 0x82ff, 0x1138, 0x6888, 0x698c, + 0xa105, 0x0118, 0x2001, 0x602c, 0x0018, 0xa280, 0x6022, 0x2005, + 0x70c6, 0x7010, 0xa015, 0x0904, 0x600e, 0x080c, 0x15df, 0x1118, + 0x7007, 0x000f, 0x0005, 0x2d00, 0x7022, 0x70c4, 0x2060, 0x2c05, + 0x6836, 0xe004, 0xad00, 0x7096, 0xe008, 0xa20a, 0x1210, 0xa00e, + 0x2200, 0x7112, 0xe20c, 0x8003, 0x800b, 0xa296, 0x0004, 0x0108, + 0xa108, 0x719a, 0x810b, 0x719e, 0xae90, 0x0022, 0x080c, 0x1643, + 0x7090, 0xa08e, 0x0100, 0x0170, 0xa086, 0x0200, 0x0118, 0x7007, + 0x0010, 0x0005, 0x7020, 0x2068, 0x080c, 0x160f, 0x7014, 0x2068, + 0x0804, 0x5f3e, 0x7020, 0x2068, 0x7018, 0x6802, 0x6807, 0x0000, + 0x2d08, 0x2068, 0x6906, 0x711a, 0x0804, 0x5fc9, 0x7014, 0x2068, + 0x7007, 0x0001, 0x6884, 0xa005, 0x1128, 0x6888, 0x698c, 0xa105, + 0x0108, 0x00b1, 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, 0x0904, + 0x626e, 0x04b8, 0x6024, 0x6028, 0x0002, 0x0011, 0x0007, 0x0004, + 0x000a, 0x000f, 0x0005, 0x0006, 0x000a, 0x0011, 0x0005, 0x0004, + 0x00f6, 0x00e6, 0x00c6, 0x0076, 0x0066, 0x6f88, 0x6e8c, 0x6804, + 0x2060, 0xacf0, 0x0021, 0xacf8, 0x0027, 0x2009, 0x0005, 0x700c, + 0x7816, 0x7008, 0x7812, 0x7004, 0x7806, 0x7000, 0x7802, 0x7e0e, + 0x7f0a, 0x8109, 0x0128, 0xaef2, 0x0004, 0xaffa, 0x0006, 0x0c78, + 0x6004, 0xa065, 0x1d30, 0x006e, 0x007e, 0x00ce, 0x00ee, 0x00fe, + 0x0005, 0x2009, 0xb531, 0x210c, 0x81ff, 0x1198, 0x6838, 0xa084, + 0x00ff, 0x683a, 0x080c, 0x4c64, 0x1108, 0x0005, 0x080c, 0x54db, + 0x0126, 0x2091, 0x8000, 0x080c, 0x9ecc, 0x080c, 0x5408, 0x012e, + 0x0ca0, 0x2001, 0x0028, 0x2009, 0x0000, 0x0c80, 0x2009, 0xb531, + 0x210c, 0x81ff, 0x11b0, 0x6858, 0xa005, 0x01c0, 0x6838, 0xa084, + 0x00ff, 0x683a, 0x6853, 0x0000, 0x080c, 0x4d26, 0x1108, 0x0005, + 0x0126, 0x2091, 0x8000, 0x684a, 0x6952, 0x080c, 0x5408, 0x012e, + 0x0cb0, 0x2001, 0x0028, 0x2009, 0x0000, 0x0c90, 0x2001, 0x0000, + 0x0c78, 0x7018, 0x6802, 0x2d08, 0x2068, 0x6906, 0x711a, 0x7010, + 0x8001, 0x7012, 0x0118, 0x7007, 0x0006, 0x0030, 0x7014, 0x2068, + 0x7007, 0x0001, 0x7048, 0x080f, 0x0005, 0x7007, 0x0001, 0x6944, + 0x810f, 0xa18c, 0x00ff, 0x6848, 0xa084, 0x00ff, 0x20a9, 0x0001, + 0xa096, 0x0001, 0x01b0, 0x2009, 0x0000, 0x20a9, 0x00ff, 0xa096, + 0x0002, 0x0178, 0xa005, 0x11f0, 0x6944, 0x810f, 0xa18c, 0x00ff, + 0x080c, 0x4fa9, 0x11b8, 0x0066, 0x6e50, 0x080c, 0x50a8, 0x006e, + 0x0088, 0x0046, 0x2011, 0xb50c, 0x2224, 0xc484, 0x2412, 0x004e, + 0x00c6, 0x080c, 0x4fa9, 0x1110, 0x080c, 0x5209, 0x8108, 0x1f04, + 0x60d9, 0x00ce, 0x684c, 0xd084, 0x1118, 0x080c, 0x160f, 0x0005, + 0x0126, 0x2091, 0x8000, 0x080c, 0x5408, 0x012e, 0x0005, 0x0126, + 0x2091, 0x8000, 0x7007, 0x0001, 0x2001, 0xb553, 0x2004, 0xd0a4, + 0x0580, 0x2061, 0xb874, 0x6100, 0xd184, 0x0178, 0x6858, 0xa084, + 0x00ff, 0x1550, 0x6000, 0xd084, 0x0520, 0x6004, 0xa005, 0x1538, + 0x6003, 0x0000, 0x600b, 0x0000, 0x00c8, 0x2011, 0x0001, 0x6860, + 0xa005, 0x1110, 0x2001, 0x001e, 0x8000, 0x6016, 0x6858, 0xa084, + 0x00ff, 0x0178, 0x6006, 0x6858, 0x8007, 0xa084, 0x00ff, 0x0148, + 0x600a, 0x6858, 0x8000, 0x1108, 0xc28d, 0x6202, 0x012e, 0x0804, + 0x6332, 0x012e, 0x0804, 0x632c, 0x012e, 0x0804, 0x6326, 0x012e, + 0x0804, 0x6329, 0x0126, 0x2091, 0x8000, 0x7007, 0x0001, 0x2001, + 0xb553, 0x2004, 0xd0a4, 0x05e0, 0x2061, 0xb874, 0x6000, 0xd084, + 0x05b8, 0x6204, 0x6308, 0xd08c, 0x1530, 0x6c48, 0xa484, 0x0003, + 0x0170, 0x6958, 0xa18c, 0x00ff, 0x8001, 0x1120, 0x2100, 0xa210, + 0x0620, 0x0028, 0x8001, 0x1508, 0x2100, 0xa212, 0x02f0, 0xa484, + 0x000c, 0x0188, 0x6958, 0x810f, 0xa18c, 0x00ff, 0xa082, 0x0004, + 0x1120, 0x2100, 0xa318, 0x0288, 0x0030, 0xa082, 0x0004, 0x1168, + 0x2100, 0xa31a, 0x0250, 0x6860, 0xa005, 0x0110, 0x8000, 0x6016, + 0x6206, 0x630a, 0x012e, 0x0804, 0x6332, 0x012e, 0x0804, 0x632f, + 0x012e, 0x0804, 0x632c, 0x0126, 0x2091, 0x8000, 0x7007, 0x0001, + 0x2061, 0xb874, 0x6300, 0xd38c, 0x1120, 0x6308, 0x8318, 0x0220, + 0x630a, 0x012e, 0x0804, 0x6340, 0x012e, 0x0804, 0x632f, 0x0126, + 0x00c6, 0x2091, 0x8000, 0x7007, 0x0001, 0x684c, 0xd0ac, 0x0148, + 0x00c6, 0x2061, 0xb874, 0x6000, 0xa084, 0xfcff, 0x6002, 0x00ce, + 0x0448, 0x6858, 0xa005, 0x05d0, 0x685c, 0xa065, 0x0598, 0x2001, + 0xb531, 0x2004, 0xa005, 0x0118, 0x080c, 0x9e1d, 0x0068, 0x6013, + 0x0400, 0x6057, 0x0000, 0x694c, 0xd1a4, 0x0110, 0x6950, 0x6156, + 0x2009, 0x0041, 0x080c, 0x864c, 0x6958, 0xa18c, 0xff00, 0xa186, + 0x2000, 0x1140, 0x0026, 0x2009, 0x0000, 0x2011, 0xfdff, 0x080c, + 0x6b1a, 0x002e, 0x684c, 0xd0c4, 0x0148, 0x2061, 0xb874, 0x6000, + 0xd08c, 0x1120, 0x6008, 0x8000, 0x0208, 0x600a, 0x00ce, 0x012e, + 0x0804, 0x6332, 0x00ce, 0x012e, 0x0804, 0x632c, 0x6954, 0xa186, + 0x002e, 0x0d40, 0xa186, 0x002d, 0x0d28, 0xa186, 0x0045, 0x0528, + 0xa186, 0x002a, 0x1130, 0x2001, 0xb50c, 0x200c, 0xc194, 0x2102, + 0x08c8, 0xa186, 0x0020, 0x0170, 0xa186, 0x0029, 0x1d18, 0x6944, + 0xa18c, 0xff00, 0x810f, 0x080c, 0x4fa9, 0x1960, 0x6000, 0xc0e4, + 0x6002, 0x0840, 0x685c, 0xa065, 0x09a8, 0x6007, 0x0024, 0x2001, + 0xb7b6, 0x2004, 0x6016, 0x0804, 0x61ca, 0x685c, 0xa065, 0x0950, + 0x00e6, 0x6860, 0xa075, 0x2001, 0xb531, 0x2004, 0xa005, 0x0150, + 0x080c, 0x9e1d, 0x8eff, 0x0118, 0x2e60, 0x080c, 0x9e1d, 0x00ee, + 0x0804, 0x61ca, 0x6020, 0xc0dc, 0xc0d5, 0x6022, 0x2e60, 0x6007, + 0x003a, 0x6870, 0xa005, 0x0130, 0x6007, 0x003b, 0x6874, 0x602a, + 0x6878, 0x6012, 0x6003, 0x0001, 0x080c, 0x6c8d, 0x080c, 0x7173, + 0x00ee, 0x0804, 0x61ca, 0x2061, 0xb874, 0x6000, 0xd084, 0x0190, + 0xd08c, 0x1904, 0x6340, 0x0126, 0x2091, 0x8000, 0x6204, 0x8210, + 0x0220, 0x6206, 0x012e, 0x0804, 0x6340, 0x012e, 0x6853, 0x0016, + 0x0804, 0x6339, 0x6853, 0x0007, 0x0804, 0x6339, 0x6834, 0x8007, + 0xa084, 0x00ff, 0x1118, 0x080c, 0x5f22, 0x0078, 0x2030, 0x8001, + 0x1120, 0x7007, 0x0001, 0x0051, 0x0040, 0x7007, 0x0006, 0x7012, + 0x2d00, 0x7016, 0x701a, 0x704b, 0x626e, 0x0005, 0x00e6, 0x0126, + 0x2091, 0x8000, 0xa03e, 0x2009, 0xb531, 0x210c, 0x81ff, 0x1904, + 0x62ec, 0x2009, 0xb50c, 0x210c, 0xd194, 0x1904, 0x6316, 0x6848, + 0x2070, 0xae82, 0xbd00, 0x0a04, 0x62e0, 0x2001, 0xb517, 0x2004, + 0xae02, 0x1a04, 0x62e0, 0x711c, 0xa186, 0x0006, 0x1904, 0x62cf, + 0x7018, 0xa005, 0x0904, 0x62ec, 0x2004, 0xd0e4, 0x1904, 0x6311, + 0x2061, 0xb874, 0x6100, 0xa184, 0x0301, 0xa086, 0x0001, 0x1550, + 0x7020, 0xd0dc, 0x1904, 0x6319, 0x6853, 0x0000, 0x6803, 0x0000, + 0x2d08, 0x7010, 0xa005, 0x1158, 0x7112, 0x684c, 0xd0f4, 0x1904, + 0x631c, 0x2e60, 0x080c, 0x6a76, 0x012e, 0x00ee, 0x0005, 0x2068, + 0x6800, 0xa005, 0x1de0, 0x6902, 0x2168, 0x684c, 0xd0f4, 0x1904, + 0x631c, 0x012e, 0x00ee, 0x0005, 0x012e, 0x00ee, 0x6853, 0x0006, + 0x0804, 0x6339, 0xd184, 0x0dc0, 0xd1c4, 0x11a8, 0x00b8, 0x6944, + 0xa18c, 0xff00, 0x810f, 0x080c, 0x4fa9, 0x15d8, 0x6000, 0xd0e4, + 0x15c0, 0x711c, 0xa186, 0x0007, 0x1118, 0x6853, 0x0002, 0x0498, + 0x6853, 0x0008, 0x0480, 0x6853, 0x000e, 0x0468, 0x6853, 0x0017, + 0x0450, 0x6853, 0x0035, 0x0438, 0x2001, 0xb572, 0x2004, 0xd0fc, + 0x01e8, 0x6848, 0x2070, 0xae82, 0xbd00, 0x02c0, 0x605c, 0xae02, + 0x12a8, 0x711c, 0xa186, 0x0006, 0x1188, 0x7018, 0xa005, 0x0170, + 0x2004, 0xd0bc, 0x0158, 0x2039, 0x0001, 0x7000, 0xa086, 0x0007, + 0x1904, 0x6279, 0x7003, 0x0002, 0x0804, 0x6279, 0x6853, 0x0028, + 0x0010, 0x6853, 0x0029, 0x012e, 0x00ee, 0x0418, 0x6853, 0x002a, + 0x0cd0, 0x6853, 0x0045, 0x0cb8, 0x2e60, 0x2019, 0x0002, 0x6017, + 0x0014, 0x080c, 0xace0, 0x012e, 0x00ee, 0x0005, 0x2009, 0x003e, + 0x0058, 0x2009, 0x0004, 0x0040, 0x2009, 0x0006, 0x0028, 0x2009, + 0x0016, 0x0010, 0x2009, 0x0001, 0x6854, 0xa084, 0xff00, 0xa105, + 0x6856, 0x0126, 0x2091, 0x8000, 0x080c, 0x5408, 0x012e, 0x0005, + 0x080c, 0x160f, 0x0005, 0x702c, 0x7130, 0x8108, 0xa102, 0x0230, + 0xa00e, 0x7034, 0x7072, 0x7038, 0x7076, 0x0058, 0x7070, 0xa080, + 0x0040, 0x7072, 0x1230, 0x7074, 0xa081, 0x0000, 0x7076, 0xa085, + 0x0001, 0x7932, 0x7132, 0x0005, 0x00d6, 0x080c, 0x6a6d, 0x00de, + 0x0005, 0x00d6, 0x00c6, 0x0036, 0x0026, 0x0016, 0x7007, 0x0001, + 0x6a44, 0xa282, 0x0004, 0x1a04, 0x63ac, 0xd284, 0x0170, 0x6a4c, + 0xa290, 0xb635, 0x2204, 0xa065, 0x6004, 0x05e0, 0x8007, 0xa084, + 0x00ff, 0xa084, 0x0006, 0x1108, 0x04a8, 0x2c10, 0x080c, 0x85c7, + 0x1118, 0x080c, 0x9ed6, 0x05a0, 0x621a, 0x6844, 0x0002, 0x638b, + 0x6390, 0x6393, 0x6399, 0x2019, 0x0002, 0x080c, 0xb065, 0x0060, + 0x080c, 0xaffc, 0x0048, 0x2019, 0x0002, 0x6950, 0x080c, 0xb017, + 0x0018, 0x6950, 0x080c, 0xaffc, 0x080c, 0x861d, 0x6857, 0x0000, + 0x0126, 0x2091, 0x8000, 0x080c, 0x5408, 0x012e, 0x001e, 0x002e, + 0x003e, 0x00ce, 0x00de, 0x0005, 0x6857, 0x0006, 0x0c88, 0x6857, + 0x0002, 0x0c70, 0x6857, 0x0005, 0x0c58, 0x6857, 0x0004, 0x0c40, + 0x6857, 0x0007, 0x0c28, 0x00d6, 0x2011, 0x0004, 0x2204, 0xa085, + 0x8002, 0x2012, 0x00de, 0x0005, 0x20e1, 0x0002, 0x3d08, 0x20e1, + 0x2000, 0x3d00, 0xa084, 0x7000, 0x0118, 0xa086, 0x1000, 0x1570, + 0x20e1, 0x0000, 0x3d00, 0xa094, 0xff00, 0x8217, 0xa084, 0xf000, + 0xa086, 0x3000, 0x1160, 0xa184, 0xff00, 0x8007, 0xa086, 0x0008, + 0x11e8, 0x080c, 0x2dbf, 0x11d0, 0x080c, 0x6603, 0x0098, 0x20e1, + 0x0004, 0x3d60, 0xd1bc, 0x1108, 0x3e60, 0xac84, 0x0007, 0x1170, + 0xac82, 0xbd00, 0x0258, 0x685c, 0xac02, 0x1240, 0x2009, 0x0047, + 0x080c, 0x864c, 0x7a1c, 0xd284, 0x1938, 0x0005, 0xa016, 0x080c, + 0x185e, 0x0cc0, 0x0cd8, 0x781c, 0xd08c, 0x0500, 0x0156, 0x0136, + 0x0146, 0x20e1, 0x3000, 0x3d20, 0x3e28, 0xa584, 0x0076, 0x1538, + 0xa484, 0x7000, 0xa086, 0x1000, 0x11a8, 0x080c, 0x647e, 0x01f8, + 0x20e1, 0x3000, 0x7828, 0x7828, 0x080c, 0x649a, 0x014e, 0x013e, + 0x015e, 0x2009, 0xb7e8, 0x2104, 0xa005, 0x1108, 0x0005, 0x080c, + 0x7173, 0x0ce0, 0xa484, 0x7000, 0x1548, 0x080c, 0x647e, 0x01d8, + 0x7000, 0xa084, 0xff00, 0xa086, 0x8100, 0x0d10, 0x00a0, 0xd5a4, + 0x0178, 0x0056, 0x0046, 0x080c, 0x1e6e, 0x080c, 0x24b0, 0x2001, + 0x0160, 0x2502, 0x2001, 0x0138, 0x2202, 0x004e, 0x005e, 0x0048, + 0x04a9, 0x6887, 0x0000, 0x080c, 0xb3df, 0x20e1, 0x3000, 0x7828, + 0x7828, 0x00b9, 0x014e, 0x013e, 0x015e, 0x0880, 0x0439, 0x1130, + 0x7000, 0xa084, 0xff00, 0xa086, 0x8100, 0x1d68, 0x080c, 0xb3df, + 0x20e1, 0x3000, 0x7828, 0x7828, 0x0056, 0x080c, 0x6874, 0x005e, + 0x0c40, 0x2001, 0xb50e, 0x2004, 0xd08c, 0x0178, 0x2001, 0xb500, + 0x2004, 0xa086, 0x0003, 0x1148, 0x0026, 0x0036, 0x2011, 0x8048, + 0x2518, 0x080c, 0x3ecc, 0x003e, 0x002e, 0x0005, 0xa484, 0x01ff, + 0x6886, 0xa005, 0x0160, 0xa080, 0x001f, 0xa084, 0x03f8, 0x80ac, + 0x20e1, 0x1000, 0x2ea0, 0x2099, 0x020a, 0x53a5, 0x0005, 0x20a9, + 0x000c, 0x20e1, 0x1000, 0x2ea0, 0x2099, 0x020a, 0x53a5, 0xa085, + 0x0001, 0x0ca0, 0x7000, 0xa084, 0xff00, 0xa08c, 0xf000, 0x8007, + 0xa196, 0x0000, 0x1118, 0x0804, 0x6708, 0x0005, 0xa196, 0x2000, + 0x1148, 0x6900, 0xa18e, 0x0001, 0x1118, 0x080c, 0x448f, 0x0ca8, + 0x0039, 0x0c98, 0xa196, 0x8000, 0x1d80, 0x080c, 0x67b4, 0x0c68, + 0x00c6, 0x6a84, 0x82ff, 0x0904, 0x65fd, 0x7110, 0xa18c, 0xff00, + 0x810f, 0xa196, 0x0001, 0x0120, 0xa196, 0x0023, 0x1904, 0x65fd, + 0xa08e, 0x0023, 0x1570, 0x080c, 0x684f, 0x0904, 0x65fd, 0x7124, + 0x610a, 0x7030, 0xa08e, 0x0200, 0x1150, 0x7034, 0xa005, 0x1904, + 0x65fd, 0x2009, 0x0015, 0x080c, 0x864c, 0x0804, 0x65fd, 0xa08e, + 0x0214, 0x0118, 0xa08e, 0x0210, 0x1130, 0x2009, 0x0015, 0x080c, + 0x864c, 0x0804, 0x65fd, 0xa08e, 0x0100, 0x1904, 0x65fd, 0x7034, + 0xa005, 0x1904, 0x65fd, 0x2009, 0x0016, 0x080c, 0x864c, 0x0804, + 0x65fd, 0xa08e, 0x0022, 0x1904, 0x65fd, 0x7030, 0xa08e, 0x0300, + 0x1580, 0x68d4, 0xd0a4, 0x0528, 0xc0b5, 0x68d6, 0x7100, 0xa18c, + 0x00ff, 0x6972, 0x7004, 0x6876, 0x00f6, 0x2079, 0x0100, 0x79e6, + 0x78ea, 0x0006, 0xa084, 0x00ff, 0x0016, 0x2008, 0x080c, 0x2847, + 0x7932, 0x7936, 0x001e, 0x000e, 0x00fe, 0x080c, 0x281d, 0x6952, + 0x703c, 0x00e6, 0x2071, 0x0140, 0x7086, 0x2071, 0xb500, 0x70a6, + 0x00ee, 0x7034, 0xa005, 0x1904, 0x65fd, 0x2009, 0x0017, 0x0804, + 0x65c3, 0xa08e, 0x0400, 0x1158, 0x7034, 0xa005, 0x1904, 0x65fd, + 0x68d4, 0xc0a5, 0x68d6, 0x2009, 0x0030, 0x0804, 0x65c3, 0xa08e, + 0x0500, 0x1140, 0x7034, 0xa005, 0x1904, 0x65fd, 0x2009, 0x0018, + 0x0804, 0x65c3, 0xa08e, 0x2010, 0x1120, 0x2009, 0x0019, 0x0804, + 0x65c3, 0xa08e, 0x2110, 0x1120, 0x2009, 0x001a, 0x0804, 0x65c3, + 0xa08e, 0x5200, 0x1140, 0x7034, 0xa005, 0x1904, 0x65fd, 0x2009, + 0x001b, 0x0804, 0x65c3, 0xa08e, 0x5000, 0x1140, 0x7034, 0xa005, + 0x1904, 0x65fd, 0x2009, 0x001c, 0x0804, 0x65c3, 0xa08e, 0x1300, + 0x1120, 0x2009, 0x0034, 0x0804, 0x65c3, 0xa08e, 0x1200, 0x1140, + 0x7034, 0xa005, 0x1904, 0x65fd, 0x2009, 0x0024, 0x0804, 0x65c3, + 0xa08c, 0xff00, 0xa18e, 0x2400, 0x1118, 0x2009, 0x002d, 0x04d8, + 0xa08c, 0xff00, 0xa18e, 0x5300, 0x1118, 0x2009, 0x002a, 0x0498, + 0xa08e, 0x0f00, 0x1118, 0x2009, 0x0020, 0x0468, 0xa08e, 0x5300, + 0x1108, 0x00d8, 0xa08e, 0x6104, 0x11c0, 0x2011, 0xbb8d, 0x8208, + 0x2204, 0xa082, 0x0004, 0x20a8, 0x95ac, 0x95ac, 0x2011, 0x8015, + 0x211c, 0x8108, 0x0046, 0x2124, 0x080c, 0x3ecc, 0x004e, 0x8108, + 0x1f04, 0x65a6, 0x2009, 0x0023, 0x0070, 0xa08e, 0x6000, 0x1118, + 0x2009, 0x003f, 0x0040, 0xa08e, 0x7800, 0x1118, 0x2009, 0x0045, + 0x0010, 0x2009, 0x001d, 0x0016, 0x2011, 0xbb83, 0x2204, 0x8211, + 0x220c, 0x080c, 0x281d, 0x1598, 0x080c, 0x4f4d, 0x1580, 0x6612, + 0x6516, 0x86ff, 0x01e8, 0x001e, 0x0016, 0xa186, 0x0017, 0x1158, + 0x6870, 0xa606, 0x11a8, 0x6874, 0xa506, 0xa084, 0xff00, 0x1180, + 0x6000, 0xc0f5, 0x6002, 0xa186, 0x0046, 0x1150, 0x6870, 0xa606, + 0x1138, 0x6874, 0xa506, 0xa084, 0xff00, 0x1110, 0x001e, 0x0068, + 0x00c6, 0x080c, 0x85c7, 0x0168, 0x001e, 0x611a, 0x601f, 0x0004, + 0x7120, 0x610a, 0x001e, 0x080c, 0x864c, 0x00ce, 0x0005, 0x001e, + 0x0ce0, 0x00ce, 0x0ce0, 0x00c6, 0x0046, 0x080c, 0x6657, 0x1904, + 0x6654, 0xa28e, 0x0033, 0x11e8, 0x080c, 0x684f, 0x0904, 0x6654, + 0x7124, 0x610a, 0x7030, 0xa08e, 0x0200, 0x1140, 0x7034, 0xa005, + 0x15d8, 0x2009, 0x0015, 0x080c, 0x864c, 0x04b0, 0xa08e, 0x0100, + 0x1598, 0x7034, 0xa005, 0x1580, 0x2009, 0x0016, 0x080c, 0x864c, + 0x0458, 0xa28e, 0x0032, 0x1540, 0x7030, 0xa08e, 0x1400, 0x1520, + 0x2009, 0x0038, 0x0016, 0x2011, 0xbb83, 0x2204, 0x8211, 0x220c, + 0x080c, 0x281d, 0x11c0, 0x080c, 0x4f4d, 0x11a8, 0x6612, 0x6516, + 0x00c6, 0x080c, 0x85c7, 0x0170, 0x001e, 0x611a, 0x080c, 0xa027, + 0x601f, 0x0004, 0x7120, 0x610a, 0x001e, 0x080c, 0x864c, 0x080c, + 0x7173, 0x0010, 0x00ce, 0x001e, 0x004e, 0x00ce, 0x0005, 0x00f6, + 0x00d6, 0x0026, 0x0016, 0x0136, 0x0146, 0x0156, 0x3c00, 0x0006, + 0x2079, 0x0030, 0x2069, 0x0200, 0x080c, 0x1f2d, 0x1590, 0x080c, + 0x1dd2, 0x05e0, 0x04f1, 0x1130, 0x7908, 0xa18c, 0x1fff, 0xa182, + 0x0011, 0x1688, 0x20a9, 0x000c, 0x20e1, 0x0000, 0x2ea0, 0x2099, + 0x020a, 0x53a5, 0x20e1, 0x2000, 0x2001, 0x020a, 0x2004, 0x7a0c, + 0x7808, 0xa080, 0x0007, 0xa084, 0x1ff8, 0x0419, 0x1120, 0xa08a, + 0x0140, 0x1a0c, 0x1515, 0x80ac, 0x20e1, 0x6000, 0x2099, 0x020a, + 0x53a5, 0x20e1, 0x7000, 0x6828, 0x6828, 0x7803, 0x0004, 0xa294, + 0x0070, 0x000e, 0x20e0, 0x015e, 0x014e, 0x013e, 0x001e, 0x002e, + 0x00de, 0x00fe, 0x0005, 0xa016, 0x080c, 0x185e, 0xa085, 0x0001, + 0x0c80, 0x0006, 0x2001, 0x0111, 0x2004, 0xa084, 0x0003, 0x000e, + 0x0005, 0x0046, 0x00e6, 0x00d6, 0x2028, 0x2130, 0xa696, 0x00ff, + 0x1198, 0xa596, 0xfffd, 0x1120, 0x2009, 0x007f, 0x0804, 0x6703, + 0xa596, 0xfffe, 0x1118, 0x2009, 0x007e, 0x04e8, 0xa596, 0xfffc, + 0x1118, 0x2009, 0x0080, 0x04b8, 0x2011, 0x0000, 0x2019, 0xb535, + 0x231c, 0xd3ac, 0x0138, 0x2021, 0x0000, 0x20a9, 0x00ff, 0x2071, + 0xb635, 0x0030, 0x2021, 0x0081, 0x20a9, 0x007e, 0x2071, 0xb6b6, + 0x2e1c, 0x83ff, 0x1128, 0x82ff, 0x1198, 0x2410, 0xc2fd, 0x0080, + 0x2368, 0x6f10, 0x0006, 0x2100, 0xa706, 0x000e, 0x6b14, 0x1120, + 0xa346, 0x1110, 0x2408, 0x0078, 0x87ff, 0x1110, 0x83ff, 0x0d58, + 0x8420, 0x8e70, 0x1f04, 0x66e0, 0x82ff, 0x1118, 0xa085, 0x0001, + 0x0018, 0xc2fc, 0x2208, 0xa006, 0x00de, 0x00ee, 0x004e, 0x0005, + 0xa084, 0x0007, 0x000a, 0x0005, 0x6714, 0x6714, 0x6714, 0x6861, + 0x6714, 0x6715, 0x672a, 0x679f, 0x0005, 0x7110, 0xd1bc, 0x0188, + 0x7120, 0x2160, 0xac8c, 0x0007, 0x1160, 0xac8a, 0xbd00, 0x0248, + 0x685c, 0xac02, 0x1230, 0x7124, 0x610a, 0x2009, 0x0046, 0x080c, + 0x864c, 0x0005, 0x00c6, 0xa484, 0x01ff, 0x0904, 0x677d, 0x7110, + 0xd1bc, 0x1904, 0x677d, 0x2011, 0xbb83, 0x2204, 0x8211, 0x220c, + 0x080c, 0x281d, 0x1904, 0x677d, 0x080c, 0x4f4d, 0x15f0, 0x6612, + 0x6516, 0x6000, 0xd0ec, 0x15c8, 0x6204, 0xa294, 0xff00, 0x8217, + 0xa286, 0x0006, 0x0148, 0x6204, 0xa294, 0x00ff, 0xa286, 0x0006, + 0x11a0, 0xa295, 0x0600, 0x6206, 0x00c6, 0x080c, 0x85c7, 0x001e, + 0x0530, 0x611a, 0x601f, 0x0006, 0x7120, 0x610a, 0x7130, 0x6152, + 0x2009, 0x0044, 0x080c, 0x864c, 0x00c0, 0x00c6, 0x080c, 0x85c7, + 0x001e, 0x0198, 0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0xa286, + 0x0004, 0x1118, 0x6007, 0x0005, 0x0010, 0x6007, 0x0001, 0x6003, + 0x0001, 0x080c, 0x6cd3, 0x080c, 0x7173, 0x00ce, 0x0005, 0x2001, + 0xb50d, 0x2004, 0xd0ec, 0x0120, 0x2011, 0x8049, 0x080c, 0x3ecc, + 0x00c6, 0x080c, 0x9ed6, 0x001e, 0x0d80, 0x611a, 0x601f, 0x0006, + 0x7120, 0x610a, 0x7130, 0x6152, 0x6013, 0x0300, 0x6003, 0x0001, + 0x6007, 0x0041, 0x080c, 0x6c8d, 0x080c, 0x7173, 0x08f0, 0x7110, + 0xd1bc, 0x0188, 0x7020, 0x2060, 0xac84, 0x0007, 0x1160, 0xac82, + 0xbd00, 0x0248, 0x685c, 0xac02, 0x1230, 0x7124, 0x610a, 0x2009, + 0x0045, 0x080c, 0x864c, 0x0005, 0x0006, 0x080c, 0x2dbf, 0x000e, + 0x1168, 0x7110, 0xa18c, 0xff00, 0x810f, 0xa18e, 0x0000, 0x1130, + 0xa084, 0x000f, 0xa08a, 0x0006, 0x1208, 0x000b, 0x0005, 0x67cd, + 0x67ce, 0x67cd, 0x67cd, 0x6837, 0x6843, 0x0005, 0x7110, 0xd1bc, + 0x0120, 0x702c, 0xd084, 0x0904, 0x6836, 0x700c, 0x7108, 0x080c, + 0x281d, 0x1904, 0x6836, 0x080c, 0x4f4d, 0x1904, 0x6836, 0x6612, + 0x6516, 0x6204, 0x7110, 0xd1bc, 0x01f8, 0xa28c, 0x00ff, 0xa186, + 0x0004, 0x0118, 0xa186, 0x0006, 0x15c8, 0x00c6, 0x080c, 0x684f, + 0x00ce, 0x0904, 0x6836, 0x00c6, 0x080c, 0x85c7, 0x001e, 0x05f0, + 0x611a, 0x080c, 0xa027, 0x601f, 0x0002, 0x7120, 0x610a, 0x2009, + 0x0088, 0x080c, 0x864c, 0x0490, 0xa28c, 0x00ff, 0xa186, 0x0006, + 0x0160, 0xa186, 0x0004, 0x0148, 0xa294, 0xff00, 0x8217, 0xa286, + 0x0004, 0x0118, 0xa286, 0x0006, 0x1188, 0x00c6, 0x080c, 0x85c7, + 0x001e, 0x01e0, 0x611a, 0x080c, 0xa027, 0x601f, 0x0005, 0x7120, + 0x610a, 0x2009, 0x0088, 0x080c, 0x864c, 0x0080, 0x00c6, 0x080c, + 0x85c7, 0x001e, 0x0158, 0x611a, 0x080c, 0xa027, 0x601f, 0x0004, + 0x7120, 0x610a, 0x2009, 0x0001, 0x080c, 0x864c, 0x0005, 0x7110, + 0xd1bc, 0x0140, 0x00a1, 0x0130, 0x7124, 0x610a, 0x2009, 0x0089, + 0x080c, 0x864c, 0x0005, 0x7110, 0xd1bc, 0x0140, 0x0041, 0x0130, + 0x7124, 0x610a, 0x2009, 0x008a, 0x080c, 0x864c, 0x0005, 0x7020, + 0x2060, 0xac84, 0x0007, 0x1158, 0xac82, 0xbd00, 0x0240, 0x2001, + 0xb517, 0x2004, 0xac02, 0x1218, 0xa085, 0x0001, 0x0005, 0xa006, + 0x0ce8, 0x7110, 0xd1bc, 0x1178, 0x7024, 0x2060, 0xac84, 0x0007, + 0x1150, 0xac82, 0xbd00, 0x0238, 0x685c, 0xac02, 0x1220, 0x2009, + 0x0051, 0x080c, 0x864c, 0x0005, 0x2031, 0x0105, 0x0069, 0x0005, + 0x2031, 0x0206, 0x0049, 0x0005, 0x2031, 0x0207, 0x0029, 0x0005, + 0x2031, 0x0213, 0x0009, 0x0005, 0x00c6, 0x00d6, 0x00f6, 0x7000, + 0xa084, 0xf000, 0xa086, 0xc000, 0x05b0, 0x080c, 0x85c7, 0x0598, + 0x0066, 0x00c6, 0x0046, 0x2011, 0xbb83, 0x2204, 0x8211, 0x220c, + 0x080c, 0x281d, 0x1580, 0x080c, 0x4f4d, 0x1568, 0x6612, 0x6516, + 0x2c00, 0x004e, 0x00ce, 0x601a, 0x080c, 0xa027, 0x080c, 0x15f8, + 0x01f0, 0x2d00, 0x6056, 0x6803, 0x0000, 0x6837, 0x0000, 0x6c3a, + 0xadf8, 0x000f, 0x20a9, 0x000e, 0x2fa0, 0x2e98, 0x53a3, 0x006e, + 0x6612, 0x6007, 0x003e, 0x601f, 0x0001, 0x6003, 0x0001, 0x080c, + 0x6cd3, 0x080c, 0x7173, 0x00fe, 0x00de, 0x00ce, 0x0005, 0x080c, + 0x861d, 0x006e, 0x0cc0, 0x004e, 0x00ce, 0x0cc8, 0x2071, 0xb7f3, + 0x7003, 0x0003, 0x700f, 0x0361, 0xa006, 0x701a, 0x7076, 0x7012, + 0x7017, 0xbd00, 0x7007, 0x0000, 0x7026, 0x702b, 0x7d91, 0x7032, + 0x7037, 0x7df1, 0x703b, 0xffff, 0x703f, 0xffff, 0x7042, 0x7047, + 0x444b, 0x704a, 0x705b, 0x6a2b, 0x2001, 0xb7a1, 0x2003, 0x0003, + 0x2001, 0xb7a3, 0x2003, 0x0100, 0x3a00, 0xa084, 0x0005, 0x706e, + 0x0005, 0x2071, 0xb7f3, 0x1d04, 0x698b, 0x2091, 0x6000, 0x700c, + 0x8001, 0x700e, 0x1518, 0x700f, 0x0361, 0x7007, 0x0001, 0x0126, + 0x2091, 0x8000, 0x7040, 0xa00d, 0x0128, 0x8109, 0x7142, 0x1110, + 0x7044, 0x080f, 0x00c6, 0x2061, 0xb500, 0x6034, 0x00ce, 0xd0cc, + 0x0180, 0x3a00, 0xa084, 0x0005, 0x726c, 0xa216, 0x0150, 0x706e, + 0x2011, 0x8043, 0x2018, 0x080c, 0x3ecc, 0x0018, 0x0126, 0x2091, + 0x8000, 0x7024, 0xa00d, 0x0188, 0x7020, 0x8001, 0x7022, 0x1168, + 0x7023, 0x0009, 0x8109, 0x7126, 0xa186, 0x03e8, 0x1110, 0x7028, + 0x080f, 0x81ff, 0x1110, 0x7028, 0x080f, 0x7030, 0xa00d, 0x0180, + 0x702c, 0x8001, 0x702e, 0x1160, 0x702f, 0x0009, 0x8109, 0x7132, + 0x0128, 0xa184, 0x007f, 0x090c, 0x7e36, 0x0010, 0x7034, 0x080f, + 0x7038, 0xa005, 0x0118, 0x0310, 0x8001, 0x703a, 0x703c, 0xa005, + 0x0118, 0x0310, 0x8001, 0x703e, 0x704c, 0xa00d, 0x0168, 0x7048, + 0x8001, 0x704a, 0x1148, 0x704b, 0x0009, 0x8109, 0x714e, 0x1120, + 0x7150, 0x714e, 0x7058, 0x080f, 0x7018, 0xa00d, 0x01d8, 0x0016, + 0x7074, 0xa00d, 0x0158, 0x7070, 0x8001, 0x7072, 0x1138, 0x7073, + 0x0009, 0x8109, 0x7176, 0x1110, 0x7078, 0x080f, 0x001e, 0x7008, + 0x8001, 0x700a, 0x1138, 0x700b, 0x0009, 0x8109, 0x711a, 0x1110, + 0x701c, 0x080f, 0x012e, 0x7004, 0x0002, 0x69b1, 0x69b2, 0x69ca, + 0x00e6, 0x2071, 0xb7f3, 0x7018, 0xa005, 0x1120, 0x711a, 0x721e, + 0x700b, 0x0009, 0x00ee, 0x0005, 0x00e6, 0x0006, 0x2071, 0xb7f3, + 0x701c, 0xa206, 0x1110, 0x701a, 0x701e, 0x000e, 0x00ee, 0x0005, + 0x00e6, 0x2071, 0xb7f3, 0x6088, 0xa102, 0x0208, 0x618a, 0x00ee, + 0x0005, 0x0005, 0x7110, 0x080c, 0x4fa9, 0x1158, 0x6088, 0x8001, + 0x0240, 0x608a, 0x1130, 0x0126, 0x2091, 0x8000, 0x080c, 0x7173, + 0x012e, 0x8108, 0xa182, 0x00ff, 0x0218, 0xa00e, 0x7007, 0x0002, + 0x7112, 0x0005, 0x7014, 0x2060, 0x0126, 0x2091, 0x8000, 0x603c, + 0xa005, 0x0128, 0x8001, 0x603e, 0x1110, 0x080c, 0x9f15, 0x6014, + 0xa005, 0x0500, 0x8001, 0x6016, 0x11e8, 0x611c, 0xa186, 0x0003, + 0x0118, 0xa186, 0x0006, 0x11a0, 0x6010, 0x2068, 0x6854, 0xa08a, + 0x199a, 0x0270, 0xa082, 0x1999, 0x6856, 0xa08a, 0x199a, 0x0210, + 0x2001, 0x1999, 0x8003, 0x800b, 0x810b, 0xa108, 0x6116, 0x0010, + 0x080c, 0x99e5, 0x012e, 0xac88, 0x0018, 0x7116, 0x2001, 0xed00, + 0xa102, 0x0220, 0x7017, 0xbd00, 0x7007, 0x0000, 0x0005, 0x00e6, + 0x2071, 0xb7f3, 0x7027, 0x07d0, 0x7023, 0x0009, 0x00ee, 0x0005, + 0x2001, 0xb7fc, 0x2003, 0x0000, 0x0005, 0x00e6, 0x2071, 0xb7f3, + 0x7132, 0x702f, 0x0009, 0x00ee, 0x0005, 0x2011, 0xb7ff, 0x2013, + 0x0000, 0x0005, 0x00e6, 0x2071, 0xb7f3, 0x711a, 0x721e, 0x700b, + 0x0009, 0x00ee, 0x0005, 0x00c6, 0x0026, 0x7054, 0x8000, 0x7056, + 0x2061, 0xb7a1, 0x6008, 0xa086, 0x0000, 0x0158, 0x7068, 0x6032, + 0x7064, 0x602e, 0x7060, 0x602a, 0x705c, 0x6026, 0x2c10, 0x080c, + 0x1643, 0x002e, 0x00ce, 0x0005, 0x0006, 0x0016, 0x00c6, 0x00d6, + 0x00e6, 0x00f6, 0x080c, 0x68f9, 0x00fe, 0x00ee, 0x00de, 0x00ce, + 0x001e, 0x000e, 0x0005, 0x00e6, 0x2071, 0xb7f3, 0x7176, 0x727a, + 0x7073, 0x0009, 0x00ee, 0x0005, 0x00e6, 0x0006, 0x2071, 0xb7f3, + 0x7078, 0xa206, 0x1110, 0x7076, 0x707a, 0x000e, 0x00ee, 0x0005, + 0x00c6, 0x2061, 0xb874, 0x00ce, 0x0005, 0xa184, 0x000f, 0x8003, + 0x8003, 0x8003, 0xa080, 0xb874, 0x2060, 0x0005, 0x6854, 0xa08a, + 0x199a, 0x0210, 0x2001, 0x1999, 0xa005, 0x1150, 0x00c6, 0x2061, + 0xb874, 0x6014, 0x00ce, 0xa005, 0x1138, 0x2001, 0x001e, 0x0020, + 0xa08e, 0xffff, 0x1108, 0xa006, 0x8003, 0x800b, 0x810b, 0xa108, + 0x6116, 0x684c, 0xa08c, 0x00c0, 0xa18e, 0x00c0, 0x05e8, 0xd0b4, + 0x1138, 0xd0bc, 0x1550, 0x2009, 0x0006, 0x080c, 0x6af1, 0x0005, + 0xd0fc, 0x0138, 0xa084, 0x0003, 0x0120, 0xa086, 0x0003, 0x1904, + 0x6aeb, 0x6020, 0xd0d4, 0x0130, 0xc0d4, 0x6022, 0x6860, 0x602a, + 0x685c, 0x602e, 0x2009, 0xb574, 0x2104, 0xd084, 0x0138, 0x87ff, + 0x1120, 0x2009, 0x0042, 0x080c, 0x864c, 0x0005, 0x87ff, 0x1120, + 0x2009, 0x0043, 0x080c, 0x864c, 0x0005, 0xd0fc, 0x0130, 0xa084, + 0x0003, 0x0118, 0xa086, 0x0003, 0x11f0, 0x87ff, 0x1120, 0x2009, + 0x0042, 0x080c, 0x864c, 0x0005, 0xd0fc, 0x0160, 0xa084, 0x0003, + 0xa08e, 0x0002, 0x0148, 0x87ff, 0x1120, 0x2009, 0x0041, 0x080c, + 0x864c, 0x0005, 0x0061, 0x0ce8, 0x87ff, 0x1dd8, 0x2009, 0x0043, + 0x080c, 0x864c, 0x0cb0, 0x2009, 0x0004, 0x0019, 0x0005, 0x2009, + 0x0001, 0x00d6, 0x6010, 0xa0ec, 0xf000, 0x0510, 0x2068, 0x6952, + 0x6800, 0x6012, 0xa186, 0x0001, 0x1188, 0x694c, 0xa18c, 0x8100, + 0xa18e, 0x8100, 0x1158, 0x00c6, 0x2061, 0xb874, 0x6200, 0xd28c, + 0x1120, 0x6204, 0x8210, 0x0208, 0x6206, 0x00ce, 0x080c, 0x5408, + 0x6010, 0xa06d, 0x0076, 0x2039, 0x0000, 0x190c, 0x6a76, 0x007e, + 0x00de, 0x0005, 0x0156, 0x00c6, 0x2061, 0xb874, 0x6000, 0x81ff, + 0x0110, 0xa205, 0x0008, 0xa204, 0x6002, 0x00ce, 0x015e, 0x0005, + 0x6800, 0xd08c, 0x1138, 0x6808, 0xa005, 0x0120, 0x8001, 0x680a, + 0xa085, 0x0001, 0x0005, 0x20a9, 0x0010, 0xa006, 0x8004, 0x8086, + 0x818e, 0x1208, 0xa200, 0x1f04, 0x6b37, 0x8086, 0x818e, 0x0005, + 0x0156, 0x20a9, 0x0010, 0xa005, 0x01b8, 0xa11a, 0x12a8, 0x8213, + 0x818d, 0x0228, 0xa11a, 0x1220, 0x1f04, 0x6b47, 0x0028, 0xa11a, + 0x2308, 0x8210, 0x1f04, 0x6b47, 0x0006, 0x3200, 0xa084, 0xefff, + 0x2080, 0x000e, 0x015e, 0x0005, 0x0006, 0x3200, 0xa085, 0x1000, + 0x0cb8, 0x0126, 0x2091, 0x2800, 0x2079, 0xb7e0, 0x012e, 0x00d6, + 0x2069, 0xb7e0, 0x6803, 0x0005, 0x2069, 0x0004, 0x2d04, 0xa085, + 0x8001, 0x206a, 0x00de, 0x0005, 0x00c6, 0x6027, 0x0001, 0x7804, + 0xa084, 0x0007, 0x0002, 0x6b85, 0x6ba6, 0x6bf9, 0x6b8b, 0x6ba6, + 0x6b85, 0x6b83, 0x6b83, 0x080c, 0x1515, 0x080c, 0x6a10, 0x080c, + 0x7173, 0x00ce, 0x0005, 0x62c0, 0x82ff, 0x1110, 0x00ce, 0x0005, + 0x2011, 0x4adc, 0x080c, 0x699c, 0x7828, 0xa092, 0x00c8, 0x1228, + 0x8000, 0x782a, 0x080c, 0x4b16, 0x0c88, 0x080c, 0x4adc, 0x7807, + 0x0003, 0x7827, 0x0000, 0x782b, 0x0000, 0x0c40, 0x080c, 0x6a10, + 0x3c00, 0x0006, 0x2011, 0x0209, 0x20e1, 0x4000, 0x2214, 0x000e, + 0x20e0, 0x82ff, 0x0178, 0x62c0, 0x82ff, 0x1160, 0x782b, 0x0000, + 0x7824, 0xa065, 0x090c, 0x1515, 0x2009, 0x0013, 0x080c, 0x864c, + 0x00ce, 0x0005, 0x3900, 0xa082, 0xb92c, 0x1210, 0x080c, 0x8332, + 0x00c6, 0x7824, 0xa065, 0x090c, 0x1515, 0x7804, 0xa086, 0x0004, + 0x0904, 0x6c39, 0x7828, 0xa092, 0x2710, 0x1230, 0x8000, 0x782a, + 0x00ce, 0x080c, 0x7d6d, 0x0c20, 0x6104, 0xa186, 0x0003, 0x1188, + 0x00e6, 0x2071, 0xb500, 0x70e0, 0x00ee, 0xd08c, 0x0150, 0x00c6, + 0x00e6, 0x2061, 0x0100, 0x2071, 0xb500, 0x080c, 0x4b1f, 0x00ee, + 0x00ce, 0x080c, 0xb444, 0x2009, 0x0014, 0x080c, 0x864c, 0x00ce, + 0x0838, 0x2001, 0xb7fc, 0x2003, 0x0000, 0x62c0, 0x82ff, 0x1160, + 0x782b, 0x0000, 0x7824, 0xa065, 0x090c, 0x1515, 0x2009, 0x0013, + 0x080c, 0x86a0, 0x00ce, 0x0005, 0x00c6, 0x00d6, 0x3900, 0xa082, + 0xb92c, 0x1210, 0x080c, 0x8332, 0x7824, 0xa005, 0x090c, 0x1515, + 0x781c, 0xa06d, 0x090c, 0x1515, 0x6800, 0xc0dc, 0x6802, 0x7924, + 0x2160, 0x080c, 0x861d, 0x693c, 0x81ff, 0x090c, 0x1515, 0x8109, + 0x693e, 0x6854, 0xa015, 0x0110, 0x7a1e, 0x0010, 0x7918, 0x791e, + 0x7807, 0x0000, 0x7827, 0x0000, 0x00de, 0x00ce, 0x080c, 0x7173, + 0x0888, 0x6104, 0xa186, 0x0002, 0x0128, 0xa186, 0x0004, 0x0110, + 0x0804, 0x6bd2, 0x7808, 0xac06, 0x0904, 0x6bd2, 0x080c, 0x7090, + 0x080c, 0x6cd3, 0x00ce, 0x080c, 0x7173, 0x0804, 0x6bc0, 0x00c6, + 0x6027, 0x0002, 0x62c8, 0x60c4, 0xa205, 0x1178, 0x793c, 0xa1e5, + 0x0000, 0x0130, 0x2009, 0x0049, 0x080c, 0x864c, 0x00ce, 0x0005, + 0x2011, 0xb7ff, 0x2013, 0x0000, 0x0cc8, 0x3908, 0xa192, 0xb92c, + 0x1210, 0x080c, 0x8332, 0x793c, 0x81ff, 0x0d90, 0x7944, 0xa192, + 0x7530, 0x12b8, 0x8108, 0x7946, 0x793c, 0xa188, 0x0007, 0x210c, + 0xa18e, 0x0006, 0x1138, 0x6014, 0xa084, 0x0184, 0xa085, 0x0012, + 0x6016, 0x08e0, 0x6014, 0xa084, 0x0184, 0xa085, 0x0016, 0x6016, + 0x08a8, 0x7848, 0xc085, 0x784a, 0x0888, 0x0006, 0x0016, 0x00c6, + 0x0126, 0x2091, 0x8000, 0x600f, 0x0000, 0x2c08, 0x2061, 0xb7e0, + 0x6020, 0x8000, 0x6022, 0x6010, 0xa005, 0x0148, 0xa080, 0x0003, + 0x2102, 0x6112, 0x012e, 0x00ce, 0x001e, 0x000e, 0x0005, 0x6116, + 0x6112, 0x0cc0, 0x00d6, 0x2069, 0xb7e0, 0x6000, 0xd0d4, 0x0168, + 0x6820, 0x8000, 0x6822, 0xa086, 0x0001, 0x1110, 0x2c00, 0x681e, + 0x6804, 0xa084, 0x0007, 0x0804, 0x7179, 0xc0d5, 0x6002, 0x6818, + 0xa005, 0x0158, 0x6056, 0x605b, 0x0000, 0x0006, 0x2c00, 0x681a, + 0x00de, 0x685a, 0x2069, 0xb7e0, 0x0c18, 0x6056, 0x605a, 0x2c00, + 0x681a, 0x681e, 0x08e8, 0x0006, 0x0016, 0x00c6, 0x0126, 0x2091, + 0x8000, 0x600f, 0x0000, 0x2c08, 0x2061, 0xb7e0, 0x6020, 0x8000, + 0x6022, 0x6008, 0xa005, 0x0148, 0xa080, 0x0003, 0x2102, 0x610a, + 0x012e, 0x00ce, 0x001e, 0x000e, 0x0005, 0x610e, 0x610a, 0x0cc0, + 0x00c6, 0x600f, 0x0000, 0x2c08, 0x2061, 0xb7e0, 0x6034, 0xa005, + 0x0130, 0xa080, 0x0003, 0x2102, 0x6136, 0x00ce, 0x0005, 0x613a, + 0x6136, 0x0cd8, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0076, 0x0066, + 0x0056, 0x0036, 0x0026, 0x0016, 0x0006, 0x0126, 0xa02e, 0x2071, + 0xb7e0, 0x7638, 0x2660, 0x2678, 0x2091, 0x8000, 0x8cff, 0x0904, + 0x6d7b, 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, 0x1904, 0x6d76, + 0x87ff, 0x0120, 0x6050, 0xa106, 0x1904, 0x6d76, 0x703c, 0xac06, + 0x1190, 0x0036, 0x2019, 0x0001, 0x080c, 0x7fe4, 0x7033, 0x0000, + 0x703f, 0x0000, 0x7043, 0x0000, 0x7047, 0x0000, 0x704b, 0x0000, + 0x003e, 0x2029, 0x0001, 0x7038, 0xac36, 0x1110, 0x660c, 0x763a, + 0x7034, 0xac36, 0x1140, 0x2c00, 0xaf36, 0x0118, 0x2f00, 0x7036, + 0x0010, 0x7037, 0x0000, 0x660c, 0x0066, 0x2c00, 0xaf06, 0x0110, + 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0x080c, 0x9c5a, 0x01c8, + 0x6010, 0x2068, 0x601c, 0xa086, 0x0003, 0x1580, 0x6837, 0x0103, + 0x6b4a, 0x6847, 0x0000, 0x0016, 0x0036, 0x0076, 0x080c, 0x9ecc, + 0x080c, 0xb380, 0x080c, 0x5408, 0x007e, 0x003e, 0x001e, 0x080c, + 0x9e11, 0x080c, 0x9e1d, 0x00ce, 0x0804, 0x6d16, 0x2c78, 0x600c, + 0x2060, 0x0804, 0x6d16, 0x85ff, 0x0120, 0x0036, 0x080c, 0x7230, + 0x003e, 0x012e, 0x000e, 0x001e, 0x002e, 0x003e, 0x005e, 0x006e, + 0x007e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x0005, 0x601c, 0xa086, + 0x0006, 0x1158, 0x0016, 0x0036, 0x0076, 0x080c, 0xb380, 0x080c, + 0xb099, 0x007e, 0x003e, 0x001e, 0x08a0, 0x601c, 0xa086, 0x000a, + 0x0904, 0x6d60, 0x0804, 0x6d5e, 0x0006, 0x0066, 0x00c6, 0x00d6, + 0x00f6, 0x2031, 0x0000, 0x0126, 0x2091, 0x8000, 0x2079, 0xb7e0, + 0x7838, 0xa065, 0x0568, 0x600c, 0x0006, 0x600f, 0x0000, 0x783c, + 0xac06, 0x1180, 0x0036, 0x2019, 0x0001, 0x080c, 0x7fe4, 0x7833, + 0x0000, 0x783f, 0x0000, 0x7843, 0x0000, 0x7847, 0x0000, 0x784b, + 0x0000, 0x003e, 0x080c, 0x9c5a, 0x0178, 0x6010, 0x2068, 0x601c, + 0xa086, 0x0003, 0x11b0, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, + 0x080c, 0x5408, 0x080c, 0x9e11, 0x080c, 0x9e1d, 0x000e, 0x0888, + 0x7e3a, 0x7e36, 0x012e, 0x00fe, 0x00de, 0x00ce, 0x006e, 0x000e, + 0x0005, 0x601c, 0xa086, 0x0006, 0x1118, 0x080c, 0xb099, 0x0c60, + 0x601c, 0xa086, 0x000a, 0x0d08, 0x08f0, 0x0016, 0x0026, 0x0086, + 0x2041, 0x0000, 0x0099, 0x080c, 0x6ec3, 0x008e, 0x002e, 0x001e, + 0x0005, 0x00f6, 0x0126, 0x2079, 0xb7e0, 0x2091, 0x8000, 0x080c, + 0x6f50, 0x080c, 0x6fc2, 0x012e, 0x00fe, 0x0005, 0x00f6, 0x00e6, + 0x00d6, 0x00c6, 0x0066, 0x0016, 0x0006, 0x0126, 0x2091, 0x8000, + 0x2071, 0xb7e0, 0x7614, 0x2660, 0x2678, 0x8cff, 0x0904, 0x6e99, + 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, 0x1904, 0x6e94, 0x88ff, + 0x0120, 0x6050, 0xa106, 0x1904, 0x6e94, 0x7024, 0xac06, 0x1538, + 0x2069, 0x0100, 0x68c0, 0xa005, 0x01f0, 0x080c, 0x6a10, 0x080c, + 0x7d7a, 0x68c3, 0x0000, 0x080c, 0x824d, 0x7027, 0x0000, 0x0036, + 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0120, 0x6803, 0x0100, + 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, + 0x0001, 0x003e, 0x0020, 0x6003, 0x0009, 0x630a, 0x04e8, 0x7014, + 0xac36, 0x1110, 0x660c, 0x7616, 0x7010, 0xac36, 0x1140, 0x2c00, + 0xaf36, 0x0118, 0x2f00, 0x7012, 0x0010, 0x7013, 0x0000, 0x660c, + 0x0066, 0x2c00, 0xaf06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f, + 0x0000, 0x6010, 0x2068, 0x080c, 0x9c5a, 0x01b8, 0x601c, 0xa086, + 0x0003, 0x1540, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x0016, + 0x0036, 0x0086, 0x080c, 0x9ecc, 0x080c, 0xb380, 0x080c, 0x5408, + 0x008e, 0x003e, 0x001e, 0x080c, 0x9e11, 0x080c, 0x9e1d, 0x080c, + 0x811e, 0x00ce, 0x0804, 0x6e1d, 0x2c78, 0x600c, 0x2060, 0x0804, + 0x6e1d, 0x012e, 0x000e, 0x001e, 0x006e, 0x00ce, 0x00de, 0x00ee, + 0x00fe, 0x0005, 0x601c, 0xa086, 0x0006, 0x1158, 0x0016, 0x0036, + 0x0086, 0x080c, 0xb380, 0x080c, 0xb099, 0x008e, 0x003e, 0x001e, + 0x08e0, 0x601c, 0xa086, 0x0002, 0x1128, 0x6004, 0xa086, 0x0085, + 0x0908, 0x0898, 0x601c, 0xa086, 0x0005, 0x1978, 0x6004, 0xa086, + 0x0085, 0x0d20, 0x0850, 0x00c6, 0x0006, 0x0126, 0x2091, 0x8000, + 0xa280, 0xb635, 0x2004, 0xa065, 0x0904, 0x6f4c, 0x00f6, 0x00e6, + 0x00d6, 0x0066, 0x2071, 0xb7e0, 0x6654, 0x7018, 0xac06, 0x1108, + 0x761a, 0x701c, 0xac06, 0x1130, 0x86ff, 0x1118, 0x7018, 0x701e, + 0x0008, 0x761e, 0x6058, 0xa07d, 0x0108, 0x7e56, 0xa6ed, 0x0000, + 0x0110, 0x2f00, 0x685a, 0x6057, 0x0000, 0x605b, 0x0000, 0x6000, + 0xc0d4, 0xc0dc, 0x6002, 0x080c, 0x4ed4, 0x0904, 0x6f48, 0x7624, + 0x86ff, 0x05e8, 0xa680, 0x0004, 0x2004, 0xad06, 0x15c0, 0x00d6, + 0x2069, 0x0100, 0x68c0, 0xa005, 0x0548, 0x080c, 0x6a10, 0x080c, + 0x7d7a, 0x68c3, 0x0000, 0x080c, 0x824d, 0x7027, 0x0000, 0x0036, + 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0120, 0x6803, 0x0100, + 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, + 0x0001, 0x003e, 0x00de, 0x00c6, 0x603c, 0xa005, 0x0110, 0x8001, + 0x603e, 0x2660, 0x080c, 0x9e1d, 0x00ce, 0x0048, 0x00de, 0x00c6, + 0x2660, 0x6003, 0x0009, 0x630a, 0x00ce, 0x0804, 0x6ef3, 0x8dff, + 0x0158, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, 0x9ecc, + 0x080c, 0xb380, 0x080c, 0x5408, 0x080c, 0x811e, 0x0804, 0x6ef3, + 0x006e, 0x00de, 0x00ee, 0x00fe, 0x012e, 0x000e, 0x00ce, 0x0005, + 0x0006, 0x0066, 0x00c6, 0x00d6, 0x2031, 0x0000, 0x7814, 0xa065, + 0x0904, 0x6fa2, 0x600c, 0x0006, 0x600f, 0x0000, 0x7824, 0xac06, + 0x1540, 0x2069, 0x0100, 0x68c0, 0xa005, 0x01f0, 0x080c, 0x6a10, + 0x080c, 0x7d7a, 0x68c3, 0x0000, 0x080c, 0x824d, 0x7827, 0x0000, + 0x0036, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0120, 0x6803, + 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0110, + 0x6827, 0x0001, 0x003e, 0x0028, 0x6003, 0x0009, 0x630a, 0x2c30, + 0x00b0, 0x6010, 0x2068, 0x080c, 0x9c5a, 0x0168, 0x601c, 0xa086, + 0x0003, 0x11b8, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, + 0x5408, 0x080c, 0x9e11, 0x080c, 0x9e1d, 0x080c, 0x811e, 0x000e, + 0x0804, 0x6f57, 0x7e16, 0x7e12, 0x00de, 0x00ce, 0x006e, 0x000e, + 0x0005, 0x601c, 0xa086, 0x0006, 0x1118, 0x080c, 0xb099, 0x0c58, + 0x601c, 0xa086, 0x0002, 0x1128, 0x6004, 0xa086, 0x0085, 0x09d0, + 0x0c10, 0x601c, 0xa086, 0x0005, 0x19f0, 0x6004, 0xa086, 0x0085, + 0x0d60, 0x08c8, 0x0006, 0x0066, 0x00c6, 0x00d6, 0x7818, 0xa065, + 0x0904, 0x7028, 0x6054, 0x0006, 0x6057, 0x0000, 0x605b, 0x0000, + 0x6000, 0xc0d4, 0xc0dc, 0x6002, 0x080c, 0x4ed4, 0x0904, 0x7025, + 0x7e24, 0x86ff, 0x05e8, 0xa680, 0x0004, 0x2004, 0xad06, 0x15c0, + 0x00d6, 0x2069, 0x0100, 0x68c0, 0xa005, 0x0548, 0x080c, 0x6a10, + 0x080c, 0x7d7a, 0x68c3, 0x0000, 0x080c, 0x824d, 0x7827, 0x0000, + 0x0036, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0120, 0x6803, + 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0110, + 0x6827, 0x0001, 0x003e, 0x00de, 0x00c6, 0x603c, 0xa005, 0x0110, + 0x8001, 0x603e, 0x2660, 0x080c, 0x9e1d, 0x00ce, 0x0048, 0x00de, + 0x00c6, 0x2660, 0x6003, 0x0009, 0x630a, 0x00ce, 0x0804, 0x6fd4, + 0x8dff, 0x0138, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, + 0x5408, 0x080c, 0x811e, 0x0804, 0x6fd4, 0x000e, 0x0804, 0x6fc7, + 0x781e, 0x781a, 0x00de, 0x00ce, 0x006e, 0x000e, 0x0005, 0x00e6, + 0x00d6, 0x0066, 0x6000, 0xd0dc, 0x01a0, 0x604c, 0xa06d, 0x0188, + 0x6848, 0xa606, 0x1170, 0x2071, 0xb7e0, 0x7024, 0xa035, 0x0148, + 0xa080, 0x0004, 0x2004, 0xad06, 0x1120, 0x6000, 0xc0dc, 0x6002, + 0x0021, 0x006e, 0x00de, 0x00ee, 0x0005, 0x00f6, 0x2079, 0x0100, + 0x78c0, 0xa005, 0x1138, 0x00c6, 0x2660, 0x6003, 0x0009, 0x630a, + 0x00ce, 0x04a0, 0x080c, 0x7d7a, 0x78c3, 0x0000, 0x080c, 0x824d, + 0x7027, 0x0000, 0x0036, 0x2079, 0x0140, 0x7b04, 0xa384, 0x1000, + 0x0120, 0x7803, 0x0100, 0x7803, 0x0000, 0x2079, 0x0100, 0x7824, + 0xd084, 0x0110, 0x7827, 0x0001, 0x080c, 0x824d, 0x003e, 0x080c, + 0x4ed4, 0x00c6, 0x603c, 0xa005, 0x0110, 0x8001, 0x603e, 0x2660, + 0x080c, 0x861d, 0x00ce, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, + 0x080c, 0x9ecc, 0x080c, 0x5408, 0x080c, 0x811e, 0x00fe, 0x0005, + 0x00e6, 0x00c6, 0x2071, 0xb7e0, 0x7004, 0xa084, 0x0007, 0x0002, + 0x70a2, 0x70a5, 0x70bb, 0x70d4, 0x7111, 0x70a2, 0x70a0, 0x70a0, + 0x080c, 0x1515, 0x00ce, 0x00ee, 0x0005, 0x7024, 0xa065, 0x0148, + 0x7020, 0x8001, 0x7022, 0x600c, 0xa015, 0x0150, 0x7216, 0x600f, + 0x0000, 0x7007, 0x0000, 0x7027, 0x0000, 0x00ce, 0x00ee, 0x0005, + 0x7216, 0x7212, 0x0cb0, 0x6018, 0x2060, 0x080c, 0x4ed4, 0x6000, + 0xc0dc, 0x6002, 0x7020, 0x8001, 0x7022, 0x0120, 0x6054, 0xa015, + 0x0140, 0x721e, 0x7007, 0x0000, 0x7027, 0x0000, 0x00ce, 0x00ee, + 0x0005, 0x7218, 0x721e, 0x0cb0, 0x7024, 0xa065, 0x05b8, 0x700c, + 0xac06, 0x1160, 0x080c, 0x811e, 0x600c, 0xa015, 0x0120, 0x720e, + 0x600f, 0x0000, 0x0448, 0x720e, 0x720a, 0x0430, 0x7014, 0xac06, + 0x1160, 0x080c, 0x811e, 0x600c, 0xa015, 0x0120, 0x7216, 0x600f, + 0x0000, 0x00d0, 0x7216, 0x7212, 0x00b8, 0x601c, 0xa086, 0x0003, + 0x1198, 0x6018, 0x2060, 0x080c, 0x4ed4, 0x6000, 0xc0dc, 0x6002, + 0x080c, 0x811e, 0x701c, 0xa065, 0x0138, 0x6054, 0xa015, 0x0110, + 0x721e, 0x0010, 0x7218, 0x721e, 0x7027, 0x0000, 0x00ce, 0x00ee, + 0x0005, 0x7024, 0xa065, 0x0140, 0x080c, 0x811e, 0x600c, 0xa015, + 0x0150, 0x720e, 0x600f, 0x0000, 0x080c, 0x824d, 0x7027, 0x0000, + 0x00ce, 0x00ee, 0x0005, 0x720e, 0x720a, 0x0cb0, 0x00d6, 0x2069, + 0xb7e0, 0x6830, 0xa084, 0x0003, 0x0002, 0x7133, 0x7135, 0x7159, + 0x7131, 0x080c, 0x1515, 0x00de, 0x0005, 0x00c6, 0x6840, 0xa086, + 0x0001, 0x01b8, 0x683c, 0xa065, 0x0130, 0x600c, 0xa015, 0x0170, + 0x6a3a, 0x600f, 0x0000, 0x6833, 0x0000, 0x683f, 0x0000, 0x2011, + 0xb7ff, 0x2013, 0x0000, 0x00ce, 0x00de, 0x0005, 0x683a, 0x6836, + 0x0c90, 0x6843, 0x0000, 0x6838, 0xa065, 0x0d68, 0x6003, 0x0003, + 0x0c50, 0x00c6, 0x6843, 0x0000, 0x6847, 0x0000, 0x684b, 0x0000, + 0x683c, 0xa065, 0x0168, 0x600c, 0xa015, 0x0130, 0x6a3a, 0x600f, + 0x0000, 0x683f, 0x0000, 0x0020, 0x683f, 0x0000, 0x683a, 0x6836, + 0x00ce, 0x00de, 0x0005, 0x00d6, 0x2069, 0xb7e0, 0x6804, 0xa084, + 0x0007, 0x0002, 0x7184, 0x7220, 0x7220, 0x7220, 0x7220, 0x7222, + 0x7182, 0x7182, 0x080c, 0x1515, 0x6820, 0xa005, 0x1110, 0x00de, + 0x0005, 0x00c6, 0x680c, 0xa065, 0x0150, 0x6807, 0x0004, 0x6826, + 0x682b, 0x0000, 0x080c, 0x7272, 0x00ce, 0x00de, 0x0005, 0x6814, + 0xa065, 0x0150, 0x6807, 0x0001, 0x6826, 0x682b, 0x0000, 0x080c, + 0x7272, 0x00ce, 0x00de, 0x0005, 0x00e6, 0x0036, 0x6a1c, 0xa2f5, + 0x0000, 0x0904, 0x721c, 0x704c, 0xa00d, 0x0118, 0x7088, 0xa005, + 0x01a0, 0x7054, 0xa075, 0x0120, 0xa20e, 0x0904, 0x721c, 0x0028, + 0x6818, 0xa20e, 0x0904, 0x721c, 0x2070, 0x704c, 0xa00d, 0x0d88, + 0x7088, 0xa005, 0x1d70, 0x2e00, 0x681e, 0x733c, 0x7038, 0xa302, + 0x1e40, 0x080c, 0x85f4, 0x0904, 0x721c, 0x8318, 0x733e, 0x6112, + 0x2e10, 0x621a, 0xa180, 0x0014, 0x2004, 0xa084, 0x00ff, 0x605a, + 0xa180, 0x0014, 0x2003, 0x0000, 0xa180, 0x0015, 0x2004, 0xa08a, + 0x199a, 0x0210, 0x2001, 0x1999, 0x8003, 0x801b, 0x831b, 0xa318, + 0x6316, 0x003e, 0x00f6, 0x2c78, 0x71a0, 0x2001, 0xb535, 0x2004, + 0xd0ac, 0x1110, 0xd1bc, 0x0150, 0x7100, 0xd1f4, 0x0120, 0x7114, + 0xa18c, 0x00ff, 0x0040, 0x2009, 0x0000, 0x0028, 0xa1e0, 0x2dc4, + 0x2c0d, 0xa18c, 0x00ff, 0x2061, 0x0100, 0x619a, 0x080c, 0x78a2, + 0x7300, 0xc3dd, 0x7302, 0x6807, 0x0002, 0x2f18, 0x6b26, 0x682b, + 0x0000, 0x781f, 0x0003, 0x7803, 0x0001, 0x7807, 0x0040, 0x00fe, + 0x00ee, 0x00ce, 0x00de, 0x0005, 0x003e, 0x00ee, 0x00ce, 0x0cd0, + 0x00de, 0x0005, 0x00c6, 0x680c, 0xa065, 0x0138, 0x6807, 0x0004, + 0x6826, 0x682b, 0x0000, 0x080c, 0x7272, 0x00ce, 0x00de, 0x0005, + 0x00f6, 0x00d6, 0x2069, 0xb7e0, 0x6830, 0xa086, 0x0000, 0x11d0, + 0x2001, 0xb50c, 0x200c, 0xd1bc, 0x1560, 0x6838, 0xa07d, 0x0190, + 0x6833, 0x0001, 0x683e, 0x6847, 0x0000, 0x684b, 0x0000, 0x0126, + 0x00f6, 0x2091, 0x2400, 0x002e, 0x080c, 0x2021, 0x1130, 0x012e, + 0x080c, 0x7beb, 0x00de, 0x00fe, 0x0005, 0x012e, 0xe000, 0x6843, + 0x0000, 0x7803, 0x0002, 0x780c, 0xa015, 0x0140, 0x6a3a, 0x780f, + 0x0000, 0x6833, 0x0000, 0x683f, 0x0000, 0x0c60, 0x683a, 0x6836, + 0x0cc0, 0xc1bc, 0x2102, 0x0066, 0x2031, 0x0001, 0x080c, 0x5b51, + 0x006e, 0x0858, 0x601c, 0xa084, 0x000f, 0x000b, 0x0005, 0x7280, + 0x7285, 0x7743, 0x785f, 0x7285, 0x7743, 0x785f, 0x7280, 0x7285, + 0x080c, 0x7090, 0x080c, 0x7173, 0x0005, 0x0156, 0x0136, 0x0146, + 0x00c6, 0x00f6, 0x6004, 0xa08a, 0x0080, 0x1a0c, 0x1515, 0x6118, + 0x2178, 0x79a0, 0x2011, 0xb535, 0x2214, 0xd2ac, 0x1110, 0xd1bc, + 0x0150, 0x7900, 0xd1f4, 0x0120, 0x7914, 0xa18c, 0x00ff, 0x0040, + 0x2009, 0x0000, 0x0028, 0xa1f8, 0x2dc4, 0x2f0d, 0xa18c, 0x00ff, + 0x2c78, 0x2061, 0x0100, 0x619a, 0xa08a, 0x0040, 0x1a04, 0x72f9, + 0x0033, 0x00fe, 0x00ce, 0x014e, 0x013e, 0x015e, 0x0005, 0x73a8, + 0x73f3, 0x7420, 0x74ed, 0x751b, 0x7523, 0x7549, 0x755a, 0x756b, + 0x7573, 0x7589, 0x7573, 0x75ea, 0x755a, 0x760b, 0x7613, 0x756b, + 0x7613, 0x7624, 0x72f7, 0x72f7, 0x72f7, 0x72f7, 0x72f7, 0x72f7, + 0x72f7, 0x72f7, 0x72f7, 0x72f7, 0x72f7, 0x7e85, 0x7eaa, 0x7ebf, + 0x7ee2, 0x7f03, 0x7549, 0x72f7, 0x7549, 0x7573, 0x72f7, 0x7420, + 0x74ed, 0x72f7, 0x834f, 0x7573, 0x72f7, 0x836f, 0x7573, 0x72f7, + 0x756b, 0x73a1, 0x730c, 0x72f7, 0x8394, 0x8409, 0x84e0, 0x72f7, + 0x84f1, 0x7544, 0x850d, 0x72f7, 0x7f18, 0x8568, 0x72f7, 0x080c, + 0x1515, 0x2100, 0x0033, 0x00fe, 0x00ce, 0x014e, 0x013e, 0x015e, + 0x0005, 0x730a, 0x730a, 0x730a, 0x7340, 0x735e, 0x7374, 0x730a, + 0x730a, 0x730a, 0x080c, 0x1515, 0x00d6, 0x20a1, 0x020b, 0x080c, + 0x7641, 0x7810, 0x2068, 0x20a3, 0x2414, 0x20a3, 0x0018, 0x20a3, + 0x0800, 0x683c, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x6850, 0x20a2, 0x6854, 0x20a2, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0018, 0x080c, 0x7d67, 0x00de, + 0x0005, 0x00d6, 0x7818, 0x2068, 0x68a0, 0x2069, 0xb500, 0x6ad4, + 0xd2ac, 0x1110, 0xd0bc, 0x0110, 0xa085, 0x0001, 0x00de, 0x0005, + 0x00d6, 0x20a1, 0x020b, 0x080c, 0x7641, 0x20a3, 0x0500, 0x20a3, + 0x0000, 0x7810, 0xa0e8, 0x000f, 0x6808, 0x20a2, 0x680c, 0x20a2, + 0x6810, 0x20a2, 0x6814, 0x20a2, 0x6818, 0x20a2, 0x681c, 0x20a2, + 0x60c3, 0x0010, 0x080c, 0x7d67, 0x00de, 0x0005, 0x0156, 0x0146, + 0x20a1, 0x020b, 0x080c, 0x7641, 0x20a3, 0x7800, 0x20a3, 0x0000, + 0x7808, 0x8007, 0x20a2, 0x20a3, 0x0000, 0x60c3, 0x0008, 0x080c, + 0x7d67, 0x014e, 0x015e, 0x0005, 0x0156, 0x0146, 0x20a1, 0x020b, + 0x080c, 0x76dd, 0x20a3, 0x0200, 0x20a3, 0x0000, 0x20a3, 0xdf10, + 0x20a3, 0x0034, 0x2099, 0xb505, 0x20a9, 0x0004, 0x53a6, 0x2099, + 0xb501, 0x20a9, 0x0004, 0x53a6, 0x2099, 0xb7c6, 0x20a9, 0x001a, + 0x3304, 0x8007, 0x20a2, 0x9398, 0x1f04, 0x7390, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x60c3, 0x004c, 0x080c, 0x7d67, 0x014e, 0x015e, + 0x0005, 0x2001, 0xb515, 0x2004, 0x609a, 0x080c, 0x7d67, 0x0005, + 0x20a1, 0x020b, 0x080c, 0x7641, 0x20a3, 0x5200, 0x20a3, 0x0000, + 0x00d6, 0x2069, 0xb552, 0x6804, 0xd084, 0x0150, 0x6828, 0x20a3, + 0x0000, 0x0016, 0x080c, 0x2831, 0x21a2, 0x001e, 0x00de, 0x0028, + 0x00de, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a9, 0x0004, 0x2099, + 0xb505, 0x53a6, 0x20a9, 0x0004, 0x2099, 0xb501, 0x53a6, 0x2001, + 0xb535, 0x2004, 0xd0ac, 0x1138, 0x7818, 0xa080, 0x0028, 0x2004, + 0xa082, 0x007f, 0x0238, 0x2001, 0xb51c, 0x20a6, 0x2001, 0xb51d, + 0x20a6, 0x0040, 0x20a3, 0x0000, 0x2001, 0xb515, 0x2004, 0xa084, + 0x00ff, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x001c, + 0x080c, 0x7d67, 0x0005, 0x20a1, 0x020b, 0x080c, 0x7641, 0x20a3, + 0x0500, 0x20a3, 0x0000, 0x2001, 0xb535, 0x2004, 0xd0ac, 0x1138, + 0x7818, 0xa080, 0x0028, 0x2004, 0xa082, 0x007f, 0x0238, 0x2001, + 0xb51c, 0x20a6, 0x2001, 0xb51d, 0x20a6, 0x0040, 0x20a3, 0x0000, + 0x2001, 0xb515, 0x2004, 0xa084, 0x00ff, 0x20a2, 0x20a9, 0x0004, + 0x2099, 0xb505, 0x53a6, 0x60c3, 0x0010, 0x080c, 0x7d67, 0x0005, + 0x20a1, 0x020b, 0x080c, 0x7641, 0x00c6, 0x7818, 0x2060, 0x2001, + 0x0000, 0x080c, 0x5313, 0x00ce, 0x7818, 0xa080, 0x0028, 0x2004, + 0xa086, 0x007e, 0x1130, 0x20a3, 0x0400, 0x620c, 0xc2b4, 0x620e, + 0x0010, 0x20a3, 0x0300, 0x20a3, 0x0000, 0x7818, 0xa080, 0x0028, + 0x2004, 0xa086, 0x007e, 0x1904, 0x74af, 0x2001, 0xb535, 0x2004, + 0xd0a4, 0x01c8, 0x2099, 0xb78e, 0x33a6, 0x9398, 0x20a3, 0x0000, + 0x9398, 0x3304, 0xa084, 0x2000, 0x20a2, 0x9398, 0x33a6, 0x9398, + 0x20a3, 0x0000, 0x9398, 0x2001, 0x2710, 0x20a2, 0x9398, 0x33a6, + 0x9398, 0x33a6, 0x00d0, 0x2099, 0xb78e, 0x33a6, 0x9398, 0x33a6, + 0x9398, 0x3304, 0x080c, 0x5acf, 0x1118, 0xa084, 0x37ff, 0x0010, + 0xa084, 0x3fff, 0x20a2, 0x9398, 0x33a6, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a9, 0x0004, 0x2099, + 0xb505, 0x53a6, 0x20a9, 0x0004, 0x2099, 0xb501, 0x53a6, 0x20a9, + 0x0008, 0x20a3, 0x0000, 0x1f04, 0x7489, 0x20a9, 0x0008, 0x20a3, + 0x0000, 0x1f04, 0x748f, 0x2099, 0xb796, 0x3304, 0xc0dd, 0x20a2, + 0x2001, 0xb572, 0x2004, 0xd0e4, 0x0158, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x9398, 0x9398, 0x9398, 0x33a6, 0x20a9, 0x0004, 0x0010, + 0x20a9, 0x0007, 0x20a3, 0x0000, 0x1f04, 0x74aa, 0x0468, 0x2001, + 0xb535, 0x2004, 0xd0a4, 0x0140, 0x2001, 0xb78f, 0x2004, 0x60e3, + 0x0000, 0x080c, 0x2872, 0x60e2, 0x2099, 0xb78e, 0x20a9, 0x0008, + 0x53a6, 0x20a9, 0x0004, 0x2099, 0xb505, 0x53a6, 0x20a9, 0x0004, + 0x2099, 0xb501, 0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x1f04, + 0x74cd, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x1f04, 0x74d3, 0x2099, + 0xb796, 0x20a9, 0x0008, 0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000, + 0x1f04, 0x74de, 0x20a9, 0x000a, 0x20a3, 0x0000, 0x1f04, 0x74e4, + 0x60c3, 0x0074, 0x080c, 0x7d67, 0x0005, 0x20a1, 0x020b, 0x080c, + 0x7641, 0x20a3, 0x2010, 0x20a3, 0x0014, 0x20a3, 0x0800, 0x20a3, + 0x2000, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x00f6, + 0x2079, 0xb552, 0x7904, 0x00fe, 0xd1ac, 0x1110, 0xa085, 0x0020, + 0xd1a4, 0x0110, 0xa085, 0x0010, 0xa085, 0x0002, 0x00d6, 0x0804, + 0x75cc, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, + 0x080c, 0x7d67, 0x0005, 0x20a1, 0x020b, 0x080c, 0x7641, 0x20a3, + 0x5000, 0x0804, 0x743b, 0x20a1, 0x020b, 0x080c, 0x7641, 0x20a3, + 0x2110, 0x20a3, 0x0014, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, + 0x0014, 0x080c, 0x7d67, 0x0005, 0x20a1, 0x020b, 0x080c, 0x76d5, + 0x0020, 0x20a1, 0x020b, 0x080c, 0x76dd, 0x20a3, 0x0200, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0004, 0x080c, + 0x7d67, 0x0005, 0x20a1, 0x020b, 0x080c, 0x76dd, 0x20a3, 0x0100, + 0x20a3, 0x0000, 0x20a3, 0x0003, 0x20a3, 0x2a00, 0x60c3, 0x0008, + 0x080c, 0x7d67, 0x0005, 0x20a1, 0x020b, 0x080c, 0x76dd, 0x20a3, + 0x0200, 0x0804, 0x743b, 0x20a1, 0x020b, 0x080c, 0x76dd, 0x20a3, + 0x0100, 0x20a3, 0x0000, 0x7828, 0xa005, 0x0110, 0x20a2, 0x0010, + 0x20a3, 0x0003, 0x7810, 0x20a2, 0x60c3, 0x0008, 0x080c, 0x7d67, + 0x0005, 0x00d6, 0x20a1, 0x020b, 0x080c, 0x76dd, 0x20a3, 0x0210, + 0x20a3, 0x0014, 0x20a3, 0x0800, 0x7818, 0x2068, 0x6894, 0xa086, + 0x0014, 0x1198, 0x699c, 0xa184, 0x0030, 0x0190, 0x6998, 0xa184, + 0xc000, 0x1140, 0xd1ec, 0x0118, 0x20a3, 0x2100, 0x0058, 0x20a3, + 0x0100, 0x0040, 0x20a3, 0x0400, 0x0028, 0x20a3, 0x0700, 0x0010, + 0x700f, 0x0800, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a2, + 0x00f6, 0x2079, 0xb552, 0x7904, 0x00fe, 0xd1ac, 0x1110, 0xa085, + 0x0020, 0xd1a4, 0x0110, 0xa085, 0x0010, 0x2009, 0xb574, 0x210c, + 0xd184, 0x1110, 0xa085, 0x0002, 0x0026, 0x2009, 0xb572, 0x210c, + 0xd1e4, 0x0130, 0xc0c5, 0xa094, 0x0030, 0xa296, 0x0010, 0x0140, + 0xd1ec, 0x0130, 0xa094, 0x0030, 0xa296, 0x0010, 0x0108, 0xc0bd, + 0x002e, 0x20a2, 0x20a2, 0x20a2, 0x60c3, 0x0014, 0x080c, 0x7d67, + 0x00de, 0x0005, 0x20a1, 0x020b, 0x080c, 0x76dd, 0x20a3, 0x0210, + 0x20a3, 0x0014, 0x20a3, 0x0000, 0x20a3, 0x0100, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, + 0x080c, 0x7d67, 0x0005, 0x20a1, 0x020b, 0x080c, 0x76dd, 0x20a3, + 0x0200, 0x0804, 0x73ae, 0x20a1, 0x020b, 0x080c, 0x76dd, 0x20a3, + 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0003, 0x20a3, 0x2a00, 0x60c3, + 0x0008, 0x080c, 0x7d67, 0x0005, 0x20e1, 0x9080, 0x20e1, 0x4000, + 0x20a1, 0x020b, 0x080c, 0x76dd, 0x20a3, 0x0100, 0x20a3, 0x0000, + 0x20a3, 0x000b, 0x20a3, 0x0000, 0x60c3, 0x0008, 0x080c, 0x7d67, + 0x0005, 0x0026, 0x0036, 0x0046, 0x2019, 0x3200, 0x2021, 0x0800, + 0x0038, 0x0026, 0x0036, 0x0046, 0x2019, 0x2200, 0x2021, 0x0100, + 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2014, + 0xa286, 0x007e, 0x11a0, 0xa385, 0x00ff, 0x20a2, 0x20a3, 0xfffe, + 0x20a3, 0x0000, 0x2011, 0xb515, 0x2214, 0x2001, 0xb79e, 0x2004, + 0xa005, 0x0118, 0x2011, 0xb51d, 0x2214, 0x22a2, 0x04d0, 0xa286, + 0x007f, 0x1138, 0x00d6, 0xa385, 0x00ff, 0x20a2, 0x20a3, 0xfffd, + 0x00c8, 0x2001, 0xb535, 0x2004, 0xd0ac, 0x1110, 0xd2bc, 0x01c8, + 0xa286, 0x0080, 0x00d6, 0x1130, 0xa385, 0x00ff, 0x20a2, 0x20a3, + 0xfffc, 0x0040, 0xa2e8, 0xb635, 0x2d6c, 0x6810, 0xa305, 0x20a2, + 0x6814, 0x20a2, 0x2069, 0xb51c, 0x2da6, 0x8d68, 0x2da6, 0x00de, + 0x0080, 0x00d6, 0xa2e8, 0xb635, 0x2d6c, 0x6810, 0xa305, 0x20a2, + 0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011, 0xb515, 0x2214, + 0x22a2, 0xa485, 0x0029, 0x20a2, 0x004e, 0x003e, 0x20a3, 0x0000, + 0x080c, 0x7d56, 0x22a2, 0x20a3, 0x0000, 0x2fa2, 0x20a3, 0xffff, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x002e, 0x0005, 0x0026, 0x20e1, + 0x9080, 0x20e1, 0x4000, 0x20a3, 0x02ff, 0x2011, 0xfffc, 0x22a2, + 0x00d6, 0x2069, 0xb51c, 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x20a3, + 0x2029, 0x20a3, 0x0000, 0x08e0, 0x20a3, 0x0100, 0x20a3, 0x0000, + 0x20a3, 0xfc02, 0x20a3, 0x0000, 0x0005, 0x0026, 0x0036, 0x0046, + 0x2019, 0x3300, 0x2021, 0x0800, 0x0038, 0x0026, 0x0036, 0x0046, + 0x2019, 0x2300, 0x2021, 0x0100, 0x20e1, 0x9080, 0x20e1, 0x4000, + 0x7818, 0xa080, 0x0028, 0x2004, 0x2011, 0xb535, 0x2214, 0xd2ac, + 0x1118, 0xa092, 0x007e, 0x02d8, 0x00d6, 0xa0e8, 0xb635, 0x2d6c, + 0x6810, 0xa305, 0x20a2, 0x6814, 0x20a2, 0x6810, 0xa005, 0x1140, + 0x6814, 0xa005, 0x1128, 0x20a3, 0x00ff, 0x20a3, 0xfffe, 0x0028, + 0x2069, 0xb51c, 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0080, 0x00d6, + 0xa0e8, 0xb635, 0x2d6c, 0x6810, 0xa305, 0x20a2, 0x6814, 0x20a2, + 0x00de, 0x20a3, 0x0000, 0x2011, 0xb515, 0x2214, 0x22a2, 0xa485, + 0x0098, 0x20a2, 0x20a3, 0x0000, 0x004e, 0x003e, 0x080c, 0x7d56, + 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x002e, 0x0005, 0x080c, 0x7d56, 0x22a2, 0x20a3, + 0x0000, 0x7a08, 0x22a2, 0x7810, 0x20a2, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x002e, 0x0005, 0x00c6, 0x00f6, 0x6004, 0xa08a, 0x0085, + 0x0a0c, 0x1515, 0xa08a, 0x008c, 0x1a0c, 0x1515, 0x6118, 0x2178, + 0x79a0, 0x2011, 0xb535, 0x2214, 0xd2ac, 0x1110, 0xd1bc, 0x0150, + 0x7900, 0xd1f4, 0x0120, 0x7914, 0xa18c, 0x00ff, 0x0040, 0x2009, + 0x0000, 0x0028, 0xa1f8, 0x2dc4, 0x2f0d, 0xa18c, 0x00ff, 0x2c78, + 0x2061, 0x0100, 0x619a, 0xa082, 0x0085, 0x001b, 0x00fe, 0x00ce, + 0x0005, 0x777a, 0x7784, 0x779f, 0x7778, 0x7778, 0x7778, 0x777a, + 0x080c, 0x1515, 0x0146, 0x20a1, 0x020b, 0x04a1, 0x60c3, 0x0000, + 0x080c, 0x7d67, 0x014e, 0x0005, 0x0146, 0x20a1, 0x020b, 0x080c, + 0x77eb, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808, 0x20a2, 0x7810, + 0x20a2, 0x20a3, 0x0000, 0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x60c3, 0x000c, 0x080c, 0x7d67, 0x014e, 0x0005, 0x0146, + 0x20a1, 0x020b, 0x080c, 0x7825, 0x20a3, 0x0003, 0x20a3, 0x0300, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0004, 0x080c, 0x7d67, + 0x014e, 0x0005, 0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, + 0xa080, 0x0028, 0x2004, 0x2011, 0xb535, 0x2214, 0xd2ac, 0x1118, + 0xa092, 0x007e, 0x0288, 0x00d6, 0xa0e8, 0xb635, 0x2d6c, 0x6810, + 0xa085, 0x8100, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xb51c, 0x2da6, + 0x8d68, 0x2da6, 0x00de, 0x0088, 0x00d6, 0xa0e8, 0xb635, 0x2d6c, + 0x6810, 0xa085, 0x8100, 0x20a2, 0x6814, 0x20a2, 0x00de, 0x20a3, + 0x0000, 0x2011, 0xb515, 0x2214, 0x22a2, 0x20a3, 0x0009, 0x20a3, + 0x0000, 0x0804, 0x76a8, 0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, + 0x7818, 0xa080, 0x0028, 0x2004, 0x2011, 0xb535, 0x2214, 0xd2ac, + 0x1118, 0xa092, 0x007e, 0x0288, 0x00d6, 0xa0e8, 0xb635, 0x2d6c, + 0x6810, 0xa085, 0x8400, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xb51c, + 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0088, 0x00d6, 0xa0e8, 0xb635, + 0x2d6c, 0x6810, 0xa085, 0x8400, 0x20a2, 0x6814, 0x20a2, 0x00de, + 0x20a3, 0x0000, 0x2011, 0xb515, 0x2214, 0x22a2, 0x2001, 0x0099, + 0x20a2, 0x20a3, 0x0000, 0x0804, 0x7734, 0x0026, 0x20e1, 0x9080, + 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0x2011, 0xb535, + 0x2214, 0xd2ac, 0x1118, 0xa092, 0x007e, 0x0288, 0x00d6, 0xa0e8, + 0xb635, 0x2d6c, 0x6810, 0xa085, 0x8500, 0x20a2, 0x6814, 0x20a2, + 0x2069, 0xb51c, 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0088, 0x00d6, + 0xa0e8, 0xb635, 0x2d6c, 0x6810, 0xa085, 0x8500, 0x20a2, 0x6814, + 0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011, 0xb515, 0x2214, 0x22a2, + 0x2001, 0x0099, 0x20a2, 0x20a3, 0x0000, 0x0804, 0x7734, 0x00c6, + 0x00f6, 0x2c78, 0x7804, 0xa08a, 0x0040, 0x0a0c, 0x1515, 0xa08a, + 0x0053, 0x1a0c, 0x1515, 0x7918, 0x2160, 0x61a0, 0x2011, 0xb535, + 0x2214, 0xd2ac, 0x1110, 0xd1bc, 0x0150, 0x6100, 0xd1f4, 0x0120, + 0x6114, 0xa18c, 0x00ff, 0x0040, 0x2009, 0x0000, 0x0028, 0xa1e0, + 0x2dc4, 0x2c0d, 0xa18c, 0x00ff, 0x2061, 0x0100, 0x619a, 0xa082, + 0x0040, 0x001b, 0x00fe, 0x00ce, 0x0005, 0x78a2, 0x79ae, 0x794b, + 0x7b60, 0x78a0, 0x78a0, 0x78a0, 0x78a0, 0x78a0, 0x78a0, 0x78a0, + 0x80d7, 0x80e7, 0x80f7, 0x8107, 0x78a0, 0x851e, 0x78a0, 0x80c6, + 0x080c, 0x1515, 0x00d6, 0x0156, 0x0146, 0x780b, 0xffff, 0x20a1, + 0x020b, 0x080c, 0x7902, 0x7910, 0x2168, 0x6948, 0x7952, 0x21a2, + 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x694c, 0xa184, 0x000f, 0x1118, + 0x2001, 0x0005, 0x0040, 0xd184, 0x0118, 0x2001, 0x0004, 0x0018, + 0xa084, 0x0006, 0x8004, 0x0016, 0x2008, 0x7858, 0xa084, 0x00ff, + 0x8007, 0xa105, 0x001e, 0x20a2, 0xd1ac, 0x0118, 0x20a3, 0x0002, + 0x0048, 0xd1b4, 0x0118, 0x20a3, 0x0001, 0x0020, 0x20a3, 0x0000, + 0x2230, 0x0010, 0x6a80, 0x6e7c, 0x20a9, 0x0008, 0x0136, 0xad88, + 0x0017, 0x2198, 0x20a1, 0x021b, 0x53a6, 0x013e, 0x20a1, 0x020b, + 0x22a2, 0x26a2, 0x60c3, 0x0020, 0x20e1, 0x9080, 0x6014, 0xa084, + 0x0004, 0xa085, 0x0009, 0x6016, 0x2001, 0xb7fc, 0x2003, 0x07d0, + 0x2001, 0xb7fb, 0x2003, 0x0009, 0x080c, 0x17e2, 0x014e, 0x015e, + 0x00de, 0x0005, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7a18, 0xa280, + 0x0023, 0x2014, 0x8210, 0xa294, 0x00ff, 0x2202, 0x8217, 0x7818, + 0xa080, 0x0028, 0x2004, 0x2019, 0xb535, 0x231c, 0xd3ac, 0x1110, + 0xd0bc, 0x0188, 0x00d6, 0xa0e8, 0xb635, 0x2d6c, 0x6810, 0xa085, + 0x0600, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xb51c, 0x2da6, 0x8d68, + 0x2da6, 0x00de, 0x0088, 0x00d6, 0xa0e8, 0xb635, 0x2d6c, 0x6810, + 0xa085, 0x0600, 0x20a2, 0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000, + 0x2009, 0xb515, 0x210c, 0x21a2, 0x20a3, 0x0829, 0x20a3, 0x0000, + 0x22a2, 0x20a3, 0x0000, 0x2fa2, 0x20a3, 0xffff, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x0005, 0x00d6, 0x0156, 0x0136, 0x0146, 0x20a1, + 0x020b, 0x00c1, 0x7810, 0x2068, 0x6860, 0x20a2, 0x685c, 0x20a2, + 0x6880, 0x20a2, 0x687c, 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, + 0x20a2, 0x60c3, 0x000c, 0x080c, 0x7d67, 0x014e, 0x013e, 0x015e, + 0x00de, 0x0005, 0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, + 0xa080, 0x0028, 0x2004, 0x2011, 0xb535, 0x2214, 0xd2ac, 0x1110, + 0xd0bc, 0x0188, 0x00d6, 0xa0e8, 0xb635, 0x2d6c, 0x6810, 0xa085, + 0x0500, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xb51c, 0x2da6, 0x8d68, + 0x2da6, 0x00de, 0x0088, 0x00d6, 0xa0e8, 0xb635, 0x2d6c, 0x6810, + 0xa085, 0x0500, 0x20a2, 0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000, + 0x2011, 0xb515, 0x2214, 0x22a2, 0x20a3, 0x0889, 0x20a3, 0x0000, + 0x080c, 0x7d56, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x002e, 0x0005, 0x00d6, 0x0156, + 0x0136, 0x0146, 0x7810, 0xa0ec, 0xf000, 0x0168, 0xa06d, 0x080c, + 0x5301, 0x0148, 0x684c, 0xa084, 0x2020, 0xa086, 0x2020, 0x1118, + 0x7820, 0xc0cd, 0x7822, 0x20a1, 0x020b, 0x080c, 0x7b16, 0xa016, + 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x7810, 0xa084, 0xf000, + 0x1130, 0x7810, 0xa084, 0x0700, 0x8007, 0x0043, 0x0010, 0xa006, + 0x002b, 0x014e, 0x013e, 0x015e, 0x00de, 0x0005, 0x79e8, 0x7a7d, + 0x7a8d, 0x7abf, 0x7ad2, 0x7aed, 0x7af6, 0x79e6, 0x080c, 0x1515, + 0x0016, 0x0036, 0x694c, 0xa18c, 0x0003, 0x0118, 0xa186, 0x0003, + 0x1170, 0x6b78, 0x7820, 0xd0cc, 0x0108, 0xc3e5, 0x23a2, 0x6868, + 0x20a2, 0x6864, 0x20a2, 0x003e, 0x001e, 0x0804, 0x7ac9, 0xa186, + 0x0001, 0x190c, 0x1515, 0x6b78, 0x7820, 0xd0cc, 0x0108, 0xc3e5, + 0x23a2, 0x6868, 0x20a2, 0x6864, 0x20a2, 0x22a2, 0x6874, 0x20a2, + 0x22a2, 0x687c, 0x20a2, 0x2009, 0x0018, 0xa384, 0x0300, 0x0904, + 0x7a77, 0xd3c4, 0x0110, 0x687c, 0xa108, 0xd3cc, 0x0110, 0x6874, + 0xa108, 0x0156, 0x20a9, 0x000d, 0xad80, 0x0020, 0x201c, 0x831f, + 0x23a2, 0x8000, 0x1f04, 0x7a26, 0x015e, 0x22a2, 0x22a2, 0x22a2, + 0xa184, 0x0003, 0x0904, 0x7a77, 0x20a1, 0x020b, 0x20e1, 0x9080, + 0x20e1, 0x4000, 0x0006, 0x7818, 0xa080, 0x0028, 0x2004, 0x2011, + 0xb535, 0x2214, 0xd2ac, 0x1110, 0xd0bc, 0x0188, 0x00d6, 0xa0e8, + 0xb635, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, 0x6814, 0x20a2, + 0x2069, 0xb51c, 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0088, 0x00d6, + 0xa0e8, 0xb635, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, 0x6814, + 0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011, 0xb515, 0x2214, 0x22a2, + 0x000e, 0x7b20, 0xd3cc, 0x0118, 0x20a3, 0x0889, 0x0010, 0x20a3, + 0x0898, 0x20a2, 0x080c, 0x7d56, 0x22a2, 0x20a3, 0x0000, 0x61c2, + 0x003e, 0x001e, 0x080c, 0x7d67, 0x0005, 0x2011, 0x0008, 0x2001, + 0xb50d, 0x2004, 0xd0f4, 0x0110, 0x2011, 0x0028, 0x7820, 0xd0cc, + 0x0108, 0xc2e5, 0x22a2, 0xa016, 0x04d0, 0x2011, 0x0302, 0x0016, + 0x0036, 0x7828, 0x792c, 0xa11d, 0x0108, 0xc2dd, 0x7b20, 0xd3cc, + 0x0108, 0xc2e5, 0x22a2, 0x20a2, 0x21a2, 0x003e, 0x001e, 0xa016, + 0x22a2, 0x20a3, 0x0012, 0x22a2, 0x20a3, 0x0008, 0x22a2, 0x22a2, + 0x22a2, 0x22a2, 0x20a3, 0x7000, 0x20a3, 0x0500, 0x22a2, 0x20a3, + 0x000a, 0x22a2, 0x22a2, 0x20a3, 0x2500, 0x22a2, 0x22a2, 0x22a2, + 0x22a2, 0x22a2, 0x60c3, 0x0032, 0x080c, 0x7d67, 0x0005, 0x2011, + 0x0028, 0x7820, 0xd0cc, 0x0108, 0xc2e5, 0x22a2, 0xa016, 0x22a2, + 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0018, 0x080c, + 0x7d67, 0x0005, 0x2011, 0x0100, 0x7820, 0xd0cc, 0x0108, 0xc2e5, + 0x22a2, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x20a3, + 0x0008, 0x22a2, 0x7854, 0xa084, 0x00ff, 0x20a2, 0x22a2, 0x22a2, + 0x60c3, 0x0020, 0x080c, 0x7d67, 0x0005, 0x2011, 0x0008, 0x7820, + 0xd0cc, 0x0108, 0xc2e5, 0x22a2, 0xa016, 0x0888, 0x0036, 0x7b10, + 0xa384, 0xff00, 0x7812, 0xa384, 0x00ff, 0x8001, 0x1138, 0x7820, + 0xd0cc, 0x0108, 0xc2e5, 0x22a2, 0x003e, 0x0808, 0x0046, 0x2021, + 0x0800, 0x0006, 0x7820, 0xd0cc, 0x000e, 0x0108, 0xc4e5, 0x24a2, + 0x004e, 0x22a2, 0x20a2, 0x003e, 0x0804, 0x7ac9, 0x0026, 0x20e1, + 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0x2011, + 0xb535, 0x2214, 0xd2ac, 0x1110, 0xd0bc, 0x0188, 0x00d6, 0xa0e8, + 0xb635, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, 0x6814, 0x20a2, + 0x2069, 0xb51c, 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0088, 0x00d6, + 0xa0e8, 0xb635, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, 0x6814, + 0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011, 0xb515, 0x2214, 0x22a2, + 0x7820, 0xd0cc, 0x0118, 0x20a3, 0x0889, 0x0010, 0x20a3, 0x0898, + 0x20a3, 0x0000, 0x080c, 0x7d56, 0x22a2, 0x20a3, 0x0000, 0x7a08, + 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x002e, 0x0005, + 0x00d6, 0x0156, 0x0136, 0x0146, 0x0016, 0x0036, 0x7810, 0xa084, + 0x0700, 0x8007, 0x003b, 0x003e, 0x001e, 0x014e, 0x013e, 0x015e, + 0x00de, 0x0005, 0x7b7a, 0x7b7a, 0x7b7c, 0x7b7a, 0x7b7a, 0x7b7a, + 0x7b9e, 0x7b7a, 0x080c, 0x1515, 0x7910, 0xa18c, 0xf8ff, 0xa18d, + 0x0600, 0x7912, 0x20a1, 0x020b, 0x2009, 0x0003, 0x00f9, 0x00d6, + 0x2069, 0xb552, 0x6804, 0xd0bc, 0x0130, 0x682c, 0xa084, 0x00ff, + 0x8007, 0x20a2, 0x0010, 0x20a3, 0x3f00, 0x00de, 0x22a2, 0x22a2, + 0x22a2, 0x60c3, 0x0001, 0x080c, 0x7d67, 0x0005, 0x20a1, 0x020b, + 0x2009, 0x0003, 0x0019, 0x20a3, 0x7f00, 0x0c80, 0x0026, 0x20e1, + 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0x2011, + 0xb535, 0x2214, 0xd2ac, 0x1110, 0xd0bc, 0x0188, 0x00d6, 0xa0e8, + 0xb635, 0x2d6c, 0x6810, 0xa085, 0x0100, 0x20a2, 0x6814, 0x20a2, + 0x2069, 0xb51c, 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0088, 0x00d6, + 0xa0e8, 0xb635, 0x2d6c, 0x6810, 0xa085, 0x0100, 0x20a2, 0x6814, + 0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011, 0xb515, 0x2214, 0x22a2, + 0x20a3, 0x0888, 0xa18d, 0x0008, 0x21a2, 0x080c, 0x7d56, 0x22a2, + 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x002e, 0x0005, 0x00e6, 0x00d6, 0x00c6, 0x0056, 0x0046, + 0x0036, 0x2061, 0x0100, 0x2071, 0xb500, 0x7154, 0x7818, 0x2068, + 0x68a0, 0x2028, 0x76d4, 0xd6ac, 0x1130, 0xd0bc, 0x1120, 0x6910, + 0x6a14, 0x7454, 0x0020, 0x6910, 0x6a14, 0x7370, 0x7474, 0x781c, + 0xa0be, 0x0006, 0x0904, 0x7ca1, 0xa0be, 0x000a, 0x15e8, 0xa185, + 0x0200, 0x6062, 0x6266, 0x636a, 0x646e, 0x6073, 0x2029, 0x6077, + 0x0000, 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e, 0x8007, 0x607a, + 0x607f, 0x0000, 0x2f00, 0x6082, 0x7808, 0x6086, 0x7810, 0x2070, + 0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6, 0x7008, 0x60ca, + 0x686c, 0x60ce, 0x60af, 0x95d5, 0x60d7, 0x0000, 0x609f, 0x0000, + 0x080c, 0x85b9, 0x2009, 0x07d0, 0x60c4, 0xa084, 0xfff0, 0xa005, + 0x0110, 0x2009, 0x1b58, 0x080c, 0x6a15, 0x003e, 0x004e, 0x005e, + 0x00ce, 0x00de, 0x00ee, 0x0005, 0x70d4, 0xd0ac, 0x1110, 0xd5bc, + 0x0138, 0xa185, 0x0100, 0x6062, 0x6266, 0x636a, 0x646e, 0x0038, + 0xa185, 0x0100, 0x6062, 0x6266, 0x606b, 0x0000, 0x646e, 0x6073, + 0x0809, 0x6077, 0x0008, 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e, + 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6082, 0x7808, 0x6086, + 0x7810, 0x2070, 0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6, + 0x7008, 0x60ca, 0x686c, 0x60ce, 0x60af, 0x95d5, 0x60d7, 0x0000, + 0xa582, 0x0080, 0x0248, 0x6a00, 0xd2f4, 0x0120, 0x6a14, 0xa294, + 0x00ff, 0x0010, 0x2011, 0x0000, 0x629e, 0x080c, 0x85b9, 0x2009, + 0x07d0, 0x60c4, 0xa084, 0xfff0, 0xa005, 0x0110, 0x2009, 0x1b58, + 0x080c, 0x6a15, 0x003e, 0x004e, 0x005e, 0x00ce, 0x00de, 0x00ee, + 0x0005, 0x7810, 0x2070, 0x704c, 0xa084, 0x0003, 0xa086, 0x0002, + 0x0904, 0x7cf7, 0x2001, 0xb535, 0x2004, 0xd0ac, 0x1110, 0xd5bc, + 0x0138, 0xa185, 0x0100, 0x6062, 0x6266, 0x636a, 0x646e, 0x0038, + 0xa185, 0x0100, 0x6062, 0x6266, 0x606b, 0x0000, 0x646e, 0x6073, + 0x0880, 0x6077, 0x0008, 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e, + 0x8007, 0x607a, 0x7834, 0x607e, 0x2f00, 0x6086, 0x7808, 0x6082, + 0x7060, 0x608a, 0x705c, 0x608e, 0x7080, 0x60c6, 0x707c, 0x60ca, + 0x707c, 0x792c, 0xa108, 0x792e, 0x7080, 0x7928, 0xa109, 0x792a, + 0x686c, 0x60ce, 0x60af, 0x95d5, 0x60d7, 0x0000, 0xa582, 0x0080, + 0x0248, 0x6a00, 0xd2f4, 0x0120, 0x6a14, 0xa294, 0x00ff, 0x0010, + 0x2011, 0x0000, 0x629e, 0x080c, 0x85b6, 0x0804, 0x7c8f, 0x2001, + 0xb535, 0x2004, 0xd0ac, 0x1110, 0xd5bc, 0x0138, 0xa185, 0x0700, + 0x6062, 0x6266, 0x636a, 0x646e, 0x0038, 0xa185, 0x0700, 0x6062, + 0x6266, 0x606b, 0x0000, 0x646e, 0x080c, 0x5301, 0x0180, 0x00d6, + 0x7810, 0xa06d, 0x684c, 0x00de, 0xa084, 0x2020, 0xa086, 0x2020, + 0x1130, 0x7820, 0xc0cd, 0x7822, 0x6073, 0x0889, 0x0010, 0x6073, + 0x0898, 0x6077, 0x0000, 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e, + 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6086, 0x7808, 0x6082, + 0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6, 0x7008, 0x60ca, + 0x686c, 0x60ce, 0x60af, 0x95d5, 0x60d7, 0x0000, 0xa582, 0x0080, + 0x0248, 0x6a00, 0xd2f4, 0x0120, 0x6a14, 0xa294, 0x00ff, 0x0010, + 0x2011, 0x0000, 0x629e, 0x7820, 0xd0cc, 0x0120, 0x080c, 0x85b9, + 0x0804, 0x7c8f, 0x080c, 0x85b6, 0x0804, 0x7c8f, 0x7a18, 0xa280, + 0x0023, 0x2014, 0x8210, 0xa294, 0x00ff, 0x2202, 0x8217, 0x0005, + 0x00d6, 0x2069, 0xb7e0, 0x6843, 0x0001, 0x00de, 0x0005, 0x20e1, + 0x9080, 0x60a3, 0x0056, 0x60a7, 0x9575, 0x0019, 0x080c, 0x6a07, + 0x0005, 0x0006, 0x6014, 0xa084, 0x0004, 0xa085, 0x0009, 0x6016, + 0x000e, 0x0005, 0x0016, 0x00c6, 0x0006, 0x2061, 0x0100, 0x61a4, + 0x60a7, 0x95f5, 0x6014, 0xa084, 0x0004, 0xa085, 0x0008, 0x6016, + 0x000e, 0xe000, 0xe000, 0xe000, 0xe000, 0x61a6, 0x00ce, 0x001e, + 0x0005, 0x00c6, 0x00d6, 0x0016, 0x0026, 0x2061, 0x0100, 0x2069, + 0x0140, 0x080c, 0x5acf, 0x1198, 0x2001, 0xb7fc, 0x2004, 0xa005, + 0x15b8, 0x0066, 0x2031, 0x0001, 0x080c, 0x5b51, 0x006e, 0x1118, + 0x080c, 0x6a07, 0x0468, 0x00c6, 0x2061, 0xb7e0, 0x00d8, 0x6904, + 0xa194, 0x4000, 0x0550, 0x0831, 0x6803, 0x1000, 0x6803, 0x0000, + 0x00c6, 0x2061, 0xb7e0, 0x6128, 0xa192, 0x00c8, 0x1258, 0x8108, + 0x612a, 0x6124, 0x00ce, 0x81ff, 0x0198, 0x080c, 0x6a07, 0x080c, + 0x7d71, 0x0070, 0x6124, 0xa1e5, 0x0000, 0x0140, 0x080c, 0xb444, + 0x080c, 0x6a10, 0x2009, 0x0014, 0x080c, 0x864c, 0x00ce, 0x0000, + 0x002e, 0x001e, 0x00de, 0x00ce, 0x0005, 0x2001, 0xb7fc, 0x2004, + 0xa005, 0x1db0, 0x00c6, 0x2061, 0xb7e0, 0x6128, 0xa192, 0x0003, + 0x1e08, 0x8108, 0x612a, 0x00ce, 0x080c, 0x6a07, 0x080c, 0x4b1f, + 0x0c38, 0x00c6, 0x00d6, 0x00e6, 0x0016, 0x0026, 0x080c, 0x6a1d, + 0x2071, 0xb7e0, 0x713c, 0x81ff, 0x0590, 0x2061, 0x0100, 0x2069, + 0x0140, 0x080c, 0x5acf, 0x11a8, 0x0036, 0x2019, 0x0002, 0x080c, + 0x7fe4, 0x003e, 0x713c, 0x2160, 0x080c, 0xb444, 0x2009, 0x004a, + 0x080c, 0x864c, 0x0066, 0x2031, 0x0001, 0x080c, 0x5b51, 0x006e, + 0x00b0, 0x6904, 0xa194, 0x4000, 0x01c0, 0x6803, 0x1000, 0x6803, + 0x0000, 0x0036, 0x2019, 0x0001, 0x080c, 0x7fe4, 0x003e, 0x713c, + 0x2160, 0x080c, 0xb444, 0x2009, 0x004a, 0x080c, 0x864c, 0x002e, + 0x001e, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x0c58, 0x0026, 0x00e6, + 0x2071, 0xb7e0, 0x7048, 0xd084, 0x01c0, 0x713c, 0x81ff, 0x01a8, + 0x2071, 0x0100, 0xa188, 0x0007, 0x2114, 0xa28e, 0x0006, 0x1138, + 0x7014, 0xa084, 0x0184, 0xa085, 0x0012, 0x7016, 0x0030, 0x7014, + 0xa084, 0x0184, 0xa085, 0x0016, 0x7016, 0x00ee, 0x002e, 0x0005, + 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0056, 0x0046, 0x0006, 0x0126, + 0x2091, 0x8000, 0x6018, 0x2068, 0x6ca0, 0x2071, 0xb7e0, 0x7018, + 0x2068, 0x8dff, 0x0188, 0x68a0, 0xa406, 0x0118, 0x6854, 0x2068, + 0x0cc0, 0x6010, 0x2060, 0x643c, 0x6540, 0x6648, 0x2d60, 0x080c, + 0x511a, 0x0110, 0xa085, 0x0001, 0x012e, 0x000e, 0x004e, 0x005e, + 0x006e, 0x00ce, 0x00de, 0x00ee, 0x0005, 0x20a1, 0x020b, 0x080c, + 0x7641, 0x20a3, 0x1200, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x781c, + 0xa086, 0x0004, 0x1110, 0x6098, 0x0018, 0x2001, 0xb515, 0x2004, + 0x20a2, 0x7834, 0x20a2, 0x7838, 0x20a2, 0x20a9, 0x0010, 0xa006, + 0x20a2, 0x1f04, 0x7ea0, 0x20a2, 0x20a2, 0x60c3, 0x002c, 0x080c, + 0x7d67, 0x0005, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x7641, + 0x20a3, 0x0f00, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808, 0x20a2, + 0x60c3, 0x0008, 0x080c, 0x7d67, 0x014e, 0x015e, 0x0005, 0x0156, + 0x0146, 0x20a1, 0x020b, 0x080c, 0x76dd, 0x20a3, 0x0200, 0x20a3, + 0x0000, 0x20a9, 0x0006, 0x2011, 0xb540, 0x2019, 0xb541, 0x23a6, + 0x22a6, 0xa398, 0x0002, 0xa290, 0x0002, 0x1f04, 0x7ecf, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x60c3, 0x001c, 0x080c, 0x7d67, 0x014e, + 0x015e, 0x0005, 0x0156, 0x0146, 0x0016, 0x0026, 0x20a1, 0x020b, + 0x080c, 0x76b6, 0x080c, 0x76cc, 0x7810, 0xa080, 0x0000, 0x2004, + 0xa080, 0x0015, 0x2098, 0x7808, 0xa088, 0x0002, 0x21a8, 0x53a6, + 0xa080, 0x0004, 0x8003, 0x60c2, 0x080c, 0x7d67, 0x002e, 0x001e, + 0x014e, 0x015e, 0x0005, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, + 0x7641, 0x20a3, 0x6200, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808, + 0x20a2, 0x60c3, 0x0008, 0x080c, 0x7d67, 0x014e, 0x015e, 0x0005, + 0x0156, 0x0146, 0x0016, 0x0026, 0x20a1, 0x020b, 0x080c, 0x7641, + 0x7810, 0xa080, 0x0000, 0x2004, 0xa080, 0x0017, 0x2098, 0x7808, + 0xa088, 0x0002, 0x21a8, 0x53a6, 0x8003, 0x60c2, 0x080c, 0x7d67, + 0x002e, 0x001e, 0x014e, 0x015e, 0x0005, 0x00e6, 0x00c6, 0x0006, + 0x0126, 0x2091, 0x8000, 0x2071, 0xb7e0, 0x700c, 0x2060, 0x8cff, + 0x0178, 0x080c, 0x9e58, 0x1110, 0x080c, 0x8c19, 0x600c, 0x0006, + 0x080c, 0xa01f, 0x080c, 0x861d, 0x080c, 0x811e, 0x00ce, 0x0c78, + 0x700f, 0x0000, 0x700b, 0x0000, 0x012e, 0x000e, 0x00ce, 0x00ee, + 0x0005, 0x0126, 0x0156, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0026, + 0x0016, 0x0006, 0x2091, 0x8000, 0x2069, 0x0100, 0x2079, 0x0140, + 0x2071, 0xb7e0, 0x7024, 0x2060, 0x8cff, 0x05a0, 0x080c, 0x7d7a, + 0x68c3, 0x0000, 0x080c, 0x6a10, 0x2009, 0x0013, 0x080c, 0x864c, + 0x20a9, 0x01f4, 0x6824, 0xd094, 0x0158, 0x6827, 0x0004, 0x7804, + 0xa084, 0x4000, 0x01a0, 0x7803, 0x1000, 0x7803, 0x0000, 0x0078, + 0xd084, 0x0118, 0x6827, 0x0001, 0x0010, 0x1f04, 0x7f7a, 0x7804, + 0xa084, 0x1000, 0x0120, 0x7803, 0x0100, 0x7803, 0x0000, 0x6824, + 0x000e, 0x001e, 0x002e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x015e, + 0x012e, 0x0005, 0x2001, 0xb500, 0x2004, 0xa096, 0x0001, 0x0590, + 0xa096, 0x0004, 0x0578, 0x080c, 0x6a10, 0x6814, 0xa084, 0x0001, + 0x0110, 0x68a7, 0x95f5, 0x6817, 0x0008, 0x68c3, 0x0000, 0x2011, + 0x4adc, 0x080c, 0x699c, 0x20a9, 0x01f4, 0x6824, 0xd094, 0x0158, + 0x6827, 0x0004, 0x7804, 0xa084, 0x4000, 0x01a0, 0x7803, 0x1000, + 0x7803, 0x0000, 0x0078, 0xd084, 0x0118, 0x6827, 0x0001, 0x0010, + 0x1f04, 0x7fbd, 0x7804, 0xa084, 0x1000, 0x0120, 0x7803, 0x0100, + 0x7803, 0x0000, 0x000e, 0x001e, 0x002e, 0x00ce, 0x00de, 0x00ee, + 0x00fe, 0x015e, 0x012e, 0x0005, 0x0126, 0x0156, 0x00f6, 0x00e6, + 0x00d6, 0x00c6, 0x0026, 0x0016, 0x0006, 0x2091, 0x8000, 0x2069, + 0x0100, 0x2079, 0x0140, 0x2071, 0xb7e0, 0x703c, 0x2060, 0x8cff, + 0x0904, 0x806b, 0xa386, 0x0002, 0x1128, 0x6814, 0xa084, 0x0002, + 0x0904, 0x806b, 0x68af, 0x95f5, 0x6817, 0x0010, 0x2009, 0x00fa, + 0x8109, 0x1df0, 0x68c7, 0x0000, 0x68cb, 0x0008, 0x080c, 0x6a1d, + 0x080c, 0x220c, 0x0046, 0x2009, 0x017f, 0x200b, 0x00a5, 0x2021, + 0x0169, 0x2404, 0xa084, 0x000f, 0xa086, 0x0004, 0x1500, 0x68af, + 0x95f5, 0x68c7, 0x0000, 0x68cb, 0x0008, 0x00e6, 0x00f6, 0x2079, + 0x0020, 0x2071, 0xb84a, 0x6814, 0xa084, 0x0184, 0xa085, 0x0012, + 0x6816, 0x7803, 0x0008, 0x7003, 0x0000, 0x00fe, 0x00ee, 0xa386, + 0x0002, 0x1128, 0x7884, 0xa005, 0x1110, 0x7887, 0x0001, 0x2001, + 0xb7b1, 0x2004, 0x200a, 0x004e, 0xa39d, 0x0000, 0x1120, 0x2009, + 0x0049, 0x080c, 0x864c, 0x20a9, 0x03e8, 0x6824, 0xd094, 0x0158, + 0x6827, 0x0004, 0x7804, 0xa084, 0x4000, 0x01a0, 0x7803, 0x1000, + 0x7803, 0x0000, 0x0078, 0xd08c, 0x0118, 0x6827, 0x0002, 0x0010, + 0x1f04, 0x804d, 0x7804, 0xa084, 0x1000, 0x0120, 0x7803, 0x0100, + 0x7803, 0x0000, 0x6824, 0x000e, 0x001e, 0x002e, 0x00ce, 0x00de, + 0x00ee, 0x00fe, 0x015e, 0x012e, 0x0005, 0x00d6, 0x0126, 0x2091, + 0x8000, 0x2069, 0xb7e0, 0x6a06, 0x012e, 0x00de, 0x0005, 0x00d6, + 0x0126, 0x2091, 0x8000, 0x2069, 0xb7e0, 0x6a32, 0x012e, 0x00de, + 0x0005, 0x00f6, 0x00e6, 0x00c6, 0x0066, 0x0006, 0x0126, 0x2071, + 0xb7e0, 0x7614, 0x2660, 0x2678, 0x2091, 0x8000, 0x8cff, 0x0538, + 0x601c, 0xa206, 0x1500, 0x7014, 0xac36, 0x1110, 0x660c, 0x7616, + 0x7010, 0xac36, 0x1140, 0x2c00, 0xaf36, 0x0118, 0x2f00, 0x7012, + 0x0010, 0x7013, 0x0000, 0x660c, 0x0066, 0x2c00, 0xaf06, 0x0110, + 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0x080c, 0x9e1d, 0x080c, + 0x811e, 0x00ce, 0x08d8, 0x2c78, 0x600c, 0x2060, 0x08b8, 0x012e, + 0x000e, 0x006e, 0x00ce, 0x00ee, 0x00fe, 0x0005, 0x0156, 0x0146, + 0x20a1, 0x020b, 0x080c, 0x7902, 0x7810, 0x20a2, 0xa006, 0x20a2, + 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x1000, 0x0804, 0x8116, 0x0156, + 0x0146, 0x20a1, 0x020b, 0x080c, 0x7902, 0x7810, 0x20a2, 0xa006, + 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x4000, 0x0478, 0x0156, + 0x0146, 0x20a1, 0x020b, 0x080c, 0x7902, 0x7810, 0x20a2, 0xa006, + 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x2000, 0x00f8, 0x0156, + 0x0146, 0x20a1, 0x020b, 0x080c, 0x7902, 0x7810, 0x20a2, 0xa006, + 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x0400, 0x0078, 0x0156, + 0x0146, 0x20a1, 0x020b, 0x080c, 0x7902, 0x7810, 0x20a2, 0xa006, + 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x0200, 0x0089, 0x60c3, + 0x0020, 0x080c, 0x7d67, 0x014e, 0x015e, 0x0005, 0x00e6, 0x2071, + 0xb7e0, 0x7020, 0xa005, 0x0110, 0x8001, 0x7022, 0x00ee, 0x0005, + 0x20a9, 0x0008, 0x20a2, 0x1f04, 0x812a, 0x20a2, 0x20a2, 0x0005, + 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0076, 0x0066, 0x0006, 0x0126, + 0x2091, 0x8000, 0x2071, 0xb7e0, 0x7614, 0x2660, 0x2678, 0x2039, + 0x0001, 0x87ff, 0x0904, 0x81c6, 0x8cff, 0x0904, 0x81c6, 0x601c, + 0xa086, 0x0006, 0x1904, 0x81c1, 0x88ff, 0x0138, 0x2800, 0xac06, + 0x1904, 0x81c1, 0x2039, 0x0000, 0x0050, 0x6018, 0xa206, 0x1904, + 0x81c1, 0x85ff, 0x0120, 0x6050, 0xa106, 0x1904, 0x81c1, 0x7024, + 0xac06, 0x1598, 0x2069, 0x0100, 0x68c0, 0xa005, 0x1160, 0x6824, + 0xd084, 0x0148, 0x6827, 0x0001, 0x080c, 0x6a10, 0x080c, 0x824d, + 0x7027, 0x0000, 0x0410, 0x080c, 0x6a10, 0x6820, 0xd0b4, 0x0110, + 0x68a7, 0x95f5, 0x6817, 0x0008, 0x68c3, 0x0000, 0x080c, 0x824d, + 0x7027, 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, + 0x0120, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, + 0xd084, 0x0110, 0x6827, 0x0001, 0x003e, 0x7014, 0xac36, 0x1110, + 0x660c, 0x7616, 0x7010, 0xac36, 0x1140, 0x2c00, 0xaf36, 0x0118, + 0x2f00, 0x7012, 0x0010, 0x7013, 0x0000, 0x660c, 0x0066, 0x2c00, + 0xaf06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x89ff, 0x1158, 0x600f, + 0x0000, 0x6010, 0x2068, 0x080c, 0x9c5a, 0x0110, 0x080c, 0xb099, + 0x080c, 0x9e1d, 0x080c, 0x811e, 0x88ff, 0x1190, 0x00ce, 0x0804, + 0x8141, 0x2c78, 0x600c, 0x2060, 0x0804, 0x8141, 0xa006, 0x012e, + 0x000e, 0x006e, 0x007e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x0005, + 0x6017, 0x0000, 0x00ce, 0xa8c5, 0x0001, 0x0c88, 0x00f6, 0x00e6, + 0x00d6, 0x00c6, 0x0066, 0x0026, 0x0006, 0x0126, 0x2091, 0x8000, + 0x2071, 0xb7e0, 0x7638, 0x2660, 0x2678, 0x8cff, 0x0904, 0x823d, + 0x601c, 0xa086, 0x0006, 0x1904, 0x8238, 0x87ff, 0x0128, 0x2700, + 0xac06, 0x1904, 0x8238, 0x0048, 0x6018, 0xa206, 0x1904, 0x8238, + 0x85ff, 0x0118, 0x6050, 0xa106, 0x15d8, 0x703c, 0xac06, 0x1180, + 0x0036, 0x2019, 0x0001, 0x080c, 0x7fe4, 0x7033, 0x0000, 0x703f, + 0x0000, 0x7043, 0x0000, 0x7047, 0x0000, 0x704b, 0x0000, 0x003e, + 0x7038, 0xac36, 0x1110, 0x660c, 0x763a, 0x7034, 0xac36, 0x1140, + 0x2c00, 0xaf36, 0x0118, 0x2f00, 0x7036, 0x0010, 0x7037, 0x0000, + 0x660c, 0x0066, 0x2c00, 0xaf06, 0x0110, 0x7e0e, 0x0008, 0x2678, + 0x600f, 0x0000, 0x6010, 0x2068, 0x080c, 0x9c5a, 0x0110, 0x080c, + 0xb099, 0x080c, 0x9e1d, 0x87ff, 0x1190, 0x00ce, 0x0804, 0x81e5, + 0x2c78, 0x600c, 0x2060, 0x0804, 0x81e5, 0xa006, 0x012e, 0x000e, + 0x002e, 0x006e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x0005, 0x6017, + 0x0000, 0x00ce, 0xa7bd, 0x0001, 0x0c88, 0x00e6, 0x2071, 0xb7e0, + 0x2001, 0xb500, 0x2004, 0xa086, 0x0002, 0x1118, 0x7007, 0x0005, + 0x0010, 0x7007, 0x0000, 0x00ee, 0x0005, 0x00f6, 0x00e6, 0x00c6, + 0x0066, 0x0026, 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, 0xb7e0, + 0x2c10, 0x7638, 0x2660, 0x2678, 0x8cff, 0x0518, 0x2200, 0xac06, + 0x11e0, 0x7038, 0xac36, 0x1110, 0x660c, 0x763a, 0x7034, 0xac36, + 0x1140, 0x2c00, 0xaf36, 0x0118, 0x2f00, 0x7036, 0x0010, 0x7037, + 0x0000, 0x660c, 0x2c00, 0xaf06, 0x0110, 0x7e0e, 0x0008, 0x2678, + 0x600f, 0x0000, 0xa085, 0x0001, 0x0020, 0x2c78, 0x600c, 0x2060, + 0x08d8, 0x012e, 0x000e, 0x002e, 0x006e, 0x00ce, 0x00ee, 0x00fe, + 0x0005, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0006, 0x0126, + 0x2091, 0x8000, 0x2071, 0xb7e0, 0x760c, 0x2660, 0x2678, 0x8cff, + 0x0904, 0x8323, 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, 0x1904, + 0x831e, 0x7024, 0xac06, 0x1508, 0x2069, 0x0100, 0x68c0, 0xa005, + 0x0904, 0x82fa, 0x080c, 0x7d7a, 0x68c3, 0x0000, 0x080c, 0x824d, + 0x7027, 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, + 0x0120, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, + 0xd084, 0x0110, 0x6827, 0x0001, 0x003e, 0x700c, 0xac36, 0x1110, + 0x660c, 0x760e, 0x7008, 0xac36, 0x1140, 0x2c00, 0xaf36, 0x0118, + 0x2f00, 0x700a, 0x0010, 0x700b, 0x0000, 0x660c, 0x0066, 0x2c00, + 0xaf06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0x080c, + 0x9e47, 0x1158, 0x080c, 0x2cc2, 0x080c, 0x9e58, 0x11f0, 0x080c, + 0x8c19, 0x00d8, 0x080c, 0x824d, 0x08c0, 0x080c, 0x9e58, 0x1118, + 0x080c, 0x8c19, 0x0090, 0x6010, 0x2068, 0x080c, 0x9c5a, 0x0168, + 0x601c, 0xa086, 0x0003, 0x11f8, 0x6837, 0x0103, 0x6b4a, 0x6847, + 0x0000, 0x080c, 0x5408, 0x080c, 0x9e11, 0x080c, 0xa01f, 0x080c, + 0x9e1d, 0x080c, 0x811e, 0x00ce, 0x0804, 0x82a7, 0x2c78, 0x600c, + 0x2060, 0x0804, 0x82a7, 0x012e, 0x000e, 0x006e, 0x00ce, 0x00de, + 0x00ee, 0x00fe, 0x0005, 0x601c, 0xa086, 0x0006, 0x1d30, 0x080c, + 0xb099, 0x0c18, 0x0036, 0x0156, 0x0136, 0x0146, 0x3908, 0xa006, + 0xa190, 0x0020, 0x221c, 0xa39e, 0x2ab7, 0x1118, 0x8210, 0x8000, + 0x0cc8, 0xa005, 0x0138, 0x20a9, 0x0020, 0x2198, 0xa110, 0x22a0, + 0x22c8, 0x53a3, 0x014e, 0x013e, 0x015e, 0x003e, 0x0005, 0x00d6, + 0x20a1, 0x020b, 0x080c, 0x76dd, 0x20a3, 0x0200, 0x20a3, 0x0014, + 0x60c3, 0x0014, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x2099, 0xb7b9, + 0x20a9, 0x0004, 0x53a6, 0x20a3, 0x0004, 0x20a3, 0x7878, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x080c, 0x7d67, 0x00de, 0x0005, 0x20a1, + 0x020b, 0x080c, 0x76dd, 0x20a3, 0x0214, 0x20a3, 0x0018, 0x20a3, + 0x0800, 0x7810, 0xa084, 0xff00, 0x20a2, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7810, 0xa084, 0x00ff, + 0x20a2, 0x7828, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, + 0x0018, 0x080c, 0x7d67, 0x0005, 0x00d6, 0x0016, 0x2f68, 0x2009, + 0x0035, 0x080c, 0xa10a, 0x1904, 0x8402, 0x20a1, 0x020b, 0x080c, + 0x7641, 0x20a3, 0x1300, 0x20a3, 0x0000, 0x7828, 0x2068, 0x681c, + 0xa086, 0x0003, 0x0580, 0x7818, 0xa080, 0x0028, 0x2014, 0x2001, + 0xb535, 0x2004, 0xd0ac, 0x11d0, 0xa286, 0x007e, 0x1128, 0x20a3, + 0x00ff, 0x20a3, 0xfffe, 0x04b8, 0xa286, 0x007f, 0x1128, 0x20a3, + 0x00ff, 0x20a3, 0xfffd, 0x0478, 0xd2bc, 0x0180, 0xa286, 0x0080, + 0x1128, 0x20a3, 0x00ff, 0x20a3, 0xfffc, 0x0428, 0xa2e8, 0xb635, + 0x2d6c, 0x6810, 0x20a2, 0x6814, 0x20a2, 0x00e8, 0x20a3, 0x0000, + 0x6098, 0x20a2, 0x00c0, 0x2001, 0xb535, 0x2004, 0xd0ac, 0x1138, + 0x7818, 0xa080, 0x0028, 0x2004, 0xa082, 0x007e, 0x0240, 0x00d6, + 0x2069, 0xb51c, 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0020, 0x20a3, + 0x0000, 0x6034, 0x20a2, 0x7834, 0x20a2, 0x7838, 0x20a2, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x60c3, 0x000c, 0x080c, 0x7d67, 0x001e, + 0x00de, 0x0005, 0x7817, 0x0001, 0x7803, 0x0006, 0x001e, 0x00de, + 0x0005, 0x00d6, 0x0026, 0x7928, 0x2168, 0x691c, 0xa186, 0x0006, + 0x01c0, 0xa186, 0x0003, 0x0904, 0x8478, 0xa186, 0x0005, 0x0904, + 0x8461, 0xa186, 0x0004, 0x05b8, 0xa186, 0x0008, 0x0904, 0x8469, + 0x7807, 0x0037, 0x7813, 0x1700, 0x080c, 0x84e0, 0x002e, 0x00de, + 0x0005, 0x080c, 0x849c, 0x2009, 0x4000, 0x6800, 0x0002, 0x8442, + 0x844d, 0x8444, 0x844d, 0x8449, 0x8442, 0x8442, 0x844d, 0x844d, + 0x844d, 0x844d, 0x8442, 0x8442, 0x8442, 0x8442, 0x8442, 0x844d, + 0x8442, 0x844d, 0x080c, 0x1515, 0x6820, 0xd0e4, 0x0110, 0xd0cc, + 0x0110, 0xa00e, 0x0010, 0x2009, 0x2000, 0x6828, 0x20a2, 0x682c, + 0x20a2, 0x0804, 0x8492, 0x080c, 0x849c, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x2009, 0x4000, 0x6a00, 0xa286, 0x0002, 0x1108, 0xa00e, + 0x0488, 0x04d1, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x2009, 0x4000, + 0x0448, 0x0491, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x2009, 0x4000, + 0xa286, 0x0005, 0x0118, 0xa286, 0x0002, 0x1108, 0xa00e, 0x00d0, + 0x0419, 0x6810, 0x2068, 0x697c, 0x6810, 0xa112, 0x6980, 0x6814, + 0xa103, 0x20a2, 0x22a2, 0x7928, 0xa180, 0x0000, 0x2004, 0xa08e, + 0x0002, 0x0130, 0xa08e, 0x0004, 0x0118, 0x2009, 0x4000, 0x0010, + 0x2009, 0x0000, 0x21a2, 0x20a3, 0x0000, 0x60c3, 0x0018, 0x080c, + 0x7d67, 0x002e, 0x00de, 0x0005, 0x0036, 0x0046, 0x0056, 0x0066, + 0x20a1, 0x020b, 0x080c, 0x76dd, 0xa006, 0x20a3, 0x0200, 0x20a2, + 0x7934, 0x21a2, 0x7938, 0x21a2, 0x7818, 0xa080, 0x0028, 0x2004, + 0x2011, 0xb535, 0x2214, 0xd2ac, 0x1118, 0xa092, 0x007e, 0x0268, + 0x00d6, 0x2069, 0xb51c, 0x2d2c, 0x8d68, 0x2d34, 0xa0e8, 0xb635, + 0x2d6c, 0x6b10, 0x6c14, 0x00de, 0x0030, 0x2019, 0x0000, 0x6498, + 0x2029, 0x0000, 0x6634, 0x7828, 0xa080, 0x0007, 0x2004, 0xa086, + 0x0003, 0x1128, 0x25a2, 0x26a2, 0x23a2, 0x24a2, 0x0020, 0x23a2, + 0x24a2, 0x25a2, 0x26a2, 0x006e, 0x005e, 0x004e, 0x003e, 0x0005, + 0x20a1, 0x020b, 0x080c, 0x76dd, 0x20a3, 0x0100, 0x20a3, 0x0000, + 0x20a3, 0x0009, 0x7810, 0x20a2, 0x60c3, 0x0008, 0x080c, 0x7d67, + 0x0005, 0x20a1, 0x020b, 0x080c, 0x7639, 0x20a3, 0x1400, 0x20a3, + 0x0000, 0x7834, 0x20a2, 0x7838, 0x20a2, 0x7828, 0x20a2, 0x782c, + 0x20a2, 0x7830, 0xa084, 0x00ff, 0x8007, 0x20a2, 0x20a3, 0x0000, + 0x60c3, 0x0010, 0x080c, 0x7d67, 0x0005, 0x20a1, 0x020b, 0x080c, + 0x76d5, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x7828, 0x20a2, 0x7810, + 0x20a2, 0x60c3, 0x0008, 0x080c, 0x7d67, 0x0005, 0x0146, 0x20a1, + 0x020b, 0x0031, 0x60c3, 0x0000, 0x080c, 0x7d67, 0x014e, 0x0005, + 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, + 0x2011, 0xb535, 0x2214, 0xd2ac, 0x1110, 0xd0bc, 0x0188, 0x00d6, + 0xa0e8, 0xb635, 0x2d6c, 0x6810, 0xa085, 0x0300, 0x20a2, 0x6814, + 0x20a2, 0x2069, 0xb51c, 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0078, + 0x00d6, 0xa0e8, 0xb635, 0x2d6c, 0x6810, 0xa085, 0x0300, 0x20a2, + 0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000, 0x6234, 0x22a2, 0x20a3, + 0x0819, 0x20a3, 0x0000, 0x080c, 0x7d56, 0x22a2, 0x20a3, 0x0000, + 0x2fa2, 0x7a08, 0x22a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x0005, + 0x20a1, 0x020b, 0x0079, 0x7910, 0x21a2, 0x20a3, 0x0000, 0x60c3, + 0x0000, 0x20e1, 0x9080, 0x60a7, 0x9575, 0x080c, 0x7d71, 0x080c, + 0x6a07, 0x0005, 0x0156, 0x0136, 0x0036, 0x00d6, 0x00e6, 0x20e1, + 0x9080, 0x20e1, 0x4000, 0x7854, 0x2068, 0xadf0, 0x000f, 0x7210, + 0xa296, 0x00c0, 0xa294, 0xfffd, 0x7212, 0x7214, 0xa294, 0x0300, + 0x7216, 0x7100, 0xa194, 0x00ff, 0x7308, 0xa384, 0x00ff, 0xa08d, + 0xc200, 0x7102, 0xa384, 0xff00, 0xa215, 0x720a, 0x7004, 0x720c, + 0x700e, 0x7206, 0x20a9, 0x000a, 0x2e98, 0x53a6, 0x60a3, 0x0035, + 0x6a38, 0xa294, 0x7000, 0xa286, 0x3000, 0x0110, 0x60a3, 0x0037, + 0x00ee, 0x00de, 0x003e, 0x013e, 0x015e, 0x0005, 0x2009, 0x0092, + 0x0010, 0x2009, 0x0096, 0x60ab, 0x0036, 0x6116, 0x0005, 0x2061, + 0xbd00, 0x2a70, 0x7068, 0x704a, 0x704f, 0xbd00, 0x0005, 0x00e6, + 0x0126, 0x2071, 0xb500, 0x2091, 0x8000, 0x7548, 0xa582, 0x0010, + 0x0608, 0x704c, 0x2060, 0x6000, 0xa086, 0x0000, 0x0148, 0xace0, + 0x0018, 0x705c, 0xac02, 0x1208, 0x0cb0, 0x2061, 0xbd00, 0x0c98, + 0x6003, 0x0008, 0x8529, 0x754a, 0xaca8, 0x0018, 0x705c, 0xa502, + 0x1230, 0x754e, 0xa085, 0x0001, 0x012e, 0x00ee, 0x0005, 0x704f, + 0xbd00, 0x0cc0, 0xa006, 0x0cc0, 0x00e6, 0x2071, 0xb500, 0x7548, + 0xa582, 0x0010, 0x0600, 0x704c, 0x2060, 0x6000, 0xa086, 0x0000, + 0x0148, 0xace0, 0x0018, 0x705c, 0xac02, 0x1208, 0x0cb0, 0x2061, + 0xbd00, 0x0c98, 0x6003, 0x0008, 0x8529, 0x754a, 0xaca8, 0x0018, + 0x705c, 0xa502, 0x1228, 0x754e, 0xa085, 0x0001, 0x00ee, 0x0005, + 0x704f, 0xbd00, 0x0cc8, 0xa006, 0x0cc8, 0xac82, 0xbd00, 0x0a0c, + 0x1515, 0x2001, 0xb517, 0x2004, 0xac02, 0x1a0c, 0x1515, 0xa006, + 0x6006, 0x600a, 0x600e, 0x6012, 0x6016, 0x601a, 0x601f, 0x0000, + 0x6003, 0x0000, 0x6052, 0x6056, 0x6022, 0x6026, 0x602a, 0x602e, + 0x6032, 0x6036, 0x603a, 0x603e, 0x2061, 0xb500, 0x6048, 0x8000, + 0x604a, 0xa086, 0x0001, 0x0108, 0x0005, 0x0126, 0x2091, 0x8000, + 0x080c, 0x7173, 0x012e, 0x0cc0, 0x601c, 0xa084, 0x000f, 0x0002, + 0x865b, 0x866a, 0x8685, 0x86a0, 0xa152, 0xa16d, 0xa188, 0x865b, + 0x866a, 0x865b, 0x86bb, 0xa186, 0x0013, 0x1128, 0x080c, 0x7090, + 0x080c, 0x7173, 0x0005, 0xa18e, 0x0047, 0x1118, 0xa016, 0x080c, + 0x185e, 0x0005, 0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c, 0x1515, + 0x0013, 0x006e, 0x0005, 0x8683, 0x8a9b, 0x8c53, 0x8683, 0x8cc8, + 0x8779, 0x8683, 0x8683, 0x8a2d, 0x90ef, 0x8683, 0x8683, 0x8683, + 0x8683, 0x8683, 0x8683, 0x080c, 0x1515, 0x0066, 0x6000, 0xa0b2, + 0x0010, 0x1a0c, 0x1515, 0x0013, 0x006e, 0x0005, 0x869e, 0x9722, + 0x869e, 0x869e, 0x869e, 0x869e, 0x869e, 0x869e, 0x96cd, 0x988e, + 0x869e, 0x974f, 0x97c6, 0x974f, 0x97c6, 0x869e, 0x080c, 0x1515, + 0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c, 0x1515, 0x0013, 0x006e, + 0x0005, 0x86b9, 0x9130, 0x91fa, 0x9335, 0x9491, 0x86b9, 0x86b9, + 0x86b9, 0x910a, 0x967d, 0x9680, 0x86b9, 0x86b9, 0x86b9, 0x86b9, + 0x96aa, 0x080c, 0x1515, 0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c, + 0x1515, 0x0013, 0x006e, 0x0005, 0x86d4, 0x86d4, 0x86d4, 0x8702, + 0x874f, 0x86d4, 0x86d4, 0x86d4, 0x86d6, 0x86d4, 0x86d4, 0x86d4, + 0x86d4, 0x86d4, 0x86d4, 0x86d4, 0x080c, 0x1515, 0xa186, 0x0003, + 0x190c, 0x1515, 0x00d6, 0x6003, 0x0003, 0x6106, 0x6010, 0x2068, + 0x684f, 0x0040, 0x687c, 0x680a, 0x6880, 0x680e, 0x6813, 0x0000, + 0x6817, 0x0000, 0x6854, 0xa092, 0x199a, 0x0210, 0x2001, 0x1999, + 0x8003, 0x8013, 0x8213, 0xa210, 0x6216, 0x00de, 0x2c10, 0x080c, + 0x1fa9, 0x080c, 0x6cf0, 0x0126, 0x2091, 0x8000, 0x080c, 0x7230, + 0x012e, 0x0005, 0xa182, 0x0047, 0x0002, 0x870e, 0x870e, 0x8710, + 0x8729, 0x870e, 0x870e, 0x870e, 0x870e, 0x873b, 0x080c, 0x1515, + 0x00d6, 0x0016, 0x080c, 0x7126, 0x080c, 0x7230, 0x6003, 0x0004, + 0x6110, 0x2168, 0x684f, 0x0020, 0x685c, 0x685a, 0x6874, 0x687e, + 0x6878, 0x6882, 0x6897, 0x0000, 0x689b, 0x0000, 0x001e, 0x00de, + 0x0005, 0x080c, 0x7126, 0x00d6, 0x6110, 0x2168, 0x080c, 0x9c5a, + 0x0120, 0x684b, 0x0006, 0x080c, 0x5408, 0x00de, 0x080c, 0x861d, + 0x080c, 0x7230, 0x0005, 0x080c, 0x7126, 0x080c, 0x2c9c, 0x00d6, + 0x6110, 0x2168, 0x080c, 0x9c5a, 0x0120, 0x684b, 0x0029, 0x080c, + 0x5408, 0x00de, 0x080c, 0x861d, 0x080c, 0x7230, 0x0005, 0xa182, + 0x0047, 0x0002, 0x875d, 0x876c, 0x875b, 0x875b, 0x875b, 0x875b, + 0x875b, 0x875b, 0x875b, 0x080c, 0x1515, 0x00d6, 0x6010, 0x2068, + 0x684c, 0xc0f4, 0x684e, 0x00de, 0x20e1, 0x0005, 0x3d18, 0x3e20, + 0x2c10, 0x080c, 0x185e, 0x0005, 0x00d6, 0x6110, 0x2168, 0x684b, + 0x0000, 0x6853, 0x0000, 0x080c, 0x5408, 0x00de, 0x080c, 0x861d, + 0x0005, 0xa1b6, 0x0015, 0x1118, 0x080c, 0x861d, 0x0030, 0xa1b6, + 0x0016, 0x190c, 0x1515, 0x080c, 0x861d, 0x0005, 0x20a9, 0x000e, + 0x2e98, 0x6010, 0x20a0, 0x53a3, 0x20a9, 0x0006, 0x3310, 0x3420, + 0x9398, 0x94a0, 0x3318, 0x3428, 0x222e, 0x2326, 0xa290, 0x0002, + 0xa5a8, 0x0002, 0xa398, 0x0002, 0xa4a0, 0x0002, 0x1f04, 0x8794, + 0x00e6, 0x080c, 0x9c5a, 0x0130, 0x6010, 0x2070, 0x7007, 0x0000, + 0x7037, 0x0103, 0x00ee, 0x080c, 0x861d, 0x0005, 0x00d6, 0x0036, + 0x7330, 0xa386, 0x0200, 0x1130, 0x6018, 0x2068, 0x6813, 0x00ff, + 0x6817, 0xfffd, 0x6010, 0xa005, 0x0130, 0x2068, 0x6807, 0x0000, + 0x6837, 0x0103, 0x6b32, 0x080c, 0x861d, 0x003e, 0x00de, 0x0005, + 0x0016, 0x20a9, 0x002a, 0xae80, 0x000c, 0x2098, 0x6010, 0xa080, + 0x0002, 0x20a0, 0x53a3, 0x20a9, 0x002a, 0x6010, 0xa080, 0x0001, + 0x2004, 0xa080, 0x0002, 0x20a0, 0x53a3, 0x00e6, 0x6010, 0x2004, + 0x2070, 0x7037, 0x0103, 0x00ee, 0x080c, 0x861d, 0x001e, 0x0005, + 0x0016, 0x2009, 0x0000, 0x7030, 0xa086, 0x0100, 0x0140, 0x7038, + 0xa084, 0x00ff, 0x800c, 0x703c, 0xa084, 0x00ff, 0x8004, 0xa080, + 0x0004, 0xa108, 0x21a8, 0xae80, 0x000c, 0x2098, 0x6010, 0xa080, + 0x0002, 0x20a0, 0x080c, 0x4b8f, 0x00e6, 0x080c, 0x9c5a, 0x0140, + 0x6010, 0x2070, 0x7007, 0x0000, 0x7034, 0x70b2, 0x7037, 0x0103, + 0x00ee, 0x080c, 0x861d, 0x001e, 0x0005, 0x00e6, 0x00d6, 0x603f, + 0x0000, 0x2c68, 0x0016, 0x2009, 0x0035, 0x080c, 0xa10a, 0x001e, + 0x1168, 0x0026, 0x6228, 0x2268, 0x002e, 0x2071, 0xbb8c, 0x6b1c, + 0xa386, 0x0003, 0x0130, 0xa386, 0x0006, 0x0128, 0x080c, 0x861d, + 0x0020, 0x0031, 0x0010, 0x080c, 0x88f6, 0x00de, 0x00ee, 0x0005, + 0x00f6, 0x6810, 0x2078, 0xa186, 0x0015, 0x0904, 0x88dd, 0xa18e, + 0x0016, 0x1904, 0x88f4, 0x700c, 0xa08c, 0xff00, 0xa186, 0x1700, + 0x0120, 0xa186, 0x0300, 0x1904, 0x88bc, 0x8fff, 0x1138, 0x6800, + 0xa086, 0x000f, 0x0904, 0x88a0, 0x0804, 0x88f2, 0x6808, 0xa086, + 0xffff, 0x1904, 0x88df, 0x784c, 0xa084, 0x0060, 0xa086, 0x0020, + 0x1150, 0x797c, 0x7810, 0xa106, 0x1904, 0x88df, 0x7980, 0x7814, + 0xa106, 0x1904, 0x88df, 0x080c, 0x9e11, 0x6858, 0x7852, 0x784c, + 0xc0dc, 0xc0f4, 0xc0d4, 0x784e, 0x0026, 0xa00e, 0x6a14, 0x2001, + 0x000a, 0x080c, 0x6b40, 0x7854, 0xa20a, 0x0208, 0x8011, 0x7a56, + 0x82ff, 0x002e, 0x1138, 0x00c6, 0x2d60, 0x080c, 0x9a09, 0x00ce, + 0x0804, 0x88f2, 0x00c6, 0x00d6, 0x2f68, 0x6838, 0xd0fc, 0x1118, + 0x080c, 0x4c64, 0x0010, 0x080c, 0x4e49, 0x00de, 0x00ce, 0x1904, + 0x88df, 0x00c6, 0x2d60, 0x080c, 0x861d, 0x00ce, 0x0804, 0x88f2, + 0x00c6, 0x080c, 0x9ed6, 0x0190, 0x6013, 0x0000, 0x6818, 0x601a, + 0x080c, 0xa027, 0x601f, 0x0003, 0x6904, 0x00c6, 0x2d60, 0x080c, + 0x861d, 0x00ce, 0x080c, 0x864c, 0x00ce, 0x04e0, 0x2001, 0xb7b8, + 0x2004, 0x683e, 0x00ce, 0x04b0, 0x7008, 0xa086, 0x000b, 0x11a0, + 0x6018, 0x200c, 0xc1bc, 0x2102, 0x00c6, 0x2d60, 0x7853, 0x0003, + 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x080c, 0x6c8d, + 0x080c, 0x7173, 0x00ce, 0x00f0, 0x700c, 0xa086, 0x2a00, 0x1138, + 0x2001, 0xb7b8, 0x2004, 0x683e, 0x00a8, 0x0481, 0x00a8, 0x8fff, + 0x090c, 0x1515, 0x00c6, 0x00d6, 0x2d60, 0x2f68, 0x6837, 0x0103, + 0x684b, 0x0003, 0x080c, 0x98fd, 0x080c, 0x9e11, 0x080c, 0x9e1d, + 0x00de, 0x00ce, 0x080c, 0x861d, 0x00fe, 0x0005, 0xa186, 0x0015, + 0x1128, 0x2001, 0xb7b8, 0x2004, 0x683e, 0x0068, 0xa18e, 0x0016, + 0x1160, 0x00c6, 0x2d00, 0x2060, 0x080c, 0xb33a, 0x080c, 0x6aef, + 0x080c, 0x861d, 0x00ce, 0x080c, 0x861d, 0x0005, 0x0026, 0x0036, + 0x0046, 0x7228, 0x7c80, 0x7b7c, 0xd2f4, 0x0130, 0x2001, 0xb7b8, + 0x2004, 0x683e, 0x0804, 0x8970, 0x00c6, 0x2d60, 0x080c, 0x991d, + 0x00ce, 0x6804, 0xa086, 0x0050, 0x1168, 0x00c6, 0x2d00, 0x2060, + 0x6003, 0x0001, 0x6007, 0x0050, 0x080c, 0x6c8d, 0x080c, 0x7173, + 0x00ce, 0x04f0, 0x6800, 0xa086, 0x000f, 0x01c8, 0x8fff, 0x090c, + 0x1515, 0x6820, 0xd0dc, 0x1198, 0x6800, 0xa086, 0x0004, 0x1198, + 0x784c, 0xd0ac, 0x0180, 0x784c, 0xc0dc, 0xc0f4, 0x784e, 0x7850, + 0xc0f4, 0xc0fc, 0x7852, 0x2001, 0x0001, 0x682e, 0x00e0, 0x2001, + 0x0007, 0x682e, 0x00c0, 0x784c, 0xd0b4, 0x1130, 0xd0ac, 0x0db8, + 0x784c, 0xd0f4, 0x1da0, 0x0c38, 0xd2ec, 0x1d88, 0x7024, 0xa306, + 0x1118, 0x7020, 0xa406, 0x0d58, 0x7020, 0x6836, 0x7024, 0x683a, + 0x2001, 0x0005, 0x682e, 0x080c, 0x9f63, 0x080c, 0x7173, 0x0010, + 0x080c, 0x861d, 0x004e, 0x003e, 0x002e, 0x0005, 0x00e6, 0x00d6, + 0x0026, 0x6034, 0x2068, 0x6a1c, 0xa286, 0x0007, 0x0904, 0x89d4, + 0xa286, 0x0002, 0x0904, 0x89d4, 0xa286, 0x0000, 0x0904, 0x89d4, + 0x6808, 0x6338, 0xa306, 0x1904, 0x89d4, 0x2071, 0xbb8c, 0xa186, + 0x0015, 0x05e0, 0xa18e, 0x0016, 0x1190, 0x6030, 0xa084, 0x00ff, + 0xa086, 0x0001, 0x1160, 0x700c, 0xa086, 0x2a00, 0x1140, 0x6034, + 0xa080, 0x0008, 0x200c, 0xc1dd, 0xc1f5, 0x2102, 0x0438, 0x00c6, + 0x6034, 0x2060, 0x6104, 0xa186, 0x004b, 0x01a0, 0xa186, 0x004c, + 0x0188, 0xa186, 0x004d, 0x0170, 0xa186, 0x004e, 0x0158, 0xa186, + 0x0052, 0x0140, 0x6010, 0x2068, 0x080c, 0x9c5a, 0x090c, 0x1515, + 0x6853, 0x0003, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, + 0x080c, 0x6c8d, 0x080c, 0x7173, 0x00ce, 0x0030, 0x6034, 0x2070, + 0x2001, 0xb7b8, 0x2004, 0x703e, 0x080c, 0x861d, 0x002e, 0x00de, + 0x00ee, 0x0005, 0x00d6, 0x20a9, 0x000e, 0x2e98, 0x6010, 0x20a0, + 0x53a3, 0xa1b6, 0x0015, 0x1558, 0x6018, 0x2068, 0x0156, 0x0036, + 0x0026, 0xae90, 0x000c, 0xa290, 0x0004, 0x20a9, 0x0004, 0xad98, + 0x000a, 0x080c, 0x90da, 0x002e, 0x003e, 0x015e, 0x11d8, 0x0156, + 0x0036, 0x0026, 0xae90, 0x000c, 0xa290, 0x0008, 0x20a9, 0x0004, + 0xad98, 0x0006, 0x080c, 0x90da, 0x002e, 0x003e, 0x015e, 0x1150, + 0x7038, 0x680a, 0x703c, 0x680e, 0x6800, 0xc08d, 0x6802, 0x00de, + 0x0804, 0x87a0, 0x080c, 0x2c9c, 0x00c6, 0x080c, 0x85c7, 0x2f00, + 0x601a, 0x6013, 0x0000, 0x601f, 0x0001, 0x6007, 0x0001, 0x6003, + 0x0001, 0x2001, 0x0007, 0x080c, 0x4efd, 0x080c, 0x4f2a, 0x080c, + 0x6cd3, 0x080c, 0x7173, 0x00ce, 0x0c10, 0x2100, 0xa1b2, 0x0080, + 0x1a0c, 0x1515, 0xa1b2, 0x0040, 0x1a04, 0x8a91, 0x0002, 0x8a85, + 0x8a79, 0x8a85, 0x8a85, 0x8a85, 0x8a85, 0x8a77, 0x8a77, 0x8a77, + 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77, + 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77, + 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a85, 0x8a77, + 0x8a85, 0x8a85, 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a85, + 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77, + 0x8a77, 0x8a85, 0x8a85, 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77, + 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a85, 0x8a77, 0x8a77, 0x080c, + 0x1515, 0x6003, 0x0001, 0x6106, 0x080c, 0x6cd3, 0x0126, 0x2091, + 0x8000, 0x080c, 0x7173, 0x012e, 0x0005, 0x6003, 0x0001, 0x6106, + 0x080c, 0x6cd3, 0x0126, 0x2091, 0x8000, 0x080c, 0x7173, 0x012e, + 0x0005, 0x2600, 0x0002, 0x8a85, 0x8a85, 0x8a99, 0x8a85, 0x8a85, + 0x8a99, 0x080c, 0x1515, 0x6004, 0xa0b2, 0x0080, 0x1a0c, 0x1515, + 0xa1b6, 0x0013, 0x0904, 0x8b4b, 0xa1b6, 0x0027, 0x1904, 0x8b11, + 0x080c, 0x7090, 0x6004, 0x080c, 0x9e47, 0x0190, 0x080c, 0x9e58, + 0x0904, 0x8b0b, 0xa08e, 0x0021, 0x0904, 0x8b0e, 0xa08e, 0x0022, + 0x0904, 0x8b0b, 0xa08e, 0x003d, 0x0904, 0x8b0e, 0x0804, 0x8b04, + 0x080c, 0x2cc2, 0x2001, 0x0007, 0x080c, 0x4efd, 0x6018, 0xa080, + 0x0028, 0x200c, 0x080c, 0x8c19, 0xa186, 0x007e, 0x1148, 0x2001, + 0xb535, 0x2014, 0xc285, 0x080c, 0x5acf, 0x1108, 0xc2ad, 0x2202, + 0x0016, 0x0026, 0x0036, 0x2110, 0x0026, 0x2019, 0x0028, 0x080c, + 0x8299, 0x002e, 0x080c, 0xb38d, 0x003e, 0x002e, 0x001e, 0x0016, + 0x0026, 0x0036, 0x2110, 0x2019, 0x0028, 0x080c, 0x6df5, 0x0076, + 0x2039, 0x0000, 0x080c, 0x6d02, 0x00c6, 0x6018, 0xa065, 0x0110, + 0x080c, 0x51aa, 0x00ce, 0x2c08, 0x080c, 0xae82, 0x007e, 0x003e, + 0x002e, 0x001e, 0x080c, 0x4f6c, 0x080c, 0xa01f, 0x080c, 0x861d, + 0x080c, 0x7173, 0x0005, 0x080c, 0x8c19, 0x0cb0, 0x080c, 0x8c47, + 0x0c98, 0xa186, 0x0014, 0x1db0, 0x080c, 0x7090, 0x080c, 0x2c9c, + 0x080c, 0x9e47, 0x1188, 0x080c, 0x2cc2, 0x6018, 0xa080, 0x0028, + 0x200c, 0x080c, 0x8c19, 0xa186, 0x007e, 0x1128, 0x2001, 0xb535, + 0x200c, 0xc185, 0x2102, 0x08c0, 0x080c, 0x9e58, 0x1118, 0x080c, + 0x8c19, 0x0890, 0x6004, 0xa08e, 0x0032, 0x1158, 0x00e6, 0x00f6, + 0x2071, 0xb582, 0x2079, 0x0000, 0x080c, 0x2fcf, 0x00fe, 0x00ee, + 0x0818, 0x6004, 0xa08e, 0x0021, 0x0d50, 0xa08e, 0x0022, 0x090c, + 0x8c19, 0x0804, 0x8b04, 0xa0b2, 0x0040, 0x1a04, 0x8c0e, 0x2008, + 0x0002, 0x8b93, 0x8b94, 0x8b97, 0x8b9a, 0x8b9d, 0x8ba0, 0x8b91, + 0x8b91, 0x8b91, 0x8b91, 0x8b91, 0x8b91, 0x8b91, 0x8b91, 0x8b91, + 0x8b91, 0x8b91, 0x8b91, 0x8b91, 0x8b91, 0x8b91, 0x8b91, 0x8b91, + 0x8b91, 0x8b91, 0x8b91, 0x8b91, 0x8b91, 0x8b91, 0x8b91, 0x8ba3, + 0x8bb2, 0x8b91, 0x8bb4, 0x8bb2, 0x8b91, 0x8b91, 0x8b91, 0x8b91, + 0x8b91, 0x8bb2, 0x8bb2, 0x8b91, 0x8b91, 0x8b91, 0x8b91, 0x8b91, + 0x8b91, 0x8b91, 0x8b91, 0x8bee, 0x8bb2, 0x8b91, 0x8bae, 0x8b91, + 0x8b91, 0x8b91, 0x8baf, 0x8b91, 0x8b91, 0x8b91, 0x8bb2, 0x8be5, + 0x8b91, 0x080c, 0x1515, 0x00f0, 0x2001, 0x000b, 0x0460, 0x2001, + 0x0003, 0x0448, 0x2001, 0x0005, 0x0430, 0x2001, 0x0001, 0x0418, + 0x2001, 0x0009, 0x0400, 0x080c, 0x7090, 0x6003, 0x0005, 0x2001, + 0xb7b8, 0x2004, 0x603e, 0x080c, 0x7173, 0x00a0, 0x0018, 0x0010, + 0x080c, 0x4efd, 0x0804, 0x8bff, 0x080c, 0x7090, 0x2001, 0xb7b6, + 0x2004, 0x6016, 0x2001, 0xb7b8, 0x2004, 0x603e, 0x6003, 0x0004, + 0x080c, 0x7173, 0x0005, 0x080c, 0x4efd, 0x080c, 0x7090, 0x6003, + 0x0002, 0x2001, 0xb7b8, 0x2004, 0x603e, 0x0036, 0x2019, 0xb55d, + 0x2304, 0xa084, 0xff00, 0x1120, 0x2001, 0xb7b6, 0x201c, 0x0040, + 0x8007, 0xa09a, 0x0004, 0x0ec0, 0x8003, 0x801b, 0x831b, 0xa318, + 0x6316, 0x003e, 0x080c, 0x7173, 0x08e8, 0x080c, 0x7090, 0x080c, + 0xa01f, 0x080c, 0x861d, 0x080c, 0x7173, 0x08a0, 0x00e6, 0x00f6, + 0x2071, 0xb582, 0x2079, 0x0000, 0x080c, 0x2fcf, 0x00fe, 0x00ee, + 0x080c, 0x7090, 0x080c, 0x861d, 0x080c, 0x7173, 0x0818, 0x080c, + 0x7090, 0x2001, 0xb7b8, 0x2004, 0x603e, 0x6003, 0x0002, 0x2001, + 0xb7b6, 0x2004, 0x6016, 0x080c, 0x7173, 0x0005, 0x2600, 0x2008, + 0x0002, 0x8c17, 0x8c17, 0x8c17, 0x8bff, 0x8bff, 0x8c17, 0x080c, + 0x1515, 0x00e6, 0x0026, 0x0016, 0x080c, 0x9c5a, 0x0508, 0x6010, + 0x2070, 0x7034, 0xa086, 0x0139, 0x1148, 0x2001, 0x0030, 0x2009, + 0x0000, 0x2011, 0x4005, 0x080c, 0xa0d6, 0x0090, 0x7038, 0xd0fc, + 0x0178, 0x7007, 0x0000, 0x0016, 0x6004, 0xa08e, 0x0021, 0x0160, + 0xa08e, 0x003d, 0x0148, 0x001e, 0x7037, 0x0103, 0x7033, 0x0100, + 0x001e, 0x002e, 0x00ee, 0x0005, 0x001e, 0x0009, 0x0cc8, 0x00e6, + 0xacf0, 0x0004, 0x2e74, 0x7000, 0x2070, 0x7037, 0x0103, 0x7023, + 0x8001, 0x00ee, 0x0005, 0x00d6, 0x6618, 0x2668, 0x6804, 0xa084, + 0x00ff, 0x00de, 0xa0b2, 0x000c, 0x1a0c, 0x1515, 0x6604, 0xa6b6, + 0x0043, 0x1120, 0x080c, 0xa092, 0x0804, 0x8cb8, 0x6604, 0xa6b6, + 0x0033, 0x1120, 0x080c, 0xa042, 0x0804, 0x8cb8, 0x6604, 0xa6b6, + 0x0028, 0x1120, 0x080c, 0x9e88, 0x0804, 0x8cb8, 0x6604, 0xa6b6, + 0x0029, 0x1118, 0x080c, 0x9e9f, 0x04d8, 0x6604, 0xa6b6, 0x001f, + 0x1118, 0x080c, 0x8786, 0x04a0, 0x6604, 0xa6b6, 0x0000, 0x1118, + 0x080c, 0x89da, 0x0468, 0x6604, 0xa6b6, 0x0022, 0x1118, 0x080c, + 0x87ae, 0x0430, 0x6604, 0xa6b6, 0x0035, 0x1118, 0x080c, 0x8815, + 0x00f8, 0x6604, 0xa6b6, 0x0039, 0x1118, 0x080c, 0x8976, 0x00c0, + 0x6604, 0xa6b6, 0x003d, 0x1118, 0x080c, 0x87c8, 0x0088, 0x6604, + 0xa6b6, 0x0044, 0x1118, 0x080c, 0x87e8, 0x0050, 0xa1b6, 0x0015, + 0x1110, 0x0053, 0x0028, 0xa1b6, 0x0016, 0x1118, 0x0804, 0x8e7c, + 0x0005, 0x080c, 0x8663, 0x0ce0, 0x8cdf, 0x8ce2, 0x8cdf, 0x8d24, + 0x8cdf, 0x8e09, 0x8e8a, 0x8cdf, 0x8cdf, 0x8e58, 0x8cdf, 0x8e6c, + 0xa1b6, 0x0048, 0x0140, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, + 0x080c, 0x185e, 0x0005, 0x00e6, 0xacf0, 0x0004, 0x2e74, 0x7000, + 0x2070, 0x7037, 0x0103, 0x00ee, 0x080c, 0x861d, 0x0005, 0xe000, + 0xe000, 0x0005, 0x00e6, 0x2071, 0xb500, 0x7084, 0xa086, 0x0074, + 0x1530, 0x080c, 0xae59, 0x11b0, 0x00d6, 0x6018, 0x2068, 0x7030, + 0xd08c, 0x0128, 0x6800, 0xd0bc, 0x0110, 0xc0c5, 0x6802, 0x00d9, + 0x00de, 0x2001, 0x0006, 0x080c, 0x4efd, 0x080c, 0x2cc2, 0x080c, + 0x861d, 0x0078, 0x2001, 0x000a, 0x080c, 0x4efd, 0x080c, 0x2cc2, + 0x6003, 0x0001, 0x6007, 0x0001, 0x080c, 0x6cd3, 0x0010, 0x080c, + 0x8df6, 0x00ee, 0x0005, 0x6800, 0xd084, 0x0168, 0x2001, 0x0000, + 0x080c, 0x4eeb, 0x2069, 0xb552, 0x6804, 0xd0a4, 0x0120, 0x2001, + 0x0006, 0x080c, 0x4f2a, 0x0005, 0x00d6, 0x2011, 0xb521, 0x2204, + 0xa086, 0x0074, 0x1904, 0x8df3, 0x6018, 0x2068, 0x6aa0, 0xa286, + 0x007e, 0x1120, 0x080c, 0x8fa2, 0x0804, 0x8d92, 0x080c, 0x8f98, + 0x6018, 0x2068, 0xa080, 0x0028, 0x2014, 0xa286, 0x0080, 0x11c0, + 0x6813, 0x00ff, 0x6817, 0xfffc, 0x6010, 0xa005, 0x0138, 0x2068, + 0x6807, 0x0000, 0x6837, 0x0103, 0x6833, 0x0200, 0x2001, 0x0006, + 0x080c, 0x4efd, 0x080c, 0x2cc2, 0x080c, 0x861d, 0x0804, 0x8df4, + 0x00e6, 0x2071, 0xb535, 0x2e04, 0xd09c, 0x0188, 0x2071, 0xbb80, + 0x7108, 0x720c, 0xa18c, 0x00ff, 0x1118, 0xa284, 0xff00, 0x0138, + 0x6018, 0x2070, 0x70a0, 0xd0bc, 0x1110, 0x7112, 0x7216, 0x00ee, + 0x6010, 0xa005, 0x0198, 0x2068, 0x6838, 0xd0f4, 0x0178, 0x6834, + 0xa084, 0x00ff, 0xa086, 0x0039, 0x1958, 0x2001, 0x0000, 0x2009, + 0x0000, 0x2011, 0x4000, 0x080c, 0xa0d6, 0x0840, 0x2001, 0x0004, + 0x080c, 0x4efd, 0x6003, 0x0001, 0x6007, 0x0003, 0x080c, 0x6cd3, + 0x0804, 0x8df4, 0x685c, 0xd0e4, 0x01d8, 0x080c, 0x9fd2, 0x080c, + 0x5acf, 0x0118, 0xd0dc, 0x1904, 0x8d4e, 0x2011, 0xb535, 0x2204, + 0xc0ad, 0x2012, 0x2001, 0xb78f, 0x2004, 0x00f6, 0x2079, 0x0100, + 0x78e3, 0x0000, 0x080c, 0x2872, 0x78e2, 0x00fe, 0x0804, 0x8d4e, + 0x080c, 0xa008, 0x2011, 0xb535, 0x2204, 0xc0a5, 0x2012, 0x0006, + 0x080c, 0xaf7b, 0x000e, 0x1904, 0x8d4e, 0xc0b5, 0x2012, 0x2001, + 0x0006, 0x080c, 0x4efd, 0x2001, 0x0000, 0x080c, 0x4eeb, 0x00c6, + 0x2009, 0x00ef, 0x00f6, 0x2079, 0x0100, 0x79ea, 0x7932, 0x7936, + 0x00fe, 0x080c, 0x2847, 0x00f6, 0x2079, 0xb500, 0x7976, 0x2100, + 0x2009, 0x0000, 0x080c, 0x281d, 0x7952, 0x00fe, 0x8108, 0x080c, + 0x4f4d, 0x2c00, 0x00ce, 0x1904, 0x8d4e, 0x601a, 0x2001, 0x0002, + 0x080c, 0x4efd, 0x601f, 0x0001, 0x6003, 0x0001, 0x6007, 0x0002, + 0x080c, 0x6cd3, 0x0008, 0x0011, 0x00de, 0x0005, 0x2001, 0x0007, + 0x080c, 0x4efd, 0x2001, 0xb500, 0x2004, 0xa086, 0x0003, 0x1120, + 0x2001, 0x0007, 0x080c, 0x4f2a, 0x080c, 0x2cc2, 0x080c, 0x861d, + 0x0005, 0x00e6, 0x0026, 0x0016, 0x2071, 0xb500, 0x7084, 0xa086, + 0x0014, 0x15f0, 0x7000, 0xa086, 0x0003, 0x1128, 0x6010, 0xa005, + 0x1110, 0x080c, 0x3f3e, 0x00d6, 0x6018, 0x2068, 0x080c, 0x504b, + 0x080c, 0x8d13, 0x00de, 0x080c, 0x9051, 0x1550, 0x00d6, 0x6018, + 0x2068, 0x6890, 0x00de, 0xa005, 0x0518, 0x2001, 0x0006, 0x080c, + 0x4efd, 0x00e6, 0x6010, 0xa075, 0x01a8, 0x7034, 0xa084, 0x00ff, + 0xa086, 0x0039, 0x1148, 0x2001, 0x0000, 0x2009, 0x0000, 0x2011, + 0x4000, 0x080c, 0xa0d6, 0x0030, 0x7007, 0x0000, 0x7037, 0x0103, + 0x7033, 0x0200, 0x00ee, 0x080c, 0x2cc2, 0x080c, 0x861d, 0x0020, + 0x080c, 0x8c19, 0x080c, 0x8df6, 0x001e, 0x002e, 0x00ee, 0x0005, + 0x2011, 0xb521, 0x2204, 0xa086, 0x0014, 0x1158, 0x2001, 0x0002, + 0x080c, 0x4efd, 0x6003, 0x0001, 0x6007, 0x0001, 0x080c, 0x6cd3, + 0x0010, 0x080c, 0x8df6, 0x0005, 0x2011, 0xb521, 0x2204, 0xa086, + 0x0004, 0x1138, 0x2001, 0x0007, 0x080c, 0x4efd, 0x080c, 0x861d, + 0x0010, 0x080c, 0x8df6, 0x0005, 0x000b, 0x0005, 0x8cdf, 0x8e95, + 0x8cdf, 0x8ec9, 0x8cdf, 0x8f54, 0x8e8a, 0x8cdf, 0x8cdf, 0x8f67, + 0x8cdf, 0x8f77, 0x6604, 0xa686, 0x0003, 0x0904, 0x8e09, 0xa6b6, + 0x001e, 0x1110, 0x080c, 0x861d, 0x0005, 0x00d6, 0x00c6, 0x080c, + 0x8f87, 0x1178, 0x2001, 0x0000, 0x080c, 0x4eeb, 0x2001, 0x0002, + 0x080c, 0x4efd, 0x6003, 0x0001, 0x6007, 0x0002, 0x080c, 0x6cd3, + 0x00e8, 0x2009, 0xbb8e, 0x2104, 0xa086, 0x0009, 0x1160, 0x6018, + 0x2068, 0x6840, 0xa084, 0x00ff, 0xa005, 0x0170, 0x8001, 0x6842, + 0x6017, 0x000a, 0x0058, 0x2009, 0xbb8f, 0x2104, 0xa084, 0xff00, + 0xa086, 0x1900, 0x1108, 0x08d0, 0x080c, 0x8df6, 0x00ce, 0x00de, + 0x0005, 0x0026, 0x2011, 0x0000, 0x080c, 0x8f95, 0x00d6, 0x2069, + 0xb79e, 0x2d04, 0xa005, 0x0168, 0x6018, 0x2068, 0x68a0, 0xa086, + 0x007e, 0x1138, 0x2069, 0xb51d, 0x2d04, 0x8000, 0x206a, 0x00de, + 0x0010, 0x00de, 0x0078, 0x2001, 0x0000, 0x080c, 0x4eeb, 0x2001, + 0x0002, 0x080c, 0x4efd, 0x6003, 0x0001, 0x6007, 0x0002, 0x080c, + 0x6cd3, 0x0480, 0x00d6, 0x6010, 0x2068, 0x080c, 0x9c5a, 0x00de, + 0x0108, 0x6a34, 0x080c, 0x8c19, 0x2009, 0xbb8e, 0x2134, 0xa6b4, + 0x00ff, 0xa686, 0x0005, 0x0500, 0xa686, 0x000b, 0x01c8, 0x2009, + 0xbb8f, 0x2104, 0xa084, 0xff00, 0x1118, 0xa686, 0x0009, 0x01a0, + 0xa086, 0x1900, 0x1168, 0xa686, 0x0009, 0x0170, 0x2001, 0x0004, + 0x080c, 0x4efd, 0x2001, 0x0028, 0x6016, 0x6007, 0x004b, 0x0010, + 0x080c, 0x8df6, 0x002e, 0x0005, 0x00d6, 0xa286, 0x0139, 0x0160, + 0x6010, 0x2068, 0x080c, 0x9c5a, 0x0148, 0x6834, 0xa086, 0x0139, + 0x0118, 0x6838, 0xd0fc, 0x0110, 0x00de, 0x0c50, 0x6018, 0x2068, + 0x6840, 0xa084, 0x00ff, 0xa005, 0x0140, 0x8001, 0x6842, 0x6017, + 0x000a, 0x6007, 0x0016, 0x00de, 0x08e8, 0x68a0, 0xa086, 0x007e, + 0x1138, 0x00e6, 0x2071, 0xb500, 0x080c, 0x4bc6, 0x00ee, 0x0010, + 0x080c, 0x2c9c, 0x00de, 0x0860, 0x080c, 0x8f95, 0x1158, 0x2001, + 0x0004, 0x080c, 0x4efd, 0x6003, 0x0001, 0x6007, 0x0003, 0x080c, + 0x6cd3, 0x0020, 0x080c, 0x8c19, 0x080c, 0x8df6, 0x0005, 0x0469, + 0x1158, 0x2001, 0x0008, 0x080c, 0x4efd, 0x6003, 0x0001, 0x6007, + 0x0005, 0x080c, 0x6cd3, 0x0010, 0x080c, 0x8df6, 0x0005, 0x00e9, + 0x1158, 0x2001, 0x000a, 0x080c, 0x4efd, 0x6003, 0x0001, 0x6007, + 0x0001, 0x080c, 0x6cd3, 0x0010, 0x080c, 0x8df6, 0x0005, 0x2009, + 0xbb8e, 0x2104, 0xa086, 0x0003, 0x1138, 0x2009, 0xbb8f, 0x2104, + 0xa084, 0xff00, 0xa086, 0x2a00, 0x0005, 0xa085, 0x0001, 0x0005, + 0x00c6, 0x0016, 0xac88, 0x0006, 0x2164, 0x080c, 0x4fb8, 0x001e, + 0x00ce, 0x0005, 0x00f6, 0x00e6, 0x00d6, 0x0036, 0x0016, 0x6018, + 0x2068, 0x2071, 0xb535, 0x2e04, 0xa085, 0x0003, 0x2072, 0x080c, + 0x9026, 0x0560, 0x2009, 0xb535, 0x2104, 0xc0cd, 0x200a, 0x2001, + 0xb553, 0x2004, 0xd0a4, 0x0158, 0xa006, 0x2020, 0x2009, 0x002a, + 0x080c, 0xb0e8, 0x2001, 0xb50c, 0x200c, 0xc195, 0x2102, 0x2019, + 0x002a, 0x2009, 0x0001, 0x080c, 0x2c6f, 0x2071, 0xb500, 0x080c, + 0x2ab8, 0x00c6, 0x0156, 0x20a9, 0x0081, 0x2009, 0x007f, 0x080c, + 0x2d97, 0x8108, 0x1f04, 0x8fd7, 0x015e, 0x00ce, 0x080c, 0x8f98, + 0x6813, 0x00ff, 0x6817, 0xfffe, 0x2071, 0xbb80, 0x2079, 0x0100, + 0x2e04, 0xa084, 0x00ff, 0x2069, 0xb51c, 0x206a, 0x78e6, 0x0006, + 0x8e70, 0x2e04, 0x2069, 0xb51d, 0x206a, 0x78ea, 0x7832, 0x7836, + 0x2010, 0xa084, 0xff00, 0x001e, 0xa105, 0x2009, 0xb528, 0x200a, + 0x2200, 0xa084, 0x00ff, 0x2008, 0x080c, 0x2847, 0x080c, 0x5acf, + 0x0170, 0x2069, 0xbb8e, 0x2071, 0xb7b2, 0x6810, 0x2072, 0x6814, + 0x7006, 0x6818, 0x700a, 0x681c, 0x700e, 0x080c, 0x9fd2, 0x0040, + 0x2001, 0x0006, 0x080c, 0x4efd, 0x080c, 0x2cc2, 0x080c, 0x861d, + 0x001e, 0x003e, 0x00de, 0x00ee, 0x00fe, 0x0005, 0x0026, 0x0036, + 0x00e6, 0x0156, 0x2019, 0xb528, 0x231c, 0x83ff, 0x01e8, 0x2071, + 0xbb80, 0x2e14, 0xa294, 0x00ff, 0x7004, 0xa084, 0xff00, 0xa205, + 0xa306, 0x1190, 0x2011, 0xbb96, 0xad98, 0x000a, 0x20a9, 0x0004, + 0x080c, 0x90da, 0x1148, 0x2011, 0xbb9a, 0xad98, 0x0006, 0x20a9, + 0x0004, 0x080c, 0x90da, 0x1100, 0x015e, 0x00ee, 0x003e, 0x002e, + 0x0005, 0x00e6, 0x2071, 0xbb8c, 0x7004, 0xa086, 0x0014, 0x11a8, + 0x7008, 0xa086, 0x0800, 0x1188, 0x700c, 0xd0ec, 0x0160, 0xa084, + 0x0f00, 0xa086, 0x0100, 0x1138, 0x7024, 0xd0a4, 0x1110, 0xd0ac, + 0x0110, 0xa006, 0x0010, 0xa085, 0x0001, 0x00ee, 0x0005, 0x00e6, + 0x00d6, 0x00c6, 0x0076, 0x0056, 0x0046, 0x0026, 0x0006, 0x0126, + 0x2091, 0x8000, 0x2029, 0xb7e9, 0x252c, 0x2021, 0xb7ef, 0x2424, + 0x2061, 0xbd00, 0x2071, 0xb500, 0x7248, 0x7068, 0xa202, 0x16f0, + 0x080c, 0xb110, 0x05a0, 0x671c, 0xa786, 0x0001, 0x0580, 0xa786, + 0x0007, 0x0568, 0x2500, 0xac06, 0x0550, 0x2400, 0xac06, 0x0538, + 0x00c6, 0x6000, 0xa086, 0x0004, 0x1110, 0x080c, 0x194d, 0xa786, + 0x0008, 0x1148, 0x080c, 0x9e58, 0x1130, 0x00ce, 0x080c, 0x8c19, + 0x080c, 0x9e1d, 0x00a0, 0x6010, 0x2068, 0x080c, 0x9c5a, 0x0160, + 0xa786, 0x0003, 0x11e8, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, + 0x080c, 0x5408, 0x080c, 0x9e11, 0x080c, 0x9e1d, 0x00ce, 0xace0, + 0x0018, 0x705c, 0xac02, 0x1210, 0x0804, 0x9084, 0x012e, 0x000e, + 0x002e, 0x004e, 0x005e, 0x007e, 0x00ce, 0x00de, 0x00ee, 0x0005, + 0xa786, 0x0006, 0x1118, 0x080c, 0xb099, 0x0c30, 0xa786, 0x000a, + 0x09e0, 0x08c8, 0x220c, 0x2304, 0xa106, 0x1130, 0x8210, 0x8318, + 0x1f04, 0x90da, 0xa006, 0x0005, 0x2304, 0xa102, 0x0218, 0x2001, + 0x0001, 0x0010, 0x2001, 0x0000, 0xa18d, 0x0001, 0x0005, 0x6004, + 0xa08a, 0x0080, 0x1a0c, 0x1515, 0x080c, 0x9e47, 0x0120, 0x080c, + 0x9e58, 0x0168, 0x0028, 0x080c, 0x2cc2, 0x080c, 0x9e58, 0x0138, + 0x080c, 0x7090, 0x080c, 0x861d, 0x080c, 0x7173, 0x0005, 0x080c, + 0x8c19, 0x0cb0, 0xa182, 0x0040, 0x0002, 0x9120, 0x9120, 0x9120, + 0x9120, 0x9120, 0x9120, 0x9120, 0x9120, 0x9120, 0x9120, 0x9120, + 0x9122, 0x9122, 0x9122, 0x9122, 0x9120, 0x9120, 0x9120, 0x9122, + 0x080c, 0x1515, 0x600b, 0xffff, 0x6003, 0x0001, 0x6106, 0x080c, + 0x6c8d, 0x0126, 0x2091, 0x8000, 0x080c, 0x7173, 0x012e, 0x0005, + 0xa186, 0x0013, 0x1128, 0x6004, 0xa082, 0x0040, 0x0804, 0x91bc, + 0xa186, 0x0027, 0x11e8, 0x080c, 0x7090, 0x080c, 0x2c9c, 0x00d6, + 0x6110, 0x2168, 0x080c, 0x9c5a, 0x0168, 0x6837, 0x0103, 0x684b, + 0x0029, 0x6847, 0x0000, 0x694c, 0xc1c5, 0x694e, 0x080c, 0x5408, + 0x080c, 0x9e11, 0x00de, 0x080c, 0x861d, 0x080c, 0x7173, 0x0005, + 0xa186, 0x0014, 0x1120, 0x6004, 0xa082, 0x0040, 0x0428, 0xa186, + 0x0046, 0x0138, 0xa186, 0x0045, 0x0120, 0xa186, 0x0047, 0x190c, + 0x1515, 0x2001, 0x0109, 0x2004, 0xd084, 0x0198, 0x0126, 0x2091, + 0x2800, 0x0006, 0x0016, 0x0026, 0x080c, 0x6b74, 0x002e, 0x001e, + 0x000e, 0x012e, 0xe000, 0x6000, 0xa086, 0x0002, 0x1110, 0x0804, + 0x91fa, 0x080c, 0x8663, 0x0005, 0x0002, 0x919a, 0x9198, 0x9198, + 0x9198, 0x9198, 0x9198, 0x9198, 0x9198, 0x9198, 0x9198, 0x9198, + 0x91b5, 0x91b5, 0x91b5, 0x91b5, 0x9198, 0x91b5, 0x9198, 0x91b5, + 0x080c, 0x1515, 0x080c, 0x7090, 0x00d6, 0x6110, 0x2168, 0x080c, + 0x9c5a, 0x0168, 0x6837, 0x0103, 0x684b, 0x0006, 0x6847, 0x0000, + 0x6850, 0xc0ec, 0x6852, 0x080c, 0x5408, 0x080c, 0x9e11, 0x00de, + 0x080c, 0x861d, 0x080c, 0x7173, 0x0005, 0x080c, 0x7090, 0x080c, + 0x861d, 0x080c, 0x7173, 0x0005, 0x0002, 0x91d2, 0x91d0, 0x91d0, + 0x91d0, 0x91d0, 0x91d0, 0x91d0, 0x91d0, 0x91d0, 0x91d0, 0x91d0, + 0x91e4, 0x91e4, 0x91e4, 0x91e4, 0x91d0, 0x91f3, 0x91d0, 0x91e4, + 0x080c, 0x1515, 0x080c, 0x7090, 0x2001, 0xb7b8, 0x2004, 0x603e, + 0x6003, 0x0002, 0x080c, 0x7173, 0x6010, 0xa088, 0x0013, 0x2104, + 0xa085, 0x0400, 0x200a, 0x0005, 0x080c, 0x7090, 0x2001, 0xb7b6, + 0x2004, 0x6016, 0x2001, 0xb7b8, 0x2004, 0x603e, 0x6003, 0x000f, + 0x080c, 0x7173, 0x0005, 0x080c, 0x7090, 0x080c, 0x861d, 0x080c, + 0x7173, 0x0005, 0xa182, 0x0040, 0x0002, 0x9210, 0x9210, 0x9210, + 0x9210, 0x9210, 0x9212, 0x92f7, 0x9326, 0x9210, 0x9210, 0x9210, + 0x9210, 0x9210, 0x9210, 0x9210, 0x9210, 0x9210, 0x9210, 0x9210, + 0x080c, 0x1515, 0x00e6, 0x00d6, 0x603f, 0x0000, 0x2071, 0xbb80, + 0x7124, 0x610a, 0x2071, 0xbb8c, 0x6110, 0x2168, 0x7614, 0xa6b4, + 0x0fff, 0x86ff, 0x0904, 0x92c0, 0xa68c, 0x0c00, 0x0518, 0x00f6, + 0x2c78, 0x080c, 0x5305, 0x00fe, 0x01c8, 0x684c, 0xd0ac, 0x01b0, + 0x6020, 0xd0dc, 0x1198, 0x6850, 0xd0bc, 0x1180, 0x7318, 0x6814, + 0xa306, 0x1904, 0x92d3, 0x731c, 0x6810, 0xa31e, 0x0138, 0xd6d4, + 0x0904, 0x92d3, 0x6b14, 0xa305, 0x1904, 0x92d3, 0x7318, 0x6b62, + 0x731c, 0x6b5e, 0xa68c, 0x00ff, 0xa186, 0x0002, 0x0518, 0xa186, + 0x0028, 0x1128, 0x080c, 0x9e36, 0x684b, 0x001c, 0x00e8, 0xd6dc, + 0x01a0, 0x684b, 0x0015, 0x684c, 0xd0ac, 0x0170, 0x6914, 0x6a10, + 0x2100, 0xa205, 0x0148, 0x7018, 0xa106, 0x1118, 0x701c, 0xa206, + 0x0118, 0x6962, 0x6a5e, 0xc6dc, 0x0038, 0xd6d4, 0x0118, 0x684b, + 0x0007, 0x0010, 0x684b, 0x0000, 0x6837, 0x0103, 0x6e46, 0xa01e, + 0xd6c4, 0x01f0, 0xa686, 0x0100, 0x1140, 0x2001, 0xbb99, 0x2004, + 0xa005, 0x1118, 0xc6c4, 0x0804, 0x9221, 0x7328, 0x732c, 0x6b56, + 0x83ff, 0x0170, 0xa38a, 0x0009, 0x0210, 0x2019, 0x0008, 0x0036, + 0x2308, 0x2019, 0xbb98, 0xad90, 0x0019, 0x080c, 0x990d, 0x003e, + 0xd6cc, 0x0904, 0x92e6, 0x7124, 0x695a, 0x81ff, 0x0904, 0x92e6, + 0xa192, 0x0021, 0x1260, 0x2071, 0xbb98, 0x831c, 0x2300, 0xae18, + 0xad90, 0x001d, 0x080c, 0x990d, 0x080c, 0xa137, 0x04b8, 0x6838, + 0xd0fc, 0x0120, 0x2009, 0x0020, 0x695a, 0x0c68, 0x00f6, 0x2d78, + 0x080c, 0x98b2, 0x00fe, 0x080c, 0xa137, 0x080c, 0x98fd, 0x0440, + 0x00f6, 0x2c78, 0x080c, 0x5305, 0x00fe, 0x0190, 0x684c, 0xd0ac, + 0x0178, 0x6020, 0xd0dc, 0x1160, 0x6850, 0xd0bc, 0x1148, 0x6810, + 0x6914, 0xa105, 0x0128, 0x080c, 0x9f35, 0x00de, 0x00ee, 0x00f0, + 0x684b, 0x0000, 0x6837, 0x0103, 0x6e46, 0x684c, 0xd0ac, 0x0130, + 0x6810, 0x6914, 0xa115, 0x0110, 0x080c, 0x9483, 0x080c, 0x5408, + 0x6218, 0x2268, 0x6a3c, 0x82ff, 0x0110, 0x8211, 0x6a3e, 0x080c, + 0x9f03, 0x00de, 0x00ee, 0x1110, 0x080c, 0x861d, 0x0005, 0x00f6, + 0x6003, 0x0003, 0x2079, 0xbb8c, 0x7c04, 0x7b00, 0x7e0c, 0x7d08, + 0x6010, 0x2078, 0x784c, 0xd0ac, 0x0138, 0x6003, 0x0002, 0x00fe, + 0x0005, 0x2130, 0x2228, 0x0058, 0x2400, 0x797c, 0xa10a, 0x2300, + 0x7a80, 0xa213, 0x2600, 0xa102, 0x2500, 0xa203, 0x0e90, 0x7c12, + 0x7b16, 0x7e0a, 0x7d0e, 0x00fe, 0x603f, 0x0000, 0x2c10, 0x080c, + 0x1fa9, 0x080c, 0x6cf0, 0x080c, 0x7230, 0x0005, 0x2001, 0xb7b8, + 0x2004, 0x603e, 0x6003, 0x0004, 0x6110, 0x20e1, 0x0005, 0x3d18, + 0x3e20, 0x2c10, 0x080c, 0x185e, 0x0005, 0xa182, 0x0040, 0x0002, + 0x934b, 0x934b, 0x934b, 0x934b, 0x934b, 0x934d, 0x93e0, 0x934b, + 0x934b, 0x93f6, 0x945a, 0x934b, 0x934b, 0x934b, 0x934b, 0x9469, + 0x934b, 0x934b, 0x934b, 0x080c, 0x1515, 0x0076, 0x00f6, 0x00e6, + 0x00d6, 0x2071, 0xbb8c, 0x6110, 0x2178, 0x7614, 0xa6b4, 0x0fff, + 0x7e46, 0x7f4c, 0xc7e5, 0x7f4e, 0x6218, 0x2268, 0x6a3c, 0x82ff, + 0x0110, 0x8211, 0x6a3e, 0x86ff, 0x0904, 0x93db, 0xa694, 0xff00, + 0xa284, 0x0c00, 0x0120, 0x7018, 0x7862, 0x701c, 0x785e, 0xa284, + 0x0300, 0x0904, 0x93db, 0x080c, 0x15f8, 0x090c, 0x1515, 0x2d00, + 0x784a, 0x7f4c, 0xc7cd, 0x7f4e, 0x6837, 0x0103, 0x7838, 0x683a, + 0x783c, 0x683e, 0x7840, 0x6842, 0x6e46, 0xa68c, 0x0c00, 0x0120, + 0x7318, 0x6b62, 0x731c, 0x6b5e, 0xa68c, 0x00ff, 0xa186, 0x0002, + 0x0180, 0xa186, 0x0028, 0x1118, 0x684b, 0x001c, 0x0060, 0xd6dc, + 0x0118, 0x684b, 0x0015, 0x0038, 0xd6d4, 0x0118, 0x684b, 0x0007, + 0x0010, 0x684b, 0x0000, 0x6f4e, 0x7850, 0x6852, 0x7854, 0x6856, + 0xa01e, 0xd6c4, 0x0198, 0x7328, 0x732c, 0x6b56, 0x83ff, 0x0170, + 0xa38a, 0x0009, 0x0210, 0x2019, 0x0008, 0x0036, 0x2308, 0x2019, + 0xbb98, 0xad90, 0x0019, 0x080c, 0x990d, 0x003e, 0xd6cc, 0x01d8, + 0x7124, 0x695a, 0x81ff, 0x01b8, 0xa192, 0x0021, 0x1250, 0x2071, + 0xbb98, 0x831c, 0x2300, 0xae18, 0xad90, 0x001d, 0x080c, 0x990d, + 0x0050, 0x7838, 0xd0fc, 0x0120, 0x2009, 0x0020, 0x695a, 0x0c78, + 0x2d78, 0x080c, 0x98b2, 0x00de, 0x00ee, 0x00fe, 0x007e, 0x0005, + 0x00f6, 0x6003, 0x0003, 0x2079, 0xbb8c, 0x7c04, 0x7b00, 0x7e0c, + 0x7d08, 0x6010, 0x2078, 0x7c12, 0x7b16, 0x7e0a, 0x7d0e, 0x00fe, + 0x2c10, 0x080c, 0x1fa9, 0x080c, 0x7d60, 0x0005, 0x00d6, 0x00f6, + 0x2c78, 0x080c, 0x5305, 0x00fe, 0x0120, 0x2001, 0xb7b8, 0x2004, + 0x603e, 0x6003, 0x0002, 0x080c, 0x7126, 0x080c, 0x7230, 0x6110, + 0x2168, 0x694c, 0xd1e4, 0x0904, 0x9458, 0xd1cc, 0x0540, 0x6948, + 0x6838, 0xd0fc, 0x01e8, 0x0016, 0x684c, 0x0006, 0x6850, 0x0006, + 0xad90, 0x000d, 0xa198, 0x000d, 0x2009, 0x0020, 0x0156, 0x21a8, + 0x2304, 0x2012, 0x8318, 0x8210, 0x1f04, 0x9420, 0x015e, 0x000e, + 0x6852, 0x000e, 0x684e, 0x001e, 0x2168, 0x080c, 0x161f, 0x0418, + 0x0016, 0x080c, 0x161f, 0x00de, 0x080c, 0x98fd, 0x00e0, 0x6837, + 0x0103, 0x6944, 0xa184, 0x00ff, 0xa0b6, 0x0002, 0x0180, 0xa086, + 0x0028, 0x1118, 0x684b, 0x001c, 0x0060, 0xd1dc, 0x0118, 0x684b, + 0x0015, 0x0038, 0xd1d4, 0x0118, 0x684b, 0x0007, 0x0010, 0x684b, + 0x0000, 0x080c, 0x5408, 0x080c, 0x9f03, 0x1110, 0x080c, 0x861d, + 0x00de, 0x0005, 0x2019, 0x0001, 0x080c, 0x7fe4, 0x6003, 0x0002, + 0x2001, 0xb7b8, 0x2004, 0x603e, 0x080c, 0x7126, 0x080c, 0x7230, + 0x0005, 0x080c, 0x7126, 0x080c, 0x2c9c, 0x00d6, 0x6110, 0x2168, + 0x080c, 0x9c5a, 0x0150, 0x6837, 0x0103, 0x684b, 0x0029, 0x6847, + 0x0000, 0x080c, 0x5408, 0x080c, 0x9e11, 0x00de, 0x080c, 0x861d, + 0x080c, 0x7230, 0x0005, 0x684b, 0x0015, 0xd1fc, 0x0138, 0x684b, + 0x0007, 0x8002, 0x8000, 0x810a, 0xa189, 0x0000, 0x6962, 0x685e, + 0x0005, 0xa182, 0x0040, 0x0002, 0x94a7, 0x94a7, 0x94a7, 0x94a7, + 0x94a7, 0x94a9, 0x94a7, 0x9564, 0x9570, 0x94a7, 0x94a7, 0x94a7, + 0x94a7, 0x94a7, 0x94a7, 0x94a7, 0x94a7, 0x94a7, 0x94a7, 0x080c, + 0x1515, 0x0076, 0x00f6, 0x00e6, 0x00d6, 0x2071, 0xbb8c, 0x6110, + 0x2178, 0x7614, 0xa6b4, 0x0fff, 0x00f6, 0x2c78, 0x080c, 0x5305, + 0x00fe, 0x0150, 0xa684, 0x00ff, 0x1138, 0x6020, 0xd0f4, 0x0120, + 0x080c, 0x9f35, 0x0804, 0x955f, 0x7e46, 0x7f4c, 0xc7e5, 0x7f4e, + 0x6218, 0x2268, 0x6a3c, 0x82ff, 0x0110, 0x8211, 0x6a3e, 0x86ff, + 0x0904, 0x9555, 0xa694, 0xff00, 0xa284, 0x0c00, 0x0120, 0x7018, + 0x7862, 0x701c, 0x785e, 0xa284, 0x0300, 0x0904, 0x9553, 0xa686, + 0x0100, 0x1140, 0x2001, 0xbb99, 0x2004, 0xa005, 0x1118, 0xc6c4, + 0x7e46, 0x0c28, 0x080c, 0x15f8, 0x090c, 0x1515, 0x2d00, 0x784a, + 0x7f4c, 0xa7bd, 0x0200, 0x7f4e, 0x6837, 0x0103, 0x7838, 0x683a, + 0x783c, 0x683e, 0x7840, 0x6842, 0x6e46, 0xa68c, 0x0c00, 0x0120, + 0x7318, 0x6b62, 0x731c, 0x6b5e, 0xa68c, 0x00ff, 0xa186, 0x0002, + 0x0180, 0xa186, 0x0028, 0x1118, 0x684b, 0x001c, 0x0060, 0xd6dc, + 0x0118, 0x684b, 0x0015, 0x0038, 0xd6d4, 0x0118, 0x684b, 0x0007, + 0x0010, 0x684b, 0x0000, 0x6f4e, 0x7850, 0x6852, 0x7854, 0x6856, + 0xa01e, 0xd6c4, 0x0198, 0x7328, 0x732c, 0x6b56, 0x83ff, 0x0170, + 0xa38a, 0x0009, 0x0210, 0x2019, 0x0008, 0x0036, 0x2308, 0x2019, + 0xbb98, 0xad90, 0x0019, 0x080c, 0x990d, 0x003e, 0xd6cc, 0x01d8, + 0x7124, 0x695a, 0x81ff, 0x01b8, 0xa192, 0x0021, 0x1250, 0x2071, + 0xbb98, 0x831c, 0x2300, 0xae18, 0xad90, 0x001d, 0x080c, 0x990d, + 0x0050, 0x7838, 0xd0fc, 0x0120, 0x2009, 0x0020, 0x695a, 0x0c78, + 0x2d78, 0x080c, 0x98b2, 0xd6dc, 0x1110, 0xa006, 0x0030, 0x2001, + 0x0001, 0x2071, 0xbb8c, 0x7218, 0x731c, 0x080c, 0x18b1, 0x00de, + 0x00ee, 0x00fe, 0x007e, 0x0005, 0x2001, 0xb7b8, 0x2004, 0x603e, + 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x080c, 0x185e, 0x0005, + 0x2001, 0xb7b8, 0x2004, 0x603e, 0x00d6, 0x6003, 0x0002, 0x6110, + 0x2168, 0x694c, 0xd1e4, 0x0904, 0x967b, 0x603f, 0x0000, 0x00f6, + 0x2c78, 0x080c, 0x5305, 0x00fe, 0x0560, 0x6814, 0x6910, 0xa115, + 0x0540, 0x6a60, 0xa206, 0x1118, 0x685c, 0xa106, 0x0510, 0x684c, + 0xc0e4, 0x684e, 0x6847, 0x0000, 0x6863, 0x0000, 0x685f, 0x0000, + 0x6020, 0xd0f4, 0x1158, 0x697c, 0x6810, 0xa102, 0x603a, 0x6980, + 0x6814, 0xa103, 0x6036, 0x6020, 0xc0f5, 0x6022, 0x00d6, 0x6018, + 0x2068, 0x683c, 0x8000, 0x683e, 0x00de, 0x080c, 0x9f35, 0x0804, + 0x967b, 0x694c, 0xd1cc, 0x0904, 0x964b, 0x6948, 0x6838, 0xd0fc, + 0x0904, 0x960e, 0x0016, 0x684c, 0x0006, 0x6850, 0x0006, 0x00f6, + 0x2178, 0x7944, 0xa184, 0x00ff, 0xa0b6, 0x0002, 0x01e0, 0xa086, + 0x0028, 0x1128, 0x684b, 0x001c, 0x784b, 0x001c, 0x00e8, 0xd1dc, + 0x0158, 0x684b, 0x0015, 0x784b, 0x0015, 0x080c, 0xa0bf, 0x0118, + 0x7944, 0xc1dc, 0x7946, 0x0080, 0xd1d4, 0x0128, 0x684b, 0x0007, + 0x784b, 0x0007, 0x0048, 0x684c, 0xd0ac, 0x0130, 0x6810, 0x6914, + 0xa115, 0x0110, 0x080c, 0x9483, 0x6848, 0x784a, 0x6860, 0x7862, + 0x685c, 0x785e, 0xad90, 0x000d, 0xaf98, 0x000d, 0x2009, 0x0020, + 0x0156, 0x21a8, 0x2304, 0x2012, 0x8318, 0x8210, 0x1f04, 0x95fa, + 0x015e, 0x00fe, 0x000e, 0x6852, 0x000e, 0x684e, 0x080c, 0xa137, + 0x001e, 0x2168, 0x080c, 0x161f, 0x0804, 0x9676, 0x0016, 0x00f6, + 0x2178, 0x7944, 0xa184, 0x00ff, 0xa0b6, 0x0002, 0x01e0, 0xa086, + 0x0028, 0x1128, 0x684b, 0x001c, 0x784b, 0x001c, 0x00e8, 0xd1dc, + 0x0158, 0x684b, 0x0015, 0x784b, 0x0015, 0x080c, 0xa0bf, 0x0118, + 0x7944, 0xc1dc, 0x7946, 0x0080, 0xd1d4, 0x0128, 0x684b, 0x0007, + 0x784b, 0x0007, 0x0048, 0x684c, 0xd0ac, 0x0130, 0x6810, 0x6914, + 0xa115, 0x0110, 0x080c, 0x9483, 0x6860, 0x7862, 0x685c, 0x785e, + 0x684c, 0x784e, 0x00fe, 0x080c, 0x161f, 0x00de, 0x080c, 0xa137, + 0x080c, 0x98fd, 0x0458, 0x6837, 0x0103, 0x6944, 0xa184, 0x00ff, + 0xa0b6, 0x0002, 0x01b0, 0xa086, 0x0028, 0x1118, 0x684b, 0x001c, + 0x00d8, 0xd1dc, 0x0148, 0x684b, 0x0015, 0x080c, 0xa0bf, 0x0118, + 0x6944, 0xc1dc, 0x6946, 0x0080, 0xd1d4, 0x0118, 0x684b, 0x0007, + 0x0058, 0x684b, 0x0000, 0x684c, 0xd0ac, 0x0130, 0x6810, 0x6914, + 0xa115, 0x0110, 0x080c, 0x9483, 0x080c, 0x5408, 0x080c, 0x9f03, + 0x1110, 0x080c, 0x861d, 0x00de, 0x0005, 0x080c, 0x7090, 0x0010, + 0x080c, 0x7126, 0x080c, 0x9c5a, 0x01c0, 0x00d6, 0x6110, 0x2168, + 0x6837, 0x0103, 0x2009, 0xb50c, 0x210c, 0xd18c, 0x11c0, 0xd184, + 0x1198, 0x6108, 0x694a, 0xa18e, 0x0029, 0x1110, 0x080c, 0xb380, + 0x6847, 0x0000, 0x080c, 0x5408, 0x00de, 0x080c, 0x861d, 0x080c, + 0x7173, 0x080c, 0x7230, 0x0005, 0x684b, 0x0004, 0x0c88, 0x684b, + 0x0004, 0x0c70, 0xa182, 0x0040, 0x0002, 0x96c0, 0x96c0, 0x96c0, + 0x96c0, 0x96c0, 0x96c2, 0x96c0, 0x96c5, 0x96c0, 0x96c0, 0x96c0, + 0x96c0, 0x96c0, 0x96c0, 0x96c0, 0x96c0, 0x96c0, 0x96c0, 0x96c0, + 0x080c, 0x1515, 0x080c, 0x861d, 0x0005, 0x0006, 0x0026, 0xa016, + 0x080c, 0x185e, 0x002e, 0x000e, 0x0005, 0xa182, 0x0085, 0x0002, + 0x96d9, 0x96d7, 0x96d7, 0x96e5, 0x96d7, 0x96d7, 0x96d7, 0x080c, + 0x1515, 0x6003, 0x0001, 0x6106, 0x080c, 0x6c8d, 0x0126, 0x2091, + 0x8000, 0x080c, 0x7173, 0x012e, 0x0005, 0x0026, 0x0056, 0x00d6, + 0x00e6, 0x2071, 0xbb80, 0x7224, 0x6212, 0x7220, 0x080c, 0x9c4a, + 0x01a0, 0x2268, 0x6800, 0xa086, 0x0000, 0x0178, 0x6018, 0x6d18, + 0xa52e, 0x1158, 0x00c6, 0x2d60, 0x080c, 0x991d, 0x00ce, 0x0128, + 0x6803, 0x0002, 0x6007, 0x0086, 0x0010, 0x6007, 0x0087, 0x6003, + 0x0001, 0x080c, 0x6c8d, 0x080c, 0x7173, 0x00f6, 0x2278, 0x080c, + 0x5305, 0x00fe, 0x0150, 0x6820, 0xd0ec, 0x0138, 0x00c6, 0x2260, + 0x603f, 0x0000, 0x080c, 0x9f35, 0x00ce, 0x00ee, 0x00de, 0x005e, + 0x002e, 0x0005, 0xa186, 0x0013, 0x1160, 0x6004, 0xa08a, 0x0085, + 0x0a0c, 0x1515, 0xa08a, 0x008c, 0x1a0c, 0x1515, 0xa082, 0x0085, + 0x0072, 0xa186, 0x0027, 0x0120, 0xa186, 0x0014, 0x190c, 0x1515, + 0x080c, 0x7090, 0x080c, 0x9e1d, 0x080c, 0x7173, 0x0005, 0x9746, + 0x9748, 0x9748, 0x9746, 0x9746, 0x9746, 0x9746, 0x080c, 0x1515, + 0x080c, 0x7090, 0x080c, 0x9e1d, 0x080c, 0x7173, 0x0005, 0xa186, + 0x0013, 0x1128, 0x6004, 0xa082, 0x0085, 0x2008, 0x04a8, 0xa186, + 0x0027, 0x11e8, 0x080c, 0x7090, 0x080c, 0x2c9c, 0x00d6, 0x6010, + 0x2068, 0x080c, 0x9c5a, 0x0150, 0x6837, 0x0103, 0x6847, 0x0000, + 0x684b, 0x0029, 0x080c, 0x5408, 0x080c, 0x9e11, 0x00de, 0x080c, + 0x861d, 0x080c, 0x7173, 0x0005, 0x080c, 0x8663, 0x0ce0, 0xa186, + 0x0014, 0x1dd0, 0x080c, 0x7090, 0x00d6, 0x6010, 0x2068, 0x080c, + 0x9c5a, 0x0d60, 0x6837, 0x0103, 0x6847, 0x0000, 0x684b, 0x0006, + 0x6850, 0xc0ec, 0x6852, 0x08f0, 0x0002, 0x9796, 0x9794, 0x9794, + 0x9794, 0x9794, 0x9794, 0x97ae, 0x080c, 0x1515, 0x080c, 0x7090, + 0x6030, 0xa08c, 0xff00, 0x810f, 0xa186, 0x0039, 0x0118, 0xa186, + 0x0035, 0x1118, 0x2001, 0xb7b6, 0x0010, 0x2001, 0xb7b7, 0x2004, + 0x6016, 0x6003, 0x000c, 0x080c, 0x7173, 0x0005, 0x080c, 0x7090, + 0x6030, 0xa08c, 0xff00, 0x810f, 0xa186, 0x0039, 0x0118, 0xa186, + 0x0035, 0x1118, 0x2001, 0xb7b6, 0x0010, 0x2001, 0xb7b7, 0x2004, + 0x6016, 0x6003, 0x000e, 0x080c, 0x7173, 0x0005, 0xa182, 0x008c, + 0x1220, 0xa182, 0x0085, 0x0208, 0x001a, 0x080c, 0x8663, 0x0005, + 0x97d7, 0x97d7, 0x97d7, 0x97d7, 0x97d9, 0x9832, 0x97d7, 0x080c, + 0x1515, 0x00d6, 0x00f6, 0x2c78, 0x080c, 0x5305, 0x00fe, 0x0168, + 0x6030, 0xa08c, 0xff00, 0x810f, 0xa186, 0x0039, 0x0118, 0xa186, + 0x0035, 0x1118, 0x00de, 0x0804, 0x9845, 0x080c, 0x9c5a, 0x1118, + 0x080c, 0x9e11, 0x00f0, 0x6010, 0x2068, 0x684c, 0xd0e4, 0x1110, + 0x080c, 0x9e11, 0x6837, 0x0103, 0x6850, 0xd0b4, 0x0128, 0x684b, + 0x0006, 0xc0ec, 0x6852, 0x0048, 0xd0bc, 0x0118, 0x684b, 0x0002, + 0x0020, 0x684b, 0x0005, 0x080c, 0x9ed2, 0x6847, 0x0000, 0x080c, + 0x5408, 0x2c68, 0x080c, 0x85c7, 0x01c0, 0x6003, 0x0001, 0x6007, + 0x001e, 0x600b, 0xffff, 0x2009, 0xbb8e, 0x210c, 0x6136, 0x2009, + 0xbb8f, 0x210c, 0x613a, 0x6918, 0x611a, 0x080c, 0xa027, 0x6950, + 0x6152, 0x601f, 0x0001, 0x080c, 0x6c8d, 0x2d60, 0x080c, 0x861d, + 0x00de, 0x0005, 0x00f6, 0x2c78, 0x080c, 0x5305, 0x00fe, 0x0598, + 0x6030, 0xa08c, 0xff00, 0x810f, 0xa186, 0x0035, 0x0130, 0xa186, + 0x001e, 0x0118, 0xa186, 0x0039, 0x1530, 0x00d6, 0x2c68, 0x080c, + 0xa10a, 0x1904, 0x988a, 0x080c, 0x85c7, 0x01d8, 0x6106, 0x6003, + 0x0001, 0x601f, 0x0001, 0x6918, 0x611a, 0x6928, 0x612a, 0x692c, + 0x612e, 0x6930, 0xa18c, 0x00ff, 0x6132, 0x6934, 0x6136, 0x6938, + 0x613a, 0x6950, 0x6152, 0x080c, 0xa027, 0x080c, 0x6c8d, 0x080c, + 0x7173, 0x2d60, 0x00f8, 0x00d6, 0x6010, 0x2068, 0x080c, 0x9c5a, + 0x01c8, 0x6837, 0x0103, 0x6850, 0xd0b4, 0x0128, 0xc0ec, 0x6852, + 0x684b, 0x0006, 0x0048, 0xd0bc, 0x0118, 0x684b, 0x0002, 0x0020, + 0x684b, 0x0005, 0x080c, 0x9ed2, 0x6847, 0x0000, 0x080c, 0x5408, + 0x080c, 0x9e11, 0x00de, 0x080c, 0x861d, 0x0005, 0x0016, 0x00d6, + 0x6010, 0x2068, 0x080c, 0x9c5a, 0x0140, 0x6837, 0x0103, 0x684b, + 0x0028, 0x6847, 0x0000, 0x080c, 0x5408, 0x00de, 0x001e, 0xa186, + 0x0013, 0x0148, 0xa186, 0x0014, 0x0130, 0xa186, 0x0027, 0x0118, + 0x080c, 0x8663, 0x0030, 0x080c, 0x7090, 0x080c, 0x9e1d, 0x080c, + 0x7173, 0x0005, 0x0056, 0x0066, 0x00d6, 0x00f6, 0x2029, 0x0001, + 0xa182, 0x0101, 0x1208, 0x0010, 0x2009, 0x0100, 0x2130, 0x2069, + 0xbb98, 0x831c, 0x2300, 0xad18, 0x2009, 0x0020, 0xaf90, 0x001d, + 0x080c, 0x990d, 0xa6b2, 0x0020, 0x7804, 0xa06d, 0x0110, 0x080c, + 0x161f, 0x080c, 0x15f8, 0x0500, 0x8528, 0x6837, 0x0110, 0x683b, + 0x0000, 0x2d20, 0x7c06, 0xa68a, 0x003d, 0x1228, 0x2608, 0xad90, + 0x000f, 0x0459, 0x0088, 0xa6b2, 0x003c, 0x2009, 0x003c, 0x2d78, + 0xad90, 0x000f, 0x0411, 0x0c28, 0x00fe, 0x852f, 0xa5ad, 0x0003, + 0x7d36, 0xa5ac, 0x0000, 0x0028, 0x00fe, 0x852f, 0xa5ad, 0x0003, + 0x7d36, 0x00de, 0x006e, 0x005e, 0x0005, 0x00f6, 0x8dff, 0x0158, + 0x6804, 0xa07d, 0x0130, 0x6807, 0x0000, 0x080c, 0x5408, 0x2f68, + 0x0cb8, 0x080c, 0x5408, 0x00fe, 0x0005, 0x0156, 0xa184, 0x0001, + 0x0108, 0x8108, 0x810c, 0x21a8, 0x2304, 0x8007, 0x2012, 0x8318, + 0x8210, 0x1f04, 0x9914, 0x015e, 0x0005, 0x0066, 0x0126, 0x2091, + 0x8000, 0x2031, 0x0001, 0x601c, 0xa084, 0x000f, 0x0083, 0x012e, + 0x006e, 0x0005, 0x0126, 0x2091, 0x8000, 0x0066, 0x2031, 0x0000, + 0x601c, 0xa084, 0x000f, 0x001b, 0x006e, 0x012e, 0x0005, 0x9954, + 0x9954, 0x994f, 0x9976, 0x9942, 0x994f, 0x9976, 0x994f, 0x994f, + 0x9942, 0x994f, 0x080c, 0x1515, 0x0036, 0x2019, 0x0010, 0x080c, + 0xace0, 0x601f, 0x0006, 0x6003, 0x0007, 0x003e, 0x0005, 0xa006, + 0x0005, 0xa085, 0x0001, 0x0005, 0x00d6, 0x86ff, 0x11d8, 0x6010, + 0x2068, 0x080c, 0x9c5a, 0x01c0, 0x6834, 0xa086, 0x0139, 0x1128, + 0x684b, 0x0005, 0x6853, 0x0000, 0x0028, 0xa00e, 0x2001, 0x0005, + 0x080c, 0x54db, 0x080c, 0x9ed2, 0x080c, 0x5408, 0x080c, 0x861d, + 0xa085, 0x0001, 0x00de, 0x0005, 0xa006, 0x0ce0, 0x6000, 0xa08a, + 0x0010, 0x1a0c, 0x1515, 0x000b, 0x0005, 0x998d, 0x99ae, 0x998f, + 0x99cd, 0x99ab, 0x998d, 0x994f, 0x9954, 0x9954, 0x994f, 0x994f, + 0x994f, 0x994f, 0x994f, 0x994f, 0x994f, 0x080c, 0x1515, 0x86ff, + 0x11b8, 0x601c, 0xa086, 0x0006, 0x0198, 0x00d6, 0x6010, 0x2068, + 0x080c, 0x9c5a, 0x0110, 0x080c, 0x9ed2, 0x00de, 0x6007, 0x0085, + 0x6003, 0x000b, 0x601f, 0x0002, 0x080c, 0x6c8d, 0x080c, 0x7173, + 0xa085, 0x0001, 0x0005, 0x080c, 0x194d, 0x0c08, 0x00e6, 0x2071, + 0xb7e0, 0x7024, 0xac06, 0x1110, 0x080c, 0x7f59, 0x601c, 0xa084, + 0x000f, 0xa086, 0x0006, 0x1150, 0x0086, 0x0096, 0x2049, 0x0001, + 0x2c40, 0x080c, 0x8130, 0x009e, 0x008e, 0x0010, 0x080c, 0x7e58, + 0x00ee, 0x1928, 0x080c, 0x994f, 0x0005, 0x0036, 0x00e6, 0x2071, + 0xb7e0, 0x703c, 0xac06, 0x1140, 0x2019, 0x0000, 0x080c, 0x7fe4, + 0x00ee, 0x003e, 0x0804, 0x998f, 0x080c, 0x825d, 0x00ee, 0x003e, + 0x1904, 0x998f, 0x080c, 0x994f, 0x0005, 0x00c6, 0x601c, 0xa084, + 0x000f, 0x0013, 0x00ce, 0x0005, 0x99fe, 0x9a6b, 0x9bb9, 0x9a09, + 0x9e1d, 0x99fe, 0xacd2, 0xa14e, 0x9a6b, 0x99f7, 0x9c24, 0x080c, + 0x1515, 0x080c, 0x9e58, 0x1110, 0x080c, 0x8c19, 0x0005, 0x080c, + 0x7090, 0x080c, 0x7173, 0x080c, 0x861d, 0x0005, 0x6017, 0x0001, + 0x0005, 0x080c, 0x9c5a, 0x0120, 0x6010, 0xa080, 0x0019, 0x2c02, + 0x6000, 0xa08a, 0x0010, 0x1a0c, 0x1515, 0x000b, 0x0005, 0x9a27, + 0x9a29, 0x9a49, 0x9a5b, 0x9a68, 0x9a27, 0x99fe, 0x99fe, 0x99fe, + 0x9a5b, 0x9a5b, 0x9a27, 0x9a27, 0x9a27, 0x9a27, 0x9a65, 0x080c, + 0x1515, 0x00e6, 0x6010, 0x2070, 0x7050, 0xc0b5, 0x7052, 0x2071, + 0xb7e0, 0x7024, 0xac06, 0x0190, 0x080c, 0x7e58, 0x6007, 0x0085, + 0x6003, 0x000b, 0x601f, 0x0002, 0x2001, 0xb7b7, 0x2004, 0x6016, + 0x080c, 0x6c8d, 0x080c, 0x7173, 0x00ee, 0x0005, 0x6017, 0x0001, + 0x0cd8, 0x00d6, 0x6010, 0x2068, 0x6850, 0xc0b5, 0x6852, 0x00de, + 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x080c, 0x6c8d, + 0x080c, 0x7173, 0x0005, 0x00d6, 0x6017, 0x0001, 0x6010, 0x2068, + 0x6850, 0xc0b5, 0x6852, 0x00de, 0x0005, 0x080c, 0x861d, 0x0005, + 0x080c, 0x194d, 0x08f0, 0x6000, 0xa08a, 0x0010, 0x1a0c, 0x1515, + 0x000b, 0x0005, 0x9a82, 0x9a06, 0x9a84, 0x9a82, 0x9a84, 0x9a84, + 0x99ff, 0x9a82, 0x99f9, 0x99f9, 0x9a82, 0x9a82, 0x9a82, 0x9a82, + 0x9a82, 0x9a82, 0x080c, 0x1515, 0x00d6, 0x6018, 0x2068, 0x6804, + 0xa084, 0x00ff, 0x00de, 0xa08a, 0x000c, 0x1a0c, 0x1515, 0x000b, + 0x0005, 0x9a9d, 0x9b5f, 0x9a9f, 0x9add, 0x9a9f, 0x9add, 0x9a9f, + 0x9aad, 0x9a9d, 0x9add, 0x9a9d, 0x9ac9, 0x080c, 0x1515, 0x6004, + 0xa08e, 0x0016, 0x05a8, 0xa08e, 0x0004, 0x0590, 0xa08e, 0x0002, + 0x0578, 0xa08e, 0x004b, 0x0904, 0x9b5b, 0x6004, 0x080c, 0x9e58, + 0x0904, 0x9b78, 0xa08e, 0x0021, 0x0904, 0x9b7c, 0xa08e, 0x0022, + 0x0904, 0x9b78, 0xa08e, 0x003d, 0x0904, 0x9b7c, 0xa08e, 0x0039, + 0x0904, 0x9b80, 0xa08e, 0x0035, 0x0904, 0x9b80, 0xa08e, 0x001e, + 0x0188, 0xa08e, 0x0001, 0x1150, 0x00d6, 0x6018, 0x2068, 0x6804, + 0xa084, 0x00ff, 0x00de, 0xa086, 0x0006, 0x0110, 0x080c, 0x2c9c, + 0x080c, 0x8c19, 0x080c, 0x9e1d, 0x0005, 0x00c6, 0x00d6, 0x6104, + 0xa186, 0x0016, 0x0904, 0x9b4c, 0xa186, 0x0002, 0x15d8, 0x2001, + 0xb535, 0x2004, 0xd08c, 0x1198, 0x080c, 0x5acf, 0x1180, 0x2001, + 0xb79f, 0x2003, 0x0001, 0x2001, 0xb500, 0x2003, 0x0001, 0xa085, + 0x0001, 0x080c, 0x5b13, 0x080c, 0x5a07, 0x0804, 0x9ba2, 0x6018, + 0x2068, 0x2001, 0xb535, 0x2004, 0xd0ac, 0x1904, 0x9ba2, 0x68a0, + 0xd0bc, 0x1904, 0x9ba2, 0x6840, 0xa084, 0x00ff, 0xa005, 0x0190, + 0x8001, 0x6842, 0x6013, 0x0000, 0x601f, 0x0007, 0x6017, 0x0398, + 0x603f, 0x0000, 0x080c, 0x85c7, 0x0128, 0x2d00, 0x601a, 0x601f, + 0x0001, 0x0450, 0x00de, 0x00ce, 0x6004, 0xa08e, 0x0002, 0x11a8, + 0x6018, 0xa080, 0x0028, 0x2004, 0xa086, 0x007e, 0x1170, 0x2009, + 0xb535, 0x2104, 0xc085, 0x200a, 0x00e6, 0x2071, 0xb500, 0x080c, + 0x4bc6, 0x00ee, 0x080c, 0x8c19, 0x0020, 0x080c, 0x8c19, 0x080c, + 0x2c9c, 0x00e6, 0x0126, 0x2091, 0x8000, 0x080c, 0x2cc2, 0x012e, + 0x00ee, 0x080c, 0x9e1d, 0x0005, 0x2001, 0x0002, 0x080c, 0x4efd, + 0x6003, 0x0001, 0x6007, 0x0002, 0x080c, 0x6cd3, 0x080c, 0x7173, + 0x00de, 0x00ce, 0x0c80, 0x080c, 0x2cc2, 0x0804, 0x9ad8, 0x00c6, + 0x00d6, 0x6104, 0xa186, 0x0016, 0x0d38, 0x6018, 0x2068, 0x6840, + 0xa084, 0x00ff, 0xa005, 0x0904, 0x9b22, 0x8001, 0x6842, 0x6003, + 0x0001, 0x080c, 0x6cd3, 0x080c, 0x7173, 0x00de, 0x00ce, 0x0898, + 0x080c, 0x8c19, 0x0804, 0x9ada, 0x080c, 0x8c47, 0x0804, 0x9ada, + 0x00d6, 0x2c68, 0x6104, 0x080c, 0xa10a, 0x00de, 0x0118, 0x080c, + 0x861d, 0x00b8, 0x6004, 0x8007, 0x6130, 0xa18c, 0x00ff, 0xa105, + 0x6032, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x6038, + 0x600a, 0x2001, 0xb7b7, 0x2004, 0x6016, 0x080c, 0x6c8d, 0x080c, + 0x7173, 0x0005, 0x00de, 0x00ce, 0x080c, 0x8c19, 0x080c, 0x2c9c, + 0x00e6, 0x0126, 0x2091, 0x8000, 0x080c, 0x2cc2, 0x6013, 0x0000, + 0x601f, 0x0007, 0x6017, 0x0398, 0x603f, 0x0000, 0x012e, 0x00ee, + 0x0005, 0x6000, 0xa08a, 0x0010, 0x1a0c, 0x1515, 0x000b, 0x0005, + 0x9bd0, 0x9bd0, 0x9bd0, 0x9bd0, 0x9bd0, 0x9bd0, 0x9bd0, 0x9bd0, + 0x9bd0, 0x99fe, 0x9bd0, 0x9a06, 0x9bd2, 0x9a06, 0x9bdf, 0x9bd0, + 0x080c, 0x1515, 0x6004, 0xa086, 0x008b, 0x0148, 0x6007, 0x008b, + 0x6003, 0x000d, 0x080c, 0x6c8d, 0x080c, 0x7173, 0x0005, 0x080c, + 0x9e11, 0x080c, 0x9c5a, 0x0580, 0x080c, 0x2c9c, 0x00d6, 0x080c, + 0x9c5a, 0x0168, 0x6010, 0x2068, 0x6837, 0x0103, 0x684b, 0x0006, + 0x6847, 0x0000, 0x6850, 0xc0ed, 0x6852, 0x080c, 0x5408, 0x2c68, + 0x080c, 0x85c7, 0x0150, 0x6818, 0x601a, 0x080c, 0xa027, 0x00c6, + 0x2d60, 0x080c, 0x9e1d, 0x00ce, 0x0008, 0x2d60, 0x00de, 0x6013, + 0x0000, 0x601f, 0x0001, 0x6007, 0x0001, 0x6003, 0x0001, 0x080c, + 0x6cd3, 0x080c, 0x7173, 0x0078, 0x6030, 0xa08c, 0xff00, 0x810f, + 0xa186, 0x0039, 0x0118, 0xa186, 0x0035, 0x1118, 0x080c, 0x2c9c, + 0x08b0, 0x080c, 0x9e1d, 0x0005, 0x6000, 0xa08a, 0x0010, 0x1a0c, + 0x1515, 0x000b, 0x0005, 0x9c3b, 0x9c3b, 0x9c3b, 0x9c3d, 0x9c3d, + 0x9c3b, 0x9c3b, 0x9c3b, 0x9c3b, 0x9c3b, 0x9c3b, 0x9c3b, 0x9c3b, + 0x9c3b, 0x9c3b, 0x9c3b, 0x080c, 0x1515, 0x080c, 0x825d, 0x190c, + 0x1515, 0x6110, 0x2168, 0x684b, 0x0006, 0x080c, 0x5408, 0x080c, + 0x861d, 0x0005, 0xa284, 0x0007, 0x1158, 0xa282, 0xbd00, 0x0240, + 0x2001, 0xb517, 0x2004, 0xa202, 0x1218, 0xa085, 0x0001, 0x0005, + 0xa006, 0x0ce8, 0x0026, 0x6210, 0xa294, 0xf000, 0x002e, 0x0005, + 0x00e6, 0x00c6, 0x0036, 0x0006, 0x0126, 0x2091, 0x8000, 0x2061, + 0xbd00, 0x2071, 0xb500, 0x7348, 0x7068, 0xa302, 0x12a8, 0x601c, + 0xa206, 0x1160, 0x080c, 0x9fb2, 0x0148, 0x080c, 0x9e58, 0x1110, + 0x080c, 0x8c19, 0x00c6, 0x080c, 0x861d, 0x00ce, 0xace0, 0x0018, + 0x705c, 0xac02, 0x1208, 0x0c38, 0x012e, 0x000e, 0x003e, 0x00ce, + 0x00ee, 0x0005, 0x00e6, 0x00c6, 0x0016, 0xa188, 0xb635, 0x210c, + 0x81ff, 0x0128, 0x2061, 0xb8f4, 0x611a, 0x080c, 0x2c9c, 0xa006, + 0x0010, 0xa085, 0x0001, 0x001e, 0x00ce, 0x00ee, 0x0005, 0x00c6, + 0x0056, 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, 0x85c7, 0x005e, + 0x0180, 0x6612, 0x651a, 0x080c, 0xa027, 0x601f, 0x0003, 0x2009, + 0x004b, 0x080c, 0x864c, 0xa085, 0x0001, 0x012e, 0x005e, 0x00ce, + 0x0005, 0xa006, 0x0cd0, 0x00c6, 0x0056, 0x0126, 0x2091, 0x8000, + 0x62a0, 0x00c6, 0x080c, 0x9ed6, 0x005e, 0x0550, 0x6013, 0x0000, + 0x651a, 0x080c, 0xa027, 0x601f, 0x0003, 0x0016, 0x00c6, 0x2560, + 0x080c, 0x51aa, 0x00ce, 0x080c, 0x6df5, 0x0076, 0x2039, 0x0000, + 0x080c, 0x6d02, 0x2c08, 0x080c, 0xae82, 0x007e, 0x001e, 0xd184, + 0x0128, 0x080c, 0x861d, 0xa085, 0x0001, 0x0030, 0x2009, 0x004c, + 0x080c, 0x864c, 0xa085, 0x0001, 0x012e, 0x005e, 0x00ce, 0x0005, + 0xa006, 0x0cd0, 0x00f6, 0x00c6, 0x0046, 0x00c6, 0x080c, 0x85c7, + 0x2c78, 0x00ce, 0x0180, 0x7e12, 0x2c00, 0x781a, 0x781f, 0x0003, + 0x2021, 0x0005, 0x080c, 0x9d50, 0x2f60, 0x2009, 0x004d, 0x080c, + 0x864c, 0xa085, 0x0001, 0x004e, 0x00ce, 0x00fe, 0x0005, 0x00f6, + 0x00c6, 0x0046, 0x00c6, 0x080c, 0x85c7, 0x2c78, 0x00ce, 0x0178, + 0x7e12, 0x2c00, 0x781a, 0x781f, 0x0003, 0x2021, 0x0005, 0x0481, + 0x2f60, 0x2009, 0x004e, 0x080c, 0x864c, 0xa085, 0x0001, 0x004e, + 0x00ce, 0x00fe, 0x0005, 0x00f6, 0x00c6, 0x0046, 0x00c6, 0x080c, + 0x85c7, 0x2c78, 0x00ce, 0x01c0, 0x7e12, 0x2c00, 0x781a, 0x781f, + 0x0003, 0x2021, 0x0004, 0x00a1, 0x2001, 0xb7a0, 0x2004, 0xd0fc, + 0x0120, 0x2f60, 0x080c, 0x861d, 0x0028, 0x2f60, 0x2009, 0x0052, + 0x080c, 0x864c, 0xa085, 0x0001, 0x004e, 0x00ce, 0x00fe, 0x0005, + 0x0096, 0x0076, 0x0126, 0x2091, 0x8000, 0x080c, 0x514c, 0x0118, + 0x2001, 0x9d55, 0x0028, 0x080c, 0x511c, 0x0158, 0x2001, 0x9d5b, + 0x0006, 0xa00e, 0x2400, 0x080c, 0x54db, 0x080c, 0x5408, 0x000e, + 0x0807, 0x2418, 0x080c, 0x702f, 0x62a0, 0x0086, 0x2041, 0x0001, + 0x2039, 0x0001, 0x2608, 0x080c, 0x6e0e, 0x008e, 0x080c, 0x6d02, + 0x2f08, 0x2648, 0x080c, 0xae82, 0x613c, 0x81ff, 0x090c, 0x6ec3, + 0x080c, 0x7173, 0x012e, 0x007e, 0x009e, 0x0005, 0x00c6, 0x0126, + 0x2091, 0x8000, 0x00c6, 0x080c, 0x85c7, 0x001e, 0x0188, 0x660a, + 0x611a, 0x080c, 0xa027, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, + 0x001f, 0x080c, 0x864c, 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005, + 0xa006, 0x0cd8, 0x00c6, 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, + 0x85c7, 0x001e, 0x0188, 0x660a, 0x611a, 0x080c, 0xa027, 0x601f, + 0x0008, 0x2d00, 0x6012, 0x2009, 0x0021, 0x080c, 0x864c, 0xa085, + 0x0001, 0x012e, 0x00ce, 0x0005, 0xa006, 0x0cd8, 0x00c6, 0x0126, + 0x2091, 0x8000, 0x00c6, 0x080c, 0x85c7, 0x001e, 0x0188, 0x660a, + 0x611a, 0x080c, 0xa027, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, + 0x003d, 0x080c, 0x864c, 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005, + 0xa006, 0x0cd8, 0x00c6, 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, + 0x9ed6, 0x001e, 0x0180, 0x611a, 0x080c, 0xa027, 0x601f, 0x0001, + 0x2d00, 0x6012, 0x2009, 0x0000, 0x080c, 0x864c, 0xa085, 0x0001, + 0x012e, 0x00ce, 0x0005, 0xa006, 0x0cd8, 0x00c6, 0x0126, 0x2091, + 0x8000, 0x00c6, 0x080c, 0x85c7, 0x001e, 0x0188, 0x660a, 0x611a, + 0x080c, 0xa027, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x0044, + 0x080c, 0x864c, 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005, 0xa006, + 0x0cd8, 0x0026, 0x00d6, 0x6218, 0x2268, 0x6a3c, 0x82ff, 0x0110, + 0x8211, 0x6a3e, 0x00de, 0x002e, 0x0005, 0x0006, 0x6000, 0xa086, + 0x0000, 0x0190, 0x6013, 0x0000, 0x601f, 0x0007, 0x2001, 0xb7b6, + 0x2004, 0x0006, 0xa082, 0x0051, 0x000e, 0x0208, 0x8004, 0x6016, + 0x080c, 0xb33a, 0x603f, 0x0000, 0x000e, 0x0005, 0x0066, 0x00c6, + 0x00d6, 0x2031, 0xb553, 0x2634, 0xd6e4, 0x0128, 0x6618, 0x2660, + 0x6e48, 0x080c, 0x50d5, 0x00de, 0x00ce, 0x006e, 0x0005, 0x0006, + 0x0016, 0x6004, 0xa08e, 0x0002, 0x0140, 0xa08e, 0x0003, 0x0128, + 0xa08e, 0x0004, 0x0110, 0xa085, 0x0001, 0x001e, 0x000e, 0x0005, + 0x0006, 0x00d6, 0x6010, 0xa06d, 0x0148, 0x6834, 0xa086, 0x0139, + 0x0138, 0x6838, 0xd0fc, 0x0110, 0xa006, 0x0010, 0xa085, 0x0001, + 0x00de, 0x000e, 0x0005, 0x00c6, 0x0126, 0x2091, 0x8000, 0x00c6, + 0x080c, 0x85c7, 0x001e, 0x0190, 0x611a, 0x080c, 0xa027, 0x601f, + 0x0001, 0x2d00, 0x6012, 0x080c, 0x2c9c, 0x2009, 0x0028, 0x080c, + 0x864c, 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005, 0xa006, 0x0cd8, + 0xa186, 0x0015, 0x1178, 0x2011, 0xb521, 0x2204, 0xa086, 0x0074, + 0x1148, 0x080c, 0x8f98, 0x6003, 0x0001, 0x6007, 0x0029, 0x080c, + 0x6cd3, 0x0020, 0x080c, 0x8c19, 0x080c, 0x861d, 0x0005, 0xa186, + 0x0016, 0x1128, 0x2001, 0x0004, 0x080c, 0x4efd, 0x00e8, 0xa186, + 0x0015, 0x11e8, 0x2011, 0xb521, 0x2204, 0xa086, 0x0014, 0x11b8, + 0x00d6, 0x6018, 0x2068, 0x080c, 0x504b, 0x00de, 0x080c, 0x9051, + 0x1170, 0x00d6, 0x6018, 0x2068, 0x6890, 0x00de, 0xa005, 0x0138, + 0x2001, 0x0006, 0x080c, 0x4efd, 0x080c, 0x87a0, 0x0020, 0x080c, + 0x8c19, 0x080c, 0x861d, 0x0005, 0x6848, 0xa086, 0x0005, 0x1108, + 0x0009, 0x0005, 0x6850, 0xc0ad, 0x6852, 0x0005, 0x00e6, 0x0126, + 0x2071, 0xb500, 0x2091, 0x8000, 0x7548, 0xa582, 0x0001, 0x0608, + 0x704c, 0x2060, 0x6000, 0xa086, 0x0000, 0x0148, 0xace0, 0x0018, + 0x705c, 0xac02, 0x1208, 0x0cb0, 0x2061, 0xbd00, 0x0c98, 0x6003, + 0x0008, 0x8529, 0x754a, 0xaca8, 0x0018, 0x705c, 0xa502, 0x1230, + 0x754e, 0xa085, 0x0001, 0x012e, 0x00ee, 0x0005, 0x704f, 0xbd00, + 0x0cc0, 0xa006, 0x0cc0, 0x00e6, 0x2071, 0xbb8c, 0x7014, 0xd0e4, + 0x0150, 0x6013, 0x0000, 0x6003, 0x0001, 0x6007, 0x0050, 0x080c, + 0x6c8d, 0x080c, 0x7173, 0x00ee, 0x0005, 0x00c6, 0x00f6, 0x2c78, + 0x080c, 0x5305, 0x00fe, 0x0120, 0x601c, 0xa084, 0x000f, 0x0013, + 0x00ce, 0x0005, 0x99fe, 0x9f2d, 0x9f30, 0x9f33, 0xb127, 0xb142, + 0xb145, 0x99fe, 0x99fe, 0x080c, 0x1515, 0xe000, 0xe000, 0x0005, + 0xe000, 0xe000, 0x0005, 0x0009, 0x0005, 0x00f6, 0x2c78, 0x080c, + 0x5305, 0x0538, 0x080c, 0x85c7, 0x1128, 0x2001, 0xb7b8, 0x2004, + 0x783e, 0x00f8, 0x7818, 0x601a, 0x080c, 0xa027, 0x781c, 0xa086, + 0x0003, 0x0128, 0x7808, 0x6036, 0x2f00, 0x603a, 0x0020, 0x7808, + 0x603a, 0x2f00, 0x6036, 0x602a, 0x601f, 0x0001, 0x6007, 0x0035, + 0x6003, 0x0001, 0x7950, 0x6152, 0x080c, 0x6c8d, 0x080c, 0x7173, + 0x2f60, 0x00fe, 0x0005, 0x0016, 0x00f6, 0x682c, 0x6032, 0xa08e, + 0x0001, 0x0138, 0xa086, 0x0005, 0x0140, 0xa006, 0x602a, 0x602e, + 0x00a0, 0x6820, 0xc0f4, 0xc0d5, 0x6822, 0x6810, 0x2078, 0x787c, + 0x6938, 0xa102, 0x7880, 0x6934, 0xa103, 0x1e78, 0x6834, 0x602a, + 0x6838, 0xa084, 0xfffc, 0x683a, 0x602e, 0x2d00, 0x6036, 0x6808, + 0x603a, 0x6918, 0x611a, 0x6950, 0x6152, 0x601f, 0x0001, 0x6007, + 0x0039, 0x6003, 0x0001, 0x080c, 0x6c8d, 0x6803, 0x0002, 0x00fe, + 0x001e, 0x0005, 0x00f6, 0x2c78, 0x080c, 0x5305, 0x1118, 0xa085, + 0x0001, 0x0070, 0x6020, 0xd0f4, 0x1150, 0xc0f5, 0x6022, 0x6010, + 0x2078, 0x7828, 0x603a, 0x782c, 0x6036, 0x080c, 0x194d, 0xa006, + 0x00fe, 0x0005, 0x0006, 0x0016, 0x6004, 0xa08e, 0x0034, 0x01b8, + 0xa08e, 0x0035, 0x01a0, 0xa08e, 0x0036, 0x0188, 0xa08e, 0x0037, + 0x0170, 0xa08e, 0x0038, 0x0158, 0xa08e, 0x0039, 0x0140, 0xa08e, + 0x003a, 0x0128, 0xa08e, 0x003b, 0x0110, 0xa085, 0x0001, 0x001e, + 0x000e, 0x0005, 0x0006, 0x0016, 0x0026, 0x0036, 0x00e6, 0x2001, + 0xb7b2, 0x200c, 0x8000, 0x2014, 0x2001, 0x0032, 0x080c, 0x6b40, + 0x2001, 0xb7b6, 0x82ff, 0x1110, 0x2011, 0x0014, 0x2202, 0x2001, + 0xb7b4, 0x200c, 0x8000, 0x2014, 0x2071, 0xb78e, 0x711a, 0x721e, + 0x2001, 0x0064, 0x080c, 0x6b40, 0x2001, 0xb7b7, 0x82ff, 0x1110, + 0x2011, 0x0014, 0x2202, 0x2009, 0xb7b8, 0xa280, 0x000a, 0x200a, + 0x080c, 0x532a, 0x00ee, 0x003e, 0x002e, 0x001e, 0x000e, 0x0005, + 0x0006, 0x00e6, 0x2001, 0xb7b6, 0x2003, 0x0028, 0x2001, 0xb7b7, + 0x2003, 0x0014, 0x2071, 0xb78e, 0x701b, 0x0000, 0x701f, 0x07d0, + 0x2001, 0xb7b8, 0x2003, 0x001e, 0x00ee, 0x000e, 0x0005, 0x00d6, + 0x6054, 0xa06d, 0x0110, 0x080c, 0x160f, 0x00de, 0x0005, 0x0005, + 0x00c6, 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, 0x85c7, 0x001e, + 0x0178, 0x611a, 0x0ca1, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, + 0x0033, 0x080c, 0x864c, 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005, + 0xa006, 0x0cd8, 0x00d6, 0x00e6, 0x00f6, 0x2071, 0xb500, 0xa186, + 0x0015, 0x1500, 0x7084, 0xa086, 0x0018, 0x11e0, 0x6010, 0x2068, + 0x6a3c, 0xd2e4, 0x1160, 0x2c78, 0x080c, 0x7331, 0x01d8, 0x7070, + 0x6a50, 0xa206, 0x1160, 0x7074, 0x6a54, 0xa206, 0x1140, 0x6218, + 0xa290, 0x0028, 0x2214, 0x2009, 0x0000, 0x080c, 0x2ce1, 0x080c, + 0x87a0, 0x0020, 0x080c, 0x8c19, 0x080c, 0x861d, 0x00fe, 0x00ee, + 0x00de, 0x0005, 0x7054, 0x6a54, 0xa206, 0x0d48, 0x0c80, 0x00c6, + 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, 0x85c7, 0x001e, 0x0180, + 0x611a, 0x080c, 0xa027, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, + 0x0043, 0x080c, 0x864c, 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005, + 0xa006, 0x0cd8, 0x00d6, 0x00e6, 0x00f6, 0x2071, 0xb500, 0xa186, + 0x0015, 0x11c0, 0x7084, 0xa086, 0x0004, 0x11a0, 0x6010, 0xa0e8, + 0x000f, 0x2c78, 0x080c, 0x7331, 0x01a8, 0x7070, 0x6a08, 0xa206, + 0x1130, 0x7074, 0x6a0c, 0xa206, 0x1110, 0x080c, 0x2c9c, 0x080c, + 0x87a0, 0x0020, 0x080c, 0x8c19, 0x080c, 0x861d, 0x00fe, 0x00ee, + 0x00de, 0x0005, 0x7054, 0x6a0c, 0xa206, 0x0d78, 0x0c80, 0x0016, + 0x0026, 0x684c, 0xd0ac, 0x0178, 0x6914, 0x6a10, 0x2100, 0xa205, + 0x0150, 0x6860, 0xa106, 0x1118, 0x685c, 0xa206, 0x0120, 0x6962, + 0x6a5e, 0xa085, 0x0001, 0x002e, 0x001e, 0x0005, 0x00d6, 0x0036, + 0x6310, 0x2368, 0x684a, 0x6952, 0xa29e, 0x4000, 0x11a0, 0x00c6, + 0x6318, 0x2360, 0x2009, 0x0000, 0x6838, 0xd0f4, 0x1140, 0x080c, + 0x524a, 0x1108, 0xc185, 0x6000, 0xd0bc, 0x0108, 0xc18d, 0x6a66, + 0x696a, 0x00ce, 0x0080, 0x6a66, 0x3918, 0xa398, 0x0006, 0x231c, + 0x686b, 0x0004, 0x6b72, 0x00c6, 0x6318, 0x2360, 0x6004, 0xa084, + 0x00ff, 0x686e, 0x00ce, 0x080c, 0x5408, 0x6013, 0x0000, 0x003e, + 0x00de, 0x0005, 0x00c6, 0x0026, 0x0016, 0xa186, 0x0035, 0x0110, + 0x6a34, 0x0008, 0x6a28, 0x080c, 0x9c4a, 0x01f0, 0x2260, 0x611c, + 0xa186, 0x0003, 0x0118, 0xa186, 0x0006, 0x1190, 0x6834, 0xa206, + 0x0140, 0x6838, 0xa206, 0x1160, 0x6108, 0x6834, 0xa106, 0x1140, + 0x0020, 0x6008, 0x6938, 0xa106, 0x1118, 0x6018, 0x6918, 0xa106, + 0x001e, 0x002e, 0x00ce, 0x0005, 0xa085, 0x0001, 0x0cc8, 0x6944, + 0xd1cc, 0x0198, 0xa18c, 0x00ff, 0xa18e, 0x0002, 0x1170, 0xad88, + 0x001e, 0x210c, 0xa18c, 0x0f00, 0x810f, 0xa18e, 0x0001, 0x1128, + 0x6810, 0x6914, 0xa115, 0x190c, 0x9483, 0x0005, 0x080c, 0x861d, + 0x0804, 0x7173, 0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c, 0x1515, + 0x0013, 0x006e, 0x0005, 0xa16b, 0xa646, 0xa76c, 0xa16b, 0xa16b, + 0xa16b, 0xa16b, 0xa16b, 0xa1a3, 0xa7f0, 0xa16b, 0xa16b, 0xa16b, + 0xa16b, 0xa16b, 0xa16b, 0x080c, 0x1515, 0x0066, 0x6000, 0xa0b2, + 0x0010, 0x1a0c, 0x1515, 0x0013, 0x006e, 0x0005, 0xa186, 0xac77, + 0xa186, 0xa186, 0xa186, 0xa186, 0xa186, 0xa186, 0xac39, 0xacbf, + 0xa186, 0xb26c, 0xb29c, 0xb26c, 0xb29c, 0xa186, 0x080c, 0x1515, + 0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c, 0x1515, 0x0013, 0x006e, + 0x0005, 0xa1a1, 0xa940, 0xaa0d, 0xaa3a, 0xaabe, 0xa1a1, 0xabab, + 0xab56, 0xa7fc, 0xac0f, 0xac24, 0xa1a1, 0xa1a1, 0xa1a1, 0xa1a1, + 0xa1a1, 0x080c, 0x1515, 0xa1b2, 0x0080, 0x1a0c, 0x1515, 0x2100, + 0xa1b2, 0x0040, 0x1a04, 0xa5ba, 0x0002, 0xa1ed, 0xa3b8, 0xa1ed, + 0xa1ed, 0xa1ed, 0xa3bf, 0xa1ed, 0xa1ed, 0xa1ed, 0xa1ed, 0xa1ed, + 0xa1ed, 0xa1ed, 0xa1ed, 0xa1ed, 0xa1ed, 0xa1ed, 0xa1ed, 0xa1ed, + 0xa1ed, 0xa1ed, 0xa1ed, 0xa1ed, 0xa1ef, 0xa24d, 0xa25c, 0xa2aa, + 0xa2c8, 0xa346, 0xa3a5, 0xa1ed, 0xa1ed, 0xa3c2, 0xa1ed, 0xa1ed, + 0xa3d5, 0xa3e0, 0xa1ed, 0xa1ed, 0xa1ed, 0xa1ed, 0xa1ed, 0xa46b, + 0xa1ed, 0xa1ed, 0xa47e, 0xa1ed, 0xa1ed, 0xa436, 0xa1ed, 0xa1ed, + 0xa1ed, 0xa496, 0xa1ed, 0xa1ed, 0xa1ed, 0xa510, 0xa1ed, 0xa1ed, + 0xa1ed, 0xa1ed, 0xa1ed, 0xa1ed, 0xa581, 0x080c, 0x1515, 0x080c, + 0x5309, 0x1150, 0x2001, 0xb535, 0x2004, 0xd0cc, 0x1128, 0xa084, + 0x0009, 0xa086, 0x0008, 0x1140, 0x6007, 0x0009, 0x602b, 0x0009, + 0x6013, 0x0000, 0x0804, 0xa3b3, 0x080c, 0x52f9, 0x00e6, 0x00c6, + 0x0036, 0x0026, 0x0016, 0x6218, 0x2270, 0x72a0, 0x0026, 0x2019, + 0x0029, 0x080c, 0x6df5, 0x0076, 0x2039, 0x0000, 0x080c, 0x6d02, + 0x2c08, 0x080c, 0xae82, 0x007e, 0x001e, 0x2e60, 0x080c, 0x51aa, + 0x001e, 0x002e, 0x003e, 0x00ce, 0x00ee, 0x6618, 0x00c6, 0x2660, + 0x080c, 0x4fb8, 0x00ce, 0xa6b0, 0x0001, 0x2634, 0xa684, 0x00ff, + 0xa082, 0x0006, 0x0278, 0x080c, 0xadc6, 0x1904, 0xa2a4, 0x080c, + 0xad66, 0x1120, 0x6007, 0x0008, 0x0804, 0xa3b3, 0x6007, 0x0009, + 0x0804, 0xa3b3, 0x080c, 0xaf7b, 0x0128, 0x080c, 0xadc6, 0x0d78, + 0x0804, 0xa2a4, 0x6013, 0x1900, 0x0c88, 0x080c, 0x2dbf, 0x1904, + 0xa5b7, 0x6106, 0x080c, 0xad20, 0x6007, 0x0006, 0x0804, 0xa3b3, + 0x6007, 0x0007, 0x0804, 0xa3b3, 0x080c, 0xb2d0, 0x1904, 0xa5b7, + 0x080c, 0x2dbf, 0x1904, 0xa5b7, 0x00d6, 0x6618, 0x2668, 0x6e04, + 0xa684, 0x00ff, 0xa082, 0x0006, 0x1220, 0x2001, 0x0001, 0x080c, + 0x4eeb, 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x0188, 0xa686, + 0x0004, 0x0170, 0x6e04, 0xa6b4, 0x00ff, 0xa686, 0x0006, 0x0140, + 0xa686, 0x0004, 0x0128, 0xa686, 0x0005, 0x0110, 0x00de, 0x00e0, + 0x080c, 0xae24, 0x11a0, 0xa686, 0x0006, 0x1150, 0x0026, 0x6218, + 0xa290, 0x0028, 0x2214, 0x2009, 0x0000, 0x080c, 0x2ce1, 0x002e, + 0x080c, 0x504b, 0x6007, 0x000a, 0x00de, 0x0804, 0xa3b3, 0x6007, + 0x000b, 0x00de, 0x0804, 0xa3b3, 0x080c, 0x2c9c, 0x6007, 0x0001, + 0x0804, 0xa3b3, 0x080c, 0xb2d0, 0x1904, 0xa5b7, 0x080c, 0x2dbf, + 0x1904, 0xa5b7, 0x6618, 0x00d6, 0x2668, 0x6e04, 0x00de, 0xa686, + 0x0707, 0x0d50, 0x0026, 0x6218, 0xa290, 0x0028, 0x2214, 0x2009, + 0x0000, 0x080c, 0x2ce1, 0x002e, 0x6007, 0x000c, 0x0804, 0xa3b3, + 0x080c, 0x5309, 0x1140, 0x2001, 0xb535, 0x2004, 0xa084, 0x0009, + 0xa086, 0x0008, 0x1110, 0x0804, 0xa1fc, 0x080c, 0x52f9, 0x6618, + 0xa6b0, 0x0001, 0x2634, 0xa684, 0x00ff, 0xa082, 0x0006, 0x06e8, + 0x1138, 0x0026, 0x2001, 0x0006, 0x080c, 0x4f2a, 0x002e, 0x0050, + 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0004, 0x0120, 0xa686, 0x0006, + 0x1904, 0xa2a4, 0x080c, 0xae31, 0x1120, 0x6007, 0x000e, 0x0804, + 0xa3b3, 0x0046, 0x6418, 0xa4a0, 0x0028, 0x2424, 0xa4a4, 0x00ff, + 0x8427, 0x0046, 0x080c, 0x2c9c, 0x004e, 0x0016, 0xa006, 0x2009, + 0xb553, 0x210c, 0xd1a4, 0x0158, 0x2009, 0x0029, 0x080c, 0xb0e8, + 0x6018, 0x00d6, 0x2068, 0x6800, 0xc0e5, 0x6802, 0x00de, 0x001e, + 0x004e, 0x6007, 0x0001, 0x0804, 0xa3b3, 0x2001, 0x0001, 0x080c, + 0x4eeb, 0x0156, 0x0016, 0x0026, 0x0036, 0x20a9, 0x0004, 0x2019, + 0xb505, 0x2011, 0xbb90, 0x080c, 0x90da, 0x003e, 0x002e, 0x001e, + 0x015e, 0xa005, 0x0168, 0xa6b4, 0xff00, 0x8637, 0xa682, 0x0004, + 0x0a04, 0xa2a4, 0xa682, 0x0007, 0x0a04, 0xa2f2, 0x0804, 0xa2a4, + 0x6013, 0x1900, 0x6007, 0x0009, 0x0804, 0xa3b3, 0x080c, 0x5309, + 0x1140, 0x2001, 0xb535, 0x2004, 0xa084, 0x0009, 0xa086, 0x0008, + 0x1110, 0x0804, 0xa1fc, 0x080c, 0x52f9, 0x6618, 0xa6b0, 0x0001, + 0x2634, 0xa684, 0x00ff, 0xa082, 0x0006, 0x06b8, 0xa6b4, 0xff00, + 0x8637, 0xa686, 0x0004, 0x0120, 0xa686, 0x0006, 0x1904, 0xa2a4, + 0x080c, 0xae59, 0x1138, 0x080c, 0xad66, 0x1120, 0x6007, 0x0010, + 0x0804, 0xa3b3, 0x0046, 0x6418, 0xa4a0, 0x0028, 0x2424, 0xa4a4, + 0x00ff, 0x8427, 0x0046, 0x080c, 0x2c9c, 0x004e, 0x0016, 0xa006, + 0x2009, 0xb553, 0x210c, 0xd1a4, 0x0158, 0x2009, 0x0029, 0x080c, + 0xb0e8, 0x6018, 0x00d6, 0x2068, 0x6800, 0xc0e5, 0x6802, 0x00de, + 0x001e, 0x004e, 0x6007, 0x0001, 0x00f0, 0x080c, 0xaf7b, 0x0140, + 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x0950, 0x0804, 0xa2a4, + 0x6013, 0x1900, 0x6007, 0x0009, 0x0070, 0x080c, 0x2dbf, 0x1904, + 0xa5b7, 0x080c, 0xb2d0, 0x1904, 0xa5b7, 0x080c, 0xa5df, 0x1904, + 0xa2a4, 0x6007, 0x0012, 0x6003, 0x0001, 0x080c, 0x6cd3, 0x0005, + 0x6007, 0x0001, 0x6003, 0x0001, 0x080c, 0x6cd3, 0x0cc0, 0x6007, + 0x0005, 0x0cc0, 0x080c, 0xb2d0, 0x1904, 0xa5b7, 0x080c, 0x2dbf, + 0x1904, 0xa5b7, 0x080c, 0xa5df, 0x1904, 0xa2a4, 0x6007, 0x0020, + 0x6003, 0x0001, 0x080c, 0x6cd3, 0x0005, 0x080c, 0x2dbf, 0x1904, + 0xa5b7, 0x6007, 0x0023, 0x6003, 0x0001, 0x080c, 0x6cd3, 0x0005, + 0x080c, 0xb2d0, 0x1904, 0xa5b7, 0x080c, 0x2dbf, 0x1904, 0xa5b7, + 0x080c, 0xa5df, 0x1904, 0xa2a4, 0x0016, 0x0026, 0x2011, 0xbb91, + 0x2214, 0xa286, 0xffff, 0x0190, 0x2c08, 0x080c, 0x9c4a, 0x01e0, + 0x2260, 0x2011, 0xbb90, 0x2214, 0x6008, 0xa206, 0x11a8, 0x6018, + 0xa190, 0x0006, 0x2214, 0xa206, 0x01e8, 0x0070, 0x2011, 0xbb90, + 0x2214, 0x2c08, 0xa006, 0x080c, 0xb0ba, 0x11a0, 0x2011, 0xbb91, + 0x2214, 0xa286, 0xffff, 0x01c0, 0x2160, 0x6007, 0x0026, 0x6013, + 0x1700, 0x2011, 0xbb89, 0x2214, 0xa296, 0xffff, 0x1180, 0x6007, + 0x0025, 0x0068, 0x601c, 0xa086, 0x0007, 0x1d70, 0x6004, 0xa086, + 0x0024, 0x1110, 0x080c, 0x861d, 0x2160, 0x6007, 0x0025, 0x6003, + 0x0001, 0x080c, 0x6cd3, 0x002e, 0x001e, 0x0005, 0x2001, 0x0001, + 0x080c, 0x4eeb, 0x0156, 0x0016, 0x0026, 0x0036, 0x20a9, 0x0004, + 0x2019, 0xb505, 0x2011, 0xbb96, 0x080c, 0x90da, 0x003e, 0x002e, + 0x001e, 0x015e, 0x0120, 0x6007, 0x0031, 0x0804, 0xa3b3, 0x080c, + 0x8df6, 0x080c, 0x5acf, 0x11b0, 0x0006, 0x0026, 0x0036, 0x080c, + 0x5aeb, 0x1158, 0x2001, 0xb79f, 0x2003, 0x0001, 0x2001, 0xb500, + 0x2003, 0x0001, 0x080c, 0x5a07, 0x0010, 0x080c, 0x5aa6, 0x003e, + 0x002e, 0x000e, 0x0005, 0x080c, 0x2dbf, 0x1904, 0xa5b7, 0x080c, + 0xa5df, 0x1904, 0xa2a4, 0x6106, 0x080c, 0xa5fb, 0x6007, 0x002b, + 0x0804, 0xa3b3, 0x6007, 0x002c, 0x0804, 0xa3b3, 0x080c, 0xb2d0, + 0x1904, 0xa5b7, 0x080c, 0x2dbf, 0x1904, 0xa5b7, 0x080c, 0xa5df, + 0x1904, 0xa2a4, 0x6106, 0x080c, 0xa5ff, 0x1120, 0x6007, 0x002e, + 0x0804, 0xa3b3, 0x6007, 0x002f, 0x0804, 0xa3b3, 0x080c, 0x2dbf, + 0x1904, 0xa5b7, 0x00e6, 0x00d6, 0x00c6, 0x6018, 0xa080, 0x0001, + 0x200c, 0xa184, 0x00ff, 0xa086, 0x0006, 0x0158, 0xa184, 0xff00, + 0x8007, 0xa086, 0x0006, 0x0128, 0x00ce, 0x00de, 0x00ee, 0x0804, + 0xa3b8, 0x2001, 0xb572, 0x2004, 0xd0e4, 0x0904, 0xa50d, 0x2071, + 0xbb8c, 0x7010, 0x6036, 0x7014, 0x603a, 0x7108, 0x720c, 0x2001, + 0xb553, 0x2004, 0xd0a4, 0x0140, 0x6018, 0x2068, 0x6810, 0xa106, + 0x1118, 0x6814, 0xa206, 0x01f8, 0x2001, 0xb553, 0x2004, 0xd0ac, + 0x1590, 0x2069, 0xb500, 0x6874, 0xa206, 0x1568, 0x6870, 0xa106, + 0x1550, 0x7210, 0x080c, 0x9c4a, 0x0558, 0x080c, 0xb154, 0x0540, + 0x622a, 0x6007, 0x0036, 0x6003, 0x0001, 0x080c, 0x6c8d, 0x00ce, + 0x00de, 0x00ee, 0x0005, 0x7214, 0xa286, 0xffff, 0x0150, 0x080c, + 0x9c4a, 0x01b0, 0xa280, 0x0002, 0x2004, 0x7110, 0xa106, 0x1180, + 0x0c08, 0x7210, 0x2c08, 0xa085, 0x0001, 0x080c, 0xb0ba, 0x2c10, + 0x2160, 0x0130, 0x08b8, 0x6007, 0x0037, 0x6013, 0x1500, 0x08d8, + 0x6007, 0x0037, 0x6013, 0x1700, 0x08b0, 0x6007, 0x0012, 0x0898, + 0x080c, 0x2dbf, 0x1904, 0xa5b7, 0x6018, 0xa080, 0x0001, 0x2004, + 0xa084, 0xff00, 0x8007, 0xa086, 0x0006, 0x1904, 0xa3b8, 0x00e6, + 0x00d6, 0x00c6, 0x2001, 0xb572, 0x2004, 0xd0e4, 0x0904, 0xa579, + 0x2069, 0xb500, 0x2071, 0xbb8c, 0x7008, 0x6036, 0x720c, 0x623a, + 0xa286, 0xffff, 0x1150, 0x7208, 0x00c6, 0x2c08, 0xa085, 0x0001, + 0x080c, 0xb0ba, 0x2c10, 0x00ce, 0x0588, 0x080c, 0x9c4a, 0x0570, + 0x00c6, 0x0026, 0x2260, 0x080c, 0x991d, 0x002e, 0x00ce, 0x7118, + 0xa18c, 0xff00, 0x810f, 0xa186, 0x0001, 0x0158, 0xa186, 0x0005, + 0x0118, 0xa186, 0x0007, 0x1178, 0xa280, 0x0004, 0x2004, 0xa005, + 0x0150, 0x0056, 0x7510, 0x7614, 0x080c, 0xb16b, 0x005e, 0x00ce, + 0x00de, 0x00ee, 0x0005, 0x6007, 0x003b, 0x602b, 0x0009, 0x6013, + 0x2a00, 0x6003, 0x0001, 0x080c, 0x6c8d, 0x0c88, 0x6007, 0x003b, + 0x602b, 0x0009, 0x6013, 0x1700, 0x6003, 0x0001, 0x080c, 0x6c8d, + 0x0c30, 0x6007, 0x003b, 0x602b, 0x000b, 0x6013, 0x0000, 0x0804, + 0xa4e3, 0x00e6, 0x0026, 0x080c, 0x5309, 0x0558, 0x080c, 0x52f9, + 0x080c, 0xb34b, 0x1520, 0x2071, 0xb500, 0x70d4, 0xc085, 0x70d6, + 0x00f6, 0x2079, 0x0100, 0x72a0, 0xa284, 0x00ff, 0x7072, 0x78e6, + 0xa284, 0xff00, 0x7274, 0xa205, 0x7076, 0x78ea, 0x00fe, 0x70df, + 0x0000, 0x2001, 0xb553, 0x2004, 0xd0a4, 0x0120, 0x2011, 0xb7f9, + 0x2013, 0x07d0, 0xd0ac, 0x1128, 0x080c, 0x2ab8, 0x0010, 0x080c, + 0xb377, 0x002e, 0x00ee, 0x080c, 0x861d, 0x0804, 0xa3b7, 0x080c, + 0x861d, 0x0005, 0x2600, 0x0002, 0xa5c5, 0xa5c5, 0xa5c5, 0xa5c5, + 0xa5c5, 0xa5c7, 0xa5c5, 0xa5c5, 0xa5c5, 0x080c, 0x1515, 0x080c, + 0xb2d0, 0x1d68, 0x080c, 0x2dbf, 0x1d50, 0x0089, 0x1138, 0x6007, + 0x0045, 0x6003, 0x0001, 0x080c, 0x6cd3, 0x0005, 0x080c, 0x2c9c, + 0x6007, 0x0001, 0x6003, 0x0001, 0x080c, 0x6cd3, 0x0005, 0x00d6, + 0x0066, 0x6618, 0x2668, 0x6e04, 0xa6b4, 0xff00, 0x8637, 0xa686, + 0x0006, 0x0170, 0xa686, 0x0004, 0x0158, 0x6e04, 0xa6b4, 0x00ff, + 0xa686, 0x0006, 0x0128, 0xa686, 0x0004, 0x0110, 0xa085, 0x0001, + 0x006e, 0x00de, 0x0005, 0x00d6, 0x0449, 0x00de, 0x0005, 0x00d6, + 0x0491, 0x11f0, 0x680c, 0xa08c, 0xff00, 0x6820, 0xa084, 0x00ff, + 0xa115, 0x6212, 0x6824, 0x602a, 0xd1e4, 0x0118, 0x2009, 0x0001, + 0x0060, 0xd1ec, 0x0168, 0x6920, 0xa18c, 0x00ff, 0x6824, 0x080c, + 0x281d, 0x1130, 0x2110, 0x2009, 0x0000, 0x080c, 0x2ce1, 0x0018, + 0xa085, 0x0001, 0x0008, 0xa006, 0x00de, 0x0005, 0x2069, 0xbb8d, + 0x6800, 0xa082, 0x0010, 0x1228, 0x6013, 0x0000, 0xa085, 0x0001, + 0x0008, 0xa006, 0x0005, 0x6013, 0x0000, 0x2069, 0xbb8c, 0x6808, + 0xa084, 0xff00, 0xa086, 0x0800, 0x1140, 0x6800, 0xa084, 0x00ff, + 0xa08e, 0x0014, 0x0110, 0xa08e, 0x0010, 0x0005, 0x6004, 0xa0b2, + 0x0080, 0x1a0c, 0x1515, 0xa1b6, 0x0013, 0x1130, 0x2008, 0xa1b2, + 0x0040, 0x1a04, 0xa746, 0x0092, 0xa1b6, 0x0027, 0x0120, 0xa1b6, + 0x0014, 0x190c, 0x1515, 0x2001, 0x0007, 0x080c, 0x4f2a, 0x080c, + 0x7090, 0x080c, 0x9e1d, 0x080c, 0x7173, 0x0005, 0xa6a6, 0xa6a8, + 0xa6a6, 0xa6a6, 0xa6a6, 0xa6a8, 0xa6ba, 0xa73f, 0xa70a, 0xa73f, + 0xa71b, 0xa73f, 0xa6ba, 0xa73f, 0xa737, 0xa73f, 0xa737, 0xa73f, + 0xa73f, 0xa6a6, 0xa6a6, 0xa6a6, 0xa6a6, 0xa6a6, 0xa6a6, 0xa6a6, + 0xa6a6, 0xa6a6, 0xa6a6, 0xa6a6, 0xa6a8, 0xa6a6, 0xa73f, 0xa6a6, + 0xa6a6, 0xa73f, 0xa6a6, 0xa73c, 0xa73f, 0xa6a6, 0xa6a6, 0xa6a6, + 0xa6a6, 0xa73f, 0xa73f, 0xa6a6, 0xa73f, 0xa73f, 0xa6a6, 0xa6b4, + 0xa6a6, 0xa6a6, 0xa6a6, 0xa6a6, 0xa73b, 0xa73f, 0xa6a6, 0xa6a6, + 0xa73f, 0xa73f, 0xa6a6, 0xa6a6, 0xa6a6, 0xa6a6, 0x080c, 0x1515, + 0x080c, 0x7090, 0x2001, 0xb7b6, 0x2004, 0x6016, 0x6003, 0x0002, + 0x080c, 0x7173, 0x0804, 0xa745, 0x2001, 0x0000, 0x080c, 0x4eeb, + 0x0804, 0xa73f, 0x00f6, 0x2079, 0xb552, 0x7804, 0x00fe, 0xd0ac, + 0x1904, 0xa73f, 0x2001, 0x0000, 0x080c, 0x4eeb, 0x6018, 0xa080, + 0x0004, 0x2004, 0xa086, 0x00ff, 0x1140, 0x00f6, 0x2079, 0xb500, + 0x7898, 0x8000, 0x789a, 0x00fe, 0x00e0, 0x00c6, 0x6018, 0x2060, + 0x6000, 0xd0f4, 0x1140, 0x6010, 0xa005, 0x0128, 0x00ce, 0x080c, + 0x3f3e, 0x0804, 0xa73f, 0x00ce, 0x2001, 0xb500, 0x2004, 0xa086, + 0x0002, 0x1138, 0x00f6, 0x2079, 0xb500, 0x7898, 0x8000, 0x789a, + 0x00fe, 0x2001, 0x0002, 0x080c, 0x4efd, 0x080c, 0x7090, 0x601f, + 0x0001, 0x6003, 0x0001, 0x6007, 0x0002, 0x080c, 0x6cd3, 0x080c, + 0x7173, 0x00c6, 0x6118, 0x2160, 0x2009, 0x0001, 0x080c, 0x69a8, + 0x00ce, 0x04d8, 0x6618, 0x00d6, 0x2668, 0x6e04, 0x00de, 0xa6b4, + 0xff00, 0x8637, 0xa686, 0x0006, 0x0550, 0xa686, 0x0004, 0x0538, + 0x2001, 0x0004, 0x0410, 0x2001, 0xb500, 0x2004, 0xa086, 0x0003, + 0x1110, 0x080c, 0x3f3e, 0x2001, 0x0006, 0x04a1, 0x6618, 0x00d6, + 0x2668, 0x6e04, 0x00de, 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, + 0x0170, 0x2001, 0x0006, 0x0048, 0x2001, 0x0004, 0x0030, 0x2001, + 0x0006, 0x0401, 0x0020, 0x0018, 0x0010, 0x080c, 0x4f2a, 0x080c, + 0x7090, 0x080c, 0x861d, 0x080c, 0x7173, 0x0005, 0x2600, 0x0002, + 0xa751, 0xa751, 0xa751, 0xa751, 0xa751, 0xa753, 0xa751, 0xa751, + 0xa751, 0x080c, 0x1515, 0x080c, 0x7090, 0x080c, 0x861d, 0x080c, + 0x7173, 0x0005, 0x0016, 0x00d6, 0x6118, 0x2168, 0x6900, 0xd184, + 0x0140, 0x080c, 0x4efd, 0x2001, 0x0000, 0x080c, 0x4eeb, 0x080c, + 0x2cc2, 0x00de, 0x001e, 0x0005, 0x00d6, 0x6618, 0x2668, 0x6804, + 0xa084, 0xff00, 0x8007, 0x00de, 0xa0b2, 0x000c, 0x1a0c, 0x1515, + 0xa1b6, 0x0015, 0x1110, 0x003b, 0x0028, 0xa1b6, 0x0016, 0x190c, + 0x1515, 0x006b, 0x0005, 0x8cdf, 0x8cdf, 0x8cdf, 0x8cdf, 0x8cdf, + 0x8cdf, 0xa7dc, 0xa79b, 0x8cdf, 0x8cdf, 0x8cdf, 0x8cdf, 0x8cdf, + 0x8cdf, 0x8cdf, 0x8cdf, 0x8cdf, 0x8cdf, 0xa7dc, 0xa7e3, 0x8cdf, + 0x8cdf, 0x8cdf, 0x8cdf, 0x00f6, 0x2079, 0xb552, 0x7804, 0xd0ac, + 0x11e0, 0x6018, 0xa07d, 0x01c8, 0x7800, 0xd0f4, 0x1118, 0x7810, + 0xa005, 0x1198, 0x2001, 0x0000, 0x080c, 0x4eeb, 0x2001, 0x0002, + 0x080c, 0x4efd, 0x601f, 0x0001, 0x6003, 0x0001, 0x6007, 0x0002, + 0x080c, 0x6cd3, 0x080c, 0x7173, 0x00e8, 0x2011, 0xbb83, 0x2204, + 0x8211, 0x220c, 0x080c, 0x281d, 0x11a8, 0x00c6, 0x080c, 0x4fa9, + 0x0120, 0x00ce, 0x080c, 0x861d, 0x0068, 0x6010, 0x0006, 0x6014, + 0x0006, 0x080c, 0x4c0b, 0x000e, 0x6016, 0x000e, 0x6012, 0x00ce, + 0x080c, 0x861d, 0x00fe, 0x0005, 0x6604, 0xa6b6, 0x001e, 0x1110, + 0x080c, 0x861d, 0x0005, 0x080c, 0x8f95, 0x1138, 0x6003, 0x0001, + 0x6007, 0x0001, 0x080c, 0x6cd3, 0x0010, 0x080c, 0x861d, 0x0005, + 0x6004, 0xa08a, 0x0080, 0x1a0c, 0x1515, 0x080c, 0x7090, 0x080c, + 0x9e1d, 0x080c, 0x7173, 0x0005, 0xa182, 0x0040, 0x0002, 0xa812, + 0xa812, 0xa812, 0xa812, 0xa814, 0xa812, 0xa812, 0xa812, 0xa812, + 0xa812, 0xa812, 0xa812, 0xa812, 0xa812, 0xa812, 0xa812, 0xa812, + 0xa812, 0xa812, 0x080c, 0x1515, 0x00d6, 0x00e6, 0x00f6, 0x0156, + 0x0046, 0x0026, 0x6218, 0xa280, 0x002b, 0x2004, 0xa005, 0x0120, + 0x2021, 0x0000, 0x080c, 0xb31c, 0x6106, 0x2071, 0xbb80, 0x7444, + 0xa4a4, 0xff00, 0x0904, 0xa878, 0xa486, 0x2000, 0x1130, 0x2009, + 0x0001, 0x2011, 0x0200, 0x080c, 0x6b1a, 0x080c, 0x15f8, 0x090c, + 0x1515, 0x6003, 0x0007, 0x2d00, 0x6837, 0x010d, 0x6803, 0x0000, + 0x683b, 0x0000, 0x6c5a, 0x2c00, 0x685e, 0x6008, 0x68b2, 0x6018, + 0x2078, 0x78a0, 0x8007, 0x7130, 0x694a, 0x0016, 0xa084, 0xff00, + 0x6846, 0x684f, 0x0000, 0x6853, 0x0000, 0x6857, 0x0036, 0x080c, + 0x5408, 0x001e, 0xa486, 0x2000, 0x1130, 0x2019, 0x0017, 0x080c, + 0xb065, 0x0804, 0xa8d5, 0xa486, 0x0400, 0x1130, 0x2019, 0x0002, + 0x080c, 0xb017, 0x0804, 0xa8d5, 0xa486, 0x0200, 0x1110, 0x080c, + 0xaffc, 0xa486, 0x1000, 0x1110, 0x080c, 0xb04a, 0x0804, 0xa8d5, + 0x2069, 0xb874, 0x6a00, 0xd284, 0x0904, 0xa93c, 0xa284, 0x0300, + 0x1904, 0xa935, 0x6804, 0xa005, 0x0904, 0xa91d, 0x2d78, 0x6003, + 0x0007, 0x080c, 0x15df, 0x0904, 0xa8dc, 0x7800, 0xd08c, 0x1118, + 0x7804, 0x8001, 0x7806, 0x6013, 0x0000, 0x6803, 0x0000, 0x6837, + 0x0116, 0x683b, 0x0000, 0x6008, 0x68b2, 0x2c00, 0x684a, 0x6018, + 0x2078, 0x78a0, 0x8007, 0x7130, 0x6986, 0x6846, 0x7928, 0x698a, + 0x792c, 0x698e, 0x7930, 0x6992, 0x7934, 0x6996, 0x6853, 0x003d, + 0x7244, 0xa294, 0x0003, 0xa286, 0x0002, 0x1118, 0x684f, 0x0040, + 0x0040, 0xa286, 0x0001, 0x1118, 0x684f, 0x0080, 0x0010, 0x684f, + 0x0000, 0x20a9, 0x000a, 0x2001, 0xbb90, 0xad90, 0x0015, 0x200c, + 0x810f, 0x2112, 0x8000, 0x8210, 0x1f04, 0xa8c7, 0x200c, 0x6982, + 0x8000, 0x200c, 0x697e, 0x080c, 0x5408, 0x002e, 0x004e, 0x015e, + 0x00fe, 0x00ee, 0x00de, 0x0005, 0x2001, 0xb50e, 0x2004, 0xd084, + 0x0120, 0x080c, 0x15f8, 0x1904, 0xa88d, 0x6013, 0x0100, 0x6003, + 0x0001, 0x6007, 0x0041, 0x080c, 0x6c8d, 0x080c, 0x7173, 0x0c28, + 0x2069, 0xbb92, 0x2d04, 0xa084, 0xff00, 0xa086, 0x1200, 0x11a8, + 0x2069, 0xbb80, 0x686c, 0xa084, 0x00ff, 0x0016, 0x6110, 0xa18c, + 0x0700, 0xa10d, 0x6112, 0x001e, 0x6003, 0x0001, 0x6007, 0x0043, + 0x080c, 0x6c8d, 0x080c, 0x7173, 0x0840, 0x6868, 0x602a, 0x686c, + 0x602e, 0x6013, 0x0200, 0x6003, 0x0001, 0x6007, 0x0041, 0x080c, + 0x6c8d, 0x080c, 0x7173, 0x0804, 0xa8d5, 0x2001, 0xb50d, 0x2004, + 0xd0ec, 0x0120, 0x2011, 0x8049, 0x080c, 0x3ecc, 0x6013, 0x0300, + 0x0010, 0x6013, 0x0100, 0x6003, 0x0001, 0x6007, 0x0041, 0x080c, + 0x6c8d, 0x080c, 0x7173, 0x0804, 0xa8d5, 0x6013, 0x0500, 0x0c98, + 0x6013, 0x0600, 0x0804, 0xa8f0, 0x6013, 0x0200, 0x0804, 0xa8f0, + 0xa186, 0x0013, 0x1170, 0x6004, 0xa08a, 0x0040, 0x0a0c, 0x1515, + 0xa08a, 0x0053, 0x1a0c, 0x1515, 0xa082, 0x0040, 0x2008, 0x0804, + 0xa9ca, 0xa186, 0x0051, 0x0138, 0xa186, 0x0047, 0x11d8, 0x6004, + 0xa086, 0x0041, 0x0518, 0x2001, 0x0109, 0x2004, 0xd084, 0x01f0, + 0x0126, 0x2091, 0x2800, 0x0006, 0x0016, 0x0026, 0x080c, 0x6b74, + 0x002e, 0x001e, 0x000e, 0x012e, 0x6000, 0xa086, 0x0002, 0x1170, + 0x0804, 0xaa0d, 0xa186, 0x0027, 0x0120, 0xa186, 0x0014, 0x190c, + 0x1515, 0x6004, 0xa082, 0x0040, 0x2008, 0x001a, 0x080c, 0x8663, + 0x0005, 0xa994, 0xa996, 0xa996, 0xa9ba, 0xa994, 0xa994, 0xa994, + 0xa994, 0xa994, 0xa994, 0xa994, 0xa994, 0xa994, 0xa994, 0xa994, + 0xa994, 0xa994, 0xa994, 0xa994, 0x080c, 0x1515, 0x080c, 0x7090, + 0x080c, 0x7173, 0x0036, 0x00d6, 0x6010, 0xa06d, 0x01c0, 0xad84, + 0xf000, 0x01a8, 0x6003, 0x0002, 0x6018, 0x2004, 0xd0bc, 0x1178, + 0x2019, 0x0004, 0x080c, 0xb099, 0x6013, 0x0000, 0x6014, 0xa005, + 0x1120, 0x2001, 0xb7b7, 0x2004, 0x6016, 0x6003, 0x0007, 0x00de, + 0x003e, 0x0005, 0x00d6, 0x080c, 0x7090, 0x080c, 0x7173, 0x080c, + 0x9c5a, 0x0120, 0x6010, 0x2068, 0x080c, 0x160f, 0x080c, 0x9e1d, + 0x00de, 0x0005, 0x0002, 0xa9de, 0xa9fb, 0xa9e7, 0xaa07, 0xa9de, + 0xa9de, 0xa9de, 0xa9de, 0xa9de, 0xa9de, 0xa9de, 0xa9de, 0xa9de, + 0xa9de, 0xa9de, 0xa9de, 0xa9de, 0xa9de, 0xa9de, 0x080c, 0x1515, + 0x6010, 0xa088, 0x0013, 0x2104, 0xa085, 0x0400, 0x200a, 0x080c, + 0x7090, 0x6010, 0xa080, 0x0013, 0x2004, 0xd0b4, 0x0138, 0x6003, + 0x0007, 0x2009, 0x0043, 0x080c, 0x864c, 0x0010, 0x6003, 0x0002, + 0x080c, 0x7173, 0x0005, 0x080c, 0x7090, 0x080c, 0xb2d7, 0x1120, + 0x080c, 0x6aef, 0x080c, 0x861d, 0x080c, 0x7173, 0x0005, 0x080c, + 0x7090, 0x2009, 0x0041, 0x0804, 0xab56, 0xa182, 0x0040, 0x0002, + 0xaa23, 0xaa25, 0xaa23, 0xaa23, 0xaa23, 0xaa23, 0xaa23, 0xaa26, + 0xaa23, 0xaa23, 0xaa23, 0xaa23, 0xaa23, 0xaa23, 0xaa23, 0xaa23, + 0xaa23, 0xaa31, 0xaa23, 0x080c, 0x1515, 0x0005, 0x6003, 0x0004, + 0x6110, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x080c, 0x185e, + 0x0005, 0x00d6, 0x080c, 0x6aef, 0x00de, 0x080c, 0xb33a, 0x080c, + 0x861d, 0x0005, 0xa182, 0x0040, 0x0002, 0xaa50, 0xaa50, 0xaa50, + 0xaa50, 0xaa50, 0xaa50, 0xaa50, 0xaa52, 0xaa50, 0xaa55, 0xaa8e, + 0xaa50, 0xaa50, 0xaa50, 0xaa50, 0xaa8e, 0xaa50, 0xaa50, 0xaa50, + 0x080c, 0x1515, 0x080c, 0x8663, 0x0005, 0x2001, 0xb572, 0x2004, + 0xd0e4, 0x0158, 0x2001, 0x0100, 0x2004, 0xa082, 0x0005, 0x0228, + 0x2001, 0x011f, 0x2004, 0x6036, 0x0010, 0x6037, 0x0000, 0x080c, + 0x7126, 0x080c, 0x7230, 0x6010, 0x00d6, 0x2068, 0x684c, 0xd0fc, + 0x0150, 0xa08c, 0x0003, 0xa18e, 0x0002, 0x0168, 0x2009, 0x0041, + 0x00de, 0x0804, 0xab56, 0x6003, 0x0007, 0x6017, 0x0000, 0x080c, + 0x6aef, 0x00de, 0x0005, 0x080c, 0xb2d7, 0x0110, 0x00de, 0x0005, + 0x080c, 0x6aef, 0x080c, 0x861d, 0x00de, 0x0ca0, 0x0036, 0x080c, + 0x7126, 0x080c, 0x7230, 0x6010, 0x00d6, 0x2068, 0x6018, 0x2004, + 0xd0bc, 0x0188, 0x684c, 0xa084, 0x0003, 0xa086, 0x0002, 0x0140, + 0x687c, 0x632c, 0xa31a, 0x632e, 0x6880, 0x6328, 0xa31b, 0x632a, + 0x6003, 0x0002, 0x0080, 0x2019, 0x0004, 0x080c, 0xb099, 0x6014, + 0xa005, 0x1128, 0x2001, 0xb7b7, 0x2004, 0x8003, 0x6016, 0x6013, + 0x0000, 0x6003, 0x0007, 0x00de, 0x003e, 0x0005, 0xa186, 0x0013, + 0x1150, 0x6004, 0xa086, 0x0042, 0x190c, 0x1515, 0x080c, 0x7090, + 0x080c, 0x7173, 0x0005, 0xa186, 0x0027, 0x0118, 0xa186, 0x0014, + 0x1180, 0x6004, 0xa086, 0x0042, 0x190c, 0x1515, 0x2001, 0x0007, + 0x080c, 0x4f2a, 0x080c, 0x7090, 0x080c, 0x9e1d, 0x080c, 0x7173, + 0x0005, 0xa182, 0x0040, 0x0002, 0xaaf7, 0xaaf7, 0xaaf7, 0xaaf7, + 0xaaf7, 0xaaf7, 0xaaf7, 0xaaf9, 0xab05, 0xaaf7, 0xaaf7, 0xaaf7, + 0xaaf7, 0xaaf7, 0xaaf7, 0xaaf7, 0xaaf7, 0xaaf7, 0xaaf7, 0x080c, + 0x1515, 0x0036, 0x0046, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, + 0x080c, 0x185e, 0x004e, 0x003e, 0x0005, 0x6010, 0x00d6, 0x2068, + 0x6810, 0x6a14, 0x0006, 0x0046, 0x0056, 0x6c7c, 0xa422, 0x6d80, + 0x2200, 0xa52b, 0x602c, 0xa420, 0x642e, 0x6028, 0xa529, 0x652a, + 0x005e, 0x004e, 0x000e, 0xa20d, 0x1178, 0x684c, 0xd0fc, 0x0120, + 0x2009, 0x0041, 0x00de, 0x0490, 0x6003, 0x0007, 0x6017, 0x0000, + 0x080c, 0x6aef, 0x00de, 0x0005, 0x0006, 0x00f6, 0x2c78, 0x080c, + 0x5305, 0x00fe, 0x000e, 0x0120, 0x6003, 0x0002, 0x00de, 0x0005, + 0x2009, 0xb50d, 0x210c, 0xd19c, 0x0118, 0x6003, 0x0007, 0x0010, + 0x6003, 0x0006, 0x0021, 0x080c, 0x6af1, 0x00de, 0x0005, 0xd2fc, + 0x0140, 0x8002, 0x8000, 0x8212, 0xa291, 0x0000, 0x2009, 0x0009, + 0x0010, 0x2009, 0x0015, 0x6a6a, 0x6866, 0x0005, 0xa182, 0x0040, + 0x0208, 0x0062, 0xa186, 0x0013, 0x0120, 0xa186, 0x0014, 0x190c, + 0x1515, 0x6020, 0xd0dc, 0x090c, 0x1515, 0x0005, 0xab79, 0xab80, + 0xab8c, 0xab98, 0xab79, 0xab79, 0xab79, 0xaba7, 0xab79, 0xab7b, + 0xab7b, 0xab79, 0xab79, 0xab79, 0xab79, 0xab7b, 0xab79, 0xab7b, + 0xab79, 0x080c, 0x1515, 0x6020, 0xd0dc, 0x090c, 0x1515, 0x0005, + 0x6003, 0x0001, 0x6106, 0x080c, 0x6c8d, 0x0126, 0x2091, 0x8000, + 0x080c, 0x7173, 0x012e, 0x0005, 0x6003, 0x0001, 0x6106, 0x080c, + 0x6c8d, 0x0126, 0x2091, 0x8000, 0x080c, 0x7173, 0x012e, 0x0005, + 0x6003, 0x0003, 0x6106, 0x2c10, 0x080c, 0x1fa9, 0x0126, 0x2091, + 0x8000, 0x080c, 0x6cf0, 0x080c, 0x7230, 0x012e, 0x0005, 0xa016, + 0x080c, 0x185e, 0x0005, 0x0126, 0x2091, 0x8000, 0x0036, 0x00d6, + 0xa182, 0x0040, 0x0023, 0x00de, 0x003e, 0x012e, 0x0005, 0xabc7, + 0xabc9, 0xabdb, 0xabf6, 0xabc7, 0xabc7, 0xabc7, 0xac0b, 0xabc7, + 0xabc7, 0xabc7, 0xabc7, 0xabc7, 0xabc7, 0xabc7, 0xabc7, 0x080c, + 0x1515, 0x6010, 0x2068, 0x684c, 0xd0fc, 0x01f8, 0xa09c, 0x0003, + 0xa39e, 0x0003, 0x01d0, 0x6003, 0x0001, 0x6106, 0x080c, 0x6c8d, + 0x080c, 0x7173, 0x0498, 0x6010, 0x2068, 0x684c, 0xd0fc, 0x0168, + 0xa09c, 0x0003, 0xa39e, 0x0003, 0x0140, 0x6003, 0x0001, 0x6106, + 0x080c, 0x6c8d, 0x080c, 0x7173, 0x0408, 0x6013, 0x0000, 0x6017, + 0x0000, 0x2019, 0x0004, 0x080c, 0xb099, 0x00c0, 0x6010, 0x2068, + 0x684c, 0xd0fc, 0x0d90, 0xa09c, 0x0003, 0xa39e, 0x0003, 0x0d68, + 0x6003, 0x0003, 0x6106, 0x2c10, 0x080c, 0x1fa9, 0x080c, 0x6cf0, + 0x080c, 0x7230, 0x0018, 0xa016, 0x080c, 0x185e, 0x0005, 0x080c, + 0x7090, 0x6110, 0x81ff, 0x0158, 0x00d6, 0x2168, 0x080c, 0xb380, + 0x0036, 0x2019, 0x0029, 0x080c, 0xb099, 0x003e, 0x00de, 0x080c, + 0x9e1d, 0x080c, 0x7173, 0x0005, 0x080c, 0x7126, 0x6110, 0x81ff, + 0x0158, 0x00d6, 0x2168, 0x080c, 0xb380, 0x0036, 0x2019, 0x0029, + 0x080c, 0xb099, 0x003e, 0x00de, 0x080c, 0x9e1d, 0x080c, 0x7230, + 0x0005, 0xa182, 0x0085, 0x0002, 0xac45, 0xac43, 0xac43, 0xac51, + 0xac43, 0xac43, 0xac43, 0x080c, 0x1515, 0x6003, 0x000b, 0x6106, + 0x080c, 0x6c8d, 0x0126, 0x2091, 0x8000, 0x080c, 0x7173, 0x012e, + 0x0005, 0x0026, 0x00e6, 0x080c, 0xb2d0, 0x0118, 0x080c, 0x861d, + 0x00d8, 0x2071, 0xbb80, 0x7224, 0x6212, 0x7220, 0x080c, 0xaf47, + 0x0118, 0x6007, 0x0086, 0x0040, 0x6007, 0x0087, 0x7224, 0xa296, + 0xffff, 0x1110, 0x6007, 0x0086, 0x6003, 0x0001, 0x080c, 0x6c8d, + 0x080c, 0x7173, 0x080c, 0x7230, 0x00ee, 0x002e, 0x0005, 0xa186, + 0x0013, 0x1160, 0x6004, 0xa08a, 0x0085, 0x0a0c, 0x1515, 0xa08a, + 0x008c, 0x1a0c, 0x1515, 0xa082, 0x0085, 0x00a2, 0xa186, 0x0027, + 0x0130, 0xa186, 0x0014, 0x0118, 0x080c, 0x8663, 0x0050, 0x2001, + 0x0007, 0x080c, 0x4f2a, 0x080c, 0x7090, 0x080c, 0x9e1d, 0x080c, + 0x7173, 0x0005, 0xaca1, 0xaca3, 0xaca3, 0xaca1, 0xaca1, 0xaca1, + 0xaca1, 0x080c, 0x1515, 0x080c, 0x7090, 0x080c, 0x9e1d, 0x080c, + 0x7173, 0x0005, 0xa182, 0x0085, 0x0a0c, 0x1515, 0xa182, 0x008c, + 0x1a0c, 0x1515, 0xa182, 0x0085, 0x0002, 0xacbc, 0xacbc, 0xacbc, + 0xacbe, 0xacbc, 0xacbc, 0xacbc, 0x080c, 0x1515, 0x0005, 0xa186, + 0x0013, 0x0148, 0xa186, 0x0014, 0x0130, 0xa186, 0x0027, 0x0118, + 0x080c, 0x8663, 0x0030, 0x080c, 0x7090, 0x080c, 0x9e1d, 0x080c, + 0x7173, 0x0005, 0x0036, 0x080c, 0xb33a, 0x603f, 0x0000, 0x2019, + 0x000b, 0x0031, 0x601f, 0x0006, 0x6003, 0x0007, 0x003e, 0x0005, + 0x0126, 0x0036, 0x2091, 0x8000, 0x0086, 0x2c40, 0x0096, 0x2049, + 0x0000, 0x080c, 0x8130, 0x009e, 0x008e, 0x1578, 0x0076, 0x2c38, + 0x080c, 0x81d6, 0x007e, 0x1548, 0x6000, 0xa086, 0x0000, 0x0528, + 0x601c, 0xa086, 0x0007, 0x0508, 0x00d6, 0x6000, 0xa086, 0x0004, + 0x1150, 0x080c, 0xb33a, 0x601f, 0x0007, 0x2001, 0xb7b6, 0x2004, + 0x6016, 0x080c, 0x194d, 0x6010, 0x2068, 0x080c, 0x9c5a, 0x0110, + 0x080c, 0xb099, 0x00de, 0x6013, 0x0000, 0x080c, 0xb33a, 0x601f, + 0x0007, 0x2001, 0xb7b6, 0x2004, 0x6016, 0x003e, 0x012e, 0x0005, + 0x00f6, 0x00c6, 0x0036, 0x0156, 0x2079, 0xbb80, 0x7938, 0x783c, + 0x080c, 0x281d, 0x15b0, 0x0016, 0x00c6, 0x080c, 0x4fa9, 0x1578, + 0x001e, 0x002e, 0x0026, 0x0016, 0x2019, 0x0029, 0x080c, 0x8299, + 0x080c, 0x6df5, 0x0076, 0x2039, 0x0000, 0x080c, 0x6d02, 0x007e, + 0x001e, 0x0076, 0x2039, 0x0000, 0x080c, 0xae82, 0x007e, 0x080c, + 0x51aa, 0x0026, 0x6204, 0xa294, 0xff00, 0x8217, 0xa286, 0x0006, + 0x0118, 0xa286, 0x0004, 0x1118, 0x62a0, 0x080c, 0x2d55, 0x002e, + 0x001e, 0x080c, 0x4c0b, 0x6612, 0x6516, 0xa006, 0x0010, 0x00ce, + 0x001e, 0x015e, 0x003e, 0x00ce, 0x00fe, 0x0005, 0x00c6, 0x00d6, + 0x00e6, 0x0016, 0x2009, 0xb521, 0x2104, 0xa086, 0x0074, 0x1904, + 0xadbb, 0x2069, 0xbb8e, 0x690c, 0xa182, 0x0100, 0x06c0, 0x6908, + 0xa184, 0x8000, 0x05e8, 0x2001, 0xb79e, 0x2004, 0xa005, 0x1160, + 0x6018, 0x2070, 0x7010, 0xa084, 0x00ff, 0x0118, 0x7000, 0xd0f4, + 0x0118, 0xa184, 0x0800, 0x0560, 0x6910, 0xa18a, 0x0001, 0x0610, + 0x6914, 0x2069, 0xbbae, 0x6904, 0x81ff, 0x1198, 0x690c, 0xa182, + 0x0100, 0x02a8, 0x6908, 0x81ff, 0x1178, 0x6910, 0xa18a, 0x0001, + 0x0288, 0x6918, 0xa18a, 0x0001, 0x0298, 0x00d0, 0x6013, 0x0100, + 0x00a0, 0x6013, 0x0300, 0x0088, 0x6013, 0x0500, 0x0070, 0x6013, + 0x0700, 0x0058, 0x6013, 0x0900, 0x0040, 0x6013, 0x0b00, 0x0028, + 0x6013, 0x0f00, 0x0010, 0x6013, 0x2d00, 0xa085, 0x0001, 0x0008, + 0xa006, 0x001e, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x00c6, 0x00d6, + 0x0026, 0x0036, 0x0156, 0x6218, 0x2268, 0x6b04, 0xa394, 0x00ff, + 0xa286, 0x0006, 0x0190, 0xa286, 0x0004, 0x0178, 0xa394, 0xff00, + 0x8217, 0xa286, 0x0006, 0x0148, 0xa286, 0x0004, 0x0130, 0x00c6, + 0x2d60, 0x080c, 0x4fb8, 0x00ce, 0x04c0, 0x2011, 0xbb96, 0xad98, + 0x000a, 0x20a9, 0x0004, 0x080c, 0x90da, 0x1580, 0x2011, 0xbb9a, + 0xad98, 0x0006, 0x20a9, 0x0004, 0x080c, 0x90da, 0x1538, 0x0046, + 0x0016, 0x6aa0, 0xa294, 0x00ff, 0x8227, 0xa006, 0x2009, 0xb553, + 0x210c, 0xd1a4, 0x0138, 0x2009, 0x0029, 0x080c, 0xb0e8, 0x6800, + 0xc0e5, 0x6802, 0x2019, 0x0029, 0x080c, 0x6df5, 0x0076, 0x2039, + 0x0000, 0x080c, 0x6d02, 0x2c08, 0x080c, 0xae82, 0x007e, 0x2001, + 0x0007, 0x080c, 0x4f2a, 0x001e, 0x004e, 0xa006, 0x015e, 0x003e, + 0x002e, 0x00de, 0x00ce, 0x0005, 0x00d6, 0x2069, 0xbb8e, 0x6800, + 0xa086, 0x0800, 0x0118, 0x6013, 0x0000, 0x0008, 0xa006, 0x00de, + 0x0005, 0x00c6, 0x00f6, 0x0016, 0x0026, 0x0036, 0x0156, 0x2079, + 0xbb8c, 0x7930, 0x7834, 0x080c, 0x281d, 0x11a0, 0x080c, 0x4fa9, + 0x1188, 0x2011, 0xbb90, 0xac98, 0x000a, 0x20a9, 0x0004, 0x080c, + 0x90da, 0x1140, 0x2011, 0xbb94, 0xac98, 0x0006, 0x20a9, 0x0004, + 0x080c, 0x90da, 0x015e, 0x003e, 0x002e, 0x001e, 0x00fe, 0x00ce, + 0x0005, 0x00c6, 0x0006, 0x0016, 0x0026, 0x0036, 0x0156, 0x2011, + 0xbb83, 0x2204, 0x8211, 0x220c, 0x080c, 0x281d, 0x11a0, 0x080c, + 0x4fa9, 0x1188, 0x2011, 0xbb96, 0xac98, 0x000a, 0x20a9, 0x0004, + 0x080c, 0x90da, 0x1140, 0x2011, 0xbb9a, 0xac98, 0x0006, 0x20a9, + 0x0004, 0x080c, 0x90da, 0x015e, 0x003e, 0x002e, 0x001e, 0x000e, + 0x00ce, 0x0005, 0x00e6, 0x00c6, 0x0086, 0x0076, 0x0066, 0x0056, + 0x0046, 0x0026, 0x0126, 0x2091, 0x8000, 0x2740, 0x2029, 0xb7e9, + 0x252c, 0x2021, 0xb7ef, 0x2424, 0x2061, 0xbd00, 0x2071, 0xb500, + 0x7648, 0x7068, 0x81ff, 0x0150, 0x0006, 0xa186, 0xb8f4, 0x000e, + 0x0128, 0x8001, 0xa602, 0x1a04, 0xaf03, 0x0018, 0xa606, 0x0904, + 0xaf03, 0x2100, 0xac06, 0x0904, 0xaefa, 0x080c, 0xb110, 0x0904, + 0xaefa, 0x671c, 0xa786, 0x0001, 0x0904, 0xaf1e, 0xa786, 0x0004, + 0x0904, 0xaf1e, 0xa786, 0x0007, 0x05e8, 0x2500, 0xac06, 0x05d0, + 0x2400, 0xac06, 0x05b8, 0x080c, 0xb120, 0x15a0, 0x88ff, 0x0118, + 0x6050, 0xa906, 0x1578, 0x00d6, 0x6000, 0xa086, 0x0004, 0x1120, + 0x0016, 0x080c, 0x194d, 0x001e, 0xa786, 0x0008, 0x1148, 0x080c, + 0x9e58, 0x1130, 0x080c, 0x8c19, 0x00de, 0x080c, 0x9e1d, 0x00d0, + 0x6010, 0x2068, 0x080c, 0x9c5a, 0x0190, 0xa786, 0x0003, 0x1528, + 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, 0xb380, 0x0016, + 0x080c, 0x9ecc, 0x080c, 0x5408, 0x001e, 0x080c, 0x9e11, 0x00de, + 0x080c, 0x9e1d, 0xace0, 0x0018, 0x2001, 0xb517, 0x2004, 0xac02, + 0x1210, 0x0804, 0xae96, 0x012e, 0x002e, 0x004e, 0x005e, 0x006e, + 0x007e, 0x008e, 0x00ce, 0x00ee, 0x0005, 0xa786, 0x0006, 0x1150, + 0xa386, 0x0005, 0x0128, 0x080c, 0xb380, 0x080c, 0xb099, 0x08f8, + 0x00de, 0x0c00, 0xa786, 0x000a, 0x0968, 0x0850, 0x080c, 0xb120, + 0x19c8, 0x81ff, 0x09b8, 0xa180, 0x0001, 0x2004, 0xa086, 0x0018, + 0x0130, 0xa180, 0x0001, 0x2004, 0xa086, 0x002d, 0x1958, 0x6000, + 0xa086, 0x0002, 0x1938, 0x080c, 0x9e47, 0x0130, 0x080c, 0x9e58, + 0x1908, 0x080c, 0x8c19, 0x0038, 0x080c, 0x2cc2, 0x080c, 0x9e58, + 0x1110, 0x080c, 0x8c19, 0x080c, 0x9e1d, 0x0804, 0xaefa, 0x00c6, + 0x00e6, 0x0016, 0x2c08, 0x2170, 0xa006, 0x080c, 0xb0ba, 0x001e, + 0x0120, 0x601c, 0xa084, 0x000f, 0x001b, 0x00ee, 0x00ce, 0x0005, + 0xaf60, 0xaf60, 0xaf60, 0xaf60, 0xaf60, 0xaf60, 0xaf62, 0xaf60, + 0xa006, 0x0005, 0x0046, 0x0016, 0x7018, 0xa080, 0x0028, 0x2024, + 0xa4a4, 0x00ff, 0x8427, 0x2c00, 0x2009, 0x0020, 0x080c, 0xb0e8, + 0x001e, 0x004e, 0x0036, 0x2019, 0x0002, 0x080c, 0xace0, 0x003e, + 0xa085, 0x0001, 0x0005, 0x2001, 0x0001, 0x080c, 0x4eeb, 0x0156, + 0x0016, 0x0026, 0x0036, 0x20a9, 0x0004, 0x2019, 0xb505, 0x2011, + 0xbb96, 0x080c, 0x90da, 0x003e, 0x002e, 0x001e, 0x015e, 0xa005, + 0x0005, 0x00f6, 0x00e6, 0x00c6, 0x0086, 0x0076, 0x0066, 0x0026, + 0x0126, 0x2091, 0x8000, 0x2740, 0x2061, 0xbd00, 0x2079, 0x0001, + 0x8fff, 0x0904, 0xafef, 0x2071, 0xb500, 0x7648, 0x7068, 0x8001, + 0xa602, 0x1a04, 0xafef, 0x88ff, 0x0128, 0x2800, 0xac06, 0x15b0, + 0x2079, 0x0000, 0x080c, 0xb110, 0x0588, 0x2400, 0xac06, 0x0570, + 0x671c, 0xa786, 0x0006, 0x1550, 0xa786, 0x0007, 0x0538, 0x88ff, + 0x1140, 0x6018, 0xa206, 0x1510, 0x85ff, 0x0118, 0x6050, 0xa106, + 0x11e8, 0x00d6, 0x6000, 0xa086, 0x0004, 0x1150, 0x080c, 0xb33a, + 0x601f, 0x0007, 0x2001, 0xb7b6, 0x2004, 0x6016, 0x080c, 0x194d, + 0x6010, 0x2068, 0x080c, 0x9c5a, 0x0120, 0x0046, 0x080c, 0xb099, + 0x004e, 0x00de, 0x080c, 0x9e1d, 0x88ff, 0x1198, 0xace0, 0x0018, + 0x2001, 0xb517, 0x2004, 0xac02, 0x1210, 0x0804, 0xafa0, 0xa006, + 0x012e, 0x002e, 0x006e, 0x007e, 0x008e, 0x00ce, 0x00ee, 0x00fe, + 0x0005, 0xa8c5, 0x0001, 0x0ca0, 0x0076, 0x0056, 0x0086, 0x2041, + 0x0000, 0x2029, 0x0001, 0x2c20, 0x2019, 0x0002, 0x6218, 0x0096, + 0x2049, 0x0000, 0x080c, 0x8130, 0x009e, 0x008e, 0x2039, 0x0000, + 0x080c, 0x81d6, 0x080c, 0xaf91, 0x005e, 0x007e, 0x0005, 0x0026, + 0x0046, 0x0056, 0x0076, 0x00c6, 0x0156, 0x2c20, 0x2128, 0x20a9, + 0x007f, 0x2009, 0x0000, 0x0016, 0x0036, 0x080c, 0x4fa9, 0x11b0, + 0x2c10, 0x0056, 0x0086, 0x2041, 0x0000, 0x2508, 0x2029, 0x0001, + 0x0096, 0x2049, 0x0000, 0x080c, 0x8130, 0x009e, 0x008e, 0x2039, + 0x0000, 0x080c, 0x81d6, 0x080c, 0xaf91, 0x005e, 0x003e, 0x001e, + 0x8108, 0x1f04, 0xb023, 0x015e, 0x00ce, 0x007e, 0x005e, 0x004e, + 0x002e, 0x0005, 0x0076, 0x0056, 0x6218, 0x0086, 0x2041, 0x0000, + 0x2029, 0x0001, 0x2019, 0x0048, 0x0096, 0x2049, 0x0000, 0x080c, + 0x8130, 0x009e, 0x008e, 0x2039, 0x0000, 0x080c, 0x81d6, 0x2c20, + 0x080c, 0xaf91, 0x005e, 0x007e, 0x0005, 0x0026, 0x0046, 0x0056, + 0x0076, 0x00c6, 0x0156, 0x2c20, 0x20a9, 0x007f, 0x2009, 0x0000, + 0x0016, 0x0036, 0x080c, 0x4fa9, 0x11c0, 0x2c10, 0x0086, 0x2041, + 0x0000, 0x2828, 0x0046, 0x2021, 0x0001, 0x080c, 0xb31c, 0x004e, + 0x0096, 0x2049, 0x0000, 0x080c, 0x8130, 0x009e, 0x008e, 0x2039, + 0x0000, 0x080c, 0x81d6, 0x080c, 0xaf91, 0x003e, 0x001e, 0x8108, + 0x1f04, 0xb070, 0x015e, 0x00ce, 0x007e, 0x005e, 0x004e, 0x002e, + 0x0005, 0x0016, 0x00f6, 0x3800, 0xd08c, 0x0130, 0xad82, 0x1000, + 0x02b0, 0xad82, 0xb500, 0x0230, 0xad82, 0xed00, 0x0280, 0xad82, + 0xffff, 0x1268, 0x6800, 0xa07d, 0x0138, 0x6803, 0x0000, 0x6b52, + 0x080c, 0x5408, 0x2f68, 0x0cb0, 0x6b52, 0x080c, 0x5408, 0x00fe, + 0x001e, 0x0005, 0x00e6, 0x0046, 0x0036, 0x2061, 0xbd00, 0xa005, + 0x1138, 0x2071, 0xb500, 0x7448, 0x7068, 0x8001, 0xa402, 0x12d8, + 0x2100, 0xac06, 0x0168, 0x6000, 0xa086, 0x0000, 0x0148, 0x6008, + 0xa206, 0x1130, 0x6018, 0xa1a0, 0x0006, 0x2424, 0xa406, 0x0140, + 0xace0, 0x0018, 0x2001, 0xb517, 0x2004, 0xac02, 0x1220, 0x0c40, + 0xa085, 0x0001, 0x0008, 0xa006, 0x003e, 0x004e, 0x00ee, 0x0005, + 0x00d6, 0x0006, 0x080c, 0x15f8, 0x000e, 0x090c, 0x1515, 0x6837, + 0x010d, 0x685e, 0x0026, 0x2010, 0x080c, 0x9c4a, 0x2001, 0x0000, + 0x0120, 0x2200, 0xa080, 0x0014, 0x2004, 0x002e, 0x684a, 0x6956, + 0x6c46, 0x684f, 0x0000, 0x2001, 0xb7be, 0x2004, 0x6852, 0xa006, + 0x68b2, 0x6802, 0x683a, 0x685a, 0x080c, 0x5408, 0x00de, 0x0005, + 0x6700, 0xa786, 0x0000, 0x0158, 0xa786, 0x0001, 0x0140, 0xa786, + 0x000a, 0x0128, 0xa786, 0x0009, 0x0110, 0xa085, 0x0001, 0x0005, + 0x00e6, 0x6018, 0x2070, 0x70a0, 0xa206, 0x00ee, 0x0005, 0x0016, + 0x6004, 0xa08e, 0x001e, 0x11a0, 0x8007, 0x6130, 0xa18c, 0x00ff, + 0xa105, 0x6032, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0005, + 0x2001, 0xb7b7, 0x2004, 0x6016, 0x080c, 0x6c8d, 0x080c, 0x7173, + 0x001e, 0x0005, 0xe000, 0xe000, 0x0005, 0x6020, 0xd0e4, 0x0158, + 0xd0cc, 0x0118, 0x080c, 0x9f35, 0x0030, 0x080c, 0xb33a, 0x080c, + 0x6aef, 0x080c, 0x861d, 0x0005, 0xa280, 0x0007, 0x2004, 0xa084, + 0x000f, 0x0002, 0xb163, 0xb163, 0xb163, 0xb168, 0xb163, 0xb165, + 0xb165, 0xb163, 0xb165, 0xa006, 0x0005, 0x00c6, 0x2260, 0x00ce, + 0xa085, 0x0001, 0x0005, 0xa280, 0x0007, 0x2004, 0xa084, 0x000f, + 0x0002, 0xb17a, 0xb17a, 0xb17a, 0xb17a, 0xb17a, 0xb17a, 0xb185, + 0xb17a, 0xb17a, 0x6007, 0x003b, 0x602b, 0x0009, 0x6013, 0x2a00, + 0x6003, 0x0001, 0x080c, 0x6c8d, 0x0005, 0x00c6, 0x2260, 0x080c, + 0xb33a, 0x603f, 0x0000, 0x6020, 0xc0f4, 0xc0cc, 0x6022, 0x6037, + 0x0000, 0x00ce, 0x00d6, 0x2268, 0xa186, 0x0007, 0x1904, 0xb1e0, + 0x6810, 0xa005, 0x0138, 0xa080, 0x0013, 0x2004, 0xd0fc, 0x1110, + 0x00de, 0x08c0, 0x6007, 0x003a, 0x6003, 0x0001, 0x080c, 0x6c8d, + 0x080c, 0x7173, 0x00c6, 0x2d60, 0x6100, 0xa186, 0x0002, 0x1904, + 0xb269, 0x6010, 0xa005, 0x1138, 0x6000, 0xa086, 0x0007, 0x190c, + 0x1515, 0x0804, 0xb269, 0xa08c, 0xf000, 0x1130, 0x0028, 0x2068, + 0x6800, 0xa005, 0x1de0, 0x2d00, 0xa080, 0x0013, 0x2004, 0xa084, + 0x0003, 0xa086, 0x0002, 0x1180, 0x6010, 0x2068, 0x684c, 0xc0dc, + 0xc0f4, 0x684e, 0x6850, 0xc0f4, 0xc0fc, 0x6852, 0x2009, 0x0043, + 0x080c, 0xab56, 0x0804, 0xb269, 0x2009, 0x0041, 0x0804, 0xb263, + 0xa186, 0x0005, 0x15f0, 0x6810, 0xa080, 0x0013, 0x2004, 0xd0bc, + 0x1118, 0x00de, 0x0804, 0xb17a, 0xd0b4, 0x0128, 0xd0fc, 0x090c, + 0x1515, 0x0804, 0xb198, 0x6007, 0x003a, 0x6003, 0x0001, 0x080c, + 0x6c8d, 0x080c, 0x7173, 0x00c6, 0x2d60, 0x6100, 0xa186, 0x0002, + 0x0120, 0xa186, 0x0004, 0x1904, 0xb269, 0x2071, 0xb823, 0x7000, + 0xa086, 0x0003, 0x1128, 0x7004, 0xac06, 0x1110, 0x7003, 0x0000, + 0x6810, 0xa080, 0x0013, 0x200c, 0xc1f4, 0xc1dc, 0x2102, 0x8000, + 0x200c, 0xc1f4, 0xc1fc, 0xc1bc, 0x2102, 0x2009, 0x0042, 0x0804, + 0xb263, 0x0036, 0x00d6, 0x00d6, 0x080c, 0x15f8, 0x003e, 0x090c, + 0x1515, 0x6837, 0x010d, 0x6803, 0x0000, 0x683b, 0x0000, 0x685b, + 0x0000, 0x6b5e, 0x6857, 0x0045, 0x2c00, 0x6862, 0x6034, 0x6872, + 0x2360, 0x6020, 0xc0dd, 0x6022, 0x6018, 0xa080, 0x0028, 0x2004, + 0xa084, 0x00ff, 0x8007, 0x6350, 0x6b4a, 0x6846, 0x684f, 0x0000, + 0x6853, 0x0000, 0x6d6a, 0x6e66, 0x686f, 0x0001, 0x080c, 0x5408, + 0x2019, 0x0045, 0x6008, 0x2068, 0x080c, 0xace0, 0x2d00, 0x600a, + 0x601f, 0x0006, 0x6003, 0x0007, 0x6017, 0x0000, 0x603f, 0x0000, + 0x00de, 0x003e, 0x0038, 0x603f, 0x0000, 0x6003, 0x0007, 0x080c, + 0xab56, 0x00ce, 0x00de, 0x0005, 0xa186, 0x0013, 0x1128, 0x6004, + 0xa082, 0x0085, 0x2008, 0x00c2, 0xa186, 0x0027, 0x1178, 0x080c, + 0x7090, 0x0036, 0x00d6, 0x6010, 0x2068, 0x2019, 0x0004, 0x080c, + 0xb099, 0x00de, 0x003e, 0x080c, 0x7173, 0x0005, 0xa186, 0x0014, + 0x0d70, 0x080c, 0x8663, 0x0005, 0xb295, 0xb293, 0xb293, 0xb293, + 0xb293, 0xb293, 0xb295, 0x080c, 0x1515, 0x080c, 0x7090, 0x6003, + 0x000c, 0x080c, 0x7173, 0x0005, 0xa182, 0x008c, 0x1220, 0xa182, + 0x0085, 0x0208, 0x001a, 0x080c, 0x8663, 0x0005, 0xb2ad, 0xb2ad, + 0xb2ad, 0xb2ad, 0xb2af, 0xb2cd, 0xb2ad, 0x080c, 0x1515, 0x00d6, + 0x2c68, 0x080c, 0x85c7, 0x01a0, 0x6003, 0x0001, 0x6007, 0x001e, + 0x2009, 0xbb8e, 0x210c, 0x6136, 0x2009, 0xbb8f, 0x210c, 0x613a, + 0x600b, 0xffff, 0x6918, 0x611a, 0x601f, 0x0004, 0x080c, 0x6c8d, + 0x2d60, 0x080c, 0x861d, 0x00de, 0x0005, 0x080c, 0x861d, 0x0005, + 0x00e6, 0x6018, 0x2070, 0x7000, 0xd0ec, 0x00ee, 0x0005, 0x6010, + 0xa08c, 0xf000, 0x0904, 0xb31b, 0xa080, 0x0013, 0x200c, 0xd1ec, + 0x05d0, 0x2001, 0xb572, 0x2004, 0xd0ec, 0x05a8, 0x6003, 0x0002, + 0x6020, 0xc0e5, 0x6022, 0xd1ac, 0x0180, 0x00f6, 0x2c78, 0x080c, + 0x5301, 0x00fe, 0x0150, 0x2001, 0xb7b8, 0x2004, 0x603e, 0x2009, + 0xb572, 0x210c, 0xd1f4, 0x11e8, 0x0080, 0x2009, 0xb572, 0x210c, + 0xd1f4, 0x0128, 0x6020, 0xc0e4, 0x6022, 0xa006, 0x00a0, 0x2001, + 0xb7b8, 0x200c, 0x8103, 0xa100, 0x603e, 0x6018, 0xa088, 0x002b, + 0x2104, 0xa005, 0x0118, 0xa088, 0x0003, 0x0cd0, 0x2c0a, 0x600f, + 0x0000, 0xa085, 0x0001, 0x0005, 0x0016, 0x00c6, 0x00e6, 0x6150, + 0xa2f0, 0x002b, 0x2e04, 0x2060, 0x8cff, 0x0180, 0x84ff, 0x1118, + 0x6050, 0xa106, 0x1138, 0x600c, 0x2072, 0x080c, 0x6aef, 0x080c, + 0x861d, 0x0010, 0xacf0, 0x0003, 0x2e64, 0x0c70, 0x00ee, 0x00ce, + 0x001e, 0x0005, 0x00d6, 0x6018, 0xa0e8, 0x002b, 0x2d04, 0xa005, + 0x0140, 0xac06, 0x0120, 0x2d04, 0xa0e8, 0x0003, 0x0cb8, 0x600c, + 0x206a, 0x00de, 0x0005, 0x0026, 0x0036, 0x0156, 0x2011, 0xb528, + 0x2204, 0xa084, 0x00ff, 0x2019, 0xbb8e, 0x2334, 0xa636, 0x11d8, + 0x8318, 0x2334, 0x2204, 0xa084, 0xff00, 0xa636, 0x11a0, 0x2011, + 0xbb90, 0x6018, 0xa098, 0x000a, 0x20a9, 0x0004, 0x080c, 0x90da, + 0x1150, 0x2011, 0xbb94, 0x6018, 0xa098, 0x0006, 0x20a9, 0x0004, + 0x080c, 0x90da, 0x1100, 0x015e, 0x003e, 0x002e, 0x0005, 0x00e6, + 0x2071, 0xb500, 0x080c, 0x4bc6, 0x080c, 0x2ab8, 0x00ee, 0x0005, + 0x00e6, 0x6018, 0x2070, 0x7000, 0xd0fc, 0x0108, 0x0011, 0x00ee, + 0x0005, 0x6850, 0xc0e5, 0x6852, 0x0005, 0x00e6, 0x00c6, 0x0076, + 0x0066, 0x0056, 0x0046, 0x0026, 0x0016, 0x0126, 0x2091, 0x8000, + 0x2029, 0xb7e9, 0x252c, 0x2021, 0xb7ef, 0x2424, 0x2061, 0xbd00, + 0x2071, 0xb500, 0x7648, 0x7068, 0xa606, 0x0578, 0x671c, 0xa786, + 0x0001, 0x0118, 0xa786, 0x0008, 0x1500, 0x2500, 0xac06, 0x01e8, + 0x2400, 0xac06, 0x01d0, 0x080c, 0xb110, 0x01b8, 0x080c, 0xb120, + 0x11a0, 0x6000, 0xa086, 0x0004, 0x1120, 0x0016, 0x080c, 0x194d, + 0x001e, 0x080c, 0x9e47, 0x1110, 0x080c, 0x2cc2, 0x080c, 0x9e58, + 0x1110, 0x080c, 0x8c19, 0x080c, 0x9e1d, 0xace0, 0x0018, 0x2001, + 0xb517, 0x2004, 0xac02, 0x1208, 0x0858, 0x012e, 0x001e, 0x002e, + 0x004e, 0x005e, 0x006e, 0x007e, 0x00ce, 0x00ee, 0x0005, 0x0126, + 0x0006, 0x00e6, 0x0016, 0x2091, 0x8000, 0x2071, 0xb540, 0xd5a4, + 0x0118, 0x7034, 0x8000, 0x7036, 0xd5b4, 0x0118, 0x7030, 0x8000, + 0x7032, 0xd5ac, 0x0178, 0x2500, 0xa084, 0x0007, 0xa08e, 0x0003, + 0x0148, 0xa08e, 0x0004, 0x0130, 0xa08e, 0x0005, 0x0118, 0x2071, + 0xb54a, 0x04c9, 0x001e, 0x00ee, 0x000e, 0x012e, 0x0005, 0x0126, + 0x0006, 0x00e6, 0x0016, 0x2091, 0x8000, 0x2071, 0xb540, 0xd5a4, + 0x0118, 0x7034, 0x8000, 0x7036, 0xd5b4, 0x0118, 0x7030, 0x8000, + 0x7032, 0xd5ac, 0x0178, 0x2500, 0xa084, 0x0007, 0xa08e, 0x0003, + 0x0148, 0xa08e, 0x0004, 0x0130, 0xa08e, 0x0005, 0x0118, 0x2071, + 0xb54a, 0x0089, 0x001e, 0x00ee, 0x000e, 0x012e, 0x0005, 0x0126, + 0x0006, 0x00e6, 0x2091, 0x8000, 0x2071, 0xb542, 0x0021, 0x00ee, + 0x000e, 0x012e, 0x0005, 0x2e04, 0x8000, 0x2072, 0x1220, 0x8e70, + 0x2e04, 0x8000, 0x2072, 0x0005, 0x00e6, 0x2071, 0xb540, 0x0c99, + 0x00ee, 0x0005, 0x00e6, 0x2071, 0xb544, 0x0c69, 0x00ee, 0x0005, + 0x0126, 0x0006, 0x00e6, 0x2091, 0x8000, 0x2071, 0xb540, 0x7044, + 0x8000, 0x7046, 0x00ee, 0x000e, 0x012e, 0x0005, 0x0001, 0x0002, + 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200, + 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000, 0x2440 +}; +#ifdef UNIQUE_FW_NAME +unsigned short fw2200tp_length01 = 0xa46f; +#else +unsigned short risc_code_length01 = 0xa46f; +#endif + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/ql2300.c 830-ivtv/drivers/scsi/qla2xxx/ql2300.c --- 000-virgin/drivers/scsi/qla2xxx/ql2300.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/ql2300.c Thu Jan 8 10:22:00 2004 @@ -0,0 +1,161 @@ +/* + * QLogic ISP23XX device driver for Linux 2.6.x + * Copyright (C) 2003 Christoph Hellwig. + * Copyright (C) 2003 QLogic Corporation (www.qlogic.com) + * + * Released under GPL v2. + */ + +#include +#include +#include + +#include "qla_os.h" +#include "qla_def.h" + +static char qla_driver_name[] = "qla2300"; + +extern unsigned char fw2300tpx_version[]; +extern unsigned char fw2300tpx_version_str[]; +extern unsigned short fw2300tpx_addr01; +extern unsigned short fw2300tpx_code01[]; +extern unsigned short fw2300tpx_length01; + +extern unsigned char fw2322tpx_version[]; +extern unsigned char fw2322tpx_version_str[]; +extern unsigned short fw2322tpx_addr01; +extern unsigned short fw2322tpx_code01[]; +extern unsigned short fw2322tpx_length01; +extern unsigned long rseqtpx_code_addr01; +extern unsigned short rseqtpx_code01[]; +extern unsigned short rseqtpx_code_length01; +extern unsigned long xseqtpx_code_addr01; +extern unsigned short xseqtpx_code01[]; +extern unsigned short xseqtpx_code_length01; + +static struct qla_fw_info qla_fw_tbl[] = { + { + .addressing = FW_INFO_ADDR_NORMAL, + .fwcode = &fw2300tpx_code01[0], + .fwlen = &fw2300tpx_length01, + .fwstart = &fw2300tpx_addr01, + }, +#if defined(ISP2322) + /* End of 23xx firmware list */ + { FW_INFO_ADDR_NOMORE, }, + + /* Start of 232x firmware list */ + { + .addressing = FW_INFO_ADDR_NORMAL, + .fwcode = &fw2322tpx_code01[0], + .fwlen = &fw2322tpx_length01, + .fwstart = &fw2322tpx_addr01, + }, + { + .addressing = FW_INFO_ADDR_EXTENDED, + .fwcode = &rseqtpx_code01[0], + .fwlen = &rseqtpx_code_length01, + .lfwstart = &rseqtpx_code_addr01, + }, + { + .addressing = FW_INFO_ADDR_EXTENDED, + .fwcode = &xseqtpx_code01[0], + .fwlen = &xseqtpx_code_length01, + .lfwstart = &xseqtpx_code_addr01, + }, +#endif + { FW_INFO_ADDR_NOMORE, }, +}; + +static struct qla_board_info qla_board_tbl[] = { + { + .drv_name = qla_driver_name, + + .isp_name = "ISP2300", + .fw_info = qla_fw_tbl, + }, + + { + .drv_name = qla_driver_name, + + .isp_name = "ISP2312", + .fw_info = qla_fw_tbl, + }, +#if defined(ISP2322) + { + .drv_name = qla_driver_name, + + .isp_name = "ISP2322", + .fw_info = &qla_fw_tbl[2], + }, +#endif +}; + +static struct pci_device_id qla2300_pci_tbl[] = { + { + .vendor = PCI_VENDOR_ID_QLOGIC, + .device = PCI_DEVICE_ID_QLOGIC_ISP2300, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (unsigned long)&qla_board_tbl[0], + }, + + { + .vendor = PCI_VENDOR_ID_QLOGIC, + .device = PCI_DEVICE_ID_QLOGIC_ISP2312, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (unsigned long)&qla_board_tbl[1], + }, + +#if defined(ISP2322) + { + .vendor = PCI_VENDOR_ID_QLOGIC, + .device = PCI_DEVICE_ID_QLOGIC_ISP2322, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (unsigned long)&qla_board_tbl[2], + }, +#endif + {0, 0}, +}; +MODULE_DEVICE_TABLE(pci, qla2300_pci_tbl); + +static int __devinit +qla2300_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) +{ + return qla2x00_probe_one(pdev, + (struct qla_board_info *)id->driver_data); +} + +static void __devexit +qla2300_remove_one(struct pci_dev *pdev) +{ + qla2x00_remove_one(pdev); +} + +static struct pci_driver qla2300_pci_driver = { + .name = "qla2300", + .id_table = qla2300_pci_tbl, + .probe = qla2300_probe_one, + .remove = __devexit_p(qla2300_remove_one), +}; + +static int __init +qla2300_init(void) +{ + return pci_module_init(&qla2300_pci_driver); +} + +static void __exit +qla2300_exit(void) +{ + pci_unregister_driver(&qla2300_pci_driver); +} + +module_init(qla2300_init); +module_exit(qla2300_exit); + +MODULE_AUTHOR("QLogic Corporation"); +MODULE_DESCRIPTION("QLogic ISP23xx FC-SCSI Host Bus Adapter driver"); +MODULE_LICENSE("GPL"); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/ql2300_fw.c 830-ivtv/drivers/scsi/qla2xxx/ql2300_fw.c --- 000-virgin/drivers/scsi/qla2xxx/ql2300_fw.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/ql2300_fw.c Thu Jan 8 10:22:00 2004 @@ -0,0 +1,6695 @@ +/************************************************************************** + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + *************************************************************************/ + +/* + * Firmware Version 3.02.18 (10:33 Nov 03, 2003) + */ + +#ifdef UNIQUE_FW_NAME +unsigned short fw2300tpx_version = 3*1024+2; +#else +unsigned short risc_code_version = 3*1024+2; +#endif + +#ifdef UNIQUE_FW_NAME +unsigned char fw2300tpx_version_str[] = {3, 2,18}; +#else +unsigned char firmware_version[] = {3, 2,18}; +#endif + +#ifdef UNIQUE_FW_NAME +#define fw2300tpx_VERSION_STRING "3.02.18" +#else +#define FW_VERSION_STRING "3.02.18" +#endif + +#ifdef UNIQUE_FW_NAME +unsigned short fw2300tpx_addr01 = 0x0800 ; +#else +unsigned short risc_code_addr01 = 0x0800 ; +#endif + +#ifdef UNIQUE_FW_NAME +unsigned short fw2300tpx_code01[] = { +#else +unsigned short risc_code01[] = { +#endif + 0x0470, 0x0000, 0x0000, 0xcf5b, 0x0000, 0x0003, 0x0002, 0x0012, + 0x0117, 0x2043, 0x4f50, 0x5952, 0x4947, 0x4854, 0x2032, 0x3030, + 0x3120, 0x514c, 0x4f47, 0x4943, 0x2043, 0x4f52, 0x504f, 0x5241, + 0x5449, 0x4f4e, 0x2049, 0x5350, 0x3233, 0x3030, 0x2046, 0x6972, + 0x6d77, 0x6172, 0x6520, 0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030, + 0x332e, 0x3032, 0x2e31, 0x3820, 0x2020, 0x2020, 0x2400, 0x20a9, + 0x000f, 0x2001, 0x0000, 0x400f, 0x2091, 0x2200, 0x20a9, 0x000f, + 0x2001, 0x0000, 0x400f, 0x2091, 0x2400, 0x20a9, 0x000f, 0x2001, + 0x0000, 0x400f, 0x2091, 0x2600, 0x20a9, 0x000f, 0x2001, 0x0000, + 0x400f, 0x2091, 0x2800, 0x20a9, 0x000f, 0x2001, 0x0000, 0x400f, + 0x2091, 0x2a00, 0x20a9, 0x000f, 0x2001, 0x0000, 0x400f, 0x2091, + 0x2c00, 0x20a9, 0x000f, 0x2001, 0x0000, 0x400f, 0x2091, 0x2e00, + 0x20a9, 0x000f, 0x2001, 0x0000, 0x400f, 0x2091, 0x2000, 0x2001, + 0x0000, 0x20c1, 0x0004, 0x2001, 0x017f, 0x2003, 0x0000, 0x20c9, + 0x1bff, 0x2059, 0x0000, 0x2b78, 0x7883, 0x0004, 0x2089, 0x29be, + 0x2051, 0x1800, 0x2a70, 0x20e1, 0x0001, 0x20e9, 0x0001, 0x2029, + 0x4d00, 0x2031, 0xffff, 0x2039, 0x4cd0, 0x2021, 0x0200, 0x20e9, + 0x0001, 0x20a1, 0x0000, 0x20a9, 0x0800, 0x900e, 0x4104, 0x20e9, + 0x0001, 0x20a1, 0x1000, 0x900e, 0x2001, 0x0cc0, 0x9084, 0x0fff, + 0x20a8, 0x4104, 0x2001, 0x0000, 0x9086, 0x0000, 0x0120, 0x21a8, + 0x4104, 0x8001, 0x1de0, 0x7566, 0x766a, 0x7762, 0x746e, 0x7472, + 0x00e6, 0x2071, 0x1a8b, 0x2472, 0x00ee, 0x20a1, 0x1cd0, 0x7168, + 0x810d, 0x810d, 0x810d, 0x810d, 0x918c, 0x000f, 0x2001, 0x0001, + 0x9112, 0x900e, 0x21a8, 0x4104, 0x8211, 0x1de0, 0x7168, 0x3400, + 0x8001, 0x9102, 0x0120, 0x0218, 0x20a8, 0x900e, 0x4104, 0x2009, + 0x1800, 0x810d, 0x810d, 0x810d, 0x810d, 0x810d, 0x918c, 0x001f, + 0x2001, 0x0001, 0x9112, 0x20e9, 0x0001, 0x20a1, 0x0800, 0x900e, + 0x20a9, 0x0800, 0x4104, 0x8211, 0x1dd8, 0x080c, 0x0eed, 0x080c, + 0x5a2f, 0x080c, 0x996c, 0x080c, 0x10a4, 0x080c, 0x127c, 0x080c, + 0x196d, 0x080c, 0x0d4b, 0x080c, 0x1029, 0x080c, 0x3092, 0x080c, + 0x6f3e, 0x080c, 0x62c8, 0x080c, 0x7b85, 0x080c, 0x217b, 0x080c, + 0x7eaf, 0x080c, 0x757c, 0x080c, 0x1fb8, 0x080c, 0x20ec, 0x080c, + 0x2170, 0x2091, 0x3009, 0x7883, 0x0000, 0x1004, 0x091d, 0x7880, + 0x9086, 0x0002, 0x1190, 0x7883, 0x4000, 0x7837, 0x4000, 0x7833, + 0x0010, 0x0e04, 0x0911, 0x2091, 0x5000, 0x2091, 0x4080, 0x2001, + 0x0089, 0x2004, 0xd084, 0x190c, 0x1167, 0x2071, 0x1800, 0x7003, + 0x0000, 0x2071, 0x1800, 0x7000, 0x908e, 0x0003, 0x1168, 0x080c, + 0x4737, 0x080c, 0x30b9, 0x080c, 0x6faf, 0x080c, 0x6787, 0x080c, + 0x7bae, 0x080c, 0x292b, 0x0c68, 0x000b, 0x0c88, 0x0940, 0x0941, + 0x0ad4, 0x093e, 0x0b94, 0x0d4a, 0x0d4a, 0x0d4a, 0x080c, 0x0db2, + 0x0005, 0x0126, 0x00f6, 0x2091, 0x8000, 0x7000, 0x9086, 0x0001, + 0x1904, 0x0aa7, 0x080c, 0x0e5a, 0x080c, 0x6c53, 0x0150, 0x080c, + 0x6c76, 0x1590, 0x2079, 0x0100, 0x7828, 0x9085, 0x1800, 0x782a, + 0x0458, 0x080c, 0x6b8a, 0x7000, 0x9086, 0x0001, 0x1904, 0x0aa7, + 0x7090, 0x9086, 0x0028, 0x1904, 0x0aa7, 0x080c, 0x7b7c, 0x2001, + 0x0161, 0x2003, 0x0001, 0x2079, 0x0100, 0x7827, 0xffff, 0x7a28, + 0x9295, 0x5e2f, 0x7a2a, 0x2011, 0x6ad9, 0x080c, 0x7c4a, 0x2011, + 0x6acc, 0x080c, 0x7d1b, 0x2011, 0x588a, 0x080c, 0x7c4a, 0x2011, + 0x8030, 0x901e, 0x738e, 0x04a0, 0x080c, 0x5137, 0x2079, 0x0100, + 0x7844, 0x9005, 0x1904, 0x0aa7, 0x2011, 0x588a, 0x080c, 0x7c4a, + 0x2011, 0x6ad9, 0x080c, 0x7c4a, 0x2011, 0x6acc, 0x080c, 0x7d1b, + 0x2001, 0x0265, 0x2001, 0x0205, 0x2003, 0x0000, 0x7840, 0x9084, + 0xfffb, 0x7842, 0x2001, 0x1975, 0x2004, 0x9005, 0x1140, 0x00c6, + 0x2061, 0x0100, 0x080c, 0x59d7, 0x00ce, 0x0804, 0x0aa7, 0x780f, + 0x006b, 0x7a28, 0x9295, 0x5e2f, 0x7a2a, 0x2011, 0x8010, 0x73d0, + 0x2001, 0x1976, 0x2003, 0x0001, 0x080c, 0x27f1, 0x080c, 0x4672, + 0x7240, 0xc284, 0x7242, 0x2001, 0x180c, 0x200c, 0xc1ac, 0xc1cc, + 0x2102, 0x080c, 0x91bb, 0x2011, 0x0004, 0x080c, 0xb60b, 0x080c, + 0x61a1, 0x080c, 0x6c53, 0x1120, 0x080c, 0x2835, 0x02e0, 0x0400, + 0x080c, 0x59de, 0x0140, 0x708f, 0x0001, 0x70cb, 0x0000, 0x080c, + 0x5304, 0x0804, 0x0aa7, 0x080c, 0x5113, 0xd094, 0x0188, 0x2011, + 0x180c, 0x2204, 0xc0cd, 0x2012, 0x080c, 0x5117, 0xd0d4, 0x1118, + 0x080c, 0x2835, 0x1270, 0x2011, 0x180c, 0x2204, 0xc0bc, 0x00a8, + 0x080c, 0x5117, 0xd0d4, 0x1db8, 0x2011, 0x180c, 0x2204, 0xc0bd, + 0x0060, 0x2011, 0x180c, 0x2204, 0xc0bd, 0x2012, 0x080c, 0x629c, + 0x1128, 0xd0a4, 0x0118, 0x2204, 0xc0fd, 0x2012, 0x080c, 0x6262, + 0x0120, 0x7a0c, 0xc2b4, 0x7a0e, 0x00a8, 0x7077, 0x0000, 0x080c, + 0x6c53, 0x1130, 0x70a8, 0x9005, 0x1168, 0x080c, 0xba40, 0x0050, + 0x080c, 0xba40, 0x70d4, 0xd09c, 0x1128, 0x70a8, 0x9005, 0x0110, + 0x080c, 0x59b4, 0x70df, 0x0000, 0x70db, 0x0000, 0x709f, 0x0000, + 0x080c, 0x283d, 0x0228, 0x2011, 0x0101, 0x2204, 0xc0c4, 0x2012, + 0x72d4, 0x080c, 0x6c53, 0x1178, 0x9016, 0x0016, 0x080c, 0x25ee, + 0x2019, 0x193e, 0x211a, 0x001e, 0x7057, 0xffff, 0x705b, 0x00ef, + 0x707b, 0x0000, 0x0020, 0x2019, 0x193e, 0x201b, 0x0000, 0x2079, + 0x1853, 0x7804, 0xd0ac, 0x0108, 0xc295, 0x72d6, 0x080c, 0x6c53, + 0x0118, 0x9296, 0x0004, 0x0548, 0x2011, 0x0001, 0x080c, 0xb60b, + 0x70a3, 0x0000, 0x70a7, 0xffff, 0x7003, 0x0002, 0x2079, 0x0100, + 0x7827, 0x0003, 0x7828, 0x9085, 0x0003, 0x782a, 0x00fe, 0x080c, + 0x2c2b, 0x2011, 0x0005, 0x080c, 0x92ec, 0x080c, 0x8582, 0x080c, + 0x6c53, 0x0148, 0x00c6, 0x2061, 0x0100, 0x0016, 0x080c, 0x25ee, + 0x61e2, 0x001e, 0x00ce, 0x012e, 0x0420, 0x70a3, 0x0000, 0x70a7, + 0xffff, 0x7003, 0x0002, 0x00f6, 0x2079, 0x0100, 0x7827, 0x0003, + 0x7828, 0x9085, 0x0003, 0x782a, 0x00fe, 0x2011, 0x0005, 0x080c, + 0x92ec, 0x080c, 0x8582, 0x080c, 0x6c53, 0x0148, 0x00c6, 0x2061, + 0x0100, 0x0016, 0x080c, 0x25ee, 0x61e2, 0x001e, 0x00ce, 0x00fe, + 0x012e, 0x0005, 0x00c6, 0x00b6, 0x080c, 0x6c53, 0x1118, 0x20a9, + 0x0800, 0x0010, 0x20a9, 0x0782, 0x080c, 0x6c53, 0x1110, 0x900e, + 0x0010, 0x2009, 0x007e, 0x86ff, 0x0138, 0x9180, 0x1000, 0x2004, + 0x905d, 0x0110, 0xb800, 0xd0bc, 0x090c, 0x2f28, 0x8108, 0x1f04, + 0x0abb, 0x7077, 0x0000, 0x7078, 0x9084, 0x00ff, 0x707a, 0x70ab, + 0x0000, 0x00be, 0x00ce, 0x0005, 0x00b6, 0x0126, 0x2091, 0x8000, + 0x7000, 0x9086, 0x0002, 0x1904, 0x0b91, 0x70a4, 0x9086, 0xffff, + 0x0130, 0x080c, 0x2c2b, 0x080c, 0x8582, 0x0804, 0x0b91, 0x70d4, + 0xd0ac, 0x1110, 0xd09c, 0x0558, 0xd084, 0x0548, 0x0006, 0x2001, + 0x0103, 0x2003, 0x002b, 0x000e, 0xd08c, 0x0508, 0x080c, 0x2f8b, + 0x11d0, 0x70d8, 0x9086, 0xffff, 0x01b0, 0x080c, 0x2d9c, 0x080c, + 0x8582, 0x70d4, 0xd094, 0x1904, 0x0b91, 0x2011, 0x0001, 0x080c, + 0xbcec, 0x0110, 0x2011, 0x0003, 0x901e, 0x080c, 0x2dd6, 0x080c, + 0x8582, 0x0804, 0x0b91, 0x70dc, 0x9005, 0x1904, 0x0b91, 0x70a0, + 0x9005, 0x1904, 0x0b91, 0x70d4, 0xd0a4, 0x0118, 0xd0b4, 0x0904, + 0x0b91, 0x080c, 0x6262, 0x1904, 0x0b91, 0x080c, 0x62b5, 0x1904, + 0x0b91, 0x080c, 0x629c, 0x01c0, 0x0156, 0x00c6, 0x20a9, 0x007f, + 0x900e, 0x0016, 0x080c, 0x5f7e, 0x1118, 0xb800, 0xd0ec, 0x1138, + 0x001e, 0x8108, 0x1f04, 0x0b31, 0x00ce, 0x015e, 0x0028, 0x001e, + 0x00ce, 0x015e, 0x0804, 0x0b91, 0x0006, 0x2001, 0x0103, 0x2003, + 0x006b, 0x000e, 0x2011, 0x1982, 0x080c, 0x0f5d, 0x2011, 0x199c, + 0x080c, 0x0f5d, 0x7030, 0xc08c, 0x7032, 0x7003, 0x0003, 0x70a7, + 0xffff, 0x080c, 0x0e3c, 0x9006, 0x080c, 0x247f, 0x080c, 0x2f8b, + 0x0118, 0x080c, 0x480f, 0x0050, 0x0036, 0x0046, 0x2019, 0xffff, + 0x2021, 0x0006, 0x080c, 0x4829, 0x004e, 0x003e, 0x00f6, 0x2079, + 0x0100, 0x080c, 0x6c76, 0x0150, 0x080c, 0x6c53, 0x7828, 0x0118, + 0x9084, 0xe1ff, 0x0010, 0x9084, 0xffdf, 0x782a, 0x00fe, 0x2001, + 0x19b7, 0x2004, 0x9086, 0x0005, 0x1120, 0x2011, 0x0000, 0x080c, + 0x92ec, 0x2011, 0x0000, 0x080c, 0x92f6, 0x080c, 0x8582, 0x080c, + 0x865d, 0x012e, 0x00be, 0x0005, 0x0016, 0x0046, 0x00f6, 0x0126, + 0x2091, 0x8000, 0x2079, 0x0100, 0x7904, 0x918c, 0xfffd, 0x7906, + 0x2009, 0x00f7, 0x080c, 0x599d, 0x7940, 0x918c, 0x0010, 0x7942, + 0x7924, 0xd1b4, 0x0110, 0x7827, 0x0040, 0xd19c, 0x0110, 0x7827, + 0x0008, 0x0006, 0x0036, 0x0156, 0x7954, 0xd1ac, 0x1904, 0x0c21, + 0x2001, 0x1976, 0x2004, 0x9005, 0x1518, 0x080c, 0x28b8, 0x1148, + 0x2001, 0x0001, 0x080c, 0x2820, 0x2001, 0x0001, 0x080c, 0x2803, + 0x00b8, 0x080c, 0x28c0, 0x1138, 0x9006, 0x080c, 0x2820, 0x9006, + 0x080c, 0x2803, 0x0068, 0x080c, 0x28c8, 0x1d50, 0x2001, 0x1967, + 0x2004, 0xd0fc, 0x0108, 0x0020, 0x080c, 0x261a, 0x0804, 0x0d01, + 0x080c, 0x6c64, 0x0148, 0x080c, 0x6c76, 0x1118, 0x080c, 0x6f39, + 0x0050, 0x080c, 0x6c5b, 0x0dd0, 0x080c, 0x6f34, 0x080c, 0x6f2a, + 0x080c, 0x6b8a, 0x0058, 0x080c, 0x6c53, 0x0140, 0x2009, 0x00f8, + 0x080c, 0x599d, 0x7843, 0x0090, 0x7843, 0x0010, 0x20a9, 0x09c4, + 0x7820, 0xd09c, 0x1138, 0x080c, 0x6c53, 0x0138, 0x7824, 0xd0ac, + 0x1904, 0x0d06, 0x1f04, 0x0c00, 0x0070, 0x7824, 0x080c, 0x6c6d, + 0x0118, 0xd0ac, 0x1904, 0x0d06, 0x9084, 0x1800, 0x0d98, 0x7003, + 0x0001, 0x0804, 0x0d06, 0x2001, 0x0001, 0x080c, 0x247f, 0x0804, + 0x0d19, 0x2001, 0x1976, 0x2004, 0x9005, 0x1518, 0x080c, 0x28b8, + 0x1148, 0x2001, 0x0001, 0x080c, 0x2820, 0x2001, 0x0001, 0x080c, + 0x2803, 0x00b8, 0x080c, 0x28c0, 0x1138, 0x9006, 0x080c, 0x2820, + 0x9006, 0x080c, 0x2803, 0x0068, 0x080c, 0x28c8, 0x1d50, 0x2001, + 0x1967, 0x2004, 0xd0fc, 0x0108, 0x0020, 0x080c, 0x261a, 0x0804, + 0x0d01, 0x7850, 0x9085, 0x0040, 0x7852, 0x7938, 0x7850, 0x9084, + 0xfbcf, 0x7852, 0x080c, 0x28d0, 0x9085, 0x2000, 0x7852, 0x793a, + 0x20a9, 0x0046, 0x1d04, 0x0c5a, 0x080c, 0x7cfb, 0x1f04, 0x0c5a, + 0x7850, 0x9085, 0x0400, 0x9084, 0xdfbf, 0x7852, 0x793a, 0x080c, + 0x6c64, 0x0148, 0x080c, 0x6c76, 0x1118, 0x080c, 0x6f39, 0x0050, + 0x080c, 0x6c5b, 0x0dd0, 0x080c, 0x6f34, 0x080c, 0x6f2a, 0x080c, + 0x6b8a, 0x0020, 0x2009, 0x00f8, 0x080c, 0x599d, 0x20a9, 0x0028, + 0xa001, 0x1f04, 0x0c80, 0x7850, 0x9085, 0x1400, 0x7852, 0x080c, + 0x6c53, 0x0120, 0x7843, 0x0090, 0x7843, 0x0010, 0x2021, 0xe678, + 0x2019, 0xea60, 0x0d0c, 0x7cfb, 0x7820, 0xd09c, 0x1588, 0x080c, + 0x6c53, 0x0904, 0x0ce6, 0x7824, 0xd0ac, 0x1904, 0x0d06, 0x080c, + 0x6c76, 0x1530, 0x0046, 0x2021, 0x0320, 0x8421, 0x1df0, 0x004e, + 0x7827, 0x1800, 0x080c, 0x28d0, 0x7824, 0x9084, 0x1800, 0x1168, + 0x9484, 0x0fff, 0x1140, 0x2001, 0x180f, 0x2004, 0x9084, 0x9000, + 0x0110, 0x080c, 0x0d27, 0x8421, 0x1158, 0x1d04, 0x0cc1, 0x080c, + 0x7cfb, 0x080c, 0x6f34, 0x080c, 0x6f2a, 0x7003, 0x0001, 0x04f0, + 0x8319, 0x1940, 0x1d04, 0x0cce, 0x080c, 0x7cfb, 0x2009, 0x196a, + 0x2104, 0x9005, 0x0118, 0x8001, 0x200a, 0x1178, 0x200b, 0x000a, + 0x7827, 0x0048, 0x20a9, 0x0002, 0x080c, 0x28b1, 0x7924, 0x080c, + 0x28d0, 0xd19c, 0x0110, 0x080c, 0x27f1, 0x00d8, 0x080c, 0x6c64, + 0x1140, 0x94a2, 0x03e8, 0x1128, 0x080c, 0x6c2d, 0x7003, 0x0001, + 0x00a8, 0x7827, 0x1800, 0x080c, 0x28d0, 0x7824, 0x080c, 0x6c6d, + 0x0110, 0xd0ac, 0x1158, 0x9084, 0x1800, 0x0950, 0x7003, 0x0001, + 0x0028, 0x2001, 0x0001, 0x080c, 0x247f, 0x0078, 0x2009, 0x180c, + 0x210c, 0xd19c, 0x1120, 0x7904, 0x918d, 0x0002, 0x7906, 0x7827, + 0x0048, 0x7828, 0x9085, 0x0028, 0x782a, 0x7850, 0x9085, 0x0400, + 0x7852, 0x2001, 0x1976, 0x2003, 0x0000, 0x9006, 0x78f2, 0x015e, + 0x003e, 0x000e, 0x012e, 0x00fe, 0x004e, 0x001e, 0x0005, 0x0006, + 0x0016, 0x0036, 0x0046, 0x00b6, 0x00c6, 0x00d6, 0x00e6, 0x00f6, + 0x0156, 0x0069, 0x0d0c, 0x7cfb, 0x015e, 0x00fe, 0x00ee, 0x00de, + 0x00ce, 0x00be, 0x004e, 0x003e, 0x001e, 0x000e, 0x0005, 0x00e6, + 0x2071, 0x1894, 0x7004, 0x9086, 0x0001, 0x1110, 0x080c, 0x30b9, + 0x00ee, 0x0005, 0x0005, 0x2a70, 0x2061, 0x197a, 0x2063, 0x0003, + 0x6007, 0x0002, 0x600b, 0x0012, 0x600f, 0x0117, 0x2001, 0x194d, + 0x900e, 0x2102, 0x718e, 0x2001, 0x0100, 0x2004, 0x9082, 0x0002, + 0x0218, 0x7057, 0xffff, 0x0008, 0x7156, 0x705f, 0xffff, 0x7176, + 0x717a, 0x080c, 0xba40, 0x70e3, 0x00c0, 0x2061, 0x193d, 0x6003, + 0x0909, 0x6106, 0x600b, 0x8800, 0x600f, 0x0200, 0x6013, 0x00ff, + 0x6017, 0x000f, 0x611a, 0x601f, 0x07d0, 0x2061, 0x1945, 0x6003, + 0x8000, 0x6106, 0x610a, 0x600f, 0x0200, 0x6013, 0x00ff, 0x6116, + 0x601b, 0x0001, 0x611e, 0x2061, 0x1958, 0x6003, 0x514c, 0x6007, + 0x4f47, 0x600b, 0x4943, 0x600f, 0x2020, 0x2001, 0x182a, 0x2102, + 0x0005, 0x9016, 0x080c, 0x5f7e, 0x1178, 0xb804, 0x90c4, 0x00ff, + 0x98c6, 0x0006, 0x0128, 0x90c4, 0xff00, 0x98c6, 0x0600, 0x1120, + 0x9186, 0x0080, 0x0108, 0x8210, 0x8108, 0x9186, 0x0800, 0x1d50, + 0x2208, 0x0005, 0x2091, 0x8000, 0x0e04, 0x0db4, 0x0006, 0x0016, + 0x2001, 0x8002, 0x0006, 0x2079, 0x0000, 0x000e, 0x7882, 0x7836, + 0x001e, 0x798e, 0x000e, 0x788a, 0x000e, 0x7886, 0x3900, 0x789a, + 0x7833, 0x0012, 0x2091, 0x5000, 0x0156, 0x00d6, 0x0036, 0x0026, + 0x2079, 0x0300, 0x2069, 0x1a66, 0x7a18, 0x226a, 0x8d68, 0x7a1c, + 0x226a, 0x782c, 0x2019, 0x1a73, 0x201a, 0x2019, 0x1a76, 0x9016, + 0x7808, 0xd09c, 0x0168, 0x7820, 0x201a, 0x8210, 0x8318, 0x9386, + 0x1a8b, 0x0108, 0x0ca8, 0x7808, 0xd09c, 0x0110, 0x2011, 0xdead, + 0x2019, 0x1a74, 0x782c, 0x201a, 0x8318, 0x221a, 0x7803, 0x0000, + 0x2069, 0x1a46, 0x901e, 0x20a9, 0x0020, 0x7b26, 0x7a28, 0x226a, + 0x8d68, 0x8318, 0x1f04, 0x0dfd, 0x002e, 0x003e, 0x00de, 0x015e, + 0x2079, 0x1800, 0x7803, 0x0005, 0x2091, 0x4080, 0x2001, 0x0089, + 0x2004, 0xd084, 0x0180, 0x2001, 0x19e8, 0x2004, 0x9005, 0x0128, + 0x2001, 0x008b, 0x2004, 0xd0fc, 0x0dd8, 0x2001, 0x008a, 0x2003, + 0x0002, 0x2003, 0x1001, 0x080c, 0x5122, 0x1108, 0x0011, 0x0cd8, + 0x0005, 0x0026, 0x0126, 0x2011, 0x0080, 0x080c, 0x0eb4, 0x20a9, + 0x0900, 0x080c, 0x0ed5, 0x2011, 0x0040, 0x080c, 0x0eb4, 0x20a9, + 0x0900, 0x080c, 0x0ed5, 0x0c78, 0x0026, 0x080c, 0x0ec1, 0x1118, + 0x2011, 0x0040, 0x0098, 0x2011, 0x010e, 0x2214, 0x9294, 0x0007, + 0x9296, 0x0007, 0x0118, 0x2011, 0xa880, 0x0010, 0x2011, 0x6840, + 0xd0e4, 0x70e7, 0x0000, 0x1128, 0x70e7, 0x0fa0, 0x080c, 0x0ec6, + 0x002e, 0x0005, 0x0026, 0x080c, 0x0ec1, 0x0128, 0xd0a4, 0x1138, + 0x2011, 0xcdd5, 0x0010, 0x2011, 0x0080, 0x080c, 0x0ec6, 0x002e, + 0x0005, 0x0026, 0x70e7, 0x0000, 0x080c, 0x0ec1, 0x1148, 0x080c, + 0x28c8, 0x1118, 0x2011, 0x8484, 0x0058, 0x2011, 0x8282, 0x0040, + 0x080c, 0x28c8, 0x1118, 0x2011, 0xcdc5, 0x0010, 0x2011, 0xcac2, + 0x080c, 0x0ec6, 0x002e, 0x0005, 0x00e6, 0x0006, 0x2071, 0x1800, + 0xd0b4, 0x70e0, 0x1110, 0xc0e4, 0x0048, 0x0006, 0x3b00, 0x9084, + 0xff3f, 0x20d8, 0x000e, 0x70e7, 0x0000, 0xc0e5, 0x0079, 0x000e, + 0x00ee, 0x0005, 0x00e6, 0x2071, 0x1800, 0xd0e4, 0x70e0, 0x1110, + 0xc0dc, 0x0008, 0xc0dd, 0x0011, 0x00ee, 0x0005, 0x70e2, 0x7000, + 0x9084, 0x0007, 0x000b, 0x0005, 0x0e83, 0x0e5a, 0x0e5a, 0x0e3c, + 0x0e69, 0x0e5a, 0x0e5a, 0x0e69, 0x0016, 0x3b08, 0x3a00, 0x9104, + 0x918d, 0x00c0, 0x21d8, 0x9084, 0xff3f, 0x9205, 0x20d0, 0x001e, + 0x0005, 0x2001, 0x1838, 0x2004, 0xd0dc, 0x0005, 0x9e86, 0x1800, + 0x190c, 0x0db2, 0x70e0, 0xd0e4, 0x0108, 0xc2e5, 0x72e2, 0xd0e4, + 0x1118, 0x9294, 0x00c0, 0x0c01, 0x0005, 0x1d04, 0x0ed5, 0x2091, + 0x6000, 0x1f04, 0x0ed5, 0x0005, 0x890e, 0x810e, 0x810f, 0x9194, + 0x003f, 0x918c, 0xffc0, 0x0005, 0x0006, 0x2200, 0x914d, 0x894f, + 0x894d, 0x894d, 0x000e, 0x000e, 0x0005, 0x01d6, 0x0146, 0x0036, + 0x0096, 0x2061, 0x1883, 0x600b, 0x0000, 0x600f, 0x0000, 0x6003, + 0x0000, 0x6007, 0x0000, 0x2009, 0xffc0, 0x2105, 0x0006, 0x2001, + 0xaaaa, 0x200f, 0x2019, 0x5555, 0x9016, 0x2049, 0x0bff, 0xab02, + 0xa001, 0xa001, 0xa800, 0x9306, 0x1138, 0x2105, 0x9306, 0x0120, + 0x8210, 0x99c8, 0x0400, 0x0c98, 0x000e, 0x200f, 0x2001, 0x1893, + 0x928a, 0x000e, 0x1638, 0x928a, 0x0006, 0x2011, 0x0006, 0x1210, + 0x2011, 0x0000, 0x2202, 0x9006, 0x2008, 0x82ff, 0x01b0, 0x8200, + 0x600a, 0x600f, 0xffff, 0x6003, 0x0002, 0x6007, 0x0000, 0x0026, + 0x2019, 0x0010, 0x9280, 0x0001, 0x20e8, 0x21a0, 0x21a8, 0x4104, + 0x8319, 0x1de0, 0x8211, 0x1da0, 0x002e, 0x009e, 0x003e, 0x014e, + 0x01de, 0x0005, 0x2011, 0x000e, 0x08e8, 0x0016, 0x0026, 0x0096, + 0x3348, 0x080c, 0x0edc, 0x2100, 0x9300, 0x2098, 0x22e0, 0x009e, + 0x002e, 0x001e, 0x0036, 0x3518, 0x20a9, 0x0001, 0x4002, 0x8007, + 0x4004, 0x8319, 0x1dd8, 0x003e, 0x0005, 0x20e9, 0x0001, 0x71b0, + 0x81ff, 0x11c0, 0x9006, 0x2009, 0x0200, 0x20a9, 0x0002, 0x9298, + 0x0018, 0x23a0, 0x4001, 0x2009, 0x0700, 0x20a9, 0x0002, 0x9298, + 0x0008, 0x23a0, 0x4001, 0x7074, 0x8007, 0x7178, 0x810f, 0x20a9, + 0x0002, 0x4001, 0x9298, 0x000c, 0x23a0, 0x900e, 0x080c, 0x0d99, + 0x2001, 0x0000, 0x810f, 0x20a9, 0x0002, 0x4001, 0x0005, 0x89ff, + 0x0140, 0xa804, 0xa807, 0x0000, 0x0006, 0x080c, 0x1007, 0x009e, + 0x0cb0, 0x0005, 0x00e6, 0x2071, 0x1800, 0x080c, 0x1080, 0x090c, + 0x0db2, 0x00ee, 0x0005, 0x0086, 0x00e6, 0x0006, 0x0026, 0x0036, + 0x0126, 0x2091, 0x8000, 0x00c9, 0x2071, 0x1800, 0x73b8, 0x702c, + 0x9016, 0x9045, 0x0158, 0x8210, 0x9906, 0x090c, 0x0db2, 0x2300, + 0x9202, 0x0120, 0x1a0c, 0x0db2, 0xa000, 0x0c98, 0x012e, 0x003e, + 0x002e, 0x000e, 0x00ee, 0x008e, 0x0005, 0x0086, 0x00e6, 0x0006, + 0x0126, 0x2091, 0x8000, 0x2071, 0x1906, 0x7010, 0x9005, 0x0140, + 0x7018, 0x9045, 0x0128, 0x9906, 0x090c, 0x0db2, 0xa000, 0x0cc8, + 0x012e, 0x000e, 0x00ee, 0x008e, 0x0005, 0x00e6, 0x2071, 0x1800, + 0x0126, 0x2091, 0x8000, 0x70b8, 0x8001, 0x0270, 0x70ba, 0x702c, + 0x2048, 0x9085, 0x0001, 0xa800, 0x702e, 0xa803, 0x0000, 0xa807, + 0x0000, 0x012e, 0x00ee, 0x0005, 0x904e, 0x0cd8, 0x00e6, 0x0126, + 0x2091, 0x8000, 0x2071, 0x1800, 0x70b8, 0x90ca, 0x0040, 0x0268, + 0x8001, 0x70ba, 0x702c, 0x2048, 0xa800, 0x702e, 0xa803, 0x0000, + 0xa807, 0x0000, 0x012e, 0x00ee, 0x0005, 0x904e, 0x0cd8, 0x00e6, + 0x0126, 0x2091, 0x8000, 0x0016, 0x890e, 0x810e, 0x810f, 0x9184, + 0x003f, 0xa862, 0x9184, 0xffc0, 0xa85e, 0x001e, 0x0020, 0x00e6, + 0x0126, 0x2091, 0x8000, 0x2071, 0x1800, 0x702c, 0xa802, 0x2900, + 0x702e, 0x70b8, 0x8000, 0x70ba, 0x080c, 0x7b7c, 0x012e, 0x00ee, + 0x0005, 0x2071, 0x1800, 0x9026, 0x2009, 0x0000, 0x2049, 0x0400, + 0x2900, 0x702e, 0x8940, 0x2800, 0xa802, 0xa95e, 0xa863, 0x0001, + 0x8420, 0x9886, 0x0440, 0x0120, 0x2848, 0x9188, 0x0040, 0x0c90, + 0x2071, 0x1883, 0x7000, 0x9005, 0x11a0, 0x2001, 0x0534, 0xa802, + 0x2048, 0x2009, 0x4d00, 0x8940, 0x2800, 0xa802, 0xa95e, 0xa863, + 0x0001, 0x8420, 0x9886, 0x0800, 0x0120, 0x2848, 0x9188, 0x0040, + 0x0c90, 0x2071, 0x1883, 0x7104, 0x7200, 0x82ff, 0x01d0, 0x7308, + 0x8318, 0x831f, 0x831b, 0x831b, 0x7312, 0x8319, 0x2001, 0x0800, + 0xa802, 0x2048, 0x8900, 0xa802, 0x2040, 0xa95e, 0xaa62, 0x8420, + 0x2300, 0x9906, 0x0130, 0x2848, 0x9188, 0x0040, 0x9291, 0x0000, + 0x0c88, 0xa803, 0x0000, 0x2071, 0x1800, 0x74b6, 0x74ba, 0x0005, + 0x00e6, 0x0016, 0x9984, 0xfc00, 0x01e8, 0x908c, 0xf800, 0x1168, + 0x9982, 0x0400, 0x02b8, 0x9982, 0x0440, 0x0278, 0x9982, 0x0534, + 0x0288, 0x9982, 0x0800, 0x1270, 0x0040, 0x9982, 0x0800, 0x0250, + 0x2071, 0x1883, 0x7010, 0x9902, 0x1228, 0x9085, 0x0001, 0x001e, + 0x00ee, 0x0005, 0x9006, 0x0cd8, 0x00e6, 0x2071, 0x19e7, 0x7007, + 0x0000, 0x9006, 0x701e, 0x7022, 0x7002, 0x2071, 0x0000, 0x7010, + 0x9085, 0x8004, 0x7012, 0x00ee, 0x0005, 0x0126, 0x2091, 0x8000, + 0x00e6, 0xa06f, 0x0000, 0x2071, 0x19e7, 0x701c, 0x9088, 0x19f1, + 0x280a, 0x8000, 0x9084, 0x003f, 0x701e, 0x7120, 0x9106, 0x090c, + 0x0db2, 0x7004, 0x9005, 0x1128, 0x00f6, 0x2079, 0x0080, 0x00a9, + 0x00fe, 0x00ee, 0x012e, 0x0005, 0x0126, 0x2091, 0x8000, 0x00e6, + 0x2071, 0x19e7, 0x7004, 0x9005, 0x1128, 0x00f6, 0x2079, 0x0080, + 0x0021, 0x00fe, 0x00ee, 0x012e, 0x0005, 0x7004, 0x9086, 0x0000, + 0x1110, 0x7007, 0x0006, 0x7000, 0x0002, 0x10f7, 0x10f5, 0x10f5, + 0x10f5, 0x126b, 0x126b, 0x126b, 0x126b, 0x080c, 0x0db2, 0x701c, + 0x7120, 0x9106, 0x1148, 0x792c, 0x9184, 0x0001, 0x1120, 0xd1fc, + 0x1110, 0x7007, 0x0000, 0x0005, 0x0096, 0x9180, 0x19f1, 0x2004, + 0x700a, 0x2048, 0x8108, 0x918c, 0x003f, 0x7122, 0x782b, 0x0026, + 0xa88c, 0x7802, 0xa890, 0x7806, 0xa894, 0x780a, 0xa898, 0x780e, + 0xa878, 0x700e, 0xa870, 0x7016, 0xa874, 0x701a, 0xa868, 0x009e, + 0xd084, 0x0120, 0x7007, 0x0001, 0x0029, 0x0005, 0x7007, 0x0002, + 0x00b1, 0x0005, 0x0016, 0x0026, 0x710c, 0x2011, 0x0040, 0x9182, + 0x0040, 0x1210, 0x2110, 0x9006, 0x700e, 0x7212, 0x8203, 0x7812, + 0x782b, 0x0020, 0x782b, 0x0041, 0x002e, 0x001e, 0x0005, 0x0016, + 0x0026, 0x0136, 0x0146, 0x0156, 0x7014, 0x20e0, 0x7018, 0x2098, + 0x20e9, 0x0000, 0x20a1, 0x0088, 0x782b, 0x0026, 0x710c, 0x2011, + 0x0040, 0x9182, 0x0040, 0x1210, 0x2110, 0x9006, 0x700e, 0x22a8, + 0x4006, 0x8203, 0x7812, 0x782b, 0x0020, 0x3300, 0x701a, 0x782b, + 0x0001, 0x015e, 0x014e, 0x013e, 0x002e, 0x001e, 0x0005, 0x2009, + 0x19e7, 0x2104, 0xc095, 0x200a, 0x080c, 0x10d4, 0x0005, 0x0016, + 0x00e6, 0x2071, 0x19e7, 0x00f6, 0x2079, 0x0080, 0x792c, 0x782b, + 0x0002, 0xd1fc, 0x0120, 0x918c, 0x0700, 0x7004, 0x0023, 0x00fe, + 0x00ee, 0x001e, 0x0005, 0x10e5, 0x118a, 0x11be, 0x0db2, 0x0db2, + 0x1277, 0x0db2, 0x918c, 0x0700, 0x1550, 0x0136, 0x0146, 0x0156, + 0x7014, 0x20e8, 0x7018, 0x20a0, 0x20e1, 0x0000, 0x2099, 0x0088, + 0x782b, 0x0040, 0x7010, 0x20a8, 0x4005, 0x3400, 0x701a, 0x015e, + 0x014e, 0x013e, 0x700c, 0x9005, 0x0578, 0x7800, 0x7802, 0x7804, + 0x7806, 0x080c, 0x112a, 0x0005, 0x7008, 0x0096, 0x2048, 0xa86f, + 0x0100, 0x009e, 0x7007, 0x0000, 0x080c, 0x10e5, 0x0005, 0x7008, + 0x0096, 0x2048, 0xa86f, 0x0200, 0x009e, 0x0ca0, 0x918c, 0x0700, + 0x1150, 0x700c, 0x9005, 0x0180, 0x7800, 0x7802, 0x7804, 0x7806, + 0x080c, 0x113f, 0x0005, 0x7008, 0x0096, 0x2048, 0xa86f, 0x0200, + 0x009e, 0x7007, 0x0000, 0x0080, 0x0096, 0x7008, 0x2048, 0x7800, + 0xa88e, 0x7804, 0xa892, 0x7808, 0xa896, 0x780c, 0xa89a, 0xa86f, + 0x0100, 0x009e, 0x7007, 0x0000, 0x0096, 0x00d6, 0x7008, 0x2048, + 0x2001, 0x18af, 0x2004, 0x9906, 0x1128, 0xa89c, 0x080f, 0x00de, + 0x009e, 0x00a0, 0x00de, 0x009e, 0x0096, 0x00d6, 0x7008, 0x2048, + 0x0081, 0x0150, 0xa89c, 0x0086, 0x2940, 0x080f, 0x008e, 0x00de, + 0x009e, 0x080c, 0x10d4, 0x0005, 0x00de, 0x009e, 0x080c, 0x10d4, + 0x0005, 0xa8a8, 0xd08c, 0x0005, 0x0096, 0xa0a0, 0x904d, 0x090c, + 0x0db2, 0xa06c, 0x908e, 0x0100, 0x0130, 0xa87b, 0x0030, 0xa883, + 0x0000, 0xa897, 0x4002, 0x080c, 0x6529, 0xa09f, 0x0000, 0xa0a3, + 0x0000, 0x2848, 0x080c, 0x1007, 0x009e, 0x0005, 0x00a6, 0xa0a0, + 0x904d, 0x090c, 0x0db2, 0xa06c, 0x908e, 0x0100, 0x0128, 0xa87b, + 0x0001, 0xa883, 0x0000, 0x00c0, 0xa80c, 0x2050, 0xb004, 0x9005, + 0x0198, 0xa80e, 0x2050, 0x8006, 0x8006, 0x8007, 0x908c, 0x003f, + 0x9084, 0xffc0, 0x9080, 0x0002, 0xa076, 0xa172, 0xb000, 0xa07a, + 0x2810, 0x080c, 0x10b5, 0x00e8, 0xa97c, 0xa894, 0x0016, 0x0006, + 0x080c, 0x6529, 0x000e, 0x001e, 0xd1fc, 0x1138, 0xd1f4, 0x0128, + 0x00c6, 0x2060, 0x080c, 0x99d6, 0x00ce, 0x7008, 0x2048, 0xa89f, + 0x0000, 0xa8a3, 0x0000, 0x080c, 0x1007, 0x7007, 0x0000, 0x080c, + 0x10d4, 0x00ae, 0x0005, 0x0126, 0x2091, 0x8000, 0x782b, 0x1001, + 0x7007, 0x0005, 0x7000, 0xc094, 0x7002, 0x012e, 0x0005, 0x7007, + 0x0000, 0x080c, 0x10e5, 0x0005, 0x0126, 0x2091, 0x2200, 0x2079, + 0x0300, 0x2071, 0x1a31, 0x7003, 0x0000, 0x78bf, 0x00f6, 0x00c1, + 0x7803, 0x0003, 0x780f, 0x0000, 0x20a9, 0x01ed, 0x2061, 0xd372, + 0x2c0d, 0x7912, 0xe104, 0x9ce0, 0x0002, 0x7916, 0x1f04, 0x1290, + 0x7807, 0x0001, 0x7803, 0x0000, 0x7803, 0x0001, 0x012e, 0x0005, + 0x00c6, 0x7803, 0x0000, 0x7808, 0xd09c, 0x0110, 0x7820, 0x0cd8, + 0x2001, 0x1a32, 0x2003, 0x0000, 0x78ab, 0x0004, 0x78ac, 0xd0ac, + 0x1de8, 0x78ab, 0x0002, 0x7807, 0x0001, 0x7827, 0x0030, 0x782b, + 0x0400, 0x7827, 0x0031, 0x782b, 0x1a46, 0x781f, 0xff00, 0x781b, + 0xff00, 0x2001, 0x0200, 0x2004, 0xd0dc, 0x0110, 0x781f, 0x0303, + 0x2061, 0x1a46, 0x602f, 0x1cd0, 0x2001, 0x1818, 0x2004, 0x9082, + 0x1cd0, 0x6032, 0x603b, 0x1da2, 0x00ce, 0x0005, 0x0126, 0x2091, + 0x2200, 0x7808, 0xd09c, 0x0158, 0x7820, 0x908c, 0xf000, 0x1588, + 0x908a, 0x0021, 0x1a0c, 0x0db2, 0x0043, 0x012e, 0x0005, 0x9084, + 0x0070, 0x190c, 0x0db2, 0x012e, 0x0005, 0x130f, 0x130f, 0x1318, + 0x131d, 0x1321, 0x1326, 0x134e, 0x1352, 0x1360, 0x1364, 0x130f, + 0x13ee, 0x13f2, 0x1455, 0x130f, 0x130f, 0x130f, 0x130f, 0x130f, + 0x130f, 0x130f, 0x130f, 0x130f, 0x130f, 0x130f, 0x130f, 0x130f, + 0x1328, 0x130f, 0x130f, 0x130f, 0x130f, 0x130f, 0x130f, 0x080c, + 0x0db2, 0x2009, 0x0048, 0x2060, 0x080c, 0x9a50, 0x012e, 0x0005, + 0x7004, 0xc085, 0xc0b5, 0x7006, 0x0005, 0x7004, 0xc085, 0x7006, + 0x0005, 0x080c, 0x145c, 0x080c, 0x1518, 0x0005, 0x080c, 0x0db2, + 0x080c, 0x145c, 0x2060, 0x6014, 0x0096, 0x2048, 0xa83b, 0xffff, + 0x009e, 0x2009, 0x0048, 0x080c, 0x9a50, 0x2001, 0x015d, 0x2003, + 0x0000, 0x2009, 0x03e8, 0x8109, 0x0160, 0x2001, 0x0201, 0x2004, + 0x9005, 0x0dc8, 0x2001, 0x0218, 0x2004, 0xd0ec, 0x1110, 0x080c, + 0x1461, 0x2001, 0x0307, 0x2003, 0x8000, 0x0005, 0x7004, 0xc095, + 0x7006, 0x0005, 0x080c, 0x145c, 0x2060, 0x6014, 0x0096, 0x2048, + 0xa83b, 0xffff, 0x009e, 0x2009, 0x0048, 0x080c, 0x9a50, 0x0005, + 0x080c, 0x145c, 0x080c, 0x0db2, 0x080c, 0x145c, 0x080c, 0x13d9, + 0x7827, 0x0018, 0x79ac, 0xd1dc, 0x0540, 0x7827, 0x0015, 0x7828, + 0x782b, 0x0000, 0x9065, 0x0138, 0x2001, 0x020d, 0x2003, 0x0050, + 0x2003, 0x0020, 0x0400, 0x7004, 0x9005, 0x1180, 0x78ab, 0x0004, + 0x7827, 0x0018, 0x782b, 0x0000, 0xd1bc, 0x090c, 0x0db2, 0x2001, + 0x020d, 0x2003, 0x0050, 0x2003, 0x0020, 0x0480, 0x78ab, 0x0004, + 0x7803, 0x0001, 0x080c, 0x13f2, 0x0005, 0x7828, 0x782b, 0x0000, + 0x9065, 0x090c, 0x0db2, 0x6014, 0x2048, 0x78ab, 0x0004, 0x918c, + 0x0700, 0x0198, 0x080c, 0x763f, 0x080c, 0x1872, 0x080c, 0xb5fb, + 0x0158, 0xa9ac, 0xa936, 0xa9b0, 0xa93a, 0xa83f, 0xffff, 0xa843, + 0xffff, 0xa880, 0xc0bd, 0xa882, 0x0005, 0x6010, 0x00b6, 0x2058, + 0xb800, 0x00be, 0xd0bc, 0x6024, 0x190c, 0xb9d9, 0x2029, 0x00c8, + 0x8529, 0x0128, 0x2001, 0x0201, 0x2004, 0x9005, 0x0dc8, 0x7dbc, + 0x080c, 0xd31b, 0xd5a4, 0x1118, 0x080c, 0x1461, 0x0005, 0x080c, + 0x763f, 0x080c, 0x1872, 0x0005, 0x781f, 0x0300, 0x7803, 0x0001, + 0x0005, 0x0016, 0x0066, 0x0076, 0x00f6, 0x2079, 0x0300, 0x7908, + 0x918c, 0x0007, 0x9186, 0x0003, 0x0120, 0x2001, 0x0016, 0x080c, + 0x14d2, 0x00fe, 0x007e, 0x006e, 0x001e, 0x0005, 0x7004, 0xc09d, + 0x7006, 0x0005, 0x7104, 0x9184, 0x0004, 0x190c, 0x0db2, 0xd184, + 0x1189, 0xd19c, 0x0158, 0xc19c, 0x7106, 0x2001, 0x020d, 0x2003, + 0x0050, 0x2003, 0x0020, 0x080c, 0x1461, 0x0005, 0x81ff, 0x190c, + 0x0db2, 0x0005, 0xc184, 0xd1b4, 0xc1b4, 0x7106, 0x0016, 0x00e6, + 0x15e0, 0x2071, 0x0200, 0x080c, 0x150c, 0x6014, 0x9005, 0x05a8, + 0x0096, 0x2048, 0xa864, 0x009e, 0x9084, 0x00ff, 0x908e, 0x0029, + 0x0160, 0x908e, 0x0048, 0x1548, 0x601c, 0xd084, 0x11d8, 0x00f6, + 0x2c78, 0x080c, 0x1582, 0x00fe, 0x00a8, 0x00f6, 0x2c78, 0x080c, + 0x16b6, 0x00fe, 0x2009, 0x01f4, 0x8109, 0x0160, 0x2001, 0x0201, + 0x2004, 0x9005, 0x0dc8, 0x2001, 0x0218, 0x2004, 0xd0ec, 0x1110, + 0x0401, 0x0040, 0x2001, 0x020d, 0x2003, 0x0020, 0x080c, 0x12a0, + 0x7803, 0x0001, 0x00ee, 0x001e, 0x0005, 0x2001, 0x020d, 0x2003, + 0x0050, 0x2003, 0x0020, 0x0069, 0x0ca8, 0x0031, 0x2060, 0x2009, + 0x0053, 0x080c, 0x9a50, 0x0005, 0x7808, 0xd09c, 0x0de8, 0x7820, + 0x0005, 0x080c, 0x13d9, 0x00d6, 0x2069, 0x0200, 0x2009, 0x01f4, + 0x8109, 0x0510, 0x6804, 0x9005, 0x0dd8, 0x2001, 0x015d, 0x2003, + 0x0000, 0x79bc, 0xd1a4, 0x1528, 0x79b8, 0x918c, 0x0fff, 0x0180, + 0x9182, 0x0841, 0x1268, 0x9188, 0x0007, 0x918c, 0x0ff8, 0x810c, + 0x810c, 0x810c, 0x080c, 0x14c4, 0x6827, 0x0001, 0x8109, 0x1dd0, + 0x04d9, 0x6827, 0x0002, 0x04c1, 0x6804, 0x9005, 0x1130, 0x682c, + 0xd0e4, 0x1500, 0x6804, 0x9005, 0x0de8, 0x79b8, 0xd1ec, 0x1130, + 0x08c0, 0x080c, 0x763f, 0x080c, 0x1872, 0x0090, 0x7827, 0x0015, + 0x782b, 0x0000, 0x7827, 0x0018, 0x782b, 0x0000, 0x2001, 0x020d, + 0x2003, 0x0020, 0x2001, 0x0307, 0x2003, 0x0300, 0x7803, 0x0001, + 0x00de, 0x0005, 0x682c, 0x9084, 0x5400, 0x9086, 0x5400, 0x0d30, + 0x7827, 0x0015, 0x782b, 0x0000, 0x7803, 0x0001, 0x6800, 0x9085, + 0x1800, 0x6802, 0x00de, 0x0005, 0x6824, 0x9084, 0x0003, 0x1de0, + 0x0005, 0x2001, 0x0030, 0x2c08, 0x621c, 0x0021, 0x7830, 0x9086, + 0x0041, 0x0005, 0x00f6, 0x2079, 0x0300, 0x0006, 0x7808, 0xd09c, + 0x0140, 0x0016, 0x0026, 0x00c6, 0x080c, 0x12d6, 0x00ce, 0x002e, + 0x001e, 0x000e, 0x0006, 0x7832, 0x7936, 0x7a3a, 0x781b, 0x8080, + 0x2009, 0xff00, 0x8109, 0x0130, 0x7818, 0xd0bc, 0x1dd8, 0x000e, + 0x00fe, 0x0005, 0x000e, 0x792c, 0x3900, 0x8000, 0x2004, 0x080c, + 0x0db2, 0x7832, 0x7936, 0x7a3a, 0x781b, 0x8080, 0x2009, 0xff00, + 0x8109, 0x0120, 0x7818, 0xd0bc, 0x1dd8, 0x0005, 0x792c, 0x3900, + 0x8000, 0x2004, 0x080c, 0x0db2, 0x7037, 0x0001, 0x7150, 0x7037, + 0x0002, 0x7050, 0x2060, 0xd1bc, 0x1110, 0x7054, 0x2060, 0x0005, + 0x00e6, 0x0016, 0x2071, 0x0200, 0x0c79, 0x6124, 0xd1dc, 0x01f8, + 0x701c, 0xd08c, 0x0904, 0x1577, 0x7017, 0x0000, 0x2001, 0x0264, + 0x2004, 0xd0bc, 0x0904, 0x1577, 0x2001, 0x0268, 0x00c6, 0x2064, + 0x6104, 0x6038, 0x00ce, 0x918e, 0x0039, 0x1904, 0x1577, 0x9c06, + 0x15f0, 0x0126, 0x2091, 0x2600, 0x080c, 0x7597, 0x012e, 0x7358, + 0x745c, 0x6014, 0x905d, 0x0598, 0x2b48, 0x6010, 0x00b6, 0x2058, + 0xb800, 0x00be, 0xd0bc, 0x190c, 0xb9b4, 0xab42, 0xac3e, 0x2001, + 0x1875, 0x2004, 0xd0b4, 0x1170, 0x601c, 0xd0e4, 0x1158, 0x6010, + 0x00b6, 0x2058, 0xb800, 0x00be, 0xd0bc, 0x1120, 0xa83b, 0x7fff, + 0xa837, 0xffff, 0x080c, 0x1dc2, 0x1190, 0x080c, 0x1705, 0x2a00, + 0xa816, 0x0130, 0x2800, 0xa80e, 0x2c05, 0xa80a, 0x2c00, 0xa812, + 0x7037, 0x0020, 0x781f, 0x0300, 0x001e, 0x00ee, 0x0005, 0x7037, + 0x0050, 0x7037, 0x0020, 0x001e, 0x00ee, 0x080c, 0x1461, 0x0005, + 0x080c, 0x0db2, 0x2ff0, 0x0126, 0x2091, 0x2200, 0x3e60, 0x6014, + 0x2048, 0x2940, 0x903e, 0x2730, 0xa864, 0x2068, 0xa81a, 0x9d84, + 0x000f, 0x9088, 0x1da2, 0x2165, 0x0002, 0x15ac, 0x15f9, 0x15ac, + 0x15ac, 0x15ac, 0x15db, 0x15ac, 0x15b0, 0x15a5, 0x15f0, 0x15ac, + 0x15ac, 0x15ac, 0x16b4, 0x15c4, 0x15ba, 0xa964, 0x918c, 0x00ff, + 0x918e, 0x0048, 0x0904, 0x15f0, 0x9085, 0x0001, 0x0804, 0x16ac, + 0xa87c, 0xd0bc, 0x0dc8, 0xa890, 0xa842, 0xa88c, 0xa83e, 0xa888, + 0x0804, 0x1600, 0xa87c, 0xd0bc, 0x0d78, 0xa890, 0xa842, 0xa88c, + 0xa83e, 0xa888, 0x0804, 0x164f, 0xa87c, 0xd0bc, 0x0d28, 0xa890, + 0xa842, 0xa88c, 0xa83e, 0xa804, 0x9045, 0x090c, 0x0db2, 0xa164, + 0xa91a, 0x91ec, 0x000f, 0x9d80, 0x1da2, 0x2065, 0xa888, 0xd19c, + 0x1904, 0x164f, 0x0428, 0xa87c, 0xd0ac, 0x0970, 0xa804, 0x9045, + 0x090c, 0x0db2, 0xa164, 0xa91a, 0x91ec, 0x000f, 0x9d80, 0x1da2, + 0x2065, 0x9006, 0xa842, 0xa83e, 0xd19c, 0x1904, 0x164f, 0x0080, + 0xa87c, 0xd0ac, 0x0904, 0x15ac, 0x9006, 0xa842, 0xa83e, 0x0804, + 0x164f, 0xa87c, 0xd0ac, 0x0904, 0x15ac, 0x9006, 0xa842, 0xa83e, + 0x2c05, 0x908a, 0x0036, 0x1a0c, 0x0db2, 0x9082, 0x001b, 0x0002, + 0x1623, 0x1623, 0x1625, 0x1623, 0x1623, 0x1623, 0x162b, 0x1623, + 0x1623, 0x1623, 0x1631, 0x1623, 0x1623, 0x1623, 0x1637, 0x1623, + 0x1623, 0x1623, 0x163d, 0x1623, 0x1623, 0x1623, 0x1643, 0x1623, + 0x1623, 0x1623, 0x1649, 0x080c, 0x0db2, 0xa574, 0xa478, 0xa37c, + 0xa280, 0x0804, 0x1694, 0xa584, 0xa488, 0xa38c, 0xa290, 0x0804, + 0x1694, 0xa594, 0xa498, 0xa39c, 0xa2a0, 0x0804, 0x1694, 0xa5a4, + 0xa4a8, 0xa3ac, 0xa2b0, 0x0804, 0x1694, 0xa5b4, 0xa4b8, 0xa3bc, + 0xa2c0, 0x0804, 0x1694, 0xa5c4, 0xa4c8, 0xa3cc, 0xa2d0, 0x0804, + 0x1694, 0xa5d4, 0xa4d8, 0xa3dc, 0xa2e0, 0x0804, 0x1694, 0x2c05, + 0x908a, 0x0034, 0x1a0c, 0x0db2, 0x9082, 0x001b, 0x0002, 0x1672, + 0x1670, 0x1670, 0x1670, 0x1670, 0x1670, 0x1679, 0x1670, 0x1670, + 0x1670, 0x1670, 0x1670, 0x1680, 0x1670, 0x1670, 0x1670, 0x1670, + 0x1670, 0x1687, 0x1670, 0x1670, 0x1670, 0x1670, 0x1670, 0x168e, + 0x080c, 0x0db2, 0xa56c, 0xa470, 0xa774, 0xa678, 0xa37c, 0xa280, + 0x00d8, 0xa584, 0xa488, 0xa78c, 0xa690, 0xa394, 0xa298, 0x00a0, + 0xa59c, 0xa4a0, 0xa7a4, 0xa6a8, 0xa3ac, 0xa2b0, 0x0068, 0xa5b4, + 0xa4b8, 0xa7bc, 0xa6c0, 0xa3c4, 0xa2c8, 0x0030, 0xa5cc, 0xa4d0, + 0xa7d4, 0xa6d8, 0xa3dc, 0xa2e0, 0xab2e, 0xaa32, 0xad1e, 0xac22, + 0xaf26, 0xae2a, 0xa988, 0x8c60, 0x2c1d, 0xa8ac, 0xaab0, 0xa836, + 0xaa3a, 0x8109, 0xa916, 0x1150, 0x3e60, 0x601c, 0xc085, 0x601e, + 0xa87c, 0xc0dd, 0xa87e, 0x9006, 0x012e, 0x0005, 0x2800, 0xa80e, + 0xab0a, 0x2c00, 0xa812, 0x0c80, 0x0804, 0x15ac, 0x2ff0, 0x0126, + 0x2091, 0x2200, 0x3e60, 0x6014, 0x2048, 0x2940, 0xa80e, 0x2061, + 0x1d9d, 0xa80b, 0x1d9d, 0x2c05, 0xa812, 0xa964, 0xa91a, 0xa87c, + 0xd0ac, 0x090c, 0x0db2, 0x9006, 0xa842, 0xa83e, 0x2c05, 0x908a, + 0x0034, 0x1a0c, 0x0db2, 0xadcc, 0xacd0, 0xafd4, 0xaed8, 0xabdc, + 0xaae0, 0xab2e, 0xaa32, 0xad1e, 0xac22, 0xaf26, 0xae2a, 0xa8ac, + 0xaab0, 0xa836, 0xaa3a, 0xa988, 0x918a, 0x0002, 0xa916, 0x1150, + 0x3e60, 0x601c, 0xc085, 0x601e, 0xa87c, 0xc0dd, 0xa87e, 0x9006, + 0x012e, 0x0005, 0xa804, 0x9045, 0x090c, 0x0db2, 0xa80e, 0xa064, + 0xa81a, 0x9084, 0x000f, 0x9080, 0x1da2, 0x2015, 0x82ff, 0x090c, + 0x0db2, 0xaa0a, 0x2205, 0xa812, 0x0c18, 0x903e, 0x2730, 0xa880, + 0xd0fc, 0x1190, 0x2d00, 0x0002, 0x17fa, 0x175c, 0x175c, 0x17fa, + 0x17fa, 0x17f4, 0x17fa, 0x175c, 0x17fa, 0x17ab, 0x17ab, 0x17fa, + 0x17fa, 0x17fa, 0x17f1, 0x17ab, 0xc0fc, 0xa882, 0xab2c, 0xaa30, + 0xad1c, 0xac20, 0xdd9c, 0x0904, 0x17fc, 0x2c05, 0x908a, 0x0034, + 0x1a0c, 0x0db2, 0x9082, 0x001b, 0x0002, 0x1748, 0x1746, 0x1746, + 0x1746, 0x1746, 0x1746, 0x174c, 0x1746, 0x1746, 0x1746, 0x1746, + 0x1746, 0x1750, 0x1746, 0x1746, 0x1746, 0x1746, 0x1746, 0x1754, + 0x1746, 0x1746, 0x1746, 0x1746, 0x1746, 0x1758, 0x080c, 0x0db2, + 0xa774, 0xa678, 0x0804, 0x17fc, 0xa78c, 0xa690, 0x0804, 0x17fc, + 0xa7a4, 0xa6a8, 0x0804, 0x17fc, 0xa7bc, 0xa6c0, 0x0804, 0x17fc, + 0xa7d4, 0xa6d8, 0x0804, 0x17fc, 0x2c05, 0x908a, 0x0036, 0x1a0c, + 0x0db2, 0x9082, 0x001b, 0x0002, 0x177f, 0x177f, 0x1781, 0x177f, + 0x177f, 0x177f, 0x1787, 0x177f, 0x177f, 0x177f, 0x178d, 0x177f, + 0x177f, 0x177f, 0x1793, 0x177f, 0x177f, 0x177f, 0x1799, 0x177f, + 0x177f, 0x177f, 0x179f, 0x177f, 0x177f, 0x177f, 0x17a5, 0x080c, + 0x0db2, 0xa574, 0xa478, 0xa37c, 0xa280, 0x0804, 0x17fc, 0xa584, + 0xa488, 0xa38c, 0xa290, 0x0804, 0x17fc, 0xa594, 0xa498, 0xa39c, + 0xa2a0, 0x0804, 0x17fc, 0xa5a4, 0xa4a8, 0xa3ac, 0xa2b0, 0x0804, + 0x17fc, 0xa5b4, 0xa4b8, 0xa3bc, 0xa2c0, 0x0804, 0x17fc, 0xa5c4, + 0xa4c8, 0xa3cc, 0xa2d0, 0x0804, 0x17fc, 0xa5d4, 0xa4d8, 0xa3dc, + 0xa2e0, 0x0804, 0x17fc, 0x2c05, 0x908a, 0x0034, 0x1a0c, 0x0db2, + 0x9082, 0x001b, 0x0002, 0x17ce, 0x17cc, 0x17cc, 0x17cc, 0x17cc, + 0x17cc, 0x17d5, 0x17cc, 0x17cc, 0x17cc, 0x17cc, 0x17cc, 0x17dc, + 0x17cc, 0x17cc, 0x17cc, 0x17cc, 0x17cc, 0x17e3, 0x17cc, 0x17cc, + 0x17cc, 0x17cc, 0x17cc, 0x17ea, 0x080c, 0x0db2, 0xa56c, 0xa470, + 0xa774, 0xa678, 0xa37c, 0xa280, 0x0438, 0xa584, 0xa488, 0xa78c, + 0xa690, 0xa394, 0xa298, 0x0400, 0xa59c, 0xa4a0, 0xa7a4, 0xa6a8, + 0xa3ac, 0xa2b0, 0x00c8, 0xa5b4, 0xa4b8, 0xa7bc, 0xa6c0, 0xa3c4, + 0xa2c8, 0x0090, 0xa5cc, 0xa4d0, 0xa7d4, 0xa6d8, 0xa3dc, 0xa2e0, + 0x0058, 0x9d86, 0x000e, 0x1130, 0x080c, 0x1d60, 0x1904, 0x1705, + 0x900e, 0x0050, 0x080c, 0x0db2, 0xab2e, 0xaa32, 0xad1e, 0xac22, + 0xaf26, 0xae2a, 0x080c, 0x1d60, 0x0005, 0x6014, 0x2048, 0x6118, + 0x810c, 0x810c, 0x810c, 0x81ff, 0x1118, 0xa887, 0x0001, 0x0008, + 0xa986, 0x601b, 0x0002, 0xa974, 0xd1dc, 0x1108, 0x0005, 0xa934, + 0xa88c, 0x9106, 0x1158, 0xa938, 0xa890, 0x9106, 0x1138, 0x601c, + 0xc084, 0x601e, 0x2009, 0x0048, 0x0804, 0x9a50, 0x0005, 0x0126, + 0x00c6, 0x2091, 0x2200, 0x00ce, 0x7908, 0x918c, 0x0007, 0x9186, + 0x0000, 0x05b0, 0x9186, 0x0003, 0x0598, 0x6020, 0x6023, 0x0000, + 0x0006, 0x2031, 0x0008, 0x00c6, 0x781f, 0x0808, 0x7808, 0xd09c, + 0x0120, 0x080c, 0x12d6, 0x8631, 0x1db8, 0x00ce, 0x781f, 0x0800, + 0x2031, 0x0168, 0x00c6, 0x7808, 0xd09c, 0x190c, 0x12d6, 0x00ce, + 0x2001, 0x0038, 0x080c, 0x18ff, 0x7930, 0x9186, 0x0040, 0x0160, + 0x9186, 0x0042, 0x190c, 0x0db2, 0x2001, 0x001e, 0x8001, 0x1df0, + 0x8631, 0x1d40, 0x080c, 0x190e, 0x000e, 0x6022, 0x012e, 0x0005, + 0x080c, 0x18fb, 0x7827, 0x0015, 0x7828, 0x9c06, 0x1db8, 0x782b, + 0x0000, 0x0ca0, 0x00f6, 0x2079, 0x0300, 0x7803, 0x0000, 0x78ab, + 0x0004, 0x00fe, 0x080c, 0x6c53, 0x11b0, 0x2001, 0x0138, 0x2003, + 0x0000, 0x2001, 0x0160, 0x2003, 0x0000, 0x2011, 0x012c, 0xa001, + 0xa001, 0x8211, 0x1de0, 0x0081, 0x0066, 0x2031, 0x0000, 0x080c, + 0x6d03, 0x006e, 0x0005, 0x0479, 0x0039, 0x2001, 0x0160, 0x2502, + 0x2001, 0x0138, 0x2202, 0x0005, 0x00e6, 0x2071, 0x0200, 0x080c, + 0x28dc, 0x2009, 0x003c, 0x080c, 0x20d9, 0x2001, 0x015d, 0x2003, + 0x0000, 0x7000, 0x9084, 0x003c, 0x1de0, 0x080c, 0x7b7c, 0x70a0, + 0x70a2, 0x7098, 0x709a, 0x709c, 0x709e, 0x2001, 0x020d, 0x2003, + 0x0020, 0x00f6, 0x2079, 0x0300, 0x080c, 0x12a0, 0x7803, 0x0001, + 0x00fe, 0x00ee, 0x0005, 0x2001, 0x0138, 0x2014, 0x2003, 0x0000, + 0x2001, 0x0160, 0x202c, 0x2003, 0x0000, 0x080c, 0x6c53, 0x1108, + 0x0005, 0x2021, 0x0260, 0x2001, 0x0141, 0x201c, 0xd3dc, 0x1168, + 0x2001, 0x0109, 0x201c, 0x939c, 0x0048, 0x1160, 0x2001, 0x0111, + 0x201c, 0x83ff, 0x1110, 0x8421, 0x1d70, 0x2001, 0x015d, 0x2003, + 0x0000, 0x0005, 0x0046, 0x2021, 0x0019, 0x2003, 0x0048, 0xa001, + 0xa001, 0x201c, 0x939c, 0x0048, 0x0120, 0x8421, 0x1db0, 0x004e, + 0x0c60, 0x004e, 0x0c40, 0x601c, 0xc084, 0x601e, 0x0005, 0x2c08, + 0x621c, 0x080c, 0x14d2, 0x7930, 0x0005, 0x2c08, 0x621c, 0x080c, + 0x14f9, 0x7930, 0x0005, 0x8001, 0x1df0, 0x0005, 0x2031, 0x0005, + 0x781c, 0x9084, 0x0007, 0x0170, 0x2001, 0x0038, 0x0c41, 0x9186, + 0x0040, 0x0904, 0x196c, 0x2001, 0x001e, 0x0c69, 0x8631, 0x1d80, + 0x080c, 0x0db2, 0x781f, 0x0202, 0x2001, 0x015d, 0x2003, 0x0000, + 0x2001, 0x0b10, 0x0c01, 0x781c, 0xd084, 0x0110, 0x0861, 0x04e0, + 0x2001, 0x0030, 0x0891, 0x9186, 0x0040, 0x0568, 0x781c, 0xd084, + 0x1da8, 0x781f, 0x0101, 0x2001, 0x0014, 0x0869, 0x2001, 0x0037, + 0x0821, 0x9186, 0x0040, 0x0140, 0x2001, 0x0030, 0x080c, 0x1905, + 0x9186, 0x0040, 0x190c, 0x0db2, 0x00d6, 0x2069, 0x0200, 0x692c, + 0xd1f4, 0x1170, 0xd1c4, 0x0160, 0xd19c, 0x0130, 0x6800, 0x9085, + 0x1800, 0x6802, 0x00de, 0x0080, 0x6908, 0x9184, 0x0007, 0x1db0, + 0x00de, 0x781f, 0x0100, 0x791c, 0x9184, 0x0007, 0x090c, 0x0db2, + 0xa001, 0xa001, 0x781f, 0x0200, 0x0005, 0x0126, 0x2091, 0x2400, + 0x2071, 0x1a34, 0x2079, 0x0090, 0x012e, 0x0005, 0x9280, 0x0005, + 0x2004, 0x2048, 0xa97c, 0xd1dc, 0x1904, 0x19f1, 0xa964, 0x9184, + 0x0007, 0x0002, 0x198a, 0x19dc, 0x1991, 0x1991, 0x1991, 0x19c4, + 0x19a4, 0x1993, 0x2100, 0x9084, 0x00ff, 0x9086, 0x0048, 0x0904, + 0x19dc, 0x080c, 0x0db2, 0xa87c, 0xd0b4, 0x0904, 0x1ba3, 0xa890, + 0xa842, 0xa83a, 0xa88c, 0xa83e, 0xa836, 0xa8ac, 0xa846, 0xa8b0, + 0xa84a, 0xa988, 0x0804, 0x19e4, 0xa864, 0x9084, 0x00ff, 0x9086, + 0x001e, 0x1d38, 0xa87c, 0xd0b4, 0x0904, 0x1ba3, 0xa890, 0xa842, + 0xa83a, 0xa88c, 0xa83e, 0xa836, 0xa8ac, 0xa846, 0xa8b0, 0xa84a, + 0xa804, 0xa85a, 0x2040, 0xa064, 0x9084, 0x000f, 0x9080, 0x1da2, + 0x2005, 0xa812, 0xa988, 0x0448, 0x918c, 0x00ff, 0x9186, 0x0015, + 0x1540, 0xa87c, 0xd0b4, 0x0904, 0x1ba3, 0xa804, 0xa85a, 0x2040, + 0xa064, 0x9084, 0x000f, 0x9080, 0x1da2, 0x2005, 0xa812, 0xa988, + 0x9006, 0xa842, 0xa83e, 0x0088, 0xa87c, 0xd0b4, 0x0904, 0x1ba3, + 0xa988, 0x9006, 0xa842, 0xa83e, 0x2900, 0xa85a, 0xa864, 0x9084, + 0x000f, 0x9080, 0x1da2, 0x2005, 0xa812, 0xa916, 0xa87c, 0xc0dd, + 0xa87e, 0x0005, 0x00f6, 0x2079, 0x0090, 0x782c, 0xd0fc, 0x190c, + 0x1be4, 0x00e6, 0x2071, 0x1a34, 0x7000, 0x9005, 0x1904, 0x1a4b, + 0x7206, 0x9280, 0x0005, 0x204c, 0x9280, 0x0004, 0x2004, 0x782b, + 0x0004, 0x00f6, 0x2079, 0x0200, 0x7803, 0x0040, 0x00fe, 0x00b6, + 0x2058, 0xb86c, 0x7836, 0xb890, 0x00be, 0x00f6, 0x2079, 0x0200, + 0x7803, 0x0040, 0xa001, 0xa001, 0xa001, 0xa001, 0xa001, 0xa001, + 0x781a, 0x2079, 0x0100, 0x8004, 0x78d6, 0x00fe, 0xa814, 0x2050, + 0xa858, 0x2040, 0xa810, 0x2060, 0xa064, 0x90ec, 0x000f, 0xa944, + 0x791a, 0x7116, 0xa848, 0x781e, 0x701a, 0x9006, 0x700e, 0x7012, + 0x7004, 0xa940, 0xa838, 0x9106, 0x1188, 0xa93c, 0xa834, 0x9106, + 0x1168, 0x8aff, 0x01a8, 0x0126, 0x2091, 0x8000, 0x00a1, 0x0108, + 0x0091, 0x012e, 0x9006, 0x00ee, 0x00fe, 0x0005, 0x0036, 0x0046, + 0xab38, 0xac34, 0x080c, 0x1dc2, 0x004e, 0x003e, 0x0d50, 0x0c98, + 0x9085, 0x0001, 0x0c80, 0x0076, 0x0066, 0x0056, 0x0046, 0x0036, + 0x0026, 0x8aff, 0x0904, 0x1b9c, 0x700c, 0x7214, 0x923a, 0x7010, + 0x7218, 0x9203, 0x0a04, 0x1b9b, 0x9705, 0x0904, 0x1b9b, 0x903e, + 0x2730, 0xa880, 0xd0fc, 0x1190, 0x2d00, 0x0002, 0x1b7f, 0x1ac6, + 0x1ac6, 0x1b7f, 0x1b7f, 0x1b62, 0x1b7f, 0x1ac6, 0x1b68, 0x1b15, + 0x1b15, 0x1b7f, 0x1b7f, 0x1b7f, 0x1b5c, 0x1b15, 0xc0fc, 0xa882, + 0xab2c, 0xaa30, 0xad1c, 0xac20, 0xdd9c, 0x0904, 0x1b81, 0x2c05, + 0x908a, 0x0034, 0x1a0c, 0x0db2, 0x9082, 0x001b, 0x0002, 0x1ab2, + 0x1ab0, 0x1ab0, 0x1ab0, 0x1ab0, 0x1ab0, 0x1ab6, 0x1ab0, 0x1ab0, + 0x1ab0, 0x1ab0, 0x1ab0, 0x1aba, 0x1ab0, 0x1ab0, 0x1ab0, 0x1ab0, + 0x1ab0, 0x1abe, 0x1ab0, 0x1ab0, 0x1ab0, 0x1ab0, 0x1ab0, 0x1ac2, + 0x080c, 0x0db2, 0xa774, 0xa678, 0x0804, 0x1b81, 0xa78c, 0xa690, + 0x0804, 0x1b81, 0xa7a4, 0xa6a8, 0x0804, 0x1b81, 0xa7bc, 0xa6c0, + 0x0804, 0x1b81, 0xa7d4, 0xa6d8, 0x0804, 0x1b81, 0x2c05, 0x908a, + 0x0036, 0x1a0c, 0x0db2, 0x9082, 0x001b, 0x0002, 0x1ae9, 0x1ae9, + 0x1aeb, 0x1ae9, 0x1ae9, 0x1ae9, 0x1af1, 0x1ae9, 0x1ae9, 0x1ae9, + 0x1af7, 0x1ae9, 0x1ae9, 0x1ae9, 0x1afd, 0x1ae9, 0x1ae9, 0x1ae9, + 0x1b03, 0x1ae9, 0x1ae9, 0x1ae9, 0x1b09, 0x1ae9, 0x1ae9, 0x1ae9, + 0x1b0f, 0x080c, 0x0db2, 0xa574, 0xa478, 0xa37c, 0xa280, 0x0804, + 0x1b81, 0xa584, 0xa488, 0xa38c, 0xa290, 0x0804, 0x1b81, 0xa594, + 0xa498, 0xa39c, 0xa2a0, 0x0804, 0x1b81, 0xa5a4, 0xa4a8, 0xa3ac, + 0xa2b0, 0x0804, 0x1b81, 0xa5b4, 0xa4b8, 0xa3bc, 0xa2c0, 0x0804, + 0x1b81, 0xa5c4, 0xa4c8, 0xa3cc, 0xa2d0, 0x0804, 0x1b81, 0xa5d4, + 0xa4d8, 0xa3dc, 0xa2e0, 0x0804, 0x1b81, 0x2c05, 0x908a, 0x0034, + 0x1a0c, 0x0db2, 0x9082, 0x001b, 0x0002, 0x1b38, 0x1b36, 0x1b36, + 0x1b36, 0x1b36, 0x1b36, 0x1b40, 0x1b36, 0x1b36, 0x1b36, 0x1b36, + 0x1b36, 0x1b47, 0x1b36, 0x1b36, 0x1b36, 0x1b36, 0x1b36, 0x1b4e, + 0x1b36, 0x1b36, 0x1b36, 0x1b36, 0x1b36, 0x1b55, 0x080c, 0x0db2, + 0xa56c, 0xa470, 0xa774, 0xa678, 0xa37c, 0xa280, 0x0804, 0x1b81, + 0xa584, 0xa488, 0xa78c, 0xa690, 0xa394, 0xa298, 0x04d0, 0xa59c, + 0xa4a0, 0xa7a4, 0xa6a8, 0xa3ac, 0xa2b0, 0x0498, 0xa5b4, 0xa4b8, + 0xa7bc, 0xa6c0, 0xa3c4, 0xa2c8, 0x0460, 0xa5cc, 0xa4d0, 0xa7d4, + 0xa6d8, 0xa3dc, 0xa2e0, 0x0428, 0xa864, 0x9084, 0x00ff, 0x9086, + 0x001e, 0x11e8, 0x080c, 0x1d60, 0x1904, 0x1a61, 0x900e, 0x04a0, + 0xa864, 0x9084, 0x00ff, 0x9086, 0x0048, 0x190c, 0x0db2, 0x00c6, + 0x7004, 0x2060, 0x6004, 0x9086, 0x0043, 0x00ce, 0x0904, 0x1b15, + 0xab9c, 0x9016, 0xad8c, 0xac90, 0xaf94, 0xae98, 0x0010, 0x080c, + 0x0db2, 0x7b12, 0x7a16, 0x7d02, 0x7c06, 0x7f0a, 0x7e0e, 0x782b, + 0x0001, 0x7000, 0x8000, 0x7002, 0xa83c, 0x9300, 0xa83e, 0xa840, + 0x9201, 0xa842, 0x700c, 0x9300, 0x700e, 0x7010, 0x9201, 0x7012, + 0x080c, 0x1d60, 0x0008, 0x9006, 0x002e, 0x003e, 0x004e, 0x005e, + 0x006e, 0x007e, 0x0005, 0x080c, 0x0db2, 0x0026, 0x2001, 0x0105, + 0x2003, 0x0010, 0x782b, 0x0004, 0x7003, 0x0000, 0x7004, 0x2060, + 0x6014, 0x2048, 0x080c, 0xb5fb, 0x0118, 0xa880, 0xc0bd, 0xa882, + 0x6020, 0x9086, 0x0006, 0x1180, 0x2061, 0x0100, 0x62c8, 0x2001, + 0x00fa, 0x8001, 0x1df0, 0x60c8, 0x9206, 0x1dc0, 0x60c4, 0xa89a, + 0x60c8, 0xa896, 0x7004, 0x2060, 0x00c6, 0x080c, 0xb251, 0x00ce, + 0x2001, 0x19c5, 0x2004, 0x9c06, 0x1160, 0x2009, 0x0040, 0x080c, + 0x20d9, 0x080c, 0x9479, 0x2011, 0x0000, 0x080c, 0x92f6, 0x080c, + 0x865d, 0x002e, 0x0804, 0x1d12, 0x0126, 0x2091, 0x2400, 0xa858, + 0x2040, 0x792c, 0x782b, 0x0002, 0x9184, 0x0700, 0x1904, 0x1ba5, + 0x7000, 0x0002, 0x1d12, 0x1bf6, 0x1c63, 0x1d10, 0x8001, 0x7002, + 0xd19c, 0x1150, 0x8aff, 0x05b0, 0x080c, 0x1a5b, 0x0904, 0x1d12, + 0x080c, 0x1a5b, 0x0804, 0x1d12, 0x782b, 0x0004, 0xd194, 0x0148, + 0xa880, 0xc0fc, 0xa882, 0x8aff, 0x11d8, 0xa87c, 0xc0f5, 0xa87e, + 0x00b8, 0x0026, 0x0036, 0xab3c, 0xaa40, 0x7810, 0xa82e, 0x931a, + 0x7814, 0xa832, 0x9213, 0x7800, 0xa81e, 0x7804, 0xa822, 0xab3e, + 0xaa42, 0x003e, 0x002e, 0x080c, 0x1d78, 0xa880, 0xc0fd, 0xa882, + 0x2a00, 0xa816, 0x2800, 0xa85a, 0x2c00, 0xa812, 0x7003, 0x0000, + 0x0804, 0x1d12, 0x00f6, 0x0026, 0x781c, 0x0006, 0x7818, 0x0006, + 0x2079, 0x0100, 0x7a14, 0x9284, 0x1984, 0x9085, 0x0012, 0x7816, + 0x0036, 0x2019, 0x1000, 0x8319, 0x090c, 0x0db2, 0x7820, 0xd0bc, + 0x1dd0, 0x003e, 0x79c8, 0x000e, 0x9102, 0x001e, 0x0006, 0x0016, + 0x79c4, 0x000e, 0x9103, 0x78c6, 0x000e, 0x78ca, 0x9284, 0x1984, + 0x9085, 0x0012, 0x7816, 0x002e, 0x00fe, 0x782b, 0x0008, 0x7003, + 0x0000, 0x0804, 0x1d12, 0x8001, 0x7002, 0xd194, 0x0170, 0x782c, + 0xd0fc, 0x1904, 0x1be9, 0xd19c, 0x1904, 0x1d0e, 0x8aff, 0x0904, + 0x1d12, 0x080c, 0x1a5b, 0x0804, 0x1d12, 0x0026, 0x0036, 0xab3c, + 0xaa40, 0x080c, 0x1d78, 0xdd9c, 0x1904, 0x1ccd, 0x2c05, 0x908a, + 0x0036, 0x1a0c, 0x0db2, 0x9082, 0x001b, 0x0002, 0x1ca1, 0x1ca1, + 0x1ca3, 0x1ca1, 0x1ca1, 0x1ca1, 0x1ca9, 0x1ca1, 0x1ca1, 0x1ca1, + 0x1caf, 0x1ca1, 0x1ca1, 0x1ca1, 0x1cb5, 0x1ca1, 0x1ca1, 0x1ca1, + 0x1cbb, 0x1ca1, 0x1ca1, 0x1ca1, 0x1cc1, 0x1ca1, 0x1ca1, 0x1ca1, + 0x1cc7, 0x080c, 0x0db2, 0xa07c, 0x931a, 0xa080, 0x9213, 0x0804, + 0x1c15, 0xa08c, 0x931a, 0xa090, 0x9213, 0x0804, 0x1c15, 0xa09c, + 0x931a, 0xa0a0, 0x9213, 0x0804, 0x1c15, 0xa0ac, 0x931a, 0xa0b0, + 0x9213, 0x0804, 0x1c15, 0xa0bc, 0x931a, 0xa0c0, 0x9213, 0x0804, + 0x1c15, 0xa0cc, 0x931a, 0xa0d0, 0x9213, 0x0804, 0x1c15, 0xa0dc, + 0x931a, 0xa0e0, 0x9213, 0x0804, 0x1c15, 0x2c05, 0x908a, 0x0034, + 0x1a0c, 0x0db2, 0x9082, 0x001b, 0x0002, 0x1cf0, 0x1cee, 0x1cee, + 0x1cee, 0x1cee, 0x1cee, 0x1cf6, 0x1cee, 0x1cee, 0x1cee, 0x1cee, + 0x1cee, 0x1cfc, 0x1cee, 0x1cee, 0x1cee, 0x1cee, 0x1cee, 0x1d02, + 0x1cee, 0x1cee, 0x1cee, 0x1cee, 0x1cee, 0x1d08, 0x080c, 0x0db2, + 0xa07c, 0x931a, 0xa080, 0x9213, 0x0804, 0x1c15, 0xa094, 0x931a, + 0xa098, 0x9213, 0x0804, 0x1c15, 0xa0ac, 0x931a, 0xa0b0, 0x9213, + 0x0804, 0x1c15, 0xa0c4, 0x931a, 0xa0c8, 0x9213, 0x0804, 0x1c15, + 0xa0dc, 0x931a, 0xa0e0, 0x9213, 0x0804, 0x1c15, 0x0804, 0x1c11, + 0x080c, 0x0db2, 0x012e, 0x0005, 0x00f6, 0x00e6, 0x2071, 0x1a34, + 0x7000, 0x9086, 0x0000, 0x0904, 0x1d5d, 0x2079, 0x0090, 0x2009, + 0x0207, 0x210c, 0xd194, 0x01b8, 0x2009, 0x020c, 0x210c, 0x9184, + 0x0003, 0x0188, 0x080c, 0xd364, 0x2001, 0x0133, 0x2004, 0x9005, + 0x090c, 0x0db2, 0x0016, 0x2009, 0x0040, 0x080c, 0x20d9, 0x001e, + 0x2001, 0x020c, 0x2102, 0x2009, 0x0206, 0x2104, 0x2009, 0x0203, + 0x210c, 0x9106, 0x1120, 0x2009, 0x0040, 0x080c, 0x20d9, 0x782c, + 0xd0fc, 0x09a8, 0x080c, 0x1be4, 0x7000, 0x9086, 0x0000, 0x1978, + 0x782b, 0x0004, 0x782c, 0xd0ac, 0x1de8, 0x2009, 0x0040, 0x080c, + 0x20d9, 0x782b, 0x0002, 0x7003, 0x0000, 0x00ee, 0x00fe, 0x0005, + 0x8c60, 0x2c05, 0x9005, 0x0110, 0x8a51, 0x0005, 0xa004, 0x9005, + 0x0168, 0xa85a, 0x2040, 0xa064, 0x9084, 0x000f, 0x9080, 0x1da2, + 0x2065, 0x8cff, 0x090c, 0x0db2, 0x8a51, 0x0005, 0x2050, 0x0005, + 0x8a50, 0x8c61, 0x2c05, 0x9005, 0x1190, 0x2800, 0x9906, 0x0120, + 0xa000, 0x9005, 0x1108, 0x2900, 0x2040, 0xa85a, 0xa064, 0x9084, + 0x000f, 0x9080, 0x1db2, 0x2065, 0x8cff, 0x090c, 0x0db2, 0x0005, + 0x0000, 0x001d, 0x0021, 0x0025, 0x0029, 0x002d, 0x0031, 0x0035, + 0x0000, 0x001b, 0x0021, 0x0027, 0x002d, 0x0033, 0x0000, 0x0000, + 0x0023, 0x0000, 0x0000, 0x1d95, 0x1d91, 0x0000, 0x0000, 0x1d9f, + 0x0000, 0x1d95, 0x1d9c, 0x1d9c, 0x1d99, 0x0000, 0x0000, 0x0000, + 0x1d9f, 0x1d9c, 0x0000, 0x1d97, 0x1d97, 0x0000, 0x0000, 0x1d9f, + 0x0000, 0x1d97, 0x1d9d, 0x1d9d, 0x1d9d, 0x0000, 0x0000, 0x0000, + 0x1d9f, 0x1d9d, 0x00c6, 0x00d6, 0x0086, 0xab42, 0xac3e, 0xa888, + 0x9055, 0x0904, 0x1f99, 0x2940, 0xa064, 0x90ec, 0x000f, 0x9de0, + 0x1da2, 0x9d86, 0x0007, 0x0130, 0x9d86, 0x000e, 0x0118, 0x9d86, + 0x000f, 0x1120, 0xa08c, 0x9422, 0xa090, 0x931b, 0x2c05, 0x9065, + 0x1140, 0x0310, 0x0804, 0x1f99, 0xa004, 0x9045, 0x0904, 0x1f99, + 0x0c18, 0x2c05, 0x9005, 0x0904, 0x1e81, 0xdd9c, 0x1904, 0x1e3d, + 0x908a, 0x0036, 0x1a0c, 0x0db2, 0x9082, 0x001b, 0x0002, 0x1e12, + 0x1e12, 0x1e14, 0x1e12, 0x1e12, 0x1e12, 0x1e1a, 0x1e12, 0x1e12, + 0x1e12, 0x1e20, 0x1e12, 0x1e12, 0x1e12, 0x1e26, 0x1e12, 0x1e12, + 0x1e12, 0x1e2c, 0x1e12, 0x1e12, 0x1e12, 0x1e32, 0x1e12, 0x1e12, + 0x1e12, 0x1e38, 0x080c, 0x0db2, 0xa07c, 0x9422, 0xa080, 0x931b, + 0x0804, 0x1e77, 0xa08c, 0x9422, 0xa090, 0x931b, 0x0804, 0x1e77, + 0xa09c, 0x9422, 0xa0a0, 0x931b, 0x0804, 0x1e77, 0xa0ac, 0x9422, + 0xa0b0, 0x931b, 0x0804, 0x1e77, 0xa0bc, 0x9422, 0xa0c0, 0x931b, + 0x0804, 0x1e77, 0xa0cc, 0x9422, 0xa0d0, 0x931b, 0x0804, 0x1e77, + 0xa0dc, 0x9422, 0xa0e0, 0x931b, 0x04d0, 0x908a, 0x0034, 0x1a0c, + 0x0db2, 0x9082, 0x001b, 0x0002, 0x1e5f, 0x1e5d, 0x1e5d, 0x1e5d, + 0x1e5d, 0x1e5d, 0x1e64, 0x1e5d, 0x1e5d, 0x1e5d, 0x1e5d, 0x1e5d, + 0x1e69, 0x1e5d, 0x1e5d, 0x1e5d, 0x1e5d, 0x1e5d, 0x1e6e, 0x1e5d, + 0x1e5d, 0x1e5d, 0x1e5d, 0x1e5d, 0x1e73, 0x080c, 0x0db2, 0xa07c, + 0x9422, 0xa080, 0x931b, 0x0098, 0xa094, 0x9422, 0xa098, 0x931b, + 0x0070, 0xa0ac, 0x9422, 0xa0b0, 0x931b, 0x0048, 0xa0c4, 0x9422, + 0xa0c8, 0x931b, 0x0020, 0xa0dc, 0x9422, 0xa0e0, 0x931b, 0x0630, + 0x2300, 0x9405, 0x0160, 0x8a51, 0x0904, 0x1f99, 0x8c60, 0x0804, + 0x1de9, 0xa004, 0x9045, 0x0904, 0x1f99, 0x0804, 0x1dcc, 0x8a51, + 0x0904, 0x1f99, 0x8c60, 0x2c05, 0x9005, 0x1158, 0xa004, 0x9045, + 0x0904, 0x1f99, 0xa064, 0x90ec, 0x000f, 0x9de0, 0x1da2, 0x2c05, + 0x2060, 0xa880, 0xc0fc, 0xa882, 0x0804, 0x1f8e, 0x2c05, 0x8422, + 0x8420, 0x831a, 0x9399, 0x0000, 0xac2e, 0xab32, 0xdd9c, 0x1904, + 0x1f2b, 0x9082, 0x001b, 0x0002, 0x1ec7, 0x1ec7, 0x1ec9, 0x1ec7, + 0x1ec7, 0x1ec7, 0x1ed7, 0x1ec7, 0x1ec7, 0x1ec7, 0x1ee5, 0x1ec7, + 0x1ec7, 0x1ec7, 0x1ef3, 0x1ec7, 0x1ec7, 0x1ec7, 0x1f01, 0x1ec7, + 0x1ec7, 0x1ec7, 0x1f0f, 0x1ec7, 0x1ec7, 0x1ec7, 0x1f1d, 0x080c, + 0x0db2, 0xa17c, 0x2400, 0x9122, 0xa180, 0x2300, 0x911b, 0x0a0c, + 0x0db2, 0xa074, 0x9420, 0xa078, 0x9319, 0x0804, 0x1f89, 0xa18c, + 0x2400, 0x9122, 0xa190, 0x2300, 0x911b, 0x0a0c, 0x0db2, 0xa084, + 0x9420, 0xa088, 0x9319, 0x0804, 0x1f89, 0xa19c, 0x2400, 0x9122, + 0xa1a0, 0x2300, 0x911b, 0x0a0c, 0x0db2, 0xa094, 0x9420, 0xa098, + 0x9319, 0x0804, 0x1f89, 0xa1ac, 0x2400, 0x9122, 0xa1b0, 0x2300, + 0x911b, 0x0a0c, 0x0db2, 0xa0a4, 0x9420, 0xa0a8, 0x9319, 0x0804, + 0x1f89, 0xa1bc, 0x2400, 0x9122, 0xa1c0, 0x2300, 0x911b, 0x0a0c, + 0x0db2, 0xa0b4, 0x9420, 0xa0b8, 0x9319, 0x0804, 0x1f89, 0xa1cc, + 0x2400, 0x9122, 0xa1d0, 0x2300, 0x911b, 0x0a0c, 0x0db2, 0xa0c4, + 0x9420, 0xa0c8, 0x9319, 0x0804, 0x1f89, 0xa1dc, 0x2400, 0x9122, + 0xa1e0, 0x2300, 0x911b, 0x0a0c, 0x0db2, 0xa0d4, 0x9420, 0xa0d8, + 0x9319, 0x0804, 0x1f89, 0x9082, 0x001b, 0x0002, 0x1f49, 0x1f47, + 0x1f47, 0x1f47, 0x1f47, 0x1f47, 0x1f56, 0x1f47, 0x1f47, 0x1f47, + 0x1f47, 0x1f47, 0x1f63, 0x1f47, 0x1f47, 0x1f47, 0x1f47, 0x1f47, + 0x1f70, 0x1f47, 0x1f47, 0x1f47, 0x1f47, 0x1f47, 0x1f7d, 0x080c, + 0x0db2, 0xa17c, 0x2400, 0x9122, 0xa180, 0x2300, 0x911b, 0x0a0c, + 0x0db2, 0xa06c, 0x9420, 0xa070, 0x9319, 0x0498, 0xa194, 0x2400, + 0x9122, 0xa198, 0x2300, 0x911b, 0x0a0c, 0x0db2, 0xa084, 0x9420, + 0xa088, 0x9319, 0x0430, 0xa1ac, 0x2400, 0x9122, 0xa1b0, 0x2300, + 0x911b, 0x0a0c, 0x0db2, 0xa09c, 0x9420, 0xa0a0, 0x9319, 0x00c8, + 0xa1c4, 0x2400, 0x9122, 0xa1c8, 0x2300, 0x911b, 0x0a0c, 0x0db2, + 0xa0b4, 0x9420, 0xa0b8, 0x9319, 0x0060, 0xa1dc, 0x2400, 0x9122, + 0xa1e0, 0x2300, 0x911b, 0x0a0c, 0x0db2, 0xa0cc, 0x9420, 0xa0d0, + 0x9319, 0xac1e, 0xab22, 0xa880, 0xc0fd, 0xa882, 0x2800, 0xa85a, + 0x2c00, 0xa812, 0x2a00, 0xa816, 0x000e, 0x000e, 0x000e, 0x9006, + 0x0028, 0x008e, 0x00de, 0x00ce, 0x9085, 0x0001, 0x0005, 0x2001, + 0x0005, 0x2004, 0x9084, 0x0007, 0x0002, 0x1fb7, 0x1be4, 0x1fb7, + 0x1fad, 0x1fb0, 0x1fb3, 0x1fb0, 0x1fb3, 0x080c, 0x1be4, 0x0005, + 0x080c, 0x116f, 0x0005, 0x080c, 0x1be4, 0x080c, 0x116f, 0x0005, + 0x0126, 0x2091, 0x2600, 0x2079, 0x0200, 0x2071, 0x0260, 0x2069, + 0x1800, 0x7817, 0x0000, 0x789b, 0x0814, 0x78a3, 0x0406, 0x789f, + 0x0410, 0x2009, 0x013b, 0x200b, 0x0400, 0x781b, 0x0002, 0x783b, + 0x001f, 0x7837, 0x0020, 0x7803, 0x1600, 0x012e, 0x0005, 0x2091, + 0x2600, 0x781c, 0xd0a4, 0x190c, 0x20d6, 0x7900, 0xd1dc, 0x1118, + 0x9084, 0x0006, 0x001a, 0x9084, 0x000e, 0x0002, 0x1ffe, 0x1ff6, + 0x7597, 0x1ff6, 0x1ff8, 0x1ff8, 0x1ff8, 0x1ff8, 0x757d, 0x1ff6, + 0x1ffa, 0x1ff6, 0x1ff8, 0x1ff6, 0x1ff8, 0x1ff6, 0x080c, 0x0db2, + 0x0031, 0x0020, 0x080c, 0x757d, 0x080c, 0x7597, 0x0005, 0x0006, + 0x0016, 0x0026, 0x080c, 0xd364, 0x7930, 0x9184, 0x0003, 0x01c0, + 0x2001, 0x19c5, 0x2004, 0x9005, 0x0170, 0x2001, 0x0133, 0x2004, + 0x9005, 0x090c, 0x0db2, 0x00c6, 0x2001, 0x19c5, 0x2064, 0x080c, + 0xb251, 0x00ce, 0x00f8, 0x2009, 0x0040, 0x080c, 0x20d9, 0x00d0, + 0x9184, 0x0014, 0x01a0, 0x6a00, 0x9286, 0x0003, 0x0160, 0x080c, + 0x6c53, 0x1138, 0x080c, 0x6f2a, 0x080c, 0x5a21, 0x080c, 0x6b8a, + 0x0010, 0x080c, 0x58e0, 0x080c, 0x7635, 0x0041, 0x0018, 0x9184, + 0x9540, 0x1dc8, 0x002e, 0x001e, 0x000e, 0x0005, 0x00e6, 0x0036, + 0x0046, 0x0056, 0x2071, 0x1a31, 0x080c, 0x1872, 0x005e, 0x004e, + 0x003e, 0x00ee, 0x0005, 0x0126, 0x2091, 0x2e00, 0x2071, 0x1800, + 0x7128, 0x2001, 0x1940, 0x2102, 0x2001, 0x1948, 0x2102, 0x2001, + 0x013b, 0x2102, 0x2079, 0x0200, 0x2001, 0x0201, 0x789e, 0x78a3, + 0x0200, 0x9198, 0x0007, 0x831c, 0x831c, 0x831c, 0x9398, 0x0005, + 0x2320, 0x9182, 0x0204, 0x1230, 0x2011, 0x0008, 0x8423, 0x8423, + 0x8423, 0x0488, 0x9182, 0x024c, 0x1240, 0x2011, 0x0007, 0x8403, + 0x8003, 0x9400, 0x9400, 0x9420, 0x0430, 0x9182, 0x02bc, 0x1238, + 0x2011, 0x0006, 0x8403, 0x8003, 0x9400, 0x9420, 0x00e0, 0x9182, + 0x034c, 0x1230, 0x2011, 0x0005, 0x8403, 0x8003, 0x9420, 0x0098, + 0x9182, 0x042c, 0x1228, 0x2011, 0x0004, 0x8423, 0x8423, 0x0058, + 0x9182, 0x059c, 0x1228, 0x2011, 0x0003, 0x8403, 0x9420, 0x0018, + 0x2011, 0x0002, 0x8423, 0x9482, 0x0228, 0x8002, 0x8020, 0x8301, + 0x9402, 0x0110, 0x0208, 0x8321, 0x8217, 0x8203, 0x9405, 0x789a, + 0x012e, 0x0005, 0x0006, 0x00d6, 0x2069, 0x0200, 0x6814, 0x9084, + 0xffc0, 0x910d, 0x6916, 0x00de, 0x000e, 0x0005, 0x00d6, 0x2069, + 0x0200, 0x9005, 0x6810, 0x0110, 0xc0a5, 0x0008, 0xc0a4, 0x6812, + 0x00de, 0x0005, 0x0006, 0x00d6, 0x2069, 0x0200, 0x6810, 0x9084, + 0xfff8, 0x910d, 0x6912, 0x00de, 0x000e, 0x0005, 0x7938, 0x080c, + 0x0db2, 0x00f6, 0x2079, 0x0200, 0x7902, 0xa001, 0xa001, 0xa001, + 0xa001, 0xa001, 0xa001, 0x7902, 0xa001, 0xa001, 0xa001, 0xa001, + 0xa001, 0xa001, 0x00fe, 0x0005, 0x0126, 0x2091, 0x2800, 0x2061, + 0x0100, 0x2071, 0x1800, 0x2009, 0x0000, 0x080c, 0x28d6, 0x080c, + 0x27f1, 0x6054, 0x8004, 0x8004, 0x8004, 0x8004, 0x9084, 0x000c, + 0x6150, 0x918c, 0xfff3, 0x9105, 0x6052, 0x6050, 0x9084, 0xb17f, + 0x9085, 0x2000, 0x6052, 0x2009, 0x196c, 0x2011, 0x196d, 0x6358, + 0x939c, 0x38f0, 0x2320, 0x080c, 0x2835, 0x1238, 0x939d, 0x4003, + 0x94a5, 0x8603, 0x230a, 0x2412, 0x0030, 0x939d, 0x0203, 0x94a5, + 0x8603, 0x230a, 0x2412, 0x9006, 0x080c, 0x2820, 0x9006, 0x080c, + 0x2803, 0x20a9, 0x0012, 0x1d04, 0x212b, 0x2091, 0x6000, 0x1f04, + 0x212b, 0x602f, 0x0100, 0x602f, 0x0000, 0x6050, 0x9085, 0x0400, + 0x9084, 0xdfff, 0x6052, 0x6024, 0x6026, 0x080c, 0x250f, 0x2009, + 0x00ef, 0x6132, 0x6136, 0x080c, 0x251f, 0x60e7, 0x0000, 0x61ea, + 0x60e3, 0x0008, 0x604b, 0xf7f7, 0x6043, 0x0000, 0x602f, 0x0080, + 0x602f, 0x0000, 0x6007, 0x049f, 0x60bb, 0x0000, 0x20a9, 0x0018, + 0x60bf, 0x0000, 0x1f04, 0x2158, 0x60bb, 0x0000, 0x60bf, 0x0108, + 0x60bf, 0x0012, 0x60bf, 0x0320, 0x60bf, 0x0018, 0x601b, 0x00f0, + 0x601f, 0x001e, 0x600f, 0x006b, 0x602b, 0x402f, 0x012e, 0x0005, + 0x00f6, 0x2079, 0x0140, 0x78c3, 0x0080, 0x78c3, 0x0083, 0x78c3, + 0x0000, 0x00fe, 0x0005, 0x2001, 0x1833, 0x2003, 0x0000, 0x2001, + 0x1832, 0x2003, 0x0001, 0x0005, 0x0126, 0x2091, 0x2800, 0x0006, + 0x0016, 0x0026, 0x6124, 0x9184, 0x5e2c, 0x1118, 0x9184, 0x0007, + 0x002a, 0x9195, 0x0004, 0x9284, 0x0007, 0x0002, 0x21b8, 0x219e, + 0x21a1, 0x21a4, 0x21a9, 0x21ab, 0x21af, 0x21b3, 0x080c, 0x7eec, + 0x00b8, 0x080c, 0x7fb9, 0x00a0, 0x080c, 0x7fb9, 0x080c, 0x7eec, + 0x0078, 0x0099, 0x0068, 0x080c, 0x7eec, 0x0079, 0x0048, 0x080c, + 0x7fb9, 0x0059, 0x0028, 0x080c, 0x7fb9, 0x080c, 0x7eec, 0x0029, + 0x002e, 0x001e, 0x000e, 0x012e, 0x0005, 0x00a6, 0x6124, 0x6028, + 0xd09c, 0x0118, 0xd19c, 0x1904, 0x2408, 0xd1f4, 0x0110, 0x080c, + 0x0db2, 0x080c, 0x6c53, 0x0904, 0x2214, 0x080c, 0xbcec, 0x1120, + 0x7000, 0x9086, 0x0003, 0x0570, 0x6024, 0x9084, 0x1800, 0x0550, + 0x080c, 0x6c76, 0x0118, 0x080c, 0x6c64, 0x1520, 0x6027, 0x0020, + 0x6043, 0x0000, 0x080c, 0xbcec, 0x0168, 0x080c, 0x6c76, 0x1150, + 0x2001, 0x1976, 0x2003, 0x0001, 0x6027, 0x1800, 0x080c, 0x6ad9, + 0x0804, 0x240b, 0x709c, 0x9005, 0x1150, 0x709f, 0x0001, 0x00d6, + 0x2069, 0x0140, 0x080c, 0x6caa, 0x00de, 0x1904, 0x240b, 0x080c, + 0x6f34, 0x0428, 0x080c, 0x6c76, 0x1590, 0x6024, 0x9084, 0x1800, + 0x1108, 0x0468, 0x080c, 0x6f34, 0x080c, 0x6f2a, 0x080c, 0x5a21, + 0x080c, 0x6b8a, 0x0804, 0x2408, 0xd1ac, 0x1508, 0x6024, 0xd0dc, + 0x1170, 0xd0e4, 0x1178, 0xd0d4, 0x1190, 0xd0cc, 0x0130, 0x7090, + 0x9086, 0x0028, 0x1110, 0x080c, 0x6e17, 0x0804, 0x2408, 0x080c, + 0x6f2f, 0x0048, 0x2001, 0x194e, 0x2003, 0x0002, 0x0020, 0x080c, + 0x6d8d, 0x0804, 0x2408, 0x080c, 0x6eb2, 0x0804, 0x2408, 0xd1ac, + 0x0904, 0x2329, 0x080c, 0x6c53, 0x11c0, 0x6027, 0x0020, 0x0006, + 0x0026, 0x0036, 0x080c, 0x6c6d, 0x1158, 0x080c, 0x6f2a, 0x080c, + 0x5a21, 0x080c, 0x6b8a, 0x003e, 0x002e, 0x000e, 0x00ae, 0x0005, + 0x003e, 0x002e, 0x000e, 0x080c, 0x6c2d, 0x0016, 0x0046, 0x00c6, + 0x644c, 0x9486, 0xf0f0, 0x1138, 0x2061, 0x0100, 0x644a, 0x6043, + 0x0090, 0x6043, 0x0010, 0x74d2, 0x948c, 0xff00, 0x7034, 0xd084, + 0x0178, 0x9186, 0xf800, 0x1160, 0x7040, 0xd084, 0x1148, 0xc085, + 0x7042, 0x0036, 0x2418, 0x2011, 0x8016, 0x080c, 0x4672, 0x003e, + 0x080c, 0xbce5, 0x1904, 0x2306, 0x9196, 0xff00, 0x05a8, 0x7058, + 0x9084, 0x00ff, 0x810f, 0x81ff, 0x0110, 0x9116, 0x0568, 0x7130, + 0xd184, 0x1550, 0x080c, 0x2f86, 0x0128, 0xc18d, 0x7132, 0x080c, + 0x629c, 0x1510, 0x6240, 0x9294, 0x0010, 0x0130, 0x6248, 0x9294, + 0xff00, 0x9296, 0xff00, 0x01c0, 0x7030, 0xd08c, 0x0904, 0x2306, + 0x7034, 0xd08c, 0x1140, 0x2001, 0x180c, 0x200c, 0xd1ac, 0x1904, + 0x2306, 0xc1ad, 0x2102, 0x0036, 0x73d0, 0x2011, 0x8013, 0x080c, + 0x4672, 0x003e, 0x0804, 0x2306, 0x7034, 0xd08c, 0x1140, 0x2001, + 0x180c, 0x200c, 0xd1ac, 0x1904, 0x2306, 0xc1ad, 0x2102, 0x0036, + 0x73d0, 0x2011, 0x8013, 0x080c, 0x4672, 0x003e, 0x7130, 0xc185, + 0x7132, 0x2011, 0x1854, 0x220c, 0xd1a4, 0x01f0, 0x0016, 0x2009, + 0x0001, 0x2011, 0x0100, 0x080c, 0x7e3e, 0x2019, 0x000e, 0x00c6, + 0x2061, 0x0000, 0x080c, 0xcf62, 0x00ce, 0x9484, 0x00ff, 0x9080, + 0x2f92, 0x200d, 0x918c, 0xff00, 0x810f, 0x2120, 0x9006, 0x2009, + 0x000e, 0x080c, 0xcfe6, 0x001e, 0xd1ac, 0x1148, 0x0016, 0x2009, + 0x0002, 0x2019, 0x0004, 0x080c, 0x2dfb, 0x001e, 0x0078, 0x0156, + 0x00b6, 0x20a9, 0x007f, 0x900e, 0x080c, 0x5f7e, 0x1110, 0x080c, + 0x5a3b, 0x8108, 0x1f04, 0x22fc, 0x00be, 0x015e, 0x00ce, 0x004e, + 0x080c, 0x9947, 0x60e3, 0x0000, 0x001e, 0x2001, 0x1800, 0x2014, + 0x9296, 0x0004, 0x1170, 0xd19c, 0x11a0, 0x2011, 0x180c, 0x2214, + 0xd29c, 0x1120, 0x6204, 0x9295, 0x0002, 0x6206, 0x6228, 0xc29d, + 0x622a, 0x2003, 0x0001, 0x2001, 0x1824, 0x2003, 0x0000, 0x6027, + 0x0020, 0xd194, 0x0904, 0x2408, 0x0016, 0x6220, 0xd2b4, 0x0904, + 0x23b1, 0x080c, 0x7cc7, 0x080c, 0x8fbb, 0x6027, 0x0004, 0x00f6, + 0x2019, 0x19bf, 0x2304, 0x907d, 0x0904, 0x2380, 0x7804, 0x9086, + 0x0032, 0x15f0, 0x00d6, 0x00c6, 0x00e6, 0x0096, 0x2069, 0x0140, + 0x782c, 0x685e, 0x7808, 0x685a, 0x6043, 0x0002, 0x2001, 0x0003, + 0x8001, 0x1df0, 0x6043, 0x0000, 0x2001, 0x003c, 0x8001, 0x1df0, + 0x080c, 0x2997, 0x2001, 0x001e, 0x8001, 0x0240, 0x20a9, 0x0009, + 0x080c, 0x28b1, 0x6904, 0xd1dc, 0x1140, 0x0cb0, 0x2001, 0x0100, + 0x080c, 0x2987, 0x9006, 0x080c, 0x2987, 0x080c, 0x847d, 0x080c, + 0x8582, 0x7814, 0x2048, 0xa867, 0x0103, 0x2f60, 0x080c, 0x99d6, + 0x009e, 0x00ee, 0x00ce, 0x00de, 0x00fe, 0x001e, 0x00ae, 0x0005, + 0x00fe, 0x00d6, 0x2069, 0x0140, 0x6804, 0x9084, 0x4000, 0x0110, + 0x080c, 0x2997, 0x00de, 0x00c6, 0x2061, 0x19b6, 0x6028, 0x080c, + 0xbcec, 0x0120, 0x909a, 0x0003, 0x1258, 0x0018, 0x909a, 0x00c8, + 0x1238, 0x8000, 0x602a, 0x00ce, 0x080c, 0x8f97, 0x0804, 0x2407, + 0x2061, 0x0100, 0x62c0, 0x080c, 0x97d2, 0x2019, 0x19bf, 0x2304, + 0x9065, 0x0120, 0x2009, 0x0027, 0x080c, 0x9a50, 0x00ce, 0x0804, + 0x2407, 0xd2bc, 0x0904, 0x23f4, 0x080c, 0x7cd4, 0x6014, 0x9084, + 0x1984, 0x9085, 0x0010, 0x6016, 0x6027, 0x0004, 0x00d6, 0x2069, + 0x0140, 0x6804, 0x9084, 0x4000, 0x0110, 0x080c, 0x2997, 0x00de, + 0x00c6, 0x2061, 0x19b6, 0x6044, 0x080c, 0xbcec, 0x0120, 0x909a, + 0x0003, 0x1628, 0x0018, 0x909a, 0x00c8, 0x1608, 0x8000, 0x6046, + 0x603c, 0x00ce, 0x9005, 0x0558, 0x2009, 0x07d0, 0x080c, 0x7ccc, + 0x9080, 0x0008, 0x2004, 0x9086, 0x0006, 0x1138, 0x6114, 0x918c, + 0x1984, 0x918d, 0x0012, 0x6116, 0x00d0, 0x6114, 0x918c, 0x1984, + 0x918d, 0x0016, 0x6116, 0x0098, 0x6027, 0x0004, 0x0080, 0x0036, + 0x2019, 0x0001, 0x080c, 0x9254, 0x003e, 0x2019, 0x19c5, 0x2304, + 0x9065, 0x0120, 0x2009, 0x004f, 0x080c, 0x9a50, 0x00ce, 0x001e, + 0xd19c, 0x0904, 0x247a, 0x7034, 0xd0ac, 0x1904, 0x244f, 0x0016, + 0x0156, 0x6027, 0x0008, 0x6050, 0x9085, 0x0040, 0x6052, 0x6050, + 0x9084, 0xfbcf, 0x6052, 0x080c, 0x28d0, 0x9085, 0x2000, 0x6052, + 0x20a9, 0x0012, 0x1d04, 0x2422, 0x080c, 0x7cfb, 0x1f04, 0x2422, + 0x6050, 0x9085, 0x0400, 0x9084, 0xdfbf, 0x6052, 0x20a9, 0x0028, + 0xa001, 0x1f04, 0x2430, 0x6150, 0x9185, 0x1400, 0x6052, 0x20a9, + 0x0366, 0x1d04, 0x2439, 0x080c, 0x7cfb, 0x6020, 0xd09c, 0x1130, + 0x015e, 0x6152, 0x001e, 0x6027, 0x0008, 0x04a0, 0x080c, 0x2898, + 0x1f04, 0x2439, 0x015e, 0x6152, 0x001e, 0x6027, 0x0008, 0x0016, + 0x6028, 0xc09c, 0x602a, 0x080c, 0x9947, 0x60e3, 0x0000, 0x080c, + 0xd343, 0x080c, 0xd35e, 0x080c, 0x5117, 0xd0fc, 0x1138, 0x080c, + 0xbce5, 0x1120, 0x9085, 0x0001, 0x080c, 0x6c9a, 0x9006, 0x080c, + 0x2987, 0x2009, 0x0002, 0x080c, 0x28d6, 0x00e6, 0x2071, 0x1800, + 0x7003, 0x0004, 0x080c, 0x0e69, 0x00ee, 0x6027, 0x0008, 0x080c, + 0x0b94, 0x001e, 0x918c, 0xffd0, 0x6126, 0x00ae, 0x0005, 0x0006, + 0x0016, 0x0026, 0x0036, 0x00e6, 0x00f6, 0x0126, 0x2091, 0x8000, + 0x2071, 0x1800, 0x71c8, 0x70ca, 0x9116, 0x0904, 0x24ce, 0x81ff, + 0x01a0, 0x2009, 0x0000, 0x080c, 0x28d6, 0x2011, 0x8011, 0x2019, + 0x010e, 0x231c, 0x939e, 0x0007, 0x1118, 0x2019, 0x0001, 0x0010, + 0x2019, 0x0000, 0x080c, 0x4672, 0x0448, 0x2001, 0x1977, 0x200c, + 0x81ff, 0x1140, 0x2001, 0x0109, 0x2004, 0xd0b4, 0x0118, 0x2019, + 0x0003, 0x0008, 0x2118, 0x2011, 0x8012, 0x080c, 0x4672, 0x080c, + 0x0e69, 0x080c, 0x5117, 0xd0fc, 0x1188, 0x080c, 0xbce5, 0x1170, + 0x00c6, 0x080c, 0x256a, 0x080c, 0x91bb, 0x2061, 0x0100, 0x2019, + 0x0028, 0x2009, 0x0002, 0x080c, 0x2dfb, 0x00ce, 0x012e, 0x00fe, + 0x00ee, 0x003e, 0x002e, 0x001e, 0x000e, 0x0005, 0x2028, 0x918c, + 0x00ff, 0x2130, 0x9094, 0xff00, 0x11f0, 0x2011, 0x1835, 0x2214, + 0xd2ac, 0x11c8, 0x81ff, 0x01e8, 0x2011, 0x181d, 0x2204, 0x9106, + 0x1190, 0x2011, 0x181e, 0x2214, 0x9294, 0xff00, 0x9584, 0xff00, + 0x9206, 0x1148, 0x2011, 0x181e, 0x2214, 0x9294, 0x00ff, 0x9584, + 0x00ff, 0x9206, 0x1120, 0x2500, 0x080c, 0x7876, 0x0048, 0x9584, + 0x00ff, 0x9080, 0x2f92, 0x200d, 0x918c, 0xff00, 0x810f, 0x9006, + 0x0005, 0x9080, 0x2f92, 0x200d, 0x918c, 0x00ff, 0x0005, 0x00d6, + 0x2069, 0x0140, 0x2001, 0x1816, 0x2003, 0x00ef, 0x20a9, 0x0010, + 0x9006, 0x6852, 0x6856, 0x1f04, 0x251a, 0x00de, 0x0005, 0x0006, + 0x00d6, 0x0026, 0x2069, 0x0140, 0x2001, 0x1816, 0x2102, 0x8114, + 0x8214, 0x8214, 0x8214, 0x20a9, 0x0010, 0x6853, 0x0000, 0x9006, + 0x82ff, 0x1128, 0x9184, 0x000f, 0x9080, 0xd74a, 0x2005, 0x6856, + 0x8211, 0x1f04, 0x252f, 0x002e, 0x00de, 0x000e, 0x0005, 0x00c6, + 0x2061, 0x1800, 0x6030, 0x0110, 0xc09d, 0x0008, 0xc09c, 0x6032, + 0x00ce, 0x0005, 0x0156, 0x00d6, 0x0026, 0x0016, 0x0006, 0x2069, + 0x0140, 0x6980, 0x9116, 0x0180, 0x9112, 0x1230, 0x8212, 0x8210, + 0x22a8, 0x2001, 0x0402, 0x0018, 0x22a8, 0x2001, 0x0404, 0x680e, + 0x1f04, 0x255f, 0x680f, 0x0000, 0x000e, 0x001e, 0x002e, 0x00de, + 0x015e, 0x0005, 0x080c, 0x5113, 0xd0c4, 0x0150, 0xd0a4, 0x0140, + 0x9006, 0x0046, 0x2020, 0x2009, 0x002e, 0x080c, 0xcfe6, 0x004e, + 0x0005, 0x00f6, 0x0016, 0x0026, 0x2079, 0x0140, 0x78c4, 0xd0dc, + 0x0904, 0x25d6, 0x080c, 0x2835, 0x0660, 0x9084, 0x0700, 0x908e, + 0x0600, 0x1120, 0x2011, 0x4000, 0x900e, 0x0458, 0x908e, 0x0500, + 0x1120, 0x2011, 0x8000, 0x900e, 0x0420, 0x908e, 0x0400, 0x1120, + 0x9016, 0x2009, 0x0001, 0x00e8, 0x908e, 0x0300, 0x1120, 0x9016, + 0x2009, 0x0002, 0x00b0, 0x908e, 0x0200, 0x1120, 0x9016, 0x2009, + 0x0004, 0x0078, 0x908e, 0x0100, 0x1548, 0x9016, 0x2009, 0x0008, + 0x0040, 0x9084, 0x0700, 0x908e, 0x0300, 0x1500, 0x2011, 0x0030, + 0x0058, 0x2300, 0x9080, 0x0020, 0x2018, 0x080c, 0x7e7f, 0x928c, + 0xff00, 0x0110, 0x2011, 0x00ff, 0x2200, 0x8007, 0x9085, 0x004c, + 0x78c2, 0x2009, 0x0138, 0x220a, 0x080c, 0x6c53, 0x1118, 0x2009, + 0x193e, 0x220a, 0x002e, 0x001e, 0x00fe, 0x0005, 0x78c3, 0x0000, + 0x0cc8, 0x0126, 0x2091, 0x2800, 0x0006, 0x0016, 0x0026, 0x2001, + 0x0170, 0x200c, 0x8000, 0x2014, 0x9184, 0x0003, 0x0110, 0x080c, + 0x0db2, 0x002e, 0x001e, 0x000e, 0x012e, 0x0005, 0x2001, 0x0171, + 0x2004, 0xd0dc, 0x0168, 0x2001, 0x0170, 0x200c, 0x918c, 0x00ff, + 0x918e, 0x004c, 0x1128, 0x200c, 0x918c, 0xff00, 0x810f, 0x0005, + 0x900e, 0x2001, 0x0227, 0x2004, 0x8007, 0x9084, 0x00ff, 0x8004, + 0x9108, 0x2001, 0x0226, 0x2004, 0x8007, 0x9084, 0x00ff, 0x8004, + 0x9108, 0x0005, 0x0018, 0x000c, 0x0018, 0x0020, 0x1000, 0x0800, + 0x1000, 0x1800, 0x0156, 0x0006, 0x0016, 0x0026, 0x00e6, 0x2001, + 0x195f, 0x2004, 0x908a, 0x0007, 0x1a0c, 0x0db2, 0x0033, 0x00ee, + 0x002e, 0x001e, 0x000e, 0x015e, 0x0005, 0x2634, 0x2652, 0x2676, + 0x2678, 0x26a1, 0x26a3, 0x26a5, 0x2001, 0x0001, 0x080c, 0x247f, + 0x080c, 0x2893, 0x2001, 0x1961, 0x2003, 0x0000, 0x7828, 0x9084, + 0xe1d7, 0x782a, 0x9006, 0x20a9, 0x0009, 0x080c, 0x2851, 0x2001, + 0x195f, 0x2003, 0x0006, 0x2009, 0x001e, 0x2011, 0x26a6, 0x080c, + 0x7cd9, 0x0005, 0x2009, 0x1964, 0x200b, 0x0000, 0x2001, 0x1969, + 0x2003, 0x0036, 0x2001, 0x1968, 0x2003, 0x002a, 0x2001, 0x1961, + 0x2003, 0x0001, 0x9006, 0x080c, 0x2803, 0x2001, 0xffff, 0x20a9, + 0x0009, 0x080c, 0x2851, 0x2001, 0x195f, 0x2003, 0x0006, 0x2009, + 0x001e, 0x2011, 0x26a6, 0x080c, 0x7cd9, 0x0005, 0x080c, 0x0db2, + 0x2001, 0x1969, 0x2003, 0x0036, 0x2001, 0x1961, 0x2003, 0x0003, + 0x7a38, 0x9294, 0x0005, 0x9296, 0x0004, 0x0110, 0x9006, 0x0010, + 0x2001, 0x0001, 0x080c, 0x2803, 0x2001, 0x1965, 0x2003, 0x0000, + 0x2001, 0xffff, 0x20a9, 0x0009, 0x080c, 0x2851, 0x2001, 0x195f, + 0x2003, 0x0006, 0x2009, 0x001e, 0x2011, 0x26a6, 0x080c, 0x7cd9, + 0x0005, 0x080c, 0x0db2, 0x080c, 0x0db2, 0x0005, 0x0006, 0x0016, + 0x0026, 0x00e6, 0x00f6, 0x0156, 0x0126, 0x2091, 0x8000, 0x2079, + 0x0100, 0x2001, 0x1961, 0x2004, 0x908a, 0x0007, 0x1a0c, 0x0db2, + 0x0043, 0x012e, 0x015e, 0x00fe, 0x00ee, 0x002e, 0x001e, 0x000e, + 0x0005, 0x26c8, 0x26e8, 0x2728, 0x2758, 0x277c, 0x278c, 0x278e, + 0x080c, 0x2845, 0x11b0, 0x7850, 0x9084, 0xefff, 0x7852, 0x2009, + 0x1967, 0x2104, 0x7a38, 0x9294, 0x0005, 0x9296, 0x0004, 0x0110, + 0xc08d, 0x0008, 0xc085, 0x200a, 0x2001, 0x195f, 0x2003, 0x0001, + 0x0030, 0x080c, 0x27b2, 0x2001, 0xffff, 0x080c, 0x2643, 0x0005, + 0x080c, 0x2790, 0x05e0, 0x2009, 0x1968, 0x2104, 0x8001, 0x200a, + 0x080c, 0x2845, 0x1178, 0x7850, 0x9084, 0xefff, 0x7852, 0x7a38, + 0x9294, 0x0005, 0x9296, 0x0005, 0x0518, 0x2009, 0x1967, 0x2104, + 0xc085, 0x200a, 0x2009, 0x1964, 0x2104, 0x8000, 0x200a, 0x9086, + 0x0005, 0x0118, 0x080c, 0x2798, 0x00c0, 0x200b, 0x0000, 0x7a38, + 0x9294, 0x0006, 0x9296, 0x0004, 0x0110, 0x9006, 0x0010, 0x2001, + 0x0001, 0x080c, 0x2820, 0x2001, 0x1961, 0x2003, 0x0002, 0x0028, + 0x2001, 0x195f, 0x2003, 0x0003, 0x0010, 0x080c, 0x2665, 0x0005, + 0x080c, 0x2790, 0x0560, 0x2009, 0x1968, 0x2104, 0x8001, 0x200a, + 0x080c, 0x2845, 0x1168, 0x7850, 0x9084, 0xefff, 0x7852, 0x2001, + 0x195f, 0x2003, 0x0003, 0x2001, 0x1960, 0x2003, 0x0000, 0x00b8, + 0x2009, 0x1968, 0x2104, 0x9005, 0x1118, 0x080c, 0x27d5, 0x0010, + 0x080c, 0x27a5, 0x080c, 0x2798, 0x2009, 0x1964, 0x200b, 0x0000, + 0x2001, 0x1961, 0x2003, 0x0001, 0x080c, 0x2665, 0x0000, 0x0005, + 0x04b9, 0x0508, 0x080c, 0x2845, 0x11b8, 0x7850, 0x9084, 0xefff, + 0x7852, 0x2009, 0x1965, 0x2104, 0x8000, 0x200a, 0x9086, 0x0007, + 0x0108, 0x0078, 0x2001, 0x196a, 0x2003, 0x000a, 0x2009, 0x1967, + 0x2104, 0xc0fd, 0x200a, 0x0038, 0x0419, 0x2001, 0x1961, 0x2003, + 0x0004, 0x080c, 0x2690, 0x0005, 0x0099, 0x0168, 0x080c, 0x2845, + 0x1138, 0x7850, 0x9084, 0xefff, 0x7852, 0x080c, 0x267c, 0x0018, + 0x0079, 0x080c, 0x2690, 0x0005, 0x080c, 0x0db2, 0x080c, 0x0db2, + 0x2009, 0x1969, 0x2104, 0x8001, 0x200a, 0x090c, 0x27f1, 0x0005, + 0x7a38, 0x9294, 0x0005, 0x9296, 0x0005, 0x0110, 0x9006, 0x0010, + 0x2001, 0x0001, 0x080c, 0x2820, 0x0005, 0x7a38, 0x9294, 0x0006, + 0x9296, 0x0006, 0x0110, 0x9006, 0x0010, 0x2001, 0x0001, 0x080c, + 0x2803, 0x0005, 0x2009, 0x1964, 0x2104, 0x8000, 0x200a, 0x9086, + 0x0005, 0x0108, 0x0068, 0x200b, 0x0000, 0x7a38, 0x9294, 0x0006, + 0x9296, 0x0006, 0x0110, 0x9006, 0x0010, 0x2001, 0x0001, 0x04d9, + 0x7a38, 0x9294, 0x0005, 0x9296, 0x0005, 0x0110, 0x9006, 0x0010, + 0x2001, 0x0001, 0x080c, 0x2820, 0x0005, 0x0086, 0x2001, 0x1967, + 0x2004, 0x9084, 0x7fff, 0x090c, 0x0db2, 0x2009, 0x1966, 0x2144, + 0x8846, 0x280a, 0x9844, 0x0dd8, 0xd08c, 0x1120, 0xd084, 0x1120, + 0x080c, 0x0db2, 0x9006, 0x0010, 0x2001, 0x0001, 0x00a1, 0x008e, + 0x0005, 0x0006, 0x0156, 0x2001, 0x195f, 0x20a9, 0x0009, 0x2003, + 0x0000, 0x8000, 0x1f04, 0x27f7, 0x2001, 0x1966, 0x2003, 0x8000, + 0x015e, 0x000e, 0x0005, 0x00f6, 0x2079, 0x0100, 0x9085, 0x0000, + 0x0158, 0x7838, 0x9084, 0xfff9, 0x9085, 0x0004, 0x783a, 0x2009, + 0x196c, 0x210c, 0x795a, 0x0050, 0x7838, 0x9084, 0xfffb, 0x9085, + 0x0006, 0x783a, 0x2009, 0x196d, 0x210c, 0x795a, 0x00fe, 0x0005, + 0x00f6, 0x2079, 0x0100, 0x9085, 0x0000, 0x0138, 0x7838, 0x9084, + 0xfffa, 0x9085, 0x0004, 0x783a, 0x0030, 0x7838, 0x9084, 0xfffb, + 0x9085, 0x0005, 0x783a, 0x00fe, 0x0005, 0x0006, 0x2001, 0x0100, + 0x2004, 0x9082, 0x0007, 0x000e, 0x0005, 0x0006, 0x2001, 0x0100, + 0x2004, 0x9082, 0x0009, 0x000e, 0x0005, 0x0156, 0x20a9, 0x0064, + 0x7820, 0x080c, 0x28d0, 0xd09c, 0x1110, 0x1f04, 0x2848, 0x015e, + 0x0005, 0x0126, 0x0016, 0x0006, 0x2091, 0x8000, 0x7850, 0x9085, + 0x0040, 0x7852, 0x7850, 0x9084, 0xfbcf, 0x7852, 0x080c, 0x28d0, + 0x9085, 0x2000, 0x7852, 0x000e, 0x2008, 0x9186, 0x0000, 0x1118, + 0x783b, 0x0007, 0x0090, 0x9186, 0x0001, 0x1118, 0x783b, 0x0006, + 0x0060, 0x9186, 0x0002, 0x1118, 0x783b, 0x0005, 0x0030, 0x9186, + 0x0003, 0x1118, 0x783b, 0x0004, 0x0000, 0x0006, 0x1d04, 0x287e, + 0x080c, 0x7cfb, 0x1f04, 0x287e, 0x7850, 0x9085, 0x0400, 0x9084, + 0xdfbf, 0x7852, 0x080c, 0x28d0, 0x9085, 0x1000, 0x7852, 0x000e, + 0x001e, 0x012e, 0x0005, 0x7850, 0x9084, 0xffcf, 0x7852, 0x0005, + 0x0006, 0x0156, 0x00f6, 0x2079, 0x0100, 0x20a9, 0x000a, 0x7854, + 0xd0ac, 0x1130, 0x7820, 0xd0e4, 0x1140, 0x1f04, 0x28a2, 0x0028, + 0x7854, 0xd08c, 0x1110, 0x1f04, 0x28a8, 0x00fe, 0x015e, 0x000e, + 0x0005, 0x1d04, 0x28b1, 0x080c, 0x7cfb, 0x1f04, 0x28b1, 0x0005, + 0x0006, 0x2001, 0x196b, 0x2004, 0x9086, 0x0000, 0x000e, 0x0005, + 0x0006, 0x2001, 0x196b, 0x2004, 0x9086, 0x0001, 0x000e, 0x0005, + 0x0006, 0x2001, 0x196b, 0x2004, 0x9086, 0x0002, 0x000e, 0x0005, + 0xa001, 0xa001, 0xa001, 0xa001, 0xa001, 0x0005, 0x0006, 0x2001, + 0x1977, 0x2102, 0x000e, 0x0005, 0x2009, 0x0171, 0x2104, 0xd0dc, + 0x0140, 0x2009, 0x0170, 0x2104, 0x200b, 0x0080, 0xa001, 0xa001, + 0x200a, 0x0005, 0x0036, 0x0046, 0x2001, 0x0141, 0x200c, 0x918c, + 0xff00, 0x9186, 0x2000, 0x0118, 0x9186, 0x0100, 0x1588, 0x2009, + 0x017f, 0x200b, 0x00a2, 0x2019, 0x0160, 0x2324, 0x2011, 0x0003, + 0x2009, 0x0169, 0x2104, 0x9084, 0x0007, 0x210c, 0x918c, 0x0007, + 0x910e, 0x1db0, 0x9086, 0x0003, 0x11b8, 0x2304, 0x9402, 0x02a0, + 0x1d60, 0x8211, 0x1d68, 0x84ff, 0x0170, 0x2001, 0x0141, 0x200c, + 0x918c, 0xff00, 0x9186, 0x0100, 0x0130, 0x2009, 0x180c, 0x2104, + 0xc0dd, 0x200a, 0x0008, 0x0419, 0x2001, 0x017f, 0x2003, 0x0000, + 0x004e, 0x003e, 0x0005, 0x2001, 0x180c, 0x2004, 0xd0dc, 0x01b0, + 0x2001, 0x0160, 0x2004, 0x9005, 0x0140, 0x2001, 0x0141, 0x2004, + 0x9084, 0xff00, 0x9086, 0x0100, 0x1148, 0x0126, 0x2091, 0x8000, + 0x0016, 0x0026, 0x0021, 0x002e, 0x001e, 0x012e, 0x0005, 0x00c6, + 0x2061, 0x0100, 0x6014, 0x0006, 0x2001, 0x0161, 0x2003, 0x0000, + 0x6017, 0x0018, 0xa001, 0xa001, 0x602f, 0x0008, 0x6104, 0x918e, + 0x0010, 0x6106, 0x918e, 0x0010, 0x6106, 0x6017, 0x0040, 0x04b9, + 0x001e, 0x9184, 0x0003, 0x01e0, 0x0036, 0x0016, 0x2019, 0x0141, + 0x6124, 0x918c, 0x0028, 0x1120, 0x2304, 0x9084, 0x2800, 0x0dc0, + 0x001e, 0x919c, 0xffe4, 0x9184, 0x0001, 0x0118, 0x9385, 0x0009, + 0x6016, 0x9184, 0x0002, 0x0118, 0x9385, 0x0012, 0x6016, 0x003e, + 0x2001, 0x180c, 0x200c, 0xc1dc, 0x2102, 0x00ce, 0x0005, 0x0016, + 0x0026, 0x080c, 0x6c6d, 0x0108, 0xc0bc, 0x2009, 0x0140, 0x2114, + 0x9294, 0x0001, 0x9215, 0x220a, 0x002e, 0x001e, 0x0005, 0x0016, + 0x0026, 0x2009, 0x0140, 0x2114, 0x9294, 0x0001, 0x9285, 0x1000, + 0x200a, 0x220a, 0x002e, 0x001e, 0x0005, 0x0016, 0x0026, 0x2009, + 0x0140, 0x2114, 0x9294, 0x0001, 0x9215, 0x220a, 0x002e, 0x001e, + 0x0005, 0x0006, 0x0016, 0x2009, 0x0140, 0x2104, 0x1110, 0xc0bc, + 0x0008, 0xc0bd, 0x200a, 0x001e, 0x000e, 0x0005, 0x2c2a, 0x2c2a, + 0x2a4e, 0x2a4e, 0x2a5a, 0x2a5a, 0x2a66, 0x2a66, 0x2a74, 0x2a74, + 0x2a80, 0x2a80, 0x2a8e, 0x2a8e, 0x2a9c, 0x2a9c, 0x2aae, 0x2aae, + 0x2aba, 0x2aba, 0x2ac8, 0x2ac8, 0x2ae6, 0x2ae6, 0x2b06, 0x2b06, + 0x2ad6, 0x2ad6, 0x2af6, 0x2af6, 0x2b14, 0x2b14, 0x2aac, 0x2aac, + 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, + 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, + 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, + 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2b26, 0x2b26, + 0x2b32, 0x2b32, 0x2b40, 0x2b40, 0x2b4e, 0x2b4e, 0x2b5e, 0x2b5e, + 0x2b6c, 0x2b6c, 0x2b7c, 0x2b7c, 0x2b8c, 0x2b8c, 0x2b9e, 0x2b9e, + 0x2bac, 0x2bac, 0x2bbc, 0x2bbc, 0x2bde, 0x2bde, 0x2c00, 0x2c00, + 0x2bcc, 0x2bcc, 0x2bef, 0x2bef, 0x2c0f, 0x2c0f, 0x2aac, 0x2aac, + 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, + 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, + 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, + 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, + 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, + 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x2aac, 0x0106, 0x0006, + 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x2184, + 0x0804, 0x2c22, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, + 0x0146, 0x0156, 0x080c, 0x1f9f, 0x0804, 0x2c22, 0x0106, 0x0006, + 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x1f9f, + 0x080c, 0x2184, 0x0804, 0x2c22, 0x0106, 0x0006, 0x0126, 0x01c6, + 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x1fd7, 0x0804, 0x2c22, + 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, + 0x080c, 0x2184, 0x080c, 0x1fd7, 0x0804, 0x2c22, 0x0106, 0x0006, + 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x1f9f, + 0x080c, 0x1fd7, 0x0804, 0x2c22, 0x0106, 0x0006, 0x0126, 0x01c6, + 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x1f9f, 0x080c, 0x2184, + 0x080c, 0x1fd7, 0x0804, 0x2c22, 0xa001, 0x0cf0, 0x0106, 0x0006, + 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x12d6, + 0x0804, 0x2c22, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, + 0x0146, 0x0156, 0x080c, 0x2184, 0x080c, 0x12d6, 0x0804, 0x2c22, + 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, + 0x080c, 0x1f9f, 0x080c, 0x12d6, 0x0804, 0x2c22, 0x0106, 0x0006, + 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x2184, + 0x080c, 0x12d6, 0x080c, 0x1fd7, 0x0804, 0x2c22, 0x0106, 0x0006, + 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x1f9f, + 0x080c, 0x2184, 0x080c, 0x12d6, 0x0804, 0x2c22, 0x0106, 0x0006, + 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x1f9f, + 0x080c, 0x12d6, 0x080c, 0x1fd7, 0x0804, 0x2c22, 0x0106, 0x0006, + 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x12d6, + 0x080c, 0x1fd7, 0x0804, 0x2c22, 0x0106, 0x0006, 0x0126, 0x01c6, + 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x1f9f, 0x080c, 0x2184, + 0x080c, 0x12d6, 0x080c, 0x1fd7, 0x0804, 0x2c22, 0x0106, 0x0006, + 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x25d9, + 0x0804, 0x2c22, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, + 0x0146, 0x0156, 0x080c, 0x25d9, 0x080c, 0x2184, 0x0804, 0x2c22, + 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, + 0x080c, 0x25d9, 0x080c, 0x1f9f, 0x0804, 0x2c22, 0x0106, 0x0006, + 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x25d9, + 0x080c, 0x1f9f, 0x080c, 0x2184, 0x0804, 0x2c22, 0x0106, 0x0006, + 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x25d9, + 0x080c, 0x1fd7, 0x0804, 0x2c22, 0x0106, 0x0006, 0x0126, 0x01c6, + 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x25d9, 0x080c, 0x2184, + 0x080c, 0x1fd7, 0x0804, 0x2c22, 0x0106, 0x0006, 0x0126, 0x01c6, + 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x25d9, 0x080c, 0x1f9f, + 0x080c, 0x1fd7, 0x0804, 0x2c22, 0x0106, 0x0006, 0x0126, 0x01c6, + 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x25d9, 0x080c, 0x1f9f, + 0x080c, 0x2184, 0x080c, 0x1fd7, 0x0804, 0x2c22, 0x0106, 0x0006, + 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x25d9, + 0x080c, 0x12d6, 0x0804, 0x2c22, 0x0106, 0x0006, 0x0126, 0x01c6, + 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x25d9, 0x080c, 0x2184, + 0x080c, 0x12d6, 0x0804, 0x2c22, 0x0106, 0x0006, 0x0126, 0x01c6, + 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x25d9, 0x080c, 0x1f9f, + 0x080c, 0x12d6, 0x0804, 0x2c22, 0x0106, 0x0006, 0x0126, 0x01c6, + 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x25d9, 0x080c, 0x2184, + 0x080c, 0x12d6, 0x080c, 0x1fd7, 0x0804, 0x2c22, 0x0106, 0x0006, + 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x25d9, + 0x080c, 0x1f9f, 0x080c, 0x2184, 0x080c, 0x12d6, 0x0498, 0x0106, + 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, + 0x25d9, 0x080c, 0x1f9f, 0x080c, 0x12d6, 0x080c, 0x1fd7, 0x0410, + 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, + 0x080c, 0x25d9, 0x080c, 0x12d6, 0x080c, 0x1fd7, 0x0098, 0x0106, + 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, + 0x25d9, 0x080c, 0x1f9f, 0x080c, 0x2184, 0x080c, 0x12d6, 0x080c, + 0x1fd7, 0x0000, 0x015e, 0x014e, 0x013e, 0x01de, 0x01ce, 0x012e, + 0x000e, 0x010e, 0x000d, 0x00b6, 0x00c6, 0x0026, 0x0046, 0x9026, + 0x080c, 0x6262, 0x1904, 0x2d17, 0x72d4, 0x2001, 0x194d, 0x2004, + 0x9005, 0x1110, 0xd29c, 0x0148, 0xd284, 0x1138, 0xd2bc, 0x1904, + 0x2d17, 0x080c, 0x2d1c, 0x0804, 0x2d17, 0xd2cc, 0x1904, 0x2d17, + 0x080c, 0x6c53, 0x1120, 0x70a7, 0xffff, 0x0804, 0x2d17, 0xd294, + 0x0120, 0x70a7, 0xffff, 0x0804, 0x2d17, 0x080c, 0x2f81, 0x0160, + 0x080c, 0xbcec, 0x0128, 0x2001, 0x1816, 0x203c, 0x0804, 0x2cb5, + 0x70a7, 0xffff, 0x0804, 0x2d17, 0x2001, 0x1816, 0x203c, 0x728c, + 0xd284, 0x0904, 0x2cb5, 0xd28c, 0x1904, 0x2cb5, 0x0036, 0x73a4, + 0x938e, 0xffff, 0x1110, 0x2019, 0x0001, 0x8314, 0x92e0, 0x1c80, + 0x2c04, 0x938c, 0x0001, 0x0120, 0x9084, 0xff00, 0x8007, 0x0010, + 0x9084, 0x00ff, 0x970e, 0x0540, 0x908e, 0x0000, 0x0528, 0x908e, + 0x00ff, 0x1150, 0x7230, 0xd284, 0x1518, 0x728c, 0xc28d, 0x728e, + 0x70a7, 0xffff, 0x003e, 0x0408, 0x900e, 0x080c, 0x24d6, 0x080c, + 0x5f1e, 0x11a0, 0x080c, 0x62a4, 0x1150, 0x7030, 0xd08c, 0x0118, + 0xb800, 0xd0bc, 0x0120, 0x080c, 0x2d35, 0x0140, 0x0028, 0x080c, + 0x2e71, 0x080c, 0x2d61, 0x0110, 0x8318, 0x0838, 0x73a6, 0x0010, + 0x70a7, 0xffff, 0x003e, 0x0804, 0x2d17, 0x9780, 0x2f92, 0x203d, + 0x97bc, 0xff00, 0x873f, 0x2041, 0x007e, 0x70a4, 0x9096, 0xffff, + 0x1118, 0x900e, 0x28a8, 0x0050, 0x9812, 0x0220, 0x2008, 0x9802, + 0x20a8, 0x0020, 0x70a7, 0xffff, 0x0804, 0x2d17, 0x2700, 0x0156, + 0x0016, 0x9106, 0x05c8, 0xc484, 0x080c, 0x5f7e, 0x0138, 0x080c, + 0xbcec, 0x1590, 0x080c, 0x5f1e, 0x15b8, 0x0008, 0xc485, 0x080c, + 0x62a4, 0x1130, 0x7030, 0xd08c, 0x01f8, 0xb800, 0xd0bc, 0x11e0, + 0x728c, 0xd28c, 0x0180, 0x080c, 0x62a4, 0x9082, 0x0006, 0x02e0, + 0xd484, 0x1118, 0x080c, 0x5f42, 0x0028, 0x080c, 0x2efd, 0x01a0, + 0x080c, 0x2f28, 0x0088, 0x080c, 0x2e71, 0x080c, 0xbcec, 0x1160, + 0x080c, 0x2d61, 0x0188, 0x0040, 0x080c, 0xbcec, 0x1118, 0x080c, + 0x2efd, 0x0110, 0x0451, 0x0140, 0x001e, 0x8108, 0x015e, 0x1f04, + 0x2cce, 0x70a7, 0xffff, 0x0018, 0x001e, 0x015e, 0x71a6, 0x004e, + 0x002e, 0x00ce, 0x00be, 0x0005, 0x00c6, 0x0016, 0x70a7, 0x0001, + 0x2009, 0x007e, 0x080c, 0x5f1e, 0x1168, 0xb813, 0x00ff, 0xb817, + 0xfffe, 0x080c, 0x2e71, 0x04a9, 0x0128, 0x70d4, 0xc0bd, 0x70d6, + 0x080c, 0xba40, 0x001e, 0x00ce, 0x0005, 0x0016, 0x0076, 0x00d6, + 0x00c6, 0x2001, 0x1858, 0x2004, 0x9084, 0x00ff, 0xb842, 0x080c, + 0x9a23, 0x01d0, 0x2b00, 0x6012, 0x080c, 0xba69, 0x6023, 0x0001, + 0x9006, 0x080c, 0x5ebb, 0x2001, 0x0000, 0x080c, 0x5ecf, 0x0126, + 0x2091, 0x8000, 0x70a0, 0x8000, 0x70a2, 0x012e, 0x2009, 0x0004, + 0x080c, 0x9a50, 0x9085, 0x0001, 0x00ce, 0x00de, 0x007e, 0x001e, + 0x0005, 0x0016, 0x0076, 0x00d6, 0x00c6, 0x2001, 0x1858, 0x2004, + 0x9084, 0x00ff, 0xb842, 0x080c, 0x9a23, 0x0548, 0x2b00, 0x6012, + 0xb800, 0xc0c4, 0xb802, 0xb8a0, 0x9086, 0x007e, 0x0140, 0xb804, + 0x9084, 0x00ff, 0x9086, 0x0006, 0x1110, 0x080c, 0x2e30, 0x080c, + 0xba69, 0x6023, 0x0001, 0x9006, 0x080c, 0x5ebb, 0x2001, 0x0002, + 0x080c, 0x5ecf, 0x0126, 0x2091, 0x8000, 0x70a0, 0x8000, 0x70a2, + 0x012e, 0x2009, 0x0002, 0x080c, 0x9a50, 0x9085, 0x0001, 0x00ce, + 0x00de, 0x007e, 0x001e, 0x0005, 0x00b6, 0x00c6, 0x0026, 0x2009, + 0x0080, 0x080c, 0x5f1e, 0x1140, 0xb813, 0x00ff, 0xb817, 0xfffc, + 0x0039, 0x0110, 0x70db, 0xffff, 0x002e, 0x00ce, 0x00be, 0x0005, + 0x0016, 0x0076, 0x00d6, 0x00c6, 0x080c, 0x9980, 0x01d0, 0x2b00, + 0x6012, 0x080c, 0xba69, 0x6023, 0x0001, 0x9006, 0x080c, 0x5ebb, + 0x2001, 0x0002, 0x080c, 0x5ecf, 0x0126, 0x2091, 0x8000, 0x70dc, + 0x8000, 0x70de, 0x012e, 0x2009, 0x0002, 0x080c, 0x9a50, 0x9085, + 0x0001, 0x00ce, 0x00de, 0x007e, 0x001e, 0x0005, 0x00c6, 0x00d6, + 0x0126, 0x2091, 0x8000, 0x2009, 0x007f, 0x080c, 0x5f1e, 0x11b8, + 0xb813, 0x00ff, 0xb817, 0xfffd, 0xb8bf, 0x0004, 0x080c, 0x9980, + 0x0170, 0x2b00, 0x6012, 0x6316, 0x6023, 0x0001, 0x620a, 0x080c, + 0xba69, 0x2009, 0x0022, 0x080c, 0x9a50, 0x9085, 0x0001, 0x012e, + 0x00de, 0x00ce, 0x0005, 0x00e6, 0x00c6, 0x0066, 0x0036, 0x0026, + 0x00b6, 0x21f0, 0x080c, 0x818b, 0x080c, 0x811a, 0x080c, 0x9819, + 0x080c, 0xa893, 0x3e08, 0x2130, 0x81ff, 0x0120, 0x20a9, 0x007e, + 0x900e, 0x0018, 0x20a9, 0x007f, 0x900e, 0x0016, 0x080c, 0x5f7e, + 0x1140, 0x9686, 0x0002, 0x1118, 0xb800, 0xd0bc, 0x1110, 0x080c, + 0x5a3b, 0x001e, 0x8108, 0x1f04, 0x2e15, 0x9686, 0x0001, 0x190c, + 0x2f55, 0x00be, 0x002e, 0x003e, 0x006e, 0x00ce, 0x00ee, 0x0005, + 0x00e6, 0x00c6, 0x0036, 0x0026, 0x0016, 0x00b6, 0x6210, 0x2258, + 0xbaa0, 0x0026, 0x2019, 0x0029, 0x080c, 0x8180, 0x0076, 0x2039, + 0x0000, 0x080c, 0x8078, 0x2c08, 0x080c, 0xcd62, 0x007e, 0x001e, + 0xba10, 0xbb14, 0x080c, 0x5a3b, 0xba12, 0xbb16, 0x00be, 0x001e, + 0x002e, 0x003e, 0x00ce, 0x00ee, 0x0005, 0x00e6, 0x0006, 0x00b6, + 0x6010, 0x2058, 0xb8a0, 0x00be, 0x9086, 0x0080, 0x0150, 0x2071, + 0x1800, 0x70a0, 0x9005, 0x0110, 0x8001, 0x70a2, 0x000e, 0x00ee, + 0x0005, 0x2071, 0x1800, 0x70dc, 0x9005, 0x0dc0, 0x8001, 0x70de, + 0x0ca8, 0xb800, 0xc08c, 0xb802, 0x0005, 0x00f6, 0x00e6, 0x00c6, + 0x00b6, 0x0036, 0x0026, 0x0016, 0x0156, 0x2178, 0x81ff, 0x1118, + 0x20a9, 0x0001, 0x0088, 0x080c, 0x5113, 0xd0c4, 0x0150, 0xd0a4, + 0x0140, 0x9006, 0x0046, 0x2020, 0x2009, 0x002d, 0x080c, 0xcfe6, + 0x004e, 0x20a9, 0x0800, 0x9016, 0x0026, 0x928e, 0x007e, 0x0904, + 0x2edd, 0x928e, 0x007f, 0x0904, 0x2edd, 0x928e, 0x0080, 0x05e8, + 0x9288, 0x1000, 0x210c, 0x81ff, 0x05c0, 0x8fff, 0x1148, 0x2001, + 0x195d, 0x0006, 0x2003, 0x0001, 0x04e9, 0x000e, 0x2003, 0x0000, + 0x00b6, 0x00c6, 0x2158, 0x2001, 0x0001, 0x080c, 0x626e, 0x00ce, + 0x00be, 0x2019, 0x0029, 0x080c, 0x8180, 0x0076, 0x2039, 0x0000, + 0x080c, 0x8078, 0x00b6, 0x00c6, 0x0026, 0x2158, 0xba04, 0x9294, + 0x00ff, 0x9286, 0x0006, 0x1118, 0xb807, 0x0404, 0x0028, 0x2001, + 0x0004, 0x8007, 0x9215, 0xba06, 0x002e, 0x00ce, 0x00be, 0x0016, + 0x2c08, 0x080c, 0xcd62, 0x001e, 0x007e, 0x002e, 0x8210, 0x1f04, + 0x2e94, 0x015e, 0x001e, 0x002e, 0x003e, 0x00be, 0x00ce, 0x00ee, + 0x00fe, 0x0005, 0x0046, 0x0026, 0x0016, 0x080c, 0x5113, 0xd0c4, + 0x0140, 0xd0a4, 0x0130, 0x9006, 0x2220, 0x2009, 0x0029, 0x080c, + 0xcfe6, 0x001e, 0x002e, 0x004e, 0x0005, 0x0016, 0x0026, 0x0036, + 0x00c6, 0x728c, 0x82ff, 0x01e8, 0x080c, 0x629c, 0x11d0, 0x2100, + 0x080c, 0x2509, 0x81ff, 0x01b8, 0x2019, 0x0001, 0x8314, 0x92e0, + 0x1c80, 0x2c04, 0xd384, 0x0120, 0x9084, 0xff00, 0x8007, 0x0010, + 0x9084, 0x00ff, 0x9116, 0x0138, 0x9096, 0x00ff, 0x0110, 0x8318, + 0x0c68, 0x9085, 0x0001, 0x00ce, 0x003e, 0x002e, 0x001e, 0x0005, + 0x0016, 0x00c6, 0x0126, 0x2091, 0x8000, 0x0036, 0x2019, 0x0029, + 0x00a9, 0x003e, 0x9180, 0x1000, 0x2004, 0x9065, 0x0158, 0x0016, + 0x00c6, 0x2061, 0x1a73, 0x001e, 0x6112, 0x080c, 0x2e30, 0x001e, + 0x080c, 0x5f42, 0x012e, 0x00ce, 0x001e, 0x0005, 0x0016, 0x0026, + 0x2110, 0x080c, 0x94b5, 0x080c, 0xd29b, 0x002e, 0x001e, 0x0005, + 0x2001, 0x1835, 0x2004, 0xd0cc, 0x0005, 0x00c6, 0x00b6, 0x080c, + 0x6c53, 0x1118, 0x20a9, 0x0800, 0x0010, 0x20a9, 0x0782, 0x080c, + 0x6c53, 0x1110, 0x900e, 0x0010, 0x2009, 0x007e, 0x9180, 0x1000, + 0x2004, 0x905d, 0x0130, 0x86ff, 0x0110, 0xb800, 0xd0bc, 0x090c, + 0x5f42, 0x8108, 0x1f04, 0x2f66, 0x2061, 0x1800, 0x6077, 0x0000, + 0x6078, 0x9084, 0x00ff, 0x607a, 0x60ab, 0x0000, 0x00be, 0x00ce, + 0x0005, 0x2001, 0x1875, 0x2004, 0xd0bc, 0x0005, 0x2011, 0x1854, + 0x2214, 0xd2ec, 0x0005, 0x0026, 0x2011, 0x1873, 0x2214, 0xd2dc, + 0x002e, 0x0005, 0x7eef, 0x7de8, 0x7ce4, 0x80e2, 0x7be1, 0x80e0, + 0x80dc, 0x80da, 0x7ad9, 0x80d6, 0x80d5, 0x80d4, 0x80d3, 0x80d2, + 0x80d1, 0x79ce, 0x78cd, 0x80cc, 0x80cb, 0x80ca, 0x80c9, 0x80c7, + 0x80c6, 0x77c5, 0x76c3, 0x80bc, 0x80ba, 0x75b9, 0x80b6, 0x74b5, + 0x73b4, 0x72b3, 0x80b2, 0x80b1, 0x80ae, 0x71ad, 0x80ac, 0x70ab, + 0x6faa, 0x6ea9, 0x80a7, 0x6da6, 0x6ca5, 0x6ba3, 0x6a9f, 0x699e, + 0x689d, 0x809b, 0x8098, 0x6797, 0x6690, 0x658f, 0x6488, 0x6384, + 0x6282, 0x8081, 0x8080, 0x617c, 0x607a, 0x8079, 0x5f76, 0x8075, + 0x8074, 0x8073, 0x8072, 0x8071, 0x806e, 0x5e6d, 0x806c, 0x5d6b, + 0x5c6a, 0x5b69, 0x8067, 0x5a66, 0x5965, 0x5863, 0x575c, 0x565a, + 0x5559, 0x8056, 0x8055, 0x5454, 0x5353, 0x5252, 0x5151, 0x504e, + 0x4f4d, 0x804c, 0x804b, 0x4e4a, 0x4d49, 0x8047, 0x4c46, 0x8045, + 0x8043, 0x803c, 0x803a, 0x8039, 0x8036, 0x4b35, 0x8034, 0x4a33, + 0x4932, 0x4831, 0x802e, 0x472d, 0x462c, 0x452b, 0x442a, 0x4329, + 0x4227, 0x8026, 0x8025, 0x4123, 0x401f, 0x3f1e, 0x3e1d, 0x3d1b, + 0x3c18, 0x8017, 0x8010, 0x3b0f, 0x3a08, 0x8004, 0x3902, 0x8001, + 0x8000, 0x8000, 0x3800, 0x3700, 0x3600, 0x8000, 0x3500, 0x8000, + 0x8000, 0x8000, 0x3400, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x8000, 0x3300, 0x3200, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x8000, 0x3100, 0x3000, 0x8000, 0x8000, 0x2f00, 0x8000, 0x2e00, + 0x2d00, 0x2c00, 0x8000, 0x8000, 0x8000, 0x2b00, 0x8000, 0x2a00, + 0x2900, 0x2800, 0x8000, 0x2700, 0x2600, 0x2500, 0x2400, 0x2300, + 0x2200, 0x8000, 0x8000, 0x2100, 0x2000, 0x1f00, 0x1e00, 0x1d00, + 0x1c00, 0x8000, 0x8000, 0x1b00, 0x1a00, 0x8000, 0x1900, 0x8000, + 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x1800, 0x8000, 0x1700, + 0x1600, 0x1500, 0x8000, 0x1400, 0x1300, 0x1200, 0x1100, 0x1000, + 0x0f00, 0x8000, 0x8000, 0x0e00, 0x0d00, 0x0c00, 0x0b00, 0x0a00, + 0x0900, 0x8000, 0x8000, 0x0800, 0x0700, 0x8000, 0x0600, 0x8000, + 0x8000, 0x8000, 0x0500, 0x0400, 0x0300, 0x8000, 0x0200, 0x8000, + 0x8000, 0x8000, 0x0100, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x8000, 0x0000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x8000, 0x8000, 0x2071, 0x1894, 0x7003, 0x0002, 0x9006, 0x7016, + 0x701a, 0x704a, 0x704e, 0x700e, 0x7042, 0x7046, 0x703b, 0x18b0, + 0x703f, 0x18b0, 0x7007, 0x0001, 0x080c, 0x0fee, 0x090c, 0x0db2, + 0x2900, 0x706a, 0xa867, 0x0002, 0xa8ab, 0xdcb0, 0x080c, 0x0fee, + 0x090c, 0x0db2, 0x2900, 0x706e, 0xa867, 0x0002, 0xa8ab, 0xdcb0, + 0x0005, 0x2071, 0x1894, 0x7004, 0x0002, 0x30c1, 0x30c2, 0x30d5, + 0x30e9, 0x0005, 0x1004, 0x30d2, 0x0e04, 0x30d2, 0x2079, 0x0000, + 0x0126, 0x2091, 0x8000, 0x700c, 0x9005, 0x1128, 0x700f, 0x0001, + 0x012e, 0x0468, 0x0005, 0x012e, 0x0ce8, 0x2079, 0x0000, 0x2061, + 0x18ae, 0x2c4c, 0xa86c, 0x908e, 0x0100, 0x0128, 0x9086, 0x0200, + 0x0904, 0x31bd, 0x0005, 0x7018, 0x2048, 0x2061, 0x1800, 0x701c, + 0x0807, 0x7014, 0x2048, 0xa864, 0x9094, 0x00ff, 0x9296, 0x0029, + 0x1120, 0xaa78, 0xd2fc, 0x0128, 0x0005, 0x9086, 0x0103, 0x0108, + 0x0005, 0x2079, 0x0000, 0x2061, 0x1800, 0x701c, 0x0807, 0x2061, + 0x1800, 0x7880, 0x908a, 0x0040, 0x1210, 0x61c8, 0x0042, 0x2100, + 0x908a, 0x003f, 0x1a04, 0x31ba, 0x61c8, 0x0804, 0x314f, 0x3191, + 0x31c9, 0x31d3, 0x31d7, 0x31e1, 0x31e7, 0x31eb, 0x31fb, 0x31fe, + 0x3208, 0x320d, 0x3212, 0x321d, 0x3228, 0x3237, 0x3246, 0x3254, + 0x326b, 0x3286, 0x31ba, 0x332f, 0x336d, 0x3413, 0x3424, 0x3447, + 0x31ba, 0x31ba, 0x31ba, 0x347f, 0x349b, 0x34a4, 0x34d3, 0x34d9, + 0x31ba, 0x351f, 0x31ba, 0x31ba, 0x31ba, 0x31ba, 0x31ba, 0x352a, + 0x3533, 0x353b, 0x353d, 0x31ba, 0x31ba, 0x31ba, 0x31ba, 0x31ba, + 0x31ba, 0x3569, 0x31ba, 0x31ba, 0x31ba, 0x31ba, 0x31ba, 0x3586, + 0x35e1, 0x31ba, 0x31ba, 0x31ba, 0x31ba, 0x31ba, 0x31ba, 0x0002, + 0x360b, 0x360e, 0x366d, 0x3686, 0x36b6, 0x3954, 0x31ba, 0x4cec, + 0x31ba, 0x31ba, 0x31ba, 0x31ba, 0x31ba, 0x31ba, 0x31ba, 0x31ba, + 0x3208, 0x320d, 0x3e75, 0x31ba, 0x3e8b, 0x4d7b, 0x4dcc, 0x4ecf, + 0x31ba, 0x4f31, 0x4f6d, 0x4f9e, 0x50a2, 0x4fcb, 0x5022, 0x31ba, + 0x3e8f, 0x404f, 0x4065, 0x408a, 0x40ef, 0x4163, 0x4183, 0x41fa, + 0x420b, 0x421c, 0x421f, 0x4244, 0x42b7, 0x431d, 0x4325, 0x4457, + 0x459c, 0x45d0, 0x4834, 0x31ba, 0x4852, 0x48fe, 0x49d4, 0x31ba, + 0x31ba, 0x31ba, 0x31ba, 0x4a3a, 0x4a55, 0x4325, 0x4c9b, 0x714c, + 0x0000, 0x2021, 0x4000, 0x080c, 0x464e, 0x0126, 0x2091, 0x8000, + 0x0e04, 0x319b, 0x0010, 0x012e, 0x0cc0, 0x7c36, 0x9486, 0x4000, + 0x0118, 0x7833, 0x0011, 0x0010, 0x7833, 0x0010, 0x7c82, 0x7986, + 0x7a8a, 0x7b8e, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004, 0xd084, + 0x190c, 0x1167, 0x7007, 0x0001, 0x2091, 0x5000, 0x700f, 0x0000, + 0x012e, 0x0005, 0x2021, 0x4001, 0x08b0, 0x2021, 0x4002, 0x0898, + 0x2021, 0x4003, 0x0880, 0x2021, 0x4005, 0x0868, 0x2021, 0x4006, + 0x0850, 0x2039, 0x0001, 0x902e, 0x2520, 0x7b88, 0x7a8c, 0x7884, + 0x7990, 0x0804, 0x465b, 0x7883, 0x0004, 0x7884, 0x0807, 0x2039, + 0x0001, 0x902e, 0x2520, 0x7b88, 0x7a8c, 0x7884, 0x7990, 0x0804, + 0x465e, 0x7984, 0x7888, 0x2114, 0x200a, 0x0804, 0x3191, 0x7984, + 0x2114, 0x0804, 0x3191, 0x20e1, 0x0000, 0x2099, 0x0021, 0x20e9, + 0x0000, 0x20a1, 0x0021, 0x20a9, 0x001f, 0x4003, 0x7984, 0x7a88, + 0x7b8c, 0x0804, 0x3191, 0x7884, 0x2060, 0x04d8, 0x2009, 0x0003, + 0x2011, 0x0002, 0x2019, 0x0012, 0x789b, 0x0117, 0x0804, 0x3191, + 0x2039, 0x0001, 0x7d98, 0x7c9c, 0x0800, 0x2039, 0x0001, 0x7d98, + 0x7c9c, 0x0848, 0x79a0, 0x9182, 0x0040, 0x0210, 0x0804, 0x31c6, + 0x2138, 0x7d98, 0x7c9c, 0x0804, 0x31cd, 0x79a0, 0x9182, 0x0040, + 0x0210, 0x0804, 0x31c6, 0x2138, 0x7d98, 0x7c9c, 0x0804, 0x31db, + 0x79a0, 0x9182, 0x0040, 0x0210, 0x0804, 0x31c6, 0x21e8, 0x7984, + 0x7888, 0x20a9, 0x0001, 0x21a0, 0x4004, 0x0804, 0x3191, 0x2061, + 0x0800, 0xe10c, 0x9006, 0x2c15, 0x9200, 0x8c60, 0x8109, 0x1dd8, + 0x2010, 0x9005, 0x0904, 0x3191, 0x0804, 0x31c0, 0x79a0, 0x9182, + 0x0040, 0x0210, 0x0804, 0x31c6, 0x21e0, 0x20a9, 0x0001, 0x7984, + 0x2198, 0x4012, 0x0804, 0x3191, 0x2069, 0x1853, 0x7884, 0x7990, + 0x911a, 0x1a04, 0x31c6, 0x8019, 0x0904, 0x31c6, 0x684a, 0x6942, + 0x788c, 0x6852, 0x7888, 0x6856, 0x9006, 0x685a, 0x685e, 0x080c, + 0x6f5b, 0x0804, 0x3191, 0x2069, 0x1853, 0x7884, 0x7994, 0x911a, + 0x1a04, 0x31c6, 0x8019, 0x0904, 0x31c6, 0x684e, 0x6946, 0x788c, + 0x6862, 0x7888, 0x6866, 0x9006, 0x686a, 0x686e, 0x0126, 0x2091, + 0x8000, 0x080c, 0x630e, 0x012e, 0x0804, 0x3191, 0x902e, 0x2520, + 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804, 0x31c3, 0x7984, 0x7b88, + 0x7a8c, 0x20a9, 0x0005, 0x20e9, 0x0001, 0x20a1, 0x189c, 0x4101, + 0x080c, 0x4612, 0x1120, 0x2009, 0x0002, 0x0804, 0x31c3, 0x2009, + 0x0020, 0xa85c, 0x9080, 0x0019, 0xaf60, 0x080c, 0x465b, 0x701f, + 0x32aa, 0x0005, 0xa864, 0x2008, 0x9084, 0x00ff, 0x9096, 0x0011, + 0x0168, 0x9096, 0x0019, 0x0150, 0x9096, 0x0015, 0x0138, 0x9096, + 0x0048, 0x0120, 0x9096, 0x0029, 0x1904, 0x31c3, 0x810f, 0x918c, + 0x00ff, 0x0904, 0x31c3, 0x7112, 0x7010, 0x8001, 0x0560, 0x7012, + 0x080c, 0x4612, 0x1120, 0x2009, 0x0002, 0x0804, 0x31c3, 0x2009, + 0x0020, 0x7068, 0x2040, 0xa28c, 0xa390, 0xa494, 0xa598, 0x9290, + 0x0040, 0x9399, 0x0000, 0x94a1, 0x0000, 0x95a9, 0x0000, 0xa85c, + 0x9080, 0x0019, 0xaf60, 0x080c, 0x465b, 0x701f, 0x32e8, 0x0005, + 0xa864, 0x9084, 0x00ff, 0x9096, 0x0002, 0x0120, 0x9096, 0x000a, + 0x1904, 0x31c3, 0x0888, 0x7014, 0x2048, 0xa868, 0xc0fd, 0xa86a, + 0xa864, 0x9084, 0x00ff, 0x9096, 0x0029, 0x1160, 0xc2fd, 0xaa7a, + 0x080c, 0x5b2d, 0x0150, 0x0126, 0x2091, 0x8000, 0xa87a, 0xa982, + 0x012e, 0x0050, 0x080c, 0x5e34, 0x1128, 0x7007, 0x0003, 0x701f, + 0x3314, 0x0005, 0x080c, 0x6770, 0x0126, 0x2091, 0x8000, 0x20a9, + 0x0005, 0x20e1, 0x0001, 0x2099, 0x189c, 0x400a, 0x2100, 0x9210, + 0x9399, 0x0000, 0x94a1, 0x0000, 0x95a9, 0x0000, 0xa85c, 0x9080, + 0x0019, 0x2009, 0x0020, 0x012e, 0xaf60, 0x0804, 0x465e, 0x2091, + 0x8000, 0x7837, 0x4000, 0x7833, 0x0010, 0x7883, 0x4000, 0x7887, + 0x4953, 0x788b, 0x5020, 0x788f, 0x2020, 0x2009, 0x017f, 0x2104, + 0x7892, 0x3f00, 0x7896, 0x2061, 0x0100, 0x6200, 0x2061, 0x0200, + 0x603c, 0x8007, 0x9205, 0x789a, 0x2009, 0x04fd, 0x2104, 0x789e, + 0x2091, 0x5000, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004, 0xd084, + 0x0180, 0x2001, 0x19e8, 0x2004, 0x9005, 0x0128, 0x2001, 0x008b, + 0x2004, 0xd0fc, 0x0dd8, 0x2001, 0x008a, 0x2003, 0x0002, 0x2003, + 0x1001, 0x2071, 0x0080, 0x0804, 0x0427, 0x81ff, 0x1904, 0x31c3, + 0x7984, 0x080c, 0x5f7e, 0x1904, 0x31c6, 0x7e98, 0x9684, 0x3fff, + 0x9082, 0x4000, 0x1a04, 0x31c6, 0x7c88, 0x7d8c, 0x080c, 0x60e1, + 0x080c, 0x60b0, 0x0000, 0x1518, 0x2061, 0x1cd0, 0x0126, 0x2091, + 0x8000, 0x6000, 0x9086, 0x0000, 0x0148, 0x6014, 0x904d, 0x0130, + 0xa86c, 0x9406, 0x1118, 0xa870, 0x9506, 0x0150, 0x012e, 0x9ce0, + 0x0018, 0x2001, 0x1818, 0x2004, 0x9c02, 0x1a04, 0x31c3, 0x0c30, + 0x080c, 0xb251, 0x012e, 0x0904, 0x31c3, 0x0804, 0x3191, 0x900e, + 0x2001, 0x0005, 0x080c, 0x6770, 0x0126, 0x2091, 0x8000, 0x080c, + 0xb8e9, 0x080c, 0x6536, 0x012e, 0x0804, 0x3191, 0x00a6, 0x2950, + 0xb198, 0x080c, 0x5f7e, 0x1904, 0x3400, 0xb6a4, 0x9684, 0x3fff, + 0x9082, 0x4000, 0x16e8, 0xb49c, 0xb5a0, 0x080c, 0x60e1, 0x080c, + 0x60b0, 0x1520, 0x2061, 0x1cd0, 0x0126, 0x2091, 0x8000, 0x6000, + 0x9086, 0x0000, 0x0148, 0x6014, 0x904d, 0x0130, 0xa86c, 0x9406, + 0x1118, 0xa870, 0x9506, 0x0158, 0x012e, 0x9ce0, 0x0018, 0x2001, + 0x1818, 0x2004, 0x9c02, 0x2009, 0x000d, 0x12b0, 0x0c28, 0x080c, + 0xb251, 0x012e, 0x2009, 0x0003, 0x0178, 0x00e0, 0x900e, 0x2001, + 0x0005, 0x080c, 0x6770, 0x0126, 0x2091, 0x8000, 0x080c, 0xb8e9, + 0x080c, 0x6529, 0x012e, 0x0070, 0xb097, 0x4005, 0xb19a, 0x0010, + 0xb097, 0x4006, 0x900e, 0x9085, 0x0001, 0x2001, 0x0030, 0x2a48, + 0x00ae, 0x0005, 0xb097, 0x4000, 0x9006, 0x918d, 0x0001, 0x2008, + 0x2a48, 0x00ae, 0x0005, 0x81ff, 0x1904, 0x31c3, 0x080c, 0x4629, + 0x0904, 0x31c6, 0x080c, 0x6045, 0x0904, 0x31c3, 0x080c, 0x60e7, + 0x0904, 0x31c3, 0x0804, 0x417a, 0x81ff, 0x1904, 0x31c3, 0x080c, + 0x4645, 0x0904, 0x31c6, 0x080c, 0x6175, 0x0904, 0x31c3, 0x2019, + 0x0005, 0x79a8, 0x080c, 0x6102, 0x0904, 0x31c3, 0x7888, 0x908a, + 0x1000, 0x1a04, 0x31c6, 0x8003, 0x800b, 0x810b, 0x9108, 0x080c, + 0x7c58, 0x7984, 0xd184, 0x1904, 0x3191, 0x0804, 0x417a, 0x0126, + 0x2091, 0x8000, 0x81ff, 0x0118, 0x2009, 0x0001, 0x0450, 0x2029, + 0x07ff, 0x6454, 0x2400, 0x9506, 0x01f8, 0x2508, 0x080c, 0x5f7e, + 0x11d8, 0x080c, 0x6175, 0x1128, 0x2009, 0x0002, 0x62b8, 0x2518, + 0x00c0, 0x2019, 0x0004, 0x900e, 0x080c, 0x6102, 0x1118, 0x2009, + 0x0006, 0x0078, 0x7884, 0x908a, 0x1000, 0x1270, 0x8003, 0x800b, + 0x810b, 0x9108, 0x080c, 0x7c58, 0x8529, 0x1ae0, 0x012e, 0x0804, + 0x3191, 0x012e, 0x0804, 0x31c3, 0x012e, 0x0804, 0x31c6, 0x080c, + 0x4629, 0x0904, 0x31c6, 0x080c, 0x6045, 0x0904, 0x31c3, 0xbaa0, + 0x2019, 0x0005, 0x00c6, 0x9066, 0x080c, 0x8180, 0x0076, 0x903e, + 0x080c, 0x8078, 0x900e, 0x080c, 0xcd62, 0x007e, 0x00ce, 0x080c, + 0x60e1, 0x0804, 0x3191, 0x080c, 0x4629, 0x0904, 0x31c6, 0x080c, + 0x60e1, 0x2208, 0x0804, 0x3191, 0x0156, 0x00d6, 0x00e6, 0x2069, + 0x1906, 0x6810, 0x6914, 0x910a, 0x1208, 0x900e, 0x6816, 0x9016, + 0x901e, 0x20a9, 0x007e, 0x2069, 0x1000, 0x2d04, 0x905d, 0x0118, + 0xb84c, 0x0059, 0x9210, 0x8d68, 0x1f04, 0x34b5, 0x2300, 0x9218, + 0x00ee, 0x00de, 0x015e, 0x0804, 0x3191, 0x00f6, 0x0016, 0x907d, + 0x0138, 0x9006, 0x8000, 0x2f0c, 0x81ff, 0x0110, 0x2178, 0x0cd0, + 0x001e, 0x00fe, 0x0005, 0x2069, 0x1906, 0x6910, 0x62b4, 0x0804, + 0x3191, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804, 0x31c3, 0x0126, + 0x2091, 0x8000, 0x080c, 0x5127, 0x0128, 0x2009, 0x0007, 0x012e, + 0x0804, 0x31c3, 0x012e, 0x6154, 0x9190, 0x2f92, 0x2215, 0x9294, + 0x00ff, 0x6374, 0x83ff, 0x0108, 0x6278, 0x67d4, 0x97c4, 0x000a, + 0x98c6, 0x000a, 0x1118, 0x2031, 0x0001, 0x00e8, 0x97c4, 0x0022, + 0x98c6, 0x0022, 0x1118, 0x2031, 0x0003, 0x00a8, 0x97c4, 0x0012, + 0x98c6, 0x0012, 0x1118, 0x2031, 0x0002, 0x0068, 0x080c, 0x6c53, + 0x1118, 0x2031, 0x0004, 0x0038, 0xd79c, 0x0120, 0x2009, 0x0005, + 0x0804, 0x31c3, 0x9036, 0x7e9a, 0x7f9e, 0x0804, 0x3191, 0x6144, + 0x6248, 0x2019, 0x1955, 0x231c, 0x2001, 0x1956, 0x2004, 0x789a, + 0x0804, 0x3191, 0x0126, 0x2091, 0x8000, 0x6134, 0x6238, 0x633c, + 0x012e, 0x0804, 0x3191, 0x080c, 0x4645, 0x0904, 0x31c6, 0xba44, + 0xbb38, 0x0804, 0x3191, 0x080c, 0x0db2, 0x080c, 0x4645, 0x2110, + 0x0904, 0x31c6, 0xb804, 0x908c, 0x00ff, 0x918e, 0x0006, 0x0140, + 0x9084, 0xff00, 0x9086, 0x0600, 0x2009, 0x0009, 0x1904, 0x31c3, + 0x0126, 0x2091, 0x8000, 0x2019, 0x0005, 0x00c6, 0x9066, 0x080c, + 0x94b5, 0x080c, 0x8180, 0x0076, 0x903e, 0x080c, 0x8078, 0x900e, + 0x080c, 0xcd62, 0x007e, 0x00ce, 0xb807, 0x0407, 0x012e, 0x0804, + 0x3191, 0x6144, 0x6248, 0x7884, 0x6046, 0x7b88, 0x634a, 0x2069, + 0x1853, 0x831f, 0x9305, 0x6816, 0x788c, 0x2069, 0x1955, 0x2d1c, + 0x206a, 0x7e98, 0x9682, 0x0014, 0x1210, 0x2031, 0x07d0, 0x2069, + 0x1956, 0x2d04, 0x266a, 0x789a, 0x0804, 0x3191, 0x0126, 0x2091, + 0x8000, 0x6134, 0x7884, 0x6036, 0x910e, 0xd1b4, 0x190c, 0x0e84, + 0xd0c4, 0x01a8, 0x00d6, 0x78a8, 0x2009, 0x196c, 0x200a, 0x78ac, + 0x2011, 0x196d, 0x2012, 0x2069, 0x0100, 0x6838, 0x9086, 0x0007, + 0x1118, 0x2214, 0x6a5a, 0x0010, 0x210c, 0x695a, 0x00de, 0x7888, + 0x603a, 0x2011, 0x0114, 0x220c, 0x7888, 0xd08c, 0x0118, 0x918d, + 0x0080, 0x0010, 0x918c, 0xff7f, 0x2112, 0x613c, 0x788c, 0x603e, + 0x910e, 0xd1e4, 0x190c, 0x0e9a, 0x603c, 0xd0cc, 0x0120, 0x78b0, + 0x2011, 0x0114, 0x2012, 0x012e, 0x0804, 0x3191, 0x00f6, 0x2079, + 0x1800, 0x7a34, 0xa898, 0x9084, 0xfebf, 0x9215, 0xa89c, 0x9084, + 0xfebf, 0x8002, 0x9214, 0x7834, 0x9084, 0x0140, 0x9215, 0x7a36, + 0xa897, 0x4000, 0x900e, 0x9085, 0x0001, 0x2001, 0x0000, 0x00fe, + 0x0005, 0x7898, 0x9005, 0x01a8, 0x7888, 0x9025, 0x0904, 0x31c6, + 0x788c, 0x902d, 0x0904, 0x31c6, 0x900e, 0x080c, 0x5f7e, 0x1120, + 0xba44, 0xbb38, 0xbc46, 0xbd3a, 0x9186, 0x07ff, 0x0190, 0x8108, + 0x0ca0, 0x080c, 0x4645, 0x0904, 0x31c6, 0x7888, 0x900d, 0x0904, + 0x31c6, 0x788c, 0x9005, 0x0904, 0x31c6, 0xba44, 0xb946, 0xbb38, + 0xb83a, 0x0804, 0x3191, 0x2011, 0xbc09, 0x0010, 0x2011, 0xbc05, + 0x080c, 0x5127, 0x1904, 0x31c3, 0x00c6, 0x2061, 0x0100, 0x7984, + 0x9186, 0x00ff, 0x1130, 0x2001, 0x1816, 0x2004, 0x9085, 0xff00, + 0x0088, 0x9182, 0x007f, 0x16e0, 0x9188, 0x2f92, 0x210d, 0x918c, + 0x00ff, 0x2001, 0x1816, 0x2004, 0x0026, 0x9116, 0x002e, 0x0580, + 0x810f, 0x9105, 0x0126, 0x2091, 0x8000, 0x0006, 0x080c, 0x9980, + 0x000e, 0x0510, 0x602e, 0x620a, 0x7984, 0x00b6, 0x080c, 0x5f24, + 0x2b08, 0x00be, 0x1500, 0x6112, 0x6023, 0x0001, 0x080c, 0x4612, + 0x01d0, 0x9006, 0xa866, 0x7007, 0x0003, 0xa832, 0xa868, 0xc0fd, + 0xa86a, 0x701f, 0x3666, 0x2900, 0x6016, 0x2009, 0x0032, 0x080c, + 0x9a50, 0x012e, 0x00ce, 0x0005, 0x012e, 0x00ce, 0x0804, 0x31c3, + 0x00ce, 0x0804, 0x31c6, 0x080c, 0x99d6, 0x0cb0, 0xa830, 0x9086, + 0x0100, 0x0904, 0x31c3, 0x0804, 0x3191, 0x2061, 0x1a3e, 0x0126, + 0x2091, 0x8000, 0x6000, 0xd084, 0x0170, 0x6104, 0x6208, 0x2061, + 0x1800, 0x634c, 0x606c, 0x789a, 0x60b8, 0x789e, 0x60b4, 0x78aa, + 0x012e, 0x0804, 0x3191, 0x900e, 0x2110, 0x0c88, 0x81ff, 0x1904, + 0x31c3, 0x080c, 0x6c53, 0x0904, 0x31c3, 0x0126, 0x2091, 0x8000, + 0x624c, 0x606c, 0x9202, 0x0248, 0x9085, 0x0001, 0x080c, 0x253f, + 0x080c, 0x5304, 0x012e, 0x0804, 0x3191, 0x012e, 0x0804, 0x31c6, + 0x0006, 0x0016, 0x00c6, 0x00e6, 0x2001, 0x1978, 0x2070, 0x2061, + 0x1853, 0x6008, 0x2072, 0x900e, 0x2011, 0x1400, 0x080c, 0x7e7f, + 0x7206, 0x00ee, 0x00ce, 0x001e, 0x000e, 0x0005, 0x0126, 0x2091, + 0x8000, 0x81ff, 0x0128, 0x012e, 0x2021, 0x400b, 0x0804, 0x3193, + 0x7884, 0xd0fc, 0x0148, 0x2001, 0x002a, 0x2004, 0x9082, 0x00e1, + 0x0288, 0x012e, 0x0804, 0x31c6, 0x2001, 0x002a, 0x2004, 0x2069, + 0x1853, 0x6908, 0x9102, 0x1230, 0x012e, 0x0804, 0x31c6, 0x012e, + 0x0804, 0x31c3, 0x080c, 0x9940, 0x0dd0, 0x7884, 0xd0fc, 0x0904, + 0x3731, 0x00c6, 0x080c, 0x4612, 0x00ce, 0x0d88, 0xa867, 0x0000, + 0x7884, 0xa80a, 0x7898, 0xa80e, 0x789c, 0xa812, 0x2001, 0x002e, + 0x2004, 0xa81a, 0x2001, 0x002f, 0x2004, 0xa81e, 0x2001, 0x0030, + 0x2004, 0xa822, 0x2001, 0x0031, 0x2004, 0xa826, 0x2001, 0x0034, + 0x2004, 0xa82a, 0x2001, 0x0035, 0x2004, 0xa82e, 0x2001, 0x002a, + 0x2004, 0x9080, 0x0003, 0x9084, 0x00fc, 0x8004, 0xa816, 0x080c, + 0x38b7, 0x0928, 0x7014, 0x2048, 0xad2c, 0xac28, 0xab1c, 0xaa18, + 0xa930, 0xa808, 0xd0b4, 0x1120, 0x2029, 0x0000, 0x2021, 0x0000, + 0x8906, 0x8006, 0x8007, 0x90bc, 0x003f, 0x9084, 0xffc0, 0x9080, + 0x001b, 0x080c, 0x465b, 0x701f, 0x37f4, 0x7023, 0x0001, 0x012e, + 0x0005, 0x0046, 0x0086, 0x0096, 0x00a6, 0x00b6, 0x00c6, 0x00d6, + 0x00e6, 0x00f6, 0x080c, 0x36a0, 0x2001, 0x196e, 0x2003, 0x0000, + 0x2021, 0x000a, 0x2061, 0x0100, 0x6104, 0x0016, 0x60bb, 0x0000, + 0x60bf, 0x32e1, 0x60bf, 0x0012, 0x080c, 0x3926, 0x080c, 0x38e5, + 0x00f6, 0x00e6, 0x0086, 0x2940, 0x2071, 0x1a34, 0x2079, 0x0090, + 0x00d6, 0x2069, 0x0000, 0x6884, 0xd0b4, 0x0140, 0x2001, 0x0035, + 0x2004, 0x780e, 0x2001, 0x0034, 0x2004, 0x780a, 0x00de, 0x2011, + 0x0001, 0x080c, 0x3cb9, 0x008e, 0x00ee, 0x00fe, 0x080c, 0x3be6, + 0x080c, 0x3aeb, 0x05b8, 0x2001, 0x020b, 0x2004, 0x9084, 0x0140, + 0x1db8, 0x080c, 0x3d2d, 0x00f6, 0x2079, 0x0300, 0x78bc, 0x00fe, + 0x908c, 0x0070, 0x1560, 0x2071, 0x0200, 0x7037, 0x0000, 0x7050, + 0x9084, 0xff00, 0x9086, 0x3200, 0x1510, 0x7037, 0x0001, 0x7050, + 0x9084, 0xff00, 0x9086, 0xe100, 0x11d0, 0x7037, 0x0000, 0x7054, + 0x7037, 0x0000, 0x715c, 0x9106, 0x1190, 0x2001, 0x181e, 0x2004, + 0x9106, 0x1168, 0x00c6, 0x2061, 0x0100, 0x6024, 0x9084, 0x1e00, + 0x00ce, 0x0138, 0x080c, 0x3af5, 0x080c, 0x38e0, 0x0058, 0x080c, + 0x38e0, 0x080c, 0x3c51, 0x080c, 0x3bdc, 0x2001, 0x020b, 0x2004, + 0xd0e4, 0x0dd8, 0x2001, 0x032a, 0x2003, 0x0004, 0x2061, 0x0100, + 0x6027, 0x0002, 0x001e, 0x6106, 0x2011, 0x020d, 0x2013, 0x0020, + 0x60bb, 0x0000, 0x60bf, 0x0108, 0x60bf, 0x0012, 0x2001, 0x0004, + 0x200c, 0x918c, 0xfffd, 0x2102, 0x080c, 0x127c, 0x2009, 0x0028, + 0x080c, 0x20d9, 0x2001, 0x0227, 0x200c, 0x2102, 0x00fe, 0x00ee, + 0x00de, 0x00ce, 0x00be, 0x00ae, 0x009e, 0x008e, 0x004e, 0x2001, + 0x196e, 0x2004, 0x9005, 0x1118, 0x012e, 0x0804, 0x3191, 0x012e, + 0x2021, 0x400c, 0x0804, 0x3193, 0x0016, 0x0026, 0x0036, 0x0046, + 0x0056, 0x0076, 0x0086, 0x0096, 0x00d6, 0x0156, 0x7014, 0x2048, + 0x7020, 0x20a8, 0x8000, 0x7022, 0xa804, 0x9005, 0x0904, 0x3850, + 0x2048, 0x1f04, 0x3804, 0x7068, 0x2040, 0xa28c, 0xa390, 0xa494, + 0xa598, 0xa930, 0xa808, 0xd0b4, 0x1120, 0x2029, 0x0000, 0x2021, + 0x0000, 0x0096, 0x7014, 0x2048, 0xa864, 0x009e, 0x9086, 0x0103, + 0x0170, 0x8906, 0x8006, 0x8007, 0x90bc, 0x003f, 0x9084, 0xffc0, + 0x9080, 0x001b, 0x080c, 0x465b, 0x701f, 0x37f4, 0x00b0, 0x8906, + 0x8006, 0x8007, 0x90bc, 0x003f, 0x9084, 0xffc0, 0x9080, 0x001b, + 0x21a8, 0x27e0, 0x2098, 0x27e8, 0x20a0, 0x0006, 0x080c, 0x0f52, + 0x000e, 0x080c, 0x465e, 0x701f, 0x37f4, 0x015e, 0x00de, 0x009e, + 0x008e, 0x007e, 0x005e, 0x004e, 0x003e, 0x002e, 0x001e, 0x0005, + 0x7014, 0x2048, 0xa864, 0x9086, 0x0103, 0x1118, 0x701f, 0x38b5, + 0x0450, 0x7014, 0x2048, 0xa868, 0xc0fd, 0xa86a, 0x2009, 0x007f, + 0x080c, 0x5f1e, 0x0110, 0x9006, 0x0030, 0xb813, 0x00ff, 0xb817, + 0xfffd, 0x080c, 0xbab8, 0x015e, 0x00de, 0x009e, 0x008e, 0x007e, + 0x005e, 0x004e, 0x003e, 0x002e, 0x001e, 0x0904, 0x31c3, 0x0016, + 0x0026, 0x0036, 0x0046, 0x0056, 0x0076, 0x0086, 0x0096, 0x00d6, + 0x0156, 0x701f, 0x3887, 0x7007, 0x0003, 0x0804, 0x3845, 0x0076, + 0xa830, 0x9086, 0x0100, 0x2021, 0x400c, 0x0904, 0x3193, 0xad10, + 0xac0c, 0xab24, 0xaa20, 0xa930, 0xa808, 0xd0b4, 0x1120, 0x2029, + 0x0000, 0x2021, 0x0000, 0x8906, 0x8006, 0x8007, 0x90bc, 0x003f, + 0x9084, 0xffc0, 0x9080, 0x001b, 0x21a8, 0x27e0, 0x2098, 0x27e8, + 0x20a0, 0x0006, 0x080c, 0x0f52, 0x000e, 0x080c, 0x465e, 0x007e, + 0x701f, 0x37f4, 0x7023, 0x0001, 0x0005, 0x0804, 0x3191, 0x0156, + 0x00c6, 0xa814, 0x908a, 0x001e, 0x0218, 0xa833, 0x001e, 0x0010, + 0xa832, 0x0078, 0x81ff, 0x0168, 0x0016, 0x080c, 0x4612, 0x001e, + 0x0130, 0xa800, 0x2040, 0xa008, 0xa80a, 0x2100, 0x0c58, 0x9006, + 0x0010, 0x9085, 0x0001, 0x00ce, 0x015e, 0x0005, 0x0006, 0x00f6, + 0x2079, 0x0000, 0x7880, 0x9086, 0x0044, 0x00fe, 0x000e, 0x0005, + 0x2001, 0x196e, 0x2003, 0x0001, 0x0005, 0x00f6, 0x00e6, 0x00c6, + 0x2061, 0x0200, 0x2001, 0x1979, 0x2004, 0x601a, 0x2061, 0x0100, + 0x2001, 0x1978, 0x2004, 0x60ce, 0x6104, 0xc1ac, 0x6106, 0x080c, + 0x4612, 0xa813, 0x0019, 0xa817, 0x0001, 0x2900, 0xa85a, 0x2001, + 0x002e, 0x2004, 0xa866, 0x2001, 0x002f, 0x2004, 0xa86a, 0x2061, + 0x0090, 0x2079, 0x0100, 0x2001, 0x1978, 0x2004, 0x6036, 0x2009, + 0x0040, 0x080c, 0x20d9, 0x2001, 0x002a, 0x2004, 0x9084, 0xfff8, + 0xa86e, 0x601a, 0xa873, 0x0000, 0x601f, 0x0000, 0x78ca, 0x9006, + 0x600a, 0x600e, 0x00ce, 0x00ee, 0x00fe, 0x0005, 0x00e6, 0x080c, + 0x4612, 0x2940, 0xa013, 0x0019, 0xa017, 0x0001, 0x2800, 0xa05a, + 0x2001, 0x0030, 0x2004, 0xa866, 0x2001, 0x0031, 0x2004, 0xa86a, + 0x2001, 0x002a, 0x2004, 0x9084, 0xfff8, 0xa86e, 0xa873, 0x0000, + 0x2001, 0x032a, 0x2003, 0x0004, 0x2001, 0x0300, 0x2003, 0x0000, + 0x2001, 0x020d, 0x2003, 0x0000, 0x2001, 0x0004, 0x200c, 0x918d, + 0x0002, 0x2102, 0x00ee, 0x0005, 0x0126, 0x2091, 0x8000, 0x81ff, + 0x0148, 0x080c, 0x28c8, 0x1130, 0x9006, 0x080c, 0x2820, 0x9006, + 0x080c, 0x2803, 0x7884, 0x9084, 0x0007, 0x0002, 0x3971, 0x397a, + 0x3983, 0x396e, 0x396e, 0x396e, 0x396e, 0x396e, 0x012e, 0x0804, + 0x31c6, 0x2009, 0x0114, 0x2104, 0x9085, 0x0800, 0x200a, 0x080c, + 0x3b3f, 0x00c0, 0x2009, 0x0114, 0x2104, 0x9085, 0x4000, 0x200a, + 0x080c, 0x3b3f, 0x0078, 0x080c, 0x6c53, 0x1128, 0x012e, 0x2009, + 0x0016, 0x0804, 0x31c3, 0x81ff, 0x0128, 0x012e, 0x2021, 0x400b, + 0x0804, 0x3193, 0x0086, 0x0096, 0x00a6, 0x00b6, 0x00c6, 0x00d6, + 0x00e6, 0x00f6, 0x080c, 0x36a0, 0x2009, 0x0101, 0x210c, 0x0016, + 0x7ec8, 0x7dcc, 0x9006, 0x2068, 0x2060, 0x2058, 0x080c, 0x3e08, + 0x080c, 0x3d58, 0x903e, 0x2720, 0x00f6, 0x00e6, 0x0086, 0x2940, + 0x2071, 0x1a34, 0x2079, 0x0090, 0x00d6, 0x2069, 0x0000, 0x6884, + 0xd0b4, 0x0120, 0x68d4, 0x780e, 0x68d0, 0x780a, 0x00de, 0x2011, + 0x0001, 0x080c, 0x3cb9, 0x080c, 0x28d0, 0x080c, 0x28d0, 0x080c, + 0x28d0, 0x080c, 0x28d0, 0x080c, 0x3cb9, 0x008e, 0x00ee, 0x00fe, + 0x080c, 0x3be6, 0x2009, 0x0190, 0x8109, 0x11b0, 0x080c, 0x3af5, + 0x2001, 0x0004, 0x200c, 0x918c, 0xfffd, 0x2102, 0x001e, 0x00fe, + 0x00ee, 0x00de, 0x00ce, 0x00be, 0x00ae, 0x009e, 0x008e, 0x2009, + 0x0017, 0x080c, 0x31c3, 0x0cf8, 0x2001, 0x020b, 0x2004, 0x9084, + 0x0140, 0x1d10, 0x00f6, 0x2079, 0x0000, 0x7884, 0x00fe, 0xd0bc, + 0x0178, 0x2001, 0x0201, 0x200c, 0x81ff, 0x0150, 0x080c, 0x3bc4, + 0x2d00, 0x9c05, 0x9b05, 0x0120, 0x080c, 0x3af5, 0x0804, 0x3aa2, + 0x080c, 0x3d2d, 0x080c, 0x3c51, 0x080c, 0x3ba7, 0x080c, 0x3bdc, + 0x00f6, 0x2079, 0x0100, 0x7824, 0xd0ac, 0x0130, 0x8b58, 0x080c, + 0x3af5, 0x00fe, 0x0804, 0x3aa2, 0x00fe, 0x080c, 0x3aeb, 0x1150, + 0x8d68, 0x2001, 0x0032, 0x2602, 0x2001, 0x0033, 0x2502, 0x080c, + 0x3af5, 0x0080, 0x87ff, 0x0138, 0x2001, 0x0201, 0x2004, 0x9005, + 0x1908, 0x8739, 0x0038, 0x2001, 0x1a31, 0x2004, 0x9086, 0x0000, + 0x1904, 0x39f2, 0x2001, 0x032f, 0x2003, 0x00f6, 0x8631, 0x1208, + 0x8529, 0x2500, 0x9605, 0x0904, 0x3aa2, 0x7884, 0xd0bc, 0x0128, + 0x2d00, 0x9c05, 0x9b05, 0x1904, 0x3aa2, 0xa013, 0x0019, 0x2001, + 0x032a, 0x2003, 0x0004, 0x7884, 0xd0ac, 0x1148, 0x2001, 0x1a31, + 0x2003, 0x0003, 0x2001, 0x032a, 0x2003, 0x0009, 0x0030, 0xa017, + 0x0001, 0x78b4, 0x9005, 0x0108, 0xa016, 0x2800, 0xa05a, 0x2009, + 0x0040, 0x080c, 0x20d9, 0x2900, 0xa85a, 0xa813, 0x0019, 0x7884, + 0xd0a4, 0x1180, 0xa817, 0x0000, 0x00c6, 0x20a9, 0x0004, 0x2061, + 0x0090, 0x602b, 0x0008, 0x2001, 0x0203, 0x2004, 0x1f04, 0x3a79, + 0x00ce, 0x0030, 0xa817, 0x0001, 0x78b0, 0x9005, 0x0108, 0xa816, + 0x00f6, 0x00c6, 0x2079, 0x0100, 0x2061, 0x0090, 0x7827, 0x0002, + 0x2001, 0x002a, 0x2004, 0x9084, 0xfff8, 0x601a, 0x0006, 0x2001, + 0x002b, 0x2004, 0x601e, 0x78c6, 0x000e, 0x78ca, 0x00ce, 0x00fe, + 0x0804, 0x39ac, 0x001e, 0x00c6, 0x2001, 0x032a, 0x2003, 0x0004, + 0x2061, 0x0100, 0x6027, 0x0002, 0x6106, 0x2011, 0x020d, 0x2013, + 0x0020, 0x2001, 0x0004, 0x200c, 0x918c, 0xfffd, 0x2102, 0x080c, + 0x127c, 0x7884, 0x9084, 0x0003, 0x9086, 0x0002, 0x01a0, 0x2009, + 0x0028, 0x080c, 0x20d9, 0x2001, 0x0227, 0x200c, 0x2102, 0x6050, + 0x9084, 0xb7ef, 0x6052, 0x602f, 0x0000, 0x604b, 0xf7f7, 0x6043, + 0x0090, 0x6043, 0x0010, 0x00ce, 0x2d08, 0x2c10, 0x2b18, 0x2b00, + 0x9c05, 0x9d05, 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x00be, 0x00ae, + 0x009e, 0x008e, 0x1118, 0x012e, 0x0804, 0x3191, 0x012e, 0x2021, + 0x400c, 0x0804, 0x3193, 0x9085, 0x0001, 0x1d04, 0x3af4, 0x2091, + 0x6000, 0x8420, 0x9486, 0x0064, 0x0005, 0x2001, 0x0105, 0x2003, + 0x0010, 0x2001, 0x032a, 0x2003, 0x0004, 0x2001, 0x1a31, 0x2003, + 0x0000, 0x0071, 0x2009, 0x0048, 0x080c, 0x20d9, 0x2001, 0x0227, + 0x2024, 0x2402, 0x2001, 0x0109, 0x2003, 0x4000, 0x9026, 0x0005, + 0x00f6, 0x00e6, 0x2071, 0x1a34, 0x7000, 0x9086, 0x0000, 0x0520, + 0x2079, 0x0090, 0x2009, 0x0206, 0x2104, 0x2009, 0x0203, 0x210c, + 0x9106, 0x1120, 0x2009, 0x0040, 0x080c, 0x20d9, 0x782c, 0xd0fc, + 0x0d88, 0x080c, 0x3d2d, 0x7000, 0x9086, 0x0000, 0x1d58, 0x782b, + 0x0004, 0x782c, 0xd0ac, 0x1de8, 0x2009, 0x0040, 0x080c, 0x20d9, + 0x782b, 0x0002, 0x7003, 0x0000, 0x00ee, 0x00fe, 0x0005, 0x00f6, + 0x2079, 0x0100, 0x2001, 0x1816, 0x200c, 0x7932, 0x7936, 0x080c, + 0x251f, 0x7850, 0x9084, 0xfbff, 0x9085, 0x0030, 0x7852, 0x2019, + 0x01f4, 0x8319, 0x1df0, 0x9084, 0xffcf, 0x9085, 0x2000, 0x7852, + 0x20a9, 0x0046, 0x1d04, 0x3b5a, 0x2091, 0x6000, 0x1f04, 0x3b5a, + 0x7850, 0x9085, 0x0400, 0x9084, 0xdfff, 0x7852, 0x2001, 0x0021, + 0x2004, 0x9084, 0x0003, 0x9086, 0x0001, 0x1120, 0x7850, 0x9084, + 0xdfff, 0x7852, 0x784b, 0xf7f7, 0x7843, 0x0090, 0x7843, 0x0010, + 0x20a9, 0x0028, 0xa001, 0x1f04, 0x3b7a, 0x7850, 0x9085, 0x1400, + 0x7852, 0x2019, 0x61a8, 0x7854, 0xa001, 0xa001, 0xd08c, 0x1110, + 0x8319, 0x1dc8, 0x7827, 0x0048, 0x7850, 0x9085, 0x0400, 0x7852, + 0x7843, 0x0040, 0x2019, 0x01f4, 0xa001, 0xa001, 0x8319, 0x1de0, + 0x2001, 0x0100, 0x080c, 0x2987, 0x7827, 0x0020, 0x7843, 0x0000, + 0x9006, 0x080c, 0x2987, 0x7827, 0x0048, 0x00fe, 0x0005, 0x7884, + 0xd0ac, 0x11c8, 0x00f6, 0x00e6, 0x2071, 0x1a31, 0x2079, 0x0320, + 0x2001, 0x0201, 0x2004, 0x9005, 0x0160, 0x7000, 0x9086, 0x0000, + 0x1140, 0x0051, 0xd0bc, 0x0108, 0x8738, 0x7003, 0x0003, 0x782b, + 0x0019, 0x00ee, 0x00fe, 0x0005, 0x00f6, 0x2079, 0x0300, 0x78bc, + 0x00fe, 0x908c, 0x0070, 0x0178, 0x2009, 0x0032, 0x260a, 0x2009, + 0x0033, 0x250a, 0xd0b4, 0x0108, 0x8c60, 0xd0ac, 0x0108, 0x8d68, + 0xd0a4, 0x0108, 0x8b58, 0x0005, 0x00f6, 0x2079, 0x0200, 0x781c, + 0xd084, 0x0110, 0x7837, 0x0050, 0x00fe, 0x0005, 0x00e6, 0x2071, + 0x0100, 0x2001, 0x1979, 0x2004, 0x70e2, 0x080c, 0x38d6, 0x1188, + 0x2001, 0x181e, 0x2004, 0x2009, 0x181d, 0x210c, 0x918c, 0x00ff, + 0x706e, 0x716a, 0x7066, 0x918d, 0x3200, 0x7162, 0x7073, 0xe109, + 0x0080, 0x702c, 0x9085, 0x0002, 0x702e, 0x2009, 0x1816, 0x210c, + 0x716e, 0x7063, 0x0100, 0x7166, 0x719e, 0x706b, 0x0000, 0x7073, + 0x0809, 0x7077, 0x0008, 0x7078, 0x9080, 0x0100, 0x707a, 0x7080, + 0x8000, 0x7082, 0x7087, 0xaaaa, 0x9006, 0x708a, 0x708e, 0x707e, + 0x70d6, 0x70ab, 0x0036, 0x70af, 0x95d5, 0x7014, 0x9084, 0x1984, + 0x9085, 0x0092, 0x7016, 0x080c, 0x3d2d, 0x00f6, 0x2071, 0x1a31, + 0x2079, 0x0320, 0x00d6, 0x2069, 0x0000, 0x6884, 0xd0b4, 0x0120, + 0x689c, 0x780e, 0x6898, 0x780a, 0x00de, 0x2009, 0x03e8, 0x8109, + 0x1df0, 0x792c, 0xd1fc, 0x0110, 0x782b, 0x0004, 0x2011, 0x0011, + 0x080c, 0x3cb9, 0x2011, 0x0001, 0x080c, 0x3cb9, 0x00fe, 0x00ee, + 0x0005, 0x00f6, 0x00e6, 0x2071, 0x1a31, 0x2079, 0x0320, 0x792c, + 0xd1fc, 0x0904, 0x3cb6, 0x782b, 0x0002, 0x9026, 0xd19c, 0x1904, + 0x3cb2, 0x7000, 0x0002, 0x3cb6, 0x3c67, 0x3c97, 0x3cb2, 0xd1bc, + 0x1170, 0xd1dc, 0x1190, 0x8001, 0x7002, 0x2011, 0x0001, 0x080c, + 0x3cb9, 0x0904, 0x3cb6, 0x080c, 0x3cb9, 0x0804, 0x3cb6, 0x00f6, + 0x2079, 0x0300, 0x78bf, 0x0000, 0x00fe, 0x7810, 0x7914, 0x782b, + 0x0004, 0x7812, 0x7916, 0x2001, 0x0201, 0x200c, 0x81ff, 0x0de8, + 0x080c, 0x3bc4, 0x2009, 0x0001, 0x00f6, 0x2079, 0x0300, 0x78b8, + 0x00fe, 0xd0ec, 0x0110, 0x2009, 0x0011, 0x792a, 0x00f8, 0x8001, + 0x7002, 0x9184, 0x0880, 0x1140, 0x782c, 0xd0fc, 0x1904, 0x3c5b, + 0x2011, 0x0001, 0x00b1, 0x0090, 0xa010, 0x9092, 0x0004, 0x9086, + 0x0015, 0x1120, 0xa000, 0xa05a, 0x2011, 0x0031, 0xa212, 0xd1dc, + 0x1960, 0x0828, 0x782b, 0x0004, 0x7003, 0x0000, 0x00ee, 0x00fe, + 0x0005, 0xa014, 0x9005, 0x0550, 0x8001, 0x0036, 0x0096, 0xa016, + 0xa058, 0x2048, 0xa010, 0x2009, 0x0031, 0x911a, 0x831c, 0x831c, + 0x938a, 0x0007, 0x1a0c, 0x0db2, 0x9398, 0x3ce7, 0x231d, 0x083f, + 0x9080, 0x0004, 0x7a2a, 0x7100, 0x8108, 0x7102, 0x009e, 0x003e, + 0x908a, 0x0035, 0x1140, 0x0096, 0xa058, 0x2048, 0xa804, 0xa05a, + 0x2001, 0x0019, 0x009e, 0xa012, 0x9085, 0x0001, 0x0005, 0x3d24, + 0x3d1b, 0x3d12, 0x3d09, 0x3d00, 0x3cf7, 0x3cee, 0xa964, 0x7902, + 0xa968, 0x7906, 0xa96c, 0x7912, 0xa970, 0x7916, 0x0005, 0xa974, + 0x7902, 0xa978, 0x7906, 0xa97c, 0x7912, 0xa980, 0x7916, 0x0005, + 0xa984, 0x7902, 0xa988, 0x7906, 0xa98c, 0x7912, 0xa990, 0x7916, + 0x0005, 0xa994, 0x7902, 0xa998, 0x7906, 0xa99c, 0x7912, 0xa9a0, + 0x7916, 0x0005, 0xa9a4, 0x7902, 0xa9a8, 0x7906, 0xa9ac, 0x7912, + 0xa9b0, 0x7916, 0x0005, 0xa9b4, 0x7902, 0xa9b8, 0x7906, 0xa9bc, + 0x7912, 0xa9c0, 0x7916, 0x0005, 0xa9c4, 0x7902, 0xa9c8, 0x7906, + 0xa9cc, 0x7912, 0xa9d0, 0x7916, 0x0005, 0x00f6, 0x00e6, 0x0086, + 0x2071, 0x1a34, 0x2079, 0x0090, 0x792c, 0xd1fc, 0x01e8, 0x782b, + 0x0002, 0x2940, 0x9026, 0x7000, 0x0002, 0x3d54, 0x3d40, 0x3d4b, + 0x8001, 0x7002, 0xd19c, 0x1180, 0x2011, 0x0001, 0x080c, 0x3cb9, + 0x190c, 0x3cb9, 0x0048, 0x8001, 0x7002, 0x782c, 0xd0fc, 0x1d38, + 0x2011, 0x0001, 0x080c, 0x3cb9, 0x008e, 0x00ee, 0x00fe, 0x0005, + 0x00f6, 0x00e6, 0x00c6, 0x0086, 0x2061, 0x0200, 0x2001, 0x1979, + 0x2004, 0x601a, 0x2061, 0x0100, 0x2001, 0x1978, 0x2004, 0x60ce, + 0x6104, 0xc1ac, 0x6106, 0x2001, 0x002c, 0x2004, 0x9005, 0x0520, + 0x2038, 0x2001, 0x002e, 0x2024, 0x2001, 0x002f, 0x201c, 0x080c, + 0x4612, 0xa813, 0x0019, 0xaf16, 0x2900, 0xa85a, 0x978a, 0x0007, + 0x0220, 0x2138, 0x2009, 0x0007, 0x0010, 0x2708, 0x903e, 0x0096, + 0xa858, 0x2048, 0xa85c, 0x9080, 0x0019, 0x009e, 0x080c, 0x3dd0, + 0x1d68, 0x2900, 0xa85a, 0x00d0, 0x080c, 0x4612, 0xa813, 0x0019, + 0xa817, 0x0001, 0x2900, 0xa85a, 0x2001, 0x002e, 0x2004, 0xa866, + 0x2001, 0x002f, 0x2004, 0xa86a, 0x2001, 0x002a, 0x2004, 0x9084, + 0xfff8, 0xa86e, 0x2001, 0x002b, 0x2004, 0xa872, 0x2061, 0x0090, + 0x2079, 0x0100, 0x2001, 0x1978, 0x2004, 0x6036, 0x2009, 0x0040, + 0x080c, 0x20d9, 0x2001, 0x002a, 0x2004, 0x9084, 0xfff8, 0x601a, + 0x0006, 0x2001, 0x002b, 0x2004, 0x601e, 0x78c6, 0x000e, 0x78ca, + 0x9006, 0x600a, 0x600e, 0x008e, 0x00ce, 0x00ee, 0x00fe, 0x0005, + 0x00e6, 0x2071, 0x0080, 0xaa60, 0x22e8, 0x20a0, 0x20e1, 0x0000, + 0x2099, 0x0088, 0x702b, 0x0026, 0x7402, 0x7306, 0x9006, 0x700a, + 0x700e, 0x810b, 0x810b, 0x21a8, 0x810b, 0x7112, 0x702b, 0x0041, + 0x702c, 0xd0fc, 0x0de8, 0x702b, 0x0002, 0x702b, 0x0040, 0x4005, + 0x7400, 0x7304, 0x87ff, 0x0190, 0x0086, 0x0096, 0x2940, 0x0086, + 0x080c, 0x4612, 0x008e, 0xa058, 0x00a6, 0x2050, 0x2900, 0xb006, + 0xa05a, 0x00ae, 0x009e, 0x008e, 0x9085, 0x0001, 0x00ee, 0x0005, + 0x00e6, 0x2001, 0x002d, 0x2004, 0x9005, 0x0528, 0x2038, 0x2001, + 0x0030, 0x2024, 0x2001, 0x0031, 0x201c, 0x080c, 0x4612, 0x2940, + 0xa813, 0x0019, 0xaf16, 0x2900, 0xa85a, 0x978a, 0x0007, 0x0220, + 0x2138, 0x2009, 0x0007, 0x0010, 0x2708, 0x903e, 0x0096, 0xa858, + 0x2048, 0xa85c, 0x9080, 0x0019, 0x009e, 0x080c, 0x3dd0, 0x1d68, + 0x2900, 0xa85a, 0x00d8, 0x080c, 0x4612, 0x2940, 0xa013, 0x0019, + 0xa017, 0x0001, 0x2800, 0xa05a, 0x2001, 0x0030, 0x2004, 0xa066, + 0x2001, 0x0031, 0x2004, 0xa06a, 0x2001, 0x002a, 0x2004, 0x9084, + 0xfff8, 0xa06e, 0x2001, 0x002b, 0x2004, 0xa072, 0x2001, 0x032a, + 0x2003, 0x0004, 0x7884, 0xd0ac, 0x1180, 0x2001, 0x0101, 0x200c, + 0x918d, 0x0200, 0x2102, 0xa017, 0x0000, 0x2001, 0x1a31, 0x2003, + 0x0003, 0x2001, 0x032a, 0x2003, 0x0009, 0x2001, 0x0300, 0x2003, + 0x0000, 0x2001, 0x020d, 0x2003, 0x0000, 0x2001, 0x0004, 0x200c, + 0x918d, 0x0002, 0x2102, 0x00ee, 0x0005, 0x0126, 0x2091, 0x8000, + 0x20a9, 0x0013, 0x20a1, 0x1840, 0x20e9, 0x0001, 0x9006, 0x4004, + 0x2009, 0x013c, 0x200a, 0x012e, 0x7880, 0x9086, 0x0052, 0x0108, + 0x0005, 0x0804, 0x3191, 0x7d98, 0x7c9c, 0x0804, 0x3288, 0x080c, + 0x6c53, 0x190c, 0x59e6, 0x2069, 0x1853, 0x2d00, 0x2009, 0x0030, + 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0x2039, 0x0001, 0x080c, 0x465b, + 0x701f, 0x3ea3, 0x0005, 0x080c, 0x5122, 0x1130, 0x3b00, 0x3a08, + 0xc194, 0xc095, 0x20d8, 0x21d0, 0x2069, 0x1853, 0x6800, 0x9005, + 0x0904, 0x31c6, 0x6804, 0xd0ac, 0x0118, 0xd0a4, 0x0904, 0x31c6, + 0xd094, 0x00c6, 0x2061, 0x0100, 0x6104, 0x0138, 0x6200, 0x9292, + 0x0005, 0x0218, 0x918c, 0xffdf, 0x0010, 0x918d, 0x0020, 0x6106, + 0x00ce, 0xd08c, 0x00c6, 0x2061, 0x0100, 0x6104, 0x0118, 0x918d, + 0x0010, 0x0010, 0x918c, 0xffef, 0x6106, 0x00ce, 0xd084, 0x0158, + 0x6a28, 0x928a, 0x007f, 0x1a04, 0x31c6, 0x9288, 0x2f92, 0x210d, + 0x918c, 0x00ff, 0x615e, 0xd0dc, 0x0130, 0x6828, 0x908a, 0x007f, + 0x1a04, 0x31c6, 0x6056, 0x6888, 0x9084, 0x0030, 0x8004, 0x8004, + 0x8004, 0x8004, 0x0006, 0x2009, 0x1980, 0x9080, 0x2612, 0x2005, + 0x200a, 0x000e, 0x2009, 0x1981, 0x9080, 0x2616, 0x2005, 0x200a, + 0x6808, 0x908a, 0x0100, 0x0a04, 0x31c6, 0x908a, 0x0841, 0x1a04, + 0x31c6, 0x9084, 0x0007, 0x1904, 0x31c6, 0x680c, 0x9005, 0x0904, + 0x31c6, 0x6810, 0x9005, 0x0904, 0x31c6, 0x6848, 0x6940, 0x910a, + 0x1a04, 0x31c6, 0x8001, 0x0904, 0x31c6, 0x684c, 0x6944, 0x910a, + 0x1a04, 0x31c6, 0x8001, 0x0904, 0x31c6, 0x2009, 0x1950, 0x200b, + 0x0000, 0x2001, 0x1875, 0x2004, 0xd0c4, 0x0140, 0x7884, 0x200a, + 0x2009, 0x017f, 0x200a, 0x3b00, 0xc085, 0x20d8, 0x6814, 0x908c, + 0x00ff, 0x6146, 0x8007, 0x9084, 0x00ff, 0x604a, 0x080c, 0x6f5b, + 0x080c, 0x62da, 0x080c, 0x630e, 0x6808, 0x602a, 0x080c, 0x204b, + 0x2009, 0x0170, 0x200b, 0x0080, 0xa001, 0xa001, 0x200b, 0x0000, + 0x0036, 0x6b08, 0x080c, 0x2579, 0x003e, 0x6000, 0x9086, 0x0000, + 0x1904, 0x403f, 0x6818, 0x691c, 0x6a20, 0x6b24, 0x8007, 0x810f, + 0x8217, 0x831f, 0x6016, 0x611a, 0x621e, 0x6322, 0x6c04, 0xd4f4, + 0x0148, 0x6830, 0x6934, 0x6a38, 0x6b3c, 0x8007, 0x810f, 0x8217, + 0x831f, 0x0010, 0x9084, 0xf0ff, 0x6006, 0x610a, 0x620e, 0x6312, + 0x8007, 0x810f, 0x8217, 0x831f, 0x20a9, 0x0004, 0x20a1, 0x1982, + 0x20e9, 0x0001, 0x4001, 0x20a9, 0x0004, 0x20a1, 0x199c, 0x20e9, + 0x0001, 0x4001, 0x080c, 0x7d50, 0x00c6, 0x900e, 0x20a9, 0x0001, + 0x6b70, 0xd384, 0x0510, 0x0068, 0x2009, 0x0100, 0x210c, 0x918e, + 0x0008, 0x1110, 0x839d, 0x0010, 0x83f5, 0x3e18, 0x12b0, 0x3508, + 0x8109, 0x080c, 0x74e0, 0x6878, 0x6016, 0x6874, 0x2008, 0x9084, + 0xff00, 0x8007, 0x600a, 0x9184, 0x00ff, 0x6006, 0x8108, 0x1118, + 0x6003, 0x0003, 0x0010, 0x6003, 0x0001, 0x1f04, 0x3f94, 0x00ce, + 0x00c6, 0x2061, 0x196b, 0x6a88, 0x9284, 0xc000, 0x2010, 0x9286, + 0x0000, 0x1158, 0x2063, 0x0000, 0x2001, 0x0001, 0x080c, 0x2820, + 0x2001, 0x0001, 0x080c, 0x2803, 0x0088, 0x9286, 0x4000, 0x1148, + 0x2063, 0x0001, 0x9006, 0x080c, 0x2820, 0x9006, 0x080c, 0x2803, + 0x0028, 0x9286, 0x8000, 0x1d30, 0x2063, 0x0002, 0x00ce, 0x00e6, + 0x2c70, 0x080c, 0x0e69, 0x00ee, 0x6888, 0xd0ec, 0x0130, 0x2011, + 0x0114, 0x2204, 0x9085, 0x0100, 0x2012, 0x6a80, 0x9284, 0x0030, + 0x9086, 0x0030, 0x1128, 0x9294, 0xffcf, 0x9295, 0x0020, 0x6a82, + 0x2001, 0x194d, 0x6a80, 0x9294, 0x0030, 0x928e, 0x0000, 0x0170, + 0x928e, 0x0010, 0x0118, 0x928e, 0x0020, 0x0140, 0x2003, 0xaaaa, + 0x080c, 0x25ee, 0x2001, 0x193e, 0x2102, 0x0008, 0x2102, 0x00c6, + 0x2061, 0x0100, 0x602f, 0x0040, 0x602f, 0x0000, 0x00ce, 0x080c, + 0x6c53, 0x0128, 0x080c, 0x4a2e, 0x0110, 0x080c, 0x253f, 0x60cc, + 0x9005, 0x01c0, 0x6003, 0x0001, 0x2009, 0x4027, 0x00d0, 0x080c, + 0x6c53, 0x1168, 0x2011, 0x6ad9, 0x080c, 0x7c4a, 0x2011, 0x6acc, + 0x080c, 0x7d1b, 0x080c, 0x6f2f, 0x080c, 0x6b8a, 0x0040, 0x080c, + 0x58e0, 0x0028, 0x6003, 0x0004, 0x2009, 0x403f, 0x0010, 0x0804, + 0x3191, 0x2001, 0x0170, 0x2004, 0x9084, 0x00ff, 0x9086, 0x004c, + 0x1118, 0x2091, 0x30bd, 0x0817, 0x2091, 0x303d, 0x0817, 0x6000, + 0x9086, 0x0000, 0x0904, 0x31c3, 0x2069, 0x1853, 0x7890, 0x6842, + 0x7894, 0x6846, 0x2d00, 0x2009, 0x0030, 0x7a8c, 0x7b88, 0x7c9c, + 0x7d98, 0x2039, 0x0001, 0x0804, 0x465e, 0x9006, 0x080c, 0x253f, + 0x81ff, 0x1904, 0x31c3, 0x080c, 0x6c53, 0x11b0, 0x080c, 0x6f2a, + 0x080c, 0x5a21, 0x080c, 0x2f86, 0x0118, 0x6130, 0xc18d, 0x6132, + 0x080c, 0xbcec, 0x0130, 0x080c, 0x6c76, 0x1118, 0x080c, 0x6c2d, + 0x0038, 0x080c, 0x6b8a, 0x0020, 0x080c, 0x59e6, 0x080c, 0x58e0, + 0x0804, 0x3191, 0x81ff, 0x1904, 0x31c3, 0x080c, 0x6c53, 0x1110, + 0x0804, 0x31c3, 0x618c, 0x81ff, 0x01a8, 0x704f, 0x0000, 0x2001, + 0x1c80, 0x2009, 0x0040, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0x0126, + 0x2091, 0x8000, 0x2039, 0x0001, 0x080c, 0x465e, 0x701f, 0x318f, + 0x012e, 0x0005, 0x704f, 0x0001, 0x00d6, 0x2069, 0x1c80, 0x20a9, + 0x0040, 0x20e9, 0x0001, 0x20a1, 0x1c80, 0x2019, 0xffff, 0x4304, + 0x6554, 0x9588, 0x2f92, 0x210d, 0x918c, 0x00ff, 0x216a, 0x900e, + 0x2011, 0x0002, 0x2100, 0x9506, 0x01a8, 0x080c, 0x5f7e, 0x1190, + 0xb814, 0x821c, 0x0238, 0x9398, 0x1c80, 0x9085, 0xff00, 0x8007, + 0x201a, 0x0038, 0x9398, 0x1c80, 0x2324, 0x94a4, 0xff00, 0x9405, + 0x201a, 0x8210, 0x8108, 0x9182, 0x0080, 0x1208, 0x0c18, 0x8201, + 0x8007, 0x2d0c, 0x9105, 0x206a, 0x00de, 0x20a9, 0x0040, 0x20a1, + 0x1c80, 0x2099, 0x1c80, 0x080c, 0x5971, 0x0804, 0x4097, 0x080c, + 0x4645, 0x0904, 0x31c6, 0x080c, 0x4612, 0x1120, 0x2009, 0x0002, + 0x0804, 0x31c3, 0x080c, 0x5113, 0xd0b4, 0x0558, 0x7884, 0x908e, + 0x007e, 0x0538, 0x908e, 0x007f, 0x0520, 0x908e, 0x0080, 0x0508, + 0x080c, 0x2f81, 0x1148, 0xb800, 0xd08c, 0x11d8, 0xb804, 0x9084, + 0x00ff, 0x9086, 0x0006, 0x11a8, 0xa867, 0x0000, 0xa868, 0xc0fd, + 0xa86a, 0x080c, 0xb7bd, 0x1120, 0x2009, 0x0003, 0x0804, 0x31c3, + 0x7007, 0x0003, 0x701f, 0x4125, 0x0005, 0x080c, 0x4645, 0x0904, + 0x31c6, 0x20a9, 0x002b, 0xb8b4, 0x20e0, 0xb8b8, 0x2098, 0xa860, + 0x20e8, 0xa85c, 0x9080, 0x0002, 0x20a0, 0x4003, 0x20a9, 0x0008, + 0x9080, 0x0006, 0x20a0, 0xb8b4, 0x20e0, 0xb8b8, 0x9080, 0x0006, + 0x2098, 0x080c, 0x0f52, 0x0070, 0x20a9, 0x0004, 0xa85c, 0x9080, + 0x000a, 0x20a0, 0xb8b4, 0x20e0, 0xb8b8, 0x9080, 0x000a, 0x2098, + 0x080c, 0x0f52, 0x8906, 0x8006, 0x8007, 0x90bc, 0x003f, 0x9084, + 0xffc0, 0x9080, 0x0002, 0x2009, 0x002b, 0x7a8c, 0x7b88, 0x7c9c, + 0x7d98, 0x0804, 0x465e, 0x81ff, 0x1904, 0x31c3, 0x080c, 0x4629, + 0x0904, 0x31c6, 0x080c, 0x60f0, 0x0904, 0x31c3, 0x0058, 0xa878, + 0x9005, 0x0120, 0x2009, 0x0004, 0x0804, 0x31c3, 0xa974, 0xaa94, + 0x0804, 0x3191, 0x080c, 0x511b, 0x0904, 0x3191, 0x701f, 0x416f, + 0x7007, 0x0003, 0x0005, 0x81ff, 0x1904, 0x31c3, 0x7888, 0x908a, + 0x1000, 0x1a04, 0x31c6, 0x080c, 0x4645, 0x0904, 0x31c6, 0x080c, + 0x62a4, 0x0120, 0x080c, 0x62ac, 0x1904, 0x31c6, 0x080c, 0x6175, + 0x0904, 0x31c3, 0x2019, 0x0004, 0x900e, 0x080c, 0x6102, 0x0904, + 0x31c3, 0x7984, 0x7a88, 0x04c9, 0x08a8, 0xa89c, 0x908a, 0x1000, + 0x12f8, 0x080c, 0x4643, 0x01e0, 0x080c, 0x62a4, 0x0118, 0x080c, + 0x62ac, 0x11b0, 0x080c, 0x6175, 0x2009, 0x0002, 0x0168, 0x2009, + 0x0002, 0x2019, 0x0004, 0x080c, 0x6102, 0x2009, 0x0003, 0x0120, + 0xa998, 0xaa9c, 0x00d1, 0x0060, 0xa897, 0x4005, 0xa99a, 0x0010, + 0xa897, 0x4006, 0x900e, 0x9085, 0x0001, 0x2001, 0x0030, 0x0005, + 0xa897, 0x4000, 0x080c, 0x511b, 0x0110, 0x9006, 0x0018, 0x900e, + 0x9085, 0x0001, 0x2001, 0x0000, 0x0005, 0x9186, 0x00ff, 0x0110, + 0x0071, 0x0060, 0x2029, 0x007e, 0x2061, 0x1800, 0x6454, 0x2400, + 0x9506, 0x0110, 0x2508, 0x0019, 0x8529, 0x1ec8, 0x0005, 0x080c, + 0x5f7e, 0x1138, 0x2200, 0x8003, 0x800b, 0x810b, 0x9108, 0x080c, + 0x7c58, 0x0005, 0x81ff, 0x1904, 0x31c3, 0x080c, 0x4629, 0x0904, + 0x31c6, 0x080c, 0x6045, 0x0904, 0x31c3, 0x080c, 0x60f9, 0x0904, + 0x31c3, 0x0804, 0x417a, 0x81ff, 0x1904, 0x31c3, 0x080c, 0x4629, + 0x0904, 0x31c6, 0x080c, 0x6045, 0x0904, 0x31c3, 0x080c, 0x60e7, + 0x0904, 0x31c3, 0x0804, 0x417a, 0x6100, 0x0804, 0x3191, 0x080c, + 0x4645, 0x0904, 0x31c6, 0x080c, 0x5127, 0x1904, 0x31c3, 0x79a8, + 0xd184, 0x1158, 0xb834, 0x8007, 0x789e, 0xb830, 0x8007, 0x789a, + 0xbb2c, 0x831f, 0xba28, 0x8217, 0x0050, 0xb824, 0x8007, 0x789e, + 0xb820, 0x8007, 0x789a, 0xbb1c, 0x831f, 0xba18, 0x8217, 0xb900, + 0x918c, 0x0200, 0x0804, 0x3191, 0x78a8, 0x909c, 0x0003, 0xd0b4, + 0x1140, 0x939a, 0x0003, 0x1a04, 0x31c3, 0x6254, 0x7884, 0x9206, + 0x1560, 0x2031, 0x1848, 0x2009, 0x013c, 0x2136, 0x2001, 0x1840, + 0x2009, 0x000c, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0x2039, 0x0001, + 0x0006, 0x78a8, 0x9084, 0x0080, 0x1118, 0x000e, 0x0804, 0x465e, + 0x000e, 0x2031, 0x0000, 0x2061, 0x18ae, 0x2c44, 0xa66a, 0xa17a, + 0xa772, 0xa076, 0xa28e, 0xa392, 0xa496, 0xa59a, 0x080c, 0x10b5, + 0x7007, 0x0002, 0x701f, 0x429d, 0x0005, 0x81ff, 0x1904, 0x31c3, + 0x080c, 0x4645, 0x0904, 0x31c6, 0x080c, 0x62a4, 0x1904, 0x31c3, + 0x00c6, 0x080c, 0x4612, 0x00ce, 0x0904, 0x31c3, 0xa867, 0x0000, + 0xa868, 0xc0fd, 0xa86a, 0x7ea8, 0x080c, 0xb763, 0x0904, 0x31c3, + 0x7007, 0x0003, 0x701f, 0x42a1, 0x0005, 0x080c, 0x3e75, 0x0804, + 0x3191, 0xa830, 0x9086, 0x0100, 0x0904, 0x31c3, 0x8906, 0x8006, + 0x8007, 0x90bc, 0x003f, 0x9084, 0xffc0, 0x9080, 0x001b, 0x2009, + 0x000c, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0x0804, 0x465e, 0x9006, + 0x080c, 0x253f, 0x78a8, 0x9084, 0x00ff, 0x9086, 0x00ff, 0x0118, + 0x81ff, 0x1904, 0x31c3, 0x080c, 0x6c53, 0x0110, 0x080c, 0x59e6, + 0x7888, 0x908a, 0x1000, 0x1a04, 0x31c6, 0x7984, 0x9186, 0x00ff, + 0x0138, 0x9182, 0x007f, 0x1a04, 0x31c6, 0x2100, 0x080c, 0x2509, + 0x0026, 0x00c6, 0x0126, 0x2091, 0x8000, 0x2061, 0x19c9, 0x601b, + 0x0000, 0x601f, 0x0000, 0x6073, 0x0000, 0x6077, 0x0000, 0x080c, + 0x6c53, 0x1158, 0x080c, 0x6f2a, 0x080c, 0x5a21, 0x9085, 0x0001, + 0x080c, 0x6c9a, 0x080c, 0x6b8a, 0x00d0, 0x080c, 0x9947, 0x2061, + 0x0100, 0x2001, 0x1816, 0x2004, 0x9084, 0x00ff, 0x810f, 0x9105, + 0x604a, 0x6043, 0x0090, 0x6043, 0x0010, 0x2009, 0x1968, 0x200b, + 0x0000, 0x2009, 0x002d, 0x2011, 0x590c, 0x080c, 0x7cd9, 0x7984, + 0x080c, 0x6c53, 0x1110, 0x2009, 0x00ff, 0x7a88, 0x080c, 0x41dd, + 0x012e, 0x00ce, 0x002e, 0x0804, 0x3191, 0x7984, 0x080c, 0x5f1e, + 0x2b08, 0x1904, 0x31c6, 0x0804, 0x3191, 0x81ff, 0x0120, 0x2009, + 0x0001, 0x0804, 0x31c3, 0x60d4, 0xd0ac, 0x1130, 0xd09c, 0x1120, + 0x2009, 0x0005, 0x0804, 0x31c3, 0x080c, 0x4612, 0x1120, 0x2009, + 0x0002, 0x0804, 0x31c3, 0x7984, 0x9192, 0x0021, 0x1a04, 0x31c6, + 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0xa85c, 0x9080, 0x0019, 0x702a, + 0xaf60, 0x7736, 0x080c, 0x465b, 0x701f, 0x4355, 0x7880, 0x9086, + 0x006e, 0x0110, 0x701f, 0x4be0, 0x0005, 0x2009, 0x0080, 0x080c, + 0x5f7e, 0x1118, 0x080c, 0x62a4, 0x0120, 0x2021, 0x400a, 0x0804, + 0x3193, 0x00d6, 0x0096, 0xa964, 0xaa6c, 0xab70, 0xac74, 0xad78, + 0xae7c, 0xa884, 0x90be, 0x0100, 0x0904, 0x43ee, 0x90be, 0x0112, + 0x0904, 0x43ee, 0x90be, 0x0113, 0x0904, 0x43ee, 0x90be, 0x0114, + 0x0904, 0x43ee, 0x90be, 0x0117, 0x0904, 0x43ee, 0x90be, 0x011a, + 0x0904, 0x43ee, 0x90be, 0x011c, 0x0904, 0x43ee, 0x90be, 0x0121, + 0x0904, 0x43d5, 0x90be, 0x0131, 0x0904, 0x43d5, 0x90be, 0x0171, + 0x0904, 0x43ee, 0x90be, 0x0173, 0x0904, 0x43ee, 0x90be, 0x01a1, + 0x1128, 0xa894, 0x8007, 0xa896, 0x0804, 0x43f9, 0x90be, 0x0212, + 0x0904, 0x43e2, 0x90be, 0x0213, 0x05e8, 0x90be, 0x0214, 0x0500, + 0x90be, 0x0217, 0x0188, 0x90be, 0x021a, 0x1120, 0xa89c, 0x8007, + 0xa89e, 0x04e0, 0x90be, 0x021f, 0x05c8, 0x90be, 0x0300, 0x05b0, + 0x009e, 0x00de, 0x0804, 0x31c6, 0x7028, 0x9080, 0x0010, 0x2098, + 0x20a0, 0x7034, 0x20e0, 0x20e8, 0x20a9, 0x0007, 0x080c, 0x4437, + 0x7028, 0x9080, 0x000e, 0x2098, 0x20a0, 0x7034, 0x20e0, 0x20e8, + 0x20a9, 0x0001, 0x080c, 0x4437, 0x00c8, 0x7028, 0x9080, 0x000c, + 0x2098, 0x20a0, 0x7034, 0x20e0, 0x20e8, 0x20a9, 0x0001, 0x080c, + 0x4444, 0x00b8, 0x7028, 0x9080, 0x000e, 0x2098, 0x20a0, 0x7034, + 0x20e0, 0x20e8, 0x20a9, 0x0001, 0x080c, 0x4444, 0x7028, 0x9080, + 0x000c, 0x2098, 0x20a0, 0x7034, 0x20e0, 0x20e8, 0x20a9, 0x0001, + 0x04f1, 0x00c6, 0x080c, 0x4612, 0x0550, 0xa868, 0xc0fd, 0xa86a, + 0xa867, 0x0119, 0x9006, 0xa882, 0xa87f, 0x0020, 0xa88b, 0x0001, + 0x810b, 0xa9ae, 0xa8b2, 0xaab6, 0xabba, 0xacbe, 0xadc2, 0xa9c6, + 0xa8ca, 0x00ce, 0x009e, 0x00de, 0xa866, 0xa822, 0xa868, 0xc0fd, + 0xa86a, 0xa804, 0x2048, 0x080c, 0xb77e, 0x1120, 0x2009, 0x0003, + 0x0804, 0x31c3, 0x7007, 0x0003, 0x701f, 0x442e, 0x0005, 0x00ce, + 0x009e, 0x00de, 0x2009, 0x0002, 0x0804, 0x31c3, 0xa820, 0x9086, + 0x8001, 0x1904, 0x3191, 0x2009, 0x0004, 0x0804, 0x31c3, 0x0016, + 0x0026, 0x3510, 0x20a9, 0x0002, 0x4002, 0x4104, 0x4004, 0x8211, + 0x1dc8, 0x002e, 0x001e, 0x0005, 0x0016, 0x0026, 0x0036, 0x0046, + 0x3520, 0x20a9, 0x0004, 0x4002, 0x4304, 0x4204, 0x4104, 0x4004, + 0x8421, 0x1db8, 0x004e, 0x003e, 0x002e, 0x001e, 0x0005, 0x81ff, + 0x0120, 0x2009, 0x0001, 0x0804, 0x31c3, 0x60d4, 0xd0ac, 0x1130, + 0xd09c, 0x1120, 0x2009, 0x0005, 0x0804, 0x31c3, 0x7984, 0x78a8, + 0x2040, 0x080c, 0x9940, 0x1120, 0x9182, 0x007f, 0x0a04, 0x31c6, + 0x9186, 0x00ff, 0x0904, 0x31c6, 0x9182, 0x0800, 0x1a04, 0x31c6, + 0x7a8c, 0x7b88, 0x6074, 0x9306, 0x1140, 0x6078, 0x924e, 0x0904, + 0x31c6, 0x99cc, 0xff00, 0x0904, 0x31c6, 0x0126, 0x2091, 0x8000, + 0x080c, 0x452c, 0x0560, 0x90c6, 0x4000, 0x1170, 0x00c6, 0x0006, + 0x900e, 0x080c, 0x619e, 0x1108, 0xc185, 0xb800, 0xd0bc, 0x0108, + 0xc18d, 0x000e, 0x00ce, 0x00b8, 0x90c6, 0x4007, 0x1110, 0x2408, + 0x0090, 0x90c6, 0x4008, 0x1118, 0x2708, 0x2610, 0x0060, 0x90c6, + 0x4009, 0x1108, 0x0040, 0x90c6, 0x4006, 0x1108, 0x0020, 0x2001, + 0x4005, 0x2009, 0x000a, 0x2020, 0x012e, 0x0804, 0x3193, 0x2b00, + 0x7026, 0x0016, 0x00b6, 0x00c6, 0x00e6, 0x2c70, 0x080c, 0x9a23, + 0x0904, 0x4501, 0x2b00, 0x6012, 0x080c, 0xba69, 0x2e58, 0x00ee, + 0x00e6, 0x00c6, 0x080c, 0x4612, 0x00ce, 0x2b70, 0x1158, 0x080c, + 0x99d6, 0x00ee, 0x00ce, 0x00be, 0x001e, 0x012e, 0x2009, 0x0002, + 0x0804, 0x31c3, 0x900e, 0xa966, 0xa96a, 0x2900, 0x6016, 0xa932, + 0xa868, 0xc0fd, 0xd88c, 0x0108, 0xc0f5, 0xa86a, 0x080c, 0x2e30, + 0x6023, 0x0001, 0x9006, 0x080c, 0x5ebb, 0x2001, 0x0002, 0x080c, + 0x5ecf, 0x2009, 0x0002, 0x080c, 0x9a50, 0x78a8, 0xd094, 0x0138, + 0x00ee, 0x7024, 0x00e6, 0x2058, 0xb8bc, 0xc08d, 0xb8be, 0x9085, + 0x0001, 0x00ee, 0x00ce, 0x00be, 0x001e, 0x012e, 0x1120, 0x2009, + 0x0003, 0x0804, 0x31c3, 0x7007, 0x0003, 0x701f, 0x4510, 0x0005, + 0xa830, 0x9086, 0x0100, 0x7024, 0x2058, 0x1138, 0x2009, 0x0004, + 0xba04, 0x9294, 0x00ff, 0x0804, 0x5070, 0x900e, 0xa868, 0xd0f4, + 0x1904, 0x3191, 0x080c, 0x619e, 0x1108, 0xc185, 0xb800, 0xd0bc, + 0x0108, 0xc18d, 0x0804, 0x3191, 0x00e6, 0x00d6, 0x0096, 0x83ff, + 0x0904, 0x4574, 0x902e, 0x080c, 0x9940, 0x0130, 0x9026, 0x20a9, + 0x0800, 0x2071, 0x1000, 0x0030, 0x2021, 0x007f, 0x20a9, 0x0781, + 0x2071, 0x107f, 0x2e04, 0x9005, 0x11b0, 0x2100, 0x9406, 0x15e8, + 0x2428, 0x94ce, 0x007f, 0x1120, 0x92ce, 0xfffd, 0x1528, 0x0030, + 0x94ce, 0x0080, 0x1130, 0x92ce, 0xfffc, 0x11f0, 0x93ce, 0x00ff, + 0x11d8, 0xc5fd, 0x0450, 0x2058, 0xbf10, 0x2700, 0x9306, 0x11b8, + 0xbe14, 0x2600, 0x9206, 0x1198, 0x2400, 0x9106, 0x1150, 0xd884, + 0x0568, 0xd894, 0x1558, 0x080c, 0x62a4, 0x1540, 0x2001, 0x4000, + 0x0430, 0x2001, 0x4007, 0x0418, 0x2001, 0x4006, 0x0400, 0x2400, + 0x9106, 0x1158, 0xbe14, 0x87ff, 0x1128, 0x86ff, 0x0948, 0x080c, + 0x9940, 0x1930, 0x2001, 0x4008, 0x0090, 0x8420, 0x8e70, 0x1f04, + 0x4542, 0x85ff, 0x1130, 0x2001, 0x4009, 0x0048, 0x2001, 0x0001, + 0x0030, 0x080c, 0x5f1e, 0x1dd0, 0xbb12, 0xba16, 0x9006, 0x9005, + 0x009e, 0x00de, 0x00ee, 0x0005, 0x81ff, 0x0120, 0x2009, 0x0001, + 0x0804, 0x31c3, 0x080c, 0x4612, 0x1120, 0x2009, 0x0002, 0x0804, + 0x31c3, 0xa867, 0x0000, 0xa868, 0xc0fd, 0xa86a, 0x7884, 0x9005, + 0x0904, 0x31c6, 0x9096, 0x00ff, 0x0120, 0x9092, 0x0004, 0x1a04, + 0x31c6, 0x2010, 0x2918, 0x080c, 0x2dd6, 0x1120, 0x2009, 0x0003, + 0x0804, 0x31c3, 0x7007, 0x0003, 0x701f, 0x45c7, 0x0005, 0xa830, + 0x9086, 0x0100, 0x1904, 0x3191, 0x2009, 0x0004, 0x0804, 0x31c3, + 0x7984, 0x080c, 0x9940, 0x1120, 0x9182, 0x007f, 0x0a04, 0x31c6, + 0x9186, 0x00ff, 0x0904, 0x31c6, 0x9182, 0x0800, 0x1a04, 0x31c6, + 0x2001, 0x9000, 0x080c, 0x50cb, 0x1904, 0x31c3, 0x0804, 0x3191, + 0xa998, 0x080c, 0x9940, 0x1118, 0x9182, 0x007f, 0x0280, 0x9186, + 0x00ff, 0x0168, 0x9182, 0x0800, 0x1250, 0x2001, 0x9000, 0x080c, + 0x50cb, 0x11a8, 0x0060, 0xa897, 0x4005, 0xa99a, 0x0010, 0xa897, + 0x4006, 0x900e, 0x9085, 0x0001, 0x2001, 0x0030, 0x0005, 0xa897, + 0x4000, 0x900e, 0x9085, 0x0001, 0x2001, 0x0000, 0x0005, 0x2009, + 0x000a, 0x0c48, 0x080c, 0x0fd5, 0x0198, 0x9006, 0xa802, 0x7014, + 0x9005, 0x1120, 0x2900, 0x7016, 0x701a, 0x0040, 0x7018, 0xa802, + 0x0086, 0x2040, 0x2900, 0xa006, 0x701a, 0x008e, 0x9085, 0x0001, + 0x0005, 0x7984, 0x080c, 0x5f7e, 0x1130, 0x7e88, 0x9684, 0x3fff, + 0x9082, 0x4000, 0x0208, 0x905e, 0x8bff, 0x0005, 0xa998, 0x080c, + 0x5f7e, 0x1130, 0xae9c, 0x9684, 0x3fff, 0x9082, 0x4000, 0x0208, + 0x905e, 0x8bff, 0x0005, 0xae98, 0x0008, 0x7e84, 0x2608, 0x080c, + 0x5f7e, 0x1108, 0x0008, 0x905e, 0x8bff, 0x0005, 0x0016, 0x7114, + 0x81ff, 0x0128, 0x2148, 0xa904, 0x080c, 0x1007, 0x0cc8, 0x7116, + 0x711a, 0x001e, 0x0005, 0x2031, 0x0001, 0x0010, 0x2031, 0x0000, + 0x2061, 0x18ae, 0x2c44, 0xa66a, 0xa17a, 0xa772, 0xa076, 0xa28e, + 0xa392, 0xa496, 0xa59a, 0x080c, 0x10b5, 0x7007, 0x0002, 0x701f, + 0x3191, 0x0005, 0x00f6, 0x0126, 0x2091, 0x8000, 0x2079, 0x0000, + 0x2001, 0x18a6, 0x2004, 0x9005, 0x1190, 0x0e04, 0x468f, 0x7a36, + 0x7833, 0x0012, 0x7a82, 0x7b86, 0x7c8a, 0x2091, 0x4080, 0x2001, + 0x0089, 0x2004, 0xd084, 0x190c, 0x1167, 0x0804, 0x46f5, 0x0016, + 0x0086, 0x0096, 0x00c6, 0x00e6, 0x2071, 0x1894, 0x7044, 0x9005, + 0x1540, 0x7148, 0x9182, 0x0010, 0x0288, 0x7038, 0x2060, 0x080c, + 0x0fd5, 0x0904, 0x46ed, 0xa84b, 0x0000, 0x2900, 0x7046, 0x2001, + 0x0002, 0x9080, 0x1da2, 0x2005, 0xa846, 0x0098, 0x7038, 0x90e0, + 0x0004, 0x2001, 0x18b0, 0x9c82, 0x18f0, 0x0210, 0x2061, 0x18b0, + 0x2c00, 0x703a, 0x7148, 0x81ff, 0x1108, 0x703e, 0x8108, 0x714a, + 0x0460, 0x7148, 0x8108, 0x714a, 0x7044, 0x2040, 0xa144, 0x2105, + 0x0016, 0x908a, 0x0036, 0x1a0c, 0x0db2, 0x2060, 0x001e, 0x8108, + 0x2105, 0x9005, 0xa146, 0x1520, 0x080c, 0x0fd5, 0x1130, 0x8109, + 0xa946, 0x7148, 0x8109, 0x714a, 0x00d8, 0x9006, 0xa806, 0xa84a, + 0xa046, 0x2800, 0xa802, 0x2900, 0xa006, 0x7046, 0x2001, 0x0002, + 0x9080, 0x1da2, 0x2005, 0xa846, 0x0058, 0x2262, 0x6306, 0x640a, + 0x00ee, 0x00ce, 0x009e, 0x008e, 0x001e, 0x012e, 0x00fe, 0x0005, + 0x2c00, 0x9082, 0x001b, 0x0002, 0x4717, 0x4717, 0x4719, 0x4717, + 0x4717, 0x4717, 0x471d, 0x4717, 0x4717, 0x4717, 0x4721, 0x4717, + 0x4717, 0x4717, 0x4725, 0x4717, 0x4717, 0x4717, 0x4729, 0x4717, + 0x4717, 0x4717, 0x472d, 0x4717, 0x4717, 0x4717, 0x4732, 0x080c, + 0x0db2, 0xa276, 0xa37a, 0xa47e, 0x0898, 0xa286, 0xa38a, 0xa48e, + 0x0878, 0xa296, 0xa39a, 0xa49e, 0x0858, 0xa2a6, 0xa3aa, 0xa4ae, + 0x0838, 0xa2b6, 0xa3ba, 0xa4be, 0x0818, 0xa2c6, 0xa3ca, 0xa4ce, + 0x0804, 0x46f0, 0xa2d6, 0xa3da, 0xa4de, 0x0804, 0x46f0, 0x00e6, + 0x2071, 0x1894, 0x7048, 0x9005, 0x0904, 0x47c9, 0x0126, 0x2091, + 0x8000, 0x0e04, 0x47c8, 0x00f6, 0x2079, 0x0000, 0x00c6, 0x0096, + 0x0086, 0x0076, 0x9006, 0x2038, 0x7040, 0x2048, 0x9005, 0x0500, + 0xa948, 0x2105, 0x0016, 0x908a, 0x0036, 0x1a0c, 0x0db2, 0x2060, + 0x001e, 0x8108, 0x2105, 0x9005, 0xa94a, 0x1904, 0x47cb, 0xa804, + 0x9005, 0x090c, 0x0db2, 0x7042, 0x2938, 0x2040, 0xa003, 0x0000, + 0x2001, 0x0002, 0x9080, 0x1da2, 0x2005, 0xa04a, 0x0804, 0x47cb, + 0x703c, 0x2060, 0x2c14, 0x6304, 0x6408, 0x650c, 0x2200, 0x7836, + 0x7833, 0x0012, 0x7882, 0x2300, 0x7886, 0x2400, 0x788a, 0x2091, + 0x4080, 0x2001, 0x0089, 0x2004, 0xd084, 0x190c, 0x1167, 0x87ff, + 0x0118, 0x2748, 0x080c, 0x1007, 0x7048, 0x8001, 0x704a, 0x9005, + 0x1170, 0x7040, 0x2048, 0x9005, 0x0128, 0x080c, 0x1007, 0x9006, + 0x7042, 0x7046, 0x703b, 0x18b0, 0x703f, 0x18b0, 0x0420, 0x7040, + 0x9005, 0x1508, 0x7238, 0x2c00, 0x9206, 0x0148, 0x9c80, 0x0004, + 0x90fa, 0x18f0, 0x0210, 0x2001, 0x18b0, 0x703e, 0x00a0, 0x9006, + 0x703e, 0x703a, 0x7044, 0x9005, 0x090c, 0x0db2, 0x2048, 0xa800, + 0x9005, 0x1de0, 0x2900, 0x7042, 0x2001, 0x0002, 0x9080, 0x1da2, + 0x2005, 0xa84a, 0x0000, 0x007e, 0x008e, 0x009e, 0x00ce, 0x00fe, + 0x012e, 0x00ee, 0x0005, 0x2c00, 0x9082, 0x001b, 0x0002, 0x47ea, + 0x47ea, 0x47ec, 0x47ea, 0x47ea, 0x47ea, 0x47f1, 0x47ea, 0x47ea, + 0x47ea, 0x47f6, 0x47ea, 0x47ea, 0x47ea, 0x47fb, 0x47ea, 0x47ea, + 0x47ea, 0x4800, 0x47ea, 0x47ea, 0x47ea, 0x4805, 0x47ea, 0x47ea, + 0x47ea, 0x480a, 0x080c, 0x0db2, 0xaa74, 0xab78, 0xac7c, 0x0804, + 0x4776, 0xaa84, 0xab88, 0xac8c, 0x0804, 0x4776, 0xaa94, 0xab98, + 0xac9c, 0x0804, 0x4776, 0xaaa4, 0xaba8, 0xacac, 0x0804, 0x4776, + 0xaab4, 0xabb8, 0xacbc, 0x0804, 0x4776, 0xaac4, 0xabc8, 0xaccc, + 0x0804, 0x4776, 0xaad4, 0xabd8, 0xacdc, 0x0804, 0x4776, 0x0016, + 0x0026, 0x0036, 0x00b6, 0x00c6, 0x2009, 0x007e, 0x080c, 0x5f7e, + 0x2019, 0x0001, 0xb85c, 0xd0ac, 0x0110, 0x2019, 0x0000, 0x2011, + 0x801b, 0x080c, 0x4672, 0x00ce, 0x00be, 0x003e, 0x002e, 0x001e, + 0x0005, 0x0026, 0x080c, 0x5113, 0xd0c4, 0x0120, 0x2011, 0x8014, + 0x080c, 0x4672, 0x002e, 0x0005, 0x81ff, 0x1904, 0x31c3, 0x0126, + 0x2091, 0x8000, 0x6030, 0xc08d, 0xc085, 0xc0ac, 0x6032, 0x080c, + 0x6c53, 0x1158, 0x080c, 0x6f2a, 0x080c, 0x5a21, 0x9085, 0x0001, + 0x080c, 0x6c9a, 0x080c, 0x6b8a, 0x0010, 0x080c, 0x58e0, 0x012e, + 0x0804, 0x3191, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804, 0x31c3, + 0x080c, 0x5127, 0x0120, 0x2009, 0x0007, 0x0804, 0x31c3, 0x080c, + 0x629c, 0x0120, 0x2009, 0x0008, 0x0804, 0x31c3, 0x080c, 0x2f81, + 0x0128, 0x7984, 0x080c, 0x5f1e, 0x1904, 0x31c6, 0x080c, 0x4645, + 0x0904, 0x31c6, 0x2b00, 0x7026, 0x080c, 0x62a4, 0x7888, 0x1170, + 0x9084, 0x0005, 0x1158, 0x900e, 0x080c, 0x619e, 0x1108, 0xc185, + 0xb800, 0xd0bc, 0x0108, 0xc18d, 0x0804, 0x3191, 0x080c, 0x4612, + 0x0904, 0x31c3, 0x9006, 0xa866, 0xa832, 0xa868, 0xc0fd, 0xa86a, + 0x080c, 0xb817, 0x0904, 0x31c3, 0x7888, 0xd094, 0x0118, 0xb8bc, + 0xc08d, 0xb8be, 0x7007, 0x0003, 0x701f, 0x48eb, 0x0005, 0x2061, + 0x1800, 0x080c, 0x5127, 0x2009, 0x0007, 0x1578, 0x080c, 0x629c, + 0x0118, 0x2009, 0x0008, 0x0448, 0x080c, 0x2f81, 0x0120, 0xa998, + 0x080c, 0x5f1e, 0x1530, 0x080c, 0x4643, 0x0518, 0x080c, 0x62a4, + 0xa89c, 0x1168, 0x9084, 0x0005, 0x1150, 0x900e, 0x080c, 0x619e, + 0x1108, 0xc185, 0xb800, 0xd0bc, 0x0108, 0xc18d, 0x00d0, 0xa868, + 0xc0fc, 0xa86a, 0x080c, 0xb817, 0x11e0, 0xa89c, 0xd094, 0x0118, + 0xb8bc, 0xc08d, 0xb8be, 0x2009, 0x0003, 0xa897, 0x4005, 0xa99a, + 0x0010, 0xa897, 0x4006, 0x900e, 0x9085, 0x0001, 0x2001, 0x0030, + 0x0005, 0xa897, 0x4000, 0xa99a, 0x9006, 0x918d, 0x0001, 0x2008, + 0x0005, 0x9006, 0x0005, 0xa830, 0x9086, 0x0100, 0x7024, 0x2058, + 0x1110, 0x0804, 0x5070, 0x900e, 0x080c, 0x619e, 0x1108, 0xc185, + 0xb800, 0xd0bc, 0x0108, 0xc18d, 0x0804, 0x3191, 0x080c, 0x5127, + 0x0120, 0x2009, 0x0007, 0x0804, 0x31c3, 0x7f84, 0x7a8c, 0x7b88, + 0x7c9c, 0x7d98, 0x080c, 0x4612, 0x1120, 0x2009, 0x0002, 0x0804, + 0x31c3, 0x900e, 0x2130, 0x7126, 0x7132, 0xa860, 0x20e8, 0x7036, + 0xa85c, 0x9080, 0x0005, 0x702a, 0x20a0, 0x080c, 0x5f7e, 0x1904, + 0x4981, 0x080c, 0x62a4, 0x0120, 0x080c, 0x62ac, 0x1904, 0x4981, + 0x080c, 0x629c, 0x1130, 0x080c, 0x619e, 0x1118, 0xd79c, 0x0904, + 0x4981, 0xd794, 0x1110, 0xd784, 0x01a8, 0xb8b4, 0x20e0, 0xb8b8, + 0x9080, 0x0006, 0x2098, 0x3400, 0xd794, 0x0160, 0x20a9, 0x0008, + 0x4003, 0x2098, 0x20a0, 0x3d00, 0x20e0, 0x20a9, 0x0002, 0x080c, + 0x4444, 0x0048, 0x20a9, 0x0004, 0x4003, 0x2098, 0x20a0, 0x3d00, + 0x20e0, 0x080c, 0x4444, 0x4104, 0xd794, 0x0528, 0xb8b4, 0x20e0, + 0xb8b8, 0x2060, 0x9c80, 0x0000, 0x2098, 0x20a9, 0x0002, 0x4003, + 0x9c80, 0x0003, 0x2098, 0x20a9, 0x0001, 0x4005, 0x9c80, 0x0004, + 0x2098, 0x3400, 0x20a9, 0x0002, 0x4003, 0x2098, 0x20a0, 0x3d00, + 0x20e0, 0x080c, 0x4437, 0x9c80, 0x0026, 0x2098, 0xb8b4, 0x20e0, + 0x20a9, 0x0002, 0x4003, 0xd794, 0x0110, 0x96b0, 0x000b, 0x96b0, + 0x0005, 0x8108, 0x080c, 0x9940, 0x0118, 0x9186, 0x0800, 0x0040, + 0xd78c, 0x0120, 0x9186, 0x0800, 0x0170, 0x0018, 0x9186, 0x007e, + 0x0150, 0xd794, 0x0118, 0x9686, 0x0020, 0x0010, 0x9686, 0x0028, + 0x0150, 0x0804, 0x491d, 0x86ff, 0x1120, 0x7124, 0x810b, 0x0804, + 0x3191, 0x7033, 0x0001, 0x7122, 0x7024, 0x9600, 0x7026, 0x772e, + 0x2061, 0x18ae, 0x2c44, 0xa06b, 0x0000, 0xa67a, 0x7034, 0xa072, + 0x7028, 0xa076, 0xa28e, 0xa392, 0xa496, 0xa59a, 0x080c, 0x10b5, + 0x7007, 0x0002, 0x701f, 0x49bd, 0x0005, 0x7030, 0x9005, 0x1180, + 0x7120, 0x7028, 0x20a0, 0x772c, 0x9036, 0x7034, 0x20e8, 0x2061, + 0x18ae, 0x2c44, 0xa28c, 0xa390, 0xa494, 0xa598, 0x0804, 0x491d, + 0x7124, 0x810b, 0x0804, 0x3191, 0x2029, 0x007e, 0x7984, 0x7a88, + 0x7b8c, 0x7c98, 0x9184, 0xff00, 0x8007, 0x90e2, 0x0020, 0x0a04, + 0x31c6, 0x9502, 0x0a04, 0x31c6, 0x9184, 0x00ff, 0x90e2, 0x0020, + 0x0a04, 0x31c6, 0x9502, 0x0a04, 0x31c6, 0x9284, 0xff00, 0x8007, + 0x90e2, 0x0020, 0x0a04, 0x31c6, 0x9502, 0x0a04, 0x31c6, 0x9284, + 0x00ff, 0x90e2, 0x0020, 0x0a04, 0x31c6, 0x9502, 0x0a04, 0x31c6, + 0x9384, 0xff00, 0x8007, 0x90e2, 0x0020, 0x0a04, 0x31c6, 0x9502, + 0x0a04, 0x31c6, 0x9384, 0x00ff, 0x90e2, 0x0020, 0x0a04, 0x31c6, + 0x9502, 0x0a04, 0x31c6, 0x9484, 0xff00, 0x8007, 0x90e2, 0x0020, + 0x0a04, 0x31c6, 0x9502, 0x0a04, 0x31c6, 0x9484, 0x00ff, 0x90e2, + 0x0020, 0x0a04, 0x31c6, 0x9502, 0x0a04, 0x31c6, 0x2061, 0x1958, + 0x6102, 0x6206, 0x630a, 0x640e, 0x0804, 0x3191, 0x0006, 0x080c, + 0x5113, 0xd0cc, 0x000e, 0x0005, 0x0006, 0x080c, 0x5117, 0xd0bc, + 0x000e, 0x0005, 0x616c, 0x7a84, 0x6300, 0x82ff, 0x1118, 0x7986, + 0x0804, 0x3191, 0x83ff, 0x1904, 0x31c6, 0x2001, 0xfff0, 0x9200, + 0x1a04, 0x31c6, 0x2019, 0xffff, 0x6070, 0x9302, 0x9200, 0x0a04, + 0x31c6, 0x7986, 0x626e, 0x0804, 0x3191, 0x080c, 0x5127, 0x1904, + 0x31c3, 0x7c88, 0x7d84, 0x7e98, 0x7f8c, 0x080c, 0x4612, 0x0904, + 0x31c3, 0x900e, 0x901e, 0x7326, 0x7332, 0xa860, 0x20e8, 0x7036, + 0xa85c, 0x9080, 0x0003, 0x702a, 0x20a0, 0x91d8, 0x1000, 0x2b5c, + 0x8bff, 0x0178, 0x080c, 0x62a4, 0x0118, 0x080c, 0x62ac, 0x1148, + 0x20a9, 0x0001, 0xb814, 0x4004, 0xb810, 0x4004, 0x4104, 0x9398, + 0x0003, 0x8108, 0x9182, 0x0800, 0x0120, 0x9386, 0x003c, 0x0170, + 0x0c20, 0x83ff, 0x1148, 0x7224, 0x900e, 0x2001, 0x0003, 0x080c, + 0x7e7f, 0x2208, 0x0804, 0x3191, 0x7033, 0x0001, 0x7122, 0x7024, + 0x9300, 0x7026, 0x2061, 0x18ae, 0x2c44, 0xa06b, 0x0000, 0xa37a, + 0x7028, 0xa076, 0x7034, 0xa072, 0xa48e, 0xa592, 0xa696, 0xa79a, + 0x080c, 0x10b5, 0x7007, 0x0002, 0x701f, 0x4aaf, 0x0005, 0x7030, + 0x9005, 0x1178, 0x7120, 0x7028, 0x20a0, 0x901e, 0x7034, 0x20e8, + 0x2061, 0x18ae, 0x2c44, 0xa48c, 0xa590, 0xa694, 0xa798, 0x0804, + 0x4a6d, 0x7224, 0x900e, 0x2001, 0x0003, 0x080c, 0x7e7f, 0x2208, + 0x0804, 0x3191, 0x00f6, 0x00e6, 0x080c, 0x5127, 0x2009, 0x0007, + 0x1904, 0x4b42, 0x2071, 0x1894, 0x745c, 0x84ff, 0x2009, 0x000e, + 0x1904, 0x4b42, 0xac9c, 0xad98, 0xaea4, 0xafa0, 0x0096, 0x080c, + 0x0fee, 0x2009, 0x0002, 0x0904, 0x4b42, 0x2900, 0x705e, 0x900e, + 0x901e, 0x7356, 0x7362, 0xa860, 0x7066, 0xa85c, 0x9080, 0x0003, + 0x705a, 0x20a0, 0x91d8, 0x1000, 0x2b5c, 0x8bff, 0x0178, 0x080c, + 0x62a4, 0x0118, 0x080c, 0x62ac, 0x1148, 0xb814, 0x20a9, 0x0001, + 0x4004, 0xb810, 0x4004, 0x4104, 0x9398, 0x0003, 0x8108, 0x9182, + 0x0800, 0x0120, 0x9386, 0x003c, 0x01e8, 0x0c20, 0x83ff, 0x11c0, + 0x7254, 0x900e, 0x2001, 0x0003, 0x080c, 0x7e7f, 0x2208, 0x009e, + 0xa897, 0x4000, 0xa99a, 0x715c, 0x81ff, 0x090c, 0x0db2, 0x2148, + 0x080c, 0x1007, 0x9006, 0x705e, 0x918d, 0x0001, 0x2008, 0x0418, + 0x7063, 0x0001, 0x7152, 0x7054, 0x9300, 0x7056, 0x2061, 0x18af, + 0x2c44, 0xa37a, 0x7058, 0xa076, 0x7064, 0xa072, 0xa48e, 0xa592, + 0xa696, 0xa79a, 0xa09f, 0x4b4e, 0x000e, 0xa0a2, 0x080c, 0x10b5, + 0x9006, 0x0048, 0x009e, 0xa897, 0x4005, 0xa99a, 0x900e, 0x9085, + 0x0001, 0x2001, 0x0030, 0x00ee, 0x00fe, 0x0005, 0x00f6, 0xa0a0, + 0x904d, 0x090c, 0x0db2, 0x00e6, 0x2071, 0x1894, 0xa06c, 0x908e, + 0x0100, 0x0138, 0xa87b, 0x0030, 0xa883, 0x0000, 0xa897, 0x4002, + 0x00d8, 0x7060, 0x9005, 0x1158, 0x7150, 0x7058, 0x20a0, 0x901e, + 0x7064, 0x20e8, 0xa48c, 0xa590, 0xa694, 0xa798, 0x0428, 0xa87b, + 0x0000, 0xa883, 0x0000, 0xa897, 0x4000, 0x7254, 0x900e, 0x2001, + 0x0003, 0x080c, 0x7e7f, 0xaa9a, 0x715c, 0x81ff, 0x090c, 0x0db2, + 0x2148, 0x080c, 0x1007, 0x705f, 0x0000, 0xa0a0, 0x2048, 0x0126, + 0x2091, 0x8000, 0x080c, 0x6536, 0x012e, 0xa09f, 0x0000, 0xa0a3, + 0x0000, 0x00ee, 0x00fe, 0x0005, 0x91d8, 0x1000, 0x2b5c, 0x8bff, + 0x0178, 0x080c, 0x62a4, 0x0118, 0x080c, 0x62ac, 0x1148, 0xb814, + 0x20a9, 0x0001, 0x4004, 0xb810, 0x4004, 0x4104, 0x9398, 0x0003, + 0x8108, 0x9182, 0x0800, 0x0120, 0x9386, 0x003c, 0x0518, 0x0c20, + 0x83ff, 0x11f0, 0x7154, 0x810c, 0xa99a, 0xa897, 0x4000, 0x715c, + 0x81ff, 0x090c, 0x0db2, 0x2148, 0x080c, 0x1007, 0x9006, 0x705e, + 0x918d, 0x0001, 0x2008, 0xa0a0, 0x2048, 0x0126, 0x2091, 0x8000, + 0x080c, 0x6536, 0x012e, 0xa09f, 0x0000, 0xa0a3, 0x0000, 0x0070, + 0x7063, 0x0001, 0x7152, 0x7054, 0x9300, 0x7056, 0xa37a, 0xa48e, + 0xa592, 0xa696, 0xa79a, 0x080c, 0x10b5, 0x9006, 0x00ee, 0x0005, + 0x0096, 0xa88c, 0x90be, 0x7000, 0x0148, 0x90be, 0x7100, 0x0130, + 0x90be, 0x7200, 0x0118, 0x009e, 0x0804, 0x31c6, 0xa884, 0xa988, + 0x080c, 0x24d6, 0x1518, 0x080c, 0x5f1e, 0x1500, 0x7126, 0xbe12, + 0xbd16, 0xae7c, 0x080c, 0x4612, 0x01c8, 0x080c, 0x4612, 0x01b0, + 0x009e, 0xa867, 0x0000, 0xa868, 0xc0fd, 0xa86a, 0xa823, 0x0000, + 0xa804, 0x2048, 0x080c, 0xb79e, 0x1120, 0x2009, 0x0003, 0x0804, + 0x31c3, 0x7007, 0x0003, 0x701f, 0x4c1b, 0x0005, 0x009e, 0x2009, + 0x0002, 0x0804, 0x31c3, 0x7124, 0x080c, 0x2f28, 0xa820, 0x9086, + 0x8001, 0x1120, 0x2009, 0x0004, 0x0804, 0x31c3, 0x2900, 0x7022, + 0xa804, 0x0096, 0x2048, 0x8906, 0x8006, 0x8007, 0x90bc, 0x003f, + 0x9084, 0xffc0, 0x009e, 0x9080, 0x0002, 0x0076, 0x0006, 0x2098, + 0x20a0, 0x27e0, 0x27e8, 0x20a9, 0x002a, 0x080c, 0x0f52, 0xaa6c, + 0xab70, 0xac74, 0xad78, 0x2061, 0x18ae, 0x2c44, 0xa06b, 0x0000, + 0xae64, 0xaf8c, 0x97c6, 0x7000, 0x0118, 0x97c6, 0x7100, 0x1148, + 0x96c2, 0x0004, 0x0600, 0x2009, 0x0004, 0x000e, 0x007e, 0x0804, + 0x465e, 0x97c6, 0x7200, 0x11b8, 0x96c2, 0x0054, 0x02a0, 0x000e, + 0x007e, 0x2061, 0x18ae, 0x2c44, 0xa076, 0xa772, 0xa07b, 0x002a, + 0xa28e, 0xa392, 0xa496, 0xa59a, 0x080c, 0x10b5, 0x7007, 0x0002, + 0x701f, 0x4c77, 0x0005, 0x000e, 0x007e, 0x0804, 0x31c6, 0x7020, + 0x2048, 0xa804, 0x2048, 0xa804, 0x2048, 0x8906, 0x8006, 0x8007, + 0x90bc, 0x003f, 0x9084, 0xffc0, 0x9080, 0x0002, 0x2098, 0x20a0, + 0x27e0, 0x27e8, 0x20a9, 0x002a, 0x080c, 0x0f52, 0x2100, 0x2238, + 0x2061, 0x18ae, 0x2c44, 0xa28c, 0xa390, 0xa494, 0xa598, 0x2009, + 0x002a, 0x0804, 0x465e, 0x81ff, 0x1904, 0x31c3, 0x798c, 0x2001, + 0x194f, 0x2102, 0x080c, 0x4629, 0x0904, 0x31c6, 0x080c, 0x62a4, + 0x0120, 0x080c, 0x62ac, 0x1904, 0x31c6, 0x080c, 0x6045, 0x0904, + 0x31c3, 0x0126, 0x2091, 0x8000, 0x080c, 0x610b, 0x012e, 0x0904, + 0x31c3, 0x0804, 0x417a, 0xa9a0, 0x2001, 0x194f, 0xc18d, 0x2102, + 0x080c, 0x4636, 0x01a0, 0x080c, 0x62a4, 0x0118, 0x080c, 0x62ac, + 0x1170, 0x080c, 0x6045, 0x2009, 0x0002, 0x0128, 0x080c, 0x610b, + 0x1170, 0x2009, 0x0003, 0xa897, 0x4005, 0xa99a, 0x0010, 0xa897, + 0x4006, 0x900e, 0x9085, 0x0001, 0x2001, 0x0030, 0x0005, 0xa897, + 0x4000, 0x080c, 0x511b, 0x0110, 0x9006, 0x0018, 0x900e, 0x9085, + 0x0001, 0x2001, 0x0000, 0x0005, 0x78a8, 0xd08c, 0x1118, 0xd084, + 0x0904, 0x40ef, 0x080c, 0x4645, 0x0904, 0x31c6, 0x080c, 0x4612, + 0x1120, 0x2009, 0x0002, 0x0804, 0x31c3, 0x080c, 0x62a4, 0x0130, + 0x908e, 0x0004, 0x0118, 0x908e, 0x0005, 0x15a0, 0x78a8, 0xd08c, + 0x0120, 0xb800, 0xc08c, 0xb802, 0x0028, 0x080c, 0x5113, 0xd0b4, + 0x0904, 0x4129, 0x7884, 0x908e, 0x007e, 0x0904, 0x4129, 0x908e, + 0x007f, 0x0904, 0x4129, 0x908e, 0x0080, 0x0904, 0x4129, 0xb800, + 0xd08c, 0x1904, 0x4129, 0xa867, 0x0000, 0xa868, 0xc0fd, 0xa86a, + 0x080c, 0xb7bd, 0x1120, 0x2009, 0x0003, 0x0804, 0x31c3, 0x7007, + 0x0003, 0x701f, 0x4d34, 0x0005, 0x080c, 0x4645, 0x0904, 0x31c6, + 0x0804, 0x4129, 0x080c, 0x2f81, 0x0108, 0x0005, 0x2009, 0x1832, + 0x210c, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804, 0x31c3, 0x080c, + 0x5127, 0x0120, 0x2009, 0x0007, 0x0804, 0x31c3, 0x080c, 0x629c, + 0x0120, 0x2009, 0x0008, 0x0804, 0x31c3, 0xb89c, 0xd0a4, 0x1118, + 0xd0ac, 0x1904, 0x4129, 0x9006, 0xa866, 0xa832, 0xa868, 0xc0fd, + 0xa86a, 0x080c, 0xb817, 0x1120, 0x2009, 0x0003, 0x0804, 0x31c3, + 0x7007, 0x0003, 0x701f, 0x4d6d, 0x0005, 0xa830, 0x9086, 0x0100, + 0x1120, 0x2009, 0x0004, 0x0804, 0x5070, 0x080c, 0x4645, 0x0904, + 0x31c6, 0x0804, 0x4d06, 0x81ff, 0x2009, 0x0001, 0x1904, 0x31c3, + 0x080c, 0x5127, 0x2009, 0x0007, 0x1904, 0x31c3, 0x080c, 0x629c, + 0x0120, 0x2009, 0x0008, 0x0804, 0x31c3, 0x080c, 0x4645, 0x0904, + 0x31c6, 0x080c, 0x62a4, 0x2009, 0x0009, 0x1904, 0x31c3, 0x080c, + 0x4612, 0x2009, 0x0002, 0x0904, 0x31c3, 0x9006, 0xa866, 0xa832, + 0xa868, 0xc0fd, 0xa86a, 0x7988, 0x9194, 0xff00, 0x918c, 0x00ff, + 0x9006, 0x82ff, 0x1128, 0xc0ed, 0xa952, 0x798c, 0xa956, 0x0038, + 0x928e, 0x0100, 0x1904, 0x31c6, 0xc0e5, 0xa952, 0xa956, 0xa83e, + 0x080c, 0xba6a, 0x2009, 0x0003, 0x0904, 0x31c3, 0x7007, 0x0003, + 0x701f, 0x4dc3, 0x0005, 0xa830, 0x9086, 0x0100, 0x2009, 0x0004, + 0x0904, 0x31c3, 0x0804, 0x3191, 0x7aa8, 0x9284, 0xc000, 0x0148, + 0xd2ec, 0x01a0, 0x080c, 0x5127, 0x1188, 0x2009, 0x0014, 0x0804, + 0x31c3, 0xd2dc, 0x1568, 0x81ff, 0x2009, 0x0001, 0x1904, 0x31c3, + 0x080c, 0x5127, 0x2009, 0x0007, 0x1904, 0x31c3, 0xd2f4, 0x0130, + 0x9284, 0x5000, 0x080c, 0x50ee, 0x0804, 0x3191, 0xd2fc, 0x0158, + 0x080c, 0x4645, 0x0904, 0x31c6, 0x7984, 0x9284, 0x9000, 0x080c, + 0x50cb, 0x0804, 0x3191, 0x080c, 0x4645, 0x0904, 0x31c6, 0xb804, + 0x9084, 0x00ff, 0x9086, 0x0006, 0x2009, 0x0009, 0x1904, 0x4eac, + 0x080c, 0x4612, 0x2009, 0x0002, 0x0904, 0x4eac, 0xa85c, 0x9080, + 0x001b, 0xaf60, 0x2009, 0x0008, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, + 0x080c, 0x465b, 0x701f, 0x4e1d, 0x0005, 0xa86c, 0x9086, 0x0500, + 0x1138, 0xa870, 0x9005, 0x1120, 0xa874, 0x9084, 0xff00, 0x0110, + 0x1904, 0x31c6, 0xa866, 0xa832, 0xa868, 0xc0fd, 0xa86a, 0x080c, + 0x4645, 0x1110, 0x0804, 0x31c6, 0x2009, 0x0043, 0x080c, 0xbad2, + 0x2009, 0x0003, 0x0904, 0x4eac, 0x7007, 0x0003, 0x701f, 0x4e41, + 0x0005, 0xa830, 0x9086, 0x0100, 0x2009, 0x0004, 0x0904, 0x4eac, + 0x7984, 0x7aa8, 0x9284, 0x1000, 0x080c, 0x50cb, 0x0804, 0x3191, + 0x00c6, 0xaab0, 0x9284, 0xc000, 0x0140, 0xd2ec, 0x0168, 0x080c, + 0x5127, 0x1150, 0x2009, 0x0014, 0x04f0, 0x2061, 0x1800, 0x080c, + 0x5127, 0x2009, 0x0007, 0x15b8, 0xd2f4, 0x0128, 0x9284, 0x5000, + 0x080c, 0x50ee, 0x0050, 0xd2fc, 0x0178, 0x080c, 0x4643, 0x0588, + 0xa998, 0x9284, 0x9000, 0x080c, 0x50cb, 0xa87b, 0x0000, 0xa883, + 0x0000, 0xa897, 0x4000, 0x0438, 0x080c, 0x4643, 0x0510, 0x080c, + 0x62a4, 0x2009, 0x0009, 0x11b8, 0xa8c4, 0x9086, 0x0500, 0x11c8, + 0xa8c8, 0x9005, 0x11b0, 0xa8cc, 0x9084, 0xff00, 0x1190, 0x080c, + 0x4643, 0x1108, 0x0070, 0x2009, 0x004b, 0x080c, 0xbad2, 0x2009, + 0x0003, 0x0108, 0x0078, 0x0429, 0x19c0, 0xa897, 0x4005, 0xa99a, + 0x0010, 0xa897, 0x4006, 0x900e, 0x9085, 0x0001, 0x2001, 0x0030, + 0x00ce, 0x0005, 0x9006, 0x0ce0, 0x7aa8, 0xd2dc, 0x0904, 0x31c3, + 0x0016, 0x7984, 0x9284, 0x1000, 0xc0fd, 0x080c, 0x50cb, 0x001e, + 0x1904, 0x31c3, 0x0804, 0x3191, 0x00f6, 0x2d78, 0x0011, 0x00fe, + 0x0005, 0xaab0, 0xd2dc, 0x0150, 0x0016, 0xa998, 0x9284, 0x1000, + 0xc0fd, 0x080c, 0x50cb, 0x001e, 0x9085, 0x0001, 0x0005, 0x81ff, + 0x0120, 0x2009, 0x0001, 0x0804, 0x31c3, 0x080c, 0x5127, 0x0120, + 0x2009, 0x0007, 0x0804, 0x31c3, 0x7984, 0x7ea8, 0x96b4, 0x00ff, + 0x080c, 0x5f7e, 0x1904, 0x31c6, 0x9186, 0x007f, 0x0138, 0x080c, + 0x62a4, 0x0120, 0x2009, 0x0009, 0x0804, 0x31c3, 0x080c, 0x4612, + 0x1120, 0x2009, 0x0002, 0x0804, 0x31c3, 0xa867, 0x0000, 0xa868, + 0xc0fd, 0xa86a, 0x2001, 0x0100, 0x8007, 0xa80a, 0x080c, 0xb7d7, + 0x1120, 0x2009, 0x0003, 0x0804, 0x31c3, 0x7007, 0x0003, 0x701f, + 0x4f0a, 0x0005, 0xa808, 0x8007, 0x9086, 0x0100, 0x1120, 0x2009, + 0x0004, 0x0804, 0x31c3, 0xa8e0, 0xa866, 0xa810, 0x8007, 0x9084, + 0x00ff, 0x800c, 0xa814, 0x8007, 0x9084, 0x00ff, 0x8004, 0x9080, + 0x0002, 0x9108, 0x8906, 0x8006, 0x8007, 0x90bc, 0x003f, 0x9084, + 0xffc0, 0x9080, 0x0004, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0x0804, + 0x465e, 0x080c, 0x4612, 0x1120, 0x2009, 0x0002, 0x0804, 0x31c3, + 0x7984, 0x9194, 0xff00, 0x918c, 0x00ff, 0x8217, 0x82ff, 0x1118, + 0x7023, 0x1982, 0x0040, 0x92c6, 0x0001, 0x1118, 0x7023, 0x199c, + 0x0010, 0x0804, 0x31c6, 0x2009, 0x001a, 0x7a8c, 0x7b88, 0x7c9c, + 0x7d98, 0xa85c, 0x9080, 0x0019, 0xaf60, 0x080c, 0x465b, 0x701f, + 0x4f5a, 0x0005, 0x2001, 0x182c, 0x2003, 0x0001, 0xa85c, 0x9080, + 0x0019, 0x2098, 0xa860, 0x20e0, 0x20a9, 0x001a, 0x7020, 0x20a0, + 0x20e9, 0x0001, 0x4003, 0x0804, 0x3191, 0x080c, 0x4612, 0x1120, + 0x2009, 0x0002, 0x0804, 0x31c3, 0x7984, 0x9194, 0xff00, 0x918c, + 0x00ff, 0x8217, 0x82ff, 0x1118, 0x2099, 0x1982, 0x0040, 0x92c6, + 0x0001, 0x1118, 0x2099, 0x199c, 0x0010, 0x0804, 0x31c6, 0xa85c, + 0x9080, 0x0019, 0x20a0, 0xa860, 0x20e8, 0x20a9, 0x001a, 0x20e1, + 0x0001, 0x4003, 0x2009, 0x001a, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, + 0xa85c, 0x9080, 0x0019, 0xaf60, 0x0804, 0x465e, 0x7884, 0x908a, + 0x1000, 0x1a04, 0x31c6, 0x0126, 0x2091, 0x8000, 0x8003, 0x800b, + 0x810b, 0x9108, 0x00c6, 0x2061, 0x19c9, 0x6142, 0x00ce, 0x012e, + 0x0804, 0x3191, 0x00c6, 0x080c, 0x6c53, 0x1160, 0x080c, 0x6f2a, + 0x080c, 0x5a21, 0x9085, 0x0001, 0x080c, 0x6c9a, 0x080c, 0x6b8a, + 0x080c, 0x0db2, 0x2061, 0x1800, 0x6030, 0xc09d, 0x6032, 0x080c, + 0x58e0, 0x00ce, 0x0005, 0x00c6, 0x2001, 0x1800, 0x2004, 0x908e, + 0x0000, 0x0904, 0x31c3, 0x7884, 0x9005, 0x0188, 0x7888, 0x2061, + 0x196b, 0x2c0c, 0x2062, 0x080c, 0x28b8, 0x01a0, 0x080c, 0x28c0, + 0x0188, 0x080c, 0x28c8, 0x0170, 0x2162, 0x0804, 0x31c6, 0x2061, + 0x0100, 0x6038, 0x9086, 0x0007, 0x1118, 0x2009, 0x0001, 0x0010, + 0x2009, 0x0000, 0x7884, 0x9086, 0x0002, 0x1548, 0x2061, 0x0100, + 0x6028, 0xc09c, 0x602a, 0x0026, 0x2011, 0x0003, 0x080c, 0x92ec, + 0x2011, 0x0002, 0x080c, 0x92f6, 0x002e, 0x080c, 0x91de, 0x0036, + 0x901e, 0x080c, 0x9254, 0x003e, 0x60e3, 0x0000, 0x080c, 0xd343, + 0x080c, 0xd35e, 0x9085, 0x0001, 0x080c, 0x6c9a, 0x9006, 0x080c, + 0x2987, 0x2001, 0x1800, 0x2003, 0x0004, 0x6027, 0x0008, 0x00ce, + 0x0804, 0x3191, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804, 0x31c3, + 0x080c, 0x5127, 0x0120, 0x2009, 0x0007, 0x0804, 0x31c3, 0x7984, + 0x7ea8, 0x96b4, 0x00ff, 0x080c, 0x5f7e, 0x1904, 0x31c6, 0x9186, + 0x007f, 0x0138, 0x080c, 0x62a4, 0x0120, 0x2009, 0x0009, 0x0804, + 0x31c3, 0x080c, 0x4612, 0x1120, 0x2009, 0x0002, 0x0804, 0x31c3, + 0xa867, 0x0000, 0xa868, 0xc0fd, 0xa86a, 0x080c, 0xb7da, 0x1120, + 0x2009, 0x0003, 0x0804, 0x31c3, 0x7007, 0x0003, 0x701f, 0x5059, + 0x0005, 0xa830, 0x9086, 0x0100, 0x1120, 0x2009, 0x0004, 0x0804, + 0x31c3, 0xa8e0, 0xa866, 0xa834, 0x8007, 0x800c, 0xa85c, 0x9080, + 0x000c, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0xaf60, 0x0804, 0x465e, + 0xa898, 0x9086, 0x000d, 0x1904, 0x31c3, 0x2021, 0x4005, 0x0126, + 0x2091, 0x8000, 0x0e04, 0x507d, 0x0010, 0x012e, 0x0cc0, 0x7c36, + 0x9486, 0x4000, 0x0118, 0x7833, 0x0011, 0x0010, 0x7833, 0x0010, + 0x7883, 0x4005, 0xa998, 0x7986, 0xa9a4, 0x799a, 0xa9a8, 0x799e, + 0x080c, 0x464e, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004, 0xd084, + 0x190c, 0x1167, 0x7007, 0x0001, 0x2091, 0x5000, 0x700f, 0x0000, + 0x012e, 0x0005, 0x0126, 0x2091, 0x8000, 0x00c6, 0x2061, 0x19c9, + 0x7984, 0x6152, 0x614e, 0x6057, 0x0000, 0x604b, 0x0009, 0x7898, + 0x606a, 0x789c, 0x6066, 0x7888, 0x6062, 0x788c, 0x605e, 0x2001, + 0x19d7, 0x2044, 0x2001, 0x19de, 0xa076, 0xa060, 0xa072, 0xa07b, + 0x0001, 0xa07f, 0x0002, 0xa06b, 0x0000, 0xa09f, 0x0000, 0x00ce, + 0x012e, 0x0804, 0x3191, 0x0126, 0x2091, 0x8000, 0x00b6, 0x00c6, + 0x90e4, 0xc000, 0x0128, 0x0006, 0x080c, 0xb648, 0x000e, 0x1198, + 0xd0e4, 0x0160, 0x9180, 0x1000, 0x2004, 0x905d, 0x0160, 0x080c, + 0x5a3b, 0x080c, 0x9940, 0x0110, 0xb817, 0x0000, 0x9006, 0x00ce, + 0x00be, 0x012e, 0x0005, 0x9085, 0x0001, 0x0cc8, 0x0126, 0x2091, + 0x8000, 0x0156, 0x2010, 0x900e, 0x20a9, 0x0800, 0x0016, 0x9180, + 0x1000, 0x2004, 0x9005, 0x0180, 0x9186, 0x007e, 0x0168, 0x9186, + 0x007f, 0x0150, 0x9186, 0x0080, 0x0138, 0x9186, 0x00ff, 0x0120, + 0x0026, 0x2200, 0x0801, 0x002e, 0x001e, 0x8108, 0x1f04, 0x50f6, + 0x015e, 0x012e, 0x0005, 0x2001, 0x1854, 0x2004, 0x0005, 0x2001, + 0x1873, 0x2004, 0x0005, 0x0006, 0x2001, 0x180f, 0x2004, 0xd0d4, + 0x000e, 0x0005, 0x2001, 0x180d, 0x2004, 0xd0b4, 0x0005, 0x2001, + 0x1800, 0x2004, 0x9086, 0x0003, 0x0005, 0x0016, 0x00e6, 0x2071, + 0x1894, 0x7108, 0x910d, 0x710a, 0x00ee, 0x001e, 0x0005, 0x0126, + 0x0156, 0x0136, 0x0146, 0x01c6, 0x01d6, 0x00c6, 0x00d6, 0x00e6, + 0x00f6, 0x2061, 0x0100, 0x2069, 0x0200, 0x2071, 0x1800, 0x6044, + 0xd0a4, 0x11e8, 0xd084, 0x0118, 0x080c, 0x52e0, 0x0068, 0xd08c, + 0x0118, 0x080c, 0x51e9, 0x0040, 0xd094, 0x0118, 0x080c, 0x51b9, + 0x0018, 0xd09c, 0x0108, 0x0099, 0x00fe, 0x00ee, 0x00de, 0x00ce, + 0x01de, 0x01ce, 0x014e, 0x013e, 0x015e, 0x012e, 0x0005, 0x0016, + 0x6128, 0xd19c, 0x1110, 0xc19d, 0x612a, 0x001e, 0x0c68, 0x0006, + 0x7090, 0x9005, 0x000e, 0x0120, 0x7093, 0x0000, 0x708b, 0x0000, + 0x624c, 0x9286, 0xf0f0, 0x1150, 0x6048, 0x9086, 0xf0f0, 0x0130, + 0x624a, 0x6043, 0x0090, 0x6043, 0x0010, 0x0490, 0x9294, 0xff00, + 0x9296, 0xf700, 0x0178, 0x7134, 0xd1a4, 0x1160, 0x6240, 0x9295, + 0x0100, 0x6242, 0x9294, 0x0010, 0x0128, 0x2009, 0x00f7, 0x080c, + 0x599d, 0x00f0, 0x6040, 0x9084, 0x0010, 0x9085, 0x0140, 0x6042, + 0x6043, 0x0000, 0x707f, 0x0000, 0x709b, 0x0001, 0x70bf, 0x0000, + 0x70d7, 0x0000, 0x2009, 0x1c80, 0x200b, 0x0000, 0x708f, 0x0000, + 0x7083, 0x000f, 0x2009, 0x000f, 0x2011, 0x5883, 0x080c, 0x7cd9, + 0x0005, 0x2001, 0x1875, 0x2004, 0xd08c, 0x0110, 0x7057, 0xffff, + 0x7080, 0x9005, 0x1528, 0x2011, 0x5883, 0x080c, 0x7c4a, 0x6040, + 0x9094, 0x0010, 0x9285, 0x0020, 0x6042, 0x20a9, 0x00c8, 0x6044, + 0xd08c, 0x1168, 0x1f04, 0x51cf, 0x6242, 0x7093, 0x0000, 0x6040, + 0x9094, 0x0010, 0x9285, 0x0080, 0x6042, 0x6242, 0x0048, 0x6242, + 0x7093, 0x0000, 0x7087, 0x0000, 0x9006, 0x080c, 0x5a26, 0x0000, + 0x0005, 0x7084, 0x908a, 0x0003, 0x1a0c, 0x0db2, 0x000b, 0x0005, + 0x51f3, 0x5244, 0x52df, 0x00f6, 0x0016, 0x6900, 0x918c, 0x0800, + 0x7087, 0x0001, 0x2001, 0x015d, 0x2003, 0x0000, 0x6803, 0x00fc, + 0x20a9, 0x0004, 0x6800, 0x9084, 0x00fc, 0x0120, 0x1f04, 0x5202, + 0x080c, 0x0db2, 0x68a0, 0x68a2, 0x689c, 0x689e, 0x6898, 0x689a, + 0xa001, 0x918d, 0x1600, 0x6902, 0x001e, 0x6837, 0x0020, 0x080c, + 0x5a02, 0x2079, 0x1c00, 0x7833, 0x1101, 0x7837, 0x0000, 0x20e1, + 0x0001, 0x2099, 0x1805, 0x20e9, 0x0001, 0x20a1, 0x1c0e, 0x20a9, + 0x0004, 0x4003, 0x080c, 0x97ce, 0x20e1, 0x0001, 0x2099, 0x1c00, + 0x20e9, 0x0000, 0x20a1, 0x0240, 0x20a9, 0x0014, 0x4003, 0x60c3, + 0x000c, 0x600f, 0x0000, 0x080c, 0x58b4, 0x00fe, 0x9006, 0x708a, + 0x6043, 0x0008, 0x6042, 0x0005, 0x00f6, 0x7088, 0x708b, 0x0000, + 0x9025, 0x0904, 0x52bc, 0x6020, 0xd0b4, 0x1904, 0x52ba, 0x7198, + 0x81ff, 0x0904, 0x52a8, 0x9486, 0x000c, 0x1904, 0x52b5, 0x9480, + 0x0018, 0x8004, 0x20a8, 0x080c, 0x59fb, 0x2011, 0x0260, 0x2019, + 0x1c00, 0x220c, 0x2304, 0x9106, 0x11e8, 0x8210, 0x8318, 0x1f04, + 0x5261, 0x6043, 0x0004, 0x2061, 0x0140, 0x605b, 0xbc94, 0x605f, + 0xf0f0, 0x2061, 0x0100, 0x6043, 0x0006, 0x7087, 0x0002, 0x7093, + 0x0002, 0x2009, 0x07d0, 0x2011, 0x588a, 0x080c, 0x7cd9, 0x080c, + 0x5a02, 0x04c0, 0x080c, 0x59fb, 0x2079, 0x0260, 0x7930, 0x918e, + 0x1101, 0x1558, 0x7834, 0x9005, 0x1540, 0x7900, 0x918c, 0x00ff, + 0x1118, 0x7804, 0x9005, 0x0190, 0x080c, 0x59fb, 0x2011, 0x026e, + 0x2019, 0x1805, 0x20a9, 0x0004, 0x220c, 0x2304, 0x9102, 0x0230, + 0x11a0, 0x8210, 0x8318, 0x1f04, 0x529c, 0x0078, 0x709b, 0x0000, + 0x080c, 0x59fb, 0x20e1, 0x0000, 0x2099, 0x0260, 0x20e9, 0x0001, + 0x20a1, 0x1c00, 0x20a9, 0x0014, 0x4003, 0x6043, 0x0008, 0x6043, + 0x0000, 0x0010, 0x00fe, 0x0005, 0x6040, 0x9085, 0x0100, 0x6042, + 0x6020, 0xd0b4, 0x1db8, 0x080c, 0x97ce, 0x20e1, 0x0001, 0x2099, + 0x1c00, 0x20e9, 0x0000, 0x20a1, 0x0240, 0x20a9, 0x0014, 0x4003, + 0x60c3, 0x000c, 0x2011, 0x19c0, 0x2013, 0x0000, 0x708b, 0x0000, + 0x60a3, 0x0056, 0x60a7, 0x9575, 0x080c, 0x8fb2, 0x08d8, 0x0005, + 0x7090, 0x908a, 0x001d, 0x1a0c, 0x0db2, 0x000b, 0x0005, 0x5311, + 0x5324, 0x534d, 0x536d, 0x5393, 0x53c2, 0x53e8, 0x5420, 0x5446, + 0x5474, 0x54af, 0x54e7, 0x5505, 0x5530, 0x5552, 0x556d, 0x5577, + 0x55ab, 0x55d1, 0x5600, 0x5626, 0x565e, 0x56a2, 0x56df, 0x5700, + 0x5759, 0x577b, 0x57a9, 0x57a9, 0x00c6, 0x2061, 0x1800, 0x6003, + 0x0007, 0x2061, 0x0100, 0x6004, 0x9084, 0xfff9, 0x6006, 0x00ce, + 0x0005, 0x2061, 0x0140, 0x605b, 0xbc94, 0x605f, 0xf0f0, 0x2061, + 0x0100, 0x6043, 0x0002, 0x7093, 0x0001, 0x2009, 0x07d0, 0x2011, + 0x588a, 0x080c, 0x7cd9, 0x0005, 0x00f6, 0x7088, 0x9086, 0x0014, + 0x1510, 0x6042, 0x6020, 0xd0b4, 0x11f0, 0x080c, 0x59fb, 0x2079, + 0x0260, 0x7a30, 0x9296, 0x1102, 0x11a0, 0x7834, 0x9005, 0x1188, + 0x7a38, 0xd2fc, 0x0128, 0x70bc, 0x9005, 0x1110, 0x70bf, 0x0001, + 0x2011, 0x588a, 0x080c, 0x7c4a, 0x7093, 0x0010, 0x080c, 0x5577, + 0x0010, 0x708b, 0x0000, 0x00fe, 0x0005, 0x00f6, 0x7093, 0x0003, + 0x6043, 0x0004, 0x2011, 0x588a, 0x080c, 0x7c4a, 0x080c, 0x597f, + 0x2079, 0x0240, 0x7833, 0x1102, 0x7837, 0x0000, 0x20a9, 0x0008, + 0x9f88, 0x000e, 0x200b, 0x0000, 0x8108, 0x1f04, 0x5362, 0x60c3, + 0x0014, 0x080c, 0x58b4, 0x00fe, 0x0005, 0x00f6, 0x7088, 0x9005, + 0x0500, 0x2011, 0x588a, 0x080c, 0x7c4a, 0x9086, 0x0014, 0x11b8, + 0x080c, 0x59fb, 0x2079, 0x0260, 0x7a30, 0x9296, 0x1102, 0x1178, + 0x7834, 0x9005, 0x1160, 0x7a38, 0xd2fc, 0x0128, 0x70bc, 0x9005, + 0x1110, 0x70bf, 0x0001, 0x7093, 0x0004, 0x0029, 0x0010, 0x080c, + 0x59d7, 0x00fe, 0x0005, 0x00f6, 0x7093, 0x0005, 0x080c, 0x597f, + 0x2079, 0x0240, 0x7833, 0x1103, 0x7837, 0x0000, 0x080c, 0x59fb, + 0x080c, 0x59de, 0x1170, 0x707c, 0x9005, 0x1158, 0x7154, 0x9186, + 0xffff, 0x0138, 0x2011, 0x0008, 0x080c, 0x5837, 0x0168, 0x080c, + 0x59b4, 0x20a9, 0x0008, 0x20e1, 0x0000, 0x2099, 0x026e, 0x20e9, + 0x0000, 0x20a1, 0x024e, 0x4003, 0x60c3, 0x0014, 0x080c, 0x58b4, + 0x00fe, 0x0005, 0x00f6, 0x7088, 0x9005, 0x0500, 0x2011, 0x588a, + 0x080c, 0x7c4a, 0x9086, 0x0014, 0x11b8, 0x080c, 0x59fb, 0x2079, + 0x0260, 0x7a30, 0x9296, 0x1103, 0x1178, 0x7834, 0x9005, 0x1160, + 0x7a38, 0xd2fc, 0x0128, 0x70bc, 0x9005, 0x1110, 0x70bf, 0x0001, + 0x7093, 0x0006, 0x0029, 0x0010, 0x080c, 0x59d7, 0x00fe, 0x0005, + 0x00f6, 0x7093, 0x0007, 0x080c, 0x597f, 0x2079, 0x0240, 0x7833, + 0x1104, 0x7837, 0x0000, 0x080c, 0x59fb, 0x080c, 0x59de, 0x11b8, + 0x707c, 0x9005, 0x11a0, 0x715c, 0x9186, 0xffff, 0x0180, 0x9180, + 0x2f92, 0x200d, 0x918c, 0xff00, 0x810f, 0x2011, 0x0008, 0x080c, + 0x5837, 0x0180, 0x080c, 0x4a34, 0x0110, 0x080c, 0x253f, 0x20a9, + 0x0008, 0x20e1, 0x0000, 0x2099, 0x026e, 0x20e9, 0x0000, 0x20a1, + 0x024e, 0x4003, 0x60c3, 0x0014, 0x080c, 0x58b4, 0x00fe, 0x0005, + 0x00f6, 0x7088, 0x9005, 0x0500, 0x2011, 0x588a, 0x080c, 0x7c4a, + 0x9086, 0x0014, 0x11b8, 0x080c, 0x59fb, 0x2079, 0x0260, 0x7a30, + 0x9296, 0x1104, 0x1178, 0x7834, 0x9005, 0x1160, 0x7a38, 0xd2fc, + 0x0128, 0x70bc, 0x9005, 0x1110, 0x70bf, 0x0001, 0x7093, 0x0008, + 0x0029, 0x0010, 0x080c, 0x59d7, 0x00fe, 0x0005, 0x00f6, 0x7093, + 0x0009, 0x080c, 0x597f, 0x2079, 0x0240, 0x7833, 0x1105, 0x7837, + 0x0100, 0x080c, 0x59de, 0x1150, 0x707c, 0x9005, 0x1138, 0x080c, + 0x57aa, 0x1188, 0x9085, 0x0001, 0x080c, 0x253f, 0x20a9, 0x0008, + 0x080c, 0x59fb, 0x20e1, 0x0000, 0x2099, 0x026e, 0x20e9, 0x0000, + 0x20a1, 0x024e, 0x4003, 0x60c3, 0x0014, 0x080c, 0x58b4, 0x0010, + 0x080c, 0x5304, 0x00fe, 0x0005, 0x00f6, 0x7088, 0x9005, 0x05a8, + 0x2011, 0x588a, 0x080c, 0x7c4a, 0x9086, 0x0014, 0x1560, 0x080c, + 0x59fb, 0x2079, 0x0260, 0x7a30, 0x9296, 0x1105, 0x1520, 0x7834, + 0x9084, 0x0100, 0x2011, 0x0100, 0x921e, 0x1160, 0x7a38, 0xd2fc, + 0x0128, 0x70bc, 0x9005, 0x1110, 0x70bf, 0x0001, 0x7093, 0x000a, + 0x00b1, 0x0098, 0x9005, 0x1178, 0x7a38, 0xd2fc, 0x0128, 0x70bc, + 0x9005, 0x1110, 0x70bf, 0x0001, 0x708f, 0x0000, 0x7093, 0x000e, + 0x080c, 0x5552, 0x0010, 0x080c, 0x59d7, 0x00fe, 0x0005, 0x00f6, + 0x7093, 0x000b, 0x2011, 0x1c0e, 0x20e9, 0x0001, 0x22a0, 0x20a9, + 0x0040, 0x2019, 0xffff, 0x4304, 0x080c, 0x597f, 0x2079, 0x0240, + 0x7833, 0x1106, 0x7837, 0x0000, 0x080c, 0x59de, 0x0118, 0x2013, + 0x0000, 0x0020, 0x7058, 0x9085, 0x0100, 0x2012, 0x20a9, 0x0040, + 0x2009, 0x024e, 0x2011, 0x1c0e, 0x220e, 0x8210, 0x8108, 0x9186, + 0x0260, 0x1128, 0x6810, 0x8000, 0x6812, 0x2009, 0x0240, 0x1f04, + 0x54d4, 0x60c3, 0x0084, 0x080c, 0x58b4, 0x00fe, 0x0005, 0x00f6, + 0x7088, 0x9005, 0x01c0, 0x2011, 0x588a, 0x080c, 0x7c4a, 0x9086, + 0x0084, 0x1178, 0x080c, 0x59fb, 0x2079, 0x0260, 0x7a30, 0x9296, + 0x1106, 0x1138, 0x7834, 0x9005, 0x1120, 0x7093, 0x000c, 0x0029, + 0x0010, 0x080c, 0x59d7, 0x00fe, 0x0005, 0x00f6, 0x7093, 0x000d, + 0x080c, 0x597f, 0x2079, 0x0240, 0x7833, 0x1107, 0x7837, 0x0000, + 0x080c, 0x59fb, 0x20a9, 0x0040, 0x2011, 0x026e, 0x2009, 0x024e, + 0x220e, 0x8210, 0x8108, 0x9186, 0x0260, 0x1150, 0x6810, 0x8000, + 0x6812, 0x2009, 0x0240, 0x6814, 0x8000, 0x6816, 0x2011, 0x0260, + 0x1f04, 0x5518, 0x60c3, 0x0084, 0x080c, 0x58b4, 0x00fe, 0x0005, + 0x00f6, 0x7088, 0x9005, 0x01e0, 0x2011, 0x588a, 0x080c, 0x7c4a, + 0x9086, 0x0084, 0x1198, 0x080c, 0x59fb, 0x2079, 0x0260, 0x7a30, + 0x9296, 0x1107, 0x1158, 0x7834, 0x9005, 0x1140, 0x708f, 0x0001, + 0x080c, 0x5951, 0x7093, 0x000e, 0x0029, 0x0010, 0x080c, 0x59d7, + 0x00fe, 0x0005, 0x918d, 0x0001, 0x080c, 0x5a26, 0x7093, 0x000f, + 0x708b, 0x0000, 0x2061, 0x0140, 0x605b, 0xbc85, 0x605f, 0xb5b5, + 0x2061, 0x0100, 0x6043, 0x0005, 0x6043, 0x0004, 0x2009, 0x07d0, + 0x2011, 0x588a, 0x080c, 0x7c3e, 0x0005, 0x7088, 0x9005, 0x0130, + 0x2011, 0x588a, 0x080c, 0x7c4a, 0x7093, 0x0000, 0x0005, 0x7093, + 0x0011, 0x080c, 0x97ce, 0x080c, 0x59fb, 0x20e1, 0x0000, 0x2099, + 0x0260, 0x20e9, 0x0000, 0x20a1, 0x0240, 0x7488, 0x9480, 0x0018, + 0x9080, 0x0007, 0x9084, 0x03f8, 0x8004, 0x20a8, 0x4003, 0x080c, + 0x59de, 0x11a0, 0x7174, 0x81ff, 0x0188, 0x900e, 0x7078, 0x9084, + 0x00ff, 0x0160, 0x080c, 0x24d6, 0x9186, 0x007e, 0x0138, 0x9186, + 0x0080, 0x0120, 0x2011, 0x0008, 0x080c, 0x5837, 0x60c3, 0x0014, + 0x080c, 0x58b4, 0x0005, 0x00f6, 0x7088, 0x9005, 0x0500, 0x2011, + 0x588a, 0x080c, 0x7c4a, 0x9086, 0x0014, 0x11b8, 0x080c, 0x59fb, + 0x2079, 0x0260, 0x7a30, 0x9296, 0x1103, 0x1178, 0x7834, 0x9005, + 0x1160, 0x7a38, 0xd2fc, 0x0128, 0x70bc, 0x9005, 0x1110, 0x70bf, + 0x0001, 0x7093, 0x0012, 0x0029, 0x0010, 0x708b, 0x0000, 0x00fe, + 0x0005, 0x00f6, 0x7093, 0x0013, 0x080c, 0x598d, 0x2079, 0x0240, + 0x7833, 0x1103, 0x7837, 0x0000, 0x080c, 0x59fb, 0x080c, 0x59de, + 0x1170, 0x707c, 0x9005, 0x1158, 0x7154, 0x9186, 0xffff, 0x0138, + 0x2011, 0x0008, 0x080c, 0x5837, 0x0168, 0x080c, 0x59b4, 0x20a9, + 0x0008, 0x20e1, 0x0000, 0x2099, 0x026e, 0x20e9, 0x0000, 0x20a1, + 0x024e, 0x4003, 0x60c3, 0x0014, 0x080c, 0x58b4, 0x00fe, 0x0005, + 0x00f6, 0x7088, 0x9005, 0x0500, 0x2011, 0x588a, 0x080c, 0x7c4a, + 0x9086, 0x0014, 0x11b8, 0x080c, 0x59fb, 0x2079, 0x0260, 0x7a30, + 0x9296, 0x1104, 0x1178, 0x7834, 0x9005, 0x1160, 0x7a38, 0xd2fc, + 0x0128, 0x70bc, 0x9005, 0x1110, 0x70bf, 0x0001, 0x7093, 0x0014, + 0x0029, 0x0010, 0x708b, 0x0000, 0x00fe, 0x0005, 0x00f6, 0x7093, + 0x0015, 0x080c, 0x598d, 0x2079, 0x0240, 0x7833, 0x1104, 0x7837, + 0x0000, 0x080c, 0x59fb, 0x080c, 0x59de, 0x11b8, 0x707c, 0x9005, + 0x11a0, 0x715c, 0x9186, 0xffff, 0x0180, 0x9180, 0x2f92, 0x200d, + 0x918c, 0xff00, 0x810f, 0x2011, 0x0008, 0x080c, 0x5837, 0x0180, + 0x080c, 0x4a34, 0x0110, 0x080c, 0x253f, 0x20a9, 0x0008, 0x20e1, + 0x0000, 0x2099, 0x026e, 0x20e9, 0x0000, 0x20a1, 0x024e, 0x4003, + 0x60c3, 0x0014, 0x080c, 0x58b4, 0x00fe, 0x0005, 0x00f6, 0x7088, + 0x9005, 0x05f0, 0x2011, 0x588a, 0x080c, 0x7c4a, 0x9086, 0x0014, + 0x15a8, 0x080c, 0x59fb, 0x2079, 0x0260, 0x7a30, 0x9296, 0x1105, + 0x1568, 0x7834, 0x9084, 0x0100, 0x2011, 0x0100, 0x921e, 0x1168, + 0x9085, 0x0001, 0x080c, 0x5a26, 0x7a38, 0xd2fc, 0x0128, 0x70bc, + 0x9005, 0x1110, 0x70bf, 0x0001, 0x0080, 0x9005, 0x11b8, 0x7a38, + 0xd2fc, 0x0128, 0x70bc, 0x9005, 0x1110, 0x70bf, 0x0001, 0x9085, + 0x0001, 0x080c, 0x5a26, 0x708f, 0x0000, 0x7a38, 0xd2f4, 0x0110, + 0x70d7, 0x0008, 0x7093, 0x0016, 0x0029, 0x0010, 0x708b, 0x0000, + 0x00fe, 0x0005, 0x080c, 0x97ce, 0x080c, 0x59fb, 0x20e1, 0x0000, + 0x2099, 0x0260, 0x20e9, 0x0000, 0x20a1, 0x0240, 0x20a9, 0x000e, + 0x4003, 0x2011, 0x026d, 0x2204, 0x9084, 0x0100, 0x2011, 0x024d, + 0x2012, 0x2011, 0x026e, 0x7093, 0x0017, 0x080c, 0x59de, 0x1150, + 0x707c, 0x9005, 0x1138, 0x080c, 0x57aa, 0x1188, 0x9085, 0x0001, + 0x080c, 0x253f, 0x20a9, 0x0008, 0x080c, 0x59fb, 0x20e1, 0x0000, + 0x2099, 0x026e, 0x20e9, 0x0000, 0x20a1, 0x024e, 0x4003, 0x60c3, + 0x0014, 0x080c, 0x58b4, 0x0010, 0x080c, 0x5304, 0x0005, 0x00f6, + 0x7088, 0x9005, 0x01d8, 0x2011, 0x588a, 0x080c, 0x7c4a, 0x9086, + 0x0084, 0x1190, 0x080c, 0x59fb, 0x2079, 0x0260, 0x7a30, 0x9296, + 0x1106, 0x1150, 0x7834, 0x9005, 0x1138, 0x9006, 0x080c, 0x5a26, + 0x7093, 0x0018, 0x0029, 0x0010, 0x708b, 0x0000, 0x00fe, 0x0005, + 0x00f6, 0x7093, 0x0019, 0x080c, 0x598d, 0x2079, 0x0240, 0x7833, + 0x1106, 0x7837, 0x0000, 0x080c, 0x59fb, 0x2009, 0x026e, 0x2039, + 0x1c0e, 0x20a9, 0x0040, 0x213e, 0x8738, 0x8108, 0x9186, 0x0280, + 0x1128, 0x6814, 0x8000, 0x6816, 0x2009, 0x0260, 0x1f04, 0x5713, + 0x2039, 0x1c0e, 0x080c, 0x59de, 0x11e8, 0x2728, 0x2514, 0x8207, + 0x9084, 0x00ff, 0x8000, 0x2018, 0x9294, 0x00ff, 0x8007, 0x9205, + 0x202a, 0x7058, 0x2310, 0x8214, 0x92a0, 0x1c0e, 0x2414, 0x938c, + 0x0001, 0x0118, 0x9294, 0xff00, 0x0018, 0x9294, 0x00ff, 0x8007, + 0x9215, 0x2222, 0x20a9, 0x0040, 0x2009, 0x024e, 0x270e, 0x8738, + 0x8108, 0x9186, 0x0260, 0x1128, 0x6810, 0x8000, 0x6812, 0x2009, + 0x0240, 0x1f04, 0x5746, 0x60c3, 0x0084, 0x080c, 0x58b4, 0x00fe, + 0x0005, 0x00f6, 0x7088, 0x9005, 0x01e0, 0x2011, 0x588a, 0x080c, + 0x7c4a, 0x9086, 0x0084, 0x1198, 0x080c, 0x59fb, 0x2079, 0x0260, + 0x7a30, 0x9296, 0x1107, 0x1158, 0x7834, 0x9005, 0x1140, 0x708f, + 0x0001, 0x080c, 0x5951, 0x7093, 0x001a, 0x0029, 0x0010, 0x708b, + 0x0000, 0x00fe, 0x0005, 0x9085, 0x0001, 0x080c, 0x5a26, 0x7093, + 0x001b, 0x080c, 0x97ce, 0x080c, 0x59fb, 0x2011, 0x0260, 0x2009, + 0x0240, 0x7488, 0x9480, 0x0018, 0x9080, 0x0007, 0x9084, 0x03f8, + 0x8004, 0x20a8, 0x220e, 0x8210, 0x8108, 0x9186, 0x0260, 0x1150, + 0x6810, 0x8000, 0x6812, 0x2009, 0x0240, 0x6814, 0x8000, 0x6816, + 0x2011, 0x0260, 0x1f04, 0x5792, 0x60c3, 0x0084, 0x080c, 0x58b4, + 0x0005, 0x0005, 0x0086, 0x0096, 0x2029, 0x1854, 0x252c, 0x20a9, + 0x0008, 0x2041, 0x1c0e, 0x20e9, 0x0001, 0x28a0, 0x080c, 0x59fb, + 0x20e1, 0x0000, 0x2099, 0x026e, 0x4003, 0x20a9, 0x0008, 0x2011, + 0x0007, 0xd5d4, 0x0108, 0x9016, 0x2800, 0x9200, 0x200c, 0x91a6, + 0xffff, 0x1148, 0xd5d4, 0x0110, 0x8210, 0x0008, 0x8211, 0x1f04, + 0x57c4, 0x0804, 0x5833, 0x82ff, 0x1160, 0xd5d4, 0x0120, 0x91a6, + 0x3fff, 0x0d90, 0x0020, 0x91a6, 0x3fff, 0x0904, 0x5833, 0x918d, + 0xc000, 0x20a9, 0x0010, 0x2019, 0x0001, 0xd5d4, 0x0110, 0x2019, + 0x0010, 0x2120, 0xd5d4, 0x0110, 0x8423, 0x0008, 0x8424, 0x1240, + 0xd5d4, 0x0110, 0x8319, 0x0008, 0x8318, 0x1f04, 0x57ea, 0x04d8, + 0x23a8, 0x2021, 0x0001, 0x8426, 0x8425, 0x1f04, 0x57fc, 0x2328, + 0x8529, 0x92be, 0x0007, 0x0158, 0x0006, 0x2039, 0x0007, 0x2200, + 0x973a, 0x000e, 0x27a8, 0x95a8, 0x0010, 0x1f04, 0x580b, 0x7556, + 0x95c8, 0x2f92, 0x292d, 0x95ac, 0x00ff, 0x757a, 0x6532, 0x6536, + 0x0016, 0x2508, 0x080c, 0x251f, 0x001e, 0x60e7, 0x0000, 0x65ea, + 0x2018, 0x2304, 0x9405, 0x201a, 0x707f, 0x0001, 0x20e9, 0x0000, + 0x20a1, 0x024e, 0x20e1, 0x0001, 0x2898, 0x20a9, 0x0008, 0x4003, + 0x9085, 0x0001, 0x0008, 0x9006, 0x009e, 0x008e, 0x0005, 0x0156, + 0x01c6, 0x01d6, 0x0136, 0x0146, 0x22a8, 0x20e1, 0x0000, 0x2099, + 0x026e, 0x20e9, 0x0000, 0x2011, 0x024e, 0x22a0, 0x4003, 0x014e, + 0x013e, 0x01de, 0x01ce, 0x015e, 0x2118, 0x9026, 0x2001, 0x0007, + 0x939a, 0x0010, 0x0218, 0x8420, 0x8001, 0x0cd0, 0x2118, 0x84ff, + 0x0120, 0x939a, 0x0010, 0x8421, 0x1de0, 0x2021, 0x0001, 0x83ff, + 0x0118, 0x8423, 0x8319, 0x1de8, 0x9238, 0x2029, 0x026e, 0x9528, + 0x2504, 0x942c, 0x11b8, 0x9405, 0x203a, 0x7156, 0x91a0, 0x2f92, + 0x242d, 0x95ac, 0x00ff, 0x757a, 0x6532, 0x6536, 0x0016, 0x2508, + 0x080c, 0x251f, 0x001e, 0x60e7, 0x0000, 0x65ea, 0x707f, 0x0001, + 0x9084, 0x0000, 0x0005, 0x00e6, 0x2071, 0x1800, 0x7083, 0x0000, + 0x00ee, 0x0005, 0x00e6, 0x00f6, 0x2079, 0x0100, 0x2071, 0x0140, + 0x080c, 0x5940, 0x080c, 0x8fbb, 0x7004, 0x9084, 0x4000, 0x0110, + 0x080c, 0x2997, 0x0126, 0x2091, 0x8000, 0x2071, 0x1824, 0x2073, + 0x0000, 0x7840, 0x0026, 0x0016, 0x2009, 0x00f7, 0x080c, 0x599d, + 0x001e, 0x9094, 0x0010, 0x9285, 0x0080, 0x7842, 0x7a42, 0x002e, + 0x012e, 0x00fe, 0x00ee, 0x0005, 0x0126, 0x2091, 0x8000, 0x080c, + 0x283d, 0x0228, 0x2011, 0x0101, 0x2204, 0xc0c5, 0x2012, 0x2011, + 0x19c0, 0x2013, 0x0000, 0x708b, 0x0000, 0x012e, 0x60a3, 0x0056, + 0x60a7, 0x9575, 0x080c, 0x8fb2, 0x6144, 0xd184, 0x0120, 0x7190, + 0x918d, 0x2000, 0x0018, 0x7184, 0x918d, 0x1000, 0x2011, 0x1968, + 0x2112, 0x2009, 0x07d0, 0x2011, 0x588a, 0x080c, 0x7cd9, 0x0005, + 0x0016, 0x0026, 0x00c6, 0x0126, 0x2091, 0x8000, 0x080c, 0x9947, + 0x2009, 0x00f7, 0x080c, 0x599d, 0x2061, 0x19c9, 0x900e, 0x611a, + 0x611e, 0x6172, 0x6176, 0x2061, 0x1800, 0x6003, 0x0001, 0x2061, + 0x0100, 0x6043, 0x0090, 0x6043, 0x0010, 0x2009, 0x1968, 0x200b, + 0x0000, 0x2009, 0x002d, 0x2011, 0x590c, 0x080c, 0x7c3e, 0x012e, + 0x00ce, 0x002e, 0x001e, 0x0005, 0x00e6, 0x0006, 0x0126, 0x2091, + 0x8000, 0x0471, 0x2071, 0x0100, 0x080c, 0x8fbb, 0x2071, 0x0140, + 0x7004, 0x9084, 0x4000, 0x0110, 0x080c, 0x2997, 0x080c, 0x6c5b, + 0x0188, 0x080c, 0x6c76, 0x1170, 0x080c, 0x6f34, 0x0016, 0x080c, + 0x25ee, 0x2001, 0x193e, 0x2102, 0x001e, 0x080c, 0x6f2f, 0x080c, + 0x6b8a, 0x0050, 0x2009, 0x0001, 0x080c, 0x28d6, 0x2001, 0x0001, + 0x080c, 0x247f, 0x080c, 0x58e0, 0x012e, 0x000e, 0x00ee, 0x0005, + 0x2001, 0x180d, 0x2004, 0xd0bc, 0x0158, 0x0026, 0x0036, 0x2011, + 0x8017, 0x2001, 0x1968, 0x201c, 0x080c, 0x4672, 0x003e, 0x002e, + 0x0005, 0x20a9, 0x0012, 0x20e9, 0x0001, 0x20a1, 0x1c80, 0x080c, + 0x59fb, 0x20e9, 0x0000, 0x2099, 0x026e, 0x0099, 0x20a9, 0x0020, + 0x080c, 0x59f5, 0x2099, 0x0260, 0x20a1, 0x1c92, 0x0051, 0x20a9, + 0x000e, 0x080c, 0x59f8, 0x2099, 0x0260, 0x20a1, 0x1cb2, 0x0009, + 0x0005, 0x0016, 0x0026, 0x3410, 0x3308, 0x2104, 0x8007, 0x2012, + 0x8108, 0x8210, 0x1f04, 0x5975, 0x002e, 0x001e, 0x0005, 0x080c, + 0x97ce, 0x20e1, 0x0001, 0x2099, 0x1c00, 0x20e9, 0x0000, 0x20a1, + 0x0240, 0x20a9, 0x000c, 0x4003, 0x0005, 0x080c, 0x97ce, 0x080c, + 0x59fb, 0x20e1, 0x0000, 0x2099, 0x0260, 0x20e9, 0x0000, 0x20a1, + 0x0240, 0x20a9, 0x000c, 0x4003, 0x0005, 0x00c6, 0x0006, 0x2061, + 0x0100, 0x810f, 0x2001, 0x1832, 0x2004, 0x9005, 0x1138, 0x2001, + 0x1816, 0x2004, 0x9084, 0x00ff, 0x9105, 0x0010, 0x9185, 0x00f7, + 0x604a, 0x000e, 0x00ce, 0x0005, 0x0016, 0x0046, 0x080c, 0x62a0, + 0x0158, 0x9006, 0x2020, 0x2009, 0x002a, 0x080c, 0xcfe6, 0x2001, + 0x180c, 0x200c, 0xc195, 0x2102, 0x2019, 0x002a, 0x900e, 0x080c, + 0x2dfb, 0x080c, 0xbcec, 0x0140, 0x0036, 0x2019, 0xffff, 0x2021, + 0x0007, 0x080c, 0x4829, 0x003e, 0x004e, 0x001e, 0x0005, 0x080c, + 0x58e0, 0x7093, 0x0000, 0x708b, 0x0000, 0x0005, 0x0006, 0x2001, + 0x180c, 0x2004, 0xd09c, 0x0100, 0x000e, 0x0005, 0x0006, 0x0016, + 0x0126, 0x2091, 0x8000, 0x2001, 0x0101, 0x200c, 0x918d, 0x0006, + 0x2102, 0x012e, 0x001e, 0x000e, 0x0005, 0x2009, 0x0001, 0x0020, + 0x2009, 0x0002, 0x0008, 0x900e, 0x6814, 0x9084, 0xffc0, 0x910d, + 0x6916, 0x0005, 0x00f6, 0x0156, 0x0146, 0x01d6, 0x9006, 0x20a9, + 0x0080, 0x20e9, 0x0001, 0x20a1, 0x1c00, 0x4004, 0x2079, 0x1c00, + 0x7803, 0x2200, 0x7807, 0x00ef, 0x780f, 0x00ef, 0x7813, 0x0138, + 0x7823, 0xffff, 0x7827, 0xffff, 0x01de, 0x014e, 0x015e, 0x00fe, + 0x0005, 0x2001, 0x1800, 0x2003, 0x0001, 0x0005, 0x2001, 0x1975, + 0x0118, 0x2003, 0x0001, 0x0010, 0x2003, 0x0000, 0x0005, 0x0156, + 0x20a9, 0x0800, 0x2009, 0x1000, 0x9006, 0x200a, 0x8108, 0x1f04, + 0x5a35, 0x015e, 0x0005, 0x00d6, 0x0036, 0x0156, 0x0136, 0x0146, + 0x2069, 0x1853, 0x9006, 0xb802, 0xb8be, 0xb807, 0x0707, 0xb80a, + 0xb80e, 0xb812, 0x9198, 0x2f92, 0x231d, 0x939c, 0x00ff, 0xbb16, + 0x0016, 0x0026, 0xb8b2, 0x080c, 0x9940, 0x1120, 0x9192, 0x007e, + 0x1208, 0xbbb2, 0x20a9, 0x0004, 0xb8b4, 0x20e8, 0xb9b8, 0x9198, + 0x0006, 0x9006, 0x23a0, 0x4004, 0x20a9, 0x0004, 0x9198, 0x000a, + 0x23a0, 0x4004, 0x002e, 0x001e, 0xb83e, 0xb842, 0xb84e, 0xb852, + 0xb856, 0xb85a, 0xb85e, 0xb862, 0xb866, 0xb86a, 0xb86f, 0x0100, + 0xb872, 0xb876, 0xb87a, 0xb88a, 0xb88e, 0xb893, 0x0008, 0xb896, + 0xb89a, 0xb89e, 0xb8ae, 0xb9a2, 0x0096, 0xb8a4, 0x904d, 0x0110, + 0x080c, 0x1007, 0xb8a7, 0x0000, 0x009e, 0x9006, 0xb84a, 0x6810, + 0xb83a, 0x680c, 0xb846, 0x6814, 0x9084, 0x00ff, 0xb842, 0x014e, + 0x013e, 0x015e, 0x003e, 0x00de, 0x0005, 0x0126, 0x2091, 0x8000, + 0xa974, 0xae78, 0x9684, 0x3fff, 0x9082, 0x4000, 0x1a04, 0x5b0b, + 0x9182, 0x0800, 0x1a04, 0x5b0f, 0x2001, 0x180c, 0x2004, 0x9084, + 0x0003, 0x1904, 0x5b15, 0x9188, 0x1000, 0x2104, 0x905d, 0x0518, + 0xb804, 0x9084, 0x00ff, 0x908e, 0x0006, 0x1508, 0xb8a4, 0x900d, + 0x1904, 0x5b27, 0xb850, 0x900d, 0x1148, 0xa802, 0x2900, 0xb852, + 0xb84e, 0x080c, 0x801d, 0x9006, 0x012e, 0x0005, 0x00a6, 0x2150, + 0x2900, 0xb002, 0xa803, 0x0000, 0x00ae, 0xb852, 0x0c90, 0x2001, + 0x0005, 0x900e, 0x04b8, 0x2001, 0x0028, 0x900e, 0x0498, 0x9082, + 0x0006, 0x1290, 0x080c, 0x9940, 0x1160, 0xb8a0, 0x9084, 0xff80, + 0x1140, 0xb900, 0xd1fc, 0x0990, 0x2001, 0x0029, 0x2009, 0x1000, + 0x0408, 0x2001, 0x0028, 0x00a8, 0x2009, 0x180c, 0x210c, 0xd18c, + 0x0118, 0x2001, 0x0004, 0x0068, 0xd184, 0x0118, 0x2001, 0x0004, + 0x0040, 0x2001, 0x0029, 0xb900, 0xd1fc, 0x0118, 0x2009, 0x1000, + 0x0048, 0x900e, 0x0038, 0x2001, 0x0029, 0x900e, 0x0018, 0x2001, + 0x0029, 0x900e, 0x9005, 0x012e, 0x0005, 0x2001, 0x180c, 0x2004, + 0xd084, 0x19d0, 0x9188, 0x1000, 0x2104, 0x905d, 0x09a8, 0x080c, + 0x62a4, 0x1990, 0xb800, 0xd0bc, 0x0978, 0x0804, 0x5abe, 0x080c, + 0x611a, 0x0904, 0x5ad7, 0x0804, 0x5ac2, 0x00b6, 0x00e6, 0x0126, + 0x2091, 0x8000, 0xa974, 0x9182, 0x0800, 0x1a04, 0x5ba8, 0x9188, + 0x1000, 0x2104, 0x905d, 0x0904, 0x5b80, 0xb8a0, 0x9086, 0x007f, + 0x0178, 0x080c, 0x62ac, 0x0160, 0xa994, 0x81ff, 0x0130, 0x908e, + 0x0004, 0x0130, 0x908e, 0x0005, 0x0118, 0x080c, 0x62a4, 0x1598, + 0xa87c, 0xd0fc, 0x01e0, 0xa894, 0x9005, 0x01c8, 0x2060, 0x0026, + 0x2010, 0x080c, 0xb5e9, 0x002e, 0x1120, 0x2001, 0x0008, 0x0804, + 0x5baa, 0x6020, 0x9086, 0x000a, 0x0120, 0x2001, 0x0008, 0x0804, + 0x5baa, 0x601a, 0x6003, 0x0008, 0x2900, 0x6016, 0x0058, 0x080c, + 0x9980, 0x05e8, 0x2b00, 0x6012, 0x2900, 0x6016, 0x600b, 0xffff, + 0x6023, 0x000a, 0x2009, 0x0003, 0x080c, 0x9a50, 0x9006, 0x0458, + 0x2001, 0x0028, 0x0438, 0x9082, 0x0006, 0x1290, 0x080c, 0x9940, + 0x1160, 0xb8a0, 0x9084, 0xff80, 0x1140, 0xb900, 0xd1fc, 0x0900, + 0x2001, 0x0029, 0x2009, 0x1000, 0x00a8, 0x2001, 0x0028, 0x0090, + 0x2009, 0x180c, 0x210c, 0xd18c, 0x0118, 0x2001, 0x0004, 0x0050, + 0xd184, 0x0118, 0x2001, 0x0004, 0x0028, 0x2001, 0x0029, 0x0010, + 0x2001, 0x0029, 0x9005, 0x012e, 0x00ee, 0x00be, 0x0005, 0x2001, + 0x002c, 0x0cc0, 0x00f6, 0x00b6, 0x0126, 0x2091, 0x8000, 0xa8e0, + 0x9005, 0x1550, 0xa8dc, 0x9082, 0x0101, 0x1630, 0xa8c8, 0x9005, + 0x1518, 0xa8c4, 0x9082, 0x0101, 0x12f8, 0xa974, 0x2079, 0x1800, + 0x9182, 0x0800, 0x12e8, 0x7830, 0x9084, 0x0003, 0x1130, 0xaa98, + 0xab94, 0xa878, 0x9084, 0x0007, 0x00ea, 0x7930, 0xd18c, 0x0118, + 0x2001, 0x0004, 0x0038, 0xd184, 0x0118, 0x2001, 0x0004, 0x0010, + 0x2001, 0x0029, 0x900e, 0x0038, 0x2001, 0x002c, 0x900e, 0x0018, + 0x2001, 0x0029, 0x900e, 0x9006, 0x0008, 0x9005, 0x012e, 0x00be, + 0x00fe, 0x0005, 0x5c3f, 0x5bfa, 0x5c11, 0x5c3f, 0x5c3f, 0x5c3f, + 0x5c3f, 0x5c3f, 0x2100, 0x9082, 0x007e, 0x1278, 0x080c, 0x5f1e, + 0x0148, 0x9046, 0xb810, 0x9306, 0x1904, 0x5c47, 0xb814, 0x9206, + 0x15f0, 0x0028, 0xbb12, 0xba16, 0x0010, 0x080c, 0x452c, 0x0150, + 0x04b0, 0x080c, 0x5f7e, 0x1598, 0xb810, 0x9306, 0x1580, 0xb814, + 0x9206, 0x1568, 0x080c, 0x9980, 0x0530, 0x2b00, 0x6012, 0x080c, + 0xba69, 0x2900, 0x6016, 0x600b, 0xffff, 0x6023, 0x000a, 0xa878, + 0x9086, 0x0001, 0x1170, 0x080c, 0x2e30, 0x9006, 0x080c, 0x5ebb, + 0x2001, 0x0002, 0x080c, 0x5ecf, 0x2001, 0x0200, 0xb86e, 0xb893, + 0x0002, 0x2009, 0x0003, 0x080c, 0x9a50, 0x9006, 0x0068, 0x2001, + 0x0001, 0x900e, 0x0038, 0x2001, 0x002c, 0x900e, 0x0018, 0x2001, + 0x0028, 0x900e, 0x9005, 0x0000, 0x012e, 0x00be, 0x00fe, 0x0005, + 0x00b6, 0x00f6, 0x00e6, 0x0126, 0x2091, 0x8000, 0xa894, 0x90c6, + 0x0015, 0x0904, 0x5e14, 0x90c6, 0x0056, 0x0904, 0x5e18, 0x90c6, + 0x0066, 0x0904, 0x5e1c, 0x90c6, 0x0071, 0x0904, 0x5e20, 0x90c6, + 0x0074, 0x0904, 0x5e24, 0x90c6, 0x007c, 0x0904, 0x5e28, 0x90c6, + 0x007e, 0x0904, 0x5e2c, 0x90c6, 0x0037, 0x0904, 0x5e30, 0x9016, + 0x2079, 0x1800, 0xa974, 0x9186, 0x00ff, 0x0904, 0x5e0f, 0x9182, + 0x0800, 0x1a04, 0x5e0f, 0x080c, 0x5f7e, 0x1198, 0xb804, 0x9084, + 0x00ff, 0x9082, 0x0006, 0x1268, 0xa894, 0x90c6, 0x006f, 0x0148, + 0x080c, 0x9940, 0x1904, 0x5df8, 0xb8a0, 0x9084, 0xff80, 0x1904, + 0x5df8, 0xa894, 0x90c6, 0x006f, 0x0158, 0x90c6, 0x005e, 0x0904, + 0x5d58, 0x90c6, 0x0064, 0x0904, 0x5d81, 0x2008, 0x0804, 0x5d1b, + 0xa998, 0xa8b0, 0x2040, 0x080c, 0x9940, 0x1120, 0x9182, 0x007f, + 0x0a04, 0x5d1b, 0x9186, 0x00ff, 0x0904, 0x5d1b, 0x9182, 0x0800, + 0x1a04, 0x5d1b, 0xaaa0, 0xab9c, 0x7874, 0x9306, 0x1188, 0x7878, + 0x0096, 0x924e, 0x1128, 0x2208, 0x2310, 0x009e, 0x0804, 0x5d1b, + 0x99cc, 0xff00, 0x009e, 0x1120, 0x2208, 0x2310, 0x0804, 0x5d1b, + 0x080c, 0x452c, 0x0904, 0x5d24, 0x900e, 0x9016, 0x90c6, 0x4000, + 0x1558, 0x0006, 0x080c, 0x619e, 0x1108, 0xc185, 0xb800, 0xd0bc, + 0x0108, 0xc18d, 0x20a9, 0x0004, 0xa860, 0x20e8, 0xa85c, 0x9080, + 0x0031, 0x20a0, 0xb8b4, 0x20e0, 0xb8b8, 0x9080, 0x0006, 0x2098, + 0x080c, 0x0f52, 0x20a9, 0x0004, 0xa860, 0x20e8, 0xa85c, 0x9080, + 0x0035, 0x20a0, 0xb8b4, 0x20e0, 0xb8b8, 0x9080, 0x000a, 0x2098, + 0x080c, 0x0f52, 0x000e, 0x00c8, 0x90c6, 0x4007, 0x1110, 0x2408, + 0x00a0, 0x90c6, 0x4008, 0x1118, 0x2708, 0x2610, 0x0070, 0x90c6, + 0x4009, 0x1108, 0x0050, 0x90c6, 0x4006, 0x0138, 0x2001, 0x4005, + 0x2009, 0x000a, 0x0010, 0x2001, 0x4006, 0xa896, 0xa99a, 0xaa9e, + 0x2001, 0x0030, 0x900e, 0x0470, 0x080c, 0x9980, 0x1130, 0x2001, + 0x4005, 0x2009, 0x0003, 0x9016, 0x0c80, 0x2b00, 0x6012, 0x080c, + 0xba69, 0x2900, 0x6016, 0x6023, 0x0001, 0xa868, 0xd88c, 0x0108, + 0xc0f5, 0xa86a, 0x0126, 0x2091, 0x8000, 0x080c, 0x2e30, 0x012e, + 0x9006, 0x080c, 0x5ebb, 0x2001, 0x0002, 0x080c, 0x5ecf, 0x2009, + 0x0002, 0x080c, 0x9a50, 0xa8b0, 0xd094, 0x0118, 0xb8bc, 0xc08d, + 0xb8be, 0x9006, 0x9005, 0x012e, 0x00ee, 0x00fe, 0x00be, 0x0005, + 0x080c, 0x5127, 0x0118, 0x2009, 0x0007, 0x00f8, 0xa998, 0xaeb0, + 0x080c, 0x5f7e, 0x1904, 0x5d16, 0x9186, 0x007f, 0x0130, 0x080c, + 0x62a4, 0x0118, 0x2009, 0x0009, 0x0080, 0x0096, 0x080c, 0x0fd5, + 0x1120, 0x009e, 0x2009, 0x0002, 0x0040, 0x2900, 0x009e, 0xa806, + 0x080c, 0xb7da, 0x19b0, 0x2009, 0x0003, 0x2001, 0x4005, 0x0804, + 0x5d1d, 0xa998, 0xaeb0, 0x080c, 0x5f7e, 0x1904, 0x5d16, 0x0096, + 0x080c, 0x0fd5, 0x1128, 0x009e, 0x2009, 0x0002, 0x0804, 0x5dd5, + 0x2900, 0x009e, 0xa806, 0x0096, 0x2048, 0x20a9, 0x002b, 0xb8b4, + 0x20e0, 0xb8b8, 0x2098, 0xa860, 0x20e8, 0xa85c, 0x9080, 0x0002, + 0x20a0, 0x4003, 0x20a9, 0x0008, 0x9080, 0x0006, 0x20a0, 0xbbb8, + 0x9398, 0x0006, 0x2398, 0x080c, 0x0f52, 0x009e, 0xa87b, 0x0000, + 0xa883, 0x0000, 0xa897, 0x4000, 0xd684, 0x1168, 0x080c, 0x5113, + 0xd0b4, 0x1118, 0xa89b, 0x000b, 0x00e0, 0xb800, 0xd08c, 0x0118, + 0xa89b, 0x000c, 0x00b0, 0x080c, 0x62a4, 0x0118, 0xa89b, 0x0009, + 0x0080, 0x080c, 0x5127, 0x0118, 0xa89b, 0x0007, 0x0050, 0x080c, + 0xb7bd, 0x1904, 0x5d51, 0x2009, 0x0003, 0x2001, 0x4005, 0x0804, + 0x5d1d, 0xa87b, 0x0030, 0xa897, 0x4005, 0xa804, 0x8006, 0x8006, + 0x8007, 0x90bc, 0x003f, 0x9084, 0xffc0, 0x9080, 0x0002, 0x2009, + 0x002b, 0xaaa0, 0xab9c, 0xaca8, 0xada4, 0x2031, 0x0000, 0x2041, + 0x120c, 0x080c, 0x9ed6, 0x1904, 0x5d51, 0x2009, 0x0002, 0x08e8, + 0x2001, 0x0028, 0x900e, 0x0804, 0x5d52, 0x2009, 0x180c, 0x210c, + 0xd18c, 0x0118, 0x2001, 0x0004, 0x0038, 0xd184, 0x0118, 0x2001, + 0x0004, 0x0010, 0x2001, 0x0029, 0x900e, 0x0804, 0x5d52, 0x2001, + 0x0029, 0x900e, 0x0804, 0x5d52, 0x080c, 0x33b6, 0x0804, 0x5d53, + 0x080c, 0x4e50, 0x0804, 0x5d53, 0x080c, 0x41a5, 0x0804, 0x5d53, + 0x080c, 0x45e8, 0x0804, 0x5d53, 0x080c, 0x489f, 0x0804, 0x5d53, + 0x080c, 0x4aca, 0x0804, 0x5d53, 0x080c, 0x4cbb, 0x0804, 0x5d53, + 0x080c, 0x35c6, 0x0804, 0x5d53, 0x00b6, 0xa974, 0xae78, 0x9684, + 0x3fff, 0x9082, 0x4000, 0x1618, 0x9182, 0x0800, 0x1268, 0x9188, + 0x1000, 0x2104, 0x905d, 0x0140, 0x080c, 0x62a4, 0x1148, 0x00e9, + 0x080c, 0x60a9, 0x9006, 0x00b0, 0x2001, 0x0028, 0x900e, 0x0090, + 0x9082, 0x0006, 0x1240, 0xb900, 0xd1fc, 0x0d88, 0x2001, 0x0029, + 0x2009, 0x1000, 0x0038, 0x2001, 0x0029, 0x900e, 0x0018, 0x2001, + 0x0029, 0x900e, 0x9005, 0x00be, 0x0005, 0x0126, 0x2091, 0x8000, + 0xb850, 0x900d, 0x0150, 0x2900, 0x0096, 0x2148, 0xa802, 0x009e, + 0xa803, 0x0000, 0xb852, 0x012e, 0x0005, 0x2900, 0xb852, 0xb84e, + 0xa803, 0x0000, 0x0cc0, 0x0126, 0x2091, 0x8000, 0xb84c, 0x9005, + 0x0170, 0x00e6, 0x2071, 0x19b6, 0x7004, 0x9086, 0x0002, 0x0168, + 0x00ee, 0xb84c, 0xa802, 0x2900, 0xb84e, 0x012e, 0x0005, 0x2900, + 0xb852, 0xb84e, 0xa803, 0x0000, 0x0cc0, 0x701c, 0x9b06, 0x1d80, + 0xb84c, 0x00a6, 0x2050, 0xb000, 0xa802, 0x2900, 0xb002, 0x00ae, + 0x00ee, 0x012e, 0x0005, 0x0126, 0x2091, 0x8000, 0xb84c, 0x904d, + 0x0130, 0xa800, 0x9005, 0x1108, 0xb852, 0xb84e, 0x9905, 0x012e, + 0x0005, 0xb84c, 0x904d, 0x0130, 0xa800, 0x9005, 0x1108, 0xb852, + 0xb84e, 0x9905, 0x0005, 0x00b6, 0x0126, 0x00c6, 0x0026, 0x2091, + 0x8000, 0x6210, 0x2258, 0xba00, 0x9005, 0x0110, 0xc285, 0x0008, + 0xc284, 0xba02, 0x002e, 0x00ce, 0x012e, 0x00be, 0x0005, 0x00b6, + 0x0126, 0x00c6, 0x2091, 0x8000, 0x6210, 0x2258, 0xba04, 0x0006, + 0x9086, 0x0006, 0x1170, 0xb89c, 0xd0ac, 0x0158, 0x080c, 0x62a0, + 0x0140, 0x9284, 0xff00, 0x8007, 0x9086, 0x0007, 0x1110, 0x2011, + 0x0600, 0x000e, 0x9294, 0xff00, 0x9215, 0xba06, 0x0006, 0x9086, + 0x0006, 0x1120, 0xba90, 0x82ff, 0x090c, 0x0db2, 0x000e, 0x00ce, + 0x012e, 0x00be, 0x0005, 0x00b6, 0x0126, 0x00c6, 0x2091, 0x8000, + 0x6210, 0x2258, 0xba04, 0x0006, 0x9086, 0x0006, 0x1168, 0xb89c, + 0xd0a4, 0x0150, 0x080c, 0x629c, 0x1138, 0x9284, 0x00ff, 0x9086, + 0x0007, 0x1110, 0x2011, 0x0006, 0x000e, 0x9294, 0x00ff, 0x8007, + 0x9215, 0xba06, 0x00ce, 0x012e, 0x00be, 0x0005, 0x9182, 0x0800, + 0x0218, 0x9085, 0x0001, 0x0005, 0x00d6, 0x0026, 0x9190, 0x1000, + 0x2204, 0x905d, 0x1180, 0x0096, 0x080c, 0x0fd5, 0x2958, 0x009e, + 0x0160, 0x2b00, 0x2012, 0xb85c, 0xb8ba, 0xb860, 0xb8b6, 0x9006, + 0xb8a6, 0x080c, 0x5a3b, 0x9006, 0x0010, 0x9085, 0x0001, 0x002e, + 0x00de, 0x0005, 0x00b6, 0x0096, 0x0126, 0x2091, 0x8000, 0x0026, + 0x9182, 0x0800, 0x0218, 0x9085, 0x0001, 0x0458, 0x00d6, 0x9190, + 0x1000, 0x2204, 0x905d, 0x0518, 0x2013, 0x0000, 0xb8a4, 0x904d, + 0x0110, 0x080c, 0x1007, 0x00d6, 0x00c6, 0xb8ac, 0x2060, 0x8cff, + 0x0168, 0x600c, 0x0006, 0x6014, 0x2048, 0x080c, 0xb5fb, 0x0110, + 0x080c, 0x0f87, 0x080c, 0x99d6, 0x00ce, 0x0c88, 0x00ce, 0x00de, + 0x2b48, 0xb8b8, 0xb85e, 0xb8b4, 0xb862, 0x080c, 0x1017, 0x00de, + 0x9006, 0x002e, 0x012e, 0x009e, 0x00be, 0x0005, 0x0016, 0x9182, + 0x0800, 0x0218, 0x9085, 0x0001, 0x0030, 0x9188, 0x1000, 0x2104, + 0x905d, 0x0dc0, 0x9006, 0x001e, 0x0005, 0x00d6, 0x0156, 0x0136, + 0x0146, 0x9006, 0xb80a, 0xb80e, 0xb800, 0xc08c, 0xb802, 0x080c, + 0x6c53, 0x1510, 0xb8a0, 0x9086, 0x007e, 0x0120, 0x080c, 0x9940, + 0x11d8, 0x0078, 0x7040, 0xd0e4, 0x01b8, 0x00c6, 0x2061, 0x1951, + 0x7048, 0x2062, 0x704c, 0x6006, 0x7050, 0x600a, 0x7054, 0x600e, + 0x00ce, 0x703c, 0x2069, 0x0140, 0x9005, 0x1110, 0x2001, 0x0001, + 0x6886, 0x2069, 0x1800, 0x68ae, 0x7040, 0xb85e, 0x7048, 0xb862, + 0x704c, 0xb866, 0x20e1, 0x0000, 0x2099, 0x0276, 0xb8b4, 0x20e8, + 0xb8b8, 0x9088, 0x000a, 0x21a0, 0x20a9, 0x0004, 0x4003, 0x2099, + 0x027a, 0x9088, 0x0006, 0x21a0, 0x20a9, 0x0004, 0x4003, 0x2069, + 0x0200, 0x6817, 0x0001, 0x7040, 0xb86a, 0x7144, 0xb96e, 0x7048, + 0xb872, 0x7050, 0xb876, 0x2069, 0x0200, 0x6817, 0x0000, 0xb8a0, + 0x9086, 0x007e, 0x1110, 0x7144, 0xb96e, 0x9182, 0x0211, 0x1218, + 0x2009, 0x0008, 0x0400, 0x9182, 0x0259, 0x1218, 0x2009, 0x0007, + 0x00d0, 0x9182, 0x02c1, 0x1218, 0x2009, 0x0006, 0x00a0, 0x9182, + 0x0349, 0x1218, 0x2009, 0x0005, 0x0070, 0x9182, 0x0421, 0x1218, + 0x2009, 0x0004, 0x0040, 0x9182, 0x0581, 0x1218, 0x2009, 0x0003, + 0x0010, 0x2009, 0x0002, 0xb992, 0x014e, 0x013e, 0x015e, 0x00de, + 0x0005, 0x0016, 0x0026, 0x00e6, 0x2071, 0x0260, 0x7034, 0xb896, + 0x703c, 0xb89a, 0x7054, 0xb89e, 0x0036, 0xbbbc, 0xc384, 0xba00, + 0x2009, 0x1873, 0x210c, 0xd0bc, 0x0120, 0xd1ec, 0x0110, 0xc2ad, + 0x0008, 0xc2ac, 0xd0c4, 0x0148, 0xd1e4, 0x0138, 0xc2bd, 0xd0cc, + 0x0128, 0xd38c, 0x1108, 0xc385, 0x0008, 0xc2bc, 0xba02, 0xbbbe, + 0x003e, 0x00ee, 0x002e, 0x001e, 0x0005, 0x0096, 0x0126, 0x2091, + 0x8000, 0xb8a4, 0x904d, 0x0578, 0xa900, 0x81ff, 0x15c0, 0xaa04, + 0x9282, 0x0010, 0x16c8, 0x0136, 0x0146, 0x01c6, 0x01d6, 0x8906, + 0x8006, 0x8007, 0x908c, 0x003f, 0x21e0, 0x9084, 0xffc0, 0x9080, + 0x0004, 0x2098, 0x2009, 0x0010, 0x20a9, 0x0001, 0x4002, 0x9086, + 0xffff, 0x0120, 0x8109, 0x1dd0, 0x080c, 0x0db2, 0x3c00, 0x20e8, + 0x3300, 0x8001, 0x20a0, 0x4604, 0x8210, 0xaa06, 0x01de, 0x01ce, + 0x014e, 0x013e, 0x0060, 0x080c, 0x0fd5, 0x0170, 0x2900, 0xb8a6, + 0xa803, 0x0000, 0x080c, 0x613a, 0xa807, 0x0001, 0xae12, 0x9085, + 0x0001, 0x012e, 0x009e, 0x0005, 0x9006, 0x0cd8, 0x0126, 0x2091, + 0x8000, 0x0096, 0xb8a4, 0x904d, 0x0188, 0xa800, 0x9005, 0x1150, + 0x080c, 0x6149, 0x1158, 0xa804, 0x908a, 0x0002, 0x0218, 0x8001, + 0xa806, 0x0020, 0x080c, 0x1007, 0xb8a7, 0x0000, 0x009e, 0x012e, + 0x0005, 0x0126, 0x2091, 0x8000, 0x080c, 0x801d, 0x012e, 0x0005, + 0x901e, 0x0010, 0x2019, 0x0001, 0x900e, 0x0126, 0x2091, 0x8000, + 0xb84c, 0x2048, 0xb800, 0xd0dc, 0x1170, 0x89ff, 0x0500, 0x83ff, + 0x0120, 0xa878, 0x9606, 0x0158, 0x0030, 0xa86c, 0x9406, 0x1118, + 0xa870, 0x9506, 0x0120, 0x2908, 0xa800, 0x2048, 0x0c70, 0x080c, + 0x933f, 0xaa00, 0xb84c, 0x9906, 0x1110, 0xba4e, 0x0020, 0x00a6, + 0x2150, 0xb202, 0x00ae, 0x82ff, 0x1110, 0xb952, 0x89ff, 0x012e, + 0x0005, 0x9016, 0x0489, 0x1110, 0x2011, 0x0001, 0x0005, 0x080c, + 0x619e, 0x0128, 0x080c, 0xb6c3, 0x0010, 0x9085, 0x0001, 0x0005, + 0x080c, 0x619e, 0x0128, 0x080c, 0xb65d, 0x0010, 0x9085, 0x0001, + 0x0005, 0x080c, 0x619e, 0x0128, 0x080c, 0xb6c0, 0x0010, 0x9085, + 0x0001, 0x0005, 0x080c, 0x619e, 0x0128, 0x080c, 0xb681, 0x0010, + 0x9085, 0x0001, 0x0005, 0x080c, 0x619e, 0x0128, 0x080c, 0xb6ed, + 0x0010, 0x9085, 0x0001, 0x0005, 0xb8a4, 0x900d, 0x1118, 0x9085, + 0x0001, 0x0005, 0x0136, 0x01c6, 0xa800, 0x9005, 0x11b8, 0x890e, + 0x810e, 0x810f, 0x9184, 0x003f, 0x20e0, 0x9184, 0xffc0, 0x9080, + 0x0004, 0x2098, 0x20a9, 0x0001, 0x2009, 0x0010, 0x4002, 0x9606, + 0x0128, 0x8109, 0x1dd8, 0x9085, 0x0001, 0x0008, 0x9006, 0x01ce, + 0x013e, 0x0005, 0x0146, 0x01d6, 0xa860, 0x20e8, 0xa85c, 0x9080, + 0x0004, 0x20a0, 0x20a9, 0x0010, 0x2009, 0xffff, 0x4104, 0x01de, + 0x014e, 0x0136, 0x01c6, 0xa800, 0x9005, 0x11b8, 0x890e, 0x810e, + 0x810f, 0x9184, 0x003f, 0x20e0, 0x9184, 0xffc0, 0x9080, 0x0004, + 0x2098, 0x20a9, 0x0001, 0x2009, 0x0010, 0x4002, 0x9606, 0x0128, + 0x8109, 0x1dd8, 0x9085, 0x0001, 0x0068, 0x0146, 0x01d6, 0x3300, + 0x8001, 0x20a0, 0x3c00, 0x20e8, 0x2001, 0xffff, 0x4004, 0x01de, + 0x014e, 0x9006, 0x01ce, 0x013e, 0x0005, 0x0096, 0x0126, 0x2091, + 0x8000, 0xb8a4, 0x904d, 0x1128, 0x080c, 0x0fd5, 0x0168, 0x2900, + 0xb8a6, 0x080c, 0x613a, 0xa803, 0x0001, 0xa807, 0x0000, 0x9085, + 0x0001, 0x012e, 0x009e, 0x0005, 0x9006, 0x0cd8, 0x0096, 0x0126, + 0x2091, 0x8000, 0xb8a4, 0x904d, 0x0130, 0xb8a7, 0x0000, 0x080c, + 0x1007, 0x9085, 0x0001, 0x012e, 0x009e, 0x0005, 0xb89c, 0xd0a4, + 0x0005, 0x00b6, 0x00f6, 0x080c, 0x6c53, 0x01b0, 0x71bc, 0x81ff, + 0x1198, 0x71d4, 0xd19c, 0x0180, 0x2001, 0x007e, 0x9080, 0x1000, + 0x2004, 0x905d, 0x0148, 0xb804, 0x9084, 0x00ff, 0x9086, 0x0006, + 0x1118, 0xb800, 0xc0ed, 0xb802, 0x2079, 0x1853, 0x7804, 0xd0a4, + 0x01d0, 0x0156, 0x20a9, 0x007f, 0x900e, 0x0016, 0x080c, 0x5f7e, + 0x1168, 0xb804, 0x9084, 0xff00, 0x8007, 0x9096, 0x0004, 0x0118, + 0x9086, 0x0006, 0x1118, 0xb800, 0xc0ed, 0xb802, 0x001e, 0x8108, + 0x1f04, 0x61c5, 0x015e, 0x080c, 0x6262, 0x0120, 0x2001, 0x1954, + 0x200c, 0x0038, 0x2079, 0x1853, 0x7804, 0xd0a4, 0x0130, 0x2009, + 0x07d0, 0x2011, 0x61f0, 0x080c, 0x7cd9, 0x00fe, 0x00be, 0x0005, + 0x00b6, 0x2011, 0x61f0, 0x080c, 0x7c4a, 0x080c, 0x6262, 0x01d8, + 0x2001, 0x107e, 0x2004, 0x2058, 0xb900, 0xc1ec, 0xb902, 0x080c, + 0x62a0, 0x0130, 0x2009, 0x07d0, 0x2011, 0x61f0, 0x080c, 0x7cd9, + 0x00e6, 0x2071, 0x1800, 0x9006, 0x7076, 0x7058, 0x707a, 0x080c, + 0x2c2b, 0x00ee, 0x04b0, 0x0156, 0x00c6, 0x20a9, 0x007f, 0x900e, + 0x0016, 0x080c, 0x5f7e, 0x1538, 0xb800, 0xd0ec, 0x0520, 0x0046, + 0xbaa0, 0x2220, 0x9006, 0x2009, 0x0029, 0x080c, 0xcfe6, 0xb800, + 0xc0e5, 0xc0ec, 0xb802, 0x080c, 0x629c, 0x2001, 0x0707, 0x1128, + 0xb804, 0x9084, 0x00ff, 0x9085, 0x0700, 0xb806, 0x2019, 0x0029, + 0x080c, 0x8180, 0x0076, 0x903e, 0x080c, 0x8078, 0x900e, 0x080c, + 0xcd62, 0x007e, 0x004e, 0x001e, 0x8108, 0x1f04, 0x6218, 0x00ce, + 0x015e, 0x00be, 0x0005, 0x00b6, 0x6010, 0x2058, 0xb800, 0xc0ec, + 0xb802, 0x00be, 0x0005, 0x7810, 0x00b6, 0x2058, 0xb800, 0x00be, + 0xd0ac, 0x0005, 0x6010, 0x00b6, 0x905d, 0x0108, 0xb800, 0x00be, + 0xd0bc, 0x0005, 0x00b6, 0x00f6, 0x2001, 0x107e, 0x2004, 0x905d, + 0x0110, 0xb800, 0xd0ec, 0x00fe, 0x00be, 0x0005, 0x0126, 0x0026, + 0x2091, 0x8000, 0x0006, 0xbaa0, 0x9290, 0x1000, 0x2204, 0x9b06, + 0x190c, 0x0db2, 0x000e, 0xba00, 0x9005, 0x0110, 0xc2fd, 0x0008, + 0xc2fc, 0xba02, 0x002e, 0x012e, 0x0005, 0x2011, 0x1835, 0x2204, + 0xd0cc, 0x0138, 0x2001, 0x1952, 0x200c, 0x2011, 0x6292, 0x080c, + 0x7cd9, 0x0005, 0x2011, 0x6292, 0x080c, 0x7c4a, 0x2011, 0x1835, + 0x2204, 0xc0cc, 0x2012, 0x0005, 0x080c, 0x5113, 0xd0ac, 0x0005, + 0x080c, 0x5113, 0xd0a4, 0x0005, 0x0016, 0xb904, 0x9184, 0x00ff, + 0x908e, 0x0006, 0x001e, 0x0005, 0x0016, 0xb904, 0x9184, 0xff00, + 0x8007, 0x908e, 0x0006, 0x001e, 0x0005, 0x00b6, 0x00f6, 0x080c, + 0xbcec, 0x0158, 0x70d4, 0x9084, 0x0028, 0x0138, 0x2001, 0x107f, + 0x2004, 0x905d, 0x0110, 0xb8bc, 0xd094, 0x00fe, 0x00be, 0x0005, + 0x2071, 0x1906, 0x7003, 0x0001, 0x7007, 0x0000, 0x9006, 0x7012, + 0x7016, 0x701a, 0x701e, 0x700a, 0x7046, 0x2001, 0x1919, 0x2003, + 0x0000, 0x0005, 0x0016, 0x00e6, 0x2071, 0x191a, 0x900e, 0x710a, + 0x080c, 0x5113, 0xd0fc, 0x1140, 0x080c, 0x5113, 0x900e, 0xd09c, + 0x0108, 0x8108, 0x7102, 0x00f8, 0x2001, 0x1873, 0x200c, 0x9184, + 0x0007, 0x0002, 0x62e4, 0x62e4, 0x62e4, 0x62e4, 0x62e4, 0x62fa, + 0x6308, 0x62e4, 0x7003, 0x0003, 0x2009, 0x1874, 0x210c, 0x9184, + 0xff00, 0x8007, 0x9005, 0x1110, 0x2001, 0x0002, 0x7006, 0x0018, + 0x7003, 0x0005, 0x0c88, 0x00ee, 0x001e, 0x0005, 0x00e6, 0x2071, + 0x0050, 0x684c, 0x9005, 0x1150, 0x00e6, 0x2071, 0x1906, 0x7028, + 0xc085, 0x702a, 0x00ee, 0x9085, 0x0001, 0x0488, 0x6844, 0x9005, + 0x0158, 0x080c, 0x6f9c, 0x6a60, 0x9200, 0x7002, 0x6864, 0x9101, + 0x7006, 0x9006, 0x7012, 0x7016, 0x6860, 0x7002, 0x6864, 0x7006, + 0x6868, 0x700a, 0x686c, 0x700e, 0x6844, 0x9005, 0x1110, 0x7012, + 0x7016, 0x684c, 0x701a, 0x701c, 0x9085, 0x0040, 0x701e, 0x7037, + 0x0019, 0x702b, 0x0001, 0x00e6, 0x2071, 0x1906, 0x7028, 0xc084, + 0x702a, 0x7007, 0x0001, 0x700b, 0x0000, 0x00ee, 0x9006, 0x00ee, + 0x0005, 0xa868, 0xd0fc, 0x11d8, 0x00e6, 0x0026, 0x2001, 0x191a, + 0x2004, 0x9005, 0x0904, 0x653b, 0xa87c, 0xd0bc, 0x1904, 0x653b, + 0xa978, 0xa874, 0x9105, 0x1904, 0x653b, 0x2001, 0x191a, 0x2004, + 0x0002, 0x653b, 0x6394, 0x63d0, 0x63d0, 0x653b, 0x63d0, 0x0005, + 0xa868, 0xd0fc, 0x1500, 0x00e6, 0x0026, 0x2009, 0x191a, 0x210c, + 0x81ff, 0x0904, 0x653b, 0xa87c, 0xd0cc, 0x0904, 0x653b, 0xa880, + 0x9084, 0x00ff, 0x9086, 0x0001, 0x1904, 0x653b, 0x9186, 0x0003, + 0x0904, 0x63d0, 0x9186, 0x0005, 0x0904, 0x63d0, 0xa84f, 0x8021, + 0xa853, 0x0017, 0x0028, 0x0005, 0xa84f, 0x8020, 0xa853, 0x0016, + 0x2071, 0x1906, 0x701c, 0x9005, 0x1904, 0x66fb, 0x0e04, 0x6746, + 0x2071, 0x0000, 0xa84c, 0x7082, 0xa850, 0x7032, 0xa86c, 0x7086, + 0x7036, 0xa870, 0x708a, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004, + 0xd084, 0x190c, 0x1167, 0x2071, 0x1800, 0x2011, 0x0001, 0xa804, + 0x900d, 0x702c, 0x1158, 0xa802, 0x2900, 0x702e, 0x70b8, 0x9200, + 0x70ba, 0x080c, 0x7b7c, 0x002e, 0x00ee, 0x0005, 0x0096, 0x2148, + 0xa904, 0xa802, 0x8210, 0x2900, 0x81ff, 0x1dc8, 0x009e, 0x0c58, + 0xa84f, 0x0000, 0x00f6, 0x2079, 0x0050, 0x2071, 0x1906, 0xa803, + 0x0000, 0x7010, 0x9005, 0x1904, 0x64bf, 0x782c, 0x908c, 0x0780, + 0x190c, 0x686d, 0x8004, 0x8004, 0x8004, 0x9084, 0x0003, 0x0002, + 0x63ee, 0x64bf, 0x6413, 0x645a, 0x080c, 0x0db2, 0x2071, 0x1800, + 0x2900, 0x7822, 0xa804, 0x900d, 0x1170, 0x2071, 0x19c9, 0x703c, + 0x9005, 0x1328, 0x2001, 0x191b, 0x2004, 0x8005, 0x703e, 0x00fe, + 0x002e, 0x00ee, 0x0005, 0x9016, 0x702c, 0x2148, 0xa904, 0xa802, + 0x8210, 0x2900, 0x81ff, 0x1dc8, 0x702e, 0x70b8, 0x9200, 0x70ba, + 0x080c, 0x7b7c, 0x0c10, 0x2071, 0x1800, 0x2900, 0x7822, 0xa804, + 0x900d, 0x1580, 0x7824, 0x00e6, 0x2071, 0x0040, 0x712c, 0xd19c, + 0x1148, 0x2009, 0x182e, 0x210c, 0x918a, 0x0040, 0x0218, 0x7022, + 0x00ee, 0x0058, 0x00ee, 0x2048, 0x702c, 0xa802, 0x2900, 0x702e, + 0x70b8, 0x8000, 0x70ba, 0x080c, 0x7b7c, 0x782c, 0x9094, 0x0780, + 0x190c, 0x686d, 0xd0a4, 0x19f0, 0x2071, 0x19c9, 0x703c, 0x9005, + 0x1328, 0x2001, 0x191b, 0x2004, 0x8005, 0x703e, 0x00fe, 0x002e, + 0x00ee, 0x0005, 0x9016, 0x702c, 0x2148, 0xa904, 0xa802, 0x8210, + 0x2900, 0x81ff, 0x1dc8, 0x702e, 0x70b8, 0x9200, 0x70ba, 0x080c, + 0x7b7c, 0x0800, 0x0096, 0x00e6, 0x7824, 0x2048, 0x2071, 0x1800, + 0x702c, 0xa802, 0x2900, 0x702e, 0x70b8, 0x8000, 0x70ba, 0x080c, + 0x7b7c, 0x782c, 0x9094, 0x0780, 0x190c, 0x686d, 0xd0a4, 0x1d60, + 0x00ee, 0x782c, 0x9094, 0x0780, 0x190c, 0x686d, 0xd09c, 0x11a0, + 0x009e, 0x2900, 0x7822, 0xa804, 0x900d, 0x1560, 0x2071, 0x19c9, + 0x703c, 0x9005, 0x1328, 0x2001, 0x191b, 0x2004, 0x8005, 0x703e, + 0x00fe, 0x002e, 0x00ee, 0x0005, 0x009e, 0x2908, 0x7010, 0x8000, + 0x7012, 0x7018, 0x904d, 0x711a, 0x0110, 0xa902, 0x0008, 0x711e, + 0x2148, 0xa804, 0x900d, 0x1170, 0x2071, 0x19c9, 0x703c, 0x9005, + 0x1328, 0x2001, 0x191b, 0x2004, 0x8005, 0x703e, 0x00fe, 0x002e, + 0x00ee, 0x0005, 0x2071, 0x1800, 0x9016, 0x702c, 0x2148, 0xa904, + 0xa802, 0x8210, 0x2900, 0x81ff, 0x1dc8, 0x702e, 0x70b8, 0x9200, + 0x70ba, 0x080c, 0x7b7c, 0x00fe, 0x002e, 0x00ee, 0x0005, 0x2908, + 0x7010, 0x8000, 0x7012, 0x7018, 0x904d, 0x711a, 0x0110, 0xa902, + 0x0008, 0x711e, 0x2148, 0xa804, 0x900d, 0x1904, 0x6514, 0x782c, + 0x9094, 0x0780, 0x190c, 0x686d, 0xd09c, 0x1198, 0x701c, 0x904d, + 0x0180, 0x7010, 0x8001, 0x7012, 0x1108, 0x701a, 0xa800, 0x701e, + 0x2900, 0x7822, 0x782c, 0x9094, 0x0780, 0x190c, 0x686d, 0xd09c, + 0x0d68, 0x782c, 0x9094, 0x0780, 0x190c, 0x686d, 0xd0a4, 0x01b0, + 0x00e6, 0x7824, 0x2048, 0x2071, 0x1800, 0x702c, 0xa802, 0x2900, + 0x702e, 0x70b8, 0x8000, 0x70ba, 0x080c, 0x7b7c, 0x782c, 0x9094, + 0x0780, 0x190c, 0x686d, 0xd0a4, 0x1d60, 0x00ee, 0x2071, 0x19c9, + 0x703c, 0x9005, 0x1328, 0x2001, 0x191b, 0x2004, 0x8005, 0x703e, + 0x00fe, 0x002e, 0x00ee, 0x0005, 0x00e6, 0x2071, 0x1800, 0x9016, + 0x702c, 0x2148, 0xa904, 0xa802, 0x8210, 0x2900, 0x81ff, 0x1dc8, + 0x702e, 0x70b8, 0x9200, 0x70ba, 0x080c, 0x7b7c, 0x00ee, 0x0804, + 0x64cf, 0xa868, 0xd0fc, 0x1904, 0x6577, 0x0096, 0xa804, 0xa807, + 0x0000, 0x904d, 0x190c, 0x0f87, 0x009e, 0x0018, 0xa868, 0xd0fc, + 0x15f0, 0x00e6, 0x0026, 0xa84f, 0x0000, 0x00f6, 0x2079, 0x0050, + 0x2071, 0x1800, 0x70e4, 0x8001, 0x01d0, 0x1678, 0x2071, 0x1906, + 0xa803, 0x0000, 0x7010, 0x9005, 0x1904, 0x6675, 0x782c, 0x908c, + 0x0780, 0x190c, 0x686d, 0x8004, 0x8004, 0x8004, 0x9084, 0x0003, + 0x0002, 0x6578, 0x6675, 0x6593, 0x6604, 0x080c, 0x0db2, 0x70e7, + 0x0fa0, 0x71e0, 0x8107, 0x9106, 0x9094, 0x00c0, 0x9184, 0xff3f, + 0x9205, 0x70e2, 0x3b08, 0x3a00, 0x9104, 0x918d, 0x00c0, 0x21d8, + 0x9084, 0xff3f, 0x9205, 0x20d0, 0x0888, 0x70e6, 0x0878, 0x0005, + 0x2071, 0x1800, 0x2900, 0x7822, 0xa804, 0x900d, 0x1120, 0x00fe, + 0x002e, 0x00ee, 0x0005, 0x9016, 0x702c, 0x2148, 0xa904, 0xa802, + 0x8210, 0x2900, 0x81ff, 0x1dc8, 0x702e, 0x70b8, 0x9200, 0x70ba, + 0x080c, 0x7b7c, 0x0c60, 0x2071, 0x1800, 0x2900, 0x7822, 0xa804, + 0x900d, 0x1904, 0x65f3, 0x7830, 0x8007, 0x9084, 0x001f, 0x9082, + 0x0005, 0x1220, 0x00fe, 0x002e, 0x00ee, 0x0005, 0x7824, 0x00e6, + 0x2071, 0x0040, 0x712c, 0xd19c, 0x1148, 0x2009, 0x182e, 0x210c, + 0x918a, 0x0040, 0x0218, 0x7022, 0x00ee, 0x0058, 0x00ee, 0x2048, + 0x702c, 0xa802, 0x2900, 0x702e, 0x70b8, 0x8000, 0x70ba, 0x080c, + 0x7b7c, 0x782c, 0x9094, 0x0780, 0x190c, 0x686d, 0xd0a4, 0x19f0, + 0x0e04, 0x65ea, 0x7838, 0x7938, 0x910e, 0x1de0, 0x00d6, 0x2069, + 0x0000, 0x6836, 0x6833, 0x0013, 0x00de, 0x2001, 0x1917, 0x200c, + 0xc184, 0x2102, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004, 0xd084, + 0x190c, 0x1167, 0x2009, 0x1919, 0x200b, 0x0000, 0x00fe, 0x002e, + 0x00ee, 0x0005, 0x2001, 0x1917, 0x200c, 0xc185, 0x2102, 0x00fe, + 0x002e, 0x00ee, 0x0005, 0x9016, 0x702c, 0x2148, 0xa904, 0xa802, + 0x8210, 0x2900, 0x81ff, 0x1dc8, 0x702e, 0x70b8, 0x9200, 0x70ba, + 0x080c, 0x7b7c, 0x0804, 0x65a6, 0x0096, 0x00e6, 0x7824, 0x2048, + 0x2071, 0x1800, 0x702c, 0xa802, 0x2900, 0x702e, 0x70b8, 0x8000, + 0x70ba, 0x080c, 0x7b7c, 0x782c, 0x9094, 0x0780, 0x190c, 0x686d, + 0xd0a4, 0x1d60, 0x00ee, 0x0e04, 0x6648, 0x7838, 0x7938, 0x910e, + 0x1de0, 0x00d6, 0x2069, 0x0000, 0x6836, 0x6833, 0x0013, 0x00de, + 0x7044, 0xc084, 0x7046, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004, + 0xd084, 0x190c, 0x1167, 0x2009, 0x1919, 0x200b, 0x0000, 0x782c, + 0x9094, 0x0780, 0x190c, 0x686d, 0xd09c, 0x1170, 0x009e, 0x2900, + 0x7822, 0xa804, 0x900d, 0x11e0, 0x00fe, 0x002e, 0x00ee, 0x0005, + 0x7044, 0xc085, 0x7046, 0x0c58, 0x009e, 0x2908, 0x7010, 0x8000, + 0x7012, 0x7018, 0x904d, 0x711a, 0x0110, 0xa902, 0x0008, 0x711e, + 0x2148, 0xa804, 0x900d, 0x1120, 0x00fe, 0x002e, 0x00ee, 0x0005, + 0x2071, 0x1800, 0x9016, 0x702c, 0x2148, 0xa904, 0xa802, 0x8210, + 0x2900, 0x81ff, 0x1dc8, 0x702e, 0x70b8, 0x9200, 0x70ba, 0x080c, + 0x7b7c, 0x00fe, 0x002e, 0x00ee, 0x0005, 0x2908, 0x7010, 0x8000, + 0x7012, 0x7018, 0x904d, 0x711a, 0x0110, 0xa902, 0x0008, 0x711e, + 0x2148, 0xa804, 0x900d, 0x1904, 0x66e6, 0x782c, 0x9094, 0x0780, + 0x190c, 0x686d, 0xd09c, 0x11b0, 0x701c, 0x904d, 0x0198, 0xa84c, + 0x9005, 0x1180, 0x7010, 0x8001, 0x7012, 0x1108, 0x701a, 0xa800, + 0x701e, 0x2900, 0x7822, 0x782c, 0x9094, 0x0780, 0x190c, 0x686d, + 0xd09c, 0x0d50, 0x782c, 0x9094, 0x0780, 0x190c, 0x686d, 0xd0a4, + 0x05c8, 0x00e6, 0x7824, 0x2048, 0x2071, 0x1800, 0x702c, 0xa802, + 0x2900, 0x702e, 0x70b8, 0x8000, 0x70ba, 0x080c, 0x7b7c, 0x782c, + 0x9094, 0x0780, 0x190c, 0x686d, 0xd0a4, 0x1d60, 0x00ee, 0x0e04, + 0x66df, 0x7838, 0x7938, 0x910e, 0x1de0, 0x00d6, 0x2069, 0x0000, + 0x6836, 0x6833, 0x0013, 0x00de, 0x7044, 0xc084, 0x7046, 0x2091, + 0x4080, 0x2001, 0x0089, 0x2004, 0xd084, 0x190c, 0x1167, 0x2009, + 0x1919, 0x200b, 0x0000, 0x00fe, 0x002e, 0x00ee, 0x0005, 0x7044, + 0xc085, 0x7046, 0x00fe, 0x002e, 0x00ee, 0x0005, 0x00e6, 0x2071, + 0x1800, 0x9016, 0x702c, 0x2148, 0xa904, 0xa802, 0x8210, 0x2900, + 0x81ff, 0x1dc8, 0x702e, 0x70b8, 0x9200, 0x70ba, 0x080c, 0x7b7c, + 0x00ee, 0x0804, 0x6685, 0x2071, 0x1906, 0xa803, 0x0000, 0x2908, + 0x7010, 0x8000, 0x7012, 0x7018, 0x904d, 0x711a, 0x0110, 0xa902, + 0x0008, 0x711e, 0x2148, 0xa804, 0x900d, 0x1128, 0x1e04, 0x6726, + 0x002e, 0x00ee, 0x0005, 0x2071, 0x1800, 0x9016, 0x702c, 0x2148, + 0xa904, 0xa802, 0x8210, 0x2900, 0x81ff, 0x1dc8, 0x702e, 0x70b8, + 0x9200, 0x70ba, 0x080c, 0x7b7c, 0x0e04, 0x6710, 0x2071, 0x1906, + 0x701c, 0x2048, 0xa84c, 0x900d, 0x0d18, 0x2071, 0x0000, 0x7182, + 0xa850, 0x7032, 0xa86c, 0x7086, 0x7036, 0xa870, 0x708a, 0x2091, + 0x4080, 0x2001, 0x0089, 0x2004, 0xd084, 0x190c, 0x1167, 0x2071, + 0x1906, 0x080c, 0x6859, 0x002e, 0x00ee, 0x0005, 0x2071, 0x1906, + 0xa803, 0x0000, 0x2908, 0x7010, 0x8000, 0x7012, 0x7018, 0x904d, + 0x711a, 0x0110, 0xa902, 0x0008, 0x711e, 0x2148, 0xa804, 0x900d, + 0x1118, 0x002e, 0x00ee, 0x0005, 0x2071, 0x1800, 0x9016, 0x702c, + 0x2148, 0xa904, 0xa802, 0x8210, 0x2900, 0x81ff, 0x1dc8, 0x702e, + 0x70b8, 0x9200, 0x70ba, 0x080c, 0x7b7c, 0x002e, 0x00ee, 0x0005, + 0x0006, 0xa87c, 0x0006, 0xa867, 0x0103, 0x20a9, 0x001c, 0xa860, + 0x20e8, 0xa85c, 0x9080, 0x001d, 0x20a0, 0x9006, 0x4004, 0x000e, + 0x9084, 0x00ff, 0xa87e, 0x000e, 0xa87a, 0xa982, 0x0005, 0x2071, + 0x1906, 0x7004, 0x0002, 0x6791, 0x6792, 0x6858, 0x6792, 0x0db2, + 0x6858, 0x0005, 0x2001, 0x191a, 0x2004, 0x0002, 0x679c, 0x679c, + 0x67f1, 0x67f2, 0x679c, 0x67f2, 0x0126, 0x2091, 0x8000, 0x1e0c, + 0x6878, 0x701c, 0x904d, 0x01e0, 0xa84c, 0x9005, 0x01d8, 0x0e04, + 0x67c0, 0xa94c, 0x2071, 0x0000, 0x7182, 0xa850, 0x7032, 0xa86c, + 0x7086, 0x7036, 0xa870, 0x708a, 0x2091, 0x4080, 0x2001, 0x0089, + 0x2004, 0xd084, 0x190c, 0x1167, 0x2071, 0x1906, 0x080c, 0x6859, + 0x012e, 0x0470, 0x2001, 0x005b, 0x2004, 0x9094, 0x0780, 0x190c, + 0x686d, 0xd09c, 0x2071, 0x1906, 0x1510, 0x2071, 0x1906, 0x700f, + 0x0001, 0xa964, 0x9184, 0x00ff, 0x9086, 0x0003, 0x1130, 0x810f, + 0x918c, 0x00ff, 0x8101, 0x0108, 0x710e, 0x2900, 0x00d6, 0x2069, + 0x0050, 0x6822, 0x00de, 0x2071, 0x1906, 0x701c, 0x2048, 0x7010, + 0x8001, 0x7012, 0xa800, 0x701e, 0x9005, 0x1108, 0x701a, 0x012e, + 0x0005, 0x0005, 0x00d6, 0x2008, 0x2069, 0x19c9, 0x683c, 0x9005, + 0x0760, 0x0158, 0x9186, 0x0003, 0x0540, 0x2001, 0x1813, 0x2004, + 0x2009, 0x1a8b, 0x210c, 0x9102, 0x1500, 0x0126, 0x2091, 0x8000, + 0x2069, 0x0050, 0x693c, 0x6838, 0x9106, 0x0190, 0x0e04, 0x6824, + 0x2069, 0x0000, 0x6837, 0x8040, 0x6833, 0x0012, 0x6883, 0x8040, + 0x2091, 0x4080, 0x2001, 0x0089, 0x2004, 0xd084, 0x190c, 0x1167, + 0x2069, 0x19c9, 0x683f, 0xffff, 0x012e, 0x00de, 0x0126, 0x2091, + 0x8000, 0x1e0c, 0x68e9, 0x701c, 0x904d, 0x0540, 0x2001, 0x005b, + 0x2004, 0x9094, 0x0780, 0x15c9, 0xd09c, 0x1500, 0x2071, 0x1906, + 0x700f, 0x0001, 0xa964, 0x9184, 0x00ff, 0x9086, 0x0003, 0x1130, + 0x810f, 0x918c, 0x00ff, 0x8101, 0x0108, 0x710e, 0x2900, 0x00d6, + 0x2069, 0x0050, 0x6822, 0x00de, 0x701c, 0x2048, 0x7010, 0x8001, + 0x7012, 0xa800, 0x701e, 0x9005, 0x1108, 0x701a, 0x012e, 0x0005, + 0x0005, 0x0126, 0x2091, 0x8000, 0x701c, 0x904d, 0x0160, 0x7010, + 0x8001, 0x7012, 0xa800, 0x701e, 0x9005, 0x1108, 0x701a, 0x012e, + 0x080c, 0x1007, 0x0005, 0x012e, 0x0005, 0x2091, 0x8000, 0x0e04, + 0x686f, 0x0006, 0x0016, 0x2001, 0x8004, 0x0006, 0x0804, 0x0dbb, + 0x0096, 0x00f6, 0x2079, 0x0050, 0x7044, 0xd084, 0x01e0, 0xc084, + 0x7046, 0x7838, 0x7938, 0x910e, 0x1de0, 0x00d6, 0x2069, 0x0000, + 0x6836, 0x6833, 0x0013, 0x00de, 0x2091, 0x4080, 0x2001, 0x0089, + 0x2004, 0xd084, 0x190c, 0x1167, 0x2009, 0x1919, 0x200b, 0x0000, + 0x00fe, 0x009e, 0x0005, 0x782c, 0x9094, 0x0780, 0x1971, 0xd0a4, + 0x0db8, 0x2009, 0x1919, 0x2104, 0x8000, 0x200a, 0x9082, 0x000f, + 0x0e78, 0x00e6, 0x2071, 0x1800, 0x7824, 0x00e6, 0x2071, 0x0040, + 0x712c, 0xd19c, 0x1148, 0x2009, 0x182e, 0x210c, 0x918a, 0x0040, + 0x0218, 0x7022, 0x00ee, 0x0058, 0x00ee, 0x2048, 0x702c, 0xa802, + 0x2900, 0x702e, 0x70b8, 0x8000, 0x70ba, 0x080c, 0x7b7c, 0x782c, + 0x9094, 0x0780, 0x190c, 0x686d, 0xd0a4, 0x19f0, 0x7838, 0x7938, + 0x910e, 0x1de0, 0x00d6, 0x2069, 0x0000, 0x6836, 0x6833, 0x0013, + 0x00de, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004, 0xd084, 0x190c, + 0x1167, 0x2009, 0x1919, 0x200b, 0x0000, 0x00ee, 0x00fe, 0x009e, + 0x0005, 0x00f6, 0x2079, 0x0050, 0x7044, 0xd084, 0x01b8, 0xc084, + 0x7046, 0x7838, 0x7938, 0x910e, 0x1de0, 0x00d6, 0x2069, 0x0000, + 0x6836, 0x6833, 0x0013, 0x00de, 0x2091, 0x4080, 0x2001, 0x0089, + 0x2004, 0xd084, 0x190c, 0x1167, 0x00fe, 0x0005, 0x782c, 0x9094, + 0x0780, 0x190c, 0x686d, 0xd0a4, 0x0db8, 0x00e6, 0x2071, 0x1800, + 0x7824, 0x2048, 0x702c, 0xa802, 0x2900, 0x702e, 0x70b8, 0x8000, + 0x70ba, 0x080c, 0x7b7c, 0x782c, 0x9094, 0x0780, 0x190c, 0x686d, + 0xd0a4, 0x1d70, 0x00d6, 0x2069, 0x0050, 0x693c, 0x2069, 0x191a, + 0x6808, 0x690a, 0x2069, 0x19c9, 0x9102, 0x1118, 0x683c, 0x9005, + 0x1328, 0x2001, 0x191b, 0x200c, 0x810d, 0x693e, 0x00de, 0x00ee, + 0x00fe, 0x0005, 0x7090, 0x908a, 0x0029, 0x1a0c, 0x0db2, 0x9082, + 0x001d, 0x001b, 0x6027, 0x1e00, 0x0005, 0x6a0d, 0x6997, 0x69b3, + 0x69db, 0x69fc, 0x6a3c, 0x6a4e, 0x69b3, 0x6a24, 0x6952, 0x6980, + 0x6951, 0x0005, 0x00d6, 0x2069, 0x0200, 0x6804, 0x9005, 0x1180, + 0x6808, 0x9005, 0x1518, 0x7093, 0x0028, 0x2069, 0x195e, 0x2d04, + 0x7002, 0x080c, 0x6d8d, 0x6028, 0x9085, 0x0600, 0x602a, 0x00b0, + 0x7093, 0x0028, 0x2069, 0x195e, 0x2d04, 0x7002, 0x6028, 0x9085, + 0x0600, 0x602a, 0x00e6, 0x0036, 0x0046, 0x0056, 0x2071, 0x1a31, + 0x080c, 0x1872, 0x005e, 0x004e, 0x003e, 0x00ee, 0x00de, 0x0005, + 0x00d6, 0x2069, 0x0200, 0x6804, 0x9005, 0x1178, 0x6808, 0x9005, + 0x1160, 0x7093, 0x0028, 0x2069, 0x195e, 0x2d04, 0x7002, 0x080c, + 0x6e17, 0x6028, 0x9085, 0x0600, 0x602a, 0x00de, 0x0005, 0x0006, + 0x2001, 0x0090, 0x080c, 0x2987, 0x000e, 0x6124, 0xd1e4, 0x1190, + 0x080c, 0x6abb, 0xd1d4, 0x1160, 0xd1dc, 0x1138, 0xd1cc, 0x0150, + 0x7093, 0x0020, 0x080c, 0x6abb, 0x0028, 0x7093, 0x001d, 0x0010, + 0x7093, 0x001f, 0x0005, 0x2001, 0x0088, 0x080c, 0x2987, 0x6124, + 0xd1cc, 0x11d8, 0xd1dc, 0x11b0, 0xd1e4, 0x1188, 0x9184, 0x1e00, + 0x11c8, 0x60e3, 0x0001, 0x600c, 0xc0b4, 0x600e, 0x080c, 0x6c7f, + 0x2001, 0x0080, 0x080c, 0x2987, 0x7093, 0x0028, 0x0058, 0x7093, + 0x001e, 0x0040, 0x7093, 0x001d, 0x0028, 0x7093, 0x0020, 0x0010, + 0x7093, 0x001f, 0x0005, 0x60e3, 0x0001, 0x600c, 0xc0b4, 0x600e, + 0x080c, 0x6c7f, 0x2001, 0x0080, 0x080c, 0x2987, 0x6124, 0xd1d4, + 0x1180, 0xd1dc, 0x1158, 0xd1e4, 0x1130, 0x9184, 0x1e00, 0x1158, + 0x7093, 0x0028, 0x0040, 0x7093, 0x001e, 0x0028, 0x7093, 0x001d, + 0x0010, 0x7093, 0x001f, 0x0005, 0x2001, 0x00a0, 0x080c, 0x2987, + 0x6124, 0xd1dc, 0x1138, 0xd1e4, 0x0138, 0x080c, 0x189c, 0x7093, + 0x001e, 0x0010, 0x7093, 0x001d, 0x0005, 0x080c, 0x6b3e, 0x6124, + 0xd1dc, 0x1188, 0x080c, 0x6abb, 0x0016, 0x080c, 0x189c, 0x001e, + 0xd1d4, 0x1128, 0xd1e4, 0x0138, 0x7093, 0x001e, 0x0020, 0x7093, + 0x001f, 0x080c, 0x6abb, 0x0005, 0x0006, 0x2001, 0x00a0, 0x080c, + 0x2987, 0x000e, 0x6124, 0xd1d4, 0x1160, 0xd1cc, 0x1150, 0xd1dc, + 0x1128, 0xd1e4, 0x0140, 0x7093, 0x001e, 0x0028, 0x7093, 0x001d, + 0x0010, 0x7093, 0x0021, 0x0005, 0x080c, 0x6b3e, 0x6124, 0xd1d4, + 0x1150, 0xd1dc, 0x1128, 0xd1e4, 0x0140, 0x7093, 0x001e, 0x0028, + 0x7093, 0x001d, 0x0010, 0x7093, 0x001f, 0x0005, 0x0006, 0x2001, + 0x0090, 0x080c, 0x2987, 0x000e, 0x6124, 0xd1d4, 0x1178, 0xd1cc, + 0x1150, 0xd1dc, 0x1128, 0xd1e4, 0x0158, 0x7093, 0x001e, 0x0040, + 0x7093, 0x001d, 0x0028, 0x7093, 0x0020, 0x0010, 0x7093, 0x001f, + 0x0005, 0x0016, 0x00c6, 0x00d6, 0x00e6, 0x0126, 0x2061, 0x0100, + 0x2069, 0x0140, 0x2071, 0x1800, 0x2091, 0x8000, 0x080c, 0x6c53, + 0x11d8, 0x2001, 0x180c, 0x200c, 0xd1b4, 0x01b0, 0xc1b4, 0x2102, + 0x6027, 0x0200, 0x080c, 0x28d0, 0x6024, 0xd0cc, 0x0148, 0x2001, + 0x00a0, 0x080c, 0x2987, 0x080c, 0x6f2a, 0x080c, 0x5a21, 0x0428, + 0x6028, 0xc0cd, 0x602a, 0x0408, 0x080c, 0x6c6d, 0x0150, 0x080c, + 0x6c64, 0x1138, 0x2001, 0x0001, 0x080c, 0x247f, 0x080c, 0x6c2d, + 0x00a0, 0x080c, 0x6b3b, 0x0178, 0x2001, 0x0001, 0x080c, 0x247f, + 0x7090, 0x9086, 0x001e, 0x0120, 0x7090, 0x9086, 0x0022, 0x1118, + 0x7093, 0x0025, 0x0010, 0x7093, 0x0021, 0x012e, 0x00ee, 0x00de, + 0x00ce, 0x001e, 0x0005, 0x0026, 0x2011, 0x6acc, 0x080c, 0x7d1b, + 0x002e, 0x0016, 0x0026, 0x2009, 0x0064, 0x2011, 0x6acc, 0x080c, + 0x7d12, 0x002e, 0x001e, 0x0005, 0x00e6, 0x00f6, 0x0016, 0x080c, + 0x8fbb, 0x2071, 0x1800, 0x080c, 0x6a69, 0x001e, 0x00fe, 0x00ee, + 0x0005, 0x0016, 0x0026, 0x0036, 0x00c6, 0x00d6, 0x00e6, 0x00f6, + 0x0126, 0x080c, 0x8fbb, 0x2061, 0x0100, 0x2069, 0x0140, 0x2071, + 0x1800, 0x2091, 0x8000, 0x6028, 0xc09c, 0x602a, 0x2011, 0x0003, + 0x080c, 0x92ec, 0x2011, 0x0002, 0x080c, 0x92f6, 0x080c, 0x91de, + 0x080c, 0x7cc7, 0x0036, 0x901e, 0x080c, 0x9254, 0x003e, 0x60e3, + 0x0000, 0x080c, 0xd343, 0x080c, 0xd35e, 0x2009, 0x0004, 0x080c, + 0x28d6, 0x080c, 0x27f1, 0x2001, 0x1800, 0x2003, 0x0004, 0x6027, + 0x0008, 0x2011, 0x6acc, 0x080c, 0x7d1b, 0x080c, 0x6c6d, 0x0118, + 0x9006, 0x080c, 0x2987, 0x080c, 0x0b94, 0x2001, 0x0001, 0x080c, + 0x247f, 0x012e, 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x003e, 0x002e, + 0x001e, 0x0005, 0x0026, 0x00e6, 0x2011, 0x6ad9, 0x2071, 0x19c9, + 0x701c, 0x9206, 0x1118, 0x7018, 0x9005, 0x0110, 0x9085, 0x0001, + 0x00ee, 0x002e, 0x0005, 0x6020, 0xd09c, 0x0005, 0x6800, 0x9084, + 0xfffe, 0x9086, 0x00c0, 0x01b8, 0x2001, 0x00c0, 0x080c, 0x2987, + 0x0156, 0x20a9, 0x002d, 0x1d04, 0x6b4b, 0x2091, 0x6000, 0x1f04, + 0x6b4b, 0x015e, 0x00d6, 0x2069, 0x1800, 0x6894, 0x8001, 0x0220, + 0x0118, 0x6896, 0x00de, 0x0005, 0x6897, 0x0014, 0x68e0, 0xd0dc, + 0x0dc8, 0x6800, 0x9086, 0x0001, 0x1da8, 0x080c, 0x7d27, 0x0c90, + 0x00c6, 0x00d6, 0x00e6, 0x2061, 0x0100, 0x2069, 0x0140, 0x2071, + 0x1800, 0x080c, 0x6f39, 0x2001, 0x193e, 0x2003, 0x0000, 0x9006, + 0x7092, 0x60e2, 0x6886, 0x080c, 0x254a, 0x9006, 0x080c, 0x2987, + 0x080c, 0x58e0, 0x6027, 0xffff, 0x602b, 0x182f, 0x00ee, 0x00de, + 0x00ce, 0x0005, 0x00c6, 0x00d6, 0x00e6, 0x2061, 0x0100, 0x2069, + 0x0140, 0x2071, 0x1800, 0x2001, 0x194e, 0x200c, 0x9186, 0x0000, + 0x0158, 0x9186, 0x0001, 0x0158, 0x9186, 0x0002, 0x0158, 0x9186, + 0x0003, 0x0158, 0x0804, 0x6c1d, 0x7093, 0x0022, 0x0040, 0x7093, + 0x0021, 0x0028, 0x7093, 0x0023, 0x0010, 0x7093, 0x0024, 0x60e3, + 0x0000, 0x6887, 0x0001, 0x2001, 0x0001, 0x080c, 0x254a, 0x0026, + 0x080c, 0x9947, 0x002e, 0x7000, 0x908e, 0x0004, 0x0118, 0x602b, + 0x0028, 0x0010, 0x602b, 0x0020, 0x0156, 0x0126, 0x2091, 0x8000, + 0x20a9, 0x0005, 0x6024, 0xd0ac, 0x0150, 0x012e, 0x015e, 0x080c, + 0xbcec, 0x0118, 0x9006, 0x080c, 0x29b1, 0x0804, 0x6c29, 0x6800, + 0x9084, 0x00a1, 0xc0bd, 0x6802, 0x080c, 0x28d0, 0x6904, 0xd1d4, + 0x1140, 0x2001, 0x0100, 0x080c, 0x2987, 0x1f04, 0x6bca, 0x080c, + 0x6caa, 0x012e, 0x015e, 0x080c, 0x6c64, 0x01a8, 0x6044, 0x9005, + 0x0168, 0x6050, 0x0006, 0x9085, 0x0020, 0x6052, 0x080c, 0x6caa, + 0x9006, 0x8001, 0x1df0, 0x000e, 0x6052, 0x0028, 0x6804, 0xd0d4, + 0x1110, 0x080c, 0x6caa, 0x080c, 0xbcec, 0x0118, 0x9006, 0x080c, + 0x29b1, 0x0016, 0x0026, 0x7000, 0x908e, 0x0004, 0x0130, 0x2009, + 0x00c8, 0x2011, 0x6ad9, 0x080c, 0x7cd9, 0x002e, 0x001e, 0x080c, + 0x7b73, 0x2001, 0x194e, 0x2003, 0x0004, 0x080c, 0x693a, 0x080c, + 0x6c64, 0x0138, 0x6804, 0xd0d4, 0x1120, 0xd0dc, 0x1100, 0x080c, + 0x6f2f, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x00c6, 0x00d6, 0x00e6, + 0x2061, 0x0100, 0x2069, 0x0140, 0x2071, 0x1800, 0x080c, 0x7b7c, + 0x080c, 0x6f39, 0x2001, 0x193e, 0x2003, 0x0000, 0x9006, 0x7092, + 0x60e2, 0x6886, 0x080c, 0x254a, 0x9006, 0x080c, 0x2987, 0x6043, + 0x0090, 0x6043, 0x0010, 0x6027, 0xffff, 0x602b, 0x182f, 0x00ee, + 0x00de, 0x00ce, 0x0005, 0x0006, 0x2001, 0x194d, 0x2004, 0x9086, + 0xaaaa, 0x000e, 0x0005, 0x0006, 0x080c, 0x5117, 0x9084, 0x0030, + 0x9086, 0x0000, 0x000e, 0x0005, 0x0006, 0x080c, 0x5117, 0x9084, + 0x0030, 0x9086, 0x0030, 0x000e, 0x0005, 0x0006, 0x080c, 0x5117, + 0x9084, 0x0030, 0x9086, 0x0010, 0x000e, 0x0005, 0x0006, 0x080c, + 0x5117, 0x9084, 0x0030, 0x9086, 0x0020, 0x000e, 0x0005, 0x0036, + 0x0016, 0x2001, 0x180c, 0x2004, 0x908c, 0x0013, 0x0180, 0x0020, + 0x080c, 0x256a, 0x900e, 0x0028, 0x080c, 0x629c, 0x1dc8, 0x2009, + 0x0002, 0x2019, 0x0028, 0x080c, 0x2dfb, 0x9006, 0x0019, 0x001e, + 0x003e, 0x0005, 0x00e6, 0x2071, 0x180c, 0x2e04, 0x0130, 0x080c, + 0xbce5, 0x1128, 0x9085, 0x0010, 0x0010, 0x9084, 0xffef, 0x2072, + 0x00ee, 0x0005, 0x6050, 0x0006, 0x60ec, 0x0006, 0x600c, 0x0006, + 0x6004, 0x0006, 0x6028, 0x0006, 0x0016, 0x6138, 0x6050, 0x9084, + 0xfbff, 0x9085, 0x2000, 0x6052, 0x613a, 0x20a9, 0x0012, 0x1d04, + 0x6cbf, 0x2091, 0x6000, 0x1f04, 0x6cbf, 0x602f, 0x0100, 0x602f, + 0x0000, 0x6050, 0x9085, 0x0400, 0x9084, 0xdfff, 0x6052, 0x613a, + 0x001e, 0x602f, 0x0040, 0x602f, 0x0000, 0x000e, 0x602a, 0x000e, + 0x6006, 0x000e, 0x600e, 0x000e, 0x60ee, 0x60e3, 0x0000, 0x6887, + 0x0001, 0x2001, 0x0001, 0x080c, 0x254a, 0x2001, 0x00a0, 0x0006, + 0x080c, 0xbcec, 0x000e, 0x0130, 0x080c, 0x29a5, 0x9006, 0x080c, + 0x29b1, 0x0010, 0x080c, 0x2987, 0x000e, 0x6052, 0x6050, 0x0006, + 0xc0e5, 0x6052, 0x00f6, 0x2079, 0x0100, 0x080c, 0x2845, 0x00fe, + 0x000e, 0x6052, 0x0005, 0x0156, 0x0016, 0x0026, 0x0036, 0x00c6, + 0x00d6, 0x00e6, 0x2061, 0x0100, 0x2069, 0x0140, 0x2071, 0x1800, + 0x6020, 0x9084, 0x0080, 0x0138, 0x2001, 0x180c, 0x200c, 0xc1c5, + 0x2102, 0x0804, 0x6d7f, 0x2001, 0x180c, 0x200c, 0xc1c4, 0x2102, + 0x6028, 0x9084, 0xe1ff, 0x602a, 0x6027, 0x0200, 0x2001, 0x0090, + 0x080c, 0x2987, 0x20a9, 0x0366, 0x6024, 0xd0cc, 0x1518, 0x1d04, + 0x6d2c, 0x2091, 0x6000, 0x1f04, 0x6d2c, 0x2011, 0x0003, 0x080c, + 0x92ec, 0x2011, 0x0002, 0x080c, 0x92f6, 0x080c, 0x91de, 0x901e, + 0x080c, 0x9254, 0x2001, 0x00a0, 0x080c, 0x2987, 0x080c, 0x6f2a, + 0x080c, 0x5a21, 0x080c, 0xbcec, 0x0110, 0x080c, 0x0d27, 0x9085, + 0x0001, 0x0498, 0x86ff, 0x1110, 0x080c, 0x189c, 0x60e3, 0x0000, + 0x2001, 0x193e, 0x2004, 0x080c, 0x254a, 0x60e2, 0x2001, 0x0080, + 0x080c, 0x2987, 0x20a9, 0x0366, 0x6027, 0x1e00, 0x2009, 0x1e00, + 0x080c, 0x28d0, 0x6024, 0x910c, 0x0138, 0x1d04, 0x6d64, 0x2091, + 0x6000, 0x1f04, 0x6d64, 0x0808, 0x6028, 0x9085, 0x1e00, 0x602a, + 0x70ac, 0x9005, 0x1118, 0x6887, 0x0001, 0x0008, 0x6886, 0x080c, + 0xbcec, 0x0110, 0x080c, 0x0d27, 0x9006, 0x00ee, 0x00de, 0x00ce, + 0x003e, 0x002e, 0x001e, 0x015e, 0x0005, 0x0156, 0x0016, 0x0026, + 0x0036, 0x00c6, 0x00d6, 0x00e6, 0x2061, 0x0100, 0x2071, 0x1800, + 0x2069, 0x0140, 0x6020, 0x9084, 0x00c0, 0x0120, 0x6884, 0x9005, + 0x1904, 0x6de1, 0x2001, 0x0088, 0x080c, 0x2987, 0x9006, 0x60e2, + 0x6886, 0x080c, 0x254a, 0x2069, 0x0200, 0x6804, 0x9005, 0x1118, + 0x6808, 0x9005, 0x01c0, 0x6028, 0x9084, 0xfbff, 0x602a, 0x6027, + 0x0400, 0x2069, 0x195e, 0x7000, 0x206a, 0x7093, 0x0026, 0x7003, + 0x0001, 0x20a9, 0x0002, 0x1d04, 0x6dc3, 0x2091, 0x6000, 0x1f04, + 0x6dc3, 0x0804, 0x6e0f, 0x2069, 0x0140, 0x20a9, 0x0384, 0x6027, + 0x1e00, 0x2009, 0x1e00, 0x080c, 0x28d0, 0x6024, 0x910c, 0x0508, + 0x9084, 0x1a00, 0x11f0, 0x1d04, 0x6dcf, 0x2091, 0x6000, 0x1f04, + 0x6dcf, 0x2011, 0x0003, 0x080c, 0x92ec, 0x2011, 0x0002, 0x080c, + 0x92f6, 0x080c, 0x91de, 0x901e, 0x080c, 0x9254, 0x2001, 0x00a0, + 0x080c, 0x2987, 0x080c, 0x6f2a, 0x080c, 0x5a21, 0x9085, 0x0001, + 0x00b0, 0x2001, 0x0080, 0x080c, 0x2987, 0x2069, 0x0140, 0x60e3, + 0x0000, 0x70ac, 0x9005, 0x1118, 0x6887, 0x0001, 0x0008, 0x6886, + 0x2001, 0x193e, 0x2004, 0x080c, 0x254a, 0x60e2, 0x9006, 0x00ee, + 0x00de, 0x00ce, 0x003e, 0x002e, 0x001e, 0x015e, 0x0005, 0x0156, + 0x0016, 0x0026, 0x0036, 0x00c6, 0x00d6, 0x00e6, 0x2061, 0x0100, + 0x2071, 0x1800, 0x6020, 0x9084, 0x00c0, 0x01c8, 0x2011, 0x0003, + 0x080c, 0x92ec, 0x2011, 0x0002, 0x080c, 0x92f6, 0x080c, 0x91de, + 0x901e, 0x080c, 0x9254, 0x2069, 0x0140, 0x2001, 0x00a0, 0x080c, + 0x2987, 0x080c, 0x6f2a, 0x080c, 0x5a21, 0x0804, 0x6eaa, 0x2001, + 0x180c, 0x200c, 0xd1b4, 0x1160, 0xc1b5, 0x2102, 0x080c, 0x6ac1, + 0x2069, 0x0140, 0x2001, 0x0080, 0x080c, 0x2987, 0x60e3, 0x0000, + 0x2069, 0x0200, 0x6804, 0x9005, 0x1118, 0x6808, 0x9005, 0x0180, + 0x6028, 0x9084, 0xfdff, 0x602a, 0x6027, 0x0200, 0x2069, 0x195e, + 0x7000, 0x206a, 0x7093, 0x0027, 0x7003, 0x0001, 0x0804, 0x6eaa, + 0x6027, 0x1e00, 0x2009, 0x1e00, 0x080c, 0x28d0, 0x6024, 0x910c, + 0x01c8, 0x9084, 0x1c00, 0x11b0, 0x1d04, 0x6e68, 0x0006, 0x0016, + 0x00c6, 0x00d6, 0x00e6, 0x080c, 0x7bae, 0x00ee, 0x00de, 0x00ce, + 0x001e, 0x000e, 0x00e6, 0x2071, 0x19c9, 0x7018, 0x00ee, 0x9005, + 0x19f8, 0x0500, 0x0026, 0x2011, 0x6ad9, 0x080c, 0x7c4a, 0x2011, + 0x6acc, 0x080c, 0x7d1b, 0x002e, 0x2069, 0x0140, 0x60e3, 0x0000, + 0x70ac, 0x9005, 0x1118, 0x6887, 0x0001, 0x0008, 0x6886, 0x2001, + 0x193e, 0x2004, 0x080c, 0x254a, 0x60e2, 0x2001, 0x180c, 0x200c, + 0xc1b4, 0x2102, 0x00ee, 0x00de, 0x00ce, 0x003e, 0x002e, 0x001e, + 0x015e, 0x0005, 0x0156, 0x0016, 0x0026, 0x0036, 0x0046, 0x00c6, + 0x00e6, 0x2061, 0x0100, 0x2071, 0x1800, 0x080c, 0xbce5, 0x1904, + 0x6f18, 0x7130, 0xd184, 0x1170, 0x080c, 0x2f86, 0x0138, 0xc18d, + 0x7132, 0x2011, 0x1854, 0x2214, 0xd2ac, 0x1120, 0x7030, 0xd08c, + 0x0904, 0x6f18, 0x2011, 0x1854, 0x220c, 0xd1a4, 0x0538, 0x0016, + 0x2019, 0x000e, 0x080c, 0xcf62, 0x0156, 0x00b6, 0x20a9, 0x007f, + 0x900e, 0x9186, 0x007e, 0x01a0, 0x9186, 0x0080, 0x0188, 0x080c, + 0x5f7e, 0x1170, 0x2120, 0x9006, 0x0016, 0x2009, 0x000e, 0x080c, + 0xcfe6, 0x2009, 0x0001, 0x2011, 0x0100, 0x080c, 0x7e3e, 0x001e, + 0x8108, 0x1f04, 0x6ee1, 0x00be, 0x015e, 0x001e, 0xd1ac, 0x1148, + 0x0016, 0x2009, 0x0002, 0x2019, 0x0004, 0x080c, 0x2dfb, 0x001e, + 0x0078, 0x0156, 0x00b6, 0x20a9, 0x007f, 0x900e, 0x080c, 0x5f7e, + 0x1110, 0x080c, 0x5a3b, 0x8108, 0x1f04, 0x6f0e, 0x00be, 0x015e, + 0x080c, 0x189c, 0x080c, 0x9947, 0x60e3, 0x0000, 0x080c, 0x5a21, + 0x080c, 0x6b8a, 0x00ee, 0x00ce, 0x004e, 0x003e, 0x002e, 0x001e, + 0x015e, 0x0005, 0x2001, 0x194e, 0x2003, 0x0001, 0x0005, 0x2001, + 0x194e, 0x2003, 0x0000, 0x0005, 0x2001, 0x194d, 0x2003, 0xaaaa, + 0x0005, 0x2001, 0x194d, 0x2003, 0x0000, 0x0005, 0x2071, 0x18f0, + 0x7003, 0x0000, 0x7007, 0x0000, 0x080c, 0x0fee, 0x090c, 0x0db2, + 0xa8ab, 0xdcb0, 0x2900, 0x704e, 0x080c, 0x0fee, 0x090c, 0x0db2, + 0xa8ab, 0xdcb0, 0x2900, 0x7052, 0xa867, 0x0000, 0xa86b, 0x0001, + 0xa89f, 0x0000, 0x0005, 0x00e6, 0x2071, 0x0040, 0x6848, 0x9005, + 0x1118, 0x9085, 0x0001, 0x04b0, 0x6840, 0x9005, 0x0150, 0x04a1, + 0x6a50, 0x9200, 0x7002, 0x6854, 0x9101, 0x7006, 0x9006, 0x7012, + 0x7016, 0x6850, 0x7002, 0x6854, 0x7006, 0x6858, 0x700a, 0x685c, + 0x700e, 0x6840, 0x9005, 0x1110, 0x7012, 0x7016, 0x6848, 0x701a, + 0x701c, 0x9085, 0x0040, 0x701e, 0x2001, 0x0019, 0x7036, 0x702b, + 0x0001, 0x2001, 0x0004, 0x200c, 0x918c, 0xfff7, 0x918d, 0x8000, + 0x2102, 0x00d6, 0x2069, 0x18f0, 0x6807, 0x0001, 0x00de, 0x080c, + 0x74e5, 0x9006, 0x00ee, 0x0005, 0x900e, 0x0156, 0x20a9, 0x0006, + 0x8003, 0x2011, 0x0100, 0x2214, 0x9296, 0x0008, 0x1110, 0x818d, + 0x0010, 0x81f5, 0x3e08, 0x1f04, 0x6fa0, 0x015e, 0x0005, 0x2079, + 0x0040, 0x2071, 0x18f0, 0x7004, 0x0002, 0x6fbf, 0x6fc0, 0x6ff7, + 0x7052, 0x714d, 0x6fbd, 0x6fbd, 0x7177, 0x080c, 0x0db2, 0x0005, + 0x2079, 0x0040, 0x782c, 0x908c, 0x0780, 0x190c, 0x7571, 0xd0a4, + 0x01f0, 0x7824, 0x2048, 0x9006, 0xa802, 0xa806, 0xa864, 0x9084, + 0x00ff, 0x908a, 0x0040, 0x0608, 0x00b8, 0x2001, 0x1800, 0x200c, + 0x9186, 0x0003, 0x1160, 0x7104, 0x9186, 0x0004, 0x0140, 0x9186, + 0x0007, 0x0128, 0x9186, 0x0003, 0x19e8, 0x080c, 0x7052, 0x782c, + 0xd09c, 0x090c, 0x74e5, 0x0005, 0x9082, 0x005a, 0x1218, 0x2100, + 0x003b, 0x0c18, 0x080c, 0x7088, 0x0c90, 0x00e3, 0x08f0, 0x0005, + 0x7088, 0x7088, 0x7088, 0x7088, 0x7088, 0x7088, 0x7088, 0x7088, + 0x70aa, 0x7088, 0x7088, 0x7088, 0x7088, 0x7088, 0x7088, 0x7088, + 0x7088, 0x7088, 0x7088, 0x7088, 0x7088, 0x7088, 0x7088, 0x7088, + 0x7088, 0x7088, 0x7088, 0x7088, 0x7094, 0x7088, 0x724c, 0x7088, + 0x7088, 0x7088, 0x7088, 0x7088, 0x7094, 0x728d, 0x72ce, 0x7315, + 0x7329, 0x7088, 0x7088, 0x70aa, 0x7094, 0x7088, 0x7088, 0x7121, + 0x73d4, 0x73ef, 0x7088, 0x70aa, 0x7088, 0x7088, 0x7088, 0x7088, + 0x7117, 0x73ef, 0x7088, 0x7088, 0x7088, 0x7088, 0x7088, 0x7088, + 0x7088, 0x7088, 0x7088, 0x70be, 0x7088, 0x7088, 0x7088, 0x7088, + 0x7088, 0x7088, 0x7088, 0x7088, 0x7088, 0x7515, 0x7088, 0x7088, + 0x7088, 0x7088, 0x7088, 0x70d2, 0x7088, 0x7088, 0x7088, 0x7088, + 0x7088, 0x7088, 0x2079, 0x0040, 0x7004, 0x9086, 0x0003, 0x1198, + 0x782c, 0x080c, 0x750e, 0xd0a4, 0x0170, 0x7824, 0x2048, 0x9006, + 0xa802, 0xa806, 0xa864, 0x9084, 0x00ff, 0x908a, 0x001a, 0x1210, + 0x002b, 0x0c50, 0x00e9, 0x080c, 0x74e5, 0x0005, 0x7088, 0x7094, + 0x7238, 0x7088, 0x7094, 0x7088, 0x7094, 0x7094, 0x7088, 0x7094, + 0x7238, 0x7094, 0x7094, 0x7094, 0x7094, 0x7094, 0x7088, 0x7094, + 0x7238, 0x7088, 0x7088, 0x7094, 0x7088, 0x7088, 0x7088, 0x7094, + 0x00e6, 0x2071, 0x18f0, 0x2009, 0x0400, 0x0071, 0x00ee, 0x0005, + 0x2009, 0x1000, 0x0049, 0x0005, 0x2009, 0x2000, 0x0029, 0x0005, + 0x2009, 0x0800, 0x0009, 0x0005, 0x7007, 0x0001, 0xa868, 0x9084, + 0x00ff, 0x9105, 0xa86a, 0x0126, 0x2091, 0x8000, 0x080c, 0x6536, + 0x012e, 0x0005, 0xa864, 0x8007, 0x9084, 0x00ff, 0x0d08, 0x8001, + 0x1120, 0x7007, 0x0001, 0x0804, 0x71f6, 0x7007, 0x0003, 0x7012, + 0x2900, 0x7016, 0x701a, 0x704b, 0x71f6, 0x0005, 0xa864, 0x8007, + 0x9084, 0x00ff, 0x0968, 0x8001, 0x1120, 0x7007, 0x0001, 0x0804, + 0x7211, 0x7007, 0x0003, 0x7012, 0x2900, 0x7016, 0x701a, 0x704b, + 0x7211, 0x0005, 0xa864, 0x8007, 0x9084, 0x00ff, 0x9086, 0x0001, + 0x1904, 0x7090, 0x7007, 0x0001, 0x2009, 0x1832, 0x210c, 0x81ff, + 0x11a8, 0xa868, 0x9084, 0x00ff, 0xa86a, 0xa883, 0x0000, 0x080c, + 0x5c50, 0x1108, 0x0005, 0x0126, 0x2091, 0x8000, 0xa867, 0x0139, + 0xa87a, 0xa982, 0x080c, 0x6536, 0x012e, 0x0ca0, 0xa994, 0x9186, + 0x0071, 0x0d38, 0x9186, 0x0064, 0x0d20, 0x9186, 0x007c, 0x0d08, + 0x9186, 0x0028, 0x09f0, 0x9186, 0x0038, 0x09d8, 0x9186, 0x0078, + 0x09c0, 0x9186, 0x005f, 0x09a8, 0x9186, 0x0056, 0x0990, 0xa897, + 0x4005, 0xa89b, 0x0001, 0x2001, 0x0030, 0x900e, 0x08a0, 0xa87c, + 0x9084, 0x00c0, 0x9086, 0x00c0, 0x1120, 0x7007, 0x0001, 0x0804, + 0x7406, 0x2900, 0x7016, 0x701a, 0x20a9, 0x0004, 0xa860, 0x20e0, + 0xa85c, 0x9080, 0x0030, 0x2098, 0x7050, 0x2040, 0xa060, 0x20e8, + 0xa05c, 0x9080, 0x0023, 0x20a0, 0x4003, 0xa888, 0x7012, 0x9082, + 0x0401, 0x1a04, 0x7098, 0xaab4, 0x928a, 0x0002, 0x1a04, 0x7098, + 0x82ff, 0x1138, 0xa8b8, 0xa9bc, 0x9105, 0x0118, 0x2001, 0x71b4, + 0x0018, 0x9280, 0x71aa, 0x2005, 0x7056, 0x7010, 0x9015, 0x0904, + 0x7195, 0x080c, 0x0fee, 0x1118, 0x7007, 0x0004, 0x0005, 0x2900, + 0x7022, 0x7054, 0x2060, 0xe000, 0xa866, 0x7050, 0x2040, 0xa95c, + 0xe004, 0x9100, 0xa076, 0xa860, 0xa072, 0xe008, 0x920a, 0x1210, + 0x900e, 0x2200, 0x7112, 0xe20c, 0x8003, 0x800b, 0x9296, 0x0004, + 0x0108, 0x9108, 0xa17a, 0x810b, 0xa17e, 0x080c, 0x10b5, 0xa06c, + 0x908e, 0x0100, 0x0170, 0x9086, 0x0200, 0x0118, 0x7007, 0x0007, + 0x0005, 0x7020, 0x2048, 0x080c, 0x1007, 0x7014, 0x2048, 0x0804, + 0x7098, 0x7020, 0x2048, 0x7018, 0xa802, 0xa807, 0x0000, 0x2908, + 0x2048, 0xa906, 0x711a, 0x0804, 0x714d, 0x7014, 0x2048, 0x7007, + 0x0001, 0xa8b4, 0x9005, 0x1128, 0xa8b8, 0xa9bc, 0x9105, 0x0108, + 0x00b9, 0xa864, 0x9084, 0x00ff, 0x9086, 0x001e, 0x0904, 0x7406, + 0x0804, 0x71f6, 0x71ac, 0x71b0, 0x0002, 0x001d, 0x0007, 0x0004, + 0x000a, 0x001b, 0x0005, 0x0006, 0x000a, 0x001d, 0x0005, 0x0004, + 0x0076, 0x0066, 0xafb8, 0xaebc, 0xa804, 0x2050, 0xb0c0, 0xb0e2, + 0xb0bc, 0xb0de, 0xb0b8, 0xb0d2, 0xb0b4, 0xb0ce, 0xb6da, 0xb7d6, + 0xb0b0, 0xb0ca, 0xb0ac, 0xb0c6, 0xb0a8, 0xb0ba, 0xb0a4, 0xb0b6, + 0xb6c2, 0xb7be, 0xb0a0, 0xb0b2, 0xb09c, 0xb0ae, 0xb098, 0xb0a2, + 0xb094, 0xb09e, 0xb6aa, 0xb7a6, 0xb090, 0xb09a, 0xb08c, 0xb096, + 0xb088, 0xb08a, 0xb084, 0xb086, 0xb692, 0xb78e, 0xb080, 0xb082, + 0xb07c, 0xb07e, 0xb078, 0xb072, 0xb074, 0xb06e, 0xb67a, 0xb776, + 0xb004, 0x9055, 0x1958, 0x006e, 0x007e, 0x0005, 0x2009, 0x1832, + 0x210c, 0x81ff, 0x1178, 0x080c, 0x5a9d, 0x1108, 0x0005, 0x080c, + 0x6770, 0x0126, 0x2091, 0x8000, 0x080c, 0xb8e3, 0x080c, 0x6536, + 0x012e, 0x0ca0, 0x080c, 0xbce5, 0x1d70, 0x2001, 0x0028, 0x900e, + 0x0c70, 0x2009, 0x1832, 0x210c, 0x81ff, 0x11d8, 0xa888, 0x9005, + 0x01e0, 0xa883, 0x0000, 0xa87c, 0xd0f4, 0x0120, 0x080c, 0x5bb2, + 0x1138, 0x0005, 0x9006, 0xa87a, 0x080c, 0x5b2d, 0x1108, 0x0005, + 0x0126, 0x2091, 0x8000, 0xa87a, 0xa982, 0x080c, 0x6536, 0x012e, + 0x0cb0, 0x2001, 0x0028, 0x900e, 0x0c98, 0x2001, 0x0000, 0x0c80, + 0x7018, 0xa802, 0x2908, 0x2048, 0xa906, 0x711a, 0x7010, 0x8001, + 0x7012, 0x0118, 0x7007, 0x0003, 0x0030, 0x7014, 0x2048, 0x7007, + 0x0001, 0x7048, 0x080f, 0x0005, 0x00b6, 0x7007, 0x0001, 0xa974, + 0xa878, 0x9084, 0x00ff, 0x9096, 0x0004, 0x0540, 0x20a9, 0x0001, + 0x9096, 0x0001, 0x0190, 0x900e, 0x20a9, 0x0800, 0x9096, 0x0002, + 0x0160, 0x9005, 0x11d8, 0xa974, 0x080c, 0x5f7e, 0x11b8, 0x0066, + 0xae80, 0x080c, 0x608e, 0x006e, 0x0088, 0x0046, 0x2011, 0x180c, + 0x2224, 0xc484, 0x2412, 0x004e, 0x00c6, 0x080c, 0x5f7e, 0x1110, + 0x080c, 0x618e, 0x8108, 0x1f04, 0x7275, 0x00ce, 0xa87c, 0xd084, + 0x1120, 0x080c, 0x1007, 0x00be, 0x0005, 0x0126, 0x2091, 0x8000, + 0x080c, 0x6536, 0x012e, 0x00be, 0x0005, 0x0126, 0x2091, 0x8000, + 0x7007, 0x0001, 0x080c, 0x62a0, 0x0580, 0x2061, 0x1a3e, 0x6100, + 0xd184, 0x0178, 0xa888, 0x9084, 0x00ff, 0x1550, 0x6000, 0xd084, + 0x0520, 0x6004, 0x9005, 0x1538, 0x6003, 0x0000, 0x600b, 0x0000, + 0x00c8, 0x2011, 0x0001, 0xa890, 0x9005, 0x1110, 0x2001, 0x001e, + 0x8000, 0x6016, 0xa888, 0x9084, 0x00ff, 0x0178, 0x6006, 0xa888, + 0x8007, 0x9084, 0x00ff, 0x0148, 0x600a, 0xa888, 0x8000, 0x1108, + 0xc28d, 0x6202, 0x012e, 0x0804, 0x74cf, 0x012e, 0x0804, 0x74c9, + 0x012e, 0x0804, 0x74c3, 0x012e, 0x0804, 0x74c6, 0x0126, 0x2091, + 0x8000, 0x7007, 0x0001, 0x080c, 0x62a0, 0x05e0, 0x2061, 0x1a3e, + 0x6000, 0xd084, 0x05b8, 0x6204, 0x6308, 0xd08c, 0x1530, 0xac78, + 0x9484, 0x0003, 0x0170, 0xa988, 0x918c, 0x00ff, 0x8001, 0x1120, + 0x2100, 0x9210, 0x0620, 0x0028, 0x8001, 0x1508, 0x2100, 0x9212, + 0x02f0, 0x9484, 0x000c, 0x0188, 0xa988, 0x810f, 0x918c, 0x00ff, + 0x9082, 0x0004, 0x1120, 0x2100, 0x9318, 0x0288, 0x0030, 0x9082, + 0x0004, 0x1168, 0x2100, 0x931a, 0x0250, 0xa890, 0x9005, 0x0110, + 0x8000, 0x6016, 0x6206, 0x630a, 0x012e, 0x0804, 0x74cf, 0x012e, + 0x0804, 0x74cc, 0x012e, 0x0804, 0x74c9, 0x0126, 0x2091, 0x8000, + 0x7007, 0x0001, 0x2061, 0x1a3e, 0x6300, 0xd38c, 0x1120, 0x6308, + 0x8318, 0x0220, 0x630a, 0x012e, 0x0804, 0x74dd, 0x012e, 0x0804, + 0x74cc, 0x00b6, 0x0126, 0x00c6, 0x2091, 0x8000, 0x7007, 0x0001, + 0xa87c, 0xd0ac, 0x0148, 0x00c6, 0x2061, 0x1a3e, 0x6000, 0x9084, + 0xfcff, 0x6002, 0x00ce, 0x0440, 0xa888, 0x9005, 0x05d8, 0xa88c, + 0x9065, 0x0598, 0x2001, 0x1832, 0x2004, 0x9005, 0x0118, 0x080c, + 0x9a06, 0x0068, 0x6017, 0xf400, 0x605b, 0x0000, 0xa97c, 0xd1a4, + 0x0110, 0xa980, 0x615a, 0x2009, 0x0041, 0x080c, 0x9a50, 0xa988, + 0x918c, 0xff00, 0x9186, 0x2000, 0x1138, 0x0026, 0x900e, 0x2011, + 0xfdff, 0x080c, 0x7e3e, 0x002e, 0xa87c, 0xd0c4, 0x0148, 0x2061, + 0x1a3e, 0x6000, 0xd08c, 0x1120, 0x6008, 0x8000, 0x0208, 0x600a, + 0x00ce, 0x012e, 0x00be, 0x0804, 0x74cf, 0x00ce, 0x012e, 0x00be, + 0x0804, 0x74c9, 0xa984, 0x9186, 0x002e, 0x0d30, 0x9186, 0x002d, + 0x0d18, 0x9186, 0x0045, 0x0510, 0x9186, 0x002a, 0x1130, 0x2001, + 0x180c, 0x200c, 0xc194, 0x2102, 0x08b8, 0x9186, 0x0020, 0x0158, + 0x9186, 0x0029, 0x1d10, 0xa974, 0x080c, 0x5f7e, 0x1968, 0xb800, + 0xc0e4, 0xb802, 0x0848, 0xa88c, 0x9065, 0x09b8, 0x6007, 0x0024, + 0x2001, 0x1955, 0x2004, 0x601a, 0x0804, 0x7364, 0xa88c, 0x9065, + 0x0960, 0x00e6, 0xa890, 0x9075, 0x2001, 0x1832, 0x2004, 0x9005, + 0x0150, 0x080c, 0x9a06, 0x8eff, 0x0118, 0x2e60, 0x080c, 0x9a06, + 0x00ee, 0x0804, 0x7364, 0x6024, 0xc0dc, 0xc0d5, 0x6026, 0x2e60, + 0x6007, 0x003a, 0xa8a0, 0x9005, 0x0130, 0x6007, 0x003b, 0xa8a4, + 0x602e, 0xa8a8, 0x6016, 0x6003, 0x0001, 0x080c, 0x8000, 0x080c, + 0x8582, 0x00ee, 0x0804, 0x7364, 0x2061, 0x1a3e, 0x6000, 0xd084, + 0x0190, 0xd08c, 0x1904, 0x74dd, 0x0126, 0x2091, 0x8000, 0x6204, + 0x8210, 0x0220, 0x6206, 0x012e, 0x0804, 0x74dd, 0x012e, 0xa883, + 0x0016, 0x0804, 0x74d6, 0xa883, 0x0007, 0x0804, 0x74d6, 0xa864, + 0x8007, 0x9084, 0x00ff, 0x0130, 0x8001, 0x1138, 0x7007, 0x0001, + 0x0069, 0x0005, 0x080c, 0x7090, 0x0040, 0x7007, 0x0003, 0x7012, + 0x2900, 0x7016, 0x701a, 0x704b, 0x7406, 0x0005, 0x00b6, 0x00e6, + 0x0126, 0x2091, 0x8000, 0x903e, 0x2061, 0x1800, 0x61c8, 0x81ff, + 0x1904, 0x7488, 0x6130, 0xd194, 0x1904, 0x74b2, 0xa878, 0x2070, + 0x9e82, 0x1cd0, 0x0a04, 0x747c, 0x6060, 0x9e02, 0x1a04, 0x747c, + 0x7120, 0x9186, 0x0006, 0x1904, 0x746e, 0x7010, 0x905d, 0x0904, + 0x7488, 0xb800, 0xd0e4, 0x1904, 0x74ac, 0x2061, 0x1a3e, 0x6100, + 0x9184, 0x0301, 0x9086, 0x0001, 0x15a0, 0x7024, 0xd0dc, 0x1904, + 0x74b5, 0xa883, 0x0000, 0xa803, 0x0000, 0x2908, 0x7014, 0x9005, + 0x1198, 0x7116, 0xa87c, 0xd0f4, 0x1904, 0x74b8, 0x080c, 0x5113, + 0xd09c, 0x1118, 0xa87c, 0xc0cc, 0xa87e, 0x2e60, 0x080c, 0x7d5e, + 0x012e, 0x00ee, 0x00be, 0x0005, 0x2048, 0xa800, 0x9005, 0x1de0, + 0xa902, 0x2148, 0xa87c, 0xd0f4, 0x1904, 0x74b8, 0x012e, 0x00ee, + 0x00be, 0x0005, 0x012e, 0x00ee, 0xa883, 0x0006, 0x00be, 0x0804, + 0x74d6, 0xd184, 0x0db8, 0xd1c4, 0x1190, 0x00a0, 0xa974, 0x080c, + 0x5f7e, 0x15d0, 0xb800, 0xd0e4, 0x15b8, 0x7120, 0x9186, 0x0007, + 0x1118, 0xa883, 0x0002, 0x0490, 0xa883, 0x0008, 0x0478, 0xa883, + 0x000e, 0x0460, 0xa883, 0x0017, 0x0448, 0xa883, 0x0035, 0x0430, + 0x080c, 0x5117, 0xd0fc, 0x01e8, 0xa878, 0x2070, 0x9e82, 0x1cd0, + 0x02c0, 0x6060, 0x9e02, 0x12a8, 0x7120, 0x9186, 0x0006, 0x1188, + 0x7010, 0x905d, 0x0170, 0xb800, 0xd0bc, 0x0158, 0x2039, 0x0001, + 0x7000, 0x9086, 0x0007, 0x1904, 0x7412, 0x7003, 0x0002, 0x0804, + 0x7412, 0xa883, 0x0028, 0x0010, 0xa883, 0x0029, 0x012e, 0x00ee, + 0x00be, 0x0420, 0xa883, 0x002a, 0x0cc8, 0xa883, 0x0045, 0x0cb0, + 0x2e60, 0x2019, 0x0002, 0x601b, 0x0014, 0x080c, 0xcbad, 0x012e, + 0x00ee, 0x00be, 0x0005, 0x2009, 0x003e, 0x0058, 0x2009, 0x0004, + 0x0040, 0x2009, 0x0006, 0x0028, 0x2009, 0x0016, 0x0010, 0x2009, + 0x0001, 0xa884, 0x9084, 0xff00, 0x9105, 0xa886, 0x0126, 0x2091, + 0x8000, 0x080c, 0x6536, 0x012e, 0x0005, 0x080c, 0x1007, 0x0005, + 0x00d6, 0x080c, 0x7d55, 0x00de, 0x0005, 0x00d6, 0x00e6, 0x0126, + 0x2091, 0x8000, 0x2071, 0x0040, 0x702c, 0xd084, 0x01d8, 0x908c, + 0x0780, 0x190c, 0x7571, 0xd09c, 0x11a8, 0x2071, 0x1800, 0x70b8, + 0x90ea, 0x0040, 0x0278, 0x8001, 0x70ba, 0x702c, 0x2048, 0xa800, + 0x702e, 0x9006, 0xa802, 0xa806, 0x2071, 0x0040, 0x2900, 0x7022, + 0x702c, 0x0c28, 0x012e, 0x00ee, 0x00de, 0x0005, 0x0006, 0x9084, + 0x0780, 0x190c, 0x7571, 0x000e, 0x0005, 0x00d6, 0x00c6, 0x0036, + 0x0026, 0x0016, 0x00b6, 0x7007, 0x0001, 0xaa74, 0x9282, 0x0004, + 0x1a04, 0x7562, 0xa97c, 0x9188, 0x1000, 0x2104, 0x905d, 0xb804, + 0xd284, 0x0140, 0x05e8, 0x8007, 0x9084, 0x00ff, 0x9084, 0x0006, + 0x1108, 0x04b0, 0x2b10, 0x080c, 0x9980, 0x1118, 0x080c, 0x9a23, + 0x05a8, 0x6212, 0xa874, 0x0002, 0x7540, 0x7545, 0x7548, 0x754e, + 0x2019, 0x0002, 0x080c, 0xcf62, 0x0060, 0x080c, 0xcefe, 0x0048, + 0x2019, 0x0002, 0xa980, 0x080c, 0xcf19, 0x0018, 0xa980, 0x080c, + 0xcefe, 0x080c, 0x99d6, 0xa887, 0x0000, 0x0126, 0x2091, 0x8000, + 0x080c, 0x6536, 0x012e, 0x00be, 0x001e, 0x002e, 0x003e, 0x00ce, + 0x00de, 0x0005, 0xa887, 0x0006, 0x0c80, 0xa887, 0x0002, 0x0c68, + 0xa887, 0x0005, 0x0c50, 0xa887, 0x0004, 0x0c38, 0xa887, 0x0007, + 0x0c20, 0x2091, 0x8000, 0x0e04, 0x7573, 0x0006, 0x0016, 0x2001, + 0x8003, 0x0006, 0x0804, 0x0dbb, 0x0005, 0x00f6, 0x2079, 0x0300, + 0x2001, 0x0200, 0x200c, 0xc1e5, 0xc1dc, 0x2102, 0x2009, 0x0218, + 0x210c, 0xd1ec, 0x1120, 0x080c, 0x1461, 0x00fe, 0x0005, 0x2001, + 0x020d, 0x2003, 0x0020, 0x781f, 0x0300, 0x00fe, 0x0005, 0x781c, + 0xd08c, 0x0904, 0x75dd, 0x68b8, 0x90aa, 0x0005, 0x0a04, 0x7b73, + 0x7d44, 0x7c40, 0x9584, 0x00f6, 0x1508, 0x9484, 0x7000, 0x0138, + 0x908a, 0x2000, 0x1258, 0x9584, 0x0700, 0x8007, 0x04a8, 0x7000, + 0x9084, 0xff00, 0x9086, 0x8100, 0x0db0, 0x00b0, 0x9484, 0x0fff, + 0x1130, 0x7000, 0x9084, 0xff00, 0x9086, 0x8100, 0x11c0, 0x080c, + 0xd31b, 0x080c, 0x7ab8, 0x7817, 0x0140, 0x00a8, 0x9584, 0x0076, + 0x1118, 0x080c, 0x7b16, 0x19c8, 0xd5a4, 0x0148, 0x0046, 0x0056, + 0x080c, 0x763f, 0x080c, 0x203e, 0x005e, 0x004e, 0x0020, 0x080c, + 0xd31b, 0x7817, 0x0140, 0x080c, 0x7620, 0x2001, 0x19bf, 0x2004, + 0x9005, 0x090c, 0x8582, 0x0005, 0x0002, 0x75f6, 0x78da, 0x75ed, + 0x75ed, 0x75ed, 0x75ed, 0x75ed, 0x75ed, 0x7817, 0x0140, 0x2001, + 0x19bf, 0x2004, 0x9005, 0x090c, 0x8582, 0x0005, 0x7000, 0x908c, + 0xff00, 0x9194, 0xf000, 0x810f, 0x9484, 0x0fff, 0x688a, 0x9286, + 0x2000, 0x1150, 0x6800, 0x9086, 0x0001, 0x1118, 0x080c, 0x5137, + 0x0070, 0x080c, 0x765f, 0x0058, 0x9286, 0x3000, 0x1118, 0x080c, + 0x7815, 0x0028, 0x9286, 0x8000, 0x1110, 0x080c, 0x79e8, 0x7817, + 0x0140, 0x2001, 0x19bf, 0x2004, 0x9005, 0x090c, 0x8582, 0x0005, + 0x2001, 0x180f, 0x2004, 0xd08c, 0x0178, 0x2001, 0x1800, 0x2004, + 0x9086, 0x0003, 0x1148, 0x0026, 0x0036, 0x2011, 0x8048, 0x2518, + 0x080c, 0x4672, 0x003e, 0x002e, 0x0005, 0x0036, 0x0046, 0x0056, + 0x00f6, 0x2079, 0x0200, 0x2019, 0xfffe, 0x7c30, 0x0050, 0x0036, + 0x0046, 0x0056, 0x00f6, 0x2079, 0x0200, 0x7d44, 0x7c40, 0x2019, + 0xffff, 0x2001, 0x180f, 0x2004, 0xd08c, 0x0160, 0x2001, 0x1800, + 0x2004, 0x9086, 0x0003, 0x1130, 0x0026, 0x2011, 0x8048, 0x080c, + 0x4672, 0x002e, 0x00fe, 0x005e, 0x004e, 0x003e, 0x0005, 0x00b6, + 0x00c6, 0x7010, 0x9084, 0xff00, 0x8007, 0x9096, 0x0001, 0x0120, + 0x9096, 0x0023, 0x1904, 0x77e6, 0x9186, 0x0023, 0x15c0, 0x080c, + 0x7a7d, 0x0904, 0x77e6, 0x6120, 0x9186, 0x0001, 0x0150, 0x9186, + 0x0004, 0x0138, 0x9186, 0x0008, 0x0120, 0x9186, 0x000a, 0x1904, + 0x77e6, 0x7124, 0x610a, 0x7030, 0x908e, 0x0200, 0x1130, 0x2009, + 0x0015, 0x080c, 0x9a50, 0x0804, 0x77e6, 0x908e, 0x0214, 0x0118, + 0x908e, 0x0210, 0x1130, 0x2009, 0x0015, 0x080c, 0x9a50, 0x0804, + 0x77e6, 0x908e, 0x0100, 0x1904, 0x77e6, 0x7034, 0x9005, 0x1904, + 0x77e6, 0x2009, 0x0016, 0x080c, 0x9a50, 0x0804, 0x77e6, 0x9186, + 0x0022, 0x1904, 0x77e6, 0x7030, 0x908e, 0x0300, 0x1580, 0x68d4, + 0xd0a4, 0x0528, 0xc0b5, 0x68d6, 0x7100, 0x918c, 0x00ff, 0x6976, + 0x7004, 0x687a, 0x00f6, 0x2079, 0x0100, 0x79e6, 0x78ea, 0x0006, + 0x9084, 0x00ff, 0x0016, 0x2008, 0x080c, 0x251f, 0x7932, 0x7936, + 0x001e, 0x000e, 0x00fe, 0x080c, 0x24d6, 0x6956, 0x703c, 0x00e6, + 0x2071, 0x0140, 0x7086, 0x2071, 0x1800, 0x70ae, 0x00ee, 0x7034, + 0x9005, 0x1904, 0x77e6, 0x2009, 0x0017, 0x0804, 0x77b3, 0x908e, + 0x0400, 0x1190, 0x7034, 0x9005, 0x1904, 0x77e6, 0x080c, 0x6c53, + 0x0120, 0x2009, 0x001d, 0x0804, 0x77b3, 0x68d4, 0xc0a5, 0x68d6, + 0x2009, 0x0030, 0x0804, 0x77b3, 0x908e, 0x0500, 0x1140, 0x7034, + 0x9005, 0x1904, 0x77e6, 0x2009, 0x0018, 0x0804, 0x77b3, 0x908e, + 0x2010, 0x1120, 0x2009, 0x0019, 0x0804, 0x77b3, 0x908e, 0x2110, + 0x1120, 0x2009, 0x001a, 0x0804, 0x77b3, 0x908e, 0x5200, 0x1140, + 0x7034, 0x9005, 0x1904, 0x77e6, 0x2009, 0x001b, 0x0804, 0x77b3, + 0x908e, 0x5000, 0x1140, 0x7034, 0x9005, 0x1904, 0x77e6, 0x2009, + 0x001c, 0x0804, 0x77b3, 0x908e, 0x1300, 0x1120, 0x2009, 0x0034, + 0x0804, 0x77b3, 0x908e, 0x1200, 0x1140, 0x7034, 0x9005, 0x1904, + 0x77e6, 0x2009, 0x0024, 0x0804, 0x77b3, 0x908c, 0xff00, 0x918e, + 0x2400, 0x1170, 0x2009, 0x002d, 0x2001, 0x180f, 0x2004, 0xd09c, + 0x0904, 0x77b3, 0x080c, 0xc384, 0x1904, 0x77e6, 0x0804, 0x77b1, + 0x908c, 0xff00, 0x918e, 0x5300, 0x1120, 0x2009, 0x002a, 0x0804, + 0x77b3, 0x908e, 0x0f00, 0x1120, 0x2009, 0x0020, 0x0804, 0x77b3, + 0x908e, 0x5300, 0x1108, 0x0440, 0x908e, 0x6104, 0x1528, 0x2029, + 0x0205, 0x2011, 0x026d, 0x8208, 0x2204, 0x9082, 0x0004, 0x8004, + 0x8004, 0x20a8, 0x2011, 0x8015, 0x211c, 0x8108, 0x0046, 0x2124, + 0x080c, 0x4672, 0x004e, 0x8108, 0x0f04, 0x777f, 0x9186, 0x0280, + 0x1d88, 0x2504, 0x8000, 0x202a, 0x2009, 0x0260, 0x0c58, 0x202b, + 0x0000, 0x2009, 0x0023, 0x0478, 0x908e, 0x6000, 0x1118, 0x2009, + 0x003f, 0x0448, 0x908e, 0x7800, 0x1118, 0x2009, 0x0045, 0x0418, + 0x908e, 0x1000, 0x1118, 0x2009, 0x004e, 0x00e8, 0x908e, 0x6300, + 0x1118, 0x2009, 0x004a, 0x00b8, 0x908c, 0xff00, 0x918e, 0x5600, + 0x1118, 0x2009, 0x004f, 0x0078, 0x908c, 0xff00, 0x918e, 0x5700, + 0x1118, 0x2009, 0x0050, 0x0038, 0x2009, 0x001d, 0x6834, 0xd0d4, + 0x0110, 0x2009, 0x004c, 0x0016, 0x2011, 0x0263, 0x2204, 0x8211, + 0x220c, 0x080c, 0x24d6, 0x1568, 0x080c, 0x5f1e, 0x1550, 0xbe12, + 0xbd16, 0x001e, 0x0016, 0xb8b0, 0x9005, 0x1168, 0x9186, 0x0046, + 0x1150, 0x6874, 0x9606, 0x1138, 0x6878, 0x9506, 0x9084, 0xff00, + 0x1110, 0x001e, 0x0098, 0x080c, 0x9980, 0x01a8, 0x2b08, 0x6112, + 0x6023, 0x0004, 0x7120, 0x610a, 0x001e, 0x9186, 0x004c, 0x1110, + 0x6023, 0x000a, 0x0016, 0x001e, 0x080c, 0x9a50, 0x00ce, 0x00be, + 0x0005, 0x001e, 0x0cd8, 0x2001, 0x180d, 0x2004, 0xd0ec, 0x0120, + 0x2011, 0x8049, 0x080c, 0x4672, 0x080c, 0x9a23, 0x0d90, 0x2b08, + 0x6112, 0x6023, 0x0004, 0x7120, 0x610a, 0x001e, 0x0016, 0x9186, + 0x0017, 0x0118, 0x9186, 0x0030, 0x1128, 0x6007, 0x0009, 0x6017, + 0x2900, 0x0020, 0x6007, 0x0051, 0x6017, 0x0000, 0x602f, 0x0009, + 0x6003, 0x0001, 0x080c, 0x8048, 0x08a0, 0x080c, 0x2f50, 0x1140, + 0x7010, 0x9084, 0xff00, 0x8007, 0x908e, 0x0008, 0x1108, 0x0009, + 0x0005, 0x00b6, 0x00c6, 0x0046, 0x7000, 0x908c, 0xff00, 0x810f, + 0x9186, 0x0033, 0x11e8, 0x080c, 0x7a7d, 0x0904, 0x7872, 0x7124, + 0x610a, 0x7030, 0x908e, 0x0200, 0x1140, 0x7034, 0x9005, 0x15d0, + 0x2009, 0x0015, 0x080c, 0x9a50, 0x04a8, 0x908e, 0x0100, 0x1590, + 0x7034, 0x9005, 0x1578, 0x2009, 0x0016, 0x080c, 0x9a50, 0x0450, + 0x9186, 0x0032, 0x1538, 0x7030, 0x908e, 0x1400, 0x1518, 0x2009, + 0x0038, 0x0016, 0x2011, 0x0263, 0x2204, 0x8211, 0x220c, 0x080c, + 0x24d6, 0x11b8, 0x080c, 0x5f1e, 0x11a0, 0xbe12, 0xbd16, 0x080c, + 0x9980, 0x0178, 0x2b08, 0x6112, 0x080c, 0xba69, 0x6023, 0x0004, + 0x7120, 0x610a, 0x001e, 0x080c, 0x9a50, 0x080c, 0x8582, 0x0010, + 0x00ce, 0x001e, 0x004e, 0x00ce, 0x00be, 0x0005, 0x00b6, 0x0046, + 0x00e6, 0x00d6, 0x2028, 0x2130, 0x9696, 0x00ff, 0x11b8, 0x9592, + 0xfffc, 0x02a0, 0x9596, 0xfffd, 0x1120, 0x2009, 0x007f, 0x0804, + 0x78d4, 0x9596, 0xfffe, 0x1120, 0x2009, 0x007e, 0x0804, 0x78d4, + 0x9596, 0xfffc, 0x1118, 0x2009, 0x0080, 0x04f0, 0x2011, 0x0000, + 0x2019, 0x1835, 0x231c, 0xd3ac, 0x0130, 0x9026, 0x20a9, 0x0800, + 0x2071, 0x1000, 0x0030, 0x2021, 0x0081, 0x20a9, 0x077f, 0x2071, + 0x1081, 0x2e1c, 0x93dd, 0x0000, 0x1140, 0x82ff, 0x11d0, 0x9496, + 0x00ff, 0x01b8, 0x2410, 0xc2fd, 0x00a0, 0xbf10, 0x2600, 0x9706, + 0xb814, 0x1120, 0x9546, 0x1110, 0x2408, 0x00b0, 0x9745, 0x1148, + 0x94c6, 0x007e, 0x0130, 0x94c6, 0x007f, 0x0118, 0x94c6, 0x0080, + 0x1d20, 0x8420, 0x8e70, 0x1f04, 0x78a9, 0x82ff, 0x1118, 0x9085, + 0x0001, 0x0018, 0xc2fc, 0x2208, 0x9006, 0x00de, 0x00ee, 0x004e, + 0x00be, 0x0005, 0x7000, 0x908c, 0xff00, 0x810f, 0x9184, 0x000f, + 0x0002, 0x78f1, 0x78f1, 0x78f1, 0x7a8f, 0x78f1, 0x78fa, 0x7925, + 0x79b3, 0x78f1, 0x78f1, 0x78f1, 0x78f1, 0x78f1, 0x78f1, 0x78f1, + 0x78f1, 0x7817, 0x0140, 0x2001, 0x19bf, 0x2004, 0x9005, 0x090c, + 0x8582, 0x0005, 0x00b6, 0x7110, 0xd1bc, 0x01e8, 0x7120, 0x2160, + 0x9c8c, 0x0007, 0x11c0, 0x9c8a, 0x1cd0, 0x02a8, 0x6860, 0x9c02, + 0x1290, 0x7008, 0x9084, 0x00ff, 0x6110, 0x2158, 0xb910, 0x9106, + 0x1150, 0x700c, 0xb914, 0x9106, 0x1130, 0x7124, 0x610a, 0x2009, + 0x0046, 0x080c, 0x9a50, 0x7817, 0x0140, 0x2001, 0x19bf, 0x2004, + 0x9005, 0x090c, 0x8582, 0x00be, 0x0005, 0x00b6, 0x00c6, 0x9484, + 0x0fff, 0x0904, 0x7989, 0x7110, 0xd1bc, 0x1904, 0x7989, 0x7108, + 0x700c, 0x2028, 0x918c, 0x00ff, 0x2130, 0x9094, 0xff00, 0x15b0, + 0x81ff, 0x15a0, 0x9080, 0x2f92, 0x200d, 0x918c, 0xff00, 0x810f, + 0x2001, 0x0080, 0x9106, 0x0904, 0x7989, 0x080c, 0x5f1e, 0x1904, + 0x7989, 0xbe12, 0xbd16, 0xb800, 0xd0ec, 0x15d8, 0xba04, 0x9294, + 0xff00, 0x9286, 0x0600, 0x11a0, 0x080c, 0x9980, 0x05e8, 0x2b08, + 0x7028, 0x604a, 0x702c, 0x6046, 0x6112, 0x6023, 0x0006, 0x7120, + 0x610a, 0x7130, 0x6156, 0x2009, 0x0044, 0x080c, 0xc5dc, 0x0408, + 0x080c, 0x62a4, 0x1138, 0xb807, 0x0606, 0x0c30, 0x190c, 0x7876, + 0x11c0, 0x0898, 0x080c, 0x9980, 0x2b08, 0x0198, 0x6112, 0x6023, + 0x0004, 0x7120, 0x610a, 0x9286, 0x0400, 0x1118, 0x6007, 0x0005, + 0x0010, 0x6007, 0x0001, 0x6003, 0x0001, 0x080c, 0x8048, 0x080c, + 0x8582, 0x7817, 0x0140, 0x2001, 0x19bf, 0x2004, 0x9005, 0x090c, + 0x8582, 0x00ce, 0x00be, 0x0005, 0x2001, 0x180d, 0x2004, 0xd0ec, + 0x0120, 0x2011, 0x8049, 0x080c, 0x4672, 0x080c, 0x9a23, 0x0d48, + 0x2b08, 0x6112, 0x6023, 0x0006, 0x7120, 0x610a, 0x7130, 0x6156, + 0x6017, 0xf300, 0x6003, 0x0001, 0x6007, 0x0041, 0x080c, 0x8000, + 0x080c, 0x8582, 0x08b0, 0x00b6, 0x7110, 0xd1bc, 0x01e8, 0x7020, + 0x2060, 0x9c84, 0x0007, 0x11c0, 0x9c82, 0x1cd0, 0x02a8, 0x6860, + 0x9c02, 0x1290, 0x7008, 0x9084, 0x00ff, 0x6110, 0x2158, 0xb910, + 0x9106, 0x1150, 0x700c, 0xb914, 0x9106, 0x1130, 0x7124, 0x610a, + 0x2009, 0x0045, 0x080c, 0x9a50, 0x7817, 0x0140, 0x2001, 0x19bf, + 0x2004, 0x9005, 0x090c, 0x8582, 0x00be, 0x0005, 0x6120, 0x9186, + 0x0002, 0x0128, 0x9186, 0x0005, 0x0110, 0x9085, 0x0001, 0x0005, + 0x080c, 0x2f50, 0x1168, 0x7010, 0x9084, 0xff00, 0x8007, 0x9086, + 0x0000, 0x1130, 0x9184, 0x000f, 0x908a, 0x0006, 0x1208, 0x000b, + 0x0005, 0x79ff, 0x7a00, 0x79ff, 0x79ff, 0x7a5f, 0x7a6e, 0x0005, + 0x00b6, 0x7110, 0xd1bc, 0x0120, 0x702c, 0xd084, 0x0904, 0x7a5d, + 0x700c, 0x7108, 0x080c, 0x24d6, 0x1904, 0x7a5d, 0x080c, 0x5f1e, + 0x1904, 0x7a5d, 0xbe12, 0xbd16, 0x7110, 0xd1bc, 0x01d8, 0x080c, + 0x62a4, 0x0118, 0x9086, 0x0004, 0x1588, 0x00c6, 0x080c, 0x7a7d, + 0x00ce, 0x05d8, 0x080c, 0x9980, 0x2b08, 0x05b8, 0x6112, 0x080c, + 0xba69, 0x6023, 0x0002, 0x7120, 0x610a, 0x2009, 0x0088, 0x080c, + 0x9a50, 0x0458, 0x080c, 0x62a4, 0x0148, 0x9086, 0x0004, 0x0130, + 0x080c, 0x62ac, 0x0118, 0x9086, 0x0004, 0x1180, 0x080c, 0x9980, + 0x2b08, 0x01d8, 0x6112, 0x080c, 0xba69, 0x6023, 0x0005, 0x7120, + 0x610a, 0x2009, 0x0088, 0x080c, 0x9a50, 0x0078, 0x080c, 0x9980, + 0x2b08, 0x0158, 0x6112, 0x080c, 0xba69, 0x6023, 0x0004, 0x7120, + 0x610a, 0x2009, 0x0001, 0x080c, 0x9a50, 0x00be, 0x0005, 0x7110, + 0xd1bc, 0x0158, 0x00d1, 0x0148, 0x080c, 0x79de, 0x1130, 0x7124, + 0x610a, 0x2009, 0x0089, 0x080c, 0x9a50, 0x0005, 0x7110, 0xd1bc, + 0x0158, 0x0059, 0x0148, 0x080c, 0x79de, 0x1130, 0x7124, 0x610a, + 0x2009, 0x008a, 0x080c, 0x9a50, 0x0005, 0x7020, 0x2060, 0x9c84, + 0x0007, 0x1158, 0x9c82, 0x1cd0, 0x0240, 0x2001, 0x1818, 0x2004, + 0x9c02, 0x1218, 0x9085, 0x0001, 0x0005, 0x9006, 0x0ce8, 0x00b6, + 0x7110, 0xd1bc, 0x11d8, 0x7024, 0x2060, 0x9c84, 0x0007, 0x11b0, + 0x9c82, 0x1cd0, 0x0298, 0x6860, 0x9c02, 0x1280, 0x7008, 0x9084, + 0x00ff, 0x6110, 0x2158, 0xb910, 0x9106, 0x1140, 0x700c, 0xb914, + 0x9106, 0x1120, 0x2009, 0x0051, 0x080c, 0x9a50, 0x7817, 0x0140, + 0x2001, 0x19bf, 0x2004, 0x9005, 0x090c, 0x8582, 0x00be, 0x0005, + 0x2031, 0x0105, 0x0069, 0x0005, 0x2031, 0x0206, 0x0049, 0x0005, + 0x2031, 0x0207, 0x0029, 0x0005, 0x2031, 0x0213, 0x0009, 0x0005, + 0x00c6, 0x0096, 0x00f6, 0x7000, 0x9084, 0xf000, 0x9086, 0xc000, + 0x05d0, 0x080c, 0x9980, 0x05b8, 0x0066, 0x00c6, 0x0046, 0x2011, + 0x0263, 0x2204, 0x8211, 0x220c, 0x080c, 0x24d6, 0x15a0, 0x080c, + 0x5f1e, 0x1588, 0xbe12, 0xbd16, 0x2b00, 0x004e, 0x00ce, 0x6012, + 0x080c, 0xba69, 0x080c, 0x0fd5, 0x0510, 0x2900, 0x605a, 0x9006, + 0xa802, 0xa866, 0xac6a, 0xa85c, 0x90f8, 0x001b, 0x20a9, 0x000e, + 0xa860, 0x20e8, 0x20e1, 0x0000, 0x2fa0, 0x2e98, 0x4003, 0x006e, + 0x6616, 0x6007, 0x003e, 0x6023, 0x0001, 0x6003, 0x0001, 0x080c, + 0x8048, 0x080c, 0x8582, 0x00fe, 0x009e, 0x00ce, 0x0005, 0x080c, + 0x99d6, 0x006e, 0x0cc0, 0x004e, 0x00ce, 0x0cc8, 0x00c6, 0x7000, + 0x908c, 0xff00, 0x9184, 0xf000, 0x810f, 0x9086, 0x2000, 0x1904, + 0x7b6d, 0x9186, 0x0022, 0x15f0, 0x2001, 0x0111, 0x2004, 0x9005, + 0x1904, 0x7b6f, 0x7030, 0x908e, 0x0400, 0x0904, 0x7b6f, 0x908e, + 0x6000, 0x05e8, 0x908e, 0x5400, 0x05d0, 0x908e, 0x0300, 0x11d8, + 0x2009, 0x1835, 0x210c, 0xd18c, 0x1590, 0xd1a4, 0x1580, 0x080c, + 0x6262, 0x0558, 0x68a8, 0x9084, 0x00ff, 0x7100, 0x918c, 0x00ff, + 0x9106, 0x1518, 0x6878, 0x69a8, 0x918c, 0xff00, 0x9105, 0x7104, + 0x9106, 0x11d8, 0x00e0, 0x2009, 0x0103, 0x210c, 0xd1b4, 0x11a8, + 0x908e, 0x5200, 0x09e8, 0x908e, 0x0500, 0x09d0, 0x908e, 0x5000, + 0x09b8, 0x0058, 0x9186, 0x0023, 0x1140, 0x080c, 0x7a7d, 0x0128, + 0x6004, 0x9086, 0x0002, 0x0118, 0x0000, 0x9006, 0x0010, 0x9085, + 0x0001, 0x00ce, 0x0005, 0x00f6, 0x2079, 0x0200, 0x7800, 0xc0e5, + 0xc0cc, 0x7802, 0x00fe, 0x0005, 0x00f6, 0x2079, 0x0200, 0x7800, + 0x9085, 0x1200, 0x7802, 0x00fe, 0x0005, 0x2071, 0x19c9, 0x7003, + 0x0003, 0x700f, 0x0361, 0x9006, 0x701a, 0x7072, 0x7012, 0x7017, + 0x1cd0, 0x7007, 0x0000, 0x7026, 0x702b, 0x8fd1, 0x7032, 0x7037, + 0x903f, 0x703f, 0xffff, 0x7042, 0x7047, 0x4fb2, 0x704a, 0x705b, + 0x7ce2, 0x080c, 0x0fee, 0x090c, 0x0db2, 0x2900, 0x703a, 0xa867, + 0x0003, 0xa86f, 0x0100, 0xa8ab, 0xdcb0, 0x0005, 0x2071, 0x19c9, + 0x1d04, 0x7c39, 0x2091, 0x6000, 0x700c, 0x8001, 0x700e, 0x1510, + 0x2001, 0x1875, 0x2004, 0xd0c4, 0x0158, 0x3a00, 0xd08c, 0x1140, + 0x20d1, 0x0000, 0x20d1, 0x0001, 0x20d1, 0x0000, 0x080c, 0x0db2, + 0x700f, 0x0361, 0x7007, 0x0001, 0x0126, 0x2091, 0x8000, 0x080c, + 0x7d27, 0x7040, 0x900d, 0x0148, 0x8109, 0x7142, 0x1130, 0x7044, + 0x080f, 0x0018, 0x0126, 0x2091, 0x8000, 0x7024, 0x900d, 0x0188, + 0x7020, 0x8001, 0x7022, 0x1168, 0x7023, 0x0009, 0x8109, 0x7126, + 0x9186, 0x03e8, 0x1110, 0x7028, 0x080f, 0x81ff, 0x1110, 0x7028, + 0x080f, 0x7030, 0x900d, 0x0180, 0x702c, 0x8001, 0x702e, 0x1160, + 0x702f, 0x0009, 0x8109, 0x7132, 0x0128, 0x9184, 0x007f, 0x090c, + 0x90b9, 0x0010, 0x7034, 0x080f, 0x703c, 0x9005, 0x0118, 0x0310, + 0x8001, 0x703e, 0x704c, 0x900d, 0x0168, 0x7048, 0x8001, 0x704a, + 0x1148, 0x704b, 0x0009, 0x8109, 0x714e, 0x1120, 0x7150, 0x714e, + 0x7058, 0x080f, 0x7018, 0x900d, 0x01d8, 0x0016, 0x7070, 0x900d, + 0x0158, 0x706c, 0x8001, 0x706e, 0x1138, 0x706f, 0x0009, 0x8109, + 0x7172, 0x1110, 0x7074, 0x080f, 0x001e, 0x7008, 0x8001, 0x700a, + 0x1138, 0x700b, 0x0009, 0x8109, 0x711a, 0x1110, 0x701c, 0x080f, + 0x012e, 0x7004, 0x0002, 0x7c61, 0x7c62, 0x7c7e, 0x00e6, 0x2071, + 0x19c9, 0x7018, 0x9005, 0x1120, 0x711a, 0x721e, 0x700b, 0x0009, + 0x00ee, 0x0005, 0x00e6, 0x0006, 0x2071, 0x19c9, 0x701c, 0x9206, + 0x1120, 0x701a, 0x701e, 0x7072, 0x7076, 0x000e, 0x00ee, 0x0005, + 0x00e6, 0x2071, 0x19c9, 0xb888, 0x9102, 0x0208, 0xb98a, 0x00ee, + 0x0005, 0x0005, 0x00b6, 0x7110, 0x080c, 0x5f7e, 0x1168, 0xb888, + 0x8001, 0x0250, 0xb88a, 0x1140, 0x0126, 0x2091, 0x8000, 0x0016, + 0x080c, 0x8582, 0x001e, 0x012e, 0x8108, 0x9182, 0x0800, 0x0218, + 0x900e, 0x7007, 0x0002, 0x7112, 0x00be, 0x0005, 0x7014, 0x2060, + 0x0126, 0x2091, 0x8000, 0x6040, 0x9005, 0x0128, 0x8001, 0x6042, + 0x1110, 0x080c, 0xb8fa, 0x6018, 0x9005, 0x0510, 0x8001, 0x601a, + 0x11f8, 0x6120, 0x9186, 0x0003, 0x0118, 0x9186, 0x0006, 0x11b0, + 0x6014, 0x2048, 0xa884, 0x908a, 0x199a, 0x0280, 0x9082, 0x1999, + 0xa886, 0x908a, 0x199a, 0x0210, 0x2001, 0x1999, 0x8003, 0x800b, + 0x810b, 0x9108, 0x611a, 0xa87c, 0xd0e4, 0x0110, 0x080c, 0xb313, + 0x012e, 0x9c88, 0x0018, 0x7116, 0x2001, 0x1818, 0x2004, 0x9102, + 0x0220, 0x7017, 0x1cd0, 0x7007, 0x0000, 0x0005, 0x00e6, 0x2071, + 0x19c9, 0x7027, 0x07d0, 0x7023, 0x0009, 0x00ee, 0x0005, 0x2001, + 0x19d2, 0x2003, 0x0000, 0x0005, 0x00e6, 0x2071, 0x19c9, 0x7132, + 0x702f, 0x0009, 0x00ee, 0x0005, 0x2011, 0x19d5, 0x2013, 0x0000, + 0x0005, 0x00e6, 0x2071, 0x19c9, 0x711a, 0x721e, 0x700b, 0x0009, + 0x00ee, 0x0005, 0x0086, 0x0026, 0x7054, 0x8000, 0x7056, 0x2001, + 0x19d7, 0x2044, 0xa06c, 0x9086, 0x0000, 0x0150, 0x7068, 0xa09a, + 0x7064, 0xa096, 0x7060, 0xa092, 0x705c, 0xa08e, 0x080c, 0x10b5, + 0x002e, 0x008e, 0x0005, 0x0006, 0x0016, 0x0096, 0x00a6, 0x00b6, + 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x0156, 0x080c, 0x7bae, 0x015e, + 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x00be, 0x00ae, 0x009e, 0x001e, + 0x000e, 0x0005, 0x00e6, 0x2071, 0x19c9, 0x7172, 0x7276, 0x706f, + 0x0009, 0x00ee, 0x0005, 0x00e6, 0x0006, 0x2071, 0x19c9, 0x7074, + 0x9206, 0x1110, 0x7072, 0x7076, 0x000e, 0x00ee, 0x0005, 0x2069, + 0x1800, 0x69e0, 0xd1e4, 0x1518, 0x0026, 0xd1ec, 0x0140, 0x6a4c, + 0x686c, 0x9202, 0x0288, 0x8117, 0x9294, 0x00c0, 0x0088, 0x9184, + 0x0007, 0x01a0, 0x8109, 0x9184, 0x0007, 0x0110, 0x69e2, 0x0070, + 0x8107, 0x9084, 0x0007, 0x910d, 0x8107, 0x9106, 0x9094, 0x00c0, + 0x9184, 0xff3f, 0x9205, 0x68e2, 0x080c, 0x0eb4, 0x002e, 0x0005, + 0x00c6, 0x2061, 0x1a3e, 0x00ce, 0x0005, 0x9184, 0x000f, 0x8003, + 0x8003, 0x8003, 0x9080, 0x1a3e, 0x2060, 0x0005, 0xa884, 0x908a, + 0x199a, 0x1638, 0x9005, 0x1150, 0x00c6, 0x2061, 0x1a3e, 0x6014, + 0x00ce, 0x9005, 0x1130, 0x2001, 0x001e, 0x0018, 0x908e, 0xffff, + 0x01b0, 0x8003, 0x800b, 0x810b, 0x9108, 0x611a, 0xa87c, 0x908c, + 0x00c0, 0x918e, 0x00c0, 0x0904, 0x7de8, 0xd0b4, 0x1168, 0xd0bc, + 0x1904, 0x7dc1, 0x2009, 0x0006, 0x080c, 0x7e15, 0x0005, 0x900e, + 0x0c60, 0x2001, 0x1999, 0x08b0, 0xd0fc, 0x0160, 0x908c, 0x0003, + 0x0120, 0x918e, 0x0003, 0x1904, 0x7e0f, 0x908c, 0x2020, 0x918e, + 0x2020, 0x01a8, 0x6024, 0xd0d4, 0x11e8, 0x2009, 0x1875, 0x2104, + 0xd084, 0x1138, 0x87ff, 0x1120, 0x2009, 0x0043, 0x0804, 0x9a50, + 0x0005, 0x87ff, 0x1de8, 0x2009, 0x0042, 0x0804, 0x9a50, 0x6110, + 0x00b6, 0x2158, 0xb900, 0x00be, 0xd1ac, 0x0d20, 0x6024, 0xc0cd, + 0x6026, 0x0c00, 0xc0d4, 0x6026, 0xa890, 0x602e, 0xa88c, 0x6032, + 0x08e0, 0xd0fc, 0x0160, 0x908c, 0x0003, 0x0120, 0x918e, 0x0003, + 0x1904, 0x7e0f, 0x908c, 0x2020, 0x918e, 0x2020, 0x0170, 0x0076, + 0x00f6, 0x2c78, 0x080c, 0x1582, 0x00fe, 0x007e, 0x87ff, 0x1120, + 0x2009, 0x0042, 0x080c, 0x9a50, 0x0005, 0x6110, 0x00b6, 0x2158, + 0xb900, 0x00be, 0xd1ac, 0x0d58, 0x6124, 0xc1cd, 0x6126, 0x0c38, + 0xd0fc, 0x0188, 0x908c, 0x2020, 0x918e, 0x2020, 0x01a8, 0x9084, + 0x0003, 0x908e, 0x0002, 0x0148, 0x87ff, 0x1120, 0x2009, 0x0041, + 0x080c, 0x9a50, 0x0005, 0x00b9, 0x0ce8, 0x87ff, 0x1dd8, 0x2009, + 0x0043, 0x080c, 0x9a50, 0x0cb0, 0x6110, 0x00b6, 0x2158, 0xb900, + 0x00be, 0xd1ac, 0x0d20, 0x6124, 0xc1cd, 0x6126, 0x0c00, 0x2009, + 0x0004, 0x0019, 0x0005, 0x2009, 0x0001, 0x0096, 0x080c, 0xb5fb, + 0x0518, 0x6014, 0x2048, 0xa982, 0xa800, 0x6016, 0x9186, 0x0001, + 0x1188, 0xa97c, 0x918c, 0x8100, 0x918e, 0x8100, 0x1158, 0x00c6, + 0x2061, 0x1a3e, 0x6200, 0xd28c, 0x1120, 0x6204, 0x8210, 0x0208, + 0x6206, 0x00ce, 0x080c, 0x6370, 0x6014, 0x904d, 0x0076, 0x2039, + 0x0000, 0x190c, 0x7d5e, 0x007e, 0x009e, 0x0005, 0x0156, 0x00c6, + 0x2061, 0x1a3e, 0x6000, 0x81ff, 0x0110, 0x9205, 0x0008, 0x9204, + 0x6002, 0x00ce, 0x015e, 0x0005, 0x6800, 0xd08c, 0x1138, 0x6808, + 0x9005, 0x0120, 0x8001, 0x680a, 0x9085, 0x0001, 0x0005, 0x0126, + 0x2091, 0x8000, 0x0036, 0x0046, 0x20a9, 0x0010, 0x9006, 0x8004, + 0x2019, 0x0100, 0x231c, 0x93a6, 0x0008, 0x1118, 0x8086, 0x818e, + 0x0020, 0x80f6, 0x3e00, 0x81f6, 0x3e08, 0x1208, 0x9200, 0x1f04, + 0x7e60, 0x93a6, 0x0008, 0x1118, 0x8086, 0x818e, 0x0020, 0x80f6, + 0x3e00, 0x81f6, 0x3e08, 0x004e, 0x003e, 0x012e, 0x0005, 0x0126, + 0x2091, 0x8000, 0x0076, 0x0156, 0x20a9, 0x0010, 0x9005, 0x0510, + 0x911a, 0x1600, 0x8213, 0x2039, 0x0100, 0x273c, 0x97be, 0x0008, + 0x1110, 0x818d, 0x0010, 0x81f5, 0x3e08, 0x0228, 0x911a, 0x1220, + 0x1f04, 0x7e8a, 0x0028, 0x911a, 0x2308, 0x8210, 0x1f04, 0x7e8a, + 0x0006, 0x3200, 0x9084, 0xefff, 0x2080, 0x000e, 0x015e, 0x007e, + 0x012e, 0x0005, 0x0006, 0x3200, 0x9085, 0x1000, 0x0ca8, 0x0126, + 0x2091, 0x2800, 0x2079, 0x19b6, 0x012e, 0x00d6, 0x2069, 0x19b6, + 0x6803, 0x0005, 0x0156, 0x0146, 0x01d6, 0x20e9, 0x0000, 0x2069, + 0x0200, 0x080c, 0x97ce, 0x0401, 0x080c, 0x97b9, 0x00e9, 0x080c, + 0x97bc, 0x00d1, 0x080c, 0x97bf, 0x00b9, 0x080c, 0x97c2, 0x00a1, + 0x080c, 0x97c5, 0x0089, 0x080c, 0x97c8, 0x0071, 0x080c, 0x97cb, + 0x0059, 0x01de, 0x014e, 0x015e, 0x2069, 0x0004, 0x2d04, 0x9085, + 0x8001, 0x206a, 0x00de, 0x0005, 0x20a9, 0x0020, 0x20a1, 0x0240, + 0x2001, 0x0000, 0x4004, 0x0005, 0x00c6, 0x6027, 0x0001, 0x7804, + 0x9084, 0x0007, 0x0002, 0x7efd, 0x7f21, 0x7f60, 0x7f03, 0x7f21, + 0x7efd, 0x7efb, 0x7efb, 0x080c, 0x0db2, 0x080c, 0x7cc7, 0x080c, + 0x8582, 0x00ce, 0x0005, 0x62c0, 0x82ff, 0x1110, 0x00ce, 0x0005, + 0x2011, 0x588a, 0x080c, 0x7c4a, 0x7828, 0x9092, 0x00c8, 0x1228, + 0x8000, 0x782a, 0x080c, 0x58ca, 0x0c88, 0x62c0, 0x080c, 0x97d2, + 0x080c, 0x588a, 0x7807, 0x0003, 0x7827, 0x0000, 0x782b, 0x0000, + 0x0c28, 0x080c, 0x7cc7, 0x6220, 0xd2a4, 0x0160, 0x782b, 0x0000, + 0x7824, 0x9065, 0x090c, 0x0db2, 0x2009, 0x0013, 0x080c, 0x9a50, + 0x00ce, 0x0005, 0x00c6, 0x7824, 0x9065, 0x090c, 0x0db2, 0x7828, + 0x9092, 0xc350, 0x12c0, 0x8000, 0x782a, 0x00ce, 0x080c, 0x283d, + 0x0278, 0x00c6, 0x7924, 0x2160, 0x6010, 0x906d, 0x090c, 0x0db2, + 0x7807, 0x0000, 0x7827, 0x0000, 0x00ce, 0x080c, 0x8582, 0x0c00, + 0x080c, 0x8f97, 0x08e8, 0x2011, 0x0130, 0x2214, 0x080c, 0x97d2, + 0x080c, 0xd358, 0x2009, 0x0014, 0x080c, 0x9a50, 0x00ce, 0x0880, + 0x2001, 0x19d2, 0x2003, 0x0000, 0x62c0, 0x82ff, 0x1160, 0x782b, + 0x0000, 0x7824, 0x9065, 0x090c, 0x0db2, 0x2009, 0x0013, 0x080c, + 0x9aa2, 0x00ce, 0x0005, 0x00b6, 0x00c6, 0x00d6, 0x7824, 0x9005, + 0x090c, 0x0db2, 0x7828, 0x9092, 0xc350, 0x1648, 0x8000, 0x782a, + 0x00de, 0x00ce, 0x00be, 0x080c, 0x283d, 0x02f0, 0x00b6, 0x00c6, + 0x00d6, 0x781c, 0x905d, 0x090c, 0x0db2, 0xb800, 0xc0dc, 0xb802, + 0x7924, 0x2160, 0x080c, 0x99d6, 0xb93c, 0x81ff, 0x090c, 0x0db2, + 0x8109, 0xb93e, 0x7807, 0x0000, 0x7827, 0x0000, 0x00de, 0x00ce, + 0x00be, 0x080c, 0x8582, 0x0868, 0x080c, 0x8f97, 0x0850, 0x2011, + 0x0130, 0x2214, 0x080c, 0x97d2, 0x080c, 0xd358, 0x7824, 0x9065, + 0x2009, 0x0014, 0x080c, 0x9a50, 0x00de, 0x00ce, 0x00be, 0x0804, + 0x7f71, 0x00c6, 0x2001, 0x009b, 0x2004, 0xd0fc, 0x190c, 0x1be4, + 0x6024, 0x6027, 0x0002, 0xd0f4, 0x1580, 0x62c8, 0x60c4, 0x9205, + 0x1170, 0x783c, 0x9065, 0x0130, 0x2009, 0x0049, 0x080c, 0x9a50, + 0x00ce, 0x0005, 0x2011, 0x19d5, 0x2013, 0x0000, 0x0cc8, 0x793c, + 0x81ff, 0x0dc0, 0x7944, 0x9192, 0x7530, 0x12f0, 0x8108, 0x7946, + 0x793c, 0x9188, 0x0008, 0x210c, 0x918e, 0x0006, 0x1138, 0x6014, + 0x9084, 0x1984, 0x9085, 0x0012, 0x6016, 0x0c10, 0x6014, 0x9084, + 0x1984, 0x9085, 0x0016, 0x6016, 0x08d8, 0x793c, 0x2160, 0x2009, + 0x004a, 0x080c, 0x9a50, 0x08a0, 0x7848, 0xc085, 0x784a, 0x0880, + 0x0006, 0x0016, 0x00c6, 0x0126, 0x2091, 0x8000, 0x600f, 0x0000, + 0x2c08, 0x2061, 0x19b6, 0x6020, 0x8000, 0x6022, 0x6010, 0x9005, + 0x0148, 0x9080, 0x0003, 0x2102, 0x6112, 0x012e, 0x00ce, 0x001e, + 0x000e, 0x0005, 0x6116, 0x6112, 0x0cc0, 0x00d6, 0x2069, 0x19b6, + 0xb800, 0xd0d4, 0x0168, 0x6820, 0x8000, 0x6822, 0x9086, 0x0001, + 0x1110, 0x2b00, 0x681e, 0x00de, 0x0804, 0x8582, 0x00de, 0x0005, + 0xc0d5, 0xb802, 0x6818, 0x9005, 0x0168, 0xb856, 0xb85b, 0x0000, + 0x0086, 0x0006, 0x2b00, 0x681a, 0x008e, 0xa05a, 0x008e, 0x2069, + 0x19b6, 0x0c08, 0xb856, 0xb85a, 0x2b00, 0x681a, 0x681e, 0x08d8, + 0x0006, 0x0016, 0x00c6, 0x0126, 0x2091, 0x8000, 0x600f, 0x0000, + 0x2c08, 0x2061, 0x19b6, 0x6020, 0x8000, 0x6022, 0x6008, 0x9005, + 0x0148, 0x9080, 0x0003, 0x2102, 0x610a, 0x012e, 0x00ce, 0x001e, + 0x000e, 0x0005, 0x610e, 0x610a, 0x0cc0, 0x00c6, 0x600f, 0x0000, + 0x2c08, 0x2061, 0x19b6, 0x6034, 0x9005, 0x0130, 0x9080, 0x0003, + 0x2102, 0x6136, 0x00ce, 0x0005, 0x613a, 0x6136, 0x00ce, 0x0005, + 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x00b6, 0x0096, 0x0076, 0x0066, + 0x0056, 0x0036, 0x0026, 0x0016, 0x0006, 0x0126, 0x902e, 0x2071, + 0x19b6, 0x7638, 0x2660, 0x2678, 0x2091, 0x8000, 0x8cff, 0x0904, + 0x80ef, 0x6010, 0x2058, 0xb8a0, 0x9206, 0x1904, 0x80ea, 0x87ff, + 0x0120, 0x6054, 0x9106, 0x1904, 0x80ea, 0x703c, 0x9c06, 0x1178, + 0x0036, 0x2019, 0x0001, 0x080c, 0x9254, 0x7033, 0x0000, 0x9006, + 0x703e, 0x7042, 0x7046, 0x704a, 0x003e, 0x2029, 0x0001, 0x7038, + 0x9c36, 0x1110, 0x660c, 0x763a, 0x7034, 0x9c36, 0x1140, 0x2c00, + 0x9f36, 0x0118, 0x2f00, 0x7036, 0x0010, 0x7037, 0x0000, 0x660c, + 0x0066, 0x2c00, 0x9f06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f, + 0x0000, 0x080c, 0xb5fb, 0x01c8, 0x6014, 0x2048, 0x6020, 0x9086, + 0x0003, 0x1590, 0xa867, 0x0103, 0xab7a, 0xa877, 0x0000, 0x0016, + 0x0036, 0x0076, 0x080c, 0xb8e3, 0x080c, 0xd28c, 0x080c, 0x6536, + 0x007e, 0x003e, 0x001e, 0x080c, 0xb7dd, 0x080c, 0x9a06, 0x00ce, + 0x0804, 0x808e, 0x2c78, 0x600c, 0x2060, 0x0804, 0x808e, 0x85ff, + 0x0120, 0x0036, 0x080c, 0x865d, 0x003e, 0x012e, 0x000e, 0x001e, + 0x002e, 0x003e, 0x005e, 0x006e, 0x007e, 0x009e, 0x00be, 0x00ce, + 0x00de, 0x00ee, 0x00fe, 0x0005, 0x6020, 0x9086, 0x0006, 0x1158, + 0x0016, 0x0036, 0x0076, 0x080c, 0xd28c, 0x080c, 0xcf91, 0x007e, + 0x003e, 0x001e, 0x0890, 0x6020, 0x9086, 0x000a, 0x0904, 0x80d4, + 0x0804, 0x80d2, 0x0006, 0x0066, 0x0096, 0x00c6, 0x00d6, 0x00f6, + 0x9036, 0x0126, 0x2091, 0x8000, 0x2079, 0x19b6, 0x7838, 0x9065, + 0x0904, 0x816a, 0x600c, 0x0006, 0x600f, 0x0000, 0x783c, 0x9c06, + 0x1168, 0x0036, 0x2019, 0x0001, 0x080c, 0x9254, 0x7833, 0x0000, + 0x901e, 0x7b3e, 0x7b42, 0x7b46, 0x7b4a, 0x003e, 0x080c, 0xb5fb, + 0x0520, 0x6014, 0x2048, 0x6020, 0x9086, 0x0003, 0x1568, 0x3e08, + 0x918e, 0x0002, 0x1188, 0x6010, 0x9005, 0x0170, 0x00b6, 0x2058, + 0xb800, 0x00be, 0xd0bc, 0x0140, 0x6040, 0x9005, 0x1180, 0x2001, + 0x1957, 0x2004, 0x6042, 0x0058, 0xa867, 0x0103, 0xab7a, 0xa877, + 0x0000, 0x080c, 0x6529, 0x080c, 0xb7dd, 0x080c, 0x9a06, 0x000e, + 0x0804, 0x8127, 0x7e3a, 0x7e36, 0x012e, 0x00fe, 0x00de, 0x00ce, + 0x009e, 0x006e, 0x000e, 0x0005, 0x6020, 0x9086, 0x0006, 0x1118, + 0x080c, 0xcf91, 0x0c50, 0x6020, 0x9086, 0x000a, 0x09f8, 0x08e0, + 0x0016, 0x0026, 0x0086, 0x9046, 0x0099, 0x080c, 0x8269, 0x008e, + 0x002e, 0x001e, 0x0005, 0x00f6, 0x0126, 0x2079, 0x19b6, 0x2091, + 0x8000, 0x080c, 0x8300, 0x080c, 0x838e, 0x012e, 0x00fe, 0x0005, + 0x00b6, 0x0096, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0016, + 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, 0x19b6, 0x7614, 0x2660, + 0x2678, 0x8cff, 0x0904, 0x822e, 0x6010, 0x2058, 0xb8a0, 0x9206, + 0x1904, 0x8229, 0x88ff, 0x0120, 0x6054, 0x9106, 0x1904, 0x8229, + 0x7024, 0x9c06, 0x1558, 0x2069, 0x0100, 0x6820, 0xd0a4, 0x1508, + 0x080c, 0x7cc7, 0x080c, 0x8fbb, 0x68c3, 0x0000, 0x080c, 0x9469, + 0x7027, 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0x9384, 0x1000, + 0x0138, 0x2001, 0x0100, 0x080c, 0x2987, 0x9006, 0x080c, 0x2987, + 0x2069, 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e, + 0x0028, 0x6003, 0x0009, 0x630a, 0x0804, 0x8229, 0x7014, 0x9c36, + 0x1110, 0x660c, 0x7616, 0x7010, 0x9c36, 0x1140, 0x2c00, 0x9f36, + 0x0118, 0x2f00, 0x7012, 0x0010, 0x7013, 0x0000, 0x660c, 0x0066, + 0x2c00, 0x9f06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, + 0x6014, 0x2048, 0x080c, 0xb5fb, 0x01e8, 0x6020, 0x9086, 0x0003, + 0x1580, 0x080c, 0xb7fa, 0x1118, 0x080c, 0xa364, 0x0098, 0xa867, + 0x0103, 0xab7a, 0xa877, 0x0000, 0x0016, 0x0036, 0x0086, 0x080c, + 0xb8e3, 0x080c, 0xd28c, 0x080c, 0x6536, 0x008e, 0x003e, 0x001e, + 0x080c, 0xb7dd, 0x080c, 0x9a06, 0x080c, 0x933f, 0x00ce, 0x0804, + 0x81a9, 0x2c78, 0x600c, 0x2060, 0x0804, 0x81a9, 0x012e, 0x000e, + 0x001e, 0x006e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x009e, 0x00be, + 0x0005, 0x6020, 0x9086, 0x0006, 0x1158, 0x0016, 0x0036, 0x0086, + 0x080c, 0xd28c, 0x080c, 0xcf91, 0x008e, 0x003e, 0x001e, 0x08d0, + 0x080c, 0xa364, 0x6020, 0x9086, 0x0002, 0x1160, 0x6004, 0x0006, + 0x9086, 0x0085, 0x000e, 0x0904, 0x820f, 0x9086, 0x008b, 0x0904, + 0x820f, 0x0840, 0x6020, 0x9086, 0x0005, 0x1920, 0x6004, 0x0006, + 0x9086, 0x0085, 0x000e, 0x09c8, 0x9086, 0x008b, 0x09b0, 0x0804, + 0x8222, 0x00b6, 0x00a6, 0x0096, 0x00c6, 0x0006, 0x0126, 0x2091, + 0x8000, 0x9280, 0x1000, 0x2004, 0x905d, 0x0904, 0x82f9, 0x00f6, + 0x00e6, 0x00d6, 0x0066, 0x2071, 0x19b6, 0xbe54, 0x7018, 0x9b06, + 0x1108, 0x761a, 0x701c, 0x9b06, 0x1130, 0x86ff, 0x1118, 0x7018, + 0x701e, 0x0008, 0x761e, 0xb858, 0x904d, 0x0108, 0xae56, 0x96d5, + 0x0000, 0x0110, 0x2900, 0xb05a, 0xb857, 0x0000, 0xb85b, 0x0000, + 0xb800, 0xc0d4, 0xc0dc, 0xb802, 0x080c, 0x5eb1, 0x0904, 0x82f5, + 0x7624, 0x86ff, 0x0904, 0x82e4, 0x9680, 0x0005, 0x2004, 0x9906, + 0x15d8, 0x00d6, 0x2069, 0x0100, 0x68c0, 0x9005, 0x0560, 0x080c, + 0x7cc7, 0x080c, 0x8fbb, 0x68c3, 0x0000, 0x080c, 0x9469, 0x7027, + 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0x9384, 0x1000, 0x0138, + 0x2001, 0x0100, 0x080c, 0x2987, 0x9006, 0x080c, 0x2987, 0x2069, + 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e, 0x00de, + 0x00c6, 0xb83c, 0x9005, 0x0110, 0x8001, 0xb83e, 0x2660, 0x080c, + 0x9a06, 0x00ce, 0x0048, 0x00de, 0x00c6, 0x2660, 0x6003, 0x0009, + 0x630a, 0x00ce, 0x0804, 0x829c, 0x89ff, 0x0158, 0xa867, 0x0103, + 0xab7a, 0xa877, 0x0000, 0x080c, 0xb8e3, 0x080c, 0xd28c, 0x080c, + 0x6536, 0x080c, 0x933f, 0x0804, 0x829c, 0x006e, 0x00de, 0x00ee, + 0x00fe, 0x012e, 0x000e, 0x00ce, 0x009e, 0x00ae, 0x00be, 0x0005, + 0x0096, 0x0006, 0x0066, 0x00c6, 0x00d6, 0x9036, 0x7814, 0x9065, + 0x0904, 0x8361, 0x600c, 0x0006, 0x600f, 0x0000, 0x7824, 0x9c06, + 0x1570, 0x2069, 0x0100, 0x6820, 0xd0a4, 0x1508, 0x080c, 0x7cc7, + 0x080c, 0x8fbb, 0x68c3, 0x0000, 0x080c, 0x9469, 0x7827, 0x0000, + 0x0036, 0x2069, 0x0140, 0x6b04, 0x9384, 0x1000, 0x0138, 0x2001, + 0x0100, 0x080c, 0x2987, 0x9006, 0x080c, 0x2987, 0x2069, 0x0100, + 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e, 0x0040, 0x080c, + 0x625a, 0x1520, 0x6003, 0x0009, 0x630a, 0x2c30, 0x00f8, 0x6014, + 0x2048, 0x080c, 0xb5f9, 0x01b0, 0x6020, 0x9086, 0x0003, 0x1508, + 0x080c, 0xb7fa, 0x1118, 0x080c, 0xa364, 0x0060, 0x080c, 0x625a, + 0x1168, 0xa867, 0x0103, 0xab7a, 0xa877, 0x0000, 0x080c, 0x6536, + 0x080c, 0xb7dd, 0x080c, 0x9a06, 0x080c, 0x933f, 0x000e, 0x0804, + 0x8307, 0x7e16, 0x7e12, 0x00de, 0x00ce, 0x006e, 0x000e, 0x009e, + 0x0005, 0x6020, 0x9086, 0x0006, 0x1118, 0x080c, 0xcf91, 0x0c50, + 0x080c, 0xa364, 0x6020, 0x9086, 0x0002, 0x1150, 0x6004, 0x0006, + 0x9086, 0x0085, 0x000e, 0x0990, 0x9086, 0x008b, 0x0978, 0x08d0, + 0x6020, 0x9086, 0x0005, 0x19b0, 0x6004, 0x0006, 0x9086, 0x0085, + 0x000e, 0x0d18, 0x9086, 0x008b, 0x0d00, 0x0860, 0x0006, 0x0066, + 0x0096, 0x00b6, 0x00c6, 0x00d6, 0x7818, 0x905d, 0x0904, 0x840e, + 0xb854, 0x0006, 0x9006, 0xb856, 0xb85a, 0xb800, 0xc0d4, 0xc0dc, + 0xb802, 0x080c, 0x5eb1, 0x0904, 0x840b, 0x7e24, 0x86ff, 0x0904, + 0x83fe, 0x9680, 0x0005, 0x2004, 0x9906, 0x1904, 0x83fe, 0x00d6, + 0x2069, 0x0100, 0x68c0, 0x9005, 0x0904, 0x83f5, 0x080c, 0x7cc7, + 0x080c, 0x8fbb, 0x68c3, 0x0000, 0x080c, 0x9469, 0x7827, 0x0000, + 0x0036, 0x2069, 0x0140, 0x6b04, 0x9384, 0x1000, 0x0138, 0x2001, + 0x0100, 0x080c, 0x2987, 0x9006, 0x080c, 0x2987, 0x2069, 0x0100, + 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e, 0x00de, 0x00c6, + 0x3e08, 0x918e, 0x0002, 0x1168, 0xb800, 0xd0bc, 0x0150, 0x9680, + 0x0010, 0x200c, 0x81ff, 0x1518, 0x2009, 0x1957, 0x210c, 0x2102, + 0x00f0, 0xb83c, 0x9005, 0x0110, 0x8001, 0xb83e, 0x2660, 0x600f, + 0x0000, 0x080c, 0x9a06, 0x00ce, 0x0048, 0x00de, 0x00c6, 0x2660, + 0x6003, 0x0009, 0x630a, 0x00ce, 0x0804, 0x83a1, 0x89ff, 0x0138, + 0xa867, 0x0103, 0xab7a, 0xa877, 0x0000, 0x080c, 0x6536, 0x080c, + 0x933f, 0x0804, 0x83a1, 0x000e, 0x0804, 0x8395, 0x781e, 0x781a, + 0x00de, 0x00ce, 0x00be, 0x009e, 0x006e, 0x000e, 0x0005, 0x00e6, + 0x00d6, 0x0096, 0x0066, 0xb800, 0xd0dc, 0x01a0, 0xb84c, 0x904d, + 0x0188, 0xa878, 0x9606, 0x1170, 0x2071, 0x19b6, 0x7024, 0x9035, + 0x0148, 0x9080, 0x0005, 0x2004, 0x9906, 0x1120, 0xb800, 0xc0dc, + 0xb802, 0x0029, 0x006e, 0x009e, 0x00de, 0x00ee, 0x0005, 0x00f6, + 0x2079, 0x0100, 0x78c0, 0x9005, 0x1138, 0x00c6, 0x2660, 0x6003, + 0x0009, 0x630a, 0x00ce, 0x04b8, 0x080c, 0x8fbb, 0x78c3, 0x0000, + 0x080c, 0x9469, 0x7027, 0x0000, 0x0036, 0x2079, 0x0140, 0x7b04, + 0x9384, 0x1000, 0x0138, 0x2001, 0x0100, 0x080c, 0x2987, 0x9006, + 0x080c, 0x2987, 0x2079, 0x0100, 0x7824, 0xd084, 0x0110, 0x7827, + 0x0001, 0x080c, 0x9469, 0x003e, 0x080c, 0x5eb1, 0x00c6, 0xb83c, + 0x9005, 0x0110, 0x8001, 0xb83e, 0x2660, 0x080c, 0x99d6, 0x00ce, + 0xa867, 0x0103, 0xab7a, 0xa877, 0x0000, 0x080c, 0xb8e3, 0x080c, + 0x6536, 0x080c, 0x933f, 0x00fe, 0x0005, 0x00b6, 0x00e6, 0x00c6, + 0x2011, 0x0101, 0x2204, 0xc0c4, 0x2012, 0x2001, 0x180c, 0x2014, + 0xc2e4, 0x2202, 0x2071, 0x19b6, 0x7004, 0x9084, 0x0007, 0x0002, + 0x849a, 0x849e, 0x84b5, 0x84de, 0x851c, 0x849a, 0x84b5, 0x8498, + 0x080c, 0x0db2, 0x00ce, 0x00ee, 0x00be, 0x0005, 0x7024, 0x9065, + 0x0148, 0x7020, 0x8001, 0x7022, 0x600c, 0x9015, 0x0158, 0x7216, + 0x600f, 0x0000, 0x7007, 0x0000, 0x7027, 0x0000, 0x00ce, 0x00ee, + 0x00be, 0x0005, 0x7216, 0x7212, 0x0ca8, 0x6010, 0x2058, 0x080c, + 0x5eb1, 0xb800, 0xc0dc, 0xb802, 0x7007, 0x0000, 0x7027, 0x0000, + 0x7020, 0x8001, 0x7022, 0x1148, 0x2001, 0x180c, 0x2014, 0xd2ec, + 0x1180, 0x00ce, 0x00ee, 0x00be, 0x0005, 0xb854, 0x9015, 0x0120, + 0x721e, 0x080c, 0x8582, 0x0ca8, 0x7218, 0x721e, 0x080c, 0x8582, + 0x0c80, 0xc2ec, 0x2202, 0x080c, 0x865d, 0x0c58, 0x7024, 0x9065, + 0x05b8, 0x700c, 0x9c06, 0x1160, 0x080c, 0x933f, 0x600c, 0x9015, + 0x0120, 0x720e, 0x600f, 0x0000, 0x0448, 0x720e, 0x720a, 0x0430, + 0x7014, 0x9c06, 0x1160, 0x080c, 0x933f, 0x600c, 0x9015, 0x0120, + 0x7216, 0x600f, 0x0000, 0x00d0, 0x7216, 0x7212, 0x00b8, 0x6020, + 0x9086, 0x0003, 0x1198, 0x6010, 0x2058, 0x080c, 0x5eb1, 0xb800, + 0xc0dc, 0xb802, 0x080c, 0x933f, 0x701c, 0x9065, 0x0138, 0xb854, + 0x9015, 0x0110, 0x721e, 0x0010, 0x7218, 0x721e, 0x7027, 0x0000, + 0x00ce, 0x00ee, 0x00be, 0x0005, 0x7024, 0x9065, 0x0140, 0x080c, + 0x933f, 0x600c, 0x9015, 0x0158, 0x720e, 0x600f, 0x0000, 0x080c, + 0x9469, 0x7027, 0x0000, 0x00ce, 0x00ee, 0x00be, 0x0005, 0x720e, + 0x720a, 0x0ca8, 0x00d6, 0x2069, 0x19b6, 0x6830, 0x9084, 0x0003, + 0x0002, 0x853f, 0x8541, 0x8565, 0x853d, 0x080c, 0x0db2, 0x00de, + 0x0005, 0x00c6, 0x6840, 0x9086, 0x0001, 0x01b8, 0x683c, 0x9065, + 0x0130, 0x600c, 0x9015, 0x0170, 0x6a3a, 0x600f, 0x0000, 0x6833, + 0x0000, 0x683f, 0x0000, 0x2011, 0x19d5, 0x2013, 0x0000, 0x00ce, + 0x00de, 0x0005, 0x683a, 0x6836, 0x0c90, 0x6843, 0x0000, 0x6838, + 0x9065, 0x0d68, 0x6003, 0x0003, 0x0c50, 0x00c6, 0x9006, 0x6842, + 0x6846, 0x684a, 0x683c, 0x9065, 0x0160, 0x600c, 0x9015, 0x0130, + 0x6a3a, 0x600f, 0x0000, 0x683f, 0x0000, 0x0018, 0x683e, 0x683a, + 0x6836, 0x00ce, 0x00de, 0x0005, 0x2001, 0x180c, 0x200c, 0xc1e5, + 0x2102, 0x0005, 0x2001, 0x180c, 0x200c, 0xd1ec, 0x0120, 0xc1ec, + 0x2102, 0x080c, 0x865d, 0x2001, 0x19c2, 0x2004, 0x9086, 0x0001, + 0x0d58, 0x00d6, 0x2069, 0x19b6, 0x6804, 0x9084, 0x0007, 0x0002, + 0x85a2, 0x8645, 0x8645, 0x8645, 0x8645, 0x8647, 0x8645, 0x85a0, + 0x080c, 0x0db2, 0x6820, 0x9005, 0x1110, 0x00de, 0x0005, 0x00c6, + 0x680c, 0x9065, 0x0150, 0x6807, 0x0004, 0x6826, 0x682b, 0x0000, + 0x080c, 0x86b3, 0x00ce, 0x00de, 0x0005, 0x6814, 0x9065, 0x0150, + 0x6807, 0x0001, 0x6826, 0x682b, 0x0000, 0x080c, 0x86b3, 0x00ce, + 0x00de, 0x0005, 0x00b6, 0x00e6, 0x6a1c, 0x92dd, 0x0000, 0x0904, + 0x8631, 0xb84c, 0x900d, 0x0118, 0xb888, 0x9005, 0x01a0, 0xb854, + 0x905d, 0x0120, 0x920e, 0x0904, 0x8631, 0x0028, 0x6818, 0x920e, + 0x0904, 0x8631, 0x2058, 0xb84c, 0x900d, 0x0d88, 0xb888, 0x9005, + 0x1d70, 0x2b00, 0x681e, 0xbb3c, 0xb838, 0x9302, 0x1e40, 0x080c, + 0x99ad, 0x0904, 0x8631, 0x8318, 0xbb3e, 0x6116, 0x2b10, 0x6212, + 0x0096, 0x2148, 0xa880, 0x9084, 0x00ff, 0x605e, 0xa883, 0x0000, + 0xa884, 0x009e, 0x908a, 0x199a, 0x0210, 0x2001, 0x1999, 0x8003, + 0x801b, 0x831b, 0x9318, 0x631a, 0x6114, 0x0096, 0x2148, 0xa964, + 0x009e, 0x918c, 0x00ff, 0x918e, 0x0048, 0x0538, 0x00f6, 0x2c78, + 0x2061, 0x0100, 0xbab0, 0x629a, 0x2069, 0x0200, 0x2071, 0x0240, + 0x080c, 0x8bf2, 0x2069, 0x19b6, 0xbb00, 0xc3dd, 0xbb02, 0x6807, + 0x0002, 0x2f18, 0x6b26, 0x682b, 0x0000, 0x7823, 0x0003, 0x7803, + 0x0001, 0x7807, 0x0040, 0x00fe, 0x00ee, 0x00be, 0x00ce, 0x00de, + 0x0005, 0x00ee, 0x00be, 0x00ce, 0x0cd0, 0xbb00, 0xc3dd, 0xbb02, + 0x6807, 0x0006, 0x2f18, 0x6b26, 0x682b, 0x0000, 0x080c, 0x97f2, + 0x00ee, 0x00be, 0x00ce, 0x00de, 0x0005, 0x00de, 0x0005, 0x00c6, + 0x680c, 0x9065, 0x0138, 0x6807, 0x0004, 0x6826, 0x682b, 0x0000, + 0x080c, 0x86b3, 0x00ce, 0x00de, 0x0005, 0x2001, 0x180c, 0x2014, + 0xc2ed, 0x2202, 0x00de, 0x00fe, 0x0005, 0x00f6, 0x00d6, 0x2069, + 0x19b6, 0x6830, 0x9086, 0x0000, 0x1548, 0x2001, 0x180c, 0x2014, + 0xd2e4, 0x0130, 0xc2e4, 0x2202, 0x080c, 0x8591, 0x2069, 0x19b6, + 0x2001, 0x180c, 0x200c, 0xd1c4, 0x11e0, 0x6838, 0x907d, 0x01b0, + 0x6a04, 0x9296, 0x0000, 0x1588, 0x6833, 0x0001, 0x683e, 0x6847, + 0x0000, 0x684b, 0x0000, 0x0126, 0x00f6, 0x2091, 0x2400, 0x002e, + 0x080c, 0x19f2, 0x1178, 0x012e, 0x080c, 0x8e0a, 0x00de, 0x00fe, + 0x0005, 0xc1c4, 0x2102, 0x0066, 0x2031, 0x0001, 0x080c, 0x6d03, + 0x006e, 0x08d8, 0x012e, 0x6843, 0x0000, 0x7803, 0x0002, 0x780c, + 0x9015, 0x0140, 0x6a3a, 0x780f, 0x0000, 0x6833, 0x0000, 0x683f, + 0x0000, 0x0c20, 0x683a, 0x6836, 0x0cc0, 0x6a04, 0x9296, 0x0006, + 0x0958, 0x0804, 0x8655, 0x6020, 0x9084, 0x000f, 0x000b, 0x0005, + 0x86c7, 0x86cc, 0x8b2c, 0x8bbb, 0x86cc, 0x8b2c, 0x8bbb, 0x86c7, + 0x86cc, 0x86c7, 0x86c7, 0x86c7, 0x86c7, 0x86c7, 0x86c7, 0x080c, + 0x847d, 0x080c, 0x8582, 0x0005, 0x00b6, 0x0156, 0x0136, 0x0146, + 0x01c6, 0x01d6, 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x2069, 0x0200, + 0x2071, 0x0240, 0x6004, 0x908a, 0x0053, 0x1a0c, 0x0db2, 0x6110, + 0x2158, 0xb9b0, 0x2c78, 0x2061, 0x0100, 0x619a, 0x908a, 0x0040, + 0x1a04, 0x8738, 0x005b, 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x01de, + 0x01ce, 0x014e, 0x013e, 0x015e, 0x00be, 0x0005, 0x88af, 0x88ea, + 0x8913, 0x89bb, 0x89dd, 0x89e3, 0x89f0, 0x89f8, 0x8a04, 0x8a0a, + 0x8a1b, 0x8a0a, 0x8a73, 0x89f8, 0x8a7f, 0x8a85, 0x8a04, 0x8a85, + 0x8a91, 0x8736, 0x8736, 0x8736, 0x8736, 0x8736, 0x8736, 0x8736, + 0x8736, 0x8736, 0x8736, 0x8736, 0x910b, 0x912e, 0x913f, 0x915f, + 0x9191, 0x89f0, 0x8736, 0x89f0, 0x8a0a, 0x8736, 0x8913, 0x89bb, + 0x8736, 0x9556, 0x8a0a, 0x8736, 0x9572, 0x8a0a, 0x8736, 0x8a04, + 0x88a9, 0x8759, 0x8736, 0x958e, 0x95fb, 0x96d2, 0x8736, 0x96df, + 0x89ed, 0x970a, 0x8736, 0x919b, 0x9737, 0x8736, 0x080c, 0x0db2, + 0x2100, 0x005b, 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x01de, 0x01ce, + 0x014e, 0x013e, 0x015e, 0x00be, 0x0005, 0x8757, 0x8757, 0x8757, + 0x8780, 0x882c, 0x8837, 0x8757, 0x8757, 0x8757, 0x887e, 0x888a, + 0x879b, 0x8757, 0x87b6, 0x87ea, 0x98b4, 0x98f9, 0x8a0a, 0x080c, + 0x0db2, 0x00d6, 0x0096, 0x080c, 0x8aa4, 0x7003, 0x2414, 0x7007, + 0x0018, 0x700b, 0x0800, 0x7814, 0x2048, 0xa83c, 0x700e, 0xa850, + 0x7022, 0xa854, 0x7026, 0x60c3, 0x0018, 0x080c, 0x8f8f, 0x009e, + 0x00de, 0x0005, 0x7810, 0x00b6, 0x2058, 0xb8a0, 0x00be, 0x080c, + 0x9940, 0x1118, 0x9084, 0xff80, 0x0110, 0x9085, 0x0001, 0x0005, + 0x00d6, 0x0096, 0x080c, 0x8aa4, 0x7003, 0x0500, 0x7814, 0x2048, + 0xa874, 0x700a, 0xa878, 0x700e, 0xa87c, 0x7012, 0xa880, 0x7016, + 0xa884, 0x701a, 0xa888, 0x701e, 0x60c3, 0x0010, 0x080c, 0x8f8f, + 0x009e, 0x00de, 0x0005, 0x00d6, 0x0096, 0x080c, 0x8aa4, 0x7003, + 0x0500, 0x7814, 0x2048, 0xa8cc, 0x700a, 0xa8d0, 0x700e, 0xa8d4, + 0x7012, 0xa8d8, 0x7016, 0xa8dc, 0x701a, 0xa8e0, 0x701e, 0x60c3, + 0x0010, 0x080c, 0x8f8f, 0x009e, 0x00de, 0x0005, 0x00d6, 0x0096, + 0x0126, 0x2091, 0x8000, 0x080c, 0x8aa4, 0x20e9, 0x0000, 0x2001, + 0x1972, 0x2003, 0x0000, 0x7814, 0x2048, 0xa814, 0x8003, 0x60c2, + 0xa830, 0x20a8, 0xa860, 0x20e0, 0xa85c, 0x9080, 0x001b, 0x2098, + 0x2001, 0x1972, 0x0016, 0x200c, 0x2001, 0x0001, 0x080c, 0x20be, + 0x080c, 0xc2e6, 0x9006, 0x080c, 0x20be, 0x001e, 0xa804, 0x9005, + 0x0110, 0x2048, 0x0c28, 0x04d9, 0x080c, 0x8f8f, 0x012e, 0x009e, + 0x00de, 0x0005, 0x00d6, 0x0096, 0x0126, 0x2091, 0x8000, 0x080c, + 0x8aef, 0x20e9, 0x0000, 0x2001, 0x1972, 0x2003, 0x0000, 0x7814, + 0x2048, 0xa86f, 0x0200, 0xa873, 0x0000, 0xa814, 0x8003, 0x60c2, + 0xa830, 0x20a8, 0xa860, 0x20e0, 0xa85c, 0x9080, 0x001b, 0x2098, + 0x2001, 0x1972, 0x0016, 0x200c, 0x080c, 0xc2e6, 0x001e, 0xa804, + 0x9005, 0x0110, 0x2048, 0x0c60, 0x0051, 0x7814, 0x2048, 0x080c, + 0x0f87, 0x080c, 0x8f8f, 0x012e, 0x009e, 0x00de, 0x0005, 0x60c0, + 0x8004, 0x9084, 0x0003, 0x9005, 0x0130, 0x9082, 0x0004, 0x20a3, + 0x0000, 0x8000, 0x1de0, 0x0005, 0x080c, 0x8aa4, 0x7003, 0x7800, + 0x7808, 0x8007, 0x700a, 0x60c3, 0x0008, 0x0804, 0x8f8f, 0x00d6, + 0x00e6, 0x080c, 0x8aef, 0x7814, 0x9084, 0xff00, 0x2073, 0x0200, + 0x8e70, 0x8e70, 0x9095, 0x0010, 0x2272, 0x8e70, 0x2073, 0x0034, + 0x8e70, 0x2069, 0x1805, 0x20a9, 0x0004, 0x2d76, 0x8d68, 0x8e70, + 0x1f04, 0x884d, 0x2069, 0x1801, 0x20a9, 0x0004, 0x2d76, 0x8d68, + 0x8e70, 0x1f04, 0x8856, 0x2069, 0x1982, 0x9086, 0xdf00, 0x0110, + 0x2069, 0x199c, 0x20a9, 0x001a, 0x9e86, 0x0260, 0x1148, 0x00c6, + 0x2061, 0x0200, 0x6010, 0x8000, 0x6012, 0x00ce, 0x2071, 0x0240, + 0x2d04, 0x8007, 0x2072, 0x8d68, 0x8e70, 0x1f04, 0x8864, 0x60c3, + 0x004c, 0x080c, 0x8f8f, 0x00ee, 0x00de, 0x0005, 0x080c, 0x8aa4, + 0x7003, 0x6300, 0x7007, 0x0028, 0x7808, 0x700e, 0x60c3, 0x0008, + 0x0804, 0x8f8f, 0x00d6, 0x0026, 0x0016, 0x080c, 0x8aef, 0x7003, + 0x0200, 0x7814, 0x700e, 0x00e6, 0x9ef0, 0x0004, 0x2009, 0x0001, + 0x2011, 0x000c, 0x2073, 0x0800, 0x8e70, 0x2073, 0x0000, 0x00ee, + 0x7206, 0x710a, 0x62c2, 0x080c, 0x8f8f, 0x001e, 0x002e, 0x00de, + 0x0005, 0x2001, 0x1816, 0x2004, 0x609a, 0x0804, 0x8f8f, 0x080c, + 0x8aa4, 0x7003, 0x5200, 0x2069, 0x1853, 0x6804, 0xd084, 0x0130, + 0x6828, 0x0016, 0x080c, 0x2509, 0x710e, 0x001e, 0x20a9, 0x0004, + 0x20e1, 0x0001, 0x2099, 0x1805, 0x20e9, 0x0000, 0x20a1, 0x0250, + 0x4003, 0x20a9, 0x0004, 0x2099, 0x1801, 0x20a1, 0x0254, 0x4003, + 0x080c, 0x9940, 0x1120, 0xb8a0, 0x9082, 0x007f, 0x0248, 0x2001, + 0x181d, 0x2004, 0x7032, 0x2001, 0x181e, 0x2004, 0x7036, 0x0030, + 0x2001, 0x1816, 0x2004, 0x9084, 0x00ff, 0x7036, 0x60c3, 0x001c, + 0x0804, 0x8f8f, 0x080c, 0x8aa4, 0x7003, 0x0500, 0x080c, 0x9940, + 0x1120, 0xb8a0, 0x9082, 0x007f, 0x0248, 0x2001, 0x181d, 0x2004, + 0x700a, 0x2001, 0x181e, 0x2004, 0x700e, 0x0030, 0x2001, 0x1816, + 0x2004, 0x9084, 0x00ff, 0x700e, 0x20a9, 0x0004, 0x20e1, 0x0001, + 0x2099, 0x1805, 0x20e9, 0x0000, 0x20a1, 0x0250, 0x4003, 0x60c3, + 0x0010, 0x0804, 0x8f8f, 0x080c, 0x8aa4, 0x9006, 0x080c, 0x626e, + 0xb8a0, 0x9086, 0x007e, 0x1130, 0x7003, 0x0400, 0x620c, 0xc2b4, + 0x620e, 0x0058, 0x7814, 0x0096, 0x904d, 0x0120, 0x9006, 0xa89a, + 0xa8a6, 0xa8aa, 0x009e, 0x7003, 0x0300, 0xb8a0, 0x9086, 0x007e, + 0x1904, 0x8982, 0x00d6, 0x2069, 0x193d, 0x2001, 0x1835, 0x2004, + 0xd0a4, 0x0188, 0x6800, 0x700a, 0x6808, 0x9084, 0x2000, 0x7012, + 0x080c, 0x9957, 0x680c, 0x7016, 0x701f, 0x2710, 0x6818, 0x7022, + 0x681c, 0x7026, 0x0090, 0x6800, 0x700a, 0x6804, 0x700e, 0x6808, + 0x080c, 0x6c53, 0x1118, 0x9084, 0x37ff, 0x0010, 0x9084, 0x3fff, + 0x7012, 0x080c, 0x9957, 0x680c, 0x7016, 0x00de, 0x20a9, 0x0004, + 0x20e1, 0x0001, 0x2099, 0x1805, 0x20e9, 0x0000, 0x20a1, 0x0256, + 0x4003, 0x20a9, 0x0004, 0x2099, 0x1801, 0x20a1, 0x025a, 0x4003, + 0x00d6, 0x080c, 0x97b9, 0x2069, 0x1945, 0x2071, 0x024e, 0x6800, + 0xc0dd, 0x7002, 0x080c, 0x5117, 0xd0e4, 0x0110, 0x680c, 0x700e, + 0x00de, 0x04a8, 0x2001, 0x1835, 0x2004, 0xd0a4, 0x0170, 0x0016, + 0x2001, 0x193e, 0x200c, 0x60e0, 0x9106, 0x0130, 0x2100, 0x60e3, + 0x0000, 0x080c, 0x254a, 0x61e2, 0x001e, 0x20e1, 0x0001, 0x2099, + 0x193d, 0x20e9, 0x0000, 0x20a1, 0x024e, 0x20a9, 0x0008, 0x4003, + 0x20a9, 0x0004, 0x2099, 0x1805, 0x20a1, 0x0256, 0x4003, 0x20a9, + 0x0004, 0x2099, 0x1801, 0x20a1, 0x025a, 0x4003, 0x080c, 0x97b9, + 0x20a1, 0x024e, 0x20a9, 0x0008, 0x2099, 0x1945, 0x4003, 0x60c3, + 0x0074, 0x0804, 0x8f8f, 0x080c, 0x8aa4, 0x7003, 0x2010, 0x7007, + 0x0014, 0x700b, 0x0800, 0x700f, 0x2000, 0x9006, 0x00f6, 0x2079, + 0x1853, 0x7904, 0x00fe, 0xd1ac, 0x1110, 0x9085, 0x0020, 0xd1a4, + 0x0110, 0x9085, 0x0010, 0x9085, 0x0002, 0x00d6, 0x0804, 0x8a54, + 0x7026, 0x60c3, 0x0014, 0x0804, 0x8f8f, 0x080c, 0x8aa4, 0x7003, + 0x5000, 0x0804, 0x892d, 0x080c, 0x8aa4, 0x7003, 0x2110, 0x7007, + 0x0014, 0x60c3, 0x0014, 0x0804, 0x8f8f, 0x080c, 0x8ae6, 0x0010, + 0x080c, 0x8aef, 0x7003, 0x0200, 0x60c3, 0x0004, 0x0804, 0x8f8f, + 0x080c, 0x8aef, 0x7003, 0x0100, 0x700b, 0x0003, 0x700f, 0x2a00, + 0x60c3, 0x0008, 0x0804, 0x8f8f, 0x080c, 0x8aef, 0x7003, 0x0200, + 0x0804, 0x892d, 0x080c, 0x8aef, 0x7003, 0x0100, 0x782c, 0x9005, + 0x0110, 0x700a, 0x0010, 0x700b, 0x0003, 0x7814, 0x700e, 0x60c3, + 0x0008, 0x0804, 0x8f8f, 0x00d6, 0x080c, 0x8aef, 0x7003, 0x0210, + 0x7007, 0x0014, 0x700b, 0x0800, 0xb894, 0x9086, 0x0014, 0x1198, + 0xb99c, 0x9184, 0x0030, 0x0190, 0xb998, 0x9184, 0xc000, 0x1140, + 0xd1ec, 0x0118, 0x700f, 0x2100, 0x0058, 0x700f, 0x0100, 0x0040, + 0x700f, 0x0400, 0x0028, 0x700f, 0x0700, 0x0010, 0x700f, 0x0800, + 0x00f6, 0x2079, 0x1853, 0x7904, 0x00fe, 0xd1ac, 0x1110, 0x9085, + 0x0020, 0xd1a4, 0x0110, 0x9085, 0x0010, 0x2009, 0x1875, 0x210c, + 0xd184, 0x1110, 0x9085, 0x0002, 0x0026, 0x2009, 0x1873, 0x210c, + 0xd1e4, 0x0150, 0xc0c5, 0xbabc, 0xd28c, 0x1108, 0xc0cd, 0x9094, + 0x0030, 0x9296, 0x0010, 0x0140, 0xd1ec, 0x0130, 0x9094, 0x0030, + 0x9296, 0x0010, 0x0108, 0xc0bd, 0x002e, 0x7026, 0x60c3, 0x0014, + 0x00de, 0x0804, 0x8f8f, 0x080c, 0x8aef, 0x7003, 0x0210, 0x7007, + 0x0014, 0x700f, 0x0100, 0x60c3, 0x0014, 0x0804, 0x8f8f, 0x080c, + 0x8aef, 0x7003, 0x0200, 0x0804, 0x88b3, 0x080c, 0x8aef, 0x7003, + 0x0100, 0x700b, 0x0003, 0x700f, 0x2a00, 0x60c3, 0x0008, 0x0804, + 0x8f8f, 0x080c, 0x8aef, 0x7003, 0x0100, 0x700b, 0x000b, 0x60c3, + 0x0008, 0x0804, 0x8f8f, 0x0026, 0x00d6, 0x0036, 0x0046, 0x2019, + 0x3200, 0x2021, 0x0800, 0x0040, 0x0026, 0x00d6, 0x0036, 0x0046, + 0x2019, 0x2200, 0x2021, 0x0100, 0x080c, 0x97ce, 0xb810, 0x9305, + 0x7002, 0xb814, 0x7006, 0x2069, 0x1800, 0x6874, 0x700a, 0x6878, + 0x700e, 0x9485, 0x0029, 0x7012, 0x004e, 0x003e, 0x00de, 0x080c, + 0x8f7d, 0x721a, 0x9f95, 0x0000, 0x7222, 0x7027, 0xffff, 0x2071, + 0x024c, 0x002e, 0x0005, 0x0026, 0x080c, 0x97ce, 0x7003, 0x02ff, + 0x7007, 0xfffc, 0x00d6, 0x2069, 0x1800, 0x6874, 0x700a, 0x6878, + 0x700e, 0x00de, 0x7013, 0x2029, 0x0c10, 0x7003, 0x0100, 0x7007, + 0x0000, 0x700b, 0xfc02, 0x700f, 0x0000, 0x0005, 0x0026, 0x00d6, + 0x0036, 0x0046, 0x2019, 0x3300, 0x2021, 0x0800, 0x0040, 0x0026, + 0x00d6, 0x0036, 0x0046, 0x2019, 0x2300, 0x2021, 0x0100, 0x080c, + 0x97ce, 0xb810, 0x9305, 0x7002, 0xb814, 0x7006, 0x2069, 0x1800, + 0xb810, 0x9005, 0x1140, 0xb814, 0x9005, 0x1128, 0x700b, 0x00ff, + 0x700f, 0xfffe, 0x0020, 0x6874, 0x700a, 0x6878, 0x700e, 0x0000, + 0x9485, 0x0098, 0x7012, 0x004e, 0x003e, 0x00de, 0x080c, 0x8f7d, + 0x721a, 0x7a08, 0x7222, 0x2f10, 0x7226, 0x2071, 0x024c, 0x002e, + 0x0005, 0x080c, 0x8f7d, 0x721a, 0x7a08, 0x7222, 0x7814, 0x7026, + 0x2071, 0x024c, 0x002e, 0x0005, 0x00b6, 0x00c6, 0x00d6, 0x00e6, + 0x00f6, 0x2069, 0x0200, 0x2071, 0x0240, 0x6004, 0x908a, 0x0085, + 0x0a0c, 0x0db2, 0x908a, 0x0092, 0x1a0c, 0x0db2, 0x6110, 0x2158, + 0xb9b0, 0x2c78, 0x2061, 0x0100, 0x619a, 0x9082, 0x0085, 0x0033, + 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x00be, 0x0005, 0x8b5d, 0x8b6c, + 0x8b77, 0x8b5b, 0x8b5b, 0x8b5b, 0x8b5d, 0x8b5b, 0x8b5b, 0x8b5b, + 0x8b5b, 0x8b5b, 0x8b5b, 0x080c, 0x0db2, 0x0411, 0x60c3, 0x0000, + 0x0026, 0x080c, 0x283d, 0x0228, 0x2011, 0x0101, 0x2204, 0xc0c5, + 0x2012, 0x002e, 0x0804, 0x8f8f, 0x0431, 0x7808, 0x700a, 0x7814, + 0x700e, 0x7017, 0xffff, 0x60c3, 0x000c, 0x0804, 0x8f8f, 0x0479, + 0x7003, 0x0003, 0x7007, 0x0300, 0x60c3, 0x0004, 0x0804, 0x8f8f, + 0x0026, 0x080c, 0x97ce, 0xb810, 0x9085, 0x8100, 0x7002, 0xb814, + 0x7006, 0x2069, 0x1800, 0x6874, 0x700a, 0x6878, 0x700e, 0x7013, + 0x0009, 0x0804, 0x8abf, 0x0026, 0x080c, 0x97ce, 0xb810, 0x9085, + 0x8400, 0x7002, 0xb814, 0x7006, 0x2069, 0x1800, 0x6874, 0x700a, + 0x6878, 0x700e, 0x2001, 0x0099, 0x7012, 0x0804, 0x8b21, 0x0026, + 0x080c, 0x97ce, 0xb810, 0x9085, 0x8500, 0x7002, 0xb814, 0x7006, + 0x2069, 0x1800, 0x6874, 0x700a, 0x6878, 0x700e, 0x2001, 0x0099, + 0x7012, 0x0804, 0x8b21, 0x00b6, 0x00c6, 0x00d6, 0x00e6, 0x00f6, + 0x2c78, 0x2069, 0x0200, 0x2071, 0x0240, 0x7804, 0x908a, 0x0040, + 0x0a0c, 0x0db2, 0x908a, 0x0054, 0x1a0c, 0x0db2, 0x7910, 0x2158, + 0xb9b0, 0x2061, 0x0100, 0x619a, 0x9082, 0x0040, 0x0033, 0x00fe, + 0x00ee, 0x00de, 0x00ce, 0x00be, 0x0005, 0x8bf2, 0x8c99, 0x8c6c, + 0x8dbb, 0x8bf0, 0x8bf0, 0x8bf0, 0x8bf0, 0x8bf0, 0x8bf0, 0x8bf0, + 0x930c, 0x9318, 0x9324, 0x9330, 0x8bf0, 0x9716, 0x8bf0, 0x9300, + 0x080c, 0x0db2, 0x0096, 0x780b, 0xffff, 0x080c, 0x8c48, 0x7914, + 0x2148, 0xa978, 0x7956, 0x7132, 0xa97c, 0x9184, 0x000f, 0x1118, + 0x2001, 0x0005, 0x0040, 0xd184, 0x0118, 0x2001, 0x0004, 0x0018, + 0x9084, 0x0006, 0x8004, 0x2010, 0x785c, 0x9084, 0x00ff, 0x8007, + 0x9205, 0x7042, 0xd1ac, 0x0128, 0x7047, 0x0002, 0x080c, 0x1582, + 0x0050, 0xd1b4, 0x0118, 0x7047, 0x0001, 0x0028, 0x7047, 0x0000, + 0x9016, 0x2230, 0x0010, 0xaab0, 0xaeac, 0x726a, 0x766e, 0x20a9, + 0x0008, 0x20e9, 0x0000, 0xa860, 0x20e0, 0xa85c, 0x9080, 0x0023, + 0x2098, 0x20a1, 0x0252, 0x2069, 0x0200, 0x6813, 0x0018, 0x4003, + 0x6813, 0x0008, 0x60c3, 0x0020, 0x6017, 0x0009, 0x2001, 0x19d2, + 0x2003, 0x07d0, 0x2001, 0x19d1, 0x2003, 0x0009, 0x009e, 0x0005, + 0x6813, 0x0008, 0xba8c, 0x8210, 0xb8bc, 0xd084, 0x0128, 0x7a46, + 0x7b14, 0x7b4a, 0x722e, 0x732a, 0x9294, 0x00ff, 0xba8e, 0x8217, + 0x721a, 0xba10, 0x9295, 0x0600, 0x7202, 0xba14, 0x7206, 0x2069, + 0x1800, 0x6a74, 0x720a, 0x6a78, 0x720e, 0x7013, 0x0829, 0x2f10, + 0x7222, 0x7027, 0xffff, 0x0005, 0x00d6, 0x0096, 0x0081, 0x7814, + 0x2048, 0xa890, 0x7002, 0xa88c, 0x7006, 0xa8b0, 0x700a, 0xa8ac, + 0x700e, 0x60c3, 0x000c, 0x009e, 0x00de, 0x0804, 0x8f8f, 0x6813, + 0x0008, 0xb810, 0x9085, 0x0500, 0x7002, 0xb814, 0x7006, 0x2069, + 0x1800, 0x6874, 0x700a, 0x6878, 0x700e, 0x7013, 0x0889, 0x080c, + 0x8f7d, 0x721a, 0x7a08, 0x7222, 0x2f10, 0x7226, 0x2071, 0x024c, + 0x0005, 0x00d6, 0x0096, 0x080c, 0x8d99, 0x7814, 0x2048, 0x080c, + 0xb5f9, 0x1130, 0x7814, 0x9084, 0x0700, 0x8007, 0x0033, 0x0010, + 0x9006, 0x001b, 0x009e, 0x00de, 0x0005, 0x8cb7, 0x8d20, 0x8d30, + 0x8d56, 0x8d62, 0x8d73, 0x8d7b, 0x8cb5, 0x080c, 0x0db2, 0x0016, + 0x0036, 0xa97c, 0x918c, 0x0003, 0x0118, 0x9186, 0x0003, 0x1198, + 0xaba8, 0x7824, 0xd0cc, 0x1168, 0x7316, 0xa898, 0x701a, 0xa894, + 0x701e, 0x003e, 0x001e, 0x2001, 0x1980, 0x2004, 0x60c2, 0x0804, + 0x8f8f, 0xc3e5, 0x0c88, 0x9186, 0x0001, 0x190c, 0x0db2, 0xaba8, + 0x7824, 0xd0cc, 0x1904, 0x8d1d, 0x7316, 0xa898, 0x701a, 0xa894, + 0x701e, 0xa8a4, 0x7026, 0xa8ac, 0x702e, 0x2009, 0x0018, 0x9384, + 0x0300, 0x0570, 0xd3c4, 0x0110, 0xa8ac, 0x9108, 0xd3cc, 0x0110, + 0xa8a4, 0x9108, 0x6810, 0x9085, 0x0010, 0x6812, 0x2011, 0x0258, + 0x20e9, 0x0000, 0x22a0, 0x0156, 0x20a9, 0x0008, 0xa860, 0x20e0, + 0xa85c, 0x9080, 0x002c, 0x2098, 0x4003, 0x6810, 0x8000, 0x6812, + 0x2011, 0x0240, 0x22a0, 0x20a9, 0x0005, 0x4003, 0x6810, 0xc084, + 0x6812, 0x015e, 0x9184, 0x0003, 0x0118, 0x2019, 0x0245, 0x201a, + 0x61c2, 0x003e, 0x001e, 0x0804, 0x8f8f, 0xc3e5, 0x0804, 0x8cdc, + 0x2011, 0x0008, 0x2001, 0x180e, 0x2004, 0xd0a4, 0x0110, 0x2011, + 0x0028, 0x7824, 0xd0cc, 0x1110, 0x7216, 0x0470, 0x0ce8, 0xc2e5, + 0x2011, 0x0302, 0x0016, 0x782c, 0x701a, 0x7930, 0x711e, 0x9105, + 0x0108, 0xc2dd, 0x001e, 0x7824, 0xd0cc, 0x0108, 0xc2e5, 0x7216, + 0x7027, 0x0012, 0x702f, 0x0008, 0x7043, 0x7000, 0x7047, 0x0500, + 0x704f, 0x000a, 0x2069, 0x0200, 0x6813, 0x0009, 0x2071, 0x0240, + 0x700b, 0x2500, 0x60c3, 0x0032, 0x0804, 0x8f8f, 0x2011, 0x0028, + 0x7824, 0xd0cc, 0x1128, 0x7216, 0x60c3, 0x0018, 0x0804, 0x8f8f, + 0x0cd0, 0xc2e5, 0x2011, 0x0100, 0x7824, 0xd0cc, 0x0108, 0xc2e5, + 0x7216, 0x702f, 0x0008, 0x7858, 0x9084, 0x00ff, 0x7036, 0x60c3, + 0x0020, 0x0804, 0x8f8f, 0x2011, 0x0008, 0x7824, 0xd0cc, 0x0108, + 0xc2e5, 0x7216, 0x0c08, 0x0036, 0x7b14, 0x9384, 0xff00, 0x7816, + 0x9384, 0x00ff, 0x8001, 0x1138, 0x7824, 0xd0cc, 0x0108, 0xc2e5, + 0x7216, 0x003e, 0x0888, 0x0046, 0x2021, 0x0800, 0x0006, 0x7824, + 0xd0cc, 0x000e, 0x0108, 0xc4e5, 0x7416, 0x004e, 0x701e, 0x003e, + 0x0818, 0x00d6, 0x6813, 0x0008, 0xb810, 0x9085, 0x0700, 0x7002, + 0xb814, 0x7006, 0x2069, 0x1800, 0x6874, 0x700a, 0x6878, 0x700e, + 0x7824, 0xd0cc, 0x1168, 0x7013, 0x0898, 0x080c, 0x8f7d, 0x721a, + 0x7a08, 0x7222, 0x2f10, 0x7226, 0x2071, 0x024c, 0x00de, 0x0005, + 0x7013, 0x0889, 0x0c90, 0x0016, 0x7814, 0x9084, 0x0700, 0x8007, + 0x0013, 0x001e, 0x0005, 0x8dcb, 0x8dcb, 0x8dcd, 0x8dcb, 0x8dcb, + 0x8dcb, 0x8de7, 0x8dcb, 0x080c, 0x0db2, 0x7914, 0x918c, 0x08ff, + 0x918d, 0xf600, 0x7916, 0x2009, 0x0003, 0x00b9, 0x2069, 0x1853, + 0x6804, 0xd0bc, 0x0130, 0x682c, 0x9084, 0x00ff, 0x8007, 0x7032, + 0x0010, 0x7033, 0x3f00, 0x60c3, 0x0001, 0x0804, 0x8f8f, 0x2009, + 0x0003, 0x0019, 0x7033, 0x7f00, 0x0cb0, 0x0016, 0x080c, 0x97ce, + 0x001e, 0xb810, 0x9085, 0x0100, 0x7002, 0xb814, 0x7006, 0x2069, + 0x1800, 0x6a74, 0x720a, 0x6a78, 0x720e, 0x7013, 0x0888, 0x918d, + 0x0008, 0x7116, 0x080c, 0x8f7d, 0x721a, 0x7a08, 0x7222, 0x2f10, + 0x7226, 0x0005, 0x00b6, 0x0096, 0x00e6, 0x00d6, 0x00c6, 0x0056, + 0x0046, 0x0036, 0x2061, 0x0100, 0x2071, 0x1800, 0x7810, 0x2058, + 0xb8a0, 0x2028, 0xb910, 0xba14, 0x7374, 0x7478, 0x7820, 0x90be, + 0x0006, 0x0904, 0x8eec, 0x90be, 0x000a, 0x1904, 0x8ea8, 0x609f, + 0x0000, 0x7814, 0x2048, 0xa87c, 0xd0fc, 0x05c8, 0xaf90, 0x9784, + 0xff00, 0x9105, 0x6062, 0x873f, 0x9784, 0xff00, 0x0006, 0x7814, + 0x2048, 0xa878, 0x9005, 0x000e, 0x1160, 0xaf94, 0x87ff, 0x0510, + 0x2039, 0x0098, 0x9705, 0x6072, 0x7808, 0x6082, 0x2f00, 0x6086, + 0x0038, 0x9185, 0x2200, 0x6062, 0x6073, 0x0129, 0x6077, 0x0000, + 0x609f, 0x0000, 0x2001, 0x1835, 0x2004, 0xd0ac, 0x11a8, 0xd09c, + 0x0130, 0x7814, 0x2048, 0xa874, 0x9082, 0x0080, 0x1268, 0xb814, + 0x609e, 0x0050, 0x2039, 0x0029, 0x9705, 0x6072, 0x0c48, 0x9185, + 0x0200, 0x6062, 0x6073, 0x2029, 0xa87c, 0xd0fc, 0x0118, 0xaf94, + 0x87ff, 0x1120, 0x2f00, 0x6082, 0x7808, 0x6086, 0x6266, 0x636a, + 0x646e, 0x6077, 0x0000, 0xb88c, 0x8000, 0x9084, 0x00ff, 0xb88e, + 0x8007, 0x607a, 0x607f, 0x0000, 0xa838, 0x608a, 0xa834, 0x608e, + 0xa848, 0x60c6, 0xa844, 0x60ca, 0xb86c, 0x60ce, 0x60af, 0x95d5, + 0x60d7, 0x0000, 0x080c, 0x97b3, 0x2009, 0x07d0, 0x60c4, 0x9084, + 0xfff0, 0x9005, 0x0110, 0x2009, 0x1b58, 0x080c, 0x7ccc, 0x003e, + 0x004e, 0x005e, 0x00ce, 0x00de, 0x00ee, 0x009e, 0x00be, 0x0005, + 0x7804, 0x9086, 0x0040, 0x0904, 0x8f28, 0x9185, 0x0100, 0x6062, + 0x6266, 0x636a, 0x646e, 0x6073, 0x0809, 0x6077, 0x0008, 0x60af, + 0x95d5, 0x60d7, 0x0000, 0xb88c, 0x8000, 0x9084, 0x00ff, 0xb88e, + 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6082, 0x7808, 0x6086, + 0x7814, 0x2048, 0xa838, 0x608a, 0xa834, 0x608e, 0xa848, 0x60c6, + 0xa844, 0x60ca, 0xb86c, 0x60ce, 0xbab0, 0x629e, 0x080c, 0x97b3, + 0x2009, 0x07d0, 0x60c4, 0x9084, 0xfff0, 0x9005, 0x0110, 0x2009, + 0x1b58, 0x080c, 0x7ccc, 0x003e, 0x004e, 0x005e, 0x00ce, 0x00de, + 0x00ee, 0x009e, 0x00be, 0x0005, 0x7814, 0x2048, 0xa87c, 0x9084, + 0x0003, 0x9086, 0x0002, 0x0904, 0x8f44, 0x9185, 0x0100, 0x6062, + 0x6266, 0x636a, 0x646e, 0x6073, 0x0880, 0x6077, 0x0008, 0xb88c, + 0x8000, 0x9084, 0x00ff, 0xb88e, 0x8007, 0x607a, 0x7838, 0x607e, + 0x2f00, 0x6086, 0x7808, 0x6082, 0xa890, 0x608a, 0xa88c, 0x608e, + 0xa8b0, 0x60c6, 0xa8ac, 0x60ca, 0xa8ac, 0x7930, 0x9108, 0x7932, + 0xa8b0, 0x792c, 0x9109, 0x792e, 0xb86c, 0x60ce, 0x60af, 0x95d5, + 0x60d7, 0x0000, 0xbab0, 0x629e, 0x080c, 0x9790, 0x0804, 0x8ed8, + 0xb8bc, 0xd084, 0x0148, 0xb88c, 0x7814, 0x2048, 0xb88c, 0x7846, + 0xa836, 0x2900, 0xa83a, 0xb04a, 0x9185, 0x0600, 0x6062, 0x6266, + 0x636a, 0x646e, 0x6073, 0x0829, 0x6077, 0x0000, 0x60af, 0x9575, + 0x60d7, 0x0000, 0x0804, 0x8ebb, 0x9185, 0x0700, 0x6062, 0x6266, + 0x636a, 0x646e, 0x7824, 0xd0cc, 0x7826, 0x0118, 0x6073, 0x0889, + 0x0010, 0x6073, 0x0898, 0x6077, 0x0000, 0xb88c, 0x8000, 0x9084, + 0x00ff, 0xb88e, 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6086, + 0x7808, 0x6082, 0xa838, 0x608a, 0xa834, 0x608e, 0xa848, 0x60c6, + 0xa844, 0x60ca, 0xb86c, 0x60ce, 0x60af, 0x95d5, 0x60d7, 0x0000, + 0xbab0, 0x629e, 0x7824, 0xd0cc, 0x0120, 0x080c, 0x97b3, 0x0804, + 0x8ed8, 0x080c, 0x9790, 0x0804, 0x8ed8, 0x7a10, 0x00b6, 0x2258, + 0xba8c, 0x8210, 0x9294, 0x00ff, 0xba8e, 0x00be, 0x8217, 0x0005, + 0x00d6, 0x2069, 0x19b6, 0x6843, 0x0001, 0x00de, 0x0005, 0x60a3, + 0x0056, 0x60a7, 0x9575, 0x00f1, 0x080c, 0x7cbe, 0x0005, 0x0016, + 0x2001, 0x180c, 0x200c, 0x9184, 0x0600, 0x9086, 0x0600, 0x0128, + 0x0089, 0x080c, 0x7cbe, 0x001e, 0x0005, 0xc1e5, 0x2001, 0x180c, + 0x2102, 0x2001, 0x19b7, 0x2003, 0x0000, 0x2001, 0x19bf, 0x2003, + 0x0000, 0x0c88, 0x0006, 0x6014, 0x9084, 0x1804, 0x9085, 0x0009, + 0x6016, 0x000e, 0x0005, 0x0016, 0x00c6, 0x0006, 0x2061, 0x0100, + 0x61a4, 0x60a7, 0x95f5, 0x6014, 0x9084, 0x1804, 0x9085, 0x0008, + 0x6016, 0x000e, 0xa001, 0xa001, 0xa001, 0x61a6, 0x00ce, 0x001e, + 0x0005, 0x00c6, 0x00d6, 0x0016, 0x0026, 0x2061, 0x0100, 0x2069, + 0x0140, 0x080c, 0x6c53, 0x11e8, 0x2001, 0x19d2, 0x2004, 0x9005, + 0x1904, 0x9021, 0x0066, 0x2031, 0x0001, 0x080c, 0x6d03, 0x006e, + 0x1160, 0x2061, 0x0100, 0x6020, 0xd0b4, 0x1120, 0x6024, 0xd084, + 0x090c, 0x0db2, 0x080c, 0x7cbe, 0x0460, 0x00c6, 0x2061, 0x19b6, + 0x00d0, 0x6904, 0x9194, 0x4000, 0x0548, 0x080c, 0x8fbb, 0x080c, + 0x2997, 0x00c6, 0x2061, 0x19b6, 0x6128, 0x9192, 0x0008, 0x1258, + 0x8108, 0x612a, 0x6124, 0x00ce, 0x81ff, 0x0198, 0x080c, 0x7cbe, + 0x080c, 0x8fb2, 0x0070, 0x6124, 0x91e5, 0x0000, 0x0140, 0x080c, + 0xd358, 0x080c, 0x7cc7, 0x2009, 0x0014, 0x080c, 0x9a50, 0x00ce, + 0x0000, 0x002e, 0x001e, 0x00de, 0x00ce, 0x0005, 0x2001, 0x19d2, + 0x2004, 0x9005, 0x1db0, 0x00c6, 0x2061, 0x19b6, 0x6128, 0x9192, + 0x0003, 0x1e08, 0x8108, 0x612a, 0x00ce, 0x080c, 0x7cbe, 0x080c, + 0x58e0, 0x2009, 0x1852, 0x2114, 0x8210, 0x220a, 0x0c10, 0x0096, + 0x00c6, 0x00d6, 0x00e6, 0x0016, 0x0026, 0x080c, 0x7cd4, 0x2071, + 0x19b6, 0x713c, 0x81ff, 0x0904, 0x90ad, 0x2061, 0x0100, 0x2069, + 0x0140, 0x080c, 0x6c53, 0x11b0, 0x0036, 0x2019, 0x0002, 0x080c, + 0x9254, 0x003e, 0x713c, 0x2160, 0x080c, 0xd358, 0x2009, 0x004a, + 0x080c, 0x9a50, 0x0066, 0x2031, 0x0001, 0x080c, 0x6d03, 0x006e, + 0x0804, 0x90ad, 0x6904, 0xd1f4, 0x0904, 0x90b4, 0x080c, 0x2997, + 0x00c6, 0x703c, 0x9065, 0x090c, 0x0db2, 0x6020, 0x00ce, 0x9086, + 0x0006, 0x1528, 0x61c8, 0x60c4, 0x9105, 0x1508, 0x2009, 0x180c, + 0x2104, 0xd0d4, 0x01e0, 0x6214, 0x9294, 0x1800, 0x1128, 0x6224, + 0x9294, 0x0002, 0x1510, 0x0030, 0xc0d4, 0x200a, 0xd0cc, 0x0110, + 0x080c, 0x28ea, 0x6014, 0x9084, 0xe7fd, 0x9085, 0x0010, 0x6016, + 0x703c, 0x2060, 0x2009, 0x0049, 0x080c, 0x9a50, 0x0070, 0x0036, + 0x2019, 0x0001, 0x080c, 0x9254, 0x003e, 0x713c, 0x2160, 0x080c, + 0xd358, 0x2009, 0x004a, 0x080c, 0x9a50, 0x002e, 0x001e, 0x00ee, + 0x00de, 0x00ce, 0x009e, 0x0005, 0xd1ec, 0x1904, 0x906e, 0x0804, + 0x9070, 0x0026, 0x00e6, 0x2071, 0x19b6, 0x7048, 0xd084, 0x01c0, + 0x713c, 0x81ff, 0x01a8, 0x2071, 0x0100, 0x9188, 0x0008, 0x2114, + 0x928e, 0x0006, 0x1138, 0x7014, 0x9084, 0x1984, 0x9085, 0x0012, + 0x7016, 0x0030, 0x7014, 0x9084, 0x1984, 0x9085, 0x0016, 0x7016, + 0x00ee, 0x002e, 0x0005, 0x00b6, 0x00e6, 0x00d6, 0x00c6, 0x0066, + 0x0056, 0x0046, 0x0006, 0x0126, 0x2091, 0x8000, 0x6010, 0x2058, + 0xbca0, 0x2071, 0x19b6, 0x7018, 0x2058, 0x8bff, 0x0190, 0xb8a0, + 0x9406, 0x0118, 0xb854, 0x2058, 0x0cc0, 0x6014, 0x0096, 0x2048, + 0xac6c, 0xad70, 0xae78, 0x009e, 0x080c, 0x60b0, 0x0110, 0x9085, + 0x0001, 0x012e, 0x000e, 0x004e, 0x005e, 0x006e, 0x00ce, 0x00de, + 0x00ee, 0x00be, 0x0005, 0x080c, 0x8aa4, 0x7003, 0x1200, 0x7838, + 0x7012, 0x783c, 0x7016, 0x00c6, 0x7820, 0x9086, 0x0004, 0x1148, + 0x7810, 0x9005, 0x0130, 0x00b6, 0x2058, 0xb810, 0xb914, 0x00be, + 0x0020, 0x2061, 0x1800, 0x6074, 0x6178, 0x9084, 0x00ff, 0x700a, + 0x710e, 0x00ce, 0x60c3, 0x002c, 0x0804, 0x8f8f, 0x080c, 0x8aa4, + 0x7003, 0x0f00, 0x7808, 0xd09c, 0x0128, 0xb810, 0x9084, 0x00ff, + 0x700a, 0xb814, 0x700e, 0x60c3, 0x0008, 0x0804, 0x8f8f, 0x0156, + 0x080c, 0x8aef, 0x7003, 0x0200, 0x2011, 0x1848, 0x63f0, 0x2312, + 0x20a9, 0x0006, 0x2011, 0x1840, 0x2019, 0x1841, 0x9ef0, 0x0002, + 0x2376, 0x8e70, 0x2276, 0x8e70, 0x9398, 0x0002, 0x9290, 0x0002, + 0x1f04, 0x9150, 0x60c3, 0x001c, 0x015e, 0x0804, 0x8f8f, 0x0016, + 0x0026, 0x080c, 0x8acb, 0x080c, 0x8add, 0x9e80, 0x0004, 0x20e9, + 0x0000, 0x20a0, 0x7814, 0x0096, 0x2048, 0xa800, 0x2048, 0xa860, + 0x20e0, 0xa85c, 0x9080, 0x0021, 0x2098, 0x009e, 0x7808, 0x9088, + 0x0002, 0x21a8, 0x9192, 0x0010, 0x1250, 0x4003, 0x9080, 0x0004, + 0x8003, 0x60c2, 0x080c, 0x8f8f, 0x002e, 0x001e, 0x0005, 0x20a9, + 0x0010, 0x4003, 0x080c, 0x97b9, 0x20a1, 0x0240, 0x22a8, 0x4003, + 0x0c68, 0x080c, 0x8aa4, 0x7003, 0x6200, 0x7808, 0x700e, 0x60c3, + 0x0008, 0x0804, 0x8f8f, 0x0016, 0x0026, 0x080c, 0x8aa4, 0x20e9, + 0x0000, 0x20a1, 0x024c, 0x7814, 0x0096, 0x2048, 0xa800, 0x2048, + 0xa860, 0x20e0, 0xa85c, 0x9080, 0x0023, 0x2098, 0x009e, 0x7808, + 0x9088, 0x0002, 0x21a8, 0x4003, 0x8003, 0x60c2, 0x080c, 0x8f8f, + 0x002e, 0x001e, 0x0005, 0x00e6, 0x00c6, 0x0006, 0x0126, 0x2091, + 0x8000, 0x2071, 0x19b6, 0x700c, 0x2060, 0x8cff, 0x0178, 0x080c, + 0xb7fa, 0x1110, 0x080c, 0xa364, 0x600c, 0x0006, 0x080c, 0xba61, + 0x080c, 0x99d6, 0x080c, 0x933f, 0x00ce, 0x0c78, 0x2c00, 0x700e, + 0x700a, 0x012e, 0x000e, 0x00ce, 0x00ee, 0x0005, 0x0126, 0x0156, + 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0026, 0x0016, 0x0006, + 0x2091, 0x8000, 0x2001, 0x180c, 0x200c, 0x918c, 0xe7ff, 0x2102, + 0x2069, 0x0100, 0x2079, 0x0140, 0x2071, 0x19b6, 0x7024, 0x2060, + 0x8cff, 0x01f8, 0x080c, 0x8fbb, 0x6ac0, 0x68c3, 0x0000, 0x080c, + 0x7cc7, 0x00c6, 0x2061, 0x0100, 0x080c, 0x97d2, 0x00ce, 0x20a9, + 0x01f4, 0x0461, 0x2009, 0x0013, 0x080c, 0x9a50, 0x000e, 0x001e, + 0x002e, 0x006e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x015e, 0x012e, + 0x0005, 0x2001, 0x1800, 0x2004, 0x9096, 0x0001, 0x0d78, 0x9096, + 0x0004, 0x0d60, 0x080c, 0x7cc7, 0x6814, 0x9084, 0x0001, 0x0110, + 0x68a7, 0x95f5, 0x6817, 0x0008, 0x68c3, 0x0000, 0x2011, 0x588a, + 0x080c, 0x7c4a, 0x20a9, 0x01f4, 0x0009, 0x08c0, 0x6824, 0xd094, + 0x0140, 0x6827, 0x0004, 0x7804, 0x9084, 0x4000, 0x190c, 0x2997, + 0x0090, 0xd084, 0x0118, 0x6827, 0x0001, 0x0010, 0x1f04, 0x9236, + 0x7804, 0x9084, 0x1000, 0x0138, 0x2001, 0x0100, 0x080c, 0x2987, + 0x9006, 0x080c, 0x2987, 0x0005, 0x0126, 0x0156, 0x00f6, 0x00e6, + 0x00d6, 0x00c6, 0x0066, 0x0026, 0x0016, 0x0006, 0x2091, 0x8000, + 0x2001, 0x180c, 0x200c, 0x918c, 0xdbff, 0x2102, 0x2069, 0x0100, + 0x2079, 0x0140, 0x2071, 0x19b6, 0x703c, 0x2060, 0x8cff, 0x0904, + 0x92e1, 0x9386, 0x0002, 0x1128, 0x6814, 0x9084, 0x0002, 0x0904, + 0x92e1, 0x68af, 0x95f5, 0x6817, 0x0010, 0x2009, 0x00fa, 0x8109, + 0x1df0, 0x69c6, 0x68cb, 0x0008, 0x080c, 0x7cd4, 0x080c, 0x1d14, + 0x0046, 0x2009, 0x017f, 0x200b, 0x00a5, 0x2021, 0x0169, 0x2404, + 0x9084, 0x000f, 0x9086, 0x0004, 0x11f8, 0x68af, 0x95f5, 0x68c6, + 0x68cb, 0x0008, 0x00e6, 0x00f6, 0x2079, 0x0090, 0x2071, 0x1a34, + 0x6814, 0x9084, 0x1984, 0x9085, 0x0012, 0x6816, 0x782b, 0x0008, + 0x7003, 0x0000, 0x00fe, 0x00ee, 0x9386, 0x0002, 0x1128, 0x7884, + 0x9005, 0x1110, 0x7887, 0x0001, 0x2001, 0x1950, 0x2004, 0x200a, + 0x004e, 0x20a9, 0x03e8, 0x6824, 0xd094, 0x0140, 0x6827, 0x0004, + 0x7804, 0x9084, 0x4000, 0x190c, 0x2997, 0x0090, 0xd08c, 0x0118, + 0x6827, 0x0002, 0x0010, 0x1f04, 0x92bb, 0x7804, 0x9084, 0x1000, + 0x0138, 0x2001, 0x0100, 0x080c, 0x2987, 0x9006, 0x080c, 0x2987, + 0x6827, 0x4000, 0x6824, 0x83ff, 0x1120, 0x2009, 0x0049, 0x080c, + 0x9a50, 0x000e, 0x001e, 0x002e, 0x006e, 0x00ce, 0x00de, 0x00ee, + 0x00fe, 0x015e, 0x012e, 0x0005, 0x00d6, 0x0126, 0x2091, 0x8000, + 0x2069, 0x19b6, 0x6a06, 0x012e, 0x00de, 0x0005, 0x00d6, 0x0126, + 0x2091, 0x8000, 0x2069, 0x19b6, 0x6a32, 0x012e, 0x00de, 0x0005, + 0x080c, 0x8c48, 0x7814, 0x080c, 0x511b, 0x0108, 0x782c, 0x7032, + 0x7042, 0x7047, 0x1000, 0x0478, 0x080c, 0x8c48, 0x7814, 0x080c, + 0x511b, 0x0108, 0x782c, 0x7032, 0x7042, 0x7047, 0x4000, 0x0418, + 0x080c, 0x8c48, 0x7814, 0x080c, 0x511b, 0x0108, 0x782c, 0x7032, + 0x7042, 0x7047, 0x2000, 0x00b8, 0x080c, 0x8c48, 0x7814, 0x080c, + 0x511b, 0x0108, 0x782c, 0x7032, 0x7042, 0x7047, 0x0400, 0x0058, + 0x080c, 0x8c48, 0x7814, 0x080c, 0x511b, 0x0108, 0x782c, 0x7032, + 0x7042, 0x7047, 0x0200, 0x60c3, 0x0020, 0x0804, 0x8f8f, 0x00e6, + 0x2071, 0x19b6, 0x7020, 0x9005, 0x0110, 0x8001, 0x7022, 0x00ee, + 0x0005, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0076, 0x0066, 0x0006, + 0x0126, 0x2091, 0x8000, 0x2071, 0x19b6, 0x7614, 0x2660, 0x2678, + 0x2039, 0x0001, 0x87ff, 0x0904, 0x93e4, 0x8cff, 0x0904, 0x93e4, + 0x6020, 0x9086, 0x0006, 0x1904, 0x93df, 0x88ff, 0x0138, 0x2800, + 0x9c06, 0x1904, 0x93df, 0x2039, 0x0000, 0x0050, 0x6010, 0x9b06, + 0x1904, 0x93df, 0x85ff, 0x0120, 0x6054, 0x9106, 0x1904, 0x93df, + 0x7024, 0x9c06, 0x15b0, 0x2069, 0x0100, 0x68c0, 0x9005, 0x1160, + 0x6824, 0xd084, 0x0148, 0x6827, 0x0001, 0x080c, 0x7cc7, 0x080c, + 0x9469, 0x7027, 0x0000, 0x0428, 0x080c, 0x7cc7, 0x6820, 0xd0b4, + 0x0110, 0x68a7, 0x95f5, 0x6817, 0x0008, 0x68c3, 0x0000, 0x080c, + 0x9469, 0x7027, 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0x9384, + 0x1000, 0x0138, 0x2001, 0x0100, 0x080c, 0x2987, 0x9006, 0x080c, + 0x2987, 0x2069, 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, + 0x003e, 0x7014, 0x9c36, 0x1110, 0x660c, 0x7616, 0x7010, 0x9c36, + 0x1140, 0x2c00, 0x9f36, 0x0118, 0x2f00, 0x7012, 0x0010, 0x7013, + 0x0000, 0x660c, 0x0066, 0x2c00, 0x9f06, 0x0110, 0x7e0e, 0x0008, + 0x2678, 0x89ff, 0x1168, 0x600f, 0x0000, 0x6014, 0x0096, 0x2048, + 0x080c, 0xb5f9, 0x0110, 0x080c, 0xcf91, 0x009e, 0x080c, 0x9a06, + 0x080c, 0x933f, 0x88ff, 0x1190, 0x00ce, 0x0804, 0x935a, 0x2c78, + 0x600c, 0x2060, 0x0804, 0x935a, 0x9006, 0x012e, 0x000e, 0x006e, + 0x007e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x0005, 0x601b, 0x0000, + 0x00ce, 0x98c5, 0x0001, 0x0c88, 0x00f6, 0x00e6, 0x00d6, 0x0096, + 0x00c6, 0x0066, 0x0026, 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, + 0x19b6, 0x7638, 0x2660, 0x2678, 0x8cff, 0x0904, 0x9458, 0x6020, + 0x9086, 0x0006, 0x1904, 0x9453, 0x87ff, 0x0128, 0x2700, 0x9c06, + 0x1904, 0x9453, 0x0040, 0x6010, 0x9b06, 0x15e8, 0x85ff, 0x0118, + 0x6054, 0x9106, 0x15c0, 0x703c, 0x9c06, 0x1168, 0x0036, 0x2019, + 0x0001, 0x080c, 0x9254, 0x7033, 0x0000, 0x9006, 0x703e, 0x7042, + 0x7046, 0x704a, 0x003e, 0x7038, 0x9c36, 0x1110, 0x660c, 0x763a, + 0x7034, 0x9c36, 0x1140, 0x2c00, 0x9f36, 0x0118, 0x2f00, 0x7036, + 0x0010, 0x7037, 0x0000, 0x660c, 0x0066, 0x2c00, 0x9f06, 0x0110, + 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0x6014, 0x2048, 0x080c, + 0xb5f9, 0x0110, 0x080c, 0xcf91, 0x080c, 0x9a06, 0x87ff, 0x1198, + 0x00ce, 0x0804, 0x9404, 0x2c78, 0x600c, 0x2060, 0x0804, 0x9404, + 0x9006, 0x012e, 0x000e, 0x002e, 0x006e, 0x00ce, 0x009e, 0x00de, + 0x00ee, 0x00fe, 0x0005, 0x601b, 0x0000, 0x00ce, 0x97bd, 0x0001, + 0x0c80, 0x00e6, 0x2071, 0x19b6, 0x2001, 0x1800, 0x2004, 0x9086, + 0x0002, 0x1118, 0x7007, 0x0005, 0x0010, 0x7007, 0x0000, 0x00ee, + 0x0005, 0x00f6, 0x00e6, 0x00c6, 0x0066, 0x0026, 0x0006, 0x0126, + 0x2091, 0x8000, 0x2071, 0x19b6, 0x2c10, 0x7638, 0x2660, 0x2678, + 0x8cff, 0x0518, 0x2200, 0x9c06, 0x11e0, 0x7038, 0x9c36, 0x1110, + 0x660c, 0x763a, 0x7034, 0x9c36, 0x1140, 0x2c00, 0x9f36, 0x0118, + 0x2f00, 0x7036, 0x0010, 0x7037, 0x0000, 0x660c, 0x2c00, 0x9f06, + 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0x9085, 0x0001, + 0x0020, 0x2c78, 0x600c, 0x2060, 0x08d8, 0x012e, 0x000e, 0x002e, + 0x006e, 0x00ce, 0x00ee, 0x00fe, 0x0005, 0x0096, 0x00f6, 0x00e6, + 0x00d6, 0x00c6, 0x0066, 0x0026, 0x0006, 0x0126, 0x2091, 0x8000, + 0x2071, 0x19b6, 0x760c, 0x2660, 0x2678, 0x8cff, 0x0904, 0x9545, + 0x6010, 0x00b6, 0x2058, 0xb8a0, 0x00be, 0x9206, 0x1904, 0x9540, + 0x7024, 0x9c06, 0x1520, 0x2069, 0x0100, 0x68c0, 0x9005, 0x0904, + 0x951c, 0x080c, 0x8fbb, 0x68c3, 0x0000, 0x080c, 0x9469, 0x7027, + 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0x9384, 0x1000, 0x0138, + 0x2001, 0x0100, 0x080c, 0x2987, 0x9006, 0x080c, 0x2987, 0x2069, + 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e, 0x700c, + 0x9c36, 0x1110, 0x660c, 0x760e, 0x7008, 0x9c36, 0x1140, 0x2c00, + 0x9f36, 0x0118, 0x2f00, 0x700a, 0x0010, 0x700b, 0x0000, 0x660c, + 0x0066, 0x2c00, 0x9f06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f, + 0x0000, 0x080c, 0xb7e9, 0x1158, 0x080c, 0x2e55, 0x080c, 0xb7fa, + 0x11f0, 0x080c, 0xa364, 0x00d8, 0x080c, 0x9469, 0x08c0, 0x080c, + 0xb7fa, 0x1118, 0x080c, 0xa364, 0x0090, 0x6014, 0x2048, 0x080c, + 0xb5f9, 0x0168, 0x6020, 0x9086, 0x0003, 0x1508, 0xa867, 0x0103, + 0xab7a, 0xa877, 0x0000, 0x080c, 0x6529, 0x080c, 0xb7dd, 0x080c, + 0xba61, 0x080c, 0x9a06, 0x080c, 0x933f, 0x00ce, 0x0804, 0x94c5, + 0x2c78, 0x600c, 0x2060, 0x0804, 0x94c5, 0x012e, 0x000e, 0x002e, + 0x006e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x009e, 0x0005, 0x6020, + 0x9086, 0x0006, 0x1d20, 0x080c, 0xcf91, 0x0c08, 0x00d6, 0x080c, + 0x8aef, 0x7003, 0x0200, 0x7007, 0x0014, 0x60c3, 0x0014, 0x20e1, + 0x0001, 0x2099, 0x1958, 0x20e9, 0x0000, 0x20a1, 0x0250, 0x20a9, + 0x0004, 0x4003, 0x7023, 0x0004, 0x7027, 0x7878, 0x080c, 0x8f8f, + 0x00de, 0x0005, 0x080c, 0x8aef, 0x700b, 0x0800, 0x7814, 0x9084, + 0xff00, 0x700e, 0x7814, 0x9084, 0x00ff, 0x7022, 0x782c, 0x7026, + 0x7858, 0x9084, 0x00ff, 0x9085, 0x0200, 0x7002, 0x7858, 0x9084, + 0xff00, 0x8007, 0x7006, 0x60c2, 0x0804, 0x8f8f, 0x00b6, 0x00d6, + 0x0016, 0x00d6, 0x2f68, 0x2009, 0x0035, 0x080c, 0xbc66, 0x00de, + 0x1904, 0x95f3, 0x080c, 0x8aa4, 0x7003, 0x1300, 0x782c, 0x080c, + 0x96f5, 0x2068, 0x6820, 0x9086, 0x0003, 0x0560, 0x7810, 0x2058, + 0xbaa0, 0x080c, 0x9940, 0x11d8, 0x9286, 0x007e, 0x1128, 0x700b, + 0x00ff, 0x700f, 0xfffe, 0x0498, 0x9286, 0x007f, 0x1128, 0x700b, + 0x00ff, 0x700f, 0xfffd, 0x0458, 0x9284, 0xff80, 0x0180, 0x9286, + 0x0080, 0x1128, 0x700b, 0x00ff, 0x700f, 0xfffc, 0x0400, 0x92d8, + 0x1000, 0x2b5c, 0xb810, 0x700a, 0xb814, 0x700e, 0x00c0, 0x6098, + 0x700e, 0x00a8, 0x080c, 0x9940, 0x1130, 0x7810, 0x2058, 0xb8a0, + 0x9082, 0x007e, 0x0250, 0x00d6, 0x2069, 0x181d, 0x2d04, 0x700a, + 0x8d68, 0x2d04, 0x700e, 0x00de, 0x0010, 0x6034, 0x700e, 0x7838, + 0x7012, 0x783c, 0x7016, 0x60c3, 0x000c, 0x001e, 0x00de, 0x080c, + 0x8f8f, 0x00be, 0x0005, 0x781b, 0x0001, 0x7803, 0x0006, 0x001e, + 0x00de, 0x00be, 0x0005, 0x792c, 0x9180, 0x0008, 0x200c, 0x9186, + 0x0006, 0x01c0, 0x9186, 0x0003, 0x0904, 0x966d, 0x9186, 0x0005, + 0x0904, 0x9656, 0x9186, 0x0004, 0x05d8, 0x9186, 0x0008, 0x0904, + 0x965e, 0x7807, 0x0037, 0x782f, 0x0003, 0x7817, 0x1700, 0x080c, + 0x96d2, 0x0005, 0x080c, 0x9693, 0x00d6, 0x0026, 0x792c, 0x2168, + 0x2009, 0x4000, 0x6800, 0x0002, 0x9637, 0x9642, 0x9639, 0x9642, + 0x963e, 0x9637, 0x9637, 0x9642, 0x9642, 0x9642, 0x9642, 0x9637, + 0x9637, 0x9637, 0x9637, 0x9637, 0x9642, 0x9637, 0x9642, 0x080c, + 0x0db2, 0x6824, 0xd0e4, 0x0110, 0xd0cc, 0x0110, 0x900e, 0x0010, + 0x2009, 0x2000, 0x682c, 0x7022, 0x6830, 0x7026, 0x0804, 0x968c, + 0x080c, 0x9693, 0x00d6, 0x0026, 0x792c, 0x2168, 0x2009, 0x4000, + 0x6a00, 0x9286, 0x0002, 0x1108, 0x900e, 0x04b0, 0x04e1, 0x00d6, + 0x0026, 0x792c, 0x2168, 0x2009, 0x4000, 0x0470, 0x04a1, 0x00d6, + 0x0026, 0x792c, 0x2168, 0x2009, 0x4000, 0x9286, 0x0005, 0x0118, + 0x9286, 0x0002, 0x1108, 0x900e, 0x00f8, 0x0429, 0x00d6, 0x0026, + 0x792c, 0x2168, 0x6814, 0x0096, 0x2048, 0xa9ac, 0xa834, 0x9112, + 0xa9b0, 0xa838, 0x009e, 0x9103, 0x7022, 0x7226, 0x792c, 0x9180, + 0x0000, 0x2004, 0x908e, 0x0002, 0x0130, 0x908e, 0x0004, 0x0118, + 0x2009, 0x4000, 0x0008, 0x900e, 0x712a, 0x60c3, 0x0018, 0x002e, + 0x00de, 0x0804, 0x8f8f, 0x00b6, 0x0036, 0x0046, 0x0056, 0x0066, + 0x080c, 0x8aef, 0x9006, 0x7003, 0x0200, 0x7938, 0x710a, 0x793c, + 0x710e, 0x7810, 0x2058, 0xb8a0, 0x080c, 0x9940, 0x1118, 0x9092, + 0x007e, 0x0268, 0x00d6, 0x2069, 0x181d, 0x2d2c, 0x8d68, 0x2d34, + 0x90d8, 0x1000, 0x2b5c, 0xbb10, 0xbc14, 0x00de, 0x0028, 0x901e, + 0x6498, 0x2029, 0x0000, 0x6634, 0x782c, 0x9080, 0x0008, 0x2004, + 0x9086, 0x0003, 0x1128, 0x7512, 0x7616, 0x731a, 0x741e, 0x0020, + 0x7312, 0x7416, 0x751a, 0x761e, 0x006e, 0x005e, 0x004e, 0x003e, + 0x00be, 0x0005, 0x080c, 0x8aef, 0x7003, 0x0100, 0x782c, 0x700a, + 0x7814, 0x700e, 0x700e, 0x60c3, 0x0008, 0x0804, 0x8f8f, 0x080c, + 0x8a9b, 0x7003, 0x1400, 0x7838, 0x700a, 0x0079, 0x783c, 0x700e, + 0x782c, 0x7012, 0x7830, 0x7016, 0x7834, 0x9084, 0x00ff, 0x8007, + 0x701a, 0x60c3, 0x0010, 0x0804, 0x8f8f, 0x00e6, 0x2071, 0x0240, + 0x0006, 0x00f6, 0x2078, 0x7810, 0x00b6, 0x2058, 0xb8bc, 0xd084, + 0x0120, 0x7848, 0x702a, 0x7844, 0x702e, 0x00be, 0x00fe, 0x000e, + 0x00ee, 0x0005, 0x080c, 0x8ae6, 0x7003, 0x0100, 0x782c, 0x700a, + 0x7814, 0x700e, 0x60c3, 0x0008, 0x0804, 0x8f8f, 0x0021, 0x60c3, + 0x0000, 0x0804, 0x8f8f, 0x00d6, 0x080c, 0x97ce, 0xb810, 0x9085, + 0x0300, 0x7002, 0xb814, 0x7006, 0x2069, 0x1800, 0x6874, 0x700a, + 0x6878, 0x700e, 0x7013, 0x0819, 0x080c, 0x8f7d, 0x721a, 0x2f10, + 0x7222, 0x7a08, 0x7226, 0x2071, 0x024c, 0x00de, 0x0005, 0x00a9, + 0x7914, 0x712a, 0x60c3, 0x0000, 0x60a7, 0x9575, 0x0026, 0x080c, + 0x283d, 0x0228, 0x2011, 0x0101, 0x2204, 0xc0c5, 0x2012, 0x002e, + 0x080c, 0x8fb2, 0x080c, 0x7cbe, 0x0005, 0x0036, 0x0096, 0x00d6, + 0x00e6, 0x7858, 0x2048, 0xaa7c, 0x9296, 0x00c0, 0x9294, 0xfffd, + 0xaa7e, 0xaa80, 0x9294, 0x0300, 0xaa82, 0xa96c, 0x9194, 0x00ff, + 0xab74, 0x9384, 0x00ff, 0x908d, 0xc200, 0xa96e, 0x9384, 0xff00, + 0x9215, 0xaa76, 0xa870, 0xaa78, 0xa87a, 0xaa72, 0x00d6, 0x2069, + 0x0200, 0x080c, 0x97ce, 0x00de, 0x20e9, 0x0000, 0x20a1, 0x0240, + 0x20a9, 0x000a, 0xa860, 0x20e0, 0xa85c, 0x9080, 0x001b, 0x2098, + 0x4003, 0x60a3, 0x0035, 0xaa68, 0x9294, 0x7000, 0x9286, 0x3000, + 0x0110, 0x60a3, 0x0037, 0x00ee, 0x00de, 0x009e, 0x003e, 0x0005, + 0x900e, 0x7814, 0x0096, 0x2048, 0xa87c, 0xd0fc, 0x01c0, 0x9084, + 0x0003, 0x11a8, 0x2001, 0x180c, 0x2004, 0xd0bc, 0x0180, 0x7824, + 0xd0cc, 0x1168, 0xd0c4, 0x1158, 0xa8a8, 0x9005, 0x1140, 0x2001, + 0x180c, 0x200c, 0xc1d5, 0x2102, 0x2009, 0x1981, 0x210c, 0x009e, + 0x918d, 0x0092, 0x0010, 0x2009, 0x0096, 0x60ab, 0x0036, 0x6116, + 0x0005, 0x2009, 0x0009, 0x00a0, 0x2009, 0x000a, 0x0088, 0x2009, + 0x000b, 0x0070, 0x2009, 0x000c, 0x0058, 0x2009, 0x000d, 0x0040, + 0x2009, 0x000e, 0x0028, 0x2009, 0x000f, 0x0010, 0x2009, 0x0008, + 0x6912, 0x0005, 0x00d6, 0x9290, 0x0018, 0x8214, 0x20e9, 0x0000, + 0x2069, 0x0200, 0x6813, 0x0000, 0x22a8, 0x9284, 0x00e0, 0x0128, + 0x20a9, 0x0020, 0x9292, 0x0020, 0x0008, 0x9016, 0x20a1, 0x0240, + 0x9006, 0x4004, 0x82ff, 0x0120, 0x6810, 0x8000, 0x6812, 0x0c60, + 0x00de, 0x0005, 0x00d6, 0x0096, 0x6014, 0x2048, 0xa878, 0x6056, + 0x9006, 0xa836, 0xa83a, 0xa99c, 0xa946, 0xa84a, 0x6023, 0x0003, + 0x6007, 0x0040, 0x6003, 0x0003, 0x600b, 0xffff, 0xa817, 0x0001, + 0xa842, 0xa83e, 0x2900, 0xa85a, 0xa813, 0x1da0, 0x080c, 0x8065, + 0x0126, 0x2091, 0x8000, 0x080c, 0x865d, 0x012e, 0x009e, 0x00de, + 0x0005, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x00a6, 0x0096, 0x0066, + 0x0126, 0x2091, 0x8000, 0x2071, 0x19b6, 0x760c, 0x2660, 0x2678, + 0x8cff, 0x0904, 0x98a0, 0x7024, 0x9c06, 0x1520, 0x2069, 0x0100, + 0x68c0, 0x9005, 0x0904, 0x9877, 0x080c, 0x8fbb, 0x68c3, 0x0000, + 0x080c, 0x9469, 0x7027, 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, + 0x9384, 0x1000, 0x0138, 0x2001, 0x0100, 0x080c, 0x2987, 0x9006, + 0x080c, 0x2987, 0x2069, 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, + 0x0001, 0x003e, 0x700c, 0x9c36, 0x1110, 0x660c, 0x760e, 0x7008, + 0x9c36, 0x1140, 0x2c00, 0x9f36, 0x0118, 0x2f00, 0x700a, 0x0010, + 0x700b, 0x0000, 0x660c, 0x0066, 0x2c00, 0x9f06, 0x0110, 0x7e0e, + 0x0008, 0x2678, 0x600f, 0x0000, 0x080c, 0xb7e9, 0x1158, 0x080c, + 0x2e55, 0x080c, 0xb7fa, 0x11f0, 0x080c, 0xa364, 0x00d8, 0x080c, + 0x9469, 0x08c0, 0x080c, 0xb7fa, 0x1118, 0x080c, 0xa364, 0x0090, + 0x6014, 0x2048, 0x080c, 0xb5f9, 0x0168, 0x6020, 0x9086, 0x0003, + 0x1520, 0xa867, 0x0103, 0xab7a, 0xa877, 0x0000, 0x080c, 0x6536, + 0x080c, 0xb7dd, 0x080c, 0xba61, 0x080c, 0x9a06, 0x080c, 0x933f, + 0x00ce, 0x0804, 0x9828, 0x2c78, 0x600c, 0x2060, 0x0804, 0x9828, + 0x700f, 0x0000, 0x700b, 0x0000, 0x012e, 0x006e, 0x009e, 0x00ae, + 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x0005, 0x6020, 0x9086, 0x0006, + 0x1d08, 0x080c, 0xcf91, 0x08f0, 0x00d6, 0x0156, 0x080c, 0x8aef, + 0x7a14, 0x82ff, 0x0138, 0x7003, 0x0100, 0x700b, 0x0003, 0x60c3, + 0x0008, 0x0490, 0x7003, 0x0200, 0x7007, 0x0000, 0x2069, 0x1800, + 0x901e, 0x6800, 0x9086, 0x0004, 0x1110, 0xc38d, 0x0060, 0x080c, + 0x6c53, 0x1110, 0xc3ad, 0x0008, 0xc3a5, 0x6ad4, 0xd29c, 0x1110, + 0xd2ac, 0x0108, 0xc39d, 0x730e, 0x2011, 0x1848, 0x63f0, 0x2312, + 0x20a9, 0x0006, 0x2011, 0x1840, 0x2019, 0x1841, 0x2071, 0x0250, + 0x2376, 0x8e70, 0x2276, 0x8e70, 0x9398, 0x0002, 0x9290, 0x0002, + 0x1f04, 0x98e8, 0x60c3, 0x0020, 0x080c, 0x8f8f, 0x015e, 0x00de, + 0x0005, 0x0156, 0x080c, 0x8aef, 0x7a14, 0x82ff, 0x0168, 0x9286, + 0xffff, 0x0118, 0x9282, 0x000e, 0x1238, 0x7003, 0x0100, 0x700b, + 0x0003, 0x60c3, 0x0008, 0x0488, 0x7003, 0x0200, 0x7007, 0x001c, + 0x700f, 0x0001, 0x2011, 0x198c, 0x2204, 0x8007, 0x701a, 0x8210, + 0x2204, 0x8007, 0x701e, 0x0421, 0x1120, 0xb8a0, 0x9082, 0x007f, + 0x0248, 0x2001, 0x181d, 0x2004, 0x7022, 0x2001, 0x181e, 0x2004, + 0x7026, 0x0030, 0x2001, 0x1816, 0x2004, 0x9084, 0x00ff, 0x7026, + 0x20a9, 0x0004, 0x20e1, 0x0001, 0x2099, 0x1805, 0x20e9, 0x0000, + 0x20a1, 0x0256, 0x4003, 0x60c3, 0x001c, 0x015e, 0x0804, 0x8f8f, + 0x0006, 0x2001, 0x1835, 0x2004, 0xd0ac, 0x000e, 0x0005, 0x2011, + 0x0003, 0x080c, 0x92ec, 0x2011, 0x0002, 0x080c, 0x92f6, 0x080c, + 0x91de, 0x0036, 0x901e, 0x080c, 0x9254, 0x003e, 0x0005, 0x080c, + 0x2f8b, 0x0188, 0x0016, 0x00b6, 0x00c6, 0x7010, 0x9085, 0x0020, + 0x7012, 0x2009, 0x007e, 0x080c, 0x5f7e, 0xb85c, 0xc0ac, 0xb85e, + 0x00ce, 0x00be, 0x001e, 0x0005, 0x2071, 0x1883, 0x7000, 0x9005, + 0x0140, 0x2001, 0x0976, 0x2071, 0x1800, 0x706e, 0x7072, 0x7063, + 0xffe0, 0x2071, 0x1800, 0x706c, 0x704e, 0x7053, 0x1cd0, 0x0005, + 0x00e6, 0x0126, 0x2071, 0x1800, 0x2091, 0x8000, 0x754c, 0x9582, + 0x0010, 0x0608, 0x7050, 0x2060, 0x6000, 0x9086, 0x0000, 0x0148, + 0x9ce0, 0x0018, 0x7060, 0x9c02, 0x1208, 0x0cb0, 0x2061, 0x1cd0, + 0x0c98, 0x6003, 0x0008, 0x8529, 0x754e, 0x9ca8, 0x0018, 0x7060, + 0x9502, 0x1230, 0x7552, 0x9085, 0x0001, 0x012e, 0x00ee, 0x0005, + 0x7053, 0x1cd0, 0x0cc0, 0x9006, 0x0cc0, 0x00e6, 0x2071, 0x1800, + 0x754c, 0x9582, 0x0010, 0x0600, 0x7050, 0x2060, 0x6000, 0x9086, + 0x0000, 0x0148, 0x9ce0, 0x0018, 0x7060, 0x9c02, 0x1208, 0x0cb0, + 0x2061, 0x1cd0, 0x0c98, 0x6003, 0x0008, 0x8529, 0x754e, 0x9ca8, + 0x0018, 0x7060, 0x9502, 0x1228, 0x7552, 0x9085, 0x0001, 0x00ee, + 0x0005, 0x7053, 0x1cd0, 0x0cc8, 0x9006, 0x0cc8, 0x9c82, 0x1cd0, + 0x0a0c, 0x0db2, 0x2001, 0x1818, 0x2004, 0x9c02, 0x1a0c, 0x0db2, + 0x9006, 0x6006, 0x600a, 0x600e, 0x6016, 0x601a, 0x6012, 0x6023, + 0x0000, 0x6003, 0x0000, 0x601e, 0x6056, 0x605a, 0x6026, 0x602a, + 0x602e, 0x6032, 0x6036, 0x603a, 0x603e, 0x6042, 0x2061, 0x1800, + 0x604c, 0x8000, 0x604e, 0x9086, 0x0001, 0x0108, 0x0005, 0x0126, + 0x2091, 0x8000, 0x080c, 0x8582, 0x012e, 0x0cc0, 0x0006, 0x6000, + 0x9086, 0x0000, 0x01b0, 0x601c, 0xd084, 0x190c, 0x1827, 0x6017, + 0x0000, 0x6023, 0x0007, 0x2001, 0x1955, 0x2004, 0x0006, 0x9082, + 0x0051, 0x000e, 0x0208, 0x8004, 0x601a, 0x080c, 0xd240, 0x6043, + 0x0000, 0x000e, 0x0005, 0x00e6, 0x0126, 0x2071, 0x1800, 0x2091, + 0x8000, 0x754c, 0x9582, 0x0001, 0x0608, 0x7050, 0x2060, 0x6000, + 0x9086, 0x0000, 0x0148, 0x9ce0, 0x0018, 0x7060, 0x9c02, 0x1208, + 0x0cb0, 0x2061, 0x1cd0, 0x0c98, 0x6003, 0x0008, 0x8529, 0x754e, + 0x9ca8, 0x0018, 0x7060, 0x9502, 0x1230, 0x7552, 0x9085, 0x0001, + 0x012e, 0x00ee, 0x0005, 0x7053, 0x1cd0, 0x0cc0, 0x9006, 0x0cc0, + 0x6020, 0x9084, 0x000f, 0x0002, 0x9a63, 0x9a6c, 0x9a87, 0x9aa2, + 0xbd12, 0xbd2f, 0xbd4a, 0x9a63, 0x9a6c, 0x9a63, 0x9abe, 0x9a63, + 0x9a63, 0x9a63, 0x9a63, 0x9186, 0x0013, 0x1128, 0x080c, 0x847d, + 0x080c, 0x8582, 0x0005, 0x0005, 0x0066, 0x6000, 0x90b2, 0x0016, + 0x1a0c, 0x0db2, 0x0013, 0x006e, 0x0005, 0x9a85, 0xa1dd, 0xa3ab, + 0x9a85, 0xa439, 0x9d9f, 0x9a85, 0x9a85, 0xa15f, 0xa947, 0x9a85, + 0x9a85, 0x9a85, 0x9a85, 0x9a85, 0x9a85, 0x080c, 0x0db2, 0x0066, + 0x6000, 0x90b2, 0x0016, 0x1a0c, 0x0db2, 0x0013, 0x006e, 0x0005, + 0x9aa0, 0xb012, 0x9aa0, 0x9aa0, 0x9aa0, 0x9aa0, 0x9aa0, 0x9aa0, + 0xafb7, 0xb194, 0x9aa0, 0xb053, 0xb0d2, 0xb053, 0xb0d2, 0x9aa0, + 0x080c, 0x0db2, 0x6000, 0x9082, 0x0016, 0x1a0c, 0x0db2, 0x6000, + 0x0002, 0x9abc, 0xa98e, 0xaa73, 0xaba3, 0xad45, 0x9abc, 0x9abc, + 0x9abc, 0xa962, 0xaf43, 0xaf46, 0x9abc, 0x9abc, 0x9abc, 0x9abc, + 0xaf75, 0x9abc, 0x9abc, 0x9abc, 0x080c, 0x0db2, 0x0066, 0x6000, + 0x90b2, 0x0016, 0x1a0c, 0x0db2, 0x0013, 0x006e, 0x0005, 0x9ad7, + 0x9ad7, 0x9b1a, 0x9bb8, 0x9c4c, 0x9ad7, 0x9ad7, 0x9ad7, 0x9ad9, + 0x9ad7, 0x9ad7, 0x9ad7, 0x9ad7, 0x9ad7, 0x9ad7, 0x9ad7, 0x080c, + 0x0db2, 0x9186, 0x004c, 0x0588, 0x9186, 0x0003, 0x190c, 0x0db2, + 0x0096, 0x601c, 0xc0ed, 0x601e, 0x6003, 0x0003, 0x6106, 0x6014, + 0x2048, 0xa87c, 0x9084, 0xa000, 0xc0b5, 0xa87e, 0xa8ac, 0xa846, + 0xa8b0, 0xa84a, 0x9006, 0xa836, 0xa83a, 0xa884, 0x9092, 0x199a, + 0x0210, 0x2001, 0x1999, 0x8003, 0x8013, 0x8213, 0x9210, 0x621a, + 0x009e, 0x2c10, 0x080c, 0x1976, 0x080c, 0x8065, 0x0126, 0x2091, + 0x8000, 0x080c, 0x865d, 0x012e, 0x0005, 0x6010, 0x00b6, 0x2058, + 0xbca0, 0x00be, 0x2c00, 0x080c, 0x9c6e, 0x080c, 0xbd04, 0x6003, + 0x0007, 0x0005, 0x00d6, 0x0096, 0x00f6, 0x2079, 0x1800, 0x7a88, + 0x6014, 0x2048, 0xa87c, 0xd0ec, 0x1110, 0x9290, 0x0018, 0xac78, + 0x0046, 0xa8e0, 0x9005, 0x1140, 0xa8dc, 0x921a, 0x0140, 0x0220, + 0xa87b, 0x0007, 0x2010, 0x0028, 0xa87b, 0x0015, 0x0010, 0xa87b, + 0x0000, 0x8214, 0xa883, 0x0000, 0xaa02, 0x0006, 0x0016, 0x0026, + 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x2400, 0x9005, 0x1108, 0x009a, + 0x2100, 0x9086, 0x0015, 0x1118, 0x2001, 0x0001, 0x0038, 0x2100, + 0x9086, 0x0016, 0x0118, 0x2001, 0x0001, 0x002a, 0x94a4, 0x0007, + 0x8423, 0x9405, 0x0002, 0x9b80, 0x9b80, 0x9b7b, 0x9b7e, 0x9b80, + 0x9b78, 0x9b6b, 0x9b6b, 0x9b6b, 0x9b6b, 0x9b6b, 0x9b6b, 0x9b6b, + 0x9b6b, 0x9b6b, 0x9b6b, 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x002e, + 0x001e, 0x000e, 0x004e, 0x00fe, 0x009e, 0x00de, 0x080c, 0x0db2, + 0x080c, 0xa5d7, 0x0028, 0x080c, 0xa6b5, 0x0010, 0x080c, 0xa7a4, + 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x002e, 0x001e, 0x2c00, 0xa896, + 0x000e, 0x080c, 0x9d2c, 0x0530, 0xa804, 0xa80e, 0x00a6, 0x2050, + 0xb100, 0x00ae, 0x8006, 0x8006, 0x8007, 0x90bc, 0x003f, 0x9084, + 0xffc0, 0x9080, 0x0002, 0xaacc, 0xabd0, 0xacd4, 0xadd8, 0x2031, + 0x0000, 0x2041, 0x1226, 0x080c, 0x9ed6, 0x0160, 0x000e, 0x9005, + 0x0120, 0x00fe, 0x009e, 0x00de, 0x0005, 0x00fe, 0x009e, 0x00de, + 0x0804, 0x99d6, 0x2001, 0x002c, 0x900e, 0x080c, 0x9d92, 0x0c70, + 0x91b6, 0x0015, 0x0170, 0x91b6, 0x0016, 0x0158, 0x91b2, 0x0047, + 0x0a0c, 0x0db2, 0x91b2, 0x0050, 0x1a0c, 0x0db2, 0x9182, 0x0047, + 0x00ca, 0x2001, 0x0109, 0x2004, 0xd08c, 0x0198, 0x0126, 0x2091, + 0x2800, 0x0006, 0x0016, 0x0026, 0x080c, 0x7fb9, 0x002e, 0x001e, + 0x000e, 0x012e, 0xa001, 0x6000, 0x9086, 0x0002, 0x1110, 0x0804, + 0x9b1a, 0x0005, 0x9beb, 0x9beb, 0x9bed, 0x9c22, 0x9beb, 0x9beb, + 0x9beb, 0x9beb, 0x9c35, 0x080c, 0x0db2, 0x00d6, 0x0016, 0x0096, + 0x080c, 0x8532, 0x080c, 0x865d, 0x6003, 0x0004, 0x6114, 0x2148, + 0xa87c, 0xd0fc, 0x01b8, 0xa878, 0x9005, 0x1158, 0xa894, 0x9005, + 0x0140, 0x2001, 0x0000, 0x900e, 0x080c, 0x9d92, 0x080c, 0x99d6, + 0x00a8, 0x6003, 0x0002, 0xa8a4, 0xa9a8, 0x9105, 0x1178, 0xa8ae, + 0xa8b2, 0x0c78, 0xa87f, 0x0020, 0xa88c, 0xa88a, 0xa8a4, 0xa8ae, + 0xa8a8, 0xa8b2, 0xa8c7, 0x0000, 0xa8cb, 0x0000, 0x009e, 0x001e, + 0x00de, 0x0005, 0x080c, 0x8532, 0x00d6, 0x0096, 0x6114, 0x2148, + 0x080c, 0xb5fb, 0x0120, 0xa87b, 0x0006, 0x080c, 0x6536, 0x009e, + 0x00de, 0x080c, 0x99d6, 0x0804, 0x865d, 0x080c, 0x8532, 0x080c, + 0x2e30, 0x080c, 0xbd01, 0x00d6, 0x0096, 0x6114, 0x2148, 0x080c, + 0xb5fb, 0x0120, 0xa87b, 0x0029, 0x080c, 0x6536, 0x009e, 0x00de, + 0x080c, 0x99d6, 0x0804, 0x865d, 0x9182, 0x0047, 0x0002, 0x9c5c, + 0x9c5e, 0x9c5c, 0x9c5c, 0x9c5c, 0x9c5c, 0x9c5c, 0x9c5c, 0x9c5c, + 0x9c5c, 0x9c5c, 0x9c5c, 0x9c5e, 0x080c, 0x0db2, 0x00d6, 0x0096, + 0x080c, 0x14c9, 0x6114, 0x2148, 0xa87b, 0x0000, 0xa883, 0x0000, + 0x080c, 0x6536, 0x009e, 0x00de, 0x0804, 0x99d6, 0x0026, 0x0036, + 0x0056, 0x0066, 0x0096, 0x00a6, 0x00f6, 0x0006, 0x080c, 0x0fd5, + 0x000e, 0x090c, 0x0db2, 0xa960, 0x21e8, 0xa95c, 0x9188, 0x0019, + 0x21a0, 0x900e, 0x20a9, 0x0020, 0x4104, 0xa87a, 0x2079, 0x1800, + 0x7988, 0x9188, 0x0018, 0x918c, 0x0fff, 0xa972, 0xac76, 0x2950, + 0x00a6, 0x2001, 0x0205, 0x2003, 0x0000, 0x901e, 0x2029, 0x0001, + 0x9182, 0x0034, 0x1228, 0x2011, 0x001f, 0x080c, 0xb219, 0x04c0, + 0x2130, 0x2009, 0x0034, 0x2011, 0x001f, 0x080c, 0xb219, 0x96b2, + 0x0034, 0xb004, 0x904d, 0x0110, 0x080c, 0x0f87, 0x080c, 0x0fd5, + 0x01d0, 0x8528, 0xa867, 0x0110, 0xa86b, 0x0000, 0x2920, 0xb406, + 0x968a, 0x003d, 0x1230, 0x2608, 0x2011, 0x001b, 0x080c, 0xb219, + 0x00b8, 0x96b2, 0x003c, 0x2009, 0x003c, 0x2950, 0x2011, 0x001b, + 0x080c, 0xb219, 0x0c18, 0x2001, 0x0205, 0x2003, 0x0000, 0x00ae, + 0x852f, 0x95ad, 0x0050, 0xb566, 0xb070, 0xc0fd, 0xb072, 0x0048, + 0x2001, 0x0205, 0x2003, 0x0000, 0x00ae, 0x852f, 0x95ad, 0x0050, + 0xb566, 0x2a48, 0xa804, 0xa807, 0x0000, 0x0006, 0x080c, 0x6536, + 0x000e, 0x2048, 0x9005, 0x1db0, 0x00fe, 0x00ae, 0x009e, 0x006e, + 0x005e, 0x003e, 0x002e, 0x0005, 0x00d6, 0x00f6, 0x0096, 0x0006, + 0x080c, 0x0fd5, 0x000e, 0x090c, 0x0db2, 0xa960, 0x21e8, 0xa95c, + 0x9188, 0x0019, 0x21a0, 0x900e, 0x20a9, 0x0020, 0x4104, 0xaa66, + 0xa87a, 0x2079, 0x1800, 0x7988, 0x810c, 0x9188, 0x000c, 0x9182, + 0x001a, 0x0210, 0x2009, 0x001a, 0x21a8, 0x810b, 0xa972, 0xac76, + 0x2e98, 0xa85c, 0x9080, 0x001f, 0x20a0, 0x2001, 0x0205, 0x200c, + 0x918d, 0x0080, 0x2102, 0x4003, 0x2003, 0x0000, 0x080c, 0x6536, + 0x009e, 0x00fe, 0x00de, 0x0005, 0x0016, 0x00d6, 0x00f6, 0x0096, + 0x0016, 0x2001, 0x0205, 0x200c, 0x918d, 0x0080, 0x2102, 0x001e, + 0x2079, 0x0200, 0x2e98, 0xa87c, 0xd0ec, 0x0118, 0x9e80, 0x000c, + 0x2098, 0x2021, 0x003e, 0x901e, 0x9282, 0x0020, 0x0218, 0x2011, + 0x0020, 0x2018, 0x9486, 0x003e, 0x1170, 0x0096, 0x080c, 0x0fd5, + 0x2900, 0x009e, 0x05c0, 0xa806, 0x2048, 0xa860, 0x20e8, 0xa85c, + 0x9080, 0x0002, 0x20a0, 0x3300, 0x908e, 0x0260, 0x0140, 0x2009, + 0x0280, 0x9102, 0x920a, 0x0218, 0x2010, 0x2100, 0x9318, 0x2200, + 0x9402, 0x1228, 0x2400, 0x9202, 0x2410, 0x9318, 0x9006, 0x2020, + 0x22a8, 0xa800, 0x9200, 0xa802, 0x20e1, 0x0000, 0x4003, 0x83ff, + 0x0180, 0x3300, 0x9086, 0x0280, 0x1130, 0x7814, 0x8000, 0x9085, + 0x0080, 0x7816, 0x2e98, 0x2310, 0x84ff, 0x0904, 0x9d41, 0x0804, + 0x9d43, 0x9085, 0x0001, 0x7817, 0x0000, 0x009e, 0x00fe, 0x00de, + 0x001e, 0x0005, 0x00d6, 0x0036, 0x0096, 0x6314, 0x2348, 0xa87a, + 0xa982, 0x080c, 0x6529, 0x009e, 0x003e, 0x00de, 0x0005, 0x91b6, + 0x0015, 0x1118, 0x080c, 0x99d6, 0x0030, 0x91b6, 0x0016, 0x190c, + 0x0db2, 0x080c, 0x99d6, 0x0005, 0x20a9, 0x000e, 0x20e1, 0x0000, + 0x2e98, 0x6014, 0x0096, 0x2048, 0xa860, 0x20e8, 0xa85c, 0x20a0, + 0x009e, 0x4003, 0x0136, 0x9080, 0x001b, 0x2011, 0x0006, 0x20a9, + 0x0001, 0x3418, 0x8318, 0x23a0, 0x4003, 0x3318, 0x8318, 0x2398, + 0x8211, 0x1db8, 0x2011, 0x0006, 0x013e, 0x20a0, 0x3318, 0x8318, + 0x2398, 0x4003, 0x3418, 0x8318, 0x23a0, 0x8211, 0x1db8, 0x0096, + 0x080c, 0xb5fb, 0x0130, 0x6014, 0x2048, 0xa807, 0x0000, 0xa867, + 0x0103, 0x009e, 0x0804, 0x99d6, 0x0096, 0x00d6, 0x0036, 0x7330, + 0x9386, 0x0200, 0x11a8, 0x6010, 0x00b6, 0x2058, 0xb8bf, 0x0000, + 0x00be, 0x6014, 0x9005, 0x0130, 0x2048, 0xa807, 0x0000, 0xa867, + 0x0103, 0xab32, 0x080c, 0x99d6, 0x003e, 0x00de, 0x009e, 0x0005, + 0x0011, 0x1d48, 0x0cc8, 0x0006, 0x0016, 0x080c, 0xbcec, 0x0188, + 0x6014, 0x9005, 0x1170, 0x600b, 0x0003, 0x601b, 0x0000, 0x6043, + 0x0000, 0x2009, 0x0022, 0x080c, 0xa1b5, 0x9006, 0x001e, 0x000e, + 0x0005, 0x9085, 0x0001, 0x0cd0, 0x0096, 0x0016, 0x20a9, 0x0014, + 0x9e80, 0x000c, 0x20e1, 0x0000, 0x2098, 0x6014, 0x2048, 0xa860, + 0x20e8, 0xa85c, 0x9080, 0x0002, 0x20a0, 0x4003, 0x2001, 0x0205, + 0x2003, 0x0001, 0x2099, 0x0260, 0x20a9, 0x0016, 0x4003, 0x20a9, + 0x000a, 0xa804, 0x2048, 0xa860, 0x20e8, 0xa85c, 0x9080, 0x0002, + 0x20a0, 0x4003, 0x2001, 0x0205, 0x2003, 0x0002, 0x2099, 0x0260, + 0x20a9, 0x0020, 0x4003, 0x2003, 0x0000, 0x6014, 0x2048, 0xa800, + 0x2048, 0xa867, 0x0103, 0x080c, 0x99d6, 0x001e, 0x009e, 0x0005, + 0x0096, 0x0016, 0x900e, 0x7030, 0x9086, 0x0100, 0x0140, 0x7038, + 0x9084, 0x00ff, 0x800c, 0x703c, 0x9084, 0x00ff, 0x8004, 0x9080, + 0x0004, 0x9108, 0x810b, 0x2011, 0x0002, 0x2019, 0x000c, 0x6014, + 0x2048, 0x080c, 0xb219, 0x080c, 0xb5fb, 0x0140, 0x6014, 0x2048, + 0xa807, 0x0000, 0xa864, 0xa8e2, 0xa867, 0x0103, 0x080c, 0x99d6, + 0x001e, 0x009e, 0x0005, 0x0016, 0x0096, 0x7030, 0x9086, 0x0100, + 0x1118, 0x2009, 0x0004, 0x0010, 0x7034, 0x800c, 0x810b, 0x2011, + 0x000c, 0x2019, 0x000c, 0x6014, 0x2048, 0xa804, 0x0096, 0x9005, + 0x0108, 0x2048, 0x080c, 0xb219, 0x009e, 0x080c, 0xb5fb, 0x0148, + 0xa804, 0x9005, 0x1158, 0xa807, 0x0000, 0xa864, 0xa8e2, 0xa867, + 0x0103, 0x080c, 0x99d6, 0x009e, 0x001e, 0x0005, 0x0086, 0x2040, + 0xa030, 0x8007, 0x9086, 0x0100, 0x1118, 0x080c, 0xa364, 0x00e0, + 0xa034, 0x8007, 0x800c, 0x8806, 0x8006, 0x8007, 0x90bc, 0x003f, + 0x9084, 0xffc0, 0x9080, 0x000c, 0xa87b, 0x0000, 0xa883, 0x0000, + 0xa897, 0x4000, 0xaaa0, 0xab9c, 0xaca8, 0xada4, 0x2031, 0x0000, + 0x2041, 0x120c, 0x0019, 0x0d08, 0x008e, 0x0898, 0x0096, 0x0006, + 0x080c, 0x0fd5, 0x000e, 0x01b0, 0xa8ab, 0x0dcb, 0xa876, 0x000e, + 0xa8a2, 0x0006, 0xae6a, 0x2800, 0xa89e, 0xa97a, 0xaf72, 0xaa8e, + 0xab92, 0xac96, 0xad9a, 0x0086, 0x2940, 0x080c, 0x10b5, 0x008e, + 0x9085, 0x0001, 0x009e, 0x0005, 0x00e6, 0x00d6, 0x0026, 0x7008, + 0x9084, 0x00ff, 0x6210, 0x00b6, 0x2258, 0xba10, 0x00be, 0x9206, + 0x1520, 0x700c, 0x6210, 0x00b6, 0x2258, 0xba14, 0x00be, 0x9206, + 0x11e0, 0x6043, 0x0000, 0x2c68, 0x0016, 0x2009, 0x0035, 0x080c, + 0xbc66, 0x001e, 0x1158, 0x622c, 0x2268, 0x2071, 0x026c, 0x6b20, + 0x9386, 0x0003, 0x0130, 0x9386, 0x0006, 0x0128, 0x080c, 0x99d6, + 0x0020, 0x0039, 0x0010, 0x080c, 0x9fe8, 0x002e, 0x00de, 0x00ee, + 0x0005, 0x0096, 0x6814, 0x2048, 0x9186, 0x0015, 0x0904, 0x9fd0, + 0x918e, 0x0016, 0x1904, 0x9fe6, 0x700c, 0x908c, 0xff00, 0x9186, + 0x1700, 0x0120, 0x9186, 0x0300, 0x1904, 0x9faa, 0x89ff, 0x1138, + 0x6800, 0x9086, 0x000f, 0x0904, 0x9f8d, 0x0804, 0x9fe4, 0x6808, + 0x9086, 0xffff, 0x1904, 0x9fd2, 0xa87c, 0x9084, 0x0060, 0x9086, + 0x0020, 0x1128, 0xa83c, 0xa940, 0x9105, 0x1904, 0x9fd2, 0x6824, + 0xd0b4, 0x1904, 0x9fd2, 0x080c, 0xb7dd, 0x685c, 0xa882, 0xa87c, + 0xc0dc, 0xc0f4, 0xc0d4, 0xa87e, 0x0026, 0x900e, 0x6a18, 0x2001, + 0x000a, 0x080c, 0x7e7f, 0xa884, 0x920a, 0x0208, 0x8011, 0xaa86, + 0x82ff, 0x002e, 0x1138, 0x00c6, 0x2d60, 0x080c, 0xb33a, 0x00ce, + 0x0804, 0x9fe4, 0x00c6, 0xa868, 0xd0fc, 0x1118, 0x080c, 0x5a9d, + 0x0010, 0x080c, 0x5e34, 0x00ce, 0x1904, 0x9fd2, 0x00c6, 0x2d60, + 0x080c, 0x99d6, 0x00ce, 0x0804, 0x9fe4, 0x00c6, 0x080c, 0x9a23, + 0x0198, 0x6017, 0x0000, 0x6810, 0x6012, 0x080c, 0xba69, 0x6023, + 0x0003, 0x6904, 0x00c6, 0x2d60, 0x080c, 0x99d6, 0x00ce, 0x080c, + 0x9a50, 0x00ce, 0x0804, 0x9fe4, 0x2001, 0x1957, 0x2004, 0x6842, + 0x00ce, 0x04d0, 0x7008, 0x9086, 0x000b, 0x11c8, 0x6010, 0x00b6, + 0x2058, 0xb900, 0xc1bc, 0xb902, 0x00be, 0x00c6, 0x2d60, 0xa883, + 0x0003, 0x080c, 0xbca8, 0x6007, 0x0085, 0x6003, 0x000b, 0x6023, + 0x0002, 0x080c, 0x8000, 0x080c, 0x8582, 0x00ce, 0x00e8, 0x700c, + 0x9086, 0x2a00, 0x1138, 0x2001, 0x1957, 0x2004, 0x6842, 0x00a0, + 0x0479, 0x00a0, 0x89ff, 0x090c, 0x0db2, 0x00c6, 0x00d6, 0x2d60, + 0xa867, 0x0103, 0xa87b, 0x0003, 0x080c, 0x6351, 0x080c, 0xb7dd, + 0x080c, 0x9a06, 0x00de, 0x00ce, 0x080c, 0x99d6, 0x009e, 0x0005, + 0x9186, 0x0015, 0x1128, 0x2001, 0x1957, 0x2004, 0x6842, 0x0068, + 0x918e, 0x0016, 0x1160, 0x00c6, 0x2d00, 0x2060, 0x080c, 0xd240, + 0x080c, 0x7e13, 0x080c, 0x99d6, 0x00ce, 0x080c, 0x99d6, 0x0005, + 0x0026, 0x0036, 0x0046, 0x7228, 0xacb0, 0xabac, 0xd2f4, 0x0130, + 0x2001, 0x1957, 0x2004, 0x6842, 0x0804, 0xa064, 0x00c6, 0x2d60, + 0x080c, 0xb244, 0x00ce, 0x6804, 0x9086, 0x0050, 0x1170, 0x00c6, + 0x2d00, 0x2060, 0x6003, 0x0001, 0x6007, 0x0050, 0x080c, 0x8000, + 0x080c, 0x8582, 0x00ce, 0x0804, 0xa064, 0x6800, 0x9086, 0x000f, + 0x01b0, 0x89ff, 0x090c, 0x0db2, 0x6800, 0x9086, 0x0004, 0x1198, + 0xa87c, 0xd0ac, 0x0180, 0xa843, 0x0fff, 0xa83f, 0x0fff, 0xa880, + 0xc0f4, 0xc0fc, 0xa882, 0x2001, 0x0001, 0x6832, 0x0400, 0x2001, + 0x0007, 0x6832, 0x00e0, 0xa87c, 0xd0b4, 0x1150, 0xd0ac, 0x0db8, + 0x6824, 0xd0f4, 0x1d40, 0xa838, 0xa934, 0x9105, 0x0d80, 0x0c18, + 0xd2ec, 0x1d68, 0x7024, 0x9306, 0x1118, 0x7020, 0x9406, 0x0d38, + 0x7020, 0x683e, 0x7024, 0x683a, 0x2001, 0x0005, 0x6832, 0x080c, + 0xb960, 0x080c, 0x8582, 0x0010, 0x080c, 0x99d6, 0x004e, 0x003e, + 0x002e, 0x0005, 0x00e6, 0x00d6, 0x0026, 0x7008, 0x9084, 0x00ff, + 0x6210, 0x00b6, 0x2258, 0xba10, 0x00be, 0x9206, 0x1904, 0xa0cf, + 0x700c, 0x6210, 0x00b6, 0x2258, 0xba14, 0x00be, 0x9206, 0x1904, + 0xa0cf, 0x6038, 0x2068, 0x6824, 0xc0dc, 0x6826, 0x6a20, 0x9286, + 0x0007, 0x0904, 0xa0cf, 0x9286, 0x0002, 0x0904, 0xa0cf, 0x9286, + 0x0000, 0x05e8, 0x6808, 0x633c, 0x9306, 0x15c8, 0x2071, 0x026c, + 0x9186, 0x0015, 0x0570, 0x918e, 0x0016, 0x1100, 0x00c6, 0x6038, + 0x2060, 0x6104, 0x9186, 0x004b, 0x01c0, 0x9186, 0x004c, 0x01a8, + 0x9186, 0x004d, 0x0190, 0x9186, 0x004e, 0x0178, 0x9186, 0x0052, + 0x0160, 0x6014, 0x0096, 0x2048, 0x080c, 0xb5fb, 0x090c, 0x0db2, + 0xa883, 0x0003, 0x009e, 0x080c, 0xbca8, 0x6007, 0x0085, 0x6003, + 0x000b, 0x6023, 0x0002, 0x080c, 0x8000, 0x080c, 0x8582, 0x00ce, + 0x0030, 0x6038, 0x2070, 0x2001, 0x1957, 0x2004, 0x7042, 0x080c, + 0x99d6, 0x002e, 0x00de, 0x00ee, 0x0005, 0x00b6, 0x0096, 0x00f6, + 0x6014, 0x2048, 0x6010, 0x2058, 0x91b6, 0x0015, 0x0130, 0xba08, + 0xbb0c, 0xbc00, 0xc48c, 0xbc02, 0x0460, 0x0096, 0x0156, 0x0036, + 0x0026, 0x2b48, 0x9e90, 0x0010, 0x2019, 0x000a, 0x20a9, 0x0004, + 0x080c, 0xa91d, 0x002e, 0x003e, 0x015e, 0x009e, 0x1904, 0xa13e, + 0x0096, 0x0156, 0x0036, 0x0026, 0x2b48, 0x9e90, 0x0014, 0x2019, + 0x0006, 0x20a9, 0x0004, 0x080c, 0xa91d, 0x002e, 0x003e, 0x015e, + 0x009e, 0x15a0, 0x7238, 0xba0a, 0x733c, 0xbb0e, 0xbc00, 0xc48d, + 0xbc02, 0xa804, 0x9005, 0x1128, 0x00fe, 0x009e, 0x00be, 0x0804, + 0x9dd7, 0x0096, 0x2048, 0xaa12, 0xab16, 0xac0a, 0x009e, 0x8006, + 0x8006, 0x8007, 0x90bc, 0x003f, 0x9084, 0xffc0, 0x9080, 0x0002, + 0x2009, 0x002b, 0xaaa0, 0xab9c, 0xaca8, 0xada4, 0x2031, 0x0000, + 0x2041, 0x120c, 0x080c, 0x9ed6, 0x0130, 0x00fe, 0x009e, 0x080c, + 0x99d6, 0x00be, 0x0005, 0x080c, 0xa364, 0x0cb8, 0x2b78, 0x00f6, + 0x080c, 0x2e30, 0x080c, 0xbd01, 0x00fe, 0x00c6, 0x080c, 0x9980, + 0x2f00, 0x6012, 0x6017, 0x0000, 0x6023, 0x0001, 0x6007, 0x0001, + 0x6003, 0x0001, 0x2001, 0x0007, 0x080c, 0x5ecf, 0x080c, 0x5efb, + 0x080c, 0x8048, 0x080c, 0x8582, 0x00ce, 0x0804, 0xa111, 0x2100, + 0x91b2, 0x0053, 0x1a0c, 0x0db2, 0x91b2, 0x0040, 0x1a04, 0xa1c7, + 0x0002, 0xa1b5, 0xa1b5, 0xa1ab, 0xa1b5, 0xa1b5, 0xa1b5, 0xa1a9, + 0xa1a9, 0xa1a9, 0xa1a9, 0xa1a9, 0xa1a9, 0xa1a9, 0xa1a9, 0xa1a9, + 0xa1a9, 0xa1a9, 0xa1a9, 0xa1a9, 0xa1a9, 0xa1a9, 0xa1a9, 0xa1a9, + 0xa1a9, 0xa1a9, 0xa1a9, 0xa1a9, 0xa1a9, 0xa1a9, 0xa1a9, 0xa1a9, + 0xa1b5, 0xa1a9, 0xa1b5, 0xa1b5, 0xa1a9, 0xa1a9, 0xa1a9, 0xa1a9, + 0xa1a9, 0xa1ab, 0xa1a9, 0xa1a9, 0xa1a9, 0xa1a9, 0xa1a9, 0xa1a9, + 0xa1a9, 0xa1a9, 0xa1a9, 0xa1b5, 0xa1b5, 0xa1a9, 0xa1a9, 0xa1a9, + 0xa1a9, 0xa1a9, 0xa1a9, 0xa1a9, 0xa1a9, 0xa1a9, 0xa1b5, 0xa1a9, + 0xa1a9, 0x080c, 0x0db2, 0x0066, 0x00b6, 0x6610, 0x2658, 0xb8bc, + 0xc08c, 0xb8be, 0x00be, 0x006e, 0x0000, 0x6003, 0x0001, 0x6106, + 0x9186, 0x0032, 0x0118, 0x080c, 0x8048, 0x0010, 0x080c, 0x8000, + 0x0126, 0x2091, 0x8000, 0x080c, 0x8582, 0x012e, 0x0005, 0x2600, + 0x0002, 0xa1db, 0xa1db, 0xa1db, 0xa1b5, 0xa1b5, 0xa1db, 0xa1db, + 0xa1db, 0xa1db, 0xa1b5, 0xa1db, 0xa1b5, 0xa1db, 0xa1b5, 0xa1db, + 0xa1db, 0xa1db, 0xa1db, 0x080c, 0x0db2, 0x6004, 0x90b2, 0x0053, + 0x1a0c, 0x0db2, 0x91b6, 0x0013, 0x0904, 0xa29f, 0x91b6, 0x0027, + 0x1904, 0xa25a, 0x080c, 0x847d, 0x6004, 0x080c, 0xb7e9, 0x01b0, + 0x080c, 0xb7fa, 0x01a8, 0x908e, 0x0021, 0x0904, 0xa257, 0x908e, + 0x0022, 0x1130, 0x080c, 0x9e03, 0x0904, 0xa253, 0x0804, 0xa254, + 0x908e, 0x003d, 0x0904, 0xa257, 0x0804, 0xa24d, 0x080c, 0x2e55, + 0x2001, 0x0007, 0x080c, 0x5ecf, 0x6010, 0x00b6, 0x2058, 0xb9a0, + 0x00be, 0x080c, 0xa364, 0x9186, 0x007e, 0x1148, 0x2001, 0x1835, + 0x2014, 0xc285, 0x080c, 0x6c53, 0x1108, 0xc2ad, 0x2202, 0x0036, + 0x0026, 0x2019, 0x0028, 0x2110, 0x080c, 0xd29b, 0x002e, 0x003e, + 0x0016, 0x0026, 0x0036, 0x2110, 0x2019, 0x0028, 0x080c, 0x8180, + 0x0076, 0x903e, 0x080c, 0x8078, 0x6010, 0x00b6, 0x905d, 0x0100, + 0x00be, 0x2c08, 0x080c, 0xcd62, 0x007e, 0x003e, 0x002e, 0x001e, + 0x080c, 0xbd01, 0x0016, 0x080c, 0xba61, 0x080c, 0x99d6, 0x001e, + 0x080c, 0x2f28, 0x080c, 0x8582, 0x0030, 0x080c, 0xba61, 0x080c, + 0x99d6, 0x080c, 0x8582, 0x0005, 0x080c, 0xa364, 0x0cb0, 0x080c, + 0xa3a0, 0x0c98, 0x9186, 0x0014, 0x1db0, 0x080c, 0x847d, 0x6004, + 0x908e, 0x0022, 0x1118, 0x080c, 0x9e03, 0x0d68, 0x080c, 0x2e30, + 0x080c, 0xbd01, 0x080c, 0xb7e9, 0x1190, 0x080c, 0x2e55, 0x6010, + 0x00b6, 0x2058, 0xb9a0, 0x00be, 0x080c, 0xa364, 0x9186, 0x007e, + 0x1128, 0x2001, 0x1835, 0x200c, 0xc185, 0x2102, 0x0870, 0x080c, + 0xb7fa, 0x1118, 0x080c, 0xa364, 0x0840, 0x6004, 0x908e, 0x0032, + 0x1160, 0x00e6, 0x00f6, 0x2071, 0x1894, 0x2079, 0x0000, 0x080c, + 0x31c3, 0x00fe, 0x00ee, 0x0804, 0xa24d, 0x6004, 0x908e, 0x0021, + 0x0d48, 0x908e, 0x0022, 0x090c, 0xa364, 0x0804, 0xa24d, 0x90b2, + 0x0040, 0x1a04, 0xa34d, 0x2008, 0x0002, 0xa2e7, 0xa2e8, 0xa2eb, + 0xa2ee, 0xa2f1, 0xa2f4, 0xa2e5, 0xa2e5, 0xa2e5, 0xa2e5, 0xa2e5, + 0xa2e5, 0xa2e5, 0xa2e5, 0xa2e5, 0xa2e5, 0xa2e5, 0xa2e5, 0xa2e5, + 0xa2e5, 0xa2e5, 0xa2e5, 0xa2e5, 0xa2e5, 0xa2e5, 0xa2e5, 0xa2e5, + 0xa2e5, 0xa2e5, 0xa2e5, 0xa2f7, 0xa302, 0xa2e5, 0xa304, 0xa302, + 0xa2e5, 0xa2e5, 0xa2e5, 0xa2e5, 0xa2e5, 0xa302, 0xa302, 0xa2e5, + 0xa2e5, 0xa2e5, 0xa2e5, 0xa2e5, 0xa2e5, 0xa2e5, 0xa2e5, 0xa334, + 0xa302, 0xa2e5, 0xa2fe, 0xa2e5, 0xa2e5, 0xa2e5, 0xa2ff, 0xa2e5, + 0xa2e5, 0xa2e5, 0xa302, 0xa32b, 0xa2e5, 0x080c, 0x0db2, 0x00d0, + 0x2001, 0x000b, 0x0410, 0x2001, 0x0003, 0x00f8, 0x2001, 0x0005, + 0x00e0, 0x2001, 0x0001, 0x00c8, 0x2001, 0x0009, 0x00b0, 0x080c, + 0x847d, 0x6003, 0x0005, 0x080c, 0x8582, 0x0070, 0x0018, 0x0010, + 0x080c, 0x5ecf, 0x0804, 0xa345, 0x080c, 0x847d, 0x080c, 0xbd04, + 0x6003, 0x0004, 0x080c, 0x8582, 0x0005, 0x080c, 0x5ecf, 0x080c, + 0x847d, 0x6003, 0x0002, 0x0036, 0x2019, 0x185e, 0x2304, 0x9084, + 0xff00, 0x1120, 0x2001, 0x1955, 0x201c, 0x0040, 0x8007, 0x909a, + 0x0004, 0x0ec0, 0x8003, 0x801b, 0x831b, 0x9318, 0x631a, 0x003e, + 0x080c, 0x8582, 0x0c08, 0x080c, 0x847d, 0x080c, 0xba61, 0x080c, + 0x99d6, 0x080c, 0x8582, 0x08c0, 0x00e6, 0x00f6, 0x2071, 0x1894, + 0x2079, 0x0000, 0x080c, 0x31c3, 0x00fe, 0x00ee, 0x080c, 0x847d, + 0x080c, 0x99d6, 0x080c, 0x8582, 0x0838, 0x080c, 0x847d, 0x6003, + 0x0002, 0x080c, 0xbd04, 0x0804, 0x8582, 0x2600, 0x2008, 0x0002, + 0xa362, 0xa362, 0xa362, 0xa345, 0xa345, 0xa362, 0xa362, 0xa362, + 0xa362, 0xa345, 0xa362, 0xa345, 0xa362, 0xa345, 0xa362, 0xa362, + 0xa362, 0xa362, 0x080c, 0x0db2, 0x00e6, 0x0096, 0x0026, 0x0016, + 0x080c, 0xb5fb, 0x0568, 0x6014, 0x2048, 0xa864, 0x9086, 0x0139, + 0x11a8, 0xa894, 0x9086, 0x0056, 0x1148, 0x080c, 0x4ebc, 0x0130, + 0x2001, 0x0000, 0x900e, 0x2011, 0x4000, 0x0028, 0x2001, 0x0030, + 0x900e, 0x2011, 0x4005, 0x080c, 0xbbcd, 0x0090, 0xa868, 0xd0fc, + 0x0178, 0xa807, 0x0000, 0x0016, 0x6004, 0x908e, 0x0021, 0x0168, + 0x908e, 0x003d, 0x0150, 0x001e, 0xa867, 0x0103, 0xa833, 0x0100, + 0x001e, 0x002e, 0x009e, 0x00ee, 0x0005, 0x001e, 0x0009, 0x0cc0, + 0x0096, 0x6014, 0x2048, 0xa800, 0x2048, 0xa867, 0x0103, 0xa823, + 0x8001, 0x009e, 0x0005, 0x00b6, 0x6610, 0x2658, 0xb804, 0x9084, + 0x00ff, 0x90b2, 0x000c, 0x1a0c, 0x0db2, 0x6604, 0x96b6, 0x004d, + 0x1120, 0x080c, 0xbaed, 0x0804, 0xa428, 0x6604, 0x96b6, 0x0043, + 0x1120, 0x080c, 0xbb36, 0x0804, 0xa428, 0x6604, 0x96b6, 0x004b, + 0x1120, 0x080c, 0xbb62, 0x0804, 0xa428, 0x6604, 0x96b6, 0x0033, + 0x1120, 0x080c, 0xba83, 0x0804, 0xa428, 0x6604, 0x96b6, 0x0028, + 0x1120, 0x080c, 0xb833, 0x0804, 0xa428, 0x6604, 0x96b6, 0x0029, + 0x1120, 0x080c, 0xb874, 0x0804, 0xa428, 0x6604, 0x96b6, 0x001f, + 0x1118, 0x080c, 0x9dac, 0x04e0, 0x6604, 0x96b6, 0x0000, 0x1118, + 0x080c, 0xa0d5, 0x04a8, 0x6604, 0x96b6, 0x0022, 0x1118, 0x080c, + 0x9de4, 0x0470, 0x6604, 0x96b6, 0x0035, 0x1118, 0x080c, 0x9ef4, + 0x0438, 0x6604, 0x96b6, 0x0039, 0x1118, 0x080c, 0xa06a, 0x0400, + 0x6604, 0x96b6, 0x003d, 0x1118, 0x080c, 0x9e1c, 0x00c8, 0x6604, + 0x96b6, 0x0044, 0x1118, 0x080c, 0x9e58, 0x0090, 0x6604, 0x96b6, + 0x0049, 0x1118, 0x080c, 0x9e83, 0x0058, 0x91b6, 0x0015, 0x1110, + 0x0063, 0x0030, 0x91b6, 0x0016, 0x1128, 0x00be, 0x0804, 0xa65e, + 0x00be, 0x0005, 0x080c, 0x9a6b, 0x0cd8, 0xa445, 0xa448, 0xa445, + 0xa48d, 0xa445, 0xa5d7, 0xa66b, 0xa445, 0xa445, 0xa638, 0xa445, + 0xa64c, 0x0096, 0x080c, 0x14c9, 0x6014, 0x2048, 0xa800, 0x2048, + 0xa867, 0x0103, 0x009e, 0x0804, 0x99d6, 0xa001, 0xa001, 0x0005, + 0x00e6, 0x2071, 0x1800, 0x7088, 0x9086, 0x0074, 0x1540, 0x080c, + 0xcd33, 0x11b0, 0x6010, 0x00b6, 0x2058, 0x7030, 0xd08c, 0x0128, + 0xb800, 0xd0bc, 0x0110, 0xc0c5, 0xb802, 0x00e9, 0x00be, 0x2001, + 0x0006, 0x080c, 0x5ecf, 0x080c, 0x2e55, 0x080c, 0x99d6, 0x0088, + 0x2001, 0x000a, 0x080c, 0x5ecf, 0x080c, 0x2e55, 0x6003, 0x0001, + 0x6007, 0x0001, 0x080c, 0x8048, 0x080c, 0x8582, 0x0010, 0x080c, + 0xa5c2, 0x00ee, 0x0005, 0x00d6, 0xb800, 0xd084, 0x0160, 0x9006, + 0x080c, 0x5ebb, 0x2069, 0x1853, 0x6804, 0xd0a4, 0x0120, 0x2001, + 0x0006, 0x080c, 0x5efb, 0x00de, 0x0005, 0x00b6, 0x0096, 0x00d6, + 0x2011, 0x1822, 0x2204, 0x9086, 0x0074, 0x1904, 0xa59b, 0x6010, + 0x2058, 0xbaa0, 0x9286, 0x007e, 0x1120, 0x080c, 0xa7af, 0x0804, + 0xa4ff, 0x080c, 0xa7a4, 0x6010, 0x2058, 0xbaa0, 0x9286, 0x0080, + 0x1510, 0x6014, 0x9005, 0x01a8, 0x2048, 0xa864, 0x9084, 0x00ff, + 0x9086, 0x0039, 0x1140, 0x2001, 0x0000, 0x900e, 0x2011, 0x4000, + 0x080c, 0xbbcd, 0x0030, 0xa807, 0x0000, 0xa867, 0x0103, 0xa833, + 0x0200, 0x2001, 0x0006, 0x080c, 0x5ecf, 0x080c, 0x2e55, 0x080c, + 0x99d6, 0x0804, 0xa59c, 0x080c, 0xa5aa, 0x6014, 0x9005, 0x0190, + 0x2048, 0xa868, 0xd0f4, 0x01e8, 0xa864, 0x9084, 0x00ff, 0x9086, + 0x0039, 0x1d08, 0x2001, 0x0000, 0x900e, 0x2011, 0x4000, 0x080c, + 0xbbcd, 0x08f8, 0x080c, 0xa5a0, 0x0160, 0x9006, 0x080c, 0x5ebb, + 0x2001, 0x0004, 0x080c, 0x5efb, 0x2001, 0x0007, 0x080c, 0x5ecf, + 0x08a0, 0x2001, 0x0004, 0x080c, 0x5ecf, 0x6003, 0x0001, 0x6007, + 0x0003, 0x080c, 0x8048, 0x080c, 0x8582, 0x0804, 0xa59c, 0xb85c, + 0xd0e4, 0x01d8, 0x080c, 0xba03, 0x080c, 0x6c53, 0x0118, 0xd0dc, + 0x1904, 0xa4c1, 0x2011, 0x1835, 0x2204, 0xc0ad, 0x2012, 0x2001, + 0x193e, 0x2004, 0x00f6, 0x2079, 0x0100, 0x78e3, 0x0000, 0x080c, + 0x254a, 0x78e2, 0x00fe, 0x0804, 0xa4c1, 0x080c, 0xba40, 0x2011, + 0x1835, 0x2204, 0xc0a5, 0x2012, 0x0006, 0x080c, 0xce81, 0x000e, + 0x1904, 0xa4c1, 0xc0b5, 0x2012, 0x2001, 0x0006, 0x080c, 0x5ecf, + 0x9006, 0x080c, 0x5ebb, 0x00c6, 0x2001, 0x180e, 0x2004, 0xd09c, + 0x0520, 0x00f6, 0x2079, 0x0100, 0x00e6, 0x2071, 0x1800, 0x700c, + 0x9084, 0x00ff, 0x78e6, 0x7076, 0x7010, 0x78ea, 0x707a, 0x908c, + 0x00ff, 0x00ee, 0x780c, 0xc0b5, 0x780e, 0x00fe, 0x080c, 0x251f, + 0x00f6, 0x2100, 0x900e, 0x080c, 0x24d6, 0x7956, 0x00fe, 0x9186, + 0x0081, 0x01d8, 0x2009, 0x0081, 0x00c8, 0x2009, 0x00ef, 0x00f6, + 0x2079, 0x0100, 0x79ea, 0x7932, 0x7936, 0x780c, 0xc0b5, 0x780e, + 0x00fe, 0x080c, 0x251f, 0x00f6, 0x2079, 0x1800, 0x797a, 0x2100, + 0x900e, 0x080c, 0x24d6, 0x7956, 0x00fe, 0x8108, 0x080c, 0x5f1e, + 0x2b00, 0x00ce, 0x1904, 0xa4c1, 0x6012, 0x2009, 0x180e, 0x210c, + 0xd19c, 0x0150, 0x2009, 0x027c, 0x210c, 0x918c, 0x00ff, 0xb912, + 0x2009, 0x027d, 0x210c, 0xb916, 0x2001, 0x0002, 0x080c, 0x5ecf, + 0x6023, 0x0001, 0x6003, 0x0001, 0x6007, 0x0002, 0x080c, 0x8048, + 0x080c, 0x8582, 0x0008, 0x0431, 0x00de, 0x009e, 0x00be, 0x0005, + 0x2001, 0x180f, 0x2004, 0xd0a4, 0x0120, 0x2001, 0x1854, 0x2004, + 0xd0ac, 0x0005, 0x00e6, 0x080c, 0xd2f4, 0x0190, 0x2071, 0x0260, + 0x7108, 0x720c, 0x918c, 0x00ff, 0x1118, 0x9284, 0xff00, 0x0140, + 0x6010, 0x2058, 0xb8a0, 0x9084, 0xff80, 0x1110, 0xb912, 0xba16, + 0x00ee, 0x0005, 0x2030, 0x2001, 0x0007, 0x080c, 0x5ecf, 0x080c, + 0x5127, 0x1120, 0x2001, 0x0007, 0x080c, 0x5efb, 0x080c, 0x2e55, + 0x6020, 0x9086, 0x000a, 0x1108, 0x0005, 0x0804, 0x99d6, 0x00b6, + 0x00e6, 0x0026, 0x0016, 0x2071, 0x1800, 0x7088, 0x9086, 0x0014, + 0x1904, 0xa62f, 0x080c, 0x5127, 0x1170, 0x6014, 0x9005, 0x1158, + 0x0036, 0x0046, 0x6010, 0x2058, 0xbba0, 0x2021, 0x0006, 0x080c, + 0x4829, 0x004e, 0x003e, 0x00d6, 0x6010, 0x2058, 0x080c, 0x6019, + 0x080c, 0xa47b, 0x00de, 0x080c, 0xa875, 0x1588, 0x6010, 0x2058, + 0xb890, 0x9005, 0x0560, 0x2001, 0x0006, 0x080c, 0x5ecf, 0x0096, + 0x6014, 0x904d, 0x01d0, 0xa864, 0x9084, 0x00ff, 0x9086, 0x0039, + 0x1140, 0x2001, 0x0000, 0x900e, 0x2011, 0x4000, 0x080c, 0xbbcd, + 0x0060, 0xa864, 0x9084, 0x00ff, 0x9086, 0x0029, 0x0130, 0xa807, + 0x0000, 0xa867, 0x0103, 0xa833, 0x0200, 0x009e, 0x080c, 0x2e55, + 0x6020, 0x9086, 0x000a, 0x0138, 0x080c, 0x99d6, 0x0020, 0x080c, + 0xa364, 0x080c, 0xa5c2, 0x001e, 0x002e, 0x00ee, 0x00be, 0x0005, + 0x2011, 0x1822, 0x2204, 0x9086, 0x0014, 0x1160, 0x2001, 0x0002, + 0x080c, 0x5ecf, 0x6003, 0x0001, 0x6007, 0x0001, 0x080c, 0x8048, + 0x0804, 0x8582, 0x0804, 0xa5c2, 0x2030, 0x2011, 0x1822, 0x2204, + 0x9086, 0x0004, 0x1148, 0x96b6, 0x000b, 0x1120, 0x2001, 0x0007, + 0x080c, 0x5ecf, 0x0804, 0x99d6, 0x0804, 0xa5c2, 0x0002, 0xa445, + 0xa676, 0xa445, 0xa6b5, 0xa445, 0xa760, 0xa66b, 0xa445, 0xa445, + 0xa773, 0xa445, 0xa783, 0x6604, 0x9686, 0x0003, 0x0904, 0xa5d7, + 0x96b6, 0x001e, 0x1110, 0x080c, 0x99d6, 0x0005, 0x00b6, 0x00d6, + 0x00c6, 0x080c, 0xa793, 0x11a0, 0x9006, 0x080c, 0x5ebb, 0x080c, + 0x2e30, 0x080c, 0xbd01, 0x2001, 0x0002, 0x080c, 0x5ecf, 0x6003, + 0x0001, 0x6007, 0x0002, 0x080c, 0x8048, 0x080c, 0x8582, 0x0408, + 0x2009, 0x026e, 0x2104, 0x9086, 0x0009, 0x1160, 0x6010, 0x2058, + 0xb840, 0x9084, 0x00ff, 0x9005, 0x0170, 0x8001, 0xb842, 0x601b, + 0x000a, 0x0078, 0x2009, 0x026f, 0x2104, 0x9084, 0xff00, 0x9086, + 0x1900, 0x1108, 0x08a0, 0x080c, 0x2e30, 0x080c, 0xbd01, 0x080c, + 0xa5c2, 0x00ce, 0x00de, 0x00be, 0x0005, 0x0096, 0x00b6, 0x0026, + 0x9016, 0x080c, 0xa7a1, 0x00d6, 0x2069, 0x194d, 0x2d04, 0x9005, + 0x0168, 0x6010, 0x2058, 0xb8a0, 0x9086, 0x007e, 0x1138, 0x2069, + 0x181e, 0x2d04, 0x8000, 0x206a, 0x00de, 0x0010, 0x00de, 0x0088, + 0x9006, 0x080c, 0x5ebb, 0x2001, 0x0002, 0x080c, 0x5ecf, 0x6003, + 0x0001, 0x6007, 0x0002, 0x080c, 0x8048, 0x080c, 0x8582, 0x0804, + 0xa730, 0x080c, 0xb5fb, 0x01b0, 0x6014, 0x2048, 0xa864, 0x2010, + 0x9086, 0x0139, 0x1138, 0x6007, 0x0016, 0x2001, 0x0002, 0x080c, + 0xbc27, 0x00b0, 0x6014, 0x2048, 0xa864, 0xd0fc, 0x0118, 0x2001, + 0x0001, 0x0ca8, 0x2001, 0x180d, 0x2004, 0xd0dc, 0x0148, 0x6010, + 0x2058, 0xb840, 0x9084, 0x00ff, 0x9005, 0x1110, 0x9006, 0x0c38, + 0x080c, 0xa364, 0x2009, 0x026e, 0x2134, 0x96b4, 0x00ff, 0x9686, + 0x0005, 0x0510, 0x9686, 0x000b, 0x01c8, 0x2009, 0x026f, 0x2104, + 0x9084, 0xff00, 0x1118, 0x9686, 0x0009, 0x01b0, 0x9086, 0x1900, + 0x1168, 0x9686, 0x0009, 0x0180, 0x2001, 0x0004, 0x080c, 0x5ecf, + 0x2001, 0x0028, 0x601a, 0x6007, 0x0052, 0x0010, 0x080c, 0xa5c2, + 0x002e, 0x00be, 0x009e, 0x0005, 0x9286, 0x0139, 0x0160, 0x6014, + 0x2048, 0x080c, 0xb5fb, 0x0140, 0xa864, 0x9086, 0x0139, 0x0118, + 0xa868, 0xd0fc, 0x0108, 0x0c50, 0x6010, 0x2058, 0xb840, 0x9084, + 0x00ff, 0x9005, 0x0138, 0x8001, 0xb842, 0x601b, 0x000a, 0x6007, + 0x0016, 0x08f0, 0xb8a0, 0x9086, 0x007e, 0x1138, 0x00e6, 0x2071, + 0x1800, 0x080c, 0x59b4, 0x00ee, 0x0010, 0x080c, 0x2e30, 0x0870, + 0x080c, 0xa7a1, 0x1160, 0x2001, 0x0004, 0x080c, 0x5ecf, 0x6003, + 0x0001, 0x6007, 0x0003, 0x080c, 0x8048, 0x0804, 0x8582, 0x080c, + 0xa364, 0x0804, 0xa5c2, 0x0469, 0x1160, 0x2001, 0x0008, 0x080c, + 0x5ecf, 0x6003, 0x0001, 0x6007, 0x0005, 0x080c, 0x8048, 0x0804, + 0x8582, 0x0804, 0xa5c2, 0x00e9, 0x1160, 0x2001, 0x000a, 0x080c, + 0x5ecf, 0x6003, 0x0001, 0x6007, 0x0001, 0x080c, 0x8048, 0x0804, + 0x8582, 0x0804, 0xa5c2, 0x2009, 0x026e, 0x2104, 0x9086, 0x0003, + 0x1138, 0x2009, 0x026f, 0x2104, 0x9084, 0xff00, 0x9086, 0x2a00, + 0x0005, 0x9085, 0x0001, 0x0005, 0x00b6, 0x00c6, 0x0016, 0x6110, + 0x2158, 0x080c, 0x5f8d, 0x001e, 0x00ce, 0x00be, 0x0005, 0x00b6, + 0x00f6, 0x00e6, 0x00d6, 0x0036, 0x0016, 0x6010, 0x2058, 0x2009, + 0x1835, 0x2104, 0x9085, 0x0003, 0x200a, 0x080c, 0xa847, 0x0560, + 0x2009, 0x1835, 0x2104, 0xc0cd, 0x200a, 0x080c, 0x62a0, 0x0158, + 0x9006, 0x2020, 0x2009, 0x002a, 0x080c, 0xcfe6, 0x2001, 0x180c, + 0x200c, 0xc195, 0x2102, 0x2019, 0x002a, 0x2009, 0x0001, 0x080c, + 0x2dfb, 0x00e6, 0x2071, 0x1800, 0x080c, 0x2c2b, 0x00ee, 0x00c6, + 0x0156, 0x20a9, 0x0781, 0x2009, 0x007f, 0x080c, 0x2f28, 0x8108, + 0x1f04, 0xa7e5, 0x015e, 0x00ce, 0x080c, 0xa7a4, 0x2071, 0x0260, + 0x2079, 0x0200, 0x7817, 0x0001, 0x2001, 0x1835, 0x200c, 0xc1c5, + 0x7018, 0xd0fc, 0x0110, 0xd0dc, 0x0118, 0x7038, 0xd0dc, 0x1108, + 0xc1c4, 0x7817, 0x0000, 0x2001, 0x1835, 0x2102, 0x2079, 0x0100, + 0x2e04, 0x9084, 0x00ff, 0x2069, 0x181d, 0x206a, 0x78e6, 0x0006, + 0x8e70, 0x2e04, 0x2069, 0x181e, 0x206a, 0x78ea, 0x7832, 0x7836, + 0x2010, 0x9084, 0xff00, 0x001e, 0x9105, 0x2009, 0x182a, 0x200a, + 0x2200, 0x9084, 0x00ff, 0x2008, 0x080c, 0x251f, 0x080c, 0x6c53, + 0x0170, 0x2071, 0x0260, 0x2069, 0x1951, 0x7048, 0x206a, 0x704c, + 0x6806, 0x7050, 0x680a, 0x7054, 0x680e, 0x080c, 0xba03, 0x0040, + 0x2001, 0x0006, 0x080c, 0x5ecf, 0x080c, 0x2e55, 0x080c, 0x99d6, + 0x001e, 0x003e, 0x00de, 0x00ee, 0x00fe, 0x00be, 0x0005, 0x0096, + 0x0026, 0x0036, 0x00e6, 0x0156, 0x2019, 0x182a, 0x231c, 0x83ff, + 0x01f0, 0x2071, 0x0260, 0x7200, 0x9294, 0x00ff, 0x7004, 0x9084, + 0xff00, 0x9205, 0x9306, 0x1198, 0x2011, 0x0276, 0x20a9, 0x0004, + 0x2b48, 0x2019, 0x000a, 0x080c, 0xa91d, 0x1148, 0x2011, 0x027a, + 0x20a9, 0x0004, 0x2019, 0x0006, 0x080c, 0xa91d, 0x1100, 0x015e, + 0x00ee, 0x003e, 0x002e, 0x009e, 0x0005, 0x00e6, 0x2071, 0x0260, + 0x7034, 0x9086, 0x0014, 0x11a8, 0x7038, 0x9086, 0x0800, 0x1188, + 0x703c, 0xd0ec, 0x0160, 0x9084, 0x0f00, 0x9086, 0x0100, 0x1138, + 0x7054, 0xd0a4, 0x1110, 0xd0ac, 0x0110, 0x9006, 0x0010, 0x9085, + 0x0001, 0x00ee, 0x0005, 0x00e6, 0x0096, 0x00c6, 0x0076, 0x0056, + 0x0046, 0x0026, 0x0006, 0x0126, 0x2091, 0x8000, 0x2029, 0x19bf, + 0x252c, 0x2021, 0x19c5, 0x2424, 0x2061, 0x1cd0, 0x2071, 0x1800, + 0x724c, 0x706c, 0x9202, 0x1a04, 0xa8f5, 0x080c, 0xd012, 0x05f0, + 0x6720, 0x9786, 0x0007, 0x05d0, 0x2500, 0x9c06, 0x05b8, 0x2400, + 0x9c06, 0x05a0, 0x3e08, 0x9186, 0x0002, 0x1148, 0x6010, 0x9005, + 0x0130, 0x00b6, 0x2058, 0xb800, 0x00be, 0xd0bc, 0x1538, 0x00c6, + 0x6000, 0x9086, 0x0004, 0x1110, 0x080c, 0x1827, 0x9786, 0x000a, + 0x0148, 0x080c, 0xb7fa, 0x1130, 0x00ce, 0x080c, 0xa364, 0x080c, + 0x9a06, 0x00a0, 0x6014, 0x2048, 0x080c, 0xb5fb, 0x0160, 0x9786, + 0x0003, 0x11e8, 0xa867, 0x0103, 0xab7a, 0xa877, 0x0000, 0x080c, + 0x6529, 0x080c, 0xb7dd, 0x080c, 0x9a06, 0x00ce, 0x9ce0, 0x0018, + 0x7060, 0x9c02, 0x1210, 0x0804, 0xa8a8, 0x012e, 0x000e, 0x002e, + 0x004e, 0x005e, 0x007e, 0x00ce, 0x009e, 0x00ee, 0x0005, 0x9786, + 0x0006, 0x1118, 0x080c, 0xcf91, 0x0c30, 0x9786, 0x000a, 0x09e0, + 0x08c8, 0x220c, 0x2304, 0x9106, 0x1130, 0x8210, 0x8318, 0x1f04, + 0xa909, 0x9006, 0x0005, 0x2304, 0x9102, 0x0218, 0x2001, 0x0001, + 0x0008, 0x9006, 0x918d, 0x0001, 0x0005, 0x0136, 0x01c6, 0x0016, + 0x8906, 0x8006, 0x8007, 0x908c, 0x003f, 0x21e0, 0x9084, 0xffc0, + 0x9300, 0x2098, 0x3518, 0x20a9, 0x0001, 0x220c, 0x4002, 0x910e, + 0x1140, 0x8210, 0x8319, 0x1dc8, 0x9006, 0x001e, 0x01ce, 0x013e, + 0x0005, 0x220c, 0x9102, 0x0218, 0x2001, 0x0001, 0x0010, 0x2001, + 0x0000, 0x918d, 0x0001, 0x001e, 0x01ce, 0x013e, 0x0005, 0x6004, + 0x908a, 0x0053, 0x1a0c, 0x0db2, 0x080c, 0xb7e9, 0x0120, 0x080c, + 0xb7fa, 0x0168, 0x0028, 0x080c, 0x2e55, 0x080c, 0xb7fa, 0x0138, + 0x080c, 0x847d, 0x080c, 0x99d6, 0x080c, 0x8582, 0x0005, 0x080c, + 0xa364, 0x0cb0, 0x9182, 0x0054, 0x1220, 0x9182, 0x0040, 0x0208, + 0x000a, 0x0005, 0xa97e, 0xa97e, 0xa97e, 0xa97e, 0xa97e, 0xa97e, + 0xa97e, 0xa97e, 0xa97e, 0xa97e, 0xa97e, 0xa980, 0xa980, 0xa980, + 0xa980, 0xa97e, 0xa97e, 0xa97e, 0xa980, 0xa97e, 0x080c, 0x0db2, + 0x600b, 0xffff, 0x6003, 0x0001, 0x6106, 0x080c, 0x8000, 0x0126, + 0x2091, 0x8000, 0x080c, 0x8582, 0x012e, 0x0005, 0x9186, 0x0013, + 0x1128, 0x6004, 0x9082, 0x0040, 0x0804, 0xaa35, 0x9186, 0x0027, + 0x1520, 0x080c, 0x847d, 0x080c, 0x2e30, 0x080c, 0xbd01, 0x0096, + 0x6114, 0x2148, 0x080c, 0xb5fb, 0x0198, 0x080c, 0xb7fa, 0x1118, + 0x080c, 0xa364, 0x0068, 0xa867, 0x0103, 0xa87b, 0x0029, 0xa877, + 0x0000, 0xa97c, 0xc1c5, 0xa97e, 0x080c, 0x6536, 0x080c, 0xb7dd, + 0x009e, 0x080c, 0x99d6, 0x0804, 0x8582, 0x9186, 0x0014, 0x1120, + 0x6004, 0x9082, 0x0040, 0x04a0, 0x9186, 0x0046, 0x0150, 0x9186, + 0x0045, 0x0138, 0x9186, 0x0053, 0x0120, 0x9186, 0x0048, 0x190c, + 0x0db2, 0x2001, 0x0109, 0x2004, 0xd084, 0x0508, 0x0126, 0x2091, + 0x2800, 0x0006, 0x0016, 0x0026, 0x0036, 0x00f6, 0x00e6, 0x00c6, + 0x2079, 0x19b6, 0x2071, 0x1800, 0x2061, 0x0100, 0x080c, 0x7eec, + 0x00ce, 0x00ee, 0x00fe, 0x003e, 0x002e, 0x001e, 0x000e, 0x012e, + 0xa001, 0x6000, 0x9086, 0x0002, 0x1110, 0x0804, 0xaa73, 0x0005, + 0x0002, 0xaa0f, 0xaa0d, 0xaa0d, 0xaa0d, 0xaa0d, 0xaa0d, 0xaa0d, + 0xaa0d, 0xaa0d, 0xaa0d, 0xaa0d, 0xaa2a, 0xaa2a, 0xaa2a, 0xaa2a, + 0xaa0d, 0xaa2a, 0xaa0d, 0xaa2a, 0xaa0d, 0x080c, 0x0db2, 0x080c, + 0x847d, 0x0096, 0x6114, 0x2148, 0x080c, 0xb5fb, 0x0168, 0xa867, + 0x0103, 0xa87b, 0x0006, 0xa877, 0x0000, 0xa880, 0xc0ec, 0xa882, + 0x080c, 0x6536, 0x080c, 0xb7dd, 0x009e, 0x080c, 0x99d6, 0x080c, + 0x8582, 0x0005, 0x080c, 0x847d, 0x080c, 0xb7fa, 0x090c, 0xa364, + 0x080c, 0x99d6, 0x080c, 0x8582, 0x0005, 0x0002, 0xaa4c, 0xaa4a, + 0xaa4a, 0xaa4a, 0xaa4a, 0xaa4a, 0xaa4a, 0xaa4a, 0xaa4a, 0xaa4a, + 0xaa4a, 0xaa63, 0xaa63, 0xaa63, 0xaa63, 0xaa4a, 0xaa6d, 0xaa4a, + 0xaa63, 0xaa4a, 0x080c, 0x0db2, 0x0096, 0x080c, 0x847d, 0x6014, + 0x2048, 0x2001, 0x1957, 0x2004, 0x6042, 0xa97c, 0xd1ac, 0x0140, + 0x6003, 0x0004, 0xa87c, 0x9085, 0x0400, 0xa87e, 0x009e, 0x0005, + 0x6003, 0x0002, 0x0cb8, 0x080c, 0x847d, 0x080c, 0xbd04, 0x080c, + 0xbd09, 0x6003, 0x000f, 0x0804, 0x8582, 0x080c, 0x847d, 0x080c, + 0x99d6, 0x0804, 0x8582, 0x9182, 0x0054, 0x1220, 0x9182, 0x0040, + 0x0208, 0x000a, 0x0005, 0xaa8f, 0xaa8f, 0xaa8f, 0xaa8f, 0xaa8f, + 0xaa91, 0xab6e, 0xaa8f, 0xaba2, 0xaa8f, 0xaa8f, 0xaa8f, 0xaa8f, + 0xaa8f, 0xaa8f, 0xaa8f, 0xaa8f, 0xaa8f, 0xaa8f, 0xaba2, 0x080c, + 0x0db2, 0x00b6, 0x0096, 0x6114, 0x2148, 0x7644, 0x96b4, 0x0fff, + 0x86ff, 0x1528, 0x6010, 0x2058, 0xb800, 0xd0bc, 0x1904, 0xab5d, + 0xa87b, 0x0000, 0xa867, 0x0103, 0xae76, 0xa87c, 0xd0ac, 0x0128, + 0xa834, 0xa938, 0x9115, 0x190c, 0xad37, 0x080c, 0x6351, 0x6210, + 0x2258, 0xba3c, 0x82ff, 0x0110, 0x8211, 0xba3e, 0x7044, 0xd0e4, + 0x1904, 0xab41, 0x080c, 0x99d6, 0x009e, 0x00be, 0x0005, 0x968c, + 0x0c00, 0x0150, 0x6010, 0x2058, 0xb800, 0xd0bc, 0x1904, 0xab45, + 0x7348, 0xab92, 0x734c, 0xab8e, 0x968c, 0x00ff, 0x9186, 0x0002, + 0x0508, 0x9186, 0x0028, 0x1118, 0xa87b, 0x001c, 0x00e8, 0xd6dc, + 0x01a0, 0xa87b, 0x0015, 0xa87c, 0xd0ac, 0x0170, 0xa938, 0xaa34, + 0x2100, 0x9205, 0x0148, 0x7048, 0x9106, 0x1118, 0x704c, 0x9206, + 0x0118, 0xa992, 0xaa8e, 0xc6dc, 0x0038, 0xd6d4, 0x0118, 0xa87b, + 0x0007, 0x0010, 0xa87b, 0x0000, 0xa867, 0x0103, 0xae76, 0x901e, + 0xd6c4, 0x01d8, 0x9686, 0x0100, 0x1130, 0x7064, 0x9005, 0x1118, + 0xc6c4, 0x0804, 0xaa98, 0x735c, 0xab86, 0x83ff, 0x0170, 0x938a, + 0x0009, 0x0210, 0x2019, 0x0008, 0x0036, 0x2308, 0x2019, 0x0018, + 0x2011, 0x0025, 0x080c, 0xb219, 0x003e, 0xd6cc, 0x0904, 0xaaad, + 0x7154, 0xa98a, 0x81ff, 0x0904, 0xaaad, 0x9192, 0x0021, 0x1278, + 0x8304, 0x9098, 0x0018, 0x2011, 0x0029, 0x080c, 0xb219, 0x2011, + 0x0205, 0x2013, 0x0000, 0x080c, 0xbc93, 0x0804, 0xaaad, 0xa868, + 0xd0fc, 0x0120, 0x2009, 0x0020, 0xa98a, 0x0c50, 0x00a6, 0x2950, + 0x080c, 0xb1b8, 0x00ae, 0x080c, 0xbc93, 0x080c, 0xb209, 0x0804, + 0xaaaf, 0x080c, 0xb8ed, 0x0804, 0xaabc, 0xa87c, 0xd0ac, 0x0904, + 0xaac8, 0xa880, 0xd0bc, 0x1904, 0xaac8, 0x7348, 0xa838, 0x9306, + 0x11c8, 0x734c, 0xa834, 0x931e, 0x0904, 0xaac8, 0xd6d4, 0x0190, + 0xab38, 0x9305, 0x0904, 0xaac8, 0x0068, 0xa87c, 0xd0ac, 0x0904, + 0xaaa0, 0xa838, 0xa934, 0x9105, 0x0904, 0xaaa0, 0xa880, 0xd0bc, + 0x1904, 0xaaa0, 0x080c, 0xb927, 0x0804, 0xaabc, 0x0096, 0x00f6, + 0x6003, 0x0003, 0x6007, 0x0043, 0x2079, 0x026c, 0x7c04, 0x7b00, + 0x7e0c, 0x7d08, 0x6014, 0x2048, 0xa87c, 0xd0ac, 0x0140, 0x6003, + 0x0002, 0x00fe, 0x009e, 0x0005, 0x2130, 0x2228, 0x0058, 0x2400, + 0xa9ac, 0x910a, 0x2300, 0xaab0, 0x9213, 0x2600, 0x9102, 0x2500, + 0x9203, 0x0e90, 0xac36, 0xab3a, 0xae46, 0xad4a, 0x00fe, 0x6043, + 0x0000, 0x2c10, 0x080c, 0x1976, 0x080c, 0x8065, 0x080c, 0x865d, + 0x009e, 0x0005, 0x0005, 0x9182, 0x0054, 0x1220, 0x9182, 0x0040, + 0x0208, 0x000a, 0x0005, 0xabbf, 0xabbf, 0xabbf, 0xabbf, 0xabbf, + 0xabc1, 0xac57, 0xabbf, 0xabbf, 0xac6e, 0xacfa, 0xabbf, 0xabbf, + 0xabbf, 0xabbf, 0xad0f, 0xabbf, 0xabbf, 0xabbf, 0xabbf, 0x080c, + 0x0db2, 0x0076, 0x00a6, 0x00e6, 0x0096, 0x2071, 0x0260, 0x6114, + 0x2150, 0x7644, 0xb676, 0x96b4, 0x0fff, 0xb77c, 0xc7e5, 0xb77e, + 0x6210, 0x00b6, 0x2258, 0xba3c, 0x82ff, 0x0110, 0x8211, 0xba3e, + 0x00be, 0x86ff, 0x0904, 0xac52, 0x9694, 0xff00, 0x9284, 0x0c00, + 0x0120, 0x7048, 0xb092, 0x704c, 0xb08e, 0x9284, 0x0300, 0x0904, + 0xac52, 0x080c, 0x0fd5, 0x090c, 0x0db2, 0x2900, 0xb07a, 0xb77c, + 0xc7cd, 0xb77e, 0xa867, 0x0103, 0xb068, 0xa86a, 0xb06c, 0xa86e, + 0xb070, 0xa872, 0xae76, 0x968c, 0x0c00, 0x0120, 0x7348, 0xab92, + 0x734c, 0xab8e, 0x968c, 0x00ff, 0x9186, 0x0002, 0x0180, 0x9186, + 0x0028, 0x1118, 0xa87b, 0x001c, 0x0060, 0xd6dc, 0x0118, 0xa87b, + 0x0015, 0x0038, 0xd6d4, 0x0118, 0xa87b, 0x0007, 0x0010, 0xa87b, + 0x0000, 0xaf7e, 0xb080, 0xa882, 0xb084, 0xa886, 0x901e, 0xd6c4, + 0x0190, 0x735c, 0xab86, 0x83ff, 0x0170, 0x938a, 0x0009, 0x0210, + 0x2019, 0x0008, 0x0036, 0x2308, 0x2019, 0x0018, 0x2011, 0x0025, + 0x080c, 0xb219, 0x003e, 0xd6cc, 0x01e8, 0x7154, 0xa98a, 0x81ff, + 0x01c8, 0x9192, 0x0021, 0x1260, 0x8304, 0x9098, 0x0018, 0x2011, + 0x0029, 0x080c, 0xb219, 0x2011, 0x0205, 0x2013, 0x0000, 0x0050, + 0xb068, 0xd0fc, 0x0120, 0x2009, 0x0020, 0xa98a, 0x0c68, 0x2950, + 0x080c, 0xb1b8, 0x009e, 0x00ee, 0x00ae, 0x007e, 0x0005, 0x00f6, + 0x00a6, 0x6003, 0x0003, 0x2079, 0x026c, 0x7c04, 0x7b00, 0x7e0c, + 0x7d08, 0x6014, 0x2050, 0xb436, 0xb33a, 0xb646, 0xb54a, 0x00ae, + 0x00fe, 0x2c10, 0x080c, 0x1976, 0x0804, 0x8f88, 0x6003, 0x0002, + 0x6004, 0x9086, 0x0040, 0x11c8, 0x0096, 0x6014, 0x2048, 0xa87c, + 0xd0ac, 0x0160, 0x601c, 0xd084, 0x1130, 0x00f6, 0x2c00, 0x2078, + 0x080c, 0x1582, 0x00fe, 0x6003, 0x0004, 0x0010, 0x6003, 0x0002, + 0x009e, 0x080c, 0x847d, 0x080c, 0x8582, 0x0096, 0x2001, 0x1957, + 0x2004, 0x6042, 0x080c, 0x8532, 0x080c, 0x865d, 0x6114, 0x2148, + 0xa97c, 0xd1e4, 0x0904, 0xacf5, 0xd1cc, 0x05a8, 0xa978, 0xa868, + 0xd0fc, 0x0538, 0x0016, 0xa87c, 0x0006, 0xa880, 0x0006, 0xa860, + 0x20e8, 0xa85c, 0x9080, 0x0019, 0x20a0, 0x810e, 0x810e, 0x810f, + 0x9184, 0x003f, 0x20e0, 0x9184, 0xffc0, 0x9080, 0x0019, 0x2098, + 0x0156, 0x20a9, 0x0020, 0x4003, 0x015e, 0x000e, 0xa882, 0x000e, + 0xa87e, 0x001e, 0xa874, 0x0006, 0x2148, 0x080c, 0x0f87, 0x001e, + 0x0440, 0x0016, 0x080c, 0x0f87, 0x009e, 0xa974, 0x0016, 0x080c, + 0xb209, 0x001e, 0x00f0, 0xa867, 0x0103, 0xa974, 0x9184, 0x00ff, + 0x90b6, 0x0002, 0x0180, 0x9086, 0x0028, 0x1118, 0xa87b, 0x001c, + 0x0060, 0xd1dc, 0x0118, 0xa87b, 0x0015, 0x0038, 0xd1d4, 0x0118, + 0xa87b, 0x0007, 0x0010, 0xa87b, 0x0000, 0x0016, 0x080c, 0x6351, + 0x001e, 0xd1e4, 0x1120, 0x080c, 0x99d6, 0x009e, 0x0005, 0x080c, + 0xb8ed, 0x0cd8, 0x6004, 0x9086, 0x0040, 0x1120, 0x080c, 0x847d, + 0x080c, 0x8582, 0x2019, 0x0001, 0x080c, 0x9254, 0x6003, 0x0002, + 0x080c, 0xbd09, 0x080c, 0x8532, 0x080c, 0x865d, 0x0005, 0x6004, + 0x9086, 0x0040, 0x1120, 0x080c, 0x847d, 0x080c, 0x8582, 0x2019, + 0x0001, 0x080c, 0x9254, 0x080c, 0x8532, 0x080c, 0x2e30, 0x080c, + 0xbd01, 0x0096, 0x6114, 0x2148, 0x080c, 0xb5fb, 0x0150, 0xa867, + 0x0103, 0xa87b, 0x0029, 0xa877, 0x0000, 0x080c, 0x6536, 0x080c, + 0xb7dd, 0x009e, 0x080c, 0x99d6, 0x080c, 0x865d, 0x0005, 0xa87b, + 0x0015, 0xd1fc, 0x0138, 0xa87b, 0x0007, 0x8002, 0x8000, 0x810a, + 0x9189, 0x0000, 0xa992, 0xa88e, 0x0005, 0x9182, 0x0054, 0x1220, + 0x9182, 0x0040, 0x0208, 0x000a, 0x0005, 0xad61, 0xad61, 0xad61, + 0xad61, 0xad61, 0xad63, 0xad61, 0xad61, 0xae09, 0xad61, 0xad61, + 0xad61, 0xad61, 0xad61, 0xad61, 0xad61, 0xad61, 0xad61, 0xad61, + 0xaf3a, 0x080c, 0x0db2, 0x0076, 0x00a6, 0x00e6, 0x0096, 0x2071, + 0x0260, 0x6114, 0x2150, 0x7644, 0xb676, 0x96b4, 0x0fff, 0xb77c, + 0xc7e5, 0xb77e, 0x6210, 0x00b6, 0x2258, 0xba3c, 0x82ff, 0x0110, + 0x8211, 0xba3e, 0x00be, 0x86ff, 0x0904, 0xae02, 0x9694, 0xff00, + 0x9284, 0x0c00, 0x0120, 0x7048, 0xb092, 0x704c, 0xb08e, 0x9284, + 0x0300, 0x0904, 0xae02, 0x9686, 0x0100, 0x1130, 0x7064, 0x9005, + 0x1118, 0xc6c4, 0xb676, 0x0c38, 0x080c, 0x0fd5, 0x090c, 0x0db2, + 0x2900, 0xb07a, 0xb77c, 0x97bd, 0x0200, 0xb77e, 0xa867, 0x0103, + 0xb068, 0xa86a, 0xb06c, 0xa86e, 0xb070, 0xa872, 0x7044, 0x9084, + 0xf000, 0x9635, 0xae76, 0x968c, 0x0c00, 0x0120, 0x7348, 0xab92, + 0x734c, 0xab8e, 0x968c, 0x00ff, 0x9186, 0x0002, 0x0180, 0x9186, + 0x0028, 0x1118, 0xa87b, 0x001c, 0x0060, 0xd6dc, 0x0118, 0xa87b, + 0x0015, 0x0038, 0xd6d4, 0x0118, 0xa87b, 0x0007, 0x0010, 0xa87b, + 0x0000, 0xaf7e, 0xb080, 0xa882, 0xb084, 0xa886, 0x901e, 0xd6c4, + 0x0190, 0x735c, 0xab86, 0x83ff, 0x0170, 0x938a, 0x0009, 0x0210, + 0x2019, 0x0008, 0x0036, 0x2308, 0x2019, 0x0018, 0x2011, 0x0025, + 0x080c, 0xb219, 0x003e, 0xd6cc, 0x01e8, 0x7154, 0xa98a, 0x81ff, + 0x01c8, 0x9192, 0x0021, 0x1260, 0x8304, 0x9098, 0x0018, 0x2011, + 0x0029, 0x080c, 0xb219, 0x2011, 0x0205, 0x2013, 0x0000, 0x0050, + 0xb068, 0xd0fc, 0x0120, 0x2009, 0x0020, 0xa98a, 0x0c68, 0x2950, + 0x080c, 0xb1b8, 0x080c, 0x1805, 0x009e, 0x00ee, 0x00ae, 0x007e, + 0x0005, 0x2001, 0x1957, 0x2004, 0x6042, 0x0096, 0x6114, 0x2148, + 0xa83c, 0xa940, 0x9105, 0x1118, 0xa87c, 0xc0dc, 0xa87e, 0x6003, + 0x0002, 0xa97c, 0xd1e4, 0x0904, 0xaf35, 0x6043, 0x0000, 0x6010, + 0x00b6, 0x2058, 0xb800, 0x00be, 0xd0bc, 0x1500, 0xd1cc, 0x0904, + 0xaf04, 0xa978, 0xa868, 0xd0fc, 0x0904, 0xaec5, 0x0016, 0xa87c, + 0x0006, 0xa880, 0x0006, 0x00a6, 0x2150, 0xb174, 0x9184, 0x00ff, + 0x90b6, 0x0002, 0x0904, 0xae93, 0x9086, 0x0028, 0x1904, 0xae7f, + 0xa87b, 0x001c, 0xb07b, 0x001c, 0x0804, 0xae9b, 0x6024, 0xd0f4, + 0x11d0, 0xa838, 0xaa34, 0x9205, 0x09c8, 0xa838, 0xaa90, 0x9206, + 0x1120, 0xa88c, 0xaa34, 0x9206, 0x0988, 0x6024, 0xd0d4, 0x1148, + 0xa9ac, 0xa834, 0x9102, 0x603a, 0xa9b0, 0xa838, 0x9103, 0x603e, + 0x6024, 0xc0f5, 0x6026, 0x6010, 0x00b6, 0x2058, 0xb83c, 0x8000, + 0xb83e, 0x00be, 0x9006, 0xa876, 0xa892, 0xa88e, 0xa87c, 0xc0e4, + 0xa87e, 0xd0cc, 0x0140, 0xc0cc, 0xa87e, 0x0096, 0xa878, 0x2048, + 0x080c, 0x0f87, 0x009e, 0x080c, 0xb927, 0x0804, 0xaf35, 0xd1dc, + 0x0158, 0xa87b, 0x0015, 0xb07b, 0x0015, 0x080c, 0xbbb6, 0x0118, + 0xb174, 0xc1dc, 0xb176, 0x0078, 0xd1d4, 0x0128, 0xa87b, 0x0007, + 0xb07b, 0x0007, 0x0040, 0xa87c, 0xd0ac, 0x0128, 0xa834, 0xa938, + 0x9115, 0x190c, 0xad37, 0xa87c, 0xb07e, 0xa890, 0xb092, 0xa88c, + 0xb08e, 0xa860, 0x20e8, 0xa85c, 0x9080, 0x0019, 0x20a0, 0x20a9, + 0x0020, 0x8a06, 0x8006, 0x8007, 0x9094, 0x003f, 0x22e0, 0x9084, + 0xffc0, 0x9080, 0x0019, 0x2098, 0x4003, 0x00ae, 0x000e, 0xa882, + 0x000e, 0xa87e, 0x080c, 0xbc93, 0x001e, 0xa874, 0x0006, 0x2148, + 0x080c, 0x0f87, 0x001e, 0x0804, 0xaf31, 0x0016, 0x00a6, 0x2150, + 0xb174, 0x9184, 0x00ff, 0x90b6, 0x0002, 0x01e0, 0x9086, 0x0028, + 0x1128, 0xa87b, 0x001c, 0xb07b, 0x001c, 0x00e0, 0xd1dc, 0x0158, + 0xa87b, 0x0015, 0xb07b, 0x0015, 0x080c, 0xbbb6, 0x0118, 0xb174, + 0xc1dc, 0xb176, 0x0078, 0xd1d4, 0x0128, 0xa87b, 0x0007, 0xb07b, + 0x0007, 0x0040, 0xa87c, 0xd0ac, 0x0128, 0xa834, 0xa938, 0x9115, + 0x190c, 0xad37, 0xa890, 0xb092, 0xa88c, 0xb08e, 0xa87c, 0xb07e, + 0x00ae, 0x080c, 0x0f87, 0x009e, 0x080c, 0xbc93, 0xa974, 0x0016, + 0x080c, 0xb209, 0x001e, 0x0468, 0xa867, 0x0103, 0xa974, 0x9184, + 0x00ff, 0x90b6, 0x0002, 0x01b0, 0x9086, 0x0028, 0x1118, 0xa87b, + 0x001c, 0x00d0, 0xd1dc, 0x0148, 0xa87b, 0x0015, 0x080c, 0xbbb6, + 0x0118, 0xa974, 0xc1dc, 0xa976, 0x0078, 0xd1d4, 0x0118, 0xa87b, + 0x0007, 0x0050, 0xa87b, 0x0000, 0xa87c, 0xd0ac, 0x0128, 0xa834, + 0xa938, 0x9115, 0x190c, 0xad37, 0xa974, 0x0016, 0x080c, 0x6351, + 0x001e, 0xd1e4, 0x1120, 0x080c, 0x99d6, 0x009e, 0x0005, 0x080c, + 0xb8ed, 0x0cd8, 0x6114, 0x0096, 0x2148, 0xa97c, 0xd1e4, 0x190c, + 0x1813, 0x009e, 0x0005, 0x080c, 0x847d, 0x0010, 0x080c, 0x8532, + 0x080c, 0xb5fb, 0x01f0, 0x0096, 0x6114, 0x2148, 0x080c, 0xb7fa, + 0x1118, 0x080c, 0xa364, 0x00a0, 0xa867, 0x0103, 0x2009, 0x180c, + 0x210c, 0xd18c, 0x11b8, 0xd184, 0x1190, 0x6108, 0xa97a, 0x918e, + 0x0029, 0x1110, 0x080c, 0xd28c, 0xa877, 0x0000, 0x080c, 0x6536, + 0x009e, 0x080c, 0x99d6, 0x080c, 0x8582, 0x0804, 0x865d, 0xa87b, + 0x0004, 0x0c90, 0xa87b, 0x0004, 0x0c78, 0x9182, 0x0054, 0x1220, + 0x9182, 0x0040, 0x0208, 0x000a, 0x0005, 0xaf91, 0xaf91, 0xaf91, + 0xaf91, 0xaf91, 0xaf93, 0xaf91, 0xaf91, 0xaf91, 0xaf91, 0xaf91, + 0xaf91, 0xaf91, 0xaf91, 0xaf91, 0xaf91, 0xaf91, 0xaf91, 0xaf91, + 0xaf91, 0x080c, 0x0db2, 0x080c, 0x511b, 0x01f8, 0x6014, 0x7144, + 0x918c, 0x0fff, 0x9016, 0xd1c4, 0x0118, 0x7264, 0x9294, 0x00ff, + 0x0096, 0x904d, 0x0188, 0xa87b, 0x0000, 0xa864, 0x9086, 0x0139, + 0x0128, 0xa867, 0x0103, 0xa976, 0xaa96, 0x0030, 0xa897, 0x4000, + 0xa99a, 0xaa9e, 0x080c, 0x6536, 0x009e, 0x0804, 0x99d6, 0x9182, + 0x0085, 0x0002, 0xafc9, 0xafc7, 0xafc7, 0xafd5, 0xafc7, 0xafc7, + 0xafc7, 0xafc7, 0xafc7, 0xafc7, 0xafc7, 0xafc7, 0xafc7, 0x080c, + 0x0db2, 0x6003, 0x0001, 0x6106, 0x080c, 0x8000, 0x0126, 0x2091, + 0x8000, 0x080c, 0x8582, 0x012e, 0x0005, 0x0026, 0x0056, 0x00d6, + 0x00e6, 0x2071, 0x0260, 0x7224, 0x6216, 0x7220, 0x080c, 0xb5e9, + 0x01a0, 0x2268, 0x6800, 0x9086, 0x0000, 0x0178, 0x6010, 0x6d10, + 0x952e, 0x1158, 0x00c6, 0x2d60, 0x080c, 0xb244, 0x00ce, 0x0128, + 0x6803, 0x0002, 0x6007, 0x0086, 0x0010, 0x6007, 0x0087, 0x6003, + 0x0001, 0x080c, 0x8000, 0x080c, 0x8582, 0x9280, 0x0004, 0x00b6, + 0x2058, 0xb800, 0x00be, 0xd0bc, 0x0140, 0x6824, 0xd0ec, 0x0128, + 0x00c6, 0x2260, 0x080c, 0xb927, 0x00ce, 0x00ee, 0x00de, 0x005e, + 0x002e, 0x0005, 0x9186, 0x0013, 0x1160, 0x6004, 0x908a, 0x0085, + 0x0a0c, 0x0db2, 0x908a, 0x0092, 0x1a0c, 0x0db2, 0x9082, 0x0085, + 0x00e2, 0x9186, 0x0027, 0x0120, 0x9186, 0x0014, 0x190c, 0x0db2, + 0x080c, 0x847d, 0x0096, 0x6014, 0x2048, 0x080c, 0xb5fb, 0x0140, + 0xa867, 0x0103, 0xa877, 0x0000, 0xa87b, 0x0029, 0x080c, 0x6536, + 0x009e, 0x080c, 0x9a06, 0x0804, 0x8582, 0xb04a, 0xb04c, 0xb04c, + 0xb04a, 0xb04a, 0xb04a, 0xb04a, 0xb04a, 0xb04a, 0xb04a, 0xb04a, + 0xb04a, 0xb04a, 0x080c, 0x0db2, 0x080c, 0x847d, 0x080c, 0x9a06, + 0x080c, 0x8582, 0x0005, 0x9186, 0x0013, 0x1128, 0x6004, 0x9082, + 0x0085, 0x2008, 0x04b8, 0x9186, 0x0027, 0x11f8, 0x080c, 0x847d, + 0x080c, 0x2e30, 0x080c, 0xbd01, 0x0096, 0x6014, 0x2048, 0x080c, + 0xb5fb, 0x0150, 0xa867, 0x0103, 0xa877, 0x0000, 0xa87b, 0x0029, + 0x080c, 0x6536, 0x080c, 0xb7dd, 0x009e, 0x080c, 0x99d6, 0x080c, + 0x8582, 0x0005, 0x080c, 0x9a6b, 0x0ce0, 0x9186, 0x0014, 0x1dd0, + 0x080c, 0x847d, 0x0096, 0x6014, 0x2048, 0x080c, 0xb5fb, 0x0d60, + 0xa867, 0x0103, 0xa877, 0x0000, 0xa87b, 0x0006, 0xa880, 0xc0ec, + 0xa882, 0x08f0, 0x0002, 0xb0a2, 0xb0a0, 0xb0a0, 0xb0a0, 0xb0a0, + 0xb0a0, 0xb0ba, 0xb0a0, 0xb0a0, 0xb0a0, 0xb0a0, 0xb0a0, 0xb0a0, + 0x080c, 0x0db2, 0x080c, 0x847d, 0x6034, 0x908c, 0xff00, 0x810f, + 0x9186, 0x0039, 0x0118, 0x9186, 0x0035, 0x1118, 0x2001, 0x1955, + 0x0010, 0x2001, 0x1956, 0x2004, 0x601a, 0x6003, 0x000c, 0x080c, + 0x8582, 0x0005, 0x080c, 0x847d, 0x6034, 0x908c, 0xff00, 0x810f, + 0x9186, 0x0039, 0x0118, 0x9186, 0x0035, 0x1118, 0x2001, 0x1955, + 0x0010, 0x2001, 0x1956, 0x2004, 0x601a, 0x6003, 0x000e, 0x080c, + 0x8582, 0x0005, 0x9182, 0x0092, 0x1220, 0x9182, 0x0085, 0x0208, + 0x0012, 0x0804, 0x9a6b, 0xb0e8, 0xb0e8, 0xb0e8, 0xb0e8, 0xb0ea, + 0xb137, 0xb0e8, 0xb0e8, 0xb0e8, 0xb0e8, 0xb0e8, 0xb0e8, 0xb0e8, + 0x080c, 0x0db2, 0x0096, 0x6010, 0x00b6, 0x2058, 0xb800, 0x00be, + 0xd0bc, 0x0168, 0x6034, 0x908c, 0xff00, 0x810f, 0x9186, 0x0039, + 0x0118, 0x9186, 0x0035, 0x1118, 0x009e, 0x0804, 0xb14b, 0x080c, + 0xb5fb, 0x1118, 0x080c, 0xb7dd, 0x0068, 0x6014, 0x2048, 0xa87c, + 0xd0e4, 0x1110, 0x080c, 0xb7dd, 0xa867, 0x0103, 0x080c, 0xbccc, + 0x080c, 0x6536, 0x00d6, 0x2c68, 0x080c, 0x9980, 0x01d0, 0x6003, + 0x0001, 0x6007, 0x001e, 0x600b, 0xffff, 0x2009, 0x026e, 0x210c, + 0x613a, 0x2009, 0x026f, 0x210c, 0x613e, 0x6910, 0x6112, 0x080c, + 0xba69, 0x6954, 0x6156, 0x6023, 0x0001, 0x080c, 0x8000, 0x080c, + 0x8582, 0x2d60, 0x00de, 0x080c, 0x99d6, 0x009e, 0x0005, 0x6010, + 0x00b6, 0x2058, 0xb800, 0x00be, 0xd0bc, 0x05a0, 0x6034, 0x908c, + 0xff00, 0x810f, 0x9186, 0x0035, 0x0130, 0x9186, 0x001e, 0x0118, + 0x9186, 0x0039, 0x1538, 0x00d6, 0x2c68, 0x080c, 0xbc66, 0x11f0, + 0x080c, 0x9980, 0x01d8, 0x6106, 0x6003, 0x0001, 0x6023, 0x0001, + 0x6910, 0x6112, 0x692c, 0x612e, 0x6930, 0x6132, 0x6934, 0x918c, + 0x00ff, 0x6136, 0x6938, 0x613a, 0x693c, 0x613e, 0x6954, 0x6156, + 0x080c, 0xba69, 0x080c, 0x8000, 0x080c, 0x8582, 0x2d60, 0x00de, + 0x0804, 0x99d6, 0x0096, 0x6014, 0x2048, 0x080c, 0xb5fb, 0x01c8, + 0xa867, 0x0103, 0xa880, 0xd0b4, 0x0128, 0xc0ec, 0xa882, 0xa87b, + 0x0006, 0x0048, 0xd0bc, 0x0118, 0xa87b, 0x0002, 0x0020, 0xa87b, + 0x0005, 0x080c, 0xb8e9, 0xa877, 0x0000, 0x080c, 0x6536, 0x080c, + 0xb7dd, 0x009e, 0x0804, 0x99d6, 0x0016, 0x0096, 0x6014, 0x2048, + 0x080c, 0xb5fb, 0x0140, 0xa867, 0x0103, 0xa87b, 0x0028, 0xa877, + 0x0000, 0x080c, 0x6536, 0x009e, 0x001e, 0x9186, 0x0013, 0x0148, + 0x9186, 0x0014, 0x0130, 0x9186, 0x0027, 0x0118, 0x080c, 0x9a6b, + 0x0030, 0x080c, 0x847d, 0x080c, 0x9a06, 0x080c, 0x8582, 0x0005, + 0x0056, 0x0066, 0x0096, 0x00a6, 0x2029, 0x0001, 0x9182, 0x0101, + 0x1208, 0x0010, 0x2009, 0x0100, 0x2130, 0x8304, 0x9098, 0x0018, + 0x2009, 0x0020, 0x2011, 0x0029, 0x080c, 0xb219, 0x96b2, 0x0020, + 0xb004, 0x904d, 0x0110, 0x080c, 0x0f87, 0x080c, 0x0fd5, 0x0520, + 0x8528, 0xa867, 0x0110, 0xa86b, 0x0000, 0x2920, 0xb406, 0x968a, + 0x003d, 0x1228, 0x2608, 0x2011, 0x001b, 0x0499, 0x00a8, 0x96b2, + 0x003c, 0x2009, 0x003c, 0x2950, 0x2011, 0x001b, 0x0451, 0x0c28, + 0x2001, 0x0205, 0x2003, 0x0000, 0x00ae, 0x852f, 0x95ad, 0x0003, + 0xb566, 0x95ac, 0x0000, 0x0048, 0x2001, 0x0205, 0x2003, 0x0000, + 0x00ae, 0x852f, 0x95ad, 0x0003, 0xb566, 0x009e, 0x006e, 0x005e, + 0x0005, 0x00a6, 0x89ff, 0x0158, 0xa804, 0x9055, 0x0130, 0xa807, + 0x0000, 0x080c, 0x6536, 0x2a48, 0x0cb8, 0x080c, 0x6536, 0x00ae, + 0x0005, 0x00f6, 0x2079, 0x0200, 0x7814, 0x9085, 0x0080, 0x7816, + 0xd184, 0x0108, 0x8108, 0x810c, 0x20a9, 0x0001, 0xa860, 0x20e8, + 0xa85c, 0x9200, 0x20a0, 0x20e1, 0x0000, 0x2300, 0x9e00, 0x2098, + 0x4003, 0x8318, 0x9386, 0x0020, 0x1148, 0x2018, 0x2300, 0x9e00, + 0x2098, 0x7814, 0x8000, 0x9085, 0x0080, 0x7816, 0x8109, 0x1d80, + 0x7817, 0x0000, 0x00fe, 0x0005, 0x0066, 0x0126, 0x2091, 0x8000, + 0x2031, 0x0001, 0x6020, 0x9084, 0x000f, 0x0083, 0x012e, 0x006e, + 0x0005, 0x0126, 0x2091, 0x8000, 0x0066, 0x2031, 0x0000, 0x6020, + 0x9084, 0x000f, 0x001b, 0x006e, 0x012e, 0x0005, 0xb27f, 0xb27f, + 0xb27a, 0xb2a1, 0xb26d, 0xb27a, 0xb2a1, 0xb27a, 0xb26d, 0xb26d, + 0xb27a, 0xb27a, 0xb27a, 0xb26d, 0xb26d, 0x080c, 0x0db2, 0x0036, + 0x2019, 0x0010, 0x080c, 0xcbad, 0x6023, 0x0006, 0x6003, 0x0007, + 0x003e, 0x0005, 0x9006, 0x0005, 0x9085, 0x0001, 0x0005, 0x0096, + 0x86ff, 0x11d8, 0x6014, 0x2048, 0x080c, 0xb5fb, 0x01c0, 0xa864, + 0x9086, 0x0139, 0x1128, 0xa87b, 0x0005, 0xa883, 0x0000, 0x0028, + 0x900e, 0x2001, 0x0005, 0x080c, 0x6770, 0x080c, 0xb8e9, 0x080c, + 0x6529, 0x080c, 0x9a06, 0x9085, 0x0001, 0x009e, 0x0005, 0x9006, + 0x0ce0, 0x6000, 0x908a, 0x0016, 0x1a0c, 0x0db2, 0x0002, 0xb2b7, + 0xb2dc, 0xb2b9, 0xb2fd, 0xb2d7, 0xb2b7, 0xb27a, 0xb27f, 0xb27f, + 0xb27a, 0xb27a, 0xb27a, 0xb27a, 0xb27a, 0xb27a, 0xb27a, 0x080c, + 0x0db2, 0x86ff, 0x11c8, 0x6020, 0x9086, 0x0006, 0x01a8, 0x0096, + 0x6014, 0x2048, 0x080c, 0xb5fb, 0x0110, 0x080c, 0xb8e9, 0x009e, + 0x080c, 0xbca8, 0x6007, 0x0085, 0x6003, 0x000b, 0x6023, 0x0002, + 0x080c, 0x8000, 0x080c, 0x8582, 0x9085, 0x0001, 0x0005, 0x0066, + 0x080c, 0x1827, 0x006e, 0x08e8, 0x00e6, 0x2071, 0x19b6, 0x7024, + 0x9c06, 0x1120, 0x080c, 0x91de, 0x00ee, 0x0898, 0x6020, 0x9084, + 0x000f, 0x9086, 0x0006, 0x1150, 0x0086, 0x0096, 0x2049, 0x0001, + 0x2c40, 0x080c, 0x9349, 0x009e, 0x008e, 0x0010, 0x080c, 0x90db, + 0x00ee, 0x1904, 0xb2b9, 0x0804, 0xb27a, 0x0036, 0x00e6, 0x2071, + 0x19b6, 0x703c, 0x9c06, 0x1138, 0x901e, 0x080c, 0x9254, 0x00ee, + 0x003e, 0x0804, 0xb2b9, 0x080c, 0x9479, 0x00ee, 0x003e, 0x1904, + 0xb2b9, 0x0804, 0xb27a, 0x00c6, 0x6020, 0x9084, 0x000f, 0x0013, + 0x00ce, 0x0005, 0xb330, 0xb3df, 0xb546, 0xb33a, 0x9a06, 0xb330, + 0xcb9f, 0xbd0e, 0xb3df, 0xb329, 0xb5c5, 0xb329, 0xb329, 0xb329, + 0xb329, 0x080c, 0x0db2, 0x080c, 0xb7fa, 0x1110, 0x080c, 0xa364, + 0x0005, 0x080c, 0x847d, 0x080c, 0x8582, 0x0804, 0x99d6, 0x601b, + 0x0001, 0x0005, 0x080c, 0xb5fb, 0x0130, 0x6014, 0x0096, 0x2048, + 0x2c00, 0xa896, 0x009e, 0x6000, 0x908a, 0x0016, 0x1a0c, 0x0db2, + 0x0002, 0xb359, 0xb35b, 0xb37f, 0xb393, 0xb3b7, 0xb359, 0xb330, + 0xb330, 0xb330, 0xb393, 0xb393, 0xb359, 0xb359, 0xb359, 0xb359, + 0xb39d, 0x080c, 0x0db2, 0x00e6, 0x6014, 0x0096, 0x2048, 0xa880, + 0xc0b5, 0xa882, 0x009e, 0x2071, 0x19b6, 0x7024, 0x9c06, 0x01a0, + 0x080c, 0x90db, 0x080c, 0xbca8, 0x6007, 0x0085, 0x6003, 0x000b, + 0x6023, 0x0002, 0x2001, 0x1956, 0x2004, 0x601a, 0x080c, 0x8000, + 0x080c, 0x8582, 0x00ee, 0x0005, 0x601b, 0x0001, 0x0cd8, 0x0096, + 0x6014, 0x2048, 0xa880, 0xc0b5, 0xa882, 0x009e, 0x080c, 0xbca8, + 0x6007, 0x0085, 0x6003, 0x000b, 0x6023, 0x0002, 0x080c, 0x8000, + 0x080c, 0x8582, 0x0005, 0x0096, 0x601b, 0x0001, 0x6014, 0x2048, + 0xa880, 0xc0b5, 0xa882, 0x009e, 0x0005, 0x080c, 0x511b, 0x01a8, + 0x6014, 0x0096, 0x904d, 0x0180, 0xa864, 0xa867, 0x0103, 0xa87b, + 0x0006, 0x9086, 0x0139, 0x1140, 0xa867, 0x0139, 0xa897, 0x4005, + 0xa89b, 0x0004, 0x080c, 0x6536, 0x009e, 0x0804, 0x99d6, 0x6014, + 0x0096, 0x904d, 0x01f8, 0xa97c, 0xd1e4, 0x01e0, 0x2001, 0x180e, + 0x2004, 0xd0c4, 0x0110, 0x009e, 0x0005, 0xa884, 0x009e, 0x8003, + 0x800b, 0x810b, 0x9108, 0x611a, 0x2001, 0x0037, 0x2c08, 0x080c, + 0x14d2, 0x6000, 0x9086, 0x0004, 0x1120, 0x2009, 0x0048, 0x080c, + 0x9a50, 0x0005, 0x009e, 0x080c, 0x1827, 0x0804, 0xb37f, 0x6000, + 0x908a, 0x0016, 0x1a0c, 0x0db2, 0x000b, 0x0005, 0xb3f6, 0xb337, + 0xb3f8, 0xb3f6, 0xb3f8, 0xb3f8, 0xb331, 0xb3f6, 0xb32b, 0xb32b, + 0xb3f6, 0xb3f6, 0xb3f6, 0xb3f6, 0xb3f6, 0xb3f6, 0x080c, 0x0db2, + 0x6010, 0x00b6, 0x2058, 0xb804, 0x9084, 0x00ff, 0x00be, 0x908a, + 0x000c, 0x1a0c, 0x0db2, 0x00b6, 0x0013, 0x00be, 0x0005, 0xb413, + 0xb4e0, 0xb415, 0xb455, 0xb415, 0xb455, 0xb415, 0xb423, 0xb413, + 0xb455, 0xb413, 0xb444, 0x080c, 0x0db2, 0x6004, 0x908e, 0x0016, + 0x05c0, 0x908e, 0x0004, 0x05a8, 0x908e, 0x0002, 0x0590, 0x908e, + 0x0052, 0x0904, 0xb4dc, 0x6004, 0x080c, 0xb7fa, 0x0904, 0xb4f9, + 0x908e, 0x0004, 0x1110, 0x080c, 0x2e55, 0x908e, 0x0021, 0x0904, + 0xb4fd, 0x908e, 0x0022, 0x0904, 0xb541, 0x908e, 0x003d, 0x0904, + 0xb4fd, 0x908e, 0x0039, 0x0904, 0xb501, 0x908e, 0x0035, 0x0904, + 0xb501, 0x908e, 0x001e, 0x0178, 0x908e, 0x0001, 0x1140, 0x6010, + 0x2058, 0xb804, 0x9084, 0x00ff, 0x9086, 0x0006, 0x0110, 0x080c, + 0x2e30, 0x080c, 0xa364, 0x0804, 0x9a06, 0x00c6, 0x00d6, 0x6104, + 0x9186, 0x0016, 0x0904, 0xb4cd, 0x9186, 0x0002, 0x1904, 0xb4a2, + 0x2001, 0x1835, 0x2004, 0xd08c, 0x11c8, 0x080c, 0x6c53, 0x11b0, + 0x080c, 0xbcec, 0x0138, 0x080c, 0x6c76, 0x1120, 0x080c, 0x6b68, + 0x0804, 0xb52a, 0x2001, 0x194e, 0x2003, 0x0001, 0x2001, 0x1800, + 0x2003, 0x0001, 0x080c, 0x6b8a, 0x0804, 0xb52a, 0x6010, 0x2058, + 0x2001, 0x1835, 0x2004, 0xd0ac, 0x1904, 0xb52a, 0xb8a0, 0x9084, + 0xff80, 0x1904, 0xb52a, 0xb840, 0x9084, 0x00ff, 0x9005, 0x0190, + 0x8001, 0xb842, 0x6017, 0x0000, 0x6023, 0x0007, 0x601b, 0x0398, + 0x6043, 0x0000, 0x080c, 0x9980, 0x0128, 0x2b00, 0x6012, 0x6023, + 0x0001, 0x0458, 0x00de, 0x00ce, 0x6004, 0x908e, 0x0002, 0x11a0, + 0x6010, 0x2058, 0xb8a0, 0x9086, 0x007e, 0x1170, 0x2009, 0x1835, + 0x2104, 0xc085, 0x200a, 0x00e6, 0x2071, 0x1800, 0x080c, 0x59b4, + 0x00ee, 0x080c, 0xa364, 0x0030, 0x080c, 0xa364, 0x080c, 0x2e30, + 0x080c, 0xbd01, 0x00e6, 0x0126, 0x2091, 0x8000, 0x080c, 0x2e55, + 0x012e, 0x00ee, 0x080c, 0x9a06, 0x0005, 0x2001, 0x0002, 0x080c, + 0x5ecf, 0x6003, 0x0001, 0x6007, 0x0002, 0x080c, 0x8048, 0x080c, + 0x8582, 0x00de, 0x00ce, 0x0c80, 0x080c, 0x2e55, 0x0804, 0xb451, + 0x00c6, 0x00d6, 0x6104, 0x9186, 0x0016, 0x0d38, 0x6010, 0x2058, + 0xb840, 0x9084, 0x00ff, 0x9005, 0x0904, 0xb4a2, 0x8001, 0xb842, + 0x6003, 0x0001, 0x080c, 0x8048, 0x080c, 0x8582, 0x00de, 0x00ce, + 0x0898, 0x080c, 0xa364, 0x0804, 0xb453, 0x080c, 0xa3a0, 0x0804, + 0xb453, 0x00d6, 0x2c68, 0x6104, 0x080c, 0xbc66, 0x00de, 0x0118, + 0x080c, 0x99d6, 0x00f0, 0x6004, 0x8007, 0x6134, 0x918c, 0x00ff, + 0x9105, 0x6036, 0x6007, 0x0085, 0x6003, 0x000b, 0x6023, 0x0002, + 0x603c, 0x600a, 0x2001, 0x1956, 0x2004, 0x601a, 0x602c, 0x2c08, + 0x2060, 0x6024, 0xc0b5, 0x6026, 0x2160, 0x080c, 0x8000, 0x080c, + 0x8582, 0x0005, 0x00de, 0x00ce, 0x080c, 0xa364, 0x080c, 0x2e30, + 0x00e6, 0x0126, 0x2091, 0x8000, 0x080c, 0x2e55, 0x6017, 0x0000, + 0x6023, 0x0007, 0x601b, 0x0398, 0x6043, 0x0000, 0x012e, 0x00ee, + 0x0005, 0x080c, 0x9e03, 0x1904, 0xb4f9, 0x0005, 0x6000, 0x908a, + 0x0016, 0x1a0c, 0x0db2, 0x0096, 0x00d6, 0x001b, 0x00de, 0x009e, + 0x0005, 0xb561, 0xb561, 0xb561, 0xb561, 0xb561, 0xb561, 0xb561, + 0xb561, 0xb561, 0xb330, 0xb561, 0xb337, 0xb563, 0xb337, 0xb570, + 0xb561, 0x080c, 0x0db2, 0x6004, 0x9086, 0x008b, 0x0148, 0x6007, + 0x008b, 0x6003, 0x000d, 0x080c, 0x8000, 0x080c, 0x8582, 0x0005, + 0x080c, 0xbce0, 0x0118, 0x080c, 0xbcf3, 0x0010, 0x080c, 0xbd01, + 0x080c, 0xb7dd, 0x080c, 0xb5fb, 0x0570, 0x080c, 0x2e30, 0x080c, + 0xb5fb, 0x0168, 0x6014, 0x2048, 0xa867, 0x0103, 0xa87b, 0x0006, + 0xa877, 0x0000, 0xa880, 0xc0ed, 0xa882, 0x080c, 0x6536, 0x2c68, + 0x080c, 0x9980, 0x0150, 0x6810, 0x6012, 0x080c, 0xba69, 0x00c6, + 0x2d60, 0x080c, 0x9a06, 0x00ce, 0x0008, 0x2d60, 0x6017, 0x0000, + 0x6023, 0x0001, 0x6007, 0x0001, 0x6003, 0x0001, 0x080c, 0x8048, + 0x080c, 0x8582, 0x00c8, 0x080c, 0xbce0, 0x0138, 0x6034, 0x9086, + 0x4000, 0x1118, 0x080c, 0x2e30, 0x08d0, 0x6034, 0x908c, 0xff00, + 0x810f, 0x9186, 0x0039, 0x0118, 0x9186, 0x0035, 0x1118, 0x080c, + 0x2e30, 0x0868, 0x080c, 0x9a06, 0x0005, 0x6000, 0x908a, 0x0016, + 0x1a0c, 0x0db2, 0x0002, 0xb5db, 0xb5db, 0xb5dd, 0xb5dd, 0xb5dd, + 0xb5db, 0xb5db, 0x9a06, 0xb5db, 0xb5db, 0xb5db, 0xb5db, 0xb5db, + 0xb5db, 0xb5db, 0xb5db, 0x080c, 0x0db2, 0x080c, 0x9479, 0x6114, + 0x0096, 0x2148, 0xa87b, 0x0006, 0x080c, 0x6536, 0x009e, 0x0804, + 0x99d6, 0x9284, 0x0007, 0x1158, 0x9282, 0x1cd0, 0x0240, 0x2001, + 0x1818, 0x2004, 0x9202, 0x1218, 0x9085, 0x0001, 0x0005, 0x9006, + 0x0ce8, 0x0096, 0x0028, 0x0096, 0x0006, 0x6014, 0x2048, 0x000e, + 0x0006, 0x9984, 0xf000, 0x9086, 0xf000, 0x0110, 0x080c, 0x1080, + 0x000e, 0x009e, 0x0005, 0x00e6, 0x00c6, 0x0036, 0x0006, 0x0126, + 0x2091, 0x8000, 0x2061, 0x1cd0, 0x2071, 0x1800, 0x734c, 0x706c, + 0x9302, 0x1640, 0x6020, 0x9206, 0x11f8, 0x080c, 0xbcec, 0x0180, + 0x9286, 0x0001, 0x1168, 0x6004, 0x9086, 0x0004, 0x1148, 0x080c, + 0x2e30, 0x080c, 0xbd01, 0x00c6, 0x080c, 0x9a06, 0x00ce, 0x0060, + 0x080c, 0xb9e3, 0x0148, 0x080c, 0xb7fa, 0x1110, 0x080c, 0xa364, + 0x00c6, 0x080c, 0x99d6, 0x00ce, 0x9ce0, 0x0018, 0x7060, 0x9c02, + 0x1208, 0x08a0, 0x012e, 0x000e, 0x003e, 0x00ce, 0x00ee, 0x0005, + 0x00e6, 0x00c6, 0x0016, 0x9188, 0x1000, 0x210c, 0x81ff, 0x0128, + 0x2061, 0x1a73, 0x6112, 0x080c, 0x2e30, 0x9006, 0x0010, 0x9085, + 0x0001, 0x001e, 0x00ce, 0x00ee, 0x0005, 0x00c6, 0x0126, 0x2091, + 0x8000, 0x080c, 0x9980, 0x01d8, 0x080c, 0x511b, 0x0110, 0x662e, + 0x0008, 0x6616, 0x2b00, 0x6012, 0x080c, 0x511b, 0x0118, 0x080c, + 0xb721, 0x0168, 0x080c, 0xba69, 0x6023, 0x0003, 0x2009, 0x004b, + 0x080c, 0x9a50, 0x9085, 0x0001, 0x012e, 0x00ce, 0x0005, 0x9006, + 0x0cd8, 0x00c6, 0x0126, 0x2091, 0x8000, 0xbaa0, 0x080c, 0x9a23, + 0x0590, 0x080c, 0x511b, 0x0118, 0x602f, 0x0000, 0x0010, 0x6017, + 0x0000, 0x2b00, 0x6012, 0x080c, 0xba69, 0x6023, 0x0003, 0x0016, + 0x080c, 0x8180, 0x0076, 0x903e, 0x080c, 0x8078, 0x2c08, 0x080c, + 0xcd62, 0x007e, 0x001e, 0xd184, 0x0128, 0x080c, 0x99d6, 0x9085, + 0x0001, 0x0070, 0x080c, 0x511b, 0x0128, 0xd18c, 0x1170, 0x080c, + 0xb721, 0x0148, 0x2009, 0x004c, 0x080c, 0x9a50, 0x9085, 0x0001, + 0x012e, 0x00ce, 0x0005, 0x9006, 0x0cd8, 0x2900, 0x6016, 0x0c90, + 0x2009, 0x004d, 0x0010, 0x2009, 0x004e, 0x00f6, 0x00c6, 0x0046, + 0x0016, 0x080c, 0x9980, 0x2c78, 0x01d8, 0x080c, 0x511b, 0x0110, + 0x7e2e, 0x0008, 0x7e16, 0x2b00, 0x7812, 0x7823, 0x0003, 0x2021, + 0x0005, 0x080c, 0xb733, 0x2f60, 0x080c, 0x511b, 0x0118, 0x080c, + 0xb721, 0x0130, 0x001e, 0x0016, 0x080c, 0x9a50, 0x9085, 0x0001, + 0x001e, 0x004e, 0x00ce, 0x00fe, 0x0005, 0x00f6, 0x00c6, 0x0046, + 0x080c, 0x9980, 0x2c78, 0x0530, 0x080c, 0x511b, 0x0110, 0x7e2e, + 0x0008, 0x7e16, 0x2b00, 0x7812, 0x7823, 0x0003, 0x0096, 0x2021, + 0x0004, 0x0489, 0x009e, 0x2001, 0x194f, 0x200c, 0xd1fc, 0x0120, + 0x2f60, 0x080c, 0x99d6, 0x0060, 0x2f60, 0x080c, 0x511b, 0x0120, + 0xd18c, 0x1160, 0x0071, 0x0130, 0x2009, 0x0052, 0x080c, 0x9a50, + 0x9085, 0x0001, 0x004e, 0x00ce, 0x00fe, 0x0005, 0x2900, 0x7816, + 0x0c98, 0x00c6, 0x080c, 0x4612, 0x00ce, 0x1120, 0x080c, 0x99d6, + 0x9006, 0x0005, 0xa867, 0x0000, 0xa86b, 0x8000, 0x2900, 0x6016, + 0x9085, 0x0001, 0x0005, 0x0096, 0x0076, 0x0126, 0x2091, 0x8000, + 0x080c, 0x60b2, 0x0158, 0x2001, 0xb738, 0x0006, 0x900e, 0x2400, + 0x080c, 0x6770, 0x080c, 0x6536, 0x000e, 0x0807, 0x2418, 0x080c, + 0x8417, 0xbaa0, 0x0086, 0x2041, 0x0001, 0x2039, 0x0001, 0x2608, + 0x080c, 0x8198, 0x008e, 0x080c, 0x8078, 0x2f08, 0x2648, 0x080c, + 0xcd62, 0xb93c, 0x81ff, 0x090c, 0x8269, 0x080c, 0x8582, 0x012e, + 0x007e, 0x009e, 0x0005, 0x00c6, 0x0126, 0x2091, 0x8000, 0x080c, + 0x9980, 0x0190, 0x660a, 0x2b08, 0x6112, 0x080c, 0xba69, 0x6023, + 0x0001, 0x2900, 0x6016, 0x2009, 0x001f, 0x080c, 0x9a50, 0x9085, + 0x0001, 0x012e, 0x00ce, 0x0005, 0x9006, 0x0cd8, 0x00c6, 0x0126, + 0x2091, 0x8000, 0x080c, 0x9a23, 0x01b8, 0x660a, 0x2b08, 0x6112, + 0x080c, 0xba69, 0x6023, 0x0008, 0x2900, 0x6016, 0x00f6, 0x2c78, + 0x080c, 0x1582, 0x00fe, 0x2009, 0x0021, 0x080c, 0x9a50, 0x9085, + 0x0001, 0x012e, 0x00ce, 0x0005, 0x9006, 0x0cd8, 0x2009, 0x003d, + 0x00c6, 0x0126, 0x0016, 0x2091, 0x8000, 0x080c, 0x9980, 0x0198, + 0x660a, 0x2b08, 0x6112, 0x080c, 0xba69, 0x6023, 0x0001, 0x2900, + 0x6016, 0x001e, 0x0016, 0x080c, 0x9a50, 0x9085, 0x0001, 0x001e, + 0x012e, 0x00ce, 0x0005, 0x9006, 0x0cd0, 0x00c6, 0x0126, 0x2091, + 0x8000, 0x080c, 0x9a23, 0x0188, 0x2b08, 0x6112, 0x080c, 0xba69, + 0x6023, 0x0001, 0x2900, 0x6016, 0x2009, 0x0000, 0x080c, 0x9a50, + 0x9085, 0x0001, 0x012e, 0x00ce, 0x0005, 0x9006, 0x0cd8, 0x2009, + 0x0044, 0x0830, 0x2009, 0x0049, 0x0818, 0x0026, 0x00b6, 0x6210, + 0x2258, 0xba3c, 0x82ff, 0x0110, 0x8211, 0xba3e, 0x00be, 0x002e, + 0x0005, 0x0006, 0x0016, 0x6004, 0x908e, 0x0002, 0x0140, 0x908e, + 0x0003, 0x0128, 0x908e, 0x0004, 0x0110, 0x9085, 0x0001, 0x001e, + 0x000e, 0x0005, 0x0006, 0x0096, 0x6020, 0x9086, 0x0004, 0x0190, + 0x6014, 0x904d, 0x080c, 0xb5fb, 0x0168, 0xa864, 0x9086, 0x0139, + 0x0158, 0x6020, 0x9086, 0x0003, 0x0128, 0xa868, 0xd0fc, 0x0110, + 0x9006, 0x0010, 0x9085, 0x0001, 0x009e, 0x000e, 0x0005, 0x00c6, + 0x0126, 0x2091, 0x8000, 0x080c, 0x9a23, 0x0198, 0x2b08, 0x6112, + 0x080c, 0xba69, 0x6023, 0x0001, 0x2900, 0x6016, 0x080c, 0x2e30, + 0x2009, 0x0028, 0x080c, 0x9a50, 0x9085, 0x0001, 0x012e, 0x00ce, + 0x0005, 0x9006, 0x0cd8, 0x9186, 0x0015, 0x11a8, 0x2011, 0x1822, + 0x2204, 0x9086, 0x0074, 0x1178, 0x00b6, 0x080c, 0xa5aa, 0x00be, + 0x080c, 0xa7a4, 0x6003, 0x0001, 0x6007, 0x0029, 0x080c, 0x8048, + 0x080c, 0x8582, 0x0078, 0x6014, 0x0096, 0x2048, 0xa868, 0x009e, + 0xd0fc, 0x0148, 0x2001, 0x0001, 0x080c, 0xbc27, 0x080c, 0xa364, + 0x080c, 0x99d6, 0x0005, 0x0096, 0x6014, 0x904d, 0x090c, 0x0db2, + 0xa87b, 0x0030, 0xa883, 0x0000, 0xa897, 0x4005, 0xa89b, 0x0004, + 0xa867, 0x0139, 0x0126, 0x2091, 0x8000, 0x080c, 0x6536, 0x012e, + 0x009e, 0x080c, 0x99d6, 0x0c30, 0x0096, 0x9186, 0x0016, 0x1128, + 0x2001, 0x0004, 0x080c, 0x5ecf, 0x00e8, 0x9186, 0x0015, 0x1510, + 0x2011, 0x1822, 0x2204, 0x9086, 0x0014, 0x11e0, 0x6010, 0x00b6, + 0x2058, 0x080c, 0x6019, 0x00be, 0x080c, 0xa875, 0x1198, 0x6010, + 0x00b6, 0x2058, 0xb890, 0x00be, 0x9005, 0x0160, 0x2001, 0x0006, + 0x080c, 0x5ecf, 0x6014, 0x2048, 0xa868, 0xd0fc, 0x0170, 0x080c, + 0x9dd7, 0x0048, 0x6014, 0x2048, 0xa868, 0xd0fc, 0x0528, 0x080c, + 0xa364, 0x080c, 0x99d6, 0x009e, 0x0005, 0x6014, 0x6310, 0x2358, + 0x904d, 0x090c, 0x0db2, 0xa87b, 0x0000, 0xa883, 0x0000, 0xa897, + 0x4000, 0x900e, 0x080c, 0x619e, 0x1108, 0xc185, 0xb800, 0xd0bc, + 0x0108, 0xc18d, 0xa99a, 0x0126, 0x2091, 0x8000, 0x080c, 0x6536, + 0x012e, 0x080c, 0x99d6, 0x08f8, 0x6014, 0x904d, 0x090c, 0x0db2, + 0xa87b, 0x0030, 0xa883, 0x0000, 0xa897, 0x4005, 0xa89b, 0x0004, + 0xa867, 0x0139, 0x0126, 0x2091, 0x8000, 0x080c, 0x6536, 0x012e, + 0x080c, 0x99d6, 0x0840, 0xa878, 0x9086, 0x0005, 0x1108, 0x0009, + 0x0005, 0xa880, 0xc0ad, 0xa882, 0x0005, 0x6043, 0x0000, 0x6017, + 0x0000, 0x6003, 0x0001, 0x6007, 0x0050, 0x080c, 0x8000, 0x080c, + 0x8582, 0x0005, 0x00c6, 0x6010, 0x00b6, 0x2058, 0xb800, 0x00be, + 0xd0bc, 0x0120, 0x6020, 0x9084, 0x000f, 0x0013, 0x00ce, 0x0005, + 0xb330, 0xb919, 0xb919, 0xb91c, 0xd030, 0xd04b, 0xd04e, 0xb330, + 0xb330, 0xb330, 0xb330, 0xb330, 0xb330, 0xb330, 0xb330, 0x080c, + 0x0db2, 0xa001, 0xa001, 0x0005, 0x0096, 0x6014, 0x904d, 0x0118, + 0xa87c, 0xd0e4, 0x1110, 0x009e, 0x0010, 0x009e, 0x0005, 0x6010, + 0x00b6, 0x2058, 0xb800, 0x00be, 0xd0bc, 0x0550, 0x2001, 0x1832, + 0x2004, 0x9005, 0x1540, 0x00f6, 0x2c78, 0x080c, 0x9980, 0x0508, + 0x7810, 0x6012, 0x080c, 0xba69, 0x7820, 0x9086, 0x0003, 0x0128, + 0x7808, 0x603a, 0x2f00, 0x603e, 0x0020, 0x7808, 0x603e, 0x2f00, + 0x603a, 0x602e, 0x6023, 0x0001, 0x6007, 0x0035, 0x6003, 0x0001, + 0x7954, 0x6156, 0x080c, 0x8000, 0x080c, 0x8582, 0x2f60, 0x00fe, + 0x0005, 0x2f60, 0x00fe, 0x2001, 0x1957, 0x2004, 0x6042, 0x0005, + 0x0016, 0x0096, 0x6814, 0x2048, 0xa87c, 0xd0e4, 0x0180, 0xc0e4, + 0xa87e, 0xa877, 0x0000, 0xa893, 0x0000, 0xa88f, 0x0000, 0xd0cc, + 0x0130, 0xc0cc, 0xa87e, 0xa878, 0x2048, 0x080c, 0x0f87, 0x6830, + 0x6036, 0x908e, 0x0001, 0x0148, 0x6803, 0x0002, 0x9086, 0x0005, + 0x0170, 0x9006, 0x602e, 0x6032, 0x00d0, 0x681c, 0xc085, 0x681e, + 0x6803, 0x0004, 0x6824, 0xc0f4, 0x9085, 0x0c00, 0x6826, 0x6814, + 0x2048, 0xa8ac, 0x6938, 0x9102, 0xa8b0, 0x693c, 0x9103, 0x1e48, + 0x683c, 0x602e, 0x6838, 0x9084, 0xfffc, 0x683a, 0x6032, 0x2d00, + 0x603a, 0x6808, 0x603e, 0x6910, 0x6112, 0x6954, 0x6156, 0x6023, + 0x0001, 0x6007, 0x0039, 0x6003, 0x0001, 0x080c, 0x8000, 0x080c, + 0x8582, 0x009e, 0x001e, 0x0005, 0x6024, 0xd0d4, 0x0510, 0xd0f4, + 0x11f8, 0x6038, 0x940a, 0x603c, 0x9303, 0x0230, 0x9105, 0x0120, + 0x6024, 0xc0d4, 0xc0f5, 0x0098, 0x643a, 0x633e, 0xac3e, 0xab42, + 0x0046, 0x0036, 0x2400, 0xacac, 0x9402, 0xa836, 0x2300, 0xabb0, + 0x9303, 0xa83a, 0x003e, 0x004e, 0x6024, 0xc0d4, 0x0000, 0x6026, + 0x0005, 0xd0f4, 0x1138, 0xa83c, 0x603a, 0xa840, 0x603e, 0x6024, + 0xc0f5, 0x6026, 0x0005, 0x0006, 0x0016, 0x6004, 0x908e, 0x0034, + 0x01b8, 0x908e, 0x0035, 0x01a0, 0x908e, 0x0036, 0x0188, 0x908e, + 0x0037, 0x0170, 0x908e, 0x0038, 0x0158, 0x908e, 0x0039, 0x0140, + 0x908e, 0x003a, 0x0128, 0x908e, 0x003b, 0x0110, 0x9085, 0x0001, + 0x001e, 0x000e, 0x0005, 0x0006, 0x0016, 0x0026, 0x0036, 0x00e6, + 0x2001, 0x1951, 0x200c, 0x8000, 0x2014, 0x2001, 0x0032, 0x080c, + 0x7e7f, 0x2001, 0x1955, 0x82ff, 0x1110, 0x2011, 0x0014, 0x2202, + 0x2001, 0x1953, 0x200c, 0x8000, 0x2014, 0x2071, 0x193d, 0x711a, + 0x721e, 0x2001, 0x0064, 0x080c, 0x7e7f, 0x2001, 0x1956, 0x82ff, + 0x1110, 0x2011, 0x0014, 0x2202, 0x2001, 0x1957, 0x9288, 0x000a, + 0x2102, 0x2001, 0x1a55, 0x2102, 0x2001, 0x0032, 0x080c, 0x14d2, + 0x080c, 0x6285, 0x00ee, 0x003e, 0x002e, 0x001e, 0x000e, 0x0005, + 0x0006, 0x0016, 0x00e6, 0x2001, 0x1955, 0x2003, 0x0028, 0x2001, + 0x1956, 0x2003, 0x0014, 0x2071, 0x193d, 0x701b, 0x0000, 0x701f, + 0x07d0, 0x2001, 0x1957, 0x2009, 0x001e, 0x2102, 0x2001, 0x1a55, + 0x2102, 0x2001, 0x0032, 0x080c, 0x14d2, 0x00ee, 0x001e, 0x000e, + 0x0005, 0x0096, 0x6058, 0x904d, 0x0110, 0x080c, 0x1007, 0x009e, + 0x0005, 0x0005, 0x00c6, 0x0126, 0x2091, 0x8000, 0x080c, 0x9980, + 0x0180, 0x2b08, 0x6112, 0x0ca9, 0x6023, 0x0001, 0x2900, 0x6016, + 0x2009, 0x0033, 0x080c, 0x9a50, 0x9085, 0x0001, 0x012e, 0x00ce, + 0x0005, 0x9006, 0x0cd8, 0x0096, 0x00e6, 0x00f6, 0x2071, 0x1800, + 0x9186, 0x0015, 0x1500, 0x7088, 0x9086, 0x0018, 0x11e0, 0x6014, + 0x2048, 0xaa3c, 0xd2e4, 0x1160, 0x2c78, 0x080c, 0x8772, 0x01d8, + 0x7074, 0xaa50, 0x9206, 0x1160, 0x7078, 0xaa54, 0x9206, 0x1140, + 0x6210, 0x00b6, 0x2258, 0xbaa0, 0x00be, 0x900e, 0x080c, 0x2e75, + 0x080c, 0x9dd7, 0x0020, 0x080c, 0xa364, 0x080c, 0x99d6, 0x00fe, + 0x00ee, 0x009e, 0x0005, 0x7058, 0xaa54, 0x9206, 0x0d48, 0x0c80, + 0x00c6, 0x0126, 0x2091, 0x8000, 0x080c, 0x9980, 0x0188, 0x2b08, + 0x6112, 0x080c, 0xba69, 0x6023, 0x0001, 0x2900, 0x6016, 0x2009, + 0x004d, 0x080c, 0x9a50, 0x9085, 0x0001, 0x012e, 0x00ce, 0x0005, + 0x9006, 0x0cd8, 0x00c6, 0x0126, 0x2091, 0x8000, 0x0016, 0x080c, + 0x9980, 0x0180, 0x2b08, 0x6112, 0x080c, 0xba69, 0x6023, 0x0001, + 0x2900, 0x6016, 0x001e, 0x080c, 0x9a50, 0x9085, 0x0001, 0x012e, + 0x00ce, 0x0005, 0x001e, 0x9006, 0x0cd0, 0x0016, 0x0026, 0x0036, + 0x0046, 0x0056, 0x0066, 0x0096, 0x00e6, 0x00f6, 0x2071, 0x1800, + 0x9186, 0x0015, 0x1568, 0x7188, 0x6014, 0x2048, 0xa814, 0x8003, + 0x9106, 0x1530, 0x20e1, 0x0000, 0x2001, 0x196f, 0x2003, 0x0000, + 0x6014, 0x2048, 0xa830, 0x20a8, 0x8906, 0x8006, 0x8007, 0x9094, + 0x003f, 0x22e8, 0x9084, 0xffc0, 0x9080, 0x001b, 0x20a0, 0x2001, + 0x196f, 0x0016, 0x200c, 0x080c, 0xc29a, 0x001e, 0xa804, 0x9005, + 0x0110, 0x2048, 0x0c38, 0x6014, 0x2048, 0xa867, 0x0103, 0x0010, + 0x080c, 0xa364, 0x080c, 0x99d6, 0x00fe, 0x00ee, 0x009e, 0x006e, + 0x005e, 0x004e, 0x003e, 0x002e, 0x001e, 0x0005, 0x0096, 0x00e6, + 0x00f6, 0x2071, 0x1800, 0x9186, 0x0015, 0x11b8, 0x7088, 0x9086, + 0x0004, 0x1198, 0x6014, 0x2048, 0x2c78, 0x080c, 0x8772, 0x01a8, + 0x7074, 0xaa74, 0x9206, 0x1130, 0x7078, 0xaa78, 0x9206, 0x1110, + 0x080c, 0x2e30, 0x080c, 0x9dd7, 0x0020, 0x080c, 0xa364, 0x080c, + 0x99d6, 0x00fe, 0x00ee, 0x009e, 0x0005, 0x7058, 0xaa78, 0x9206, + 0x0d78, 0x0c80, 0x0096, 0x00e6, 0x00f6, 0x2071, 0x1800, 0x9186, + 0x0015, 0x1550, 0x7088, 0x9086, 0x0004, 0x1530, 0x6014, 0x2048, + 0x2c78, 0x080c, 0x8772, 0x05e8, 0x7074, 0xaacc, 0x9206, 0x1180, + 0x7078, 0xaad0, 0x9206, 0x1160, 0x080c, 0x2e30, 0x0016, 0xa998, + 0xaab0, 0x9284, 0x1000, 0xc0fd, 0x080c, 0x50cb, 0x001e, 0x0010, + 0x080c, 0x4ebc, 0x080c, 0xb5fb, 0x0500, 0xa87b, 0x0000, 0xa883, + 0x0000, 0xa897, 0x4000, 0x0078, 0x080c, 0x4ebc, 0x080c, 0xb5fb, + 0x01a0, 0x6014, 0x2048, 0xa87b, 0x0030, 0xa883, 0x0000, 0xa897, + 0x4005, 0xa89b, 0x0004, 0x0126, 0x2091, 0x8000, 0xa867, 0x0139, + 0x080c, 0x6536, 0x012e, 0x080c, 0x99d6, 0x00fe, 0x00ee, 0x009e, + 0x0005, 0x7058, 0xaad0, 0x9206, 0x0938, 0x0890, 0x0016, 0x0026, + 0xa87c, 0xd0ac, 0x0178, 0xa938, 0xaa34, 0x2100, 0x9205, 0x0150, + 0xa890, 0x9106, 0x1118, 0xa88c, 0x9206, 0x0120, 0xa992, 0xaa8e, + 0x9085, 0x0001, 0x002e, 0x001e, 0x0005, 0x00b6, 0x00d6, 0x0036, + 0x080c, 0xb5fb, 0x0904, 0xbc23, 0x0096, 0x6314, 0x2348, 0xa87a, + 0xa982, 0x929e, 0x4000, 0x1580, 0x6310, 0x00c6, 0x2358, 0x2009, + 0x0000, 0xa868, 0xd0f4, 0x1140, 0x080c, 0x619e, 0x1108, 0xc185, + 0xb800, 0xd0bc, 0x0108, 0xc18d, 0xaa96, 0xa99a, 0x20a9, 0x0004, + 0xa860, 0x20e8, 0xa85c, 0x9080, 0x0031, 0x20a0, 0xb8b4, 0x20e0, + 0xb8b8, 0x9080, 0x0006, 0x2098, 0x080c, 0x0f52, 0x20a9, 0x0004, + 0xa85c, 0x9080, 0x0035, 0x20a0, 0xb8b8, 0x9080, 0x000a, 0x2098, + 0x080c, 0x0f52, 0x00ce, 0x0090, 0xaa96, 0x3918, 0x9398, 0x0007, + 0x231c, 0x6004, 0x9086, 0x0016, 0x0110, 0xa89b, 0x0004, 0xaba2, + 0x6310, 0x2358, 0xb804, 0x9084, 0x00ff, 0xa89e, 0x080c, 0x6529, + 0x6017, 0x0000, 0x009e, 0x003e, 0x00de, 0x00be, 0x0005, 0x0026, + 0x0036, 0x0046, 0x00b6, 0x0096, 0x00f6, 0x6214, 0x2248, 0x6210, + 0x2258, 0x2079, 0x0260, 0x9096, 0x0000, 0x11a0, 0xb814, 0x9084, + 0x00ff, 0x900e, 0x080c, 0x24d6, 0x2118, 0x831f, 0x939c, 0xff00, + 0x7838, 0x9084, 0x00ff, 0x931d, 0x7c3c, 0x2011, 0x8018, 0x080c, + 0x4672, 0x00a8, 0x9096, 0x0001, 0x1148, 0x89ff, 0x0180, 0xa89b, + 0x000d, 0x7838, 0xa8a6, 0x783c, 0xa8aa, 0x0048, 0x9096, 0x0002, + 0x1130, 0xa89b, 0x000d, 0x7838, 0xa8a6, 0x783c, 0xa8aa, 0x00fe, + 0x009e, 0x00be, 0x004e, 0x003e, 0x002e, 0x0005, 0x00c6, 0x0026, + 0x0016, 0x9186, 0x0035, 0x0110, 0x6a38, 0x0008, 0x6a2c, 0x080c, + 0xb5e9, 0x01f0, 0x2260, 0x6120, 0x9186, 0x0003, 0x0118, 0x9186, + 0x0006, 0x1190, 0x6838, 0x9206, 0x0140, 0x683c, 0x9206, 0x1160, + 0x6108, 0x6838, 0x9106, 0x1140, 0x0020, 0x6008, 0x693c, 0x9106, + 0x1118, 0x6010, 0x6910, 0x9106, 0x001e, 0x002e, 0x00ce, 0x0005, + 0x9085, 0x0001, 0x0cc8, 0xa974, 0xd1cc, 0x0188, 0x918c, 0x00ff, + 0x918e, 0x0002, 0x1160, 0xa9a8, 0x918c, 0x0f00, 0x810f, 0x918e, + 0x0001, 0x1128, 0xa834, 0xa938, 0x9115, 0x190c, 0xad37, 0x0005, + 0x0036, 0x2019, 0x0001, 0x0010, 0x0036, 0x901e, 0x0489, 0x01d0, + 0x080c, 0xb5fb, 0x01b8, 0x6037, 0x4000, 0x6014, 0x6017, 0x0000, + 0x0096, 0x2048, 0xa87c, 0x080c, 0xb7fa, 0x1118, 0x080c, 0xa364, + 0x0040, 0xa867, 0x0103, 0xa877, 0x0000, 0x83ff, 0x1129, 0x080c, + 0x6536, 0x009e, 0x003e, 0x0005, 0xa880, 0xd0b4, 0x0128, 0xa87b, + 0x0006, 0xc0ec, 0xa882, 0x0048, 0xd0bc, 0x0118, 0xa87b, 0x0002, + 0x0020, 0xa87b, 0x0005, 0x080c, 0xb8e9, 0xa877, 0x0000, 0x0005, + 0x2001, 0x180f, 0x2004, 0xd0ec, 0x0005, 0x0006, 0x2001, 0x180f, + 0x2004, 0xd0f4, 0x000e, 0x0005, 0x0006, 0x2001, 0x180f, 0x2004, + 0xd0e4, 0x000e, 0x0005, 0x0036, 0x0046, 0x6010, 0x00b6, 0x2058, + 0xbba0, 0x00be, 0x2021, 0x0007, 0x080c, 0x4829, 0x004e, 0x003e, + 0x0005, 0x0c51, 0x1d81, 0x0005, 0x2001, 0x1955, 0x2004, 0x601a, + 0x0005, 0x2001, 0x1957, 0x2004, 0x6042, 0x0005, 0x080c, 0x99d6, + 0x0804, 0x8582, 0x00b6, 0x0066, 0x6000, 0x90b2, 0x0016, 0x1a0c, + 0x0db2, 0x001b, 0x006e, 0x00be, 0x0005, 0xbd2d, 0xc3f7, 0xc552, + 0xbd2d, 0xbd2d, 0xbd2d, 0xbd2d, 0xbd2d, 0xbd64, 0xc5d0, 0xbd2d, + 0xbd2d, 0xbd2d, 0xbd2d, 0xbd2d, 0xbd2d, 0x080c, 0x0db2, 0x0066, + 0x6000, 0x90b2, 0x0016, 0x1a0c, 0x0db2, 0x0013, 0x006e, 0x0005, + 0xbd48, 0xcb38, 0xbd48, 0xbd48, 0xbd48, 0xbd48, 0xbd48, 0xbd48, + 0xcae5, 0xcb8c, 0xbd48, 0xd16d, 0xd1a3, 0xd16d, 0xd1a3, 0xbd48, + 0x080c, 0x0db2, 0x6000, 0x9082, 0x0016, 0x1a0c, 0x0db2, 0x6000, + 0x000a, 0x0005, 0xbd62, 0xc7ad, 0xc89d, 0xc8bf, 0xc97e, 0xbd62, + 0xca5c, 0xca06, 0xc5dc, 0xcabb, 0xcad0, 0xbd62, 0xbd62, 0xbd62, + 0xbd62, 0xbd62, 0x080c, 0x0db2, 0x91b2, 0x0053, 0x1a0c, 0x0db2, + 0x2100, 0x91b2, 0x0040, 0x1a04, 0xc19a, 0x0002, 0xbdae, 0xbf8b, + 0xbdae, 0xbdae, 0xbdae, 0xbf94, 0xbdae, 0xbdae, 0xbdae, 0xbdae, + 0xbdae, 0xbdae, 0xbdae, 0xbdae, 0xbdae, 0xbdae, 0xbdae, 0xbdae, + 0xbdae, 0xbdae, 0xbdae, 0xbdae, 0xbdae, 0xbdb0, 0xbe06, 0xbe15, + 0xbe79, 0xbea4, 0xbf1d, 0xbf76, 0xbdae, 0xbdae, 0xbf97, 0xbdae, + 0xbdae, 0xbfac, 0xbfb9, 0xbdae, 0xbdae, 0xbdae, 0xbdae, 0xbdae, + 0xc03c, 0xbdae, 0xbdae, 0xc050, 0xbdae, 0xbdae, 0xc00b, 0xbdae, + 0xbdae, 0xbdae, 0xc068, 0xbdae, 0xbdae, 0xbdae, 0xc0e5, 0xbdae, + 0xbdae, 0xbdae, 0xbdae, 0xbdae, 0xbdae, 0xc162, 0x080c, 0x0db2, + 0x080c, 0x6262, 0x1150, 0x2001, 0x1835, 0x2004, 0xd0cc, 0x1128, + 0x9084, 0x0009, 0x9086, 0x0008, 0x1140, 0x6007, 0x0009, 0x602f, + 0x0009, 0x6017, 0x0000, 0x0804, 0xbf84, 0x080c, 0x624b, 0x00e6, + 0x00c6, 0x0036, 0x0026, 0x0016, 0x6210, 0x2258, 0xbaa0, 0x0026, + 0x2019, 0x0029, 0x080c, 0x8180, 0x0076, 0x903e, 0x080c, 0x8078, + 0x2c08, 0x080c, 0xcd62, 0x007e, 0x001e, 0x001e, 0x002e, 0x003e, + 0x00ce, 0x00ee, 0x6610, 0x2658, 0x080c, 0x5f8d, 0xbe04, 0x9684, + 0x00ff, 0x9082, 0x0006, 0x0278, 0x080c, 0xcc94, 0x1904, 0xbe71, + 0x080c, 0xcc30, 0x1120, 0x6007, 0x0008, 0x0804, 0xbf84, 0x6007, + 0x0009, 0x0804, 0xbf84, 0x080c, 0xce81, 0x0128, 0x080c, 0xcc94, + 0x0d78, 0x0804, 0xbe71, 0x6017, 0x1900, 0x0c88, 0x080c, 0x2f50, + 0x1904, 0xc197, 0x6106, 0x080c, 0xcbe7, 0x6007, 0x0006, 0x0804, + 0xbf84, 0x6007, 0x0007, 0x0804, 0xbf84, 0x080c, 0xd1df, 0x1904, + 0xc197, 0x080c, 0x2f50, 0x1904, 0xc197, 0x00d6, 0x6610, 0x2658, + 0xbe04, 0x9684, 0x00ff, 0x9082, 0x0006, 0x1220, 0x2001, 0x0001, + 0x080c, 0x5ebb, 0x96b4, 0xff00, 0x8637, 0x9686, 0x0006, 0x0188, + 0x9686, 0x0004, 0x0170, 0xbe04, 0x96b4, 0x00ff, 0x9686, 0x0006, + 0x0140, 0x9686, 0x0004, 0x0128, 0x9686, 0x0005, 0x0110, 0x00de, + 0x0480, 0x00e6, 0x2071, 0x0260, 0x7034, 0x9084, 0x0003, 0x1140, + 0x7034, 0x9082, 0x0014, 0x0220, 0x7030, 0x9084, 0x0003, 0x0130, + 0x00ee, 0x6017, 0x0000, 0x602f, 0x0007, 0x00b0, 0x00ee, 0x080c, + 0xccf8, 0x1190, 0x9686, 0x0006, 0x1140, 0x0026, 0x6210, 0x2258, + 0xbaa0, 0x900e, 0x080c, 0x2e75, 0x002e, 0x080c, 0x6019, 0x6007, + 0x000a, 0x00de, 0x0804, 0xbf84, 0x6007, 0x000b, 0x00de, 0x0804, + 0xbf84, 0x080c, 0x2e30, 0x080c, 0xbd01, 0x6007, 0x0001, 0x0804, + 0xbf84, 0x080c, 0xd1df, 0x1904, 0xc197, 0x080c, 0x2f50, 0x1904, + 0xc197, 0x2071, 0x0260, 0x7034, 0x90b4, 0x0003, 0x1948, 0x90b2, + 0x0014, 0x0a30, 0x7030, 0x9084, 0x0003, 0x1910, 0x6610, 0x2658, + 0xbe04, 0x9686, 0x0707, 0x09e8, 0x0026, 0x6210, 0x2258, 0xbaa0, + 0x900e, 0x080c, 0x2e75, 0x002e, 0x6007, 0x000c, 0x2001, 0x0001, + 0x080c, 0xd2fb, 0x0804, 0xbf84, 0x080c, 0x6262, 0x1140, 0x2001, + 0x1835, 0x2004, 0x9084, 0x0009, 0x9086, 0x0008, 0x1110, 0x0804, + 0xbdbd, 0x080c, 0x624b, 0x6610, 0x2658, 0xbe04, 0x9684, 0x00ff, + 0x9082, 0x0006, 0x06c8, 0x1138, 0x0026, 0x2001, 0x0006, 0x080c, + 0x5efb, 0x002e, 0x0050, 0x96b4, 0xff00, 0x8637, 0x9686, 0x0004, + 0x0120, 0x9686, 0x0006, 0x1904, 0xbe71, 0x080c, 0xcd05, 0x1120, + 0x6007, 0x000e, 0x0804, 0xbf84, 0x0046, 0x6410, 0x2458, 0xbca0, + 0x0046, 0x080c, 0x2e30, 0x080c, 0xbd01, 0x004e, 0x0016, 0x9006, + 0x2009, 0x1854, 0x210c, 0xd1a4, 0x0148, 0x2009, 0x0029, 0x080c, + 0xcfe6, 0x6010, 0x2058, 0xb800, 0xc0e5, 0xb802, 0x001e, 0x004e, + 0x6007, 0x0001, 0x0804, 0xbf84, 0x2001, 0x0001, 0x080c, 0x5ebb, + 0x0156, 0x0016, 0x0026, 0x0036, 0x20a9, 0x0004, 0x2019, 0x1805, + 0x2011, 0x0270, 0x080c, 0xa909, 0x003e, 0x002e, 0x001e, 0x015e, + 0x9005, 0x0168, 0x96b4, 0xff00, 0x8637, 0x9682, 0x0004, 0x0a04, + 0xbe71, 0x9682, 0x0007, 0x0a04, 0xbecd, 0x0804, 0xbe71, 0x6017, + 0x1900, 0x6007, 0x0009, 0x0804, 0xbf84, 0x080c, 0x6262, 0x1140, + 0x2001, 0x1835, 0x2004, 0x9084, 0x0009, 0x9086, 0x0008, 0x1110, + 0x0804, 0xbdbd, 0x080c, 0x624b, 0x6610, 0x2658, 0xbe04, 0x9684, + 0x00ff, 0x9082, 0x0006, 0x0690, 0x96b4, 0xff00, 0x8637, 0x9686, + 0x0004, 0x0120, 0x9686, 0x0006, 0x1904, 0xbe71, 0x080c, 0xcd33, + 0x1130, 0x080c, 0xcc30, 0x1118, 0x6007, 0x0010, 0x04e8, 0x0046, + 0x6410, 0x2458, 0xbca0, 0x0046, 0x080c, 0x2e30, 0x080c, 0xbd01, + 0x004e, 0x0016, 0x9006, 0x2009, 0x1854, 0x210c, 0xd1a4, 0x0148, + 0x2009, 0x0029, 0x080c, 0xcfe6, 0x6010, 0x2058, 0xb800, 0xc0e5, + 0xb802, 0x001e, 0x004e, 0x6007, 0x0001, 0x00f0, 0x080c, 0xce81, + 0x0140, 0x96b4, 0xff00, 0x8637, 0x9686, 0x0006, 0x0978, 0x0804, + 0xbe71, 0x6017, 0x1900, 0x6007, 0x0009, 0x0070, 0x080c, 0x2f50, + 0x1904, 0xc197, 0x080c, 0xd1df, 0x1904, 0xc197, 0x080c, 0xc335, + 0x1904, 0xbe71, 0x6007, 0x0012, 0x6003, 0x0001, 0x080c, 0x8048, + 0x080c, 0x8582, 0x0005, 0x6007, 0x0001, 0x6003, 0x0001, 0x080c, + 0x8048, 0x080c, 0x8582, 0x0cb0, 0x6007, 0x0005, 0x0c68, 0x080c, + 0xd1df, 0x1904, 0xc197, 0x080c, 0x2f50, 0x1904, 0xc197, 0x080c, + 0xc335, 0x1904, 0xbe71, 0x6007, 0x0020, 0x6003, 0x0001, 0x080c, + 0x8048, 0x080c, 0x8582, 0x0005, 0x080c, 0x2f50, 0x1904, 0xc197, + 0x6007, 0x0023, 0x6003, 0x0001, 0x080c, 0x8048, 0x080c, 0x8582, + 0x0005, 0x080c, 0xd1df, 0x1904, 0xc197, 0x080c, 0x2f50, 0x1904, + 0xc197, 0x080c, 0xc335, 0x1904, 0xbe71, 0x0016, 0x0026, 0x00e6, + 0x2071, 0x0260, 0x7244, 0x9286, 0xffff, 0x0180, 0x2c08, 0x080c, + 0xb5e9, 0x01b0, 0x2260, 0x7240, 0x6008, 0x9206, 0x1188, 0x6010, + 0x9190, 0x0004, 0x2214, 0x9206, 0x01b8, 0x0050, 0x7240, 0x2c08, + 0x9006, 0x080c, 0xcfb8, 0x1180, 0x7244, 0x9286, 0xffff, 0x01b0, + 0x2160, 0x6007, 0x0026, 0x6017, 0x1700, 0x7214, 0x9296, 0xffff, + 0x1180, 0x6007, 0x0025, 0x0068, 0x6020, 0x9086, 0x0007, 0x1d80, + 0x6004, 0x9086, 0x0024, 0x1110, 0x080c, 0x99d6, 0x2160, 0x6007, + 0x0025, 0x6003, 0x0001, 0x080c, 0x8048, 0x080c, 0x8582, 0x00ee, + 0x002e, 0x001e, 0x0005, 0x2001, 0x0001, 0x080c, 0x5ebb, 0x0156, + 0x0016, 0x0026, 0x0036, 0x20a9, 0x0004, 0x2019, 0x1805, 0x2011, + 0x0276, 0x080c, 0xa909, 0x003e, 0x002e, 0x001e, 0x015e, 0x0120, + 0x6007, 0x0031, 0x0804, 0xbf84, 0x080c, 0xa5c2, 0x080c, 0x6c53, + 0x1190, 0x0006, 0x0026, 0x0036, 0x080c, 0x6c6d, 0x1138, 0x080c, + 0x6f2a, 0x080c, 0x5a21, 0x080c, 0x6b8a, 0x0010, 0x080c, 0x6c2d, + 0x003e, 0x002e, 0x000e, 0x0005, 0x080c, 0x2f50, 0x1904, 0xc197, + 0x080c, 0xc335, 0x1904, 0xbe71, 0x6106, 0x080c, 0xc351, 0x1120, + 0x6007, 0x002b, 0x0804, 0xbf84, 0x6007, 0x002c, 0x0804, 0xbf84, + 0x080c, 0xd1df, 0x1904, 0xc197, 0x080c, 0x2f50, 0x1904, 0xc197, + 0x080c, 0xc335, 0x1904, 0xbe71, 0x6106, 0x080c, 0xc356, 0x1120, + 0x6007, 0x002e, 0x0804, 0xbf84, 0x6007, 0x002f, 0x0804, 0xbf84, + 0x080c, 0x2f50, 0x1904, 0xc197, 0x00e6, 0x00d6, 0x00c6, 0x6010, + 0x2058, 0xb904, 0x9184, 0x00ff, 0x9086, 0x0006, 0x0158, 0x9184, + 0xff00, 0x8007, 0x9086, 0x0006, 0x0128, 0x00ce, 0x00de, 0x00ee, + 0x0804, 0xbf8b, 0x080c, 0x5117, 0xd0e4, 0x0904, 0xc0e2, 0x2071, + 0x026c, 0x7010, 0x603a, 0x7014, 0x603e, 0x7108, 0x720c, 0x080c, + 0x62a0, 0x0140, 0x6010, 0x2058, 0xb810, 0x9106, 0x1118, 0xb814, + 0x9206, 0x0510, 0x080c, 0x629c, 0x15b8, 0x2069, 0x1800, 0x6878, + 0x9206, 0x1590, 0x6874, 0x9106, 0x1578, 0x7210, 0x080c, 0xb5e9, + 0x0590, 0x080c, 0xc222, 0x0578, 0x080c, 0xd05d, 0x0560, 0x622e, + 0x6007, 0x0036, 0x6003, 0x0001, 0x080c, 0x8000, 0x080c, 0x8582, + 0x00ce, 0x00de, 0x00ee, 0x0005, 0x7214, 0x9286, 0xffff, 0x0150, + 0x080c, 0xb5e9, 0x01c0, 0x9280, 0x0002, 0x2004, 0x7110, 0x9106, + 0x1190, 0x08e0, 0x7210, 0x2c08, 0x9085, 0x0001, 0x080c, 0xcfb8, + 0x2c10, 0x2160, 0x0140, 0x0890, 0x6007, 0x0037, 0x602f, 0x0009, + 0x6017, 0x1500, 0x08b8, 0x6007, 0x0037, 0x602f, 0x0003, 0x6017, + 0x1700, 0x0880, 0x6007, 0x0012, 0x0868, 0x080c, 0x2f50, 0x1904, + 0xc197, 0x6010, 0x2058, 0xb804, 0x9084, 0xff00, 0x8007, 0x9086, + 0x0006, 0x1904, 0xbf8b, 0x00e6, 0x00d6, 0x00c6, 0x080c, 0x5117, + 0xd0e4, 0x0904, 0xc15a, 0x2069, 0x1800, 0x2071, 0x026c, 0x7008, + 0x603a, 0x720c, 0x623e, 0x9286, 0xffff, 0x1150, 0x7208, 0x00c6, + 0x2c08, 0x9085, 0x0001, 0x080c, 0xcfb8, 0x2c10, 0x00ce, 0x05e8, + 0x080c, 0xb5e9, 0x05d0, 0x7108, 0x9280, 0x0002, 0x2004, 0x9106, + 0x15a0, 0x00c6, 0x0026, 0x2260, 0x080c, 0xb244, 0x002e, 0x00ce, + 0x7118, 0x918c, 0xff00, 0x810f, 0x9186, 0x0001, 0x0178, 0x9186, + 0x0005, 0x0118, 0x9186, 0x0007, 0x1198, 0x9280, 0x0005, 0x2004, + 0x9005, 0x0170, 0x080c, 0xc222, 0x0904, 0xc0db, 0x0056, 0x7510, + 0x7614, 0x080c, 0xd076, 0x005e, 0x00ce, 0x00de, 0x00ee, 0x0005, + 0x6007, 0x003b, 0x602f, 0x0009, 0x6017, 0x2a00, 0x6003, 0x0001, + 0x080c, 0x8000, 0x080c, 0x8582, 0x0c78, 0x6007, 0x003b, 0x602f, + 0x0003, 0x6017, 0x0300, 0x6003, 0x0001, 0x080c, 0x8000, 0x080c, + 0x8582, 0x0c10, 0x6007, 0x003b, 0x602f, 0x000b, 0x6017, 0x0000, + 0x0804, 0xc0b2, 0x00e6, 0x0026, 0x080c, 0x6262, 0x0550, 0x080c, + 0x624b, 0x080c, 0xd251, 0x1518, 0x2071, 0x1800, 0x70d4, 0x9085, + 0x0003, 0x70d6, 0x00f6, 0x2079, 0x0100, 0x72a8, 0x9284, 0x00ff, + 0x7076, 0x78e6, 0x9284, 0xff00, 0x7278, 0x9205, 0x707a, 0x78ea, + 0x00fe, 0x70df, 0x0000, 0x080c, 0x62a0, 0x0120, 0x2011, 0x19cf, + 0x2013, 0x07d0, 0xd0ac, 0x1128, 0x080c, 0x2c2b, 0x0010, 0x080c, + 0xd283, 0x002e, 0x00ee, 0x080c, 0x99d6, 0x0804, 0xbf8a, 0x080c, + 0x99d6, 0x0005, 0x2600, 0x0002, 0xc1ae, 0xc1ae, 0xc1ae, 0xc1ae, + 0xc1ae, 0xc1b0, 0xc1ae, 0xc1ae, 0xc1ae, 0xc1ae, 0xc1cd, 0xc1ae, + 0xc1ae, 0xc1ae, 0xc1df, 0xc1ec, 0xc21d, 0xc1ae, 0x080c, 0x0db2, + 0x080c, 0xd1df, 0x1d20, 0x080c, 0x2f50, 0x1d08, 0x080c, 0xc335, + 0x1148, 0x7038, 0x6016, 0x6007, 0x0045, 0x6003, 0x0001, 0x080c, + 0x8048, 0x0005, 0x080c, 0x2e30, 0x080c, 0xbd01, 0x6007, 0x0001, + 0x6003, 0x0001, 0x080c, 0x8048, 0x0005, 0x080c, 0xd1df, 0x1938, + 0x080c, 0x2f50, 0x1920, 0x080c, 0xc335, 0x1d60, 0x703c, 0x6016, + 0x6007, 0x004a, 0x6003, 0x0001, 0x080c, 0x8048, 0x0005, 0x080c, + 0xc23d, 0x0904, 0xc197, 0x6007, 0x004e, 0x6003, 0x0001, 0x080c, + 0x8048, 0x080c, 0x8582, 0x0005, 0x6007, 0x004f, 0x6017, 0x0000, + 0x7134, 0x918c, 0x00ff, 0x81ff, 0x0508, 0x9186, 0x0001, 0x1160, + 0x7140, 0x2001, 0x198c, 0x2004, 0x9106, 0x11b0, 0x7144, 0x2001, + 0x198d, 0x2004, 0x9106, 0x0190, 0x9186, 0x0002, 0x1168, 0x2011, + 0x0276, 0x20a9, 0x0004, 0x6010, 0x0096, 0x2048, 0x2019, 0x000a, + 0x080c, 0xa91d, 0x009e, 0x0110, 0x6017, 0x0001, 0x6003, 0x0001, + 0x080c, 0x8048, 0x080c, 0x8582, 0x0005, 0x6007, 0x0050, 0x703c, + 0x6016, 0x0ca0, 0x00e6, 0x2071, 0x0260, 0x00b6, 0x00c6, 0x2260, + 0x6010, 0x2058, 0xb8bc, 0xd084, 0x0150, 0x7128, 0x6048, 0x9106, + 0x1120, 0x712c, 0x6044, 0x9106, 0x0110, 0x9006, 0x0010, 0x9085, + 0x0001, 0x00ce, 0x00be, 0x00ee, 0x0005, 0x0016, 0x0096, 0x0086, + 0x00e6, 0x01c6, 0x01d6, 0x0126, 0x2091, 0x8000, 0x2071, 0x1800, + 0x7088, 0x908a, 0x00f9, 0x16e8, 0x20e1, 0x0000, 0x2001, 0x196f, + 0x2003, 0x0000, 0x080c, 0x0fee, 0x05a0, 0x2900, 0x6016, 0x7088, + 0x8004, 0xa816, 0x908a, 0x001e, 0x02d0, 0xa833, 0x001e, 0x20a9, + 0x001e, 0xa860, 0x20e8, 0xa85c, 0x9080, 0x001b, 0x20a0, 0x2001, + 0x196f, 0x0016, 0x200c, 0x0471, 0x001e, 0x2940, 0x080c, 0x0fee, + 0x01c0, 0x2900, 0xa006, 0x2100, 0x81ff, 0x0180, 0x0c18, 0xa832, + 0x20a8, 0xa860, 0x20e8, 0xa85c, 0x9080, 0x001b, 0x20a0, 0x2001, + 0x196f, 0x0016, 0x200c, 0x00b1, 0x001e, 0x0000, 0x9085, 0x0001, + 0x0048, 0x2071, 0x1800, 0x708b, 0x0000, 0x6014, 0x2048, 0x080c, + 0x0f87, 0x9006, 0x012e, 0x01de, 0x01ce, 0x00ee, 0x008e, 0x009e, + 0x001e, 0x0005, 0x0006, 0x0016, 0x0026, 0x0036, 0x00c6, 0x918c, + 0xffff, 0x11a8, 0x080c, 0x20b2, 0x2099, 0x026c, 0x2001, 0x0014, + 0x3518, 0x9312, 0x1218, 0x23a8, 0x4003, 0x00f8, 0x20a8, 0x4003, + 0x22a8, 0x8108, 0x080c, 0x20b2, 0x2099, 0x0260, 0x0ca8, 0x080c, + 0x20b2, 0x2061, 0x196f, 0x6004, 0x2098, 0x6008, 0x3518, 0x9312, + 0x1218, 0x23a8, 0x4003, 0x0048, 0x20a8, 0x4003, 0x22a8, 0x8108, + 0x080c, 0x20b2, 0x2099, 0x0260, 0x0ca8, 0x2061, 0x196f, 0x2019, + 0x0280, 0x3300, 0x931e, 0x0110, 0x6006, 0x0020, 0x2001, 0x0260, + 0x6006, 0x8108, 0x2162, 0x9292, 0x0021, 0x9296, 0xffff, 0x620a, + 0x00ce, 0x003e, 0x002e, 0x001e, 0x000e, 0x0005, 0x0006, 0x0016, + 0x0026, 0x0036, 0x00c6, 0x81ff, 0x11b8, 0x080c, 0x20ca, 0x20a1, + 0x024c, 0x2001, 0x0014, 0x3518, 0x9312, 0x1218, 0x23a8, 0x4003, + 0x0418, 0x20a8, 0x4003, 0x82ff, 0x01f8, 0x22a8, 0x8108, 0x080c, + 0x20ca, 0x20a1, 0x0240, 0x0c98, 0x080c, 0x20ca, 0x2061, 0x1972, + 0x6004, 0x20a0, 0x6008, 0x3518, 0x9312, 0x1218, 0x23a8, 0x4003, + 0x0058, 0x20a8, 0x4003, 0x82ff, 0x0138, 0x22a8, 0x8108, 0x080c, + 0x20ca, 0x20a1, 0x0240, 0x0c98, 0x2061, 0x1972, 0x2019, 0x0260, + 0x3400, 0x931e, 0x0110, 0x6006, 0x0020, 0x2001, 0x0240, 0x6006, + 0x8108, 0x2162, 0x9292, 0x0021, 0x9296, 0xffff, 0x620a, 0x00ce, + 0x003e, 0x002e, 0x001e, 0x000e, 0x0005, 0x00b6, 0x0066, 0x6610, + 0x2658, 0xbe04, 0x96b4, 0xff00, 0x8637, 0x9686, 0x0006, 0x0170, + 0x9686, 0x0004, 0x0158, 0xbe04, 0x96b4, 0x00ff, 0x9686, 0x0006, + 0x0128, 0x9686, 0x0004, 0x0110, 0x9085, 0x0001, 0x006e, 0x00be, + 0x0005, 0x00d6, 0x080c, 0xc3cd, 0x00de, 0x0005, 0x00d6, 0x080c, + 0xc3da, 0x1520, 0x680c, 0x908c, 0xff00, 0x6820, 0x9084, 0x00ff, + 0x9115, 0x6216, 0x6824, 0x602e, 0xd1e4, 0x0130, 0x9006, 0x080c, + 0xd2fb, 0x2009, 0x0001, 0x0078, 0xd1ec, 0x0180, 0x6920, 0x918c, + 0x00ff, 0x6824, 0x080c, 0x24d6, 0x1148, 0x2001, 0x0001, 0x080c, + 0xd2fb, 0x2110, 0x900e, 0x080c, 0x2e75, 0x0018, 0x9085, 0x0001, + 0x0008, 0x9006, 0x00de, 0x0005, 0x00b6, 0x00c6, 0x080c, 0x9a23, + 0x05a8, 0x0016, 0x0026, 0x00c6, 0x2011, 0x0263, 0x2204, 0x8211, + 0x220c, 0x080c, 0x24d6, 0x1578, 0x080c, 0x5f1e, 0x1560, 0xbe12, + 0xbd16, 0x00ce, 0x002e, 0x001e, 0x2b00, 0x6012, 0x080c, 0xd1df, + 0x11d8, 0x080c, 0x2f50, 0x11c0, 0x080c, 0xc335, 0x0510, 0x2001, + 0x0007, 0x080c, 0x5ecf, 0x2001, 0x0007, 0x080c, 0x5efb, 0x6017, + 0x0000, 0x6023, 0x0001, 0x6007, 0x0001, 0x6003, 0x0001, 0x080c, + 0x8048, 0x080c, 0x8582, 0x0010, 0x080c, 0x99d6, 0x9085, 0x0001, + 0x00ce, 0x00be, 0x0005, 0x080c, 0x99d6, 0x00ce, 0x002e, 0x001e, + 0x0ca8, 0x080c, 0x99d6, 0x9006, 0x0c98, 0x2069, 0x026d, 0x6800, + 0x9082, 0x0010, 0x1228, 0x6017, 0x0000, 0x9085, 0x0001, 0x0008, + 0x9006, 0x0005, 0x6017, 0x0000, 0x2069, 0x026c, 0x6808, 0x9084, + 0xff00, 0x9086, 0x0800, 0x1190, 0x6904, 0x9186, 0x0018, 0x0118, + 0x9186, 0x0014, 0x1158, 0x810f, 0x6800, 0x9084, 0x00ff, 0x910d, + 0x615a, 0x908e, 0x0014, 0x0110, 0x908e, 0x0010, 0x0005, 0x6004, + 0x90b2, 0x0053, 0x1a0c, 0x0db2, 0x91b6, 0x0013, 0x1130, 0x2008, + 0x91b2, 0x0040, 0x1a04, 0xc522, 0x0092, 0x91b6, 0x0027, 0x0120, + 0x91b6, 0x0014, 0x190c, 0x0db2, 0x2001, 0x0007, 0x080c, 0x5efb, + 0x080c, 0x847d, 0x080c, 0x9a06, 0x080c, 0x8582, 0x0005, 0xc457, + 0xc459, 0xc457, 0xc457, 0xc457, 0xc459, 0xc468, 0xc51b, 0xc4ba, + 0xc51b, 0xc4cc, 0xc51b, 0xc468, 0xc51b, 0xc513, 0xc51b, 0xc513, + 0xc51b, 0xc51b, 0xc457, 0xc457, 0xc457, 0xc457, 0xc457, 0xc457, + 0xc457, 0xc457, 0xc457, 0xc457, 0xc457, 0xc459, 0xc457, 0xc51b, + 0xc457, 0xc457, 0xc51b, 0xc457, 0xc518, 0xc51b, 0xc457, 0xc457, + 0xc457, 0xc457, 0xc51b, 0xc51b, 0xc457, 0xc51b, 0xc51b, 0xc457, + 0xc463, 0xc457, 0xc457, 0xc457, 0xc457, 0xc517, 0xc51b, 0xc457, + 0xc457, 0xc51b, 0xc51b, 0xc457, 0xc457, 0xc457, 0xc457, 0x080c, + 0x0db2, 0x080c, 0x847d, 0x080c, 0xbd04, 0x6003, 0x0002, 0x080c, + 0x8582, 0x0804, 0xc521, 0x9006, 0x080c, 0x5ebb, 0x0804, 0xc51b, + 0x080c, 0x629c, 0x1904, 0xc51b, 0x9006, 0x080c, 0x5ebb, 0x6010, + 0x2058, 0xb810, 0x9086, 0x00ff, 0x1140, 0x00f6, 0x2079, 0x1800, + 0x78a0, 0x8000, 0x78a2, 0x00fe, 0x0428, 0x6010, 0x2058, 0xb8b0, + 0x9005, 0x1178, 0x080c, 0xbcec, 0x1904, 0xc51b, 0x0036, 0x0046, + 0xbba0, 0x2021, 0x0007, 0x080c, 0x4829, 0x004e, 0x003e, 0x0804, + 0xc51b, 0x080c, 0x2f81, 0x1904, 0xc51b, 0x2001, 0x1800, 0x2004, + 0x9086, 0x0002, 0x1138, 0x00f6, 0x2079, 0x1800, 0x78a0, 0x8000, + 0x78a2, 0x00fe, 0x2001, 0x0002, 0x080c, 0x5ecf, 0x080c, 0x847d, + 0x6023, 0x0001, 0x6003, 0x0001, 0x6007, 0x0002, 0x080c, 0x8048, + 0x080c, 0x8582, 0x6110, 0x2158, 0x2009, 0x0001, 0x080c, 0x7c58, + 0x0804, 0xc521, 0x6610, 0x2658, 0xbe04, 0x96b4, 0xff00, 0x8637, + 0x9686, 0x0006, 0x0904, 0xc51b, 0x9686, 0x0004, 0x0904, 0xc51b, + 0x2001, 0x0004, 0x0804, 0xc519, 0x2001, 0x1800, 0x2004, 0x9086, + 0x0003, 0x1158, 0x0036, 0x0046, 0x6010, 0x2058, 0xbba0, 0x2021, + 0x0006, 0x080c, 0x4829, 0x004e, 0x003e, 0x2001, 0x0006, 0x080c, + 0xc53f, 0x6610, 0x2658, 0xbe04, 0x0066, 0x96b4, 0xff00, 0x8637, + 0x9686, 0x0006, 0x006e, 0x0168, 0x2001, 0x0006, 0x080c, 0x5efb, + 0x9284, 0x00ff, 0x908e, 0x0007, 0x1120, 0x2001, 0x0006, 0x080c, + 0x5ecf, 0x080c, 0x629c, 0x11f8, 0x2001, 0x1835, 0x2004, 0xd0a4, + 0x01d0, 0xbe04, 0x96b4, 0x00ff, 0x9686, 0x0006, 0x01a0, 0x00f6, + 0x2079, 0x1800, 0x78a0, 0x8000, 0x78a2, 0x00fe, 0x0804, 0xc4a2, + 0x2001, 0x0004, 0x0030, 0x2001, 0x0006, 0x0449, 0x0020, 0x0018, + 0x0010, 0x080c, 0x5efb, 0x080c, 0x847d, 0x080c, 0x99d6, 0x080c, + 0x8582, 0x0005, 0x2600, 0x0002, 0xc536, 0xc536, 0xc536, 0xc536, + 0xc536, 0xc538, 0xc536, 0xc536, 0xc536, 0xc536, 0xc538, 0xc536, + 0xc536, 0xc536, 0xc538, 0xc538, 0xc538, 0xc538, 0x080c, 0x0db2, + 0x080c, 0x847d, 0x080c, 0x99d6, 0x080c, 0x8582, 0x0005, 0x0016, + 0x00b6, 0x00d6, 0x6110, 0x2158, 0xb900, 0xd184, 0x0138, 0x080c, + 0x5ecf, 0x9006, 0x080c, 0x5ebb, 0x080c, 0x2e55, 0x00de, 0x00be, + 0x001e, 0x0005, 0x6610, 0x2658, 0xb804, 0x9084, 0xff00, 0x8007, + 0x90b2, 0x000c, 0x1a0c, 0x0db2, 0x91b6, 0x0015, 0x1110, 0x003b, + 0x0028, 0x91b6, 0x0016, 0x190c, 0x0db2, 0x006b, 0x0005, 0xa445, + 0xa445, 0xa445, 0xa445, 0xa445, 0xa445, 0xc5ba, 0xc57f, 0xa445, + 0xa445, 0xa445, 0xa445, 0xa445, 0xa445, 0xa445, 0xa445, 0xa445, + 0xa445, 0xc5ba, 0xc5c1, 0xa445, 0xa445, 0xa445, 0xa445, 0x00f6, + 0x080c, 0x629c, 0x11d8, 0x080c, 0xbcec, 0x11c0, 0x6010, 0x905d, + 0x01a8, 0xb8b0, 0x9005, 0x0190, 0x9006, 0x080c, 0x5ebb, 0x2001, + 0x0002, 0x080c, 0x5ecf, 0x6023, 0x0001, 0x6003, 0x0001, 0x6007, + 0x0002, 0x080c, 0x8048, 0x080c, 0x8582, 0x00d0, 0x2011, 0x0263, + 0x2204, 0x8211, 0x220c, 0x080c, 0x24d6, 0x1190, 0x080c, 0x5f7e, + 0x0118, 0x080c, 0x99d6, 0x0060, 0xb810, 0x0006, 0xb814, 0x0006, + 0x080c, 0x5a3b, 0x000e, 0xb816, 0x000e, 0xb812, 0x080c, 0x99d6, + 0x00fe, 0x0005, 0x6604, 0x96b6, 0x001e, 0x1110, 0x080c, 0x99d6, + 0x0005, 0x080c, 0xa7a1, 0x1148, 0x6003, 0x0001, 0x6007, 0x0001, + 0x080c, 0x8048, 0x080c, 0x8582, 0x0010, 0x080c, 0x99d6, 0x0005, + 0x6004, 0x908a, 0x0053, 0x1a0c, 0x0db2, 0x080c, 0x847d, 0x080c, + 0x9a06, 0x080c, 0x8582, 0x0005, 0x9182, 0x0040, 0x0002, 0xc5f2, + 0xc5f2, 0xc5f2, 0xc5f2, 0xc5f4, 0xc5f2, 0xc5f2, 0xc5f2, 0xc5f2, + 0xc5f2, 0xc5f2, 0xc5f2, 0xc5f2, 0xc5f2, 0xc5f2, 0xc5f2, 0xc5f2, + 0xc5f2, 0xc5f2, 0x080c, 0x0db2, 0x0096, 0x00b6, 0x00d6, 0x00e6, + 0x00f6, 0x0046, 0x0026, 0x6210, 0x2258, 0xb8ac, 0x9005, 0x11a8, + 0x6106, 0x2071, 0x0260, 0x7444, 0x94a4, 0xff00, 0x0904, 0xc65a, + 0x080c, 0xd2ef, 0x1170, 0x9486, 0x2000, 0x1158, 0x2009, 0x0001, + 0x2011, 0x0200, 0x080c, 0x7e3e, 0x0020, 0x9026, 0x080c, 0xd224, + 0x0c38, 0x080c, 0x0fd5, 0x090c, 0x0db2, 0x6003, 0x0007, 0xa867, + 0x010d, 0x9006, 0xa802, 0xa86a, 0xac8a, 0x2c00, 0xa88e, 0x6008, + 0xa8e2, 0x6010, 0x2058, 0xb8a0, 0x7130, 0xa97a, 0x0016, 0xa876, + 0xa87f, 0x0000, 0xa883, 0x0000, 0xa887, 0x0036, 0x080c, 0x6536, + 0x001e, 0x080c, 0xd2ef, 0x1904, 0xc6ba, 0x9486, 0x2000, 0x1130, + 0x2019, 0x0017, 0x080c, 0xcf62, 0x0804, 0xc6ba, 0x9486, 0x0200, + 0x1120, 0x080c, 0xcefe, 0x0804, 0xc6ba, 0x9486, 0x0400, 0x0120, + 0x9486, 0x1000, 0x1904, 0xc6ba, 0x2019, 0x0002, 0x080c, 0xcf19, + 0x0804, 0xc6ba, 0x2069, 0x1a3e, 0x6a00, 0xd284, 0x0904, 0xc724, + 0x9284, 0x0300, 0x1904, 0xc71d, 0x6804, 0x9005, 0x0904, 0xc705, + 0x2d78, 0x6003, 0x0007, 0x080c, 0x0fee, 0x0904, 0xc6c6, 0x7800, + 0xd08c, 0x1118, 0x7804, 0x8001, 0x7806, 0x6017, 0x0000, 0x2001, + 0x180e, 0x2004, 0xd084, 0x1904, 0xc728, 0x9006, 0xa802, 0xa867, + 0x0116, 0xa86a, 0x6008, 0xa8e2, 0x2c00, 0xa87a, 0x6010, 0x2058, + 0xb8a0, 0x7130, 0xa9b6, 0xa876, 0xb928, 0xa9ba, 0xb92c, 0xa9be, + 0xb930, 0xa9c2, 0xb934, 0xa9c6, 0xa883, 0x003d, 0x7044, 0x9084, + 0x0003, 0x9080, 0xc6c2, 0x2005, 0xa87e, 0x20a9, 0x000a, 0x2001, + 0x0270, 0xaa5c, 0x9290, 0x0021, 0x2009, 0x0205, 0x200b, 0x0080, + 0x20e1, 0x0000, 0xab60, 0x23e8, 0x2098, 0x22a0, 0x4003, 0x200b, + 0x0000, 0x2001, 0x027a, 0x200c, 0xa9b2, 0x8000, 0x200c, 0xa9ae, + 0x080c, 0x6536, 0x002e, 0x004e, 0x00fe, 0x00ee, 0x00de, 0x00be, + 0x009e, 0x0005, 0x0000, 0x0080, 0x0040, 0x0000, 0x2001, 0x180f, + 0x2004, 0xd084, 0x0120, 0x080c, 0x0fd5, 0x1904, 0xc66f, 0x6017, + 0xf100, 0x6003, 0x0001, 0x6007, 0x0041, 0x080c, 0x8000, 0x080c, + 0x8582, 0x0c00, 0x2069, 0x0260, 0x6848, 0x9084, 0xff00, 0x9086, + 0x1200, 0x1198, 0x686c, 0x9084, 0x00ff, 0x0016, 0x6114, 0x918c, + 0xf700, 0x910d, 0x6116, 0x001e, 0x6003, 0x0001, 0x6007, 0x0043, + 0x080c, 0x8000, 0x080c, 0x8582, 0x0828, 0x6868, 0x602e, 0x686c, + 0x6032, 0x6017, 0xf200, 0x6003, 0x0001, 0x6007, 0x0041, 0x080c, + 0x8000, 0x080c, 0x8582, 0x0804, 0xc6ba, 0x2001, 0x180d, 0x2004, + 0xd0ec, 0x0120, 0x2011, 0x8049, 0x080c, 0x4672, 0x6017, 0xf300, + 0x0010, 0x6017, 0xf100, 0x6003, 0x0001, 0x6007, 0x0041, 0x080c, + 0x8000, 0x080c, 0x8582, 0x0804, 0xc6ba, 0x6017, 0xf500, 0x0c98, + 0x6017, 0xf600, 0x0804, 0xc6da, 0x6017, 0xf200, 0x0804, 0xc6da, + 0xa867, 0x0146, 0xa86b, 0x0000, 0x6008, 0xa886, 0x2c00, 0xa87a, + 0x7044, 0x9084, 0x0003, 0x9080, 0xc6c2, 0x2005, 0xa87e, 0x2928, + 0x6010, 0x2058, 0xb8a0, 0xa876, 0xb828, 0xa88a, 0xb82c, 0xa88e, + 0xb830, 0xa892, 0xb834, 0xa896, 0xa883, 0x003d, 0x2009, 0x0205, + 0x2104, 0x9085, 0x0080, 0x200a, 0x20e1, 0x0000, 0x2011, 0x0210, + 0x2214, 0x9294, 0x0fff, 0xaaa2, 0x9282, 0x0111, 0x1a0c, 0x0db2, + 0x8210, 0x821c, 0x2001, 0x026c, 0x2098, 0xa860, 0x20e8, 0xa85c, + 0x9080, 0x0029, 0x20a0, 0x2011, 0xc7a4, 0x2041, 0x0001, 0x223d, + 0x9784, 0x00ff, 0x9322, 0x1208, 0x2300, 0x20a8, 0x4003, 0x931a, + 0x0530, 0x8210, 0xd7fc, 0x1130, 0x8d68, 0x2d0a, 0x2001, 0x0260, + 0x2098, 0x0c68, 0x2950, 0x080c, 0x0fee, 0x0170, 0x2900, 0xb002, + 0xa867, 0x0147, 0xa86b, 0x0000, 0xa860, 0x20e8, 0xa85c, 0x9080, + 0x001b, 0x20a0, 0x8840, 0x08d8, 0x2548, 0xa800, 0x902d, 0x0118, + 0x080c, 0x1007, 0x0cc8, 0x080c, 0x1007, 0x0804, 0xc6c6, 0x2548, + 0x8847, 0x9885, 0x0046, 0xa866, 0x2009, 0x0205, 0x200b, 0x0000, + 0x080c, 0xcf91, 0x0804, 0xc6ba, 0x8010, 0x0004, 0x801a, 0x0006, + 0x8018, 0x0008, 0x8016, 0x000a, 0x8014, 0x9186, 0x0013, 0x1160, + 0x6004, 0x908a, 0x0054, 0x1a0c, 0x0db2, 0x9082, 0x0040, 0x0a0c, + 0x0db2, 0x2008, 0x0804, 0xc855, 0x9186, 0x0051, 0x0108, 0x00c0, + 0x2001, 0x0109, 0x2004, 0xd084, 0x0904, 0xc806, 0x0126, 0x2091, + 0x2800, 0x0006, 0x0016, 0x0026, 0x080c, 0x7eec, 0x002e, 0x001e, + 0x000e, 0x012e, 0x6000, 0x9086, 0x0002, 0x1580, 0x0804, 0xc89d, + 0x9186, 0x0027, 0x0530, 0x9186, 0x0048, 0x0128, 0x9186, 0x0014, + 0x0500, 0x190c, 0x0db2, 0x2001, 0x0109, 0x2004, 0xd084, 0x01f0, + 0x00c6, 0x0126, 0x2091, 0x2800, 0x00c6, 0x2061, 0x0100, 0x0006, + 0x0016, 0x0026, 0x080c, 0x7eec, 0x002e, 0x001e, 0x000e, 0x00ce, + 0x012e, 0x00ce, 0x6000, 0x9086, 0x0004, 0x190c, 0x0db2, 0x0804, + 0xc97e, 0x6004, 0x9082, 0x0040, 0x2008, 0x001a, 0x080c, 0x9a6b, + 0x0005, 0xc81c, 0xc81e, 0xc81e, 0xc845, 0xc81c, 0xc81c, 0xc81c, + 0xc81c, 0xc81c, 0xc81c, 0xc81c, 0xc81c, 0xc81c, 0xc81c, 0xc81c, + 0xc81c, 0xc81c, 0xc81c, 0xc81c, 0x080c, 0x0db2, 0x080c, 0x847d, + 0x080c, 0x8582, 0x0036, 0x0096, 0x6014, 0x904d, 0x01d8, 0x080c, + 0xb5fb, 0x01c0, 0x6003, 0x0002, 0x6010, 0x00b6, 0x2058, 0xb800, + 0x00be, 0xd0bc, 0x1178, 0x2019, 0x0004, 0x080c, 0xcf91, 0x6017, + 0x0000, 0x6018, 0x9005, 0x1120, 0x2001, 0x1956, 0x2004, 0x601a, + 0x6003, 0x0007, 0x009e, 0x003e, 0x0005, 0x0096, 0x080c, 0x847d, + 0x080c, 0x8582, 0x080c, 0xb5fb, 0x0120, 0x6014, 0x2048, 0x080c, + 0x1007, 0x080c, 0x9a06, 0x009e, 0x0005, 0x0002, 0xc869, 0xc880, + 0xc86b, 0xc897, 0xc869, 0xc869, 0xc869, 0xc869, 0xc869, 0xc869, + 0xc869, 0xc869, 0xc869, 0xc869, 0xc869, 0xc869, 0xc869, 0xc869, + 0xc869, 0x080c, 0x0db2, 0x0096, 0x080c, 0x847d, 0x6014, 0x2048, + 0xa87c, 0xd0b4, 0x0138, 0x6003, 0x0007, 0x2009, 0x0043, 0x080c, + 0x9a50, 0x0010, 0x6003, 0x0004, 0x080c, 0x8582, 0x009e, 0x0005, + 0x080c, 0x847d, 0x080c, 0xb5fb, 0x0138, 0x6114, 0x0096, 0x2148, + 0xa97c, 0x009e, 0xd1ec, 0x1138, 0x080c, 0x7e13, 0x080c, 0x99d6, + 0x080c, 0x8582, 0x0005, 0x080c, 0xd1e8, 0x0db0, 0x0cc8, 0x080c, + 0x847d, 0x2009, 0x0041, 0x0804, 0xca06, 0x9182, 0x0040, 0x0002, + 0xc8b3, 0xc8b5, 0xc8b3, 0xc8b3, 0xc8b3, 0xc8b3, 0xc8b3, 0xc8b3, + 0xc8b3, 0xc8b3, 0xc8b3, 0xc8b3, 0xc8b3, 0xc8b3, 0xc8b3, 0xc8b3, + 0xc8b3, 0xc8b6, 0xc8b3, 0x080c, 0x0db2, 0x0005, 0x00d6, 0x080c, + 0x7e13, 0x00de, 0x080c, 0xd240, 0x080c, 0x99d6, 0x0005, 0x9182, + 0x0040, 0x0002, 0xc8d5, 0xc8d5, 0xc8d5, 0xc8d5, 0xc8d5, 0xc8d5, + 0xc8d5, 0xc8d5, 0xc8d5, 0xc8d7, 0xc946, 0xc8d5, 0xc8d5, 0xc8d5, + 0xc8d5, 0xc946, 0xc8d5, 0xc8d5, 0xc8d5, 0x080c, 0x0db2, 0x2001, + 0x0105, 0x2004, 0x9084, 0x1800, 0x01c8, 0x2001, 0x0132, 0x200c, + 0x2001, 0x0131, 0x2004, 0x9105, 0x1904, 0xc946, 0x2009, 0x180c, + 0x2104, 0xd0d4, 0x0904, 0xc946, 0xc0d4, 0x200a, 0x2009, 0x0105, + 0x2104, 0x9084, 0xe7fd, 0x9085, 0x0010, 0x200a, 0x2001, 0x1873, + 0x2004, 0xd0e4, 0x1528, 0x603b, 0x0000, 0x080c, 0x8532, 0x6014, + 0x0096, 0x2048, 0xa87c, 0xd0fc, 0x0188, 0x908c, 0x0003, 0x918e, + 0x0002, 0x0508, 0x2001, 0x180c, 0x2004, 0xd0d4, 0x11e0, 0x080c, + 0x865d, 0x2009, 0x0041, 0x009e, 0x0804, 0xca06, 0x080c, 0x865d, + 0x6003, 0x0007, 0x601b, 0x0000, 0x080c, 0x7e13, 0x009e, 0x0005, + 0x2001, 0x0100, 0x2004, 0x9082, 0x0005, 0x0aa8, 0x2001, 0x011f, + 0x2004, 0x603a, 0x0890, 0x2001, 0x180c, 0x200c, 0xc1d4, 0x2102, + 0xd1cc, 0x0110, 0x080c, 0x28ea, 0x080c, 0x865d, 0x6014, 0x2048, + 0xa97c, 0xd1ec, 0x1130, 0x080c, 0x7e13, 0x080c, 0x99d6, 0x009e, + 0x0005, 0x080c, 0xd1e8, 0x0db8, 0x009e, 0x0005, 0x2001, 0x180c, + 0x200c, 0xc1d4, 0x2102, 0x0036, 0x080c, 0x8532, 0x080c, 0x865d, + 0x6014, 0x0096, 0x2048, 0x6010, 0x00b6, 0x2058, 0xb800, 0x00be, + 0xd0bc, 0x0188, 0xa87c, 0x9084, 0x0003, 0x9086, 0x0002, 0x0140, + 0xa8ac, 0x6330, 0x931a, 0x6332, 0xa8b0, 0x632c, 0x931b, 0x632e, + 0x6003, 0x0002, 0x0080, 0x2019, 0x0004, 0x080c, 0xcf91, 0x6018, + 0x9005, 0x1128, 0x2001, 0x1956, 0x2004, 0x8003, 0x601a, 0x6017, + 0x0000, 0x6003, 0x0007, 0x009e, 0x003e, 0x0005, 0x9182, 0x0040, + 0x0002, 0xc995, 0xc995, 0xc995, 0xc995, 0xc995, 0xc995, 0xc995, + 0xc995, 0xc997, 0xc995, 0xc995, 0xc995, 0xc995, 0xc995, 0xc995, + 0xc995, 0xc995, 0xc995, 0xc995, 0xc9e2, 0x080c, 0x0db2, 0x6014, + 0x0096, 0x2048, 0xa834, 0xaa38, 0x6110, 0x00b6, 0x2058, 0xb900, + 0x00be, 0xd1bc, 0x1190, 0x920d, 0x1518, 0xa87c, 0xd0fc, 0x0128, + 0x2009, 0x0041, 0x009e, 0x0804, 0xca06, 0x6003, 0x0007, 0x601b, + 0x0000, 0x080c, 0x7e13, 0x009e, 0x0005, 0x6124, 0xd1f4, 0x1d58, + 0x0006, 0x0046, 0xacac, 0x9422, 0xa9b0, 0x2200, 0x910b, 0x6030, + 0x9420, 0x6432, 0x602c, 0x9109, 0x612e, 0x004e, 0x000e, 0x08d8, + 0x6110, 0x00b6, 0x2158, 0xb900, 0x00be, 0xd1bc, 0x1178, 0x2009, + 0x180d, 0x210c, 0xd19c, 0x0118, 0x6003, 0x0007, 0x0010, 0x6003, + 0x0006, 0x00e9, 0x080c, 0x7e15, 0x009e, 0x0005, 0x6003, 0x0002, + 0x009e, 0x0005, 0x6024, 0xd0f4, 0x0128, 0x080c, 0x14c9, 0x1904, + 0xc997, 0x0005, 0x6014, 0x0096, 0x2048, 0xa834, 0xa938, 0x009e, + 0x9105, 0x1120, 0x080c, 0x14c9, 0x1904, 0xc997, 0x0005, 0xd2fc, + 0x0140, 0x8002, 0x8000, 0x8212, 0x9291, 0x0000, 0x2009, 0x0009, + 0x0010, 0x2009, 0x0015, 0xaa9a, 0xa896, 0x0005, 0x9182, 0x0040, + 0x0208, 0x0062, 0x9186, 0x0013, 0x0120, 0x9186, 0x0014, 0x190c, + 0x0db2, 0x6024, 0xd0dc, 0x090c, 0x0db2, 0x0005, 0xca29, 0xca35, + 0xca41, 0xca4d, 0xca29, 0xca29, 0xca29, 0xca29, 0xca30, 0xca2b, + 0xca2b, 0xca29, 0xca29, 0xca29, 0xca29, 0xca2b, 0xca29, 0xca2b, + 0xca29, 0x080c, 0x0db2, 0x6024, 0xd0dc, 0x090c, 0x0db2, 0x0005, + 0x6014, 0x9005, 0x190c, 0x0db2, 0x0005, 0x6003, 0x0001, 0x6106, + 0x080c, 0x8000, 0x0126, 0x2091, 0x8000, 0x080c, 0x8582, 0x012e, + 0x0005, 0x6003, 0x0001, 0x6106, 0x080c, 0x8000, 0x0126, 0x2091, + 0x8000, 0x080c, 0x8582, 0x012e, 0x0005, 0x6003, 0x0003, 0x6106, + 0x2c10, 0x080c, 0x1976, 0x0126, 0x2091, 0x8000, 0x080c, 0x8065, + 0x080c, 0x865d, 0x012e, 0x0005, 0x0126, 0x2091, 0x8000, 0x0036, + 0x0096, 0x9182, 0x0040, 0x0023, 0x009e, 0x003e, 0x012e, 0x0005, + 0xca78, 0xca7a, 0xca8c, 0xcaa6, 0xca78, 0xca78, 0xca78, 0xca78, + 0xca78, 0xca78, 0xca78, 0xca78, 0xca78, 0xca78, 0xca78, 0xca78, + 0x080c, 0x0db2, 0x6014, 0x2048, 0xa87c, 0xd0fc, 0x01f8, 0x909c, + 0x0003, 0x939e, 0x0003, 0x01d0, 0x6003, 0x0001, 0x6106, 0x080c, + 0x8000, 0x080c, 0x8582, 0x0470, 0x6014, 0x2048, 0xa87c, 0xd0fc, + 0x0168, 0x909c, 0x0003, 0x939e, 0x0003, 0x0140, 0x6003, 0x0001, + 0x6106, 0x080c, 0x8000, 0x080c, 0x8582, 0x00e0, 0x901e, 0x6316, + 0x631a, 0x2019, 0x0004, 0x080c, 0xcf91, 0x00a0, 0x6014, 0x2048, + 0xa87c, 0xd0fc, 0x0d98, 0x909c, 0x0003, 0x939e, 0x0003, 0x0d70, + 0x6003, 0x0003, 0x6106, 0x2c10, 0x080c, 0x1976, 0x080c, 0x8065, + 0x080c, 0x865d, 0x0005, 0x080c, 0x847d, 0x6114, 0x81ff, 0x0158, + 0x0096, 0x2148, 0x080c, 0xd28c, 0x0036, 0x2019, 0x0029, 0x080c, + 0xcf91, 0x003e, 0x009e, 0x080c, 0x9a06, 0x080c, 0x8582, 0x0005, + 0x080c, 0x8532, 0x6114, 0x81ff, 0x0158, 0x0096, 0x2148, 0x080c, + 0xd28c, 0x0036, 0x2019, 0x0029, 0x080c, 0xcf91, 0x003e, 0x009e, + 0x080c, 0x9a06, 0x080c, 0x865d, 0x0005, 0x9182, 0x0085, 0x0002, + 0xcaf7, 0xcaf5, 0xcaf5, 0xcb03, 0xcaf5, 0xcaf5, 0xcaf5, 0xcaf5, + 0xcaf5, 0xcaf5, 0xcaf5, 0xcaf5, 0xcaf5, 0x080c, 0x0db2, 0x6003, + 0x000b, 0x6106, 0x080c, 0x8000, 0x0126, 0x2091, 0x8000, 0x080c, + 0x8582, 0x012e, 0x0005, 0x0026, 0x00e6, 0x080c, 0xd1df, 0x0118, + 0x080c, 0x99d6, 0x0450, 0x2071, 0x0260, 0x7224, 0x6216, 0x2001, + 0x180d, 0x2004, 0xd0e4, 0x0150, 0x6010, 0x00b6, 0x2058, 0xbca0, + 0x00be, 0x2c00, 0x2011, 0x014e, 0x080c, 0x9cf4, 0x7220, 0x080c, + 0xce37, 0x0118, 0x6007, 0x0086, 0x0040, 0x6007, 0x0087, 0x7224, + 0x9296, 0xffff, 0x1110, 0x6007, 0x0086, 0x6003, 0x0001, 0x080c, + 0x8000, 0x080c, 0x8582, 0x080c, 0x865d, 0x00ee, 0x002e, 0x0005, + 0x9186, 0x0013, 0x1160, 0x6004, 0x908a, 0x0085, 0x0a0c, 0x0db2, + 0x908a, 0x0092, 0x1a0c, 0x0db2, 0x9082, 0x0085, 0x00a2, 0x9186, + 0x0027, 0x0130, 0x9186, 0x0014, 0x0118, 0x080c, 0x9a6b, 0x0050, + 0x2001, 0x0007, 0x080c, 0x5efb, 0x080c, 0x847d, 0x080c, 0x9a06, + 0x080c, 0x8582, 0x0005, 0xcb68, 0xcb6a, 0xcb6a, 0xcb68, 0xcb68, + 0xcb68, 0xcb68, 0xcb68, 0xcb68, 0xcb68, 0xcb68, 0xcb68, 0xcb68, + 0x080c, 0x0db2, 0x080c, 0x847d, 0x080c, 0x9a06, 0x080c, 0x8582, + 0x0005, 0x9182, 0x0085, 0x0a0c, 0x0db2, 0x9182, 0x0092, 0x1a0c, + 0x0db2, 0x9182, 0x0085, 0x0002, 0xcb89, 0xcb89, 0xcb89, 0xcb8b, + 0xcb89, 0xcb89, 0xcb89, 0xcb89, 0xcb89, 0xcb89, 0xcb89, 0xcb89, + 0xcb89, 0x080c, 0x0db2, 0x0005, 0x9186, 0x0013, 0x0148, 0x9186, + 0x0014, 0x0130, 0x9186, 0x0027, 0x0118, 0x080c, 0x9a6b, 0x0030, + 0x080c, 0x847d, 0x080c, 0x9a06, 0x080c, 0x8582, 0x0005, 0x0036, + 0x080c, 0xd240, 0x6043, 0x0000, 0x2019, 0x000b, 0x0031, 0x6023, + 0x0006, 0x6003, 0x0007, 0x003e, 0x0005, 0x0126, 0x0036, 0x2091, + 0x8000, 0x0086, 0x2c40, 0x0096, 0x904e, 0x080c, 0x9349, 0x009e, + 0x008e, 0x1550, 0x0076, 0x2c38, 0x080c, 0x93f4, 0x007e, 0x1520, + 0x6000, 0x9086, 0x0000, 0x0500, 0x6020, 0x9086, 0x0007, 0x01e0, + 0x0096, 0x601c, 0xd084, 0x0140, 0x080c, 0xd240, 0x080c, 0xbd04, + 0x080c, 0x1827, 0x6023, 0x0007, 0x6014, 0x2048, 0x080c, 0xb5fb, + 0x0110, 0x080c, 0xcf91, 0x009e, 0x6017, 0x0000, 0x080c, 0xd240, + 0x6023, 0x0007, 0x080c, 0xbd04, 0x003e, 0x012e, 0x0005, 0x00f6, + 0x00c6, 0x00b6, 0x0036, 0x0156, 0x2079, 0x0260, 0x7938, 0x783c, + 0x080c, 0x24d6, 0x15b8, 0x0016, 0x00c6, 0x080c, 0x5f7e, 0x1580, + 0x001e, 0x00c6, 0x2160, 0x080c, 0xbd01, 0x00ce, 0x002e, 0x0026, + 0x0016, 0x2019, 0x0029, 0x080c, 0x94b5, 0x080c, 0x8180, 0x0076, + 0x903e, 0x080c, 0x8078, 0x007e, 0x001e, 0x0076, 0x903e, 0x080c, + 0xcd62, 0x007e, 0x0026, 0xba04, 0x9294, 0xff00, 0x8217, 0x9286, + 0x0006, 0x0118, 0x9286, 0x0004, 0x1118, 0xbaa0, 0x080c, 0x2eea, + 0x002e, 0x001e, 0x080c, 0x5a3b, 0xbe12, 0xbd16, 0x9006, 0x0010, + 0x00ce, 0x001e, 0x015e, 0x003e, 0x00be, 0x00ce, 0x00fe, 0x0005, + 0x00c6, 0x00d6, 0x00b6, 0x0016, 0x2009, 0x1822, 0x2104, 0x9086, + 0x0074, 0x1904, 0xcc89, 0x2069, 0x0260, 0x6944, 0x9182, 0x0100, + 0x06e0, 0x6940, 0x9184, 0x8000, 0x0904, 0xcc86, 0x2001, 0x194d, + 0x2004, 0x9005, 0x1140, 0x6010, 0x2058, 0xb8b0, 0x9005, 0x0118, + 0x9184, 0x0800, 0x0598, 0x6948, 0x918a, 0x0001, 0x0648, 0x080c, + 0xd2f4, 0x0118, 0x6978, 0xd1fc, 0x11b8, 0x2009, 0x0205, 0x200b, + 0x0001, 0x693c, 0x81ff, 0x1198, 0x6944, 0x9182, 0x0100, 0x02a8, + 0x6940, 0x81ff, 0x1178, 0x6948, 0x918a, 0x0001, 0x0288, 0x6950, + 0x918a, 0x0001, 0x0298, 0x00d0, 0x6017, 0x0100, 0x00a0, 0x6017, + 0x0300, 0x0088, 0x6017, 0x0500, 0x0070, 0x6017, 0x0700, 0x0058, + 0x6017, 0x0900, 0x0040, 0x6017, 0x0b00, 0x0028, 0x6017, 0x0f00, + 0x0010, 0x6017, 0x2d00, 0x9085, 0x0001, 0x0008, 0x9006, 0x001e, + 0x00be, 0x00de, 0x00ce, 0x0005, 0x00c6, 0x00b6, 0x0026, 0x0036, + 0x0156, 0x6210, 0x2258, 0xbb04, 0x9394, 0x00ff, 0x9286, 0x0006, + 0x0180, 0x9286, 0x0004, 0x0168, 0x9394, 0xff00, 0x8217, 0x9286, + 0x0006, 0x0138, 0x9286, 0x0004, 0x0120, 0x080c, 0x5f8d, 0x0804, + 0xccf1, 0x2011, 0x0276, 0x20a9, 0x0004, 0x0096, 0x2b48, 0x2019, + 0x000a, 0x080c, 0xa91d, 0x009e, 0x15a8, 0x2011, 0x027a, 0x20a9, + 0x0004, 0x0096, 0x2b48, 0x2019, 0x0006, 0x080c, 0xa91d, 0x009e, + 0x1548, 0x0046, 0x0016, 0xbaa0, 0x2220, 0x9006, 0x2009, 0x1854, + 0x210c, 0xd1a4, 0x0138, 0x2009, 0x0029, 0x080c, 0xcfe6, 0xb800, + 0xc0e5, 0xb802, 0x2019, 0x0029, 0x080c, 0x8180, 0x0076, 0x2039, + 0x0000, 0x080c, 0x8078, 0x2c08, 0x080c, 0xcd62, 0x007e, 0x2001, + 0x0007, 0x080c, 0x5efb, 0x2001, 0x0007, 0x080c, 0x5ecf, 0x001e, + 0x004e, 0x9006, 0x015e, 0x003e, 0x002e, 0x00be, 0x00ce, 0x0005, + 0x00d6, 0x2069, 0x026e, 0x6800, 0x9086, 0x0800, 0x0118, 0x6017, + 0x0000, 0x0008, 0x9006, 0x00de, 0x0005, 0x00b6, 0x00f6, 0x0016, + 0x0026, 0x0036, 0x0156, 0x2079, 0x026c, 0x7930, 0x7834, 0x080c, + 0x24d6, 0x11d0, 0x080c, 0x5f7e, 0x11b8, 0x2011, 0x0270, 0x20a9, + 0x0004, 0x0096, 0x2b48, 0x2019, 0x000a, 0x080c, 0xa91d, 0x009e, + 0x1158, 0x2011, 0x0274, 0x20a9, 0x0004, 0x0096, 0x2b48, 0x2019, + 0x0006, 0x080c, 0xa91d, 0x009e, 0x015e, 0x003e, 0x002e, 0x001e, + 0x00fe, 0x00be, 0x0005, 0x00b6, 0x0006, 0x0016, 0x0026, 0x0036, + 0x0156, 0x2011, 0x0263, 0x2204, 0x8211, 0x220c, 0x080c, 0x24d6, + 0x11d0, 0x080c, 0x5f7e, 0x11b8, 0x2011, 0x0276, 0x20a9, 0x0004, + 0x0096, 0x2b48, 0x2019, 0x000a, 0x080c, 0xa91d, 0x009e, 0x1158, + 0x2011, 0x027a, 0x20a9, 0x0004, 0x0096, 0x2b48, 0x2019, 0x0006, + 0x080c, 0xa91d, 0x009e, 0x015e, 0x003e, 0x002e, 0x001e, 0x000e, + 0x00be, 0x0005, 0x00e6, 0x00c6, 0x0086, 0x0076, 0x0066, 0x0056, + 0x0046, 0x0026, 0x0126, 0x2091, 0x8000, 0x2740, 0x2029, 0x19bf, + 0x252c, 0x2021, 0x19c5, 0x2424, 0x2061, 0x1cd0, 0x2071, 0x1800, + 0x764c, 0x706c, 0x81ff, 0x0150, 0x0006, 0x9186, 0x1a73, 0x000e, + 0x0128, 0x8001, 0x9602, 0x1a04, 0xcdf0, 0x0018, 0x9606, 0x0904, + 0xcdf0, 0x2100, 0x9c06, 0x0904, 0xcde7, 0x080c, 0xd022, 0x1904, + 0xcde7, 0x080c, 0xd311, 0x0904, 0xcde7, 0x080c, 0xd012, 0x0904, + 0xcde7, 0x6720, 0x9786, 0x0001, 0x1148, 0x080c, 0x2f81, 0x0904, + 0xce0b, 0x6004, 0x9086, 0x0000, 0x1904, 0xce0b, 0x9786, 0x0004, + 0x0904, 0xce0b, 0x9786, 0x0007, 0x05d0, 0x2500, 0x9c06, 0x05b8, + 0x2400, 0x9c06, 0x05a0, 0x88ff, 0x0118, 0x6054, 0x9906, 0x1578, + 0x0096, 0x6000, 0x9086, 0x0004, 0x1120, 0x0016, 0x080c, 0x1827, + 0x001e, 0x9786, 0x000a, 0x0148, 0x080c, 0xb7fa, 0x1130, 0x080c, + 0xa364, 0x009e, 0x080c, 0x9a06, 0x00d0, 0x6014, 0x2048, 0x080c, + 0xb5fb, 0x0190, 0x9786, 0x0003, 0x1528, 0xa867, 0x0103, 0xab7a, + 0xa877, 0x0000, 0x080c, 0xd28c, 0x0016, 0x080c, 0xb8e3, 0x080c, + 0x6529, 0x001e, 0x080c, 0xb7dd, 0x009e, 0x080c, 0x9a06, 0x9ce0, + 0x0018, 0x2001, 0x1818, 0x2004, 0x9c02, 0x1210, 0x0804, 0xcd76, + 0x012e, 0x002e, 0x004e, 0x005e, 0x006e, 0x007e, 0x008e, 0x00ce, + 0x00ee, 0x0005, 0x9786, 0x0006, 0x1150, 0x9386, 0x0005, 0x0128, + 0x080c, 0xd28c, 0x080c, 0xcf91, 0x08f8, 0x009e, 0x0c00, 0x9786, + 0x000a, 0x0968, 0x0850, 0x81ff, 0x09d0, 0x9180, 0x0001, 0x2004, + 0x9086, 0x0018, 0x0130, 0x9180, 0x0001, 0x2004, 0x9086, 0x002d, + 0x1970, 0x6000, 0x9086, 0x0002, 0x1950, 0x080c, 0xb7e9, 0x0130, + 0x080c, 0xb7fa, 0x1920, 0x080c, 0xa364, 0x0038, 0x080c, 0x2e55, + 0x080c, 0xb7fa, 0x1110, 0x080c, 0xa364, 0x080c, 0x9a06, 0x0804, + 0xcde7, 0xa864, 0x9084, 0x00ff, 0x9086, 0x0039, 0x0005, 0x00c6, + 0x00e6, 0x0016, 0x2c08, 0x2170, 0x9006, 0x080c, 0xcfb8, 0x001e, + 0x0120, 0x6020, 0x9084, 0x000f, 0x001b, 0x00ee, 0x00ce, 0x0005, + 0xce56, 0xce56, 0xce56, 0xce56, 0xce56, 0xce56, 0xce58, 0xce56, + 0xce56, 0xce56, 0xce56, 0x9a06, 0x9a06, 0xce56, 0x9006, 0x0005, + 0x0036, 0x0046, 0x0016, 0x7010, 0x00b6, 0x2058, 0xbca0, 0x00be, + 0x2c00, 0x2009, 0x0020, 0x080c, 0xcfe6, 0x001e, 0x004e, 0x2019, + 0x0002, 0x080c, 0xcbad, 0x003e, 0x9085, 0x0001, 0x0005, 0x0096, + 0x080c, 0xb5fb, 0x0140, 0x6014, 0x904d, 0x080c, 0xb251, 0x687b, + 0x0005, 0x080c, 0x6536, 0x009e, 0x080c, 0x9a06, 0x9085, 0x0001, + 0x0005, 0x2001, 0x0001, 0x080c, 0x5ebb, 0x0156, 0x0016, 0x0026, + 0x0036, 0x20a9, 0x0004, 0x2019, 0x1805, 0x2011, 0x0276, 0x080c, + 0xa909, 0x003e, 0x002e, 0x001e, 0x015e, 0x9005, 0x0005, 0x00f6, + 0x00e6, 0x00c6, 0x0086, 0x0076, 0x0066, 0x00b6, 0x0126, 0x2091, + 0x8000, 0x2740, 0x2061, 0x1cd0, 0x2079, 0x0001, 0x8fff, 0x0904, + 0xcef1, 0x2071, 0x1800, 0x764c, 0x706c, 0x8001, 0x9602, 0x1a04, + 0xcef1, 0x88ff, 0x0120, 0x2800, 0x9c06, 0x1590, 0x2078, 0x080c, + 0xd012, 0x0570, 0x2400, 0x9c06, 0x0558, 0x6720, 0x9786, 0x0006, + 0x1538, 0x9786, 0x0007, 0x0520, 0x88ff, 0x1140, 0x6010, 0x9b06, + 0x11f8, 0x85ff, 0x0118, 0x6054, 0x9106, 0x11d0, 0x0096, 0x601c, + 0xd084, 0x0140, 0x080c, 0xd240, 0x080c, 0xbd04, 0x080c, 0x1827, + 0x6023, 0x0007, 0x6014, 0x2048, 0x080c, 0xb5fb, 0x0120, 0x0046, + 0x080c, 0xcf91, 0x004e, 0x009e, 0x080c, 0x9a06, 0x88ff, 0x1198, + 0x9ce0, 0x0018, 0x2001, 0x1818, 0x2004, 0x9c02, 0x1210, 0x0804, + 0xcea6, 0x9006, 0x012e, 0x00be, 0x006e, 0x007e, 0x008e, 0x00ce, + 0x00ee, 0x00fe, 0x0005, 0x98c5, 0x0001, 0x0ca0, 0x00b6, 0x0076, + 0x0056, 0x0086, 0x9046, 0x2029, 0x0001, 0x2c20, 0x2019, 0x0002, + 0x6210, 0x2258, 0x0096, 0x904e, 0x080c, 0x9349, 0x009e, 0x008e, + 0x903e, 0x080c, 0x93f4, 0x080c, 0xce97, 0x005e, 0x007e, 0x00be, + 0x0005, 0x00b6, 0x0046, 0x0056, 0x0076, 0x00c6, 0x0156, 0x2c20, + 0x2128, 0x20a9, 0x007f, 0x900e, 0x0016, 0x0036, 0x080c, 0x5f7e, + 0x1190, 0x0056, 0x0086, 0x9046, 0x2508, 0x2029, 0x0001, 0x0096, + 0x904e, 0x080c, 0x9349, 0x009e, 0x008e, 0x903e, 0x080c, 0x93f4, + 0x080c, 0xce97, 0x005e, 0x003e, 0x001e, 0x8108, 0x1f04, 0xcf24, + 0x015e, 0x00ce, 0x007e, 0x005e, 0x004e, 0x00be, 0x0005, 0x00b6, + 0x0076, 0x0056, 0x6210, 0x2258, 0x0086, 0x9046, 0x2029, 0x0001, + 0x2019, 0x0048, 0x0096, 0x904e, 0x080c, 0x9349, 0x009e, 0x008e, + 0x903e, 0x080c, 0x93f4, 0x2c20, 0x080c, 0xce97, 0x005e, 0x007e, + 0x00be, 0x0005, 0x00b6, 0x0046, 0x0056, 0x0076, 0x00c6, 0x0156, + 0x2c20, 0x20a9, 0x0800, 0x900e, 0x0016, 0x0036, 0x080c, 0x5f7e, + 0x11a0, 0x0086, 0x9046, 0x2828, 0x0046, 0x2021, 0x0001, 0x080c, + 0xd224, 0x004e, 0x0096, 0x904e, 0x080c, 0x9349, 0x009e, 0x008e, + 0x903e, 0x080c, 0x93f4, 0x080c, 0xce97, 0x003e, 0x001e, 0x8108, + 0x1f04, 0xcf6c, 0x015e, 0x00ce, 0x007e, 0x005e, 0x004e, 0x00be, + 0x0005, 0x0016, 0x00f6, 0x080c, 0xb5f9, 0x0198, 0xa864, 0x9084, + 0x00ff, 0x9086, 0x0046, 0x0180, 0xa800, 0x907d, 0x0138, 0xa803, + 0x0000, 0xab82, 0x080c, 0x6536, 0x2f48, 0x0cb0, 0xab82, 0x080c, + 0x6536, 0x00fe, 0x001e, 0x0005, 0xa800, 0x907d, 0x0130, 0xa803, + 0x0000, 0x080c, 0x6536, 0x2f48, 0x0cb8, 0x080c, 0x6536, 0x0c88, + 0x00e6, 0x0046, 0x0036, 0x2061, 0x1cd0, 0x9005, 0x1138, 0x2071, + 0x1800, 0x744c, 0x706c, 0x8001, 0x9402, 0x12d8, 0x2100, 0x9c06, + 0x0168, 0x6000, 0x9086, 0x0000, 0x0148, 0x6008, 0x9206, 0x1130, + 0x6010, 0x91a0, 0x0004, 0x2424, 0x9406, 0x0140, 0x9ce0, 0x0018, + 0x2001, 0x1818, 0x2004, 0x9c02, 0x1220, 0x0c40, 0x9085, 0x0001, + 0x0008, 0x9006, 0x003e, 0x004e, 0x00ee, 0x0005, 0x0096, 0x0006, + 0x080c, 0x0fd5, 0x000e, 0x090c, 0x0db2, 0xa867, 0x010d, 0xa88e, + 0x0026, 0x2010, 0x080c, 0xb5e9, 0x2001, 0x0000, 0x0120, 0x2200, + 0x9080, 0x0015, 0x2004, 0x002e, 0xa87a, 0xa986, 0xac76, 0xa87f, + 0x0000, 0x2001, 0x195d, 0x2004, 0xa882, 0x9006, 0xa8e2, 0xa802, + 0xa86a, 0xa88a, 0x0126, 0x2091, 0x8000, 0x080c, 0x6536, 0x012e, + 0x009e, 0x0005, 0x6700, 0x9786, 0x0000, 0x0158, 0x9786, 0x0001, + 0x0140, 0x9786, 0x000a, 0x0128, 0x9786, 0x0009, 0x0110, 0x9085, + 0x0001, 0x0005, 0x00e6, 0x6010, 0x9075, 0x0138, 0x00b6, 0x2058, + 0xb8a0, 0x00be, 0x9206, 0x00ee, 0x0005, 0x9085, 0x0001, 0x0cd8, + 0x0016, 0x6004, 0x908e, 0x001e, 0x11a0, 0x8007, 0x6134, 0x918c, + 0x00ff, 0x9105, 0x6036, 0x6007, 0x0085, 0x6003, 0x000b, 0x6023, + 0x0005, 0x2001, 0x1956, 0x2004, 0x601a, 0x080c, 0x8000, 0x080c, + 0x8582, 0x001e, 0x0005, 0xa001, 0xa001, 0x0005, 0x6024, 0xd0e4, + 0x0158, 0xd0cc, 0x0118, 0x080c, 0xb927, 0x0030, 0x080c, 0xd240, + 0x080c, 0x7e13, 0x080c, 0x99d6, 0x0005, 0x9280, 0x0008, 0x2004, + 0x9084, 0x000f, 0x0002, 0xd071, 0xd071, 0xd071, 0xd073, 0xd071, + 0xd073, 0xd073, 0xd071, 0xd073, 0xd071, 0xd071, 0xd071, 0xd071, + 0xd071, 0x9006, 0x0005, 0x9085, 0x0001, 0x0005, 0x9280, 0x0008, + 0x2004, 0x9084, 0x000f, 0x0002, 0xd08a, 0xd08a, 0xd08a, 0xd08a, + 0xd08a, 0xd08a, 0xd097, 0xd08a, 0xd08a, 0xd08a, 0xd08a, 0xd08a, + 0xd08a, 0xd08a, 0x6007, 0x003b, 0x602f, 0x0009, 0x6017, 0x2a00, + 0x6003, 0x0001, 0x080c, 0x8000, 0x080c, 0x8582, 0x0005, 0x0096, + 0x00c6, 0x2260, 0x080c, 0xd240, 0x6043, 0x0000, 0x6024, 0xc0f4, + 0xc0e4, 0x6026, 0x603b, 0x0000, 0x00ce, 0x00d6, 0x2268, 0x9186, + 0x0007, 0x1904, 0xd0f1, 0x6814, 0x9005, 0x0138, 0x2048, 0xa87c, + 0xd0fc, 0x1118, 0x00de, 0x009e, 0x08a8, 0x6007, 0x003a, 0x6003, + 0x0001, 0x080c, 0x8000, 0x080c, 0x8582, 0x00c6, 0x2d60, 0x6100, + 0x9186, 0x0002, 0x1904, 0xd169, 0x6014, 0x9005, 0x1138, 0x6000, + 0x9086, 0x0007, 0x190c, 0x0db2, 0x0804, 0xd169, 0x2048, 0x080c, + 0xb5fb, 0x1130, 0x0028, 0x2048, 0xa800, 0x9005, 0x1de0, 0x2900, + 0x2048, 0xa87c, 0x9084, 0x0003, 0x9086, 0x0002, 0x1170, 0xa87c, + 0xc0dc, 0xc0f4, 0xa87e, 0xa880, 0xc0f4, 0xc0fc, 0xa882, 0x2009, + 0x0043, 0x080c, 0xca06, 0x0804, 0xd169, 0x2009, 0x0041, 0x0804, + 0xd163, 0x9186, 0x0005, 0x15a8, 0x6814, 0x2048, 0xa87c, 0xd0bc, + 0x1120, 0x00de, 0x009e, 0x0804, 0xd08a, 0xd0b4, 0x0128, 0xd0fc, + 0x090c, 0x0db2, 0x0804, 0xd0ab, 0x6007, 0x003a, 0x6003, 0x0001, + 0x080c, 0x8000, 0x080c, 0x8582, 0x00c6, 0x2d60, 0x6100, 0x9186, + 0x0002, 0x0120, 0x9186, 0x0004, 0x1904, 0xd169, 0x6814, 0x2048, + 0xa97c, 0xc1f4, 0xc1dc, 0xa97e, 0xa980, 0xc1f4, 0xc1fc, 0xc1bc, + 0xa982, 0x00f6, 0x2c78, 0x080c, 0x1582, 0x00fe, 0x2009, 0x0042, + 0x04d0, 0x0036, 0x080c, 0x0fd5, 0x090c, 0x0db2, 0xa867, 0x010d, + 0x9006, 0xa802, 0xa86a, 0xa88a, 0x2d18, 0xab8e, 0xa887, 0x0045, + 0x2c00, 0xa892, 0x6038, 0xa8a2, 0x2360, 0x6024, 0xc0dd, 0x6026, + 0x6010, 0x00b6, 0x2058, 0xb8a0, 0x00be, 0x2004, 0x6354, 0xab7a, + 0xa876, 0x9006, 0xa87e, 0xa882, 0xad9a, 0xae96, 0xa89f, 0x0001, + 0x080c, 0x6536, 0x2019, 0x0045, 0x6008, 0x2068, 0x080c, 0xcbad, + 0x2d00, 0x600a, 0x6023, 0x0006, 0x6003, 0x0007, 0x901e, 0x631a, + 0x6342, 0x003e, 0x0038, 0x6043, 0x0000, 0x6003, 0x0007, 0x080c, + 0xca06, 0x00ce, 0x00de, 0x009e, 0x0005, 0x9186, 0x0013, 0x1128, + 0x6004, 0x9082, 0x0085, 0x2008, 0x00c2, 0x9186, 0x0027, 0x1178, + 0x080c, 0x847d, 0x0036, 0x0096, 0x6014, 0x2048, 0x2019, 0x0004, + 0x080c, 0xcf91, 0x009e, 0x003e, 0x080c, 0x8582, 0x0005, 0x9186, + 0x0014, 0x0d70, 0x080c, 0x9a6b, 0x0005, 0xd19c, 0xd19a, 0xd19a, + 0xd19a, 0xd19a, 0xd19a, 0xd19c, 0xd19a, 0xd19a, 0xd19a, 0xd19a, + 0xd19a, 0xd19a, 0x080c, 0x0db2, 0x080c, 0x847d, 0x6003, 0x000c, + 0x080c, 0x8582, 0x0005, 0x9182, 0x0092, 0x1220, 0x9182, 0x0085, + 0x0208, 0x001a, 0x080c, 0x9a6b, 0x0005, 0xd1ba, 0xd1ba, 0xd1ba, + 0xd1ba, 0xd1bc, 0xd1dc, 0xd1ba, 0xd1ba, 0xd1ba, 0xd1ba, 0xd1ba, + 0xd1ba, 0xd1ba, 0x080c, 0x0db2, 0x00d6, 0x2c68, 0x080c, 0x9980, + 0x01b0, 0x6003, 0x0001, 0x6007, 0x001e, 0x2009, 0x026e, 0x210c, + 0x613a, 0x2009, 0x026f, 0x210c, 0x613e, 0x600b, 0xffff, 0x6910, + 0x6112, 0x6023, 0x0004, 0x080c, 0x8000, 0x080c, 0x8582, 0x2d60, + 0x080c, 0x99d6, 0x00de, 0x0005, 0x080c, 0x99d6, 0x0005, 0x00e6, + 0x6010, 0x00b6, 0x2058, 0xb800, 0x00be, 0xd0ec, 0x00ee, 0x0005, + 0x2009, 0x1873, 0x210c, 0xd1ec, 0x05b0, 0x6003, 0x0002, 0x6024, + 0xc0e5, 0x6026, 0xd0cc, 0x0150, 0x2001, 0x1957, 0x2004, 0x6042, + 0x2009, 0x1873, 0x210c, 0xd1f4, 0x1520, 0x00a0, 0x2009, 0x1873, + 0x210c, 0xd1f4, 0x0128, 0x6024, 0xc0e4, 0x6026, 0x9006, 0x00d8, + 0x2001, 0x1957, 0x200c, 0x2001, 0x1955, 0x2004, 0x9100, 0x9080, + 0x000a, 0x6042, 0x6010, 0x00b6, 0x2058, 0xb8ac, 0x00be, 0x0008, + 0x2104, 0x9005, 0x0118, 0x9088, 0x0003, 0x0cd0, 0x2c0a, 0x600f, + 0x0000, 0x9085, 0x0001, 0x0005, 0x0016, 0x00c6, 0x00e6, 0x6154, + 0xb8ac, 0x2060, 0x8cff, 0x0180, 0x84ff, 0x1118, 0x6054, 0x9106, + 0x1138, 0x600c, 0x2072, 0x080c, 0x7e13, 0x080c, 0x99d6, 0x0010, + 0x9cf0, 0x0003, 0x2e64, 0x0c70, 0x00ee, 0x00ce, 0x001e, 0x0005, + 0x00d6, 0x00b6, 0x6010, 0x2058, 0xb8ac, 0x2068, 0x9005, 0x0130, + 0x9c06, 0x0110, 0x680c, 0x0cd0, 0x600c, 0x680e, 0x00be, 0x00de, + 0x0005, 0x0026, 0x0036, 0x0156, 0x2011, 0x182a, 0x2204, 0x9084, + 0x00ff, 0x2019, 0x026e, 0x2334, 0x9636, 0x1508, 0x8318, 0x2334, + 0x2204, 0x9084, 0xff00, 0x9636, 0x11d0, 0x2011, 0x0270, 0x20a9, + 0x0004, 0x6010, 0x0096, 0x2048, 0x2019, 0x000a, 0x080c, 0xa91d, + 0x009e, 0x1168, 0x2011, 0x0274, 0x20a9, 0x0004, 0x6010, 0x0096, + 0x2048, 0x2019, 0x0006, 0x080c, 0xa91d, 0x009e, 0x1100, 0x015e, + 0x003e, 0x002e, 0x0005, 0x00e6, 0x2071, 0x1800, 0x080c, 0x59b4, + 0x080c, 0x2c2b, 0x00ee, 0x0005, 0x00e6, 0x6010, 0x00b6, 0x2058, + 0xb800, 0x00be, 0xd0fc, 0x0108, 0x0011, 0x00ee, 0x0005, 0xa880, + 0xc0e5, 0xa882, 0x0005, 0x00e6, 0x00d6, 0x00c6, 0x0076, 0x0066, + 0x0056, 0x0046, 0x0026, 0x0016, 0x0126, 0x2091, 0x8000, 0x2029, + 0x19bf, 0x252c, 0x2021, 0x19c5, 0x2424, 0x2061, 0x1cd0, 0x2071, + 0x1800, 0x764c, 0x706c, 0x9606, 0x0578, 0x6720, 0x9786, 0x0001, + 0x0118, 0x9786, 0x0008, 0x1500, 0x2500, 0x9c06, 0x01e8, 0x2400, + 0x9c06, 0x01d0, 0x080c, 0xd012, 0x01b8, 0x080c, 0xd022, 0x11a0, + 0x6000, 0x9086, 0x0004, 0x1120, 0x0016, 0x080c, 0x1827, 0x001e, + 0x080c, 0xb7e9, 0x1110, 0x080c, 0x2e55, 0x080c, 0xb7fa, 0x1110, + 0x080c, 0xa364, 0x080c, 0x9a06, 0x9ce0, 0x0018, 0x2001, 0x1818, + 0x2004, 0x9c02, 0x1208, 0x0858, 0x012e, 0x001e, 0x002e, 0x004e, + 0x005e, 0x006e, 0x007e, 0x00ce, 0x00de, 0x00ee, 0x0005, 0x2001, + 0x180f, 0x2004, 0xd0dc, 0x0005, 0x0006, 0x2001, 0x1835, 0x2004, + 0xd09c, 0x000e, 0x0005, 0x0006, 0x0036, 0x0046, 0x080c, 0xbcec, + 0x0168, 0x2019, 0xffff, 0x9005, 0x0128, 0x6010, 0x00b6, 0x2058, + 0xbba0, 0x00be, 0x2021, 0x0004, 0x080c, 0x4829, 0x004e, 0x003e, + 0x000e, 0x6004, 0x9086, 0x0001, 0x1128, 0x080c, 0x94b5, 0x080c, + 0x9a06, 0x9006, 0x0005, 0x0126, 0x0006, 0x00e6, 0x0016, 0x2091, + 0x8000, 0x2071, 0x1840, 0xd5a4, 0x0118, 0x7034, 0x8000, 0x7036, + 0xd5b4, 0x0118, 0x7030, 0x8000, 0x7032, 0xd5ac, 0x0178, 0x2500, + 0x9084, 0x0007, 0x908e, 0x0003, 0x0148, 0x908e, 0x0004, 0x0130, + 0x908e, 0x0005, 0x0118, 0x2071, 0x184a, 0x0089, 0x001e, 0x00ee, + 0x000e, 0x012e, 0x0005, 0x0126, 0x0006, 0x00e6, 0x2091, 0x8000, + 0x2071, 0x1842, 0x0021, 0x00ee, 0x000e, 0x012e, 0x0005, 0x2e04, + 0x8000, 0x2072, 0x1220, 0x8e70, 0x2e04, 0x8000, 0x2072, 0x0005, + 0x00e6, 0x2071, 0x1840, 0x0c99, 0x00ee, 0x0005, 0x00e6, 0x2071, + 0x1844, 0x0c69, 0x00ee, 0x0005, 0x0126, 0x0006, 0x00e6, 0x2091, + 0x8000, 0x2071, 0x1840, 0x7044, 0x8000, 0x7046, 0x00ee, 0x000e, + 0x012e, 0x0005, 0x0002, 0x0003, 0x03d8, 0x0000, 0x8064, 0x0008, + 0x0010, 0x0000, 0x8066, 0x0000, 0x0101, 0x0008, 0x4406, 0x000b, + 0x8060, 0x0000, 0x0400, 0x0000, 0x580c, 0x0003, 0x7933, 0x0003, + 0x5090, 0x000b, 0x4c09, 0x0003, 0xbac0, 0x0009, 0x008a, 0x0000, + 0x0c09, 0x000b, 0x15fe, 0x0008, 0x3409, 0x0003, 0x808c, 0x0008, + 0x0001, 0x0000, 0x0000, 0x0007, 0x4047, 0x000a, 0x808c, 0x0008, + 0x0002, 0x0000, 0x081b, 0x0003, 0x4022, 0x0000, 0x001c, 0x0003, + 0x4122, 0x0008, 0x4447, 0x0002, 0x0de8, 0x0003, 0x0bfe, 0x0008, + 0x11a0, 0x0001, 0x11ca, 0x000b, 0x0ca0, 0x0001, 0x11ca, 0x000b, + 0x9180, 0x0001, 0x0004, 0x0000, 0x8060, 0x0000, 0x0400, 0x0000, + 0x7f62, 0x0008, 0x8066, 0x0000, 0x0009, 0x0008, 0x442a, 0x0003, + 0x808c, 0x0008, 0x0000, 0x0008, 0x0060, 0x0008, 0x8062, 0x0008, + 0x0004, 0x0000, 0x8066, 0x0000, 0x0411, 0x0000, 0x4432, 0x0003, + 0x03fe, 0x0000, 0x43e0, 0x0001, 0x0dc7, 0x000b, 0xc2c0, 0x0009, + 0x00ff, 0x0008, 0x02e0, 0x0001, 0x0dc7, 0x000b, 0x9180, 0x0001, + 0x0005, 0x0008, 0x8060, 0x0000, 0x0400, 0x0000, 0x7f62, 0x0008, + 0x8066, 0x0000, 0x0019, 0x0000, 0x4441, 0x000b, 0x0240, 0x0002, + 0x09c4, 0x0003, 0x00fe, 0x0000, 0x31c7, 0x000b, 0x112a, 0x0000, + 0x002e, 0x0008, 0x022c, 0x0008, 0x3a44, 0x0002, 0x0c09, 0x000b, + 0x808c, 0x0008, 0x0002, 0x0000, 0x1760, 0x0008, 0x8062, 0x0008, + 0x000f, 0x0008, 0x8066, 0x0000, 0x0011, 0x0008, 0x4452, 0x0003, + 0x01fe, 0x0008, 0x42e0, 0x0009, 0x0dba, 0x000b, 0x00fe, 0x0000, + 0x43e0, 0x0001, 0x0dba, 0x000b, 0x1734, 0x0000, 0x1530, 0x0000, + 0x1632, 0x0008, 0x0d2a, 0x0008, 0x9880, 0x0001, 0x0010, 0x0000, + 0x8060, 0x0000, 0x0400, 0x0000, 0x7f62, 0x0008, 0x8066, 0x0000, + 0x1e0a, 0x0008, 0x4464, 0x0003, 0x808a, 0x0008, 0x0003, 0x0008, + 0x1a60, 0x0000, 0x8062, 0x0008, 0x0002, 0x0000, 0x586a, 0x0003, + 0x8066, 0x0000, 0x3679, 0x0000, 0x446d, 0x0003, 0x586e, 0x000b, + 0x8054, 0x0008, 0x0011, 0x0008, 0x8074, 0x0000, 0x1010, 0x0008, + 0x1efe, 0x0000, 0x3009, 0x000b, 0x0077, 0x0004, 0x0009, 0x000b, + 0x1c60, 0x0000, 0x1b62, 0x0000, 0x8066, 0x0000, 0x0231, 0x0008, + 0x447b, 0x000b, 0x587c, 0x000b, 0x0140, 0x0008, 0x0242, 0x0000, + 0x1f43, 0x0002, 0x0c86, 0x0003, 0x0d44, 0x0000, 0x0d46, 0x0008, + 0x0348, 0x0008, 0x044a, 0x0008, 0x008a, 0x0003, 0x0344, 0x0008, + 0x0446, 0x0008, 0x0548, 0x0008, 0x064a, 0x0000, 0x588a, 0x000b, + 0x8054, 0x0008, 0x0001, 0x0000, 0x8074, 0x0000, 0x2020, 0x0008, + 0x4000, 0x000f, 0x3a40, 0x000a, 0x0c0c, 0x000b, 0x2b24, 0x0008, + 0x2b24, 0x0008, 0x5894, 0x000b, 0x8054, 0x0008, 0x0002, 0x0000, + 0x1242, 0x0002, 0x08d8, 0x0003, 0x3a45, 0x000a, 0x08c9, 0x0003, + 0x1e10, 0x000a, 0x7f3c, 0x0000, 0x08c6, 0x0003, 0x1d00, 0x0002, + 0x7f3a, 0x0000, 0x0d60, 0x0000, 0x7f62, 0x0008, 0x8066, 0x0000, + 0x0009, 0x0008, 0x44a4, 0x0003, 0x00fe, 0x0000, 0x34c3, 0x0003, + 0x1c60, 0x0000, 0x8062, 0x0008, 0x0001, 0x0000, 0x8066, 0x0000, + 0x0009, 0x0008, 0x44ac, 0x000b, 0x00fe, 0x0000, 0x31a3, 0x0003, + 0x0038, 0x0000, 0x0060, 0x0008, 0x8062, 0x0008, 0x0019, 0x0000, + 0x8066, 0x0000, 0x0009, 0x0008, 0x44b5, 0x0003, 0x80c0, 0x0009, + 0x00ff, 0x0008, 0x7f3e, 0x0008, 0x0d60, 0x0000, 0x0efe, 0x0008, + 0x1f80, 0x0001, 0x7f62, 0x0008, 0x8066, 0x0000, 0x0009, 0x0008, + 0x44bf, 0x0003, 0x003a, 0x0008, 0x1dfe, 0x0000, 0x00a0, 0x000b, + 0x0036, 0x0008, 0x0077, 0x0004, 0x00d8, 0x000b, 0x8074, 0x0000, + 0x2000, 0x0000, 0x00d8, 0x000b, 0x3a44, 0x0002, 0x09cd, 0x0003, + 0x8074, 0x0000, 0x1000, 0x0000, 0x2d0e, 0x0000, 0x2d0e, 0x0000, + 0x35a3, 0x000b, 0x26fe, 0x0008, 0x26fe, 0x0008, 0x2700, 0x0008, + 0x2700, 0x0008, 0x00d0, 0x0009, 0x0ce6, 0x0003, 0x8074, 0x0000, + 0x4040, 0x0008, 0x58d8, 0x0003, 0x5090, 0x000b, 0x3a46, 0x000a, + 0x0ce6, 0x0003, 0x3a47, 0x0002, 0x08e3, 0x000b, 0x8054, 0x0008, + 0x0004, 0x0000, 0x8074, 0x0000, 0x8000, 0x0000, 0x0127, 0x0003, + 0x92c0, 0x0009, 0x0f88, 0x0008, 0x0809, 0x0003, 0x1a60, 0x0000, + 0x8062, 0x0008, 0x0002, 0x0000, 0x8066, 0x0000, 0x362a, 0x0000, + 0x44eb, 0x000b, 0x2000, 0x0000, 0x2000, 0x0000, 0x2102, 0x0000, + 0x2102, 0x0000, 0x2204, 0x0000, 0x2204, 0x0000, 0x2306, 0x0000, + 0x2306, 0x0000, 0x2408, 0x0000, 0x2408, 0x0000, 0x250a, 0x0000, + 0x250a, 0x0000, 0x260c, 0x0000, 0x260c, 0x0000, 0x270e, 0x0000, + 0x270e, 0x0000, 0x2810, 0x0000, 0x2810, 0x0000, 0x2912, 0x0000, + 0x2912, 0x0000, 0x1a60, 0x0000, 0x8062, 0x0008, 0x0007, 0x0000, + 0x8066, 0x0000, 0x0052, 0x0000, 0x4505, 0x0003, 0x92c0, 0x0009, + 0x0780, 0x0008, 0x0db4, 0x0003, 0x124b, 0x0002, 0x090e, 0x0003, + 0x2e4d, 0x0002, 0x2e4d, 0x0002, 0x09a3, 0x000b, 0x3a46, 0x000a, + 0x0d1b, 0x0003, 0x5910, 0x0003, 0x8054, 0x0008, 0x0004, 0x0000, + 0x1243, 0x000a, 0x0925, 0x0003, 0x8010, 0x0008, 0x000d, 0x0000, + 0x0194, 0x0004, 0x1810, 0x0000, 0x0194, 0x0004, 0x0125, 0x000b, + 0x194d, 0x000a, 0x091f, 0x0003, 0x1243, 0x000a, 0x09aa, 0x000b, + 0x591f, 0x0003, 0x8054, 0x0008, 0x0004, 0x0000, 0x0189, 0x0004, + 0x1810, 0x0000, 0x0194, 0x0004, 0x8074, 0x0000, 0xf000, 0x0008, + 0x0d30, 0x0000, 0x3a42, 0x0002, 0x0d2d, 0x0003, 0x15fe, 0x0008, + 0x344b, 0x0003, 0x0009, 0x000b, 0x8074, 0x0000, 0x0501, 0x0000, + 0x8010, 0x0008, 0x000c, 0x0008, 0x0194, 0x0004, 0x0009, 0x000b, + 0xbbe0, 0x0009, 0x0030, 0x0008, 0x0d43, 0x000b, 0x18fe, 0x0000, + 0x3ce0, 0x0009, 0x0940, 0x0003, 0x15fe, 0x0008, 0x3ce0, 0x0009, + 0x0940, 0x0003, 0x0184, 0x000c, 0x8076, 0x0008, 0x0040, 0x0000, + 0x0181, 0x0003, 0x8076, 0x0008, 0x0041, 0x0008, 0x0181, 0x0003, + 0xbbe0, 0x0009, 0x0032, 0x0000, 0x0d48, 0x0003, 0x3c1e, 0x0008, + 0x0181, 0x0003, 0xbbe0, 0x0009, 0x0037, 0x0000, 0x0d66, 0x0003, + 0x18fe, 0x0000, 0x3ce0, 0x0009, 0x0d40, 0x000b, 0x8076, 0x0008, + 0x0040, 0x0000, 0x1a60, 0x0000, 0x8062, 0x0008, 0x000d, 0x0000, + 0x2604, 0x0008, 0x2604, 0x0008, 0x2706, 0x0008, 0x2706, 0x0008, + 0x2808, 0x0000, 0x2808, 0x0000, 0x290a, 0x0000, 0x290a, 0x0000, + 0x8066, 0x0000, 0x0422, 0x0000, 0x455d, 0x000b, 0x0189, 0x0004, + 0x8054, 0x0008, 0x0004, 0x0000, 0x8074, 0x0000, 0xf000, 0x0008, + 0x8072, 0x0000, 0x8000, 0x0000, 0x0127, 0x0003, 0xbbe0, 0x0009, + 0x0038, 0x0000, 0x0d78, 0x0003, 0x18fe, 0x0000, 0x3ce0, 0x0009, + 0x0975, 0x0003, 0x15fe, 0x0008, 0x3ce0, 0x0009, 0x0d3c, 0x0003, + 0x0184, 0x000c, 0x8076, 0x0008, 0x0040, 0x0000, 0x8072, 0x0000, + 0x8000, 0x0000, 0x01c4, 0x000b, 0x8076, 0x0008, 0x0042, 0x0008, + 0x0181, 0x0003, 0xbbe0, 0x0009, 0x0016, 0x0000, 0x0d81, 0x0003, + 0x3a44, 0x0002, 0x0c0b, 0x0003, 0x8072, 0x0000, 0x8000, 0x0000, + 0x8000, 0x000f, 0x0009, 0x000b, 0x8072, 0x0000, 0x8000, 0x0000, + 0x0009, 0x000b, 0x3d30, 0x000a, 0x7f00, 0x0000, 0xbc80, 0x0001, + 0x0007, 0x0000, 0x018d, 0x0003, 0x1930, 0x000a, 0x7f00, 0x0000, + 0x9880, 0x0001, 0x0007, 0x0000, 0x8060, 0x0000, 0x0400, 0x0000, + 0x7f62, 0x0008, 0x8066, 0x0000, 0x000a, 0x0008, 0x4592, 0x000b, + 0x4000, 0x000f, 0x2194, 0x0003, 0x0870, 0x0008, 0x4000, 0x000f, + 0xbac0, 0x0009, 0x0090, 0x0008, 0x099d, 0x0003, 0x8074, 0x0000, + 0x0706, 0x0000, 0x019f, 0x0003, 0x8074, 0x0000, 0x0703, 0x0000, + 0x4000, 0x000f, 0x8010, 0x0008, 0x0008, 0x0000, 0x01d2, 0x0003, + 0x0189, 0x0004, 0x8010, 0x0008, 0x0007, 0x0000, 0x0194, 0x0004, + 0x1810, 0x0000, 0x0194, 0x0004, 0x01dc, 0x000b, 0x0189, 0x0004, + 0x8010, 0x0008, 0x001b, 0x0008, 0x0194, 0x0004, 0x1810, 0x0000, + 0x0194, 0x0004, 0x8074, 0x0000, 0xf080, 0x0000, 0x0d30, 0x0000, + 0x0009, 0x000b, 0x8010, 0x0008, 0x0009, 0x0008, 0x01d2, 0x0003, + 0x8010, 0x0008, 0x0005, 0x0008, 0x01d2, 0x0003, 0x808c, 0x0008, + 0x0001, 0x0000, 0x8010, 0x0008, 0x0004, 0x0000, 0x4143, 0x000a, + 0x0859, 0x0003, 0x3a44, 0x0002, 0x0c09, 0x000b, 0x0d2a, 0x0008, + 0x01d2, 0x0003, 0x8010, 0x0008, 0x0003, 0x0008, 0x01d4, 0x0003, + 0x8010, 0x0008, 0x000b, 0x0000, 0x01d4, 0x0003, 0x8010, 0x0008, + 0x0002, 0x0000, 0x01d4, 0x0003, 0x3a47, 0x0002, 0x0cd8, 0x000b, + 0x8010, 0x0008, 0x0006, 0x0008, 0x01d4, 0x0003, 0x8074, 0x0000, + 0xf000, 0x0008, 0x0194, 0x0004, 0x0197, 0x0004, 0x3a40, 0x000a, + 0x0809, 0x0003, 0x8010, 0x0008, 0x000c, 0x0008, 0x0194, 0x0004, + 0x0009, 0x000b, 0x8074, 0x0000, 0xf080, 0x0000, 0x0d30, 0x0000, + 0x2e4d, 0x0002, 0x2e4d, 0x0002, 0x09e5, 0x0003, 0x8054, 0x0008, + 0x0019, 0x0000, 0x0009, 0x000b, 0x8054, 0x0008, 0x0009, 0x0008, + 0x0009, 0x000b, 0x3a44, 0x0002, 0x0c09, 0x000b, 0x01c7, 0x000b, + 0x55d0, 0xf6d9, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, + 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, + 0x4000, 0x8000, 0xac74 +}; +#ifdef UNIQUE_FW_NAME +unsigned short fw2300tpx_length01 = 0xcf5b; +#else +unsigned short risc_code_length01 = 0xcf5b; +#endif + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qla_cfg.c 830-ivtv/drivers/scsi/qla2xxx/qla_cfg.c --- 000-virgin/drivers/scsi/qla2xxx/qla_cfg.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qla_cfg.c Thu Jan 8 10:22:00 2004 @@ -0,0 +1,3369 @@ +/****************************************************************************** + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + ******************************************************************************/ + +/* + * QLogic ISP2x00 Multi-path LUN Support Driver + * + */ + +#include "qla_os.h" +#include "qla_def.h" + +#include "qlfo.h" +#include "qlfolimits.h" + +/* + * Local Function Prototypes. + */ + +static uint32_t qla2x00_add_portname_to_mp_dev(mp_device_t *, uint8_t *); + +static mp_device_t * qla2x00_allocate_mp_dev(uint8_t *, uint8_t *); +static mp_path_t * qla2x00_allocate_path(mp_host_t *, uint16_t, fc_port_t *, + uint16_t); +static mp_path_list_t * qla2x00_allocate_path_list(void); + +static mp_host_t * qla2x00_find_host_by_name(uint8_t *); + +static mp_device_t * qla2x00_find_or_allocate_mp_dev (mp_host_t *, uint16_t, + fc_port_t *); +static mp_path_t * qla2x00_find_or_allocate_path(mp_host_t *, mp_device_t *, + uint16_t, uint16_t, fc_port_t *); + +static uint32_t qla2x00_cfg_register_failover_lun(mp_device_t *,srb_t *, + fc_lun_t *); +static uint32_t qla2x00_send_failover_notify(mp_device_t *, uint8_t, + mp_path_t *, mp_path_t *); +static mp_path_t * qla2x00_select_next_path(mp_host_t *, mp_device_t *, + uint8_t); + +static uint8_t qla2x00_update_mp_host(mp_host_t *); +static uint32_t qla2x00_update_mp_tree (void); + +static fc_lun_t *qla2x00_find_matching_lun(uint8_t , mp_path_t *); +static mp_path_t *qla2x00_find_path_by_id(mp_device_t *, uint8_t); +static mp_device_t *qla2x00_find_mp_dev_by_id(mp_host_t *, uint8_t); +static mp_device_t *qla2x00_find_mp_dev_by_nodename(mp_host_t *, uint8_t *); +static mp_device_t *qla2x00_find_mp_dev_by_portname(mp_host_t *, uint8_t *, + uint16_t *); +static mp_device_t *qla2x00_find_dp_by_pn_from_all_hosts(uint8_t *, uint16_t *); + +static mp_path_t *qla2x00_get_visible_path(mp_device_t *dp); +static void qla2x00_map_os_targets(mp_host_t *); +static void qla2x00_map_os_luns(mp_host_t *, mp_device_t *, uint16_t); +static uint8_t qla2x00_map_a_oslun(mp_host_t *, mp_device_t *, uint16_t, uint16_t); + +static uint8_t qla2x00_is_ww_name_zero(uint8_t *); +static void qla2x00_add_path(mp_path_list_t *, mp_path_t *); +static void qla2x00_failback_single_lun(mp_device_t *, uint8_t, uint8_t); +static void qla2x00_failback_luns(mp_host_t *); +static void qla2x00_setup_new_path(mp_device_t *, mp_path_t *); + +/* + * Global data items + */ +mp_host_t *mp_hosts_base = NULL; +uint8_t mp_config_required = FALSE; +static int mp_num_hosts = 0; +static uint8_t mp_initialized = FALSE; + + +/* + * ENTRY ROUTINES + */ + +/* + * qla2x00_cfg_init + * Initialize configuration structures to handle an instance of + * an HBA, QLA2x000 card. + * + * Input: + * ha = adapter state pointer. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_cfg_init(scsi_qla_host_t *ha) +{ + int rval; + + if (ConfigRequired > 0) + mp_config_required = 1; + else + mp_config_required = 0; + + ENTER("qla2x00_cfg_init"); + set_bit(CFG_ACTIVE, &ha->cfg_flags); + if (!mp_initialized) { + /* First HBA, initialize the failover global properties */ + qla2x00_fo_init_params(ha); + + /* If the user specified a device configuration then + * it is use as the configuration. Otherwise, we wait + * for path discovery. + */ + if ( mp_config_required ) + qla2x00_cfg_build_path_tree(ha); + } + rval = qla2x00_cfg_path_discovery(ha); + clear_bit(CFG_ACTIVE, &ha->cfg_flags); + LEAVE("qla2x00_cfg_init"); + return rval; +} + +/* + * qla2x00_cfg_path_discovery + * Discover the path configuration from the device configuration + * for the specified host adapter and build the path search tree. + * This function is called after the lower level driver has + * completed its port and lun discovery. + * + * Input: + * ha = adapter state pointer. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_cfg_path_discovery(scsi_qla_host_t *ha) +{ + int rval = QLA_SUCCESS; + mp_host_t *host; + uint8_t *name; + + ENTER("qla2x00_cfg_path_discovery"); + + name = &ha->init_cb->node_name[0]; + + set_bit(CFG_ACTIVE, &ha->cfg_flags); + /* Initialize the path tree for this adapter */ + host = qla2x00_find_host_by_name(name); + if ( mp_config_required ) { + if (host == NULL ) { + DEBUG4(printk("cfg_path_discovery: host not found, " + "node name = " + "%02x%02x%02x%02x%02x%02x%02x%02x\n", + name[0], name[1], name[2], name[3], + name[4], name[5], name[6], name[7]);) + rval = QLA_FUNCTION_FAILED; + } else if (ha->instance != host->instance) { + DEBUG4(printk("cfg_path_discovery: host instance " + "don't match - instance=%ld.\n", + ha->instance);) + rval = QLA_FUNCTION_FAILED; + } + } else if ( host == NULL ) { + /* New host adapter so allocate it */ + DEBUG3(printk("%s: found new ha inst %ld. alloc host.\n", + __func__, ha->instance);) + if ( (host = qla2x00_alloc_host(ha)) == NULL ) { + printk(KERN_INFO + "qla2x00(%d): Couldn't allocate " + "host - ha = %p.\n", + (int)ha->instance, ha); + rval = QLA_FUNCTION_FAILED; + } + } + + /* Fill in information about host */ + if (host != NULL ) { + host->flags |= MP_HOST_FLAG_NEEDS_UPDATE; + host->flags |= MP_HOST_FLAG_LUN_FO_ENABLED; + host->fcports = &ha->fcports; + + /* Check if multipath is enabled */ + DEBUG3(printk("%s: updating mp host for ha inst %ld.\n", + __func__, ha->instance);) + if (!qla2x00_update_mp_host(host)) { + rval = QLA_FUNCTION_FAILED; + } + host->flags &= ~MP_HOST_FLAG_LUN_FO_ENABLED; + } + + if (rval != QLA_SUCCESS) { + /* EMPTY */ + DEBUG4(printk("qla2x00_path_discovery: Exiting FAILED\n");) + } else { + LEAVE("qla2x00_cfg_path_discovery"); + } + clear_bit(CFG_ACTIVE, &ha->cfg_flags); + + return rval; +} + +/* + * qla2x00_cfg_event_notifiy + * Callback for host driver to notify us of configuration changes. + * + * Input: + * ha = adapter state pointer. + * i_type = event type + * + * Returns: + * + * Context: + * Kernel context. + */ +int +qla2x00_cfg_event_notify(scsi_qla_host_t *ha, uint32_t i_type) +{ + mp_host_t *host; /* host adapter pointer */ + + ENTER("qla2x00_cfg_event_notify"); + + set_bit(CFG_ACTIVE, &ha->cfg_flags); + switch (i_type) { + case MP_NOTIFY_RESET_DETECTED: + DEBUG(printk("scsi%ld: MP_NOTIFY_RESET_DETECTED " + "- no action\n", + ha->host_no);) + break; + case MP_NOTIFY_PWR_LOSS: + DEBUG(printk("scsi%ld: MP_NOTIFY_PWR_LOSS - " + "update tree\n", + ha->host_no);) + /* + * Update our path tree in case we are + * losing the adapter + */ + qla2x00_update_mp_tree(); + /* Free our resources for adapter */ + break; + case MP_NOTIFY_LOOP_UP: + DEBUG(printk("scsi%ld: MP_NOTIFY_LOOP_UP - " + "update host tree\n", + ha->host_no);) + /* Adapter is back up with new configuration */ + if ((host = qla2x00_cfg_find_host(ha)) != NULL) { + host->flags |= MP_HOST_FLAG_NEEDS_UPDATE; + host->fcports = &ha->fcports; + qla2x00_update_mp_tree(); + } + break; + case MP_NOTIFY_LOOP_DOWN: + case MP_NOTIFY_BUS_RESET: + DEBUG(printk("scsi%ld: MP_NOTIFY_OTHERS - " + "no action\n", + ha->host_no);) + break; + default: + break; + + } + clear_bit(CFG_ACTIVE, &ha->cfg_flags); + + LEAVE("qla2x00_cfg_event_notify"); + + return QLA_SUCCESS; +} + +/* + * qla2x00_cfg_failover + * A problem has been detected with the current path for this + * lun. Select the next available path as the current path + * for this device. + * + * Inputs: + * ha = pointer to host adapter + * fp - pointer to failed fc_lun (failback lun) + * tgt - pointer to target + * + * Returns: + * pointer to new fc_lun_t, or NULL if failover fails. + */ +fc_lun_t * +qla2x00_cfg_failover(scsi_qla_host_t *ha, fc_lun_t *fp, + os_tgt_t *tgt, srb_t *sp) +{ + mp_host_t *host; /* host adapter pointer */ + mp_device_t *dp; /* virtual device pointer */ + mp_path_t *new_path; /* new path pointer */ + fc_lun_t *new_fp = NULL; + + ENTER("qla2x00_cfg_failover"); + set_bit(CFG_ACTIVE, &ha->cfg_flags); + if ((host = qla2x00_cfg_find_host(ha)) != NULL) { + if ((dp = qla2x00_find_mp_dev_by_nodename( + host, tgt->node_name)) != NULL ) { + + DEBUG3(printk("qla2x00_cfg_failover: dp = %p\n", dp);) + /* + * Point at the next path in the path list if there is + * one, and if it hasn't already been failed over by + * another I/O. If there is only one path continuer + * to point at it. + */ + new_path = qla2x00_select_next_path(host, dp, fp->lun); + DEBUG3(printk("cfg_failover: new path @ %p\n", + new_path);) + new_fp = qla2x00_find_matching_lun(fp->lun, new_path); + DEBUG3(printk("cfg_failover: new fp lun @ %p\n", + new_fp);) + + qla2x00_cfg_register_failover_lun(dp, sp, new_fp); + } else { + printk(KERN_INFO + "qla2x00(%d): Couldn't find device " + "to failover\n", + host->instance); + } + } + clear_bit(CFG_ACTIVE, &ha->cfg_flags); + + LEAVE("qla2x00_cfg_failover"); + + return new_fp; +} + +/* + * IOCTL support + */ +#define CFG_IOCTL +#if defined(CFG_IOCTL) +/* + * qla2x00_cfg_get_paths + * Get list of paths EXT_FO_GET_PATHS. + * + * Input: + * ha = pointer to adapter + * bp = pointer to buffer + * cmd = Pointer to kernel copy of EXT_IOCTL. + * + * Return; + * 0 on success or errno. + * driver ioctl errors are returned via cmd->Status. + * + * Context: + * Kernel context. + */ +int +qla2x00_cfg_get_paths(EXT_IOCTL *cmd, FO_GET_PATHS *bp, int mode) +{ + int cnt; + int rval = 0; + uint16_t idx; + + FO_PATHS_INFO *paths, *u_paths; + FO_PATH_ENTRY *entry; + EXT_DEST_ADDR *sap = &bp->HbaAddr; + mp_host_t *host = NULL; /* host adapter pointer */ + mp_device_t *dp; /* virtual device pointer */ + mp_path_t *path; /* path pointer */ + mp_path_list_t *path_list; /* path list pointer */ + scsi_qla_host_t *ha; + + + DEBUG9(printk("%s: entered.\n", __func__);) + + u_paths = (FO_PATHS_INFO *) cmd->ResponseAdr; + ha = qla2x00_get_hba((int)bp->HbaInstance); + + if (!ha) { + DEBUG2_9_10(printk(KERN_INFO "%s: no ha matching inst %d.\n", + __func__, bp->HbaInstance);) + + cmd->Status = EXT_STATUS_DEV_NOT_FOUND; + return (rval); + } + DEBUG9(printk("%s(%ld): found matching ha inst %d.\n", + __func__, ha->host_no, bp->HbaInstance);) + + if (qla2x00_failover_enabled(ha)) { + if ((host = qla2x00_cfg_find_host(ha)) == NULL) { + cmd->Status = EXT_STATUS_DEV_NOT_FOUND; + cmd->DetailStatus = EXT_DSTATUS_HBA_INST; + DEBUG4(printk("%s: cannot find target (%ld)\n", + __func__, ha->instance);) + DEBUG9_10(printk("%s: cannot find host inst(%ld).\n", + __func__, ha->instance);) + + return rval; + } + } + + paths = (FO_PATHS_INFO *)qla2x00_kmem_zalloc( + sizeof(FO_PATHS_INFO), GFP_ATOMIC, 20); + if (paths == NULL) { + DEBUG4(printk("%s: failed to allocate memory of size (%d)\n", + __func__, (int)sizeof(FO_PATHS_INFO));) + DEBUG9_10(printk("%s: failed allocate memory size(%d).\n", + __func__, (int)sizeof(FO_PATHS_INFO));) + + cmd->Status = EXT_STATUS_NO_MEMORY; + + return -ENOMEM; + } + DEBUG9(printk("%s(%ld): found matching ha inst %d.\n", + __func__, ha->host_no, bp->HbaInstance);) + + if (!qla2x00_failover_enabled(ha)) { + /* non-fo case. There's only one path. */ + + mp_path_list_t *ptmp_plist; +#define STD_MAX_PATH_CNT 1 +#define STD_VISIBLE_INDEX 0 + int found; + struct list_head *fcpl; + fc_port_t *fcport; + + DEBUG9(printk("%s: non-fo case.\n", __func__);) + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&ptmp_plist, + sizeof(mp_path_list_t))) { + /* not enough memory */ + DEBUG9_10(printk( + "%s(%ld): inst=%ld scrap not big enough. " + "lun_mask requested=%ld.\n", + __func__, ha->host_no, ha->instance, + (ulong)sizeof(mp_path_list_t));) + cmd->Status = EXT_STATUS_NO_MEMORY; + + return -ENOMEM; + } + + found = 0; + fcport = NULL; + list_for_each(fcpl, &ha->fcports) { + fcport = list_entry(fcpl, fc_port_t, list); + + if (memcmp(fcport->node_name, sap->DestAddr.WWNN, + EXT_DEF_WWN_NAME_SIZE) == 0) { + found++; + break; + } + } + + if (found) { + DEBUG9(printk("%s: found fcport:" + "(%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x)\n.", + __func__, + sap->DestAddr.WWNN[0], sap->DestAddr.WWNN[1], + sap->DestAddr.WWNN[2], sap->DestAddr.WWNN[3], + sap->DestAddr.WWNN[4], sap->DestAddr.WWNN[5], + sap->DestAddr.WWNN[6], sap->DestAddr.WWNN[7]);) + + paths->HbaInstance = bp->HbaInstance; + paths->PathCount = STD_MAX_PATH_CNT; + paths->VisiblePathIndex = STD_VISIBLE_INDEX; + + /* Copy current path, which is the first one (0). */ + memcpy(paths->CurrentPathIndex, + ptmp_plist->current_path, + sizeof(paths->CurrentPathIndex)); + + entry = &(paths->PathEntry[STD_VISIBLE_INDEX]); + + entry->Visible = TRUE; + entry->HbaInstance = bp->HbaInstance; + + memcpy(entry->PortName, fcport->port_name, + EXT_DEF_WWP_NAME_SIZE); + + rval = verify_area(VERIFY_WRITE, (void *)u_paths, + cmd->ResponseLen); + if (rval) { + /* error */ + DEBUG9_10(printk("%s: u_paths %p verify write" + " error. paths->PathCount=%d.\n", + __func__, u_paths, paths->PathCount);) + } + + /* Copy data to user */ + if (rval == 0) + rval = copy_to_user(&u_paths->PathCount, + &paths->PathCount, 4); + if (rval == 0) + rval = copy_to_user(&u_paths->CurrentPathIndex, + &paths->CurrentPathIndex, + sizeof(paths->CurrentPathIndex)); + if (rval == 0) + rval = copy_to_user(&u_paths->PathEntry, + &paths->PathEntry, + sizeof(paths->PathEntry)); + + if (rval) { /* if any of the above failed */ + DEBUG9_10(printk("%s: data copy failed.\n", + __func__);) + + cmd->Status = EXT_STATUS_COPY_ERR; + } + } else { + cmd->Status = EXT_STATUS_DEV_NOT_FOUND; + cmd->DetailStatus = EXT_DSTATUS_TARGET; + + DEBUG10(printk("%s: cannot find fcport " + "(%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x)\n.", + __func__, + sap->DestAddr.WWNN[0], + sap->DestAddr.WWNN[1], + sap->DestAddr.WWNN[2], + sap->DestAddr.WWNN[3], + sap->DestAddr.WWNN[4], + sap->DestAddr.WWNN[5], + sap->DestAddr.WWNN[6], + sap->DestAddr.WWNN[7]);) + DEBUG4(printk("%s: cannot find fcport " + "(%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x)\n.", + __func__, + sap->DestAddr.WWNN[0], + sap->DestAddr.WWNN[1], + sap->DestAddr.WWNN[2], + sap->DestAddr.WWNN[3], + sap->DestAddr.WWNN[4], + sap->DestAddr.WWNN[5], + sap->DestAddr.WWNN[6], + sap->DestAddr.WWNN[7]);) + } + + qla2x00_free_ioctl_scrap_mem(ha); + /* end of non-fo case. */ + + } else if (sap->DestType != EXT_DEF_DESTTYPE_WWNN && + sap->DestType != EXT_DEF_DESTTYPE_WWPN) { + /* Scan for mp_dev by nodename or portname *ONLY* */ + + cmd->Status = EXT_STATUS_INVALID_PARAM; + cmd->DetailStatus = EXT_DSTATUS_TARGET; + + DEBUG4(printk("%s: target can be accessed by NodeName only.", + __func__);) + DEBUG9_10(printk("%s: target can be accessed by NodeName or " + " PortName only. Got type %d.\n", + __func__, sap->DestType);) + + } else if ((sap->DestType == EXT_DEF_DESTTYPE_WWNN && + (dp = qla2x00_find_mp_dev_by_nodename(host, + sap->DestAddr.WWNN)) != NULL) || + (sap->DestType == EXT_DEF_DESTTYPE_WWPN && + (dp = qla2x00_find_mp_dev_by_portname(host, + sap->DestAddr.WWPN, &idx)) != NULL)) { + + DEBUG9(printk("%s(%ld): Found mp_dev. nodename=" + "%02x%02x%02x%02x%02x%02x%02x%02x portname=" + "%02x%02x%02x%02x%02x%02x%02x%02x.\n.", + __func__, host->ha->host_no, + sap->DestAddr.WWNN[0], sap->DestAddr.WWNN[1], + sap->DestAddr.WWNN[2], sap->DestAddr.WWNN[3], + sap->DestAddr.WWNN[4], sap->DestAddr.WWNN[5], + sap->DestAddr.WWNN[6], sap->DestAddr.WWNN[7], + sap->DestAddr.WWPN[0], sap->DestAddr.WWPN[1], + sap->DestAddr.WWPN[2], sap->DestAddr.WWPN[3], + sap->DestAddr.WWPN[4], sap->DestAddr.WWPN[5], + sap->DestAddr.WWPN[6], sap->DestAddr.WWPN[7]);) + + path_list = dp->path_list; + + paths->HbaInstance = bp->HbaInstance; + paths->PathCount = path_list->path_cnt; + paths->VisiblePathIndex = path_list->visible; + + /* copy current paths */ + memcpy(paths->CurrentPathIndex, + path_list->current_path, + sizeof(paths->CurrentPathIndex)); + + path = path_list->last; + for (cnt = 0; cnt < path_list->path_cnt; cnt++) { + entry = &(paths->PathEntry[path->id]); + + entry->Visible = (path->id == path_list->visible); + entry->HbaInstance = path->host->instance; + DEBUG9(printk("%s: entry %d ha %d path id %d, pn=" + "%02x%02x%02x%02x%02x%02x%02x%02x. visible=%d.\n", + __func__, cnt, path->host->instance, path->id, + path->portname[0], path->portname[1], + path->portname[2], path->portname[3], + path->portname[4], path->portname[5], + path->portname[6], path->portname[7], + entry->Visible);) + + memcpy(entry->PortName, + path->portname, + EXT_DEF_WWP_NAME_SIZE); + + path = path->next; + } + DEBUG9(printk("%s: path cnt=%d, visible path=%d.\n", + __func__, path_list->path_cnt, path_list->visible);) + + rval = verify_area(VERIFY_WRITE, (void *)u_paths, + cmd->ResponseLen); + if (rval) { + /* error */ + DEBUG9_10(printk("%s: u_paths %p verify write" + " error. paths->PathCount=%d.\n", + __func__, u_paths, paths->PathCount);) + } + DEBUG9(printk("%s: path cnt=%d, visible path=%d.\n", + __func__, path_list->path_cnt, path_list->visible);) + + /* copy data to user */ + if (rval == 0) + rval = copy_to_user(&u_paths->PathCount, + &paths->PathCount, 4); + if (rval == 0) + rval = copy_to_user(&u_paths->CurrentPathIndex, + &paths->CurrentPathIndex, + sizeof(paths->CurrentPathIndex)); + if (rval == 0) + rval = copy_to_user(&u_paths->PathEntry, + &paths->PathEntry, + sizeof(paths->PathEntry)); + + if (rval != 0) { /* if any of the above failed */ + DEBUG9_10(printk("%s: u_paths %p copy" + " error. paths->PathCount=%d.\n", + __func__, u_paths, paths->PathCount);) + cmd->Status = EXT_STATUS_COPY_ERR; + } + + } else { + + cmd->Status = EXT_STATUS_DEV_NOT_FOUND; + cmd->DetailStatus = EXT_DSTATUS_TARGET; + + DEBUG9_10(printk("%s: DestType=%x.\n", + __func__, sap->DestType);) + DEBUG9_10(printk("%s: return DEV_NOT_FOUND for node=%02x%02x" + "%02x%02x%02x%02x%02x%02x port=%02x%02x%02x%02x%02x%02x" + "%02x%02x.\n", + __func__, + sap->DestAddr.WWNN[0], sap->DestAddr.WWNN[1], + sap->DestAddr.WWNN[2], sap->DestAddr.WWNN[3], + sap->DestAddr.WWNN[4], sap->DestAddr.WWNN[5], + sap->DestAddr.WWNN[6], sap->DestAddr.WWNN[7], + sap->DestAddr.WWPN[0], sap->DestAddr.WWPN[1], + sap->DestAddr.WWPN[2], sap->DestAddr.WWPN[3], + sap->DestAddr.WWPN[4], sap->DestAddr.WWPN[5], + sap->DestAddr.WWPN[6], sap->DestAddr.WWPN[7]);) + + DEBUG4(printk("%s: return DEV_NOT_FOUND for node=%02x%02x" + "%02x%02x%02x%02x%02x%02x port=%02x%02x%02x%02x%02x%02x" + "%02x%02x.\n", + __func__, + sap->DestAddr.WWNN[0], sap->DestAddr.WWNN[1], + sap->DestAddr.WWNN[2], sap->DestAddr.WWNN[3], + sap->DestAddr.WWNN[4], sap->DestAddr.WWNN[5], + sap->DestAddr.WWNN[6], sap->DestAddr.WWNN[7], + sap->DestAddr.WWPN[0], sap->DestAddr.WWPN[1], + sap->DestAddr.WWPN[2], sap->DestAddr.WWPN[3], + sap->DestAddr.WWPN[4], sap->DestAddr.WWPN[5], + sap->DestAddr.WWPN[6], sap->DestAddr.WWPN[7]);) + } + + KMEM_FREE(paths, sizeof(FO_PATHS_INFO)); + + DEBUG9(printk("%s: exiting. rval=%d.\n", __func__, rval);) + + return rval; + +} /* qla2x00_cfg_get_paths */ + +/* + * qla2x00_cfg_set_current_path + * Set the current failover path EXT_FO_GET_PATHS IOCTL call. + * + * Input: + * ha = pointer to adapter + * bp = pointer to buffer + * cmd = Pointer to kernel copy of EXT_IOCTL. + * + * Return; + * 0 on success or errno. + * + * Context: + * Kernel context. + */ +int +qla2x00_cfg_set_current_path(EXT_IOCTL *cmd, FO_SET_CURRENT_PATH *bp, int mode ) +{ + uint8_t orig_id, new_id; + uint16_t idx; + mp_host_t *host, *new_host; + mp_device_t *dp; + mp_path_list_t *path_list; + EXT_DEST_ADDR *sap = &bp->HbaAddr; + uint32_t rval = 0; + scsi_qla_host_t *ha; + mp_path_t *new_path, *old_path; + + DEBUG9(printk("%s: entered.\n", __func__);) + + /* First find the adapter with the instance number. */ + ha = qla2x00_get_hba((int)bp->HbaInstance); + if (!ha) { + DEBUG2_9_10(printk(KERN_INFO "%s: no ha matching inst %d.\n", + __func__, bp->HbaInstance);) + + cmd->Status = EXT_STATUS_DEV_NOT_FOUND; + return (rval); + } + + if (!qla2x00_failover_enabled(ha)) { + /* non-failover mode. nothing to be done. */ + DEBUG9_10(printk("%s(%ld): non-failover driver mode.\n", + __func__, ha->host_no);) + + return 0; + } + + if ((host = qla2x00_cfg_find_host(ha)) == NULL) { + cmd->Status = EXT_STATUS_DEV_NOT_FOUND; + cmd->DetailStatus = EXT_DSTATUS_HBA_INST; + DEBUG4(printk("%s: cannot find adapter.\n", + __func__);) + DEBUG9_10(printk("%s(%ld): cannot find mphost.\n", + __func__, ha->host_no);) + return (rval); + } + + set_bit(CFG_ACTIVE, &ha->cfg_flags); + sap = &bp->HbaAddr; + /* Scan for mp_dev by nodename *ONLY* */ + if (sap->DestType != EXT_DEF_DESTTYPE_WWNN && + sap->DestType != EXT_DEF_DESTTYPE_WWPN) { + cmd->Status = EXT_STATUS_DEV_NOT_FOUND; + cmd->DetailStatus = EXT_DSTATUS_TARGET; + DEBUG4(printk("%s: target can be accessed by NodeName only.", + __func__);) + DEBUG9_10(printk("%s(%ld): target can be accessed by NodeName " + " or PortName only.\n", + __func__, ha->host_no);) + } else if ((sap->DestType == EXT_DEF_DESTTYPE_WWNN && + (dp = qla2x00_find_mp_dev_by_nodename(host, + sap->DestAddr.WWNN)) != NULL) || + (sap->DestType == EXT_DEF_DESTTYPE_WWPN && + (dp = qla2x00_find_mp_dev_by_portname(host, + sap->DestAddr.WWPN, &idx)) != NULL)) { + + if (sap->DestType == EXT_DEF_DESTTYPE_WWNN) { + DEBUG9_10(printk("%s(%ld): found mpdev with matching " + " NodeName.\n", + __func__, ha->host_no);) + } else { + DEBUG9_10(printk("%s(%ld): found mpdev with matching " + " PortName.\n", + __func__, ha->host_no);) + } + + path_list = dp->path_list; + + if (bp->NewCurrentPathIndex < MAX_PATHS_PER_DEVICE && + sap->Lun < MAX_LUNS && + bp->NewCurrentPathIndex < path_list->path_cnt) { + + orig_id = path_list->current_path[sap->Lun]; + + DEBUG(printk("%s: dev no %d, lun %d, " + "newindex %d, oldindex %d " + "nn=%02x%02x%02x%02x%02x%02x%02x%02x\n", + __func__, dp->dev_id, sap->Lun, + bp->NewCurrentPathIndex, orig_id, + host->nodename[0], host->nodename[1], + host->nodename[2], host->nodename[3], + host->nodename[4], host->nodename[5], + host->nodename[6], host->nodename[7]);) + + if (bp->NewCurrentPathIndex != orig_id) { + /* Acquire the update spinlock. */ + + /* Set the new current path. */ + new_id = path_list-> current_path[sap->Lun] = + bp->NewCurrentPathIndex; + + /* Release the update spinlock. */ + old_path = qla2x00_find_path_by_id( + dp, orig_id); + new_path = qla2x00_find_path_by_id(dp, new_id); + new_host = new_path->host; + + /* remap the lun */ + qla2x00_map_a_oslun(new_host, dp, + dp->dev_id, sap->Lun); + + qla2x00_send_failover_notify(dp, + sap->Lun, old_path, new_path); + } else { + /* EMPTY */ + DEBUG4(printk("%s: path index not changed.\n", + __func__);) + DEBUG9(printk("%s(%ld): path id not changed.\n", + __func__, ha->host_no);) + } + } else { + cmd->Status = EXT_STATUS_INVALID_PARAM; + cmd->DetailStatus = EXT_DSTATUS_PATH_INDEX; + DEBUG4(printk("%s: invalid index for device.\n", + __func__);) + DEBUG9_10(printk("%s: invalid index for device.\n", + __func__);) + } + } else { + cmd->Status = EXT_STATUS_DEV_NOT_FOUND; + cmd->DetailStatus = EXT_DSTATUS_TARGET; + DEBUG4(printk("%s: cannot find device.\n", + __func__);) + DEBUG9_10(printk("%s: DestType=%x.\n", + __func__, sap->DestType);) + DEBUG9_10(printk("%s: return DEV_NOT_FOUND for node=%02x%02x" + "%02x%02x%02x%02x%02x%02x port=%02x%02x%02x%02x%02x%02x" + "%02x%02x.\n", + __func__, + sap->DestAddr.WWNN[0], sap->DestAddr.WWNN[1], + sap->DestAddr.WWNN[2], sap->DestAddr.WWNN[3], + sap->DestAddr.WWNN[4], sap->DestAddr.WWNN[5], + sap->DestAddr.WWNN[6], sap->DestAddr.WWNN[7], + sap->DestAddr.WWPN[0], sap->DestAddr.WWPN[1], + sap->DestAddr.WWPN[2], sap->DestAddr.WWPN[3], + sap->DestAddr.WWPN[4], sap->DestAddr.WWPN[5], + sap->DestAddr.WWPN[6], sap->DestAddr.WWPN[7]);) + } + clear_bit(CFG_ACTIVE, &ha->cfg_flags); + + DEBUG9(printk("%s: exiting. rval = %d.\n", __func__, rval);) + + return rval; +} +#endif + +/* + * MP SUPPORT ROUTINES + */ + +/* + * qla2x00_add_mp_host + * Add the specified host the host list. + * + * Input: + * node_name = pointer to node name + * + * Returns: + * + * Context: + * Kernel context. + */ +mp_host_t * +qla2x00_add_mp_host(uint8_t *node_name) +{ + mp_host_t *host, *temp; + + host = (mp_host_t *) KMEM_ZALLOC(sizeof(mp_host_t), 1); + if (host != NULL) { + memcpy(host->nodename, node_name, WWN_SIZE); + host->next = NULL; + /* add to list */ + if (mp_hosts_base == NULL) { + mp_hosts_base = host; + } else { + temp = mp_hosts_base; + while (temp->next != NULL) + temp = temp->next; + temp->next = host; + } + mp_num_hosts++; + } + return host; +} + +/* + * qla2x00_alloc_host + * Allocate and initialize an mp host structure. + * + * Input: + * ha = pointer to base driver's adapter structure. + * + * Returns: + * Pointer to host structure or null on error. + * + * Context: + * Kernel context. + */ +mp_host_t * +qla2x00_alloc_host(scsi_qla_host_t *ha) +{ + mp_host_t *host, *temp; + uint8_t *name, *portname; + + name = &ha->init_cb->node_name[0]; + portname = &ha->init_cb->port_name[0]; + + ENTER("qla2x00_alloc_host"); + + host = (mp_host_t *) KMEM_ZALLOC(sizeof(mp_host_t), 2); + + if (host != NULL) { + host->ha = ha; + memcpy(host->nodename, name, WWN_SIZE); + memcpy(host->portname, portname, WWN_SIZE); + host->next = NULL; + host->flags = MP_HOST_FLAG_NEEDS_UPDATE; + host->instance = ha->instance; + /* host->MaxLunsPerTarget = qla_fo_params.MaxLunsPerTarget; */ + + if (qla2x00_fo_enabled(host->ha, host->instance)) { + host->flags |= MP_HOST_FLAG_FO_ENABLED; + DEBUG4(printk("%s: Failover enabled.\n", + __func__);) + } else { + /* EMPTY */ + DEBUG4(printk("%s: Failover disabled.\n", + __func__);) + } + /* add to list */ + if (mp_hosts_base == NULL) { + mp_hosts_base = host; + } else { + temp = mp_hosts_base; + while (temp->next != NULL) + temp = temp->next; + temp->next = host; + } + mp_num_hosts++; + + DEBUG4(printk("%s: Alloc host @ %p\n", __func__, host);) + } else { + /* EMPTY */ + DEBUG4(printk("%s: Failed\n", __func__);) + } + + return host; +} + +/* + * qla2x00_add_portname_to_mp_dev + * Add the specific port name to the list of port names for a + * multi-path device. + * + * Input: + * dp = pointer ti virtual device + * portname = Port name to add to device + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +static uint32_t +qla2x00_add_portname_to_mp_dev(mp_device_t *dp, uint8_t *portname) +{ + uint8_t index; + uint32_t rval = QLA_SUCCESS; + + ENTER("qla2x00_add_portname_to_mp_dev"); + + /* Look for an empty slot and add the specified portname. */ + for (index = 0; index < MAX_NUMBER_PATHS; index++) { + if (qla2x00_is_ww_name_zero(&dp->portnames[index][0])) { + DEBUG4(printk("%s: adding portname to dp = " + "%p at index = %d\n", + __func__, dp, index);) + memcpy(&dp->portnames[index][0], portname, WWN_SIZE); + break; + } + } + if (index == MAX_NUMBER_PATHS) { + rval = QLA_FUNCTION_FAILED; + DEBUG4(printk("%s: Fail no room\n", __func__);) + } else { + /* EMPTY */ + DEBUG4(printk("%s: Exit OK\n", __func__);) + } + + LEAVE("qla2x00_add_portname_to_mp_dev"); + + return rval; +} + + +/* + * qla2x00_allocate_mp_dev + * Allocate an fc_mp_dev, clear the memory, and log a system + * error if the allocation fails. After fc_mp_dev is allocated + * + * Inputs: + * nodename = pointer to nodename of new device + * portname = pointer to portname of new device + * + * Returns: + * Pointer to new mp_device_t, or NULL if the allocation fails. + * + * Context: + * Kernel context. + */ +static mp_device_t * +qla2x00_allocate_mp_dev(uint8_t *nodename, uint8_t *portname) +{ + mp_device_t *dp; /* Virtual device pointer */ + + ENTER("qla2x00_allocate_mp_dev"); + DEBUG3(printk("%s: entered.\n", __func__);) + + dp = (mp_device_t *)KMEM_ZALLOC(sizeof(mp_device_t), 3); + + if (dp != NULL) { + DEBUG3(printk("%s: mp_device_t allocated at %p\n", + __func__, dp);) + + /* + * Copy node name into the mp_device_t. + */ + if (nodename) + { + DEBUG3(printk("%s: copying node name %02x%02x%02x" + "%02x%02x%02x%02x%02x.\n", + __func__, nodename[0], nodename[1], + nodename[2], nodename[3], nodename[4], + nodename[5], nodename[6], nodename[7]);) + memcpy(dp->nodename, nodename, WWN_SIZE); + } + + /* + * Since this is the first port, it goes at + * index zero. + */ + if (portname) + { + DEBUG3(printk("%s: copying port name %02x%02x%02x" + "%02x%02x%02x%02x%02x.\n", + __func__, portname[0], portname[1], + portname[2], portname[3], portname[4], + portname[5], portname[6], portname[7]);) + memcpy(&dp->portnames[0][0], portname, PORT_NAME_SIZE); + } + + /* Allocate an PATH_LIST for the fc_mp_dev. */ + if ((dp->path_list = qla2x00_allocate_path_list()) == NULL) { + DEBUG4(printk("%s: allocate path_list Failed.\n", + __func__);) + KMEM_FREE(dp, sizeof(mp_device_t)); + dp = NULL; + } else { + DEBUG4(printk("%s: mp_path_list_t allocated at %p\n", + __func__, dp->path_list);) + /* EMPTY */ + DEBUG4(printk("qla2x00_allocate_mp_dev: Exit Okay\n");) + } + } else { + /* EMPTY */ + DEBUG4(printk("%s: Allocate failed.\n", __func__);) + } + + DEBUG3(printk("%s: exiting.\n", __func__);) + LEAVE("qla2x00_allocate_mp_dev"); + + return dp; +} + +/* + * qla2x00_allocate_path + * Allocate a PATH. + * + * Inputs: + * host Host adapter for the device. + * path_id path number + * port port for device. + * dev_id device number + * + * Returns: + * Pointer to new PATH, or NULL if the allocation failed. + * + * Context: + * Kernel context. + */ +static mp_path_t * +qla2x00_allocate_path(mp_host_t *host, uint16_t path_id, + fc_port_t *port, uint16_t dev_id) +{ + mp_path_t *path; + uint16_t lun; + + ENTER("qla2x00_allocate_path"); + + path = (mp_path_t *) KMEM_ZALLOC(sizeof(mp_path_t), 4); + if (path != NULL) { + + DEBUG3(printk("%s(%ld): allocated path %p at path id %d.\n", + __func__, host->ha->host_no, path, path_id);) + + /* Copy the supplied information into the MP_PATH. */ + path->host = host; + + if (!(port->flags & FCF_CONFIG) && + port->loop_id != FC_NO_LOOP_ID) { + + path->port = port; + DEBUG3(printk("%s(%ld): assigned port pointer %p " + "to path id %d.\n", + __func__, host->ha->host_no, port, path_id);) + } + + path->id = path_id; + port->cur_path = path->id; + path->mp_byte = port->mp_byte; + path->next = NULL; + memcpy(path->portname, port->port_name, WWN_SIZE); + + DEBUG3(printk("%s(%ld): path id %d copied portname " + "%02x%02x%02x%02x%02x%02x%02x%02x. enabling all LUNs.\n", + __func__, host->ha->host_no, path->id, + port->port_name[0], port->port_name[1], + port->port_name[2], port->port_name[3], + port->port_name[4], port->port_name[5], + port->port_name[6], port->port_name[7]);) + + for (lun = 0; lun < MAX_LUNS; lun++) { + path->lun_data.data[lun] |= LUN_DATA_ENABLED; + } + } else { + /* EMPTY */ + DEBUG4(printk("%s: Failed\n", __func__);) + } + + return path; +} + + +/* + * qla2x00_allocate_path_list + * Allocate a PATH_LIST + * + * Input: + * None + * + * Returns: + * Pointer to new PATH_LIST, or NULL if the allocation fails. + * + * Context: + * Kernel context. + */ +static mp_path_list_t * +qla2x00_allocate_path_list( void ) +{ + mp_path_list_t *path_list; + uint16_t i; + uint8_t l; + + path_list = (mp_path_list_t *) KMEM_ZALLOC(sizeof(mp_path_list_t), 5); + + if (path_list != NULL) { + DEBUG4(printk("%s: allocated at %p\n", + __func__, path_list);) + + path_list->visible = PATH_INDEX_INVALID; + /* Initialized current path */ + for (i = 0; i < MAX_LUNS_PER_DEVICE; i++) { + l = (uint8_t)(i & 0xFF); + path_list->current_path[l] = PATH_INDEX_INVALID; + } + path_list->last = NULL; + + } else { + /* EMPTY */ + DEBUG4(printk("%s: Alloc pool failed for MP_PATH_LIST.\n", + __func__);) + } + + return path_list; +} + +/* + * qla2x00_cfg_find_host + * Look through the existing multipath tree, and find + * a host adapter to match the specified ha. + * + * Input: + * ha = pointer to host adapter + * + * Return: + * Pointer to new host, or NULL if no match found. + * + * Context: + * Kernel context. + */ +mp_host_t * +qla2x00_cfg_find_host(scsi_qla_host_t *ha) +{ + mp_host_t *host = NULL; /* Host found and null if not */ + mp_host_t *tmp_host; + + ENTER("qla2x00_cfg_find_host"); + + for (tmp_host = mp_hosts_base; (tmp_host); tmp_host = tmp_host->next) { + if (tmp_host->ha == ha) { + host = tmp_host; + DEBUG3(printk("%s: Found host =%p, instance %d\n", + __func__, host, host->instance);) + break; + } + } + + LEAVE("qla2x00_cfg_find_host"); + + return host; +} + +/* + * qla2x00_find_host_by_name + * Look through the existing multipath tree, and find + * a host adapter to match the specified name. + * + * Input: + * name = node name to match. + * + * Return: + * Pointer to new host, or NULL if no match found. + * + * Context: + * Kernel context. + */ +mp_host_t * +qla2x00_find_host_by_name(uint8_t *name) +{ + mp_host_t *host; /* Host found and null if not */ + + for (host = mp_hosts_base; (host); host = host->next) { + if (memcmp(host->nodename, name, WWN_SIZE) == 0) + break; + } + return host; +} + +/* + * qla2x00_found_hidden_path + * This is called only when the port trying to figure out whether + * to bind to this mp_device has mpbyte of zero. It doesn't matter + * if the path we check on is first path or not because if + * more than one path has mpbyte zero and not all are zero, it is + * invalid and unsupported configuration which we don't handle. + * + * Input: + * dp = mp_device pointer + * + * Returns: + * TRUE - first path in dp is hidden. + * FALSE - no hidden path. + * + * Context: + * Kernel context. + */ +static inline uint8_t +qla2x00_found_hidden_path(mp_device_t *dp) +{ + uint8_t ret = FALSE; + mp_path_list_t *path_list = dp->path_list; +#ifdef QL_DEBUG_LEVEL_2 + mp_path_t *tmp_path; + uint8_t cnt = 0; +#endif + + /* Sanity check */ + if (path_list == NULL) { + /* ERROR? Just print debug and return */ + DEBUG2_3(printk("%s: ERROR No path list found on dp.\n", + __func__);) + return (FALSE); + } + + if (path_list->last != NULL && + path_list->last->mp_byte & MP_MASK_HIDDEN) { + ret = TRUE; + } + +#ifdef QL_DEBUG_LEVEL_2 + /* If any path is visible, return FALSE right away, otherwise check + * through to make sure all existing paths in this mpdev are hidden. + */ + for (tmp_path = path_list->last; tmp_path && cnt < path_list->path_cnt; + tmp_path = tmp_path->next, cnt++) { + if (!(tmp_path->mp_byte & MP_MASK_HIDDEN)) { + printk("%s: found visible path.\n", __func__); + } + } +#endif + + return (ret); +} + +/* + * qla2x00_default_bind_mpdev + * + * Input: + * host = mp_host of current adapter + * port = fc_port of current port + * + * Returns: + * mp_device pointer + * NULL - not found. + * + * Context: + * Kernel context. + */ +static inline mp_device_t * +qla2x00_default_bind_mpdev(mp_host_t *host, fc_port_t *port) +{ + /* Default search case */ + int devid = 0; + mp_device_t *temp_dp = NULL; /* temporary pointer */ + mp_host_t *temp_host; /* temporary pointer */ + + DEBUG3(printk("%s: entered.\n", __func__);) + + for (temp_host = mp_hosts_base; (temp_host); + temp_host = temp_host->next) { + for (devid = 0; devid < MAX_MP_DEVICES; devid++) { + temp_dp = temp_host->mp_devs[devid]; + + if (temp_dp == NULL) + continue; + + if (qla2x00_is_nodename_equal(temp_dp->nodename, + port->node_name)) { + DEBUG3(printk( + "%s: Found matching dp @ host %p id %d:\n", + __func__, temp_host, devid);) + break; + } + } + if (temp_dp != NULL) { + /* found a match. */ + break; + } + } + + if (temp_dp) { + DEBUG3(printk("%s(%ld): update mpdev " + "on Matching node at dp %p. " + "dev_id %d adding new port %p-%02x" + "%02x%02x%02x%02x%02x%02x%02x\n", + __func__, host->ha->host_no, + temp_dp, devid, port, + port->port_name[0], port->port_name[1], + port->port_name[2], port->port_name[3], + port->port_name[4], port->port_name[5], + port->port_name[6], port->port_name[7]);) + + qla2x00_add_portname_to_mp_dev(temp_dp, + port->port_name); + + /* + * Set the flag that we have + * found the device. + */ + host->mp_devs[devid] = temp_dp; + temp_dp->use_cnt++; + + /* Fixme(dg) + * Copy the LUN info into + * the mp_device_t + */ + } + + return (temp_dp); +} + +/* + * qla2x00_find_or_allocate_mp_dev + * Look through the existing multipath control tree, and find + * an mp_device_t with the supplied world-wide node name. If + * one cannot be found, allocate one. + * + * Input: + * host Adapter to add device to. + * dev_id Index of device on adapter. + * port port database information. + * + * Returns: + * Pointer to new mp_device_t, or NULL if the allocation fails. + * + * Side Effects: + * If the MP HOST does not already point to the mp_device_t, + * a pointer is added at the proper port offset. + * + * Context: + * Kernel context. + */ +static mp_device_t * +qla2x00_find_or_allocate_mp_dev(mp_host_t *host, uint16_t dev_id, + fc_port_t *port) +{ + mp_device_t *dp = NULL; /* pointer to multi-path device */ + uint8_t node_found; /* Found matching node name. */ + uint8_t port_found; /* Found matching port name. */ + uint8_t names_valid; /* Node name and port name are not zero */ + mp_host_t *temp_host; /* pointer to temporary host */ + + uint16_t j; + mp_device_t *temp_dp; + + ENTER("qla2x00_find_or_allocate_mp_dev"); + + DEBUG3(printk("%s(%ld): entered. host=%p, port =%p, dev_id = %d\n", + __func__, host->ha->host_no, host, port, dev_id);) + + temp_dp = qla2x00_find_mp_dev_by_id(host,dev_id); + + DEBUG3(printk("%s: temp dp =%p\n", __func__, temp_dp);) + /* if Device already known at this port. */ + if (temp_dp != NULL) { + node_found = qla2x00_is_nodename_equal(temp_dp->nodename, + port->node_name); + port_found = qla2x00_is_portname_in_device(temp_dp, + port->port_name); + + if (node_found && port_found) { + DEBUG3(printk("%s: mp dev %02x%02x%02x%02x%02x%02x" + "%02x%02x exists on %p. dev id %d. path cnt=%d.\n", + __func__, + port->port_name[0], port->port_name[1], + port->port_name[2], port->port_name[3], + port->port_name[4], port->port_name[5], + port->port_name[6], port->port_name[7], + temp_dp, dev_id, temp_dp->path_list->path_cnt);) + dp = temp_dp; + + /* + * Copy the LUN configuration data + * into the mp_device_t. + */ + } + } + + + /* Sanity check the port information */ + names_valid = (!qla2x00_is_ww_name_zero(port->node_name) && + !qla2x00_is_ww_name_zero(port->port_name)); + + /* + * If the optimized check failed, loop through each known + * device on each known adapter looking for the node name. + */ + if (dp == NULL && names_valid) { + DEBUG3(printk("%s: Searching each adapter for the device...\n", + __func__);) + + /* Check for special cases. */ + if (port->flags & FCF_CONFIG) { + /* Here the search is done only for ports that + * are found in config file, so we can count on + * mp_byte value when binding the paths. + */ + DEBUG3(printk("%s(%ld): mpbyte=%02x process configured " + "portname=%02x%02x%02x%02x%02x%02x%02x%02x.\n", + __func__, host->ha->host_no, port->mp_byte, + port->port_name[0], port->port_name[1], + port->port_name[2], port->port_name[3], + port->port_name[4], port->port_name[5], + port->port_name[6], port->port_name[7]);) + DEBUG3(printk("%s(%ld): nodename %02x%02x%02x%02x%02x" + "%02x%02x%02x.\n", + __func__, host->ha->host_no, + port->node_name[0], port->node_name[1], + port->node_name[2], port->node_name[3], + port->node_name[4], port->node_name[5], + port->node_name[6], port->node_name[7]);) + + if (port->mp_byte == 0) { + DEBUG3(printk("%s(%ld): port visible.\n", + __func__, host->ha->host_no);) + + /* This device in conf file is set to visible */ + for (temp_host = mp_hosts_base; (temp_host); + temp_host = temp_host->next) { + /* Search all hosts with given tgt id + * for any previously created dp with + * matching node name. + */ + temp_dp = temp_host->mp_devs[dev_id]; + if (temp_dp == NULL) { + continue; + } + + node_found = + qla2x00_is_nodename_equal( + temp_dp->nodename, port->node_name); + + if (node_found && + qla2x00_found_hidden_path( + temp_dp)) { + DEBUG3(printk( + "%s(%ld): found " + "mpdev of matching " + "node %02x%02x%02x" + "%02x%02x%02x%02x" + "%02x w/ hidden " + "paths. dp=%p " + "dev_id=%d.\n", + __func__, + host->ha->host_no, + port->port_name[0], + port->port_name[1], + port->port_name[2], + port->port_name[3], + port->port_name[4], + port->port_name[5], + port->port_name[6], + port->port_name[7], + temp_dp, dev_id);) + /* + * Found the mpdev. + * Treat this same as + * default case. + */ + qla2x00_add_portname_to_mp_dev( + temp_dp, port->port_name); + dp = temp_dp; + host->mp_devs[dev_id] = dp; + dp->use_cnt++; + + break; + } + } + + } else if (port->mp_byte & MP_MASK_OVERRIDE) { + /* Bind on port name */ + DEBUG3(printk( + "%s(%ld): port has override bit.\n", + __func__, host->ha->host_no);) + + temp_dp = qla2x00_find_dp_by_pn_from_all_hosts( + port->port_name, &j); + + if (temp_dp) { + /* Found match */ + DEBUG3(printk("%s(%ld): update mpdev " + "on Matching port %02x%02x%02x" + "%02x%02x%02x%02x%02x " + "dp %p dev_id %d\n", + __func__, host->ha->host_no, + port->port_name[0], + port->port_name[1], + port->port_name[2], + port->port_name[3], + port->port_name[4], + port->port_name[5], + port->port_name[6], + port->port_name[7], + temp_dp, j);) + /* + * Set the flag that we have + * found the device. + */ + dp = temp_dp; + host->mp_devs[j] = dp; + dp->use_cnt++; + } + } else { + DEBUG3(printk("%s(%ld): default case.\n", + __func__, host->ha->host_no);) + /* Default case. Search and bind mp_dev with + * matching node name. + */ + dp = qla2x00_default_bind_mpdev(host, port); + } + + } else { + DEBUG3(printk("%s(%ld): process discovered port " + "%02x%02x%02x%02x%02x%02x%02x%02x.\n", + __func__, host->ha->host_no, + port->port_name[0], port->port_name[1], + port->port_name[2], port->port_name[3], + port->port_name[4], port->port_name[5], + port->port_name[6], port->port_name[7]);) + DEBUG3(printk("%s(%ld): nodename %02x%02x%02x%02x%02x" + "%02x%02x%02x.\n", + __func__, host->ha->host_no, + port->node_name[0], port->node_name[1], + port->node_name[2], port->node_name[3], + port->node_name[4], port->node_name[5], + port->node_name[6], port->node_name[7]);) + + /* Here we try to match ports found to any previously + * built mp_dev list. mp_byte value is not valid yet. + * First search for matching port name in current + * host. This is necessary in case the port name was + * specified in the config file with the override + * bit and saved in our mpdev tree already. + */ + temp_dp = qla2x00_find_mp_dev_by_portname(host, + port->port_name, &j); + + if (temp_dp) { + /* Found match. This mpdev port was created + * from config file. + */ + DEBUG3(printk("%s(%ld): update mpdev " + "on Matching port %02x%02x%02x" + "%02x%02x%02x%02x%02x " + "dp %p dev_id %d\n", + __func__, host->ha->host_no, + port->port_name[0], + port->port_name[1], + port->port_name[2], + port->port_name[3], + port->port_name[4], + port->port_name[5], + port->port_name[6], + port->port_name[7], + temp_dp, j);) + + dp = temp_dp; + } else if (!mp_config_required) { + + DEBUG3(printk("%s(%ld): default case.\n", + __func__, host->ha->host_no);) + /* Default case. Search and bind mp_dev with + * matching node name. + */ + dp = qla2x00_default_bind_mpdev(host, port); + } + } + + } + + /* If we couldn't find one, allocate one. */ + if (dp == NULL && + ((port->flags & FCF_CONFIG) || !mp_config_required)) { + + DEBUG3(printk("%s(%ld): No match. adding new mpdev on " + "dev_id %d. node %02x%02x%02x%02x%02x%02x%02x%02x " + "port %02x%02x%02x%02x%02x%02x%02x%02x\n", + __func__, host->ha->host_no, dev_id, + port->node_name[0], port->node_name[1], + port->node_name[2], port->node_name[3], + port->node_name[4], port->node_name[5], + port->node_name[6], port->node_name[7], + port->port_name[0], port->port_name[1], + port->port_name[2], port->port_name[3], + port->port_name[4], port->port_name[5], + port->port_name[6], port->port_name[7]);) + dp = qla2x00_allocate_mp_dev(port->node_name, port->port_name); + +#ifdef QL_DEBUG_LEVEL_2 + if (host->mp_devs[dev_id] != NULL) { + printk(KERN_WARNING + "qla2x00: invalid/unsupported configuration found. " + "overwriting target id %d.\n", + dev_id); + } +#endif + host->mp_devs[dev_id] = dp; + dp->dev_id = dev_id; + dp->use_cnt++; + } + + DEBUG3(printk("%s(%ld): exiting. return dp=%p.\n", + __func__, host->ha->host_no, dp);) + LEAVE("qla2x00_find_or_allocate_mp_dev"); + + return dp; +} + + +/* + * qla2x00_find_or_allocate_path + * Look through the path list for the supplied device, and either + * find the supplied adapter (path) for the adapter, or create + * a new one and add it to the path list. + * + * Input: + * host Adapter (path) for the device. + * dp Device and path list for the device. + * dev_id Index of device on adapter. + * port Device data from port database. + * + * Returns: + * Pointer to new PATH, or NULL if the allocation fails. + * + * Side Effects: + * 1. If the PATH_LIST does not already point to the PATH, + * a new PATH is added to the PATH_LIST. + * 2. If the new path is found to be a second visible path, it is + * marked as hidden, and the device database is updated to be + * hidden as well, to keep the miniport synchronized. + * + * Context: + * Kernel context. + */ +/* ARGSUSED */ +static mp_path_t * +qla2x00_find_or_allocate_path(mp_host_t *host, mp_device_t *dp, + uint16_t dev_id, uint16_t pathid, fc_port_t *port) +{ + mp_path_list_t *path_list = dp->path_list; + mp_path_t *path; + uint8_t id; + + + ENTER("qla2x00_find_or_allocate_path"); + + DEBUG4(printk("%s: host =%p, port =%p, dp=%p, dev id = %d\n", + __func__, host, port, dp, dev_id);) + /* + * Loop through each known path in the path list. Look for + * a PATH that matches both the adapter and the port name. + */ + path = qla2x00_find_path_by_name(host, path_list, port->port_name); + + + if (path != NULL ) { + DEBUG3(printk("%s: Found an existing " + "path %p- host %p inst=%d, port =%p, path id = %d\n", + __func__, path, host, host->instance, path->port, + path->id);) + DEBUG3(printk("%s: Luns for path_id %d, instance %d\n", + __func__, path->id, host->instance);) + DEBUG3(qla2x00_dump_buffer( + (char *)&path->lun_data.data[0], 64);) + + /* If we found an existing path, look for any changes to it. */ + if (path->port == NULL) { + DEBUG3(printk("%s: update path %p w/ port %p, path id=" + "%d, path mp_byte=0x%x port mp_byte=0x%x.\n", + __func__, path, port, path->id, + path->mp_byte, port->mp_byte);) + path->port = port; + port->mp_byte = path->mp_byte; + } else { + DEBUG3(printk("%s: update path %p port %p path id %d, " + "path mp_byte=0x%x port mp_byte=0x%x.\n", + __func__, path, path->port, path->id, + path->mp_byte, port->mp_byte);) + + if ((path->mp_byte & MP_MASK_HIDDEN) && + !(port->mp_byte & MP_MASK_HIDDEN)) { + + DEBUG3(printk("%s: Adapter(%p) " + "Device (%p) Path (%d) " + "has become visible.\n", + __func__, host, dp, path->id);) + + path->mp_byte &= ~MP_MASK_HIDDEN; + } + + if (!(path->mp_byte & MP_MASK_HIDDEN) && + (port->mp_byte & MP_MASK_HIDDEN)) { + + DEBUG3(printk("%s(%ld): Adapter(%p) " + "Device (%p) Path (%d) " + "has become hidden.\n", + __func__, host->ha->host_no, host, + dp, path->id);) + + path->mp_byte |= MP_MASK_HIDDEN; + } + } + + } else { + /* + * If we couldn't find an existing path, and there is still + * room to add one, allocate one and put it in the list. + */ + if (path_list->path_cnt < MAX_PATHS_PER_DEVICE && + path_list->path_cnt < qla_fo_params.MaxPathsPerDevice) { + + if (port->flags & FCF_CONFIG) { + /* Use id specified in config file. */ + id = pathid; + DEBUG3(printk("%s(%ld): using path id %d from " + "config file.\n", + __func__, host->ha->host_no, id);) + } else { + /* Assign one. */ + id = path_list->path_cnt; + DEBUG3(printk( + "%s(%ld): assigning path id %d.\n", + __func__, host->ha->host_no, id);) + } + + /* Update port with bitmask info */ + path = qla2x00_allocate_path(host, id, port, dev_id); + DEBUG3(printk("%s: allocated new path %p, adding " + "path id %d, mp_byte=0x%x " + "port=%p-%02x%02x%02x%02x%02x%02x%02x%02x\n", + __func__, path, id, + path->mp_byte, + path->port, + path->port->port_name[0], path->port->port_name[1], + path->port->port_name[2], path->port->port_name[3], + path->port->port_name[4], path->port->port_name[5], + path->port->port_name[6], path->port->port_name[7] + );) + qla2x00_add_path(path_list, path); + + /* Reconcile the new path against the existing ones. */ + qla2x00_setup_new_path(dp, path); + } else { + /* EMPTY */ + DEBUG4(printk("%s: Err exit, no space to add path.\n", + __func__);) + } + + } + + LEAVE("qla2x00_find_or_allocate_path"); + + return path; +} + +static uint32_t +qla2x00_cfg_register_failover_lun(mp_device_t *dp, srb_t *sp, fc_lun_t *new_lp) +{ + uint32_t status = QLA_SUCCESS; + os_tgt_t *tq; + os_lun_t *lq; + fc_lun_t *old_lp; + + DEBUG2(printk(KERN_INFO "%s: NEW fclun = %p, sp = %p\n", + __func__, new_lp, sp);) + + /* + * Fix lun descriptors to point to new fclun which is a new fcport. + */ + if (new_lp == NULL) { + DEBUG2(printk(KERN_INFO "%s: Failed new lun %p\n", + __func__, new_lp);) + return QLA_FUNCTION_FAILED; + } + + tq = sp->tgt_queue; + lq = sp->lun_queue; + if (tq == NULL) { + DEBUG2(printk(KERN_INFO "%s: Failed to get old tq %p\n", + __func__, tq);) + return QLA_FUNCTION_FAILED; + } + if (lq == NULL) { + DEBUG2(printk(KERN_INFO "%s: Failed to get old lq %p\n", + __func__, lq);) + return QLA_FUNCTION_FAILED; + } + old_lp = lq->fclun; + lq->fclun = new_lp; + + /* Log the failover to console */ + printk(KERN_INFO + "qla2x00: FAILOVER device %d from " + "%02x%02x%02x%02x%02x%02x%02x%02x -> " + "%02x%02x%02x%02x%02x%02x%02x%02x - " + "LUN %02x, reason=0x%x\n", + dp->dev_id, + old_lp->fcport->port_name[0], old_lp->fcport->port_name[1], + old_lp->fcport->port_name[2], old_lp->fcport->port_name[3], + old_lp->fcport->port_name[4], old_lp->fcport->port_name[5], + old_lp->fcport->port_name[6], old_lp->fcport->port_name[7], + new_lp->fcport->port_name[0], new_lp->fcport->port_name[1], + new_lp->fcport->port_name[2], new_lp->fcport->port_name[3], + new_lp->fcport->port_name[4], new_lp->fcport->port_name[5], + new_lp->fcport->port_name[6], new_lp->fcport->port_name[7], + new_lp->lun, sp->err_id); + printk(KERN_INFO + "qla2x00: FROM HBA %ld to HBA %ld\n", + old_lp->fcport->ha->instance, new_lp->fcport->ha->instance); + + DEBUG3(printk("%s: NEW fclun = %p , port =%p, " + "loop_id =0x%x, instance %ld\n", + __func__, + new_lp, new_lp->fcport, + new_lp->fcport->loop_id, + new_lp->fcport->ha->instance);) + + return status; +} + + +/* + * qla2x00_send_failover_notify + * A failover operation has just been done from an old path + * index to a new index. Call lower level driver + * to perform the failover notification. + * + * Inputs: + * device Device being failed over. + * lun LUN being failed over. + * newpath path that was failed over too. + * oldpath path that was failed over from. + * + * Return: + * Local function status code. + * + * Context: + * Kernel context. + */ +/* ARGSUSED */ +static uint32_t +qla2x00_send_failover_notify(mp_device_t *dp, + uint8_t lun, mp_path_t *newpath, mp_path_t *oldpath) +{ + fc_lun_t *old_lp, *new_lp; + uint32_t status = QLA_SUCCESS; + + ENTER("qla2x00_send_failover_notify"); + + old_lp = qla2x00_find_matching_lun(lun, oldpath); + new_lp = qla2x00_find_matching_lun(lun, newpath); + + /* + * If the target is the same target, but a new HBA has been selected, + * send a third party logout if required. + */ + if ((qla_fo_params.FailoverNotifyType & + FO_NOTIFY_TYPE_LOGOUT_OR_LUN_RESET || + qla_fo_params.FailoverNotifyType & + FO_NOTIFY_TYPE_LOGOUT_OR_CDB) && + qla2x00_is_portname_equal( + oldpath->portname, newpath->portname)) { + + status = qla2x00_send_fo_notification(old_lp, new_lp); + if (status == QLA_SUCCESS) { + /* EMPTY */ + DEBUG4(printk("%s: Logout succeded\n", + __func__);) + } else { + /* EMPTY */ + DEBUG4(printk("%s: Logout Failed\n", + __func__);) + } + } else if ((qla_fo_params.FailoverNotifyType & + FO_NOTIFY_TYPE_LUN_RESET) || + (qla_fo_params.FailoverNotifyType & + FO_NOTIFY_TYPE_LOGOUT_OR_LUN_RESET)) { + + /* + * If desired, send a LUN reset as the + * failover notification type. + */ + if (newpath->lun_data.data[lun] & LUN_DATA_ENABLED) { + status = qla2x00_send_fo_notification(old_lp, new_lp); + if (status == QLA_SUCCESS) { + /* EMPTY */ + DEBUG4(printk("%s: LUN reset succeeded.\n", + __func__);) + } else { + /* EMPTY */ + DEBUG4(printk("%s: Failed reset LUN.\n", + __func__);) + } + } + + } else if (qla_fo_params.FailoverNotifyType == FO_NOTIFY_TYPE_CDB || + qla_fo_params.FailoverNotifyType == + FO_NOTIFY_TYPE_LOGOUT_OR_CDB) { + + if (newpath->lun_data.data[lun] & LUN_DATA_ENABLED) { + status = qla2x00_send_fo_notification(old_lp, new_lp); + if (status == QLA_SUCCESS) { + /* EMPTY */ + DEBUG4(printk("%s: Send CDB succeeded.\n", + __func__);) + } else { + /* EMPTY */ + DEBUG4(printk("%s: Send CDB Error " + "lun=(%d).\n", __func__, lun);) + } + } + } else if (qla_fo_params.FailoverNotifyType == FO_NOTIFY_TYPE_SPINUP) { + if (newpath->lun_data.data[lun] & LUN_DATA_ENABLED) { + status = qla2x00_send_fo_notification(old_lp, new_lp); + if (status == QLA_SUCCESS) { + /* EMPTY */ + DEBUG(printk("%s: Send CDB succeeded.\n", + __func__);) + } else { + /* EMPTY */ + DEBUG(printk("%s: Send CDB Error " + "lun=(%d).\n", __func__, lun);) + } + } + } else { + /* EMPTY */ + DEBUG4(printk("%s: failover disabled or no notify routine " + "defined.\n", __func__);) + } + + return status; +} + +/* + * qla2x00_select_next_path + * A problem has been detected with the current path for this + * device. Try to select the next available path as the current + * path for this device. If there are no more paths, the same + * path will still be selected. + * + * Inputs: + * dp pointer of device structure. + * lun LUN to failover. + * + * Return Value: + * new path or same path + * + * Context: + * Kernel context. + */ +static mp_path_t * +qla2x00_select_next_path(mp_host_t *host, mp_device_t *dp, uint8_t lun) +{ + mp_path_t *path = NULL; + mp_path_list_t *path_list; + mp_path_t *orig_path; + int id; + uint32_t status; + mp_host_t *new_host; + + ENTER("qla2x00_select_next_path:"); + + path_list = dp->path_list; + if (path_list == NULL) + return NULL; + + /* Get current path */ + id = path_list->current_path[lun]; + + /* Get path for current path id */ + if ((orig_path = qla2x00_find_path_by_id(dp, id)) != NULL) { + + /* select next path */ + path = orig_path->next; + new_host = path->host; + + /* FIXME may need to check for HBA being reset */ + DEBUG3(printk("%s: orig path = %p new path = %p " + "curr idx = %d, new idx = %d\n", + __func__, orig_path, path, orig_path->id, path->id);) + DEBUG3(printk(" FAILOVER: device nodename: " + "%02x%02x%02x%02x%02x%02x%02x%02x\n", + dp->nodename[0], dp->nodename[1], + dp->nodename[2], dp->nodename[3], + dp->nodename[4], dp->nodename[5], + dp->nodename[6], dp->nodename[7]);) + DEBUG3(printk(" Original - host nodename: " + "%02x%02x%02x%02x%02x%02x%02x%02x\n", + orig_path->host->nodename[0], + orig_path->host->nodename[1], + orig_path->host->nodename[2], + orig_path->host->nodename[3], + orig_path->host->nodename[4], + orig_path->host->nodename[5], + orig_path->host->nodename[6], + orig_path->host->nodename[7]);) + DEBUG3(printk(" portname: " + "%02x%02x%02x%02x%02x%02x%02x%02x\n", + orig_path->port->port_name[0], + orig_path->port->port_name[1], + orig_path->port->port_name[2], + orig_path->port->port_name[3], + orig_path->port->port_name[4], + orig_path->port->port_name[5], + orig_path->port->port_name[6], + orig_path->port->port_name[7]);) + DEBUG3(printk(" New - host nodename: " + "%02x%02x%02x%02x%02x%02x%02x%02x\n", + new_host->nodename[0], new_host->nodename[1], + new_host->nodename[2], new_host->nodename[3], + new_host->nodename[4], new_host->nodename[5], + new_host->nodename[6], new_host->nodename[7]);) + DEBUG3(printk(" portname: " + "%02x%02x%02x%02x%02x%02x%02x%02x\n", + path->port->port_name[0], + path->port->port_name[1], + path->port->port_name[2], + path->port->port_name[3], + path->port->port_name[4], + path->port->port_name[5], + path->port->port_name[6], + path->port->port_name[7]);) + + path_list->current_path[lun] = path->id; + + /* If we selected a new path, do failover notification. */ + if (path != orig_path) { + status = qla2x00_send_failover_notify( + dp, lun, path, orig_path); + + /* + * Currently we ignore the returned status from + * the notify. however, if failover notify fails + */ + } + } + + LEAVE("qla2x00_select_next_path:"); + + return path ; +} + + + +/* + * qla2x00_update_mp_host + * Update the multipath control information from the port + * database for that adapter. + * + * Input: + * host Adapter to update. Devices that are new are + * known to be attached to this adapter. + * + * Returns: + * TRUE if updated successfully; FALSE if error. + * + */ +static uint8_t +qla2x00_update_mp_host(mp_host_t *host) +{ + uint8_t success = TRUE; + uint16_t dev_id; + struct list_head *fcpl; + fc_port_t *fcport; + scsi_qla_host_t *ha = host->ha; + + ENTER("qla2x00_update_mp_host"); + + /* + * We make sure each port is attached to some virtual device. + */ + dev_id = 0; + fcport = NULL; + list_for_each(fcpl, &ha->fcports) { + fcport = list_entry(fcpl, fc_port_t, list); + + success |= qla2x00_update_mp_device(host, fcport, dev_id, 0); + + dev_id++; + } + if (success) { + DEBUG2(printk(KERN_INFO "%s: Exit OK\n", __func__);) + qla2x00_map_os_targets(host); + } else { + /* EMPTY */ + DEBUG2(printk(KERN_INFO "%s: Exit FAILED\n", __func__);) + } + + DEBUG3(printk("%s: inst %ld exiting.\n", __func__, ha->instance);) + LEAVE("qla2x00_update_mp_host"); + + return success; +} + +/* + * qla2x00_update_mp_device + * Update the multipath control information from the port + * database for that adapter. + * + * Inputs: + * host Host adapter structure + * port Device to add to the path tree. + * dev_id Device id + * + * Synchronization: + * The Adapter Lock should have already been acquired + * before calling this routine. + * + * Return + * TRUE if updated successfully; FALSE if error. + * + */ +uint8_t +qla2x00_update_mp_device(mp_host_t *host, + fc_port_t *port, uint16_t dev_id, uint16_t pathid) +{ + uint8_t success = TRUE; + mp_device_t *dp; + mp_path_t *path; + + ENTER("qla2x00_update_mp_device"); + + DEBUG3(printk("%s(%ld): entered. host %p inst=%d, port =%p-%02x%02x" + "%02x%02x%02x%02x%02x%02x, dev id = %d\n", + __func__, host->ha->host_no, host, host->instance, port, + port->port_name[0], port->port_name[1], + port->port_name[2], port->port_name[3], + port->port_name[4], port->port_name[5], + port->port_name[6], port->port_name[7], + dev_id);) + + if (!qla2x00_is_ww_name_zero(port->port_name)) { + + /* + * Search for a device with a matching node name, + * or create one. + */ + dp = qla2x00_find_or_allocate_mp_dev(host, dev_id, port); + + /* + * We either have found or created a path list. Find this + * host's path in the path list or allocate a new one + * and add it to the list. + */ + if (dp == NULL) { + /* We did not create a mp_dev for this port. */ + port->mp_byte |= MP_MASK_UNCONFIGURED; + DEBUG4(printk("%s: Device NOT found or created at " + " dev_id=%d.\n", + __func__, dev_id);) + return FALSE; + } + + /* + * Find the path in the current path list, or allocate + * a new one and put it in the list if it doesn't exist. + * Note that we do NOT set bSuccess to FALSE in the case + * of failure here. We must tolerate the situation where + * the customer has more paths to a device than he can + * get into a PATH_LIST. + */ + + path = qla2x00_find_or_allocate_path(host, dp, dev_id, + pathid, port); + if (path == NULL) { + DEBUG4(printk("%s:Path NOT found or created.\n", + __func__);) + return FALSE; + } + + /* Set the PATH flag to match the device flag + * of whether this device needs a relogin. If any + * device needs relogin, set the relogin countdown. + */ + if (port->flags & FCF_CONFIG) + path->config = TRUE; + + if (atomic_read(&port->state) != FCS_ONLINE) { + path->relogin = TRUE; + if (host->relogin_countdown == 0) + host->relogin_countdown = 30; + } else { + path->relogin = FALSE; + } + + } else { + /* EMPTY */ + DEBUG4(printk("%s: Failed portname empty.\n", + __func__);) + } + + DEBUG3(printk("%s(%ld): exiting.\n", + __func__, host->ha->host_no);) + LEAVE("qla2x00_update_mp_device"); + + return success; +} + +/* + * qla2x00_update_mp_tree + * Get port information from each adapter, and build or rebuild + * the multipath control tree from this data. This is called + * from init and during port database notification. + * + * Input: + * None + * + * Return: + * Local function return code. + * + */ +static uint32_t +qla2x00_update_mp_tree(void) +{ + mp_host_t *host; + uint32_t rval = QLA_SUCCESS; + + ENTER("qla2x00_update_mp_tree:"); + + /* Loop through each adapter and see what needs updating. */ + for (host = mp_hosts_base; (host) ; host = host->next) { + + DEBUG4(printk("%s: hba(%d) flags (%x)\n", + __func__, host->instance, host->flags);) + /* Clear the countdown; it may be reset in the update. */ + host->relogin_countdown = 0; + + /* Override the NEEDS_UPDATE flag if disabled. */ + if (host->flags & MP_HOST_FLAG_DISABLE || + list_empty(host->fcports)) + host->flags &= ~MP_HOST_FLAG_NEEDS_UPDATE; + + if (host->flags & MP_HOST_FLAG_NEEDS_UPDATE) { + + /* + * Perform the actual updates. If this succeeds, clear + * the flag that an update is needed, and failback all + * devices that are visible on this path to use this + * path. If the update fails, leave set the flag that + * an update is needed, and it will be picked back up + * during the next timer routine. + */ + if (qla2x00_update_mp_host(host)) { + host->flags &= ~MP_HOST_FLAG_NEEDS_UPDATE; + + qla2x00_failback_luns(host); + } else + rval = QLA_FUNCTION_FAILED; + + } + + } + + if (rval != QLA_SUCCESS) { + /* EMPTY */ + DEBUG4(printk("%s: Exit FAILED.\n", __func__);) + + } else { + /* EMPTY */ + DEBUG4(printk("%s: Exit OK.\n", __func__);) + } + return rval; +} + + + +/* + * qla2x00_find_matching_lun + * Find the lun in the path that matches the + * specified lun number. + * + * Input: + * lun = lun number + * newpath = path to search for lun + * + * Returns: + * NULL or pointer to lun + * + * Context: + * Kernel context. + * (dg) + */ +static fc_lun_t * +qla2x00_find_matching_lun(uint8_t lun, mp_path_t *newpath) +{ + fc_lun_t *lp = NULL; /* lun ptr */ + struct list_head *fcll; + fc_lun_t *nlp; /* Next lun ptr */ + fc_port_t *fcport; /* port ptr */ + + if ((fcport = newpath->port) != NULL) { + list_for_each(fcll, &fcport->fcluns) { + nlp = list_entry(fcll, fc_lun_t, list); + + if (lun == nlp->lun) { + lp = nlp; + break; + } + } + } + return lp; +} + +/* + * qla2x00_find_path_by_name + * Find the path specified portname from the pathlist + * + * Input: + * host = host adapter pointer. + * pathlist = multi-path path list + * portname portname to search for + * + * Returns: + * pointer to the path or NULL + * + * Context: + * Kernel context. + */ +mp_path_t * +qla2x00_find_path_by_name(mp_host_t *host, mp_path_list_t *plp, + uint8_t *portname) +{ + mp_path_t *path = NULL; /* match if not NULL */ + mp_path_t *tmp_path; + int cnt; + + if ((tmp_path = plp->last) != NULL) { + for (cnt = 0; cnt < plp->path_cnt; cnt++) { + if (tmp_path->host == host && + qla2x00_is_portname_equal( + tmp_path->portname, portname)) { + + path = tmp_path; + break; + } + tmp_path = tmp_path->next; + } + } + return path ; +} + +/* + * qla2x00_find_path_by_id + * Find the path for the specified path id. + * + * Input: + * dp multi-path device + * id path id + * + * Returns: + * pointer to the path or NULL + * + * Context: + * Kernel context. + */ +static mp_path_t * +qla2x00_find_path_by_id(mp_device_t *dp, uint8_t id) +{ + mp_path_t *path = NULL; + mp_path_t *tmp_path; + mp_path_list_t *path_list; + int cnt; + + path_list = dp->path_list; + tmp_path = path_list->last; + for (cnt = 0; (tmp_path) && cnt < path_list->path_cnt; cnt++) { + if (tmp_path->id == id) { + path = tmp_path; + break; + } + tmp_path = tmp_path->next; + } + return path ; +} + +/* + * qla2x00_find_mp_dev_by_id + * Find the mp_dev for the specified target id. + * + * Input: + * host = host adapter pointer. + * tgt = Target id + * + * Returns: + * + * Context: + * Kernel context. + */ +static mp_device_t * +qla2x00_find_mp_dev_by_id(mp_host_t *host, uint8_t id ) +{ + if (id < MAX_MP_DEVICES) + return host->mp_devs[id]; + else + return NULL; +} + +/* + * qla2x00_find_mp_dev_by_nodename + * Find the mp_dev for the specified target name. + * + * Input: + * host = host adapter pointer. + * name = Target name + * + * Returns: + * + * Context: + * Kernel context. + */ +static mp_device_t * +qla2x00_find_mp_dev_by_nodename(mp_host_t *host, uint8_t *name ) +{ + int id; + mp_device_t *dp; + + ENTER("qla2x00_find_mp_dev_by_nodename"); + + for (id= 0; id < MAX_MP_DEVICES; id++) { + if ((dp = host->mp_devs[id] ) == NULL) + continue; + + if (qla2x00_is_nodename_equal(dp->nodename, name)) { + DEBUG3(printk("%s: Found matching device @ index %d:\n", + __func__, id);) + return dp; + } + } + + LEAVE("qla2x00_find_mp_dev_by_name"); + + return NULL; +} + +/* + * qla2x00_find_mp_dev_by_portname + * Find the mp_dev for the specified target name. + * + * Input: + * host = host adapter pointer. + * name = port name + * + * Returns: + * + * Context: + * Kernel context. + */ +static mp_device_t * +qla2x00_find_mp_dev_by_portname(mp_host_t *host, uint8_t *name, uint16_t *pidx) +{ + int id; + mp_device_t *dp; + + DEBUG3(printk("%s: entered.\n", __func__);) + + for (id= 0; id < MAX_MP_DEVICES; id++) { + if ((dp = host->mp_devs[id] ) == NULL) + continue; + + if (qla2x00_is_portname_in_device(dp, name)) { + DEBUG3(printk("%s: Found matching device @ index %d:\n", + __func__, id);) + *pidx = id; + return dp; + } + } + + DEBUG3(printk("%s: exiting.\n", __func__);) + + return NULL; + } + +/* + * qla2x00_find_dp_by_pn_from_all_hosts + * Search through all mp hosts to find the mp_dev for the + * specified port name. + * + * Input: + * pn = port name + * + * Returns: + * + * Context: + * Kernel context. + */ +static mp_device_t * +qla2x00_find_dp_by_pn_from_all_hosts(uint8_t *pn, uint16_t *pidx) +{ + int id; + mp_device_t *ret_dp = NULL; + mp_device_t *temp_dp = NULL; /* temporary pointer */ + mp_host_t *temp_host; /* temporary pointer */ + + DEBUG3(printk("%s: entered.\n", __func__);) + + for (temp_host = mp_hosts_base; (temp_host); + temp_host = temp_host->next) { + for (id= 0; id < MAX_MP_DEVICES; id++) { + temp_dp = temp_host->mp_devs[id]; + + if (temp_dp == NULL) + continue; + + if (qla2x00_is_portname_in_device(temp_dp, pn)) { + DEBUG3(printk( + "%s: Found matching dp @ host %p id %d:\n", + __func__, temp_host, id);) + ret_dp = temp_dp; + *pidx = id; + break; + } + } + if (ret_dp != NULL) { + /* found a match. */ + break; + } + } + + DEBUG3(printk("%s: exiting.\n", __func__);) + + return ret_dp; +} + +/* + * qla2x00_get_visible_path + * Find the the visible path for the specified device. + * + * Input: + * dp = device pointer + * + * Returns: + * NULL or path + * + * Context: + * Kernel context. + */ +static mp_path_t * +qla2x00_get_visible_path(mp_device_t *dp) +{ + uint16_t id; + mp_path_list_t *path_list; + mp_path_t *path; + + path_list = dp->path_list; + /* if we don't have a visible path skip it */ + if ((id = path_list->visible) == PATH_INDEX_INVALID) { + return NULL; + } + + if ((path = qla2x00_find_path_by_id(dp,id))== NULL) + return NULL; + + return path ; +} + +/* + * qla2x00_map_os_targets + * Allocate the luns and setup the OS target. + * + * Input: + * host = host adapter pointer. + * + * Returns: + * None + * + * Context: + * Kernel context. + */ +static void +qla2x00_map_os_targets(mp_host_t *host) +{ + scsi_qla_host_t *ha = host->ha; + mp_path_t *path; + mp_device_t *dp; + os_tgt_t *tgt; + int t; + + ENTER("qla2x00_map_os_targets "); + + for (t = 0; t < MAX_TARGETS; t++ ) { + dp = host->mp_devs[t]; + if (dp != NULL) { + DEBUG3(printk("%s: (%d) found a dp=%p, " + "host=%p, ha=%p\n", + __func__, t, dp, host,ha);) + + if ((path = qla2x00_get_visible_path(dp)) == NULL) { + printk(KERN_INFO + "qla_cfg(%d): No visible path " + "for target %d, dp = %p\n", + host->instance, t, dp); + continue; + } + + /* if not the visible path skip it */ + if (path->host == host) { + if (TGT_Q(ha, t) == NULL) { + tgt = qla2x00_tgt_alloc(ha, t); + memcpy(tgt->node_name, + dp->nodename, + WWN_SIZE); + tgt->fcport = path->port; + } + DEBUG3(printk("%s(%ld): host=%d, " + "device= %p has VISIBLE " + "path=%p, path id=%d\n", + __func__, ha->host_no, + host->instance, + dp, path, path->id);) + } else { + /* EMPTY */ + DEBUG3(printk("%s(%ld): host=%d, " + "device= %p has HIDDEN " + "path=%p, path id=%d\n", + __func__, ha->host_no, + host->instance, dp, path,path->id);) + } + qla2x00_map_os_luns(host, dp, t); + } else { + if ((tgt= TGT_Q(ha,t)) != NULL) { + qla2x00_tgt_free(ha,t); + } + } + } + + LEAVE("qla2x00_map_os_targets "); +} + +/* + * qla2x00_map_os_luns + * Allocate the luns for the OS target. + * + * Input: + * dp = pointer to device + * t = OS target number. + * + * Returns: + * None + * + * Context: + * Kernel context. + */ +static void +qla2x00_map_os_luns(mp_host_t *host, mp_device_t *dp, uint16_t t) +{ + uint16_t lun; + int i; + + for (lun = 0; lun < MAX_LUNS; lun++ ) { + if ( qla2x00_map_a_oslun(host, dp, t, lun) && + (host->flags & MP_HOST_FLAG_LUN_FO_ENABLED) ){ + /* find a path for us to use */ + for ( i = 0; i < dp->path_list->path_cnt; i++ ){ + qla2x00_select_next_path(host, dp, lun); + if( !qla2x00_map_a_oslun(host, dp, t, lun)) + break; + } + } + } +} + +/* + * qla2x00_map_a_osluns + * Map the OS lun to the current path + * + * Input: + * host = pointer to host + * dp = pointer to device + * lun = OS lun number. + * + * Returns: + * None + * + * Context: + * Kernel context. + */ + +static uint8_t +qla2x00_map_a_oslun(mp_host_t *host, mp_device_t *dp, uint16_t t, uint16_t lun) +{ + fc_port_t *fcport; + fc_lun_t *fclun; + os_lun_t *lq; + uint16_t id; + mp_path_t *path, *vis_path; + mp_host_t *vis_host; + uint8_t status = FALSE; + + if ((id = dp->path_list->current_path[lun]) != PATH_INDEX_INVALID) { + path = qla2x00_find_path_by_id(dp,id); + if (path) { + fcport = path->port; + if (fcport) { + /* dg 04/26/02 */ + fcport->cur_path = id; + fclun = qla2x00_find_matching_lun(lun,path); + + /* Always map all luns if they are enabled */ + if (fclun && + (path->lun_data.data[lun] & + LUN_DATA_ENABLED) ) { + + /* + * Mapped lun on the visible path + */ + if ((vis_path = + qla2x00_get_visible_path(dp)) == + NULL ) { + + printk(KERN_INFO + "qla2x00(%d): No visible " + "path for target %d, " + "dp = %p\n", + host->instance, + t, dp); + + return FALSE; + } + + vis_host = vis_path->host; + + /* ra 11/30/01 */ + /* + * Always alloc LUN 0 so kernel + * will scan past LUN 0. + */ + if (lun != 0 && + (EXT_IS_LUN_BIT_SET( + &(fcport->lun_mask), lun))) { + + /* mask this LUN */ + return FALSE; + } + + if ((lq = qla2x00_lun_alloc( + vis_host->ha, + t, lun)) != NULL) { + + lq->fclun = fclun; + } + } + } + else + status = TRUE; + } + } + return status; +} + +/* + * qla2x00_is_ww_name_zero + * + * Input: + * ww_name = Pointer to WW name to check + * + * Returns: + * TRUE if name is 0 else FALSE + * + * Context: + * Kernel context. + */ +static uint8_t +qla2x00_is_ww_name_zero(uint8_t *nn) +{ + int cnt; + + /* Check for zero node name */ + for (cnt = 0; cnt < WWN_SIZE ; cnt++, nn++) { + if (*nn != 0) + break; + } + /* if zero return TRUE */ + if (cnt == WWN_SIZE) + return TRUE; + else + return FALSE; +} + +/* + * qla2x00_add_path + * Add a path to the pathlist + * + * Input: + * pathlist -- path list of paths + * path -- path to be added to list + * + * Returns: + * None + * + * Context: + * Kernel context. + */ +static void +qla2x00_add_path( mp_path_list_t *pathlist, mp_path_t *path ) +{ + mp_path_t *last = pathlist->last; + + ENTER("qla2x00_add_path"); + DEBUG3(printk("%s: entered for path id %d.\n", + __func__, path->id);) + + DEBUG3(printk("%s: pathlist =%p, path =%p, cnt = %d\n", + __func__, pathlist, path, pathlist->path_cnt);) + if (last == NULL) { + last = path; + } else { + path->next = last->next; + } + + last->next = path; + pathlist->last = path; + pathlist->path_cnt++; + + DEBUG3(printk("%s: exiting. path cnt=%d.\n", + __func__, pathlist->path_cnt);) + LEAVE("qla2x00_add_path"); +} + + +/* + * qla2x00_is_portname_in_device + * Search for the specified "portname" in the device list. + * + * Input: + * dp = device pointer + * portname = portname to searched for in device + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +uint8_t +qla2x00_is_portname_in_device(mp_device_t *dp, uint8_t *portname) +{ + int idx; + + for (idx = 0; idx < MAX_PATHS_PER_DEVICE; idx++) { + if (memcmp(&dp->portnames[idx][0], portname, WWN_SIZE) == 0) + return TRUE; + } + return FALSE; +} + + +/* + * qla2x00_set_lun_data_from_bitmask + * Set or clear the LUN_DATA_ENABLED bits in the LUN_DATA from + * a LUN bitmask provided from the miniport driver. + * + * Inputs: + * lun_data = Extended LUN_DATA buffer to set. + * lun_mask = Pointer to lun bit mask union. + * + * Return Value: none. + */ +void +qla2x00_set_lun_data_from_bitmask(mp_lun_data_t *lun_data, + lun_bit_mask_t *lun_mask) +{ + int16_t lun; + + ENTER("qla2x00_set_lun_data_from_bitmask"); + + for (lun = 0; lun < MAX_LUNS; lun++) { + /* our bit mask is inverted */ + if (!(EXT_IS_LUN_BIT_SET(lun_mask,lun))) + lun_data->data[lun] |= LUN_DATA_ENABLED; + else + lun_data->data[lun] &= ~LUN_DATA_ENABLED; + + DEBUG5(printk("%s: lun data[%d] = 0x%x\n", + __func__, lun, lun_data->data[lun]);) + } + + LEAVE("qla2x00_set_lun_data_from_bitmask"); + + return; +} + +static void +qla2x00_failback_single_lun(mp_device_t *dp, uint8_t lun, uint8_t new) +{ + mp_path_list_t *pathlist; + mp_path_t *new_path, *old_path; + uint8_t old; + mp_host_t *host; + os_lun_t *lq; + mp_path_t *vis_path; + mp_host_t *vis_host; + + /* Failback and update statistics. */ + if ((pathlist = dp->path_list) == NULL) + return; + + old = pathlist->current_path[lun]; + pathlist->current_path[lun] = new; + + if ((new_path = qla2x00_find_path_by_id(dp, new)) == NULL) + return; + if ((old_path = qla2x00_find_path_by_id(dp, old)) == NULL) + return; + + /* An fclun should exist for the failbacked lun */ + if (qla2x00_find_matching_lun(lun, new_path) == NULL) + return; + if (qla2x00_find_matching_lun(lun, old_path) == NULL) + return; + + /* Log to console and to event log. */ + printk(KERN_INFO + "qla2x00: FAILBACK device %d -> " + "%02x%02x%02x%02x%02x%02x%02x%02x LUN %02x\n", + dp->dev_id, + dp->nodename[0], dp->nodename[1], + dp->nodename[2], dp->nodename[3], + dp->nodename[4], dp->nodename[5], + dp->nodename[6], dp->nodename[7], + lun); + + printk(KERN_INFO + "qla2x00: FROM HBA %d to HBA %d \n", + old_path->host->instance, + new_path->host->instance); + + + /* Send a failover notification. */ + qla2x00_send_failover_notify(dp, lun, new_path, old_path); + + host = new_path->host; + + /* remap the lun */ + qla2x00_map_a_oslun(host, dp, dp->dev_id, lun); + + /* 7/16 + * Reset counts on the visible path + */ + if ((vis_path = qla2x00_get_visible_path(dp)) == NULL) { + printk(KERN_INFO + "qla2x00(%d): No visible path for " + "target %d, dp = %p\n", + host->instance, + dp->dev_id, dp); + return; + } + + vis_host = vis_path->host; + if ((lq = qla2x00_lun_alloc(vis_host->ha, dp->dev_id, lun)) != NULL) { + qla2x00_delay_lun(vis_host->ha, lq, ql2xrecoveryTime); + qla2x00_flush_failover_q(vis_host->ha, lq); + qla2x00_reset_lun_fo_counts(vis_host->ha, lq); + } +} + +/* +* qla2x00_failback_luns +* This routine looks through the devices on an adapter, and +* for each device that has this adapter as the visible path, +* it forces that path to be the current path. This allows us +* to keep some semblance of static load balancing even after +* an adapter goes away and comes back. +* +* Arguments: +* host Adapter that has just come back online. +* +* Return: +* None. +*/ +static void +qla2x00_failback_luns( mp_host_t *host) +{ + uint16_t dev_no; + uint8_t l; + uint16_t lun; + int i; + mp_device_t *dp; + mp_path_list_t *path_list; + mp_path_t *path; + fc_lun_t *new_fp; + + ENTER("qla2x00_failback_luns"); + + for (dev_no = 0; dev_no < MAX_MP_DEVICES; dev_no++) { + dp = host->mp_devs[dev_no]; + + if (dp == NULL) + continue; + + path_list = dp->path_list; + for (path = path_list->last, i= 0; + i < path_list->path_cnt; + i++, path = path->next) { + + if (path->host != host ) + continue; + + if (path->port == NULL) + continue; + + if (atomic_read(&path->port->state) == FCS_DEVICE_DEAD) + continue; + + /* + * Failback all the paths for this host, + * the luns could be preferred across all paths + */ + DEBUG(printk("%s(%d): Lun Data for device %p, " + "id=%d, path id=%d\n", + __func__, host->instance, dp, dp->dev_id, + path->id);) + DEBUG4(qla2x00_dump_buffer( + (char *)&path->lun_data.data[0], 64);) + DEBUG4(printk("%s(%d): Perferrred Path data:\n", + __func__, host->instance);) + DEBUG4(qla2x00_dump_buffer( + (char *)&path_list->current_path[0], 64);) + + for (lun = 0; lun < MAX_LUNS_PER_DEVICE; lun++) { + l = (uint8_t)(lun & 0xFF); + + /* + * if this is the preferred lun and not + * the current path then failback lun. + */ + DEBUG4(printk("%s: target=%d, cur path id =%d, " + "lun data[%d] = %d)\n", + __func__, dp->dev_id, path->id, + lun, path->lun_data.data[lun]);) + + if ((path->lun_data.data[l] & + LUN_DATA_PREFERRED_PATH) && + /* !path->relogin && */ + path_list->current_path[l] != + path->id) { + /* No point in failing back a + disconnected lun */ + new_fp = qla2x00_find_matching_lun( + l, path); + + if (new_fp == NULL) + continue; + + qla2x00_failback_single_lun( + dp, l, path->id); + } + } + } + + } + + LEAVE("qla2x00_failback_luns"); + + return; +} + +/* + * qla2x00_setup_new_path + * Checks the path against the existing paths to see if there + * are any incompatibilities. It then checks and sets up the + * current path indices. + * + * Inputs: + * dp = pointer to device + * path = new path + * + * Returns: + * None + */ +static void +qla2x00_setup_new_path( mp_device_t *dp, mp_path_t *path) +{ + mp_path_list_t *path_list = dp->path_list; + mp_path_t *tmp_path, *first_path; + mp_host_t *first_host; + mp_host_t *tmp_host; + + uint16_t lun; + uint8_t l; + int i; + + ENTER("qla2x00_setup_new_path"); + + /* If this is a visible path, and there is not already a + * visible path, save it as the visible path. If there + * is already a visible path, log an error and make this + * path invisible. + */ + if (!(path->mp_byte & (MP_MASK_HIDDEN | MP_MASK_UNCONFIGURED))) { + + /* No known visible path */ + if (path_list->visible == PATH_INDEX_INVALID) { + DEBUG3(printk("%s: No know visible path - make this " + "path visible\n", + __func__);) + + path_list->visible = path->id; + path->mp_byte &= ~MP_MASK_HIDDEN; + } else { + DEBUG3(printk("%s: Second visible path found- make " + "this one hidden\n", + __func__);) + + path->mp_byte |= MP_MASK_HIDDEN; + } + if (path->port) + path->port->mp_byte = path->mp_byte; + } + + /* + * If this is not the first path added, and the setting for + * MaxLunsPerTarget does not match that of the first path + * then disable qla_cfg for all adapters. + */ + first_path = qla2x00_find_path_by_id(dp, 0); + + if (first_path != NULL) { + first_host = first_path->host; + if ((path->id != 0) && + (first_host->MaxLunsPerTarget != + path->host->MaxLunsPerTarget)) { + + for (tmp_path = path_list->last, i = 0; + (tmp_path) && i <= path->id; i++) { + + tmp_host = tmp_path->host; + if (!(tmp_host->flags & + MP_HOST_FLAG_DISABLE)) { + + DEBUG4(printk("%s: 2nd visible " + "path (%p)\n", + __func__, tmp_host);) + + tmp_host->flags |= MP_HOST_FLAG_DISABLE; + } + } + } + } + + /* + * For each LUN, evaluate whether the new path that is added + * is better than the existing path. If it is, make it the + * current path for the LUN. + */ + for (lun = 0; lun < MAX_LUNS_PER_DEVICE; lun++) { + l = (uint8_t)(lun & 0xFF); + + /* If this is the first path added, it is the only + * available path, so make it the current path. + */ + + DEBUG4(printk("%s: lun_data 0x%x, LUN %d\n", + __func__, path->lun_data.data[l], lun);) + + if (first_path == path) { + path_list->current_path[l] = 0; + path->lun_data.data[l] |= LUN_DATA_PREFERRED_PATH; + } else if (path->lun_data.data[l] & LUN_DATA_PREFERRED_PATH) { + /* + * If this is not the first path added, if this is + * the preferred path, make it the current path. + */ + path_list->current_path[l] = path->id; + } + } + + LEAVE("qla2x00_setup_new_path"); + + return; +} + +/* + * qla2x00_cfg_mem_free + * Free all configuration structures. + * + * Input: + * ha = adapter state pointer. + * + * Context: + * Kernel context. + */ +void +qla2x00_cfg_mem_free(scsi_qla_host_t *ha) +{ + mp_device_t *dp; + mp_path_list_t *path_list; + mp_path_t *tmp_path, *path; + mp_host_t *host, *temp; + int id, cnt; + + if ((host = qla2x00_cfg_find_host(ha)) != NULL) { + if( mp_num_hosts == 0 ) + return; + + for (id= 0; id < MAX_MP_DEVICES; id++) { + if ((dp = host->mp_devs[id]) == NULL) + continue; + if ((path_list = dp->path_list) == NULL) + continue; + if ((tmp_path = path_list->last) == NULL) + continue; + for (cnt = 0; cnt < path_list->path_cnt; cnt++) { + path = tmp_path; + tmp_path = tmp_path->next; + DEBUG(printk(KERN_INFO + "host%d - Removing path[%d] " + "= %p\n", + host->instance, + cnt, path);) + KMEM_FREE(path,sizeof(mp_path_t)); + } + KMEM_FREE(path_list, sizeof(mp_path_list_t)); + host->mp_devs[id] = NULL; + /* remove dp from other hosts */ + for (temp = mp_hosts_base; (temp); temp = temp->next) { + if (temp->mp_devs[id] == dp) { + DEBUG(printk(KERN_INFO + "host%d - Removing host[%d] = " + "%p\n", + host->instance, + temp->instance,temp);) + temp->mp_devs[id] = NULL; + } + } + KMEM_FREE(dp, sizeof(mp_device_t)); + } + + /* remove this host from host list */ + temp = mp_hosts_base; + if (temp != NULL) { + /* Remove from top of queue */ + if (temp == host) { + mp_hosts_base = host->next; + } else { + /* + * Remove from middle of queue + * or bottom of queue + */ + for (temp = mp_hosts_base; + temp != NULL; + temp = temp->next) { + + if (temp->next == host) { + temp->next = host->next; + break; + } + } + } + } + KMEM_FREE(host, sizeof(mp_host_t)); + mp_num_hosts--; + } +} + +int +__qla2x00_is_fcport_in_config(scsi_qla_host_t *ha, fc_port_t *fcport) +{ + mp_device_t *dp; + mp_host_t *host; + mp_path_t *path; + mp_path_list_t *pathlist; + uint16_t dev_no; + + /* no configured devices */ + host = qla2x00_cfg_find_host(ha); + if (!host) + return (FALSE); + + for (dev_no = 0; dev_no < MAX_MP_DEVICES; dev_no++) { + dp = host->mp_devs[dev_no]; + + if (dp == NULL) + continue; + + /* Sanity check */ + if (qla2x00_is_wwn_zero(dp->nodename)) + continue; + + if ((pathlist = dp->path_list) == NULL) + continue; + + path = qla2x00_find_path_by_name(host, dp->path_list, + fcport->port_name); + if (path != NULL) { + /* found path for port */ + if (path->config == TRUE) + return (TRUE); + break; + } + } + + return (FALSE); +} diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qla_cfg.h 830-ivtv/drivers/scsi/qla2xxx/qla_cfg.h --- 000-virgin/drivers/scsi/qla2xxx/qla_cfg.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qla_cfg.h Thu Jan 8 10:22:00 2004 @@ -0,0 +1,182 @@ +/****************************************************************************** + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + ******************************************************************************/ + +/* + * QLogic ISP2x00 Multi-path LUN Support + * Multi-path include file. + */ + +#if !defined(_QLA_CFG_H) +#define _QLA_CFG_H + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/* + * Failover definitions + */ +#define FAILOVER_TYPE_COUNT 4 +#define MP_NOTIFY_RESET_DETECTED 1 +#define MP_NOTIFY_PWR_LOSS 2 +#define MP_NOTIFY_LOOP_UP 3 +#define MP_NOTIFY_LOOP_DOWN 4 +#define MP_NOTIFY_BUS_RESET 5 +#define FAILOVER_TYPE_ERROR_RETRY 1 +#define MAX_NUMBER_PATHS FO_MAX_PATHS +#define PORT_NAME_SIZE WWN_SIZE +#define FAILOVER_NOTIFY_STATUS_ERROR QLA_SUCCESS +#define FAILOVER_NOTIFY_STATUS_SUCCESS QLA_SUCCESS +#define FAILOVER_NOTIFY_CDB_LENGTH_MAX FO_NOTIFY_CDB_LENGTH_MAX +#define MAX_TARGETS_PER_DEVICE SDM_DEF_MAX_TARGETS_PER_DEVICE + +/* + * Limits definitions. + */ +#define MAX_LUNS_PER_DEVICE MAX_LUNS /* Maximum # of luns */ +#define MAX_MP_DEVICES MAX_TARGETS /* Maximum # of virtual devs */ +#define MAX_PATHS_PER_DEVICE 8 /* Maximum # of paths */ +#if !defined(MAX_LUNS) +#define MAX_LUNS 256 +#endif +#define MAX_HOSTS MAX_HOST_COUNT + +/* Async notification types */ +#define NOTIFY_EVENT_LINK_DOWN 1 /* Link went down */ +#define NOTIFY_EVENT_LINK_UP 2 /* Link is back up */ +#define NOTIFY_EVENT_RESET_DETECTED 3 /* Reset detected */ + +/* MACROS */ +#define qla2x00_is_portname_equal(N1,N2) \ + ((memcmp((N1),(N2),WWN_SIZE)==0?TRUE:FALSE)) +#define qla2x00_is_nodename_equal(N1,N2) \ + ((memcmp((N1),(N2),WWN_SIZE)==0?TRUE:FALSE)) +#if 0 +#define qla2x00_allocate_path_list() \ + ((mp_path_list_t *)KMEM_ZALLOC(sizeof(mp_path_list_t))) +#endif + +/* + * Per-multipath driver parameters + */ +typedef struct _mp_lun_data { + uint8_t data[MAX_LUNS]; +#define LUN_DATA_ENABLED BIT_7 +#define LUN_DATA_PREFERRED_PATH BIT_6 +} +mp_lun_data_t; + + +#define PATH_INDEX_INVALID 0xff + +/* + * Per-device collection of all paths. + */ +typedef struct _mp_path_list { + struct _mp_path *last; /* ptrs to end of circular list of paths */ + uint8_t path_cnt; /* number of paths */ + uint8_t visible; /* visible path */ + uint16_t reserved1; /* Memory alignment */ + uint32_t reserved2; /* Memory alignment */ + uint8_t current_path[ MAX_LUNS_PER_DEVICE ]; /* current path for a given lun */ + uint16_t failover_cnt[ FAILOVER_TYPE_COUNT ]; +} +mp_path_list_t; + +/* + * Definitions for failover notify SRBs. These SRBs contain failover notify + * CDBs to notify a target that a failover has occurred. + * + */ +typedef struct _failover_notify_srb { + srb_t *srb; + uint16_t status; + uint16_t reserved; +} +failover_notify_srb_t; + +/* + * Per-device multipath control data. + */ +typedef struct _mp_device { + mp_path_list_t *path_list; /* Path list for device. */ + int dev_id; + int use_cnt; /* number of users */ + uint8_t nodename[WWN_SIZE]; /* World-wide node name. */ + /* World-wide port names. */ + uint8_t portnames[MAX_PATHS_PER_DEVICE][WWN_SIZE]; +} +mp_device_t; + +/* + * Per-adapter multipath Host + */ +typedef struct _mp_host { + struct _mp_host *next; /* ptr to next host adapter in list */ + scsi_qla_host_t *ha; /* ptr to lower-level driver adapter struct */ + int instance; /* OS instance number */ + struct list_head *fcports; /* Port chain for this adapter */ + mp_device_t *mp_devs[MAX_MP_DEVICES]; /* Multipath devices */ + + uint32_t flags; +#define MP_HOST_FLAG_NEEDS_UPDATE BIT_0 /* Need to update device data. */ +#define MP_HOST_FLAG_FO_ENABLED BIT_1 /* Failover enabled for this host */ +#define MP_HOST_FLAG_DISABLE BIT_2 /* Bypass qla_cfg. */ +#define MP_HOST_FLAG_LUN_FO_ENABLED BIT_3 /* lun Failover enabled */ + + uint8_t nodename[WWN_SIZE]; + uint8_t portname[WWN_SIZE]; + uint16_t MaxLunsPerTarget; + + uint16_t relogin_countdown; +} +mp_host_t; + +/* + * Describes path a single. + */ +typedef struct _mp_path { + struct _mp_path *next; /* next path in list */ + struct _mp_host *host; /* Pointer to adapter */ + fc_port_t *port; /* FC port info */ + uint16_t id; /* Path id (index) */ + uint8_t mp_byte; /* Multipath control byte */ +#define MP_MASK_HIDDEN 0x80 +#define MP_MASK_UNCONFIGURED 0x40 +#define MP_MASK_OVERRIDE 0x10 /* MC_MASK_SEPARATE_TARGETS */ +#define MP_MASK_PRIORITY 0x07 + + uint8_t relogin; /* Need to relogin to port */ + uint8_t config; /* User configured path */ + uint8_t reserved[3]; + mp_lun_data_t lun_data; /* Lun data information */ + uint8_t portname[WWN_SIZE]; /* Port name of this target. */ +} +mp_path_t; + +/* + * Failover notification requests from host driver. + */ +typedef struct failover_notify_entry { + struct scsi_address *os_addr; +} +failover_notify_t; + +#endif /* _QLA_CFG_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qla_cfgln.c 830-ivtv/drivers/scsi/qla2xxx/qla_cfgln.c --- 000-virgin/drivers/scsi/qla2xxx/qla_cfgln.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qla_cfgln.c Thu Jan 8 10:22:00 2004 @@ -0,0 +1,742 @@ +/****************************************************************************** + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + ******************************************************************************/ + +/* + * QLogic ISP2x00 Multi-path LUN Support Driver + * Solaris specific functions + * + */ + +#include "qla_os.h" +#include "qla_def.h" + +#include "qlfo.h" + +#define MAX_SEARCH_STR_SIZE 512 + +/* + * qla2x00_set_lun_data_from_config + * Set lun_data byte from the configuration parameters. + * + * Input: + * host -- pointer to host adapter structure. + * port -- pointer to port + * tgt -- target number + * dev_no -- device number + */ +void +qla2x00_set_lun_data_from_config(mp_host_t *host, fc_port_t *port, + uint16_t tgt, uint16_t dev_no) +{ + char *propbuf; /* As big as largest search string */ + int rval; + int16_t lun, l; + scsi_qla_host_t *ha = host->ha; + mp_device_t *dp; + lun_bit_mask_t *plun_mask; + lun_bit_mask_t *mask_ptr; + mp_path_list_t *pathlist; +#if 0 + uint8_t control_byte; +#endif + + mp_path_t *path; + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&propbuf, + MAX_SEARCH_STR_SIZE)) { + /* not enough memory */ + DEBUG9_10(printk("%s(%ld): inst=%ld scrap not big enough. " + "propbuf requested=%d.\n", + __func__, ha->host_no, ha->instance, + MAX_SEARCH_STR_SIZE);) + return; + } + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&plun_mask, + sizeof(lun_bit_mask_t))) { + /* not enough memory */ + DEBUG9_10(printk("%s(%ld): inst=%ld scrap not big enough. " + "lun_mask requested=%ld.\n", + __func__, ha->host_no, ha->instance, + (ulong)sizeof(lun_bit_mask_t));) + qla2x00_free_ioctl_scrap_mem(ha); + return; + } + mask_ptr = plun_mask; + + dp = host->mp_devs[tgt]; + if (dp == NULL) { + printk("qla2x00_set_lun_data_from_config: Target %d " + "not found for hba %d\n",tgt, host->instance); + qla2x00_free_ioctl_scrap_mem(ha); + return; + } + if ( (pathlist = dp->path_list) == NULL ) { + printk("qla2x00_set_lun_data_from_config: path list " + "not found for target %d\n", tgt); + qla2x00_free_ioctl_scrap_mem(ha); + return; + } + + if ((path = qla2x00_find_path_by_name(host, pathlist, + port->port_name)) == NULL ) { + printk("qla2x00_set_lun_data_from_config: No path found " + "for target %d\n", tgt); + qla2x00_free_ioctl_scrap_mem(ha); + return; + } + + /* Get "target-N-device-N-preferred" as a 256 bit lun_mask*/ + sprintf(propbuf, "scsi-qla%ld-tgt-%d-di-%d-preferred", + ha->instance, tgt, dev_no); + DEBUG2(printk("build_tree: %s\n",propbuf);) + + rval = qla2x00_get_prop_xstr(ha, propbuf, + (uint8_t *)(plun_mask), sizeof(lun_bit_mask_t)); + + if (rval == -1) { + /* EMPTY */ + DEBUG2(printk("%s(%ld): no preferred mask entry found for " + "path id %d on port %02x%02x%02x%02x%02x%02x%02x%02x.\n", + __func__, ha->host_no, path->id, + path->portname[0], path->portname[1], + path->portname[2], path->portname[3], + path->portname[4], path->portname[5], + path->portname[6], path->portname[7]);) + } else { + if (rval != sizeof(lun_bit_mask_t)) { + /* EMPTY */ + printk("qla2x00_set_lun_data_from_config: " + "Preferred mask len %d is incorrect.\n", rval); + } + + DEBUG3(printk("%s(%ld): reading Preferred Mask for path id %d " + "on port %02x%02x%02x%02x%02x%02x%02x%02x:\n", + __func__, ha->host_no, path->id, + path->portname[0], path->portname[1], + path->portname[2], path->portname[3], + path->portname[4], path->portname[5], + path->portname[6], path->portname[7]);) + DEBUG3(qla2x00_dump_buffer((char *)plun_mask, + sizeof(lun_bit_mask_t));) + + for (lun = MAX_LUNS-1, l =0; lun >= 0; lun--, l++ ) { + if (EXT_IS_LUN_BIT_SET(mask_ptr, lun)) { + path->lun_data.data[l] |= + LUN_DATA_PREFERRED_PATH; + pathlist->current_path[l] = path->id; + } else { + path->lun_data.data[l] &= + ~LUN_DATA_PREFERRED_PATH; + } + } + + } + + /* Get "target-N-device-N-lun-disable" as a 256 bit lun_mask*/ + sprintf(propbuf, "scsi-qla%ld-tgt-%d-di-%d-lun-disabled", + ha->instance, tgt, dev_no); + DEBUG3(printk("build_tree: %s\n",propbuf);) + + rval = qla2x00_get_prop_xstr(ha, propbuf, + (uint8_t *)plun_mask, sizeof(lun_bit_mask_t)); + if (rval == -1) { + /* default: all luns enabled */ + DEBUG3(printk("%s(%ld): no entry found for path id %d. " + "Assume all LUNs enabled on port %02x%02x%02x%02x%02x%" + "02x%02x%02x.\n", + __func__, ha->host_no, path->id, + path->portname[0], path->portname[1], + path->portname[2], path->portname[3], + path->portname[4], path->portname[5], + path->portname[6], path->portname[7]);) + + for (lun = 0; lun < MAX_LUNS; lun++) { + path->lun_data.data[lun] |= LUN_DATA_ENABLED; + } + } else { + if (rval != sizeof(lun_bit_mask_t)) { + printk("qla2x00_set_lun_data_from_config: Enable " + "mask has wrong size %d != %ld\n", + rval, (ulong)sizeof(lun_bit_mask_t)); + } else { + for (lun = MAX_LUNS-1, l =0; lun >= 0; lun--, l++) { + /* our bit mask is inverted */ + if (!EXT_IS_LUN_BIT_SET(mask_ptr,lun)) + path->lun_data.data[l] |= + LUN_DATA_ENABLED; + else + path->lun_data.data[l] &= + ~LUN_DATA_ENABLED; + } + DEBUG3(printk("%s(%ld): got lun mask for path id %d " + "port %02x%02x%02x%02x%02x%02x%02x%02x:\n", + __func__, ha->host_no, path->id, + path->portname[0], path->portname[1], + path->portname[2], path->portname[3], + path->portname[4], path->portname[5], + path->portname[6], path->portname[7]);) + DEBUG3(qla2x00_dump_buffer( + (uint8_t *)&path->lun_data.data[0], 64);) + } + } + + DEBUG3(printk("qla2x00_set_lun_data_from_config: Luns data for " + "device %p, instance %d, path id=%d\n", + dp,host->instance,path->id);) + DEBUG3(qla2x00_dump_buffer((char *)&path->lun_data.data[0], 64);) + + qla2x00_free_ioctl_scrap_mem(ha); + LEAVE("qla2x00_set_lun_data_from_config"); +} + + + +/* + * qla2x00_cfg_build_path_tree + * Find all path properties and build a path tree. The + * resulting tree has no actual port assigned to it + * until the port discovery is done by the lower level. + * + * Input: + * ha = adapter block pointer. + * + * Context: + * Kernel context. + */ +void +qla2x00_cfg_build_path_tree(scsi_qla_host_t *ha) +{ + char *propbuf; + uint8_t node_name[WWN_SIZE]; + uint8_t port_name[WWN_SIZE]; + fc_port_t *port; + uint16_t dev_no = 0, tgt; + int instance, rval; + mp_host_t *host = NULL; + uint8_t *name; + int done; + uint8_t control_byte; + + + ENTER("qla2x00_cfg_build_path_tree"); + + printk(KERN_INFO + "qla02%d: ConfigRequired is set. \n", (int)ha->instance); + DEBUG(printk("qla2x00_cfg_build_path_tree: hba =%d", + (int)ha->instance);) + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&propbuf, + MAX_SEARCH_STR_SIZE)) { + /* not enough memory */ + DEBUG9_10(printk("%s(%ld): inst=%ld scrap not big enough. " + "propbuf requested=%d.\n", + __func__, ha->host_no, ha->instance, + MAX_SEARCH_STR_SIZE);) + return; + } + + /* Look for adapter nodename in properties */ + sprintf(propbuf, "scsi-qla%ld-adapter-port", ha->instance); + DEBUG(printk("build_tree: %s\n",propbuf);) + + rval = qla2x00_get_prop_xstr(ha, propbuf, port_name, WWN_SIZE); + if (rval != WWN_SIZE) { + qla2x00_free_ioctl_scrap_mem(ha); + return; + } + + /* Does nodename match the host adapter nodename? */ + name = &ha->init_cb->port_name[0]; + if (!qla2x00_is_nodename_equal(name, port_name)) { + printk(KERN_INFO + "scsi(%d): Adapter nodenames don't match - ha = %p.\n", + (int)ha->instance,ha); + DEBUG(printk("qla(%d): Adapter nodenames don't match - " + "ha=%p. port name=%02x%02x%02x%02x%02x%02x%02x%02x\n", + (int)ha->instance,ha, + name[0], name[1], name[2], name[3], + name[4], name[5], name[6], name[7]);) + qla2x00_free_ioctl_scrap_mem(ha); + return; + } + + DEBUG(printk("%s: found entry for adapter port %02x%02x%02x%02x" + "%02x%02x%02x%02x.\n", + __func__, + port_name[0], port_name[1], port_name[2], + port_name[3], port_name[4], port_name[5], + port_name[6], port_name[7]);) + + instance = ha->instance; + if ((host = qla2x00_alloc_host(ha)) == NULL) { + printk(KERN_INFO + "scsi(%d): Couldn't allocate host - ha = %p.\n", + (int)instance,ha); + } else { + /* create a dummy port */ + port = (fc_port_t *)KMEM_ZALLOC(sizeof (fc_port_t),9); + if (port == NULL) { + printk(KERN_INFO + "scsi(%d): Couldn't allocate port.\n", + (int)instance); + DEBUG(printk("qla(%d): Couldn't allocate port.\n", + (int)host->instance);) + /* remove host */ + qla2x00_free_ioctl_scrap_mem(ha); + return; + } + + done = 0; + + /* For each target on the host bus adapter */ + for (tgt= 0; tgt< MAX_MP_DEVICES && !done; tgt++) { + + /* get all paths for this target */ + for (dev_no = 0; dev_no < MAX_PATHS_PER_DEVICE && + !done ; dev_no++) { + + /* + * O(N*M) scan, should ideally check if there + * are any tgt entries present, if not, then + * continue. + * + * sprintf(propbuf, + * "scsi-qla%d-tgt-%d-", + * instance, tgt_no); + * if (strstr(ha->cmdline, propbuf) == NULL) + * continue; + * + */ + memset(port, 0, sizeof (fc_port_t)); + + /* + * Get "target-N-device-N-node" is a 16-chars + * number + */ + sprintf(propbuf, "scsi-qla%d-tgt-%d-di-%d-node", + instance, tgt, dev_no); + DEBUG(printk("build_tree: %s\n",propbuf);) + + rval = qla2x00_get_prop_xstr(ha, propbuf, + node_name, WWN_SIZE); + if (rval != WWN_SIZE) + /* + * di values may not be contiguous for + * override case. + */ + continue; + + memcpy(port->node_name, node_name, WWN_SIZE); + + /* + * Get "target-N-device-N-port" is a 16-chars + * number + */ + sprintf(propbuf, "scsi-qla%d-tgt-%d-di-%d-port", + instance, tgt, dev_no); + DEBUG(printk("build_tree: %s\n",propbuf);) + + rval = qla2x00_get_prop_xstr(ha, propbuf, + port_name, WWN_SIZE); + if (rval != WWN_SIZE) + continue; + + memcpy(port->node_name, node_name, WWN_SIZE); + memcpy(port->port_name, port_name, WWN_SIZE); + port->flags |= FCF_CONFIG; + + /* + * Get "target-N-device-N-control" if property + * is present then all luns are visible. + */ + sprintf(propbuf, + "scsi-qla%d-tgt-%d-di-%d-control", + instance, tgt, dev_no); + DEBUG3(printk("build_tree: %s\n",propbuf);) + + rval = qla2x00_get_prop_xstr(ha, propbuf, + (uint8_t *)(&control_byte), + sizeof(control_byte)); + if (rval == -1) { + /* error getting string. go to next. */ + DEBUG2(printk( + "%s: string parsing failed.\n", + __func__);) + continue; + } + + DEBUG(printk("build_tree: control byte 0x%x\n", + control_byte);) + + port->mp_byte = control_byte; + DEBUG(printk("%s(%ld): calling update_mp_device" + " for host %p port %p-%02x%02x%02x%02x%02x" + "%02x%02x%02x tgt=%d mpbyte=%02x.\n", + __func__, ha->host_no, host, port, + port->port_name[0], port->port_name[1], + port->port_name[2], port->port_name[3], + port->port_name[4], port->port_name[5], + port->port_name[6], port->port_name[7], + tgt, port->mp_byte);) + + qla2x00_update_mp_device(host, + port, tgt, dev_no); + qla2x00_set_lun_data_from_config(host, + port, tgt, dev_no); + } + } + KMEM_FREE(port, sizeof (fc_port_t)); + } + + qla2x00_free_ioctl_scrap_mem(ha); + + LEAVE("qla2x00_cfg_build_path_tree"); + DEBUG(printk("Leaving: qla2x00_cfg_build_path_tree\n");) +} + +/* + * qla2x00_cfg_display_devices + * This routine will the node names of the different devices found + * after port inquiry. + * + * Input: + * + * Returns: + * None. + */ +void qla2x00_cfg_display_devices(void) +{ + mp_host_t *host; + int id; + mp_device_t *dp; + mp_path_t *path; + mp_path_list_t *path_list; + int cnt, i, dev_no; + int instance; + lun_bit_mask_t lun_mask; + int mask_set; + uint8_t l; + + printk("qla2x00_cfg_display_devices\n"); + for (host = mp_hosts_base; (host); host = host->next) { + + instance = (int) host->instance; + /* Display the node name for adapter */ + printk(KERN_INFO + "scsi-qla%d-adapter-port=" + "%02x%02x%02x%02x%02x%02x%02x%02x\\;\n", + instance, + host->portname[0], + host->portname[1], + host->portname[2], + host->portname[3], + host->portname[4], + host->portname[5], + host->portname[6], + host->portname[7]); + + for (id = 0; id < MAX_MP_DEVICES; id++) { + if( (dp = host->mp_devs[id] ) == NULL ) + continue; + + path_list = dp->path_list; + + + if( (path = path_list->last) != NULL ) { + /* Print out device port names */ + path = path->next; /* first path */ + for (dev_no = 0, cnt = 0; + cnt < path_list->path_cnt; + path = path->next, cnt++) { + + /* skip others if not our host */ + if (host != path->host) + continue; + printk(KERN_INFO + "scsi-qla%d-tgt-%d-di-%d-node=" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x\\;\n", + instance, id, path->id, + dp->nodename[0], + dp->nodename[1], + dp->nodename[2], + dp->nodename[3], + dp->nodename[4], + dp->nodename[5], + dp->nodename[6], + dp->nodename[7]); + + /* port_name */ + printk(KERN_INFO + "scsi-qla%d-tgt-%d-di-%d-port=" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x\\;\n", + instance, id, path->id, + path->portname[0], + path->portname[1], + path->portname[2], + path->portname[3], + path->portname[4], + path->portname[5], + path->portname[6], + path->portname[7]); + + /* control byte */ + printk(KERN_INFO + "scsi-qla%d-tgt-%d-di-%d-" + "control=%02x\\;\n", + instance, id, path->id, + path->mp_byte); + + /* + * Build preferred bit mask for this + * path */ + memset(&lun_mask, 0, sizeof(lun_mask)); + mask_set = 0; + for (i = 0; i < MAX_LUNS; i++) { + l = (uint8_t)(i & 0xFF); + if (path_list->current_path[l] == path->id ) { + EXT_SET_LUN_BIT((&lun_mask),l); + mask_set++; + } + } + if (mask_set) { + printk(KERN_INFO + "scsi-qla%d-tgt-%d-di-%d-preferred=%08x%08x%08x%08x%08x%08x%08x%08x\\;\n", + instance, id, path->id, + *((uint32_t *) &lun_mask.mask[28]), + *((uint32_t *) &lun_mask.mask[24]), + *((uint32_t *) &lun_mask.mask[20]), + *((uint32_t *) &lun_mask.mask[16]), + *((uint32_t *) &lun_mask.mask[12]), + *((uint32_t *) &lun_mask.mask[8]), + *((uint32_t *) &lun_mask.mask[4]), + *((uint32_t *) &lun_mask.mask[0]) ); + } + /* + * Build disable bit mask for this path + */ + mask_set = 0; + for (i = 0; i < MAX_LUNS; i++) { + l = (uint8_t)(i & 0xFF); + if (!(path->lun_data.data[l] & + LUN_DATA_ENABLED) ) { + + mask_set++; + } + } + if (mask_set) { + printk(KERN_INFO + "scsi-qla%d-tgt-%d-di-%d-lun-disable=%08x%08x%08x%08x%08x%08x%08x%08x\\;\n", + instance, id, path->id, + *((uint32_t *) &lun_mask.mask[28]), + *((uint32_t *) &lun_mask.mask[24]), + *((uint32_t *) &lun_mask.mask[20]), + *((uint32_t *) &lun_mask.mask[16]), + *((uint32_t *) &lun_mask.mask[12]), + *((uint32_t *) &lun_mask.mask[8]), + *((uint32_t *) &lun_mask.mask[4]), + *((uint32_t *) &lun_mask.mask[0]) ); + } + dev_no++; + } + + } + } + } +} + +#if 0 +int qla2x00_cfg_build_range( mp_path_t *path, uint8_t *buf, int siz, uint8_t mask ) +{ + int i; + int max, min; + int colonflg = FALSE; + int len = 0; + + max = -1; + min = 0; + for (i = 0; i < MAX_LUNS; i++) { + if( (path->lun_data.data[i] & mask) ) { + max = i; + } else { + if( colonflg && max >= min ) { + len += sprintf(&buf[len],":"); + if( len > siz) + return len; + colonflg = FALSE; + } + if (max > min ) { + len += sprintf(&buf[len],"%02x-%02x",min,max); + if( len > siz) + return len; + colonflg = TRUE; + } else if ( max == min ) { + len += sprintf(&buf[len],"%02x",max); + if( len > siz) + return len; + colonflg = TRUE; + } + min = i + 1; + max = i; + } + } + DEBUG4(printk("build_range: return len =%d\n",len);) + return(len); +} +#endif + +#if 0 +/* + * qla2x00_cfg_proc_display_devices + * This routine will the node names of the different devices found + * after port inquiry. + * + * Input: + * + * Returns: + * None. + */ +int qla2x00_cfg_proc_display_devices(scsi_qla_host_t *ha) +{ + mp_host_t *host; + int id; + mp_device_t *dp; + mp_path_t *path; + mp_path_list_t *path_list; + int cnt, i; + int instance; + lun_bit_mask_t lun_mask; + int mask_set; + uint8_t l; + fc_port_t *port; + int len = 0; + + for (host = mp_hosts_base; (host); host = host->next) { + + if( host->ha != ha ) + continue; + + instance = (int) host->instance; + + /* Display the node name for adapter */ + len += sprintf(PROC_BUF, + "scsi-qla%d-adapter-node=" + "%02x%02x%02x%02x%02x%02x%02x%02x;\n", + instance, + host->nodename[0], + host->nodename[1], + host->nodename[2], + host->nodename[3], + host->nodename[4], + host->nodename[5], + host->nodename[6], + host->nodename[7]); + + + for (id = 0; id < MAX_MP_DEVICES; id++) { + if( (dp = host->mp_devs[id] ) == NULL ) + continue; + + path_list = dp->path_list; + + if( (path = path_list->last) != NULL ) { + /* Print out device port names */ + path = path->next; /* first path */ + for (cnt = 0; cnt < path_list->path_cnt; path = path->next, cnt++) { + /* skip others if not our host */ + if (host != path->host) + continue; + len += sprintf(PROC_BUF, + "scsi-qla%d-target-%d-path-%d-node=%02x%02x%02x%02x%02x%02x%02x%02x;\n", + instance, id, path->id, + dp->nodename[0], + dp->nodename[1], + dp->nodename[2], + dp->nodename[3], + dp->nodename[4], + dp->nodename[5], + dp->nodename[6], + dp->nodename[7]); + + /* port_name */ + len += sprintf(PROC_BUF, + "scsi-qla%d-target-%d-path-%d-port=%02x%02x%02x%02x%02x%02x%02x%02x;\n", + instance, id, path->id, + path->portname[0], + path->portname[1], + path->portname[2], + path->portname[3], + path->portname[4], + path->portname[5], + path->portname[6], + path->portname[7]); + + if( path_list->visible == path->id ) { + len += sprintf(PROC_BUF, "scsi-qla%d-target-%d-path-%d-visible=%02x;\n", + instance, id, path->id, path->id); + } + + len +=sprintf(PROC_BUF, "scsi-qla%d-target-%d-path-%d-control=%02x;\n", + instance, id, path->id, path->mp_byte); + + /* Build preferred bit mask for this path */ + memset(&lun_mask, 0, sizeof(lun_mask)); + mask_set = 0; + for (i = 0; i < MAX_LUNS_PER_DEVICE; i++) { + l = (uint8_t)(i & 0xFF); + if( path_list->current_path[l] == path->id ) { + EXT_SET_LUN_BIT((&lun_mask),l); + mask_set++; + } + } + if( mask_set && EXT_DEF_MAX_LUNS <= 256 ) { + len += sprintf(PROC_BUF, + "scsi-qla%d-target-%d-path-%d-preferred=%08x%08x%08x%08x%08x%08x%08x%08x;\n", + instance, id, path->id, + *((uint32_t *) &lun_mask.mask[0]), + *((uint32_t *) &lun_mask.mask[4]), + *((uint32_t *) &lun_mask.mask[8]), + *((uint32_t *) &lun_mask.mask[12]), + *((uint32_t *) &lun_mask.mask[16]), + *((uint32_t *) &lun_mask.mask[20]), + *((uint32_t *) &lun_mask.mask[24]), + *((uint32_t *) &lun_mask.mask[28]) ); + } + + len += sprintf(PROC_BUF, + "scsi-qla%d-target-%d-path-%d-lun-enable=%08x%08x%08x%08x%08x%08x%08x%08x;\n", + instance, id, path->id, + *((uint32_t *) &path->lun_data.data[0]), + *((uint32_t *) &path->lun_data.data[4]), + *((uint32_t *) &path->lun_data.data[8]), + *((uint32_t *) &path->lun_data.data[12]), + *((uint32_t *) &path->lun_data.data[16]), + *((uint32_t *) &path->lun_data.data[20]), + *((uint32_t *) &path->lun_data.data[24]), + *((uint32_t *) &path->lun_data.data[28]) ); + + } /* for */ + } + } + } + return( len ); +} +#endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qla_dbg.c 830-ivtv/drivers/scsi/qla2xxx/qla_dbg.c --- 000-virgin/drivers/scsi/qla2xxx/qla_dbg.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qla_dbg.c Thu Jan 8 10:22:00 2004 @@ -0,0 +1,1229 @@ +/* + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ +#include "qla_os.h" + +#include "qla_def.h" + +static int qla_uprintf(char **, char *, ...); + +/** + * qla2300_fw_dump() - Dumps binary data from the 2300 firmware. + * @ha: HA context + * @hardware_locked: Called with the hardware_lock + */ +void +qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked) +{ + int rval; + uint32_t cnt, timer; + uint32_t risc_address; + uint16_t mb0, mb2; + + uint32_t stat; + device_reg_t *reg; + uint16_t *dmp_reg; + unsigned long flags; + struct qla2300_fw_dump *fw; + + reg = ha->iobase; + risc_address = 0; + mb0 = mb2 = 0; + flags = 0; + + if (!hardware_locked) + spin_lock_irqsave(&ha->hardware_lock, flags); + + if (ha->fw_dump != NULL) { + qla_printk(KERN_WARNING, ha, + "Firmware has been previously dumped (%p) -- ignoring " + "request...\n", ha->fw_dump); + return; + } + + /* Allocate (large) dump buffer. */ + ha->fw_dump_order = get_order(sizeof(struct qla2300_fw_dump)); + ha->fw_dump = (struct qla2300_fw_dump *) __get_free_pages(GFP_ATOMIC, + ha->fw_dump_order); + if (ha->fw_dump == NULL) { + qla_printk(KERN_WARNING, ha, + "Unable to allocated memory for firmware dump (%d/%d).\n", + ha->fw_dump_order, sizeof(struct qla2300_fw_dump)); + return; + } + fw = ha->fw_dump; + + rval = QLA_SUCCESS; + fw->hccr = RD_REG_WORD(®->hccr); + + /* Pause RISC. */ + WRT_REG_WORD(®->hccr, HCCR_PAUSE_RISC); + if (!IS_QLA2312(ha) && !IS_QLA2322(ha)) { + for (cnt = 30000; + (RD_REG_WORD(®->hccr) & HCCR_RISC_PAUSE) == 0 && + rval == QLA_SUCCESS; cnt--) { + if (cnt) + udelay(100); + else + rval = QLA_FUNCTION_TIMEOUT; + } + } else { + udelay(10); + } + + if (rval == QLA_SUCCESS) { + dmp_reg = (uint16_t *)(reg + 0); + for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++) + fw->pbiu_reg[cnt] = RD_REG_WORD(dmp_reg++); + + dmp_reg = (uint16_t *)((uint8_t *)reg + 0x10); + for (cnt = 0; cnt < sizeof(fw->risc_host_reg) / 2; cnt++) + fw->risc_host_reg[cnt] = RD_REG_WORD(dmp_reg++); + + dmp_reg = (uint16_t *)((uint8_t *)reg + 0x40); + for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++) + fw->mailbox_reg[cnt] = RD_REG_WORD(dmp_reg++); + + WRT_REG_WORD(®->ctrl_status, 0x40); + dmp_reg = (uint16_t *)((uint8_t *)reg + 0x80); + for (cnt = 0; cnt < sizeof(fw->resp_dma_reg) / 2; cnt++) + fw->resp_dma_reg[cnt] = RD_REG_WORD(dmp_reg++); + + WRT_REG_WORD(®->ctrl_status, 0x50); + dmp_reg = (uint16_t *)((uint8_t *)reg + 0x80); + for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++) + fw->dma_reg[cnt] = RD_REG_WORD(dmp_reg++); + + WRT_REG_WORD(®->ctrl_status, 0x00); + dmp_reg = (uint16_t *)((uint8_t *)reg + 0xA0); + for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++) + fw->risc_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++); + + WRT_REG_WORD(®->pcr, 0x2000); + dmp_reg = (uint16_t *)((uint8_t *)reg + 0x80); + for (cnt = 0; cnt < sizeof(fw->risc_gp0_reg) / 2; cnt++) + fw->risc_gp0_reg[cnt] = RD_REG_WORD(dmp_reg++); + + WRT_REG_WORD(®->pcr, 0x2200); + dmp_reg = (uint16_t *)((uint8_t *)reg + 0x80); + for (cnt = 0; cnt < sizeof(fw->risc_gp1_reg) / 2; cnt++) + fw->risc_gp1_reg[cnt] = RD_REG_WORD(dmp_reg++); + + WRT_REG_WORD(®->pcr, 0x2400); + dmp_reg = (uint16_t *)((uint8_t *)reg + 0x80); + for (cnt = 0; cnt < sizeof(fw->risc_gp2_reg) / 2; cnt++) + fw->risc_gp2_reg[cnt] = RD_REG_WORD(dmp_reg++); + + WRT_REG_WORD(®->pcr, 0x2600); + dmp_reg = (uint16_t *)((uint8_t *)reg + 0x80); + for (cnt = 0; cnt < sizeof(fw->risc_gp3_reg) / 2; cnt++) + fw->risc_gp3_reg[cnt] = RD_REG_WORD(dmp_reg++); + + WRT_REG_WORD(®->pcr, 0x2800); + dmp_reg = (uint16_t *)((uint8_t *)reg + 0x80); + for (cnt = 0; cnt < sizeof(fw->risc_gp4_reg) / 2; cnt++) + fw->risc_gp4_reg[cnt] = RD_REG_WORD(dmp_reg++); + + WRT_REG_WORD(®->pcr, 0x2A00); + dmp_reg = (uint16_t *)((uint8_t *)reg + 0x80); + for (cnt = 0; cnt < sizeof(fw->risc_gp5_reg) / 2; cnt++) + fw->risc_gp5_reg[cnt] = RD_REG_WORD(dmp_reg++); + + WRT_REG_WORD(®->pcr, 0x2C00); + dmp_reg = (uint16_t *)((uint8_t *)reg + 0x80); + for (cnt = 0; cnt < sizeof(fw->risc_gp6_reg) / 2; cnt++) + fw->risc_gp6_reg[cnt] = RD_REG_WORD(dmp_reg++); + + WRT_REG_WORD(®->pcr, 0x2E00); + dmp_reg = (uint16_t *)((uint8_t *)reg + 0x80); + for (cnt = 0; cnt < sizeof(fw->risc_gp7_reg) / 2; cnt++) + fw->risc_gp7_reg[cnt] = RD_REG_WORD(dmp_reg++); + + WRT_REG_WORD(®->ctrl_status, 0x10); + dmp_reg = (uint16_t *)((uint8_t *)reg + 0x80); + for (cnt = 0; cnt < sizeof(fw->frame_buf_hdw_reg) / 2; cnt++) + fw->frame_buf_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++); + + WRT_REG_WORD(®->ctrl_status, 0x20); + dmp_reg = (uint16_t *)((uint8_t *)reg + 0x80); + for (cnt = 0; cnt < sizeof(fw->fpm_b0_reg) / 2; cnt++) + fw->fpm_b0_reg[cnt] = RD_REG_WORD(dmp_reg++); + + WRT_REG_WORD(®->ctrl_status, 0x30); + dmp_reg = (uint16_t *)((uint8_t *)reg + 0x80); + for (cnt = 0; cnt < sizeof(fw->fpm_b1_reg) / 2; cnt++) + fw->fpm_b1_reg[cnt] = RD_REG_WORD(dmp_reg++); + + /* Reset RISC. */ + WRT_REG_WORD(®->ctrl_status, CSR_ISP_SOFT_RESET); + for (cnt = 0; cnt < 30000; cnt++) { + if ((RD_REG_WORD(®->ctrl_status) & + CSR_ISP_SOFT_RESET) == 0) + break; + + udelay(10); + } + } + + if (IS_QLA2312(ha) || IS_QLA2322(ha)) { + for (cnt = 30000; RD_MAILBOX_REG(ha, reg, 0) != 0 && + rval == QLA_SUCCESS; cnt--) { + if (cnt) + udelay(100); + else + rval = QLA_FUNCTION_TIMEOUT; + } + } + + if (rval == QLA_SUCCESS) { + /* Get RISC SRAM. */ + risc_address = 0x800; + WRT_MAILBOX_REG(ha, reg, 0, MBC_READ_RAM_WORD); + clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); + } + for (cnt = 0; cnt < sizeof(fw->risc_ram) / 2 && rval == QLA_SUCCESS; + cnt++, risc_address++) { + WRT_MAILBOX_REG(ha, reg, 1, (uint16_t)risc_address); + WRT_REG_WORD(®->hccr, HCCR_SET_HOST_INT); + + for (timer = 6000000; timer; timer--) { + /* Check for pending interrupts. */ + stat = RD_REG_DWORD(®->u.isp2300.host_status); + if (stat & HSR_RISC_INT) { + stat &= 0xff; + + if (stat == 0x1 || stat == 0x2) { + set_bit(MBX_INTERRUPT, + &ha->mbx_cmd_flags); + + mb0 = RD_MAILBOX_REG(ha, reg, 0); + mb2 = RD_MAILBOX_REG(ha, reg, 2); + + /* Release mailbox registers. */ + WRT_REG_WORD(®->semaphore, 0); + WRT_REG_WORD(®->hccr, + HCCR_CLR_RISC_INT); + break; + } else if (stat == 0x10 || stat == 0x11) { + set_bit(MBX_INTERRUPT, + &ha->mbx_cmd_flags); + + mb0 = RD_MAILBOX_REG(ha, reg, 0); + mb2 = RD_MAILBOX_REG(ha, reg, 2); + + WRT_REG_WORD(®->hccr, + HCCR_CLR_RISC_INT); + break; + } + + /* clear this intr; it wasn't a mailbox intr */ + WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); + } + udelay(5); + } + + if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { + rval = mb0 & MBS_MASK; + fw->risc_ram[cnt] = mb2; + } else { + rval = QLA_FUNCTION_FAILED; + } + } + + if (rval == QLA_SUCCESS) { + /* Get stack SRAM. */ + risc_address = 0x10000; + WRT_MAILBOX_REG(ha, reg, 0, MBC_READ_RAM_EXTENDED); + clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); + } + for (cnt = 0; cnt < sizeof(fw->stack_ram) / 2 && rval == QLA_SUCCESS; + cnt++, risc_address++) { + WRT_MAILBOX_REG(ha, reg, 1, LSW(risc_address)); + WRT_MAILBOX_REG(ha, reg, 8, MSW(risc_address)); + WRT_REG_WORD(®->hccr, HCCR_SET_HOST_INT); + + for (timer = 6000000; timer; timer--) { + /* Check for pending interrupts. */ + stat = RD_REG_DWORD(®->u.isp2300.host_status); + if (stat & HSR_RISC_INT) { + stat &= 0xff; + + if (stat == 0x1 || stat == 0x2) { + set_bit(MBX_INTERRUPT, + &ha->mbx_cmd_flags); + + mb0 = RD_MAILBOX_REG(ha, reg, 0); + mb2 = RD_MAILBOX_REG(ha, reg, 2); + + /* Release mailbox registers. */ + WRT_REG_WORD(®->semaphore, 0); + WRT_REG_WORD(®->hccr, + HCCR_CLR_RISC_INT); + break; + } else if (stat == 0x10 || stat == 0x11) { + set_bit(MBX_INTERRUPT, + &ha->mbx_cmd_flags); + + mb0 = RD_MAILBOX_REG(ha, reg, 0); + mb2 = RD_MAILBOX_REG(ha, reg, 2); + + WRT_REG_WORD(®->hccr, + HCCR_CLR_RISC_INT); + break; + } + + /* clear this intr; it wasn't a mailbox intr */ + WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); + } + udelay(5); + } + + if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { + rval = mb0 & MBS_MASK; + fw->stack_ram[cnt] = mb2; + } else { + rval = QLA_FUNCTION_FAILED; + } + } + + if (rval == QLA_SUCCESS) { + /* Get data SRAM. */ + risc_address = 0x11000; + WRT_MAILBOX_REG(ha, reg, 0, MBC_READ_RAM_EXTENDED); + clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); + } + for (cnt = 0; cnt < sizeof(fw->data_ram) / 2 && rval == QLA_SUCCESS; + cnt++, risc_address++) { + WRT_MAILBOX_REG(ha, reg, 1, LSW(risc_address)); + WRT_MAILBOX_REG(ha, reg, 8, MSW(risc_address)); + WRT_REG_WORD(®->hccr, HCCR_SET_HOST_INT); + + for (timer = 6000000; timer; timer--) { + /* Check for pending interrupts. */ + stat = RD_REG_DWORD(®->u.isp2300.host_status); + if (stat & HSR_RISC_INT) { + stat &= 0xff; + + if (stat == 0x1 || stat == 0x2) { + set_bit(MBX_INTERRUPT, + &ha->mbx_cmd_flags); + + mb0 = RD_MAILBOX_REG(ha, reg, 0); + mb2 = RD_MAILBOX_REG(ha, reg, 2); + + /* Release mailbox registers. */ + WRT_REG_WORD(®->semaphore, 0); + WRT_REG_WORD(®->hccr, + HCCR_CLR_RISC_INT); + break; + } else if (stat == 0x10 || stat == 0x11) { + set_bit(MBX_INTERRUPT, + &ha->mbx_cmd_flags); + + mb0 = RD_MAILBOX_REG(ha, reg, 0); + mb2 = RD_MAILBOX_REG(ha, reg, 2); + + WRT_REG_WORD(®->hccr, + HCCR_CLR_RISC_INT); + break; + } + + /* clear this intr; it wasn't a mailbox intr */ + WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); + } + udelay(5); + } + + if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { + rval = mb0 & MBS_MASK; + fw->data_ram[cnt] = mb2; + } else { + rval = QLA_FUNCTION_FAILED; + } + } + + + if (rval != QLA_SUCCESS) { + qla_printk(KERN_WARNING, ha, + "Failed to dump firmware (%d)!!!\n", rval); + + free_pages((unsigned long)ha->fw_dump, ha->fw_dump_order); + ha->fw_dump = NULL; + } else { + qla_printk(KERN_INFO, ha, + "Firmware dump saved to temp buffer (%ld/%p).\n", + ha->host_no, ha->fw_dump); + } + + if (!hardware_locked) + spin_unlock_irqrestore(&ha->hardware_lock, flags); +} + +/** + * qla2300_ascii_fw_dump() - Converts a binary firmware dump to ASCII. + * @ha: HA context + */ +void +qla2300_ascii_fw_dump(scsi_qla_host_t *ha) +{ + uint32_t cnt; + char *uiter; + char fw_info[30]; + struct qla2300_fw_dump *fw; + + uiter = ha->fw_dump_buffer; + fw = ha->fw_dump; + + qla_uprintf(&uiter, "%s Firmware Version %s\n", ha->model_number, + qla2x00_get_fw_version_str(ha, fw_info)); + + qla_uprintf(&uiter, "\n[==>BEG]\n"); + + qla_uprintf(&uiter, "HCCR Register:\n%04x\n\n", fw->hccr); + + qla_uprintf(&uiter, "PBIU Registers:"); + for (cnt = 0; cnt < sizeof (fw->pbiu_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->pbiu_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nReqQ-RspQ-Risc2Host Status registers:"); + for (cnt = 0; cnt < sizeof (fw->risc_host_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->risc_host_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nMailbox Registers:"); + for (cnt = 0; cnt < sizeof (fw->mailbox_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->mailbox_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nAuto Request Response DMA Registers:"); + for (cnt = 0; cnt < sizeof (fw->resp_dma_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->resp_dma_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nDMA Registers:"); + for (cnt = 0; cnt < sizeof (fw->dma_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->dma_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nRISC Hardware Registers:"); + for (cnt = 0; cnt < sizeof (fw->risc_hdw_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->risc_hdw_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nRISC GP0 Registers:"); + for (cnt = 0; cnt < sizeof (fw->risc_gp0_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->risc_gp0_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nRISC GP1 Registers:"); + for (cnt = 0; cnt < sizeof (fw->risc_gp1_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->risc_gp1_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nRISC GP2 Registers:"); + for (cnt = 0; cnt < sizeof (fw->risc_gp2_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->risc_gp2_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nRISC GP3 Registers:"); + for (cnt = 0; cnt < sizeof (fw->risc_gp3_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->risc_gp3_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nRISC GP4 Registers:"); + for (cnt = 0; cnt < sizeof (fw->risc_gp4_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->risc_gp4_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nRISC GP5 Registers:"); + for (cnt = 0; cnt < sizeof (fw->risc_gp5_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->risc_gp5_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nRISC GP6 Registers:"); + for (cnt = 0; cnt < sizeof (fw->risc_gp6_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->risc_gp6_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nRISC GP7 Registers:"); + for (cnt = 0; cnt < sizeof (fw->risc_gp7_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->risc_gp7_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nFrame Buffer Hardware Registers:"); + for (cnt = 0; cnt < sizeof (fw->frame_buf_hdw_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->frame_buf_hdw_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nFPM B0 Registers:"); + for (cnt = 0; cnt < sizeof (fw->fpm_b0_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->fpm_b0_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nFPM B1 Registers:"); + for (cnt = 0; cnt < sizeof (fw->fpm_b1_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->fpm_b1_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nCode RAM Dump:"); + for (cnt = 0; cnt < sizeof (fw->risc_ram) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n%04x: ", cnt + 0x0800); + } + qla_uprintf(&uiter, "%04x ", fw->risc_ram[cnt]); + } + + qla_uprintf(&uiter, "\n\nStack RAM Dump:"); + for (cnt = 0; cnt < sizeof (fw->stack_ram) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n%05x: ", cnt + 0x10000); + } + qla_uprintf(&uiter, "%04x ", fw->stack_ram[cnt]); + } + + qla_uprintf(&uiter, "\n\nData RAM Dump:"); + for (cnt = 0; cnt < sizeof (fw->data_ram) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n%05x: ", cnt + 0x11000); + } + qla_uprintf(&uiter, "%04x ", fw->data_ram[cnt]); + } + + qla_uprintf(&uiter, "\n\n[<==END] ISP Debug Dump."); +} + +/** + * qla2100_fw_dump() - Dumps binary data from the 2100/2200 firmware. + * @ha: HA context + * @hardware_locked: Called with the hardware_lock + */ +void +qla2100_fw_dump(scsi_qla_host_t *ha, int hardware_locked) +{ + int rval; + uint32_t cnt, timer; + uint32_t risc_address; + uint16_t mb0, mb2; + + device_reg_t *reg; + uint16_t *dmp_reg; + unsigned long flags; + struct qla2100_fw_dump *fw; + + reg = ha->iobase; + risc_address = 0; + mb0 = mb2 = 0; + flags = 0; + + if (!hardware_locked) + spin_lock_irqsave(&ha->hardware_lock, flags); + + if (ha->fw_dump != NULL) { + qla_printk(KERN_WARNING, ha, + "Firmware has been previously dumped (%p) -- ignoring " + "request...\n", ha->fw_dump); + return; + } + + /* Allocate (large) dump buffer. */ + ha->fw_dump_order = get_order(sizeof(struct qla2100_fw_dump)); + ha->fw_dump = (struct qla2100_fw_dump *) __get_free_pages(GFP_ATOMIC, + ha->fw_dump_order); + if (ha->fw_dump == NULL) { + qla_printk(KERN_WARNING, ha, + "Unable to allocated memory for firmware dump (%d/%d).\n", + ha->fw_dump_order, sizeof(struct qla2100_fw_dump)); + return; + } + fw = ha->fw_dump; + + rval = QLA_SUCCESS; + fw->hccr = RD_REG_WORD(®->hccr); + + /* Pause RISC. */ + WRT_REG_WORD(®->hccr, HCCR_PAUSE_RISC); + for (cnt = 30000; (RD_REG_WORD(®->hccr) & HCCR_RISC_PAUSE) == 0 && + rval == QLA_SUCCESS; cnt--) { + if (cnt) + udelay(100); + else + rval = QLA_FUNCTION_TIMEOUT; + } + + if (rval == QLA_SUCCESS) { + dmp_reg = (uint16_t *)(reg + 0); + for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++) + fw->pbiu_reg[cnt] = RD_REG_WORD(dmp_reg++); + + dmp_reg = (uint16_t *)((uint8_t *)reg + 0x10); + for (cnt = 0; cnt < ha->mbx_count; cnt++) { + if (cnt == 8) { + dmp_reg = (uint16_t *)((uint8_t *)reg + 0xe0); + } + fw->mailbox_reg[cnt] = RD_REG_WORD(dmp_reg++); + } + + dmp_reg = (uint16_t *)((uint8_t *)reg + 0x20); + for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++) + fw->dma_reg[cnt] = RD_REG_WORD(dmp_reg++); + + WRT_REG_WORD(®->ctrl_status, 0x00); + dmp_reg = (uint16_t *)((uint8_t *)reg + 0xA0); + for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++) + fw->risc_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++); + + WRT_REG_WORD(®->pcr, 0x2000); + dmp_reg = (uint16_t *)((uint8_t *)reg + 0x80); + for (cnt = 0; cnt < sizeof(fw->risc_gp0_reg) / 2; cnt++) + fw->risc_gp0_reg[cnt] = RD_REG_WORD(dmp_reg++); + + WRT_REG_WORD(®->pcr, 0x2100); + dmp_reg = (uint16_t *)((uint8_t *)reg + 0x80); + for (cnt = 0; cnt < sizeof(fw->risc_gp1_reg) / 2; cnt++) + fw->risc_gp1_reg[cnt] = RD_REG_WORD(dmp_reg++); + + WRT_REG_WORD(®->pcr, 0x2200); + dmp_reg = (uint16_t *)((uint8_t *)reg + 0x80); + for (cnt = 0; cnt < sizeof(fw->risc_gp2_reg) / 2; cnt++) + fw->risc_gp2_reg[cnt] = RD_REG_WORD(dmp_reg++); + + WRT_REG_WORD(®->pcr, 0x2300); + dmp_reg = (uint16_t *)((uint8_t *)reg + 0x80); + for (cnt = 0; cnt < sizeof(fw->risc_gp3_reg) / 2; cnt++) + fw->risc_gp3_reg[cnt] = RD_REG_WORD(dmp_reg++); + + WRT_REG_WORD(®->pcr, 0x2400); + dmp_reg = (uint16_t *)((uint8_t *)reg + 0x80); + for (cnt = 0; cnt < sizeof(fw->risc_gp4_reg) / 2; cnt++) + fw->risc_gp4_reg[cnt] = RD_REG_WORD(dmp_reg++); + + WRT_REG_WORD(®->pcr, 0x2500); + dmp_reg = (uint16_t *)((uint8_t *)reg + 0x80); + for (cnt = 0; cnt < sizeof(fw->risc_gp5_reg) / 2; cnt++) + fw->risc_gp5_reg[cnt] = RD_REG_WORD(dmp_reg++); + + WRT_REG_WORD(®->pcr, 0x2600); + dmp_reg = (uint16_t *)((uint8_t *)reg + 0x80); + for (cnt = 0; cnt < sizeof(fw->risc_gp6_reg) / 2; cnt++) + fw->risc_gp6_reg[cnt] = RD_REG_WORD(dmp_reg++); + + WRT_REG_WORD(®->pcr, 0x2700); + dmp_reg = (uint16_t *)((uint8_t *)reg + 0x80); + for (cnt = 0; cnt < sizeof(fw->risc_gp7_reg) / 2; cnt++) + fw->risc_gp7_reg[cnt] = RD_REG_WORD(dmp_reg++); + + WRT_REG_WORD(®->ctrl_status, 0x10); + dmp_reg = (uint16_t *)((uint8_t *)reg + 0x80); + for (cnt = 0; cnt < sizeof(fw->frame_buf_hdw_reg) / 2; cnt++) + fw->frame_buf_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++); + + WRT_REG_WORD(®->ctrl_status, 0x20); + dmp_reg = (uint16_t *)((uint8_t *)reg + 0x80); + for (cnt = 0; cnt < sizeof(fw->fpm_b0_reg) / 2; cnt++) + fw->fpm_b0_reg[cnt] = RD_REG_WORD(dmp_reg++); + + WRT_REG_WORD(®->ctrl_status, 0x30); + dmp_reg = (uint16_t *)((uint8_t *)reg + 0x80); + for (cnt = 0; cnt < sizeof(fw->fpm_b1_reg) / 2; cnt++) + fw->fpm_b1_reg[cnt] = RD_REG_WORD(dmp_reg++); + + /* Disable ISP interrupts. */ + WRT_REG_WORD(®->ictrl, 0); + + /* Reset RISC module. */ + WRT_REG_WORD(®->hccr, HCCR_RESET_RISC); + + /* Release RISC module. */ + WRT_REG_WORD(®->hccr, HCCR_RELEASE_RISC); + + /* Insure mailbox registers are free. */ + WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); + WRT_REG_WORD(®->hccr, HCCR_CLR_HOST_INT); + } + + for (cnt = 30000; RD_MAILBOX_REG(ha, reg, 0) != 0 && + rval == QLA_SUCCESS; cnt--) { + if (cnt) + udelay(100); + else + rval = QLA_FUNCTION_TIMEOUT; + } + + /* Pause RISC. */ + if (rval == QLA_SUCCESS && (IS_QLA2200(ha) || (IS_QLA2100(ha) && + (RD_REG_WORD(®->mctr) & (BIT_1 | BIT_0)) != 0))) { + + WRT_REG_WORD(®->hccr, HCCR_PAUSE_RISC); + for (cnt = 30000; + (RD_REG_WORD(®->hccr) & HCCR_RISC_PAUSE) == 0 && + rval == QLA_SUCCESS; cnt--) { + if (cnt) + udelay(100); + else + rval = QLA_FUNCTION_TIMEOUT; + } + + if (rval == QLA_SUCCESS) { + /* Set memory configuration and timing. */ + if (IS_QLA2100(ha)) + WRT_REG_WORD(®->mctr, 0xf1); + else + WRT_REG_WORD(®->mctr, 0xf2); + + /* Release RISC. */ + WRT_REG_WORD(®->hccr, HCCR_RELEASE_RISC); + } + } + + if (rval == QLA_SUCCESS) { + /* Get RISC SRAM. */ + risc_address = 0x1000; + WRT_MAILBOX_REG(ha, reg, 0, MBC_READ_RAM_WORD); + clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); + } + for (cnt = 0; cnt < sizeof(fw->risc_ram) / 2 && rval == QLA_SUCCESS; + cnt++, risc_address++) { + WRT_MAILBOX_REG(ha, reg, 1, (uint16_t)risc_address); + WRT_REG_WORD(®->hccr, HCCR_SET_HOST_INT); + + for (timer = 6000000; timer != 0; timer--) { + /* Check for pending interrupts. */ + if (RD_REG_WORD(®->istatus) & ISR_RISC_INT) { + if (RD_REG_WORD(®->semaphore) & BIT_0) { + set_bit(MBX_INTERRUPT, + &ha->mbx_cmd_flags); + + mb0 = RD_MAILBOX_REG(ha, reg, 0); + mb2 = RD_MAILBOX_REG(ha, reg, 2); + + WRT_REG_WORD(®->semaphore, 0); + WRT_REG_WORD(®->hccr, + HCCR_CLR_RISC_INT); + break; + } + WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); + } + udelay(5); + } + + if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { + rval = mb0 & MBS_MASK; + fw->risc_ram[cnt] = mb2; + } else { + rval = QLA_FUNCTION_FAILED; + } + } + + if (rval != QLA_SUCCESS) { + qla_printk(KERN_WARNING, ha, + "Failed to dump firmware (%d)!!!\n", rval); + + free_pages((unsigned long)ha->fw_dump, ha->fw_dump_order); + ha->fw_dump = NULL; + } else { + qla_printk(KERN_INFO, ha, + "Firmware dump saved to temp buffer (%ld/%p).\n", + ha->host_no, ha->fw_dump); + } + + if (!hardware_locked) + spin_unlock_irqrestore(&ha->hardware_lock, flags); +} + +/** + * qla2100_ascii_fw_dump() - Converts a binary firmware dump to ASCII. + * @ha: HA context + */ +void +qla2100_ascii_fw_dump(scsi_qla_host_t *ha) +{ + uint32_t cnt; + char *uiter; + char fw_info[30]; + struct qla2100_fw_dump *fw; + + uiter = ha->fw_dump_buffer; + fw = ha->fw_dump; + + qla_uprintf(&uiter, "%s Firmware Version %s\n", ha->model_number, + qla2x00_get_fw_version_str(ha, fw_info)); + + qla_uprintf(&uiter, "\n[==>BEG]\n"); + + qla_uprintf(&uiter, "HCCR Register:\n%04x\n\n", fw->hccr); + + qla_uprintf(&uiter, "PBIU Registers:"); + for (cnt = 0; cnt < sizeof (fw->pbiu_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->pbiu_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nMailbox Registers:"); + for (cnt = 0; cnt < sizeof (fw->mailbox_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->mailbox_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nDMA Registers:"); + for (cnt = 0; cnt < sizeof (fw->dma_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->dma_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nRISC Hardware Registers:"); + for (cnt = 0; cnt < sizeof (fw->risc_hdw_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->risc_hdw_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nRISC GP0 Registers:"); + for (cnt = 0; cnt < sizeof (fw->risc_gp0_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->risc_gp0_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nRISC GP1 Registers:"); + for (cnt = 0; cnt < sizeof (fw->risc_gp1_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->risc_gp1_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nRISC GP2 Registers:"); + for (cnt = 0; cnt < sizeof (fw->risc_gp2_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->risc_gp2_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nRISC GP3 Registers:"); + for (cnt = 0; cnt < sizeof (fw->risc_gp3_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->risc_gp3_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nRISC GP4 Registers:"); + for (cnt = 0; cnt < sizeof (fw->risc_gp4_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->risc_gp4_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nRISC GP5 Registers:"); + for (cnt = 0; cnt < sizeof (fw->risc_gp5_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->risc_gp5_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nRISC GP6 Registers:"); + for (cnt = 0; cnt < sizeof (fw->risc_gp6_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->risc_gp6_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nRISC GP7 Registers:"); + for (cnt = 0; cnt < sizeof (fw->risc_gp7_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->risc_gp7_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nFrame Buffer Hardware Registers:"); + for (cnt = 0; cnt < sizeof (fw->frame_buf_hdw_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->frame_buf_hdw_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nFPM B0 Registers:"); + for (cnt = 0; cnt < sizeof (fw->fpm_b0_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->fpm_b0_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nFPM B1 Registers:"); + for (cnt = 0; cnt < sizeof (fw->fpm_b1_reg) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n"); + } + qla_uprintf(&uiter, "%04x ", fw->fpm_b1_reg[cnt]); + } + + qla_uprintf(&uiter, "\n\nRISC SRAM:"); + for (cnt = 0; cnt < sizeof (fw->risc_ram) / 2; cnt++) { + if (cnt % 8 == 0) { + qla_uprintf(&uiter, "\n%04x: ", cnt + 0x1000); + } + qla_uprintf(&uiter, "%04x ", fw->risc_ram[cnt]); + } + + qla_uprintf(&uiter, "\n\n[<==END] ISP Debug Dump."); + + return; +} + +static int +qla_uprintf(char **uiter, char *fmt, ...) +{ + int iter, len; + char buf[128]; + va_list args; + + va_start(args, fmt); + len = vsprintf(buf, fmt, args); + va_end(args); + + for (iter = 0; iter < len; iter++, *uiter += 1) + *uiter[0] = buf[iter]; + + return (len); +} + +//FIXME + +/****************************************************************************/ +/* Driver Debug Functions. */ +/****************************************************************************/ + +void +qla2x00_dump_regs(scsi_qla_host_t *ha) +{ + device_reg_t *reg; + + reg = ha->iobase; + + printk("Mailbox registers:\n"); + printk("scsi(%ld): mbox 0 0x%04x \n", + ha->host_no, RD_MAILBOX_REG(ha, reg, 0)); + printk("scsi(%ld): mbox 1 0x%04x \n", + ha->host_no, RD_MAILBOX_REG(ha, reg, 1)); + printk("scsi(%ld): mbox 2 0x%04x \n", + ha->host_no, RD_MAILBOX_REG(ha, reg, 2)); + printk("scsi(%ld): mbox 3 0x%04x \n", + ha->host_no, RD_MAILBOX_REG(ha, reg, 3)); + printk("scsi(%ld): mbox 4 0x%04x \n", + ha->host_no, RD_MAILBOX_REG(ha, reg, 4)); + printk("scsi(%ld): mbox 5 0x%04x \n", + ha->host_no, RD_MAILBOX_REG(ha, reg, 5)); +} + + +void +qla2x00_dump_buffer(uint8_t * b, uint32_t size) +{ + uint32_t cnt; + uint8_t c; + + printk(" 0 1 2 3 4 5 6 7 8 9 " + "Ah Bh Ch Dh Eh Fh\n"); + printk("----------------------------------------" + "----------------------\n"); + + for (cnt = 0; cnt < size;) { + c = *b++; + printk("%02x",(uint32_t) c); + cnt++; + if (!(cnt % 16)) + printk("\n"); + else + printk(" "); + } + if (cnt % 16) + printk("\n"); +} + +/************************************************************************** + * qla2x00_print_scsi_cmd + * Dumps out info about the scsi cmd and srb. + * Input + * cmd : struct scsi_cmnd + **************************************************************************/ +void +qla2x00_print_scsi_cmd(struct scsi_cmnd * cmd) +{ + int i; + struct scsi_qla_host *ha; + srb_t *sp; + + ha = (struct scsi_qla_host *)cmd->device->host->hostdata; + + sp = (srb_t *) cmd->SCp.ptr; + printk("SCSI Command @=0x%p, Handle=0x%p\n", cmd, cmd->host_scribble); + printk(" chan=0x%02x, target=0x%02x, lun=0x%02x, cmd_len=0x%02x\n", + cmd->device->channel, cmd->device->id, cmd->device->lun, + cmd->cmd_len); + printk(" CDB: "); + for (i = 0; i < cmd->cmd_len; i++) { + printk("0x%02x ", cmd->cmnd[i]); + } + printk("\n seg_cnt=%d, allowed=%d, retries=%d, " + "serial_number_at_timeout=0x%lx\n", + cmd->use_sg, cmd->allowed, cmd->retries, + cmd->serial_number_at_timeout); + printk(" request buffer=0x%p, request buffer len=0x%x\n", + cmd->request_buffer, cmd->request_bufflen); + printk(" tag=%d, transfersize=0x%x\n", + cmd->tag, cmd->transfersize); + printk(" serial_number=%lx, SP=%p\n", cmd->serial_number, sp); + printk(" data direction=%d\n", cmd->sc_data_direction); + + if (!sp) + return; + + printk(" sp flags=0x%x\n", sp->flags); + printk(" r_start=0x%lx, u_start=0x%lx, f_start=0x%lx, state=%d\n", + sp->r_start, sp->u_start, sp->f_start, sp->state); + + printk(" e_start= 0x%lx, ext_history=%d, fo retry=%d, loopid=%x, " + "port path=%d\n", sp->e_start, sp->ext_history, sp->fo_retry_cnt, + sp->lun_queue->fclun->fcport->loop_id, + sp->lun_queue->fclun->fcport->cur_path); +} + +/* + * qla2x00_print_q_info + * Prints queue info + * Input + * q: lun queue + */ +void +qla2x00_print_q_info(struct os_lun *q) +{ + printk("Queue info: flags=0x%lx\n", q->q_flag); +} + +#if defined(QL_DEBUG_ROUTINES) +/* + * qla2x00_formatted_dump_buffer + * Prints string plus buffer. + * + * Input: + * string = Null terminated string (no newline at end). + * buffer = buffer address. + * wd_size = word size 8, 16, 32 or 64 bits + * count = number of words. + */ +void +qla2x00_formatted_dump_buffer(char *string, uint8_t * buffer, + uint8_t wd_size, uint32_t count) +{ + uint32_t cnt; + uint16_t *buf16; + uint32_t *buf32; + + if (strcmp(string, "") != 0) + printk("%s\n",string); + + switch (wd_size) { + case 8: + printk(" 0 1 2 3 4 5 6 7 " + "8 9 Ah Bh Ch Dh Eh Fh\n"); + printk("-----------------------------------------" + "-------------------------------------\n"); + + for (cnt = 1; cnt <= count; cnt++, buffer++) { + printk("%02x",*buffer); + if (cnt % 16 == 0) + printk("\n"); + else + printk(" "); + } + if (cnt % 16 != 0) + printk("\n"); + break; + case 16: + printk(" 0 2 4 6 8 Ah " + " Ch Eh\n"); + printk("-----------------------------------------" + "-------------\n"); + + buf16 = (uint16_t *) buffer; + for (cnt = 1; cnt <= count; cnt++, buf16++) { + printk("%4x",*buf16); + + if (cnt % 8 == 0) + printk("\n"); + else if (*buf16 < 10) + printk(" "); + else + printk(" "); + } + if (cnt % 8 != 0) + printk("\n"); + break; + case 32: + printk(" 0 4 8 Ch\n"); + printk("------------------------------------------\n"); + + buf32 = (uint32_t *) buffer; + for (cnt = 1; cnt <= count; cnt++, buf32++) { + printk("%8x", *buf32); + + if (cnt % 4 == 0) + printk("\n"); + else if (*buf32 < 10) + printk(" "); + else + printk(" "); + } + if (cnt % 4 != 0) + printk("\n"); + break; + default: + break; + } +} + +#endif + + +#if STOP_ON_ERROR +/************************************************************************** +* qla2x00_panic +* +**************************************************************************/ +static void +qla2x00_panic(char *cp, struct Scsi_Host *host) +{ + struct scsi_qla_host *ha; + long *fp; + + ha = (struct scsi_qla_host *) host->hostdata; + DEBUG2(ql2x_debug_print = 1;); + printk("qla2100 - PANIC: %s\n", cp); + printk("Current time=0x%lx\n", jiffies); + printk("Number of pending commands =0x%lx\n", ha->actthreads); + printk("Number of queued commands =0x%lx\n", ha->qthreads); + printk("Number of free entries = (%d)\n", ha->req_q_cnt); + printk("Request Queue @ 0x%lx, Response Queue @ 0x%lx\n", + ha->request_dma, ha->response_dma); + printk("Request In Ptr %d\n", ha->req_ring_index); + fp = (long *) &ha->flags; + printk("HA flags =0x%lx\n", *fp); + qla2x00_dump_requests(ha); + qla2x00_dump_regs(ha); + cli(); + for (;;) { + udelay(2); + barrier(); + /* cpu_relax();*/ + } + sti(); +} + +#endif + +/************************************************************************** +* qla2x00_dump_requests +* +**************************************************************************/ +void +qla2x00_dump_requests(scsi_qla_host_t *ha) +{ + + struct scsi_cmnd *cp; + srb_t *sp; + int i; + + printk("Outstanding Commands on controller:\n"); + + for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) { + if ((sp = ha->outstanding_cmds[i]) == NULL) + continue; + if ((cp = sp->cmd) == NULL) + continue; + + printk("(%d): Pid=%ld, sp flags=0x%x, cmd=0x%p\n", + i, sp->cmd->serial_number, sp->flags, CMD_SP(sp->cmd)); + } +} diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qla_dbg.h 830-ivtv/drivers/scsi/qla2xxx/qla_dbg.h --- 000-virgin/drivers/scsi/qla2xxx/qla_dbg.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qla_dbg.h Thu Jan 8 10:22:00 2004 @@ -0,0 +1,199 @@ +/****************************************************************************** + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + ******************************************************************************/ + +/* + * Firmware Dump structure definition + */ +#define FW_DUMP_SIZE 0xBC000 /* bytes */ + +struct qla2300_fw_dump { + uint16_t hccr; + uint16_t pbiu_reg[8]; + uint16_t risc_host_reg[8]; + uint16_t mailbox_reg[32]; + uint16_t resp_dma_reg[32]; + uint16_t dma_reg[48]; + uint16_t risc_hdw_reg[16]; + uint16_t risc_gp0_reg[16]; + uint16_t risc_gp1_reg[16]; + uint16_t risc_gp2_reg[16]; + uint16_t risc_gp3_reg[16]; + uint16_t risc_gp4_reg[16]; + uint16_t risc_gp5_reg[16]; + uint16_t risc_gp6_reg[16]; + uint16_t risc_gp7_reg[16]; + uint16_t frame_buf_hdw_reg[64]; + uint16_t fpm_b0_reg[64]; + uint16_t fpm_b1_reg[64]; + uint16_t risc_ram[0xf800]; + uint16_t stack_ram[0x1000]; + uint16_t data_ram[0xF000]; +}; + +struct qla2100_fw_dump { + uint16_t hccr; + uint16_t pbiu_reg[8]; + uint16_t mailbox_reg[32]; + uint16_t dma_reg[48]; + uint16_t risc_hdw_reg[16]; + uint16_t risc_gp0_reg[16]; + uint16_t risc_gp1_reg[16]; + uint16_t risc_gp2_reg[16]; + uint16_t risc_gp3_reg[16]; + uint16_t risc_gp4_reg[16]; + uint16_t risc_gp5_reg[16]; + uint16_t risc_gp6_reg[16]; + uint16_t risc_gp7_reg[16]; + uint16_t frame_buf_hdw_reg[16]; + uint16_t fpm_b0_reg[64]; + uint16_t fpm_b1_reg[64]; + uint16_t risc_ram[0xf000]; +}; + +/* +* Macros use for debugging the driver. +*/ +#undef ENTER_TRACE +#if defined(ENTER_TRACE) +#define ENTER(x) do { printk("qla2100 : Entering %s()\n", x); } while (0) +#define LEAVE(x) do { printk("qla2100 : Leaving %s()\n", x); } while (0) +#define ENTER_INTR(x) do { printk("qla2100 : Entering %s()\n", x); } while (0) +#define LEAVE_INTR(x) do { printk("qla2100 : Leaving %s()\n", x); } while (0) +#else +#define ENTER(x) do {} while (0) +#define LEAVE(x) do {} while (0) +#define ENTER_INTR(x) do {} while (0) +#define LEAVE_INTR(x) do {} while (0) +#endif + +#if DEBUG_QLA2100 +#define DEBUG(x) do {x;} while (0); +#else +#define DEBUG(x) do {} while (0); +#endif + +#if defined(QL_DEBUG_LEVEL_1) +#define DEBUG1(x) do {x;} while (0); +#else +#define DEBUG1(x) do {} while (0); +#endif + +#if defined(QL_DEBUG_LEVEL_2) +#define DEBUG2(x) do {x;} while (0); +#define DEBUG2_3(x) do {x;} while (0); +#define DEBUG2_3_11(x) do {x;} while (0); +#define DEBUG2_9_10(x) do {x;} while (0); +#define DEBUG2_11(x) do {x;} while (0); +#else +#define DEBUG2(x) do {} while (0); +#endif + +#if defined(QL_DEBUG_LEVEL_3) +#define DEBUG3(x) do {x;} while (0); +#define DEBUG2_3(x) do {x;} while (0); +#define DEBUG2_3_11(x) do {x;} while (0); +#define DEBUG3_11(x) do {x;} while (0); +#else +#define DEBUG3(x) do {} while (0); + #if !defined(QL_DEBUG_LEVEL_2) + #define DEBUG2_3(x) do {} while (0); + #endif +#endif + +#if defined(QL_DEBUG_LEVEL_4) +#define DEBUG4(x) do {x;} while (0); +#else +#define DEBUG4(x) do {} while (0); +#endif + +#if defined(QL_DEBUG_LEVEL_5) +#define DEBUG5(x) do {x;} while (0); +#else +#define DEBUG5(x) do {} while (0); +#endif + +#if defined(QL_DEBUG_LEVEL_7) +#define DEBUG7(x) do {x;} while (0); +#else +#define DEBUG7(x) do {} while (0); +#endif + +#if defined(QL_DEBUG_LEVEL_9) +#define DEBUG9(x) do {x;} while (0); +#define DEBUG9_10(x) do {x;} while (0); +#define DEBUG2_9_10(x) do {x;} while (0); +#else +#define DEBUG9(x) do {} while (0); +#endif + +#if defined(QL_DEBUG_LEVEL_10) +#define DEBUG10(x) do {x;} while (0); +#define DEBUG2_9_10(x) do {x;} while (0); +#define DEBUG9_10(x) do {x;} while (0); +#else +#define DEBUG10(x) do {} while (0); + #if !defined(DEBUG2_9_10) + #define DEBUG2_9_10(x) do {} while (0); + #endif + #if !defined(DEBUG9_10) + #define DEBUG9_10(x) do {} while (0); + #endif +#endif + +#if defined(QL_DEBUG_LEVEL_11) +#define DEBUG11(x) do{x;} while(0); +#if !defined(DEBUG2_11) +#define DEBUG2_11(x) do{x;} while(0); +#endif +#if !defined(DEBUG2_3_11) +#define DEBUG2_3_11(x) do{x;} while(0); +#endif +#if !defined(DEBUG3_11) +#define DEBUG3_11(x) do{x;} while(0); +#endif +#else +#define DEBUG11(x) do{} while(0); + #if !defined(QL_DEBUG_LEVEL_2) + #define DEBUG2_11(x) do{} while(0); + #if !defined(QL_DEBUG_LEVEL_3) + #define DEBUG2_3_11(x) do{} while(0); + #endif + #endif + #if !defined(QL_DEBUG_LEVEL_3) + #define DEBUG3_11(x) do{} while(0); + #endif +#endif + +#if defined(QL_DEBUG_LEVEL_12) +#define DEBUG12(x) do {x;} while (0); +#else +#define DEBUG12(x) do {} while (0); +#endif + +#if defined(QL_DEBUG_LEVEL_13) +#define DEBUG13(x) do {x;} while (0) +#else +#define DEBUG13(x) do {} while (0) +#endif + +#if defined(QL_DEBUG_LEVEL_14) +#define DEBUG14(x) do {x;} while (0) +#else +#define DEBUG14(x) do {} while (0) +#endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qla_def.h 830-ivtv/drivers/scsi/qla2xxx/qla_def.h --- 000-virgin/drivers/scsi/qla2xxx/qla_def.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qla_def.h Thu Jan 8 10:22:00 2004 @@ -0,0 +1,2436 @@ +/******************************************************************************** +* QLOGIC LINUX SOFTWARE +* +* QLogic ISP2x00 device driver for Linux 2.6.x +* Copyright (C) 2003 QLogic Corporation +* (www.qlogic.com) +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2, or (at your option) any +* later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +** +******************************************************************************/ + +#ifndef __QLA_DEF_H +#define __QLA_DEF_H + +/* XXX(hch): move to pci_ids.h */ +#ifndef PCI_DEVICE_ID_QLOGIC_ISP2300 +#define PCI_DEVICE_ID_QLOGIC_ISP2300 0x2300 +#endif + +#ifndef PCI_DEVICE_ID_QLOGIC_ISP2312 +#define PCI_DEVICE_ID_QLOGIC_ISP2312 0x2312 +#endif + +#ifndef PCI_DEVICE_ID_QLOGIC_ISP2322 +#define PCI_DEVICE_ID_QLOGIC_ISP2322 0x2322 +#endif + +#if !defined(CONFIG_SCSI_QLA21XX) && !defined(CONFIG_SCSI_QLA21XX_MODULE) && \ + !defined(CONFIG_SCSI_QLA22XX) && !defined(CONFIG_SCSI_QLA22XX_MODULE) && \ + !defined(CONFIG_SCSI_QLA23XX) && !defined(CONFIG_SCSI_QLA23XX_MODULE) +#error Please define an ISP type for compilation!!! +#endif + +#if defined(CONFIG_SCSI_QLA21XX) || defined(CONFIG_SCSI_QLA21XX_MODULE) +#define IS_QLA2100(ha) ((ha)->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2100) +#else +#define IS_QLA2100(ha) 0 +#endif + +#if defined(CONFIG_SCSI_QLA22XX) || defined(CONFIG_SCSI_QLA22XX_MODULE) +#define IS_QLA2200(ha) ((ha)->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2200) +#else +#define IS_QLA2200(ha) 0 +#endif + +#if defined(CONFIG_SCSI_QLA23XX) || defined(CONFIG_SCSI_QLA23XX_MODULE) +#define IS_QLA2300(ha) ((ha)->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2300) +#define IS_QLA2312(ha) ((ha)->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2312) +#define IS_QLA2322(ha) ((ha)->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2322) +#define IS_QLA23XX(ha) (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA2322(ha)) +#else +#define IS_QLA2300(ha) 0 +#define IS_QLA2312(ha) 0 +#define IS_QLA2322(ha) 0 +#define IS_QLA23XX(ha) 0 +#endif + +/* + * Only ISP23XX has extended addressing support in the firmware. + */ +#define HAS_EXTENDED_IDS(ha) IS_QLA23XX(ha) + +/* + * We have MAILBOX_REGISTER_COUNT sized arrays in a few places, + * but that's fine as we don't look at the last 24 ones for + * ISP2100 HBAs. + */ +#define MAILBOX_REGISTER_COUNT_2100 8 +#define MAILBOX_REGISTER_COUNT 32 + +#define QLA2200A_RISC_ROM_VER 4 +#define FPM_2300 6 +#define FPM_2310 7 + +#include "qla_settings.h" +#include "exioct.h" +#include "inioct.h" + +/* + * Data bit definitions + */ +#define BIT_0 0x1 +#define BIT_1 0x2 +#define BIT_2 0x4 +#define BIT_3 0x8 +#define BIT_4 0x10 +#define BIT_5 0x20 +#define BIT_6 0x40 +#define BIT_7 0x80 +#define BIT_8 0x100 +#define BIT_9 0x200 +#define BIT_10 0x400 +#define BIT_11 0x800 +#define BIT_12 0x1000 +#define BIT_13 0x2000 +#define BIT_14 0x4000 +#define BIT_15 0x8000 +#define BIT_16 0x10000 +#define BIT_17 0x20000 +#define BIT_18 0x40000 +#define BIT_19 0x80000 +#define BIT_20 0x100000 +#define BIT_21 0x200000 +#define BIT_22 0x400000 +#define BIT_23 0x800000 +#define BIT_24 0x1000000 +#define BIT_25 0x2000000 +#define BIT_26 0x4000000 +#define BIT_27 0x8000000 +#define BIT_28 0x10000000 +#define BIT_29 0x20000000 +#define BIT_30 0x40000000 +#define BIT_31 0x80000000 + +#define LSB(x) ((uint8_t)(x)) +#define MSB(x) ((uint8_t)((uint16_t)(x) >> 8)) + +#define LSW(x) ((uint16_t)(x)) +#define MSW(x) ((uint16_t)((uint32_t)(x) >> 16)) + +#define LSD(x) ((uint32_t)((uint64_t)(x))) +#define MSD(x) ((uint32_t)((((uint64_t)(x)) >> 16) >> 16)) + + +/* + * I/O register +*/ + +#if MEMORY_MAPPED_IO +#define RD_REG_BYTE(addr) readb(addr) +#define RD_REG_WORD(addr) readw(addr) +#define RD_REG_DWORD(addr) readl(addr) +#define WRT_REG_BYTE(addr, data) writeb(data,addr) +#define WRT_REG_WORD(addr, data) writew(data,addr) +#define WRT_REG_DWORD(addr, data) writel(data,addr) +#else /* MEMORY_MAPPED_IO */ +#define RD_REG_BYTE(addr) (inb((unsigned long)addr)) +#define RD_REG_WORD(addr) (inw((unsigned long)addr)) +#define RD_REG_DWORD(addr) (inl((unsigned long)addr)) +#define WRT_REG_BYTE(addr, data) (outb(data,(unsigned long)addr)) +#define WRT_REG_WORD(addr, data) (outw(data,(unsigned long)addr)) +#define WRT_REG_DWORD(addr, data) (outl(data,(unsigned long)addr)) +#endif /* MEMORY_MAPPED_IO */ + +/* + * Fibre Channel device definitions. + */ +#define WWN_SIZE 8 /* Size of WWPN, WWN & WWNN */ +#define MAX_FIBRE_DEVICES 512 +#define MAX_FIBRE_LUNS 256 +#define MAX_RSCN_COUNT 32 +#define MAX_HOST_COUNT 16 + +/* + * Host adapter default definitions. + */ +#define MAX_BUSES 1 /* We only have one bus today */ +#define MAX_TARGETS_2100 MAX_FIBRE_DEVICES +#define MAX_TARGETS_2200 MAX_FIBRE_DEVICES +#define MAX_TARGETS MAX_FIBRE_DEVICES +#define MIN_LUNS 8 +#define MAX_LUNS MAX_FIBRE_LUNS +#define MAX_CMDS_PER_LUN 255 + +/* + * Fibre Channel device definitions. + */ +#define SNS_LAST_LOOP_ID_2100 0xfe +#define SNS_LAST_LOOP_ID_2300 0x7ff + +#define LAST_LOCAL_LOOP_ID 0x7d +#define SNS_FL_PORT 0x7e +#define FABRIC_CONTROLLER 0x7f +#define SIMPLE_NAME_SERVER 0x80 +#define SNS_FIRST_LOOP_ID 0x81 +#define MANAGEMENT_SERVER 0xfe +#define BROADCAST 0xff + +#define RESERVED_LOOP_ID(x) ((x > LAST_LOCAL_LOOP_ID && \ + x < SNS_FIRST_LOOP_ID) || \ + x == MANAGEMENT_SERVER || \ + x == BROADCAST) + +/* + * Timeout timer counts in seconds + */ +#define PORT_RETRY_TIME 2 +#define LOOP_DOWN_TIMEOUT 60 +#define LOOP_DOWN_TIME 255 /* 240 */ +#define LOOP_DOWN_RESET (LOOP_DOWN_TIME - 30) + +/* Maximum outstanding commands in ISP queues (1-65535) */ +#define MAX_OUTSTANDING_COMMANDS 1024 + +/* ISP request and response entry counts (37-65535) */ +#define REQUEST_ENTRY_CNT 1024 /* Number of request entries. */ +#define RESPONSE_ENTRY_CNT_2100 64 /* Number of response entries.*/ +#define RESPONSE_ENTRY_CNT_2300 512 /* Number of response entries.*/ + +/* Calculations for SG segments */ +#define SEGS_PER_REQUEST_32 3 +#define SEGS_PER_CONT_32 7 +#define SG_SEGMENTS_32 (SEGS_PER_REQUEST_32 + \ + (SEGS_PER_CONT_32 * (REQUEST_ENTRY_CNT - 2))) +#define SEGS_PER_REQUEST_64 2 +#define SEGS_PER_CONT_64 5 +#define SG_SEGMENTS_64 (SEGS_PER_REQUEST_64 + \ + (SEGS_PER_CONT_64 * (REQUEST_ENTRY_CNT - 2))) + +/* + * SCSI Request Block + */ +typedef struct srb { + struct list_head list; + + struct scsi_qla_host *ha; /* HA the SP is queued on */ + + struct scsi_cmnd *cmd; /* Linux SCSI command pkt */ + + struct timer_list timer; /* Command timer */ + atomic_t ref_count; /* Reference count for this structure */ + uint16_t flags; + + /* Request state */ + uint16_t state; + + /* Target/LUN queue pointers. */ + struct os_tgt *tgt_queue; /* ptr to visible ha's target */ + struct os_lun *lun_queue; /* ptr to visible ha's lun */ + struct fc_lun *fclun; /* FC LUN context pointer. */ + + /* Timing counts. */ + unsigned long e_start; /* Start of extend timeout */ + unsigned long r_start; /* Start of request */ + unsigned long u_start; /* When sent to RISC */ + unsigned long f_start; /* When placed in FO queue*/ + + /* Single transfer DMA context */ + dma_addr_t dma_handle; + + uint32_t request_sense_length; + uint8_t *request_sense_ptr; + + int ext_history; + + /* Suspend delay */ + int delay; + + /* Raw completion info for use by failover ? */ + uint8_t fo_retry_cnt; /* Retry count this request */ + uint8_t err_id; /* error id */ + + /* SRB magic number */ + uint16_t magic; +#define SRB_MAGIC 0x10CB +} srb_t; + +/* + * SRB flag definitions + */ +#define SRB_TIMEOUT BIT_0 /* Command timed out */ +#define SRB_DMA_VALID BIT_1 /* Command sent to ISP */ +#define SRB_WATCHDOG BIT_2 /* Command on watchdog list */ +#define SRB_ABORT_PENDING BIT_3 /* Command abort sent to device */ + +#define SRB_ABORTED BIT_4 /* Command aborted command already */ +#define SRB_RETRY BIT_5 /* Command needs retrying */ +#define SRB_GOT_SENSE BIT_6 /* Command has sense data */ +#define SRB_FAILOVER BIT_7 /* Command in failover state */ + +#define SRB_BUSY BIT_8 /* Command is in busy retry state */ +#define SRB_FO_CANCEL BIT_9 /* Command don't need to do failover */ +#define SRB_IOCTL BIT_10 /* IOCTL command. */ + +/* + * SRB state definitions + */ +#define SRB_FREE_STATE 0 /* returned back */ +#define SRB_PENDING_STATE 1 /* queued in LUN Q */ +#define SRB_ACTIVE_STATE 2 /* in Active Array */ +#define SRB_DONE_STATE 3 /* queued in Done Queue */ +#define SRB_RETRY_STATE 4 /* in Retry Queue */ +#define SRB_SUSPENDED_STATE 5 /* in suspended state */ +#define SRB_NO_QUEUE_STATE 6 /* is in between states */ +#define SRB_ACTIVE_TIMEOUT_STATE 7 /* in Active Array but timed out */ +#define SRB_FAILOVER_STATE 8 /* in Failover Queue */ +#define SRB_SCSI_RETRY_STATE 9 /* in Scsi Retry Queue */ + + +/* + * ISP I/O Register Set structure definitions. + */ +typedef volatile struct { + volatile uint16_t flash_address; /* Flash BIOS address */ + volatile uint16_t flash_data; /* Flash BIOS data */ + uint16_t unused_1[1]; /* Gap */ + volatile uint16_t ctrl_status; /* Control/Status */ +#define CSR_FLASH_64K_BANK BIT_3 /* Flash upper 64K bank select */ +#define CSR_FLASH_ENABLE BIT_1 /* Flash BIOS Read/Write enable */ +#define CSR_ISP_SOFT_RESET BIT_0 /* ISP soft reset */ + + volatile uint16_t ictrl; /* Interrupt control */ +#define ICR_EN_INT BIT_15 /* ISP enable interrupts. */ +#define ICR_EN_RISC BIT_3 /* ISP enable RISC interrupts. */ + + volatile uint16_t istatus; /* Interrupt status */ +#define ISR_RISC_INT BIT_3 /* RISC interrupt */ + + volatile uint16_t semaphore; /* Semaphore */ + volatile uint16_t nvram; /* NVRAM register. */ +#define NVR_DESELECT 0 +#define NVR_BUSY BIT_15 +#define NVR_DATA_IN BIT_3 +#define NVR_DATA_OUT BIT_2 +#define NVR_SELECT BIT_1 +#define NVR_CLOCK BIT_0 + + union { + struct { + volatile uint16_t mailbox0; + volatile uint16_t mailbox1; + volatile uint16_t mailbox2; + volatile uint16_t mailbox3; + volatile uint16_t mailbox4; + volatile uint16_t mailbox5; + volatile uint16_t mailbox6; + volatile uint16_t mailbox7; + uint16_t unused_2[59]; /* Gap */ + } __attribute__((packed)) isp2100; + struct { + /* Request Queue */ + volatile uint16_t req_q_in; /* In-Pointer */ + volatile uint16_t req_q_out; /* Out-Pointer */ + /* Response Queue */ + volatile uint16_t rsp_q_in; /* In-Pointer */ + volatile uint16_t rsp_q_out; /* Out-Pointer */ + + /* RISC to Host Status */ + volatile uint32_t host_status; +#define HSR_RISC_INT BIT_15 /* RISC interrupt */ +#define HSR_RISC_PAUSED BIT_8 /* RISC Paused */ + + /* Host to Host Semaphore */ + volatile uint16_t host_semaphore; + uint16_t unused_3[17]; /* Gap */ + volatile uint16_t mailbox0; + volatile uint16_t mailbox1; + volatile uint16_t mailbox2; + volatile uint16_t mailbox3; + volatile uint16_t mailbox4; + volatile uint16_t mailbox5; + volatile uint16_t mailbox6; + volatile uint16_t mailbox7; + volatile uint16_t mailbox8; + volatile uint16_t mailbox9; + volatile uint16_t mailbox10; + volatile uint16_t mailbox11; + volatile uint16_t mailbox12; + volatile uint16_t mailbox13; + volatile uint16_t mailbox14; + volatile uint16_t mailbox15; + volatile uint16_t mailbox16; + volatile uint16_t mailbox17; + volatile uint16_t mailbox18; + volatile uint16_t mailbox19; + volatile uint16_t mailbox20; + volatile uint16_t mailbox21; + volatile uint16_t mailbox22; + volatile uint16_t mailbox23; + volatile uint16_t mailbox24; + volatile uint16_t mailbox25; + volatile uint16_t mailbox26; + volatile uint16_t mailbox27; + volatile uint16_t mailbox28; + volatile uint16_t mailbox29; + volatile uint16_t mailbox30; + volatile uint16_t mailbox31; + volatile uint16_t fb_cmd; + uint16_t unused_4[10]; /* Gap */ + } __attribute__((packed)) isp2300; + } u; + + volatile uint16_t fpm_diag_config; + uint16_t unused_5[0x6]; /* Gap */ + volatile uint16_t pcr; /* Processor Control Register. */ + uint16_t unused_6[0x5]; /* Gap */ + volatile uint16_t mctr; /* Memory Configuration and Timing. */ + uint16_t unused_7[0x3]; /* Gap */ + volatile uint16_t fb_cmd_2100; /* Unused on 23XX */ + uint16_t unused_8[0x3]; /* Gap */ + volatile uint16_t hccr; /* Host command & control register. */ +#define HCCR_HOST_INT BIT_7 /* Host interrupt bit */ +#define HCCR_RISC_PAUSE BIT_5 /* Pause mode bit */ + /* HCCR commands */ +#define HCCR_RESET_RISC 0x1000 /* Reset RISC */ +#define HCCR_PAUSE_RISC 0x2000 /* Pause RISC */ +#define HCCR_RELEASE_RISC 0x3000 /* Release RISC from reset. */ +#define HCCR_SET_HOST_INT 0x5000 /* Set host interrupt */ +#define HCCR_CLR_HOST_INT 0x6000 /* Clear HOST interrupt */ +#define HCCR_CLR_RISC_INT 0x7000 /* Clear RISC interrupt */ +#define HCCR_DISABLE_PARITY_PAUSE 0x4001 /* Disable parity error RISC pause. */ +#define HCCR_ENABLE_PARITY 0xA000 /* Enable PARITY interrupt */ + + uint16_t unused_9[5]; /* Gap */ + volatile uint16_t gpiod; /* GPIO Data register. */ + volatile uint16_t gpioe; /* GPIO Enable register. */ +#define GPIO_LED_MASK 0x00C0 +#define GPIO_LED_GREEN_OFF_AMBER_OFF 0x0000 +#define GPIO_LED_GREEN_ON_AMBER_OFF 0x0040 +#define GPIO_LED_GREEN_OFF_AMBER_ON 0x0080 +#define GPIO_LED_GREEN_ON_AMBER_ON 0x00C0 + + union { + struct { + uint16_t unused_10[8]; /* Gap */ + volatile uint16_t mailbox8; + volatile uint16_t mailbox9; + volatile uint16_t mailbox10; + volatile uint16_t mailbox11; + volatile uint16_t mailbox12; + volatile uint16_t mailbox13; + volatile uint16_t mailbox14; + volatile uint16_t mailbox15; + volatile uint16_t mailbox16; + volatile uint16_t mailbox17; + volatile uint16_t mailbox18; + volatile uint16_t mailbox19; + volatile uint16_t mailbox20; + volatile uint16_t mailbox21; + volatile uint16_t mailbox22; + volatile uint16_t mailbox23; /* Also probe reg. */ + } __attribute__((packed)) isp2200; + } u_end; +} device_reg_t; + +#define ISP_REQ_Q_IN(ha, reg) \ + (IS_QLA23XX(ha) ? \ + &(reg)->u.isp2300.req_q_in : \ + &(reg)->u.isp2100.mailbox4) +#define ISP_REQ_Q_OUT(ha, reg) \ + (IS_QLA23XX(ha) ? \ + &(reg)->u.isp2300.req_q_out : \ + &(reg)->u.isp2100.mailbox4) +#define ISP_RSP_Q_IN(ha, reg) \ + (IS_QLA23XX(ha) ? \ + &(reg)->u.isp2300.rsp_q_in : \ + &(reg)->u.isp2100.mailbox5) +#define ISP_RSP_Q_OUT(ha, reg) \ + (IS_QLA23XX(ha) ? \ + &(reg)->u.isp2300.rsp_q_out : \ + &(reg)->u.isp2100.mailbox5) + +#define MAILBOX_REG(ha, reg, num) \ + (IS_QLA23XX(ha) ? \ + &(reg)->u.isp2300.mailbox0 + (num) : \ + ((num < 8) ? \ + &(reg)->u.isp2100.mailbox0 + (num) : \ + &(reg)->u_end.isp2200.mailbox8 + (num) - 8)) /* only for isp2200 */ +#define RD_MAILBOX_REG(ha, reg, num) \ + RD_REG_WORD(MAILBOX_REG(ha, reg, num)) +#define WRT_MAILBOX_REG(ha, reg, num, data) \ + WRT_REG_WORD(MAILBOX_REG(ha, reg, num), data) + +#define FB_CMD_REG(ha, reg) \ + (IS_QLA23XX(ha) ? &(reg)->u.isp2300.fb_cmd : &(reg)->fb_cmd_2100) +#define RD_FB_CMD_REG(ha, reg) \ + RD_REG_WORD(FB_CMD_REG(ha, reg)) +#define WRT_FB_CMD_REG(ha, reg, data) \ + WRT_REG_WORD(FB_CMD_REG(ha, reg), data) + + +typedef struct { + uint32_t out_mb; /* outbound from driver */ + uint32_t in_mb; /* Incoming from RISC */ + uint16_t mb[MAILBOX_REGISTER_COUNT]; + long buf_size; + void *bufp; + uint32_t tov; + uint8_t flags; +#define MBX_DMA_IN BIT_0 +#define MBX_DMA_OUT BIT_1 +#define IOCTL_CMD BIT_2 +} mbx_cmd_t; + +#define MBX_TOV_SECONDS 30 + +/* + * ISP product identification definitions in mailboxes after reset. + */ +#define PROD_ID_1 0x4953 +#define PROD_ID_2 0x0000 +#define PROD_ID_2a 0x5020 +#define PROD_ID_3 0x2020 + +/* + * ISP mailbox Self-Test status codes + */ +#define MBS_FRM_ALIVE 0 /* Firmware Alive. */ +#define MBS_CHKSUM_ERR 1 /* Checksum Error. */ +#define MBS_BUSY 4 /* Busy. */ + +/* + * ISP mailbox command complete status codes + */ +#define MBS_COMMAND_COMPLETE 0x4000 +#define MBS_INVALID_COMMAND 0x4001 +#define MBS_HOST_INTERFACE_ERROR 0x4002 +#define MBS_TEST_FAILED 0x4003 +#define MBS_COMMAND_ERROR 0x4005 +#define MBS_COMMAND_PARAMETER_ERROR 0x4006 +#define MBS_PORT_ID_USED 0x4007 +#define MBS_LOOP_ID_USED 0x4008 +#define MBS_ALL_IDS_IN_USE 0x4009 +#define MBS_NOT_LOGGED_IN 0x400A + +/* + * ISP mailbox asynchronous event status codes + */ +#define MBA_ASYNC_EVENT 0x8000 /* Asynchronous event. */ +#define MBA_RESET 0x8001 /* Reset Detected. */ +#define MBA_SYSTEM_ERR 0x8002 /* System Error. */ +#define MBA_REQ_TRANSFER_ERR 0x8003 /* Request Transfer Error. */ +#define MBA_RSP_TRANSFER_ERR 0x8004 /* Response Transfer Error. */ +#define MBA_WAKEUP_THRES 0x8005 /* Request Queue Wake-up. */ +#define MBA_LIP_OCCURRED 0x8010 /* Loop Initialization Procedure */ + /* occurred. */ +#define MBA_LOOP_UP 0x8011 /* FC Loop UP. */ +#define MBA_LOOP_DOWN 0x8012 /* FC Loop Down. */ +#define MBA_LIP_RESET 0x8013 /* LIP reset occurred. */ +#define MBA_PORT_UPDATE 0x8014 /* Port Database update. */ +#define MBA_RSCN_UPDATE 0x8015 /* Register State Chg Notification. */ +#define MBA_LIP_F8 0x8016 /* Received a LIP F8. */ +#define MBA_LOOP_INIT_ERR 0x8017 /* Loop Initialization Error. */ +#define MBA_FABRIC_AUTH_REQ 0x801b /* Fabric Authentication Required. */ +#define MBA_SCSI_COMPLETION 0x8020 /* SCSI Command Complete. */ +#define MBA_CTIO_COMPLETION 0x8021 /* CTIO Complete. */ +#define MBA_IP_COMPLETION 0x8022 /* IP Transmit Command Complete. */ +#define MBA_IP_RECEIVE 0x8023 /* IP Received. */ +#define MBA_IP_BROADCAST 0x8024 /* IP Broadcast Received. */ +#define MBA_IP_LOW_WATER_MARK 0x8025 /* IP Low Water Mark reached. */ +#define MBA_IP_RCV_BUFFER_EMPTY 0x8026 /* IP receive buffer queue empty. */ +#define MBA_IP_HDR_DATA_SPLIT 0x8027 /* IP header/data splitting feature */ + /* used. */ +#define MBA_POINT_TO_POINT 0x8030 /* Point to point mode. */ +#define MBA_CMPLT_1_16BIT 0x8031 /* Completion 1 16bit IOSB. */ +#define MBA_CMPLT_2_16BIT 0x8032 /* Completion 2 16bit IOSB. */ +#define MBA_CMPLT_3_16BIT 0x8033 /* Completion 3 16bit IOSB. */ +#define MBA_CMPLT_4_16BIT 0x8034 /* Completion 4 16bit IOSB. */ +#define MBA_CMPLT_5_16BIT 0x8035 /* Completion 5 16bit IOSB. */ +#define MBA_CHG_IN_CONNECTION 0x8036 /* Change in connection mode. */ +#define MBA_RIO_RESPONSE 0x8040 /* RIO response queue update. */ +#define MBA_ZIO_RESPONSE 0x8040 /* ZIO response queue update. */ +#define MBA_CMPLT_2_32BIT 0x8042 /* Completion 2 32bit IOSB. */ +#define MBA_BYPASS_NOTIFICATION 0x8043 /* Auto bypass notification. */ +#define MBA_DISCARD_RND_FRAME 0x8048 /* discard RND frame due to error. */ +#define MBA_REJECTED_FCP_CMD 0x8049 /* rejected FCP_CMD. */ + +/* + * Firmware options 1, 2, 3. + */ +#define FO1_AE_ON_LIPF8 BIT_0 +#define FO1_AE_ALL_LIP_RESET BIT_1 +#define FO1_CTIO_RETRY BIT_3 +#define FO1_DISABLE_LIP_F7_SW BIT_4 +#define FO1_DISABLE_100MS_LOS_WAIT BIT_5 +#define FO1_DISABLE_GPIO6_7 BIT_6 +#define FO1_AE_ON_LOOP_INIT_ERR BIT_7 +#define FO1_SET_EMPHASIS_SWING BIT_8 +#define FO1_AE_AUTO_BYPASS BIT_9 +#define FO1_ENABLE_PURE_IOCB BIT_10 +#define FO1_AE_PLOGI_RJT BIT_11 +#define FO1_ENABLE_ABORT_SEQUENCE BIT_12 +#define FO1_AE_QUEUE_FULL BIT_13 + +#define FO2_ENABLE_ATIO_TYPE_3 BIT_0 +#define FO2_REV_LOOPBACK BIT_1 + +#define FO3_ENABLE_EMERG_IOCB BIT_0 +#define FO3_AE_RND_ERROR BIT_1 + +/* + * ISP mailbox commands + */ +#define MBC_LOAD_RAM 1 /* Load RAM. */ +#define MBC_EXECUTE_FIRMWARE 2 /* Execute firmware. */ +#define MBC_WRITE_RAM_WORD 4 /* Write RAM word. */ +#define MBC_READ_RAM_WORD 5 /* Read RAM word. */ +#define MBC_MAILBOX_REGISTER_TEST 6 /* Wrap incoming mailboxes */ +#define MBC_VERIFY_CHECKSUM 7 /* Verify checksum. */ +#define MBC_GET_FIRMWARE_VERSION 8 /* Get firmware revision. */ +#define MBC_LOAD_RISC_RAM 9 /* Load RAM command. */ +#define MBC_DUMP_RISC_RAM 0xa /* Dump RAM command. */ +#define MBC_LOAD_RISC_RAM_EXTENDED 0xb /* Load RAM extended. */ +#define MBC_DUMP_RISC_RAM_EXTENDED 0xc /* Dump RAM extended. */ +#define MBC_WRITE_RAM_WORD_EXTENDED 0xd /* Write RAM word extended */ +#define MBC_READ_RAM_EXTENDED 0xf /* Read RAM extended. */ +#define MBC_IOCB_COMMAND 0x12 /* Execute IOCB command. */ +#define MBC_ABORT_COMMAND 0x15 /* Abort IOCB command. */ +#define MBC_ABORT_DEVICE 0x16 /* Abort device (ID/LUN). */ +#define MBC_ABORT_TARGET 0x17 /* Abort target (ID). */ +#define MBC_RESET 0x18 /* Reset. */ +#define MBC_GET_ADAPTER_LOOP_ID 0x20 /* Get loop id of ISP2200. */ +#define MBC_GET_RETRY_COUNT 0x22 /* Get f/w retry cnt/delay. */ +#define MBC_DISABLE_VI 0x24 /* Disable VI operation. */ +#define MBC_ENABLE_VI 0x25 /* Enable VI operation. */ +#define MBC_GET_FIRMWARE_OPTION 0x28 /* Get Firmware Options. */ +#define MBC_SET_FIRMWARE_OPTION 0x38 /* Set Firmware Options. */ +#define MBC_LOOP_PORT_BYPASS 0x40 /* Loop Port Bypass. */ +#define MBC_LOOP_PORT_ENABLE 0x41 /* Loop Port Enable. */ +#define MBC_GET_RESOURCE_COUNTS 0x42 /* Get Resource Counts. */ +#define MBC_NON_PARTICIPATE 0x43 /* Non-Participating Mode. */ +#define MBC_DIAGNOSTIC_ECHO 0x44 /* Diagnostic echo. */ +#define MBC_DIAGNOSTIC_LOOP_BACK 0x45 /* Diagnostic loop back. */ +#define MBC_ONLINE_SELF_TEST 0x46 /* Online self-test. */ +#define MBC_ENHANCED_GET_PORT_DATABASE 0x47 /* Get port database + login */ +#define MBC_RESET_LINK_STATUS 0x52 /* Reset Link Error Status */ +#define MBC_IOCB_COMMAND_A64 0x54 /* Execute IOCB command (64) */ +#define MBC_SEND_RNID_ELS 0x57 /* Send RNID ELS request */ +#define MBC_SET_RNID_PARAMS 0x59 /* Set RNID parameters */ +#define MBC_GET_RNID_PARAMS 0x5a /* Data Rate */ +#define MBC_DATA_RATE 0x5d /* Get RNID parameters */ +#define MBC_INITIALIZE_FIRMWARE 0x60 /* Initialize firmware */ +#define MBC_INITIATE_LIP 0x62 /* Initiate Loop */ + /* Initialization Procedure */ +#define MBC_GET_FC_AL_POSITION_MAP 0x63 /* Get FC_AL Position Map. */ +#define MBC_GET_PORT_DATABASE 0x64 /* Get Port Database. */ +#define MBC_CLEAR_ACA 0x65 /* Clear ACA. */ +#define MBC_TARGET_RESET 0x66 /* Target Reset. */ +#define MBC_CLEAR_TASK_SET 0x67 /* Clear Task Set. */ +#define MBC_ABORT_TASK_SET 0x68 /* Abort Task Set. */ +#define MBC_GET_FIRMWARE_STATE 0x69 /* Get firmware state. */ +#define MBC_GET_PORT_NAME 0x6a /* Get port name. */ +#define MBC_GET_LINK_STATUS 0x6b /* Get port link status. */ +#define MBC_LIP_RESET 0x6c /* LIP reset. */ +#define MBC_SEND_SNS_COMMAND 0x6e /* Send Simple Name Server */ + /* commandd. */ +#define MBC_LOGIN_FABRIC_PORT 0x6f /* Login fabric port. */ +#define MBC_SEND_CHANGE_REQUEST 0x70 /* Send Change Request. */ +#define MBC_LOGOUT_FABRIC_PORT 0x71 /* Logout fabric port. */ +#define MBC_LIP_FULL_LOGIN 0x72 /* Full login LIP. */ +#define MBC_LOGIN_LOOP_PORT 0x74 /* Login Loop Port. */ +#define MBC_PORT_NODE_NAME_LIST 0x75 /* Get port/node name list. */ +#define MBC_INITIALIZE_RECEIVE_QUEUE 0x77 /* Initialize receive queue */ +#define MBC_UNLOAD_IP 0x79 /* Shutdown IP */ +#define MBC_GET_ID_LIST 0x7C /* Get Port ID list. */ +#define MBC_SEND_LFA_COMMAND 0x7D /* Send Loop Fabric Address */ +#define MBC_LUN_RESET 0x7E /* Send LUN reset */ + +/* Firmware return data sizes */ +#define FCAL_MAP_SIZE 128 + +/* Mailbox bit definitions for out_mb and in_mb */ +#define MBX_31 BIT_31 +#define MBX_30 BIT_30 +#define MBX_29 BIT_29 +#define MBX_28 BIT_28 +#define MBX_27 BIT_27 +#define MBX_26 BIT_26 +#define MBX_25 BIT_25 +#define MBX_24 BIT_24 +#define MBX_23 BIT_23 +#define MBX_22 BIT_22 +#define MBX_21 BIT_21 +#define MBX_20 BIT_20 +#define MBX_19 BIT_19 +#define MBX_18 BIT_18 +#define MBX_17 BIT_17 +#define MBX_16 BIT_16 +#define MBX_15 BIT_15 +#define MBX_14 BIT_14 +#define MBX_13 BIT_13 +#define MBX_12 BIT_12 +#define MBX_11 BIT_11 +#define MBX_10 BIT_10 +#define MBX_9 BIT_9 +#define MBX_8 BIT_8 +#define MBX_7 BIT_7 +#define MBX_6 BIT_6 +#define MBX_5 BIT_5 +#define MBX_4 BIT_4 +#define MBX_3 BIT_3 +#define MBX_2 BIT_2 +#define MBX_1 BIT_1 +#define MBX_0 BIT_0 + +/* + * Firmware state codes from get firmware state mailbox command + */ +#define FSTATE_CONFIG_WAIT 0 +#define FSTATE_WAIT_AL_PA 1 +#define FSTATE_WAIT_LOGIN 2 +#define FSTATE_READY 3 +#define FSTATE_LOSS_OF_SYNC 4 +#define FSTATE_ERROR 5 +#define FSTATE_REINIT 6 +#define FSTATE_NON_PART 7 + +#define FSTATE_CONFIG_CORRECT 0 +#define FSTATE_P2P_RCV_LIP 1 +#define FSTATE_P2P_CHOOSE_LOOP 2 +#define FSTATE_P2P_RCV_UNIDEN_LIP 3 +#define FSTATE_FATAL_ERROR 4 +#define FSTATE_LOOP_BACK_CONN 5 + +/* + * Port Database structure definition + * Little endian except where noted. + */ +#define PORT_DATABASE_SIZE 128 /* bytes */ +typedef struct { + uint8_t options; + uint8_t control; + uint8_t master_state; + uint8_t slave_state; + uint8_t reserved[2]; + uint8_t hard_address; + uint8_t reserved_1; + uint8_t port_id[4]; + uint8_t node_name[WWN_SIZE]; /* Big endian. */ + uint8_t port_name[WWN_SIZE]; /* Big endian. */ + uint16_t execution_throttle; + uint16_t execution_count; + uint8_t reset_count; + uint8_t reserved_2; + uint16_t resource_allocation; + uint16_t current_allocation; + uint16_t queue_head; + uint16_t queue_tail; + uint16_t transmit_execution_list_next; + uint16_t transmit_execution_list_previous; + uint16_t common_features; + uint16_t total_concurrent_sequences; + uint16_t RO_by_information_category; + uint8_t recipient; + uint8_t initiator; + uint16_t receive_data_size; + uint16_t concurrent_sequences; + uint16_t open_sequences_per_exchange; + uint16_t lun_abort_flags; + uint16_t lun_stop_flags; + uint16_t stop_queue_head; + uint16_t stop_queue_tail; + uint16_t port_retry_timer; + uint16_t next_sequence_id; + uint16_t frame_count; + uint16_t PRLI_payload_length; + uint8_t prli_svc_param_word_0[2]; /* Big endian */ + /* Bits 15-0 of word 0 */ + uint8_t prli_svc_param_word_3[2]; /* Big endian */ + /* Bits 15-0 of word 3 */ + uint16_t loop_id; + uint16_t extended_lun_info_list_pointer; + uint16_t extended_lun_stop_list_pointer; +} port_database_t; + +/* + * Port database slave/master states + */ +#define PD_STATE_DISCOVERY 0 +#define PD_STATE_WAIT_DISCOVERY_ACK 1 +#define PD_STATE_PORT_LOGIN 2 +#define PD_STATE_WAIT_PORT_LOGIN_ACK 3 +#define PD_STATE_PROCESS_LOGIN 4 +#define PD_STATE_WAIT_PROCESS_LOGIN_ACK 5 +#define PD_STATE_PORT_LOGGED_IN 6 +#define PD_STATE_PORT_UNAVAILABLE 7 +#define PD_STATE_PROCESS_LOGOUT 8 +#define PD_STATE_WAIT_PROCESS_LOGOUT_ACK 9 +#define PD_STATE_PORT_LOGOUT 10 +#define PD_STATE_WAIT_PORT_LOGOUT_ACK 11 + + +/* + * ISP Initialization Control Block. + * Little endian except where noted. + */ +#define ICB_VERSION 1 +typedef struct { + uint8_t version; + uint8_t reserved_1; + + /* + * LSB BIT 0 = Enable Hard Loop Id + * LSB BIT 1 = Enable Fairness + * LSB BIT 2 = Enable Full-Duplex + * LSB BIT 3 = Enable Fast Posting + * LSB BIT 4 = Enable Target Mode + * LSB BIT 5 = Disable Initiator Mode + * LSB BIT 6 = Enable ADISC + * LSB BIT 7 = Enable Target Inquiry Data + * + * MSB BIT 0 = Enable PDBC Notify + * MSB BIT 1 = Non Participating LIP + * MSB BIT 2 = Descending Loop ID Search + * MSB BIT 3 = Acquire Loop ID in LIPA + * MSB BIT 4 = Stop PortQ on Full Status + * MSB BIT 5 = Full Login after LIP + * MSB BIT 6 = Node Name Option + * MSB BIT 7 = Ext IFWCB enable bit + */ + uint8_t firmware_options[2]; + + uint16_t frame_payload_size; + uint16_t max_iocb_allocation; + uint16_t execution_throttle; + uint8_t retry_count; + uint8_t retry_delay; /* unused */ + uint8_t port_name[WWN_SIZE]; /* Big endian. */ + uint16_t hard_address; + uint8_t inquiry_data; + uint8_t login_timeout; + uint8_t node_name[WWN_SIZE]; /* Big endian. */ + + uint16_t request_q_outpointer; + uint16_t response_q_inpointer; + uint16_t request_q_length; + uint16_t response_q_length; + uint32_t request_q_address[2]; + uint32_t response_q_address[2]; + + uint16_t lun_enables; + uint8_t command_resource_count; + uint8_t immediate_notify_resource_count; + uint16_t timeout; + uint8_t reserved_2[2]; + + /* + * LSB BIT 0 = Timer Operation mode bit 0 + * LSB BIT 1 = Timer Operation mode bit 1 + * LSB BIT 2 = Timer Operation mode bit 2 + * LSB BIT 3 = Timer Operation mode bit 3 + * LSB BIT 4 = Init Config Mode bit 0 + * LSB BIT 5 = Init Config Mode bit 1 + * LSB BIT 6 = Init Config Mode bit 2 + * LSB BIT 7 = Enable Non part on LIHA failure + * + * MSB BIT 0 = Enable class 2 + * MSB BIT 1 = Enable ACK0 + * MSB BIT 2 = + * MSB BIT 3 = + * MSB BIT 4 = FC Tape Enable + * MSB BIT 5 = Enable FC Confirm + * MSB BIT 6 = Enable command queuing in target mode + * MSB BIT 7 = No Logo On Link Down + */ + uint8_t add_firmware_options[2]; + + uint8_t response_accumulation_timer; + uint8_t interrupt_delay_timer; + + /* + * LSB BIT 0 = Enable Read xfr_rdy + * LSB BIT 1 = Soft ID only + * LSB BIT 2 = + * LSB BIT 3 = + * LSB BIT 4 = FCP RSP Payload [0] + * LSB BIT 5 = FCP RSP Payload [1] / Sbus enable - 2200 + * LSB BIT 6 = Enable Out-of-Order frame handling + * LSB BIT 7 = Disable Automatic PLOGI on Local Loop + * + * MSB BIT 0 = Sbus enable - 2300 + * MSB BIT 1 = + * MSB BIT 2 = + * MSB BIT 3 = + * MSB BIT 4 = + * MSB BIT 5 = enable 50 ohm termination + * MSB BIT 6 = Data Rate (2300 only) + * MSB BIT 7 = Data Rate (2300 only) + */ + uint8_t special_options[2]; + + uint8_t reserved_3[26]; +} init_cb_t; + +/* + * Get Link Status mailbox command return buffer. + */ +typedef struct { + uint32_t link_fail_cnt; + uint32_t loss_sync_cnt; + uint32_t loss_sig_cnt; + uint32_t prim_seq_err_cnt; + uint32_t inval_xmit_word_cnt; + uint32_t inval_crc_cnt; +} link_stat_t; + +/* + * NVRAM Command values. + */ +#define NV_START_BIT BIT_2 +#define NV_WRITE_OP (BIT_26+BIT_24) +#define NV_READ_OP (BIT_26+BIT_25) +#define NV_ERASE_OP (BIT_26+BIT_25+BIT_24) +#define NV_MASK_OP (BIT_26+BIT_25+BIT_24) +#define NV_DELAY_COUNT 10 + +/* + * QLogic ISP2100, ISP2200 and ISP2300 NVRAM structure definition. + */ +typedef struct { + /* + * NVRAM header + */ + uint8_t id[4]; + uint8_t nvram_version; + uint8_t reserved_0; + + /* + * NVRAM RISC parameter block + */ + uint8_t parameter_block_version; + uint8_t reserved_1; + + /* + * LSB BIT 0 = Enable Hard Loop Id + * LSB BIT 1 = Enable Fairness + * LSB BIT 2 = Enable Full-Duplex + * LSB BIT 3 = Enable Fast Posting + * LSB BIT 4 = Enable Target Mode + * LSB BIT 5 = Disable Initiator Mode + * LSB BIT 6 = Enable ADISC + * LSB BIT 7 = Enable Target Inquiry Data + * + * MSB BIT 0 = Enable PDBC Notify + * MSB BIT 1 = Non Participating LIP + * MSB BIT 2 = Descending Loop ID Search + * MSB BIT 3 = Acquire Loop ID in LIPA + * MSB BIT 4 = Stop PortQ on Full Status + * MSB BIT 5 = Full Login after LIP + * MSB BIT 6 = Node Name Option + * MSB BIT 7 = Ext IFWCB enable bit + */ + uint8_t firmware_options[2]; + + uint16_t frame_payload_size; + uint16_t max_iocb_allocation; + uint16_t execution_throttle; + uint8_t retry_count; + uint8_t retry_delay; /* unused */ + uint8_t port_name[WWN_SIZE]; /* Big endian. */ + uint16_t hard_address; + uint8_t inquiry_data; + uint8_t login_timeout; + uint8_t node_name[WWN_SIZE]; /* Big endian. */ + + /* + * LSB BIT 0 = Timer Operation mode bit 0 + * LSB BIT 1 = Timer Operation mode bit 1 + * LSB BIT 2 = Timer Operation mode bit 2 + * LSB BIT 3 = Timer Operation mode bit 3 + * LSB BIT 4 = Init Config Mode bit 0 + * LSB BIT 5 = Init Config Mode bit 1 + * LSB BIT 6 = Init Config Mode bit 2 + * LSB BIT 7 = Enable Non part on LIHA failure + * + * MSB BIT 0 = Enable class 2 + * MSB BIT 1 = Enable ACK0 + * MSB BIT 2 = + * MSB BIT 3 = + * MSB BIT 4 = FC Tape Enable + * MSB BIT 5 = Enable FC Confirm + * MSB BIT 6 = Enable command queuing in target mode + * MSB BIT 7 = No Logo On Link Down + */ + uint8_t add_firmware_options[2]; + + uint8_t response_accumulation_timer; + uint8_t interrupt_delay_timer; + + /* + * LSB BIT 0 = Enable Read xfr_rdy + * LSB BIT 1 = Soft ID only + * LSB BIT 2 = + * LSB BIT 3 = + * LSB BIT 4 = FCP RSP Payload [0] + * LSB BIT 5 = FCP RSP Payload [1] / Sbus enable - 2200 + * LSB BIT 6 = Enable Out-of-Order frame handling + * LSB BIT 7 = Disable Automatic PLOGI on Local Loop + * + * MSB BIT 0 = Sbus enable - 2300 + * MSB BIT 1 = + * MSB BIT 2 = + * MSB BIT 3 = + * MSB BIT 4 = + * MSB BIT 5 = enable 50 ohm termination + * MSB BIT 6 = Data Rate (2300 only) + * MSB BIT 7 = Data Rate (2300 only) + */ + uint8_t special_options[2]; + + /* Reserved for expanded RISC parameter block */ + uint8_t reserved_2[24]; + + /* + * LSB BIT 0 = Output Swing 1G bit 0 + * LSB BIT 1 = Output Swing 1G bit 1 + * LSB BIT 2 = Output Swing 1G bit 2 + * LSB BIT 3 = Output Emphasis 1G bit 0 + * LSB BIT 4 = Output Emphasis 1G bit 1 + * LSB BIT 5 = Output Swing 2G bit 0 + * LSB BIT 6 = Output Swing 2G bit 1 + * LSB BIT 7 = Output Swing 2G bit 2 + * + * MSB BIT 0 = Output Emphasis 2G bit 0 + * MSB BIT 1 = Output Emphasis 2G bit 1 + * MSB BIT 2 = Output Enable + * MSB BIT 3 = + * MSB BIT 4 = + * MSB BIT 5 = + * MSB BIT 6 = + * MSB BIT 7 = + */ + uint8_t seriallink_options[2]; + + /* + * NVRAM host parameter block + * + * LSB BIT 0 = Enable spinup delay + * LSB BIT 1 = Disable BIOS + * LSB BIT 2 = Enable Memory Map BIOS + * LSB BIT 3 = Enable Selectable Boot + * LSB BIT 4 = Disable RISC code load + * LSB BIT 5 = Set cache line size 1 + * LSB BIT 6 = PCI Parity Disable + * LSB BIT 7 = Enable extended logging + * + * MSB BIT 0 = Enable 64bit addressing + * MSB BIT 1 = Enable lip reset + * MSB BIT 2 = Enable lip full login + * MSB BIT 3 = Enable target reset + * MSB BIT 4 = Enable database storage + * MSB BIT 5 = Enable cache flush read + * MSB BIT 6 = Enable database load + * MSB BIT 7 = Enable alternate WWN + */ + uint8_t host_p[2]; + + uint8_t boot_node_name[WWN_SIZE]; + uint8_t boot_lun_number; + uint8_t reset_delay; + uint8_t port_down_retry_count; + uint8_t boot_id_number; + uint16_t max_luns_per_target; + uint8_t fcode_boot_port_name[WWN_SIZE]; + uint8_t alternate_port_name[WWN_SIZE]; + uint8_t alternate_node_name[WWN_SIZE]; + + /* + * BIT 0 = Boot Zoning + * BIT 1 = Alt-Boot Enable + * BIT 2 = Report SCSI Path + * BIT 3 = unused + * BIT 4 = unused + * BIT 5 = unused + * BIT 6 = unused + * BIT 7 = unused + */ + uint8_t efi_parameters; + + uint8_t link_down_timeout; + + uint8_t adapter_id_0[4]; + uint8_t adapter_id_1[4]; + uint8_t adapter_id_2[4]; + uint8_t adapter_id_3[4]; + + uint8_t alt1_boot_node_name[WWN_SIZE]; + uint16_t alt1_boot_lun_number; + uint8_t alt2_boot_node_name[WWN_SIZE]; + uint16_t alt2_boot_lun_number; + uint8_t alt3_boot_node_name[WWN_SIZE]; + uint16_t alt3_boot_lun_number; + uint8_t alt4_boot_node_name[WWN_SIZE]; + uint16_t alt4_boot_lun_number; + uint8_t alt5_boot_node_name[WWN_SIZE]; + uint16_t alt5_boot_lun_number; + uint8_t alt6_boot_node_name[WWN_SIZE]; + uint16_t alt6_boot_lun_number; + uint8_t alt7_boot_node_name[WWN_SIZE]; + uint16_t alt7_boot_lun_number; + + uint8_t reserved_3[2]; + + /* Offset 200-215 : Model Number */ + uint8_t model_number[16]; + + /* OEM related items */ + uint8_t oem_specific[16]; + + /* + * NVRAM Adapter Features offset 232-239 + * + * LSB BIT 0 = External GBIC + * LSB BIT 1 = Risc RAM parity + * LSB BIT 2 = Buffer Plus Module + * LSB BIT 3 = Multi Chip Adapter + * LSB BIT 4 = Internal connector + * LSB BIT 5 = + * LSB BIT 6 = + * LSB BIT 7 = + * + * MSB BIT 0 = + * MSB BIT 1 = + * MSB BIT 2 = + * MSB BIT 3 = + * MSB BIT 4 = + * MSB BIT 5 = + * MSB BIT 6 = + * MSB BIT 7 = + */ + uint8_t adapter_features[2]; + + uint8_t reserved_4[16]; + + /* Subsystem vendor ID for ISP2200 */ + uint16_t subsystem_vendor_id_2200; + + /* Subsystem device ID for ISP2200 */ + uint16_t subsystem_device_id_2200; + + uint8_t reserved_5; + uint8_t checksum; +} nvram_t; + +/* + * ISP queue - response queue entry definition. + */ +typedef struct { + uint8_t data[60]; + uint32_t signature; +#define RESPONSE_PROCESSED 0xDEADDEAD /* Signature */ +} response_t; + +typedef union { + uint16_t extended; + struct { + uint8_t reserved; + uint8_t standard;; + }; +} target_id_t; + +#define SET_TARGET_ID(ha, to, from) \ +do { \ + if (HAS_EXTENDED_IDS(ha)) \ + to.extended = cpu_to_le16(from); \ + else \ + to.standard = (uint8_t)from; \ +} while (0) + +/* + * ISP queue - command entry structure definition. + */ +#define COMMAND_TYPE 0x11 /* Command entry */ +#define MAX_CMDSZ 16 /* SCSI maximum CDB size. */ +typedef struct { + uint8_t entry_type; /* Entry type. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t handle; /* System handle. */ + target_id_t target; /* SCSI ID */ + uint16_t lun; /* SCSI LUN */ + uint16_t control_flags; /* Control flags. */ +#define CF_WRITE BIT_6 +#define CF_READ BIT_5 +#define CF_SIMPLE_TAG BIT_3 +#define CF_ORDERED_TAG BIT_2 +#define CF_HEAD_TAG BIT_1 + uint16_t reserved_1; + uint16_t timeout; /* Command timeout. */ + uint16_t dseg_count; /* Data segment count. */ + uint8_t scsi_cdb[MAX_CMDSZ]; /* SCSI command words. */ + uint32_t byte_count; /* Total byte count. */ + uint32_t dseg_0_address; /* Data segment 0 address. */ + uint32_t dseg_0_length; /* Data segment 0 length. */ + uint32_t dseg_1_address; /* Data segment 1 address. */ + uint32_t dseg_1_length; /* Data segment 1 length. */ + uint32_t dseg_2_address; /* Data segment 2 address. */ + uint32_t dseg_2_length; /* Data segment 2 length. */ +} cmd_entry_t; + +/* + * ISP queue - 64-Bit addressing, command entry structure definition. + */ +#define COMMAND_A64_TYPE 0x19 /* Command A64 entry */ +typedef struct { + uint8_t entry_type; /* Entry type. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t handle; /* System handle. */ + target_id_t target; /* SCSI ID */ + uint16_t lun; /* SCSI LUN */ + uint16_t control_flags; /* Control flags. */ + uint16_t reserved_1; + uint16_t timeout; /* Command timeout. */ + uint16_t dseg_count; /* Data segment count. */ + uint8_t scsi_cdb[MAX_CMDSZ]; /* SCSI command words. */ + uint32_t byte_count; /* Total byte count. */ + uint32_t dseg_0_address[2]; /* Data segment 0 address. */ + uint32_t dseg_0_length; /* Data segment 0 length. */ + uint32_t dseg_1_address[2]; /* Data segment 1 address. */ + uint32_t dseg_1_length; /* Data segment 1 length. */ +} cmd_a64_entry_t, request_t; + +/* + * ISP queue - continuation entry structure definition. + */ +#define CONTINUE_TYPE 0x02 /* Continuation entry. */ +typedef struct { + uint8_t entry_type; /* Entry type. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t reserved; + uint32_t dseg_0_address; /* Data segment 0 address. */ + uint32_t dseg_0_length; /* Data segment 0 length. */ + uint32_t dseg_1_address; /* Data segment 1 address. */ + uint32_t dseg_1_length; /* Data segment 1 length. */ + uint32_t dseg_2_address; /* Data segment 2 address. */ + uint32_t dseg_2_length; /* Data segment 2 length. */ + uint32_t dseg_3_address; /* Data segment 3 address. */ + uint32_t dseg_3_length; /* Data segment 3 length. */ + uint32_t dseg_4_address; /* Data segment 4 address. */ + uint32_t dseg_4_length; /* Data segment 4 length. */ + uint32_t dseg_5_address; /* Data segment 5 address. */ + uint32_t dseg_5_length; /* Data segment 5 length. */ + uint32_t dseg_6_address; /* Data segment 6 address. */ + uint32_t dseg_6_length; /* Data segment 6 length. */ +} cont_entry_t; + +/* + * ISP queue - 64-Bit addressing, continuation entry structure definition. + */ +#define CONTINUE_A64_TYPE 0x0A /* Continuation A64 entry. */ +typedef struct { + uint8_t entry_type; /* Entry type. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t dseg_0_address[2]; /* Data segment 0 address. */ + uint32_t dseg_0_length; /* Data segment 0 length. */ + uint32_t dseg_1_address[2]; /* Data segment 1 address. */ + uint32_t dseg_1_length; /* Data segment 1 length. */ + uint32_t dseg_2_address [2]; /* Data segment 2 address. */ + uint32_t dseg_2_length; /* Data segment 2 length. */ + uint32_t dseg_3_address[2]; /* Data segment 3 address. */ + uint32_t dseg_3_length; /* Data segment 3 length. */ + uint32_t dseg_4_address[2]; /* Data segment 4 address. */ + uint32_t dseg_4_length; /* Data segment 4 length. */ +} cont_a64_entry_t; + +/* + * ISP queue - status entry structure definition. + */ +#define STATUS_TYPE 0x03 /* Status entry. */ +typedef struct { + uint8_t entry_type; /* Entry type. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t handle; /* System handle. */ + uint16_t scsi_status; /* SCSI status. */ + uint16_t comp_status; /* Completion status. */ + uint16_t state_flags; /* State flags. */ + uint16_t status_flags; /* Status flags. */ + uint16_t rsp_info_len; /* Response Info Length. */ + uint16_t req_sense_length; /* Request sense data length. */ + uint32_t residual_length; /* Residual transfer length. */ + uint8_t rsp_info[8]; /* FCP response information. */ + uint8_t req_sense_data[32]; /* Request sense data. */ +} sts_entry_t; + +/* + * Status entry entry status + */ +#define RF_INV_E_ORDER BIT_5 /* Invalid entry order. */ +#define RF_INV_E_COUNT BIT_4 /* Invalid entry count. */ +#define RF_INV_E_PARAM BIT_3 /* Invalid entry parameter. */ +#define RF_INV_E_TYPE BIT_2 /* Invalid entry type. */ +#define RF_BUSY BIT_1 /* Busy */ + +/* + * Status entry SCSI status bit definitions. + */ +#define SS_MASK 0xfff /* Reserved bits BIT_12-BIT_15*/ +#define SS_RESIDUAL_UNDER BIT_11 +#define SS_RESIDUAL_OVER BIT_10 +#define SS_SENSE_LEN_VALID BIT_9 +#define SS_RESIDUAL_LEN_VALID BIT_8 /* ISP2100 only */ +#define SS_RESPONSE_INFO_LEN_VALID BIT_8 /* ISP2200 and 23xx */ + +#define SS_RESERVE_CONFLICT (BIT_4 | BIT_3) +#define SS_BUSY_CONDITION BIT_3 +#define SS_CONDITION_MET BIT_2 +#define SS_CHECK_CONDITION BIT_1 + +/* + * Status entry completion status + */ +#define CS_COMPLETE 0x0 /* No errors */ +#define CS_INCOMPLETE 0x1 /* Incomplete transfer of cmd. */ +#define CS_DMA 0x2 /* A DMA direction error. */ +#define CS_TRANSPORT 0x3 /* Transport error. */ +#define CS_RESET 0x4 /* SCSI bus reset occurred */ +#define CS_ABORTED 0x5 /* System aborted command. */ +#define CS_TIMEOUT 0x6 /* Timeout error. */ +#define CS_DATA_OVERRUN 0x7 /* Data overrun. */ + +#define CS_DATA_UNDERRUN 0x15 /* Data Underrun. */ +#define CS_QUEUE_FULL 0x1C /* Queue Full. */ +#define CS_PORT_UNAVAILABLE 0x28 /* Port unavailable */ + /* (selection timeout) */ +#define CS_PORT_LOGGED_OUT 0x29 /* Port Logged Out */ +#define CS_PORT_CONFIG_CHG 0x2A /* Port Configuration Changed */ +#define CS_PORT_BUSY 0x2B /* Port Busy */ +#define CS_COMPLETE_CHKCOND 0x30 /* Error? */ +#define CS_BAD_PAYLOAD 0x80 /* Driver defined */ +#define CS_UNKNOWN 0x81 /* Driver defined */ +#define CS_RETRY 0x82 /* Driver defined */ +#define CS_LOOP_DOWN_ABORT 0x83 /* Driver defined */ + +/* + * Status entry status flags + */ +#define SF_LOGOUT_SENT BIT_13 + +/* + * ISP queue - status continuation entry structure definition. + */ +#define STATUS_CONT_TYPE 0x10 /* Status continuation entry. */ +typedef struct { + uint8_t entry_type; /* Entry type. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint8_t data[60]; /* data */ +} sts_cont_entry_t; + +/* + * ISP queue - RIO Type 1 status entry (32 bit I/O entry handles) + * structure definition. + */ +#define STATUS_TYPE_21 0x21 /* Status entry. */ +typedef struct { + uint8_t entry_type; /* Entry type. */ + uint8_t entry_count; /* Entry count. */ + uint8_t handle_count; /* Handle count. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t handle[15]; /* System handles. */ +} sts21_entry_t; + +/* + * ISP queue - RIO Type 2 status entry (16 bit I/O entry handles) + * structure definition. + */ +#define STATUS_TYPE_22 0x22 /* Status entry. */ +typedef struct { + uint8_t entry_type; /* Entry type. */ + uint8_t entry_count; /* Entry count. */ + uint8_t handle_count; /* Handle count. */ + uint8_t entry_status; /* Entry Status. */ + uint16_t handle[30]; /* System handles. */ +} sts22_entry_t; + +/* + * ISP queue - marker entry structure definition. + */ +#define MARKER_TYPE 0x04 /* Marker entry. */ +typedef struct { + uint8_t entry_type; /* Entry type. */ + uint8_t entry_count; /* Entry count. */ + uint8_t handle_count; /* Handle count. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t sys_define_2; /* System defined. */ + target_id_t target; /* SCSI ID */ + uint8_t modifier; /* Modifier (7-0). */ +#define MK_SYNC_ID_LUN 0 /* Synchronize ID/LUN */ +#define MK_SYNC_ID 1 /* Synchronize ID */ +#define MK_SYNC_ALL 2 /* Synchronize all ID/LUN */ +#define MK_SYNC_LIP 3 /* Synchronize all ID/LUN, */ + /* clear port changed, */ + /* use sequence number. */ + uint8_t reserved_1; + uint16_t sequence_number; /* Sequence number of event */ + uint16_t lun; /* SCSI LUN */ + uint8_t reserved_2[48]; +} mrk_entry_t; + +/* + * ISP queue - Management Server entry structure definition. + */ +#define MS_IOCB_TYPE 0x29 /* Management Server IOCB entry */ +typedef struct { + uint8_t entry_type; /* Entry type. */ + uint8_t entry_count; /* Entry count. */ + uint8_t handle_count; /* Handle count. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t handle1; /* System handle. */ + target_id_t loop_id; + uint16_t status; + uint16_t control_flags; /* Control flags. */ + uint16_t reserved2; + uint16_t timeout; + uint16_t cmd_dsd_count; + uint16_t total_dsd_count; + uint8_t type; + uint8_t r_ctl; + uint16_t rx_id; + uint16_t reserved3; + uint32_t handle2; + uint32_t rsp_bytecount; + uint32_t req_bytecount; + uint32_t dseg_req_address[2]; /* Data segment 0 address. */ + uint32_t dseg_req_length; /* Data segment 0 length. */ + uint32_t dseg_rsp_address[2]; /* Data segment 1 address. */ + uint32_t dseg_rsp_length; /* Data segment 1 length. */ +} ms_iocb_entry_t; + + +/* + * ISP queue - Mailbox Command entry structure definition. + */ +#define MBX_IOCB_TYPE 0x39 +struct mbx_entry { + uint8_t entry_type; + uint8_t entry_count; + uint8_t sys_define1; + /* Use sys_define1 for source type */ +#define SOURCE_SCSI 0x00 +#define SOURCE_IP 0x01 +#define SOURCE_VI 0x02 +#define SOURCE_SCTP 0x03 +#define SOURCE_MP 0x04 +#define SOURCE_MPIOCTL 0x05 +#define SOURCE_ASYNC_IOCB 0x07 + + uint8_t entry_status; + + uint32_t handle; + target_id_t loop_id; + + uint16_t status; + uint16_t state_flags; + uint16_t status_flags; + + uint32_t sys_define2[2]; + + uint16_t mb0; + uint16_t mb1; + uint16_t mb2; + uint16_t mb3; + uint16_t mb6; + uint16_t mb7; + uint16_t mb9; + uint16_t mb10; + uint32_t reserved_2[2]; + uint8_t node_name[WWN_SIZE]; + uint8_t port_name[WWN_SIZE]; +}; + +/* + * ISP request and response queue entry sizes + */ +#define RESPONSE_ENTRY_SIZE (sizeof(response_t)) +#define REQUEST_ENTRY_SIZE (sizeof(request_t)) + + +/* + * 24 bit port ID type definition. + */ +typedef union { + uint32_t b24 : 24; + + struct { + uint8_t d_id[3]; + uint8_t rsvd_1; + } r; + + struct { + uint8_t al_pa; + uint8_t area; + uint8_t domain; + uint8_t rsvd_1; + } b; +} port_id_t; +#define INVALID_PORT_ID 0xFFFFFF + +/* + * Switch info gathering structure. + */ +typedef struct { + port_id_t d_id; + uint8_t node_name[WWN_SIZE]; + uint8_t port_name[WWN_SIZE]; + uint32_t type; +#define SW_TYPE_IP BIT_1 +#define SW_TYPE_SCSI BIT_0 +} sw_info_t; + +/* + * Inquiry command structure. + */ +#define INQ_DATA_SIZE 8 + +/* + * Inquiry mailbox IOCB packet definition. + */ +typedef struct { + union { + cmd_a64_entry_t cmd; + sts_entry_t rsp; + } p; + uint8_t inq[INQ_DATA_SIZE]; +} inq_cmd_rsp_t; + +/* + * Report LUN command structure. + */ +#define CHAR_TO_SHORT(a, b) (uint16_t)((uint8_t)b << 8 | (uint8_t)a) + +typedef struct { + uint32_t len; + uint32_t rsrv; +} rpt_hdr_t; + +typedef struct { + struct { + uint8_t b : 6; + uint8_t address_method : 2; + } msb; + uint8_t lsb; + uint8_t unused[6]; +} rpt_lun_t; + +typedef struct { + rpt_hdr_t hdr; + rpt_lun_t lst[MAX_LUNS]; +} rpt_lun_lst_t; + +/* + * Report Lun mailbox IOCB packet definition. + */ +typedef struct { + union { + cmd_a64_entry_t cmd; + sts_entry_t rsp; + } p; + rpt_lun_lst_t list; +} rpt_lun_cmd_rsp_t; + +/* + * SCSI Target Queue structure + */ +typedef struct os_tgt { + struct os_lun *olun[MAX_LUNS]; /* LUN context pointer. */ + struct fc_port *fcport; + uint32_t flags; + uint8_t port_down_retry_count; + uint32_t down_timer; + struct scsi_qla_host *ha; + + /* Persistent binding information */ + port_id_t d_id; + uint8_t node_name[WWN_SIZE]; + uint8_t port_name[WWN_SIZE]; +} os_tgt_t; + +/* + * SCSI Target Queue flags + */ +#define TQF_QUEUE_SUSPENDED BIT_0 /* Queue suspended. */ +#define TQF_BOOT_DEVICE BIT_1 /* Boot device. */ +#define TQF_ONLINE BIT_2 /* Device online to OS. */ +#define TQF_TGT_RST_NEEDED BIT_3 + +/* + * SCSI LUN Queue structure + */ +typedef struct os_lun { + struct fc_lun *fclun; /* FC LUN context pointer. */ + spinlock_t q_lock; /* Lun Lock */ + + unsigned long q_flag; +#define LUN_MPIO_BUSY 2 /* Lun is changing paths */ +#define LUN_EXEC_DELAYED 7 /* Lun execution is delayed */ + + u_long q_timeout; /* total command timeouts */ + atomic_t q_timer; /* suspend timer */ + uint32_t q_count; /* current count */ + uint32_t q_max; /* maxmum count lun can be suspended */ + uint8_t q_state; /* lun State */ +#define LUN_STATE_READY 1 /* lun is ready for i/o */ +#define LUN_STATE_RUN 2 /* lun has a timer running */ +#define LUN_STATE_WAIT 3 /* lun is suspended */ +#define LUN_STATE_TIMEOUT 4 /* lun has timed out */ + + u_long io_cnt; /* total xfer count since boot */ + u_long out_cnt; /* total outstanding IO count */ + u_long w_cnt; /* total writes */ + u_long r_cnt; /* total reads */ + u_long avg_time; /* */ +} os_lun_t; + + +/* LUN BitMask structure definition, array of 32bit words, + * 1 bit per lun. When bit == 1, the lun is masked. + * Most significant bit of mask[0] is lun 0, bit 24 is lun 7. + */ +typedef struct lun_bit_mask { + /* Must allocate at least enough bits to accomodate all LUNs */ +#if ((MAX_FIBRE_LUNS & 0x7) == 0) + uint8_t mask[MAX_FIBRE_LUNS >> 3]; +#else + uint8_t mask[(MAX_FIBRE_LUNS + 8) >> 3]; +#endif +} lun_bit_mask_t; + +/* + * Fibre channel port type. + */ + typedef enum { + FCT_UNKNOWN, + FCT_RSCN, + FCT_SWITCH, + FCT_BROADCAST, + FCT_INITIATOR, + FCT_TARGET +} fc_port_type_t; + +/* + * Fibre channel port structure. + */ +typedef struct fc_port { + struct list_head list; + struct list_head fcluns; + + struct scsi_qla_host *ha; + struct scsi_qla_host *vis_ha; /* only used when suspending lun */ + + uint8_t node_name[WWN_SIZE]; + uint8_t port_name[WWN_SIZE]; + port_id_t d_id; + uint16_t loop_id; + uint16_t old_loop_id; + + fc_port_type_t port_type; + + atomic_t state; + uint32_t flags; + + os_tgt_t *tgt_queue; + uint16_t os_target_id; + + uint16_t iodesc_idx_sent; + + int port_login_retry_count; + int login_retry; + atomic_t port_down_timer; + + uint8_t device_type; + uint8_t unused; + + uint8_t mp_byte; /* multi-path byte (not used) */ + uint8_t cur_path; /* current path id */ + + lun_bit_mask_t lun_mask; +} fc_port_t; + +/* + * Fibre channel port/lun states. + */ +#define FCS_UNCONFIGURED 1 +#define FCS_DEVICE_DEAD 2 +#define FCS_DEVICE_LOST 3 +#define FCS_ONLINE 4 +#define FCS_NOT_SUPPORTED 5 +#define FCS_FAILOVER 6 +#define FCS_FAILOVER_FAILED 7 + +/* + * FC port flags. + */ +#define FCF_FABRIC_DEVICE BIT_0 +#define FCF_LOGIN_NEEDED BIT_1 +#define FCF_FO_MASKED BIT_2 +#define FCF_FAILOVER_NEEDED BIT_3 +#define FCF_RESET_NEEDED BIT_4 +#define FCF_PERSISTENT_BOUND BIT_5 +#define FCF_TAPE_PRESENT BIT_6 +#define FCF_FARP_DONE BIT_7 +#define FCF_FARP_FAILED BIT_8 +#define FCF_FARP_REPLY_NEEDED BIT_9 +#define FCF_AUTH_REQ BIT_10 +#define FCF_SEND_AUTH_REQ BIT_11 +#define FCF_RECEIVE_AUTH_REQ BIT_12 +#define FCF_AUTH_SUCCESS BIT_13 +#define FCF_RLC_SUPPORT BIT_14 +#define FCF_CONFIG BIT_15 /* Needed? */ +#define FCF_RESCAN_NEEDED BIT_16 + +/* No loop ID flag. */ +#define FC_NO_LOOP_ID 0x1000 + +/* + * Fibre channel LUN structure. + */ +typedef struct fc_lun { + struct list_head list; + + fc_port_t *fcport; + fc_port_t *o_fcport; + uint16_t lun; + atomic_t state; + uint8_t device_type; + uint8_t max_path_retries; +} fc_lun_t; + + +/* + * FC-CT interface + * + * NOTE: All structures are big-endian in form. + */ + +#define CT_REJECT_RESPONSE 0x8001 +#define CT_ACCEPT_RESPONSE 0x8002 + +#define NS_N_PORT_TYPE 0x01 +#define NS_NL_PORT_TYPE 0x02 +#define NS_NX_PORT_TYPE 0x7F + +#define GA_NXT_CMD 0x100 +#define GA_NXT_REQ_SIZE (16 + 4) +#define GA_NXT_RSP_SIZE (16 + 620) + +#define GID_PT_CMD 0x1A1 +#define GID_PT_REQ_SIZE (16 + 4) +#define GID_PT_RSP_SIZE (16 + (MAX_FIBRE_DEVICES * 4)) + +#define GPN_ID_CMD 0x112 +#define GPN_ID_REQ_SIZE (16 + 4) +#define GPN_ID_RSP_SIZE (16 + 8) + +#define GNN_ID_CMD 0x113 +#define GNN_ID_REQ_SIZE (16 + 4) +#define GNN_ID_RSP_SIZE (16 + 8) + +#define GFT_ID_CMD 0x117 +#define GFT_ID_REQ_SIZE (16 + 4) +#define GFT_ID_RSP_SIZE (16 + 32) + +#define RFT_ID_CMD 0x217 +#define RFT_ID_REQ_SIZE (16 + 4 + 32) +#define RFT_ID_RSP_SIZE 16 + +#define RFF_ID_CMD 0x21F +#define RFF_ID_REQ_SIZE (16 + 4 + 2 + 1 + 1) +#define RFF_ID_RSP_SIZE 16 + +#define RNN_ID_CMD 0x213 +#define RNN_ID_REQ_SIZE (16 + 4 + 8) +#define RNN_ID_RSP_SIZE 16 + +#define RSNN_NN_CMD 0x239 +#define RSNN_NN_REQ_SIZE (16 + 8 + 1 + 255) +#define RSNN_NN_RSP_SIZE 16 + +/* CT command header -- request/response common fields */ +struct ct_cmd_hdr { + uint8_t revision; + uint8_t in_id[3]; + uint8_t gs_type; + uint8_t gs_subtype; + uint8_t options; + uint8_t reserved; +}; + +/* CT command request */ +struct ct_sns_req { + struct ct_cmd_hdr header; + uint16_t command; + uint16_t max_rsp_size; + uint8_t fragment_id; + uint8_t reserved[3]; + + union { + /* GA_NXT, GPN_ID, GNN_ID, GFT_ID */ + struct { + uint8_t reserved; + uint8_t port_id[3]; + } port_id; + + struct { + uint8_t port_type; + uint8_t domain; + uint8_t area; + uint8_t reserved; + } gid_pt; + + struct { + uint8_t reserved; + uint8_t port_id[3]; + uint8_t fc4_types[32]; + } rft_id; + + struct { + uint8_t reserved; + uint8_t port_id[3]; + uint16_t reserved2; + uint8_t fc4_feature; + uint8_t fc4_type; + } rff_id; + + struct { + uint8_t reserved; + uint8_t port_id[3]; + uint8_t node_name[8]; + } rnn_id; + + struct { + uint8_t node_name[8]; + uint8_t name_len; + uint8_t sym_node_name[255]; + } rsnn_nn; + } req; +}; + +/* CT command response header */ +struct ct_rsp_hdr { + struct ct_cmd_hdr header; + uint16_t response; + uint16_t residual; + uint8_t fragment_id; + uint8_t reason_code; + uint8_t explanation_code; + uint8_t vendor_unique; +}; + +struct ct_sns_gid_pt_data { + uint8_t control_byte; + uint8_t port_id[3]; +}; + +struct ct_sns_rsp { + struct ct_rsp_hdr header; + + union { + struct { + uint8_t port_type; + uint8_t port_id[3]; + uint8_t port_name[8]; + uint8_t sym_port_name_len; + uint8_t sym_port_name[255]; + uint8_t node_name[8]; + uint8_t sym_node_name_len; + uint8_t sym_node_name[255]; + uint8_t init_proc_assoc[8]; + uint8_t node_ip_addr[16]; + uint8_t class_of_service[4]; + uint8_t fc4_types[32]; + uint8_t ip_address[16]; + uint8_t fabric_port_name[8]; + uint8_t reserved; + uint8_t hard_address[3]; + } ga_nxt; + + struct { + struct ct_sns_gid_pt_data entries[MAX_FIBRE_DEVICES]; + } gid_pt; + + struct { + uint8_t port_name[8]; + } gpn_id; + + struct { + uint8_t node_name[8]; + } gnn_id; + + struct { + uint8_t fc4_types[32]; + } gft_id; + } rsp; +}; + +struct ct_sns_pkt { + union { + struct ct_sns_req req; + struct ct_sns_rsp rsp; + } p; +}; + + +/* IO descriptors */ +#define MAX_IO_DESCRIPTORS 32 + +#define ABORT_IOCB_CB 0 +#define ADISC_PORT_IOCB_CB 1 +#define LOGOUT_PORT_IOCB_CB 2 +#define LOGIN_PORT_IOCB_CB 3 +#define LAST_IOCB_CB 4 + +#define IODESC_INVALID_INDEX 0xFFFF +#define IODESC_ADISC_NEEDED 0xFFFE +#define IODESC_LOGIN_NEEDED 0xFFFD + +struct io_descriptor { + uint16_t used:1; + uint16_t idx:11; + uint16_t cb_idx:4; + + struct timer_list timer; + + struct scsi_qla_host *ha; + + port_id_t d_id; + fc_port_t *remote_fcport; + + uint32_t signature; +}; + + +//TODO Complete Formatting... + +#define MAX_IOCTL_WAIT_THREADS 32 +typedef struct _wait_q_t { + uint8_t flags; +#define WQ_IN_USE 0x1 + + struct semaphore wait_q_sem; + struct _wait_q_t *pnext; +} wait_q_t; + +typedef struct hba_ioctl{ + + /* Ioctl cmd serialization */ + uint16_t access_bits; /* bits should be used atomically */ +#define IOCTL_ACTIVE 1 /* first bit */ +#define IOCTL_WANT 2 /* 2nd bit */ + + spinlock_t wait_q_lock; /* IOCTL wait_q Queue Lock */ + wait_q_t wait_q_arr[MAX_IOCTL_WAIT_THREADS]; + wait_q_t *wait_q_head; + wait_q_t *wait_q_tail; + + /* Passthru cmd/completion */ + struct semaphore cmpl_sem; + struct timer_list cmpl_timer; + uint8_t ioctl_tov; + uint8_t SCSIPT_InProgress; + uint8_t MSIOCB_InProgress; + + os_tgt_t *ioctl_tq; + os_lun_t *ioctl_lq; + + /* AEN queue */ + void *aen_tracking_queue;/* points to async events buffer */ + uint8_t aen_q_head; /* index to the current head of q */ + uint8_t aen_q_tail; /* index to the current tail of q */ + + /* Misc. */ + uint32_t flags; +#define IOCTL_OPEN BIT_0 +#define IOCTL_AEN_TRACKING_ENABLE BIT_1 + uint8_t *scrap_mem; /* per ha scrap buf for ioctl usage */ + uint32_t scrap_mem_size; /* total size */ + uint32_t scrap_mem_used; /* portion used */ + +} hba_ioctl_context; + +/* Mailbox command semaphore queue for command serialization */ +typedef struct _mbx_cmdq_t { + struct semaphore cmd_sem; + struct _mbx_cmdq_t *pnext; +} mbx_cmdq_t; + +struct qla_fw_info { + unsigned short addressing; /* addressing method used to load fw */ +#define FW_INFO_ADDR_NORMAL 0 +#define FW_INFO_ADDR_EXTENDED 1 +#define FW_INFO_ADDR_NOMORE 0xffff + unsigned short *fwcode; /* pointer to FW array */ + unsigned short *fwlen; /* number of words in array */ + unsigned short *fwstart; /* start address for F/W */ + unsigned long *lfwstart; /* start address (long) for F/W */ +}; + +struct qla_board_info { + char *drv_name; + + char isp_name[8]; + struct qla_fw_info *fw_info; +}; + +/* + * Linux Host Adapter structure + */ +typedef struct scsi_qla_host { + struct list_head list; + + /* Commonly used flags and state information. */ + struct Scsi_Host *host; + struct pci_dev *pdev; + + unsigned long host_no; + unsigned long instance; + + volatile struct { + uint32_t init_done :1; + uint32_t online :1; + uint32_t mbox_int :1; + uint32_t mbox_busy :1; + uint32_t rscn_queue_overflow :1; + uint32_t reset_active :1; + + uint32_t management_server_logged_in :1; + uint32_t process_response_queue :1; + + uint32_t disable_risc_code_load :1; + uint32_t enable_64bit_addressing :1; + uint32_t enable_lip_reset :1; + uint32_t enable_lip_full_login :1; + uint32_t enable_target_reset :1; + } flags; + + atomic_t loop_state; +#define LOOP_TIMEOUT 1 +#define LOOP_DOWN 2 +#define LOOP_UP 3 +#define LOOP_UPDATE 4 +#define LOOP_READY 5 +#define LOOP_DEAD 6 + + unsigned long dpc_flags; +#define RESET_MARKER_NEEDED 0 /* Send marker to ISP. */ +#define RESET_ACTIVE 1 +#define ISP_ABORT_NEEDED 2 /* Initiate ISP abort. */ +#define ABORT_ISP_ACTIVE 3 /* ISP abort in progress. */ +#define LOOP_RESYNC_NEEDED 4 /* Device Resync needed. */ +#define LOOP_RESYNC_ACTIVE 5 +#define LOCAL_LOOP_UPDATE 6 /* Perform a local loop update. */ +#define RSCN_UPDATE 7 /* Perform an RSCN update. */ +#define MAILBOX_RETRY 8 +#define ISP_RESET_NEEDED 9 /* Initiate a ISP reset. */ +#define FAILOVER_EVENT_NEEDED 10 +#define FAILOVER_EVENT 11 +#define FAILOVER_NEEDED 12 +#define SCSI_RESTART_NEEDED 13 /* Processes SCSI retry queue. */ +#define PORT_RESTART_NEEDED 14 /* Processes Retry queue. */ +#define RESTART_QUEUES_NEEDED 15 /* Restarts the Lun queue. */ +#define ABORT_QUEUES_NEEDED 16 +#define RELOGIN_NEEDED 17 +#define LOGIN_RETRY_NEEDED 18 /* Initiate required fabric logins. */ +#define REGISTER_FC4_NEEDED 19 /* SNS FC4 registration required. */ +#define ISP_ABORT_RETRY 20 /* ISP aborted. */ +#define FCPORT_RESCAN_NEEDED 21 /* IO descriptor processing needed */ +#define IODESC_PROCESS_NEEDED 22 /* IO descriptor processing needed */ + + uint32_t device_flags; +#define DFLG_LOCAL_DEVICES BIT_0 +#define DFLG_RETRY_LOCAL_DEVICES BIT_1 +#define DFLG_FABRIC_DEVICES BIT_2 +#define SWITCH_FOUND BIT_3 +#define DFLG_NO_CABLE BIT_4 + + /* SRB cache. */ +#define SRB_MIN_REQ 128 + mempool_t *srb_mempool; + + /* This spinlock is used to protect "io transactions", you must + * aquire it before doing any IO to the card, eg with RD_REG*() and + * WRT_REG*() for the duration of your entire commandtransaction. + * + * This spinlock is of lower priority than the io request lock. + */ + + spinlock_t hardware_lock ____cacheline_aligned; + + device_reg_t *iobase; /* Base I/O address */ + unsigned long pio_address; + unsigned long pio_length; + void * mmio_address; + unsigned long mmio_length; +#define MIN_IOBASE_LEN 0x100 + + /* ISP ring lock, rings, and indexes */ + dma_addr_t request_dma; /* Physical address. */ + request_t *request_ring; /* Base virtual address */ + request_t *request_ring_ptr; /* Current address. */ + uint16_t req_ring_index; /* Current index. */ + uint16_t req_q_cnt; /* Number of available entries. */ + + dma_addr_t response_dma; /* Physical address. */ + response_t *response_ring; /* Base virtual address */ + response_t *response_ring_ptr; /* Current address. */ + uint16_t rsp_ring_index; /* Current index. */ + uint16_t response_q_length; + + uint16_t (*calc_request_entries)(uint16_t); + void (*build_scsi_iocbs)(srb_t *, cmd_entry_t *, uint16_t); + + /* Outstandings ISP commands. */ + srb_t *outstanding_cmds[MAX_OUTSTANDING_COMMANDS]; + uint32_t current_outstanding_cmd; + srb_t *status_srb; /* Status continuation entry. */ + + /* + * Need to hold the list_lock with irq's disabled in order to access + * the following list. + * + * This list_lock is of lower priority than the io_request_lock. + * + */ + spinlock_t list_lock ____cacheline_aligned; + /* lock to guard lists which + * hold srb_t's */ + struct list_head retry_queue; /* watchdog queue */ + struct list_head done_queue; /* job on done queue */ + struct list_head failover_queue; /* failover list link. */ + struct list_head scsi_retry_queue; /* SCSI retry queue */ + struct list_head pending_queue; /* SCSI command pending queue */ + + unsigned long done_q_cnt; + unsigned long pending_in_q; + uint32_t retry_q_cnt; + uint32_t scsi_retry_q_cnt; + uint32_t failover_cnt; + + unsigned long last_irq_cpu; /* cpu where we got our last irq */ + + uint16_t revision; + uint8_t ports; + u_long actthreads; + u_long ipreq_cnt; + u_long qthreads; + + uint32_t total_isr_cnt; /* Interrupt count */ + uint32_t total_isp_aborts; /* controller err cnt */ + uint32_t total_lip_cnt; /* LIP cnt */ + uint32_t total_dev_errs; /* device error cnt */ + uint32_t total_ios; /* IO cnt */ + uint64_t total_bytes; /* xfr byte cnt */ + uint32_t total_mbx_timeout; /* mailbox timeout cnt */ + uint32_t total_loop_resync; /* loop resyn cnt */ + uint32_t dropped_frame_error_cnt; + + /* ISP configuration data. */ + uint16_t loop_id; /* Host adapter loop id */ + uint16_t fb_rev; + + port_id_t d_id; /* Host adapter port id */ + uint16_t max_public_loop_ids; + uint16_t min_external_loopid; /* First external loop Id */ + + uint8_t current_topology; + uint8_t prev_topology; +#define ISP_CFG_NL 1 +#define ISP_CFG_N 2 +#define ISP_CFG_FL 4 +#define ISP_CFG_F 8 + + uint8_t operating_mode; /* F/W operating mode */ +#define LOOP 0 +#define P2P 1 +#define LOOP_P2P 2 +#define P2P_LOOP 3 + + uint8_t active_fc4_types; /* Active fc4 types */ + + uint8_t current_speed; /* F/W operating speed */ + uint8_t marker_needed; + uint8_t sns_retry_cnt; + uint8_t mem_err; + + uint8_t interrupts_on; + + /* HBA serial number */ + uint8_t serial0; + uint8_t serial1; + uint8_t serial2; + + /* NVRAM configuration data */ + uint16_t nvram_base; + + uint16_t loop_reset_delay; + uint16_t minimum_timeout; + uint8_t retry_count; + uint8_t login_timeout; + uint16_t r_a_tov; + int port_down_retry_count; + uint8_t loop_down_timeout; + uint8_t mbx_count; + uint16_t max_probe_luns; + uint16_t max_luns; + uint16_t max_targets; + uint16_t last_loop_id; + + uint32_t login_retry_count; + + /* Fibre Channel Device List. */ + struct list_head fcports; + struct list_head rscn_fcports; + + struct io_descriptor io_descriptors[MAX_IO_DESCRIPTORS]; + uint16_t iodesc_signature; + port_database_t *iodesc_pd; + dma_addr_t iodesc_pd_dma; + + /* OS target queue pointers. */ + os_tgt_t *otgt[MAX_FIBRE_DEVICES]; + + /* RSCN queue. */ + uint32_t rscn_queue[MAX_RSCN_COUNT]; + uint8_t rscn_in_ptr; + uint8_t rscn_out_ptr; + + ms_iocb_entry_t *ms_iocb; + dma_addr_t ms_iocb_dma; + struct ct_sns_pkt *ct_sns; + dma_addr_t ct_sns_dma; + + pid_t dpc_pid; + int dpc_should_die; + struct completion dpc_inited; + struct completion dpc_exited; + struct semaphore *dpc_wait; + uint8_t dpc_active; /* DPC routine is active */ + + /* Timeout timers. */ + uint8_t queue_restart_timer; + uint8_t loop_down_abort_time; /* port down timer */ + atomic_t loop_down_timer; /* loop down timer */ + uint8_t link_down_timeout; /* link down timeout */ + + uint32_t timer_active; + struct timer_list timer; + + /* Firmware Initialization Control Block data */ + dma_addr_t init_cb_dma; /* Physical address. */ + init_cb_t *init_cb; + + /* These are used by mailbox operations. */ + volatile uint16_t mailbox_out[MAILBOX_REGISTER_COUNT]; + + mbx_cmd_t *mcp; + unsigned long mbx_cmd_flags; +#define MBX_CMD_ACTIVE 1 +#define MBX_CMD_WANT 2 +#define MBX_INTERRUPT 3 +#define MBX_INTR_WAIT 4 + + spinlock_t mbx_reg_lock; /* Mbx Cmd Register Lock */ + spinlock_t mbx_q_lock; /* Mbx Active Cmd Queue Lock */ + spinlock_t mbx_bits_lock; /* Mailbox access bits Lock */ + + struct semaphore mbx_intr_sem; /* Used for completion notification */ + + mbx_cmdq_t *mbx_sem_pool_head; /* Head Pointer to a list of + * recyclable mbx semaphore pool + * to be used during run time. + */ + mbx_cmdq_t *mbx_sem_pool_tail; /* Tail Pointer to semaphore pool*/ +#define MBQ_INIT_LEN 16 /* initial mbx sem pool q len. actual len may vary */ + + mbx_cmdq_t *mbx_q_head; /* Head Pointer to sem q for active cmds */ + mbx_cmdq_t *mbx_q_tail; /* Tail Pointer to sem q for active cmds */ + + uint32_t mbx_flags; +#define MBX_IN_PROGRESS BIT_0 +#define MBX_BUSY BIT_1 /* Got the Access */ +#define MBX_SLEEPING_ON_SEM BIT_2 +#define MBX_POLLING_FOR_COMP BIT_3 +#define MBX_COMPLETED BIT_4 +#define MBX_TIMEDOUT BIT_5 +#define MBX_ACCESS_TIMEDOUT BIT_6 + + mbx_cmd_t mc; + + uint8_t *cmdline; + + uint32_t failover_type; + uint32_t failback_delay; + unsigned long cfg_flags; +#define CFG_ACTIVE 0 /* CFG during a failover, event update, or ioctl */ + + uint32_t binding_type; +#define BIND_BY_PORT_NAME 0 +#define BIND_BY_PORT_ID 1 + + /* Basic firmware related information. */ + struct qla_board_info *brd_info; + uint16_t fw_major_version; + uint16_t fw_minor_version; + uint16_t fw_subminor_version; + uint16_t fw_attributes; + uint32_t fw_transfer_size; + + uint16_t fw_options[16]; /* slots: 1,2,3,10,11 */ + uint8_t fw_seriallink_options[2]; + + /* Firmware dump information. */ + void *fw_dump; + int fw_dump_order; + int fw_dump_reading; + char *fw_dump_buffer; + int fw_dump_buffer_len; + + uint8_t host_str[16]; + uint16_t pci_attr; + uint16_t xchg_buf_cnt; + uint16_t iocb_buf_cnt; + + uint8_t model_number[16+1]; +#define BINZERO "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + char *model_desc; + +/* following are new and needed for IOCTL support */ + hba_ioctl_context *ioctl; + uint8_t node_name[WWN_SIZE]; + + uint8_t optrom_major; + uint8_t optrom_minor; + + uint8_t nvram_version; + + void *ioctl_mem; + dma_addr_t ioctl_mem_phys; + uint32_t ioctl_mem_size; + uint32_t isp_abort_cnt; + + /* Adapter I/O statistics for failover */ + uint64_t IosRequested; + uint64_t BytesRequested; + uint64_t IosExecuted; + uint64_t BytesExecuted; + + /* Needed for BEACON */ + uint16_t beacon_blink_led; + uint16_t beacon_green_on; +} scsi_qla_host_t; + + +/* + * Macros to help code, maintain, etc. + */ +#define LOOP_TRANSITION(ha) \ + (test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) || \ + test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) + +#define LOOP_NOT_READY(ha) \ + ((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) || \ + test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) || \ + test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) || \ + test_bit(LOOP_RESYNC_ACTIVE, &ha->dpc_flags)) || \ + atomic_read(&ha->loop_state) == LOOP_DOWN) + +#define LOOP_RDY(ha) (!LOOP_NOT_READY(ha)) + +#define TGT_Q(ha, t) (ha->otgt[t]) +#define LUN_Q(ha, t, l) (TGT_Q(ha, t)->olun[l]) +#define GET_LU_Q(ha, t, l) ((TGT_Q(ha,t) != NULL)? TGT_Q(ha, t)->olun[l] : NULL) + +#define KMEM_ZALLOC(siz,id) qla2x00_kmem_zalloc((siz), GFP_ATOMIC, (id)) +#define KMEM_FREE(ip,siz) kfree((ip)) + +#define to_qla_host(x) ((scsi_qla_host_t *) (x)->hostdata) + +#define qla_printk(level, ha, format, arg...) \ + dev_printk(level , &((ha)->pdev->dev) , format , ## arg) + +/* + * qla2x00 local function return status codes + */ +#define MBS_MASK 0x3fff + +#define QLA_SUCCESS (MBS_COMMAND_COMPLETE & MBS_MASK) +#define QLA_INVALID_COMMAND (MBS_INVALID_COMMAND & MBS_MASK) +#define QLA_INTERFACE_ERROR (MBS_HOST_INTERFACE_ERROR & MBS_MASK) +#define QLA_TEST_FAILED (MBS_TEST_FAILED & MBS_MASK) +#define QLA_COMMAND_ERROR (MBS_COMMAND_ERROR & MBS_MASK) +#define QLA_PARAMETER_ERROR (MBS_COMMAND_PARAMETER_ERROR & MBS_MASK) +#define QLA_PORT_ID_USED (MBS_PORT_ID_USED & MBS_MASK) +#define QLA_LOOP_ID_USED (MBS_LOOP_ID_USED & MBS_MASK) +#define QLA_ALL_IDS_IN_USE (MBS_ALL_IDS_IN_USE & MBS_MASK) +#define QLA_NOT_LOGGED_IN (MBS_NOT_LOGGED_IN & MBS_MASK) + +#define QLA_FUNCTION_TIMEOUT 0x100 +#define QLA_FUNCTION_PARAMETER_ERROR 0x101 +#define QLA_FUNCTION_FAILED 0x102 +#define QLA_MEMORY_ALLOC_FAILED 0x103 +#define QLA_LOCK_TIMEOUT 0x104 +#define QLA_ABORTED 0x105 +#define QLA_SUSPENDED 0x106 +#define QLA_BUSY 0x107 +#define QLA_RSCNS_HANDLED 0x108 + +/* +* Stat info for all adpaters +*/ +struct _qla2x00stats { + unsigned long mboxtout; /* mailbox timeouts */ + unsigned long mboxerr; /* mailbox errors */ + unsigned long ispAbort; /* ISP aborts */ + unsigned long debugNo; + unsigned long loop_resync; + unsigned long outarray_full; + unsigned long retry_q_cnt; +}; + +#define SYS_DELAY(x) udelay(x);barrier() +#define QLA2100_DELAY(sec) mdelay(sec * HZ) +#define NVRAM_DELAY() udelay(10) +#define UDELAY(x) udelay(x) + +#define INVALID_HANDLE (MAX_OUTSTANDING_COMMANDS+1) + +/* + * Flash support definitions + */ +#define FLASH_IMAGE_SIZE 131072 + +#include "qla_foln.h" +#include "qla_gbl.h" +#include "qla_dbg.h" +#include "qla_inline.h" +#include "qla_listops.h" + +#endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qla_devtbl.h 830-ivtv/drivers/scsi/qla2xxx/qla_devtbl.h --- 000-virgin/drivers/scsi/qla2xxx/qla_devtbl.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qla_devtbl.h Thu Jan 8 10:22:00 2004 @@ -0,0 +1,65 @@ +#define QLA_MODEL_NAMES 0x1B + +/* + * Adapter model names. + */ +char *qla2x00_model_name[QLA_MODEL_NAMES] = { + "QLA2340", /* 0x100 */ + "QLA2342", /* 0x101 */ + "QLA2344", /* 0x102 */ + "QCP2342", /* 0x103 */ + "QSB2340", /* 0x104 */ + "QSB2342", /* 0x105 */ + "QLA2310", /* 0x106 */ + "QLA2332", /* 0x107 */ + "QCP2332", /* 0x108 */ + "QCP2340", /* 0x109 */ + "QLA2342", /* 0x10a */ + "QCP2342", /* 0x10b */ + "QLA2350", /* 0x10c */ + "QLA2352", /* 0x10d */ + "QLA2352", /* 0x10e */ + "HPQSVS ", /* 0x10f */ + "HPQSVS ", /* 0x110 */ + "QLA4010", /* 0x111 */ + "QLA4010", /* 0x112 */ + "QLA4010C", /* 0x113 */ + "QLA4010C", /* 0x114 */ + "QLA2360", /* 0x115 */ + "QLA2362", /* 0x116 */ + " ", /* 0x117 */ + " ", /* 0x118 */ + "QLA200", /* 0x119 */ + "QLA200C" /* 0x11A */ +}; + +char *qla2x00_model_desc[QLA_MODEL_NAMES] = { + "133MHz PCI-X to 2Gb FC, Single Channel", /* 0x100 */ + "133MHz PCI-X to 2Gb FC, Dual Channel", /* 0x101 */ + "133MHz PCI-X to 2Gb FC, Quad Channel", /* 0x102 */ + " ", /* 0x103 */ + " ", /* 0x104 */ + " ", /* 0x105 */ + " ", /* 0x106 */ + " ", /* 0x107 */ + " ", /* 0x108 */ + " ", /* 0x109 */ + " ", /* 0x10a */ + " ", /* 0x10b */ + "133MHz PCI-X to 2Gb FC, Single Channel", /* 0x10c */ + "133MHz PCI-X to 2Gb FC, Dual Channel", /* 0x10d */ + " ", /* 0x10e */ + "HPQ SVS HBA- Initiator device", /* 0x10f */ + "HPQ SVS HBA- Target device", /* 0x110 */ + "Optical- 133MHz to 1Gb iSCSI- networking", /* 0x111 */ + "Optical- 133MHz to 1Gb iSCSI- storage", /* 0x112 */ + "Copper- 133MHz to 1Gb iSCSI- networking", /* 0x113 */ + "Copper- 133MHz to 1Gb iSCSI- storage", /* 0x114 */ + "133MHz PCI-X to 2Gb FC Single Channel", /* 0x115 */ + "133MHz PCI-X to 2Gb FC Dual Channel", /* 0x116 */ + " ", /* 0x117 */ + " ", /* 0x118 */ + "133MHz PCI-X to 2Gb FC Optical", /* 0x119 */ + "133MHz PCI-X to 2Gb FC Copper" /* 0x11A */ +}; + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qla_fo.c 830-ivtv/drivers/scsi/qla2xxx/qla_fo.c --- 000-virgin/drivers/scsi/qla2xxx/qla_fo.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qla_fo.c Thu Jan 8 10:22:00 2004 @@ -0,0 +1,2624 @@ +/******************************************************************************** +* QLOGIC LINUX SOFTWARE +* +* QLogic ISP2x00 device driver for Linux 2.6.x +* Copyright (C) 2003 QLogic Corporation +* (www.qlogic.com) +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2, or (at your option) any +* later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +****************************************************************************** +* Failover include file +******************************************************************************/ + +#include "qla_os.h" +#include "qla_def.h" + +#include "qlfo.h" +#include "qlfolimits.h" + +//TODO Why?? +#include "qla_fo.cfg" + +/* This type is used to create a temporary list of port names */ +typedef struct _portname_list { + struct _portname_list *pnext; + uint8_t portname[8]; +} portname_list; + +/* + * Global variables + */ +SysFoParams_t qla_fo_params; + +/* + * Local routines + */ +#if !defined(linux) +static int qla2x00_sdm_setup(EXT_IOCTL *cmd_stp, void *arg, int mode); +#endif +static uint32_t qla2x00_fo_get_params(PFO_PARAMS pp); +static uint32_t qla2x00_fo_set_params(PFO_PARAMS pp); +static uint8_t qla2x00_fo_count_retries(scsi_qla_host_t *ha, srb_t *sp); +static int qla2x00_fo_get_lun_data(EXT_IOCTL *pext, + FO_LUN_DATA_INPUT *bp, int mode); +static int qla2x00_fo_set_lun_data(EXT_IOCTL *pext, + FO_LUN_DATA_INPUT *bp, int mode); +static uint32_t qla2x00_fo_stats(FO_HBA_STAT *stat_p, uint8_t reset); +static int qla2x00_fo_get_target_data(EXT_IOCTL *pext, + FO_TARGET_DATA_INPUT *bp, int mode); + +static int qla2x00_std_get_tgt(scsi_qla_host_t *, EXT_IOCTL *, + FO_DEVICE_DATA *); +static int qla2x00_fo_get_tgt(mp_host_t *, scsi_qla_host_t *, EXT_IOCTL *, + FO_DEVICE_DATA *); +static int qla2x00_fo_set_target_data(EXT_IOCTL *pext, + FO_TARGET_DATA_INPUT *bp, int mode); + +static int qla2x00_port_name_in_list(uint8_t *, portname_list *); +static int qla2x00_add_to_portname_list(uint8_t *, portname_list **); +static void qla2x00_free_portname_list(portname_list **); + +/* + * qla2x00_get_hba + * Searches the hba structure chain for the requested instance + * aquires the mutex and returns a pointer to the hba structure. + * + * Input: + * inst = adapter instance number. + * + * Returns: + * Return value is a pointer to the adapter structure or + * NULL if instance not found. + * + * Context: + * Kernel context. + */ +scsi_qla_host_t * +qla2x00_get_hba(unsigned long instance) +{ + int found; + struct list_head *hal; + scsi_qla_host_t *ha; + + ha = NULL; + found = 0; + read_lock(&qla_hostlist_lock); + list_for_each(hal, &qla_hostlist) { + ha = list_entry(hal, scsi_qla_host_t, list); + + if (ha->instance == instance) { + found++; + break; + } + } + read_unlock(&qla_hostlist_lock); + + return (found ? ha : NULL); +} + +/* + * qla2x00_fo_stats + * Searches the hba structure chan for the requested instance + * aquires the mutex and returns a pointer to the hba structure. + * + * Input: + * stat_p = Pointer to FO_HBA_STAT union. + * reset = Flag, TRUE = reset statistics. + * FALSE = return statistics values. + * + * Returns: + * 0 = success + * + * Context: + * Kernel context. + */ +static uint32_t +qla2x00_fo_stats(FO_HBA_STAT *stat_p, uint8_t reset) +{ + int32_t inst, idx; + uint32_t rval = 0; + struct list_head *hal; + scsi_qla_host_t *ha; + + DEBUG9(printk("%s: entered.\n", __func__);) + + inst = stat_p->input.HbaInstance; + stat_p->info.HbaCount = 0; + + ha = NULL; + + read_lock(&qla_hostlist_lock); + list_for_each(hal, &qla_hostlist) { + ha = list_entry(hal, scsi_qla_host_t, list); + + if (inst == FO_ADAPTER_ALL) { + stat_p->info.HbaCount++; + idx = ha->instance; + } else if (ha->instance == inst) { + stat_p->info.HbaCount = 1; + idx = inst; + } + if (reset == TRUE) { + DEBUG9(printk("%s: reset stats.\n", __func__);) + ha->IosRequested = 0; + ha->BytesRequested = 0; + ha->IosExecuted = 0; + ha->BytesExecuted = 0; + } else { + DEBUG9(printk("%s: get stats for inst %d.\n", + __func__, inst);) + +#if 0 + stat_p->info.StatEntry[idx].IosRequested = + ha->IosRequested; + stat_p->info.StatEntry[idx].BytesRequested = + ha->BytesRequested; + stat_p->info.StatEntry[idx].IosExecuted = + ha->IosExecuted; + stat_p->info.StatEntry[idx].BytesExecuted = + ha->BytesExecuted; +#endif + } + if (inst != FO_ADAPTER_ALL) + break; + } + read_unlock(&qla_hostlist_lock); + + DEBUG9(printk("%s: exiting.\n", __func__);) + + return rval; +} + +/* + * qla2x00_fo_get_lun_data + * Get lun data from all devices attached to a HBA (FO_GET_LUN_DATA). + * Gets lun mask if failover not enabled. + * + * Input: + * ha = pointer to adapter + * bp = pointer to buffer + * + * Return; + * 0 on success or errno. + * + * Context: + * Kernel context. + */ +static int +qla2x00_fo_get_lun_data(EXT_IOCTL *pext, FO_LUN_DATA_INPUT *bp, int mode) +{ + scsi_qla_host_t *ha; + struct list_head *fcports; + fc_port_t *fcport; + int ret = 0; + mp_host_t *host = NULL; + mp_device_t *dp; + mp_path_t *path; + mp_path_list_t *pathlist; + os_tgt_t *ostgt; + uint8_t path_id; + uint16_t dev_no; + uint16_t cnt; + uint16_t lun; + FO_EXTERNAL_LUN_DATA_ENTRY *u_entry, *entry; + FO_LUN_DATA_LIST *u_list, *list; + + + DEBUG9(printk("%s: entered.\n", __func__);) + + ha = qla2x00_get_hba((unsigned long)bp->HbaInstance); + + if (!ha) { + DEBUG2_9_10(printk("%s: no ha matching inst %d.\n", + __func__, bp->HbaInstance);) + + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + return (ret); + } + + DEBUG9(printk("%s: ha inst %ld, buff %p.\n", + __func__, ha->instance, bp);) + DEBUG4(printk("%s: hba %p, buff %p bp->HbaInstance(%x).\n", + __func__, ha, bp, (int)bp->HbaInstance)); + + if (qla2x00_failover_enabled(ha)) { + if ((host = qla2x00_cfg_find_host(ha)) == NULL) { + if (list_empty(&ha->fcports)) { + DEBUG2_9_10(printk( + "%s: no HOST for ha inst %ld.\n", + __func__, ha->instance);) + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + return (ret); + } + + /* Since all ports are unconfigured, return a dummy + * entry for each of them. + */ + list = (FO_LUN_DATA_LIST *)qla2x00_kmem_zalloc( + sizeof(FO_LUN_DATA_LIST), GFP_ATOMIC, 12); + if (list == NULL) { + DEBUG2_9_10(printk("%s: failed to alloc " + "memory of size (%d)\n", __func__, + (int)sizeof(FO_LUN_DATA_LIST));) + pext->Status = EXT_STATUS_NO_MEMORY; + return (-ENOMEM); + } + + entry = &list->DataEntry[0]; + + u_list = (FO_LUN_DATA_LIST *)pext->ResponseAdr; + u_entry = &u_list->DataEntry[0]; + + fcport = NULL; + list_for_each_entry(fcport, &ha->fcports, list) { + memcpy(entry->NodeName, fcport->node_name, + EXT_DEF_WWN_NAME_SIZE); + memcpy(entry->PortName, fcport->port_name, + EXT_DEF_WWN_NAME_SIZE); + + DEBUG9(printk("%s(%ld): entry %d for " + "unconfigured portname=%02x%02x" + "%02x%02x%02x%02x%02x%02x, " + "tgt_id=%d.\n", + __func__, ha->host_no, + list->EntryCount, + entry->PortName[0], + entry->PortName[1], + entry->PortName[2], + entry->PortName[3], + entry->PortName[4], + entry->PortName[5], + entry->PortName[6], + entry->PortName[7], + entry->TargetId);) + + list->EntryCount++; + + ret = verify_area(VERIFY_WRITE, + (void *)u_entry, + sizeof(FO_EXTERNAL_LUN_DATA_ENTRY)); + if (ret) { + /* error */ + DEBUG2_9_10(printk( + "%s: u_entry %p verify " + "wrt err. EntryCount=%d.\n", __func__, u_entry, + list->EntryCount);) + pext->Status = EXT_STATUS_COPY_ERR; + break; + } + + ret = copy_to_user(u_entry, entry, + sizeof(FO_EXTERNAL_LUN_DATA_ENTRY)); + if (ret) { /* error */ + DEBUG2_9_10(printk( + "%s: u_entry %p copy out " + "err. EntryCount=%d.\n", + __func__, u_entry, + list->EntryCount);) + pext->Status = EXT_STATUS_COPY_ERR; + break; + } + + u_entry++; + } + + if (ret == 0) { + ret = verify_area(VERIFY_WRITE, + (void *)&u_list->EntryCount, + sizeof(list->EntryCount)); + if (ret) { + /* error */ + DEBUG2_9_10(printk( + "%s: u_list->EntryCount %p verify " + " write error. " + "list->EntryCount=%d.\n", + __func__, u_entry, + list->EntryCount);) + pext->Status = EXT_STATUS_COPY_ERR; + } else { + /* copy number of entries */ + ret = copy_to_user(&u_list->EntryCount, + &list->EntryCount, + sizeof(list->EntryCount)); + } + } + + KMEM_FREE(list, sizeof(FO_LUN_DATA_LIST)); + + return (ret); + } + } + + list = (FO_LUN_DATA_LIST *)qla2x00_kmem_zalloc( + sizeof(FO_LUN_DATA_LIST), GFP_ATOMIC, 12); + if (list == NULL) { + DEBUG2_9_10(printk("%s: failed to alloc memory of size (%d)\n", + __func__, (int)sizeof(FO_LUN_DATA_LIST));) + pext->Status = EXT_STATUS_NO_MEMORY; + return (-ENOMEM); + } + + entry = &list->DataEntry[0]; + + u_list = (FO_LUN_DATA_LIST *)pext->ResponseAdr; + u_entry = &u_list->DataEntry[0]; + + /* find the correct fcport list */ + if (!qla2x00_failover_enabled(ha)) + fcports = &ha->fcports; + else + fcports = host->fcports; + + /* Check thru this adapter's fcport list */ + fcport = NULL; + list_for_each_entry(fcport, fcports, list) { + if ((atomic_read(&fcport->state) != FCS_ONLINE) && + !qla2x00_is_fcport_in_config(ha, fcport)) { + /* no need to report */ + DEBUG2_9_10(printk("%s(%ld): not reporting fcport " + "%02x%02x%02x%02x%02x%02x%02x%02x. state=%i," + " flags=%02x.\n", + __func__, ha->host_no, fcport->port_name[0], + fcport->port_name[1], fcport->port_name[2], + fcport->port_name[3], fcport->port_name[4], + fcport->port_name[5], fcport->port_name[6], + fcport->port_name[7], atomic_read(&fcport->state), + fcport->flags);) + continue; + } + + memcpy(entry->NodeName, + fcport->node_name, EXT_DEF_WWN_NAME_SIZE); + memcpy(entry->PortName, + fcport->port_name, EXT_DEF_WWN_NAME_SIZE); + + /* Return dummy entry for unconfigured ports */ + if (fcport->mp_byte & MP_MASK_UNCONFIGURED) { + for (lun = 0; lun < MAX_LUNS; lun++) { + entry->Data[lun] = 0; + } + entry->TargetId = 0; + + DEBUG9(printk("%s(%ld): entry %d for unconfigured " + "portname=%02x%02x%02x%02x%02x%02x%02x%02x, " + "tgt_id=%d.\n", + __func__, ha->host_no, + list->EntryCount, + entry->PortName[0], entry->PortName[1], + entry->PortName[2], entry->PortName[3], + entry->PortName[4], entry->PortName[5], + entry->PortName[6], entry->PortName[7], + entry->TargetId);) + + list->EntryCount++; + + ret = verify_area(VERIFY_WRITE, (void *)u_entry, + sizeof(FO_EXTERNAL_LUN_DATA_ENTRY)); + if (ret) { + /* error */ + DEBUG2_9_10(printk("%s: u_entry %p " + "verify wrt err. EntryCount=%d.\n", + __func__, u_entry, list->EntryCount);) + pext->Status = EXT_STATUS_COPY_ERR; + break; + } + + ret = copy_to_user(u_entry, entry, + sizeof(FO_EXTERNAL_LUN_DATA_ENTRY)); + if (ret) { + /* error */ + DEBUG2_9_10(printk("%s: u_entry %p " + "copy out err. EntryCount=%d.\n", + __func__, u_entry, list->EntryCount);) + pext->Status = EXT_STATUS_COPY_ERR; + break; + } + + u_entry++; + + continue; + } + + if (!qla2x00_failover_enabled(ha)) { + /* + * Failover disabled. Just return LUN mask info + * in lun data entry of this port. + */ + entry->TargetId = 0; + for (cnt = 0; cnt < MAX_FIBRE_DEVICES; cnt++) { + if (!(ostgt = ha->otgt[cnt])) { + continue; + } + + if (ostgt->fcport == fcport) { + entry->TargetId = cnt; + break; + } + } + if (cnt == MAX_FIBRE_DEVICES) { + /* Not found? For now just go to next port. */ +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_10) + uint8_t *tmp_name; + + tmp_name = fcport->port_name; + + printk("%s(%ld): ERROR - port " + "%02x%02x%02x%02x%02x%02x%02x%02x " + "not configured.\n", + __func__, ha->host_no, + tmp_name[0], tmp_name[1], tmp_name[2], + tmp_name[3], tmp_name[4], tmp_name[5], + tmp_name[6], tmp_name[7]); +#endif /* DEBUG */ + + continue; + } + + /* Got a valid port */ + list->EntryCount++; + + for (lun = 0; lun < MAX_LUNS; lun++) { + /* set MSB if masked */ + entry->Data[lun] = LUN_DATA_PREFERRED_PATH; + if (!EXT_IS_LUN_BIT_SET(&(fcport->lun_mask), + lun)) { + entry->Data[lun] |= LUN_DATA_ENABLED; + } + } + + DEBUG9(printk("%s: got lun_mask for tgt %d\n", + __func__, cnt);) + DEBUG9(qla2x00_dump_buffer((char *)&(fcport->lun_mask), + sizeof(lun_bit_mask_t));) + + ret = verify_area(VERIFY_WRITE, (void *)u_entry, + sizeof(FO_EXTERNAL_LUN_DATA_ENTRY)); + if (ret) { + /* error */ + DEBUG9_10(printk("%s: u_entry %p verify write" + " error. list->EntryCount=%d.\n", + __func__, u_entry, list->EntryCount);) + pext->Status = EXT_STATUS_COPY_ERR; + break; + } + + ret = copy_to_user(u_entry, entry, + sizeof(FO_EXTERNAL_LUN_DATA_ENTRY)); + + if (ret) { + /* error */ + DEBUG9_10(printk("%s: u_entry %p copy " + "error. list->EntryCount=%d.\n", + __func__, u_entry, list->EntryCount);) + pext->Status = EXT_STATUS_COPY_ERR; + break; + } + + copy_to_user(u_entry, entry, + sizeof(FO_EXTERNAL_LUN_DATA_ENTRY)); + + /* Go to next port */ + u_entry++; + continue; + } + + /* + * Failover is enabled. Go through the mp_devs list and return + * lun data in configured path. + */ + for (dev_no = 0; dev_no < MAX_MP_DEVICES; dev_no++) { + dp = host->mp_devs[dev_no]; + + if (dp == NULL) + continue; + + /* Lookup entry name */ + if (!qla2x00_is_portname_in_device(dp, entry->PortName)) + continue; + + if ((pathlist = dp->path_list) == NULL) + continue; + + path = pathlist->last; + for (path_id = 0; path_id < pathlist->path_cnt; + path_id++, path = path->next) { + + if (path->host != host) + continue; + + if (!qla2x00_is_portname_equal(path->portname, + entry->PortName)) + continue; + + /* Got an entry */ + entry->TargetId = dp->dev_id; + entry->Dev_No = path->id; + list->EntryCount++; + + DEBUG9_10(printk( + "%s(%ld): got lun_mask for tgt %d\n", + __func__, ha->host_no, entry->TargetId);) + DEBUG9(qla2x00_dump_buffer( + (char *)&(fcport->lun_mask), + sizeof(lun_bit_mask_t));) + + for (lun = 0; lun < MAX_LUNS; lun++) { + entry->Data[lun] = + path->lun_data.data[lun]; + } + + ret = verify_area(VERIFY_WRITE, (void *)u_entry, + sizeof(FO_EXTERNAL_LUN_DATA_ENTRY)); + if (ret) { + /* error */ + DEBUG2_9_10(printk("%s: u_entry %p " + "verify wrt err. EntryCount=%d.\n", + __func__, u_entry, list->EntryCount);) + pext->Status = EXT_STATUS_COPY_ERR; + break; + } + + ret = copy_to_user(u_entry, entry, + sizeof(FO_EXTERNAL_LUN_DATA_ENTRY)); + if (ret) { + /* error */ + DEBUG2_9_10(printk("%s: u_entry %p " + "copy out err. EntryCount=%d.\n", + __func__, u_entry, list->EntryCount);) + pext->Status = EXT_STATUS_COPY_ERR; + break; + } + + u_entry++; + + DEBUG9_10(printk("%s: get_lun_data for tgt " + "%d- u_entry(%p) - lun entry[%d] :\n", + __func__, entry->TargetId, + u_entry,list->EntryCount - 1);) + + DEBUG9(qla2x00_dump_buffer((void *)entry, 64);) + + /* + * We found the right path for this port. + * Continue with next port. + */ + break; + } + + /* Continue with next port. */ + break; + } + } + + DEBUG9(printk("%s: get_lun_data - entry count = [%d]\n", + __func__, list->EntryCount);) + DEBUG4(printk("%s: get_lun_data - entry count = [%d]\n", + __func__, list->EntryCount);) + + if (ret == 0) { + ret = verify_area(VERIFY_WRITE, (void *)&u_list->EntryCount, + sizeof(list->EntryCount)); + if (ret) { + /* error */ + DEBUG2_9_10(printk("%s: u_list->EntryCount %p verify " + " write error. list->EntryCount=%d.\n", + __func__, u_entry, list->EntryCount);) + pext->Status = EXT_STATUS_COPY_ERR; + } else { + /* copy number of entries */ + ret = copy_to_user(&u_list->EntryCount, &list->EntryCount, + sizeof(list->EntryCount)); + pext->ResponseLen = FO_LUN_DATA_LIST_MAX_SIZE; + } + } + + KMEM_FREE(list, sizeof(FO_LUN_DATA_LIST)); + + DEBUG9(printk("%s: exiting. ret=%d.\n", __func__, ret);) + + return ret; +} + +/* + * qla2x00_fo_set_lun_data + * Set lun data for the specified device on the attached hba + * (FO_SET_LUN_DATA). + * Sets lun mask if failover not enabled. + * + * Input: + * bp = pointer to buffer + * + * Return; + * 0 on success or errno. + * + * Context: + * Kernel context. + */ +static int +qla2x00_fo_set_lun_data(EXT_IOCTL *pext, FO_LUN_DATA_INPUT *bp, int mode) +{ + scsi_qla_host_t *ha; + fc_port_t *fcport; + int i; + int ret = 0; + mp_host_t *host = NULL; + mp_device_t *dp; + mp_path_t *path; + mp_path_list_t *pathlist; + os_tgt_t *ostgt; + uint8_t path_id; + uint16_t dev_no; + uint16_t lun; + FO_LUN_DATA_LIST *u_list, *list; + FO_EXTERNAL_LUN_DATA_ENTRY *u_entry, *entry; + + typedef struct _tagStruct { + FO_LUN_DATA_INPUT foLunDataInput; + FO_LUN_DATA_LIST foLunDataList; + } + com_struc; + com_struc *com_iter; + + + DEBUG9(printk("%s: entered.\n", __func__);) + + ha = qla2x00_get_hba((unsigned long)bp->HbaInstance); + + if (!ha) { + DEBUG2_9_10(printk("%s: no ha matching inst %d.\n", + __func__, bp->HbaInstance);) + + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + return (ret); + } + + DEBUG9(printk("%s: ha inst %ld, buff %p.\n", + __func__, ha->instance, bp);) + + if (qla2x00_failover_enabled(ha)) { + if ((host = qla2x00_cfg_find_host(ha)) == NULL) { + DEBUG2_9_10(printk("%s: no HOST for ha inst %ld.\n", + __func__, ha->instance);) + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + return (ret); + } + } + + list = (FO_LUN_DATA_LIST *)qla2x00_kmem_zalloc( + sizeof(FO_LUN_DATA_LIST), GFP_ATOMIC, 13); + if (list == NULL) { + DEBUG2_9_10(printk("%s: failed to alloc memory of size (%d)\n", + __func__, (int)sizeof(FO_LUN_DATA_LIST));) + pext->Status = EXT_STATUS_NO_MEMORY; + return (-ENOMEM); + } + + entry = &list->DataEntry[0]; + + /* get lun data list from user */ + com_iter = (com_struc *)pext->RequestAdr; + u_list = &(com_iter->foLunDataList); + u_entry = &u_list->DataEntry[0]; + + ret = verify_area(VERIFY_READ, (void *)u_list, + sizeof(FO_LUN_DATA_LIST)); + if (ret) { + /* error */ + DEBUG2_9_10(printk("%s: u_list %p verify read error.\n", + __func__, u_list);) + pext->Status = EXT_STATUS_COPY_ERR; + KMEM_FREE(list, FO_LUN_DATA_LIST); + return (ret); + } + + ret = copy_from_user(list, u_list, sizeof(FO_LUN_DATA_LIST)); + if (ret) { + /* error */ + DEBUG2_9_10(printk("%s: u_list %p copy error.\n", + __func__, u_list);) + pext->Status = EXT_STATUS_COPY_ERR; + KMEM_FREE(list, FO_LUN_DATA_LIST); + return (ret); + } + + DEBUG2(printk("qla_fo_set_lun_data: pext->RequestAdr(%p) u_list (%p) " + "sizeof(FO_LUN_DATA_INPUT) =(%d) and 64 bytes...\n", + pext->RequestAdr, u_list, + (int)sizeof(FO_LUN_DATA_INPUT));) + DEBUG2(qla2x00_dump_buffer((void *)u_list, 64);) + + for (i = 0; i < list->EntryCount; i++, u_entry++) { + + ret = verify_area(VERIFY_READ, (void *)u_entry, + sizeof(FO_EXTERNAL_LUN_DATA_ENTRY)); + if (ret) { + /* error */ + DEBUG2_9_10(printk("%s: u_entry %p verify " + " read error.\n", + __func__, u_entry);) + pext->Status = EXT_STATUS_COPY_ERR; + break; + } + ret = copy_from_user(entry, u_entry, + sizeof(FO_EXTERNAL_LUN_DATA_ENTRY)); + if (ret) { + /* error */ + DEBUG2_9_10(printk("%s: u_entry %p copy error.\n", + __func__, u_entry);) + pext->Status = EXT_STATUS_COPY_ERR; + break; + } + + if (!qla2x00_failover_enabled(ha)) { + /* + * Failover disabled. Just find the port and set + * LUN mask values in lun_mask field of this port. + */ + + if (entry->TargetId >= MAX_FIBRE_DEVICES) + /* ERROR */ + continue; + + if (!(ostgt = ha->otgt[entry->TargetId])) + /* ERROR */ + continue; + + if (!(fcport = ostgt->fcport)) + /* ERROR */ + continue; + + for (lun = 0; lun < MAX_LUNS; lun++) { + /* set MSB if masked */ + if (entry->Data[lun] | LUN_DATA_ENABLED) { + EXT_CLR_LUN_BIT(&(fcport->lun_mask), + lun); + } else { + EXT_SET_LUN_BIT(&(fcport->lun_mask), + lun); + } + } + + /* Go to next entry */ + continue; + } + + /* + * Failover is enabled. Go through the mp_devs list and set lun + * data in configured path. + */ + for (dev_no = 0; dev_no < MAX_MP_DEVICES; dev_no++) { + dp = host->mp_devs[dev_no]; + + if (dp == NULL) + continue; + + /* Lookup entry name */ + if (!qla2x00_is_portname_in_device(dp, entry->PortName)) + continue; + + if ((pathlist = dp->path_list) == NULL) + continue; + + path = pathlist->last; + for (path_id = 0; path_id < pathlist->path_cnt; + path_id++, path = path->next) { + + if (path->host != host) + continue; + + if (!qla2x00_is_portname_equal(path->portname, + entry->PortName)) + continue; + + for (lun = 0; lun < MAX_LUNS; lun++) { + path->lun_data.data[lun] = + entry->Data[lun]; + DEBUG4(printk("cfg_set_lun_data: lun " + "data[%d] = 0x%x \n", lun, + path->lun_data.data[lun]);) + } + + break; + } + break; + } + } + + KMEM_FREE(list, FO_LUN_DATA_LIST); + + DEBUG9(printk("%s: exiting. ret = %d.\n", __func__, ret);) + + return ret; +} + +/* + * qla2x00_fo_get_target_data + * Get the target control byte for all devices attached to a HBA. + * + * Input: + * bp = pointer to buffer + * + * Return; + * 0 on success or errno. + * + * Context: + * Kernel context. + */ +static int +qla2x00_fo_get_target_data(EXT_IOCTL *pext, FO_TARGET_DATA_INPUT *bp, int mode) +{ + scsi_qla_host_t *ha; + int ret = 0; + mp_host_t *host = NULL; + FO_DEVICE_DATA *entry; + + + DEBUG9(printk("%s: entered.\n", __func__);) + + ha = qla2x00_get_hba((unsigned long)bp->HbaInstance); + + if (!ha) { + DEBUG2_9_10(printk("%s: no ha matching inst %d.\n", + __func__, bp->HbaInstance);) + + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + return (ret); + } + + DEBUG9(printk("%s: ha inst %ld, buff %p.\n", + __func__, ha->instance, bp);) + + if (qla2x00_failover_enabled(ha)) { + if ((host = qla2x00_cfg_find_host(ha)) == NULL && + list_empty(&ha->fcports)) { + DEBUG2_9_10(printk("%s: no HOST for ha inst %ld.\n", + __func__, ha->instance);) + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + return (ret); + } + } + + if ((entry = (FO_DEVICE_DATA *)kmalloc(sizeof(FO_DEVICE_DATA), + GFP_ATOMIC)) == NULL) { + DEBUG2_9_10(printk("%s: failed to alloc memory of size (%d)\n", + __func__, (int)sizeof(FO_DEVICE_DATA));) + pext->Status = EXT_STATUS_NO_MEMORY; + return (-ENOMEM); + } + + /* Return data accordingly. */ + if (!qla2x00_failover_enabled(ha)) + ret = qla2x00_std_get_tgt(ha, pext, entry); + else + ret = qla2x00_fo_get_tgt(host, ha, pext, entry); + + + if (ret == 0) { + pext->ResponseLen = sizeof(FO_DEVICE_DATABASE); + } + + KMEM_FREE(entry, sizeof(FO_DEVICE_DATA)); + + DEBUG9(printk("%s: exiting. ret = %d.\n", __func__, ret);) + + return (ret); +} + +static int +qla2x00_std_get_tgt(scsi_qla_host_t *ha, EXT_IOCTL *pext, FO_DEVICE_DATA *entry) +{ + int ret = 0; + uint8_t i, cnt; + uint32_t b; + fc_port_t *fcport; + os_tgt_t *ostgt; + FO_DEVICE_DATA *u_entry; + + DEBUG9(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + + u_entry = (FO_DEVICE_DATA *) pext->ResponseAdr; + + if (pext->ResponseLen < sizeof(FO_DEVICE_DATA)) { + pext->Status = EXT_STATUS_BUFFER_TOO_SMALL; + DEBUG9_10(printk("%s: ERROR ResponseLen %d too small.\n", + __func__, pext->ResponseLen);) + + return (ret); + } + + DEBUG9(printk("%s(%ld): user buffer size=%d. Copying fcport list\n", + __func__, ha->host_no, pext->ResponseLen);) + + /* Loop through and return ports found. */ + /* Check thru this adapter's fcport list */ + i = 0; + fcport = NULL; + list_for_each_entry(fcport, &ha->fcports, list) { + if (i >= MAX_TARGETS) + break; + + /* clear for a new entry */ + memset(entry, 0, sizeof(FO_DEVICE_DATA)); + + memcpy(entry->WorldWideName, + fcport->node_name, EXT_DEF_WWN_NAME_SIZE); + memcpy(entry->PortName, + fcport->port_name, EXT_DEF_WWN_NAME_SIZE); + + for (b = 0; b < 3 ; b++) + entry->PortId[b] = fcport->d_id.r.d_id[2-b]; + + DEBUG9(printk("%s(%ld): found fcport %p:%02x%02x%02x%02x" + "%02x%02x%02x%02x.\n", + __func__, ha->host_no, + fcport, + fcport->port_name[0], + fcport->port_name[1], + fcport->port_name[2], + fcport->port_name[3], + fcport->port_name[4], + fcport->port_name[5], + fcport->port_name[6], + fcport->port_name[7]);) + + /* + * Just find the port and return target info. + */ + for (cnt = 0; cnt < MAX_FIBRE_DEVICES; cnt++) { + if (!(ostgt = ha->otgt[cnt])) { + continue; + } + + if (ostgt->fcport == fcport) { + DEBUG9(printk("%s(%ld): Found target %d.\n", + __func__, ha->host_no, cnt);) + + entry->TargetId = cnt; + break; + } + } + + if (cnt == MAX_FIBRE_DEVICES) { + /* Not bound, this target is unconfigured. */ + entry->MultipathControl = MP_MASK_UNCONFIGURED; + } else { + entry->MultipathControl = 0; /* always configured */ + } + + ret = verify_area(VERIFY_WRITE, (void *)u_entry, + sizeof(FO_DEVICE_DATA)); + if (ret) { + /* error */ + DEBUG2_9_10(printk("%s(%ld): u_entry %p verify " + " wrt err. tgt id=%d.\n", + __func__, ha->host_no, u_entry, cnt);) + pext->Status = EXT_STATUS_COPY_ERR; + break; + } + + ret = copy_to_user(u_entry, entry, + sizeof(FO_DEVICE_DATA)); + if (ret) { + /* error */ + DEBUG2_9_10(printk("%s(%ld): u_entry %p copy " + "out err. tgt id=%d.\n", + __func__, ha->host_no, u_entry, cnt);) + pext->Status = EXT_STATUS_COPY_ERR; + break; + } + + u_entry++; + } + + DEBUG9(printk("%s(%ld): done copying fcport list entries.\n", + __func__, ha->host_no);) + + DEBUG9(printk("%s(%ld): exiting. ret = %d.\n", + __func__, ha->host_no, ret);) + + return (ret); +} + +static int +qla2x00_fo_get_tgt(mp_host_t *host, scsi_qla_host_t *ha, EXT_IOCTL *pext, + FO_DEVICE_DATA *entry) +{ + int ret = 0; + uint8_t path_id; + uint16_t dev_no; + uint32_t b; + uint16_t cnt; + + fc_port_t *fcport; + mp_device_t *dp; + mp_path_list_t *pathlist; + mp_path_t *path; + + FO_DEVICE_DATA *u_entry; + + DEBUG9(printk("%s(%ld): entered.\n", __func__, host->ha->host_no);) + + u_entry = (FO_DEVICE_DATA *) pext->ResponseAdr; + + /* If host is NULL then report all online fcports of the corresponding + * ha as unconfigured devices. ha should never be NULL. + */ + if (host == NULL) { + /* Loop through and return ports found. */ + /* Check thru this adapter's fcport list */ + cnt = 0; + fcport = NULL; + list_for_each_entry(fcport, &ha->fcports, list) { + + if (atomic_read(&fcport->state) != FCS_ONLINE) { + /* no need to report */ + DEBUG2_9_10(printk("%s(%ld): not reporting " + "fcport %02x%02x%02x%02x%02x%02x%02x%02x. " + "state=%i, flags=%02x.\n", + __func__, ha->host_no, + fcport->port_name[0], fcport->port_name[1], + fcport->port_name[2], fcport->port_name[3], + fcport->port_name[4], fcport->port_name[5], + fcport->port_name[6], fcport->port_name[7], + atomic_read(&fcport->state), + fcport->flags);) + continue; + } + + cnt++; + if (cnt >= MAX_TARGETS) + break; + + /* clear for a new entry */ + memset(entry, 0, sizeof(FO_DEVICE_DATA)); + + memcpy(entry->WorldWideName, + fcport->node_name, EXT_DEF_WWN_NAME_SIZE); + memcpy(entry->PortName, + fcport->port_name, EXT_DEF_WWN_NAME_SIZE); + + DEBUG10(printk("%s(%ld): found fcport %p:%02x%02x%02x" + "%02x%02x%02x%02x%02x.\n", + __func__, host->ha->host_no, + fcport, + fcport->port_name[0], + fcport->port_name[1], + fcport->port_name[2], + fcport->port_name[3], + fcport->port_name[4], + fcport->port_name[5], + fcport->port_name[6], + fcport->port_name[7]);) + + for (b = 0; b < 3 ; b++) + entry->PortId[b] = fcport->d_id.r.d_id[2-b]; + + DEBUG9_10(printk("%s(%ld): fcport mpbyte=%02x. " + "return unconfigured. ", + __func__, host->ha->host_no, fcport->mp_byte);) + + entry->TargetId = 0; + entry->Dev_No = 0; + entry->MultipathControl = MP_MASK_UNCONFIGURED; + + DEBUG9_10(printk("tgtid=%d dev_no=%d, mpdata=0x%x.\n", + entry->TargetId, entry->Dev_No, + entry->MultipathControl);) + + ret = verify_area(VERIFY_WRITE, (void *)u_entry, + sizeof(FO_DEVICE_DATA)); + if (ret) { + /* error */ + DEBUG2_9_10(printk("%s(%ld): u_entry %p " + "verify wrt err. no tgt id.\n", + __func__, host->ha->host_no, u_entry);) + pext->Status = EXT_STATUS_COPY_ERR; + break; + } + + ret = copy_to_user(u_entry, entry, + sizeof(FO_DEVICE_DATA)); + if (ret) { + /* error */ + DEBUG2_9_10(printk("%s(%ld): u_entry %p " + "copy out err. no tgt id.\n", + __func__, host->ha->host_no, u_entry);) + pext->Status = EXT_STATUS_COPY_ERR; + break; + } + + u_entry++; + } + + DEBUG9(printk("%s(%ld): after returning unconfigured fcport " + "list. got %d entries.\n", + __func__, host->ha->host_no, cnt);) + + return (ret); + } + + /* Check thru fcport list on host */ + /* Loop through and return online ports found. */ + /* Check thru this adapter's fcport list */ + cnt = 0; + fcport = NULL; + list_for_each_entry(fcport, host->fcports, list) { + + if ((atomic_read(&fcport->state) != FCS_ONLINE) && + !qla2x00_is_fcport_in_config(ha, fcport)) { + /* no need to report */ + DEBUG2_9_10(printk("%s(%ld): not reporting " + "fcport %02x%02x%02x%02x%02x%02x%02x%02x. " + "state=%i, flags=%02x.\n", + __func__, ha->host_no, fcport->port_name[0], + fcport->port_name[1], fcport->port_name[2], + fcport->port_name[3], fcport->port_name[4], + fcport->port_name[5], fcport->port_name[6], + fcport->port_name[7], + atomic_read(&fcport->state), + fcport->flags);) + continue; + } + + cnt++; + if (cnt >= MAX_TARGETS) + break; + + /* clear for a new entry */ + memset(entry, 0, sizeof(FO_DEVICE_DATA)); + + memcpy(entry->WorldWideName, + fcport->node_name, EXT_DEF_WWN_NAME_SIZE); + memcpy(entry->PortName, + fcport->port_name, EXT_DEF_WWN_NAME_SIZE); + + DEBUG10(printk("%s(%ld): found fcport %p:%02x%02x%02x%02x" + "%02x%02x%02x%02x.\n", + __func__, host->ha->host_no, + fcport, + fcport->port_name[0], + fcport->port_name[1], + fcport->port_name[2], + fcport->port_name[3], + fcport->port_name[4], + fcport->port_name[5], + fcport->port_name[6], + fcport->port_name[7]);) + + for (b = 0; b < 3 ; b++) + entry->PortId[b] = fcport->d_id.r.d_id[2-b]; + + if (fcport->mp_byte & MP_MASK_UNCONFIGURED) { + DEBUG9_10(printk("%s(%ld): fcport mpbyte=%02x. " + "return unconfigured. ", + __func__, host->ha->host_no, fcport->mp_byte);) + + entry->TargetId = fcport->os_target_id; + entry->Dev_No = 0; + entry->MultipathControl = MP_MASK_UNCONFIGURED; + + DEBUG9_10(printk("tgtid=%d dev_no=%d, mpdata=0x%x.\n", + entry->TargetId, entry->Dev_No, + entry->MultipathControl);) + + ret = verify_area(VERIFY_WRITE, (void *)u_entry, + sizeof(FO_DEVICE_DATA)); + if (ret) { + /* error */ + DEBUG2_9_10(printk("%s(%ld): u_entry %p " + "verify wrt err. tgt id=%d.\n", + __func__, host->ha->host_no, u_entry, + fcport->os_target_id);) + pext->Status = EXT_STATUS_COPY_ERR; + break; + } + + ret = copy_to_user(u_entry, entry, + sizeof(FO_DEVICE_DATA)); + if (ret) { + /* error */ + DEBUG2_9_10(printk("%s(%ld): u_entry %p " + "copy out err. tgt id=%d.\n", + __func__, host->ha->host_no, u_entry, + fcport->os_target_id);) + pext->Status = EXT_STATUS_COPY_ERR; + break; + } + + u_entry++; + continue; + } + + /* + * Port was configured. Go through the mp_devs list and + * get target data in configured path. + */ + for (dev_no = 0; dev_no < MAX_MP_DEVICES; dev_no++) { + dp = host->mp_devs[dev_no]; + + if (dp == NULL) + continue; + + /* Lookup entry name */ + if (!qla2x00_is_portname_in_device(dp, entry->PortName)) + continue; + + if ((pathlist = dp->path_list) == NULL) + continue; + + path = pathlist->last; + for (path_id = 0; path_id < pathlist->path_cnt; + path_id++, path= path->next) { + + if (path->host != host) + continue; + + if (!qla2x00_is_portname_equal(path->portname, + entry->PortName)) + continue; + + entry->TargetId = dp->dev_id; + entry->Dev_No = path->id; + entry->MultipathControl = path->mp_byte; + + if (path->config == TRUE || + !mp_config_required) { + entry->MultipathControl = path->mp_byte; + } else { + entry->MultipathControl = + MP_MASK_UNCONFIGURED; + } + + DEBUG9_10(printk("%s(%ld): fcport path->id " + "= %d, target/mpbyte data = 0x%02x.\n", + __func__, host->ha->host_no, + path->id, entry->MultipathControl);) + + ret = verify_area(VERIFY_WRITE, (void *)u_entry, + sizeof(FO_DEVICE_DATA)); + if (ret) { + /* error */ + DEBUG2_9_10(printk("%s(%ld): u_entry %p" + " verify wrt err. tgt id=%d.\n", + __func__, host->ha->host_no, + u_entry, dp->dev_id);) + pext->Status = EXT_STATUS_COPY_ERR; + break; + } + + ret = copy_to_user(u_entry, entry, + sizeof(FO_DEVICE_DATA)); + if (ret) { + /* error */ + DEBUG2_9_10(printk("%s(%ld): u_entry %p " + "copy out err. tgt id=%d.\n", + __func__, host->ha->host_no, + u_entry, dp->dev_id);) + pext->Status = EXT_STATUS_COPY_ERR; + break; + } + + u_entry++; + + /* Path found. Continue with next fcport */ + break; + } + break; + } + } + + DEBUG9(printk("%s(%ld): after checking fcport list. got %d entries.\n", + __func__, host->ha->host_no, cnt);) + + /* For ports not found but were in config file, return unconfigured + * status so agent will try to issue commands to it and GUI will display + * them as missing. + */ + for (dev_no = 0; dev_no < MAX_MP_DEVICES; dev_no++) { + dp = host->mp_devs[dev_no]; + + if (dp == NULL) + continue; + + /* Sanity check */ + if (qla2x00_is_wwn_zero(dp->nodename)) + continue; + + if ((pathlist = dp->path_list) == NULL) + continue; + + path = pathlist->last; + for (path_id = 0; path_id < pathlist->path_cnt; + path_id++, path = path->next) { + + /* Sanity check */ + if (qla2x00_is_wwn_zero(path->portname)) + continue; + + if (path->port == NULL) { + if (path->host != host) { + /* path on other host. no need to + * report + */ + DEBUG10(printk("%s(%ld): path host %p " + "not for current host %p.\n", + __func__, host->ha->host_no, + path->host, host);) + + continue; + } + + /* clear for a new entry */ + memset(entry, 0, sizeof(FO_DEVICE_DATA)); + + /* This device was not found. Return + * unconfigured. + */ + memcpy(entry->WorldWideName, + dp->nodename, EXT_DEF_WWN_NAME_SIZE); + memcpy(entry->PortName, + path->portname, EXT_DEF_WWN_NAME_SIZE); + + entry->TargetId = dp->dev_id; + entry->Dev_No = path->id; + /* + entry->MultipathControl = path->mp_byte + | MP_MASK_UNCONFIGURED; + */ + entry->MultipathControl = MP_MASK_UNCONFIGURED; + cnt++; + + DEBUG9_10(printk("%s: found missing device. " + "return tgtid=%d dev_no=%d, mpdata=0x%x for" + " port %02x%02x%02x%02x%02x%02x%02x%02x\n", + __func__, entry->TargetId, entry->Dev_No, + entry->MultipathControl, + path->portname[0], path->portname[1], + path->portname[2], path->portname[3], + path->portname[4], path->portname[5], + path->portname[6], path->portname[7]);) + + ret = verify_area(VERIFY_WRITE, (void *)u_entry, + sizeof(FO_DEVICE_DATA)); + if (ret) { + /* error */ + DEBUG2_9_10(printk("%s: u_entry %p " + "verify wrt err. tgt id=%d.\n", + __func__, u_entry, dp->dev_id);) + pext->Status = EXT_STATUS_COPY_ERR; + break; + } + + ret = copy_to_user(u_entry, entry, + sizeof(FO_DEVICE_DATA)); + if (ret) { + /* error */ + DEBUG2_9_10(printk("%s: u_entry %p " + "copy out err. tgt id=%d.\n", + __func__, u_entry, dp->dev_id);) + pext->Status = EXT_STATUS_COPY_ERR; + break; + } + + u_entry++; + } + } + } + + DEBUG9(printk("%s(%ld): after checking missing devs. got %d entries.\n", + __func__, host->ha->host_no, cnt);) + + DEBUG9(printk("%s(%ld): exiting. ret = %d.\n", + __func__, host->ha->host_no, ret);) + + return (ret); + +} /* qla2x00_get_fo_tgt */ + +/* + * qla2x00_fo_set_target_data + * Set multipath control byte for all devices on the attached hba + * + * Input: + * bp = pointer to buffer + * + * Return; + * 0 on success or errno. + * + * Context: + * Kernel context. + */ +static int +qla2x00_fo_set_target_data(EXT_IOCTL *pext, FO_TARGET_DATA_INPUT *bp, int mode) +{ + scsi_qla_host_t *ha; + int i; + int ret = 0; + mp_host_t *host; + mp_device_t *dp; + mp_path_t *path; + mp_path_list_t *pathlist; + uint16_t dev_no; + uint8_t path_id; + FO_DEVICE_DATA *entry, *u_entry; + + DEBUG9(printk("%s: entered.\n", __func__);) + + ha = qla2x00_get_hba((unsigned long)bp->HbaInstance); + + if (!ha) { + DEBUG2_9_10(printk("%s: no ha matching inst %d.\n", + __func__, bp->HbaInstance);) + + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + return (ret); + } + + DEBUG9(printk("%s: ha inst %ld, buff %p.\n", + __func__, ha->instance, bp);) + + if (!qla2x00_failover_enabled(ha)) + /* non-failover mode. nothing to be done. */ + return 0; + + if ((host = qla2x00_cfg_find_host(ha)) == NULL) { + DEBUG2_9_10(printk("%s: no HOST for ha inst %ld.\n", + __func__, ha->instance);) + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + return (ret); + } + + entry = (FO_DEVICE_DATA *)qla2x00_kmem_zalloc( + sizeof(FO_DEVICE_DATA), GFP_ATOMIC, 15); + if (entry == NULL) { + DEBUG2_9_10(printk("%s: failed to alloc memory of size (%d)\n", + __func__, (int)sizeof(FO_DEVICE_DATA));) + pext->Status = EXT_STATUS_NO_MEMORY; + return (-ENOMEM); + } + + u_entry = (FO_DEVICE_DATA *)(pext->RequestAdr + + sizeof(FO_TARGET_DATA_INPUT)); + + for (i = 0; i < MAX_TARGETS; i++, u_entry++) { + ret = verify_area(VERIFY_READ, (void *)u_entry, + sizeof(FO_DEVICE_DATA)); + if (ret) { + /* error */ + DEBUG2_9_10(printk("%s: u_entry %p verify read err.\n", + __func__, u_entry);) + pext->Status = EXT_STATUS_COPY_ERR; + break; + } + + ret = copy_from_user(entry, u_entry, sizeof(FO_DEVICE_DATA)); + + if (ret) { + /* error */ + DEBUG2_9_10(printk("%s: u_entry %p copy error.\n", + __func__, u_entry);) + pext->Status = EXT_STATUS_COPY_ERR; + break; + } + + for (dev_no = 0; dev_no < MAX_MP_DEVICES; dev_no++) { + dp = host->mp_devs[dev_no]; + + if (dp == NULL) + continue; + + /* Lookup entry name */ + if (!qla2x00_is_portname_in_device(dp, entry->PortName)) + continue; + + if ((pathlist = dp->path_list) == NULL) + continue; + + path = pathlist->last; + for (path_id = 0; path_id < pathlist->path_cnt; + path_id++, path= path->next) { + + if (path->host != host) + continue; + + if (!qla2x00_is_portname_equal(path->portname, + entry->PortName)) + continue; + + path->mp_byte = entry->MultipathControl; + + DEBUG9(printk("cfg_set_target_data: %d target " + "data = 0x%x \n", + path->id,path->mp_byte);) + + /* + * If this is the visible path, then make it + * available on next reboot. + */ + if (!((path->mp_byte & MP_MASK_HIDDEN) || + (path->mp_byte & MP_MASK_UNCONFIGURED))) { + pathlist->visible = path->id; + } + + /* Found path. Go to next entry. */ + break; + } + break; + } + } + + KMEM_FREE(entry, sizeof(FO_DEVICE_DATA)); + + DEBUG9(printk("%s: exiting. ret = %d.\n", __func__, ret);) + + return (ret); + +} + +/* + * qla2x00_fo_ioctl + * Provides functions for failover ioctl() calls. + * + * Input: + * ha = adapter state pointer. + * ioctl_code = ioctl function to perform + * arg = Address of application EXT_IOCTL cmd data + * mode = flags + * + * Returns: + * Return value is the ioctl rval_p return value. + * 0 = success + * + * Context: + * Kernel context. + */ +/* ARGSUSED */ +int +qla2x00_fo_ioctl(scsi_qla_host_t *ha, int ioctl_code, EXT_IOCTL *pext, int mode) +{ + int rval = 0; + size_t in_size, out_size; + static union { + FO_PARAMS params; + FO_GET_PATHS path; + FO_SET_CURRENT_PATH set_path; + /* FO_HBA_STAT_INPUT stat; */ + FO_HBA_STAT stat; + FO_LUN_DATA_INPUT lun_data; + FO_TARGET_DATA_INPUT target_data; + } buff; + + ENTER("qla2x00_fo_ioctl"); + DEBUG9(printk("%s: entered. arg (%p):\n", __func__, pext);) + + /* + * default case for this switch not needed, + * ioctl_code validated by caller. + */ + in_size = out_size = 0; + switch (ioctl_code) { + case FO_CC_GET_PARAMS: + out_size = sizeof(FO_PARAMS); + break; + case FO_CC_SET_PARAMS: + in_size = sizeof(FO_PARAMS); + break; + case FO_CC_GET_PATHS: + in_size = sizeof(FO_GET_PATHS); + break; + case FO_CC_SET_CURRENT_PATH: + in_size = sizeof(FO_SET_CURRENT_PATH); + break; + case FO_CC_GET_HBA_STAT: + case FO_CC_RESET_HBA_STAT: + in_size = sizeof(FO_HBA_STAT_INPUT); + break; + case FO_CC_GET_LUN_DATA: + in_size = sizeof(FO_LUN_DATA_INPUT); + break; + case FO_CC_SET_LUN_DATA: + in_size = sizeof(FO_LUN_DATA_INPUT); + break; + case FO_CC_GET_TARGET_DATA: + in_size = sizeof(FO_TARGET_DATA_INPUT); + break; + case FO_CC_SET_TARGET_DATA: + in_size = sizeof(FO_TARGET_DATA_INPUT); + break; + + } + if (in_size != 0) { + if ((int)pext->RequestLen < in_size) { + pext->Status = EXT_STATUS_INVALID_PARAM; + pext->DetailStatus = EXT_DSTATUS_REQUEST_LEN; + DEBUG10(printk("%s: got invalie req len (%d).\n", + __func__, pext->RequestLen);) + + } else { + + rval = verify_area(VERIFY_READ, + (void *)pext->RequestAdr, in_size); + if (rval) { + /* error */ + DEBUG2_9_10(printk("%s: req buf verify read " + "error. size=%ld.\n", + __func__, (ulong)in_size);) + pext->Status = EXT_STATUS_COPY_ERR; + } + rval = copy_from_user(&buff, + (void *)pext->RequestAdr, in_size); + + if (rval) { + DEBUG2_9_10(printk("%s: req buf copy error. " + "size=%ld.\n", + __func__, (ulong)in_size);) + + pext->Status = EXT_STATUS_COPY_ERR; + } else { + DEBUG9(printk("qla2x00_fo_ioctl: req buf " + "copied ok.\n")); + } + } + } else if (out_size != 0 && (ulong)pext->ResponseLen < out_size) { + pext->Status = EXT_STATUS_BUFFER_TOO_SMALL; + pext->DetailStatus = out_size; + DEBUG10(printk("%s: got invalie resp len (%d).\n", + __func__, pext->ResponseLen);) + } + + if (rval != 0 || pext->Status != 0) + goto done_fo_ioctl; + + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + + switch (ioctl_code) { + case FO_CC_GET_PARAMS: + rval = qla2x00_fo_get_params(&buff.params); + break; + case FO_CC_SET_PARAMS: + rval = qla2x00_fo_set_params(&buff.params); + break; + case FO_CC_GET_PATHS: + rval = qla2x00_cfg_get_paths(pext, + &buff.path,mode); + if (rval != 0) + out_size = 0; + break; + case FO_CC_SET_CURRENT_PATH: + rval = qla2x00_cfg_set_current_path(pext, + &buff.set_path,mode); + break; + case FO_CC_RESET_HBA_STAT: + rval = qla2x00_fo_stats(&buff.stat, TRUE); + break; + case FO_CC_GET_HBA_STAT: + rval = qla2x00_fo_stats(&buff.stat, FALSE); + break; + case FO_CC_GET_LUN_DATA: + + DEBUG4(printk("calling qla2x00_fo_get_lun_data\n");) + DEBUG4(printk("pext->RequestAdr (%p):\n", + pext->RequestAdr);) + + rval = qla2x00_fo_get_lun_data(pext, + &buff.lun_data, mode); + + if (rval != 0) + out_size = 0; + break; + case FO_CC_SET_LUN_DATA: + + DEBUG4(printk("calling qla2x00_fo_set_lun_data\n");) + DEBUG4(printk(" pext->RequestAdr (%p):\n", + pext->RequestAdr);) + + rval = qla2x00_fo_set_lun_data(pext, + &buff.lun_data, mode); + break; + case FO_CC_GET_TARGET_DATA: + DEBUG4(printk("calling qla2x00_fo_get_target_data\n");) + DEBUG4(printk("pext->RequestAdr (%p):\n", + pext->RequestAdr);) + + rval = qla2x00_fo_get_target_data(pext, + &buff.target_data, mode); + + if (rval != 0) { + out_size = 0; + } + break; + case FO_CC_SET_TARGET_DATA: + DEBUG4(printk("calling qla2x00_fo_set_target_data\n");) + DEBUG4(printk(" pext->RequestAdr (%p):\n", + pext->RequestAdr);) + rval = qla2x00_fo_set_target_data(pext, + &buff.target_data, mode); + break; + + } + + if (rval == 0 && (pext->ResponseLen = out_size) != 0) { + rval = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr, + out_size); + if (rval != 0) { + DEBUG10(printk("%s: resp buf very write error.\n", + __func__);) + pext->Status = EXT_STATUS_COPY_ERR; + } + } + + if (rval == 0) { + rval = copy_to_user((void *)pext->ResponseAdr, + &buff, out_size); + + if (rval != 0) { + DEBUG10(printk("%s: resp buf copy error. size=%ld.\n", + __func__, (ulong)out_size);) + pext->Status = EXT_STATUS_COPY_ERR; + } + } + +done_fo_ioctl: + + if (rval != 0) { + /*EMPTY*/ + DEBUG10(printk("%s: **** FAILED ****\n", __func__);) + } else { + /*EMPTY*/ + DEBUG9(printk("%s: exiting normally\n", __func__);) + } + + return rval; +} + + +/* + * qla2x00_fo_count_retries + * Increment the retry counter for the command. + * Set or reset the SRB_RETRY flag. + * + * Input: + * sp = Pointer to command. + * + * Returns: + * TRUE -- retry + * FALSE -- don't retry + * + * Context: + * Kernel context. + */ +static uint8_t +qla2x00_fo_count_retries(scsi_qla_host_t *ha, srb_t *sp) +{ + uint8_t retry = TRUE; + os_lun_t *lq; + os_tgt_t *tq; + + DEBUG9(printk("%s: entered.\n", __func__);) + + if (++sp->fo_retry_cnt > qla_fo_params.MaxRetriesPerIo) { + /* no more failovers for this request */ + retry = FALSE; + sp->fo_retry_cnt = 0; + printk(KERN_INFO + "qla2x00: no more failovers for request - pid= %ld\n", + sp->cmd->serial_number); + } else { + /* + * We haven't exceeded the max retries for this request, check + * max retries this path + */ + if ((sp->fo_retry_cnt % qla_fo_params.MaxRetriesPerPath) == 0) { + DEBUG(printk("qla2x00_fo_count_retries: FAILOVER - " + "queuing ha=%ld, sp=%p, pid =%ld, fo retry= %d\n", + ha->host_no, sp, sp->cmd->serial_number, + sp->fo_retry_cnt);) + + /* + * Note: we don't want it to timeout, so it is + * recycling on the retry queue and the fialover queue. + */ + lq = sp->lun_queue; + tq = sp->tgt_queue; + set_bit(LUN_MPIO_BUSY, &lq->q_flag); + + /* + * ??? We can get a path error on any ha, but always + * queue failover on originating ha. This will allow us + * to syncronized the requests for a given lun. + */ + sp->f_start=jiffies; /*ra 10/29/01*/ + /* Now queue it on to be failover */ + sp->ha = ha; + add_to_failover_queue(ha, sp); + } + } + + DEBUG9(printk("%s: exiting. retry = %d.\n", __func__, retry);) + + return retry ; +} + + +/* + * qla2x00_fo_check + * This function is called from the done routine to see if + * the SRB requires a failover. + * + * This function examines the available os returned status and + * if meets condition, the command(srb) is placed ont the failover + * queue for processing. + * + * Input: + * sp = Pointer to the SCSI Request Block + * + * Output: + * sp->flags SRB_RETRY bit id command is to + * be retried otherwise bit is reset. + * + * Returns: + * None. + * + * Context: + * Kernel/Interrupt context. + */ +uint8_t +qla2x00_fo_check(scsi_qla_host_t *ha, srb_t *sp) +{ + uint8_t retry = FALSE; + int host_status; +#if DEBUG_QLA2100 + static char *reason[] = { + "DID_OK", + "DID_NO_CONNECT", + "DID_BUS_BUSY", + "DID_TIME_OUT", + "DID_BAD_TARGET", + "DID_ABORT", + "DID_PARITY", + "DID_ERROR", + "DID_RESET", + "DID_BAD_INTR" + }; +#endif + + DEBUG9(printk("%s: entered.\n", __func__);) + + /* we failover on selction timeouts only */ + host_status = host_byte(sp->cmd->result); + if (host_status == DID_NO_CONNECT) { + if (qla2x00_fo_count_retries(ha, sp)) { + /* Force a retry on this request, it will + * cause the LINUX timer to get reset, while we + * we are processing the failover. + */ + sp->cmd->result = DID_BUS_BUSY << 16; + retry = TRUE; + } + DEBUG(printk("qla2x00_fo_check: pid= %ld sp %p retry count=%d, " + "retry flag = %d, host status (%s)\n", + sp->cmd->serial_number, sp, sp->fo_retry_cnt, retry, + reason[host_status]);) + } + + DEBUG9(printk("%s: exiting. retry = %d.\n", __func__, retry);) + + return retry; +} + +/* + * qla2x00_fo_path_change + * This function is called from configuration mgr to notify + * of a path change. + * + * Input: + * type = Failover notify type, FO_NOTIFY_LUN_RESET or FO_NOTIFY_LOGOUT + * newlunp = Pointer to the fc_lun struct for current path. + * oldlunp = Pointer to fc_lun struct for previous path. + * + * Returns: + * + * Context: + * Kernel context. + */ +uint32_t +qla2x00_fo_path_change(uint32_t type, fc_lun_t *newlunp, fc_lun_t *oldlunp) +{ + uint32_t ret = QLA_SUCCESS; + + newlunp->max_path_retries = 0; + return ret; +} + +/* + * qla2x00_fo_get_params + * Process an ioctl request to get system wide failover parameters. + * + * Input: + * pp = Pointer to FO_PARAMS structure. + * + * Returns: + * EXT_STATUS code. + * + * Context: + * Kernel context. + */ +static uint32_t +qla2x00_fo_get_params(PFO_PARAMS pp) +{ + DEBUG9(printk("%s: entered.\n", __func__);) + + pp->MaxPathsPerDevice = qla_fo_params.MaxPathsPerDevice; + pp->MaxRetriesPerPath = qla_fo_params.MaxRetriesPerPath; + pp->MaxRetriesPerIo = qla_fo_params.MaxRetriesPerIo; + pp->Flags = qla_fo_params.Flags; + pp->FailoverNotifyType = qla_fo_params.FailoverNotifyType; + pp->FailoverNotifyCdbLength = qla_fo_params.FailoverNotifyCdbLength; + memset(pp->FailoverNotifyCdb, 0, sizeof(pp->FailoverNotifyCdb)); + memcpy(pp->FailoverNotifyCdb, + &qla_fo_params.FailoverNotifyCdb[0], sizeof(pp->FailoverNotifyCdb)); + + DEBUG9(printk("%s: exiting.\n", __func__);) + + return EXT_STATUS_OK; +} + +/* + * qla2x00_fo_set_params + * Process an ioctl request to set system wide failover parameters. + * + * Input: + * pp = Pointer to FO_PARAMS structure. + * + * Returns: + * EXT_STATUS code. + * + * Context: + * Kernel context. + */ +static uint32_t +qla2x00_fo_set_params(PFO_PARAMS pp) +{ + DEBUG9(printk("%s: entered.\n", __func__);) + + /* Check values for defined MIN and MAX */ + if ((pp->MaxPathsPerDevice > SDM_DEF_MAX_PATHS_PER_DEVICE) || + (pp->MaxRetriesPerPath < FO_MAX_RETRIES_PER_PATH_MIN) || + (pp->MaxRetriesPerPath > FO_MAX_RETRIES_PER_PATH_MAX) || + (pp->MaxRetriesPerIo < FO_MAX_RETRIES_PER_IO_MIN) || + (pp->MaxRetriesPerPath > FO_MAX_RETRIES_PER_IO_MAX)) { + DEBUG2_9_10(printk("%s: got invalid params.\n", __func__);) + return EXT_STATUS_INVALID_PARAM; + } + + /* Update the global structure. */ + qla_fo_params.MaxPathsPerDevice = pp->MaxPathsPerDevice; + qla_fo_params.MaxRetriesPerPath = pp->MaxRetriesPerPath; + qla_fo_params.MaxRetriesPerIo = pp->MaxRetriesPerIo; + qla_fo_params.Flags = pp->Flags; + qla_fo_params.FailoverNotifyType = pp->FailoverNotifyType; + qla_fo_params.FailoverNotifyCdbLength = pp->FailoverNotifyCdbLength; + if (pp->FailoverNotifyType & FO_NOTIFY_TYPE_CDB) { + if (pp->FailoverNotifyCdbLength > + sizeof(qla_fo_params.FailoverNotifyCdb)) { + DEBUG2_9_10(printk("%s: got invalid cdb length.\n", + __func__);) + return EXT_STATUS_INVALID_PARAM; + } + + memcpy(qla_fo_params.FailoverNotifyCdb, + pp->FailoverNotifyCdb, + sizeof(qla_fo_params.FailoverNotifyCdb)); + } + + DEBUG9(printk("%s: exiting.\n", __func__);) + + return EXT_STATUS_OK; +} + + +/* + * qla2x00_fo_init_params + * Gets driver configuration file failover properties to initalize + * the global failover parameters structure. + * + * Input: + * ha = adapter block pointer. + * + * Context: + * Kernel context. + */ +void +qla2x00_fo_init_params(scsi_qla_host_t *ha) +{ + DEBUG3(printk("%s: entered.\n", __func__);) + + /* For parameters that are not completely implemented yet, */ + + memset(&qla_fo_params, 0, sizeof(qla_fo_params)); + + if(MaxPathsPerDevice) { + qla_fo_params.MaxPathsPerDevice = MaxPathsPerDevice; + } else + qla_fo_params.MaxPathsPerDevice =FO_MAX_PATHS_PER_DEVICE_DEF ; + if(MaxRetriesPerPath) { + qla_fo_params.MaxRetriesPerPath = MaxRetriesPerPath; + } else + qla_fo_params.MaxRetriesPerPath =FO_MAX_RETRIES_PER_PATH_DEF; + if(MaxRetriesPerIo) { + qla_fo_params.MaxRetriesPerIo =MaxRetriesPerIo; + } else + qla_fo_params.MaxRetriesPerIo =FO_MAX_RETRIES_PER_IO_DEF; + + qla_fo_params.Flags = 0; + qla_fo_params.FailoverNotifyType = FO_NOTIFY_TYPE_NONE; + + /* Set it to whatever user specified on the cmdline */ + if (qlFailoverNotifyType != FO_NOTIFY_TYPE_NONE) + qla_fo_params.FailoverNotifyType = qlFailoverNotifyType; + + + DEBUG3(printk("%s: exiting.\n", __func__);) +} + +static int +qla2x00_spinup(scsi_qla_host_t *ha, fc_port_t *fcport, uint16_t lun) +{ + inq_cmd_rsp_t *pkt; + int rval, count, retry; + dma_addr_t phys_address = 0; + uint16_t comp_status; + uint16_t scsi_status; + + ENTER(__func__); + + pkt = pci_alloc_consistent(ha->pdev, + sizeof(inq_cmd_rsp_t), &phys_address); + + if (pkt == NULL) { + printk(KERN_WARNING + "scsi(%ld): Memory Allocation failed - INQ\n", + ha->host_no); + } + + count = 100; + retry = 10; + do { + /* issue spinup */ + memset(pkt, 0, sizeof(inq_cmd_rsp_t)); + pkt->p.cmd.entry_type = COMMAND_A64_TYPE; + pkt->p.cmd.entry_count = 1; + pkt->p.cmd.lun = cpu_to_le16(lun); + SET_TARGET_ID(ha, pkt->p.cmd.target, fcport->loop_id); + /* no direction for this command */ + pkt->p.cmd.control_flags = + __constant_cpu_to_le16(CF_SIMPLE_TAG); + pkt->p.cmd.scsi_cdb[0] = START_STOP; + pkt->p.cmd.scsi_cdb[4] = 1; /* start spin cycle */ + pkt->p.cmd.dseg_count = __constant_cpu_to_le16(0); + pkt->p.cmd.timeout = __constant_cpu_to_le16(10); + pkt->p.cmd.byte_count = __constant_cpu_to_le32(0); + + rval = qla2x00_issue_iocb(ha, pkt, + phys_address, sizeof(inq_cmd_rsp_t)); + + comp_status = le16_to_cpu(pkt->p.rsp.comp_status); + scsi_status = le16_to_cpu(pkt->p.rsp.scsi_status); + + if ( (scsi_status & SS_CHECK_CONDITION) ) { + DEBUG2(printk("%s(%ld): SS_CHECK_CONDITION " + "Sense Data " + "%02x %02x %02x %02x " + "%02x %02x %02x %02x\n", + __func__, + ha->host_no, + pkt->p.rsp.req_sense_data[0], + pkt->p.rsp.req_sense_data[1], + pkt->p.rsp.req_sense_data[2], + pkt->p.rsp.req_sense_data[3], + pkt->p.rsp.req_sense_data[4], + pkt->p.rsp.req_sense_data[5], + pkt->p.rsp.req_sense_data[6], + pkt->p.rsp.req_sense_data[7]);) + if (pkt->p.rsp.req_sense_data[2] == + NOT_READY && + (pkt->p.rsp.req_sense_data[12] == 4 ) && + (pkt->p.rsp.req_sense_data[13] == 3 ) ) { + + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ); + printk("."); + count--; + } else + retry--; + } + + printk("qla_fo: Sending Start - count %d, retry=%d" + "comp status 0x%x, " + "scsi status 0x%x, rval=%d\n", + count, + retry, + comp_status, + scsi_status, + rval); + + if (rval != QLA_SUCCESS || comp_status != CS_COMPLETE) + retry--; + + } while ( count && retry && + (rval != QLA_SUCCESS || comp_status != CS_COMPLETE || + (scsi_status & SS_CHECK_CONDITION))); + + if (rval != QLA_SUCCESS || + comp_status != CS_COMPLETE || + (scsi_status & SS_CHECK_CONDITION)) { + + DEBUG(printk("qla_fo: Failed spinup - " + "comp status 0x%x, " + "scsi status 0x%x. loop_id=%d\n", + comp_status, + scsi_status, + fcport->loop_id);) + } + + pci_free_consistent(ha->pdev, sizeof(rpt_lun_cmd_rsp_t), + pkt, phys_address); + + + LEAVE(__func__); + + return( rval ); + +} + + +/* + * qla2x00_send_fo_notification + * Sends failover notification if needed. Change the fc_lun pointer + * in the old path lun queue. + * + * Input: + * old_lp = Pointer to old fc_lun. + * new_lp = Pointer to new fc_lun. + * + * Returns: + * Local function status code. + * + * Context: + * Kernel context. + */ +uint32_t +qla2x00_send_fo_notification(fc_lun_t *old_lp, fc_lun_t *new_lp) +{ + scsi_qla_host_t *old_ha = old_lp->fcport->ha; + int rval = QLA_SUCCESS; + inq_cmd_rsp_t *pkt; + uint16_t loop_id, lun; + dma_addr_t phys_address; + + + ENTER("qla2x00_send_fo_notification"); + DEBUG3(printk("%s: entered.\n", __func__);) + + loop_id = new_lp->fcport->loop_id; + lun = new_lp->lun; + + if (qla_fo_params.FailoverNotifyType == FO_NOTIFY_TYPE_LUN_RESET) { + rval = qla2x00_lun_reset(old_ha, loop_id, lun); + if (rval == QLA_SUCCESS) { + DEBUG4(printk("qla2x00_send_fo_notification: LUN " + "reset succeded\n");) + } else { + DEBUG4(printk("qla2x00_send_fo_notification: LUN " + "reset failed\n");) + } + + } + if ( (qla_fo_params.FailoverNotifyType == + FO_NOTIFY_TYPE_LOGOUT_OR_LUN_RESET) || + (qla_fo_params.FailoverNotifyType == + FO_NOTIFY_TYPE_LOGOUT_OR_CDB) ) { + + rval = qla2x00_fabric_logout(old_ha, loop_id); + if (rval == QLA_SUCCESS) { + DEBUG4(printk("qla2x00_send_fo_failover_notify: " + "logout succeded\n");) + } else { + DEBUG4(printk("qla2x00_send_fo_failover_notify: " + "logout failed\n");) + } + + } + + if (qla_fo_params.FailoverNotifyType == FO_NOTIFY_TYPE_SPINUP) { + qla2x00_spinup(new_lp->fcport->ha, new_lp->fcport, new_lp->lun); + } + + if (qla_fo_params.FailoverNotifyType == FO_NOTIFY_TYPE_CDB) { + pkt = pci_alloc_consistent(old_ha->pdev, + sizeof(inq_cmd_rsp_t), &phys_address); + if (pkt == NULL) { + DEBUG4(printk("qla2x00_send_fo_failover_notify: " + "memory allocation failed\n");) + + return(QLA_FUNCTION_FAILED); + } + + memset(pkt,0, sizeof(inq_cmd_rsp_t)); + pkt->p.cmd.entry_type = COMMAND_A64_TYPE; + pkt->p.cmd.entry_count = 1; + pkt->p.cmd.lun = cpu_to_le16(lun); + SET_TARGET_ID(old_ha, pkt->p.cmd.target, loop_id); + + /* FIXME: How do you know the direction ???? */ + /* This has same issues as passthur commands - you + * need more than just the CDB. + */ + pkt->p.cmd.control_flags = + __constant_cpu_to_le16(CF_SIMPLE_TAG); + memcpy(pkt->p.cmd.scsi_cdb, + qla_fo_params.FailoverNotifyCdb, + qla_fo_params.FailoverNotifyCdbLength); + pkt->p.cmd.dseg_count = __constant_cpu_to_le16(1); + pkt->p.cmd.byte_count = __constant_cpu_to_le32(0); + pkt->p.cmd.dseg_0_address[0] = cpu_to_le32( + LSD(phys_address + sizeof (sts_entry_t))); + pkt->p.cmd.dseg_0_address[1] = cpu_to_le32( + MSD(phys_address + sizeof (sts_entry_t))); + pkt->p.cmd.dseg_0_length = __constant_cpu_to_le32(0); + + rval = qla2x00_issue_iocb(old_ha, + pkt, phys_address, sizeof (inq_cmd_rsp_t)); + + if (rval != QLA_SUCCESS || + pkt->p.rsp.comp_status != CS_COMPLETE || + pkt->p.rsp.scsi_status & SS_CHECK_CONDITION || + pkt->inq[0] == 0x7f) { + + DEBUG4(printk("qla2x00_fo_notification: send CDB " + "failed: comp_status = %x" + "scsi_status = %x inq[0] = %x\n", + pkt->p.rsp.comp_status, + pkt->p.rsp.scsi_status, + pkt->inq[0]);) + } + + pci_free_consistent(old_ha->pdev, + sizeof(inq_cmd_rsp_t), pkt, phys_address); + } + + DEBUG3(printk("%s: exiting. rval = %d.\n", __func__, rval);) + + return rval; +} + + +/* + * qla2100_fo_enabled + * Reads and validates the failover enabled property. + * + * Input: + * ha = adapter state pointer. + * instance = HBA number. + * + * Returns: + * TRUE when failover is authorized else FALSE + * + * Context: + * Kernel context. + */ +uint8_t +qla2x00_fo_enabled(scsi_qla_host_t *ha, int instance) +{ + return qla2x00_failover_enabled(ha); +} + +/* + * qla2x00_fo_missing_port_summary + * Returns values of devices not connected but found in configuration + * file in user's dd_entry list. + * + * Input: + * ha = adapter state pointer. + * pdd_entry = pointer to a temporary EXT_DEVICEDATAENTRY struct + * pstart_of_entry_list = start of user addr of buffer for dd_entry entries + * max_entries = max number of entries allowed by user buffer + * pentry_cnt = pointer to total number of entries so far + * ret_status = pointer to ioctl status field + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +int +qla2x00_fo_missing_port_summary(scsi_qla_host_t *ha, + EXT_DEVICEDATAENTRY *pdd_entry, void *pstart_of_entry_list, + uint32_t max_entries, uint32_t *pentry_cnt, uint32_t *ret_status) +{ + int ret = 0; + uint8_t path_id; + uint8_t *usr_temp, *kernel_tmp; + uint16_t dev_no; + uint32_t b; + uint32_t current_offset; + uint32_t transfer_size; + mp_device_t *dp; + mp_host_t *host; + mp_path_list_t *pathlist; + mp_path_t *path; + portname_list *portname_used = NULL; + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + if ((host = qla2x00_cfg_find_host(ha)) == NULL) { + DEBUG2_9_10(printk("%s(%ld): no HOST for ha inst %ld.\n", + __func__, ha->host_no, ha->instance);) + *ret_status = EXT_STATUS_DEV_NOT_FOUND; + return (ret); + } + + /* Assumption: each port name cannot appear in more than one mpdev + * structure. + */ + for (dev_no = 0; dev_no < MAX_MP_DEVICES && *pentry_cnt < max_entries; + dev_no++) { + dp = host->mp_devs[dev_no]; + + if (dp == NULL) + continue; + + /* Sanity check */ + if (qla2x00_is_wwn_zero(dp->nodename)) + continue; + + if ((pathlist = dp->path_list) == NULL) + continue; + + path = pathlist->last; + for (path_id = 0; path_id < pathlist->path_cnt && + *pentry_cnt < max_entries; path_id++, path = path->next) { + + /* Sanity check */ + if (qla2x00_is_wwn_zero(path->portname)) + continue; + + if (path->config == TRUE && path->port == NULL) { + /* This path was created from config file + * but has not been configured. + */ + if (path->host != host) { + /* path on other host. don't report */ + DEBUG10(printk("%s(%ld): path host %p " + "not for current host %p.\n", + __func__, ha->host_no, path->host, + host);) + + continue; + } + + /* Check whether we've copied info on this + * port name before. If this is a new port + * name, save the port name so we won't copy + * it again if it's also found on other hosts. + */ + if (qla2x00_port_name_in_list(path->portname, + portname_used)) { + DEBUG10(printk("%s(%ld): found previously " + "reported portname=%02x%02x%02x" + "%02x%02x%02x%02x%02x.\n", + __func__, ha->host_no, + path->portname[0], + path->portname[1], + path->portname[2], + path->portname[3], + path->portname[4], + path->portname[5], + path->portname[6], + path->portname[7]);) + continue; + } + + if ((ret = qla2x00_add_to_portname_list( + path->portname, &portname_used))) { + /* mem alloc error? */ + *ret_status = EXT_STATUS_NO_MEMORY; + break; + } + + DEBUG10(printk("%s(%ld): returning missing device " + "%02x%02x%02x%02x%02x%02x%02x%02x.\n", + __func__, ha->host_no, + path->portname[0], path->portname[1], + path->portname[2], path->portname[3], + path->portname[4], path->portname[5], + path->portname[6], path->portname[7]);) + + /* This device was not found. Return + * as unconfigured. + */ + memcpy(pdd_entry->NodeWWN, dp->nodename, + WWN_SIZE); + memcpy(pdd_entry->PortWWN, path->portname, + WWN_SIZE); + + for (b = 0; b < 3 ; b++) + pdd_entry->PortID[b] = 0; + + /* assume fabric dev so api won't translate the portid from loopid */ + pdd_entry->ControlFlags = EXT_DEF_GET_FABRIC_DEVICE; + + pdd_entry->TargetAddress.Bus = 0; + pdd_entry->TargetAddress.Target = dp->dev_id; + pdd_entry->TargetAddress.Lun = 0; + pdd_entry->DeviceFlags = 0; + pdd_entry->LoopID = 0; + pdd_entry->BaseLunNumber = 0; + + current_offset = *pentry_cnt * + sizeof(EXT_DEVICEDATAENTRY); + + transfer_size = sizeof(EXT_DEVICEDATAENTRY); + ret = verify_area(VERIFY_WRITE, + (void *)(pstart_of_entry_list + + current_offset), transfer_size); + + if (ret) { + *ret_status = EXT_STATUS_COPY_ERR; + DEBUG10(printk("%s(%ld): inst=%ld " + "ERROR verify wrt rsp bufaddr=%p\n", + __func__, ha->host_no, ha->instance, + (void *)(pstart_of_entry_list + + current_offset));) + break; + } + + /* now copy up this dd_entry to user */ + usr_temp = (uint8_t *)pstart_of_entry_list + + current_offset; + kernel_tmp = (uint8_t *)pdd_entry; + ret = copy_to_user(usr_temp, kernel_tmp, + transfer_size); + if (ret) { + *ret_status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld " + "ERROR copy rsp list buffer.\n", + __func__, ha->host_no, + ha->instance);) + break; + } + *pentry_cnt+=1; + } + + } + + if (ret || *ret_status) { + break; + } + } + + DEBUG9(printk("%s(%ld): ending entry cnt=%d.\n", + __func__, ha->host_no, *pentry_cnt);) + + qla2x00_free_portname_list(&portname_used); + + DEBUG9(printk("%s(%ld): inst=%ld exiting. ret=%d.\n", + __func__, ha->host_no, ha->instance, ret);) + + return (ret); +} + +/* + * qla2x00_port_name_in_list + * Returns whether we found the specified port name in the list given. + * + * Input: + * wwpn = pointer to ww port name. + * list = pointer to a portname_list list. + * + * Returns: + * 1 = found portname in list + * 0 = portname not in list + * + * Context: + * Kernel context. + */ +static int +qla2x00_port_name_in_list(uint8_t *wwpn, portname_list *list) +{ + int found_name = 0; + portname_list *ptmp; + + for (ptmp = list; ptmp; ptmp = ptmp->pnext) { + if (qla2x00_is_nodename_equal(ptmp->portname, wwpn)) { + found_name = 1; + break; + } + } + + return (found_name); +} + +/* + * qla2x00_add_to_portname_list + * Allocates a portname_list member and adds it to the list given + * with the specified port name. + * + * Input: + * wwpn = pointer to ww port name. + * plist = pointer to a pointer of portname_list list. + * + * Returns: + * 0 = success + * others = errno indicating error + * + * Context: + * Kernel context. + */ +static int +qla2x00_add_to_portname_list(uint8_t *wwpn, portname_list **plist) +{ + int ret = 0; + portname_list *ptmp; + portname_list *plast; + + if ((ptmp = (portname_list *)KMEM_ZALLOC(sizeof(portname_list), 50))) { + + memcpy(ptmp->portname, wwpn, EXT_DEF_WWN_NAME_SIZE); + + if (*plist) { + /* Add to tail of list */ + for (plast = *plist; plast->pnext; plast=plast->pnext) { + /* empty */ + } + plast->pnext = ptmp; + } else { + *plist = ptmp; + } + + } else { + DEBUG2_9_10(printk("%s: failed to alloc memory of size (%d)\n", + __func__, (int)sizeof(FO_LUN_DATA_LIST));) + ret = -ENOMEM; + } + + return (ret); +} + +/* + * qla2x00_free_portname_list + * Free the list given. + * + * Input: + * plist = pointer to a pointer of portname_list list to free. + * + * Returns: + * + * Context: + * Kernel context. + */ +static void +qla2x00_free_portname_list(portname_list **plist) +{ + portname_list *ptmp; + portname_list *ptmpnext; + + for (ptmp = *plist; ptmp; ptmp = ptmpnext) { + ptmpnext = ptmp->pnext; + KMEM_FREE(ptmp, sizeof(portname_list)); + } + *plist = NULL; +} diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qla_fo.cfg 830-ivtv/drivers/scsi/qla2xxx/qla_fo.cfg --- 000-virgin/drivers/scsi/qla2xxx/qla_fo.cfg Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qla_fo.cfg Thu Jan 8 10:22:00 2004 @@ -0,0 +1,33 @@ +/****************************************************************************** + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.4.x + * Copyright (C) 2003 Qlogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + ******************************************************************************/ + +/* + * QLogic ISP2x00 Multi-path LUN Support Driver + */ +int MaxPathsPerDevice = 0; +int MaxRetriesPerPath = 0; +int MaxRetriesPerIo = 0; +int qlFailoverNotifyType = 0; +#if defined(MODULE) +/* insmod qla2100 ql2xopts= */ +MODULE_PARM(MaxPathsPerDevice, "i"); +MODULE_PARM(MaxRetriesPerPath, "i"); +MODULE_PARM(MaxRetriesPerIo, "i"); +MODULE_PARM(qlFailoverNotifyType, "i"); +#endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qla_fo.h 830-ivtv/drivers/scsi/qla2xxx/qla_fo.h --- 000-virgin/drivers/scsi/qla2xxx/qla_fo.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qla_fo.h Thu Jan 8 10:22:00 2004 @@ -0,0 +1,75 @@ +/****************************************************************************** + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + ******************************************************************************/ + +/* + * QLogic ISP2x00 Failover Header + * + */ +#ifndef _QLA_FO_H +#define _QLA_FO_H + +#if defined(__cplusplus) +extern "C" +{ +#endif + +#include "qlfo.h" + /* + * This structure definition is for a scsi I/O request NOT subject to + * failover re-routing. It is for the use of configuration operations + * and diagnostics functions as definted in ExIoct.h + */ + typedef struct scsi_cdb_request { + struct adapter_state *ha; + uint16_t target; + uint16_t lun; + uint8_t *cdb_ptr; /* Pointer to cdb to be sent */ + uint8_t cdb_len; /* cdb length */ + uint8_t direction; /* Direction of I/O for buffer */ + uint8_t scb_len; /* Scsi completion block length */ + uint8_t *scb_ptr; /* Scsi completion block pointer */ + uint8_t *buf_ptr; /* Pointer to I/O buffer */ + uint16_t buf_len; /* Buffer size */ + } + SCSI_REQ_t, *SCSI_REQ_p; + + + /* + * Special defines + */ + typedef union _FO_HBA_STAT { + FO_HBA_STAT_INPUT input; + FO_HBA_STAT_INFO info; + } FO_HBA_STAT; + + typedef union _FO_LUN_DATA { + FO_LUN_DATA_INPUT input; + FO_LUN_DATA_LIST list; + } FO_LUN_DATA; + + typedef union _FO_TARGET_DATA { + FO_TARGET_DATA_INPUT input; + FO_DEVICE_DATABASE list; + } FO_TARGET_DATA; + +#if defined(__cplusplus) +} +#endif + +#endif /* ifndef _QLA_FO_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qla_foln.c 830-ivtv/drivers/scsi/qla2xxx/qla_foln.c --- 000-virgin/drivers/scsi/qla2xxx/qla_foln.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qla_foln.c Thu Jan 8 10:22:00 2004 @@ -0,0 +1,294 @@ +/******************************************************************************** +* QLOGIC LINUX SOFTWARE +* +* QLogic ISP2x00 device driver for Linux 2.6.x +* Copyright (C) 2003 QLogic Corporation +* (www.qlogic.com) +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2, or (at your option) any +* later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +******************************************************************************/ + +#include "qla_os.h" +#include "qla_def.h" + + +int ql2xfailover; +module_param(ql2xfailover, int, 0); +MODULE_PARM_DESC(ql2xfailover, + "Driver failover support: 0 to disable; 1 to enable."); + +int ql2xrecoveryTime = MAX_RECOVERYTIME; +module_param_named(recoveryTime, ql2xrecoveryTime, int, 0); +MODULE_PARM_DESC(recoveryTime, + "Recovery time in seconds before a target device is sent I/O " + "after a failback is performed."); + +int ql2xfailbackTime = MAX_FAILBACKTIME; +module_param_named(failbackTime, ql2xfailbackTime, int, 0); +MODULE_PARM_DESC(failbackTime, + "Delay in seconds before a failback is performed."); + + +/* + * qla2x00_check_for_devices_online + * + * Check fcport state of all devices to make sure online. + * + * Input: + * ha = adapter block pointer. + * + * Return: + * None. + * + * Context: + */ +static uint8_t +qla2x00_check_for_devices_online(scsi_qla_host_t *ha) +{ + fc_port_t *fcport; + + list_for_each_entry(fcport, &ha->fcports, list) { + if ((atomic_read(&fcport->state) == FCS_ONLINE) || + (atomic_read(&fcport->state) == FCS_DEVICE_DEAD)) + continue; + return 0; + } + + return 1; +} + +/* + * qla2x00_failover_cleanup + * Cleanup queues after a failover. + * + * Input: + * sp = command pointer + * + * Context: + * Interrupt context. + */ +static void +qla2x00_failover_cleanup(srb_t *sp) +{ + sp->cmd->result = DID_BUS_BUSY << 16; + sp->cmd->host_scribble = (unsigned char *) NULL; + + /* turn-off all failover flags */ + sp->flags = sp->flags & ~(SRB_RETRY|SRB_FAILOVER|SRB_FO_CANCEL); +} + + +/* + * qla2x00_process_failover + * Process any command on the failover queue. + * + * Input: + * ha = adapter block pointer. + * + * Context: + * Interrupt context. + */ +static void +qla2x00_process_failover(scsi_qla_host_t *ha) +{ + + os_tgt_t *tq; + os_lun_t *lq; + srb_t *sp; + fc_port_t *fcport; + struct list_head *list, *temp; + unsigned long flags; + unsigned int t, l; + scsi_qla_host_t *vis_ha = NULL; + + DEBUG(printk("scsi(%ld): Processing failover for hba.\n", ha->host_no)); + + /* + * Process all the commands in the failover queue. Attempt to failover + * then either complete the command as is or requeue for retry. + */ + + /* Prevent or allow acceptance of new I/O requests. */ + spin_lock_irqsave(&ha->list_lock, flags); + + /* + * Get first entry to find our visible adapter. We could never get + * here if the list is empty + */ + list = ha->failover_queue.next; + sp = list_entry(list, srb_t, list); + vis_ha = (scsi_qla_host_t *) sp->cmd->device->host->hostdata; + list_for_each_safe(list, temp, &ha->failover_queue) { + sp = list_entry(list, srb_t, list); + + tq = sp->tgt_queue; + lq = sp->lun_queue; + fcport = lq->fclun->fcport; + + /* Remove srb from failover queue. */ + __del_from_failover_queue(ha, sp); + + DEBUG2(printk("%s(): pid %ld retrycnt=%d\n", + __func__, sp->cmd->serial_number, sp->cmd->retries)); + + /*** Select an alternate path ***/ + /* + * If the path has already been change by a previous request + * sp->fclun != lq->fclun + */ + if (sp->fclun != lq->fclun || + atomic_read(&fcport->state) != FCS_DEVICE_DEAD) { + + qla2x00_failover_cleanup(sp); + + } else if (qla2x00_cfg_failover(ha, lq->fclun, tq, sp) == + NULL) { + /* + * We ran out of paths, so just post the status which + * is already set in the cmd. + */ + printk(KERN_INFO + "scsi(%ld): Ran out of paths - pid %ld\n", + ha->host_no, sp->cmd->serial_number); + } else { + qla2x00_failover_cleanup(sp); + + } + __add_to_done_queue(ha, sp); + } /* list_for_each_safe */ + spin_unlock_irqrestore(&ha->list_lock, flags); + + for (t = 0; t < vis_ha->max_targets; t++) { + if ((tq = vis_ha->otgt[t]) == NULL) + continue; + for (l = 0; l < vis_ha->max_luns; l++) { + if ((lq = (os_lun_t *) tq->olun[l]) == NULL) + continue; + + if( test_and_clear_bit(LUN_MPIO_BUSY, &lq->q_flag) ) { + /* EMPTY */ + DEBUG(printk("scsi(%ld): remove suspend for " + "lun %d\n", ha->host_no, lq->fclun->lun)); + } + } + } + + //qla2x00_restart_queues(ha,TRUE); + qla2x00_restart_queues(ha, FALSE); + + DEBUG(printk("%s() - done", __func__)); +} + +int +qla2x00_search_failover_queue(scsi_qla_host_t *ha, struct scsi_cmnd *cmd) +{ + struct list_head *list, *temp; + unsigned long flags; + srb_t *sp; + + DEBUG3(printk("qla2xxx_eh_abort: searching sp %p in " + "failover queue.\n", sp);) + + spin_lock_irqsave(&ha->list_lock, flags); + list_for_each_safe(list, temp, &ha->failover_queue) { + sp = list_entry(list, srb_t, list); + + if (cmd == sp->cmd) + goto found; + + } + spin_unlock_irqrestore(&ha->list_lock, flags); + + return 0; + + found: + /* Remove srb from failover queue. */ + __del_from_failover_queue(ha, sp); + cmd->result = DID_ABORT << 16; + __add_to_done_queue(ha, sp); + + spin_unlock_irqrestore(&ha->list_lock, flags); + return 1; +} + +/* + * If we are not processing a ioctl or one of + * the ports are still MISSING or need a resync + * then process the failover event. + */ +void +qla2x00_process_failover_event(scsi_qla_host_t *ha) +{ + if (test_bit(CFG_ACTIVE, &ha->cfg_flags)) + return; + if (qla2x00_check_for_devices_online(ha)) { + if (test_and_clear_bit(FAILOVER_EVENT, &ha->dpc_flags)) { + if (ha->flags.online) + qla2x00_cfg_event_notify(ha, ha->failover_type); + } + } + + /* + * Get any requests from failover queue + */ + if (test_and_clear_bit(FAILOVER_NEEDED, &ha->dpc_flags)) + qla2x00_process_failover(ha); +} + +int +qla2x00_do_fo_check(scsi_qla_host_t *ha, srb_t *sp, scsi_qla_host_t *vis_ha) +{ + /* + * This routine checks for DID_NO_CONNECT to decide + * whether to failover to another path or not. We only + * failover on that status. + */ + if (!qla2x00_fo_check(ha, sp)) + return 0; + + if ((sp->state != SRB_FAILOVER_STATE)) { + /* + * Retry the command on this path + * several times before selecting a new + * path. + */ + add_to_pending_queue_head(vis_ha, sp); + qla2x00_next(vis_ha); + } else + qla2x00_extend_timeout(sp->cmd, EXTEND_CMD_TIMEOUT); + + return 1; +} + +void +qla2xxx_start_all_adapters(scsi_qla_host_t *ha) +{ + struct list_head *hal; + scsi_qla_host_t *vis_ha; + + /* Try and start all visible adapters */ + read_lock(&qla_hostlist_lock); + list_for_each(hal, &qla_hostlist) { + vis_ha = list_entry(hal, scsi_qla_host_t, list); + + if (!list_empty(&vis_ha->pending_queue)) + qla2x00_next(vis_ha); + + DEBUG2(printk("host(%ld):Commands busy=%d " + "failed=%d\neh_active=%d\n ", + vis_ha->host_no, + vis_ha->host->host_busy, + vis_ha->host->host_failed, + vis_ha->host->eh_active);) + } + read_unlock(&qla_hostlist_lock); +} diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qla_foln.h 830-ivtv/drivers/scsi/qla2xxx/qla_foln.h --- 000-virgin/drivers/scsi/qla2xxx/qla_foln.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qla_foln.h Thu Jan 8 10:22:00 2004 @@ -0,0 +1,119 @@ +/****************************************************************************** + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + ******************************************************************************/ + +#ifndef __QLA_FOLN_H +#define __QLA_FOLN_H + +#if defined(CONFIG_SCSI_QLA2XXX_FAILOVER_ENABLE) + +#include "qla_fo.h" +#include "qla_cfg.h" + +/* + * Global Data in qla_fo.c source file. + */ +extern SysFoParams_t qla_fo_params; + +/* + * Global Function Prototypes in qla_fo.c source file. + */ +extern scsi_qla_host_t *qla2x00_get_hba(unsigned long); +extern uint32_t qla2x00_send_fo_notification(fc_lun_t *fclun_p, fc_lun_t *olun_p); +extern void qla2x00_fo_init_params(scsi_qla_host_t *ha); +extern uint8_t qla2x00_fo_enabled(scsi_qla_host_t *ha, int instance); +extern int qla2x00_fo_ioctl(scsi_qla_host_t *, int, EXT_IOCTL *, int); + +extern int qla2x00_fo_missing_port_summary(scsi_qla_host_t *, + EXT_DEVICEDATAENTRY *, void *, uint32_t, uint32_t *, uint32_t *); + +/* + * Global Data in qla_cfg.c source file. + */ +extern mp_host_t *mp_hosts_base; +extern uint8_t mp_config_required; +/* + * Global Function Prototypes in qla_cfg.c source file. + */ +extern mp_host_t * qla2x00_cfg_find_host(scsi_qla_host_t *); +extern uint8_t qla2x00_is_portname_in_device(mp_device_t *, uint8_t *); +extern int qla2x00_cfg_path_discovery(scsi_qla_host_t *ha); +extern int qla2x00_cfg_event_notify(scsi_qla_host_t *ha, uint32_t i_type); +extern fc_lun_t *qla2x00_cfg_failover(scsi_qla_host_t *ha, fc_lun_t *fp, + os_tgt_t *tgt, srb_t *sp); +extern int qla2x00_cfg_get_paths( EXT_IOCTL *, FO_GET_PATHS *, int); +extern int qla2x00_cfg_set_current_path( EXT_IOCTL *, + FO_SET_CURRENT_PATH *, int); +extern void qla2x00_fo_properties(scsi_qla_host_t *ha); +extern mp_host_t * qla2x00_add_mp_host(uint8_t *); +extern mp_host_t * qla2x00_alloc_host(scsi_qla_host_t *); +extern uint8_t qla2x00_fo_check(scsi_qla_host_t *ha, srb_t *sp); +extern mp_path_t *qla2x00_find_path_by_name(mp_host_t *, mp_path_list_t *, + uint8_t *name); + +extern int __qla2x00_is_fcport_in_config(scsi_qla_host_t *, fc_port_t *); +extern int qla2x00_cfg_init(scsi_qla_host_t *ha); +extern void qla2x00_cfg_mem_free(scsi_qla_host_t *ha); + +/* + * Global Function Prototypes in qla_cfgln.c source file. + */ +extern void qla2x00_cfg_build_path_tree( scsi_qla_host_t *ha); +extern uint8_t qla2x00_update_mp_device(mp_host_t *, + fc_port_t *, uint16_t, uint16_t); +extern void qla2x00_cfg_display_devices(void); + + +/* + * Global Function Prototypes in qla_foln.c source file. + */ +extern int qla2x00_search_failover_queue(scsi_qla_host_t *, struct scsi_cmnd *); +extern void qla2x00_process_failover_event(scsi_qla_host_t *); +extern int qla2x00_do_fo_check(scsi_qla_host_t *, srb_t *, scsi_qla_host_t *); +extern void qla2xxx_start_all_adapters(scsi_qla_host_t *); + +extern int ql2xrecoveryTime; +extern int ql2xfailbackTime; +extern int ql2xfailover; +#define qla2x00_failover_enabled(ha) (ql2xfailover) + +#else +#define __qla2x00_is_fcport_in_config(ha, fcport) (0) +#define qla2x00_fo_missing_port_summary(ha, e, s, m, c, r) (0) +/* qla2x00_cfg_init() is declared int but the retval isn't checked.. */ +#define qla2x00_cfg_init(ha) do { } while (0) +#define qla2x00_cfg_mem_free(ha) do { } while (0) +#define qla2x00_cfg_display_devices() do { } while (0) +#define qla2x00_process_failover_event(ha) do { } while (0) +#define qla2xxx_start_all_adapters(ha) do { } while (0) +#define qla2x00_search_failover_queue(ha, cmd) (0) +#define qla2x00_do_fo_check(ha, sp, vis_ha) (0) +#define qla2x00_failover_enabled(ha) (0) +#endif /* CONFIG_SCSI_QLA2XXX_FAILOVER_ENABLE */ + +static __inline int +qla2x00_is_fcport_in_config(scsi_qla_host_t *ha, fc_port_t *fcport) +{ + if (qla2x00_failover_enabled(ha)) + return __qla2x00_is_fcport_in_config(ha, fcport); + else if (fcport->flags & FCF_PERSISTENT_BOUND) + return 1; + return 0; +} + +#endif /* __QLA_FOLN_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qla_gbl.h 830-ivtv/drivers/scsi/qla2xxx/qla_gbl.h --- 000-virgin/drivers/scsi/qla2xxx/qla_gbl.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qla_gbl.h Thu Jan 8 10:22:00 2004 @@ -0,0 +1,344 @@ +/******************************************************************************** +* QLOGIC LINUX SOFTWARE +* +* QLogic ISP2x00 device driver for Linux 2.6.x +* Copyright (C) 2003 QLogic Corporation +* (www.qlogic.com) +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2, or (at your option) any +* later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +****************************************************************************** +* Global include file. +******************************************************************************/ + + +#ifndef __QLA_GBL_H +#define __QLA_GBL_H + +extern void qla2x00_remove_one(struct pci_dev *); +extern int qla2x00_probe_one(struct pci_dev *, struct qla_board_info *); + +/* + * Global Function Prototypes in qla_init.c source file. + */ +extern int qla2x00_initialize_adapter(scsi_qla_host_t *); +extern fc_port_t *qla2x00_alloc_fcport(scsi_qla_host_t *, int); + +extern int qla2x00_loop_resync(scsi_qla_host_t *); + +extern int qla2x00_find_new_loop_id(scsi_qla_host_t *, fc_port_t *); +extern int qla2x00_fabric_login(scsi_qla_host_t *, fc_port_t *, uint16_t *); +extern int qla2x00_local_device_login(scsi_qla_host_t *, uint16_t); + +extern void qla2x00_restart_queues(scsi_qla_host_t *, uint8_t); + +extern void qla2x00_rescan_fcports(scsi_qla_host_t *); + +extern void qla2x00_tgt_free(scsi_qla_host_t *ha, uint16_t t); +extern os_tgt_t *qla2x00_tgt_alloc(scsi_qla_host_t *, uint16_t); +extern os_lun_t * qla2x00_lun_alloc(scsi_qla_host_t *, uint16_t, uint16_t); + +extern int qla2x00_abort_isp(scsi_qla_host_t *); + + +/* + * Global Data in qla_os.c source file. + */ +extern char qla2x00_version_str[]; +extern unsigned long qla2x00_verbose; +extern unsigned long qla2x00_reinit; +extern unsigned long qla2x00_req_dmp; + +extern int num_hosts; +extern int apiHBAInstance; + +extern struct _qla2x00stats qla2x00_stats; +extern char *ql2xdevconf; +extern int ql2xretrycount; +extern int qla2xenbinq; +extern int ql2xlogintimeout; +extern int qlport_down_retry; +extern int ql2xmaxqdepth; +extern int displayConfig; +extern int ql2xplogiabsentdevice; +extern int ql2xintrdelaytimer; + +extern int ConfigRequired; + +extern int Bind; +extern int ql2xsuspendcount; +extern int qla2x00_retryq_dmp; +#if defined(MODULE) +extern char *ql2xopts; +#endif +extern struct list_head qla_hostlist; +extern rwlock_t qla_hostlist_lock; + +extern char *qla2x00_get_fw_version_str(struct scsi_qla_host *, char *); + +extern int qla2x00_queuecommand(struct scsi_cmnd *, + void (*)(struct scsi_cmnd *)); + +extern int __qla2x00_suspend_lun(scsi_qla_host_t *, os_lun_t *, int, int, int); + +extern void qla2x00_done(scsi_qla_host_t *); +extern void qla2x00_next(scsi_qla_host_t *); +extern void qla2x00_flush_failover_q(scsi_qla_host_t *, os_lun_t *); +extern void qla2x00_reset_lun_fo_counts(scsi_qla_host_t *, os_lun_t *); + +extern int qla2x00_check_tgt_status(scsi_qla_host_t *, struct scsi_cmnd *); +extern int qla2x00_check_port_status(scsi_qla_host_t *, fc_port_t *); + +extern void qla2x00_extend_timeout(struct scsi_cmnd *, int); +extern srb_t * qla2x00_get_new_sp (scsi_qla_host_t *ha); + +extern void qla2x00_mark_device_lost(scsi_qla_host_t *, fc_port_t *, int); +extern void qla2x00_mark_all_devices_lost(scsi_qla_host_t *); + +extern int qla2x00_get_prop_xstr(scsi_qla_host_t *, char *, uint8_t *, int); + +extern void qla2x00_abort_queues(scsi_qla_host_t *, uint8_t); + +extern void qla2x00_blink_led(scsi_qla_host_t *); + +/* + * Global Function Prototypes in qla_iocb.c source file. + */ +extern request_t *qla2x00_req_pkt(scsi_qla_host_t *); +extern request_t *qla2x00_ms_req_pkt(scsi_qla_host_t *, srb_t *); +extern void qla2x00_isp_cmd(scsi_qla_host_t *); + +extern uint16_t qla2x00_calc_iocbs_32(uint16_t); +extern uint16_t qla2x00_calc_iocbs_64(uint16_t); +extern void qla2x00_build_scsi_iocbs_32(srb_t *, cmd_entry_t *, uint16_t); +extern void qla2x00_build_scsi_iocbs_64(srb_t *, cmd_entry_t *, uint16_t); +extern int qla2x00_start_scsi(srb_t *sp); +int qla2x00_marker(scsi_qla_host_t *, uint16_t, uint16_t, uint8_t); +int __qla2x00_marker(scsi_qla_host_t *, uint16_t, uint16_t, uint8_t); + +/* + * Global Function Prototypes in qla_mbx.c source file. + */ +extern int +qla2x00_mailbox_command(scsi_qla_host_t *, mbx_cmd_t *); + +extern int +qla2x00_load_ram(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t); + +extern int +qla2x00_load_ram_ext(scsi_qla_host_t *, dma_addr_t, uint32_t, uint16_t); + +extern int +qla2x00_execute_fw(scsi_qla_host_t *); + +extern void +qla2x00_get_fw_version(scsi_qla_host_t *, uint16_t *, + uint16_t *, uint16_t *, uint16_t *); + +extern int +qla2x00_get_fw_options(scsi_qla_host_t *, uint16_t *); + +extern int +qla2x00_set_fw_options(scsi_qla_host_t *, uint16_t *); + +extern int +qla2x00_read_ram_word(scsi_qla_host_t *, uint16_t, uint16_t *); +extern int +qla2x00_write_ram_word(scsi_qla_host_t *, uint16_t, uint16_t); +extern int +qla2x00_write_ram_word_ext(scsi_qla_host_t *, uint32_t, uint16_t); + +extern int +qla2x00_mbx_reg_test(scsi_qla_host_t *); + +extern int +qla2x00_verify_checksum(scsi_qla_host_t *); + +extern int +qla2x00_issue_iocb(scsi_qla_host_t *, void *, dma_addr_t, size_t); + +extern int +qla2x00_abort_command(scsi_qla_host_t *, srb_t *); + +extern int +qla2x00_abort_device(scsi_qla_host_t *, uint16_t, uint16_t); + +#if USE_ABORT_TGT +extern int +qla2x00_abort_target(fc_port_t *fcport); +#endif + +extern int +qla2x00_target_reset(scsi_qla_host_t *, uint16_t, uint16_t); + +extern int +qla2x00_get_adapter_id(scsi_qla_host_t *, uint16_t *, uint8_t *, uint8_t *, + uint8_t *, uint16_t *); + +extern int +qla2x00_get_retry_cnt(scsi_qla_host_t *, uint8_t *, uint8_t *, uint16_t *); + +extern int +qla2x00_loopback_test(scsi_qla_host_t *, INT_LOOPBACK_REQ *, uint16_t *); + +extern int +qla2x00_echo_test(scsi_qla_host_t *, INT_LOOPBACK_REQ *, uint16_t *); + +extern int +qla2x00_init_firmware(scsi_qla_host_t *, uint16_t); + +extern int +qla2x00_get_port_database(scsi_qla_host_t *, fc_port_t *, uint8_t); + +extern int +qla2x00_get_firmware_state(scsi_qla_host_t *, uint16_t *); + +extern int +qla2x00_get_port_name(scsi_qla_host_t *, uint16_t, uint8_t *, uint8_t); + +extern uint8_t +qla2x00_get_link_status(scsi_qla_host_t *, uint8_t, void *, uint16_t *); + +extern int +qla2x00_lip_reset(scsi_qla_host_t *); + +extern int +qla2x00_send_sns(scsi_qla_host_t *, dma_addr_t, uint16_t, size_t); + +extern int +qla2x00_login_fabric(scsi_qla_host_t *, uint16_t, uint8_t, uint8_t, uint8_t, + uint16_t *, uint8_t); + +extern int +qla2x00_login_local_device(scsi_qla_host_t *, uint16_t, uint16_t *, uint8_t); + +extern int +qla2x00_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id); + +extern int +qla2x00_full_login_lip(scsi_qla_host_t *ha); + +extern int +qla2x00_get_id_list(scsi_qla_host_t *, void *, dma_addr_t, uint16_t *); + +#if 0 /* not yet needed */ +extern int +qla2x00_dump_ram(scsi_qla_host_t *, uint32_t, dma_addr_t, uint32_t); +#endif + +extern int +qla2x00_lun_reset(scsi_qla_host_t *, uint16_t, uint16_t); + +extern int +qla2x00_send_rnid_mbx(scsi_qla_host_t *, uint16_t, uint8_t, dma_addr_t, + size_t, uint16_t *); + +extern int +qla2x00_set_rnid_params_mbx(scsi_qla_host_t *, dma_addr_t, size_t, uint16_t *); + +extern int +qla2x00_get_rnid_params_mbx(scsi_qla_host_t *, dma_addr_t, size_t, uint16_t *); + +extern int +qla2x00_get_resource_cnts(scsi_qla_host_t *, uint16_t *, uint16_t *, uint16_t *, + uint16_t *); + +#if defined(QL_DEBUG_LEVEL_3) +extern int +qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map); +#endif + +/* + * Global Function Prototypes in qla_xioctl.c source file. + */ +extern void qla2x00_enqueue_aen(scsi_qla_host_t *, uint16_t, void *); +extern int qla2x00_alloc_ioctl_mem(scsi_qla_host_t *); +extern void qla2x00_free_ioctl_mem(scsi_qla_host_t *); +extern int qla2x00_get_ioctl_scrap_mem(scsi_qla_host_t *, void **, uint32_t); +extern void qla2x00_free_ioctl_scrap_mem(scsi_qla_host_t *); + +/* + * Global Function Prototypes in qla_inioctl.c source file. + */ +extern int qla2x00_read_nvram(scsi_qla_host_t *, EXT_IOCTL *, int); +extern int qla2x00_update_nvram(scsi_qla_host_t *, EXT_IOCTL *, int); +extern int qla2x00_send_loopback(scsi_qla_host_t *, EXT_IOCTL *, int); +extern int qla2x00_read_option_rom(scsi_qla_host_t *, EXT_IOCTL *, int); +extern int qla2x00_update_option_rom(scsi_qla_host_t *, EXT_IOCTL *, int); + + +/* + * Global Function Prototypes in qla_isr.c source file. + */ +extern irqreturn_t qla2x00_intr_handler(int, void *, struct pt_regs *); +extern void qla2x00_process_response_queue(struct scsi_qla_host *); + + +/* + * Global Function Prototypes in qla_sup.c source file. + */ +extern void qla2x00_lock_nvram_access(scsi_qla_host_t *); +extern void qla2x00_unlock_nvram_access(scsi_qla_host_t *); +extern uint16_t qla2x00_get_nvram_word(scsi_qla_host_t *, uint32_t); +extern void qla2x00_write_nvram_word(scsi_qla_host_t *, uint32_t, uint16_t); +extern void qla2x00_flash_enable(scsi_qla_host_t *); +extern void qla2x00_flash_disable(scsi_qla_host_t *); +extern uint8_t qla2x00_read_flash_byte(scsi_qla_host_t *, uint32_t); +extern uint8_t qla2x00_get_flash_manufacturer(scsi_qla_host_t *); +extern uint16_t qla2x00_get_flash_version(scsi_qla_host_t *); +extern uint16_t qla2x00_get_flash_image(scsi_qla_host_t *, uint8_t *); +extern uint16_t qla2x00_set_flash_image(scsi_qla_host_t *, uint8_t *); + +/* + * Global Function Prototypes in qla_dbg.c source file. + */ +extern void qla2100_fw_dump(scsi_qla_host_t *, int); +extern void qla2300_fw_dump(scsi_qla_host_t *, int); +extern void qla2100_ascii_fw_dump(scsi_qla_host_t *); +extern void qla2300_ascii_fw_dump(scsi_qla_host_t *); +extern void qla2x00_dump_regs(scsi_qla_host_t *); +extern void qla2x00_dump_buffer(uint8_t *, uint32_t); +extern void qla2x00_print_scsi_cmd(struct scsi_cmnd *); +extern void qla2x00_print_q_info(struct os_lun *); + +/* + * Global Function Prototypes in qla_ip.c source file. + */ +extern int qla2x00_ip_initialize(scsi_qla_host_t *); +extern int qla2x00_update_ip_device_data(scsi_qla_host_t *, fc_port_t *); +extern void qla2x00_ip_send_complete(scsi_qla_host_t *, uint32_t, uint16_t); +extern void qla2x00_ip_receive(scsi_qla_host_t *, sts_entry_t *); +extern void qla2x00_ip_receive_fastpost(scsi_qla_host_t *, uint16_t); +extern void qla2x00_ip_mailbox_iocb_done(scsi_qla_host_t *, struct mbx_entry *); + +/* + * Global Function Prototypes in qla_gs.c source file. + */ +extern int qla2x00_ga_nxt(scsi_qla_host_t *, fc_port_t *); +extern int qla2x00_gid_pt(scsi_qla_host_t *, sw_info_t *); +extern int qla2x00_gpn_id(scsi_qla_host_t *, sw_info_t *); +extern int qla2x00_gnn_id(scsi_qla_host_t *, sw_info_t *); +extern int qla2x00_gft_id(scsi_qla_host_t *, sw_info_t *); +extern int qla2x00_rft_id(scsi_qla_host_t *); +extern int qla2x00_rff_id(scsi_qla_host_t *); +extern int qla2x00_rnn_id(scsi_qla_host_t *); +extern int qla2x00_rsnn_nn(scsi_qla_host_t *); + +/* + * Global Function Prototypes in qla_rscn.c source file. + */ +extern fc_port_t *qla2x00_alloc_rscn_fcport(scsi_qla_host_t *, int); +extern int qla2x00_handle_port_rscn(scsi_qla_host_t *, uint32_t, fc_port_t *, + int); +extern void qla2x00_process_iodesc(scsi_qla_host_t *, struct mbx_entry *); +extern void qla2x00_cancel_io_descriptors(scsi_qla_host_t *); + +#endif /* _QLA_GBL_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qla_gs.c 830-ivtv/drivers/scsi/qla2xxx/qla_gs.c --- 000-virgin/drivers/scsi/qla2xxx/qla_gs.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qla_gs.c Thu Jan 8 10:22:00 2004 @@ -0,0 +1,677 @@ +/* + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ +#include "qla_os.h" + +#include "qla_def.h" + + +static inline ms_iocb_entry_t * +qla2x00_prep_ms_iocb(scsi_qla_host_t *, uint32_t, uint32_t); + +static inline struct ct_sns_req * +qla2x00_prep_ct_req(struct ct_sns_req *, uint16_t, uint16_t); + +/** + * qla2x00_prep_ms_iocb() - Prepare common MS IOCB fields for SNS CT query. + * @ha: HA context + * @req_size: request size in bytes + * @rsp_size: response size in bytes + * + * Returns a pointer to the @ha's ms_iocb. + */ +static inline ms_iocb_entry_t * +qla2x00_prep_ms_iocb(scsi_qla_host_t *ha, uint32_t req_size, uint32_t rsp_size) +{ + ms_iocb_entry_t *ms_pkt; + + ms_pkt = ha->ms_iocb; + memset(ms_pkt, 0, sizeof(ms_iocb_entry_t)); + + ms_pkt->entry_type = MS_IOCB_TYPE; + ms_pkt->entry_count = 1; + SET_TARGET_ID(ha, ms_pkt->loop_id, SIMPLE_NAME_SERVER); + ms_pkt->control_flags = __constant_cpu_to_le16(CF_READ | CF_HEAD_TAG); + ms_pkt->timeout = __constant_cpu_to_le16(25); + ms_pkt->cmd_dsd_count = __constant_cpu_to_le16(1); + ms_pkt->total_dsd_count = __constant_cpu_to_le16(2); + ms_pkt->rsp_bytecount = cpu_to_le32(rsp_size); + ms_pkt->req_bytecount = cpu_to_le32(req_size); + + ms_pkt->dseg_req_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); + ms_pkt->dseg_req_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); + ms_pkt->dseg_req_length = ms_pkt->req_bytecount; + + ms_pkt->dseg_rsp_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); + ms_pkt->dseg_rsp_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); + ms_pkt->dseg_rsp_length = ms_pkt->rsp_bytecount; + + return (ms_pkt); +} + +/** + * qla2x00_prep_ct_req() - Prepare common CT request fields for SNS query. + * @ct_req: CT request buffer + * @cmd: GS command + * @rsp_size: response size in bytes + * + * Returns a pointer to the intitialized @ct_req. + */ +static inline struct ct_sns_req * +qla2x00_prep_ct_req(struct ct_sns_req *ct_req, uint16_t cmd, uint16_t rsp_size) +{ + memset(ct_req, 0, sizeof(struct ct_sns_pkt)); + + ct_req->header.revision = 0x01; + ct_req->header.gs_type = 0xFC; + ct_req->header.gs_subtype = 0x02; + ct_req->command = cpu_to_be16(cmd); + ct_req->max_rsp_size = cpu_to_be16((rsp_size - 16) / 4); + + return (ct_req); +} + +/** + * qla2x00_ga_nxt() - SNS scan for fabric devices via GA_NXT command. + * @ha: HA context + * @fcport: fcport entry to updated + * + * Returns 0 on success. + */ +int +qla2x00_ga_nxt(scsi_qla_host_t *ha, fc_port_t *fcport) +{ + int rval; + + ms_iocb_entry_t *ms_pkt; + struct ct_sns_req *ct_req; + struct ct_sns_rsp *ct_rsp; + + /* Issue GA_NXT */ + /* Prepare common MS IOCB */ + ms_pkt = qla2x00_prep_ms_iocb(ha, GA_NXT_REQ_SIZE, GA_NXT_RSP_SIZE); + + /* Prepare CT request */ + ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GA_NXT_CMD, + GA_NXT_RSP_SIZE); + ct_rsp = &ha->ct_sns->p.rsp; + + /* Prepare CT arguments -- port_id */ + ct_req->req.port_id.port_id[0] = fcport->d_id.b.domain; + ct_req->req.port_id.port_id[1] = fcport->d_id.b.area; + ct_req->req.port_id.port_id[2] = fcport->d_id.b.al_pa; + + /* Execute MS IOCB */ + rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, + sizeof(ms_iocb_entry_t)); + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3(printk("scsi(%ld): GA_NXT issue IOCB failed (%d).\n", + ha->host_no, rval)); + } else if (ct_rsp->header.response != + __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) { + DEBUG2_3(printk("scsi(%ld): GA_NXT failed, rejected request, " + "ga_nxt_rsp:\n", ha->host_no)); + DEBUG2_3(qla2x00_dump_buffer((uint8_t *)&ct_rsp->header, + sizeof(struct ct_rsp_hdr))); + rval = QLA_FUNCTION_FAILED; + } else { + /* Populate fc_port_t entry. */ + fcport->d_id.b.domain = ct_rsp->rsp.ga_nxt.port_id[0]; + fcport->d_id.b.area = ct_rsp->rsp.ga_nxt.port_id[1]; + fcport->d_id.b.al_pa = ct_rsp->rsp.ga_nxt.port_id[2]; + + memcpy(fcport->node_name, ct_rsp->rsp.ga_nxt.node_name, + WWN_SIZE); + memcpy(fcport->port_name, ct_rsp->rsp.ga_nxt.port_name, + WWN_SIZE); + + if (ct_rsp->rsp.ga_nxt.port_type != NS_N_PORT_TYPE && + ct_rsp->rsp.ga_nxt.port_type != NS_NL_PORT_TYPE) + fcport->d_id.b.domain = 0xf0; + + DEBUG2_3(printk("scsi(%ld): GA_NXT entry - " + "nn %02x%02x%02x%02x%02x%02x%02x%02x " + "pn %02x%02x%02x%02x%02x%02x%02x%02x " + "portid=%02x%02x%02x.\n", + ha->host_no, + fcport->node_name[0], fcport->node_name[1], + fcport->node_name[2], fcport->node_name[3], + fcport->node_name[4], fcport->node_name[5], + fcport->node_name[6], fcport->node_name[7], + fcport->port_name[0], fcport->port_name[1], + fcport->port_name[2], fcport->port_name[3], + fcport->port_name[4], fcport->port_name[5], + fcport->port_name[6], fcport->port_name[7], + fcport->d_id.b.domain, fcport->d_id.b.area, + fcport->d_id.b.al_pa)); + } + + return (rval); +} + +/** + * qla2x00_gid_pt() - SNS scan for fabric devices via GID_PT command. + * @ha: HA context + * @list: switch info entries to populate + * + * NOTE: Non-Nx_Ports are not requested. + * + * Returns 0 on success. + */ +int +qla2x00_gid_pt(scsi_qla_host_t *ha, sw_info_t *list) +{ + int rval; + uint16_t i; + + ms_iocb_entry_t *ms_pkt; + struct ct_sns_req *ct_req; + struct ct_sns_rsp *ct_rsp; + + struct ct_sns_gid_pt_data *gid_data; + + gid_data = NULL; + + /* Issue GID_PT */ + /* Prepare common MS IOCB */ + ms_pkt = qla2x00_prep_ms_iocb(ha, GID_PT_REQ_SIZE, GID_PT_RSP_SIZE); + + /* Prepare CT request */ + ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GID_PT_CMD, + GID_PT_RSP_SIZE); + ct_rsp = &ha->ct_sns->p.rsp; + + /* Prepare CT arguments -- port_type */ + ct_req->req.gid_pt.port_type = NS_NX_PORT_TYPE; + + /* Execute MS IOCB */ + rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, + sizeof(ms_iocb_entry_t)); + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3(printk("scsi(%ld): GID_PT issue IOCB failed (%d).\n", + ha->host_no, rval)); + } else if (ct_rsp->header.response != + __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) { + DEBUG2_3(printk("scsi(%ld): GID_PT failed, rejected request, " + "gid_pt_rsp:\n", ha->host_no)); + DEBUG2_3(qla2x00_dump_buffer((uint8_t *)&ct_rsp->header, + sizeof(struct ct_rsp_hdr))); + rval = QLA_FUNCTION_FAILED; + } else { + /* Set port IDs in switch info list. */ + for (i = 0; i < MAX_FIBRE_DEVICES; i++) { + gid_data = &ct_rsp->rsp.gid_pt.entries[i]; + list[i].d_id.b.domain = gid_data->port_id[0]; + list[i].d_id.b.area = gid_data->port_id[1]; + list[i].d_id.b.al_pa = gid_data->port_id[2]; + + /* Last one exit. */ + if (gid_data->control_byte & BIT_7) { + list[i].d_id.b.rsvd_1 = gid_data->control_byte; + break; + } + } + + /* + * If we've used all available slots, then the switch is + * reporting back more devices that we can handle with this + * single call. Return a failed status, and let GA_NXT handle + * the overload. + */ + if (i == MAX_FIBRE_DEVICES) + rval = QLA_FUNCTION_FAILED; + } + + return (rval); +} + +/** + * qla2x00_gpn_id() - SNS Get Port Name (GPN_ID) query. + * @ha: HA context + * @list: switch info entries to populate + * + * Returns 0 on success. + */ +int +qla2x00_gpn_id(scsi_qla_host_t *ha, sw_info_t *list) +{ + int rval; + uint16_t i; + + ms_iocb_entry_t *ms_pkt; + struct ct_sns_req *ct_req; + struct ct_sns_rsp *ct_rsp; + + for (i = 0; i < MAX_FIBRE_DEVICES; i++) { + /* Issue GPN_ID */ + /* Prepare common MS IOCB */ + ms_pkt = qla2x00_prep_ms_iocb(ha, GPN_ID_REQ_SIZE, + GPN_ID_RSP_SIZE); + + /* Prepare CT request */ + ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GPN_ID_CMD, + GPN_ID_RSP_SIZE); + ct_rsp = &ha->ct_sns->p.rsp; + + /* Prepare CT arguments -- port_id */ + ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain; + ct_req->req.port_id.port_id[1] = list[i].d_id.b.area; + ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa; + + /* Execute MS IOCB */ + rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, + sizeof(ms_iocb_entry_t)); + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3(printk("scsi(%ld): GPN_ID issue IOCB failed " + "(%d).\n", ha->host_no, rval)); + } else if (ct_rsp->header.response != + __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) { + DEBUG2_3(printk("scsi(%ld): GPN_ID failed, rejected " + "request, gpn_id_rsp:\n", ha->host_no)); + DEBUG2_3(qla2x00_dump_buffer((uint8_t *)&ct_rsp->header, + sizeof(struct ct_rsp_hdr))); + rval = QLA_FUNCTION_FAILED; + } else { + /* Save portname */ + memcpy(list[i].port_name, + ct_rsp->rsp.gpn_id.port_name, WWN_SIZE); + } + + /* Last device exit. */ + if (list[i].d_id.b.rsvd_1 != 0) + break; + } + + return (rval); +} + +/** + * qla2x00_gnn_id() - SNS Get Node Name (GPN_ID) query. + * @ha: HA context + * @list: switch info entries to populate + * + * Returns 0 on success. + */ +int +qla2x00_gnn_id(scsi_qla_host_t *ha, sw_info_t *list) +{ + int rval; + uint16_t i; + + ms_iocb_entry_t *ms_pkt; + struct ct_sns_req *ct_req; + struct ct_sns_rsp *ct_rsp; + + for (i = 0; i < MAX_FIBRE_DEVICES; i++) { + /* Issue GNN_ID */ + /* Prepare common MS IOCB */ + ms_pkt = qla2x00_prep_ms_iocb(ha, GNN_ID_REQ_SIZE, + GNN_ID_RSP_SIZE); + + /* Prepare CT request */ + ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GNN_ID_CMD, + GNN_ID_RSP_SIZE); + ct_rsp = &ha->ct_sns->p.rsp; + + /* Prepare CT arguments -- port_id */ + ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain; + ct_req->req.port_id.port_id[1] = list[i].d_id.b.area; + ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa; + + /* Execute MS IOCB */ + rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, + sizeof(ms_iocb_entry_t)); + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3(printk("scsi(%ld): GNN_ID issue IOCB failed " + "(%d).\n", ha->host_no, rval)); + } else if (ct_rsp->header.response != + __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) { + DEBUG2_3(printk("scsi(%ld): GNN_ID failed, rejected " + "request, gnn_id_rsp:\n", ha->host_no)); + DEBUG2_3(qla2x00_dump_buffer((uint8_t *)&ct_rsp->header, + sizeof(struct ct_rsp_hdr))); + rval = QLA_FUNCTION_FAILED; + } else { + /* Save nodename */ + memcpy(list[i].node_name, + ct_rsp->rsp.gnn_id.node_name, WWN_SIZE); + + DEBUG2_3(printk("scsi(%ld): GID_PT entry - " + "nn %02x%02x%02x%02x%02x%02x%02x%02x " + "pn %02x%02x%02x%02x%02x%02x%02x%02x " + "portid=%02x%02x%02x.\n", + ha->host_no, + list[i].node_name[0], list[i].node_name[1], + list[i].node_name[2], list[i].node_name[3], + list[i].node_name[4], list[i].node_name[5], + list[i].node_name[6], list[i].node_name[7], + list[i].port_name[0], list[i].port_name[1], + list[i].port_name[2], list[i].port_name[3], + list[i].port_name[4], list[i].port_name[5], + list[i].port_name[6], list[i].port_name[7], + list[i].d_id.b.domain, list[i].d_id.b.area, + list[i].d_id.b.al_pa)); + } + + /* Last device exit. */ + if (list[i].d_id.b.rsvd_1 != 0) + break; + } + + return (rval); +} + +/** + * qla2x00_gft_id() - SNS Get FC-4 TYPEs (GFT_ID) query. + * @ha: HA context + * @list: switch info entries to populate + * + * Returns 0 on success. + */ +int +qla2x00_gft_id(scsi_qla_host_t *ha, sw_info_t *list) +{ + int rval; + uint16_t i; + + ms_iocb_entry_t *ms_pkt; + struct ct_sns_req *ct_req; + struct ct_sns_rsp *ct_rsp; + + for (i = 0; i < MAX_FIBRE_DEVICES; i++) { + /* Issue GFT_ID */ + /* Prepare common MS IOCB */ + ms_pkt = qla2x00_prep_ms_iocb(ha, GFT_ID_REQ_SIZE, + GFT_ID_RSP_SIZE); + + /* Prepare CT request */ + ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GFT_ID_CMD, + GFT_ID_RSP_SIZE); + ct_rsp = &ha->ct_sns->p.rsp; + + /* Prepare CT arguments -- port_id */ + ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain; + ct_req->req.port_id.port_id[1] = list[i].d_id.b.area; + ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa; + + /* Execute MS IOCB */ + rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, + sizeof(ms_iocb_entry_t)); + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3(printk("scsi(%ld): GFT_ID issue IOCB failed " + "(%d).\n", ha->host_no, rval)); + } else if (ct_rsp->header.response != + __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) { + DEBUG2_3(printk("scsi(%ld): GFT_ID failed, rejected " + "request, gft_id_rsp:\n", ha->host_no)); + DEBUG2_3(qla2x00_dump_buffer((uint8_t *)&ct_rsp->header, + sizeof(struct ct_rsp_hdr))); + rval = QLA_FUNCTION_FAILED; + } else { + /* FCP-3 check necessary? No, assume FCP-3 */ + /*if (ct_rsp->rsp.gft_id.fc4_types[2] & 0x01)*/ + list[i].type = SW_TYPE_SCSI; + if (ct_rsp->rsp.gft_id.fc4_types[3] & 0x20) + list[i].type |= SW_TYPE_IP; + } + + /* Last device exit. */ + if (list[i].d_id.b.rsvd_1 != 0) + break; + } + + return (rval); +} + +/** + * qla2x00_rft_id() - SNS Register FC-4 TYPEs (RFT_ID) supported by the HBA. + * @ha: HA context + * + * Returns 0 on success. + */ +int +qla2x00_rft_id(scsi_qla_host_t *ha) +{ + int rval; + + ms_iocb_entry_t *ms_pkt; + struct ct_sns_req *ct_req; + struct ct_sns_rsp *ct_rsp; + + /* Issue RFT_ID */ + /* Prepare common MS IOCB */ + ms_pkt = qla2x00_prep_ms_iocb(ha, RFT_ID_REQ_SIZE, RFT_ID_RSP_SIZE); + + /* Prepare CT request */ + ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RFT_ID_CMD, + RFT_ID_RSP_SIZE); + ct_rsp = &ha->ct_sns->p.rsp; + + /* Prepare CT arguments -- port_id, FC-4 types */ + ct_req->req.rft_id.port_id[0] = ha->d_id.b.domain; + ct_req->req.rft_id.port_id[1] = ha->d_id.b.area; + ct_req->req.rft_id.port_id[2] = ha->d_id.b.al_pa; + + ct_req->req.rft_id.fc4_types[2] = 0x01; /* FCP-3 */ + ha->active_fc4_types = EXT_DEF_FC4_TYPE_SCSI; + + /* Execute MS IOCB */ + rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, + sizeof(ms_iocb_entry_t)); + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3(printk("scsi(%ld): RFT_ID issue IOCB failed (%d).\n", + ha->host_no, rval)); + } else if (ct_rsp->header.response != + __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) { + DEBUG2_3(printk("scsi(%ld): RFT_ID failed, rejected " + "request, rft_id_rsp:\n", ha->host_no)); + DEBUG2_3(qla2x00_dump_buffer((uint8_t *)&ct_rsp->header, + sizeof(struct ct_rsp_hdr))); + rval = QLA_FUNCTION_FAILED; + } else { + DEBUG2(printk("scsi(%ld): RFT_ID exiting normally.\n", + ha->host_no)); + } + + return (rval); +} + +/** + * qla2x00_rff_id() - SNS Register FC-4 Features (RFF_ID) supported by the HBA. + * @ha: HA context + * + * Returns 0 on success. + */ +int +qla2x00_rff_id(scsi_qla_host_t *ha) +{ + int rval; + + ms_iocb_entry_t *ms_pkt; + struct ct_sns_req *ct_req; + struct ct_sns_rsp *ct_rsp; + + /* Issue RFF_ID */ + /* Prepare common MS IOCB */ + ms_pkt = qla2x00_prep_ms_iocb(ha, RFF_ID_REQ_SIZE, RFF_ID_RSP_SIZE); + + /* Prepare CT request */ + ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RFF_ID_CMD, + RFF_ID_RSP_SIZE); + ct_rsp = &ha->ct_sns->p.rsp; + + /* Prepare CT arguments -- port_id, FC-4 feature, FC-4 type */ + ct_req->req.rff_id.port_id[0] = ha->d_id.b.domain; + ct_req->req.rff_id.port_id[1] = ha->d_id.b.area; + ct_req->req.rff_id.port_id[2] = ha->d_id.b.al_pa; + + ct_req->req.rff_id.fc4_type = 0x08; /* SCSI - FCP */ + + /* Execute MS IOCB */ + rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, + sizeof(ms_iocb_entry_t)); + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3(printk("scsi(%ld): RFF_ID issue IOCB failed (%d).\n", + ha->host_no, rval)); + } else if (ct_rsp->header.response != + __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) { + DEBUG2_3(printk("scsi(%ld): RFF_ID failed, rejected " + "request, rff_id_rsp:\n", ha->host_no)); + DEBUG2_3(qla2x00_dump_buffer((uint8_t *)&ct_rsp->header, + sizeof(struct ct_rsp_hdr))); + rval = QLA_FUNCTION_FAILED; + } else { + DEBUG2(printk("scsi(%ld): RFF_ID exiting normally.\n", + ha->host_no)); + } + + return (rval); +} + +/** + * qla2x00_rnn_id() - SNS Register Node Name (RNN_ID) of the HBA. + * @ha: HA context + * + * Returns 0 on success. + */ +int +qla2x00_rnn_id(scsi_qla_host_t *ha) +{ + int rval; + + ms_iocb_entry_t *ms_pkt; + struct ct_sns_req *ct_req; + struct ct_sns_rsp *ct_rsp; + + /* Issue RNN_ID */ + /* Prepare common MS IOCB */ + ms_pkt = qla2x00_prep_ms_iocb(ha, RNN_ID_REQ_SIZE, RNN_ID_RSP_SIZE); + + /* Prepare CT request */ + ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RNN_ID_CMD, + RNN_ID_RSP_SIZE); + ct_rsp = &ha->ct_sns->p.rsp; + + /* Prepare CT arguments -- port_id, node_name */ + ct_req->req.rnn_id.port_id[0] = ha->d_id.b.domain; + ct_req->req.rnn_id.port_id[1] = ha->d_id.b.area; + ct_req->req.rnn_id.port_id[2] = ha->d_id.b.al_pa; + + memcpy(ct_req->req.rnn_id.node_name, ha->init_cb->node_name, WWN_SIZE); + + /* Execute MS IOCB */ + rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, + sizeof(ms_iocb_entry_t)); + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3(printk("scsi(%ld): RNN_ID issue IOCB failed (%d).\n", + ha->host_no, rval)); + } else if (ct_rsp->header.response != + __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) { + DEBUG2_3(printk("scsi(%ld): RNN_ID failed, rejected " + "request, rnn_id_rsp:\n", ha->host_no)); + DEBUG2_3(qla2x00_dump_buffer((uint8_t *)&ct_rsp->header, + sizeof(struct ct_rsp_hdr))); + rval = QLA_FUNCTION_FAILED; + } else { + DEBUG2(printk("scsi(%ld): RNN_ID exiting normally.\n", + ha->host_no)); + } + + return (rval); +} + +/** + * qla2x00_rsnn_nn() - SNS Register Symbolic Node Name (RSNN_NN) of the HBA. + * @ha: HA context + * + * Returns 0 on success. + */ +int +qla2x00_rsnn_nn(scsi_qla_host_t *ha) +{ + int rval; + uint8_t *snn; + uint8_t version[20]; + + ms_iocb_entry_t *ms_pkt; + struct ct_sns_req *ct_req; + struct ct_sns_rsp *ct_rsp; + + /* Issue RSNN_NN */ + /* Prepare common MS IOCB */ + /* Request size adjusted after CT preparation */ + ms_pkt = qla2x00_prep_ms_iocb(ha, 0, RSNN_NN_RSP_SIZE); + + /* Prepare CT request */ + ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RSNN_NN_CMD, + RSNN_NN_RSP_SIZE); + ct_rsp = &ha->ct_sns->p.rsp; + + /* Prepare CT arguments -- node_name, symbolic node_name, size */ + memcpy(ct_req->req.rsnn_nn.node_name, ha->init_cb->node_name, WWN_SIZE); + + /* Prepare the Symbolic Node Name */ + /* Board type */ + snn = ct_req->req.rsnn_nn.sym_node_name; + strcpy(snn, ha->model_number); + /* Firmware version */ + strcat(snn, " FW:v"); + sprintf(version, "%d.%02d.%02d", ha->fw_major_version, + ha->fw_minor_version, ha->fw_subminor_version); + strcat(snn, version); + /* Driver version */ + strcat(snn, " DVR:v"); + strcat(snn, qla2x00_version_str); + + /* Calculate SNN length */ + ct_req->req.rsnn_nn.name_len = (uint8_t)strlen(snn); + + /* Update MS IOCB request */ + ms_pkt->req_bytecount = + cpu_to_le32(24 + 1 + ct_req->req.rsnn_nn.name_len); + ms_pkt->dseg_req_length = ms_pkt->req_bytecount; + + /* Execute MS IOCB */ + rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, + sizeof(ms_iocb_entry_t)); + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3(printk("scsi(%ld): RSNN_NN issue IOCB failed (%d).\n", + ha->host_no, rval)); + } else if (ct_rsp->header.response != + __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) { + DEBUG2_3(printk("scsi(%ld): RSNN_NN failed, rejected " + "request, rsnn_id_rsp:\n", ha->host_no)); + DEBUG2_3(qla2x00_dump_buffer((uint8_t *)&ct_rsp->header, + sizeof(struct ct_rsp_hdr))); + rval = QLA_FUNCTION_FAILED; + } else { + DEBUG2(printk("scsi(%ld): RSNN_NN exiting normally.\n", + ha->host_no)); + } + + return (rval); +} diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qla_inioct.c 830-ivtv/drivers/scsi/qla2xxx/qla_inioct.c --- 000-virgin/drivers/scsi/qla2xxx/qla_inioct.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qla_inioct.c Thu Jan 8 10:22:00 2004 @@ -0,0 +1,483 @@ +/****************************************************************************** + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + ******************************************************************************/ + +#include "qla_os.h" +#include "qla_def.h" + +#include "inioct.h" + +extern int qla2x00_loopback_test(scsi_qla_host_t *ha, INT_LOOPBACK_REQ *req, + uint16_t *ret_mb); + +int qla2x00_read_nvram(scsi_qla_host_t *, EXT_IOCTL *, int); +int qla2x00_update_nvram(scsi_qla_host_t *, EXT_IOCTL *, int); +int qla2x00_send_loopback(scsi_qla_host_t *, EXT_IOCTL *, int); +int qla2x00_read_option_rom(scsi_qla_host_t *, EXT_IOCTL *, int); +int qla2x00_update_option_rom(scsi_qla_host_t *, EXT_IOCTL *, int); + +int +qla2x00_read_nvram(scsi_qla_host_t *ha, EXT_IOCTL *pext, int mode) +{ + int ret = 0; + char *ptmp_buf; + uint16_t cnt; + uint16_t *wptr; + uint32_t transfer_size; + + DEBUG9(printk("qla2x00_read_nvram: entered.\n");) + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&ptmp_buf, + sizeof(nvram_t))) { + /* not enough memory */ + pext->Status = EXT_STATUS_NO_MEMORY; + DEBUG9_10(printk("%s(%ld): inst=%ld scrap not big enough. " + "size requested=%d.\n", + __func__, ha->host_no, ha->instance, + sizeof(nvram_t));) + return (ret); + } + + if (pext->ResponseLen < sizeof(nvram_t)) + transfer_size = pext->ResponseLen / 2; + else + transfer_size = sizeof(nvram_t) / 2; + + /* Dump NVRAM. */ + qla2x00_lock_nvram_access(ha); + + wptr = (uint16_t *)ptmp_buf; + for (cnt = 0; cnt < transfer_size; cnt++) { + *wptr = cpu_to_le16(qla2x00_get_nvram_word(ha, + cnt+ha->nvram_base)); + wptr++; + } + qla2x00_unlock_nvram_access(ha); + + ret = copy_to_user((uint8_t *)pext->ResponseAdr, ptmp_buf, + transfer_size * 2); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR copy rsp buffer.\n", + __func__, ha->host_no, ha->instance);) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + + qla2x00_free_ioctl_scrap_mem(ha); + + DEBUG9(printk("qla2x00_read_nvram: exiting.\n");) + + return (ret); +} + +/* + * qla2x00_update_nvram + * Write data to NVRAM. + * + * Input: + * ha = adapter block pointer. + * pext = pointer to driver internal IOCTL structure. + * + * Returns: + * + * Context: + * Kernel context. + */ +int +qla2x00_update_nvram(scsi_qla_host_t *ha, EXT_IOCTL *pext, int mode) +{ + device_reg_t *reg = ha->iobase; + uint8_t i, cnt; + uint8_t *usr_tmp, *kernel_tmp; + nvram_t *pnew_nv; + uint16_t *wptr; + uint16_t data; + uint32_t transfer_size; + uint8_t chksum = 0; + int ret = 0; + + DEBUG9(printk("qla2x00_update_nvram: entered.\n");) + + if (pext->RequestLen < sizeof(nvram_t)) + transfer_size = pext->RequestLen; + else + transfer_size = sizeof(nvram_t); + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&pnew_nv, + sizeof(nvram_t))) { + /* not enough memory */ + pext->Status = EXT_STATUS_NO_MEMORY; + DEBUG9_10(printk("%s(%ld): inst=%ld scrap not big enough. " + "size requested=%ld.\n", + __func__, ha->host_no, ha->instance, + (ulong)sizeof(nvram_t));) + return (ret); + } + + /* Read from user buffer */ + kernel_tmp = (uint8_t *)pnew_nv; + usr_tmp = (uint8_t *)pext->RequestAdr; + + ret = verify_area(VERIFY_READ, (void *)usr_tmp, transfer_size); + if (ret) { + DEBUG9_10(printk( + "qla2x00_update_nvram: ERROR in buffer verify READ. " + "RequestAdr=%p\n", pext->RequestAdr);) + qla2x00_free_ioctl_scrap_mem(ha); + return ret; + } + + copy_from_user(kernel_tmp, usr_tmp, transfer_size); + + kernel_tmp = (uint8_t *)pnew_nv; + + /* we need to checksum the nvram */ + for (i = 0; i < sizeof(nvram_t) - 1; i++) { + chksum += *kernel_tmp; + kernel_tmp++; + } + + chksum = ~chksum + 1; + + *kernel_tmp = chksum; + + /* Write to NVRAM */ + if (IS_QLA2312(ha) || IS_QLA2322(ha)) { + data = RD_REG_WORD(®->nvram); + while (data & NVR_BUSY) { + udelay(100); + data = RD_REG_WORD(®->nvram); + } + + /* Lock resource */ + WRT_REG_WORD(®->u.isp2300.host_semaphore, 0x1); + udelay(5); + data = RD_REG_WORD(®->u.isp2300.host_semaphore); + while ((data & BIT_0) == 0) { + /* Lock failed */ + udelay(100); + WRT_REG_WORD(®->u.isp2300.host_semaphore, 0x1); + udelay(5); + data = RD_REG_WORD(®->u.isp2300.host_semaphore); + } + } + + wptr = (uint16_t *)pnew_nv; + for (cnt = 0; cnt < transfer_size / 2; cnt++) { + data = cpu_to_le16(*wptr++); + qla2x00_write_nvram_word(ha, cnt+ha->nvram_base, data); + } + + /* Unlock resource */ + if (IS_QLA2312(ha) || IS_QLA2322(ha)) + WRT_REG_WORD(®->u.isp2300.host_semaphore, 0); + + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + + qla2x00_free_ioctl_scrap_mem(ha); + + DEBUG9(printk("qla2x00_update_nvram: exiting.\n");) + + return 0; +} + +int +qla2x00_send_loopback(scsi_qla_host_t *ha, EXT_IOCTL *pext, int mode) +{ + int status; + uint16_t ret_mb[MAILBOX_REGISTER_COUNT]; + INT_LOOPBACK_REQ req; + INT_LOOPBACK_RSP rsp; + + DEBUG9(printk("qla2x00_send_loopback: entered.\n");) + + + if (pext->RequestLen != sizeof(INT_LOOPBACK_REQ)) { + pext->Status = EXT_STATUS_INVALID_PARAM; + DEBUG9_10(printk( + "qla2x00_send_loopback: invalid RequestLen =%d.\n", + pext->RequestLen);) + return pext->Status; + } + + if (pext->ResponseLen != sizeof(INT_LOOPBACK_RSP)) { + pext->Status = EXT_STATUS_INVALID_PARAM; + DEBUG9_10(printk( + "qla2x00_send_loopback: invalid ResponseLen =%d.\n", + pext->ResponseLen);) + return pext->Status; + } + + status = verify_area(VERIFY_READ, (void *)pext->RequestAdr, + pext->RequestLen); + if (status) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("qla2x00_send_loopback: ERROR verify read of " + "request buffer.\n");) + return pext->Status; + } + + copy_from_user((uint8_t *)&req, (uint8_t *)pext->RequestAdr, + pext->RequestLen); + + status = verify_area(VERIFY_READ, (void *)pext->ResponseAdr, + pext->ResponseLen); + if (status) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("qla2x00_send_loopback: ERROR verify read of " + "response buffer.\n");) + return pext->Status; + } + + copy_from_user((uint8_t *)&rsp, (uint8_t *)pext->ResponseAdr, + pext->ResponseLen); + + if (req.TransferCount > req.BufferLength || + req.TransferCount > rsp.BufferLength) { + + /* Buffer lengths not large enough. */ + pext->Status = EXT_STATUS_INVALID_PARAM; + + DEBUG9_10(printk( + "qla2x00_send_loopback: invalid TransferCount =%d. " + "req BufferLength =%d rspBufferLength =%d.\n", + req.TransferCount, req.BufferLength, rsp.BufferLength);) + + return pext->Status; + } + + status = verify_area(VERIFY_READ, (void *)req.BufferAddress, + req.TransferCount); + if (status) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("qla2x00_send_loopback: ERROR verify read of " + "user loopback data buffer.\n");) + return pext->Status; + } + + copy_from_user((uint8_t *)ha->ioctl_mem, (uint8_t *)req.BufferAddress, + req.TransferCount); + + DEBUG9(printk("qla2x00_send_loopback: req -- bufadr=%p, buflen=%x, " + "xfrcnt=%x, rsp -- bufadr=%p, buflen=%x.\n", + req.BufferAddress, req.BufferLength, req.TransferCount, + rsp.BufferAddress, rsp.BufferLength);) + + /* + * AV - the caller of this IOCTL expects the FW to handle + * a loopdown situation and return a good status for the + * call function and a LOOPDOWN status for the test operations + */ + /*if (atomic_read(&ha->loop_state) != LOOP_READY || */ + if (test_bit(CFG_ACTIVE, &ha->cfg_flags) || + test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) || + test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) || ha->dpc_active) { + + pext->Status = EXT_STATUS_BUSY; + DEBUG9_10(printk("qla2x00_send_loopback(%ld): " + "loop not ready.\n", ha->host_no);) + return pext->Status; + } + + if (ha->current_topology == ISP_CFG_F) { + if (IS_QLA2100(ha) || IS_QLA2200(ha)) { + pext->Status = EXT_STATUS_INVALID_REQUEST ; + DEBUG9_10(printk("qla2x00_send_loopback: ERROR " + "command only supported for QLA23xx.\n");) + return 0; + } + status = qla2x00_echo_test(ha, &req, ret_mb); + } else { + status = qla2x00_loopback_test(ha, &req, ret_mb); + } + + if (status) { + if (status == QLA_FUNCTION_TIMEOUT ) { + pext->Status = EXT_STATUS_BUSY; + DEBUG9_10(printk("qla2x00_send_loopback: ERROR " + "command timed out.\n");) + return 0; + } else { + /* EMPTY. Just proceed to copy back mailbox reg + * values for users to interpret. + */ + DEBUG10(printk("qla2x00_send_loopback: ERROR " + "loopback command failed 0x%x.\n", ret_mb[0]);) + } + } + + status = verify_area(VERIFY_WRITE, (void *)rsp.BufferAddress, + req.TransferCount); + if (status) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("qla2x00_send_loopback: ERROR verify " + "write of return data buffer.\n");) + return status; + } + + DEBUG9(printk("qla2x00_send_loopback: loopback mbx cmd ok. " + "copying data.\n");) + + /* put loopback return data in user buffer */ + copy_to_user((uint8_t *)rsp.BufferAddress, + (uint8_t *)ha->ioctl_mem, req.TransferCount); + + rsp.CompletionStatus = ret_mb[0]; + if (ha->current_topology == ISP_CFG_F) { + rsp.CommandSent = INT_DEF_LB_ECHO_CMD; + } else { + if (rsp.CompletionStatus == INT_DEF_LB_COMPLETE || + rsp.CompletionStatus == INT_DEF_LB_CMD_ERROR) { + rsp.CrcErrorCount = ret_mb[1]; + rsp.DisparityErrorCount = ret_mb[2]; + rsp.FrameLengthErrorCount = ret_mb[3]; + rsp.IterationCountLastError = + (ret_mb[19] << 16) | ret_mb[18]; + } + } + + status = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr, + pext->ResponseLen); + if (status) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("qla2x00_send_loopback: ERROR verify " + "write of response buffer.\n");) + return pext->Status; + } + + copy_to_user((uint8_t *)pext->ResponseAdr, (uint8_t *)&rsp, + pext->ResponseLen); + + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + + DEBUG9(printk("qla2x00_send_loopback: exiting.\n");) + + return pext->Status; +} + +int qla2x00_read_option_rom(scsi_qla_host_t *ha, EXT_IOCTL *pext, int mode) +{ + uint8_t *usr_tmp; + uint32_t addr; + uint32_t midpoint; + uint32_t transfer_size; + uint8_t data; + device_reg_t *reg = ha->iobase; + unsigned long cpu_flags; + + DEBUG9(printk("%s: entered.\n", __func__);) + + if (pext->ResponseLen != FLASH_IMAGE_SIZE) { + pext->Status = EXT_STATUS_BUFFER_TOO_SMALL; + return (1); + } + + transfer_size = FLASH_IMAGE_SIZE; + + midpoint = FLASH_IMAGE_SIZE / 2; + usr_tmp = (uint8_t *)pext->ResponseAdr; + + /* Dump FLASH. */ + spin_lock_irqsave(&ha->hardware_lock, cpu_flags); + qla2x00_flash_enable(ha); + WRT_REG_WORD(®->nvram, 0); + for (addr = 0; addr < transfer_size; addr++, usr_tmp++) { + if (addr == midpoint) + WRT_REG_WORD(®->nvram, NVR_SELECT); + + data = qla2x00_read_flash_byte(ha, addr); + if (addr % 100) + udelay(10); + __put_user(data, usr_tmp); + } + qla2x00_flash_disable(ha); + spin_unlock_irqrestore(&ha->hardware_lock, cpu_flags); + + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + + DEBUG9(printk("%s: exiting.\n", __func__);) + + return (0); +} + +int qla2x00_update_option_rom(scsi_qla_host_t *ha, EXT_IOCTL *pext, int mode) +{ + int ret; + uint8_t *usr_tmp; + uint8_t *kern_tmp; + uint16_t status; + unsigned long cpu_flags; + + DEBUG9(printk("%s: entered.\n", __func__);) + + if (pext->RequestLen != FLASH_IMAGE_SIZE) { + pext->Status = EXT_STATUS_COPY_ERR; + return (1); + } + + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + + /* Read from user buffer */ + usr_tmp = (uint8_t *)pext->RequestAdr; + ret = verify_area(VERIFY_READ, (void *)usr_tmp, FLASH_IMAGE_SIZE); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s: ERROR in buffer verify READ. " + "RequestAdr=%p\n", + __func__, pext->RequestAdr);) + return (ret); + } + + kern_tmp = (uint8_t *)KMEM_ZALLOC(FLASH_IMAGE_SIZE, 30); + if (kern_tmp == NULL) { + pext->Status = EXT_STATUS_COPY_ERR; + printk(KERN_WARNING + "%s: ERROR in flash allocation.\n", __func__); + return (1); + } + copy_from_user(kern_tmp, usr_tmp, FLASH_IMAGE_SIZE); + + /* Go with update */ + spin_lock_irqsave(&ha->hardware_lock, cpu_flags); + status = qla2x00_set_flash_image(ha, kern_tmp); + spin_unlock_irqrestore(&ha->hardware_lock, cpu_flags); + + /* Schedule DPC to restart the RISC */ + set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); + up(ha->dpc_wait); + + KMEM_FREE(kern_tmp, FLASH_IMAGE_SIZE); + + if (status) { + ret = 1; + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s: ERROR updating flash.\n", __func__);) + } + + DEBUG9(printk("%s: exiting.\n", __func__);) + + return (ret); +} diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qla_init.c 830-ivtv/drivers/scsi/qla2xxx/qla_init.c --- 000-virgin/drivers/scsi/qla2xxx/qla_init.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qla_init.c Thu Jan 8 10:22:00 2004 @@ -0,0 +1,4313 @@ +/* + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ +#include "qla_os.h" +#include "qla_def.h" +#include "qla_devtbl.h" + +/* +* QLogic ISP2x00 Hardware Support Function Prototypes. +*/ +static int qla2x00_pci_config(scsi_qla_host_t *); +static int qla2x00_isp_firmware(scsi_qla_host_t *); +static void qla2x00_reset_chip(scsi_qla_host_t *); +static int qla2x00_chip_diag(scsi_qla_host_t *); +static int qla2x00_setup_chip(scsi_qla_host_t *); +static void qla2x00_init_response_q_entries(scsi_qla_host_t *); +static int qla2x00_init_rings(scsi_qla_host_t *); +static int qla2x00_fw_ready(scsi_qla_host_t *); +static int qla2x00_configure_hba(scsi_qla_host_t *); +static int qla2x00_nvram_config(scsi_qla_host_t *); +static void qla2x00_init_tgt_map(scsi_qla_host_t *); +static int qla2x00_configure_loop(scsi_qla_host_t *); +static int qla2x00_configure_local_loop(scsi_qla_host_t *); +static void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *); +static void qla2x00_lun_discovery(scsi_qla_host_t *, fc_port_t *); +static int qla2x00_rpt_lun_discovery(scsi_qla_host_t *, fc_port_t *, + inq_cmd_rsp_t *, dma_addr_t); +static int qla2x00_report_lun(scsi_qla_host_t *, fc_port_t *, + rpt_lun_cmd_rsp_t *, dma_addr_t); +static fc_lun_t *qla2x00_cfg_lun(scsi_qla_host_t *, fc_port_t *, uint16_t, + inq_cmd_rsp_t *, dma_addr_t); +static fc_lun_t * qla2x00_add_lun(fc_port_t *, uint16_t); +static int qla2x00_inquiry(scsi_qla_host_t *, fc_port_t *, uint16_t, + inq_cmd_rsp_t *, dma_addr_t); +static int qla2x00_configure_fabric(scsi_qla_host_t *); +static int qla2x00_find_all_fabric_devs(scsi_qla_host_t *, struct list_head *); +static int qla2x00_device_resync(scsi_qla_host_t *); +static int qla2x00_fabric_dev_login(scsi_qla_host_t *, fc_port_t *, + uint16_t *); +static void qla2x00_config_os(scsi_qla_host_t *ha); +static uint16_t qla2x00_fcport_bind(scsi_qla_host_t *ha, fc_port_t *fcport); +static os_lun_t * qla2x00_fclun_bind(scsi_qla_host_t *, fc_port_t *, + fc_lun_t *); +static void qla2x00_lun_free(scsi_qla_host_t *, uint16_t, uint16_t); +static void qla2x00_get_lun_mask_from_config(scsi_qla_host_t *, fc_port_t *, + uint16_t, uint16_t); + +static int qla2x00_bstr_to_hex(char *, uint8_t *, int); +static int qla2x00_find_propname(scsi_qla_host_t *, + char *, char *, char *, int); +static int qla2x00_get_prop_16chars(scsi_qla_host_t *, + char *, char *, char *); +static void qla2x00_get_properties(scsi_qla_host_t *, char *); + +static void qla2x00_cfg_persistent_binding(scsi_qla_host_t *); +static os_tgt_t *qla2x00_persistent_bind(scsi_qla_host_t *, uint8_t *, + uint8_t *, port_id_t *, uint16_t); + +static int qla2x00_restart_isp(scsi_qla_host_t *); +static void qla2x00_reset_adapter(scsi_qla_host_t *); + +/****************************************************************************/ +/* QLogic ISP2x00 Hardware Support Functions. */ +/****************************************************************************/ + +/* +* qla2x00_initialize_adapter +* Initialize board. +* +* Input: +* ha = adapter block pointer. +* +* Returns: +* 0 = success +*/ +int +qla2x00_initialize_adapter(scsi_qla_host_t *ha) +{ + int rval; + uint8_t isp_init = 0; + uint8_t restart_risc = 0; + uint8_t retry; + + /* Clear adapter flags. */ + ha->flags.online = FALSE; + ha->flags.reset_active = FALSE; + atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME); + atomic_set(&ha->loop_state, LOOP_DOWN); + ha->device_flags = 0; + ha->sns_retry_cnt = 0; + ha->dpc_flags = 0; + ha->failback_delay = 0; + ha->flags.management_server_logged_in = 0; + ha->marker_needed = 0; + ha->mbx_flags = 0; + ha->isp_abort_cnt = 0; + ha->beacon_blink_led = 0; + + rval = qla2x00_pci_config(ha); + if (rval) { + DEBUG2(printk("scsi(%ld): Unable to configure PCI space=n", + ha->host_no)); + return (rval); + } + + qla2x00_reset_chip(ha); + + /* Initialize target map database. */ + qla2x00_init_tgt_map(ha); + + /* Get Flash Version */ + qla2x00_get_flash_version(ha); + + qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n"); + qla2x00_nvram_config(ha); + + ha->retry_count = ql2xretrycount; + + qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n"); + + /* + * If the user specified a device configuration on the command line + * then use it as the configuration. Otherwise, we scan for all + * devices. + */ + if (ql2xdevconf) { + ha->cmdline = ql2xdevconf; + if (!qla2x00_failover_enabled(ha)) + qla2x00_get_properties(ha, ql2xdevconf); + } + + retry = 10; + /* + * Try to configure the loop. + */ + do { + restart_risc = 0; + isp_init = 0; + + /* If firmware needs to be loaded */ + if (qla2x00_isp_firmware(ha) != QLA_SUCCESS) { + if ((rval = qla2x00_chip_diag(ha)) == QLA_SUCCESS) { + rval = qla2x00_setup_chip(ha); + } + } + + /* Retrieve firmware information */ + qla2x00_get_fw_version(ha, &ha->fw_major_version, + &ha->fw_minor_version, &ha->fw_subminor_version, + &ha->fw_attributes); + qla2x00_get_resource_cnts(ha, NULL, &ha->xchg_buf_cnt, + &ha->iocb_buf_cnt, NULL); + + if (rval == QLA_SUCCESS && + (rval = qla2x00_init_rings(ha)) == QLA_SUCCESS) { +check_fw_ready_again: + /* + * Wait for a successful LIP up to a maximum + * of (in seconds): RISC login timeout value, + * RISC retry count value, and port down retry + * value OR a minimum of 4 seconds OR If no + * cable, only 5 seconds. + */ + if (!qla2x00_fw_ready(ha)) { + clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); + + /* + * Go setup flash database devices with proper + * Loop ID's. + */ + do { + clear_bit(LOOP_RESYNC_NEEDED, + &ha->dpc_flags); + rval = qla2x00_configure_loop(ha); + + if (test_bit(ISP_ABORT_NEEDED, + &ha->dpc_flags)) { + + restart_risc = 1; + break; + } + + /* + * If loop state change while we were + * discoverying devices then wait for + * LIP to complete + */ + + if (atomic_read(&ha->loop_state) == + LOOP_DOWN && retry--) { + goto check_fw_ready_again; + } + } while (!atomic_read(&ha->loop_down_timer) && + retry && + (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))); + } + + if (ha->mem_err) { + restart_risc = 1; + } + isp_init = 1; + + } + } while (restart_risc && retry--); + + if (isp_init) { + clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); + ha->marker_needed = 1; + qla2x00_marker(ha, 0, 0, MK_SYNC_ALL); + ha->marker_needed = 0; + + ha->flags.online = TRUE; + } + + if (rval) { + DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__)); + } + + return (rval); +} + +/** + * qla2x00_pci_config() - Setup device PCI configuration registers. + * @ha: HA context + * + * Returns 0 on success. + */ +static int +qla2x00_pci_config(scsi_qla_host_t *ha) +{ + uint16_t w, mwi; + unsigned long flags = 0; + uint32_t cnt; + + qla_printk(KERN_INFO, ha, "Configuring PCI space...\n"); + + /* + * Turn on PCI master; for system BIOSes that don't turn it on by + * default. + */ + pci_set_master(ha->pdev); + mwi = 0; + if (pci_set_mwi(ha->pdev)) + mwi = PCI_COMMAND_INVALIDATE; + pci_read_config_word(ha->pdev, PCI_REVISION_ID, &ha->revision); + + if (!ha->iobase) + return (QLA_FUNCTION_FAILED); + + /* + * We want to respect framework's setting of PCI configuration space + * command register and also want to make sure that all bits of + * interest to us are properly set in command register. + */ + pci_read_config_word(ha->pdev, PCI_COMMAND, &w); + w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR); + + /* Get PCI bus information. */ + spin_lock_irqsave(&ha->hardware_lock, flags); + ha->pci_attr = RD_REG_WORD(&ha->iobase->ctrl_status); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + if (IS_QLA23XX(ha)) { + pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80); + + /* PCI Specification Revision 2.3 changes */ + if (IS_QLA2322(ha)) + /* Command Register - Reset Interrupt Disable. */ + w &= ~BIT_10; + + /* + * If this is a 2300 card and not 2312, reset the + * COMMAND_INVALIDATE due to a bug in the 2300. Unfortunately, + * the 2310 also reports itself as a 2300 so we need to get the + * fb revision level -- a 6 indicates it really is a 2300 and + * not a 2310. + */ + if (IS_QLA2300(ha)) { + spin_lock_irqsave(&ha->hardware_lock, flags); + + /* Pause RISC. */ + WRT_REG_WORD(&ha->iobase->hccr, HCCR_PAUSE_RISC); + for (cnt = 0; cnt < 30000; cnt++) { + if ((RD_REG_WORD(&ha->iobase->hccr) & + HCCR_RISC_PAUSE) != 0) + break; + + udelay(10); + } + + /* Select FPM registers. */ + WRT_REG_WORD(&ha->iobase->ctrl_status, 0x20); + + /* Get the fb rev level */ + ha->fb_rev = RD_FB_CMD_REG(ha, ha->iobase); + + if (ha->fb_rev == FPM_2300) + w &= ~PCI_COMMAND_INVALIDATE; + + /* Deselect FPM registers. */ + WRT_REG_WORD(&ha->iobase->ctrl_status, 0x0); + + /* Release RISC module. */ + WRT_REG_WORD(&ha->iobase->hccr, HCCR_RELEASE_RISC); + for (cnt = 0; cnt < 30000; cnt++) { + if ((RD_REG_WORD(&ha->iobase->hccr) & + HCCR_RISC_PAUSE) == 0) + break; + + udelay(10); + } + + spin_unlock_irqrestore(&ha->hardware_lock, flags); + } + } + + pci_write_config_word(ha->pdev, PCI_COMMAND, w); + + /* Reset expansion ROM address decode enable */ + pci_read_config_word(ha->pdev, PCI_ROM_ADDRESS, &w); + w &= ~PCI_ROM_ADDRESS_ENABLE; + pci_write_config_word(ha->pdev, PCI_ROM_ADDRESS, w); + + return (QLA_SUCCESS); +} + +/** + * qla2x00_isp_firmware() - Choose firmware image. + * @ha: HA context + * + * Returns 0 on success. + */ +static int +qla2x00_isp_firmware(scsi_qla_host_t *ha) +{ + int rval; + + /* Assume loading risc code */ + rval = QLA_FUNCTION_FAILED; + + if (ha->flags.disable_risc_code_load) { + DEBUG2(printk("scsi(%ld): RISC CODE NOT loaded\n", + ha->host_no)); + qla_printk(KERN_INFO, ha, "RISC CODE NOT loaded\n"); + + /* Verify checksum of loaded RISC code. */ + rval = qla2x00_verify_checksum(ha); + } + + if (rval) { + DEBUG2_3(printk("scsi(%ld): **** Load RISC code ****\n", + ha->host_no)); + } + + return (rval); +} + +/** + * qla2x00_reset_chip() - Reset ISP chip. + * @ha: HA context + * + * Returns 0 on success. + */ +static void +qla2x00_reset_chip(scsi_qla_host_t *ha) +{ + unsigned long flags = 0; + device_reg_t *reg = ha->iobase; + uint32_t cnt; + unsigned long mbx_flags = 0; + uint16_t cmd; + + /* Disable ISP interrupts. */ + qla2x00_disable_intrs(ha); + + spin_lock_irqsave(&ha->hardware_lock, flags); + + /* Turn off master enable */ + cmd = 0; + pci_read_config_word(ha->pdev, PCI_COMMAND, &cmd); + cmd &= ~PCI_COMMAND_MASTER; + pci_write_config_word(ha->pdev, PCI_COMMAND, cmd); + + if (!IS_QLA2100(ha)) { + /* Pause RISC. */ + WRT_REG_WORD(®->hccr, HCCR_PAUSE_RISC); + if (!IS_QLA2312(ha) && !IS_QLA2322(ha)) { + for (cnt = 0; cnt < 30000; cnt++) { + if ((RD_REG_WORD(®->hccr) & + HCCR_RISC_PAUSE) != 0) + break; + udelay(100); + } + } else { + udelay(10); + } + + /* Select FPM registers. */ + WRT_REG_WORD(®->ctrl_status, 0x20); + + /* FPM Soft Reset. */ + WRT_REG_WORD(®->fpm_diag_config, 0x100); + + /* Toggle Fpm Reset. */ + if (IS_QLA23XX(ha)) + WRT_REG_WORD(®->fpm_diag_config, 0x0); + + /* Select frame buffer registers. */ + WRT_REG_WORD(®->ctrl_status, 0x10); + + /* Reset frame buffer FIFOs. */ + if (IS_QLA2200(ha)) { + WRT_FB_CMD_REG(ha, reg, 0xa000); + } else { + WRT_FB_CMD_REG(ha, reg, 0x00fc); + + /* Read back fb_cmd until zero or 3 seconds max */ + for (cnt = 0; cnt < 3000; cnt++) { + if ((RD_FB_CMD_REG(ha, reg) & 0xff) == 0) + break; + udelay(100); + } + } + + /* Select RISC module registers. */ + WRT_REG_WORD(®->ctrl_status, 0); + + /* Reset RISC processor. */ + WRT_REG_WORD(®->hccr, HCCR_RESET_RISC); + + /* Release RISC processor. */ + WRT_REG_WORD(®->hccr, HCCR_RELEASE_RISC); + } + + WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); + WRT_REG_WORD(®->hccr, HCCR_CLR_HOST_INT); + + /* Reset ISP chip. */ + WRT_REG_WORD(®->ctrl_status, CSR_ISP_SOFT_RESET); + + /* Wait for RISC to recover from reset. */ + if (IS_QLA2312(ha) || IS_QLA2322(ha)) { + udelay(10); + } else { + /* + * It is necessary to for a delay here since the card doesn't + * respond to PCI reads during a reset. On some architectures + * this will result in an MCA. + */ + udelay(20); + for (cnt = 30000; cnt; cnt--) { + if ((RD_REG_WORD(®->ctrl_status) & + CSR_ISP_SOFT_RESET) == 0) + break; + udelay(100); + } + } + + /* Reset RISC processor. */ + WRT_REG_WORD(®->hccr, HCCR_RESET_RISC); + + WRT_REG_WORD(®->semaphore, 0); + + /* Release RISC processor. */ + WRT_REG_WORD(®->hccr, HCCR_RELEASE_RISC); + RD_REG_WORD(®->hccr); /* PCI Posting. */ + + if (IS_QLA2312(ha) || IS_QLA2322(ha)) + udelay(100); + else { + for (cnt = 0; cnt < 30000; cnt++) { + if (!(test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags))) + spin_lock_irqsave(&ha->mbx_reg_lock, mbx_flags); + + if (RD_MAILBOX_REG(ha, reg, 0) != MBS_BUSY) { + if (!(test_bit(ABORT_ISP_ACTIVE, + &ha->dpc_flags))) + spin_unlock_irqrestore( + &ha->mbx_reg_lock, mbx_flags); + break; + } + + if (!(test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags))) + spin_unlock_irqrestore(&ha->mbx_reg_lock, + mbx_flags); + + udelay(100); + } + } + + /* Turn on master enable */ + cmd |= PCI_COMMAND_MASTER; + pci_write_config_word(ha->pdev, PCI_COMMAND, cmd); + + /* Disable RISC pause on FPM parity error. */ + if (!IS_QLA2100(ha)) + WRT_REG_WORD(®->hccr, HCCR_DISABLE_PARITY_PAUSE); + + spin_unlock_irqrestore(&ha->hardware_lock, flags); +} + +/** + * qla2x00_chip_diag() - Test chip for proper operation. + * @ha: HA context + * + * Returns 0 on success. + */ +static int +qla2x00_chip_diag(scsi_qla_host_t *ha) +{ + int rval; + device_reg_t *reg = ha->iobase; + unsigned long flags = 0; + uint16_t data; + uint32_t cnt; + uint16_t mb[5]; + + /* Assume a failed state */ + rval = QLA_FUNCTION_FAILED; + + DEBUG3(printk("scsi(%ld): Testing device at %lx.\n", + ha->host_no, (u_long)®->flash_address)); + + spin_lock_irqsave(&ha->hardware_lock, flags); + + /* Reset ISP chip. */ + WRT_REG_WORD(®->ctrl_status, CSR_ISP_SOFT_RESET); + /* + * We need to have a delay here since the card will not respond while + * in reset causing an MCA on some architectures. + */ + udelay(20); + data = qla2x00_debounce_register(®->ctrl_status); + for (cnt = 6000000 ; cnt && (data & CSR_ISP_SOFT_RESET); cnt--) { + udelay(5); + data = RD_REG_WORD(®->ctrl_status); + barrier(); + } + + if (!cnt) + goto chip_diag_failed; + + DEBUG3(printk("scsi(%ld): Reset register cleared by chip reset\n", + ha->host_no)); + + /* Reset RISC processor. */ + WRT_REG_WORD(®->hccr, HCCR_RESET_RISC); + WRT_REG_WORD(®->hccr, HCCR_RELEASE_RISC); + + /* Workaround for QLA2312 PCI parity error */ + if (IS_QLA2312(ha) || IS_QLA2322(ha)) + udelay(10); + else { + data = qla2x00_debounce_register(MAILBOX_REG(ha, reg, 0)); + for (cnt = 6000000; cnt && (data == MBS_BUSY); cnt--) { + udelay(5); + data = RD_MAILBOX_REG(ha, reg, 0); + barrier(); + } + } + + if (!cnt) + goto chip_diag_failed; + + /* Check product ID of chip */ + DEBUG3(printk("scsi(%ld): Checking product ID of chip\n", ha->host_no)); + + mb[1] = RD_MAILBOX_REG(ha, reg, 1); + mb[2] = RD_MAILBOX_REG(ha, reg, 2); + mb[3] = RD_MAILBOX_REG(ha, reg, 3); + + if (mb[1] != PROD_ID_1 || (mb[2] != PROD_ID_2 && mb[2] != PROD_ID_2a) || + mb[3] != PROD_ID_3) { + qla_printk(KERN_WARNING, ha, + "Wrong product ID = 0x%x,0x%x,0x%x\n", mb[1], mb[2], mb[3]); + + goto chip_diag_failed; + } + + /* Adjust fw RISC transfer size */ + ha->fw_transfer_size = REQUEST_ENTRY_SIZE * REQUEST_ENTRY_CNT; + + if (IS_QLA2200(ha) && + RD_MAILBOX_REG(ha, reg, 7) == QLA2200A_RISC_ROM_VER) { + /* Limit firmware transfer size with a 2200A */ + DEBUG3(printk("scsi(%ld): Found QLA2200A chip.\n", + ha->host_no)); + + ha->fw_transfer_size = 128; + } + + /* Wrap Incoming Mailboxes Test. */ + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + DEBUG3(printk("scsi(%ld): Checking mailboxes.\n", ha->host_no)); + rval = qla2x00_mbx_reg_test(ha); + if (rval) { + DEBUG(printk("scsi(%ld): Failed mailbox send register test\n", + ha->host_no)); + qla_printk(KERN_WARNING, ha, + "Failed mailbox send register test\n"); + } + else { + /* Flag a successful rval */ + rval = QLA_SUCCESS; + } + spin_lock_irqsave(&ha->hardware_lock, flags); + +chip_diag_failed: + if (rval) + DEBUG2_3(printk("scsi(%ld): Chip diagnostics **** FAILED " + "****\n", ha->host_no)); + + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + return (rval); +} + +/** + * qla2x00_setup_chip() - Load and start RISC firmware. + * @ha: HA context + * + * Returns 0 on success. + */ +static int +qla2x00_setup_chip(scsi_qla_host_t *ha) +{ + int rval; + uint16_t cnt; + uint16_t *risc_code; + unsigned long risc_address; + unsigned long risc_code_size; + int num; + int i; + uint16_t *req_ring; + struct qla_fw_info *fw_iter; + + rval = QLA_SUCCESS; + + /* Load firmware sequences */ + fw_iter = ha->brd_info->fw_info; + while (fw_iter->addressing != FW_INFO_ADDR_NOMORE) { + risc_code = fw_iter->fwcode; + risc_code_size = *fw_iter->fwlen; + + if (fw_iter->addressing == FW_INFO_ADDR_NORMAL) { + risc_address = *fw_iter->fwstart; + } else { + /* Extended address */ + risc_address = *fw_iter->lfwstart; + } + + num = 0; + rval = 0; + while (risc_code_size > 0 && !rval) { + cnt = (uint16_t)(ha->fw_transfer_size >> 1); + if (cnt > risc_code_size) + cnt = risc_code_size; + + DEBUG7(printk("scsi(%ld): Loading risc segment@ " + "addr %p, number of bytes 0x%x, offset 0x%lx.\n", + ha->host_no, risc_code, cnt, risc_address)); + + req_ring = (uint16_t *)ha->request_ring; + for (i = 0; i < cnt; i++) + req_ring[i] = cpu_to_le16(risc_code[i]); + + /* + * Flush written firmware to the ha->request_ring buffer + * before DMA. + */ + flush_cache_all(); + + if (fw_iter->addressing == FW_INFO_ADDR_NORMAL) { + rval = qla2x00_load_ram(ha, + ha->request_dma, risc_address, cnt); + } else { + rval = qla2x00_load_ram_ext(ha, + ha->request_dma, risc_address, cnt); + } + if (rval) { + DEBUG(printk("scsi(%ld): [ERROR] Failed to " + "load segment %d of firmware\n", + ha->host_no, num)); + qla_printk(KERN_WARNING, ha, + "[ERROR] Failed to load " + "segment %d of firmware\n", num); + + qla2x00_dump_regs(ha); + break; + } + + risc_code += cnt; + risc_address += cnt; + risc_code_size -= cnt; + num++; + } + + /* Next firmware sequence */ + fw_iter++; + } + + /* Verify checksum of loaded RISC code. */ + if (!rval) { + DEBUG(printk("scsi(%ld): Verifying Checksum of loaded RISC " + "code.\n", ha->host_no)); + + rval = qla2x00_verify_checksum(ha); + if (rval == QLA_SUCCESS) { + /* Start firmware execution. */ + DEBUG(printk("scsi(%ld): Checksum OK, start " + "firmware.\n", ha->host_no)); + + rval = qla2x00_execute_fw(ha); + } + else { + DEBUG2(printk(KERN_INFO + "scsi(%ld): ISP Firmware failed checksum.\n", + ha->host_no)); + } + } + + if (rval) { + DEBUG2_3(printk("scsi(%ld): Setup chip **** FAILED ****.\n", + ha->host_no)); + } + + return (rval); +} + +/** + * qla2x00_init_response_q_entries() - Initializes response queue entries. + * @ha: HA context + * + * Beginning of request ring has initialization control block already built + * by nvram config routine. + * + * Returns 0 on success. + */ +static void +qla2x00_init_response_q_entries(scsi_qla_host_t *ha) +{ + uint16_t cnt; + response_t *pkt; + + pkt = ha->response_ring_ptr; + for (cnt = 0; cnt < ha->response_q_length; cnt++) { + pkt->signature = RESPONSE_PROCESSED; + pkt++; + } + +} + +/** + * qla2x00_init_rings() - Initializes firmware. + * @ha: HA context + * + * Beginning of request ring has initialization control block already built + * by nvram config routine. + * + * Returns 0 on success. + */ +static int +qla2x00_init_rings(scsi_qla_host_t *ha) +{ + int rval; + unsigned long flags = 0; + int cnt; + device_reg_t *reg = ha->iobase; + + spin_lock_irqsave(&ha->hardware_lock, flags); + + /* Clear outstanding commands array. */ + for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) + ha->outstanding_cmds[cnt] = 0; + + ha->current_outstanding_cmd = 0; + + /* Clear RSCN queue. */ + ha->rscn_in_ptr = 0; + ha->rscn_out_ptr = 0; + + /* Initialize firmware. */ + ha->request_ring_ptr = ha->request_ring; + ha->req_ring_index = 0; + ha->req_q_cnt = REQUEST_ENTRY_CNT; + ha->response_ring_ptr = ha->response_ring; + ha->rsp_ring_index = 0; + + /* Initialize response queue entries */ + qla2x00_init_response_q_entries(ha); + + WRT_REG_WORD(ISP_REQ_Q_IN(ha, reg), 0); + WRT_REG_WORD(ISP_REQ_Q_OUT(ha, reg), 0); + WRT_REG_WORD(ISP_RSP_Q_IN(ha, reg), 0); + WRT_REG_WORD(ISP_RSP_Q_OUT(ha, reg), 0); + RD_REG_WORD(ISP_RSP_Q_OUT(ha, reg)); + + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + DEBUG(printk("scsi(%ld): Issue init firmware.\n", ha->host_no)); + rval = qla2x00_init_firmware(ha, sizeof(init_cb_t)); + if (rval) { + DEBUG2_3(printk("scsi(%ld): Init firmware **** FAILED ****.\n", + ha->host_no)); + } else { + /* Setup seriallink options */ + uint16_t swing, emphasis; + + DEBUG3(printk("scsi(%ld): Serial link options:\n", + ha->host_no)); + DEBUG3(qla2x00_dump_buffer( + (uint8_t *)&ha->fw_seriallink_options, + sizeof(ha->fw_seriallink_options))); + + memset(ha->fw_options, 0, sizeof(ha->fw_options)); + qla2x00_get_fw_options(ha, ha->fw_options); + + ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING; + if (ha->fw_seriallink_options[1] & BIT_2) + ha->fw_options[1] |= FO1_SET_EMPHASIS_SWING; + + /* 1G settings */ + swing = ha->fw_seriallink_options[0] & (BIT_2 | BIT_1 | BIT_0); + emphasis = ha->fw_seriallink_options[0] & (BIT_4 | BIT_3); + emphasis >>= 3; + ha->fw_options[10] = (emphasis << 14) | (swing << 8) | 0x3; + + /* 2G settings */ + swing = ha->fw_seriallink_options[0] & (BIT_7 | BIT_6 | BIT_5); + swing >>= 5; + emphasis = ha->fw_seriallink_options[1] & (BIT_1 | BIT_0); + ha->fw_options[11] = (emphasis << 14) | (swing << 8) | 0x3; + + qla2x00_set_fw_options(ha, ha->fw_options); + + DEBUG3(printk("scsi(%ld): Init firmware -- success.\n", + ha->host_no)); + } + + return (rval); +} + +/** + * qla2x00_fw_ready() - Waits for firmware ready. + * @ha: HA context + * + * Returns 0 on success. + */ +static int +qla2x00_fw_ready(scsi_qla_host_t *ha) +{ + int rval; + unsigned long wtime, mtime; + uint16_t min_wait; /* Minimum wait time if loop is down */ + uint16_t wait_time; /* Wait time if loop is coming ready */ + uint16_t fw_state; + + rval = QLA_SUCCESS; + + /* 20 seconds for loop down. */ + min_wait = 20; + + /* + * Firmware should take at most one RATOV to login, plus 5 seconds for + * our own processing. + */ + if ((wait_time = (ha->retry_count*ha->login_timeout) + 5) < min_wait) { + wait_time = min_wait; + } + + /* Min wait time if loop down */ + mtime = jiffies + (min_wait * HZ); + + /* wait time before firmware ready */ + wtime = jiffies + (wait_time * HZ); + + /* Wait for ISP to finish LIP */ + if (!ha->flags.init_done || qla2x00_verbose) + qla_printk(KERN_INFO, ha, "Waiting for LIP to complete...\n"); + + DEBUG3(printk("scsi(%ld): Waiting for LIP to complete...\n", + ha->host_no)); + + do { + rval = qla2x00_get_firmware_state(ha, &fw_state); + if (rval == QLA_SUCCESS) { + if (fw_state < FSTATE_LOSS_OF_SYNC) { + ha->device_flags &= ~DFLG_NO_CABLE; + } + if (fw_state == FSTATE_READY) { + DEBUG(printk("scsi(%ld): F/W Ready - OK \n", + ha->host_no)); + + qla2x00_get_retry_cnt(ha, &ha->retry_count, + &ha->login_timeout, &ha->r_a_tov); + + rval = QLA_SUCCESS; + break; + } + + rval = QLA_FUNCTION_FAILED; + + if (atomic_read(&ha->loop_down_timer) && + fw_state >= FSTATE_LOSS_OF_SYNC) { + /* Loop down. Timeout on min_wait for states + * other than Wait for Login. + */ + if (time_after_eq(jiffies, mtime)) { + qla_printk(KERN_INFO, ha, + "Cable is unplugged...\n"); + + ha->device_flags |= DFLG_NO_CABLE; + break; + } + } + } else { + /* Mailbox cmd failed. Timeout on min_wait. */ + if (time_after_eq(jiffies, mtime)) + break; + } + + if (time_after_eq(jiffies, wtime)) + break; + + /* Delay for a while */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ / 2); + + DEBUG3(printk("scsi(%ld): fw_state=%x curr time=%lx.\n", + ha->host_no, fw_state, jiffies)); + } while (1); + + DEBUG(printk("scsi(%ld): fw_state=%x curr time=%lx.\n", + ha->host_no, fw_state, jiffies)); + + if (rval) { + DEBUG2_3(printk("scsi(%ld): Firmware ready **** FAILED ****.\n", + ha->host_no)); + } + + return (rval); +} + +/* +* qla2x00_configure_hba +* Setup adapter context. +* +* Input: +* ha = adapter state pointer. +* +* Returns: +* 0 = success +* +* Context: +* Kernel context. +*/ +static int +qla2x00_configure_hba(scsi_qla_host_t *ha) +{ + int rval; + uint16_t loop_id; + uint16_t topo; + uint8_t al_pa; + uint8_t area; + uint8_t domain; + char connect_type[22]; + + /* Get host addresses. */ + rval = qla2x00_get_adapter_id(ha, + &loop_id, &al_pa, &area, &domain, &topo); + if (rval != QLA_SUCCESS) { + qla_printk(KERN_WARNING, ha, + "ERROR -- Unable to get host loop ID.\n"); + return (rval); + } + + if (topo == 4) { + qla_printk(KERN_INFO, ha, + "Cannot get topology - retrying.\n"); + return (QLA_FUNCTION_FAILED); + } + + ha->loop_id = loop_id; + + /* Make sure 2100 only has loop, in case of any firmware bug. */ + if (IS_QLA2100(ha)) + topo = 0; + + /* initialize */ + ha->min_external_loopid = SNS_FIRST_LOOP_ID; + ha->operating_mode = LOOP; + + switch (topo) { + case 0: + DEBUG3(printk("scsi(%ld): HBA in NL topology.\n", + ha->host_no)); + ha->current_topology = ISP_CFG_NL; + strcpy(connect_type, "(Loop)"); + break; + + case 1: + DEBUG3(printk("scsi(%ld): HBA in FL topology.\n", + ha->host_no)); + ha->current_topology = ISP_CFG_FL; + strcpy(connect_type, "(FL_Port)"); + break; + + case 2: + DEBUG3(printk("scsi(%ld): HBA in N P2P topology.\n", + ha->host_no)); + ha->operating_mode = P2P; + ha->current_topology = ISP_CFG_N; + strcpy(connect_type, "(N_Port-to-N_Port)"); + break; + + case 3: + DEBUG3(printk("scsi(%ld): HBA in F P2P topology.\n", + ha->host_no)); + ha->operating_mode = P2P; + ha->current_topology = ISP_CFG_F; + strcpy(connect_type, "(F_Port)"); + break; + + default: + DEBUG3(printk("scsi(%ld): HBA in unknown topology %x. " + "Using NL.\n", + ha->host_no, topo)); + ha->current_topology = ISP_CFG_NL; + strcpy(connect_type, "(Loop)"); + break; + } + + /* Save Host port and loop ID. */ + /* byte order - Big Endian */ + ha->d_id.b.domain = domain; + ha->d_id.b.area = area; + ha->d_id.b.al_pa = al_pa; + + if (!ha->flags.init_done || qla2x00_verbose) + qla_printk(KERN_INFO, ha, + "Topology - %s, Host Loop address 0x%x\n", + connect_type, ha->loop_id); + + if (rval) { + DEBUG2_3(printk("scsi(%ld): FAILED.\n", ha->host_no)); + } else { + DEBUG3(printk("scsi(%ld): exiting normally.\n", ha->host_no)); + } + + return(rval); +} + +/* +* NVRAM configuration for ISP 2xxx +* +* Input: +* ha = adapter block pointer. +* +* Output: +* initialization control block in response_ring +* host adapters parameters in host adapter block +* +* Returns: +* 0 = success. +*/ +static int +qla2x00_nvram_config(scsi_qla_host_t *ha) +{ + int rval; + uint8_t chksum = 0; + uint16_t cnt; + uint8_t *dptr1, *dptr2; + init_cb_t *icb = ha->init_cb; + nvram_t *nv = (nvram_t *)ha->request_ring; + uint16_t *wptr = (uint16_t *)ha->request_ring; + device_reg_t *reg = ha->iobase; + uint16_t timer_mode; + + rval = QLA_SUCCESS; + + if (ha->flags.init_done) + return (rval); + + /* Determine NVRAM starting address. */ + ha->nvram_base = 0; + if (IS_QLA2312(ha) || IS_QLA2322(ha)) + if ((RD_REG_WORD(®->ctrl_status) >> 14) == 1) + ha->nvram_base = 0x80; + + /* Get NVRAM data and calculate checksum. */ + qla2x00_lock_nvram_access(ha); + for (cnt = 0; cnt < sizeof(nvram_t)/2; cnt++) { + *wptr = cpu_to_le16(qla2x00_get_nvram_word(ha, + (cnt+ha->nvram_base))); + chksum += (uint8_t)*wptr; + chksum += (uint8_t)(*wptr >> 8); + wptr++; + } + qla2x00_unlock_nvram_access(ha); + + DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no)); + DEBUG5(qla2x00_dump_buffer((uint8_t *)ha->request_ring, + sizeof(nvram_t))); + + /* Bad NVRAM data, set defaults parameters. */ + if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || + nv->id[2] != 'P' || nv->id[3] != ' ' || nv->nvram_version < 1) { + /* Reset NVRAM data. */ + qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: " + "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0], + nv->nvram_version); + qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet " + "invalid -- WWPN) defaults.\n"); + + /* + * Set default initialization control block. + */ + memset(nv, 0, sizeof(nvram_t)); + nv->parameter_block_version = ICB_VERSION; + + if (IS_QLA23XX(ha)) { + nv->firmware_options[0] = BIT_2 | BIT_1; + nv->firmware_options[1] = BIT_7 | BIT_5; + nv->add_firmware_options[0] = BIT_5; + nv->add_firmware_options[1] = BIT_5 | BIT_4; + nv->frame_payload_size = __constant_cpu_to_le16(2048); + nv->special_options[1] = BIT_7; + } else if (IS_QLA2200(ha)) { + nv->firmware_options[0] = BIT_2 | BIT_1; + nv->firmware_options[1] = BIT_7 | BIT_5; + nv->add_firmware_options[0] = BIT_5 | BIT_4; + nv->add_firmware_options[1] = BIT_5 | BIT_4; + nv->frame_payload_size = __constant_cpu_to_le16(1024); + } else if (IS_QLA2100(ha)) { + nv->firmware_options[0] = BIT_3 | BIT_1; + nv->firmware_options[1] = BIT_5; + nv->frame_payload_size = __constant_cpu_to_le16(1024); + } + + nv->max_iocb_allocation = __constant_cpu_to_le16(256); + nv->execution_throttle = __constant_cpu_to_le16(16); + nv->retry_count = 8; + nv->retry_delay = 1; + + nv->port_name[0] = 33; + nv->port_name[3] = 224; + nv->port_name[4] = 139; + + nv->login_timeout = 4; + + /* + * Set default host adapter parameters + */ + nv->host_p[1] = BIT_2; + nv->reset_delay = 5; + nv->port_down_retry_count = 8; + nv->max_luns_per_target = __constant_cpu_to_le16(8); + nv->link_down_timeout = 60; + + rval = 1; + } + +#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2) + /* + * The SN2 does not provide BIOS emulation which means you can't change + * potentially bogus BIOS settings. Force the use of default settings + * for link rate and frame size. Hope that the rest of the settings + * are valid. + */ + if (ia64_platform_is("sn2")) { + nv->frame_payload_size = __constant_cpu_to_le16(2048); + if (IS_QLA23XX(ha)) + nv->special_options[1] = BIT_7; + } +#endif + + /* Reset Initialization control block */ + memset(icb, 0, sizeof(init_cb_t)); + + /* + * Setup driver NVRAM options. + */ + nv->firmware_options[0] |= (BIT_6 | BIT_1); + nv->firmware_options[0] &= ~(BIT_5 | BIT_4); + nv->firmware_options[1] |= (BIT_5 | BIT_0); + nv->firmware_options[1] &= ~BIT_4; + + if (IS_QLA23XX(ha)) { + nv->firmware_options[0] |= BIT_2; + nv->firmware_options[0] &= ~BIT_3; + + if (IS_QLA2300(ha)) { + if (ha->fb_rev == FPM_2310) { + strcpy(ha->model_number, "QLA2310"); + } else { + strcpy(ha->model_number, "QLA2300"); + } + } else if (IS_QLA2312(ha) || IS_QLA2322(ha)) { + if (rval == 0 && + memcmp(nv->model_number, BINZERO, + sizeof(nv->model_number)) != 0) { + char *st, *en; + + strncpy(ha->model_number, nv->model_number, + sizeof(nv->model_number)); + st = en = ha->model_number; + en += sizeof(nv->model_number) - 1; + while (en > st) { + if (*en != 0x20) + break; + *en-- = '\0'; + } + } else { + uint16_t index; + + index = (ha->pdev->subsystem_device & 0xff); + if (index < QLA_MODEL_NAMES) { + strcpy(ha->model_number, + qla2x00_model_name[index]); + ha->model_desc = + qla2x00_model_desc[index]; + } else { + strcpy(ha->model_number, "QLA23xx"); + } + } + } else { + strcpy(ha->model_number, "QLA23xx"); + } + } else if (IS_QLA2200(ha)) { + nv->firmware_options[0] |= BIT_2; + strcpy(ha->model_number, "QLA22xx"); + } else /*if (IS_QLA2100(ha))*/ { + strcpy(ha->model_number, "QLA2100"); + } + + /* + * Copy over NVRAM RISC parameter block to initialization control block. + */ + dptr1 = (uint8_t *)icb; + dptr2 = (uint8_t *)&nv->parameter_block_version; + cnt = (uint8_t *)&icb->request_q_outpointer - (uint8_t *)&icb->version; + while (cnt--) + *dptr1++ = *dptr2++; + + /* Copy 2nd half. */ + dptr1 = (uint8_t *)icb->add_firmware_options; + cnt = (uint8_t *)icb->reserved_3 - (uint8_t *)icb->add_firmware_options; + while (cnt--) + *dptr1++ = *dptr2++; + + /* Prepare nodename */ + if ((icb->firmware_options[1] & BIT_6) == 0) { + /* + * Firmware will apply the following mask if the nodename was + * not provided. + */ + memcpy(icb->node_name, icb->port_name, WWN_SIZE); + icb->node_name[0] &= 0xF0; + } + + /* + * Set host adapter parameters. + */ + ha->nvram_version = nv->nvram_version; + + ha->flags.disable_risc_code_load = ((nv->host_p[0] & BIT_4) ? 1 : 0); + ha->flags.enable_lip_reset = ((nv->host_p[1] & BIT_1) ? 1 : 0); + ha->flags.enable_lip_full_login = ((nv->host_p[1] & BIT_2) ? 1 : 0); + ha->flags.enable_target_reset = ((nv->host_p[1] & BIT_3) ? 1 : 0); + + ha->operating_mode = + (icb->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) >> 4; + + ha->fw_seriallink_options[0] = nv->seriallink_options[0]; + ha->fw_seriallink_options[1] = nv->seriallink_options[1]; + + /* save HBA serial number */ + ha->serial0 = icb->port_name[5]; + ha->serial1 = icb->port_name[6]; + ha->serial2 = icb->port_name[7]; + memcpy(ha->node_name, icb->node_name, WWN_SIZE); + + icb->execution_throttle = __constant_cpu_to_le16(0xFFFF); + + ha->retry_count = nv->retry_count; + + /* Set minimum login_timeout to 4 seconds. */ + if (nv->login_timeout < ql2xlogintimeout) + nv->login_timeout = ql2xlogintimeout; + if (nv->login_timeout < 4) + nv->login_timeout = 4; + ha->login_timeout = nv->login_timeout; + icb->login_timeout = nv->login_timeout; + + /* Set minimum RATOV to 200 tenths of a second. */ + ha->r_a_tov = 200; + +/* FIXME + * + * port_down_retry_count updated twice + * + */ + ha->port_down_retry_count = nv->port_down_retry_count; + ha->minimum_timeout = + (ha->login_timeout * ha->retry_count) + ha->port_down_retry_count; + ha->loop_reset_delay = nv->reset_delay; + + /* Will get the value from NVRAM. */ + ha->loop_down_timeout = LOOP_DOWN_TIMEOUT; + + /* Link Down Timeout = 0: + * + * When Port Down timer expires we will start returning + * I/O's to OS with "DID_NO_CONNECT". + * + * Link Down Timeout != 0: + * + * The driver waits for the link to come up after link down + * before returning I/Os to OS with "DID_NO_CONNECT". + */ + if (nv->link_down_timeout == 0) { + ha->loop_down_abort_time = + (LOOP_DOWN_TIME - ha->loop_down_timeout); + } else { + ha->link_down_timeout = nv->link_down_timeout; + ha->loop_down_abort_time = + (LOOP_DOWN_TIME - ha->link_down_timeout); + } + + ha->max_probe_luns = le16_to_cpu(nv->max_luns_per_target); + if (ha->max_probe_luns == 0) + ha->max_probe_luns = MIN_LUNS; + +#if USE_BIOS_MAX_LUNS + ha->max_luns = le16_to_cpu(nv->max_luns_per_target); + if (ha->max_luns == 0) + ha->max_luns = MAX_LUNS; + else if (ha->max_luns > MAX_LUNS) + ha->max_luns = MAX_LUNS; +#else + ha->max_luns = MAX_LUNS; +#endif + +/* FIXME + * + * port_down_retry_count updated twice + * + */ + /* + * Need enough time to try and get the port back. + */ + if (qlport_down_retry) + ha->port_down_retry_count = qlport_down_retry; + /* Set login_retry_count */ + ha->login_retry_count = nv->retry_count; + if (ha->port_down_retry_count == nv->port_down_retry_count && + ha->port_down_retry_count > 3) + ha->login_retry_count = ha->port_down_retry_count; + else if (ha->port_down_retry_count > (int)ha->login_retry_count) + ha->login_retry_count = ha->port_down_retry_count; + + ha->binding_type = Bind; + if (ha->binding_type != BIND_BY_PORT_NAME && + ha->binding_type != BIND_BY_PORT_ID) { + qla_printk(KERN_WARNING, ha, + "Invalid binding type specified (%d), " + "defaulting to BIND_BY_PORT_NAME!!!\n", ha->binding_type); + + ha->binding_type = BIND_BY_PORT_NAME; + } + + /* + * Setup ring parameters in initialization control block + */ + icb->request_q_outpointer = __constant_cpu_to_le16(0); + icb->response_q_inpointer = __constant_cpu_to_le16(0); + icb->request_q_length = __constant_cpu_to_le16(REQUEST_ENTRY_CNT); + icb->response_q_length = cpu_to_le16(ha->response_q_length); + icb->request_q_address[0] = cpu_to_le32(LSD(ha->request_dma)); + icb->request_q_address[1] = cpu_to_le32(MSD(ha->request_dma)); + icb->response_q_address[0] = cpu_to_le32(LSD(ha->response_dma)); + icb->response_q_address[1] = cpu_to_le32(MSD(ha->response_dma)); + + icb->lun_enables = __constant_cpu_to_le16(0); + icb->command_resource_count = 0; + icb->immediate_notify_resource_count = 0; + icb->timeout = __constant_cpu_to_le16(0); + + if (IS_QLA2100(ha) || IS_QLA2200(ha)) { + /* Enable RIO */ + icb->firmware_options[0] &= ~BIT_3; + icb->add_firmware_options[0] &= + ~(BIT_3 | BIT_2 | BIT_1 | BIT_0); + icb->add_firmware_options[0] |= (BIT_1 | BIT_0); + icb->response_accumulation_timer = 3; + icb->interrupt_delay_timer = 5; + + ha->flags.process_response_queue = 1; + } else { + /* TEST ZIO: + * + * icb->add_firmware_options[0] &= + * ~(BIT_3 | BIT_2 | BIT_1 | BIT_0); + * icb->add_firmware_options[0] |= (BIT_2 | BIT_0); + */ + timer_mode = icb->add_firmware_options[0] & + (BIT_3 | BIT_2 | BIT_1 | BIT_0); + if (timer_mode == 5) { + DEBUG2(printk("scsi(%ld): ZIO enabled; timer delay " + "(%d).\n", ha->host_no, ql2xintrdelaytimer)); + qla_printk(KERN_INFO, ha, + "ZIO enabled; timer delay (%d).\n", + ql2xintrdelaytimer); + + icb->interrupt_delay_timer = ql2xintrdelaytimer; + + ha->flags.process_response_queue = 1; + } + } + + if (rval) { + DEBUG2_3(printk(KERN_WARNING + "scsi(%ld): NVRAM configuration failed!\n", ha->host_no)); + } + + LEAVE(__func__); + + return (rval); +} + +/* +* qla2x00_init_tgt_map +* Initializes target map. +* +* Input: +* ha = adapter block pointer. +* +* Output: +* TGT_Q initialized +*/ +static void +qla2x00_init_tgt_map(scsi_qla_host_t *ha) +{ + uint32_t t; + + ENTER(__func__); + + for (t = 0; t < MAX_TARGETS; t++) + TGT_Q(ha, t) = (os_tgt_t *)NULL; + + LEAVE(__func__); +} + +/** + * qla2x00_alloc_fcport() - Allocate a generic fcport. + * @ha: HA context + * @flags: allocation flags + * + * Returns a pointer to the allocated fcport, or NULL, if none available. + */ +fc_port_t * +qla2x00_alloc_fcport(scsi_qla_host_t *ha, int flags) +{ + fc_port_t *fcport; + + fcport = kmalloc(sizeof(fc_port_t), flags); + if (fcport == NULL) + return (fcport); + + /* Setup fcport template structure. */ + memset(fcport, 0, sizeof (fc_port_t)); + fcport->ha = ha; + fcport->port_type = FCT_UNKNOWN; + fcport->loop_id = FC_NO_LOOP_ID; + fcport->iodesc_idx_sent = IODESC_INVALID_INDEX; + atomic_set(&fcport->state, FCS_UNCONFIGURED); + fcport->flags = FCF_RLC_SUPPORT; + INIT_LIST_HEAD(&fcport->fcluns); + + return (fcport); +} + +/* + * qla2x00_configure_loop + * Updates Fibre Channel Device Database with what is actually on loop. + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * 0 = success. + * 1 = error. + * 2 = database was full and device was not configured. + */ +static int +qla2x00_configure_loop(scsi_qla_host_t *ha) +{ + int rval; + uint8_t rval1 = 0; + static unsigned long flags, save_flags; + + rval = QLA_SUCCESS; + + /* Get Initiator ID */ + if (qla2x00_configure_hba(ha)) { + DEBUG(printk("scsi(%ld): Unable to configure HBA.\n", + ha->host_no)); + return (QLA_FUNCTION_FAILED); + } + + save_flags = flags = ha->dpc_flags; + DEBUG(printk("scsi(%ld): Configure loop -- dpc flags =0x%lx\n", + ha->host_no, flags)); + + /* dg 02/26/02 ha->dpc_flags &= ~(LOCAL_LOOP_UPDATE | RSCN_UPDATE); */ + + /* + * If we have both an RSCN and PORT UPDATE pending then handle them + * both at the same time. + */ + clear_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags); + clear_bit(RSCN_UPDATE, &ha->dpc_flags); + ha->mem_err = 0 ; + + /* Determine what we need to do */ + if (ha->current_topology == ISP_CFG_FL && + (test_bit(LOCAL_LOOP_UPDATE, &flags))) { + + ha->flags.rscn_queue_overflow = TRUE; + set_bit(RSCN_UPDATE, &flags); + + } else if (ha->current_topology == ISP_CFG_F && + (test_bit(LOCAL_LOOP_UPDATE, &flags))) { + + ha->flags.rscn_queue_overflow = TRUE; + set_bit(RSCN_UPDATE, &flags); + clear_bit(LOCAL_LOOP_UPDATE, &flags); + + } else if (!ha->flags.online || + (test_bit(ABORT_ISP_ACTIVE, &flags))) { + + ha->flags.rscn_queue_overflow = TRUE; + set_bit(RSCN_UPDATE, &flags); + set_bit(LOCAL_LOOP_UPDATE, &flags); + } + + do { + if (test_bit(LOCAL_LOOP_UPDATE, &flags)) { + rval = rval | qla2x00_configure_local_loop(ha); + } + + if (test_bit(RSCN_UPDATE, &flags)) { + rval1 = qla2x00_configure_fabric(ha); + if ((rval1 & BIT_0) && ha->sns_retry_cnt < 8) { + ha->sns_retry_cnt++; + set_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags); + } + } + + /* Isolate error status. */ + if (rval & BIT_0) { + rval = 1; + } else { + rval = QLA_SUCCESS; + } + + } while (rval != QLA_SUCCESS); + + if (!atomic_read(&ha->loop_down_timer) && + !(test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))) { + + if (!qla2x00_failover_enabled(ha)) + qla2x00_config_os(ha); + + /* If we found all devices then go ready */ + if (!(test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags))) { + atomic_set(&ha->loop_state, LOOP_READY); + +#if defined(CONFIG_SCSI_QLA2XXX_FAILOVER_ENABLE) + if (qla2x00_failover_enabled(ha)) { + DEBUG(printk("scsi(%ld): schedule FAILBACK " + "EVENT\n", ha->host_no)); + if (!(test_and_set_bit(FAILOVER_EVENT_NEEDED, + &ha->dpc_flags))) { + ha->failback_delay = ql2xfailbackTime; + } + ha->failover_type = MP_NOTIFY_LOOP_UP; + } +#endif + DEBUG(printk("scsi(%ld): LOOP READY\n", ha->host_no)); + } else { + if (test_bit(LOCAL_LOOP_UPDATE, &save_flags)) + set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags); + if (test_bit(RSCN_UPDATE, &save_flags)) + set_bit(RSCN_UPDATE, &ha->dpc_flags); + } + } else { + DEBUG(printk("scsi(%ld): Loop down counter running= %d or " + "Resync needed- dpc flags= %ld\n", + ha->host_no, + atomic_read(&ha->loop_down_timer), ha->dpc_flags)); + /* ???? dg 02/26/02 rval = 1; */ + } + + if (rval) { + DEBUG2_3(printk("%s(%ld): *** FAILED ***\n", + __func__, ha->host_no)); + } else { + DEBUG3(printk("%s: exiting normally\n", __func__)); + } + + return (rval); +} + + + +/* + * qla2x00_configure_local_loop + * Updates Fibre Channel Device Database with local loop devices. + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * 0 = success. + * BIT_0 = error. + */ +static int +qla2x00_configure_local_loop(scsi_qla_host_t *ha) +{ + int rval, rval2; + int found_devs; + int found; + fc_port_t *fcport, *new_fcport; + + uint16_t index; + uint16_t entries; + struct dev_id { + uint8_t al_pa; + uint8_t area; + uint8_t domain; + uint8_t loop_id_2100; /* ISP2100/ISP2200 -- 4 bytes. */ + uint16_t loop_id; /* ISP23XX -- 6 bytes. */ + } *id_list; +#define MAX_ID_LIST_SIZE (sizeof(struct dev_id) * MAX_FIBRE_DEVICES) + dma_addr_t id_list_dma; + char *id_iter; + uint16_t loop_id; + uint8_t domain, area, al_pa; + + rval = QLA_SUCCESS; + found_devs = 0; + new_fcport = NULL; + + /* + * No point in continuing if the loop is in a volatile state -- + * reschedule LOCAL_LOOP_UPDATE for later processing + */ + if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) { + set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags); + return (rval); + } + + entries = MAX_FIBRE_DEVICES; + id_list = pci_alloc_consistent(ha->pdev, MAX_ID_LIST_SIZE, + &id_list_dma); + if (id_list == NULL) { + DEBUG2(printk("scsi(%ld): Failed to allocate memory, No local " + "loop\n", ha->host_no)); + + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - port_list"); + + ha->mem_err++; + return (BIT_0); + } + memset(id_list, 0, MAX_ID_LIST_SIZE); + + DEBUG3(printk("scsi(%ld): Getting FCAL position map\n", ha->host_no)); + DEBUG3(qla2x00_get_fcal_position_map(ha, NULL)); + + /* Get list of logged in devices. */ + rval = qla2x00_get_id_list(ha, id_list, id_list_dma, &entries); + if (rval) { + rval = BIT_0; + goto cleanup_allocation; + } + + DEBUG3(printk("scsi(%ld): Entries in ID list (%d)\n", + ha->host_no, entries)); + DEBUG3(qla2x00_dump_buffer((uint8_t *)id_list, + entries * sizeof(struct dev_id))); + + /* Allocate temporary fcport for any new fcports discovered. */ + new_fcport = qla2x00_alloc_fcport(ha, GFP_KERNEL); + if (new_fcport == NULL) { + rval = BIT_0; + goto cleanup_allocation; + } + new_fcport->flags &= ~FCF_FABRIC_DEVICE; + + /* + * Mark local devices that were present with FCF_DEVICE_LOST for now. + */ + list_for_each_entry(fcport, &ha->fcports, list) { + if (atomic_read(&fcport->state) == FCS_ONLINE && + fcport->port_type != FCT_BROADCAST && + (fcport->flags & FCF_FABRIC_DEVICE) == 0) { + + DEBUG(printk("scsi(%ld): Marking port lost, " + "loop_id=0x%04x\n", + ha->host_no, fcport->loop_id)); + + atomic_set(&fcport->state, FCS_DEVICE_LOST); + fcport->flags &= ~FCF_FARP_DONE; + } + } + + /* Add devices to port list. */ + id_iter = (char *)id_list; + for (index = 0; index < entries; index++) { + domain = ((struct dev_id *)id_iter)->domain; + area = ((struct dev_id *)id_iter)->area; + al_pa = ((struct dev_id *)id_iter)->al_pa; + if (IS_QLA2100(ha) || IS_QLA2200(ha)) { + loop_id = + (uint16_t)((struct dev_id *)id_iter)->loop_id_2100; + id_iter += 4; + } else { + loop_id = + le16_to_cpu(((struct dev_id *)id_iter)->loop_id); + id_iter += 6; + } + + /* Bypass reserved domain fields. */ + if ((domain & 0xf0) == 0xf0) + continue; + + /* Bypass if not same domain and area of adapter. */ + if (area != ha->d_id.b.area || domain != ha->d_id.b.domain) + continue; + + /* Bypass invalid local loop ID. */ + if (loop_id > LAST_LOCAL_LOOP_ID) + continue; + + /* Fill in member data. */ + new_fcport->d_id.b.domain = domain; + new_fcport->d_id.b.area = area; + new_fcport->d_id.b.al_pa = al_pa; + new_fcport->loop_id = loop_id; + rval2 = qla2x00_get_port_database(ha, new_fcport, 0); + if (rval2 != QLA_SUCCESS) { + DEBUG2(printk("scsi(%ld): Failed to retrieve fcport " + "information -- get_port_database=%x, " + "loop_id=0x%04x\n", + ha->host_no, rval2, new_fcport->loop_id)); + continue; + } + + /* Check for matching device in port list. */ + found = 0; + fcport = NULL; + list_for_each_entry(fcport, &ha->fcports, list) { + if (memcmp(new_fcport->port_name, fcport->port_name, + WWN_SIZE)) + continue; + + fcport->flags &= ~(FCF_FABRIC_DEVICE | + FCF_PERSISTENT_BOUND); + fcport->loop_id = new_fcport->loop_id; + fcport->port_type = new_fcport->port_type; + fcport->d_id.b24 = new_fcport->d_id.b24; + memcpy(fcport->node_name, new_fcport->node_name, + WWN_SIZE); + + found++; + break; + } + + if (!found) { + /* New device, add to fcports list. */ + new_fcport->flags &= ~FCF_PERSISTENT_BOUND; + list_add_tail(&new_fcport->list, &ha->fcports); + + /* Allocate a new replacement fcport. */ + fcport = new_fcport; + new_fcport = qla2x00_alloc_fcport(ha, GFP_KERNEL); + if (new_fcport == NULL) { + rval = BIT_0; + goto cleanup_allocation; + } + new_fcport->flags &= ~FCF_FABRIC_DEVICE; + } + + qla2x00_update_fcport(ha, fcport); + + found_devs++; + } + +cleanup_allocation: + pci_free_consistent(ha->pdev, MAX_ID_LIST_SIZE, id_list, id_list_dma); + + if (new_fcport) + kfree(new_fcport); + + if (rval & BIT_0) { + DEBUG2(printk("scsi(%ld): Configure local loop error exit: " + "rval=%x\n", ha->host_no, rval)); + } + + if (found_devs) { + ha->device_flags |= DFLG_LOCAL_DEVICES; + ha->device_flags &= ~DFLG_RETRY_LOCAL_DEVICES; + } + + return (rval); +} + +/* + * qla2x00_update_fcport + * Updates device on list. + * + * Input: + * ha = adapter block pointer. + * fcport = port structure pointer. + * + * Return: + * 0 - Success + * BIT_0 - error + * + * Context: + * Kernel context. + */ +static void +qla2x00_update_fcport(scsi_qla_host_t *ha, fc_port_t *fcport) +{ + uint16_t index; + unsigned long flags; + srb_t *sp; + + fcport->ha = ha; + fcport->login_retry = 0; + fcport->port_login_retry_count = ha->port_down_retry_count * + PORT_RETRY_TIME; + atomic_set(&fcport->port_down_timer, ha->port_down_retry_count * + PORT_RETRY_TIME); + fcport->flags &= ~(FCF_FAILOVER_NEEDED | FCF_LOGIN_NEEDED); + + /* + * Check for outstanding cmd on tape Bypass LUN discovery if active + * command on tape. + */ + if (fcport->flags & FCF_TAPE_PRESENT) { + spin_lock_irqsave(&ha->hardware_lock, flags); + for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) { + if ((sp = ha->outstanding_cmds[index]) != 0) { + if (sp->fclun->fcport == fcport) { + atomic_set(&fcport->state, FCS_ONLINE); + spin_unlock_irqrestore( + &ha->hardware_lock, flags); + return; + } + } + } + spin_unlock_irqrestore(&ha->hardware_lock, flags); + } + + /* Do LUN discovery. */ + if (fcport->port_type == FCT_INITIATOR || + fcport->port_type == FCT_BROADCAST) { + fcport->device_type = TYPE_PROCESSOR; + } else { + qla2x00_lun_discovery(ha, fcport); + } + atomic_set(&fcport->state, FCS_ONLINE); +} + +/* + * qla2x00_lun_discovery + * Issue SCSI inquiry command for LUN discovery. + * + * Input: + * ha: adapter state pointer. + * fcport: FC port structure pointer. + * + * Context: + * Kernel context. + */ +static void +qla2x00_lun_discovery(scsi_qla_host_t *ha, fc_port_t *fcport) +{ + inq_cmd_rsp_t *inq; + dma_addr_t inq_dma; + uint16_t lun; + + inq = pci_alloc_consistent(ha->pdev, sizeof(inq_cmd_rsp_t), &inq_dma); + if (inq == NULL) { + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - INQ\n"); + return; + } + + /* If report LUN works, exit. */ + if (qla2x00_rpt_lun_discovery(ha, fcport, inq, inq_dma) != + QLA_SUCCESS) { + for (lun = 0; lun < ha->max_probe_luns; lun++) { + /* Configure LUN. */ + qla2x00_cfg_lun(ha, fcport, lun, inq, inq_dma); + } + } + + pci_free_consistent(ha->pdev, sizeof(inq_cmd_rsp_t), inq, inq_dma); +} + +/* + * qla2x00_rpt_lun_discovery + * Issue SCSI report LUN command for LUN discovery. + * + * Input: + * ha: adapter state pointer. + * fcport: FC port structure pointer. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +static int +qla2x00_rpt_lun_discovery(scsi_qla_host_t *ha, fc_port_t *fcport, + inq_cmd_rsp_t *inq, dma_addr_t inq_dma) +{ + int rval; + uint32_t len, cnt; + uint16_t lun; + rpt_lun_cmd_rsp_t *rlc; + dma_addr_t rlc_dma; + + /* Assume a failed status */ + rval = QLA_FUNCTION_FAILED; + + /* No point in continuing if the device doesn't support RLC */ + if ((fcport->flags & FCF_RLC_SUPPORT) == 0) + return (rval); + + rlc = pci_alloc_consistent(ha->pdev, sizeof(rpt_lun_cmd_rsp_t), + &rlc_dma); + if (rlc == NULL) { + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - RLC"); + return QLA_MEMORY_ALLOC_FAILED; + } + + rval = qla2x00_report_lun(ha, fcport, rlc, rlc_dma); + if (rval != QLA_SUCCESS) { + pci_free_consistent(ha->pdev, sizeof(rpt_lun_cmd_rsp_t), rlc, + rlc_dma); + return (rval); + } + + /* Always add a fc_lun_t structure for lun 0 -- mid-layer requirement */ + qla2x00_add_lun(fcport, 0); + + /* Configure LUN list. */ + len = be32_to_cpu(rlc->list.hdr.len); + len /= 8; + for (cnt = 0; cnt < len; cnt++) { + lun = CHAR_TO_SHORT(rlc->list.lst[cnt].lsb, + rlc->list.lst[cnt].msb.b); + + DEBUG3(printk("scsi(%ld): RLC lun = (%d)\n", ha->host_no, lun)); + + /* We only support 0 through MAX_LUNS-1 range */ + if (lun < MAX_LUNS) { + qla2x00_cfg_lun(ha, fcport, lun, inq, inq_dma); + } + } + atomic_set(&fcport->state, FCS_ONLINE); + + pci_free_consistent(ha->pdev, sizeof(rpt_lun_cmd_rsp_t), rlc, rlc_dma); + + return (rval); +} + +/* + * qla2x00_report_lun + * Issue SCSI report LUN command. + * + * Input: + * ha: adapter state pointer. + * fcport: FC port structure pointer. + * mem: pointer to dma memory object for report LUN IOCB + * packet. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +static int +qla2x00_report_lun(scsi_qla_host_t *ha, + fc_port_t *fcport, rpt_lun_cmd_rsp_t *rlc, dma_addr_t rlc_dma) +{ + int rval; + uint16_t retries; + uint16_t comp_status; + uint16_t scsi_status; + + rval = QLA_FUNCTION_FAILED; + + for (retries = 3; retries; retries--) { + memset(rlc, 0, sizeof(rpt_lun_cmd_rsp_t)); + rlc->p.cmd.entry_type = COMMAND_A64_TYPE; + rlc->p.cmd.entry_count = 1; + SET_TARGET_ID(ha, rlc->p.cmd.target, fcport->loop_id); + rlc->p.cmd.control_flags = + __constant_cpu_to_le16(CF_READ | CF_SIMPLE_TAG); + rlc->p.cmd.scsi_cdb[0] = REPORT_LUNS; + rlc->p.cmd.scsi_cdb[8] = MSB(sizeof(rpt_lun_lst_t)); + rlc->p.cmd.scsi_cdb[9] = LSB(sizeof(rpt_lun_lst_t)); + rlc->p.cmd.dseg_count = __constant_cpu_to_le16(1); + rlc->p.cmd.timeout = __constant_cpu_to_le16(10); + rlc->p.cmd.byte_count = + __constant_cpu_to_le32(sizeof(rpt_lun_lst_t)); + rlc->p.cmd.dseg_0_address[0] = cpu_to_le32( + LSD(rlc_dma + sizeof(sts_entry_t))); + rlc->p.cmd.dseg_0_address[1] = cpu_to_le32( + MSD(rlc_dma + sizeof(sts_entry_t))); + rlc->p.cmd.dseg_0_length = + __constant_cpu_to_le32(sizeof(rpt_lun_lst_t)); + + rval = qla2x00_issue_iocb(ha, rlc, rlc_dma, + sizeof(rpt_lun_cmd_rsp_t)); + + comp_status = le16_to_cpu(rlc->p.rsp.comp_status); + scsi_status = le16_to_cpu(rlc->p.rsp.scsi_status); + + if (rval != QLA_SUCCESS || comp_status != CS_COMPLETE || + scsi_status & SS_CHECK_CONDITION) { + + /* Device underrun, treat as OK. */ + if (rval == QLA_SUCCESS && + comp_status == CS_DATA_UNDERRUN && + scsi_status & SS_RESIDUAL_UNDER) { + + rval = QLA_SUCCESS; + break; + } + + DEBUG(printk("scsi(%ld): RLC failed to issue iocb! " + "fcport=[%04x/%p] rval=%x cs=%x ss=%x\n", + ha->host_no, fcport->loop_id, fcport, rval, + comp_status, scsi_status)); + + rval = QLA_FUNCTION_FAILED; + if (scsi_status & SS_CHECK_CONDITION) { + DEBUG2(printk("scsi(%ld): RLC " + "SS_CHECK_CONDITION Sense Data " + "%02x %02x %02x %02x %02x %02x %02x %02x\n", + ha->host_no, + rlc->p.rsp.req_sense_data[0], + rlc->p.rsp.req_sense_data[1], + rlc->p.rsp.req_sense_data[2], + rlc->p.rsp.req_sense_data[3], + rlc->p.rsp.req_sense_data[4], + rlc->p.rsp.req_sense_data[5], + rlc->p.rsp.req_sense_data[6], + rlc->p.rsp.req_sense_data[7])); + if (rlc->p.rsp.req_sense_data[2] == + ILLEGAL_REQUEST) { + fcport->flags &= ~(FCF_RLC_SUPPORT); + break; + } + } + } else { + break; + } + } + + return (rval); +} + +/* + * qla2x00_cfg_lun + * Configures LUN into fcport LUN list. + * + * Input: + * fcport: FC port structure pointer. + * lun: LUN number. + * + * Context: + * Kernel context. + */ +static fc_lun_t * +qla2x00_cfg_lun(scsi_qla_host_t *ha, fc_port_t *fcport, uint16_t lun, + inq_cmd_rsp_t *inq, dma_addr_t inq_dma) +{ + fc_lun_t *fclun; + + /* Bypass LUNs that failed. */ + if (qla2x00_inquiry(ha, fcport, lun, inq, inq_dma) != QLA_SUCCESS) { + DEBUG2(printk("scsi(%ld): Failed inquiry - loop id=0x%04x " + "lun=%d\n", ha->host_no, fcport->loop_id, lun)); + + return (NULL); + } + + switch (inq->inq[0]) { + case TYPE_DISK: + case TYPE_PROCESSOR: + case TYPE_WORM: + case TYPE_ROM: + case TYPE_SCANNER: + case TYPE_MOD: + case TYPE_MEDIUM_CHANGER: + case TYPE_ENCLOSURE: + case 0x20: + break; + case TYPE_TAPE: + fcport->flags |= FCF_TAPE_PRESENT; + break; + default: + DEBUG2(printk("scsi(%ld): Unsupported lun type -- " + "loop id=0x%04x lun=%d type=%x\n", + ha->host_no, fcport->loop_id, lun, inq->inq[0])); + return (NULL); + } + + fcport->device_type = inq->inq[0]; + fclun = qla2x00_add_lun(fcport, lun); + + if (fclun != NULL) { + atomic_set(&fcport->state, FCS_ONLINE); + } + + return (fclun); +} + +/* + * qla2x00_add_lun + * Adds LUN to database + * + * Input: + * fcport: FC port structure pointer. + * lun: LUN number. + * + * Context: + * Kernel context. + */ +static fc_lun_t * +qla2x00_add_lun(fc_port_t *fcport, uint16_t lun) +{ + int found; + fc_lun_t *fclun; + + if (fcport == NULL) { + DEBUG(printk("scsi: Unable to add lun to NULL port\n")); + return (NULL); + } + + /* Allocate LUN if not already allocated. */ + found = 0; + list_for_each_entry(fclun, &fcport->fcluns, list) { + if (fclun->lun == lun) { + found++; + break; + } + } + if (found) + return (NULL); + + fclun = kmalloc(sizeof(fc_lun_t), GFP_ATOMIC); + if (fclun == NULL) { + printk(KERN_WARNING + "%s(): Memory Allocation failed - FCLUN\n", + __func__); + return (NULL); + } + + /* Setup LUN structure. */ + memset(fclun, 0, sizeof(fc_lun_t)); + fclun->lun = lun; + fclun->fcport = fcport; + fclun->o_fcport = fcport; + fclun->device_type = fcport->device_type; + atomic_set(&fcport->state, FCS_UNCONFIGURED); + + list_add_tail(&fclun->list, &fcport->fcluns); + + return (fclun); +} + +/* + * qla2x00_inquiry + * Issue SCSI inquiry command. + * + * Input: + * ha = adapter block pointer. + * fcport = FC port structure pointer. + * + * Return: + * 0 - Success + * BIT_0 - error + * + * Context: + * Kernel context. + */ +static int +qla2x00_inquiry(scsi_qla_host_t *ha, + fc_port_t *fcport, uint16_t lun, inq_cmd_rsp_t *inq, dma_addr_t inq_dma) +{ + int rval; + uint16_t retries; + uint16_t comp_status; + uint16_t scsi_status; + + rval = QLA_FUNCTION_FAILED; + + for (retries = 3; retries; retries--) { + memset(inq, 0, sizeof(inq_cmd_rsp_t)); + inq->p.cmd.entry_type = COMMAND_A64_TYPE; + inq->p.cmd.entry_count = 1; + inq->p.cmd.lun = cpu_to_le16(lun); + SET_TARGET_ID(ha, inq->p.cmd.target, fcport->loop_id); + inq->p.cmd.control_flags = + __constant_cpu_to_le16(CF_READ | CF_SIMPLE_TAG); + inq->p.cmd.scsi_cdb[0] = INQUIRY; + inq->p.cmd.scsi_cdb[4] = INQ_DATA_SIZE; + inq->p.cmd.dseg_count = __constant_cpu_to_le16(1); + inq->p.cmd.timeout = __constant_cpu_to_le16(10); + inq->p.cmd.byte_count = + __constant_cpu_to_le32(INQ_DATA_SIZE); + inq->p.cmd.dseg_0_address[0] = cpu_to_le32( + LSD(inq_dma + sizeof(sts_entry_t))); + inq->p.cmd.dseg_0_address[1] = cpu_to_le32( + MSD(inq_dma + sizeof(sts_entry_t))); + inq->p.cmd.dseg_0_length = + __constant_cpu_to_le32(INQ_DATA_SIZE); + + DEBUG5(printk("scsi(%ld): Lun Inquiry - fcport=[%04x/%p]," + " lun (%d)\n", + ha->host_no, fcport->loop_id, fcport, lun)); + + rval = qla2x00_issue_iocb(ha, inq, inq_dma, + sizeof(inq_cmd_rsp_t)); + + comp_status = le16_to_cpu(inq->p.rsp.comp_status); + scsi_status = le16_to_cpu(inq->p.rsp.scsi_status); + + DEBUG5(printk("scsi(%ld): lun (%d) inquiry - " + "inq[0]= 0x%x, comp status 0x%x, scsi status 0x%x, " + "rval=%d\n", + ha->host_no, lun, inq->inq[0], comp_status, scsi_status, + rval)); + + if (rval != QLA_SUCCESS || comp_status != CS_COMPLETE || + scsi_status & SS_CHECK_CONDITION) { + + DEBUG(printk("scsi(%ld): INQ failed to issue iocb! " + "fcport=[%04x/%p] rval=%x cs=%x ss=%x\n", + ha->host_no, fcport->loop_id, fcport, rval, + comp_status, scsi_status)); + + if (rval == QLA_SUCCESS) + rval = QLA_FUNCTION_FAILED; + + if (scsi_status & SS_CHECK_CONDITION) { + DEBUG2(printk("scsi(%ld): INQ " + "SS_CHECK_CONDITION Sense Data " + "%02x %02x %02x %02x %02x %02x %02x %02x\n", + ha->host_no, + inq->p.rsp.req_sense_data[0], + inq->p.rsp.req_sense_data[1], + inq->p.rsp.req_sense_data[2], + inq->p.rsp.req_sense_data[3], + inq->p.rsp.req_sense_data[4], + inq->p.rsp.req_sense_data[5], + inq->p.rsp.req_sense_data[6], + inq->p.rsp.req_sense_data[7])); + } + + /* Device underrun drop LUN. */ + if (comp_status == CS_DATA_UNDERRUN && + scsi_status & SS_RESIDUAL_UNDER) { + break; + } + } else { + break; + } + } + + return (rval); +} + + +/* + * qla2x00_configure_fabric + * Setup SNS devices with loop ID's. + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * 0 = success. + * BIT_0 = error + */ +static int +qla2x00_configure_fabric(scsi_qla_host_t *ha) +{ + int rval, rval2; + fc_port_t *fcport, *fcptemp; + uint16_t next_loopid; + LIST_HEAD(new_fcports); + + /* If FL port exists, then SNS is present */ + rval = qla2x00_get_port_name(ha, SNS_FL_PORT, NULL, 0); + if (rval != QLA_SUCCESS) { + DEBUG2(printk("scsi(%ld): MBC_GET_PORT_NAME Failed, No FL " + "Port\n", ha->host_no)); + + ha->device_flags &= ~SWITCH_FOUND; + return (QLA_SUCCESS); + } + + /* Mark devices that need re-synchronization. */ + rval2 = qla2x00_device_resync(ha); + if (rval2 == QLA_RSCNS_HANDLED) { + /* No, point doing the scan, just continue. */ + return (QLA_SUCCESS); + } + do { + if (test_and_clear_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags)) { + if (qla2x00_rft_id(ha)) { + /* EMPTY */ + DEBUG2(printk("scsi(%ld): Register FC-4 " + "TYPE failed.\n", ha->host_no)); + } + if (qla2x00_rff_id(ha)) { + /* EMPTY */ + DEBUG2(printk("scsi(%ld): Register FC-4 " + "Features failed.\n", ha->host_no)); + } + if (qla2x00_rnn_id(ha)) { + /* EMPTY */ + DEBUG2(printk("scsi(%ld): Register Node Name " + "failed.\n", ha->host_no)); + } else if (qla2x00_rsnn_nn(ha)) { + /* EMPTY */ + DEBUG2(printk("scsi(%ld): Register Symbolic " + "Node Name failed.\n", ha->host_no)); + } + } + + rval = qla2x00_find_all_fabric_devs(ha, &new_fcports); + if (rval != QLA_SUCCESS) + break; + + /* + * Logout all previous fabric devices marked lost, except + * tape devices. + */ + list_for_each_entry(fcport, &ha->fcports, list) { + if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) + break; + + if ((fcport->flags & FCF_FABRIC_DEVICE) == 0) + continue; + + if (atomic_read(&fcport->state) == FCS_DEVICE_LOST) { + qla2x00_mark_device_lost(ha, fcport, + ql2xplogiabsentdevice); + if (fcport->loop_id != FC_NO_LOOP_ID && + (fcport->flags & FCF_TAPE_PRESENT) == 0 && + fcport->port_type != FCT_INITIATOR && + fcport->port_type != FCT_BROADCAST) { + + qla2x00_fabric_logout(ha, + fcport->loop_id); + fcport->loop_id = FC_NO_LOOP_ID; + } + } + } + + /* Starting free loop ID. */ + next_loopid = ha->min_external_loopid; + + /* + * Scan through our port list and login entries that need to be + * logged in. + */ + list_for_each_entry(fcport, &ha->fcports, list) { + if (atomic_read(&ha->loop_down_timer) || + test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) + break; + + if ((fcport->flags & FCF_FABRIC_DEVICE) == 0 || + (fcport->flags & FCF_LOGIN_NEEDED) == 0) + continue; + + if (fcport->loop_id == FC_NO_LOOP_ID) { + fcport->loop_id = next_loopid; + rval = qla2x00_find_new_loop_id(ha, fcport); + if (rval != QLA_SUCCESS) { + /* Ran out of IDs to use */ + break; + } + } + + /* Login and update database */ + qla2x00_fabric_dev_login(ha, fcport, &next_loopid); + } + + /* Exit if out of loop IDs. */ + if (rval != QLA_SUCCESS) { + break; + } + + /* + * Login and add the new devices to our port list. + */ + list_for_each_entry_safe(fcport, fcptemp, &new_fcports, list) { + if (atomic_read(&ha->loop_down_timer) || + test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) + break; + + /* Find a new loop ID to use. */ + fcport->loop_id = next_loopid; + rval = qla2x00_find_new_loop_id(ha, fcport); + if (rval != QLA_SUCCESS) { + /* Ran out of IDs to use */ + break; + } + + /* Login and update database */ + qla2x00_fabric_dev_login(ha, fcport, &next_loopid); + + /* Remove device from the new list and add it to DB */ + list_del(&fcport->list); + list_add_tail(&fcport->list, &ha->fcports); + } + } while (0); + + /* Free all new device structures not processed. */ + list_for_each_entry_safe(fcport, fcptemp, &new_fcports, list) { + list_del(&fcport->list); + kfree(fcport); + } + + if (rval) { + DEBUG2(printk("scsi(%ld): Configure fabric error exit: " + "rval=%d\n", ha->host_no, rval)); + } + + return (rval); +} + + +/* + * qla2x00_find_all_fabric_devs + * + * Input: + * ha = adapter block pointer. + * dev = database device entry pointer. + * + * Returns: + * 0 = success. + * BIT_0 = error. + * + * Context: + * Kernel context. + */ +static int +qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports) +{ + int rval; + uint16_t loop_id; + fc_port_t *fcport, *new_fcport; + int found; + + sw_info_t *swl; + int swl_idx; + int first_dev, last_dev; + port_id_t wrap, nxt_d_id; + + rval = QLA_SUCCESS; + + /* Try GID_PT to get device list, else GAN. */ + swl = kmalloc(sizeof(sw_info_t) * MAX_FIBRE_DEVICES, GFP_ATOMIC); + if (swl == NULL) { + /*EMPTY*/ + DEBUG2(printk("scsi(%ld): GID_PT allocations failed, fallback " + "on GA_NXT\n", ha->host_no)); + } else { + memset(swl, 0, sizeof(sw_info_t) * MAX_FIBRE_DEVICES); + if (qla2x00_gid_pt(ha, swl) != QLA_SUCCESS) { + kfree(swl); + swl = NULL; + } else if (qla2x00_gpn_id(ha, swl) != QLA_SUCCESS) { + kfree(swl); + swl = NULL; + } else if (qla2x00_gnn_id(ha, swl) != QLA_SUCCESS) { + kfree(swl); + swl = NULL; + } + } + swl_idx = 0; + + /* Allocate temporary fcport for any new fcports discovered. */ + new_fcport = qla2x00_alloc_fcport(ha, GFP_KERNEL); + if (new_fcport == NULL) { + if (swl) + kfree(swl); + return (QLA_MEMORY_ALLOC_FAILED); + } + new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED); + + /* Set start port ID scan at adapter ID. */ + first_dev = 1; + last_dev = 0; + + /* Starting free loop ID. */ + loop_id = ha->min_external_loopid; + + for (; loop_id <= ha->last_loop_id; loop_id++) { + if (RESERVED_LOOP_ID(loop_id)) + continue; + + if (atomic_read(&ha->loop_down_timer) || + test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) + break; + + if (swl != NULL) { + if (last_dev) { + wrap.b24 = new_fcport->d_id.b24; + } else { + new_fcport->d_id.b24 = swl[swl_idx].d_id.b24; + memcpy(new_fcport->node_name, + swl[swl_idx].node_name, WWN_SIZE); + memcpy(new_fcport->port_name, + swl[swl_idx].port_name, WWN_SIZE); + + if (swl[swl_idx].d_id.b.rsvd_1 != 0) { + last_dev = 1; + } + swl_idx++; + } + } else { + /* Send GA_NXT to the switch */ + rval = qla2x00_ga_nxt(ha, new_fcport); + if (rval != QLA_SUCCESS) { + break; + } + } + + /* If wrap on switch device list, exit. */ + if (first_dev) { + wrap.b24 = new_fcport->d_id.b24; + first_dev = 0; + } else if (new_fcport->d_id.b24 == wrap.b24) { + DEBUG2(printk("scsi(%ld): device wrap (%02x%02x%02x)\n", + ha->host_no, new_fcport->d_id.b.domain, + new_fcport->d_id.b.area, new_fcport->d_id.b.al_pa)); + break; + } + + /* Bypass if host adapter. */ + if (new_fcport->d_id.b24 == ha->d_id.b24) + continue; + + /* Bypass reserved domain fields. */ + if ((new_fcport->d_id.b.domain & 0xf0) == 0xf0) + continue; + + /* Bypass if same domain and area of adapter. */ + if ((new_fcport->d_id.b24 & 0xffff00) == + (ha->d_id.b24 & 0xffff00)) + continue; + + /* Locate matching device in database. */ + found = 0; + list_for_each_entry(fcport, &ha->fcports, list) { + if (memcmp(new_fcport->port_name, fcport->port_name, + WWN_SIZE)) + continue; + + found++; + + /* + * If device was not a fabric device before. + */ + if ((fcport->flags & FCF_FABRIC_DEVICE) == 0) { + fcport->d_id.b24 = new_fcport->d_id.b24; + fcport->loop_id = FC_NO_LOOP_ID; + fcport->flags |= (FCF_FABRIC_DEVICE | + FCF_LOGIN_NEEDED); + fcport->flags &= ~FCF_PERSISTENT_BOUND; + break; + } + + /* + * If address the same and state FCS_ONLINE, nothing + * changed. + */ + if (fcport->d_id.b24 == new_fcport->d_id.b24 && + atomic_read(&fcport->state) == FCS_ONLINE) { + break; + } + + /* + * Port ID changed or device was marked to be updated; + * Log it out if still logged in and mark it for + * relogin later. + */ + fcport->d_id.b24 = new_fcport->d_id.b24; + fcport->flags |= FCF_LOGIN_NEEDED; + if (fcport->loop_id != FC_NO_LOOP_ID && + (fcport->flags & FCF_TAPE_PRESENT) == 0 && + fcport->port_type != FCT_INITIATOR && + fcport->port_type != FCT_BROADCAST) { + qla2x00_fabric_logout(ha, fcport->loop_id); + fcport->loop_id = FC_NO_LOOP_ID; + } + + break; + } + + if (found) + continue; + + /* If device was not in our fcports list, then add it. */ + list_add_tail(&new_fcport->list, new_fcports); + + /* Allocate a new replacement fcport. */ + nxt_d_id.b24 = new_fcport->d_id.b24; + new_fcport = qla2x00_alloc_fcport(ha, GFP_KERNEL); + if (new_fcport == NULL) { + if (swl) + kfree(swl); + return (QLA_MEMORY_ALLOC_FAILED); + } + new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED); + new_fcport->d_id.b24 = nxt_d_id.b24; + } + + if (swl) + kfree(swl); + + if (new_fcport) + kfree(new_fcport); + + if (!list_empty(new_fcports)) + ha->device_flags |= DFLG_FABRIC_DEVICES; + + return (rval); +} + +/* + * qla2x00_find_new_loop_id + * Scan through our port list and find a new usable loop ID. + * + * Input: + * ha: adapter state pointer. + * dev: port structure pointer. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_find_new_loop_id(scsi_qla_host_t *ha, fc_port_t *dev) +{ + int rval; + int found; + fc_port_t *fcport; + uint16_t first_loop_id; + + rval = QLA_SUCCESS; + + /* Save starting loop ID. */ + first_loop_id = dev->loop_id; + + for (;;) { + /* Skip loop ID if already used by adapter. */ + if (dev->loop_id == ha->loop_id) { + dev->loop_id++; + } + + /* Skip reserved loop IDs. */ + while (RESERVED_LOOP_ID(dev->loop_id)) { + dev->loop_id++; + } + + /* Reset loop ID if passed the end. */ + if (dev->loop_id > ha->last_loop_id) { + /* first loop ID. */ + dev->loop_id = ha->min_external_loopid; + } + + /* Check for loop ID being already in use. */ + found = 0; + fcport = NULL; + list_for_each_entry(fcport, &ha->fcports, list) { + if (fcport->loop_id == dev->loop_id && fcport != dev) { + /* ID possibly in use */ + found++; + break; + } + } + + /* If not in use then it is free to use. */ + if (!found) { + break; + } + + /* ID in use. Try next value. */ + dev->loop_id++; + + /* If wrap around. No free ID to use. */ + if (dev->loop_id == first_loop_id) { + dev->loop_id = FC_NO_LOOP_ID; + rval = QLA_FUNCTION_FAILED; + break; + } + } + + return (rval); +} + +/* + * qla2x00_device_resync + * Marks devices in the database that needs resynchronization. + * + * Input: + * ha = adapter block pointer. + * + * Context: + * Kernel context. + */ +static int +qla2x00_device_resync(scsi_qla_host_t *ha) +{ + int rval; + int rval2; + uint32_t mask; + fc_port_t *fcport; + uint32_t rscn_entry; + uint8_t rscn_out_iter; + uint8_t format; + port_id_t d_id; + + rval = QLA_RSCNS_HANDLED; + + while (ha->rscn_out_ptr != ha->rscn_in_ptr || + ha->flags.rscn_queue_overflow) { + + rscn_entry = ha->rscn_queue[ha->rscn_out_ptr]; + format = MSB(MSW(rscn_entry)); + d_id.b.domain = LSB(MSW(rscn_entry)); + d_id.b.area = MSB(LSW(rscn_entry)); + d_id.b.al_pa = LSB(LSW(rscn_entry)); + + DEBUG(printk("scsi(%ld): RSCN queue entry[%d] = " + "[%02x/%02x%02x%02x].\n", + ha->host_no, ha->rscn_out_ptr, format, d_id.b.domain, + d_id.b.area, d_id.b.al_pa)); + + ha->rscn_out_ptr++; + if (ha->rscn_out_ptr == MAX_RSCN_COUNT) + ha->rscn_out_ptr = 0; + + /* Skip duplicate entries. */ + for (rscn_out_iter = ha->rscn_out_ptr; + !ha->flags.rscn_queue_overflow && + rscn_out_iter != ha->rscn_in_ptr; + rscn_out_iter = (rscn_out_iter == + (MAX_RSCN_COUNT - 1)) ? 0: rscn_out_iter + 1) { + + if (rscn_entry != ha->rscn_queue[rscn_out_iter]) + break; + + DEBUG(printk("scsi(%ld): Skipping duplicate RSCN queue " + "entry found at [%d].\n", ha->host_no, + rscn_out_iter)); + + ha->rscn_out_ptr = rscn_out_iter; + } + + /* Queue overflow, set switch default case. */ + if (ha->flags.rscn_queue_overflow) { + DEBUG(printk("scsi(%ld): device_resync: rscn " + "overflow.\n", ha->host_no)); + + format = 3; + ha->flags.rscn_queue_overflow = 0; + } + + switch (format) { + case 0: + if (IS_QLA23XX(ha) && ha->flags.init_done) { + /* Handle port RSCN via asyncronous IOCBs */ + rval2 = qla2x00_handle_port_rscn(ha, rscn_entry, + NULL, 0); + if (rval2 == QLA_SUCCESS) + continue; + } + mask = 0xffffff; + break; + case 1: + mask = 0xffff00; + break; + case 2: + mask = 0xff0000; + break; + default: + mask = 0x0; + d_id.b24 = 0; + ha->rscn_out_ptr = ha->rscn_in_ptr; + break; + } + + rval = QLA_SUCCESS; + + /* Abort any outstanding IO descriptors. */ + if (IS_QLA23XX(ha)) + qla2x00_cancel_io_descriptors(ha); + + list_for_each_entry(fcport, &ha->fcports, list) { + if ((fcport->flags & FCF_FABRIC_DEVICE) == 0 || + (fcport->d_id.b24 & mask) != d_id.b24 || + fcport->port_type == FCT_BROADCAST) + continue; + + if (atomic_read(&fcport->state) == FCS_ONLINE) { + if (format != 3 || + fcport->port_type != FCT_INITIATOR) { + atomic_set(&fcport->state, + FCS_DEVICE_LOST); + } + } + fcport->flags &= ~FCF_FARP_DONE; + } + } + return (rval); +} + +/* + * qla2x00_fabric_dev_login + * Login fabric target device and update FC port database. + * + * Input: + * ha: adapter state pointer. + * fcport: port structure list pointer. + * next_loopid: contains value of a new loop ID that can be used + * by the next login attempt. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +static int +qla2x00_fabric_dev_login(scsi_qla_host_t *ha, fc_port_t *fcport, + uint16_t *next_loopid) +{ + int rval; + int retry; + + rval = QLA_SUCCESS; + retry = 0; + + rval = qla2x00_fabric_login(ha, fcport, next_loopid); + if (rval == QLA_SUCCESS) { + rval = qla2x00_get_port_database(ha, fcport, BIT_1 | BIT_0); + if (rval != QLA_SUCCESS) { + qla2x00_fabric_logout(ha, fcport->loop_id); + } else { + qla2x00_update_fcport(ha, fcport); + } + } + + return (rval); +} + +/* + * qla2x00_fabric_login + * Issue fabric login command. + * + * Input: + * ha = adapter block pointer. + * device = pointer to FC device type structure. + * + * Returns: + * 0 - Login successfully + * 1 - Login failed + * 2 - Initiator device + * 3 - Fatal error + */ +int +qla2x00_fabric_login(scsi_qla_host_t *ha, fc_port_t *fcport, + uint16_t *next_loopid) +{ + int rval; + int retry; + uint16_t tmp_loopid; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + + retry = 0; + tmp_loopid = 0; + + for (;;) { + DEBUG(printk("scsi(%ld): Trying Fabric Login w/loop id 0x%04x " + "for port %02x%02x%02x.\n", + ha->host_no, fcport->loop_id, fcport->d_id.b.domain, + fcport->d_id.b.area, fcport->d_id.b.al_pa)); + + /* Login fcport on switch. */ + qla2x00_login_fabric(ha, fcport->loop_id, + fcport->d_id.b.domain, fcport->d_id.b.area, + fcport->d_id.b.al_pa, mb, BIT_0); + if (mb[0] == MBS_PORT_ID_USED) { + /* + * Device has another loop ID. The firmware team + * recommends us to perform an implicit login with the + * specified ID again. The ID we just used is save here + * so we return with an ID that can be tried by the + * next login. + */ + retry++; + tmp_loopid = fcport->loop_id; + fcport->loop_id = mb[1]; + + DEBUG(printk("Fabric Login: port in use - next " + "loop id=0x%04x, port Id=%02x%02x%02x.\n", + fcport->loop_id, fcport->d_id.b.domain, + fcport->d_id.b.area, fcport->d_id.b.al_pa)); + + } else if (mb[0] == MBS_COMMAND_COMPLETE) { + /* + * Login succeeded. + */ + if (retry) { + /* A retry occurred before. */ + *next_loopid = tmp_loopid; + } else { + /* + * No retry occurred before. Just increment the + * ID value for next login. + */ + *next_loopid = (fcport->loop_id + 1); + } + + if (mb[1] & BIT_0) { + fcport->port_type = FCT_INITIATOR; + } else { + fcport->port_type = FCT_TARGET; + if (mb[1] & BIT_1) { + fcport->flags |= FCF_TAPE_PRESENT; + } + } + + rval = QLA_SUCCESS; + break; + } else if (mb[0] == MBS_LOOP_ID_USED) { + /* + * Loop ID already used, try next loop ID. + */ + fcport->loop_id++; + rval = qla2x00_find_new_loop_id(ha, fcport); + if (rval != QLA_SUCCESS) { + /* Ran out of loop IDs to use */ + break; + } + } else if (mb[0] == MBS_COMMAND_ERROR) { + /* + * Firmware possibly timed out during login. If NO + * retries are left to do then the device is declared + * dead. + */ + *next_loopid = fcport->loop_id; + qla2x00_fabric_logout(ha, fcport->loop_id); + fcport->loop_id = FC_NO_LOOP_ID; + + rval = 3; + break; + } else { + /* + * unrecoverable / not handled error + */ + DEBUG2(printk("%s(%ld): failed=%x port_id=%02x%02x%02x " + "loop_id=%x jiffies=%lx.\n", + __func__, ha->host_no, mb[0], + fcport->d_id.b.domain, fcport->d_id.b.area, + fcport->d_id.b.al_pa, fcport->loop_id, jiffies)); + + *next_loopid = fcport->loop_id; + qla2x00_fabric_logout(ha, fcport->loop_id); + fcport->loop_id = FC_NO_LOOP_ID; + atomic_set(&fcport->state, FCS_DEVICE_DEAD); + + rval = 1; + break; + } + } + + return (rval); +} + +/* + * qla2x00_local_device_login + * Issue local device login command. + * + * Input: + * ha = adapter block pointer. + * loop_id = loop id of device to login to. + * + * Returns (Where's the #define!!!!): + * 0 - Login successfully + * 1 - Login failed + * 3 - Fatal error + */ +int +qla2x00_local_device_login(scsi_qla_host_t *ha, uint16_t loop_id) +{ + int rval; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + + memset(mb, 0, sizeof(mb)); + rval = qla2x00_login_local_device(ha, loop_id, mb, BIT_0); + if (rval == QLA_SUCCESS) { + /* Interrogate mailbox registers for any errors */ + if (mb[0] == MBS_COMMAND_ERROR) + rval = 1; + else if (mb[0] == MBS_COMMAND_PARAMETER_ERROR) + /* device not in PCB table */ + rval = 3; + } + + return (rval); +} + +/* + * qla2x00_loop_resync + * Resync with fibre channel devices. + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * 0 = success + */ +int +qla2x00_loop_resync(scsi_qla_host_t *ha) +{ + int rval; + + rval = QLA_SUCCESS; + + atomic_set(&ha->loop_state, LOOP_UPDATE); + qla2x00_stats.loop_resync++; + clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags); + if (ha->flags.online) { + if (!(rval = qla2x00_fw_ready(ha))) { + do { + /* v2.19.05b6 */ + atomic_set(&ha->loop_state, LOOP_UPDATE); + + /* + * Issue marker command only when we are going + * to start the I/O . + */ + ha->marker_needed = 1; + + /* Remap devices on Loop. */ + clear_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); + + qla2x00_configure_loop(ha); + + } while (!atomic_read(&ha->loop_down_timer) && + !(test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) && + (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))); + } + qla2x00_restart_queues(ha,TRUE); + } + + if (test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) { + return (QLA_FUNCTION_FAILED); + } + + if (rval) { + DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__)); + } + + return (rval); +} + +/* + * qla2x00_restart_queues + * Restart device queues. + * + * Input: + * ha = adapter block pointer. + * + * Context: + * Kernel/Interrupt context. + */ +void +qla2x00_restart_queues(scsi_qla_host_t *ha, uint8_t flush) +{ + srb_t *sp; + int retry_q_cnt = 0; + int pending_q_cnt = 0; + struct list_head *list, *temp; + unsigned long flags = 0; + + ENTER(__func__); + + clear_bit(RESTART_QUEUES_NEEDED, &ha->dpc_flags); + + /* + * start pending queue + */ + pending_q_cnt = ha->qthreads; + if (flush) { + spin_lock_irqsave(&ha->list_lock,flags); + list_for_each_safe(list, temp, &ha->pending_queue) { + sp = list_entry(list, srb_t, list); + /* + * When time expire return request back to OS as BUSY + */ + __del_from_pending_queue(ha, sp); + sp->cmd->result = DID_BUS_BUSY << 16; + sp->cmd->host_scribble = (unsigned char *)NULL; + __add_to_done_queue(ha, sp); + } + spin_unlock_irqrestore(&ha->list_lock, flags); + } else { + if (!list_empty(&ha->pending_queue)) + qla2x00_next(ha); + } + + /* + * Clear out our retry queue + */ + if (flush) { + spin_lock_irqsave(&ha->list_lock, flags); + retry_q_cnt = ha->retry_q_cnt; + list_for_each_safe(list, temp, &ha->retry_queue) { + sp = list_entry(list, srb_t, list); + /* when time expire return request back to OS as BUSY */ + __del_from_retry_queue(ha, sp); + sp->cmd->result = DID_BUS_BUSY << 16; + sp->cmd->host_scribble = (unsigned char *)NULL; + __add_to_done_queue(ha, sp); + } + spin_unlock_irqrestore(&ha->list_lock, flags); + + DEBUG2(printk("%s(%ld): callback %d commands.\n", + __func__, + ha->host_no, + retry_q_cnt);) + } + + DEBUG2(printk("%s(%ld): active=%ld, retry=%d, pending=%d, " + "done=%ld, failover=%d, scsi retry=%d commands.\n", + __func__, + ha->host_no, + ha->actthreads, + ha->retry_q_cnt, + pending_q_cnt, + ha->done_q_cnt, + ha->failover_cnt, + ha->scsi_retry_q_cnt);) + + if (qla2x00_failover_enabled(ha)) + qla2xxx_start_all_adapters(ha); + if (!list_empty(&ha->done_queue)) + qla2x00_done(ha); + + LEAVE(__func__); +} + +//FIXME - Document +void +qla2x00_rescan_fcports(scsi_qla_host_t *ha) +{ + int rescan_done; + fc_port_t *fcport; + + rescan_done = 0; + list_for_each_entry(fcport, &ha->fcports, list) { + if ((fcport->flags & FCF_RESCAN_NEEDED) == 0) + continue; + + qla2x00_update_fcport(ha, fcport); + fcport->flags &= ~FCF_RESCAN_NEEDED; + + rescan_done = 1; + } + + /* Update OS target and lun structures if necessary. */ + if (rescan_done) + qla2x00_config_os(ha); +} + + +/* + * qla2x00_config_os + * Setup OS target and LUN structures. + * + * Input: + * ha = adapter state pointer. + * + * Context: + * Kernel context. + */ +static void +qla2x00_config_os(scsi_qla_host_t *ha) +{ + fc_port_t *fcport; + fc_lun_t *fclun; + os_tgt_t *tq; + uint16_t tgt; + + + for (tgt = 0; tgt < MAX_TARGETS; tgt++) { + if ((tq = TGT_Q(ha, tgt)) == NULL) + continue; + + tq->flags &= ~TQF_ONLINE; + } + + list_for_each_entry(fcport, &ha->fcports, list) { + if (atomic_read(&fcport->state) != FCS_ONLINE || + fcport->port_type == FCT_INITIATOR || + fcport->port_type == FCT_BROADCAST) { + fcport->os_target_id = MAX_TARGETS; + continue; + } + + if (fcport->flags & FCF_FO_MASKED) { + continue; + } + + /* Bind FC port to OS target number. */ + if (qla2x00_fcport_bind(ha, fcport) == MAX_TARGETS) { + continue; + } + + /* Bind FC LUN to OS LUN number. */ + list_for_each_entry(fclun, &fcport->fcluns, list) { + qla2x00_fclun_bind(ha, fcport, fclun); + } + } +} + +/* + * qla2x00_fcport_bind + * Locates a target number for FC port. + * + * Input: + * ha = adapter state pointer. + * fcport = FC port structure pointer. + * + * Returns: + * target number + * + * Context: + * Kernel context. + */ +static uint16_t +qla2x00_fcport_bind(scsi_qla_host_t *ha, fc_port_t *fcport) +{ + uint16_t tgt; + os_tgt_t *tq; + + /* Check for persistent binding. */ + for (tgt = 0; tgt < MAX_TARGETS; tgt++) { + if ((tq = TGT_Q(ha, tgt)) == NULL) + continue; + + if (ha->binding_type == BIND_BY_PORT_ID && + fcport->d_id.b24 == tq->d_id.b24) { + memcpy(tq->node_name, fcport->node_name, WWN_SIZE); + memcpy(tq->port_name, fcport->port_name, WWN_SIZE); + break; + } + + if (memcmp(fcport->port_name, tq->port_name, WWN_SIZE) == 0) { + /* In case of persistent binding, update the WWNN */ + memcpy(tq->node_name, fcport->node_name, WWN_SIZE); + break; + } + } + + /* TODO: honor the ConfigRequired flag */ + if (tgt == MAX_TARGETS) { + /* Check if targetID 0 available. */ + tgt = 0; + + if (TGT_Q(ha, tgt) != NULL) { + /* Locate first free target for device. */ + for (tgt = 0; tgt < MAX_TARGETS; tgt++) { + if (TGT_Q(ha, tgt) == NULL) { + break; + } + } + } + if (tgt != MAX_TARGETS) { + if ((tq = qla2x00_tgt_alloc(ha, tgt)) != NULL) { + memcpy(tq->node_name, fcport->node_name, + WWN_SIZE); + memcpy(tq->port_name, fcport->port_name, + WWN_SIZE); + tq->d_id.b24 = fcport->d_id.b24; + } + } + } + + /* Reset target numbers incase it changed. */ + fcport->os_target_id = tgt; + if (tgt != MAX_TARGETS && tq != NULL) { + DEBUG2(printk("scsi(%ld): Assigning target ID=%02d @ %p to " + "loop id=0x%04x, port state=0x%x, port down retry=%d\n", + ha->host_no, tgt, tq, fcport->loop_id, + atomic_read(&fcport->state), + atomic_read(&fcport->port_down_timer))); + + fcport->tgt_queue = tq; + fcport->flags |= FCF_PERSISTENT_BOUND; + tq->fcport = fcport; + tq->flags |= TQF_ONLINE; + tq->port_down_retry_count = ha->port_down_retry_count; + + if (!qla2x00_failover_enabled(ha)) + qla2x00_get_lun_mask_from_config(ha, fcport, tgt, 0); + } + + if (tgt == MAX_TARGETS) { + qla_printk(KERN_WARNING, ha, + "Unable to bind fcport, loop_id=%x\n", fcport->loop_id); + } + + return (tgt); +} + +/* + * qla2x00_fclun_bind + * Binds all FC device LUNS to OS LUNS. + * + * Input: + * ha: adapter state pointer. + * fcport: FC port structure pointer. + * + * Returns: + * target number + * + * Context: + * Kernel context. + */ +static os_lun_t * +qla2x00_fclun_bind(scsi_qla_host_t *ha, fc_port_t *fcport, fc_lun_t *fclun) +{ + os_lun_t *lq; + uint16_t tgt; + uint16_t lun; + + tgt = fcport->os_target_id; + lun = fclun->lun; + + /* Allocate LUNs */ + if (lun >= MAX_LUNS) { + DEBUG2(printk("scsi(%ld): Unable to bind lun, invalid " + "lun=(%x).\n", ha->host_no, lun)); + return (NULL); + } + + /* Always alloc LUN 0 so kernel will scan past LUN 0. */ + if (lun != 0 && (EXT_IS_LUN_BIT_SET(&(fcport->lun_mask), lun))) { + return (NULL); + } + + if ((lq = qla2x00_lun_alloc(ha, tgt, lun)) == NULL) { + qla_printk(KERN_WARNING, ha, + "Unable to bind fclun, loop_id=%x lun=%x\n", + fcport->loop_id, lun); + return (NULL); + } + + lq->fclun = fclun; + + return (lq); +} + +/* + * qla2x00_tgt_alloc + * Allocate and pre-initialize target queue. + * + * Input: + * ha = adapter block pointer. + * t = SCSI target number. + * + * Returns: + * NULL = failure + * + * Context: + * Kernel context. + */ +os_tgt_t * +qla2x00_tgt_alloc(scsi_qla_host_t *ha, uint16_t tgt) +{ + os_tgt_t *tq; + + /* + * If SCSI addressing OK, allocate TGT queue and lock. + */ + if (tgt >= MAX_TARGETS) { + DEBUG2(printk("scsi(%ld): Unable to allocate target, invalid " + "target number %d.\n", ha->host_no, tgt)); + return (NULL); + } + + tq = TGT_Q(ha, tgt); + if (tq == NULL) { + tq = kmalloc(sizeof(os_tgt_t), GFP_ATOMIC); + if (tq != NULL) { + DEBUG2(printk("scsi(%ld): Alloc Target %d @ %p\n", + ha->host_no, tgt, tq)); + + memset(tq, 0, sizeof(os_tgt_t)); + tq->ha = ha; + + TGT_Q(ha, tgt) = tq; + } + } + if (tq != NULL) { + tq->port_down_retry_count = ha->port_down_retry_count; + } else { + qla_printk(KERN_WARNING, ha, + "Unable to allocate target.\n"); + ha->mem_err++; + } + + return (tq); +} + +/* + * qla2x00_tgt_free + * Frees target and LUN queues. + * + * Input: + * ha = adapter block pointer. + * t = SCSI target number. + * + * Context: + * Kernel context. + */ +void +qla2x00_tgt_free(scsi_qla_host_t *ha, uint16_t tgt) +{ + os_tgt_t *tq; + uint16_t lun; + + /* + * If SCSI addressing OK, allocate TGT queue and lock. + */ + if (tgt >= MAX_TARGETS) { + DEBUG2(printk("scsi(%ld): Unable to de-allocate target, " + "invalid target number %d.\n", ha->host_no, tgt)); + + return; + } + + tq = TGT_Q(ha, tgt); + if (tq != NULL) { + TGT_Q(ha, tgt) = NULL; + + /* Free LUN structures. */ + for (lun = 0; lun < MAX_LUNS; lun++) + qla2x00_lun_free(ha, tgt, lun); + + kfree(tq); + } + + return; +} + +/* + * qla2x00_lun_alloc + * Allocate and initialize LUN queue. + * + * Input: + * ha = adapter block pointer. + * t = SCSI target number. + * l = LUN number. + * + * Returns: + * NULL = failure + * + * Context: + * Kernel context. + */ +os_lun_t * +qla2x00_lun_alloc(scsi_qla_host_t *ha, uint16_t tgt, uint16_t lun) +{ + os_lun_t *lq; + + /* + * If SCSI addressing OK, allocate LUN queue. + */ + if (tgt >= MAX_TARGETS || lun >= MAX_LUNS || TGT_Q(ha, tgt) == NULL) { + DEBUG2(printk("scsi(%ld): Unable to allocate lun, invalid " + "parameter.\n", ha->host_no)); + + return (NULL); + } + + lq = LUN_Q(ha, tgt, lun); + if (lq == NULL) { + lq = kmalloc(sizeof(os_lun_t), GFP_ATOMIC); + if (lq != NULL) { + DEBUG2(printk("scsi(%ld): Alloc Lun %d @ tgt %d.\n", + ha->host_no, lun, tgt)); + + memset(lq, 0, sizeof (os_lun_t)); + LUN_Q(ha, tgt, lun) = lq; + + /* + * The following lun queue initialization code + * must be duplicated in alloc_ioctl_mem function + * for ioctl_lq. + */ + lq->q_state = LUN_STATE_READY; + spin_lock_init(&lq->q_lock); + } + } + + if (lq == NULL) { + qla_printk(KERN_WARNING, ha, "Unable to allocate lun.\n"); + } + + return (lq); +} + +/* + * qla2x00_lun_free + * Frees LUN queue. + * + * Input: + * ha = adapter block pointer. + * t = SCSI target number. + * + * Context: + * Kernel context. + */ +static void +qla2x00_lun_free(scsi_qla_host_t *ha, uint16_t tgt, uint16_t lun) +{ + os_lun_t *lq; + + /* + * If SCSI addressing OK, allocate TGT queue and lock. + */ + if (tgt >= MAX_TARGETS || lun >= MAX_LUNS) { + DEBUG2(printk("scsi(%ld): Unable to deallocate lun, invalid " + "parameter.\n", ha->host_no)); + + return; + } + + if (TGT_Q(ha, tgt) != NULL && (lq = LUN_Q(ha, tgt, lun)) != NULL) { + LUN_Q(ha, tgt, lun) = NULL; + kfree(lq); + } + + return; +} + + +/* + * qla2x00_get_lun_mask_from_config + * Get lun mask from the configuration parameters. + * Bit order is little endian. + * + * Input: + * ha -- Host adapter + * tgt -- target/device number + * port -- pointer to port + */ +static void +qla2x00_get_lun_mask_from_config(scsi_qla_host_t *ha, + fc_port_t *fcport, uint16_t tgt, uint16_t dev_no) +{ + char propbuf[60]; /* size of search string */ + int rval, lun, bit; + lun_bit_mask_t lun_mask, *mask_ptr = &lun_mask; + + /* Get "target-N-device-N-lun-mask" as a 256 bit lun_mask*/ + sprintf(propbuf, "scsi-qla%ld-tgt-%d-di-%d-lun-disabled", + ha->instance, tgt, dev_no); + + rval = qla2x00_get_prop_xstr(ha, propbuf, + (uint8_t *)&lun_mask, sizeof(lun_bit_mask_t)); + if (rval == sizeof(lun_bit_mask_t)) { + memset(&fcport->lun_mask, 0, sizeof(lun_bit_mask_t)); + for (lun = 8 * sizeof(lun_bit_mask_t) - 1, bit = 0; + lun >= 0; lun--, bit++) { + if (EXT_IS_LUN_BIT_SET(mask_ptr, lun)) + EXT_SET_LUN_BIT((&fcport->lun_mask), bit); + } + + DEBUG3(printk("scsi(%ld): returning lun mask for fcport " + "%02x%02x%02x%02x%02x%02x%02x%02x:\n", + ha->host_no, + fcport->port_name[0], fcport->port_name[1], + fcport->port_name[2], fcport->port_name[3], + fcport->port_name[4], fcport->port_name[5], + fcport->port_name[6], fcport->port_name[7])); + DEBUG3(qla2x00_dump_buffer((uint8_t *)&fcport->lun_mask, + sizeof(lun_bit_mask_t));) + } +} + +/* + * qla2x00_bstr_to_hex + * Convert hex byte string to number. + * + * Input: + * s = byte string pointer. + * bp = byte pointer for number. + * size = number of bytes. + * + * Context: + * Kernel/Interrupt context. + */ +static int +qla2x00_bstr_to_hex(char *s, uint8_t *bp, int size) +{ + int cnt; + uint8_t n; + + for (cnt = 0; *s != '\0' && cnt / 2 < size; cnt++) { + if (*s >= 'A' && *s <= 'F') { + n = (*s++ - 'A') + 10; + } else if (*s >= 'a' && *s <= 'f') { + n = (*s++ - 'a') + 10; + } else if (*s >= '0' && *s <= '9') { + n = *s++ - '0'; + } else { + cnt = 0; + break; + } + + if (cnt & BIT_0) + *bp++ |= n; + else + *bp = n << 4; + } + + /* fixme(dg) Need to swap data little endian */ + + return (cnt / 2); +} + +/* + * qla2x00_get_prop_xstr + * Get a string property value for the specified property name and + * convert from the property string found in the configuration file, + * which are ASCII characters representing nibbles, 2 characters represent + * the hexdecimal value for a byte in the byte array. + * The byte array is initialized to zero. + * The resulting converted value is in big endian format (MSB at byte0). + * + * Input: + * ha = adapter state pointer. + * propname = property name pointer. + * propval = pointer where to store converted property val. + * size = max or expected size of 'propval' array. + * + * Returns: + * 0 = empty value string or invalid character in string + * >0 = count of characters converted + * -1 = property not found + * + * Context: + * Kernel context. + */ +int +qla2x00_get_prop_xstr(scsi_qla_host_t *ha, + char *propname, uint8_t *propval, int size) +{ + char *propstr; + int rval = -1; + static char buf[LINESIZE]; + + /* Get the requested property string */ + rval = qla2x00_find_propname(ha, propname, buf, ha->cmdline, size*2); + DEBUG3(printk("%s(): Ret rval from find propname = %d\n", + __func__, + rval);) + + propstr = &buf[0]; + if (*propstr == '=') + propstr++; /* ignore equal sign */ + + if (rval == 0) { /* not found */ + LEAVE(__func__); + return (-1); + } + + rval = qla2x00_bstr_to_hex(propstr, (uint8_t *)propval, size); + if (rval == 0) { + /* Invalid character in value string */ + qla_printk(KERN_INFO, ha, + "%s(): %s Invalid hex string for property\n", + __func__, + propname); + qla_printk(KERN_INFO, ha, + " Invalid string - %s\n", + propstr); + } + + return (rval); +} + +/* + * qla2x00_find_propname + * Get property in database. + * + * Input: + * ha = adapter structure pointer. + * db = pointer to database + * propstr = pointer to dest array for string + * propname = name of property to search for. + * siz = size of property + * + * Returns: + * 0 = no property + * size = index of property + * + * Context: + * Kernel context. + */ +static int +qla2x00_find_propname(scsi_qla_host_t *ha, + char *propname, char *propstr, + char *db, int siz) +{ + char *cp; + + /* find the specified string */ + if (db) { + /* find the property name */ + if ((cp = strstr(db,propname)) != NULL) { + while ((*cp) && *cp != '=') + cp++; + if (*cp) { + strncpy(propstr, cp, siz+1); + propstr[siz+1] = '\0'; + DEBUG(printk("qla2x00_find_propname: found " + "property = {%s}\n", + propstr);) + return (siz); /* match */ + } + } + } + + return (0); +} + + +/* + * qla2x00_get_prop_16chars + * Get an 8-byte property value for the specified property name by + * converting from the property string found in the configuration file. + * The resulting converted value is in big endian format (MSB at byte0). + * + * Input: + * ha = adapter state pointer. + * propname = property name pointer. + * propval = pointer to location for the converted property val. + * db = pointer to database + * + * Returns: + * 0 = value returned successfully. + * + * Context: + * Kernel context. + */ +static int +qla2x00_get_prop_16chars(scsi_qla_host_t *ha, + char *propname, char *propval, char *db) +{ + char *propstr; + int i, k; + int rval; + uint8_t nval; + uint8_t *pchar; + uint8_t *ret_byte; + uint8_t *tmp_byte; + uint8_t *retval = (uint8_t*)propval; + uint8_t tmpval[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + uint16_t max_byte_cnt = 8; /* 16 chars = 8 bytes */ + uint16_t max_strlen = 16; + static char buf[LINESIZE]; + + rval = qla2x00_find_propname(ha, propname, buf, db, max_strlen); + + propstr = &buf[0]; + if (*propstr == '=') + propstr++; /* ignore equal sign */ + + if (rval == 0) { + return (1); + } + + /* Convert string to numbers. */ + pchar = (uint8_t *)propstr; + tmp_byte = (uint8_t *)tmpval; + + rval = 0; + for (i = 0; i < max_strlen; i++) { + /* + * Check for invalid character, two at a time, + * then convert them starting with first byte. + */ + + if ((pchar[i] >= '0') && (pchar[i] <= '9')) { + nval = pchar[i] - '0'; + } else if ((pchar[i] >= 'A') && (pchar[i] <= 'F')) { + nval = pchar[i] - 'A' + 10; + } else if ((pchar[i] >= 'a') && (pchar[i] <= 'f')) { + nval = pchar[i] - 'a' + 10; + } else { + /* invalid character */ + rval = 1; + break; + } + + if (i & BIT_0) { + *tmp_byte = *tmp_byte | nval; + tmp_byte++; + } else { + *tmp_byte = *tmp_byte | nval << 4; + } + } + + if (rval != 0) { + /* Encountered invalid character. */ + return (rval); + } + + /* Copy over the converted value. */ + ret_byte = retval; + tmp_byte = tmpval; + + i = max_byte_cnt; + k = 0; + while (i--) { + *ret_byte++ = *tmp_byte++; + } + + /* big endian retval[0]; */ + return (0); +} + +/* +* qla2x00_get_properties +* Find all properties for the specified adapeter in +* command line. +* +* Input: +* ha = adapter block pointer. +* cmdline = pointer to command line string +* +* Context: +* Kernel context. +*/ +static void +qla2x00_get_properties(scsi_qla_host_t *ha, char *cmdline) +{ + int rval; + static char propbuf[LINESIZE]; + uint8_t fc_name[8]; + + /* Adapter FC node names. */ + sprintf(propbuf, "scsi-qla%d-adapter-node", (int) ha->instance); + rval = qla2x00_get_prop_16chars(ha, propbuf, fc_name, cmdline); + if (rval == QLA_SUCCESS) + memcpy(ha->init_cb->node_name, fc_name, WWN_SIZE); + + /* DG 04/07 check portname of adapter */ + sprintf(propbuf, "scsi-qla%d-adapter-port", (int)ha->instance); + rval = qla2x00_get_prop_16chars(ha, propbuf, fc_name, cmdline); + if (rval == QLA_SUCCESS && + memcmp(ha->init_cb->port_name, fc_name, WWN_SIZE)) { + /* + * Adapter port name is WWN, and cannot be changed. + * Inform users of the mismatch, then just continue driver + * loading using the original adapter port name in NVRAM. + */ + qla_printk(KERN_WARNING, ha, + "Found mismatch in adapter port names.\n"); + qla_printk(KERN_INFO, ha, + " qla%ld port name found in NVRAM -> " + "%02x%02x%02x%02x%02x%02x%02x%02x\n", + ha->instance, + ha->init_cb->port_name[0], + ha->init_cb->port_name[1], + ha->init_cb->port_name[2], + ha->init_cb->port_name[3], + ha->init_cb->port_name[4], + ha->init_cb->port_name[5], + ha->init_cb->port_name[6], + ha->init_cb->port_name[7]); + qla_printk(KERN_INFO, ha, + " qla%ld port name found on command line -> " + "%02x%02x%02x%02x%02x%02x%02x%02x\n", + ha->instance, + fc_name[0], fc_name[1], fc_name[2], fc_name[3], + fc_name[4], fc_name[5], fc_name[6], fc_name[7]); + qla_printk(KERN_INFO, ha, + " Using port name from NVRAM.\n"); + } + + qla2x00_cfg_persistent_binding(ha); +} + +/* + * qla2x00_cfg_persistent_binding + * Get driver configuration file target persistent binding entries. + * + * Input: + * ha = adapter block pointer. + * + * Context: + * Kernel context. + */ +static void +qla2x00_cfg_persistent_binding(scsi_qla_host_t *ha) +{ + int rval; + static char propbuf[LINESIZE]; + char *cmdline = ha->cmdline; + uint16_t tgt; + port_id_t d_id; + uint8_t portid[3]; + uint8_t port_name[8]; + + for (tgt = 0; tgt < MAX_TARGETS; tgt++) { + if (ha->binding_type == BIND_BY_PORT_ID) { + sprintf(propbuf, "scsi-qla%d-tgt-%d-di-0-pid", + (int)ha->instance, tgt); + rval = qla2x00_get_prop_xstr(ha, + propbuf, portid, sizeof(portid)); + if (rval != sizeof(portid)) + continue; + + memset(&d_id, 0, sizeof(port_id_t)); + d_id.r.d_id[0] = portid[2]; + d_id.r.d_id[1] = portid[1]; + d_id.r.d_id[2] = portid[0]; + } else { + sprintf(propbuf, "scsi-qla%d-tgt-%d-di-0-port", + (int)ha->instance, tgt); + rval = qla2x00_get_prop_16chars(ha, + propbuf, port_name, cmdline); + if (rval != QLA_SUCCESS) + continue; + + /* Fallthru since port_name already populated */ + } + + /* + * Create target context for device. + */ + if (ha->binding_type == BIND_BY_PORT_ID) { + qla2x00_persistent_bind(ha, NULL, NULL, &d_id, tgt); + } else { + qla2x00_persistent_bind(ha, NULL, port_name, NULL, tgt); + } + } +} + +/* + * qla2x00_persistent_bind + * Allocates target and fcport. + * + * Input: + * ha: adapter state pointer. + * node_name: node name pointer. + * port_name: port name pointer. + * d_id: port ID pointer. + * tgt: OS target number. + * + * Returns: + * success = target queue pointer. + * failure = NULL. + * + * Context: + * Kernel context. + */ +static os_tgt_t * +qla2x00_persistent_bind(scsi_qla_host_t *ha, uint8_t *node_name, + uint8_t *port_name, port_id_t *d_id, uint16_t tgt) +{ + os_tgt_t *tq; + uint16_t tgt2; + + /* + * Check for duplicates. + */ + for (tgt2 = 0; tgt2 < MAX_TARGETS; tgt2++) { + if ((tq = TGT_Q(ha, tgt2)) == NULL) { + continue; + } + + if (ha->binding_type == BIND_BY_PORT_ID) { + if (tq->d_id.b24 != d_id->b24) { + continue; + } + } else if (memcmp(tq->port_name, port_name, WWN_SIZE) != 0) { + continue; + } + + qla_printk(KERN_WARNING, ha, + "Duplicate persistent bindings found for " + "WWPN: %02x%02x%02x%02x%02x%02x%02x%02x.\n", + port_name[0], port_name[1], port_name[2], port_name[3], + port_name[4], port_name[5], port_name[6], port_name[7]); + + return (tq); + } + + tq = qla2x00_tgt_alloc(ha, tgt); + if (tq == NULL) { + return (NULL); + } + + if (node_name != NULL) { + memcpy(tq->node_name, node_name, WWN_SIZE); + } + if (port_name != NULL) { + memcpy(tq->port_name, port_name, WWN_SIZE); + } + if (d_id != NULL) { + tq->d_id.b24 = d_id->b24; + } + + return (tq); +} + +/* +* qla2x00_abort_isp +* Resets ISP and aborts all outstanding commands. +* +* Input: +* ha = adapter block pointer. +* +* Returns: +* 0 = success +*/ +int +qla2x00_abort_isp(scsi_qla_host_t *ha) +{ + unsigned long flags = 0; + uint16_t cnt; + srb_t *sp; + uint8_t status = 0; + + ENTER("qla2x00_abort_isp"); + + if (ha->flags.online) { + ha->flags.online = FALSE; + clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); + qla2x00_stats.ispAbort++; + ha->total_isp_aborts++; /* used by ioctl */ + ha->sns_retry_cnt = 0; + + qla_printk(KERN_INFO, ha, + "Performing ISP error recovery - ha= %p.\n", ha); + qla2x00_reset_chip(ha); + + if (atomic_read(&ha->loop_state) != LOOP_DOWN) { + atomic_set(&ha->loop_state, LOOP_DOWN); + atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME); + qla2x00_mark_all_devices_lost(ha); + } + + spin_lock_irqsave(&ha->hardware_lock, flags); + /* Requeue all commands in outstanding command list. */ + for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { + sp = ha->outstanding_cmds[cnt]; + if (sp) { + ha->outstanding_cmds[cnt] = 0; + if (ha->actthreads) + ha->actthreads--; + sp->lun_queue->out_cnt--; + sp->flags = 0; + + /* + * Set the cmd host_byte status depending on + * whether the scsi_error_handler is + * active or not. + */ + if (ha->host->eh_active != EH_ACTIVE) { + sp->cmd->result = DID_BUS_BUSY << 16; + } else { + sp->cmd->result = DID_RESET << 16; + } + sp->cmd->host_scribble = (unsigned char *)NULL; + add_to_done_queue(ha, sp); + } + } + + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + qla2x00_nvram_config(ha); + + if (!qla2x00_restart_isp(ha)) { + clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); + + if (!atomic_read(&ha->loop_down_timer)) { + /* + * Issue marker command only when we are going + * to start the I/O . + */ + ha->marker_needed = 1; + } + + ha->flags.online = TRUE; + + /* Enable ISP interrupts. */ + qla2x00_enable_intrs(ha); + + /* v2.19.5b6 Return all commands */ + qla2x00_abort_queues(ha, TRUE); + + /* Restart queues that may have been stopped. */ + qla2x00_restart_queues(ha,TRUE); + ha->isp_abort_cnt = 0; + clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags); + } else { /* failed the ISP abort */ + ha->flags.online = TRUE; + if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) { + if (ha->isp_abort_cnt == 0) { + qla_printk(KERN_WARNING, ha, + "ISP error recovery failed - " + "board disabled\n"); + /* + * The next call disables the board + * completely. + */ + qla2x00_reset_adapter(ha); + qla2x00_abort_queues(ha, FALSE); + ha->flags.online = FALSE; + clear_bit(ISP_ABORT_RETRY, + &ha->dpc_flags); + status = 0; + } else { /* schedule another ISP abort */ + ha->isp_abort_cnt--; + DEBUG(printk("qla%ld: ISP abort - " + "retry remainning %d\n", + ha->host_no, ha->isp_abort_cnt);) + status = 1; + } + } else { + ha->isp_abort_cnt = MAX_RETRIES_OF_ISP_ABORT; + DEBUG(printk("qla2x00(%ld): ISP error recovery " + "- retrying (%d) more times\n", + ha->host_no, ha->isp_abort_cnt);) + set_bit(ISP_ABORT_RETRY, &ha->dpc_flags); + status = 1; + } + } + + } + + if (status) { + qla_printk(KERN_INFO, ha, + "qla2x00_abort_isp: **** FAILED ****\n"); + } else { + DEBUG(printk(KERN_INFO + "qla2x00_abort_isp(%ld): exiting.\n", + ha->host_no);) + } + + return(status); +} + +/* +* qla2x00_restart_isp +* restarts the ISP after a reset +* +* Input: +* ha = adapter block pointer. +* +* Returns: +* 0 = success +*/ +static int +qla2x00_restart_isp(scsi_qla_host_t *ha) +{ + uint8_t status = 0; + device_reg_t *reg; + unsigned long flags = 0; + + /* If firmware needs to be loaded */ + if (qla2x00_isp_firmware(ha)) { + ha->flags.online = FALSE; + if (!(status = qla2x00_chip_diag(ha))) { + if (!IS_QLA23XX(ha)) { + status = qla2x00_setup_chip(ha); + goto done; + } + + reg = ha->iobase; + spin_lock_irqsave(&ha->hardware_lock, flags); + /* Disable SRAM, Instruction RAM and GP RAM parity. */ + WRT_REG_WORD(®->hccr, (HCCR_ENABLE_PARITY + 0x0)); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + status = qla2x00_setup_chip(ha); + + spin_lock_irqsave(&ha->hardware_lock, flags); + + /* Enable proper parity */ + if (IS_QLA2312(ha) || IS_QLA2322(ha)) + /* SRAM, Instruction RAM and GP RAM parity */ + WRT_REG_WORD(®->hccr, + (HCCR_ENABLE_PARITY + 0x7)); + else + /* SRAM parity */ + WRT_REG_WORD(®->hccr, + (HCCR_ENABLE_PARITY + 0x1)); + + spin_unlock_irqrestore(&ha->hardware_lock, flags); + } + } + + done: + if (!status && !(status = qla2x00_init_rings(ha))) { + clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); + if (!(status = qla2x00_fw_ready(ha))) { + DEBUG(printk("%s(): Start configure loop, " + "status = %d\n", + __func__, + status);) + ha->flags.online = TRUE; + do { + clear_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); + qla2x00_configure_loop(ha); + } while (!atomic_read(&ha->loop_down_timer) && + !(test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) && + (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))); + } + + /* if no cable then assume it's good */ + if ((ha->device_flags & DFLG_NO_CABLE)) + status = 0; + + DEBUG(printk("%s(): Configure loop done, status = 0x%x\n", + __func__, + status);) + } + return (status); +} + +/* +* qla2x00_reset_adapter +* Reset adapter. +* +* Input: +* ha = adapter block pointer. +*/ +static void +qla2x00_reset_adapter(scsi_qla_host_t *ha) +{ + unsigned long flags = 0; + device_reg_t *reg = ha->iobase; + + ENTER(__func__); + + ha->flags.online = FALSE; + qla2x00_disable_intrs(ha); + /* Reset RISC processor. */ + spin_lock_irqsave(&ha->hardware_lock, flags); + WRT_REG_WORD(®->hccr, HCCR_RESET_RISC); + WRT_REG_WORD(®->hccr, HCCR_RELEASE_RISC); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + LEAVE(__func__); +} diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qla_inline.h 830-ivtv/drivers/scsi/qla2xxx/qla_inline.h --- 000-virgin/drivers/scsi/qla2xxx/qla_inline.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qla_inline.h Thu Jan 8 10:22:00 2004 @@ -0,0 +1,290 @@ +/* + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + + +static __inline__ uint16_t qla2x00_debounce_register(volatile uint16_t *); +/* + * qla2x00_debounce_register + * Debounce register. + * + * Input: + * port = register address. + * + * Returns: + * register value. + */ +static __inline__ uint16_t +qla2x00_debounce_register(volatile uint16_t *addr) +{ + volatile uint16_t first; + volatile uint16_t second; + + do { + first = RD_REG_WORD(addr); + barrier(); + cpu_relax(); + second = RD_REG_WORD(addr); + } while (first != second); + + return (first); +} + +static __inline__ int qla2x00_normalize_dma_addr( + dma_addr_t *e_addr, uint32_t *e_len, + dma_addr_t *ne_addr, uint32_t *ne_len); + +/** + * qla2x00_normalize_dma_addr() - Normalize an DMA address. + * @e_addr: Raw DMA address + * @e_len: Raw DMA length + * @ne_addr: Normalized second DMA address + * @ne_len: Normalized second DMA length + * + * If the address does not span a 4GB page boundary, the contents of @ne_addr + * and @ne_len are undefined. @e_len is updated to reflect a normalization. + * + * Example: + * + * ffffabc0ffffeeee (e_addr) start of DMA address + * 0000000020000000 (e_len) length of DMA transfer + * ffffabc11fffeeed end of DMA transfer + * + * Is the 4GB boundary crossed? + * + * ffffabc0ffffeeee (e_addr) + * ffffabc11fffeeed (e_addr + e_len - 1) + * 00000001e0000003 ((e_addr ^ (e_addr + e_len - 1)) + * 0000000100000000 ((e_addr ^ (e_addr + e_len - 1)) & ~(0xffffffff) + * + * Compute start of second DMA segment: + * + * ffffabc0ffffeeee (e_addr) + * ffffabc1ffffeeee (0x100000000 + e_addr) + * ffffabc100000000 (0x100000000 + e_addr) & ~(0xffffffff) + * ffffabc100000000 (ne_addr) + * + * Compute length of second DMA segment: + * + * 00000000ffffeeee (e_addr & 0xffffffff) + * 0000000000001112 (0x100000000 - (e_addr & 0xffffffff)) + * 000000001fffeeee (e_len - (0x100000000 - (e_addr & 0xffffffff)) + * 000000001fffeeee (ne_len) + * + * Adjust length of first DMA segment + * + * 0000000020000000 (e_len) + * 0000000000001112 (e_len - ne_len) + * 0000000000001112 (e_len) + * + * Returns non-zero if the specified address was normalized, else zero. + */ +static __inline__ int +qla2x00_normalize_dma_addr( + dma_addr_t *e_addr, uint32_t *e_len, + dma_addr_t *ne_addr, uint32_t *ne_len) +{ + int normalized; + + normalized = 0; + if ((*e_addr ^ (*e_addr + *e_len - 1)) & ~(0xFFFFFFFFULL)) { + /* Compute normalized crossed address and len */ + *ne_addr = (0x100000000ULL + *e_addr) & ~(0xFFFFFFFFULL); + *ne_len = *e_len - (0x100000000ULL - (*e_addr & 0xFFFFFFFFULL)); + *e_len -= *ne_len; + + normalized++; + } + return (normalized); +} + +static __inline__ void qla2x00_poll(scsi_qla_host_t *); +static inline void +qla2x00_poll(scsi_qla_host_t *ha) +{ + qla2x00_intr_handler(0, ha, NULL); +} + + +static __inline__ void qla2x00_enable_intrs(scsi_qla_host_t *); +static __inline__ void qla2x00_disable_intrs(scsi_qla_host_t *); + +static inline void +qla2x00_enable_intrs(scsi_qla_host_t *ha) +{ + unsigned long flags = 0; + device_reg_t *reg; + + spin_lock_irqsave(&ha->hardware_lock, flags); + reg = ha->iobase; + ha->interrupts_on = 1; + /* enable risc and host interrupts */ + WRT_REG_WORD(®->ictrl, ICR_EN_INT | ICR_EN_RISC); + RD_REG_WORD(®->ictrl); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + +} + +static inline void +qla2x00_disable_intrs(scsi_qla_host_t *ha) +{ + unsigned long flags = 0; + device_reg_t *reg; + + spin_lock_irqsave(&ha->hardware_lock, flags); + reg = ha->iobase; + ha->interrupts_on = 0; + /* disable risc and host interrupts */ + WRT_REG_WORD(®->ictrl, 0); + RD_REG_WORD(®->ictrl); + spin_unlock_irqrestore(&ha->hardware_lock, flags); +} + + +static __inline__ int qla2x00_is_wwn_zero(uint8_t *); + +/* + * qla2x00_is_wwn_zero - Check for zero node name + * + * Input: + * wwn = Pointer to WW name to check + * + * Returns: + * TRUE if name is 0 else FALSE + * + * Context: + * Kernel context. + */ +static __inline__ int +qla2x00_is_wwn_zero(uint8_t *wwn) +{ + int cnt; + + for (cnt = 0; cnt < WWN_SIZE ; cnt++, wwn++) { + if (*wwn != 0) + break; + } + /* if zero return TRUE */ + if (cnt == WWN_SIZE) + return (1); + else + return (0); +} + +static __inline__ uint8_t +qla2x00_suspend_lun(scsi_qla_host_t *, os_lun_t *, int, int); +static __inline__ uint8_t +qla2x00_delay_lun(scsi_qla_host_t *, os_lun_t *, int); + +static __inline__ uint8_t +qla2x00_suspend_lun(scsi_qla_host_t *ha, os_lun_t *lq, int time, int count) +{ + return (__qla2x00_suspend_lun(ha, lq, time, count, 0)); +} + +static __inline__ uint8_t +qla2x00_delay_lun(scsi_qla_host_t *ha, os_lun_t *lq, int time) +{ + return (__qla2x00_suspend_lun(ha, lq, time, 1, 1)); +} + +static __inline__ void qla2x00_check_fabric_devices(scsi_qla_host_t *); +/* + * This routine will wait for fabric devices for + * the reset delay. + */ +static __inline__ void qla2x00_check_fabric_devices(scsi_qla_host_t *ha) +{ + uint16_t fw_state; + + qla2x00_get_firmware_state(ha, &fw_state); +} + +static inline void qla2x00_filter_command(scsi_qla_host_t *ha, srb_t *sp); +static inline void +qla2x00_filter_command(scsi_qla_host_t *ha, srb_t *sp) +{ + /* NOTE: 20/08/2003 + * + * The SCSI lun-scanning code in 2.6 has changed such that the + * following workaround code is no longer necessary. If the device + * returns 011b for the PQ, the mid-layer will revert to a standard + * sequential lun scan. + * + * Special case considertaion on an Inquiry command (0x12) for Lun 0, + * device responds with no devices (0x7F), then Linux will not scan + * further Luns. While reporting that some device exists on Lun 0 Linux + * will scan all devices on this target. + */ +#if 0 + struct scsi_cmnd *cp = sp->cmd; + uint8_t *strp; + + if (qla2xenbinq && cp->cmnd[0] == INQUIRY && cp->device->lun == 0) { + strp = (uint8_t *)cp->request_buffer; + if (*strp == 0x7f) { + /* Make lun unassigned and processor type */ + *strp = 0x23; + } + } +#endif +} + +static __inline__ void * qla2x00_kmem_zalloc(int, int, int); +/* + * qla2x00_kmem_zalloc + * Allocate and zero out the block of memory + */ +static __inline__ void * +qla2x00_kmem_zalloc(int siz, int code, int id) +{ + uint8_t *bp; + + if ((bp = kmalloc(siz, code)) != NULL) { + memset(bp, 0, siz); + } + + return ((void *)bp); +} + +static inline int qla2x00_issue_marker(scsi_qla_host_t *, int); +/** + * qla2x00_issue_marker() - Issue a Marker IOCB if necessary. + * @ha: HA context + * @ha_locked: is function called with the hardware lock + * + * Returns non-zero if a failure occured, else zero. + */ +static inline int +qla2x00_issue_marker(scsi_qla_host_t *ha, int ha_locked) +{ + /* Send marker if required */ + if (ha->marker_needed != 0) { + if (ha_locked) { + if (__qla2x00_marker(ha, 0, 0, MK_SYNC_ALL) != + QLA_SUCCESS) + return (QLA_FUNCTION_FAILED); + } else { + if (qla2x00_marker(ha, 0, 0, MK_SYNC_ALL) != + QLA_SUCCESS) + return (QLA_FUNCTION_FAILED); + } + ha->marker_needed = 0; + } + return (QLA_SUCCESS); +} diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qla_iocb.c 830-ivtv/drivers/scsi/qla2xxx/qla_iocb.c --- 000-virgin/drivers/scsi/qla2xxx/qla_iocb.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qla_iocb.c Thu Jan 8 10:22:00 2004 @@ -0,0 +1,764 @@ +/****************************************************************************** + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + ******************************************************************************/ + +#include "qla_os.h" +#include "qla_def.h" + +static inline uint16_t qla2x00_get_cmd_direction(struct scsi_cmnd *cmd); +static inline cont_entry_t *qla2x00_prep_cont_type0_iocb(scsi_qla_host_t *); +static inline cont_a64_entry_t *qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *); + +/** + * qla2x00_get_cmd_direction() - Determine control_flag data direction. + * @cmd: SCSI command + * + * Returns the proper CF_* direction based on CDB. + */ +static inline uint16_t +qla2x00_get_cmd_direction(struct scsi_cmnd *cmd) +{ + uint16_t cflags; + + cflags = 0; + + /* Set transfer direction */ + if (cmd->sc_data_direction == DMA_TO_DEVICE) + cflags = CF_WRITE; + else if (cmd->sc_data_direction == DMA_FROM_DEVICE) + cflags = CF_READ; + else { + switch (cmd->data_cmnd[0]) { + case WRITE_6: + case WRITE_10: + case WRITE_12: + case WRITE_BUFFER: + case WRITE_LONG: + case WRITE_SAME: + case WRITE_VERIFY: + case WRITE_VERIFY_12: + case FORMAT_UNIT: + case SEND_VOLUME_TAG: + case MODE_SELECT: + case SEND_DIAGNOSTIC: + case MODE_SELECT_10: + cflags = CF_WRITE; + break; + default: + cflags = CF_READ; + break; + } + } + return (cflags); +} + +/** + * qla2x00_calc_iocbs_32() - Determine number of Command Type 2 and + * Continuation Type 0 IOCBs to allocate. + * + * @dsds: number of data segment decriptors needed + * + * Returns the number of IOCB entries needed to store @dsds. + */ +uint16_t +qla2x00_calc_iocbs_32(uint16_t dsds) +{ + uint16_t iocbs; + + iocbs = 1; + if (dsds > 3) { + iocbs += (dsds - 3) / 7; + if ((dsds - 3) % 7) + iocbs++; + } + return (iocbs); +} + +/** + * qla2x00_calc_iocbs_64() - Determine number of Command Type 3 and + * Continuation Type 1 IOCBs to allocate. + * + * @dsds: number of data segment decriptors needed + * + * Returns the number of IOCB entries needed to store @dsds. + */ +uint16_t +qla2x00_calc_iocbs_64(uint16_t dsds) +{ + uint16_t iocbs; + + iocbs = 1; + if (dsds > 2) { + iocbs += (dsds - 2) / 5; + if ((dsds - 2) % 5) + iocbs++; + } + return (iocbs); +} + +/** + * qla2x00_prep_cont_type0_iocb() - Initialize a Continuation Type 0 IOCB. + * @ha: HA context + * + * Returns a pointer to the Continuation Type 0 IOCB packet. + */ +static inline cont_entry_t * +qla2x00_prep_cont_type0_iocb(scsi_qla_host_t *ha) +{ + cont_entry_t *cont_pkt; + + /* Adjust ring index. */ + ha->req_ring_index++; + if (ha->req_ring_index == REQUEST_ENTRY_CNT) { + ha->req_ring_index = 0; + ha->request_ring_ptr = ha->request_ring; + } else { + ha->request_ring_ptr++; + } + + cont_pkt = (cont_entry_t *)ha->request_ring_ptr; + + /* Load packet defaults. */ + *((uint32_t *)(&cont_pkt->entry_type)) = + __constant_cpu_to_le32(CONTINUE_TYPE); + + return (cont_pkt); +} + +/** + * qla2x00_prep_cont_type1_iocb() - Initialize a Continuation Type 1 IOCB. + * @ha: HA context + * + * Returns a pointer to the continuation type 1 IOCB packet. + */ +static inline cont_a64_entry_t * +qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *ha) +{ + cont_a64_entry_t *cont_pkt; + + /* Adjust ring index. */ + ha->req_ring_index++; + if (ha->req_ring_index == REQUEST_ENTRY_CNT) { + ha->req_ring_index = 0; + ha->request_ring_ptr = ha->request_ring; + } else { + ha->request_ring_ptr++; + } + + cont_pkt = (cont_a64_entry_t *)ha->request_ring_ptr; + + /* Load packet defaults. */ + *((uint32_t *)(&cont_pkt->entry_type)) = + __constant_cpu_to_le32(CONTINUE_A64_TYPE); + + return (cont_pkt); +} + +/** + * qla2x00_build_scsi_iocbs_32() - Build IOCB command utilizing 32bit + * capable IOCB types. + * + * @sp: SRB command to process + * @cmd_pkt: Command type 2 IOCB + * @tot_dsds: Total number of segments to transfer + */ +void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt, + uint16_t tot_dsds) +{ + uint16_t avail_dsds; + uint32_t *cur_dsd; + scsi_qla_host_t *ha; + struct scsi_cmnd *cmd; + + cmd = sp->cmd; + + /* Update entry type to indicate Command Type 2 IOCB */ + *((uint32_t *)(&cmd_pkt->entry_type)) = + __constant_cpu_to_le32(COMMAND_TYPE); + + /* No data transfer */ + if (cmd->request_bufflen == 0 || cmd->sc_data_direction == DMA_NONE) { + cmd_pkt->byte_count = __constant_cpu_to_le32(0); + return; + } + + ha = sp->ha; + + cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(cmd)); + + /* Three DSDs are available in the Command Type 2 IOCB */ + avail_dsds = 3; + cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address; + + /* Load data segments */ + if (cmd->use_sg != 0) { + struct scatterlist *cur_seg; + struct scatterlist *end_seg; + + cur_seg = (struct scatterlist *)cmd->request_buffer; + end_seg = cur_seg + tot_dsds; + while (cur_seg < end_seg) { + cont_entry_t *cont_pkt; + + /* Allocate additional continuation packets? */ + if (avail_dsds == 0) { + /* + * Seven DSDs are available in the Continuation + * Type 0 IOCB. + */ + cont_pkt = qla2x00_prep_cont_type0_iocb(ha); + cur_dsd = (uint32_t *)&cont_pkt->dseg_0_address; + avail_dsds = 7; + } + + *cur_dsd++ = cpu_to_le32(sg_dma_address(cur_seg)); + *cur_dsd++ = cpu_to_le32(sg_dma_len(cur_seg)); + avail_dsds--; + + cur_seg++; + } + } else { + dma_addr_t req_dma; + struct page *page; + unsigned long offset; + + page = virt_to_page(cmd->request_buffer); + offset = ((unsigned long)cmd->request_buffer & ~PAGE_MASK); + req_dma = pci_map_page(ha->pdev, page, offset, + cmd->request_bufflen, cmd->sc_data_direction); + + sp->dma_handle = req_dma; + + *cur_dsd++ = cpu_to_le32(req_dma); + *cur_dsd++ = cpu_to_le32(cmd->request_bufflen); + } +} + +/** + * qla2x00_build_scsi_iocbs_64() - Build IOCB command utilizing 64bit + * capable IOCB types. + * + * @sp: SRB command to process + * @cmd_pkt: Command type 3 IOCB + * @tot_dsds: Total number of segments to transfer + */ +void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt, + uint16_t tot_dsds) +{ + uint16_t avail_dsds; + uint32_t *cur_dsd; + scsi_qla_host_t *ha; + struct scsi_cmnd *cmd; + + cmd = sp->cmd; + + /* Update entry type to indicate Command Type 3 IOCB */ + *((uint32_t *)(&cmd_pkt->entry_type)) = + __constant_cpu_to_le32(COMMAND_A64_TYPE); + + /* No data transfer */ + if (cmd->request_bufflen == 0 || cmd->sc_data_direction == DMA_NONE) { + cmd_pkt->byte_count = __constant_cpu_to_le32(0); + return; + } + + ha = sp->ha; + + cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(cmd)); + + /* Two DSDs are available in the Command Type 3 IOCB */ + avail_dsds = 2; + cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address; + + /* Load data segments */ + if (cmd->use_sg != 0) { + struct scatterlist *cur_seg; + struct scatterlist *end_seg; + + cur_seg = (struct scatterlist *)cmd->request_buffer; + end_seg = cur_seg + tot_dsds; + while (cur_seg < end_seg) { + dma_addr_t sle_dma; + cont_a64_entry_t *cont_pkt; + + /* Allocate additional continuation packets? */ + if (avail_dsds == 0) { + /* + * Five DSDs are available in the Continuation + * Type 1 IOCB. + */ + cont_pkt = qla2x00_prep_cont_type1_iocb(ha); + cur_dsd = (uint32_t *)cont_pkt->dseg_0_address; + avail_dsds = 5; + } + + sle_dma = sg_dma_address(cur_seg); + *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); + *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); + *cur_dsd++ = cpu_to_le32(sg_dma_len(cur_seg)); + avail_dsds--; + + cur_seg++; + } + } else { + dma_addr_t req_dma; + struct page *page; + unsigned long offset; + + page = virt_to_page(cmd->request_buffer); + offset = ((unsigned long)cmd->request_buffer & ~PAGE_MASK); + req_dma = pci_map_page(ha->pdev, page, offset, + cmd->request_bufflen, cmd->sc_data_direction); + + sp->dma_handle = req_dma; + + *cur_dsd++ = cpu_to_le32(LSD(req_dma)); + *cur_dsd++ = cpu_to_le32(MSD(req_dma)); + *cur_dsd++ = cpu_to_le32(cmd->request_bufflen); + } +} + +/** + * qla2x00_start_scsi() - Send a SCSI command to the ISP + * @sp: command to send to the ISP + * + * Returns non-zero if a failure occured, else zero. + */ +int +qla2x00_start_scsi(srb_t *sp) +{ + int ret; + unsigned long flags; + scsi_qla_host_t *ha; + fc_lun_t *fclun; + struct scsi_cmnd *cmd; + uint32_t *clr_ptr; + uint32_t index; + uint32_t handle; + uint16_t cnt, tot_dsds, req_cnt; + cmd_entry_t *cmd_pkt; + uint32_t timeout; + struct scatterlist *sg; + + device_reg_t *reg; + + /* Setup device pointers. */ + ret = 0; + fclun = sp->lun_queue->fclun; + ha = fclun->fcport->ha; + cmd = sp->cmd; + reg = ha->iobase; + + /* Send marker if required */ + if (ha->marker_needed != 0) { + if (qla2x00_marker(ha, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) { + return (QLA_FUNCTION_FAILED); + } + ha->marker_needed = 0; + } + + /* Calculate number of segments and entries required */ + tot_dsds = 0; + if (cmd->use_sg) { + sg = (struct scatterlist *) cmd->request_buffer; + tot_dsds = pci_map_sg(ha->pdev, sg, cmd->use_sg, + cmd->sc_data_direction); + } else if (cmd->request_bufflen) { /* Single segment transfer */ + tot_dsds++; + } + req_cnt = (ha->calc_request_entries)(tot_dsds); + + /* Acquire ring specific lock */ + spin_lock_irqsave(&ha->hardware_lock, flags); + + if (ha->req_q_cnt < (req_cnt + 2)) { + /* Calculate number of free request entries */ + cnt = RD_REG_WORD(ISP_REQ_Q_OUT(ha, reg)); + if (ha->req_ring_index < cnt) + ha->req_q_cnt = cnt - ha->req_ring_index; + else + ha->req_q_cnt = REQUEST_ENTRY_CNT - + (ha->req_ring_index - cnt); + } + + /* If no room for request in request ring */ + if (ha->req_q_cnt < (req_cnt + 2)) { + DEBUG5(printk("scsi(%ld): in-ptr=%x req_q_cnt=%x " + "tot_dsds=%x.\n", + ha->host_no, ha->req_ring_index, ha->req_q_cnt, tot_dsds)); + + goto queuing_error; + } + + /* Check for room in outstanding command list. */ + handle = ha->current_outstanding_cmd; + for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) { + handle++; + if (handle == MAX_OUTSTANDING_COMMANDS) + handle = 1; + if (ha->outstanding_cmds[handle] == 0) { + ha->current_outstanding_cmd = handle; + break; + } + } + if (index == MAX_OUTSTANDING_COMMANDS) { + DEBUG5(printk("scsi(%ld): Unable to queue command -- NO ROOM " + "IN OUTSTANDING ARRAY (req_q_cnt=%x).\n", + ha->host_no, ha->req_q_cnt)); + goto queuing_error; + } + + /* Build command packet */ + ha->outstanding_cmds[handle] = sp; + sp->ha = ha; + sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle; + ha->req_q_cnt -= req_cnt; + + cmd_pkt = (cmd_entry_t *)ha->request_ring_ptr; + cmd_pkt->handle = handle; + /* Zero out remaining portion of packet. */ + clr_ptr = (uint32_t *)cmd_pkt + 2; + memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); + cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); + + /* Set target ID */ + SET_TARGET_ID(ha, cmd_pkt->target, fclun->fcport->loop_id); + + /* Set LUN number*/ + cmd_pkt->lun = cpu_to_le16(fclun->lun); + + /* Update tagged queuing modifier */ + cmd_pkt->control_flags = __constant_cpu_to_le16(CF_SIMPLE_TAG); + if (cmd->device->tagged_supported) { + switch (cmd->tag) { + case HEAD_OF_QUEUE_TAG: + cmd_pkt->control_flags = + __constant_cpu_to_le16(CF_HEAD_TAG); + break; + case ORDERED_QUEUE_TAG: + cmd_pkt->control_flags = + __constant_cpu_to_le16(CF_ORDERED_TAG); + break; + } + } + + /* + * Allocate at least 5 (+ QLA_CMD_TIMER_DELTA) seconds for RISC timeout. + */ + timeout = (uint32_t)(cmd->timeout_per_command / HZ); + if (timeout > 65535) + cmd_pkt->timeout = __constant_cpu_to_le16(0); + else if (timeout > 25) + cmd_pkt->timeout = cpu_to_le16((uint16_t)timeout - + (5 + QLA_CMD_TIMER_DELTA)); + else + cmd_pkt->timeout = cpu_to_le16((uint16_t)timeout); + + /* Load SCSI command packet. */ + memcpy(cmd_pkt->scsi_cdb, cmd->cmnd, cmd->cmd_len); + cmd_pkt->byte_count = cpu_to_le32((uint32_t)cmd->request_bufflen); + + /* Build IOCB segments */ + (ha->build_scsi_iocbs)(sp, cmd_pkt, tot_dsds); + + /* Set total data segment count. */ + cmd_pkt->entry_count = (uint8_t)req_cnt; + + /* Adjust ring index. */ + ha->req_ring_index++; + if (ha->req_ring_index == REQUEST_ENTRY_CNT) { + ha->req_ring_index = 0; + ha->request_ring_ptr = ha->request_ring; + } else + ha->request_ring_ptr++; + + ha->actthreads++; + ha->total_ios++; + sp->lun_queue->out_cnt++; + sp->flags |= SRB_DMA_VALID; + sp->state = SRB_ACTIVE_STATE; + sp->u_start = jiffies; + + /* Set chip new ring index. */ + WRT_REG_WORD(ISP_REQ_Q_IN(ha, reg), ha->req_ring_index); + RD_REG_WORD(ISP_REQ_Q_IN(ha, reg)); /* PCI Posting. */ + + spin_unlock_irqrestore(&ha->hardware_lock, flags); + return (QLA_SUCCESS); + +queuing_error: + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + if (cmd->use_sg) + pci_unmap_sg(ha->pdev, sg, cmd->use_sg, cmd->sc_data_direction); + + return (QLA_FUNCTION_FAILED); +} + +/** + * qla2x00_marker() - Send a marker IOCB to the firmware. + * @ha: HA context + * @loop_id: loop ID + * @lun: LUN + * @type: marker modifier + * + * Can be called from both normal and interrupt context. + * + * Returns non-zero if a failure occured, else zero. + */ +int +__qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun, + uint8_t type) +{ + mrk_entry_t *pkt; + + ENTER(__func__); + + pkt = (mrk_entry_t *)qla2x00_req_pkt(ha); + if (pkt == NULL) { + DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__)); + + return (QLA_FUNCTION_FAILED); + } + + pkt->entry_type = MARKER_TYPE; + pkt->modifier = type; + + if (type != MK_SYNC_ALL) { + pkt->lun = cpu_to_le16(lun); + SET_TARGET_ID(ha, pkt->target, loop_id); + } + + /* Issue command to ISP */ + qla2x00_isp_cmd(ha); + + LEAVE(__func__); + + return (QLA_SUCCESS); +} + +int +qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun, + uint8_t type) +{ + int ret; + unsigned long flags = 0; + + spin_lock_irqsave(&ha->hardware_lock, flags); + ret = __qla2x00_marker(ha, loop_id, lun, type); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + return (ret); +} + +/** + * qla2x00_req_pkt() - Retrieve a request packet from the request ring. + * @ha: HA context + * + * Note: The caller must hold the hardware lock before calling this routine. + * + * Returns NULL if function failed, else, a pointer to the request packet. + */ +request_t * +qla2x00_req_pkt(scsi_qla_host_t *ha) +{ + device_reg_t *reg = ha->iobase; + request_t *pkt = NULL; + uint16_t cnt; + uint32_t *dword_ptr; + uint32_t timer; + uint16_t req_cnt = 1; + + ENTER(__func__); + + /* Wait 1 second for slot. */ + for (timer = HZ; timer; timer--) { + if ((req_cnt + 2) >= ha->req_q_cnt) { + /* Calculate number of free request entries. */ + cnt = qla2x00_debounce_register(ISP_REQ_Q_OUT(ha, reg)); + if (ha->req_ring_index < cnt) + ha->req_q_cnt = cnt - ha->req_ring_index; + else + ha->req_q_cnt = REQUEST_ENTRY_CNT - + (ha->req_ring_index - cnt); + } + /* If room for request in request ring. */ + if ((req_cnt + 2) < ha->req_q_cnt) { + ha->req_q_cnt--; + pkt = ha->request_ring_ptr; + + /* Zero out packet. */ + dword_ptr = (uint32_t *)pkt; + for (cnt = 0; cnt < REQUEST_ENTRY_SIZE / 4; cnt++) + *dword_ptr++ = 0; + + /* Set system defined field. */ + pkt->sys_define = (uint8_t)ha->req_ring_index; + + /* Set entry count. */ + pkt->entry_count = 1; + + break; + } + + /* Release ring specific lock */ + spin_unlock(&ha->hardware_lock); + + udelay(2); /* 2 us */ + + /* Check for pending interrupts. */ + /* During init we issue marker directly */ + if (!ha->marker_needed) + qla2x00_poll(ha); + + spin_lock_irq(&ha->hardware_lock); + } + if (!pkt) { + DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__)); + } + + LEAVE(__func__); + + return (pkt); +} + +/** + * qla2x00_ms_req_pkt() - Retrieve a Management Server request packet from + * the request ring. + * @ha: HA context + * @sp: pointer to handle post function call + * + * Note: The caller must hold the hardware lock before calling this routine. + * + * Returns NULL if function failed, else, a pointer to the request packet. + */ +request_t * +qla2x00_ms_req_pkt(scsi_qla_host_t *ha, srb_t *sp) +{ + device_reg_t *reg = ha->iobase; + request_t *pkt = NULL; + uint16_t cnt, i, index; + uint32_t *dword_ptr; + uint32_t timer; + uint8_t found = 0; + uint16_t req_cnt = 1; + + ENTER(__func__); + + /* Wait 1 second for slot. */ + for (timer = HZ; timer; timer--) { + if ((req_cnt + 2) >= ha->req_q_cnt) { + /* Calculate number of free request entries. */ + cnt = qla2x00_debounce_register(ISP_REQ_Q_OUT(ha, reg)); + if (ha->req_ring_index < cnt) { + ha->req_q_cnt = cnt - ha->req_ring_index; + } else { + ha->req_q_cnt = REQUEST_ENTRY_CNT - + (ha->req_ring_index - cnt); + } + } + + /* Check for room in outstanding command list. */ + cnt = ha->current_outstanding_cmd; + for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) { + cnt++; + if (cnt == MAX_OUTSTANDING_COMMANDS) + cnt = 1; + + if (ha->outstanding_cmds[cnt] == 0) { + found = 1; + ha->current_outstanding_cmd = cnt; + break; + } + } + + /* If room for request in request ring. */ + if (found && (req_cnt + 2) < ha->req_q_cnt) { + pkt = ha->request_ring_ptr; + + /* Zero out packet. */ + dword_ptr = (uint32_t *)pkt; + for (i = 0; i < REQUEST_ENTRY_SIZE / 4; i++ ) + *dword_ptr++ = 0; + + DEBUG5(printk("%s(): putting sp=%p in " + "outstanding_cmds[%x]\n", + __func__, + sp, cnt)); + + ha->outstanding_cmds[cnt] = sp; + + /* save the handle */ + sp->cmd->host_scribble = (unsigned char *) (u_long) cnt; + CMD_SP(sp->cmd) = (void *)sp; + + ha->req_q_cnt--; + pkt->handle = (uint32_t)cnt; + + /* Set system defined field. */ + pkt->sys_define = (uint8_t)ha->req_ring_index; + pkt->entry_status = 0; + + break; + } + + /* Release ring specific lock */ + spin_unlock(&ha->hardware_lock); + udelay(20); + + /* Check for pending interrupts. */ + qla2x00_poll(ha); + + spin_lock_irq(&ha->hardware_lock); + } + if (!pkt) { + DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__)); + } + + LEAVE(__func__); + + return (pkt); +} + +/** + * qla2x00_isp_cmd() - Modify the request ring pointer. + * @ha: HA context + * + * Note: The caller must hold the hardware lock before calling this routine. + */ +void +qla2x00_isp_cmd(scsi_qla_host_t *ha) +{ + device_reg_t *reg = ha->iobase; + + DEBUG5(printk("%s(): IOCB data:\n", __func__)); + DEBUG5(qla2x00_dump_buffer( + (uint8_t *)ha->request_ring_ptr, REQUEST_ENTRY_SIZE)); + + /* Adjust ring index. */ + ha->req_ring_index++; + if (ha->req_ring_index == REQUEST_ENTRY_CNT) { + ha->req_ring_index = 0; + ha->request_ring_ptr = ha->request_ring; + } else + ha->request_ring_ptr++; + + /* Set chip new ring index. */ + WRT_REG_WORD(ISP_REQ_Q_IN(ha, reg), ha->req_ring_index); + RD_REG_WORD(ISP_REQ_Q_IN(ha, reg)); /* PCI Posting. */ +} diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qla_isr.c 830-ivtv/drivers/scsi/qla2xxx/qla_isr.c --- 000-virgin/drivers/scsi/qla2xxx/qla_isr.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qla_isr.c Thu Jan 8 10:22:00 2004 @@ -0,0 +1,1436 @@ +/* + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +#include "qla_os.h" + +#include "qla_def.h" + +static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t); +static void qla2x00_async_event(scsi_qla_host_t *, uint32_t); +static void qla2x00_process_completed_request(struct scsi_qla_host *, uint32_t); +void qla2x00_process_response_queue(struct scsi_qla_host *); +static void qla2x00_status_entry(scsi_qla_host_t *, sts_entry_t *); +static void qla2x00_status_cont_entry(scsi_qla_host_t *, sts_cont_entry_t *); +static void qla2x00_error_entry(scsi_qla_host_t *, sts_entry_t *); +static void qla2x00_ms_entry(scsi_qla_host_t *, ms_iocb_entry_t *); + +static int qla2x00_check_sense(struct scsi_cmnd *cp, os_lun_t *); + +/** + * qla2x00_intr_handler() - Process interrupts for the ISP. + * @irq: + * @dev_id: SCSI driver HA context + * @regs: + * + * Called by system whenever the host adapter generates an interrupt. + * + * Returns handled flag. + */ +irqreturn_t +qla2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + scsi_qla_host_t *ha; + device_reg_t *reg; + uint32_t mbx; + int status = 0; + unsigned long flags = 0; + unsigned long mbx_flags = 0; + unsigned long intr_iter; + uint32_t stat; + uint16_t hccr; + + /* Don't loop forever, interrupt are OFF */ + intr_iter = 50; + + ha = (scsi_qla_host_t *) dev_id; + if (!ha) { + printk(KERN_INFO + "%s(): NULL host pointer\n", __func__); + return (IRQ_NONE); + } + + reg = ha->iobase; + + spin_lock_irqsave(&ha->hardware_lock, flags); + + for (;;) { + /* Relax CPU! */ + if (!(intr_iter--)) + break; + + if (IS_QLA2100(ha) || IS_QLA2200(ha)) { + if ((RD_REG_WORD(®->istatus) & ISR_RISC_INT) == 0) + break; + + if (RD_REG_WORD(®->semaphore) & BIT_0) { + WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); + RD_REG_WORD(®->hccr); + + /* Get mailbox data. */ + mbx = RD_MAILBOX_REG(ha, reg, 0); + if (mbx > 0x3fff && mbx < 0x8000) { + qla2x00_mbx_completion(ha, + (uint16_t)mbx); + status |= MBX_INTERRUPT; + } else if (mbx > 0x7fff && mbx < 0xc000) { + qla2x00_async_event(ha, mbx); + } else { + /*EMPTY*/ + DEBUG2(printk("scsi(%ld): Unrecognized " + "interrupt type (%d)\n", + ha->host_no, mbx)); + } + /* Release mailbox registers. */ + WRT_REG_WORD(®->semaphore, 0); + /* Workaround for ISP2100 chip. */ + if (IS_QLA2100(ha)) + RD_REG_WORD(®->semaphore); + } else { + qla2x00_process_response_queue(ha); + + WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); + RD_REG_WORD(®->hccr); + } + } else /* IS_QLA23XX(ha) */ { + stat = RD_REG_DWORD(®->u.isp2300.host_status); + if ((stat & HSR_RISC_INT) == 0) + break; + + mbx = MSW(stat); + switch (stat & 0xff) { + case 0x13: + qla2x00_process_response_queue(ha); + break; + case 0x1: + case 0x2: + case 0x10: + case 0x11: + qla2x00_mbx_completion(ha, (uint16_t)mbx); + status |= MBX_INTERRUPT; + + /* Release mailbox registers. */ + WRT_REG_WORD(®->semaphore, 0); + break; + case 0x12: + qla2x00_async_event(ha, mbx); + break; + case 0x15: + mbx = mbx << 16 | MBA_CMPLT_1_16BIT; + qla2x00_async_event(ha, mbx); + break; + case 0x16: + mbx = mbx << 16 | MBA_SCSI_COMPLETION; + qla2x00_async_event(ha, mbx); + break; + default: + hccr = RD_REG_WORD(®->hccr); + if (hccr & HCCR_RISC_PAUSE) { + qla_printk(KERN_INFO, ha, + "RISC paused, dumping HCCR=%x\n", + hccr); + + /* + * Issue a "HARD" reset in order for + * the RISC interrupt bit to be + * cleared. Schedule a big hammmer to + * get out of the RISC PAUSED state. + */ + WRT_REG_WORD(®->hccr, + HCCR_RESET_RISC); + RD_REG_WORD(®->hccr); + set_bit(ISP_ABORT_NEEDED, + &ha->dpc_flags); + break; + } else { + DEBUG2(printk("scsi(%ld): Unrecognized " + "interrupt type (%d)\n", + ha->host_no, stat & 0xff)); + } + break; + } + WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); + RD_REG_WORD(®->hccr); + } + } + + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + qla2x00_next(ha); + ha->last_irq_cpu = smp_processor_id(); + ha->total_isr_cnt++; + + if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && + (status & MBX_INTERRUPT) && ha->flags.mbox_int) { + + /* There was a mailbox completion */ + DEBUG3(printk("%s(%ld): Going to get mbx reg lock.\n", + __func__, ha->host_no)); + + spin_lock_irqsave(&ha->mbx_reg_lock, mbx_flags); + + if (ha->mcp == NULL) { + DEBUG3(printk("%s(%ld): Error mbx pointer.\n", + __func__, ha->host_no)); + } else { + DEBUG3(printk("%s(%ld): Going to set mbx intr flags. " + "cmd=%x.\n", + __func__, ha->host_no, ha->mcp->mb[0])); + } + set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); + + DEBUG3(printk("%s(%ld): Going to wake up mbx function for " + "completion.\n", + __func__, ha->host_no)); + + up(&ha->mbx_intr_sem); + + DEBUG3(printk("%s(%ld): Going to release mbx reg lock.\n", + __func__, ha->host_no)); + + spin_unlock_irqrestore(&ha->mbx_reg_lock, mbx_flags); + } + + if (!list_empty(&ha->done_queue)) + qla2x00_done(ha); + + /* Wakeup the DPC routine */ + if ((!ha->flags.mbox_busy && + (test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) || + test_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) || + test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))) && + ha->dpc_wait && !ha->dpc_active) { + + up(ha->dpc_wait); + } + + return (IRQ_HANDLED); +} + +/** + * qla2x00_mbx_completion() - Process mailbox command completions. + * @ha: SCSI driver HA context + * @mb0: Mailbox0 register + */ +static void +qla2x00_mbx_completion(scsi_qla_host_t *ha, uint16_t mb0) +{ + uint16_t cnt; + uint16_t *wptr; + device_reg_t *reg = ha->iobase; + + /* Load return mailbox registers. */ + ha->flags.mbox_int = TRUE; + ha->mailbox_out[0] = mb0; + wptr = (uint16_t *)MAILBOX_REG(ha, reg, 1); + + for (cnt = 1; cnt < ha->mbx_count; cnt++) { + if (IS_QLA2200(ha) && cnt == 8) + wptr = (uint16_t *)MAILBOX_REG(ha, reg, 8); + if (cnt == 4 || cnt == 5) + ha->mailbox_out[cnt] = qla2x00_debounce_register(wptr); + else + ha->mailbox_out[cnt] = RD_REG_WORD(wptr); + + wptr++; + } + + if (ha->mcp) { + DEBUG3(printk("%s(%ld): Got mailbox completion. cmd=%x.\n", + __func__, ha->host_no, ha->mcp->mb[0])); + } else { + DEBUG2_3(printk("%s(%ld): MBX pointer ERROR!\n", + __func__, ha->host_no)); + } +} + +/** + * qla2x00_async_event() - Process aynchronous events. + * @ha: SCSI driver HA context + * @mb0: Mailbox0 register + */ +static void +qla2x00_async_event(scsi_qla_host_t *ha, uint32_t mbx) +{ + static char *link_speeds[5] = { "1", "2", "4", "?", "10" }; + char *link_speed; + uint16_t mb[4]; + uint16_t handle_cnt; + uint16_t cnt; + uint32_t handles[5]; + device_reg_t *reg = ha->iobase; + uint32_t rscn_entry, host_pid; + uint8_t rscn_queue_index; + + /* Setup to process RIO completion. */ + handle_cnt = 0; + mb[0] = LSW(mbx); + switch (mb[0]) { + case MBA_SCSI_COMPLETION: + if (IS_QLA2100(ha) || IS_QLA2200(ha)) + handles[0] = RD_MAILBOX_REG(ha, reg, 1); + else + handles[0] = MSW(mbx); + handles[0] |= (uint32_t)(RD_MAILBOX_REG(ha, reg, 2) << 16); + handle_cnt = 1; + break; + case MBA_CMPLT_1_16BIT: + if (IS_QLA2100(ha) || IS_QLA2200(ha)) + handles[0] = (uint32_t)RD_MAILBOX_REG(ha, reg, 1); + else + handles[0] = MSW(mbx); + handle_cnt = 1; + mb[0] = MBA_SCSI_COMPLETION; + break; + case MBA_CMPLT_2_16BIT: + handles[0] = (uint32_t)RD_MAILBOX_REG(ha, reg, 1); + handles[1] = (uint32_t)RD_MAILBOX_REG(ha, reg, 2); + handle_cnt = 2; + mb[0] = MBA_SCSI_COMPLETION; + break; + case MBA_CMPLT_3_16BIT: + handles[0] = (uint32_t)RD_MAILBOX_REG(ha, reg, 1); + handles[1] = (uint32_t)RD_MAILBOX_REG(ha, reg, 2); + handles[2] = (uint32_t)RD_MAILBOX_REG(ha, reg, 3); + handle_cnt = 3; + mb[0] = MBA_SCSI_COMPLETION; + break; + case MBA_CMPLT_4_16BIT: + handles[0] = (uint32_t)RD_MAILBOX_REG(ha, reg, 1); + handles[1] = (uint32_t)RD_MAILBOX_REG(ha, reg, 2); + handles[2] = (uint32_t)RD_MAILBOX_REG(ha, reg, 3); + handles[3] = (uint32_t)RD_MAILBOX_REG(ha, reg, 6); + handle_cnt = 4; + mb[0] = MBA_SCSI_COMPLETION; + break; + case MBA_CMPLT_5_16BIT: + handles[0] = (uint32_t)RD_MAILBOX_REG(ha, reg, 1); + handles[1] = (uint32_t)RD_MAILBOX_REG(ha, reg, 2); + handles[2] = (uint32_t)RD_MAILBOX_REG(ha, reg, 3); + handles[3] = (uint32_t)RD_MAILBOX_REG(ha, reg, 6); + handles[4] = (uint32_t)RD_MAILBOX_REG(ha, reg, 7); + handle_cnt = 5; + mb[0] = MBA_SCSI_COMPLETION; + break; + case MBA_CMPLT_2_32BIT: + handles[0] = (uint32_t)((RD_MAILBOX_REG(ha, reg, 2) << 16) | + RD_MAILBOX_REG(ha, reg, 1)); + handles[1] = (uint32_t)((RD_MAILBOX_REG(ha, reg, 7) << 16) | + RD_MAILBOX_REG(ha, reg, 6)); + handle_cnt = 2; + mb[0] = MBA_SCSI_COMPLETION; + break; + default: + break; + } + + mb[0] = LSW(mbx); + switch (mb[0]) { + case MBA_SCSI_COMPLETION: /* Fast Post */ + if (!ha->flags.online) + break; + + for (cnt = 0; cnt < handle_cnt; cnt++) + qla2x00_process_completed_request(ha, handles[cnt]); + break; + + case MBA_RESET: /* Reset */ + DEBUG2(printk("scsi(%ld): Asynchronous RESET.\n", ha->host_no)); + + set_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); + break; + + case MBA_SYSTEM_ERR: /* System Error */ + mb[1] = RD_MAILBOX_REG(ha, reg, 1); + mb[2] = RD_MAILBOX_REG(ha, reg, 2); + mb[3] = RD_MAILBOX_REG(ha, reg, 3); + + qla_printk(KERN_INFO, ha, + "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n", + mb[1], mb[2], mb[3]); + + if (IS_QLA2100(ha) || IS_QLA2200(ha)) + qla2100_fw_dump(ha, 1); + else + qla2300_fw_dump(ha, 1); + set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); + break; + + case MBA_REQ_TRANSFER_ERR: /* Request Transfer Error */ + DEBUG2(printk("scsi(%ld): ISP Request Transfer Error.\n", + ha->host_no)); + qla_printk(KERN_WARNING, ha, "ISP Request Transfer Error.\n"); + + set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); + break; + + case MBA_RSP_TRANSFER_ERR: /* Response Transfer Error */ + DEBUG2(printk("scsi(%ld): ISP Response Transfer Error.\n", + ha->host_no)); + qla_printk(KERN_WARNING, ha, "ISP Response Transfer Error.\n"); + + set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); + break; + + case MBA_WAKEUP_THRES: /* Request Queue Wake-up */ + DEBUG2(printk("scsi(%ld): Asynchronous WAKEUP_THRES.\n", + ha->host_no)); + break; + + case MBA_LIP_OCCURRED: /* Loop Initialization Procedure */ + mb[1] = RD_MAILBOX_REG(ha, reg, 1); + + DEBUG2(printk("scsi(%ld): LIP occured (%x).\n", ha->host_no, + mb[1])); + qla_printk(KERN_INFO, ha, "LIP occured (%x).\n", mb[1]); + + if (atomic_read(&ha->loop_state) != LOOP_DOWN) { + atomic_set(&ha->loop_state, LOOP_DOWN); + atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME); + qla2x00_mark_all_devices_lost(ha); + } + + set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags); + + ha->flags.management_server_logged_in = 0; + + /* Update AEN queue. */ + if (ha->ioctl->flags & IOCTL_AEN_TRACKING_ENABLE) { + qla2x00_enqueue_aen(ha, MBA_LIP_OCCURRED, NULL); + } + + ha->total_lip_cnt++; + break; + + case MBA_LOOP_UP: /* Loop Up Event */ + mb[1] = RD_MAILBOX_REG(ha, reg, 1); + + ha->current_speed = EXT_DEF_PORTSPEED_1GBIT; + if (IS_QLA2100(ha) || IS_QLA2200(ha)) { + link_speed = link_speeds[0]; + } else { + link_speed = link_speeds[3]; + if (mb[1] < 5) + link_speed = link_speeds[mb[1]]; + if (mb[1] == 1) + ha->current_speed = EXT_DEF_PORTSPEED_2GBIT; + } + + DEBUG2(printk("scsi(%ld): Asynchronous LOOP UP (%s Gbps).\n", + ha->host_no, link_speed)); + qla_printk(KERN_INFO, ha, "LOOP UP detected (%s Gbps).\n", + link_speed); + + ha->flags.management_server_logged_in = 0; + + /* Update AEN queue. */ + if (ha->ioctl->flags & IOCTL_AEN_TRACKING_ENABLE) { + qla2x00_enqueue_aen(ha, MBA_LOOP_UP, NULL); + } + break; + + case MBA_LOOP_DOWN: /* Loop Down Event */ + DEBUG2(printk("scsi(%ld): Asynchronous LOOP DOWN.\n", + ha->host_no)); + qla_printk(KERN_INFO, ha, "LOOP DOWN detected.\n"); + + if (atomic_read(&ha->loop_state) != LOOP_DOWN) { + atomic_set(&ha->loop_state, LOOP_DOWN); + atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME); + qla2x00_mark_all_devices_lost(ha); + } + + ha->flags.management_server_logged_in = 0; + ha->current_speed = 0; /* reset value */ + + /* Update AEN queue. */ + if (ha->ioctl->flags & IOCTL_AEN_TRACKING_ENABLE) { + qla2x00_enqueue_aen(ha, MBA_LOOP_DOWN, NULL); + } + break; + + case MBA_LIP_RESET: /* LIP reset occurred */ + mb[1] = RD_MAILBOX_REG(ha, reg, 1); + + DEBUG2(printk("scsi(%ld): Asynchronous LIP RESET (%x).\n", + ha->host_no, mb[1])); + qla_printk(KERN_INFO, ha, + "LIP reset occured (%x).\n", mb[1]); + + if (atomic_read(&ha->loop_state) != LOOP_DOWN) { + atomic_set(&ha->loop_state, LOOP_DOWN); + atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME); + qla2x00_mark_all_devices_lost(ha); + } + + set_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); + + ha->operating_mode = LOOP; + ha->flags.management_server_logged_in = 0; + + /* Update AEN queue. */ + if (ha->ioctl->flags & IOCTL_AEN_TRACKING_ENABLE) { + qla2x00_enqueue_aen(ha, MBA_LIP_RESET, NULL); + } + + ha->total_lip_cnt++; + break; + + case MBA_POINT_TO_POINT: /* Point-to-Point */ + if (IS_QLA2100(ha)) + break; + + DEBUG2(printk("scsi(%ld): Asynchronous P2P MODE received.\n", + ha->host_no)); + + /* + * Until there's a transition from loop down to loop up, treat + * this as loop down only. + */ + if (atomic_read(&ha->loop_state) != LOOP_DOWN) { + atomic_set(&ha->loop_state, LOOP_DOWN); + if (!atomic_read(&ha->loop_down_timer)) + atomic_set(&ha->loop_down_timer, + LOOP_DOWN_TIME); + qla2x00_mark_all_devices_lost(ha); + } + + if (!(test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags))) { + set_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); + } + set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags); + break; + + case MBA_CHG_IN_CONNECTION: /* Change in connection mode */ + if (IS_QLA2100(ha)) + break; + + mb[1] = RD_MAILBOX_REG(ha, reg, 1); + + DEBUG2(printk("scsi(%ld): Asynchronous Change In Connection " + "received.\n", + ha->host_no)); + qla_printk(KERN_INFO, ha, + "Configuration change detected: value=%x.\n", mb[1]); + + if (atomic_read(&ha->loop_state) != LOOP_DOWN) { + atomic_set(&ha->loop_state, LOOP_DOWN); + if (!atomic_read(&ha->loop_down_timer)) + atomic_set(&ha->loop_down_timer, + LOOP_DOWN_TIME); + qla2x00_mark_all_devices_lost(ha); + } + + set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); + set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags); + break; + + case MBA_PORT_UPDATE: /* Port database update */ + mb[1] = RD_MAILBOX_REG(ha, reg, 1); + mb[2] = RD_MAILBOX_REG(ha, reg, 2); + + /* + * If a single remote port just logged into (or logged out of) + * us, create a new entry in our rscn fcports list and handle + * the event like an RSCN. + */ + if (IS_QLA23XX(ha) && ha->flags.init_done && mb[1] != 0xffff && + ((ha->operating_mode == P2P && mb[1] != 0) || + (ha->operating_mode != P2P && mb[1] != + SNS_FIRST_LOOP_ID)) && (mb[2] == 6 || mb[2] == 7)) { + int rval; + fc_port_t *rscn_fcport; + + /* Create new fcport for login. */ + rscn_fcport = qla2x00_alloc_rscn_fcport(ha, GFP_ATOMIC); + if (rscn_fcport) { + DEBUG14(printk("scsi(%ld): Port Update -- " + "creating RSCN fcport %p for login.\n", + ha->host_no, rscn_fcport)); + + rscn_fcport->loop_id = mb[1]; + rscn_fcport->d_id.b24 = INVALID_PORT_ID; + atomic_set(&rscn_fcport->state, + FCS_DEVICE_LOST); + list_add_tail(&rscn_fcport->list, + &ha->rscn_fcports); + + rval = qla2x00_handle_port_rscn(ha, 0, + rscn_fcport, 1); + if (rval == QLA_SUCCESS) + break; + } else { + DEBUG14(printk("scsi(%ld): Port Update -- " + "-- unable to allocate RSCN fcport " + "login.\n", ha->host_no)); + } + } + + /* + * If PORT UPDATE is global (recieved LIP_OCCURED/LIP_RESET + * event etc. earlier indicating loop is down) then process + * it. Otherwise ignore it and Wait for RSCN to come in. + */ + if (atomic_read(&ha->loop_state) != LOOP_DOWN) { + DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE " + "ignored.\n", ha->host_no)); + break; + } + + DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE.\n", + ha->host_no)); + DEBUG(printk(KERN_INFO + "scsi(%ld): Port database changed %04x %04x.\n", + ha->host_no, mb[1], mb[2])); + + /* + * Mark all devices as missing so we will login again. + */ + atomic_set(&ha->loop_state, LOOP_UP); + + atomic_set(&ha->loop_down_timer, 0); + qla2x00_mark_all_devices_lost(ha); + + ha->flags.rscn_queue_overflow = 1; + + set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); + set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags); + + /* Update AEN queue. */ + if (ha->ioctl->flags & IOCTL_AEN_TRACKING_ENABLE) { + qla2x00_enqueue_aen(ha, MBA_PORT_UPDATE, NULL); + } + break; + + case MBA_RSCN_UPDATE: /* State Change Registration */ + mb[1] = RD_MAILBOX_REG(ha, reg, 1); + mb[2] = RD_MAILBOX_REG(ha, reg, 2); + + DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n", + ha->host_no)); + DEBUG(printk(KERN_INFO + "scsi(%ld): RSCN database changed -- %04x %04x.\n", + ha->host_no, mb[1], mb[2])); + + rscn_entry = (mb[1] << 16) | mb[2]; + host_pid = (ha->d_id.b.domain << 16) | (ha->d_id.b.area << 8) | + ha->d_id.b.al_pa; + if (rscn_entry == host_pid) { + DEBUG(printk(KERN_INFO + "scsi(%ld): Ignoring RSCN update to local host " + "port ID (%06x)\n", + ha->host_no, host_pid)); + break; + } + + rscn_queue_index = ha->rscn_in_ptr + 1; + if (rscn_queue_index == MAX_RSCN_COUNT) + rscn_queue_index = 0; + if (rscn_queue_index != ha->rscn_out_ptr) { + ha->rscn_queue[ha->rscn_in_ptr] = rscn_entry; + ha->rscn_in_ptr = rscn_queue_index; + } else { + ha->flags.rscn_queue_overflow = 1; + } + + atomic_set(&ha->loop_state, LOOP_UPDATE); + atomic_set(&ha->loop_down_timer, 0); + ha->flags.management_server_logged_in = 0; + + set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); + set_bit(RSCN_UPDATE, &ha->dpc_flags); + + /* Update AEN queue. */ + if (ha->ioctl->flags & IOCTL_AEN_TRACKING_ENABLE) { + qla2x00_enqueue_aen(ha, MBA_RSCN_UPDATE, &mb[0]); + } + break; + + /* case MBA_RIO_RESPONSE: */ + case MBA_ZIO_RESPONSE: + DEBUG2(printk("scsi(%ld): [R|Z]IO update completion.\n", + ha->host_no)); + DEBUG(printk(KERN_INFO + "scsi(%ld): [R|Z]IO update completion.\n", + ha->host_no)); + + qla2x00_process_response_queue(ha); + break; + } +} + +/** + * qla2x00_process_completed_request() - Process a Fast Post response. + * @ha: SCSI driver HA context + * @index: SRB index + */ +static void +qla2x00_process_completed_request(struct scsi_qla_host *ha, uint32_t index) +{ + srb_t *sp; + + /* Validate handle. */ + if (index >= MAX_OUTSTANDING_COMMANDS) { + DEBUG2(printk("scsi(%ld): Invalid SCSI completion handle %d.\n", + ha->host_no, index)); + qla_printk(KERN_WARNING, ha, + "Invalid SCSI completion handle %d.\n", index); + + set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); + return; + } + + sp = ha->outstanding_cmds[index]; + if (sp) { + /* Free outstanding command slot. */ + ha->outstanding_cmds[index] = 0; + + /* Perform any post command processing */ + qla2x00_filter_command(ha, sp); + + if (ha->actthreads) + ha->actthreads--; + sp->lun_queue->out_cnt--; + CMD_COMPL_STATUS(sp->cmd) = 0L; + CMD_SCSI_STATUS(sp->cmd) = 0L; + + /* Save ISP completion status */ + sp->cmd->result = DID_OK << 16; + sp->fo_retry_cnt = 0; + add_to_done_queue(ha, sp); + } else { + DEBUG2(printk("scsi(%ld): Invalid ISP SCSI completion handle\n", + ha->host_no)); + qla_printk(KERN_WARNING, ha, + "Invalid ISP SCSI completion handle\n"); + + set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); + } +} + +/** + * qla2x00_process_response_queue() - Process response queue entries. + * @ha: SCSI driver HA context + */ +void +qla2x00_process_response_queue(struct scsi_qla_host *ha) +{ + device_reg_t *reg = ha->iobase; + sts_entry_t *pkt; + uint16_t handle_cnt; + uint16_t cnt; + + if (!ha->flags.online) + return; + + while (ha->response_ring_ptr->signature != RESPONSE_PROCESSED) { + pkt = (sts_entry_t *)ha->response_ring_ptr; + + ha->rsp_ring_index++; + if (ha->rsp_ring_index == ha->response_q_length) { + ha->rsp_ring_index = 0; + ha->response_ring_ptr = ha->response_ring; + } else { + ha->response_ring_ptr++; + } + + if (pkt->entry_status != 0) { + DEBUG3(printk(KERN_INFO + "scsi(%ld): Process error entry.\n", ha->host_no)); + + qla2x00_error_entry(ha, pkt); + ((response_t *)pkt)->signature = RESPONSE_PROCESSED; + wmb(); + continue; + } + + switch (pkt->entry_type) { + case STATUS_TYPE: + qla2x00_status_entry(ha, pkt); + break; + case STATUS_TYPE_21: + handle_cnt = ((sts21_entry_t *)pkt)->handle_count; + for (cnt = 0; cnt < handle_cnt; cnt++) { + qla2x00_process_completed_request(ha, + ((sts21_entry_t *)pkt)->handle[cnt]); + } + break; + case STATUS_TYPE_22: + handle_cnt = ((sts22_entry_t *)pkt)->handle_count; + for (cnt = 0; cnt < handle_cnt; cnt++) { + qla2x00_process_completed_request(ha, + ((sts22_entry_t *)pkt)->handle[cnt]); + } + break; + case STATUS_CONT_TYPE: + qla2x00_status_cont_entry(ha, (sts_cont_entry_t *)pkt); + break; + case MS_IOCB_TYPE: + qla2x00_ms_entry(ha, (ms_iocb_entry_t *)pkt); + break; + case MBX_IOCB_TYPE: + if (IS_QLA23XX(ha)) { + if (pkt->sys_define == SOURCE_ASYNC_IOCB) { + qla2x00_process_iodesc(ha, + (struct mbx_entry *)pkt); + } else { + /* MBX IOCB Type Not Supported. */ + DEBUG4(printk(KERN_WARNING + "scsi(%ld): Received unknown MBX " + "IOCB response pkt type=%x " + "source=%x entry status=%x.\n", + ha->host_no, pkt->entry_type, + pkt->sys_define, + pkt->entry_status)); + } + break; + } + /* Fallthrough. */ + default: + /* Type Not Supported. */ + DEBUG4(printk(KERN_WARNING + "scsi(%ld): Received unknown response pkt type %x " + "entry status=%x.\n", + ha->host_no, pkt->entry_type, pkt->entry_status)); + break; + } + ((response_t *)pkt)->signature = RESPONSE_PROCESSED; + wmb(); + } + + /* Adjust ring index */ + WRT_REG_WORD(ISP_RSP_Q_OUT(ha, reg), ha->rsp_ring_index); +} + +/** + * qla2x00_status_entry() - Process a Status IOCB entry. + * @ha: SCSI driver HA context + * @pkt: Entry pointer + */ +static void +qla2x00_status_entry(scsi_qla_host_t *ha, sts_entry_t *pkt) +{ + int ret; + unsigned b, t, l; + srb_t *sp; + os_lun_t *lq; + os_tgt_t *tq; + fc_port_t *fcport; + struct scsi_cmnd *cp; + uint16_t comp_status; + uint16_t scsi_status; + uint8_t lscsi_status; + uint32_t resid; + uint8_t sense_sz = 0; + + /* Fast path completion. */ + if (le16_to_cpu(pkt->comp_status) == CS_COMPLETE && + (le16_to_cpu(pkt->scsi_status) & SS_MASK) == 0) { + qla2x00_process_completed_request(ha, pkt->handle); + + return; + } + + /* Validate handle. */ + if (pkt->handle < MAX_OUTSTANDING_COMMANDS) { + sp = ha->outstanding_cmds[pkt->handle]; + ha->outstanding_cmds[pkt->handle] = 0; + } else + sp = NULL; + + if (sp == NULL) { + DEBUG2(printk("scsi(%ld): Status Entry invalid handle.\n", + ha->host_no)); + qla_printk(KERN_WARNING, ha, "Status Entry invalid handle.\n"); + + set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); + if (ha->dpc_wait && !ha->dpc_active) + up(ha->dpc_wait); + + return; + } + cp = sp->cmd; + if (cp == NULL) { + DEBUG2(printk("scsi(%ld): Command already returned back to OS " + "pkt->handle=%d sp=%p sp->state:%d\n", + ha->host_no, pkt->handle, sp, sp->state)); + qla_printk(KERN_WARNING, ha, + "Command is NULL: already returned to OS (sp=%p)\n", sp); + + return; + } + + if (ha->actthreads) + ha->actthreads--; + + if (sp->lun_queue == NULL) { + DEBUG2(printk("scsi(%ld): Status Entry invalid lun pointer.\n", + ha->host_no)); + qla_printk(KERN_WARNING, ha, + "Status Entry invalid lun pointer.\n"); + + set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); + if (ha->dpc_wait && !ha->dpc_active) + up(ha->dpc_wait); + + return; + } + + sp->lun_queue->out_cnt--; + + comp_status = le16_to_cpu(pkt->comp_status); + /* Mask of reserved bits 12-15, before we examine the scsi status */ + scsi_status = le16_to_cpu(pkt->scsi_status) & SS_MASK; + lscsi_status = scsi_status & STATUS_MASK; + + CMD_ENTRY_STATUS(cp) = pkt->entry_status; + CMD_COMPL_STATUS(cp) = comp_status; + CMD_SCSI_STATUS(cp) = scsi_status; + + /* Generate LU queue on cntrl, target, LUN */ + b = cp->device->channel; + t = cp->device->id; + l = cp->device->lun, + + tq = sp->tgt_queue; + lq = sp->lun_queue; + + /* + * If loop is in transient state Report DID_BUS_BUSY + */ + if ((comp_status != CS_COMPLETE || scsi_status != 0)) { + if (!(sp->flags & SRB_IOCTL) && + (atomic_read(&ha->loop_down_timer) || + atomic_read(&ha->loop_state) != LOOP_READY)) { + + DEBUG2(printk("scsi(%ld:%d:%d:%d): Loop Not Ready - " + "pid=%lx.\n", + ha->host_no, b, t, l, cp->serial_number)); + + qla2x00_extend_timeout(cp, EXTEND_CMD_TIMEOUT); + add_to_retry_queue(ha, sp); + return; + } + } + + /* + * Based on Host and scsi status generate status code for Linux + */ + switch (comp_status) { + case CS_COMPLETE: + if (scsi_status == 0) { + cp->result = DID_OK << 16; + + /* Perform any post command processing */ + qla2x00_filter_command(ha, sp); + break; + } + if (lscsi_status == SS_BUSY_CONDITION) { + cp->result = DID_BUS_BUSY << 16 | lscsi_status; + break; + } + + cp->result = DID_OK << 16 | lscsi_status; + + if (lscsi_status != SS_CHECK_CONDITION) + break; + + /* + * Copy Sense Data into sense buffer + */ + memset(cp->sense_buffer, 0, sizeof(cp->sense_buffer)); + + if (!(scsi_status & SS_SENSE_LEN_VALID)) + break; + + if (le16_to_cpu(pkt->req_sense_length) < + sizeof(cp->sense_buffer)) + sense_sz = le16_to_cpu(pkt->req_sense_length); + else + sense_sz = sizeof(cp->sense_buffer) - 1; + + CMD_ACTUAL_SNSLEN(cp) = sense_sz; + sp->request_sense_length = sense_sz; + sp->request_sense_ptr = cp->sense_buffer; + + if (sp->request_sense_length > 32) + sense_sz = 32; + + memcpy(cp->sense_buffer, pkt->req_sense_data, sense_sz); + + sp->request_sense_ptr += sense_sz; + sp->request_sense_length -= sense_sz; + if (sp->request_sense_length != 0) + ha->status_srb = sp; + + if (!(sp->flags & SRB_IOCTL) && + qla2x00_check_sense(cp, lq) == QLA_SUCCESS) { + /* Throw away status_cont if any */ + ha->status_srb = NULL; + add_to_scsi_retry_queue(ha, sp); + return; + } + + DEBUG5(printk("%s(): Check condition Sense data, " + "scsi(%ld:%d:%d:%d) cmd=%p pid=%ld\n", + __func__, ha->host_no, b, t, l, cp, + cp->serial_number)); + if (sense_sz) + DEBUG5(qla2x00_dump_buffer(cp->sense_buffer, + CMD_ACTUAL_SNSLEN(cp))); + break; + + case CS_DATA_UNDERRUN: + DEBUG2(printk(KERN_INFO + "scsi(%ld:%d:%d) UNDERRUN status detected 0x%x-0x%x.\n", + ha->host_no, t, l, comp_status, scsi_status)); + + resid = le32_to_cpu(pkt->residual_length); + CMD_RESID_LEN(cp) = resid; + + /* + * Check to see if SCSI Status is non zero. If so report SCSI + * Status. + */ + if (lscsi_status != 0) { + if (lscsi_status == SS_BUSY_CONDITION) { + cp->result = DID_BUS_BUSY << 16 | + lscsi_status; + break; + } + + cp->result = DID_OK << 16 | lscsi_status; + + if (lscsi_status != SS_CHECK_CONDITION) + break; + + /* Copy Sense Data into sense buffer */ + memset(cp->sense_buffer, 0, sizeof(cp->sense_buffer)); + + if (!(scsi_status & SS_SENSE_LEN_VALID)) + break; + + if (le16_to_cpu(pkt->req_sense_length) < + sizeof(cp->sense_buffer)) + sense_sz = le16_to_cpu(pkt->req_sense_length); + else + sense_sz = sizeof(cp->sense_buffer) - 1; + + CMD_ACTUAL_SNSLEN(cp) = sense_sz; + sp->request_sense_length = sense_sz; + sp->request_sense_ptr = cp->sense_buffer; + + if (sp->request_sense_length > 32) + sense_sz = 32; + + memcpy(cp->sense_buffer, pkt->req_sense_data, sense_sz); + + sp->request_sense_ptr += sense_sz; + sp->request_sense_length -= sense_sz; + if (sp->request_sense_length != 0) + ha->status_srb = sp; + + if (!(sp->flags & SRB_IOCTL) && + (qla2x00_check_sense(cp, lq) == QLA_SUCCESS)) { + ha->status_srb = NULL; + add_to_scsi_retry_queue(ha, sp); + return; + } + DEBUG5(printk("%s(): Check condition Sense data, " + "scsi(%ld:%d:%d:%d) cmd=%p pid=%ld\n", + __func__, ha->host_no, b, t, l, cp, + cp->serial_number)); + if (sense_sz) + DEBUG5(qla2x00_dump_buffer(cp->sense_buffer, + CMD_ACTUAL_SNSLEN(cp))); + } else { + /* + * If RISC reports underrun and target does not report + * it then we must have a lost frame, so tell upper + * layer to retry it by reporting a bus busy. + */ + if (!(scsi_status & SS_RESIDUAL_UNDER)) { + DEBUG2(printk("scsi(%ld:%d:%d:%d) Dropped " + "frame(s) detected (%x of %x bytes)..." + "retrying command.\n", + ha->host_no, b, t, l, resid, + cp->request_bufflen)); + + cp->result = DID_BUS_BUSY << 16; + ha->dropped_frame_error_cnt++; + break; + } + + /* Handle mid-layer underflow */ + cp->resid = resid; + if ((unsigned)(cp->request_bufflen - resid) < + cp->underflow) { + qla_printk(KERN_INFO, ha, + "scsi(%ld:%d:%d:%d): Mid-layer underflow " + "detected (%x of %x bytes)...returning " + "error status.\n", + ha->host_no, b, t, l, resid, + cp->request_bufflen); + + cp->result = DID_ERROR << 16; + break; + } + + /* Everybody online, looking good... */ + cp->result = DID_OK << 16; + + /* Perform any post command processing */ + qla2x00_filter_command(ha, sp); + } + break; + + case CS_DATA_OVERRUN: + DEBUG2(printk(KERN_INFO + "scsi(%ld:%d:%d): OVERRUN status detected 0x%x-0x%x\n", + ha->host_no, t, l, comp_status, scsi_status)); + DEBUG2(printk(KERN_INFO + "CDB: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + cp->cmnd[0], cp->cmnd[1], cp->cmnd[2], cp->cmnd[3], + cp->cmnd[4], cp->cmnd[5])); + DEBUG2(printk(KERN_INFO + "PID=0x%lx req=0x%x xtra=0x%x -- returning DID_ERROR " + "status!\n", + cp->serial_number, cp->request_bufflen, + le32_to_cpu(pkt->residual_length))); + + cp->result = DID_ERROR << 16; + break; + + case CS_PORT_LOGGED_OUT: + case CS_PORT_CONFIG_CHG: + case CS_PORT_BUSY: + case CS_INCOMPLETE: + case CS_PORT_UNAVAILABLE: + /* + * If the port is in Target Down state, return all IOs for this + * Target with DID_NO_CONNECT ELSE Queue the IOs in the + * retry_queue. + */ + fcport = sp->fclun->fcport; + DEBUG2(printk("scsi(%ld:%d:%d): status_entry: Port Down " + "pid=%ld, compl status=0x%x, port state=0x%x\n", + ha->host_no, t, l, cp->serial_number, comp_status, + atomic_read(&fcport->state))); + + if ((sp->flags & SRB_IOCTL) || + atomic_read(&fcport->state) == FCS_DEVICE_DEAD) { + cp->result = DID_NO_CONNECT << 16; + add_to_done_queue(ha, sp); + } else { + qla2x00_extend_timeout(cp, EXTEND_CMD_TIMEOUT); + add_to_retry_queue(ha, sp); + } + + if (atomic_read(&fcport->state) == FCS_ONLINE) { + qla2x00_mark_device_lost(ha, fcport, 1); + } + + return; + break; + + case CS_RESET: + DEBUG2(printk(KERN_INFO + "scsi(%ld): RESET status detected 0x%x-0x%x.\n", + ha->host_no, comp_status, scsi_status)); + + if (sp->flags & SRB_IOCTL) { + cp->result = DID_RESET << 16; + } else { + qla2x00_extend_timeout(cp, EXTEND_CMD_TIMEOUT); + add_to_retry_queue(ha, sp); + return; + } + break; + + case CS_ABORTED: + /* + * hv2.19.12 - DID_ABORT does not retry the request if we + * aborted this request then abort otherwise it must be a + * reset. + */ + DEBUG2(printk(KERN_INFO + "scsi(%ld): ABORT status detected 0x%x-0x%x.\n", + ha->host_no, comp_status, scsi_status)); + + cp->result = DID_RESET << 16; + break; + + case CS_TIMEOUT: + DEBUG2(printk(KERN_INFO + "scsi(%ld:%d:%d:%d): TIMEOUT status detected 0x%x-0x%x.\n", + ha->host_no, b, t, l, comp_status, scsi_status)); + + cp->result = DID_BUS_BUSY << 16; + + fcport = lq->fclun->fcport; + + /* Check to see if logout occurred */ + if ((le16_to_cpu(pkt->status_flags) & SF_LOGOUT_SENT)) { + qla2x00_mark_device_lost(ha, fcport, 1); + } + break; + + case CS_QUEUE_FULL: + DEBUG2(printk(KERN_INFO + "scsi(%ld): QUEUE FULL status detected 0x%x-0x%x.\n", + ha->host_no, comp_status, scsi_status)); + + /* SCSI Mid-Layer handles device queue full */ + + cp->result = DID_OK << 16 | lscsi_status; + + /* TODO: ??? */ + /* Adjust queue depth */ + ret = scsi_track_queue_full(cp->device, + sp->lun_queue->out_cnt - 1); + if (ret) { + qla_printk(KERN_INFO, ha, + "scsi(%ld:%d:%d:%d): Queue depth adjusted to %d.\n", + ha->host_no, cp->device->channel, cp->device->id, + cp->device->lun, ret); + } + break; + + default: + DEBUG3(printk("scsi(%ld): Error detected (unknown status) " + "0x%x-0x%x.\n", + ha->host_no, comp_status, scsi_status)); + qla_printk(KERN_INFO, ha, + "Unknown status detected 0x%x-0x%x.\n", + comp_status, scsi_status); + + cp->result = DID_ERROR << 16; + break; + } + + /* Place command on done queue. */ + if (ha->status_srb == NULL) + add_to_done_queue(ha, sp); +} + +/** + * qla2x00_status_cont_entry() - Process a Status Continuations entry. + * @ha: SCSI driver HA context + * @pkt: Entry pointer + * + * Extended sense data. + */ +static void +qla2x00_status_cont_entry(scsi_qla_host_t *ha, sts_cont_entry_t *pkt) +{ + uint8_t sense_sz = 0; + srb_t *sp = ha->status_srb; + struct scsi_cmnd *cp; + + if (sp != NULL && sp->request_sense_length != 0) { + cp = sp->cmd; + if (cp == NULL) { + DEBUG2(printk("%s(): Cmd already returned back to OS " + "sp=%p sp->state:%d\n", __func__, sp, sp->state)); + qla_printk(KERN_INFO, ha, + "cmd is NULL: already returned to OS (sp=%p)\n", + sp); + + ha->status_srb = NULL; + return; + } + + if (sp->request_sense_length > sizeof(pkt->data)) { + sense_sz = sizeof(pkt->data); + } else { + sense_sz = sp->request_sense_length; + } + + /* Move sense data. */ + memcpy(sp->request_sense_ptr, pkt->data, sense_sz); + DEBUG5(qla2x00_dump_buffer(sp->request_sense_ptr, sense_sz)); + + sp->request_sense_ptr += sense_sz; + sp->request_sense_length -= sense_sz; + + /* Place command on done queue. */ + if (sp->request_sense_length == 0) { + add_to_done_queue(ha, sp); + ha->status_srb = NULL; + } + } +} + +/** + * qla2x00_error_entry() - Process an error entry. + * @ha: SCSI driver HA context + * @pkt: Entry pointer + */ +static void +qla2x00_error_entry(scsi_qla_host_t *ha, sts_entry_t *pkt) +{ + srb_t *sp; + +#if defined(QL_DEBUG_LEVEL_2) + if (pkt->entry_status & RF_INV_E_ORDER) + qla_printk(KERN_ERR, ha, "%s: Invalid Entry Order\n", __func__); + else if (pkt->entry_status & RF_INV_E_COUNT) + qla_printk(KERN_ERR, ha, "%s: Invalid Entry Count\n", __func__); + else if (pkt->entry_status & RF_INV_E_PARAM) + qla_printk(KERN_ERR, ha, + "%s: Invalid Entry Parameter\n", __func__); + else if (pkt->entry_status & RF_INV_E_TYPE) + qla_printk(KERN_ERR, ha, "%s: Invalid Entry Type\n", __func__); + else if (pkt->entry_status & RF_BUSY) + qla_printk(KERN_ERR, ha, "%s: Busy\n", __func__); + else + qla_printk(KERN_ERR, ha, "%s: UNKNOWN flag error\n", __func__); +#endif + + /* Validate handle. */ + if (pkt->handle < MAX_OUTSTANDING_COMMANDS) + sp = ha->outstanding_cmds[pkt->handle]; + else + sp = NULL; + + if (sp) { + /* Free outstanding command slot. */ + ha->outstanding_cmds[pkt->handle] = 0; + if (ha->actthreads) + ha->actthreads--; + sp->lun_queue->out_cnt--; + + /* Bad payload or header */ + if (pkt->entry_status & + (RF_INV_E_ORDER | RF_INV_E_COUNT | + RF_INV_E_PARAM | RF_INV_E_TYPE)) { + sp->cmd->result = DID_ERROR << 16; + } else if (pkt->entry_status & RF_BUSY) { + sp->cmd->result = DID_BUS_BUSY << 16; + } else { + sp->cmd->result = DID_ERROR << 16; + } + /* Place command on done queue. */ + add_to_done_queue(ha, sp); + + } else if (pkt->entry_type == COMMAND_A64_TYPE || + pkt->entry_type == COMMAND_TYPE) { + DEBUG2(printk("scsi(%ld): Error entry - invalid handle\n", + ha->host_no)); + qla_printk(KERN_WARNING, ha, + "Error entry - invalid handle\n"); + + set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); + if (ha->dpc_wait && !ha->dpc_active) + up(ha->dpc_wait); + } +} + +/** + * qla2x00_ms_entry() - Process a Management Server entry. + * @ha: SCSI driver HA context + * @index: Response queue out pointer + */ +static void +qla2x00_ms_entry(scsi_qla_host_t *ha, ms_iocb_entry_t *pkt) +{ + srb_t *sp; + + DEBUG3(printk("%s(%ld): pkt=%p pkthandle=%d.\n", + __func__, ha->host_no, pkt, pkt->handle1)); + + /* Validate handle. */ + if (pkt->handle1 < MAX_OUTSTANDING_COMMANDS) + sp = ha->outstanding_cmds[pkt->handle1]; + else + sp = NULL; + + if (sp == NULL) { + DEBUG2(printk("scsi(%ld): MS entry - invalid handle\n", + ha->host_no)); + qla_printk(KERN_WARNING, ha, "MS entry - invalid handle\n"); + + set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); + return; + } + + CMD_COMPL_STATUS(sp->cmd) = le16_to_cpu(pkt->status); + CMD_ENTRY_STATUS(sp->cmd) = pkt->entry_status; + + /* Free outstanding command slot. */ + ha->outstanding_cmds[pkt->handle1] = 0; + + add_to_done_queue(ha, sp); +} + +/** + * qla2x00_check_sense() - Perform any sense data interrogation. + * @cp: SCSI Command + * @lq: Lun queue + * + * Returns QLA_SUCCESS if the lun queue is suspended, else + * QLA_FUNCTION_FAILED (lun queue not suspended). + */ +static int +qla2x00_check_sense(struct scsi_cmnd *cp, os_lun_t *lq) +{ + scsi_qla_host_t *ha; + srb_t *sp; + fc_port_t *fcport; + + ha = (scsi_qla_host_t *) cp->device->host->hostdata; + if ((cp->sense_buffer[0] & 0x70) != 0x70) { + return (QLA_FUNCTION_FAILED); + } + + sp = (srb_t * )CMD_SP(cp); + sp->flags |= SRB_GOT_SENSE; + + switch (cp->sense_buffer[2] & 0xf) { + case RECOVERED_ERROR: + cp->result = DID_OK << 16; + cp->sense_buffer[0] = 0; + break; + + case NOT_READY: + fcport = lq->fclun->fcport; + + /* + * Suspend the lun only for hard disk device type. + */ + if ((fcport->flags & FCF_TAPE_PRESENT) == 0 && + lq->q_state != LUN_STATE_TIMEOUT) { + /* + * If target is in process of being ready then suspend + * lun for 6 secs and retry all the commands. + */ + if (cp->sense_buffer[12] == 0x4 && + cp->sense_buffer[13] == 0x1) { + + /* Suspend the lun for 6 secs */ + qla2x00_suspend_lun(ha, lq, 6, + ql2xsuspendcount); + + return (QLA_SUCCESS); + } + } + break; + } + + return (QLA_FUNCTION_FAILED); +} diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qla_listops.h 830-ivtv/drivers/scsi/qla2xxx/qla_listops.h --- 000-virgin/drivers/scsi/qla2xxx/qla_listops.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qla_listops.h Thu Jan 8 10:22:00 2004 @@ -0,0 +1,351 @@ +/****************************************************************************** + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + ******************************************************************************/ + +/* Management functions for various lists */ + +/* __add_to_done_queue() + * + * Place SRB command on done queue. + * + * Input: + * ha = host pointer + * sp = srb pointer. + * Locking: + * this function assumes the ha->list_lock is already taken + */ +static inline void +__add_to_done_queue(struct scsi_qla_host * ha, srb_t * sp) +{ + /* + if (sp->state != SRB_NO_QUEUE_STATE && + sp->state != SRB_ACTIVE_STATE) + BUG(); + */ + + /* Place block on done queue */ + sp->cmd->host_scribble = (unsigned char *) NULL; + sp->state = SRB_DONE_STATE; + list_add_tail(&sp->list,&ha->done_queue); + ha->done_q_cnt++; + sp->ha = ha; +} + +static inline void +__add_to_retry_queue(struct scsi_qla_host * ha, srb_t * sp) +{ + /* + if( sp->state != SRB_NO_QUEUE_STATE && + sp->state != SRB_ACTIVE_STATE) + BUG(); + */ + + /* Place block on retry queue */ + list_add_tail(&sp->list,&ha->retry_queue); + ha->retry_q_cnt++; + sp->flags |= SRB_WATCHDOG; + sp->state = SRB_RETRY_STATE; + sp->ha = ha; +} + +static inline void +__add_to_scsi_retry_queue(struct scsi_qla_host * ha, srb_t * sp) +{ + /* + if( sp->state != SRB_NO_QUEUE_STATE && + sp->state != SRB_ACTIVE_STATE) + BUG(); + */ + + /* Place block on retry queue */ + list_add_tail(&sp->list,&ha->scsi_retry_queue); + ha->scsi_retry_q_cnt++; + sp->state = SRB_SCSI_RETRY_STATE; + sp->ha = ha; +} + +static inline void +add_to_done_queue(struct scsi_qla_host * ha, srb_t * sp) +{ + unsigned long flags; + + spin_lock_irqsave(&ha->list_lock, flags); + __add_to_done_queue(ha,sp); + spin_unlock_irqrestore(&ha->list_lock, flags); +} + +static inline void +add_to_free_queue(struct scsi_qla_host * ha, srb_t * sp) +{ + mempool_free(sp, ha->srb_mempool); +} + +static inline void +add_to_retry_queue(struct scsi_qla_host * ha, srb_t * sp) +{ + unsigned long flags; + + spin_lock_irqsave(&ha->list_lock, flags); + __add_to_retry_queue(ha,sp); + spin_unlock_irqrestore(&ha->list_lock, flags); +} + +static inline void +add_to_scsi_retry_queue(struct scsi_qla_host * ha, srb_t * sp) +{ + unsigned long flags; + + spin_lock_irqsave(&ha->list_lock, flags); + __add_to_scsi_retry_queue(ha,sp); + spin_unlock_irqrestore(&ha->list_lock, flags); +} + +/* + * __del_from_retry_queue + * Function used to remove a command block from the + * watchdog timer queue. + * + * Note: Must insure that command is on watchdog + * list before calling del_from_retry_queue + * if (sp->flags & SRB_WATCHDOG) + * + * Input: + * ha = adapter block pointer. + * sp = srb pointer. + * Locking: + * this function assumes the list_lock is already taken + */ +static inline void +__del_from_retry_queue(struct scsi_qla_host * ha, srb_t * sp) +{ + list_del_init(&sp->list); + + sp->flags &= ~(SRB_WATCHDOG | SRB_BUSY); + sp->state = SRB_NO_QUEUE_STATE; + ha->retry_q_cnt--; +} + +/* + * __del_from_scsi_retry_queue + * Function used to remove a command block from the + * scsi retry queue. + * + * Input: + * ha = adapter block pointer. + * sp = srb pointer. + * Locking: + * this function assumes the list_lock is already taken + */ +static inline void +__del_from_scsi_retry_queue(struct scsi_qla_host * ha, srb_t * sp) +{ + list_del_init(&sp->list); + + ha->scsi_retry_q_cnt--; + sp->state = SRB_NO_QUEUE_STATE; +} + +/* + * del_from_retry_queue + * Function used to remove a command block from the + * watchdog timer queue. + * + * Note: Must insure that command is on watchdog + * list before calling del_from_retry_queue + * if (sp->flags & SRB_WATCHDOG) + * + * Input: + * ha = adapter block pointer. + * sp = srb pointer. + * Locking: + * this function takes and releases the list_lock + */ +static inline void +del_from_retry_queue(struct scsi_qla_host * ha, srb_t * sp) +{ + unsigned long flags; + + /* if (unlikely(!(sp->flags & SRB_WATCHDOG))) + BUG();*/ + spin_lock_irqsave(&ha->list_lock, flags); + + /* if (unlikely(list_empty(&ha->retry_queue))) + BUG();*/ + + __del_from_retry_queue(ha,sp); + + spin_unlock_irqrestore(&ha->list_lock, flags); +} +/* + * del_from_scsi_retry_queue + * Function used to remove a command block from the + * scsi retry queue. + * + * Input: + * ha = adapter block pointer. + * sp = srb pointer. + * Locking: + * this function takes and releases the list_lock + */ +static inline void +del_from_scsi_retry_queue(struct scsi_qla_host * ha, srb_t * sp) +{ + unsigned long flags; + + spin_lock_irqsave(&ha->list_lock, flags); + + /* if (unlikely(list_empty(&ha->scsi_retry_queue))) + BUG();*/ + + __del_from_scsi_retry_queue(ha,sp); + + spin_unlock_irqrestore(&ha->list_lock, flags); +} + +/* + * __add_to_pending_queue + * Add the standard SCB job to the bottom of standard SCB commands. + * + * Input: + * COMPLETE!!! + * q = SCSI LU pointer. + * sp = srb pointer. + * SCSI_LU_Q lock must be already obtained. + */ +static inline int +__add_to_pending_queue(struct scsi_qla_host *ha, srb_t * sp) +{ + int empty; + /* + if( sp->state != SRB_NO_QUEUE_STATE && + sp->state != SRB_FREE_STATE && + sp->state != SRB_ACTIVE_STATE) + BUG(); + */ + + empty = list_empty(&ha->pending_queue); + list_add_tail(&sp->list, &ha->pending_queue); + ha->qthreads++; + sp->state = SRB_PENDING_STATE; + + return (empty); +} + +static inline void +__add_to_pending_queue_head(struct scsi_qla_host *ha, srb_t * sp) +{ + /* + if( sp->state != SRB_NO_QUEUE_STATE && + sp->state != SRB_FREE_STATE && + sp->state != SRB_ACTIVE_STATE) + BUG(); + */ + + list_add(&sp->list, &ha->pending_queue); + ha->qthreads++; + sp->state = SRB_PENDING_STATE; +} + +static inline int +add_to_pending_queue(struct scsi_qla_host *ha, srb_t *sp) +{ + int empty; + unsigned long flags; + + spin_lock_irqsave(&ha->list_lock, flags); + empty = __add_to_pending_queue(ha, sp); + spin_unlock_irqrestore(&ha->list_lock, flags); + + return (empty); +} +static inline void +add_to_pending_queue_head(struct scsi_qla_host *ha, srb_t *sp) +{ + unsigned long flags; + + spin_lock_irqsave(&ha->list_lock, flags); + __add_to_pending_queue_head(ha, sp); + spin_unlock_irqrestore(&ha->list_lock, flags); +} + +static inline void +__del_from_pending_queue(struct scsi_qla_host *ha, srb_t *sp) +{ + list_del_init(&sp->list); + ha->qthreads--; + sp->state = SRB_NO_QUEUE_STATE; +} + +/* + * Failover Stuff. + */ +static inline void +__add_to_failover_queue(struct scsi_qla_host * ha, srb_t * sp) +{ + /* + if( sp->state != SRB_NO_QUEUE_STATE && + sp->state != SRB_ACTIVE_STATE) + BUG(); + */ + + list_add_tail(&sp->list,&ha->failover_queue); + ha->failover_cnt++; + sp->state = SRB_FAILOVER_STATE; + sp->ha = ha; +} + +static inline void add_to_failover_queue(struct scsi_qla_host * ha, srb_t * sp) +{ + unsigned long flags; + + spin_lock_irqsave(&ha->list_lock, flags); + + __add_to_failover_queue(ha,sp); + + spin_unlock_irqrestore(&ha->list_lock, flags); +} +static inline void __del_from_failover_queue(struct scsi_qla_host * ha, srb_t * + sp) +{ + ha->failover_cnt--; + list_del_init(&sp->list); + sp->state = SRB_NO_QUEUE_STATE; +} + +static inline void del_from_failover_queue(struct scsi_qla_host * ha, srb_t * sp) +{ + unsigned long flags; + + spin_lock_irqsave(&ha->list_lock, flags); + + __del_from_failover_queue(ha,sp); + + spin_unlock_irqrestore(&ha->list_lock, flags); +} + +static inline void +del_from_pending_queue(struct scsi_qla_host * ha, srb_t * sp) +{ + unsigned long flags; + + spin_lock_irqsave(&ha->list_lock, flags); + + __del_from_pending_queue(ha,sp); + + spin_unlock_irqrestore(&ha->list_lock, flags); +} diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qla_mbx.c 830-ivtv/drivers/scsi/qla2xxx/qla_mbx.c --- 000-virgin/drivers/scsi/qla2xxx/qla_mbx.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qla_mbx.c Thu Jan 8 10:22:00 2004 @@ -0,0 +1,2903 @@ +/* + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +#include "qla_os.h" + +#include "qla_def.h" + +/* + * Local Function Prototypes. + */ +static void +qla2x00_mbx_sem_timeout(unsigned long); + +static int +qla2x00_get_mbx_access(scsi_qla_host_t *, uint32_t); + +static int +qla2x00_release_mbx_access(scsi_qla_host_t *, uint32_t); + +static int +qla2x00_mbx_q_add(scsi_qla_host_t *, mbx_cmdq_t **); + +static void +qla2x00_mbx_q_get(scsi_qla_host_t *, mbx_cmdq_t **); + +static void +qla2x00_mbx_q_memb_alloc(scsi_qla_host_t *, mbx_cmdq_t **); + +static void +qla2x00_mbx_q_memb_free(scsi_qla_host_t *, mbx_cmdq_t *); + +/***************************/ +/* Function implementation */ +/***************************/ + +static void +qla2x00_mbx_sem_timeout(unsigned long data) +{ + struct semaphore *sem_ptr = (struct semaphore *)data; + + DEBUG11(printk("qla2x00_sem_timeout: entered.\n");) + + if (sem_ptr != NULL) { + up(sem_ptr); + } + + DEBUG11(printk("qla2x00_mbx_sem_timeout: exiting.\n");) +} + +/* + * tov = timeout value in seconds + */ +static int +qla2x00_get_mbx_access(scsi_qla_host_t *ha, uint32_t tov) +{ + int ret; + int prev_val = 1; /* assume no access yet */ + mbx_cmdq_t *ptmp_mbq; + struct timer_list tmp_cmd_timer; + unsigned long cpu_flags; + + + DEBUG11(printk("qla2x00_get_mbx_access(%ld): entered.\n", + ha->host_no);) + + while (1) { + if (test_bit(MBX_CMD_WANT, &ha->mbx_cmd_flags) == 0) { + + DEBUG11(printk("qla2x00_get_mbx_access(%ld): going " + " to test access flags.\n", ha->host_no);) + + /* No one else is waiting. Go ahead and try to + * get access. + */ + if ((prev_val = test_and_set_bit(MBX_CMD_ACTIVE, + &ha->mbx_cmd_flags)) == 0) { + break; + } + } + + /* wait for previous command to finish */ + DEBUG(printk("qla2x00_get_mbx_access(%ld): access " + "flags=%lx. busy. Waiting for access. curr time=0x%lx.\n", + ha->host_no, ha->mbx_cmd_flags, jiffies);) + + DEBUG11(printk("qla2x00_get_mbx_access(%ld): access " + "flags=%lx. busy. Waiting for access. curr time=0x%lx.\n", + ha->host_no, ha->mbx_cmd_flags, jiffies);) + + /* + * Init timer and get semaphore from mbx q. After we got valid + * semaphore pointer the MBX_CMD_WANT flag would also had + * been set. + */ + qla2x00_mbx_q_add(ha, &ptmp_mbq); + + if (ptmp_mbq == NULL) { + /* queue full? problem? can't proceed. */ + DEBUG2_3_11(printk("qla2x00_get_mbx_access(%ld): ERROR " + "no more mbx_q allowed. exiting.\n", ha->host_no);) + + break; + } + + /* init timer and semaphore */ + init_timer(&tmp_cmd_timer); + tmp_cmd_timer.data = (unsigned long)&ptmp_mbq->cmd_sem; + tmp_cmd_timer.function = + (void (*)(unsigned long))qla2x00_mbx_sem_timeout; + tmp_cmd_timer.expires = jiffies + tov * HZ; + + DEBUG11(printk("get_mbx_access(%ld): adding timer. " + "curr time=0x%lx timeoutval=0x%lx.\n", + ha->host_no, jiffies, tmp_cmd_timer.expires);) + + /* wait. */ +/* add_timer(&tmp_cmd_timer);*/ + DEBUG11(printk("get_mbx_access(%ld): going to sleep. " + "current time=0x%lx.\n", ha->host_no, jiffies);) + + down_interruptible(&ptmp_mbq->cmd_sem); + + DEBUG11(printk("get_mbx_access(%ld): woke up. current " + "time=0x%lx.\n", + ha->host_no, jiffies);) + +/* del_timer(&tmp_cmd_timer);*/ + + /* try to get lock again. we'll test later to see + * if we actually got the lock. + */ + prev_val = test_and_set_bit(MBX_CMD_ACTIVE, + &ha->mbx_cmd_flags); + + /* + * After we tried to get access then we check to see + * if we need to clear the MBX_CMD_WANT flag. Don't clear + * this flag before trying to get access or else another + * new thread might grab it before we did. + */ + spin_lock_irqsave(&ha->mbx_q_lock, cpu_flags); + if (ha->mbx_q_head == NULL) { + /* We're the last thread in queue. */ + clear_bit(MBX_CMD_WANT, &ha->mbx_cmd_flags); + } + qla2x00_mbx_q_memb_free(ha, ptmp_mbq); + spin_unlock_irqrestore(&ha->mbx_q_lock, cpu_flags); + + break; + } + + if (prev_val == 0) { + /* We got the lock */ + DEBUG11(printk("qla2x00_get_mbx_access(%ld): success.\n", + ha->host_no);) + + ret = QLA_SUCCESS; + } else { + /* Timeout or resource error. */ + DEBUG2_3_11(printk("qla2x00_get_mbx_access(%ld): timed out.\n", + ha->host_no);) + + ret = QLA_FUNCTION_TIMEOUT; + } + + return ret; +} + +static int +qla2x00_release_mbx_access(scsi_qla_host_t *ha, uint32_t tov) +{ + mbx_cmdq_t *next_thread; + + DEBUG11(printk("qla2x00_release_mbx_access:(%ld): entered.\n", + ha->host_no);) + + clear_bit(MBX_CMD_ACTIVE, &ha->mbx_cmd_flags); + + /* Wake up one pending mailbox cmd thread in queue. */ + qla2x00_mbx_q_get(ha, &next_thread); + if (next_thread) { + DEBUG11(printk("qla2x00_release_mbx_access: found pending " + "mbx cmd. Waking up sem in %p.\n", &next_thread);) + up(&next_thread->cmd_sem); + } + + DEBUG11(printk("qla2x00_release_mbx_access:(%ld): exiting.\n", + ha->host_no);) + + return QLA_SUCCESS; +} + +/* Allocates a mbx_cmdq_t struct and add to the mbx_q list. */ +static int +qla2x00_mbx_q_add(scsi_qla_host_t *ha, mbx_cmdq_t **ret_mbq) +{ + int ret; + unsigned long cpu_flags; + mbx_cmdq_t *ptmp = NULL; + + spin_lock_irqsave(&ha->mbx_q_lock, cpu_flags); + + DEBUG11(printk("qla2x00_mbx_q_add: got mbx_q spinlock. " + "Inst=%d.\n", apiHBAInstance);) + + qla2x00_mbx_q_memb_alloc(ha, &ptmp); + if (ptmp == NULL) { + /* can't add any more threads */ + DEBUG2_3_11(printk("qla2x00_mbx_q_add: ERROR no more " + "ioctl threads allowed. Inst=%d.\n", apiHBAInstance);) + + ret = QLA_MEMORY_ALLOC_FAILED; + } else { + if (ha->mbx_q_tail == NULL) { + /* First thread to queue. */ + set_bit(IOCTL_WANT, &ha->mbx_cmd_flags); + + ha->mbx_q_head = ptmp; + } else { + ha->mbx_q_tail->pnext = ptmp; + } + ha->mbx_q_tail = ptmp; + + /* Now init the semaphore */ + init_MUTEX_LOCKED(&ptmp->cmd_sem); + ret = QLA_SUCCESS; + } + + *ret_mbq = ptmp; + + DEBUG11(printk("qla2x00_mbx_q_add: going to release spinlock. " + "ret_mbq=%p, ret=%d. Inst=%d.\n", *ret_mbq, ret, apiHBAInstance);) + + spin_unlock_irqrestore(&ha->mbx_q_lock, cpu_flags); + + return ret; +} + +/* Just remove and return first member from mbx_cmdq. Don't free anything. */ +static void +qla2x00_mbx_q_get(scsi_qla_host_t *ha, mbx_cmdq_t **ret_mbq) +{ + unsigned long cpu_flags; + + spin_lock_irqsave(&ha->mbx_q_lock, cpu_flags); + + DEBUG11(printk("qla2x00_mbx_q_get: got mbx_q spinlock. " + "Inst=%d.\n", apiHBAInstance);) + + /* Remove from head */ + *ret_mbq = ha->mbx_q_head; + if (ha->mbx_q_head != NULL) { + ha->mbx_q_head = ha->mbx_q_head->pnext; + if (ha->mbx_q_head == NULL) { + /* That's the last one in queue. */ + ha->mbx_q_tail = NULL; + } + (*ret_mbq)->pnext = NULL; + } + + DEBUG11(printk("qla2x00_mbx_q_remove: return ret_mbq=%p. Going to " + "release spinlock. Inst=%d.\n", *ret_mbq, apiHBAInstance);) + + spin_unlock_irqrestore(&ha->mbx_q_lock, cpu_flags); +} + +/* Find a free mbx_q member from the array. Must already got the + * mbx_q_lock spinlock. + */ +static void +qla2x00_mbx_q_memb_alloc(scsi_qla_host_t *ha, mbx_cmdq_t **ret_mbx_q_memb) +{ + mbx_cmdq_t *ptmp = NULL; + + DEBUG11(printk("qla2x00_mbx_q_memb_alloc: entered. " + "Inst=%d.\n", apiHBAInstance);) + + ptmp = ha->mbx_sem_pool_head; + if (ptmp != NULL) { + ha->mbx_sem_pool_head = ptmp->pnext; + ptmp->pnext = NULL; + if (ha->mbx_sem_pool_head == NULL) { + ha->mbx_sem_pool_tail = NULL; + } + } else { + /* We ran out of pre-allocated semaphores. Try to allocate + * a new one. + */ + ptmp = (void *)KMEM_ZALLOC(sizeof(mbx_cmdq_t), 40); + } + + *ret_mbx_q_memb = ptmp; + + DEBUG11(printk("qla2x00_mbx_q_memb_alloc: return waitq_memb=%p. " + "Inst=%d.\n", *ret_mbx_q_memb, apiHBAInstance);) +} + +/* Add the specified mbx_q member back to the free semaphore pool. Must + * already got the mbx_q_lock spinlock. + */ +static void +qla2x00_mbx_q_memb_free(scsi_qla_host_t *ha, mbx_cmdq_t *pfree_mbx_q_memb) +{ + DEBUG11(printk("qla2x00_mbx_q_memb_free: entered. Inst=%d.\n", + apiHBAInstance);) + + if (pfree_mbx_q_memb != NULL) { + if (ha->mbx_sem_pool_tail != NULL) { + /* Add to tail */ + ha->mbx_sem_pool_tail->pnext = pfree_mbx_q_memb; + } else { + ha->mbx_sem_pool_head = pfree_mbx_q_memb; + } + ha->mbx_sem_pool_tail = pfree_mbx_q_memb; + } + + /* put it back to the free pool. */ + + DEBUG11(printk("qla2x00_mbx_q_memb_free: exiting. " + "Inst=%d.\n", apiHBAInstance);) +} + +/* + * qla2x00_mailbox_command + * Issue mailbox command and waits for completion. + * + * Input: + * ha = adapter block pointer. + * mcp = driver internal mbx struct pointer. + * + * Output: + * mb[MAX_MAILBOX_REGISTER_COUNT] = returned mailbox data. + * + * Returns: + * 0 : QLA_SUCCESS = cmd performed success + * 1 : QLA_FUNCTION_FAILED (error encountered) + * 6 : QLA_FUNCTION_TIMEOUT (timeout condition encountered) + * + * Context: + * Kernel context. + */ +int +qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) +{ + int rval; + unsigned long flags = 0; + device_reg_t *reg = ha->iobase; + struct timer_list tmp_intr_timer; + uint8_t abort_active = test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); + uint8_t io_lock_on = ha->flags.init_done; + uint8_t tmp_stat = 0; + uint16_t command; + uint16_t *iptr, *optr; + uint32_t cnt; + uint32_t mboxes; + unsigned long mbx_flags = 0; + unsigned long wait_time; + + rval = QLA_SUCCESS; + + DEBUG11(printk("qla2x00_mailbox_command(%ld): entered.\n", + ha->host_no);) + /* + * Wait for active mailbox commands to finish by waiting at most + * tov seconds. This is to serialize actual issuing of mailbox cmds + * during non ISP abort time. + */ + if (!abort_active) { + tmp_stat = qla2x00_get_mbx_access(ha, mcp->tov); + if (tmp_stat != QLA_SUCCESS) { + /* Timeout occurred. Return error. */ + DEBUG2_3_11(printk("qla2x00_mailbox_command(%ld): cmd " + "access timeout. Exiting.\n", ha->host_no);) + return QLA_FUNCTION_TIMEOUT; + } + } + + ha->flags.mbox_busy = TRUE; + /* Save mailbox command for debug */ + ha->mcp = mcp; + + /* Try to get mailbox register access */ + if (!abort_active) + spin_lock_irqsave(&ha->mbx_reg_lock, mbx_flags); + + DEBUG11(printk("scsi%d: prepare to issue mbox cmd=0x%x.\n", + (int)ha->host_no, mcp->mb[0]);) + + spin_lock_irqsave(&ha->hardware_lock, flags); + + /* Load mailbox registers. */ + optr = (uint16_t *)MAILBOX_REG(ha, reg, 0); + + iptr = mcp->mb; + command = mcp->mb[0]; + mboxes = mcp->out_mb; + + for (cnt = 0; cnt < ha->mbx_count; cnt++) { + if (IS_QLA2200(ha) && cnt == 8) + optr = (uint16_t *)MAILBOX_REG(ha, reg, 8); + if (mboxes & BIT_0) + WRT_REG_WORD(optr, *iptr); + + mboxes >>= 1; + optr++; + iptr++; + } + +#if defined(QL_DEBUG_LEVEL_1) + printk("qla2x00_mailbox_command: Loaded MBX registers " + "(displayed in bytes) = \n"); + qla2x00_dump_buffer((uint8_t *)mcp->mb, 16); + printk("\n"); + qla2x00_dump_buffer(((uint8_t *)mcp->mb + 0x10), 16); + printk("\n"); + qla2x00_dump_buffer(((uint8_t *)mcp->mb + 0x20), 8); + printk("\n"); + printk("qla2x00_mailbox_command: I/O address = %lx.\n", + (u_long)optr); + qla2x00_dump_regs(ha); +#endif + + /* Issue set host interrupt command to send cmd out. */ + ha->flags.mbox_int = FALSE; + clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); + + /* Unlock mbx registers and wait for interrupt */ + + DEBUG11(printk("qla2x00_mailbox_command: going to unlock irq & " + "waiting for interrupt. jiffies=%lx.\n", jiffies);) + + /* Wait for mbx cmd completion until timeout */ + + if (!abort_active && io_lock_on) { + /* sleep on completion semaphore */ + DEBUG11(printk("qla2x00_mailbox_command(%ld): " + "INTERRUPT MODE. Initializing timer.\n", + ha->host_no);) + + init_timer(&tmp_intr_timer); + tmp_intr_timer.data = (unsigned long)&ha->mbx_intr_sem; + tmp_intr_timer.expires = jiffies + mcp->tov * HZ; + tmp_intr_timer.function = + (void (*)(unsigned long))qla2x00_mbx_sem_timeout; + + DEBUG11(printk("qla2x00_mailbox_command(%ld): " + "Adding timer.\n", ha->host_no);) + add_timer(&tmp_intr_timer); + + DEBUG11(printk("qla2x00_mailbox_command: going to " + "unlock & sleep. time=0x%lx.\n", jiffies);) + + set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags); + + WRT_REG_WORD(®->hccr, HCCR_SET_HOST_INT); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + if (!abort_active) + spin_unlock_irqrestore(&ha->mbx_reg_lock, mbx_flags); + + /* Wait for either the timer to expire + * or the mbox completion interrupt + */ + down_interruptible(&ha->mbx_intr_sem); + + DEBUG11(printk("qla2x00_mailbox_command:" + "waking up." + "time=0x%lx\n", jiffies);) + clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags); + + /* delete the timer */ + del_timer(&tmp_intr_timer); + } else { + + DEBUG3_11(printk("qla2x00_mailbox_command(%ld): cmd=%x " + "POLLING MODE.\n", ha->host_no, command);) + + WRT_REG_WORD(®->hccr, HCCR_SET_HOST_INT); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + if (!abort_active) + spin_unlock_irqrestore(&ha->mbx_reg_lock, mbx_flags); + + wait_time = jiffies + mcp->tov * HZ; /* wait at most tov secs */ + while (!ha->flags.mbox_int) { + if (time_after(jiffies, wait_time)) + break; + + /* Check for pending interrupts. */ + qla2x00_poll(ha); + + udelay(10); /* v4.27 */ + } /* while */ + } + + if (!abort_active) + spin_lock_irqsave(&ha->mbx_reg_lock, mbx_flags); + + /* Check whether we timed out */ + if (ha->flags.mbox_int) { + + DEBUG3_11(printk("qla2x00_mailbox_cmd: cmd %x completed.\n", + command);) + + /* Got interrupt. Clear the flag. */ + ha->flags.mbox_int = FALSE; + clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); + + if (ha->mailbox_out[0] != MBS_COMMAND_COMPLETE) { + qla2x00_stats.mboxerr++; + rval = QLA_FUNCTION_FAILED; + } + + /* Load return mailbox registers. */ + optr = mcp->mb; + iptr = (uint16_t *)&ha->mailbox_out[0]; + mboxes = mcp->in_mb; + for (cnt = 0; cnt < ha->mbx_count; cnt++) { + if (mboxes & BIT_0) + *optr = *iptr; + + mboxes >>= 1; + optr++; + iptr++; + } + } else { + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) || \ + defined(QL_DEBUG_LEVEL_11) + printk("qla2x00_mailbox_command(%ld): **** MB Command Timeout " + "for cmd %x ****\n", ha->host_no, command); + printk("qla2x00_mailbox_command: icontrol=%x jiffies=%lx\n", + RD_REG_WORD(®->ictrl), jiffies); + printk("qla2x00_mailbox_command: *** mailbox[0] = 0x%x ***\n", + RD_REG_WORD(optr)); + qla2x00_dump_regs(ha); +#endif + + qla2x00_stats.mboxtout++; + ha->total_mbx_timeout++; + rval = QLA_FUNCTION_TIMEOUT; + } + + if (!abort_active) + spin_unlock_irqrestore(&ha->mbx_reg_lock, mbx_flags); + + ha->flags.mbox_busy = FALSE; + + /* Clean up */ + ha->mcp = NULL; + + if (!abort_active) { + DEBUG11(printk("qla2x00_mailbox_cmd: checking for additional " + "resp interrupt.\n");) + + /* polling mode for non isp_abort commands. */ + qla2x00_poll(ha); + } + + if (rval == QLA_FUNCTION_TIMEOUT) { + if (!io_lock_on || (mcp->flags & IOCTL_CMD)) { + /* not in dpc. schedule it for dpc to take over. */ + DEBUG(printk("qla2x00_mailbox_command(%ld): timeout " + "schedule isp_abort_needed.\n", + ha->host_no);) + DEBUG2_3_11(printk("qla2x00_mailbox_command(%ld): " + "timeout schedule isp_abort_needed.\n", + ha->host_no);) + set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); + if (ha->dpc_wait && !ha->dpc_active) + up(ha->dpc_wait); + + } else if (!abort_active) { + + /* call abort directly since we are in the DPC thread */ + DEBUG(printk("qla2x00_mailbox_command(%ld): timeout " + "calling abort_isp\n", ha->host_no);) + DEBUG2_3_11(printk("qla2x00_mailbox_command(%ld): " + "timeout calling abort_isp\n", ha->host_no);) + + set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); + clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); + if (qla2x00_abort_isp(ha)) { + /* failed. retry later. */ + set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); + } + clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); + + DEBUG(printk("qla2x00_mailbox_command: finished " + "abort_isp\n");) + DEBUG2_3_11(printk("qla2x00_mailbox_command: finished " + "abort_isp\n");) + } + } + + /* Allow next mbx cmd to come in. */ + if (!abort_active) { + tmp_stat = qla2x00_release_mbx_access(ha, mcp->tov); + + if (rval == 0) + rval = tmp_stat; + } + + if (rval) { + DEBUG2_3_11(printk("qla2x00_mailbox_command(%ld): **** FAILED. " + "mbx0=%x, mbx1=%x, mbx2=%x, cmd=%x ****\n", + ha->host_no, mcp->mb[0], mcp->mb[1], mcp->mb[2], command);) + } else { + DEBUG11(printk("qla2x00_mailbox_command(%ld): done.\n", + ha->host_no);) + } + + DEBUG11(printk("qla2x00_mailbox_command(%ld): exiting.\n", + ha->host_no);) + + return rval; +} + +/* + * qla2x00_load_ram + * Load adapter RAM using DMA. + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_load_ram(scsi_qla_host_t *ha, dma_addr_t req_dma, uint16_t risc_addr, + uint16_t risc_code_size) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + uint32_t req_len; + dma_addr_t nml_dma; + uint32_t nml_len; + uint32_t normalized; + + DEBUG11(printk("qla2x00_load_ram(%ld): entered.\n", + ha->host_no);) + + req_len = risc_code_size; + nml_dma = 0; + nml_len = 0; + + normalized = qla2x00_normalize_dma_addr(&req_dma, &req_len, &nml_dma, + &nml_len); + + /* Load first segment */ + mcp->mb[0] = MBC_LOAD_RISC_RAM; + mcp->mb[1] = risc_addr; + mcp->mb[2] = MSW(req_dma); + mcp->mb[3] = LSW(req_dma); + mcp->mb[4] = (uint16_t)req_len; + mcp->mb[6] = MSW(MSD(req_dma)); + mcp->mb[7] = LSW(MSD(req_dma)); + mcp->out_mb = MBX_7|MBX_6|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + /* Load second segment - if necessary */ + if (normalized && (rval == QLA_SUCCESS)) { + mcp->mb[0] = MBC_LOAD_RISC_RAM; + mcp->mb[1] = risc_addr + (uint16_t)req_len; + mcp->mb[2] = MSW(nml_dma); + mcp->mb[3] = LSW(nml_dma); + mcp->mb[4] = (uint16_t)nml_len; + mcp->mb[6] = MSW(MSD(nml_dma)); + mcp->mb[7] = LSW(MSD(nml_dma)); + mcp->out_mb = MBX_7|MBX_6|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + } + + if (rval == QLA_SUCCESS) { + /* Empty */ + DEBUG11(printk("qla2x00_load_ram(%ld): done.\n", ha->host_no);) + } else { + /* Empty */ + DEBUG2_3_11(printk("qla2x00_load_ram(%ld): failed. rval=%x " + "mb[0]=%x.\n", ha->host_no, rval, mcp->mb[0]);) + } + return rval; +} + +/* + * qla2x00_load_ram_ext + * Load adapter extended RAM using DMA. + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_load_ram_ext(scsi_qla_host_t *ha, dma_addr_t req_dma, + uint32_t risc_addr, uint16_t risc_code_size) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + uint32_t req_len; + dma_addr_t nml_dma; + uint32_t nml_len; + uint32_t normalized; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); + + req_len = risc_code_size; + nml_dma = 0; + nml_len = 0; + + normalized = qla2x00_normalize_dma_addr(&req_dma, &req_len, &nml_dma, + &nml_len); + + /* Load first segment */ + mcp->mb[0] = MBC_LOAD_RISC_RAM_EXTENDED; + mcp->mb[1] = LSW(risc_addr); + mcp->mb[2] = MSW(req_dma); + mcp->mb[3] = LSW(req_dma); + mcp->mb[4] = (uint16_t)req_len; + mcp->mb[6] = MSW(MSD(req_dma)); + mcp->mb[7] = LSW(MSD(req_dma)); + mcp->mb[8] = MSW(risc_addr); + mcp->out_mb = MBX_8|MBX_7|MBX_6|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + /* Load second segment - if necessary */ + if (normalized && (rval == QLA_SUCCESS)) { + risc_addr += req_len; + mcp->mb[0] = MBC_LOAD_RISC_RAM_EXTENDED; + mcp->mb[1] = LSW(risc_addr); + mcp->mb[2] = MSW(nml_dma); + mcp->mb[3] = LSW(nml_dma); + mcp->mb[4] = (uint16_t)nml_len; + mcp->mb[6] = MSW(MSD(nml_dma)); + mcp->mb[7] = LSW(MSD(nml_dma)); + mcp->mb[8] = MSW(risc_addr); + mcp->out_mb = MBX_8|MBX_7|MBX_6|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + } + + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x.\n", + __func__, ha->host_no, rval, mcp->mb[0])); + } else { + /*EMPTY*/ + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); + } + + return rval; +} + +/* + * qla2x00_execute_fw + * Start adapter firmware. + * + * Input: + * ha = adapter block pointer. + * TARGET_QUEUE_LOCK must be released. + * ADAPTER_STATE_LOCK must be released. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_execute_fw(scsi_qla_host_t *ha) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("qla2x00_execute_fw(%ld): entered.\n", ha->host_no);) + + mcp->mb[0] = MBC_EXECUTE_FIRMWARE; + mcp->mb[1] = *ha->brd_info->fw_info[0].fwstart; + mcp->out_mb = MBX_1|MBX_0; + if (IS_QLA2322(ha)) { + mcp->mb[2] = 0; + mcp->out_mb |= MBX_2; + } + + mcp->in_mb = MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + DEBUG11(printk("qla2x00_execute_fw(%ld): done.\n", ha->host_no);) + + return rval; +} + +/* + * qla2x00_get_fw_version + * Get firmware version. + * + * Input: + * ha: adapter state pointer. + * major: pointer for major number. + * minor: pointer for minor number. + * subminor: pointer for subminor number. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +void +qla2x00_get_fw_version(scsi_qla_host_t *ha, uint16_t *major, uint16_t *minor, + uint16_t *subminor, uint16_t *attributes) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); + + mcp->mb[0] = MBC_GET_FIRMWARE_VERSION; + mcp->out_mb = MBX_0; + mcp->in_mb = MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->flags = 0; + mcp->tov = 30; + rval = qla2x00_mailbox_command(ha, mcp); + + /* Return mailbox data. */ + *major = mcp->mb[1]; + *minor = mcp->mb[2]; + *subminor = mcp->mb[3]; + *attributes = mcp->mb[6]; + + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__, + ha->host_no, rval)); + } else { + /*EMPTY*/ + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); + } +} + +/* + * qla2x00_get_fw_options + * Set firmware options. + * + * Input: + * ha = adapter block pointer. + * fwopt = pointer for firmware options. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_get_fw_options(scsi_qla_host_t *ha, uint16_t *fwopts) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); + + mcp->mb[0] = MBC_GET_FIRMWARE_OPTION; + mcp->out_mb = MBX_0; + mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__, + ha->host_no, rval)); + } else { + fwopts[1] = mcp->mb[1]; + fwopts[2] = mcp->mb[2]; + fwopts[3] = mcp->mb[3]; + + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); + } + + return rval; +} + + +/* + * qla2x00_set_fw_options + * Set firmware options. + * + * Input: + * ha = adapter block pointer. + * fwopt = pointer for firmware options. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_set_fw_options(scsi_qla_host_t *ha, uint16_t *fwopts) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); + + mcp->mb[0] = MBC_SET_FIRMWARE_OPTION; + mcp->mb[1] = fwopts[1]; + mcp->mb[2] = fwopts[2]; + mcp->mb[3] = fwopts[3]; + mcp->mb[10] = fwopts[10]; + mcp->mb[11] = fwopts[11]; + mcp->mb[12] = 0; /* Undocumented, but used */ + mcp->out_mb = MBX_12|MBX_11|MBX_10|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__, + ha->host_no, rval)); + } else { + /*EMPTY*/ + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); + } + + return rval; +} + +/* + * qla2x00_read_ram_word + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_read_ram_word(scsi_qla_host_t *ha, uint16_t addr, uint16_t *data) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("qla2x00_read_ram_word(%ld): entered.\n", ha->host_no);) + + mcp->mb[0] = MBC_READ_RAM_WORD; + mcp->mb[1] = addr; + mcp->out_mb = MBX_1|MBX_0; + mcp->in_mb = MBX_0|MBX_2; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3_11(printk("qla2x00_read_ram_word(%ld): failed=%x.\n", + ha->host_no, rval);) + } else { + *data = mcp->mb[2]; + DEBUG11(printk("qla2x00_read_ram_word(%ld): done.\n", + ha->host_no);) + } + + return rval; +} + +/* + * qla2x00_write_ram_word + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_write_ram_word(scsi_qla_host_t *ha, uint16_t addr, uint16_t data) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("qla2x00_write_ram_word(%ld): entered.\n", + ha->host_no);) + + mcp->mb[0] = MBC_WRITE_RAM_WORD; + mcp->mb[1] = addr; + mcp->mb[2] = data; + mcp->out_mb = MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3_11(printk("qla2x00_write_ram_word(%ld): failed=%x.\n", + ha->host_no, rval);) + } else { + /*EMPTY*/ + DEBUG11(printk("qla2x00_write_ram_word(%ld): done.\n", + ha->host_no);) + } + + return rval; +} + +/* + * qla2x00_write_ram_word_ext + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_write_ram_word_ext(scsi_qla_host_t *ha, uint32_t addr, uint16_t data) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); + + mcp->mb[0] = MBC_WRITE_RAM_WORD_EXTENDED; + mcp->mb[1] = LSW(addr); + mcp->mb[2] = data; + mcp->mb[8] = MSW(addr); + mcp->out_mb = MBX_8|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__, + ha->host_no, rval)); + } else { + /*EMPTY*/ + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); + } + + return rval; +} + +/* + * qla2x00_mbx_reg_test + * Mailbox register wrap test. + * + * Input: + * ha = adapter block pointer. + * TARGET_QUEUE_LOCK must be released. + * ADAPTER_STATE_LOCK must be released. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_mbx_reg_test(scsi_qla_host_t *ha) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("qla2x00_mbx_reg_test(%ld): entered.\n", ha->host_no);) + + mcp->mb[0] = MBC_MAILBOX_REGISTER_TEST; + mcp->mb[1] = 0xAAAA; + mcp->mb[2] = 0x5555; + mcp->mb[3] = 0xAA55; + mcp->mb[4] = 0x55AA; + mcp->mb[5] = 0xA5A5; + mcp->mb[6] = 0x5A5A; + mcp->mb[7] = 0x2525; + mcp->out_mb = MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval == QLA_SUCCESS) { + if (mcp->mb[1] != 0xAAAA || mcp->mb[2] != 0x5555 || + mcp->mb[3] != 0xAA55 || mcp->mb[4] != 0x55AA) + rval = QLA_FUNCTION_FAILED; + if (mcp->mb[5] != 0xA5A5 || mcp->mb[6] != 0x5A5A || + mcp->mb[7] != 0x2525) + rval = QLA_FUNCTION_FAILED; + } + + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3_11(printk("qla2x00_mbx_reg_test(%ld): failed=%x.\n", + ha->host_no, rval);) + } else { + /*EMPTY*/ + DEBUG11(printk("qla2x00_mbx_reg_test(%ld): done.\n", + ha->host_no);) + } + + return rval; +} + +/* + * qla2x00_verify_checksum + * Verify firmware checksum. + * + * Input: + * ha = adapter block pointer. + * TARGET_QUEUE_LOCK must be released. + * ADAPTER_STATE_LOCK must be released. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_verify_checksum(scsi_qla_host_t *ha) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("qla2x00_verify_checksum(%ld): entered.\n", + ha->host_no);) + + mcp->mb[0] = MBC_VERIFY_CHECKSUM; + mcp->mb[1] = *ha->brd_info->fw_info[0].fwstart; + mcp->out_mb = MBX_1|MBX_0; + mcp->in_mb = MBX_2|MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3_11(printk("qla2x00_verify_checksum(%ld): failed=%x.\n", + ha->host_no, rval);) + } else { + /*EMPTY*/ + DEBUG11(printk("qla2x00_verify_checksum(%ld): done.\n", + ha->host_no);) + } + + return rval; +} + +/* + * qla2x00_issue_iocb + * Issue IOCB using mailbox command + * + * Input: + * ha = adapter state pointer. + * buffer = buffer pointer. + * phys_addr = physical address of buffer. + * size = size of buffer. + * TARGET_QUEUE_LOCK must be released. + * ADAPTER_STATE_LOCK must be released. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_issue_iocb(scsi_qla_host_t *ha, void* buffer, dma_addr_t phys_addr, + size_t size) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + ENTER("qla2x00_issue_iocb: started"); + + mcp->mb[0] = MBC_IOCB_COMMAND_A64; + mcp->mb[1] = 0; + mcp->mb[2] = MSW(phys_addr); + mcp->mb[3] = LSW(phys_addr); + mcp->mb[6] = MSW(MSD(phys_addr)); + mcp->mb[7] = LSW(MSD(phys_addr)); + mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_2|MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG(printk("qla2x00_issue_iocb(%ld): failed rval 0x%x", + ha->host_no,rval);) + DEBUG2(printk("qla2x00_issue_iocb(%ld): failed rval 0x%x", + ha->host_no,rval);) + } else { + /*EMPTY*/ + LEAVE("qla2x00_issue_iocb: exiting normally"); + } + + return rval; +} + +/* + * qla2x00_abort_command + * Abort command aborts a specified IOCB. + * + * Input: + * ha = adapter block pointer. + * sp = SB structure pointer. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_abort_command(scsi_qla_host_t *ha, srb_t *sp) +{ + unsigned long flags = 0; + fc_port_t *fcport; + int rval; + uint32_t handle; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("qla2x00_abort_command(%ld): entered.\n", ha->host_no);) + + fcport = sp->fclun->fcport; + + if (atomic_read(&ha->loop_state) == LOOP_DOWN || + atomic_read(&fcport->state) == FCS_DEVICE_LOST) { + /* v2.19.8 Ignore abort request if port is down */ + return 1; + } + + spin_lock_irqsave(&ha->hardware_lock, flags); + for (handle = 1; handle < MAX_OUTSTANDING_COMMANDS; handle++) { + if (ha->outstanding_cmds[handle] == sp) + break; + } + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + if (handle == MAX_OUTSTANDING_COMMANDS) { + /* command not found */ + return QLA_FUNCTION_FAILED; + } + + mcp->mb[0] = MBC_ABORT_COMMAND; + if (HAS_EXTENDED_IDS(ha)) + mcp->mb[1] = fcport->loop_id; + else + mcp->mb[1] = fcport->loop_id << 8; + mcp->mb[2] = (uint16_t)handle; + mcp->mb[3] = (uint16_t)(handle >> 16); + mcp->mb[6] = (uint16_t)sp->fclun->lun; + mcp->out_mb = MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk("qla2x00_abort_command(%ld): failed=%x.\n", + ha->host_no, rval);) + } else { + sp->flags |= SRB_ABORT_PENDING; + DEBUG11(printk("qla2x00_abort_command(%ld): done.\n", + ha->host_no);) + } + + return rval; +} + +/* + * qla2x00_abort_device + * + * Input: + * ha = adapter block pointer. + * loop_id = FC loop ID + * lun = SCSI LUN. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_abort_device(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("qla2x00_abort_device(%ld): entered.\n", ha->host_no);) + + mcp->mb[0] = MBC_ABORT_DEVICE; + if (HAS_EXTENDED_IDS(ha)) + mcp->mb[1] = loop_id; + else + mcp->mb[1] = loop_id << 8; + mcp->mb[2] = lun; + mcp->out_mb = MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + /* Issue marker command. */ + qla2x00_marker(ha, loop_id, lun, MK_SYNC_ID_LUN); + + if (rval != QLA_SUCCESS) { + set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); + if (ha->dpc_wait && !ha->dpc_active) + up(ha->dpc_wait); + DEBUG2_3_11(printk("qla2x00_abort_device(%ld): failed=%x.\n", + ha->host_no, rval);) + } else { + /*EMPTY*/ + DEBUG11(printk("qla2x00_abort_device(%ld): done.\n", + ha->host_no);) + } + + return rval; +} + +#if USE_ABORT_TGT +/* + * qla2x00_abort_target + * Issue abort target mailbox command. + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_abort_target(fc_port_t *fcport) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("qla2x00_abort_target(%ld): entered.\n", + fcport->ha->host_no);) + + if (fcport == NULL) { + /* no target to abort */ + return 0; + } + + mcp->mb[0] = MBC_ABORT_TARGET; + mcp->out_mb = MBX_2|MBX_1|MBX_0; + if (HAS_EXTENDED_IDS(fcport->ha)) { + mcp->mb[1] = fcport->loop_id; + mcp->mb[10] = 0; + mcp->out_mb |= MBX_10; + } else { + mcp->mb[1] = fcport->loop_id << 8; + } + mcp->mb[2] = fcport->ha->loop_reset_delay; + + mcp->in_mb = MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(fcport->ha, mcp); + + /* Issue marker command. */ + fcport->ha->marker_needed = 1; + + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk("qla2x00_abort_target(%ld): failed=%x.\n", + fcport->ha->host_no, rval);) + } else { + /*EMPTY*/ + DEBUG11(printk("qla2x00_abort_target(%ld): done.\n", + fcport->ha->host_no);) + } + + return rval; +} +#endif + +/* + * qla2x00_target_reset + * Issue target reset mailbox command. + * + * Input: + * ha = adapter block pointer. + * TARGET_QUEUE_LOCK must be released. + * ADAPTER_STATE_LOCK must be released. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_target_reset(scsi_qla_host_t *ha, uint16_t b, uint16_t t) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + os_tgt_t *tgt; + + DEBUG11(printk("qla2x00_target_reset(%ld): entered.\n", ha->host_no);) + + tgt = TGT_Q(ha, t); + if (tgt->fcport == NULL) { + /* no target to abort */ + return 0; + } + if (atomic_read(&tgt->fcport->state) != FCS_ONLINE) { + /* target not online */ + return 0; + } + + mcp->mb[0] = MBC_TARGET_RESET; + if (HAS_EXTENDED_IDS(ha)) + mcp->mb[1] = tgt->fcport->loop_id; + else + mcp->mb[1] = tgt->fcport->loop_id << 8; + mcp->mb[2] = ha->loop_reset_delay; + mcp->out_mb = MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3_11(printk("qla2x00_target_reset(%ld): failed=%x.\n", + ha->host_no, rval);) + } else { + /*EMPTY*/ + DEBUG11(printk("qla2x00_target_reset(%ld): done.\n", + ha->host_no);) + } + + return rval; +} + +/* + * qla2x00_get_adapter_id + * Get adapter ID and topology. + * + * Input: + * ha = adapter block pointer. + * id = pointer for loop ID. + * al_pa = pointer for AL_PA. + * area = pointer for area. + * domain = pointer for domain. + * top = pointer for topology. + * TARGET_QUEUE_LOCK must be released. + * ADAPTER_STATE_LOCK must be released. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa, + uint8_t *area, uint8_t *domain, uint16_t *top) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("qla2x00_get_adapter_id(%ld): entered.\n", + ha->host_no);) + + mcp->mb[0] = MBC_GET_ADAPTER_LOOP_ID; + mcp->out_mb = MBX_0; + mcp->in_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + /* Return data. */ + *id = mcp->mb[1]; + *al_pa = LSB(mcp->mb[2]); + *area = MSB(mcp->mb[2]); + *domain = LSB(mcp->mb[3]); + *top = mcp->mb[6]; + + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3_11(printk("qla2x00_get_adapter_id(%ld): failed=%x.\n", + ha->host_no, rval);) + } else { + /*EMPTY*/ + DEBUG11(printk("qla2x00_get_adapter_id(%ld): done.\n", + ha->host_no);) + } + + return rval; +} + +/* + * qla2x00_get_retry_cnt + * Get current firmware login retry count and delay. + * + * Input: + * ha = adapter block pointer. + * retry_cnt = pointer to login retry count. + * tov = pointer to login timeout value. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_get_retry_cnt(scsi_qla_host_t *ha, uint8_t *retry_cnt, uint8_t *tov, + uint16_t *r_a_tov) +{ + int rval; + uint16_t ratov; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("qla2x00_get_retry_cnt(%ld): entered.\n", + ha->host_no);) + + mcp->mb[0] = MBC_GET_RETRY_COUNT; + mcp->out_mb = MBX_0; + mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3_11(printk("qla2x00_get_retry_cnt(%ld): failed = %x.\n", + ha->host_no, mcp->mb[0]);) + } else { + /* Convert returned data and check our values. */ + *r_a_tov = mcp->mb[3] / 2; + ratov = (mcp->mb[3]/2) / 10; /* mb[3] value is in 100ms */ + if (mcp->mb[1] * ratov > (*retry_cnt) * (*tov)) { + /* Update to the larger values */ + *retry_cnt = (uint8_t)mcp->mb[1]; + *tov = ratov; + } + + DEBUG11(printk("qla2x00_get_retry_cnt(%ld): done. mb3=%d " + "ratov=%d.\n", ha->host_no, mcp->mb[3], ratov);) + } + + return rval; +} + +/* + * qla2x00_loopback_test + * Send out a LOOPBACK mailbox command. + * + * Input: + * ha = adapter block pointer. + * retry_cnt = pointer to login retry count. + * tov = pointer to login timeout value. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_loopback_test(scsi_qla_host_t *ha, INT_LOOPBACK_REQ *req, + uint16_t *ret_mb) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("qla2x00_send_loopback: req.Options=%x iterations=%x " + "MAILBOX_CNT=%d.\n", req->Options, req->IterationCount, + MAILBOX_REGISTER_COUNT);) + + memset(mcp->mb, 0 , sizeof(mcp->mb)); + + mcp->mb[0] = MBC_DIAGNOSTIC_LOOP_BACK; + mcp->mb[1] = req->Options | MBX_6; + mcp->mb[10] = LSW(req->TransferCount); + mcp->mb[11] = MSW(req->TransferCount); + mcp->mb[14] = LSW(ha->ioctl_mem_phys); /* send data address */ + mcp->mb[15] = MSW(ha->ioctl_mem_phys); + mcp->mb[20] = LSW(MSD(ha->ioctl_mem_phys)); + mcp->mb[21] = MSW(MSD(ha->ioctl_mem_phys)); + mcp->mb[16] = LSW(ha->ioctl_mem_phys); /* rcv data address */ + mcp->mb[17] = MSW(ha->ioctl_mem_phys); + mcp->mb[6] = LSW(MSD(ha->ioctl_mem_phys)); + mcp->mb[7] = MSW(MSD(ha->ioctl_mem_phys)); + mcp->mb[18] = LSW(req->IterationCount); /* iteration count lsb */ + mcp->mb[19] = MSW(req->IterationCount); /* iteration count msb */ + mcp->out_mb = MBX_21|MBX_20|MBX_19|MBX_18|MBX_17|MBX_16|MBX_15| + MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_7|MBX_6|MBX_1|MBX_0; + mcp->in_mb = MBX_19|MBX_18|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->buf_size = req->TransferCount; + mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD; + mcp->tov = 30; + rval = qla2x00_mailbox_command(ha, mcp); + + /* Always copy back return mailbox values. */ + memcpy((void *)ret_mb, (void *)mcp->mb, sizeof(mcp->mb)); + + if (rval != QLA_SUCCESS) { + /* Empty. */ + DEBUG2_3_11(printk( + "qla2x00_loopback_test(%ld): mailbox command FAILED=%x.\n", + ha->host_no, mcp->mb[0]);) + } else { + /* Empty. */ + DEBUG11(printk( + "qla2x00_loopback_test(%ld): done.\n", ha->host_no);) + } + + return rval; +} + +/* + * qla2x00_echo_test + * Send out a DIAGNOSTIC ECHO mailbox command. + * + * Input: + * ha = adapter block pointer. + * retry_cnt = pointer to login retry count. + * tov = pointer to login timeout value. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_echo_test(scsi_qla_host_t *ha, INT_LOOPBACK_REQ *req, uint16_t *ret_mb) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + memset(mcp->mb, 0 , sizeof(mcp->mb)); + + mcp->mb[0] = MBC_DIAGNOSTIC_ECHO; + mcp->mb[1] = BIT_6; /* use 64bit DMA addr */ + mcp->mb[10] = req->TransferCount; + mcp->mb[14] = LSW(ha->ioctl_mem_phys); /* send data address */ + mcp->mb[15] = MSW(ha->ioctl_mem_phys); + mcp->mb[20] = LSW(MSD(ha->ioctl_mem_phys)); + mcp->mb[21] = MSW(MSD(ha->ioctl_mem_phys)); + mcp->mb[16] = LSW(ha->ioctl_mem_phys); /* rcv data address */ + mcp->mb[17] = MSW(ha->ioctl_mem_phys); + mcp->mb[6] = LSW(MSD(ha->ioctl_mem_phys)); + mcp->mb[7] = MSW(MSD(ha->ioctl_mem_phys)); + mcp->out_mb = MBX_21|MBX_20|MBX_17|MBX_16|MBX_15|MBX_14|MBX_10| + MBX_7|MBX_6|MBX_1|MBX_0; + mcp->in_mb = MBX_0; + mcp->buf_size = req->TransferCount; + mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD; + mcp->tov = 30; + rval = qla2x00_mailbox_command(ha, mcp); + + /* Always copy back return mailbox values. */ + memcpy((void *)ret_mb, (void *)mcp->mb, sizeof(mcp->mb)); + + if (rval != QLA_SUCCESS) { + /* Empty. */ + DEBUG2_3_11(printk( + "%s(%ld): mailbox command FAILED=%x.\n", __func__, + ha->host_no, mcp->mb[0]);) + } else { + /* Empty. */ + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);) + } + + return rval; +} + +/* + * qla2x00_init_firmware + * Initialize adapter firmware. + * + * Input: + * ha = adapter block pointer. + * dptr = Initialization control block pointer. + * size = size of initialization control block. + * TARGET_QUEUE_LOCK must be released. + * ADAPTER_STATE_LOCK must be released. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_init_firmware(scsi_qla_host_t *ha, uint16_t size) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("qla2x00_init_firmware(%ld): entered.\n", + ha->host_no);) + + mcp->mb[0] = MBC_INITIALIZE_FIRMWARE; + mcp->mb[2] = MSW(ha->init_cb_dma); + mcp->mb[3] = LSW(ha->init_cb_dma); + mcp->mb[4] = 0; + mcp->mb[5] = 0; + mcp->mb[6] = MSW(MSD(ha->init_cb_dma)); + mcp->mb[7] = LSW(MSD(ha->init_cb_dma)); + mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0; + mcp->in_mb = MBX_5|MBX_4|MBX_0; + mcp->buf_size = size; + mcp->flags = MBX_DMA_OUT; + mcp->tov = 30; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3_11(printk("qla2x00_init_firmware(%ld): failed=%x " + "mb0=%x.\n", + ha->host_no, rval, mcp->mb[0]);) + } else { + /*EMPTY*/ + DEBUG11(printk("qla2x00_init_firmware(%ld): done.\n", + ha->host_no);) + } + + return rval; +} + +/* + * qla2x00_get_port_database + * Issue normal/enhanced get port database mailbox command + * and copy device name as necessary. + * + * Input: + * ha = adapter state pointer. + * dev = structure pointer. + * opt = enhanced cmd option byte. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_get_port_database(scsi_qla_host_t *ha, fc_port_t *fcport, uint8_t opt) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + port_database_t *pd; + dma_addr_t pd_dma; + + DEBUG11(printk("qla2x00_get_port_database(%ld): entered.\n", + ha->host_no);) + + pd = pci_alloc_consistent(ha->pdev, PORT_DATABASE_SIZE, &pd_dma); + if (pd == NULL) { + DEBUG2_3_11(printk("qla2x00_get_port_database(%ld): **** " + "Mem Alloc Failed ****", ha->host_no);) + return QLA_MEMORY_ALLOC_FAILED; + } + memset(pd, 0, PORT_DATABASE_SIZE); + + if (opt != 0) + mcp->mb[0] = MBC_ENHANCED_GET_PORT_DATABASE; + else + mcp->mb[0] = MBC_GET_PORT_DATABASE; + mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + if (HAS_EXTENDED_IDS(ha)) { + mcp->mb[1] = fcport->loop_id; + mcp->mb[10] = opt; + mcp->out_mb |= MBX_10; + } else { + mcp->mb[1] = fcport->loop_id << 8 | opt; + } + mcp->mb[2] = MSW(pd_dma); + mcp->mb[3] = LSW(pd_dma); + mcp->mb[6] = MSW(MSD(pd_dma)); + mcp->mb[7] = LSW(MSD(pd_dma)); + + mcp->in_mb = MBX_0; + mcp->buf_size = PORT_DATABASE_SIZE; + mcp->flags = MBX_DMA_IN; + mcp->tov = ha->login_timeout * 2; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval == QLA_SUCCESS) { + /* Names are little-endian. */ + memcpy(fcport->node_name, pd->node_name, WWN_SIZE); + memcpy(fcport->port_name, pd->port_name, WWN_SIZE); + + /* Get port_id of device. */ + fcport->d_id.b.al_pa = pd->port_id[2]; + fcport->d_id.b.area = pd->port_id[3]; + fcport->d_id.b.domain = pd->port_id[0]; + fcport->d_id.b.rsvd_1 = 0; + + /* Check for device require authentication. */ + pd->common_features & BIT_5 ? (fcport->flags |= FCF_AUTH_REQ) : + (fcport->flags &= ~FCF_AUTH_REQ); + + /* If not target must be initiator or unknown type. */ + if ((pd->prli_svc_param_word_3[0] & BIT_4) == 0) { + fcport->port_type = FCT_INITIATOR; + } else { + fcport->port_type = FCT_TARGET; + + /* Check for logged in. */ + if (pd->master_state != PD_STATE_PORT_LOGGED_IN && + pd->slave_state != PD_STATE_PORT_LOGGED_IN) + rval = QLA_FUNCTION_FAILED; + } + } + + pci_free_consistent(ha->pdev, PORT_DATABASE_SIZE, pd, pd_dma); + + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3_11(printk("qla2x00_get_port_database(%ld): " + "failed=%x.\n", ha->host_no, rval);) + } else { + /*EMPTY*/ + DEBUG11(printk("qla2x00_get_port_database(%ld): done.\n", + ha->host_no);) + } + + return rval; +} + +/* + * qla2x00_get_firmware_state + * Get adapter firmware state. + * + * Input: + * ha = adapter block pointer. + * dptr = pointer for firmware state. + * TARGET_QUEUE_LOCK must be released. + * ADAPTER_STATE_LOCK must be released. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_get_firmware_state(scsi_qla_host_t *ha, uint16_t *dptr) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("qla2x00_get_firmware_state(%ld): entered.\n", + ha->host_no);) + + mcp->mb[0] = MBC_GET_FIRMWARE_STATE; + mcp->out_mb = MBX_0; + mcp->in_mb = MBX_2|MBX_1|MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + /* Return firmware state. */ + *dptr = mcp->mb[1]; + + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3_11(printk("qla2x00_get_firmware_state(%ld): " + "failed=%x.\n", ha->host_no, rval);) + } else { + /*EMPTY*/ + DEBUG11(printk("qla2x00_get_firmware_state(%ld): done.\n", + ha->host_no);) + } + + return rval; +} + +/* + * qla2x00_get_port_name + * Issue get port name mailbox command. + * Returned name is in big endian format. + * + * Input: + * ha = adapter block pointer. + * loop_id = loop ID of device. + * name = pointer for name. + * TARGET_QUEUE_LOCK must be released. + * ADAPTER_STATE_LOCK must be released. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_get_port_name(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t *name, + uint8_t opt) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("qla2x00_get_port_name(%ld): entered.\n", + ha->host_no);) + + mcp->mb[0] = MBC_GET_PORT_NAME; + mcp->out_mb = MBX_1|MBX_0; + if (HAS_EXTENDED_IDS(ha)) { + mcp->mb[1] = loop_id; + mcp->mb[10] = opt; + mcp->out_mb |= MBX_10; + } else { + mcp->mb[1] = loop_id << 8 | opt; + } + + mcp->in_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3_11(printk("qla2x00_get_port_name(%ld): failed=%x.\n", + ha->host_no, rval);) + } else { + if (name != NULL) { + /* This function returns name in big endian. */ + name[0] = LSB(mcp->mb[2]); + name[1] = MSB(mcp->mb[2]); + name[2] = LSB(mcp->mb[3]); + name[3] = MSB(mcp->mb[3]); + name[4] = LSB(mcp->mb[6]); + name[5] = MSB(mcp->mb[6]); + name[6] = LSB(mcp->mb[7]); + name[7] = MSB(mcp->mb[7]); + } + + DEBUG11(printk("qla2x00_get_port_name(%ld): done.\n", + ha->host_no);) + } + + return rval; +} + +/* + * qla2x00_get_link_status + * + * Input: + * ha = adapter block pointer. + * loop_id = device loop ID. + * ret_buf = pointer to link status return buffer. + * + * Returns: + * 0 = success. + * BIT_0 = mem alloc error. + * BIT_1 = mailbox error. + */ +uint8_t +qla2x00_get_link_status(scsi_qla_host_t *ha, uint8_t loop_id, void *ret_buf, + uint16_t *status) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + link_stat_t *stat_buf; + dma_addr_t phys_address = 0; + + + DEBUG11(printk("qla2x00_get_link_status(%ld): entered.\n", + ha->host_no);) + + stat_buf = pci_alloc_consistent(ha->pdev, sizeof(link_stat_t), + &phys_address); + if (stat_buf == NULL) { + DEBUG2_3_11(printk("qla2x00_get_link_status(%ld): Failed to " + "allocate memory.\n", ha->host_no)); + return BIT_0; + } + memset(stat_buf, 0, sizeof(link_stat_t)); + + mcp->mb[0] = MBC_GET_LINK_STATUS; + mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + if (HAS_EXTENDED_IDS(ha)) { + mcp->mb[1] = loop_id; + mcp->mb[10] = 0; + mcp->out_mb |= MBX_10; + } else { + mcp->mb[1] = loop_id << 8; + } + mcp->mb[2] = MSW(phys_address); + mcp->mb[3] = LSW(phys_address); + mcp->mb[6] = MSW(MSD(phys_address)); + mcp->mb[7] = LSW(MSD(phys_address)); + + mcp->in_mb = MBX_0; + mcp->tov = 30; + mcp->flags = IOCTL_CMD; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval == QLA_SUCCESS) { + if (mcp->mb[0] != MBS_COMMAND_COMPLETE) { + DEBUG2_3_11(printk("qla2x00_get_link_status(%ld): cmd " + "failed. mbx0=%x.\n", ha->host_no, mcp->mb[0]);) + status[0] = mcp->mb[0]; + rval = BIT_1; + } else { + /* copy over data */ + memcpy(ret_buf, stat_buf,sizeof(link_stat_t)); + DEBUG(printk("qla2x00_get_link_status(%ld): stat dump: " + "fail_cnt=%d loss_sync=%d loss_sig=%d seq_err=%d " + "inval_xmt_word=%d inval_crc=%d.\n", + ha->host_no, + stat_buf->link_fail_cnt, stat_buf->loss_sync_cnt, + stat_buf->loss_sig_cnt, stat_buf->prim_seq_err_cnt, + stat_buf->inval_xmit_word_cnt, + stat_buf->inval_crc_cnt);) + DEBUG11(printk("qla2x00_get_link_status(%ld): stat " + "dump: fail_cnt=%d loss_sync=%d loss_sig=%d " + "seq_err=%d inval_xmt_word=%d inval_crc=%d.\n", + ha->host_no, + stat_buf->link_fail_cnt, stat_buf->loss_sync_cnt, + stat_buf->loss_sig_cnt, stat_buf->prim_seq_err_cnt, + stat_buf->inval_xmit_word_cnt, + stat_buf->inval_crc_cnt);) + } + } else { + /* Failed. */ + DEBUG2_3_11(printk("qla2x00_get_link_status(%ld): failed=%x.\n", + ha->host_no, rval);) + rval = BIT_1; + } + + pci_free_consistent(ha->pdev, sizeof(link_stat_t), + stat_buf, phys_address); + + return rval; +} + +/* + * qla2x00_lip_reset + * Issue LIP reset mailbox command. + * + * Input: + * ha = adapter block pointer. + * TARGET_QUEUE_LOCK must be released. + * ADAPTER_STATE_LOCK must be released. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_lip_reset(scsi_qla_host_t *ha) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("qla2x00_lip_reset(%ld): entered.\n", + ha->host_no);) + + mcp->mb[0] = MBC_LIP_RESET; + mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0; + if (HAS_EXTENDED_IDS(ha)) { + mcp->mb[1] = 0x00ff; + mcp->mb[10] = 0; + mcp->out_mb |= MBX_10; + } else { + mcp->mb[1] = 0xff00; + } + mcp->mb[2] = ha->loop_reset_delay; + mcp->mb[3] = 0; + + mcp->in_mb = MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3_11(printk("qla2x00_lip_reset(%ld): failed=%x.\n", + ha->host_no, rval);) + } else { + /*EMPTY*/ + DEBUG11(printk("qla2x00_lip_reset(%ld): done.\n", ha->host_no);) + } + + return rval; +} + +/* + * qla2x00_send_sns + * Send SNS command. + * + * Input: + * ha = adapter block pointer. + * sns = pointer for command. + * cmd_size = command size. + * buf_size = response/command size. + * TARGET_QUEUE_LOCK must be released. + * ADAPTER_STATE_LOCK must be released. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_send_sns(scsi_qla_host_t *ha, dma_addr_t sns_phys_address, + uint16_t cmd_size, size_t buf_size) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("qla2x00_send_sns(%ld): entered.\n", + ha->host_no);) + + DEBUG11(printk("qla2x00_send_sns: retry cnt=%d ratov=%d total " + "tov=%d.\n", ha->retry_count, ha->login_timeout, mcp->tov);) + + mcp->mb[0] = MBC_SEND_SNS_COMMAND; + mcp->mb[1] = cmd_size; + mcp->mb[2] = MSW(sns_phys_address); + mcp->mb[3] = LSW(sns_phys_address); + mcp->mb[6] = MSW(MSD(sns_phys_address)); + mcp->mb[7] = LSW(MSD(sns_phys_address)); + mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_0|MBX_1; + mcp->buf_size = buf_size; + mcp->flags = MBX_DMA_OUT|MBX_DMA_IN; + /*mcp->tov = ha->retry_count * ha->login_timeout * 2;*/ + mcp->tov = ha->login_timeout * 2; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG(printk("qla2x00_send_sns(%ld): failed=%x mb[0]=%x " + "mb[1]=%x.\n", ha->host_no, rval, mcp->mb[0], mcp->mb[1]);) + DEBUG2_3_11(printk("qla2x00_send_sns(%ld): failed=%x mb[0]=%x " + "mb[1]=%x.\n", ha->host_no, rval, mcp->mb[0], mcp->mb[1]);) + } else { + /*EMPTY*/ + DEBUG11(printk("qla2x00_send_sns(%ld): done.\n", ha->host_no);) + } + + return rval; +} + +/* + * qla2x00_login_fabric + * Issue login fabric port mailbox command. + * + * Input: + * ha = adapter block pointer. + * loop_id = device loop ID. + * domain = device domain. + * area = device area. + * al_pa = device AL_PA. + * status = pointer for return status. + * opt = command options. + * TARGET_QUEUE_LOCK must be released. + * ADAPTER_STATE_LOCK must be released. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, + uint8_t area, uint8_t al_pa, uint16_t *mb, uint8_t opt) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("qla2x00_login_fabric(%ld): entered.\n", ha->host_no);) + + mcp->mb[0] = MBC_LOGIN_FABRIC_PORT; + mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0; + if (HAS_EXTENDED_IDS(ha)) { + mcp->mb[1] = loop_id; + mcp->mb[10] = opt; + mcp->out_mb |= MBX_10; + } else { + mcp->mb[1] = (loop_id << 8) | opt; + } + mcp->mb[2] = domain; + mcp->mb[3] = area << 8 | al_pa; + + mcp->in_mb = MBX_7|MBX_6|MBX_2|MBX_1|MBX_0; + /*mcp->tov = ha->retry_count * ha->login_timeout * 2;*/ + mcp->tov = ha->login_timeout * 2; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + /* Return mailbox statuses. */ + if (mb != NULL) { + mb[0] = mcp->mb[0]; + mb[1] = mcp->mb[1]; + mb[2] = mcp->mb[2]; + mb[6] = mcp->mb[6]; + mb[7] = mcp->mb[7]; + } + + if (rval != QLA_SUCCESS) { + /* RLU tmp code: need to change main mailbox_command function to + * return ok even when the mailbox completion value is not + * SUCCESS. The caller needs to be responsible to interpret + * the return values of this mailbox command if we're not + * to change too much of the existing code. + */ + if (mcp->mb[0] == 0x4001 || mcp->mb[0] == 0x4002 || + mcp->mb[0] == 0x4003 || mcp->mb[0] == 0x4005 || + mcp->mb[0] == 0x4006) + rval = QLA_SUCCESS; + + /*EMPTY*/ + DEBUG2_3_11(printk("qla2x00_login_fabric(%ld): failed=%x " + "mb[0]=%x mb[1]=%x mb[2]=%x.\n", ha->host_no, rval, + mcp->mb[0], mcp->mb[1], mcp->mb[2]);) + } else { + /*EMPTY*/ + DEBUG11(printk("qla2x00_login_fabric(%ld): done.\n", + ha->host_no);) + } + + return rval; +} + +/* + * qla2x00_login_local_device + * Issue login loop port mailbox command. + * + * Input: + * ha = adapter block pointer. + * loop_id = device loop ID. + * opt = command options. + * + * Returns: + * Return status code. + * + * Context: + * Kernel context. + * + */ +int +qla2x00_login_local_device(scsi_qla_host_t *ha, uint16_t loop_id, + uint16_t *mb_ret, uint8_t opt) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG3(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + + mcp->mb[0] = MBC_LOGIN_LOOP_PORT; + if (HAS_EXTENDED_IDS(ha)) + mcp->mb[1] = loop_id; + else + mcp->mb[1] = loop_id << 8; + mcp->mb[2] = opt; + mcp->out_mb = MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_7|MBX_6|MBX_1|MBX_0; + mcp->tov = ha->login_timeout * 2; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + /* Return mailbox statuses. */ + if (mb_ret != NULL) { + mb_ret[0] = mcp->mb[0]; + mb_ret[1] = mcp->mb[1]; + mb_ret[6] = mcp->mb[6]; + mb_ret[7] = mcp->mb[7]; + } + + if (rval != QLA_SUCCESS) { + /* AV tmp code: need to change main mailbox_command function to + * return ok even when the mailbox completion value is not + * SUCCESS. The caller needs to be responsible to interpret + * the return values of this mailbox command if we're not + * to change too much of the existing code. + */ + if (mcp->mb[0] == 0x4005 || mcp->mb[0] == 0x4006) + rval = QLA_SUCCESS; + + DEBUG(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x " + "mb[6]=%x mb[7]=%x.\n", __func__, ha->host_no, rval, + mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7]);) + DEBUG2_3(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x " + "mb[6]=%x mb[7]=%x.\n", __func__, ha->host_no, rval, + mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7]);) + } else { + /*EMPTY*/ + DEBUG3(printk("%s(%ld): done.\n", __func__, ha->host_no);) + } + + return (rval); +} + +/* + * qla2x00_fabric_logout + * Issue logout fabric port mailbox command. + * + * Input: + * ha = adapter block pointer. + * loop_id = device loop ID. + * TARGET_QUEUE_LOCK must be released. + * ADAPTER_STATE_LOCK must be released. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("qla2x00_fabric_logout(%ld): entered.\n", + ha->host_no);) + + mcp->mb[0] = MBC_LOGOUT_FABRIC_PORT; + mcp->out_mb = MBX_1|MBX_0; + if (HAS_EXTENDED_IDS(ha)) { + mcp->mb[1] = loop_id; + mcp->mb[10] = 0; + mcp->out_mb |= MBX_10; + } else { + mcp->mb[1] = loop_id << 8; + } + + mcp->in_mb = MBX_1|MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3_11(printk("qla2x00_fabric_logout(%ld): failed=%x " + "mbx1=%x.\n", ha->host_no, rval, mcp->mb[1]);) + } else { + /*EMPTY*/ + DEBUG11(printk("qla2x00_fabric_logout(%ld): done.\n", + ha->host_no);) + } + + return rval; +} + +/* + * qla2x00_full_login_lip + * Issue full login LIP mailbox command. + * + * Input: + * ha = adapter block pointer. + * TARGET_QUEUE_LOCK must be released. + * ADAPTER_STATE_LOCK must be released. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_full_login_lip(scsi_qla_host_t *ha) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("qla2x00_full_login_lip(%ld): entered.\n", + ha->host_no);) + + mcp->mb[0] = MBC_LIP_FULL_LOGIN; + mcp->mb[1] = 0; + mcp->mb[2] = 0; + mcp->mb[3] = 0; + mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3_11(printk("qla2x00_full_login_lip(%ld): failed=%x.\n", + ha->instance, rval);) + } else { + /*EMPTY*/ + DEBUG11(printk("qla2x00_full_login_lip(%ld): done.\n", + ha->host_no);) + } + + return rval; +} + +/* + * qla2x00_get_id_list + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_get_id_list(scsi_qla_host_t *ha, void *id_list, dma_addr_t id_list_dma, + uint16_t *entries) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("qla2x00_get_id_list(%ld): entered.\n", + ha->host_no);) + + if (id_list == NULL) + return QLA_FUNCTION_FAILED; + + mcp->mb[0] = MBC_GET_ID_LIST; + mcp->mb[1] = MSW(id_list_dma); + mcp->mb[2] = LSW(id_list_dma); + mcp->mb[3] = MSW(MSD(id_list_dma)); + mcp->mb[6] = LSW(MSD(id_list_dma)); + mcp->out_mb = MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_1|MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3_11(printk("qla2x00_get_id_list(%ld): failed=%x.\n", + ha->host_no, rval);) + } else { + *entries = mcp->mb[1]; + DEBUG11(printk("qla2x00_get_id_list(%ld): done.\n", + ha->host_no);) + } + + return rval; +} + +#if 0 /* not yet needed */ +int +qla2x00_dump_ram(scsi_qla_host_t *ha, uint32_t risc_address, + dma_addr_t ispdump_dma, uint32_t size) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + mcp->mb[0] = MBC_DUMP_RAM; + mcp->mb[1] = risc_address & 0xffff; + mcp->mb[2] = MSW(ispdump_dma); + mcp->mb[3] = LSW(ispdump_dma); + mcp->mb[4] = 0; + mcp->mb[6] = MSW(MSD(ispdump_dma)); + mcp->mb[7] = LSW(MSD(ispdump_dma)); + mcp->out_mb = MBX_7|MBX_6|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + return rval; +} +#endif + +/* + * qla2x00_lun_reset + * Issue lun reset mailbox command. + * + * Input: + * ha = adapter block pointer. + * loop_id = device loop ID. + * lun = lun to be reset. + * TARGET_QUEUE_LOCK must be released. + * ADAPTER_STATE_LOCK must be released. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_lun_reset(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + ENTER("qla2x00_lun_reset"); + + mcp->mb[0] = MBC_LUN_RESET; + if (HAS_EXTENDED_IDS(ha)) + mcp->mb[1] = loop_id; + else + mcp->mb[1] = loop_id << 8; + mcp->mb[2] = lun; + mcp->out_mb = MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + printk(KERN_WARNING "qla2x00_lun_reset(%d): failed = %d", + (int)ha->instance, rval); + } else { + /*EMPTY*/ + LEAVE("qla2x00_lun_reset: exiting normally"); + } + + return rval; +} + +/* + * qla2x00_send_rnid_mbx + * Issue RNID ELS using mailbox command + * + * Input: + * ha = adapter state pointer. + * loop_id = loop ID of the target device. + * data_fmt = currently supports only 0xDF. + * buffer = buffer pointer. + * buf_size = size of buffer. + * mb_reg = pointer to return mailbox registers. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_send_rnid_mbx(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t data_fmt, + dma_addr_t buf_phys_addr, size_t buf_size, uint16_t *mb_reg) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("qla2x00_send_rnid_mbx(%ld): entered.\n", + ha->host_no);) + + mcp->mb[0] = MBC_SEND_RNID_ELS; + mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + if (HAS_EXTENDED_IDS(ha)) { + mcp->mb[1] = loop_id; + mcp->mb[10] = data_fmt; + mcp->out_mb |= MBX_10; + } else { + mcp->mb[1] = (loop_id << 8) | data_fmt; + } + mcp->mb[2] = MSW(buf_phys_addr); + mcp->mb[3] = LSW(buf_phys_addr); + mcp->mb[6] = MSW(MSD(buf_phys_addr)); + mcp->mb[7] = LSW(MSD(buf_phys_addr)); + + mcp->in_mb = MBX_1|MBX_0; + mcp->buf_size = buf_size; + mcp->flags = MBX_DMA_IN; + mcp->tov = 30; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + memcpy(mb_reg, mcp->mb, 2 * 2); /* 2 status regs */ + + DEBUG2_3_11(printk("qla2x00_send_rnid_mbx(%ld): failed=%x " + "mb[1]=%x.\n", + ha->host_no, mcp->mb[0], mcp->mb[1]);) + } else { + /*EMPTY*/ + DEBUG11(printk("qla2x00_send_rnid_mbx(%ld): done.\n", + ha->host_no);) + } + + return (rval); +} + +/* + * qla2x00_set_rnid_params_mbx + * Set RNID parameters using mailbox command + * + * Input: + * ha = adapter state pointer. + * buffer = buffer pointer. + * buf_size = size of buffer. + * mb_reg = pointer to return mailbox registers. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_set_rnid_params_mbx(scsi_qla_host_t *ha, dma_addr_t buf_phys_addr, + size_t buf_size, uint16_t *mb_reg) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("qla2x00_set_rnid_params_mbx(%ld): entered.\n", + ha->host_no);) + + mcp->mb[0] = MBC_SET_RNID_PARAMS; + mcp->mb[1] = 0; + mcp->mb[2] = MSW(buf_phys_addr); + mcp->mb[3] = LSW(buf_phys_addr); + mcp->mb[6] = MSW(MSD(buf_phys_addr)); + mcp->mb[7] = LSW(MSD(buf_phys_addr)); + mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_1|MBX_0; + mcp->buf_size = buf_size; + mcp->flags = MBX_DMA_OUT; + mcp->tov = 30; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + memcpy(mb_reg, mcp->mb, 2 * 2); /* 2 status regs */ + + DEBUG2_3_11(printk("qla2x00_set_rnid_params_mbx(%ld): " + "failed=%x mb[1]=%x.\n", ha->host_no, mcp->mb[0], + mcp->mb[1]);) + } else { + /*EMPTY*/ + DEBUG11(printk("qla2x00_set_rnid_params_mbx(%ld): done.\n", + ha->host_no);) + } + + return (rval); +} + +/* + * qla2x00_get_rnid_params_mbx + * Get RNID parameters using mailbox command + * + * Input: + * ha = adapter state pointer. + * buffer = buffer pointer. + * buf_size = size of buffer. + * mb_reg = pointer to return mailbox registers. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_get_rnid_params_mbx(scsi_qla_host_t *ha, dma_addr_t buf_phys_addr, + size_t buf_size, uint16_t *mb_reg) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("qla2x00_get_rnid_params_mbx(%ld): entered.\n", + ha->host_no);) + + mcp->mb[0] = MBC_GET_RNID_PARAMS; + mcp->mb[1] = 0; + mcp->mb[2] = MSW(buf_phys_addr); + mcp->mb[3] = LSW(buf_phys_addr); + mcp->mb[6] = MSW(MSD(buf_phys_addr)); + mcp->mb[7] = LSW(MSD(buf_phys_addr)); + mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_1|MBX_0; + mcp->buf_size = buf_size; + mcp->flags = MBX_DMA_IN; + mcp->tov = 30; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + memcpy(mb_reg, mcp->mb, 2 * 2); /* 2 status regs */ + + DEBUG2_3_11(printk("qla2x00_get_rnid_params_mbx(%ld): " + "failed=%x mb[1]=%x.\n", ha->host_no, mcp->mb[0], + mcp->mb[1]);) + } else { + /*EMPTY*/ + DEBUG11(printk("qla2x00_get_rnid_params_mbx(%ld): done.\n", + ha->host_no);) + } + + return (rval); +} + +/* + * qla2x00_get_resource_cnts + * Get current firmware resource counts. + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_get_resource_cnts(scsi_qla_host_t *ha, uint16_t *cur_xchg_cnt, + uint16_t *orig_xchg_cnt, uint16_t *cur_iocb_cnt, uint16_t *orig_iocb_cnt) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); + + mcp->mb[0] = MBC_GET_RESOURCE_COUNTS; + mcp->out_mb = MBX_0; + mcp->in_mb = MBX_10|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3_11(printk("%s(%ld): failed = %x.\n", __func__, + ha->host_no, mcp->mb[0]);) + } else { + DEBUG11(printk("%s(%ld): done. mb1=%x mb2=%x mb3=%x mb6=%x " + "mb7=%x mb10=%x.\n", __func__, ha->host_no, + mcp->mb[1], mcp->mb[2], mcp->mb[3], mcp->mb[6], mcp->mb[7], + mcp->mb[10])); + + if (cur_xchg_cnt) + *cur_xchg_cnt = mcp->mb[3]; + if (orig_xchg_cnt) + *orig_xchg_cnt = mcp->mb[6]; + if (cur_iocb_cnt) + *cur_iocb_cnt = mcp->mb[7]; + if (orig_iocb_cnt) + *orig_iocb_cnt = mcp->mb[10]; + } + + return (rval); +} + +#if defined(QL_DEBUG_LEVEL_3) +/* + * qla2x00_get_fcal_position_map + * Get FCAL (LILP) position map using mailbox command + * + * Input: + * ha = adapter state pointer. + * pos_map = buffer pointer (can be NULL). + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + char *pmap; + dma_addr_t pmap_dma; + + pmap = pci_alloc_consistent(ha->pdev, FCAL_MAP_SIZE, &pmap_dma); + if (pmap == NULL) { + DEBUG2_3_11(printk("%s(%ld): **** Mem Alloc Failed ****", + __func__, ha->host_no)); + return QLA_MEMORY_ALLOC_FAILED; + } + memset(pmap, 0, FCAL_MAP_SIZE); + + mcp->mb[0] = MBC_GET_FC_AL_POSITION_MAP; + mcp->mb[2] = MSW(pmap_dma); + mcp->mb[3] = LSW(pmap_dma); + mcp->mb[6] = MSW(MSD(pmap_dma)); + mcp->mb[7] = LSW(MSD(pmap_dma)); + mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0; + mcp->in_mb = MBX_1|MBX_0; + mcp->buf_size = FCAL_MAP_SIZE; + mcp->flags = MBX_DMA_IN; + mcp->tov = ha->login_timeout * 2; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval == QLA_SUCCESS) { + DEBUG11(printk("%s(%ld): (mb0=%x/mb1=%x) FC/AL Position Map " + "size (%x)\n", __func__, ha->host_no, mcp->mb[0], + mcp->mb[1], (unsigned)pmap[0])); + DEBUG11(qla2x00_dump_buffer(pmap, pmap[0] + 1)); + + if (pos_map) + memcpy(pos_map, pmap, FCAL_MAP_SIZE); + } + pci_free_consistent(ha->pdev, FCAL_MAP_SIZE, pmap, pmap_dma); + + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__, + ha->host_no, rval)); + } else { + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); + } + + return rval; +} +#endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qla_os.c 830-ivtv/drivers/scsi/qla2xxx/qla_os.c --- 000-virgin/drivers/scsi/qla2xxx/qla_os.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qla_os.c Thu Jan 8 10:22:00 2004 @@ -0,0 +1,4778 @@ +/* + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ +#define QLA_MODVERSION +#include "qla_os.h" + +#include "qla_def.h" + +/* + * Driver version + */ +char qla2x00_version_str[40]; + +/* + * SRB allocation cache + */ +char srb_cachep_name[16]; +kmem_cache_t *srb_cachep; + +/* +* Command line options. +*/ +unsigned long qla2x00_verbose; +unsigned long qla2x00_reinit = 1; +unsigned long qla2x00_req_dmp; + +/* + * Stats for all adpaters. + */ +struct _qla2x00stats qla2x00_stats; + +/* + * Ioctl related information. + */ +int num_hosts; +int apiHBAInstance; + +/* + * Module parameter information and variables + */ + +char *ql2xdevconf; +int ql2xretrycount = 20; +int qla2xenbinq = 1; +int ql2xlogintimeout = 20; +int qlport_down_retry; +int ql2xmaxqdepth; +int displayConfig; +int ql2xplogiabsentdevice; +int ql2xintrdelaytimer = 10; + +/* Enable for failover */ +int ConfigRequired; + +/* Persistent binding type */ +int Bind = BIND_BY_PORT_NAME; + +int ql2xsuspendcount = SUSPEND_COUNT; + +int ql2xdoinitscan = 1; + +int qla2x00_retryq_dmp; + +#if defined(MODULE) +char *ql2xopts; + +/* insmod qla2100 ql2xopts=verbose" */ +MODULE_PARM(ql2xopts, "s"); +MODULE_PARM_DESC(ql2xopts, + "Additional driver options."); + +MODULE_PARM(ql2xmaxqdepth, "i"); +MODULE_PARM_DESC(ql2xmaxqdepth, + "Maximum queue depth to report for target devices."); + +MODULE_PARM(ql2xlogintimeout,"i"); +MODULE_PARM_DESC(ql2xlogintimeout, + "Login timeout value in seconds."); + +MODULE_PARM(qlport_down_retry,"i"); +MODULE_PARM_DESC(qlport_down_retry, + "Maximum number of command retries to a port that returns" + "a PORT-DOWN status."); + +MODULE_PARM(ql2xretrycount,"i"); +MODULE_PARM_DESC(ql2xretrycount, + "Maximum number of mid-layer retries allowed for a command. " + "Default value is 20, "); + +MODULE_PARM(displayConfig, "i"); +MODULE_PARM_DESC(displayConfig, + "If 1 then display the configuration used in /etc/modules.conf."); + +MODULE_PARM(ql2xplogiabsentdevice, "i"); +MODULE_PARM_DESC(ql2xplogiabsentdevice, + "Option to enable PLOGI to devices that are not present after " + "a Fabric scan. This is needed for several broken switches." + "Default is 0 - no PLOGI. 1 - perfom PLOGI."); + +MODULE_PARM(ql2xintrdelaytimer,"i"); +MODULE_PARM_DESC(ql2xintrdelaytimer, + "ZIO: Waiting time for Firmware before it generates an " + "interrupt to the host to notify completion of request."); + +MODULE_PARM(ConfigRequired, "i"); +MODULE_PARM_DESC(ConfigRequired, + "If 1, then only configured devices passed in through the" + "ql2xopts parameter will be presented to the OS"); + +MODULE_PARM(Bind, "i"); +MODULE_PARM_DESC(Bind, + "Target persistent binding method: " + "0 by Portname (default); 1 by PortID; 2 by Nodename. "); + +MODULE_PARM(ql2xsuspendcount,"i"); +MODULE_PARM_DESC(ql2xsuspendcount, + "Number of 6-second suspend iterations to perform while a " + "target returns a status. Default is 10 " + "iterations."); + +MODULE_PARM(ql2xdoinitscan, "i"); +MODULE_PARM_DESC(ql2xdoinitscan, + "Signal mid-layer to perform scan after driver load: 0 -- no " + "signal sent to mid-layer."); +#endif + + +/* + * Proc structures and functions + */ +struct info_str { + char *buffer; + int length; + off_t offset; + int pos; +}; + +static void copy_mem_info(struct info_str *, char *, int); +static int copy_info(struct info_str *, char *, ...); + + +/* + * List of host adapters + */ +LIST_HEAD(qla_hostlist); +rwlock_t qla_hostlist_lock = RW_LOCK_UNLOCKED; + +static void qla2x00_free_device(scsi_qla_host_t *); + +static void qla2x00_config_dma_addressing(scsi_qla_host_t *ha); + +/* + * SCSI host template entry points + */ +static int qla2xxx_slave_configure(struct scsi_device * device); +extern int qla2x00_ioctl(struct scsi_device *, int , void *); +static int qla2xxx_eh_abort(struct scsi_cmnd *); +static int qla2xxx_eh_device_reset(struct scsi_cmnd *); +static int qla2xxx_eh_bus_reset(struct scsi_cmnd *); +static int qla2xxx_eh_host_reset(struct scsi_cmnd *); +static uint8_t qla2x00_loop_reset(scsi_qla_host_t *ha); +static int qla2x00_device_reset(scsi_qla_host_t *, fc_port_t *); + +static int qla2x00_proc_info(struct Scsi_Host *, char *, char **, + off_t, int, int); + +static struct scsi_host_template qla2x00_driver_template = { + .module = THIS_MODULE, + .name = "qla2xxx", + .proc_name = "qla2xxx", + .proc_info = qla2x00_proc_info, + .queuecommand = qla2x00_queuecommand, + + .eh_abort_handler = qla2xxx_eh_abort, + .eh_device_reset_handler = qla2xxx_eh_device_reset, + .eh_bus_reset_handler = qla2xxx_eh_bus_reset, + .eh_host_reset_handler = qla2xxx_eh_host_reset, + + .slave_configure = qla2xxx_slave_configure, + + .this_id = -1, + .can_queue = REQUEST_ENTRY_CNT+128, + .cmd_per_lun = 3, + .use_clustering = ENABLE_CLUSTERING, + .sg_tablesize = SG_ALL, + + /* + * The RISC allows for each command to transfer (2^32-1) bytes of data, + * which equates to 0x800000 sectors. + */ + .max_sectors = 0xFFFF, +}; + +static void qla2x00_display_fc_names(scsi_qla_host_t *); + +void qla2x00_blink_led(scsi_qla_host_t *); + +/* TODO Convert to inlines + * + * Timer routines + */ +#define WATCH_INTERVAL 1 /* number of seconds */ + +static void qla2x00_timer(scsi_qla_host_t *); + +static __inline__ void qla2x00_start_timer(scsi_qla_host_t *, + void *, unsigned long); +static __inline__ void qla2x00_restart_timer(scsi_qla_host_t *, unsigned long); +static __inline__ void qla2x00_stop_timer(scsi_qla_host_t *); + +static inline void +qla2x00_start_timer(scsi_qla_host_t *ha, void *func, unsigned long interval) +{ + init_timer(&ha->timer); + ha->timer.expires = jiffies + interval * HZ; + ha->timer.data = (unsigned long)ha; + ha->timer.function = (void (*)(unsigned long))func; + add_timer(&ha->timer); + ha->timer_active = 1; +} + +static inline void +qla2x00_restart_timer(scsi_qla_host_t *ha, unsigned long interval) +{ + mod_timer(&ha->timer, jiffies + interval * HZ); +} + +static __inline__ void +qla2x00_stop_timer(scsi_qla_host_t *ha) +{ + del_timer_sync(&ha->timer); + ha->timer_active = 0; +} + + +static void qla2x00_cmd_timeout(srb_t *sp); +static __inline__ void qla2x00_add_timer_to_cmd(srb_t *sp, int timeout); +static __inline__ void qla2x00_delete_timer_from_cmd(srb_t *sp); + +/************************************************************************** +* qla2x00_add_timer_to_cmd +* +* Description: +* Creates a timer for the specified command. The timeout is usually +* the command time from kernel minus 2 secs. +* +* Input: +* sp - pointer to validate +* +* Returns: +* None. +**************************************************************************/ +static inline void +qla2x00_add_timer_to_cmd(srb_t *sp, int timeout) +{ + init_timer(&sp->timer); + sp->timer.expires = jiffies + timeout * HZ; + sp->timer.data = (unsigned long) sp; + sp->timer.function = (void (*) (unsigned long))qla2x00_cmd_timeout; + add_timer(&sp->timer); +} + +/************************************************************************** +* qla2x00_delete_timer_from_cmd +* +* Description: +* Delete the timer for the specified command. +* +* Input: +* sp - pointer to validate +* +* Returns: +* None. +**************************************************************************/ +static inline void +qla2x00_delete_timer_from_cmd(srb_t *sp) +{ + if (sp->timer.function != NULL) { + del_timer(&sp->timer); + sp->timer.function = NULL; + sp->timer.data = (unsigned long) NULL; + } +} + +static __inline__ void qla2x00_callback(scsi_qla_host_t *, struct scsi_cmnd *); +static __inline__ void sp_put(struct scsi_qla_host * ha, srb_t *sp); +static __inline__ void sp_get(struct scsi_qla_host * ha, srb_t *sp); +static __inline__ void +qla2x00_delete_from_done_queue(scsi_qla_host_t *, srb_t *); + +/************************************************************************** +* sp_put +* +* Description: +* Decrement reference count and call the callback if we're the last +* owner of the specified sp. Will get io_request_lock before calling +* the callback. +* +* Input: +* ha - pointer to the scsi_qla_host_t where the callback is to occur. +* sp - pointer to srb_t structure to use. +* +* Returns: +* +**************************************************************************/ +static inline void +sp_put(struct scsi_qla_host * ha, srb_t *sp) +{ + if (atomic_read(&sp->ref_count) == 0) { + qla_printk(KERN_INFO, ha, + "%s(): **** SP->ref_count not zero\n", + __func__); + DEBUG2(BUG();) + + return; + } + + if (!atomic_dec_and_test(&sp->ref_count)) { + return; + } + + qla2x00_callback(ha, sp->cmd); +} + +/************************************************************************** +* sp_get +* +* Description: +* Increment reference count of the specified sp. +* +* Input: +* sp - pointer to srb_t structure to use. +* +* Returns: +* +**************************************************************************/ +static inline void +sp_get(struct scsi_qla_host * ha, srb_t *sp) +{ + atomic_inc(&sp->ref_count); + + if (atomic_read(&sp->ref_count) > 2) { + qla_printk(KERN_INFO, ha, + "%s(): **** SP->ref_count greater than two\n", + __func__); + DEBUG2(BUG();) + + return; + } +} + +/* +* qla2x00_callback +* Returns the completed SCSI command to LINUX. +* +* Input: +* ha -- Host adapter structure +* cmd -- SCSI mid-level command structure. +* Returns: +* None +* Note:From failover point of view we always get the sp +* from vis_ha pool in queuecommand.So when we put it +* back to the pool it has to be the vis_ha. +* So rely on struct scsi_cmnd to get the vis_ha and not on sp. +*/ +static inline void +qla2x00_callback(scsi_qla_host_t *ha, struct scsi_cmnd *cmd) +{ + srb_t *sp = (srb_t *) CMD_SP(cmd); + scsi_qla_host_t *vis_ha; + os_lun_t *lq; + int got_sense; + unsigned long cpu_flags = 0; + + ENTER(__func__); + + cmd->host_scribble = (unsigned char *) NULL; + vis_ha = (scsi_qla_host_t *) cmd->device->host->hostdata; + + if (sp == NULL) { + qla_printk(KERN_INFO, ha, + "%s(): **** CMD derives a NULL SP\n", + __func__); + DEBUG2(BUG();) + return; + } + + /* + * If command status is not DID_BUS_BUSY then go ahead and freed sp. + */ + /* + * Cancel command timeout + */ + qla2x00_delete_timer_from_cmd(sp); + + /* + * Put SP back in the free queue + */ + sp->cmd = NULL; + CMD_SP(cmd) = NULL; + lq = sp->lun_queue; + got_sense = (sp->flags & SRB_GOT_SENSE)? 1: 0; + add_to_free_queue(vis_ha, sp); + + if (host_byte(cmd->result) == DID_OK) { + /* device ok */ + ha->total_bytes += cmd->bufflen; + if (!got_sense) { + /* If lun was suspended then clear retry count */ + spin_lock_irqsave(&lq->q_lock, cpu_flags); + if (!test_bit(LUN_EXEC_DELAYED, &lq->q_flag)) + lq->q_state = LUN_STATE_READY; + spin_unlock_irqrestore(&lq->q_lock, cpu_flags); + } + } else if (host_byte(cmd->result) == DID_ERROR) { + /* device error */ + ha->total_dev_errs++; + } + + /* Call the mid-level driver interrupt handler */ + (*(cmd)->scsi_done)(cmd); + + LEAVE(__func__); +} + +static inline void +qla2x00_delete_from_done_queue(scsi_qla_host_t *dest_ha, srb_t *sp) +{ + /* remove command from done list */ + list_del_init(&sp->list); + dest_ha->done_q_cnt--; + sp->state = SRB_NO_QUEUE_STATE; + + if (sp->flags & SRB_DMA_VALID) { + sp->flags &= ~SRB_DMA_VALID; + + /* Release memory used for this I/O */ + if (sp->cmd->use_sg) { + pci_unmap_sg(dest_ha->pdev, sp->cmd->request_buffer, + sp->cmd->use_sg, sp->cmd->sc_data_direction); + } else if (sp->cmd->request_bufflen) { + pci_unmap_page(dest_ha->pdev, sp->dma_handle, + sp->cmd->request_bufflen, + sp->cmd->sc_data_direction); + } + } +} + +static int qla2x00_do_dpc(void *data); + +static void qla2x00_rst_aen(scsi_qla_host_t *); + +static uint8_t qla2x00_mem_alloc(scsi_qla_host_t *); +static void qla2x00_mem_free(scsi_qla_host_t *ha); +int qla2x00_allocate_sp_pool( scsi_qla_host_t *ha); +void qla2x00_free_sp_pool(scsi_qla_host_t *ha); + +static ssize_t qla2x00_sysfs_read_fw_dump(struct kobject *, char *, loff_t, + size_t); +static ssize_t qla2x00_sysfs_write_fw_dump(struct kobject *, char *, loff_t, + size_t); +static struct bin_attribute sysfs_fw_dump_attr = { + .attr = { + .name = "fw_dump", + .mode = S_IRUSR | S_IWUSR, + }, + .size = 0, + .read = qla2x00_sysfs_read_fw_dump, + .write = qla2x00_sysfs_write_fw_dump, +}; +static ssize_t qla2x00_sysfs_read_nvram(struct kobject *, char *, loff_t, + size_t); +static ssize_t qla2x00_sysfs_write_nvram(struct kobject *, char *, loff_t, + size_t); +static struct bin_attribute sysfs_nvram_attr = { + .attr = { + .name = "nvram", + .mode = S_IRUSR | S_IWUSR, + }, + .size = sizeof(nvram_t), + .read = qla2x00_sysfs_read_nvram, + .write = qla2x00_sysfs_write_nvram, +}; + + +int +qla2x00_set_info(char *buffer, int length, struct Scsi_Host *shost) +{ + return (-ENOSYS); /* Currently this is a no-op */ +} + +/* -------------------------------------------------------------------------- */ + + +/* SysFS attributes. */ +static ssize_t qla2x00_sysfs_read_fw_dump(struct kobject *kobj, char *buf, + loff_t off, size_t count) +{ + struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, + struct device, kobj))); + + if (ha->fw_dump_reading == 0) + return 0; + if (off > ha->fw_dump_buffer_len) + return 0; + if (off + count > ha->fw_dump_buffer_len) + count = ha->fw_dump_buffer_len - off; + + memcpy(buf, &ha->fw_dump_buffer[off], count); + + return (count); +} + +static ssize_t qla2x00_sysfs_write_fw_dump(struct kobject *kobj, char *buf, + loff_t off, size_t count) +{ + struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, + struct device, kobj))); + int reading; + + if (off != 0) + return (0); + + reading = simple_strtol(buf, NULL, 10); + switch (reading) { + case 0: + if (ha->fw_dump_reading == 1) { + qla_printk(KERN_INFO, ha, + "Firmware dump cleared on (%ld).\n", + ha->host_no); + + vfree(ha->fw_dump_buffer); + free_pages((unsigned long)ha->fw_dump, + ha->fw_dump_order); + + ha->fw_dump_reading = 0; + ha->fw_dump_buffer = NULL; + ha->fw_dump = NULL; + } + break; + case 1: + if (ha->fw_dump != NULL && !ha->fw_dump_reading) { + ha->fw_dump_reading = 1; + + ha->fw_dump_buffer = (char *)vmalloc(FW_DUMP_SIZE); + if (ha->fw_dump_buffer == NULL) { + qla_printk(KERN_WARNING, ha, + "Unable to allocate memory for firmware " + "dump buffer (%d).\n", FW_DUMP_SIZE); + + ha->fw_dump_reading = 0; + return (count); + } + qla_printk(KERN_INFO, ha, + "Firmware dump ready for read on (%ld).\n", + ha->host_no); + memset(ha->fw_dump_buffer, 0, FW_DUMP_SIZE); + if (IS_QLA2100(ha) || IS_QLA2200(ha)) + qla2100_ascii_fw_dump(ha); + else + qla2300_ascii_fw_dump(ha); + ha->fw_dump_buffer_len = strlen(ha->fw_dump_buffer); + } + break; + } + return (count); +} + +static ssize_t qla2x00_sysfs_read_nvram(struct kobject *kobj, char *buf, + loff_t off, size_t count) +{ + struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, + struct device, kobj))); + uint16_t *witer; + unsigned long flags; + uint16_t cnt; + + if (!capable(CAP_SYS_ADMIN) || off != 0 || count != sizeof(nvram_t)) + return 0; + + /* Read NVRAM. */ + spin_lock_irqsave(&ha->hardware_lock, flags); + qla2x00_lock_nvram_access(ha); + witer = (uint16_t *)buf; + for (cnt = 0; cnt < count / 2; cnt++) { + *witer = cpu_to_le16(qla2x00_get_nvram_word(ha, + cnt+ha->nvram_base)); + witer++; + } + qla2x00_unlock_nvram_access(ha); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + return (count); +} + +static ssize_t qla2x00_sysfs_write_nvram(struct kobject *kobj, char *buf, + loff_t off, size_t count) +{ + struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, + struct device, kobj))); + uint8_t *iter; + uint16_t *witer; + unsigned long flags; + uint16_t cnt; + uint8_t chksum; + + if (!capable(CAP_SYS_ADMIN) || off != 0 || count != sizeof(nvram_t)) + return 0; + + /* Checksum NVRAM. */ + iter = (uint8_t *)buf; + chksum = 0; + for (cnt = 0; cnt < count - 1; cnt++) + chksum += *iter++; + chksum = ~chksum + 1; + *iter = chksum; + + /* Write NVRAM. */ + spin_lock_irqsave(&ha->hardware_lock, flags); + qla2x00_lock_nvram_access(ha); + witer = (uint16_t *)buf; + for (cnt = 0; cnt < count / 2; cnt++) { + qla2x00_write_nvram_word(ha, cnt+ha->nvram_base, + cpu_to_le16(*witer)); + witer++; + } + qla2x00_unlock_nvram_access(ha); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + return (count); +} + +/* -------------------------------------------------------------------------- */ +char * +qla2x00_get_pci_info_str(struct scsi_qla_host *ha, char *str) +{ + static char *pci_bus_modes[] = { + "33", "66", "100", "133", + }; + uint16_t pci_bus; + + strcpy(str, "PCI"); + pci_bus = (ha->pci_attr & (BIT_9 | BIT_10)) >> 9; + if (pci_bus) { + strcat(str, "-X ("); + strcat(str, pci_bus_modes[pci_bus]); + } else { + pci_bus = (ha->pci_attr & BIT_8) >> 8; + strcat(str, " ("); + strcat(str, pci_bus_modes[pci_bus]); + } + strcat(str, " MHz)"); + + return (str); +} + +char * +qla2x00_get_fw_version_str(struct scsi_qla_host *ha, char *str) +{ + char un_str[10]; + + sprintf(str, "%d.%02d.%02d ", ha->fw_major_version, + ha->fw_minor_version, + ha->fw_subminor_version); + + switch (ha->fw_attributes & 0xFF) { + case 0x7: + strcat(str, "EF"); + break; + case 0x17: + strcat(str, "TP"); + break; + case 0x37: + strcat(str, "IP"); + break; + case 0x77: + strcat(str, "VI"); + break; + default: + sprintf(un_str, "(%x)", ha->fw_attributes); + strcat(str, un_str); + break; + } + if (ha->fw_attributes & 0x100) + strcat(str, "X"); + + return (str); +} + +/************************************************************************** +* qla2x00_queuecommand +* +* Description: +* Queue a command to the controller. +* +* Input: +* cmd - pointer to Scsi cmd structure +* fn - pointer to Scsi done function +* +* Returns: +* 0 - Always +* +* Note: +* The mid-level driver tries to ensures that queuecommand never gets invoked +* concurrently with itself or the interrupt handler (although the +* interrupt handler may call this routine as part of request-completion +* handling). +**************************************************************************/ +int +qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *)) +{ + fc_port_t *fcport; + os_lun_t *lq; + os_tgt_t *tq; + scsi_qla_host_t *ha, *ha2; + srb_t *sp; + struct Scsi_Host *host; + unsigned int b, t, l; + unsigned long handle; + int was_empty; + + + host = cmd->device->host; + ha = (scsi_qla_host_t *) host->hostdata; + + cmd->scsi_done = fn; + + spin_unlock_irq(ha->host->host_lock); + + /* + * Allocate a command packet from the "sp" pool. If we cant get back + * one then let scsi layer come back later. + */ + if ((sp = qla2x00_get_new_sp(ha)) == NULL) { + qla_printk(KERN_WARNING, ha, + "Couldn't allocate memory for sp - retried.\n"); + + spin_lock_irq(ha->host->host_lock); + + return (1); + } + + sp->cmd = cmd; + CMD_SP(cmd) = (void *)sp; + + sp->flags = 0; + if (CMD_RESID_LEN(cmd) & SRB_IOCTL) { + /* Need to set sp->flags */ + sp->flags |= SRB_IOCTL; + CMD_RESID_LEN(cmd) = 0; /* Clear it since no more use. */ + } + + sp->fo_retry_cnt = 0; + + /* Generate LU queue on bus, target, LUN */ + b = cmd->device->channel; + t = cmd->device->id; + l = cmd->device->lun; + + /* + * Start Command Timer. Typically it will be 2 seconds less than what + * is requested by the Host such that we can return the IO before + * aborts are called. + */ + if ((cmd->timeout_per_command / HZ) > QLA_CMD_TIMER_DELTA) + qla2x00_add_timer_to_cmd(sp, + (cmd->timeout_per_command / HZ) - QLA_CMD_TIMER_DELTA); + else + qla2x00_add_timer_to_cmd(sp, cmd->timeout_per_command / HZ); + + if (l >= ha->max_luns) { + cmd->result = DID_NO_CONNECT << 16; + + spin_lock_irq(ha->host->host_lock); + + sp_put(ha, sp); + + return (0); + } + + if ((tq = (os_tgt_t *) TGT_Q(ha, t)) != NULL && + (lq = (os_lun_t *) LUN_Q(ha, t, l)) != NULL) { + fcport = lq->fclun->fcport; + ha2 = fcport->ha; + } else { + lq = NULL; + fcport = NULL; + ha2 = ha; + } + + /* Set an invalid handle until we issue the command to ISP */ + /* then we will set the real handle value. */ + handle = INVALID_HANDLE; + cmd->host_scribble = (unsigned char *)handle; + + /* Bookkeeping information */ + sp->r_start = jiffies; /* time the request was recieved */ + sp->u_start = 0; + + /* Setup device queue pointers. */ + sp->tgt_queue = tq; + sp->lun_queue = lq; + + /* + * NOTE : q is NULL + * + * 1. When device is added from persistent binding but has not been + * discovered yet.The state of loopid == PORT_AVAIL. + * 2. When device is never found on the bus.(loopid == UNUSED) + * + * IF Device Queue is not created, or device is not in a valid state + * and link down error reporting is enabled, reject IO. + */ + if (fcport == NULL) { + DEBUG3(printk("scsi(%ld:%2d:%2d): port unavailable\n", + ha->host_no,t,l)); + + cmd->result = DID_NO_CONNECT << 16; + + spin_lock_irq(ha->host->host_lock); + + sp_put(ha, sp); + + return (0); + } + + /* Only modify the allowed count if the target is a *non* tape device */ + if ((fcport->flags & FCF_TAPE_PRESENT) == 0) { + if (cmd->allowed < ql2xretrycount) { + cmd->allowed = ql2xretrycount; + } + } + + DEBUG5(printk("scsi(%ld:%2d:%2d): (queuecmd) queue sp = %p, " + "flags=0x%x fo retry=%d, pid=%ld\n", + ha->host_no, t, l, sp, sp->flags, sp->fo_retry_cnt, + cmd->serial_number)); + DEBUG5(qla2x00_print_scsi_cmd(cmd)); + + sp->fclun = lq->fclun; + sp->ha = ha2; + + if (cmd->sc_data_direction == DMA_BIDIRECTIONAL && + cmd->request_bufflen != 0) { + + DEBUG2(printk(KERN_WARNING + "scsi(%ld): Incorrect data direction - transfer " + "length=%d, direction=%d, pid=%ld, opcode=%x\n", + ha->host_no, cmd->request_bufflen, cmd->sc_data_direction, + cmd->serial_number, cmd->cmnd[0])); + } + + /* Final pre-check : + * + * Either PORT_DOWN_TIMER OR LINK_DOWN_TIMER Expired. + */ + if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD || + atomic_read(&ha->loop_state) == LOOP_DEAD) { + /* + * Add the command to the done-queue for later failover + * processing + */ + cmd->result = DID_NO_CONNECT << 16; + add_to_done_queue(ha, sp); + if (!list_empty(&ha->done_queue)) + qla2x00_done(ha); + + spin_lock_irq(ha->host->host_lock); + return (0); + } + was_empty = add_to_pending_queue(ha, sp); + + if ((IS_QLA2100(ha) || IS_QLA2200(ha)) && ha->flags.online) { + unsigned long flags; + device_reg_t *reg; + reg = ha->iobase; + + if (RD_REG_WORD(ISP_RSP_Q_IN(ha, reg)) != ha->rsp_ring_index) { + spin_lock_irqsave(&ha->hardware_lock, flags); + qla2x00_process_response_queue(ha); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + } + } + + /* We submit to the hardware if: + * + * 1) we're on the cpu the irq's arrive on or + * 2) there are very few io's outstanding. + * + * In all other cases we'll let an irq pick up our IO and submit it + * to the controller to improve affinity. + */ + if (smp_processor_id() == ha->last_irq_cpu || was_empty) + qla2x00_next(ha); + + spin_lock_irq(ha->host->host_lock); + + return (0); +} + +/* + * qla2x00_eh_wait_on_command + * Waits for the command to be returned by the Firmware for some + * max time. + * + * Input: + * ha = actual ha whose done queue will contain the command + * returned by firmware. + * cmd = Scsi Command to wait on. + * flag = Abort/Reset(Bus or Device Reset) + * + * Return: + * Not Found : 0 + * Found : 1 + */ +static int +qla2x00_eh_wait_on_command(scsi_qla_host_t *ha, struct scsi_cmnd *cmd) +{ +#define ABORT_WAIT_TIME 10 /* seconds */ + + int found = 0; + int done = 0; + srb_t *rp; + struct list_head *list, *temp; + u_long cpu_flags = 0; + u_long max_wait_time = ABORT_WAIT_TIME; + + ENTER(__func__); + + do { + /* Check on done queue */ + if (!found) { + spin_lock_irqsave(&ha->list_lock, cpu_flags); + list_for_each_safe(list, temp, &ha->done_queue) { + rp = list_entry(list, srb_t, list); + + /* + * Found command. Just exit and wait for the + * cmd sent to OS. + */ + if (cmd == rp->cmd) { + found++; + DEBUG3(printk("%s: found in done " + "queue.\n", __func__);) + break; + } + } + spin_unlock_irqrestore(&ha->list_lock, cpu_flags); + } + + /* Checking to see if its returned to OS */ + rp = (srb_t *) CMD_SP(cmd); + if (rp == NULL ) { + done++; + break; + } + + spin_unlock_irq(ha->host->host_lock); + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(2*HZ); + + spin_lock_irq(ha->host->host_lock); + + } while ((max_wait_time--)); + + if (done) { + DEBUG2(printk(KERN_INFO "%s: found cmd=%p.\n", __func__, cmd)); + } else if (found) { + /* Immediately return command to the mid-layer */ + qla2x00_delete_from_done_queue(ha, rp); + sp_put(ha, rp); + done++; + } + + LEAVE(__func__); + + return (done); +} + +/* + * qla2x00_wait_for_hba_online + * Wait till the HBA is online after going through + * <= MAX_RETRIES_OF_ISP_ABORT or + * finally HBA is disabled ie marked offline + * + * Input: + * ha - pointer to host adapter structure + * + * Note: + * Does context switching-Release SPIN_LOCK + * (if any) before calling this routine. + * + * Return: + * Success (Adapter is online) : 0 + * Failed (Adapter is offline/disabled) : 1 + */ +static inline int +qla2x00_wait_for_hba_online(scsi_qla_host_t *ha) +{ + int return_status ; + + while ((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) || + test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) || + test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) { + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(3 * HZ); + } + if (ha->flags.online == TRUE) + return_status = QLA_SUCCESS; + else + /* Adapter is disabled/offline */ + return_status = QLA_FUNCTION_FAILED; + + DEBUG2(printk("%s return_status=%d\n",__func__,return_status)); + + return (return_status); +} + +/* + * qla2x00_wait_for_loop_ready + * Wait for MAX_LOOP_TIMEOUT(5 min) value for loop + * to be in LOOP_READY state. + * Input: + * ha - pointer to host adapter structure + * + * Note: + * Does context switching-Release SPIN_LOCK + * (if any) before calling this routine. + * + * + * Return: + * Success (LOOP_READY) : 0 + * Failed (LOOP_NOT_READY) : 1 + */ +static inline int +qla2x00_wait_for_loop_ready(scsi_qla_host_t *ha) +{ + int return_status = QLA_SUCCESS; + unsigned long loop_timeout ; + + /* wait for 5 min at the max for loop to be ready */ + loop_timeout = jiffies + (MAX_LOOP_TIMEOUT * HZ); + + while ((!atomic_read(&ha->loop_down_timer) && + atomic_read(&ha->loop_state) == LOOP_DOWN) || + test_bit(CFG_ACTIVE, &ha->cfg_flags) || + atomic_read(&ha->loop_state) != LOOP_READY) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(3 * HZ); + if (time_after_eq(jiffies, loop_timeout)) { + return_status = QLA_FUNCTION_FAILED; + break; + } + } + return (return_status); +} + +/************************************************************************** +* qla2xxx_eh_abort +* +* Description: +* The abort function will abort the specified command. +* +* Input: +* cmd = Linux SCSI command packet to be aborted. +* +* Returns: +* Either SUCCESS or FAILED. +* +* Note: +**************************************************************************/ +int +qla2xxx_eh_abort(struct scsi_cmnd *cmd) +{ + int i; + int return_status = FAILED; + os_lun_t *q; + scsi_qla_host_t *ha; + scsi_qla_host_t *vis_ha; + srb_t *sp; + srb_t *rp; + struct list_head *list, *temp; + struct Scsi_Host *host; + uint8_t found = 0; + unsigned int b, t, l; + unsigned long flags; + + + ENTER(__func__); + + /* Get the SCSI request ptr */ + sp = (srb_t *) CMD_SP(cmd); + + /* + * If sp is NULL, command is already returned. + * sp is NULLED just before we call back scsi_done + * + */ + if ((sp == NULL)) { + /* no action - we don't have command */ + qla_printk(KERN_INFO, to_qla_host(cmd->device->host), + "qla2xxx_eh_abort: cmd already done sp=%p\n", sp); + DEBUG(printk("qla2xxx_eh_abort: cmd already done sp=%p\n", sp);) + return(SUCCESS); + } + if (sp) { + DEBUG(printk("qla2xxx_eh_abort: refcount %i \n", + atomic_read(&sp->ref_count));) + } + + vis_ha = (scsi_qla_host_t *) cmd->device->host->hostdata; + if (qla2x00_failover_enabled(vis_ha)) + /* Get Actual HA pointer */ + ha = (scsi_qla_host_t *)sp->ha; + else + ha = (scsi_qla_host_t *)cmd->device->host->hostdata; + + host = ha->host; + + /* Generate LU queue on bus, target, LUN */ + b = cmd->device->channel; + t = cmd->device->id; + l = cmd->device->lun; + q = GET_LU_Q(vis_ha, t, l); + + qla_printk(KERN_INFO, ha, + "%s scsi(%ld:%d:%d:%d): cmd_timeout_in_sec=0x%x.\n", __func__, + ha->host_no, (int)b, (int)t, (int)l, + cmd->timeout_per_command / HZ); + + /* + * if no LUN queue then something is very wrong!!! + */ + if (q == NULL) { + qla_printk(KERN_WARNING, ha, + "qla2x00: (%x:%x:%x) No LUN queue.\n", b, t, l); + + /* no action - we don't have command */ + return(FAILED); + } + + DEBUG2(printk("scsi(%ld): ABORTing cmd=%p sp=%p jiffies = 0x%lx, " + "timeout=%x, dpc_flags=%lx, vis_ha->dpc_flags=%lx\n", + ha->host_no, cmd, sp, jiffies, cmd->timeout_per_command / HZ, + ha->dpc_flags, vis_ha->dpc_flags)); + DEBUG2(qla2x00_print_scsi_cmd(cmd)); + DEBUG2(qla2x00_print_q_info(q);) + + spin_unlock_irq(ha->host->host_lock); + /* Blocking call-Does context switching if abort isp is active etc */ + if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS) { + DEBUG2(printk("%s failed:board disabled\n", __func__);) + spin_lock_irq(ha->host->host_lock); + return (FAILED); + } + spin_lock_irq(ha->host->host_lock); + + /* Search done queue */ + spin_lock_irqsave(&ha->list_lock,flags); + list_for_each_safe(list, temp, &ha->done_queue) { + rp = list_entry(list, srb_t, list); + + if (cmd != rp->cmd) + continue; + + /* + * Found command.Remove it from done list. + * And proceed to post completion to scsi mid layer. + */ + return_status = SUCCESS; + found++; + qla2x00_delete_from_done_queue(ha, sp); + + break; + } /* list_for_each_safe() */ + spin_unlock_irqrestore(&ha->list_lock, flags); + + /* + * Return immediately if the aborted command was already in the done + * queue + */ + if (found) { + qla_printk(KERN_INFO, ha, + "qla2xxx_eh_abort: Returning completed command=%p sp=%p\n", + cmd, sp); + sp_put(ha, sp); + return (return_status); + } + + + /* + * See if this command is in the retry queue + */ + DEBUG3(printk("qla2xxx_eh_abort: searching sp %p in retry " + "queue.\n", sp);) + + spin_lock_irqsave(&ha->list_lock, flags); + list_for_each_safe(list, temp, &ha->retry_queue) { + rp = list_entry(list, srb_t, list); + + if (cmd != rp->cmd) + continue; + + + DEBUG2(printk("qla2xxx_eh_abort: found " + "in retry queue. SP=%p\n", sp);) + + __del_from_retry_queue(ha, rp); + cmd->result = DID_ABORT << 16; + __add_to_done_queue(ha, rp); + + return_status = SUCCESS; + found++; + + break; + + } + spin_unlock_irqrestore(&ha->list_lock, flags); + + /* + * Search failover queue + */ + if (qla2x00_failover_enabled(ha)) { + if (!found && qla2x00_search_failover_queue(ha, cmd)) { + return_status = SUCCESS; + found++; + } + } + + /* + * Our SP pointer points at the command we want to remove from the + * pending queue providing we haven't already sent it to the adapter. + */ + if (!found) { + DEBUG3(printk("qla2xxx_eh_abort: searching sp %p " + "in pending queue.\n", sp);) + + spin_lock_irqsave(&vis_ha->list_lock, flags); + list_for_each_safe(list, temp, &vis_ha->pending_queue) { + rp = list_entry(list, srb_t, list); + + if (rp->cmd != cmd) + continue; + + /* Remove srb from LUN queue. */ + rp->flags |= SRB_ABORTED; + + DEBUG2(printk("qla2xxx_eh_abort: Cmd in pending queue." + " serial_number %ld.\n", + sp->cmd->serial_number);) + + __del_from_pending_queue(vis_ha, rp); + cmd->result = DID_ABORT << 16; + + __add_to_done_queue(vis_ha, rp); + + return_status = SUCCESS; + + found++; + break; + } /* list_for_each_safe() */ + spin_unlock_irqrestore(&vis_ha->list_lock, flags); + } /*End of if !found */ + + if (!found) { /* find the command in our active list */ + DEBUG3(printk("qla2xxx_eh_abort: searching sp %p " + "in outstanding queue.\n", sp);) + + spin_lock_irqsave(&ha->hardware_lock, flags); + for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) { + sp = ha->outstanding_cmds[i]; + + if (sp == NULL) + continue; + + if (sp->cmd != cmd) + continue; + + DEBUG2(printk("qla2xxx_eh_abort(%ld): aborting sp %p " + "from RISC. pid=%ld sp->state=%x\n", + ha->host_no, sp, sp->cmd->serial_number, + sp->state);) + DEBUG(qla2x00_print_scsi_cmd(cmd);) + DEBUG(qla2x00_print_q_info(q);) + + /* Get a reference to the sp and drop the lock.*/ + sp_get(ha, sp); + + spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_unlock(ha->host->host_lock); + + if (qla2x00_abort_command(ha, sp)) { + DEBUG2(printk("qla2xxx_eh_abort: abort_command " + "mbx failed.\n");) + return_status = FAILED; + } else { + DEBUG3(printk("qla2xxx_eh_abort: abort_command " + " mbx success.\n");) + return_status = SUCCESS; + } + + sp_put(ha,sp); + + spin_lock_irq(ha->host->host_lock); + spin_lock_irqsave(&ha->hardware_lock, flags); + + /* + * Regardless of mailbox command status, go check on + * done queue just in case the sp is already done. + */ + break; + + }/*End of for loop */ + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + } /*End of if !found */ + + /*Waiting for our command in done_queue to be returned to OS.*/ + if (qla2x00_eh_wait_on_command(ha, cmd) != 0) { + DEBUG2(printk("qla2xxx_eh_abort: cmd returned back to OS.\n");) + return_status = SUCCESS; + } + + if (return_status == FAILED) { + qla_printk(KERN_INFO, ha, + "qla2xxx_eh_abort Exiting: status=Failed\n"); + return FAILED; + } + + DEBUG2(printk("qla2xxx_eh_abort: Exiting. return_status=0x%x.\n", + return_status)); + + LEAVE("qla2xxx_eh_abort"); + + return(return_status); +} + +/************************************************************************** +* qla2x00_eh_wait_for_pending_target_commands +* +* Description: +* Waits for all the commands to come back from the specified target. +* +* Input: +* ha - pointer to scsi_qla_host structure. +* t - target +* Returns: +* Either SUCCESS or FAILED. +* +* Note: +**************************************************************************/ +int +qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t) +{ + int cnt; + int status; + unsigned long flags; + srb_t *sp; + struct scsi_cmnd *cmd; + + status = 0; + + /* + * Waiting for all commands for the designated target in the active + * array + */ + for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { + spin_lock_irqsave(&ha->hardware_lock, flags); + sp = ha->outstanding_cmds[cnt]; + if (sp) { + cmd = sp->cmd; + spin_unlock_irqrestore(&ha->hardware_lock, flags); + if (cmd->device->id == t) { + if (!qla2x00_eh_wait_on_command(ha, cmd)) { + status = 1; + break; + } + } + } + else { + spin_unlock_irqrestore(&ha->hardware_lock, flags); + } + } + return (status); +} + + +/************************************************************************** +* qla2xxx_eh_device_reset +* +* Description: +* The device reset function will reset the target and abort any +* executing commands. +* +* NOTE: The use of SP is undefined within this context. Do *NOT* +* attempt to use this value, even if you determine it is +* non-null. +* +* Input: +* cmd = Linux SCSI command packet of the command that cause the +* bus device reset. +* +* Returns: +* SUCCESS/FAILURE (defined as macro in scsi.h). +* +**************************************************************************/ +int +qla2xxx_eh_device_reset(struct scsi_cmnd *cmd) +{ + int return_status; + unsigned int b, t, l; + scsi_qla_host_t *ha; + os_tgt_t *tq; + os_lun_t *lq; + fc_port_t *fcport_to_reset; + + return_status = FAILED; + if (cmd == NULL) { + printk(KERN_INFO + "%s(): **** SCSI mid-layer passing in NULL cmd\n", + __func__); + + return (return_status); + } + + b = cmd->device->channel; + t = cmd->device->id; + l = cmd->device->lun; + ha = (scsi_qla_host_t *)cmd->device->host->hostdata; + + tq = TGT_Q(ha, t); + if (tq == NULL) { + qla_printk(KERN_INFO, ha, + "%s(): **** CMD derives a NULL TGT_Q\n", __func__); + + return (return_status); + } + lq = (os_lun_t *)LUN_Q(ha, t, l); + if (lq == NULL) { + printk(KERN_INFO + "%s(): **** CMD derives a NULL LUN_Q\n", __func__); + + return (return_status); + } + fcport_to_reset = lq->fclun->fcport; + +#if STOP_ON_RESET + qla2x00_panic(__func__, ha->host); +#endif + + qla_printk(KERN_INFO, ha, + "scsi(%ld:%d:%d:%d): DEVICE RESET ISSUED.\n", ha->host_no, b, t, l); + + DEBUG2(printk(KERN_INFO + "scsi(%ld): DEVICE_RESET cmd=%p jiffies = 0x%lx, timeout=%x, " + "dpc_flags=%lx, status=%x allowed=%d cmd.state=%x\n", + ha->host_no, cmd, jiffies, cmd->timeout_per_command / HZ, + ha->dpc_flags, cmd->result, cmd->allowed, cmd->state)); + + spin_unlock_irq(ha->host->host_lock); + + /* Blocking call-Does context switching if abort isp is active etc */ + if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS) { + DEBUG2(printk(KERN_INFO + "%s failed:board disabled\n",__func__)); + + spin_lock_irq(ha->host->host_lock); + goto eh_dev_reset_done; + } + + /* Blocking call-Does context switching if loop is Not Ready */ + if (qla2x00_wait_for_loop_ready(ha) == QLA_SUCCESS) { + if (qla2x00_device_reset(ha, fcport_to_reset) == 0) { + return_status = SUCCESS; + } + +#if defined(LOGOUT_AFTER_DEVICE_RESET) + if (return_status == SUCCESS) { + if (fcport_to_reset->flags & FC_FABRIC_DEVICE) { + qla2x00_fabric_logout(ha, + fcport_to_reset->loop_id); + qla2x00_mark_device_lost(ha, fcport_to_reset); + } + } +#endif + } else { + DEBUG2(printk(KERN_INFO + "%s failed: loop not ready\n",__func__);) + } + + spin_lock_irq(ha->host->host_lock); + + if (return_status == FAILED) { + DEBUG3(printk("%s(%ld): device reset failed\n", + __func__,ha->host_no)); + qla_printk(KERN_INFO, ha, "%s: device reset failed\n", + __func__); + + goto eh_dev_reset_done; + } + + /* + * If we are coming down the EH path, wait for all commands to + * complete for the device. + */ + if (cmd->device->host->eh_active) { + if (qla2x00_eh_wait_for_pending_target_commands(ha, t)) + return_status = FAILED; + + if (return_status == FAILED) { + DEBUG3(printk("%s(%ld): failed while waiting for " + "commands\n", __func__, ha->host_no)); + qla_printk(KERN_INFO, ha, + "%s: failed while waiting for commands\n", + __func__); + + goto eh_dev_reset_done; + } + } + + qla_printk(KERN_INFO, ha, + "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n", + ha->host_no, b, t, l); + +eh_dev_reset_done: + + return (return_status); +} + +/************************************************************************** +* qla2x00_eh_wait_for_pending_commands +* +* Description: +* Waits for all the commands to come back from the specified host. +* +* Input: +* ha - pointer to scsi_qla_host structure. +* +* Returns: +* 1 : SUCCESS +* 0 : FAILED +* +* Note: +**************************************************************************/ +int +qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha) +{ + int cnt; + int status; + unsigned long flags; + srb_t *sp; + struct scsi_cmnd *cmd; + + status = 1; + + /* + * Waiting for all commands for the designated target in the active + * array + */ + for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { + spin_lock_irqsave(&ha->hardware_lock, flags); + sp = ha->outstanding_cmds[cnt]; + if (sp) { + cmd = sp->cmd; + spin_unlock_irqrestore(&ha->hardware_lock, flags); + status = qla2x00_eh_wait_on_command(ha, cmd); + if (status == 0) + break; + } + else { + spin_unlock_irqrestore(&ha->hardware_lock, flags); + } + } + return (status); +} + + +/************************************************************************** +* qla2xxx_eh_bus_reset +* +* Description: +* The bus reset function will reset the bus and abort any executing +* commands. +* +* Input: +* cmd = Linux SCSI command packet of the command that cause the +* bus reset. +* +* Returns: +* SUCCESS/FAILURE (defined as macro in scsi.h). +* +**************************************************************************/ +int +qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd) +{ + scsi_qla_host_t *ha; + srb_t *sp; + int rval = FAILED; + + + ENTER("qla2xxx_eh_bus_reset"); + + ha = (scsi_qla_host_t *) cmd->device->host->hostdata; + sp = (srb_t *) CMD_SP(cmd); + +#if STOP_ON_RESET + printk("Resetting the Bus= 0x%x\n", (int)cmd); + qla2x00_print_scsi_cmd(cmd); + qla2x00_panic("qla2100_reset", ha->host); +#endif + + qla_printk(KERN_INFO, ha, + "scsi(%ld:%d:%d:%d): LOOP RESET ISSUED.\n", ha->host_no, + cmd->device->channel, cmd->device->id, cmd->device->lun); + + spin_unlock_irq(ha->host->host_lock); + + /* Blocking call-Does context switching if abort isp is active etc*/ + if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS) { + DEBUG2(printk("%s failed:board disabled\n",__func__)); + spin_lock_irq(ha->host->host_lock); + return FAILED; + } + + /* Blocking call-Does context switching if loop is Not Ready */ + if (qla2x00_wait_for_loop_ready(ha) == QLA_SUCCESS) { + if (qla2x00_loop_reset(ha)) + rval = SUCCESS; + } + + spin_lock_irq(ha->host->host_lock); + if (rval == FAILED) + goto out; + + /* + * Blocking Call. It goes to sleep waiting for cmd to get to done q + * + * XXX(hch): really? We're under host_lock here.. + */ + /* Waiting for our command in done_queue to be returned to OS.*/ + if (!qla2x00_eh_wait_for_pending_commands(ha)) + rval = FAILED; + + out: + qla_printk(KERN_INFO, ha, "%s: reset %s\n", __func__, + (rval == FAILED) ? "failed" : "succeded"); + + LEAVE("qla2xxx_eh_bus_reset"); + return rval; +} + +/************************************************************************** +* qla2xxx_eh_host_reset +* +* Description: +* The reset function will reset the Adapter. +* +* Input: +* cmd = Linux SCSI command packet of the command that cause the +* adapter reset. +* +* Returns: +* Either SUCCESS or FAILED. +* +* Note: +**************************************************************************/ +int +qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) +{ + scsi_qla_host_t *ha = (scsi_qla_host_t *)cmd->device->host->hostdata; + srb_t *sp = (srb_t *)CMD_SP(cmd); + int rval = SUCCESS; + + ENTER("qla2xxx_eh_host_reset"); + + /* Find actual ha */ + if (qla2x00_failover_enabled(ha) && ha->host->eh_active == EH_ACTIVE) + ha = sp->ha; + + /* Display which one we're actually resetting for debug. */ + DEBUG(printk("qla2xxx_eh_host_reset:Resetting scsi(%ld).\n", + ha->host_no)); + +#if STOP_ON_RESET + qla_printk(KERN_INFO, ha, "Host Reset... Command=\n"); + qla2x00_print_scsi_cmd(cmd); + qla2x00_panic("qla2xxx_eh_host_reset", ha->host); +#endif + + /* + * Now issue reset. + */ + qla_printk(KERN_INFO, ha, + "scsi(%ld:%d:%d:%d): ADAPTER RESET issued.\n", ha->host_no, + cmd->device->channel, cmd->device->id, cmd->device->lun); + + spin_unlock_irq(ha->host->host_lock); + + /* Blocking call-Does context switching if abort isp is active etc*/ + if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS) + goto board_disabled; + + /* + * Fixme-may be dpc thread is active and processing + * loop_resync,so wait a while for it to + * be completed and then issue big hammer.Otherwise + * it may cause I/O failure as big hammer marks the + * devices as lost kicking of the port_down_timer + * while dpc is stuck for the mailbox to complete. + */ + /* Blocking call-Does context switching if loop is Not Ready */ + qla2x00_wait_for_loop_ready(ha); + set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); + if (qla2x00_abort_isp(ha)) { + clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); + /* failed. schedule dpc to try */ + set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); + + if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS) + goto board_disabled; + } + + clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); + + spin_lock_irq(ha->host->host_lock); + if (rval == FAILED) + goto out; + + /* Waiting for our command in done_queue to be returned to OS.*/ + if (qla2x00_eh_wait_for_pending_commands(ha)) + rval = FAILED; + + out: + qla_printk(KERN_INFO, ha, "%s: reset %s\n", __func__, + (rval == FAILED) ? "failed" : "succeded"); + + LEAVE("qla2xxx_eh_host_reset"); + return rval; + + board_disabled: + spin_lock_irq(ha->host->host_lock); + + qla_printk(KERN_INFO, ha, "%s: failed:board disabled\n", __func__); + return FAILED; +} + + +/* +* qla2x00_loop_reset +* Issue loop reset. +* +* Input: +* ha = adapter block pointer. +* +* Returns: +* 0 = success +*/ +static uint8_t +qla2x00_loop_reset(scsi_qla_host_t *ha) +{ + uint8_t status = QLA_SUCCESS; + uint16_t t; + os_tgt_t *tq; + + ENTER(__func__); + + if (ha->flags.enable_lip_reset) { + status = qla2x00_lip_reset(ha); + } + + if (status == QLA_SUCCESS && ha->flags.enable_target_reset) { + for (t = 0; t < MAX_FIBRE_DEVICES; t++) { + if ((tq = TGT_Q(ha, t)) == NULL) + continue; + + if (tq->fcport == NULL) + continue; + + status = qla2x00_target_reset(ha, 0, t); + if (status != QLA_SUCCESS) { + break; + } + } + } + + if (status == QLA_SUCCESS && + ((!ha->flags.enable_target_reset && + !ha->flags.enable_lip_reset) || + ha->flags.enable_lip_full_login)) { + + status = qla2x00_full_login_lip(ha); + } + + /* Issue marker command only when we are going to start the I/O */ + ha->marker_needed = 1; + + if (status) { + /* Empty */ + DEBUG2_3(printk("%s(%ld): **** FAILED ****\n", + __func__, + ha->host_no);) + } else { + /* Empty */ + DEBUG3(printk("%s(%ld): exiting normally.\n", + __func__, + ha->host_no);) + } + + LEAVE(__func__); + + return(status); +} + +/* + * qla2x00_device_reset + * Issue bus device reset message to the target. + * + * Input: + * ha = adapter block pointer. + * t = SCSI ID. + * TARGET_QUEUE_LOCK must be released. + * ADAPTER_STATE_LOCK must be released. + * + * Context: + * Kernel context. + */ +static int +qla2x00_device_reset(scsi_qla_host_t *ha, fc_port_t *reset_fcport) +{ + /* Abort Target command will clear Reservation */ + return qla2x00_abort_target(reset_fcport); +} + +/************************************************************************** +* qla2x00_slave_configure +* +* Description: +**************************************************************************/ +int +qla2xxx_slave_configure(struct scsi_device *sdev) +{ + scsi_qla_host_t *ha = to_qla_host(sdev->host); + int queue_depth; + + if (IS_QLA2100(ha) || IS_QLA2200(ha)) + queue_depth = 16; + else + queue_depth = 32; + + if (sdev->tagged_supported) { +#if defined(MODULE) + if (!(ql2xmaxqdepth == 0 || ql2xmaxqdepth > 256)) + queue_depth = ql2xmaxqdepth; +#endif + ql2xmaxqdepth = queue_depth; + + scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth); + + qla_printk(KERN_INFO, ha, + "scsi(%d:%d:%d:%d): Enabled tagged queuing, queue " + "depth %d.\n", + sdev->host->host_no, sdev->channel, sdev->id, sdev->lun, + sdev->queue_depth); + } else { + scsi_adjust_queue_depth(sdev, 0 /* TCQ off */, + sdev->host->hostt->cmd_per_lun /* 3 */); + } + + return (0); +} + +/** + * qla2x00_config_dma_addressing() - Configure OS DMA addressing method. + * @ha: HA context + * + * At exit, the @ha's flags.enable_64bit_addressing set to indicated + * supported addressing method. + */ +static void +qla2x00_config_dma_addressing(scsi_qla_host_t *ha) +{ + /* Assume 32bit DMA address */ + ha->flags.enable_64bit_addressing = 0; + ha->calc_request_entries = qla2x00_calc_iocbs_32; + ha->build_scsi_iocbs = qla2x00_build_scsi_iocbs_32; + + /* + * Given the two variants pci_set_dma_mask(), allow the compiler to + * assist in setting the proper dma mask. + */ + if (sizeof(dma_addr_t) > 4) { + /* Update our PCI device dma_mask for full 64 bits */ + if (pci_set_dma_mask(ha->pdev, 0xffffffffffffffffULL) == 0) { + ha->flags.enable_64bit_addressing = 1; + ha->calc_request_entries = qla2x00_calc_iocbs_64; + ha->build_scsi_iocbs = qla2x00_build_scsi_iocbs_64; + + if (pci_set_consistent_dma_mask(ha->pdev, + 0xffffffffffffffffULL)) { + qla_printk(KERN_DEBUG, ha, + "Failed to set 64 bit PCI consistent mask; " + "using 32 bit.\n"); + pci_set_consistent_dma_mask(ha->pdev, + 0xffffffffULL); + } + } else { + qla_printk(KERN_DEBUG, ha, + "Failed to set 64 bit PCI DMA mask, falling back " + "to 32 bit MASK.\n"); + pci_set_dma_mask(ha->pdev, 0xffffffff); + } + } else { + pci_set_dma_mask(ha->pdev, 0xffffffff); + } +} + +static int +qla2x00_iospace_config(scsi_qla_host_t *ha) +{ + unsigned long pio, pio_len, pio_flags; + unsigned long mmio, mmio_len, mmio_flags; + + pio = pci_resource_start(ha->pdev, 0); + pio_len = pci_resource_len(ha->pdev, 0); + pio_flags = pci_resource_flags(ha->pdev, 0); + + mmio = pci_resource_start(ha->pdev, 1); + mmio_len = pci_resource_len(ha->pdev, 1); + mmio_flags = pci_resource_flags(ha->pdev, 1); + +#if MEMORY_MAPPED_IO + if (!(mmio_flags & IORESOURCE_MEM)) { + qla_printk(KERN_ERR, ha, + "region #0 not an MMIO resource (%s), aborting\n", + ha->pdev->slot_name); + goto iospace_error_exit; + } + if (mmio_len < MIN_IOBASE_LEN) { + qla_printk(KERN_ERR, ha, + "Invalid PCI mem region size (%s), aborting\n", + ha->pdev->slot_name); + goto iospace_error_exit; + } +#else + if (!(pio_flags & IORESOURCE_IO)) { + qla_printk(KERN_ERR, ha, + "region #0 not a PIO resource (%s), aborting\n", + ha->pdev->slot_name); + goto iospace_error_exit; + } + if (pio_len < MIN_IOBASE_LEN) { + qla_printk(KERN_ERR, ha, + "Invalid PCI I/O region size (%s), aborting\n", + ha->pdev->slot_name); + goto iospace_error_exit; + } +#endif + + if (pci_request_regions(ha->pdev, ha->brd_info->drv_name)) { + qla_printk(KERN_WARNING, ha, + "Failed to reserve PIO/MMIO regions (%s)\n", + ha->pdev->slot_name); + + goto iospace_error_exit; + } + + /* Assume PIO */ + ha->iobase = (device_reg_t *) pio; + ha->pio_address = pio; + ha->pio_length = pio_len; + ha->mmio_address = NULL; +#if MEMORY_MAPPED_IO + ha->mmio_address = ioremap(mmio, MIN_IOBASE_LEN); + if (!ha->mmio_address) { + qla_printk(KERN_ERR, ha, + "cannot remap MMIO (%s), aborting\n", ha->pdev->slot_name); + + goto iospace_error_exit; + } + ha->iobase = (device_reg_t *) ha->mmio_address; + ha->mmio_length = mmio_len; +#endif + + return (0); + +iospace_error_exit: + return (-ENOMEM); +} + +/* + * PCI driver interface + */ +int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info) +{ + int ret; + device_reg_t *reg; + struct Scsi_Host *host; + scsi_qla_host_t *ha; + unsigned long flags = 0; + unsigned long wait_switch = 0; + char pci_info[20]; + char fw_str[30]; + + if (pci_enable_device(pdev)) + return -1; + + host = scsi_host_alloc(&qla2x00_driver_template, + sizeof(scsi_qla_host_t)); + if (host == NULL) { + printk(KERN_WARNING + "qla2xxx: Couldn't allocate host from scsi layer!\n"); + return -1; + } + + /* Clear our data area */ + ha = (scsi_qla_host_t *)host->hostdata; + memset(ha, 0, sizeof(scsi_qla_host_t)); + + ha->pdev = pdev; + ha->host = host; + ha->host_no = host->host_no; + ha->brd_info = brd_info; + sprintf(ha->host_str, "%s_%ld", ha->brd_info->drv_name, ha->host_no); + + /* Configure PCI I/O space */ + ret = qla2x00_iospace_config(ha); + if (ret != 0) { + goto probe_failed; + } + + /* Sanitize the information from PCI BIOS. */ + host->irq = pdev->irq; + + qla_printk(KERN_INFO, ha, + "Found an %s, irq %d, iobase 0x%p\n", ha->brd_info->isp_name, + host->irq, ha->iobase); + + spin_lock_init(&ha->hardware_lock); + + /* 4.23 Initialize /proc/scsi/qla2x00 counters */ + ha->actthreads = 0; + ha->qthreads = 0; + ha->total_isr_cnt = 0; + ha->total_isp_aborts = 0; + ha->total_lip_cnt = 0; + ha->total_dev_errs = 0; + ha->total_ios = 0; + ha->total_bytes = 0; + + ha->prev_topology = 0; + ha->ports = MAX_BUSES; + + if (IS_QLA2100(ha)) { + ha->max_targets = MAX_TARGETS_2100; + ha->mbx_count = MAILBOX_REGISTER_COUNT_2100; + ha->response_q_length = RESPONSE_ENTRY_CNT_2100; + ha->last_loop_id = SNS_LAST_LOOP_ID_2100; + } else if (IS_QLA2200(ha)) { + ha->max_targets = MAX_TARGETS_2200; + ha->mbx_count = MAILBOX_REGISTER_COUNT; + ha->response_q_length = RESPONSE_ENTRY_CNT_2100; + ha->last_loop_id = SNS_LAST_LOOP_ID_2100; + } else /*if (IS_QLA2300(ha))*/ { + ha->max_targets = MAX_TARGETS_2200; + ha->mbx_count = MAILBOX_REGISTER_COUNT; + ha->response_q_length = RESPONSE_ENTRY_CNT_2300; + ha->last_loop_id = SNS_LAST_LOOP_ID_2300; + } + + /* load the F/W, read paramaters, and init the H/W */ + ha->instance = num_hosts; + + init_MUTEX_LOCKED(&ha->mbx_intr_sem); + + INIT_LIST_HEAD(&ha->list); + INIT_LIST_HEAD(&ha->fcports); + INIT_LIST_HEAD(&ha->rscn_fcports); + INIT_LIST_HEAD(&ha->done_queue); + INIT_LIST_HEAD(&ha->retry_queue); + INIT_LIST_HEAD(&ha->scsi_retry_queue); + INIT_LIST_HEAD(&ha->failover_queue); + INIT_LIST_HEAD(&ha->pending_queue); + + /* + * These locks are used to prevent more than one CPU + * from modifying the queue at the same time. The + * higher level "io_request_lock" will reduce most + * contention for these locks. + */ + spin_lock_init(&ha->mbx_bits_lock); + spin_lock_init(&ha->mbx_reg_lock); + spin_lock_init(&ha->mbx_q_lock); + spin_lock_init(&ha->list_lock); + + init_completion(&ha->dpc_inited); + init_completion(&ha->dpc_exited); + + qla2x00_config_dma_addressing(ha); + if (qla2x00_mem_alloc(ha)) { + qla_printk(KERN_WARNING, ha, + "[ERROR] Failed to allocate memory for adapter\n"); + + goto probe_failed; + } + + if (qla2x00_initialize_adapter(ha) && + !(ha->device_flags & DFLG_NO_CABLE)) { + + qla_printk(KERN_WARNING, ha, + "Failed to initialize adapter\n"); + + DEBUG2(printk("scsi(%ld): Failed to initialize adapter - " + "Adapter flags %x.\n", + ha->host_no, ha->device_flags)); + + goto probe_failed; + } + + /* + * Startup the kernel thread for this host adapter + */ + ha->dpc_should_die = 0; + ha->dpc_pid = kernel_thread(qla2x00_do_dpc, ha, 0); + if (ha->dpc_pid < 0) { + qla_printk(KERN_WARNING, ha, + "Unable to start DPC thread!\n"); + + goto probe_failed; + } + wait_for_completion(&ha->dpc_inited); + + host->this_id = 255; + host->cmd_per_lun = 3; + host->max_cmd_len = MAX_CMDSZ; + host->max_channel = ha->ports - 1; + host->max_lun = ha->max_luns; + host->unique_id = ha->instance; + host->max_id = ha->max_targets; + + if (request_irq(host->irq, qla2x00_intr_handler, SA_INTERRUPT|SA_SHIRQ, + ha->brd_info->drv_name, ha)) { + qla_printk(KERN_WARNING, ha, + "Failed to reserve interrupt %d already in use.\n", + host->irq); + goto probe_failed; + } + + /* Initialized the timer */ + qla2x00_start_timer(ha, qla2x00_timer, WATCH_INTERVAL); + + DEBUG2(printk("DEBUG: detect hba %ld at address = %p\n", + ha->host_no, ha)); + + reg = ha->iobase; + + /* Disable ISP interrupts. */ + qla2x00_disable_intrs(ha); + + /* Ensure mailbox registers are free. */ + spin_lock_irqsave(&ha->hardware_lock, flags); + WRT_REG_WORD(®->semaphore, 0); + WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); + WRT_REG_WORD(®->hccr, HCCR_CLR_HOST_INT); + + /* Enable proper parity */ + if (IS_QLA23XX(ha)) { + if (IS_QLA2312(ha) || IS_QLA2322(ha)) + /* SRAM, Instruction RAM and GP RAM parity */ + WRT_REG_WORD(®->hccr, (HCCR_ENABLE_PARITY + 0x7)); + else + /* SRAM parity */ + WRT_REG_WORD(®->hccr, (HCCR_ENABLE_PARITY + 0x1)); + } + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + /* + * if failover is enabled read the user configuration + */ + if (qla2x00_failover_enabled(ha)) + qla2x00_cfg_init(ha); + + /* Enable chip interrupts. */ + qla2x00_enable_intrs(ha); + + /* Insert new entry into the list of adapters */ + write_lock(&qla_hostlist_lock); + list_add_tail(&ha->list, &qla_hostlist); + write_unlock(&qla_hostlist_lock); + + /* v2.19.5b6 */ + /* + * Wait around max loop_reset_delay secs for the devices to come + * on-line. We don't want Linux scanning before we are ready. + * + */ + for (wait_switch = jiffies + (ha->loop_reset_delay * HZ); + time_before(jiffies,wait_switch) && + !(ha->device_flags & (DFLG_NO_CABLE | DFLG_FABRIC_DEVICES)) + && (ha->device_flags & SWITCH_FOUND) ;) { + + qla2x00_check_fabric_devices(ha); + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(5); + } + + pci_set_drvdata(pdev, ha); + ha->flags.init_done = 1; + num_hosts++; + + /* List the target we have found */ + if (displayConfig) { + if (qla2x00_failover_enabled(ha)) + qla2x00_cfg_display_devices(); + else + qla2x00_display_fc_names(ha); + } + + if (scsi_add_host(host, &pdev->dev)) + goto probe_failed; + + sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_fw_dump_attr); + sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_nvram_attr); + + qla_printk(KERN_INFO, ha, "\n" + " QLogic ISP2xxx PCI/PCI-X Fibre Channel HBA Driver: %s\n" + " QLogic %s - %s\n" + " %s: %s @ %s hdma%c, host#=%ld, fw=%s\n", qla2x00_version_str, + ha->model_number, ha->model_desc ? ha->model_desc: "", + ha->brd_info->isp_name, qla2x00_get_pci_info_str(ha, pci_info), + pci_name(ha->pdev), ha->flags.enable_64bit_addressing ? '+': '-', + ha->host_no, qla2x00_get_fw_version_str(ha, fw_str)); + + if (ql2xdoinitscan) + scsi_scan_host(host); + + return 0; + +probe_failed: + qla2x00_free_device(ha); + + scsi_host_put(host); + + return -1; +} +EXPORT_SYMBOL_GPL(qla2x00_probe_one); + +void qla2x00_remove_one(struct pci_dev *pdev) +{ + scsi_qla_host_t *ha; + + ha = pci_get_drvdata(pdev); + + write_lock(&qla_hostlist_lock); + list_del(&ha->list); + write_unlock(&qla_hostlist_lock); + + sysfs_remove_bin_file(&ha->host->shost_gendev.kobj, + &sysfs_fw_dump_attr); + sysfs_remove_bin_file(&ha->host->shost_gendev.kobj, &sysfs_nvram_attr); + + scsi_remove_host(ha->host); + + qla2x00_free_device(ha); + + scsi_host_put(ha->host); + + pci_set_drvdata(pdev, NULL); +} +EXPORT_SYMBOL_GPL(qla2x00_remove_one); + +static void +qla2x00_free_device(scsi_qla_host_t *ha) +{ + int ret; + + /* Abort any outstanding IO descriptors. */ + if (IS_QLA23XX(ha)) + qla2x00_cancel_io_descriptors(ha); + + /* turn-off interrupts on the card */ + if (ha->interrupts_on) + qla2x00_disable_intrs(ha); + + /* Disable timer */ + if (ha->timer_active) + qla2x00_stop_timer(ha); + + /* Kill the kernel thread for this host */ + if (ha->dpc_pid >= 0) { + ha->dpc_should_die = 1; + wmb(); + ret = kill_proc(ha->dpc_pid, SIGHUP, 1); + if (ret) { + qla_printk(KERN_ERR, ha, + "Unable to signal DPC thread -- (%d)\n", ret); + + /* TODO: SOMETHING MORE??? */ + } else { + wait_for_completion(&ha->dpc_exited); + } + } + + qla2x00_mem_free(ha); + + if (qla2x00_failover_enabled(ha)) + qla2x00_cfg_mem_free(ha); + + ha->flags.online = FALSE; + + /* Detach interrupts */ + if (ha->pdev->irq) + free_irq(ha->pdev->irq, ha); + + /* release io space registers */ + pci_release_regions(ha->pdev); + +#if MEMORY_MAPPED_IO + if (ha->mmio_address) + iounmap(ha->mmio_address); +#endif +} + + +/* + * The following support functions are adopted to handle + * the re-entrant qla2x00_proc_info correctly. + */ +static void +copy_mem_info(struct info_str *info, char *data, int len) +{ + if (info->pos + len > info->offset + info->length) + len = info->offset + info->length - info->pos; + + if (info->pos + len < info->offset) { + info->pos += len; + return; + } + + if (info->pos < info->offset) { + off_t partial; + + partial = info->offset - info->pos; + data += partial; + info->pos += partial; + len -= partial; + } + + if (len > 0) { + memcpy(info->buffer, data, len); + info->pos += len; + info->buffer += len; + } +} + +static int +copy_info(struct info_str *info, char *fmt, ...) +{ + va_list args; + char buf[256]; + int len; + + va_start(args, fmt); + len = vsprintf(buf, fmt, args); + va_end(args); + + copy_mem_info(info, buf, len); + + return (len); +} + +/************************************************************************* +* qla2x00_proc_info +* +* Description: +* Return information to handle /proc support for the driver. +* +* inout : decides the direction of the dataflow and the meaning of the +* variables +* buffer: If inout==FALSE data is being written to it else read from it +* (ptr to a page buffer) +* *start: If inout==FALSE start of the valid data in the buffer +* offset: If inout==FALSE starting offset from the beginning of all +* possible data to return. +* length: If inout==FALSE max number of bytes to be written into the buffer +* else number of bytes in "buffer" +* Returns: +* < 0: error. errno value. +* >= 0: sizeof data returned. +*************************************************************************/ +int +qla2x00_proc_info(struct Scsi_Host *shost, char *buffer, + char **start, off_t offset, int length, int inout) +{ + struct info_str info; + int i; + int retval = -EINVAL; + os_lun_t *up; + os_tgt_t *tq; + unsigned int t, l; + uint32_t tmp_sn; + unsigned long *flags; + uint8_t *loop_state; + int found; + scsi_qla_host_t *ha; + char fw_info[30]; + + DEBUG3(printk(KERN_INFO + "Entering proc_info buff_in=%p, offset=0x%lx, length=0x%x\n", + buffer, offset, length);) + + ha = NULL; + + /* Find the host that was specified */ + found = 0; + read_lock(&qla_hostlist_lock); + list_for_each_entry(ha, &qla_hostlist, list) { + if (ha->host == shost) { + found++; + break; + } + } + read_unlock(&qla_hostlist_lock); + + /* if host wasn't found then exit */ + if (!found) { + DEBUG2_3(printk(KERN_WARNING + "%s: Can't find adapter for host %p\n", + __func__, shost);) + + return (retval); + } + + if (inout == TRUE) { + /* Has data been written to the file? */ + DEBUG3(printk( + "%s: has data been written to the file. \n", + __func__);) + + return (qla2x00_set_info(buffer, length, shost)); + } + + if (start) { + *start = buffer; + } + + info.buffer = buffer; + info.length = length; + info.offset = offset; + info.pos = 0; + + /* start building the print buffer */ + copy_info(&info, + "QLogic PCI to Fibre Channel Host Adapter for %s:\n" + " Firmware version %s, ", + ha->model_number, qla2x00_get_fw_version_str(ha, fw_info)); + + copy_info(&info, "Driver version %s\n", qla2x00_version_str); + + copy_info(&info, "Entry address = %p\n", qla2x00_set_info); + + tmp_sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | + ha->serial1; + copy_info(&info, "ISP: %s, Serial# %c%05d\n", + ha->brd_info->isp_name, ('A' + tmp_sn/100000), (tmp_sn%100000)); + + copy_info(&info, + "Request Queue = 0x%p, Response Queue = 0x%p\n", + (void *)ha->request_dma, (void *)ha->response_dma); + + copy_info(&info, + "Request Queue count = %ld, Response Queue count = %ld\n", + (long)REQUEST_ENTRY_CNT, (long)ha->response_q_length); + + copy_info(&info, + "Total number of active commands = %ld\n", + ha->actthreads); + + copy_info(&info, + "Total number of interrupts = %ld\n", + (long)ha->total_isr_cnt); + + copy_info(&info, + " Device queue depth = 0x%x\n", + (ql2xmaxqdepth == 0) ? 16 : ql2xmaxqdepth); + + copy_info(&info, + "Number of free request entries = %d\n", ha->req_q_cnt); + + copy_info(&info, + "Number of mailbox timeouts = %ld\n", ha->total_mbx_timeout); + + copy_info(&info, + "Number of ISP aborts = %ld\n", ha->total_isp_aborts); + + copy_info(&info, + "Number of loop resyncs = %ld\n", ha->total_loop_resync); + + copy_info(&info, + "Number of retries for empty slots = %ld\n", + qla2x00_stats.outarray_full); + + copy_info(&info, + "Number of reqs in pending_q= %ld, retry_q= %d, " + "done_q= %ld, scsi_retry_q= %d\n", + ha->qthreads, ha->retry_q_cnt, + ha->done_q_cnt, ha->scsi_retry_q_cnt); + + if (qla2x00_failover_enabled(ha)) { + copy_info(&info, + "Number of reqs in failover_q= %d\n", + ha->failover_cnt); + } + + flags = (unsigned long *) &ha->flags; + + if (atomic_read(&ha->loop_state) == LOOP_DOWN) { + loop_state = "DOWN"; + } else if (atomic_read(&ha->loop_state) == LOOP_UP) { + loop_state = "UP"; + } else if (atomic_read(&ha->loop_state) == LOOP_READY) { + loop_state = "READY"; + } else if (atomic_read(&ha->loop_state) == LOOP_TIMEOUT) { + loop_state = "TIMEOUT"; + } else if (atomic_read(&ha->loop_state) == LOOP_UPDATE) { + loop_state = "UPDATE"; + } else { + loop_state = "UNKNOWN"; + } + + copy_info(&info, + "Host adapter:loop state = <%s>, flags = 0x%lx\n", + loop_state , *flags); + + copy_info(&info, "Dpc flags = 0x%lx\n", ha->dpc_flags); + + copy_info(&info, "MBX flags = 0x%x\n", ha->mbx_flags); + + copy_info(&info, "Link down Timeout = %3.3d\n", + ha->link_down_timeout); + + copy_info(&info, "Port down retry = %3.3d\n", + ha->port_down_retry_count); + + copy_info(&info, "Login retry count = %3.3d\n", + ha->login_retry_count); + + copy_info(&info, + "Commands retried with dropped frame(s) = %d\n", + ha->dropped_frame_error_cnt); + + copy_info(&info, + "Info -- pci=%x xchgs=0x%x iocbs=0x%x\n", ha->pci_attr, + ha->xchg_buf_cnt, ha->iocb_buf_cnt); + + copy_info(&info, "\n"); + + /* 2.25 node/port display to proc */ + /* Display the node name for adapter */ + copy_info(&info, "\nSCSI Device Information:\n"); + copy_info(&info, + "scsi-qla%d-adapter-node=" + "%02x%02x%02x%02x%02x%02x%02x%02x;\n", + (int)ha->instance, + ha->init_cb->node_name[0], + ha->init_cb->node_name[1], + ha->init_cb->node_name[2], + ha->init_cb->node_name[3], + ha->init_cb->node_name[4], + ha->init_cb->node_name[5], + ha->init_cb->node_name[6], + ha->init_cb->node_name[7]); + + /* display the port name for adapter */ + copy_info(&info, + "scsi-qla%d-adapter-port=" + "%02x%02x%02x%02x%02x%02x%02x%02x;\n", + (int)ha->instance, + ha->init_cb->port_name[0], + ha->init_cb->port_name[1], + ha->init_cb->port_name[2], + ha->init_cb->port_name[3], + ha->init_cb->port_name[4], + ha->init_cb->port_name[5], + ha->init_cb->port_name[6], + ha->init_cb->port_name[7]); + + /* Print out device port names */ + for (i = 0; i < MAX_TARGETS; i++) { + if ((tq = TGT_Q(ha, i)) == NULL) + continue; + + if (qla2x00_failover_enabled(ha)) { + copy_info(&info, + "scsi-qla%d-port-%d=" + "%02x%02x%02x%02x%02x%02x%02x%02x:" + "%02x%02x%02x%02x%02x%02x%02x%02x;\n", + (int)ha->instance, i, + tq->node_name[0], tq->node_name[1], + tq->node_name[2], tq->node_name[3], + tq->node_name[4], tq->node_name[5], + tq->node_name[6], tq->node_name[7], + tq->port_name[0], tq->port_name[1], + tq->port_name[2], tq->port_name[3], + tq->port_name[4], tq->port_name[5], + tq->port_name[6], tq->port_name[7]); + } else { + copy_info(&info, + "scsi-qla%d-target-%d=" + "%02x%02x%02x%02x%02x%02x%02x%02x;\n", + (int)ha->instance, i, + tq->port_name[0], tq->port_name[1], + tq->port_name[2], tq->port_name[3], + tq->port_name[4], tq->port_name[5], + tq->port_name[6], tq->port_name[7]); + } + + } /* 2.25 node/port display to proc */ + + copy_info(&info, "\nSCSI LUN Information:\n"); + copy_info(&info, + "(Id:Lun) * - indicates lun is not registered with the OS.\n"); + + /* scan for all equipment stats */ + for (t = 0; t < MAX_FIBRE_DEVICES; t++) { + /* scan all luns */ + for (l = 0; l < ha->max_luns; l++) { + up = (os_lun_t *) GET_LU_Q(ha, t, l); + + if (up == NULL) { + continue; + } + if (up->fclun == NULL) { + continue; + } + + copy_info(&info, + "(%2d:%2d): Total reqs %ld,", + t,l,up->io_cnt); + + copy_info(&info, + " Pending reqs %ld,", + up->out_cnt); + + if (up->io_cnt < 4) { + copy_info(&info, + " flags 0x%x*,", + (int)up->q_flag); + } else { + copy_info(&info, + " flags 0x%x,", + (int)up->q_flag); + } + + copy_info(&info, + " %ld:%d:%02x %02x", + up->fclun->fcport->ha->instance, + up->fclun->fcport->cur_path, + up->fclun->fcport->loop_id, + up->fclun->device_type); + + copy_info(&info, "\n"); + + if (info.pos >= info.offset + info.length) { + /* No need to continue */ + goto profile_stop; + } + } + + if (info.pos >= info.offset + info.length) { + /* No need to continue */ + break; + } + } + +profile_stop: + + retval = info.pos > info.offset ? info.pos - info.offset : 0; + + DEBUG3(printk(KERN_INFO + "Exiting proc_info: info.pos=%d, offset=0x%lx, " + "length=0x%x\n", info.pos, offset, length);) + + return (retval); +} + +/* +* qla2x00_display_fc_names +* This routine will the node names of the different devices found +* after port inquiry. +* +* Input: +* cmd = SCSI command structure +* +* Returns: +* None. +*/ +static void +qla2x00_display_fc_names(scsi_qla_host_t *ha) +{ + uint16_t tgt; + os_tgt_t *tq; + + /* Display the node name for adapter */ + qla_printk(KERN_INFO, ha, + "scsi-qla%d-adapter-node=%02x%02x%02x%02x%02x%02x%02x%02x\\;\n", + (int)ha->instance, + ha->init_cb->node_name[0], + ha->init_cb->node_name[1], + ha->init_cb->node_name[2], + ha->init_cb->node_name[3], + ha->init_cb->node_name[4], + ha->init_cb->node_name[5], + ha->init_cb->node_name[6], + ha->init_cb->node_name[7]); + + /* display the port name for adapter */ + qla_printk(KERN_INFO, ha, + "scsi-qla%d-adapter-port=%02x%02x%02x%02x%02x%02x%02x%02x\\;\n", + (int)ha->instance, + ha->init_cb->port_name[0], + ha->init_cb->port_name[1], + ha->init_cb->port_name[2], + ha->init_cb->port_name[3], + ha->init_cb->port_name[4], + ha->init_cb->port_name[5], + ha->init_cb->port_name[6], + ha->init_cb->port_name[7]); + + /* Print out device port names */ + for (tgt = 0; tgt < MAX_TARGETS; tgt++) { + if ((tq = ha->otgt[tgt]) == NULL) + continue; + + if (tq->fcport == NULL) + continue; + + switch (ha->binding_type) { + case BIND_BY_PORT_NAME: + qla_printk(KERN_INFO, ha, + "scsi-qla%d-tgt-%d-di-0-port=" + "%02x%02x%02x%02x%02x%02x%02x%02x\\;\n", + (int)ha->instance, + tgt, + tq->port_name[0], + tq->port_name[1], + tq->port_name[2], + tq->port_name[3], + tq->port_name[4], + tq->port_name[5], + tq->port_name[6], + tq->port_name[7]); + + break; + + case BIND_BY_PORT_ID: + qla_printk(KERN_INFO, ha, + "scsi-qla%d-tgt-%d-di-0-pid=" + "%02x%02x%02x\\;\n", + (int)ha->instance, + tgt, + tq->d_id.b.domain, + tq->d_id.b.area, + tq->d_id.b.al_pa); + break; + } + +#if VSA + qla_printk(KERN_INFO, ha, + "scsi-qla%d-target-%d-vsa=01;\n", (int)ha->instance, tgt); +#endif + } +} + +/* + * qla2x00_suspend_lun + * Suspend lun and start port down timer + * + * Input: + * ha = visable adapter block pointer. + * lq = lun queue + * cp = Scsi command pointer + * time = time in seconds + * count = number of times to let time expire + * delay_lun = non-zero, if lun should be delayed rather than suspended + * + * Return: + * QLA_SUCCESS -- suspended lun + * QLA_FUNCTION_FAILED -- Didn't suspend lun + * + * Context: + * Interrupt context. + */ +int +__qla2x00_suspend_lun(scsi_qla_host_t *ha, + os_lun_t *lq, int time, int count, int delay_lun) +{ + int rval; + srb_t *sp; + struct list_head *list, *temp; + unsigned long flags; + + rval = QLA_SUCCESS; + + /* if the lun_q is already suspended then don't do it again */ + if (lq->q_state == LUN_STATE_READY ||lq->q_state == LUN_STATE_RUN) { + + spin_lock_irqsave(&lq->q_lock, flags); + if (lq->q_state == LUN_STATE_READY) { + lq->q_max = count; + lq->q_count = 0; + } + /* Set the suspend time usually 6 secs */ + atomic_set(&lq->q_timer, time); + + /* now suspend the lun */ + lq->q_state = LUN_STATE_WAIT; + + if (delay_lun) { + set_bit(LUN_EXEC_DELAYED, &lq->q_flag); + DEBUG(printk(KERN_INFO + "scsi(%ld): Delay lun execution for %d secs, " + "count=%d, max count=%d, state=%d\n", + ha->host_no, + time, + lq->q_count, lq->q_max, lq->q_state)); + } else { + DEBUG(printk(KERN_INFO + "scsi(%ld): Suspend lun for %d secs, count=%d, " + "max count=%d, state=%d\n", + ha->host_no, + time, + lq->q_count, lq->q_max, lq->q_state)); + } + spin_unlock_irqrestore(&lq->q_lock, flags); + + /* + * Remove all pending commands from request queue and put them + * in the scsi_retry queue. + */ + spin_lock_irqsave(&ha->list_lock, flags); + list_for_each_safe(list, temp, &ha->pending_queue) { + sp = list_entry(list, srb_t, list); + if (sp->lun_queue != lq) + continue; + + __del_from_pending_queue(ha, sp); + + if (sp->cmd->allowed < count) + sp->cmd->allowed = count; + __add_to_scsi_retry_queue(ha, sp); + + } /* list_for_each_safe */ + spin_unlock_irqrestore(&ha->list_lock, flags); + rval = QLA_SUCCESS; + } else { + rval = QLA_FUNCTION_FAILED; + } + + return (rval); +} + +/* + * qla2x00_mark_device_lost Updates fcport state when device goes offline. + * + * Input: ha = adapter block pointer. fcport = port structure pointer. + * + * Return: None. + * + * Context: + */ +void qla2x00_mark_device_lost(scsi_qla_host_t *ha, fc_port_t *fcport, + int do_login) +{ + /* + * We may need to retry the login, so don't change the state of the + * port but do the retries. + */ + if (atomic_read(&fcport->state) != FCS_DEVICE_DEAD) + atomic_set(&fcport->state, FCS_DEVICE_LOST); + + if (!do_login) + return; + + if (fcport->login_retry == 0) { + fcport->login_retry = ha->login_retry_count; + set_bit(RELOGIN_NEEDED, &ha->dpc_flags); + + DEBUG(printk("scsi(%ld): Port login retry: " + "%02x%02x%02x%02x%02x%02x%02x%02x, " + "id = 0x%04x retry cnt=%d\n", + ha->host_no, + fcport->port_name[0], + fcport->port_name[1], + fcport->port_name[2], + fcport->port_name[3], + fcport->port_name[4], + fcport->port_name[5], + fcport->port_name[6], + fcport->port_name[7], + fcport->loop_id, + fcport->login_retry)); + } +} + +/* + * qla2x00_mark_all_devices_lost + * Updates fcport state when device goes offline. + * + * Input: + * ha = adapter block pointer. + * fcport = port structure pointer. + * + * Return: + * None. + * + * Context: + */ +void +qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha) +{ + struct list_head *fcpl; + fc_port_t *fcport; + + list_for_each(fcpl, &ha->fcports) { + fcport = list_entry(fcpl, fc_port_t, list); + + /* + * No point in marking the device as lost, if the device is + * already DEAD. + */ + if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD) + continue; + + atomic_set(&fcport->state, FCS_DEVICE_LOST); + } +} + +/* +* qla2x00_mem_alloc +* Allocates adapter memory. +* +* Returns: +* 0 = success. +* 1 = failure. +*/ +static uint8_t +qla2x00_mem_alloc(scsi_qla_host_t *ha) +{ + uint8_t status = 1; + uint8_t i; + int retry= 10; + mbx_cmdq_t *ptmp; + mbx_cmdq_t *tmp_q_head; + mbx_cmdq_t *tmp_q_tail; + + ENTER(__func__); + + do { + /* + * This will loop only once if everything goes well, else some + * number of retries will be performed to get around a kernel + * bug where available mem is not allocated until after a + * little delay and a retry. + */ + ha->request_ring = pci_alloc_consistent(ha->pdev, + ((REQUEST_ENTRY_CNT + 1) * (sizeof(request_t))), + &ha->request_dma); + if (ha->request_ring == NULL) { + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - request_ring\n"); + + qla2x00_mem_free(ha); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/10); + + continue; + } + + ha->response_ring = pci_alloc_consistent(ha->pdev, + ((ha->response_q_length + 1) * (sizeof(response_t))), + &ha->response_dma); + if (ha->response_ring == NULL) { + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - response_ring\n"); + + qla2x00_mem_free(ha); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/10); + + continue; + } + + /* get consistent memory allocated for init control block */ + ha->init_cb = pci_alloc_consistent(ha->pdev, + sizeof(init_cb_t), &ha->init_cb_dma); + if (ha->init_cb == NULL) { + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - init_cb\n"); + + qla2x00_mem_free(ha); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/10); + + continue; + } + memset(ha->init_cb, 0, sizeof(init_cb_t)); + + /* Allocate ioctl related memory. */ + if (qla2x00_alloc_ioctl_mem(ha)) { + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - ioctl_mem\n"); + + qla2x00_mem_free(ha); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/10); + + continue; + } + + if (qla2x00_allocate_sp_pool(ha)) { + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - " + "qla2x00_allocate_sp_pool()\n"); + + qla2x00_mem_free(ha); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/10); + + continue; + } + + /* + * Allocate an initial list of mailbox semaphore queue to be + * used for serialization of the mailbox commands. + */ + tmp_q_head = (void *)KMEM_ZALLOC(sizeof(mbx_cmdq_t), 20); + if (tmp_q_head == NULL) { + /* error */ + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - mbx_cmd_q"); + + qla2x00_mem_free(ha); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/10); + + continue; + } + ha->mbx_sem_pool_head = tmp_q_head; + tmp_q_tail = tmp_q_head; + + /* Now try to allocate more */ + for (i = 1; i < MBQ_INIT_LEN; i++) { + ptmp = (void *)KMEM_ZALLOC(sizeof(mbx_cmdq_t), 20 + i); + if (ptmp == NULL) { + /* + * Error. Just exit. If more is needed later + * they will be allocated at that time. + */ + break; + } + tmp_q_tail->pnext = ptmp; + tmp_q_tail = ptmp; + } + ha->mbx_sem_pool_tail = tmp_q_tail; + + /* Get consistent memory allocated for MS IOCB */ + ha->ms_iocb = pci_alloc_consistent(ha->pdev, + sizeof(ms_iocb_entry_t), &ha->ms_iocb_dma); + if (ha->ms_iocb == NULL) { + /* error */ + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - ms_iocb\n"); + + qla2x00_mem_free(ha); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/10); + + continue; + } + memset(ha->ms_iocb, 0, sizeof(ms_iocb_entry_t)); + + /* Get consistent memory allocated for CT SNS commands */ + ha->ct_sns = pci_alloc_consistent(ha->pdev, + sizeof(struct ct_sns_pkt), &ha->ct_sns_dma); + if (ha->ct_sns == NULL) { + /* error */ + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - ct_sns\n"); + + qla2x00_mem_free(ha); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/10); + + continue; + } + memset(ha->ct_sns, 0, sizeof(struct ct_sns_pkt)); + + /* Get consistent memory allocated for Get Port Database cmd */ + ha->iodesc_pd = pci_alloc_consistent(ha->pdev, + PORT_DATABASE_SIZE, &ha->iodesc_pd_dma); + if (ha->iodesc_pd == NULL) { + /* error */ + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - iodesc_pd\n"); + + qla2x00_mem_free(ha); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/10); + + continue; + } + memset(ha->iodesc_pd, 0, PORT_DATABASE_SIZE); + + /* Done all allocations without any error. */ + status = 0; + + } while (retry-- && status != 0); + + if (status) { + printk(KERN_WARNING + "%s(): **** FAILED ****\n", __func__); + } + + LEAVE(__func__); + + return(status); +} + +/* +* qla2x00_mem_free +* Frees all adapter allocated memory. +* +* Input: +* ha = adapter block pointer. +*/ +static void +qla2x00_mem_free(scsi_qla_host_t *ha) +{ + uint32_t t; + struct list_head *fcpl, *fcptemp; + fc_port_t *fcport; + struct list_head *fcll, *fcltemp; + fc_lun_t *fclun; + mbx_cmdq_t *ptmp; + mbx_cmdq_t *tmp_q_head; + unsigned long wtime;/* max wait time if mbx cmd is busy. */ + + ENTER(__func__); + + if (ha == NULL) { + /* error */ + DEBUG2(printk("%s(): ERROR invalid ha pointer.\n", __func__)); + return; + } + + /* Free the target queues */ + for (t = 0; t < MAX_TARGETS; t++) { + qla2x00_tgt_free(ha, t); + } + + /* Make sure all other threads are stopped. */ + wtime = 60 * HZ; + while ((ha->dpc_wait != NULL || ha->mbx_q_head != NULL) && wtime) { + set_current_state(TASK_INTERRUPTIBLE); + wtime = schedule_timeout(wtime); + } + + /* Now free the mbx sem pool */ + tmp_q_head = ha->mbx_sem_pool_head; + while (tmp_q_head != NULL) { + ptmp = tmp_q_head->pnext; + KMEM_FREE(tmp_q_head, sizeof(mbx_cmdq_t)); + tmp_q_head = ptmp; + } + ha->mbx_sem_pool_head = NULL; + + /* free ioctl memory */ + qla2x00_free_ioctl_mem(ha); + + /* free sp pool */ + qla2x00_free_sp_pool(ha); + + if (ha->iodesc_pd) { + pci_free_consistent(ha->pdev, PORT_DATABASE_SIZE, + ha->iodesc_pd, ha->iodesc_pd_dma); + } + if (ha->ct_sns) { + pci_free_consistent(ha->pdev, + sizeof(struct ct_sns_pkt), ha->ct_sns, ha->ct_sns_dma); + } + if (ha->ms_iocb) { + pci_free_consistent(ha->pdev, + sizeof(ms_iocb_entry_t), ha->ms_iocb, ha->ms_iocb_dma); + } + + if (ha->init_cb) { + pci_free_consistent(ha->pdev, + sizeof(init_cb_t), ha->init_cb, ha->init_cb_dma); + } + + if (ha->request_ring) { + pci_free_consistent(ha->pdev, + ((REQUEST_ENTRY_CNT + 1) * (sizeof(request_t))), + ha->request_ring, ha->request_dma); + } + + if (ha->response_ring) { + pci_free_consistent(ha->pdev, + ((ha->response_q_length + 1) * (sizeof(response_t))), + ha->response_ring, ha->response_dma); + } + + ha->iodesc_pd = NULL; + ha->iodesc_pd_dma = 0; + ha->ct_sns = NULL; + ha->ms_iocb = NULL; + + ha->init_cb = NULL; + ha->request_ring = NULL; + ha->request_dma = 0; + ha->response_ring = NULL; + ha->response_dma = 0; + + list_for_each_safe(fcpl, fcptemp, &ha->fcports) { + fcport = list_entry(fcpl, fc_port_t, list); + + /* fc luns */ + list_for_each_safe(fcll, fcltemp, &fcport->fcluns) { + fclun = list_entry(fcll, fc_lun_t, list); + + list_del_init(&fclun->list); + kfree(fclun); + } + + /* fc ports */ + list_del_init(&fcport->list); + kfree(fcport); + } + INIT_LIST_HEAD(&ha->fcports); + + if (ha->fw_dump) { + free_pages((unsigned long)ha->fw_dump, ha->fw_dump_order); + ha->fw_dump = NULL; + } + + if (ha->fw_dump_buffer) { + vfree(ha->fw_dump_buffer); + ha->fw_dump_reading = 0; + ha->fw_dump_buffer = NULL; + } + + LEAVE(__func__); +} + +/* + * qla2x00_allocate_sp_pool + * This routine is called during initialization to allocate + * memory for local srb_t. + * + * Input: + * ha = adapter block pointer. + * + * Context: + * Kernel context. + * + * Note: Sets the ref_count for non Null sp to one. + */ +int +qla2x00_allocate_sp_pool(scsi_qla_host_t *ha) +{ + int rval; + + rval = QLA_SUCCESS; + ha->srb_mempool = mempool_create(SRB_MIN_REQ, mempool_alloc_slab, + mempool_free_slab, srb_cachep); + if (ha->srb_mempool == NULL) { + qla_printk(KERN_INFO, ha, "Unable to allocate SRB mempool.\n"); + rval = QLA_FUNCTION_FAILED; + } + return (rval); +} + +/* + * This routine frees all adapter allocated memory. + * + */ +void +qla2x00_free_sp_pool( scsi_qla_host_t *ha) +{ + if (ha->srb_mempool) { + mempool_destroy(ha->srb_mempool); + ha->srb_mempool = NULL; + } +} + +/************************************************************************** +* qla2x00_do_dpc +* This kernel thread is a task that is schedule by the interrupt handler +* to perform the background processing for interrupts. +* +* Notes: +* This task always run in the context of a kernel thread. It +* is kick-off by the driver's detect code and starts up +* up one per adapter. It immediately goes to sleep and waits for +* some fibre event. When either the interrupt handler or +* the timer routine detects a event it will one of the task +* bits then wake us up. +**************************************************************************/ +static int +qla2x00_do_dpc(void *data) +{ + DECLARE_MUTEX_LOCKED(sem); + scsi_qla_host_t *ha; + struct list_head *fcpl; + fc_port_t *fcport; + os_lun_t *q; + srb_t *sp; + uint8_t status; + unsigned long flags = 0; + struct list_head *list, *templist; + int dead_cnt, online_cnt; + uint16_t next_loopid; + + ha = (scsi_qla_host_t *)data; + + lock_kernel(); + + daemonize("%s_dpc", ha->host_str); + allow_signal(SIGHUP); + + ha->dpc_wait = &sem; + + set_user_nice(current, -20); + + unlock_kernel(); + + complete(&ha->dpc_inited); + + while (1) { + DEBUG3(printk("qla2x00: DPC handler sleeping\n")); + + if (down_interruptible(&sem)) + break; + + if (ha->dpc_should_die) + break; + + if (!list_empty(&ha->done_queue)) + qla2x00_done(ha); + + DEBUG3(printk("qla2x00: DPC handler waking up\n")); + + /* Initialization not yet finished. Don't do anything yet. */ + if (!ha->flags.init_done || ha->dpc_active) + continue; + + DEBUG3(printk("scsi(%ld): DPC handler\n", ha->host_no)); + + /* spin_lock_irqsave(&io_request_lock, ha->cpu_flags);*/ + ha->dpc_active = 1; + + /* Determine what action is necessary */ + + /* Process commands in retry queue */ + if (test_and_clear_bit(PORT_RESTART_NEEDED, &ha->dpc_flags)) { + DEBUG(printk("scsi(%ld): DPC checking retry_q. " + "total=%d\n", + ha->host_no, ha->retry_q_cnt)); + + spin_lock_irqsave(&ha->list_lock, flags); + dead_cnt = online_cnt = 0; + list_for_each_safe(list, templist, &ha->retry_queue) { + sp = list_entry(list, srb_t, list); + q = sp->lun_queue; + DEBUG3(printk("scsi(%ld): pid=%ld sp=%p, " + "spflags=0x%x, q_flag= 0x%lx\n", + ha->host_no, sp->cmd->serial_number, sp, + sp->flags, q->q_flag)); + + if (q == NULL) + continue; + fcport = q->fclun->fcport; + + if (atomic_read(&fcport->state) == + FCS_DEVICE_DEAD || + atomic_read(&ha->loop_state) == LOOP_DEAD) { + + __del_from_retry_queue(ha, sp); + sp->cmd->result = DID_NO_CONNECT << 16; + sp->cmd->host_scribble = + (unsigned char *) NULL; + __add_to_done_queue(ha, sp); + dead_cnt++; + } else if (atomic_read(&fcport->state) != + FCS_DEVICE_LOST) { + + __del_from_retry_queue(ha, sp); + sp->cmd->result = DID_BUS_BUSY << 16; + sp->cmd->host_scribble = + (unsigned char *) NULL; + __add_to_done_queue(ha, sp); + online_cnt++; + } + } /* list_for_each_safe() */ + spin_unlock_irqrestore(&ha->list_lock, flags); + + DEBUG(printk("scsi(%ld): done processing retry queue " + "- dead=%d, online=%d\n ", + ha->host_no, dead_cnt, online_cnt)); + } + + /* Process commands in scsi retry queue */ + if (test_and_clear_bit(SCSI_RESTART_NEEDED, &ha->dpc_flags)) { + /* + * Any requests we want to delay for some period is put + * in the scsi retry queue with a delay added. The + * timer will schedule a "scsi_restart_needed" every + * second as long as there are requests in the scsi + * queue. + */ + DEBUG(printk("scsi(%ld): DPC checking scsi " + "retry_q.total=%d\n", + ha->host_no, ha->scsi_retry_q_cnt)); + + online_cnt = 0; + spin_lock_irqsave(&ha->list_lock, flags); + list_for_each_safe(list, templist, + &ha->scsi_retry_queue) { + + sp = list_entry(list, srb_t, list); + q = sp->lun_queue; + + DEBUG3(printk("scsi(%ld): scsi_retry_q: " + "pid=%ld sp=%p, spflags=0x%x, " + "q_flag= 0x%lx,q_state=%d\n", + ha->host_no, sp->cmd->serial_number, + sp, sp->flags, q->q_flag, q->q_state)); + + /* Was this lun suspended */ + if (q->q_state != LUN_STATE_WAIT) { + online_cnt++; + __del_from_scsi_retry_queue(ha, sp); + __add_to_retry_queue(ha,sp); + } + + /* Was this command suspended for N secs */ + if (sp->delay != 0) { + sp->delay--; + if (sp->delay == 0) { + online_cnt++; + __del_from_scsi_retry_queue( + ha, sp); + __add_to_retry_queue(ha,sp); + } + } + } + spin_unlock_irqrestore(&ha->list_lock, flags); + + DEBUG(if (online_cnt > 0)) + DEBUG(printk("scsi(%ld): dpc() found scsi reqs to " + "restart= %d\n", + ha->host_no, online_cnt)); + } + + if (ha->flags.mbox_busy) { + if (!list_empty(&ha->done_queue)) + qla2x00_done(ha); + + ha->dpc_active = 0; + continue; + } + + if (test_and_clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) { + + DEBUG(printk("scsi(%ld): dpc: sched " + "qla2x00_abort_isp ha = %p\n", + ha->host_no, ha)); + if (!(test_and_set_bit(ABORT_ISP_ACTIVE, + &ha->dpc_flags))) { + + if (qla2x00_abort_isp(ha)) { + /* failed. retry later */ + set_bit(ISP_ABORT_NEEDED, + &ha->dpc_flags); + } + clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); + } + DEBUG(printk("scsi(%ld): dpc: qla2x00_abort_isp end\n", + ha->host_no)); + } + + if (test_and_clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) && + (!(test_and_set_bit(RESET_ACTIVE, &ha->dpc_flags)))) { + + DEBUG(printk("scsi(%ld): qla2x00_reset_marker()\n", + ha->host_no)); + + qla2x00_rst_aen(ha); + clear_bit(RESET_ACTIVE, &ha->dpc_flags); + } + + /* Retry each device up to login retry count */ + if ((test_and_clear_bit(RELOGIN_NEEDED, &ha->dpc_flags)) && + !test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) && + atomic_read(&ha->loop_state) != LOOP_DOWN) { + + DEBUG(printk("scsi(%ld): qla2x00_port_login()\n", + ha->host_no)); + + next_loopid = 0; + list_for_each(fcpl, &ha->fcports) { + fcport = list_entry(fcpl, fc_port_t, list); + + /* + * If the port is not ONLINE then try to login + * to it if we haven't run out of retries. + */ + if (atomic_read(&fcport->state) != FCS_ONLINE && + fcport->login_retry) { + + fcport->login_retry--; + if (fcport->flags & FCF_FABRIC_DEVICE) + status = qla2x00_fabric_login( + ha, fcport, &next_loopid); + else + status = + qla2x00_local_device_login( + ha, fcport->loop_id); + + if (status == QLA_SUCCESS) { + fcport->old_loop_id = fcport->loop_id; + + DEBUG(printk("scsi(%ld): port login OK: logged in ID 0x%x\n", + ha->host_no, fcport->loop_id)); + + fcport->port_login_retry_count = + ha->port_down_retry_count * PORT_RETRY_TIME; + atomic_set(&fcport->state, FCS_ONLINE); + atomic_set(&fcport->port_down_timer, + ha->port_down_retry_count * PORT_RETRY_TIME); + + fcport->login_retry = 0; + } else if (status == 1) { + set_bit(RELOGIN_NEEDED, &ha->dpc_flags); + /* retry the login again */ + DEBUG(printk("scsi(%ld): Retrying %d login again loop_id 0x%x\n", + ha->host_no, + fcport->login_retry, fcport->loop_id)); + } else { + fcport->login_retry = 0; + } + } + if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) + break; + } + DEBUG(printk("scsi(%ld): qla2x00_port_login - end\n", + ha->host_no)); + } + + if ((test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags)) && + atomic_read(&ha->loop_state) != LOOP_DOWN) { + + clear_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags); + DEBUG(printk("scsi(%ld): qla2x00_login_retry()\n", + ha->host_no)); + + set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); + + DEBUG(printk("scsi(%ld): qla2x00_login_retry - end\n", + ha->host_no)); + } + + if (test_and_clear_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) { + + DEBUG(printk("scsi(%ld): qla2x00_loop_resync()\n", + ha->host_no)); + + if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE, + &ha->dpc_flags))) { + + qla2x00_loop_resync(ha); + + clear_bit(LOOP_RESYNC_ACTIVE, &ha->dpc_flags); + } + + DEBUG(printk("scsi(%ld): qla2x00_loop_resync - end\n", + ha->host_no)); + } + + if (qla2x00_failover_enabled(ha)) + qla2x00_process_failover_event(ha); + + if (test_bit(RESTART_QUEUES_NEEDED, &ha->dpc_flags)) { + DEBUG(printk("scsi(%ld): qla2x00_restart_queues()\n", + ha->host_no)); + + qla2x00_restart_queues(ha,FALSE); + + DEBUG(printk("scsi(%ld): qla2x00_restart_queues - end\n", + ha->host_no)); + } + + if (test_bit(ABORT_QUEUES_NEEDED, &ha->dpc_flags)) { + + DEBUG(printk("scsi(%ld): qla2x00_abort_queues()\n", + ha->host_no)); + + qla2x00_abort_queues(ha, FALSE); + + DEBUG(printk("scsi(%ld): qla2x00_abort_queues - end\n", + ha->host_no)); + } + + if (test_and_clear_bit(FCPORT_RESCAN_NEEDED, &ha->dpc_flags)) { + + DEBUG(printk("scsi(%ld): Rescan flagged fcports...\n", + ha->host_no)); + + qla2x00_rescan_fcports(ha); + + DEBUG(printk("scsi(%ld): Rescan flagged fcports..." + "end.\n", + ha->host_no)); + } + + + if (!ha->interrupts_on) + qla2x00_enable_intrs(ha); + + if (!list_empty(&ha->done_queue)) + qla2x00_done(ha); + + ha->dpc_active = 0; + } /* End of while(1) */ + + DEBUG(printk("scsi(%ld): DPC handler exiting\n", ha->host_no)); + + /* + * Make sure that nobody tries to wake us up again. + */ + ha->dpc_wait = NULL; + ha->dpc_active = 0; + + complete_and_exit(&ha->dpc_exited, 0); +} + +/* + * qla2x00_abort_queues + * Abort all commands on queues on device + * + * Input: + * ha = adapter block pointer. + * + * Context: + * Interrupt context. + */ +void +qla2x00_abort_queues(scsi_qla_host_t *ha, uint8_t doneqflg) +{ + + srb_t *sp; + struct list_head *list, *temp; + unsigned long flags; + + ENTER(__func__); + + clear_bit(ABORT_QUEUES_NEEDED, &ha->dpc_flags); + + /* Return all commands device queues. */ + spin_lock_irqsave(&ha->list_lock,flags); + list_for_each_safe(list, temp, &ha->pending_queue) { + sp = list_entry(list, srb_t, list); + + if (sp->flags & SRB_ABORTED) + continue; + + /* Remove srb from LUN queue. */ + __del_from_pending_queue(ha, sp); + + /* Set ending status. */ + sp->cmd->result = DID_BUS_BUSY << 16; + + __add_to_done_queue(ha, sp); + } + spin_unlock_irqrestore(&ha->list_lock, flags); + + LEAVE(__func__); +} + +/* +* qla2x00_rst_aen +* Processes asynchronous reset. +* +* Input: +* ha = adapter block pointer. +*/ +static void +qla2x00_rst_aen(scsi_qla_host_t *ha) +{ + ENTER(__func__); + + if (ha->flags.online && !ha->flags.reset_active && + !atomic_read(&ha->loop_down_timer) && + !(test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags))) { + + /* 10/15 ha->flags.reset_active = TRUE; */ + do { + clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); + + /* + * Issue marker command only when we are going to start + * the I/O. + */ + ha->marker_needed = 1; + } while (!atomic_read(&ha->loop_down_timer) && + (test_bit(RESET_MARKER_NEEDED, &ha->dpc_flags))); + + /* 10/15 ha->flags.reset_active = FALSE; */ + } + + LEAVE(__func__); +} + + +/* + * This routine will alloacte SP from the free queue + * input: + * scsi_qla_host_t * + * output: + * srb_t * or NULL + */ +srb_t * +qla2x00_get_new_sp(scsi_qla_host_t *ha) +{ + srb_t *sp; + + sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL); + if (sp) { + atomic_set(&sp->ref_count, 1); + } + return (sp); +} + +/************************************************************************** + * qla2x00_blink_led + * + * Description: + * This function sets the colour of the LED while preserving the + * unsued GPIO pins every sec. + * + * Input: + * ha - Host adapter structure + * + * Return: + * None + * + * Context: qla2x00_timer() Interrupt + ***************************************************************************/ +void +qla2x00_blink_led(scsi_qla_host_t *ha) +{ + uint16_t gpio_enable, gpio_data, led_color; + unsigned long cpu_flags = 0; + device_reg_t *reg = ha->iobase; + + ENTER(__func__); + + /* Save the Original GPIOE */ + spin_lock_irqsave(&ha->hardware_lock, cpu_flags); + gpio_enable = RD_REG_WORD(®->gpioe); + gpio_data = RD_REG_WORD(®->gpiod); + spin_unlock_irqrestore(&ha->hardware_lock, cpu_flags); + + DEBUG2(printk("%s Original data of gpio_enable_reg=0x%x" + " gpio_data_reg=0x%x\n", + __func__,gpio_enable,gpio_data)); + + if (ha->beacon_green_on){ + led_color = GPIO_LED_GREEN_ON_AMBER_OFF; + ha->beacon_green_on = 0; + } else { + led_color = GPIO_LED_GREEN_OFF_AMBER_OFF; + ha->beacon_green_on = 1; + } + + /* Set the modified gpio_enable values */ + gpio_enable |= GPIO_LED_GREEN_ON_AMBER_OFF; + + DEBUG2(printk("%s Before writing enable : gpio_enable_reg=0x%x" + " gpio_data_reg=0x%x led_color=0x%x\n", + __func__, gpio_enable, gpio_data, led_color)); + + spin_lock_irqsave(&ha->hardware_lock, cpu_flags); + WRT_REG_WORD(®->gpioe,gpio_enable); + spin_unlock_irqrestore(&ha->hardware_lock, cpu_flags); + + /* Clear out the previously set LED colour */ + gpio_data &= ~GPIO_LED_GREEN_ON_AMBER_OFF; + + /* Set the new input LED colour to GPIOD */ + gpio_data |= led_color; + + DEBUG2(printk("%s Before writing data: gpio_enable_reg=0x%x" + " gpio_data_reg=0x%x led_color=0x%x\n", + __func__,gpio_enable,gpio_data,led_color)); + + /* Set the modified gpio_data values */ + spin_lock_irqsave(&ha->hardware_lock, cpu_flags); + WRT_REG_WORD(®->gpiod,gpio_data); + spin_unlock_irqrestore(&ha->hardware_lock, cpu_flags); + + LEAVE(__func__); +} + +/************************************************************************** +* qla2x00_timer +* +* Description: +* One second timer +* +* Context: Interrupt +***************************************************************************/ +static void +qla2x00_timer(scsi_qla_host_t *ha) +{ + int t,l; + unsigned long cpu_flags = 0; + struct list_head *fcpl; + fc_port_t *fcport; + os_lun_t *lq; + os_tgt_t *tq; + int start_dpc = 0; + + /* + * We try and restart any request in the retry queue every second. + */ + if (!list_empty(&ha->retry_queue)) { + set_bit(PORT_RESTART_NEEDED, &ha->dpc_flags); + start_dpc++; + } + + /* + * We try and restart any request in the scsi_retry queue every second. + */ + if (!list_empty(&ha->scsi_retry_queue)) { + set_bit(SCSI_RESTART_NEEDED, &ha->dpc_flags); + start_dpc++; + } + + /* Check if beacon LED needs to be blinked */ + if (IS_QLA23XX(ha) && ha->beacon_blink_led) + qla2x00_blink_led(ha); + + /* + * We try and failover any request in the failover queue every second. + */ + if (!list_empty(&ha->failover_queue)) { + set_bit(FAILOVER_NEEDED, &ha->dpc_flags); + start_dpc++; + } + + /* + * Ports - Port down timer. + * + * Whenever, a port is in the LOST state we start decrementing its port + * down timer every second until it reaches zero. Once it reaches zero + * the port it marked DEAD. + */ + t = 0; + list_for_each(fcpl, &ha->fcports) { + fcport = list_entry(fcpl, fc_port_t, list); + + if (atomic_read(&fcport->state) == FCS_DEVICE_LOST) { + + if (atomic_read(&fcport->port_down_timer) == 0) + continue; + + if (atomic_dec_and_test(&fcport->port_down_timer) != 0) + atomic_set(&fcport->state, FCS_DEVICE_DEAD); + + DEBUG(printk("scsi(%ld): fcport-%d - port retry count: " + "%d remainning\n", + ha->host_no, + t, atomic_read(&fcport->port_down_timer))); + } + t++; + } /* End of for fcport */ + + /* + * LUNS - lun suspend timer. + * + * Whenever, a lun is suspended the timer starts decrementing its + * suspend timer every second until it reaches zero. Once it reaches + * zero the lun retry count is decremented. + */ + + /* + * FIXME(dg) - Need to convert this linear search of luns into a search + * of a list of suspended luns. + */ + for (t = 0; t < ha->max_targets; t++) { + if ((tq = ha->otgt[t]) == NULL) + continue; + + for (l = 0; l < ha->max_luns; l++) { + if ((lq = (os_lun_t *) tq->olun[l]) == NULL) + continue; + + spin_lock_irqsave(&lq->q_lock, cpu_flags); + if (lq->q_state == LUN_STATE_WAIT && + atomic_read(&lq->q_timer) != 0) { + + if (atomic_dec_and_test(&lq->q_timer) != 0) { + /* + * A delay should immediately + * transition to a READY state + */ + if (test_and_clear_bit(LUN_EXEC_DELAYED, + &lq->q_flag)) { + lq->q_state = LUN_STATE_READY; + } + else { + lq->q_count++; + if (lq->q_count == lq->q_max) + lq->q_state = + LUN_STATE_TIMEOUT; + else + lq->q_state = + LUN_STATE_RUN; + } + } + DEBUG3(printk("scsi(%ld): lun%d - timer %d, " + "count=%d, max=%d, state=%d\n", + ha->host_no, + l, + atomic_read(&lq->q_timer), + lq->q_count, lq->q_max, lq->q_state)); + } + spin_unlock_irqrestore(&lq->q_lock, cpu_flags); + } /* End of for luns */ + } /* End of for targets */ + + /* Loop down handler. */ + if (atomic_read(&ha->loop_down_timer) > 0 && + !(test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags)) && ha->flags.online) { + + /* dg 10/30 if (atomic_read(&ha->loop_down_timer) == LOOP_DOWN_TIME) { */ + if (atomic_read(&ha->loop_down_timer) == + ha->loop_down_abort_time) { + + DEBUG(printk("scsi(%ld): Loop Down - aborting the " + "queues before time expire\n", + ha->host_no)); + + if (!IS_QLA2100(ha) && ha->link_down_timeout) + atomic_set(&ha->loop_state, LOOP_DEAD); + + set_bit(ABORT_QUEUES_NEEDED, &ha->dpc_flags); + start_dpc++; + } + + /* if the loop has been down for 4 minutes, reinit adapter */ + if (atomic_dec_and_test(&ha->loop_down_timer) != 0) { + DEBUG(printk("scsi(%ld): Loop down exceed 4 mins - " + "restarting queues.\n", + ha->host_no)); + + set_bit(RESTART_QUEUES_NEEDED, &ha->dpc_flags); + start_dpc++; + + if (!qla2x00_failover_enabled(ha) && qla2x00_reinit && + !(ha->device_flags & DFLG_NO_CABLE)) { + + DEBUG(printk("scsi(%ld): Loop down - " + "aborting ISP.\n", + ha->host_no)); + + set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); + } + } + DEBUG3(printk("scsi(%ld): Loop Down - seconds remainning %d\n", + ha->host_no, + atomic_read(&ha->loop_down_timer))); + } + + /* + * Done Q Handler -- dgFIXME This handler will kick off doneq if we + * haven't process it in 2 seconds. + */ + if (!list_empty(&ha->done_queue)) + qla2x00_done(ha); + + if (test_bit(FAILOVER_EVENT_NEEDED, &ha->dpc_flags)) { + if (ha->failback_delay) { + ha->failback_delay--; + if (ha->failback_delay == 0) { + set_bit(FAILOVER_EVENT, &ha->dpc_flags); + clear_bit(FAILOVER_EVENT_NEEDED, + &ha->dpc_flags); + } + } else { + set_bit(FAILOVER_EVENT, &ha->dpc_flags); + clear_bit(FAILOVER_EVENT_NEEDED, &ha->dpc_flags); + } + } + + /* Schedule the DPC routine if needed */ + if ((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) || + test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) || + start_dpc || + test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags) || + test_bit(RELOGIN_NEEDED, &ha->dpc_flags) || + test_bit(FAILOVER_EVENT, &ha->dpc_flags) || + test_bit(FAILOVER_NEEDED, &ha->dpc_flags)) && + ha->dpc_wait && !ha->dpc_active) { + + up(ha->dpc_wait); + } + + qla2x00_restart_timer(ha, WATCH_INTERVAL); +} + +/* + * qla2x00_extend_timeout + * This routine will extend the timeout to the specified value. + * + * Input: + * cmd = SCSI command structure + * + * Returns: + * None. + */ +void +qla2x00_extend_timeout(struct scsi_cmnd *cmd, int timeout) +{ + srb_t *sp = (srb_t *) CMD_SP(cmd); + u_long our_jiffies = (timeout * HZ) + jiffies; + + sp->ext_history= 0; + sp->e_start = jiffies; + if (cmd->eh_timeout.function) { + mod_timer(&cmd->eh_timeout,our_jiffies); + sp->ext_history |= 1; + } + if (sp->timer.function != NULL) { + /* + * Our internal timer should timeout before the midlayer has a + * chance begin the abort process + */ + mod_timer(&sp->timer,our_jiffies - (QLA_CMD_TIMER_DELTA * HZ)); + + sp->ext_history |= 2; + } +} + +/************************************************************************** +* qla2x00_cmd_timeout +* +* Description: +* Handles the command if it times out in any state. +* +* Input: +* sp - pointer to validate +* +* Returns: +* None. +* Note:Need to add the support for if( sp->state == SRB_FAILOVER_STATE). +**************************************************************************/ +static void +qla2x00_cmd_timeout(srb_t *sp) +{ + int t, l; + int processed; + scsi_qla_host_t *vis_ha, *dest_ha; + struct scsi_cmnd *cmd; + ulong flags; +#if defined(QL_DEBUG_LEVEL_3) + ulong cpu_flags; +#endif + fc_port_t *fcport; + + cmd = sp->cmd; + vis_ha = (scsi_qla_host_t *)cmd->device->host->hostdata; + + DEBUG3(printk("cmd_timeout: Entering sp->state = %x\n", sp->state)); + + t = cmd->device->id; + l = cmd->device->lun; + fcport = sp->fclun->fcport; + dest_ha = sp->ha; + + /* + * If IO is found either in retry Queue + * OR in Lun Queue + * Return this IO back to host + */ + spin_lock_irqsave(&vis_ha->list_lock, flags); + processed = 0; + if (sp->state == SRB_PENDING_STATE) { + __del_from_pending_queue(vis_ha, sp); + DEBUG2(printk("scsi(%ld): Found in Pending queue pid %ld, " + "State = %x., fcport state=%d jiffies=%lx\n", + vis_ha->host_no, cmd->serial_number, sp->state, + atomic_read(&fcport->state), jiffies)); + + /* + * If FC_DEVICE is marked as dead return the cmd with + * DID_NO_CONNECT status. Otherwise set the host_byte to + * DID_BUS_BUSY to let the OS retry this cmd. + */ + if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD || + atomic_read(&vis_ha->loop_state) == LOOP_DEAD) { + cmd->result = DID_NO_CONNECT << 16; + } else { + cmd->result = DID_BUS_BUSY << 16; + } + __add_to_done_queue(vis_ha, sp); + processed++; + } + spin_unlock_irqrestore(&vis_ha->list_lock, flags); + + if (processed) { + qla2x00_done(vis_ha); + return; + } + + spin_lock_irqsave(&dest_ha->list_lock, flags); + if ((sp->state == SRB_RETRY_STATE) || + (sp->state == SRB_SCSI_RETRY_STATE) || + (sp->state == SRB_FAILOVER_STATE)) { + + DEBUG2(printk("scsi(%ld): Found in (Scsi) Retry queue or " + "failover Q pid %ld, State = %x., fcport state=%d " + "jiffies=%lx retried=%d\n", + dest_ha->host_no, cmd->serial_number, sp->state, + atomic_read(&fcport->state), jiffies, cmd->retries)); + + if ((sp->state == SRB_RETRY_STATE)) { + __del_from_retry_queue(dest_ha, sp); + } else if ((sp->state == SRB_SCSI_RETRY_STATE)) { + __del_from_scsi_retry_queue(dest_ha, sp); + } else if ((sp->state == SRB_FAILOVER_STATE)) { + __del_from_failover_queue(dest_ha, sp); + } + + /* + * If FC_DEVICE is marked as dead return the cmd with + * DID_NO_CONNECT status. Otherwise set the host_byte to + * DID_BUS_BUSY to let the OS retry this cmd. + */ + if (qla2x00_failover_enabled(dest_ha)) { + cmd->result = DID_BUS_BUSY << 16; + } else { + if ((atomic_read(&fcport->state) == FCS_DEVICE_DEAD) || + atomic_read(&dest_ha->loop_state) == LOOP_DEAD) { + qla2x00_extend_timeout(cmd, EXTEND_CMD_TIMEOUT); + cmd->result = DID_NO_CONNECT << 16; + } else { + cmd->result = DID_BUS_BUSY << 16; + } + } + + __add_to_done_queue(dest_ha, sp); + processed++; + } + spin_unlock_irqrestore(&dest_ha->list_lock, flags); + + if (processed) { + qla2x00_done(dest_ha); + + return; + } +/* TODO: Remove this code!!! */ +#if defined(QL_DEBUG_LEVEL_3) + spin_lock_irqsave(&dest_ha->list_lock, cpu_flags); + if (sp->state == SRB_DONE_STATE) { + /* IO in done_q -- leave it */ + DEBUG(printk("scsi(%ld): Found in Done queue pid %ld sp=%p.\n", + dest_ha->host_no, cmd->serial_number, sp)); + } else if (sp->state == SRB_SUSPENDED_STATE) { + DEBUG(printk("scsi(%ld): Found SP %p in suspended state " + "- pid %ld:\n", + dest_ha->host_no, sp, cmd->serial_number)); + DEBUG(qla2x00_dump_buffer((uint8_t *)sp, sizeof(srb_t));) + } else if (sp->state == SRB_ACTIVE_STATE) { + /* + * IO is with ISP find the command in our active list. + */ + spin_unlock_irqrestore(&dest_ha->list_lock, cpu_flags); + spin_lock_irqsave(&dest_ha->hardware_lock, flags); + if (sp == + dest_ha->outstanding_cmds[(u_long)sp->cmd->host_scribble]) { + + DEBUG(printk("cmd_timeout: Found in ISP \n");) + + sp->state = SRB_ACTIVE_TIMEOUT_STATE; + spin_unlock_irqrestore(&dest_ha->hardware_lock, flags); + } else { + spin_unlock_irqrestore(&dest_ha->hardware_lock, flags); + printk(KERN_INFO + "qla_cmd_timeout: State indicates it is with " + "ISP, But not in active array\n"); + } + spin_lock_irqsave(&dest_ha->list_lock, cpu_flags); /* 01/03 */ + } else if (sp->state == SRB_ACTIVE_TIMEOUT_STATE) { + DEBUG(printk("qla2100%ld: Found in Active timeout state" + "pid %ld, State = %x., \n", + dest_ha->host_no, + sp->cmd->serial_number, sp->state);) + } else { + /* EMPTY */ + DEBUG2(printk("cmd_timeout%ld: LOST command state = " + "0x%x, sp=%p\n", + vis_ha->host_no, sp->state,sp);) + + qla_printk(KERN_INFO, vis_ha, + "cmd_timeout: LOST command state = 0x%x\n", sp->state); + } + spin_unlock_irqrestore(&dest_ha->list_lock, cpu_flags); +#endif + + DEBUG3(printk("cmd_timeout: Leaving\n");) +} + +/************************************************************************** +* qla2x00_done +* Process completed commands. +* +* Input: +* old_ha = adapter block pointer. +* +**************************************************************************/ +void +qla2x00_done(scsi_qla_host_t *old_ha) +{ + os_lun_t *lq; + struct scsi_cmnd *cmd; + unsigned long flags = 0; + scsi_qla_host_t *ha; + scsi_qla_host_t *vis_ha; + int send_marker_once = 0; + srb_t *sp, *sptemp; + LIST_HEAD(local_sp_list); + + /* + * Get into local queue such that we do not wind up calling done queue + * tasklet for the same IOs from DPC or any other place. + */ + spin_lock_irqsave(&old_ha->list_lock, flags); + list_splice_init(&old_ha->done_queue, &local_sp_list); + spin_unlock_irqrestore(&old_ha->list_lock, flags); + + /* + * All done commands are in the local queue, now do the call back. + */ + list_for_each_entry_safe(sp, sptemp, &local_sp_list, list) { + old_ha->done_q_cnt--; + sp->state = SRB_NO_QUEUE_STATE; + + /* remove command from local list */ + list_del_init(&sp->list); + + cmd = sp->cmd; + if (cmd == NULL) + continue; + + vis_ha = (scsi_qla_host_t *)cmd->device->host->hostdata; + lq = sp->lun_queue; + ha = sp->ha; + + if (sp->flags & SRB_DMA_VALID) { + sp->flags &= ~SRB_DMA_VALID; + + /* Release memory used for this I/O */ + if (cmd->use_sg) { + pci_unmap_sg(ha->pdev, cmd->request_buffer, + cmd->use_sg, cmd->sc_data_direction); + } else if (cmd->request_bufflen) { + pci_unmap_page(ha->pdev, sp->dma_handle, + cmd->request_bufflen, + cmd->sc_data_direction); + } + } + + if (qla2x00_failover_enabled(ha) && !(sp->flags & SRB_IOCTL)) + if (qla2x00_do_fo_check(ha, sp, vis_ha)) + continue; + + switch (host_byte(cmd->result)) { + case DID_OK: + case DID_ERROR: + break; + + case DID_RESET: + /* + * Set marker needed, so we don't have to + * send multiple markers + */ + if (!send_marker_once) { + ha->marker_needed = 1; + send_marker_once++; + } + + /* + * WORKAROUND + * + * A backdoor device-reset requires different + * error handling. This code differentiates + * between normal error handling and the + * backdoor method. + * + */ + if (ha->host->eh_active != EH_ACTIVE) + cmd->result = DID_BUS_BUSY << 16; + break; + + + case DID_ABORT: + sp->flags &= ~SRB_ABORT_PENDING; + sp->flags |= SRB_ABORTED; + + if (sp->flags & SRB_TIMEOUT) + cmd->result = DID_TIME_OUT << 16; + + break; + + default: + DEBUG2(printk("scsi(%ld:%d:%d) %s: did_error " + "= %d, comp-scsi= 0x%x-0x%x.\n", + vis_ha->host_no, + cmd->device->id, cmd->device->lun, + __func__, + host_byte(cmd->result), + CMD_COMPL_STATUS(cmd), + CMD_SCSI_STATUS(cmd))); + break; + } + + /* + * Call the mid-level driver interrupt handler -- via sp_put() + */ + sp_put(ha, sp); + } /* end of while */ +} + +/* + * qla2x00_process_response_queue_in_zio_mode + * Process response queue completion as fast as possible + * to achieve Zero Interrupt Opertions-ZIO + * + * Input: + * ha = adapter block pointer. + * + * Context: + * Kernel context. + */ +static inline void +qla2x00_process_response_queue_in_zio_mode(scsi_qla_host_t *ha) +{ + unsigned long flags; + + /* Check for unprocessed commands in response queue. */ + if (!ha->flags.process_response_queue) + return; + if (!ha->flags.online) + return; + if (ha->response_ring_ptr->signature == RESPONSE_PROCESSED) + return; + + spin_lock_irqsave(&ha->hardware_lock,flags); + qla2x00_process_response_queue(ha); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + if (!list_empty(&ha->done_queue)) + qla2x00_done(ha); +} + +/* + * qla2x00_next + * Retrieve and process next job in the LUN queue. + * + * Input: + * tq = SCSI target queue pointer. + * lq = SCSI LUN queue pointer. + * TGT_LOCK must be already obtained. + * + * Output: + * Releases TGT_LOCK upon exit. + * + * Context: + * Kernel/Interrupt context. + * + * Note: This routine will always try to start I/O from visible HBA. + */ +void +qla2x00_next(scsi_qla_host_t *vis_ha) +{ + int rval; + unsigned long flags; + scsi_qla_host_t *dest_ha; + fc_port_t *fcport; + srb_t *sp, *sptemp; + LIST_HEAD(local_sp_list); + + dest_ha = NULL; + + spin_lock_irqsave(&vis_ha->list_lock, flags); + list_splice_init(&vis_ha->pending_queue, &local_sp_list); + vis_ha->qthreads = 0; + spin_unlock_irqrestore(&vis_ha->list_lock, flags); + + list_for_each_entry_safe(sp, sptemp, &local_sp_list, list) { + list_del_init(&sp->list); + sp->state = SRB_NO_QUEUE_STATE; + + fcport = sp->fclun->fcport; + dest_ha = fcport->ha; + + /* If device is dead then send request back to OS */ + if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD) { + + sp->cmd->result = DID_NO_CONNECT << 16; + + if (!atomic_read(&dest_ha->loop_down_timer) && + atomic_read(&dest_ha->loop_state) == LOOP_DOWN) { + sp->err_id = 2; + } else { + sp->err_id = 1; + } + DEBUG3(printk("scsi(%ld): loop/port is down - " + "pid=%ld, sp=%p loopid=0x%x queued to dest HBA " + "scsi%ld.\n", + dest_ha->host_no, + sp->cmd->serial_number, sp, + fcport->loop_id, dest_ha->host_no)); + /* + * Initiate a failover - done routine will initiate. + */ + add_to_done_queue(vis_ha, sp); + + continue; + } + + /* + * SCSI Kluge: Whenever, we need to wait for an event such as + * loop down (i.e. loop_down_timer ) or port down (i.e. LUN + * request qeueue is suspended) then we will recycle new + * commands back to the SCSI layer. We do this because this is + * normally a temporary condition and we don't want the + * mid-level scsi.c driver to get upset and start aborting + * commands. The timeout value is extracted from the command + * minus 1-second and put on a retry queue (watchdog). Once the + * command timeout it is returned to the mid-level with a BUSY + * status, so the mid-level will retry it. This process + * continues until the LOOP DOWN time expires or the condition + * goes away. + */ + if (!(sp->flags & SRB_IOCTL) && + (atomic_read(&fcport->state) != FCS_ONLINE || + test_bit(ABORT_ISP_ACTIVE, &dest_ha->dpc_flags) || + atomic_read(&dest_ha->loop_state) != LOOP_READY || + (sp->flags & SRB_FAILOVER))) { + + DEBUG3(printk("scsi(%ld): port=(0x%x) retry_q(%d) " + "loop state = %d, loop counter = 0x%x dpc flags " + "= 0x%lx\n", + dest_ha->host_no, + fcport->loop_id, + atomic_read(&fcport->state), + atomic_read(&dest_ha->loop_state), + atomic_read(&dest_ha->loop_down_timer), + dest_ha->dpc_flags)); + + qla2x00_extend_timeout(sp->cmd, EXTEND_CMD_TIMEOUT); + add_to_retry_queue(vis_ha, sp); + + continue; + } + + /* + * If this request's lun is suspended then put the request on + * the scsi_retry queue. + */ + if (!(sp->flags & SRB_IOCTL) && + sp->lun_queue->q_state == LUN_STATE_WAIT) { + DEBUG3(printk("scsi(%ld): lun wait state - pid=%ld, " + "opcode=%d, allowed=%d, retries=%d\n", + dest_ha->host_no, + sp->cmd->serial_number, + sp->cmd->cmnd[0], + sp->cmd->allowed, + sp->cmd->retries)); + + add_to_scsi_retry_queue(vis_ha, sp); + + continue; + } + + sp->lun_queue->io_cnt++; + + rval = qla2x00_start_scsi(sp); + if (rval != QLA_SUCCESS) { + /* Place request back on top of device queue */ + /* add to the top of queue */ + add_to_pending_queue_head(vis_ha, sp); + + sp->lun_queue->io_cnt--; + } + } + + if (IS_QLA23XX(vis_ha)) { + /* Process response_queue if ZIO support is enabled*/ + qla2x00_process_response_queue_in_zio_mode(vis_ha); + + if (dest_ha && qla2x00_failover_enabled(dest_ha)) + qla2x00_process_response_queue_in_zio_mode(dest_ha); + } +} + +/* + * qla2x00_flush_failover_queue + * Return cmds of a "specific" LUN from the failover queue with + * DID_BUS_BUSY status. + * + * Input: + * ha = adapter block pointer. + * q = lun queue. + * + * Context: + * Interrupt context. + */ +void +qla2x00_flush_failover_q(scsi_qla_host_t *ha, os_lun_t *q) +{ + srb_t *sp; + struct list_head *list, *temp; + unsigned long flags; + + spin_lock_irqsave(&ha->list_lock, flags); + list_for_each_safe(list, temp, &ha->failover_queue) { + sp = list_entry(list, srb_t, list); + /* + * If request originated from the same lun_q then delete it + * from the failover queue + */ + if (q == sp->lun_queue) { + /* Remove srb from failover queue. */ + __del_from_failover_queue(ha, sp); + sp->cmd->result = DID_BUS_BUSY << 16; + sp->cmd->host_scribble = (unsigned char *) NULL; + __add_to_done_queue(ha, sp); + } + } + spin_unlock_irqrestore(&ha->list_lock, flags); +} + + +/* + * qla2x00_reset_lun_fo_counts + * Reset failover retry counts + * + * Input: + * ha = adapter block pointer. + * + * Context: + * Interrupt context. + */ +void +qla2x00_reset_lun_fo_counts(scsi_qla_host_t *ha, os_lun_t *lq) +{ + srb_t *tsp; + os_lun_t *orig_lq; + struct list_head *list; + unsigned long flags ; + + spin_lock_irqsave(&ha->list_lock, flags); + /* + * the pending queue. + */ + list_for_each(list,&ha->pending_queue) { + tsp = list_entry(list, srb_t, list); + orig_lq = tsp->lun_queue; + if (orig_lq == lq) + tsp->fo_retry_cnt = 0; + } + /* + * the retry queue. + */ + list_for_each(list,&ha->retry_queue) { + tsp = list_entry(list, srb_t, list); + orig_lq = tsp->lun_queue; + if (orig_lq == lq) + tsp->fo_retry_cnt = 0; + } + + /* + * the done queue. + */ + list_for_each(list, &ha->done_queue) { + tsp = list_entry(list, srb_t, list); + orig_lq = tsp->lun_queue; + if (orig_lq == lq) + tsp->fo_retry_cnt = 0; + } + spin_unlock_irqrestore(&ha->list_lock, flags); +} + +/************************************************************************** +* qla2x00_check_tgt_status +* +* Description: +* Checks to see if the target or loop is down. +* +* Input: +* cmd - pointer to Scsi cmd structure +* +* Returns: +* 1 - if target is present +* 0 - if target is not present +* +**************************************************************************/ +int +qla2x00_check_tgt_status(scsi_qla_host_t *ha, struct scsi_cmnd *cmd) +{ + os_lun_t *lq; + unsigned int b, t, l; + fc_port_t *fcport; + + /* Generate LU queue on bus, target, LUN */ + b = cmd->device->channel; + t = cmd->device->id; + l = cmd->device->lun; + + if ((lq = GET_LU_Q(ha,t,l)) == NULL) { + return (QLA_FUNCTION_FAILED); + } + + fcport = lq->fclun->fcport; + + if (TGT_Q(ha, t) == NULL || + l >= ha->max_luns || + atomic_read(&fcport->state) == FCS_DEVICE_DEAD || + atomic_read(&ha->loop_state) == LOOP_DEAD || + (!atomic_read(&ha->loop_down_timer) && + atomic_read(&ha->loop_state) == LOOP_DOWN) || + test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) || + test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) || + atomic_read(&ha->loop_state) != LOOP_READY) { + + DEBUG(printk(KERN_INFO + "scsi(%ld:%2d:%2d:%2d): %s connection is down\n", + ha->host_no, + b, t, l, + __func__)); + + cmd->result = DID_NO_CONNECT << 16; + return (QLA_FUNCTION_FAILED); + } + return (QLA_SUCCESS); +} + +/************************************************************************** +* qla2x00_check_port_status +* +* Description: +* Checks to see if the port or loop is down. +* +* Input: +* fcport - pointer to fc_port_t structure. +* +* Returns: +* 1 - if port is present +* 0 - if port is not present +* +**************************************************************************/ +int +qla2x00_check_port_status(scsi_qla_host_t *ha, fc_port_t *fcport) +{ + if (fcport == NULL) { + return (QLA_FUNCTION_FAILED); + } + + if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD || + atomic_read(&ha->loop_state) == LOOP_DEAD) { + return (QLA_FUNCTION_FAILED); + } + + if ((atomic_read(&fcport->state) != FCS_ONLINE) || + (!atomic_read(&ha->loop_down_timer) && + atomic_read(&ha->loop_state) == LOOP_DOWN) || + (test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags)) || + test_bit(CFG_ACTIVE, &ha->cfg_flags) || + test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) || + atomic_read(&ha->loop_state) != LOOP_READY) { + + DEBUG(printk(KERN_INFO + "scsi(%ld): Connection is down. fcport=%p.\n", + ha->host_no, fcport)); + + return (QLA_BUSY); + } + + return (QLA_SUCCESS); +} + +/** + * qla2x00_module_init - Module initialization. + **/ +static int __init +qla2x00_module_init(void) +{ + /* Derive version string. */ + strcpy(qla2x00_version_str, QLA2XXX_VERSION); +#if DEBUG_QLA2100 + strcat(qla2x00_version_str, "-debug"); +#endif +#if defined(CONFIG_SCSI_QLA2XXX_FAILOVER_ENABLE) + strcat(qla2x00_version_str, "-fo"); +#endif + + /* Allocate cache for SRBs. */ + sprintf(srb_cachep_name, "qla2xxx_srbs"); + srb_cachep = kmem_cache_create(srb_cachep_name, sizeof(srb_t), 0, + SLAB_HWCACHE_ALIGN, NULL, NULL); + if (srb_cachep == NULL) { + printk(KERN_ERR + "qla2xxx: Unable to allocate SRB cache...Failing load!\n"); + return -ENOMEM; + } + + printk(KERN_INFO + "QLogic ISP2xxx PCI/PCI-X Fibre Channel HBA Driver (%p)\n", + qla2x00_set_info); + + return 0; +} + +/** + * qla2x00_module_exit - Module cleanup. + **/ +static void __exit +qla2x00_module_exit(void) +{ + /* Free SRBs cache. */ + if (srb_cachep != NULL) { + if (kmem_cache_destroy(srb_cachep) != 0) { + printk(KERN_ERR + "qla2xxx: Unable to free SRB cache...Memory pools " + "still active?\n"); + } + srb_cachep = NULL; + } +} + +module_init(qla2x00_module_init); +module_exit(qla2x00_module_exit); + +MODULE_AUTHOR("QLogic Corporation"); +MODULE_DESCRIPTION("QLogic ISP2xxx FC-SCSI Host Bus Adapter driver"); +MODULE_LICENSE("GPL"); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qla_os.h 830-ivtv/drivers/scsi/qla2xxx/qla_os.h --- 000-virgin/drivers/scsi/qla2xxx/qla_os.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qla_os.h Thu Jan 8 10:22:00 2004 @@ -0,0 +1,123 @@ +/****************************************************************************** + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * Portions (C) Arjan van de Ven for Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + ******************************************************************************/ + +#ifndef __QLA_OS_H +#define __QLA_OS_H + +/* + * Driver debug definitions. + */ +/* #define QL_DEBUG_LEVEL_1 */ /* Output register accesses to COM1 */ +/* #define QL_DEBUG_LEVEL_2 */ /* Output error msgs to COM1 */ +/* #define QL_DEBUG_LEVEL_3 */ /* Output function trace msgs to COM1 */ +/* #define QL_DEBUG_LEVEL_4 */ /* Output NVRAM trace msgs to COM1 */ +/* #define QL_DEBUG_LEVEL_5 */ /* Output ring trace msgs to COM1 */ +/* #define QL_DEBUG_LEVEL_6 */ /* Output WATCHDOG timer trace to COM1 */ +/* #define QL_DEBUG_LEVEL_7 */ /* Output RISC load trace msgs to COM1 */ +/* #define QL_DEBUG_LEVEL_8 */ /* Output ring saturation msgs to COM1 */ +/* #define QL_DEBUG_LEVEL_9 */ /* Output IOCTL trace msgs */ +/* #define QL_DEBUG_LEVEL_10 */ /* Output IOCTL error msgs */ +/* #define QL_DEBUG_LEVEL_11 */ /* Output Mbx Cmd trace msgs */ +/* #define QL_DEBUG_LEVEL_12 */ /* Output IP trace msgs */ +/* #define QL_DEBUG_LEVEL_13 */ /* Output fdmi function trace msgs */ +/* #define QL_DEBUG_LEVEL_14 */ /* Output RSCN trace msgs */ +/* + * Local Macro Definitions. + */ +#if defined(QL_DEBUG_LEVEL_1) || defined(QL_DEBUG_LEVEL_2) || \ + defined(QL_DEBUG_LEVEL_3) || defined(QL_DEBUG_LEVEL_4) || \ + defined(QL_DEBUG_LEVEL_5) || defined(QL_DEBUG_LEVEL_6) || \ + defined(QL_DEBUG_LEVEL_7) || defined(QL_DEBUG_LEVEL_8) || \ + defined(QL_DEBUG_LEVEL_9) || defined(QL_DEBUG_LEVEL_10) || \ + defined(QL_DEBUG_LEVEL_11) || defined(QL_DEBUG_LEVEL_12) || \ + defined(QL_DEBUG_LEVEL_13) || defined(QL_DEBUG_LEVEL_14) + #define QL_DEBUG_ROUTINES +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define __KERNEL_SYSCALLS__ +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "scsi.h" +#include "hosts.h" + +#include +#include + +//TODO Fix this!!! +/* +* String arrays +*/ +#define LINESIZE 256 +#define MAXARGS 26 + +/*********************************************************************** +* We use the struct scsi_pointer structure that's included with each +* command SCSI_Cmnd as a scratchpad. +* +* SCp is defined as follows: +* - SCp.ptr -- > pointer to the SRB +* - SCp.this_residual -- > HBA completion status for ioctl code. +* +* Cmnd->host_scribble --> Used to hold the hba actived handle (1..255). +***********************************************************************/ +#define CMD_SP(Cmnd) ((Cmnd)->SCp.ptr) +#define CMD_COMPL_STATUS(Cmnd) ((Cmnd)->SCp.this_residual) +/* Additional fields used by ioctl passthru */ +#define CMD_RESID_LEN(Cmnd) ((Cmnd)->SCp.buffers_residual) +#define CMD_SCSI_STATUS(Cmnd) ((Cmnd)->SCp.Status) +#define CMD_ACTUAL_SNSLEN(Cmnd) ((Cmnd)->SCp.Message) +#define CMD_ENTRY_STATUS(Cmnd) ((Cmnd)->SCp.have_data_in) + +#endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qla_rscn.c 830-ivtv/drivers/scsi/qla2xxx/qla_rscn.c --- 000-virgin/drivers/scsi/qla2xxx/qla_rscn.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qla_rscn.c Thu Jan 8 10:22:00 2004 @@ -0,0 +1,1458 @@ +/* + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ +#include "qla_os.h" + +#include "qla_def.h" + +/** + * IO descriptor handle definitions. + * + * Signature form: + * + * |31------28|27-------------------12|11-------0| + * | Type | Rolling Signature | Index | + * |----------|-----------------------|----------| + * + **/ + +#define HDL_TYPE_SCSI 0 +#define HDL_TYPE_ASYNC_IOCB 0x0A + +#define HDL_INDEX_BITS 12 +#define HDL_ITER_BITS 16 +#define HDL_TYPE_BITS 4 + +#define HDL_INDEX_MASK ((1UL << HDL_INDEX_BITS) - 1) +#define HDL_ITER_MASK ((1UL << HDL_ITER_BITS) - 1) +#define HDL_TYPE_MASK ((1UL << HDL_TYPE_BITS) - 1) + +#define HDL_INDEX_SHIFT 0 +#define HDL_ITER_SHIFT (HDL_INDEX_SHIFT + HDL_INDEX_BITS) +#define HDL_TYPE_SHIFT (HDL_ITER_SHIFT + HDL_ITER_BITS) + +/* Local Prototypes. */ +static inline uint32_t qla2x00_to_handle(uint16_t, uint16_t, uint16_t); +static inline uint16_t qla2x00_handle_to_idx(uint32_t); +static inline uint16_t qla2x00_handle_to_iter(uint32_t); +static inline uint16_t qla2x00_handle_to_type(uint32_t); +static inline uint32_t qla2x00_iodesc_to_handle(struct io_descriptor *); +static inline struct io_descriptor *qla2x00_handle_to_iodesc(scsi_qla_host_t *, + uint32_t); + +static inline struct io_descriptor *qla2x00_alloc_iodesc(scsi_qla_host_t *); +static inline void qla2x00_free_iodesc(struct io_descriptor *); +static inline void qla2x00_init_io_descriptors(scsi_qla_host_t *); + +static void qla2x00_iodesc_timeout(unsigned long); +static inline void qla2x00_add_iodesc_timer(struct io_descriptor *); +static inline void qla2x00_remove_iodesc_timer(struct io_descriptor *); + +static inline void qla2x00_update_login_fcport(scsi_qla_host_t *, + struct mbx_entry *, fc_port_t *); + +static int qla2x00_send_abort_iocb(scsi_qla_host_t *, struct io_descriptor *, + uint32_t, int); +static int qla2x00_send_abort_iocb_cb(scsi_qla_host_t *, struct io_descriptor *, + struct mbx_entry *); + +static int qla2x00_send_adisc_iocb(scsi_qla_host_t *, struct io_descriptor *, + int); +static int qla2x00_send_adisc_iocb_cb(scsi_qla_host_t *, struct io_descriptor *, + struct mbx_entry *); + +static int qla2x00_send_logout_iocb(scsi_qla_host_t *, struct io_descriptor *, + int); +static int qla2x00_send_logout_iocb_cb(scsi_qla_host_t *, + struct io_descriptor *, struct mbx_entry *); + +static int qla2x00_send_login_iocb(scsi_qla_host_t *, struct io_descriptor *, + port_id_t *, int); +static int qla2x00_send_login_iocb_cb(scsi_qla_host_t *, struct io_descriptor *, + struct mbx_entry *); + +/** + * Mailbox IOCB callback array. + **/ +int (*iocb_function_cb_list[LAST_IOCB_CB]) + (scsi_qla_host_t *, struct io_descriptor *, struct mbx_entry *) = { + + qla2x00_send_abort_iocb_cb, + qla2x00_send_adisc_iocb_cb, + qla2x00_send_logout_iocb_cb, + qla2x00_send_login_iocb_cb, +}; + + +/** + * Generic IO descriptor handle routines. + **/ + +/** + * qla2x00_to_handle() - Create a descriptor handle. + * @type: descriptor type + * @iter: descriptor rolling signature + * @idx: index to the descriptor array + * + * Returns a composite handle based in the @type, @iter, and @idx. + */ +static inline uint32_t +qla2x00_to_handle(uint16_t type, uint16_t iter, uint16_t idx) +{ + return ((uint32_t)(((uint32_t)type << HDL_TYPE_SHIFT) | + ((uint32_t)iter << HDL_ITER_SHIFT) | + ((uint32_t)idx << HDL_INDEX_SHIFT))); +} + +/** + * qla2x00_handle_to_idx() - Retrive the index for a given handle. + * @handle: descriptor handle + * + * Returns the index specified by the @handle. + */ +static inline uint16_t +qla2x00_handle_to_idx(uint32_t handle) +{ + return ((uint16_t)(((handle) >> HDL_INDEX_SHIFT) & HDL_INDEX_MASK)); +} + +/** + * qla2x00_handle_to_type() - Retrive the descriptor type for a given handle. + * @handle: descriptor handle + * + * Returns the descriptor type specified by the @handle. + */ +static inline uint16_t +qla2x00_handle_to_type(uint32_t handle) +{ + return ((uint16_t)(((handle) >> HDL_TYPE_SHIFT) & HDL_TYPE_MASK)); +} + +/** + * qla2x00_handle_to_iter() - Retrive the rolling signature for a given handle. + * @handle: descriptor handle + * + * Returns the signature specified by the @handle. + */ +static inline uint16_t +qla2x00_handle_to_iter(uint32_t handle) +{ + return ((uint16_t)(((handle) >> HDL_ITER_SHIFT) & HDL_ITER_MASK)); +} + +/** + * qla2x00_iodesc_to_handle() - Convert an IO descriptor to a unique handle. + * @iodesc: io descriptor + * + * Returns a unique handle for @iodesc. + */ +static inline uint32_t +qla2x00_iodesc_to_handle(struct io_descriptor *iodesc) +{ + uint32_t handle; + + handle = qla2x00_to_handle(HDL_TYPE_ASYNC_IOCB, + ++iodesc->ha->iodesc_signature, iodesc->idx); + iodesc->signature = handle; + + return (handle); +} + +/** + * qla2x00_handle_to_iodesc() - Retrieve an IO descriptor given a unique handle. + * @ha: HA context + * @handle: handle to io descriptor + * + * Returns a pointer to the io descriptor, or NULL, if the io descriptor does + * not exist or the io descriptors signature does not @handle. + */ +static inline struct io_descriptor * +qla2x00_handle_to_iodesc(scsi_qla_host_t *ha, uint32_t handle) +{ + uint16_t idx; + struct io_descriptor *iodesc; + + idx = qla2x00_handle_to_idx(handle); + iodesc = &ha->io_descriptors[idx]; + if (iodesc) + if (iodesc->signature != handle) + iodesc = NULL; + + return (iodesc); +} + + +/** + * IO descriptor allocation routines. + **/ + +/** + * qla2x00_alloc_iodesc() - Allocate an IO descriptor from the pool. + * @ha: HA context + * + * Returns a pointer to the allocated io descriptor, or NULL, if none available. + */ +static inline struct io_descriptor * +qla2x00_alloc_iodesc(scsi_qla_host_t *ha) +{ + uint16_t iter; + struct io_descriptor *iodesc; + + iodesc = NULL; + for (iter = 0; iter < MAX_IO_DESCRIPTORS; iter++) { + if (ha->io_descriptors[iter].used) + continue; + + iodesc = &ha->io_descriptors[iter]; + iodesc->used = 1; + iodesc->idx = iter; + init_timer(&iodesc->timer); + iodesc->ha = ha; + iodesc->signature = qla2x00_iodesc_to_handle(iodesc); + break; + } + + return (iodesc); +} + +/** + * qla2x00_free_iodesc() - Free an IO descriptor. + * @iodesc: io descriptor + * + * NOTE: The io descriptors timer *must* be stopped before it can be free'd. + */ +static inline void +qla2x00_free_iodesc(struct io_descriptor *iodesc) +{ + iodesc->used = 0; + iodesc->signature = 0; +} + +/** + * qla2x00_init_io_descriptors() - Initialize the pool of IO descriptors. + * @ha: HA context + */ +static inline void +qla2x00_init_io_descriptors(scsi_qla_host_t *ha) +{ + uint16_t iter; + + for (iter = 0; iter < MAX_IO_DESCRIPTORS; iter++) { + if (!ha->io_descriptors[iter].used) + continue; + + qla2x00_remove_iodesc_timer(&ha->io_descriptors[iter]); + qla2x00_free_iodesc(&ha->io_descriptors[iter]); + } +} + + +/** + * IO descriptor timer routines. + **/ + +/** + * qla2x00_iodesc_timeout() - Timeout IO descriptor handler. + * @data: io descriptor + */ +static void +qla2x00_iodesc_timeout(unsigned long data) +{ + struct io_descriptor *iodesc; + + iodesc = (struct io_descriptor *) data; + + DEBUG14(printk("scsi(%ld): IO descriptor timeout, index=%x " + "signature=%08x, scheduling ISP abort.\n", iodesc->ha->host_no, + iodesc->idx, iodesc->signature)); + + qla2x00_free_iodesc(iodesc); + + set_bit(ISP_ABORT_NEEDED, &iodesc->ha->dpc_flags); +} + +/** + * qla2x00_add_iodesc_timer() - Add and start a timer for an IO descriptor. + * @iodesc: io descriptor + * + * NOTE: + * The firmware shall timeout an outstanding mailbox IOCB in 2 * R_A_TOV (in + * tenths of a second). The driver will wait 2.5 * R_A_TOV before scheduling + * a recovery (big hammer). + */ +static inline void +qla2x00_add_iodesc_timer(struct io_descriptor *iodesc) +{ + unsigned long timeout; + + timeout = ((iodesc->ha->r_a_tov * 2) + (iodesc->ha->r_a_tov / 2)) / 10; + init_timer(&iodesc->timer); + iodesc->timer.data = (unsigned long) iodesc; + iodesc->timer.expires = jiffies + (timeout * HZ); + iodesc->timer.function = + (void (*) (unsigned long)) qla2x00_iodesc_timeout; + add_timer(&iodesc->timer); +} + +/** + * qla2x00_remove_iodesc_timer() - Remove an active timer from an IO descriptor. + * @iodesc: io descriptor + */ +static inline void +qla2x00_remove_iodesc_timer(struct io_descriptor *iodesc) +{ + if (iodesc->timer.function != NULL) { + del_timer_sync(&iodesc->timer); + iodesc->timer.data = (unsigned long) NULL; + iodesc->timer.function = NULL; + } +} + +/** + * IO descriptor support routines. + **/ + +/** + * qla2x00_update_login_fcport() - Update fcport data after login processing. + * @ha: HA context + * @mbxstat: Mailbox command status IOCB + * @fcport: port to update + */ +static inline void +qla2x00_update_login_fcport(scsi_qla_host_t *ha, struct mbx_entry *mbxstat, + fc_port_t *fcport) +{ + if (le16_to_cpu(mbxstat->mb1) & BIT_0) { + fcport->port_type = FCT_INITIATOR; + } else { + fcport->port_type = FCT_TARGET; + if (le16_to_cpu(mbxstat->mb1) & BIT_1) { + fcport->flags |= FCF_TAPE_PRESENT; + } + } + fcport->login_retry = 0; + fcport->port_login_retry_count = ha->port_down_retry_count * + PORT_RETRY_TIME; + atomic_set(&fcport->port_down_timer, ha->port_down_retry_count * + PORT_RETRY_TIME); + fcport->flags |= FCF_FABRIC_DEVICE; + fcport->flags &= ~FCF_FAILOVER_NEEDED; + fcport->iodesc_idx_sent = IODESC_INVALID_INDEX; + atomic_set(&fcport->state, FCS_ONLINE); +} + + +/** + * Mailbox IOCB commands. + **/ + +/** + * qla2x00_get_mbx_iocb_entry() - Retrieve an IOCB from the request queue. + * @ha: HA context + * @handle: handle to io descriptor + * + * Returns a pointer to the reqest entry, or NULL, if none were available. + */ +static inline struct mbx_entry * +qla2x00_get_mbx_iocb_entry(scsi_qla_host_t *ha, uint32_t handle) +{ + uint16_t cnt; + device_reg_t *reg; + struct mbx_entry *mbxentry; + + reg = ha->iobase; + mbxentry = NULL; + + if (ha->req_q_cnt < 3) { + cnt = qla2x00_debounce_register(ISP_REQ_Q_OUT(ha, reg)); + if (ha->req_ring_index < cnt) + ha->req_q_cnt = cnt - ha->req_ring_index; + else + ha->req_q_cnt = REQUEST_ENTRY_CNT - + (ha->req_ring_index - cnt); + } + if (ha->req_q_cnt >= 3) { + mbxentry = (struct mbx_entry *)ha->request_ring_ptr; + + memset(mbxentry, 0, sizeof(struct mbx_entry)); + mbxentry->entry_type = MBX_IOCB_TYPE; + mbxentry->entry_count = 1; + mbxentry->sys_define1 = SOURCE_ASYNC_IOCB; + mbxentry->handle = handle; + } + return (mbxentry); +} + +/** + * qla2x00_send_abort_iocb() - Issue an abort IOCB to the firmware. + * @ha: HA context + * @iodesc: io descriptor + * @handle_to_abort: firmware handle to abort + * @ha_locked: is function called with the hardware lock + * + * Returns QLA_SUCCESS if the IOCB was issued. + */ +static int +qla2x00_send_abort_iocb(scsi_qla_host_t *ha, struct io_descriptor *iodesc, + uint32_t handle_to_abort, int ha_locked) +{ + unsigned long flags = 0; + struct mbx_entry *mbxentry; + + /* Send marker if required. */ + if (qla2x00_issue_marker(ha, ha_locked) != QLA_SUCCESS) + return (QLA_FUNCTION_FAILED); + + if (!ha_locked) + spin_lock_irqsave(&ha->hardware_lock, flags); + + /* Build abort mailbox IOCB. */ + mbxentry = qla2x00_get_mbx_iocb_entry(ha, iodesc->signature); + if (mbxentry == NULL) { + if (!ha_locked) + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + return (QLA_FUNCTION_FAILED); + } + mbxentry->mb0 = __constant_cpu_to_le16(MBC_ABORT_COMMAND); + mbxentry->mb1 = mbxentry->loop_id.extended = + cpu_to_le16(iodesc->remote_fcport->loop_id); + mbxentry->mb2 = LSW(handle_to_abort); + mbxentry->mb3 = MSW(handle_to_abort); + + qla2x00_add_iodesc_timer(iodesc); + + /* Issue command to ISP. */ + qla2x00_isp_cmd(ha); + + if (!ha_locked) + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + DEBUG14(printk("scsi(%ld): Sending Abort IOCB (%08x) to [%x], aborting " + "%08x.\n", ha->host_no, iodesc->signature, + iodesc->remote_fcport->loop_id, handle_to_abort)); + + return (QLA_SUCCESS); +} + +/** + * qla2x00_send_abort_iocb_cb() - Abort IOCB callback. + * @ha: HA context + * @iodesc: io descriptor + * @mbxstat: mailbox status IOCB + * + * Returns QLA_SUCCESS if @iodesc can be freed by the caller, else, @iodesc + * will be used for a retry. + */ +static int +qla2x00_send_abort_iocb_cb(scsi_qla_host_t *ha, struct io_descriptor *iodesc, + struct mbx_entry *mbxstat) +{ + DEBUG14(printk("scsi(%ld): Abort IOCB -- sent to [%x/%02x%02x%02x], " + "status=%x mb0=%x.\n", ha->host_no, iodesc->remote_fcport->loop_id, + iodesc->d_id.b.domain, iodesc->d_id.b.area, iodesc->d_id.b.al_pa, + le16_to_cpu(mbxstat->status), le16_to_cpu(mbxstat->mb0))); + + return (QLA_SUCCESS); +} + + +/** + * qla2x00_send_adisc_iocb() - Issue a Get Port Database IOCB to the firmware. + * @ha: HA context + * @iodesc: io descriptor + * @ha_locked: is function called with the hardware lock + * + * Returns QLA_SUCCESS if the IOCB was issued. + */ +static int +qla2x00_send_adisc_iocb(scsi_qla_host_t *ha, struct io_descriptor *iodesc, + int ha_locked) +{ + unsigned long flags = 0; + struct mbx_entry *mbxentry; + + /* Send marker if required. */ + if (qla2x00_issue_marker(ha, ha_locked) != QLA_SUCCESS) + return (QLA_FUNCTION_FAILED); + + if (!ha_locked) + spin_lock_irqsave(&ha->hardware_lock, flags); + + /* Build Get Port Database IOCB. */ + mbxentry = qla2x00_get_mbx_iocb_entry(ha, iodesc->signature); + if (mbxentry == NULL) { + if (!ha_locked) + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + return (QLA_FUNCTION_FAILED); + } + mbxentry->mb0 = __constant_cpu_to_le16(MBC_GET_PORT_DATABASE); + mbxentry->mb1 = mbxentry->loop_id.extended = + cpu_to_le16(iodesc->remote_fcport->loop_id); + mbxentry->mb2 = cpu_to_le16(MSW(LSD(ha->iodesc_pd_dma))); + mbxentry->mb3 = cpu_to_le16(LSW(LSD(ha->iodesc_pd_dma))); + mbxentry->mb6 = cpu_to_le16(MSW(MSD(ha->iodesc_pd_dma))); + mbxentry->mb7 = cpu_to_le16(LSW(MSD(ha->iodesc_pd_dma))); + mbxentry->mb10 = __constant_cpu_to_le16(BIT_0); + + qla2x00_add_iodesc_timer(iodesc); + + /* Issue command to ISP. */ + qla2x00_isp_cmd(ha); + + if (!ha_locked) + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + DEBUG14(printk("scsi(%ld): Sending Adisc IOCB (%08x) to [%x].\n", + ha->host_no, iodesc->signature, iodesc->remote_fcport->loop_id)); + + return (QLA_SUCCESS); +} + +/** + * qla2x00_send_adisc_iocb_cb() - Get Port Database IOCB callback. + * @ha: HA context + * @iodesc: io descriptor + * @mbxstat: mailbox status IOCB + * + * Returns QLA_SUCCESS if @iodesc can be freed by the caller, else, @iodesc + * will be used for a retry. + */ +static int +qla2x00_send_adisc_iocb_cb(scsi_qla_host_t *ha, struct io_descriptor *iodesc, + struct mbx_entry *mbxstat) +{ + fc_port_t *remote_fcport; + + remote_fcport = iodesc->remote_fcport; + + /* Ensure the port IDs are consistent. */ + if (remote_fcport->d_id.b24 != iodesc->d_id.b24) { + DEBUG14(printk("scsi(%ld): Adisc IOCB -- ignoring, remote port " + "id changed from [%02x%02x%02x] to [%02x%02x%02x].\n", + ha->host_no, remote_fcport->d_id.b.domain, + remote_fcport->d_id.b.area, remote_fcport->d_id.b.al_pa, + iodesc->d_id.b.domain, iodesc->d_id.b.area, + iodesc->d_id.b.al_pa)); + + return (QLA_SUCCESS); + } + + /* Only process the last command. */ + if (remote_fcport->iodesc_idx_sent != iodesc->idx) { + DEBUG14(printk("scsi(%ld): Adisc IOCB -- ignoring, sent to " + "[%02x%02x%02x], expected %x, received %x.\n", ha->host_no, + iodesc->d_id.b.domain, iodesc->d_id.b.area, + iodesc->d_id.b.al_pa, remote_fcport->iodesc_idx_sent, + iodesc->idx)); + + return (QLA_SUCCESS); + } + + if (le16_to_cpu(mbxstat->status) == CS_COMPLETE) { + DEBUG14(printk("scsi(%ld): Adisc IOCB -- marking " + "[%x/%02x%02x%02x] online.\n", ha->host_no, + remote_fcport->loop_id, remote_fcport->d_id.b.domain, + remote_fcport->d_id.b.area, remote_fcport->d_id.b.al_pa)); + + atomic_set(&remote_fcport->state, FCS_ONLINE); + } else { + DEBUG14(printk("scsi(%ld): Adisc IOCB -- marking " + "[%x/%02x%02x%02x] lost, status=%x mb0=%x.\n", ha->host_no, + remote_fcport->loop_id, remote_fcport->d_id.b.domain, + remote_fcport->d_id.b.area, remote_fcport->d_id.b.al_pa, + le16_to_cpu(mbxstat->status), le16_to_cpu(mbxstat->mb0))); + + if (atomic_read(&remote_fcport->state) != FCS_DEVICE_DEAD) + atomic_set(&remote_fcport->state, FCS_DEVICE_LOST); + } + remote_fcport->iodesc_idx_sent = IODESC_INVALID_INDEX; + + return (QLA_SUCCESS); +} + + +/** + * qla2x00_send_logout_iocb() - Issue a fabric port logout IOCB to the firmware. + * @ha: HA context + * @iodesc: io descriptor + * @ha_locked: is function called with the hardware lock + * + * Returns QLA_SUCCESS if the IOCB was issued. + */ +static int +qla2x00_send_logout_iocb(scsi_qla_host_t *ha, struct io_descriptor *iodesc, + int ha_locked) +{ + unsigned long flags = 0; + struct mbx_entry *mbxentry; + + /* Send marker if required. */ + if (qla2x00_issue_marker(ha, ha_locked) != QLA_SUCCESS) + return (QLA_FUNCTION_FAILED); + + if (!ha_locked) + spin_lock_irqsave(&ha->hardware_lock, flags); + + /* Build fabric port logout mailbox IOCB. */ + mbxentry = qla2x00_get_mbx_iocb_entry(ha, iodesc->signature); + if (mbxentry == NULL) { + if (!ha_locked) + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + return (QLA_FUNCTION_FAILED); + } + mbxentry->mb0 = __constant_cpu_to_le16(MBC_LOGOUT_FABRIC_PORT); + mbxentry->mb1 = mbxentry->loop_id.extended = + cpu_to_le16(iodesc->remote_fcport->loop_id); + + qla2x00_add_iodesc_timer(iodesc); + + /* Issue command to ISP. */ + qla2x00_isp_cmd(ha); + + if (!ha_locked) + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + DEBUG14(printk("scsi(%ld): Sending Logout IOCB (%08x) to [%x].\n", + ha->host_no, iodesc->signature, iodesc->remote_fcport->loop_id)); + + return (QLA_SUCCESS); +} + +/** + * qla2x00_send_logout_iocb_cb() - Fabric port logout IOCB callback. + * @ha: HA context + * @iodesc: io descriptor + * @mbxstat: mailbox status IOCB + * + * Returns QLA_SUCCESS if @iodesc can be freed by the caller, else, @iodesc + * will be used for a retry. + */ +static int +qla2x00_send_logout_iocb_cb(scsi_qla_host_t *ha, struct io_descriptor *iodesc, + struct mbx_entry *mbxstat) +{ + DEBUG14(printk("scsi(%ld): Logout IOCB -- sent to [%x/%02x%02x%02x], " + "status=%x mb0=%x mb1=%x.\n", ha->host_no, + iodesc->remote_fcport->loop_id, + iodesc->remote_fcport->d_id.b.domain, + iodesc->remote_fcport->d_id.b.area, + iodesc->remote_fcport->d_id.b.al_pa, le16_to_cpu(mbxstat->status), + le16_to_cpu(mbxstat->mb0), le16_to_cpu(mbxstat->mb1))); + + return (QLA_SUCCESS); +} + + +/** + * qla2x00_send_login_iocb() - Issue a fabric port login IOCB to the firmware. + * @ha: HA context + * @iodesc: io descriptor + * @d_id: port id for device + * @ha_locked: is function called with the hardware lock + * + * Returns QLA_SUCCESS if the IOCB was issued. + */ +static int +qla2x00_send_login_iocb(scsi_qla_host_t *ha, struct io_descriptor *iodesc, + port_id_t *d_id, int ha_locked) +{ + unsigned long flags = 0; + struct mbx_entry *mbxentry; + + /* Send marker if required. */ + if (qla2x00_issue_marker(ha, ha_locked) != QLA_SUCCESS) + return (QLA_FUNCTION_FAILED); + + if (!ha_locked) + spin_lock_irqsave(&ha->hardware_lock, flags); + + /* Build fabric port login mailbox IOCB. */ + mbxentry = qla2x00_get_mbx_iocb_entry(ha, iodesc->signature); + if (mbxentry == NULL) { + if (!ha_locked) + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + return (QLA_FUNCTION_FAILED); + } + mbxentry->mb0 = __constant_cpu_to_le16(MBC_LOGIN_FABRIC_PORT); + mbxentry->mb1 = mbxentry->loop_id.extended = + cpu_to_le16(iodesc->remote_fcport->loop_id); + mbxentry->mb2 = cpu_to_le16(d_id->b.domain); + mbxentry->mb3 = cpu_to_le16(d_id->b.area << 8 | d_id->b.al_pa); + mbxentry->mb10 = __constant_cpu_to_le16(BIT_0); + + qla2x00_add_iodesc_timer(iodesc); + + /* Issue command to ISP. */ + qla2x00_isp_cmd(ha); + + if (!ha_locked) + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + DEBUG14(printk("scsi(%ld): Sending Login IOCB (%08x) to " + "[%x/%02x%02x%02x].\n", ha->host_no, iodesc->signature, + iodesc->remote_fcport->loop_id, d_id->b.domain, d_id->b.area, + d_id->b.al_pa)); + + return (QLA_SUCCESS); +} + +/** + * qla2x00_send_login_iocb_cb() - Fabric port logout IOCB callback. + * @ha: HA context + * @iodesc: io descriptor + * @mbxstat: mailbox status IOCB + * + * Returns QLA_SUCCESS if @iodesc can be freed by the caller, else, @iodesc + * will be used for a retry. + */ +static int +qla2x00_send_login_iocb_cb(scsi_qla_host_t *ha, struct io_descriptor *iodesc, + struct mbx_entry *mbxstat) +{ + int rval; + fc_port_t *fcport, *remote_fcport, *exist_fcport; + struct io_descriptor *abort_iodesc, *login_iodesc; + uint16_t status, mb[8]; + uint16_t reuse; + uint16_t remote_loopid; + port_id_t remote_did, inuse_did; + + remote_fcport = iodesc->remote_fcport; + + /* Only process the last command. */ + if (remote_fcport->iodesc_idx_sent != iodesc->idx) { + DEBUG14(printk("scsi(%ld): Login IOCB -- ignoring, sent to " + "[%02x%02x%02x], expected %x, received %x.\n", + ha->host_no, iodesc->d_id.b.domain, iodesc->d_id.b.area, + iodesc->d_id.b.al_pa, remote_fcport->iodesc_idx_sent, + iodesc->idx)); + + /* Free RSCN fcport resources. */ + if (remote_fcport->port_type == FCT_RSCN) { + DEBUG14(printk("scsi(%ld): Login IOCB -- Freeing RSCN " + "fcport %p [%x/%02x%02x%02x] given ignored Login " + "IOCB.\n", ha->host_no, remote_fcport, + remote_fcport->loop_id, + remote_fcport->d_id.b.domain, + remote_fcport->d_id.b.area, + remote_fcport->d_id.b.al_pa)); + + list_del(&remote_fcport->list); + kfree(remote_fcport); + } + return (QLA_SUCCESS); + } + + status = le16_to_cpu(mbxstat->status); + mb[0] = le16_to_cpu(mbxstat->mb0); + mb[1] = le16_to_cpu(mbxstat->mb1); + mb[2] = le16_to_cpu(mbxstat->mb2); + mb[6] = le16_to_cpu(mbxstat->mb6); + mb[7] = le16_to_cpu(mbxstat->mb7); + + /* Good status? */ + if ((status == CS_COMPLETE || status == CS_COMPLETE_CHKCOND) && + mb[0] == MBS_COMMAND_COMPLETE) { + + DEBUG14(printk("scsi(%ld): Login IOCB -- status=%x mb1=%x pn=" + "%02x%02x%02x%02x%02x%02x%02x%02x.\n", ha->host_no, status, + mb[1], mbxstat->port_name[0], mbxstat->port_name[1], + mbxstat->port_name[2], mbxstat->port_name[3], + mbxstat->port_name[4], mbxstat->port_name[5], + mbxstat->port_name[6], mbxstat->port_name[7])); + + memcpy(remote_fcport->node_name, mbxstat->node_name, WWN_SIZE); + memcpy(remote_fcport->port_name, mbxstat->port_name, WWN_SIZE); + + /* Is the device already in our fcports list? */ + if (remote_fcport->port_type != FCT_RSCN) { + DEBUG14(printk("scsi(%ld): Login IOCB -- marking " + "[%x/%02x%02x%02x] online.\n", ha->host_no, + remote_fcport->loop_id, + remote_fcport->d_id.b.domain, + remote_fcport->d_id.b.area, + remote_fcport->d_id.b.al_pa)); + + qla2x00_update_login_fcport(ha, mbxstat, remote_fcport); + + return (QLA_SUCCESS); + } + + /* Does the RSCN portname already exist in our fcports list? */ + exist_fcport = NULL; + list_for_each_entry(fcport, &ha->fcports, list) { + if (memcmp(remote_fcport->port_name, fcport->port_name, + WWN_SIZE) == 0) { + exist_fcport = fcport; + break; + } + } + if (exist_fcport != NULL) { + DEBUG14(printk("scsi(%ld): Login IOCB -- found RSCN " + "fcport in fcports list [%p].\n", ha->host_no, + exist_fcport)); + + /* Abort any ADISC that could have been sent. */ + if (exist_fcport->iodesc_idx_sent != iodesc->idx && + exist_fcport->iodesc_idx_sent < + MAX_IO_DESCRIPTORS && + ha->io_descriptors[exist_fcport->iodesc_idx_sent]. + cb_idx == ADISC_PORT_IOCB_CB) { + + abort_iodesc = qla2x00_alloc_iodesc(ha); + if (abort_iodesc) { + DEBUG14(printk("scsi(%ld): Login IOCB " + "-- issuing abort to outstanding " + "Adisc [%x/%02x%02x%02x].\n", + ha->host_no, remote_fcport->loop_id, + exist_fcport->d_id.b.domain, + exist_fcport->d_id.b.area, + exist_fcport->d_id.b.al_pa)); + + abort_iodesc->cb_idx = ABORT_IOCB_CB; + abort_iodesc->d_id.b24 = + exist_fcport->d_id.b24; + abort_iodesc->remote_fcport = + exist_fcport; + exist_fcport->iodesc_idx_sent = + abort_iodesc->idx; + qla2x00_send_abort_iocb(ha, + abort_iodesc, ha->io_descriptors[ + exist_fcport->iodesc_idx_sent]. + signature, 1); + } else { + DEBUG14(printk("scsi(%ld): Login IOCB " + "-- unable to abort outstanding " + "Adisc [%x/%02x%02x%02x].\n", + ha->host_no, remote_fcport->loop_id, + exist_fcport->d_id.b.domain, + exist_fcport->d_id.b.area, + exist_fcport->d_id.b.al_pa)); + } + } + + /* + * If the existing fcport is waiting to send an ADISC + * or LOGIN, then reuse remote fcport (RSCN) to + * continue waiting. + */ + reuse = 0; + remote_loopid = remote_fcport->loop_id; + remote_did.b24 = remote_fcport->d_id.b24; + if (exist_fcport->iodesc_idx_sent == + IODESC_ADISC_NEEDED || + exist_fcport->iodesc_idx_sent == + IODESC_LOGIN_NEEDED) { + DEBUG14(printk("scsi(%ld): Login IOCB -- " + "existing fcport [%x/%02x%02x%02x] " + "waiting for IO descriptor, reuse RSCN " + "fcport.\n", ha->host_no, + exist_fcport->loop_id, + exist_fcport->d_id.b.domain, + exist_fcport->d_id.b.area, + exist_fcport->d_id.b.al_pa)); + + reuse++; + remote_fcport->iodesc_idx_sent = + exist_fcport->iodesc_idx_sent; + exist_fcport->iodesc_idx_sent = + IODESC_INVALID_INDEX; + remote_fcport->loop_id = exist_fcport->loop_id; + remote_fcport->d_id.b24 = + exist_fcport->d_id.b24; + } + + /* Logout the old loopid. */ + if (!reuse && + exist_fcport->loop_id != remote_fcport->loop_id && + exist_fcport->loop_id != FC_NO_LOOP_ID) { + login_iodesc = qla2x00_alloc_iodesc(ha); + if (login_iodesc) { + DEBUG14(printk("scsi(%ld): Login IOCB " + "-- issuing logout to free old " + "loop id [%x/%02x%02x%02x].\n", + ha->host_no, exist_fcport->loop_id, + exist_fcport->d_id.b.domain, + exist_fcport->d_id.b.area, + exist_fcport->d_id.b.al_pa)); + + login_iodesc->cb_idx = + LOGOUT_PORT_IOCB_CB; + login_iodesc->d_id.b24 = + exist_fcport->d_id.b24; + login_iodesc->remote_fcport = + exist_fcport; + exist_fcport->iodesc_idx_sent = + login_iodesc->idx; + qla2x00_send_logout_iocb(ha, + login_iodesc, 1); + } else { + /* Ran out of IO descriptiors. */ + DEBUG14(printk("scsi(%ld): Login IOCB " + "-- unable to logout to free old " + "loop id [%x/%02x%02x%02x].\n", + ha->host_no, exist_fcport->loop_id, + exist_fcport->d_id.b.domain, + exist_fcport->d_id.b.area, + exist_fcport->d_id.b.al_pa)); + + exist_fcport->iodesc_idx_sent = + IODESC_INVALID_INDEX; + } + + } + + /* Update existing fcport with remote fcport info. */ + DEBUG14(printk("scsi(%ld): Login IOCB -- marking " + "existing fcport [%x/%02x%02x%02x] online.\n", + ha->host_no, remote_loopid, remote_did.b.domain, + remote_did.b.area, remote_did.b.al_pa)); + + memcpy(exist_fcport->node_name, + remote_fcport->node_name, WWN_SIZE); + exist_fcport->loop_id = remote_loopid; + exist_fcport->d_id.b24 = remote_did.b24; + qla2x00_update_login_fcport(ha, mbxstat, exist_fcport); + + /* Finally, free the remote (RSCN) fcport. */ + if (!reuse) { + DEBUG14(printk("scsi(%ld): Login IOCB -- " + "Freeing RSCN fcport %p " + "[%x/%02x%02x%02x].\n", ha->host_no, + remote_fcport, remote_fcport->loop_id, + remote_fcport->d_id.b.domain, + remote_fcport->d_id.b.area, + remote_fcport->d_id.b.al_pa)); + + list_del(&remote_fcport->list); + kfree(remote_fcport); + } + + return (QLA_SUCCESS); + } + + /* + * A new device has been added, move the RSCN fcport to our + * fcports list. + */ + DEBUG14(printk("scsi(%ld): Login IOCB -- adding RSCN fcport " + "[%x/%02x%02x%02x] to fcports list.\n", ha->host_no, + remote_fcport->loop_id, remote_fcport->d_id.b.domain, + remote_fcport->d_id.b.area, remote_fcport->d_id.b.al_pa)); + + list_del(&remote_fcport->list); + remote_fcport->flags = (FCF_RLC_SUPPORT | FCF_RESCAN_NEEDED); + qla2x00_update_login_fcport(ha, mbxstat, remote_fcport); + list_add_tail(&remote_fcport->list, &ha->fcports); + set_bit(FCPORT_RESCAN_NEEDED, &ha->dpc_flags); + } else { + /* Handle login failure. */ + if (remote_fcport->login_retry != 0) { + if (mb[0] == MBS_LOOP_ID_USED) { + inuse_did.b.domain = LSB(mb[1]); + inuse_did.b.area = MSB(mb[2]); + inuse_did.b.al_pa = LSB(mb[2]); + + DEBUG14(printk("scsi(%ld): Login IOCB -- loop " + "id [%x] used by port id [%02x%02x%02x].\n", + ha->host_no, remote_fcport->loop_id, + inuse_did.b.domain, inuse_did.b.area, + inuse_did.b.al_pa)); + + if (remote_fcport->d_id.b24 == + INVALID_PORT_ID) { + /* + * Invalid port id means we are trying + * to login to a remote port with just + * a loop id without knowing about the + * port id. Copy the port id and try + * again. + */ + remote_fcport->d_id.b24 = inuse_did.b24; + iodesc->d_id.b24 = inuse_did.b24; + } else { + remote_fcport->loop_id++; + rval = qla2x00_find_new_loop_id(ha, + remote_fcport); + if (rval == QLA_FUNCTION_FAILED) { + /* No more loop ids. */ + return (QLA_SUCCESS); + } + } + } else if (mb[0] == MBS_PORT_ID_USED) { + /* + * Device has another loop ID. The firmware + * group recommends the driver perform an + * implicit login with the specified ID. + */ + DEBUG14(printk("scsi(%ld): Login IOCB -- port " + "id [%02x%02x%02x] already assigned to " + "loop id [%x].\n", ha->host_no, + iodesc->d_id.b.domain, iodesc->d_id.b.area, + iodesc->d_id.b.al_pa, mb[1])); + + remote_fcport->loop_id = mb[1]; + + } else { + /* Unable to perform login, try again. */ + DEBUG14(printk("scsi(%ld): Login IOCB -- " + "failed login [%x/%02x%02x%02x], status=%x " + "mb0=%x mb1=%x mb2=%x mb6=%x mb7=%x.\n", + ha->host_no, remote_fcport->loop_id, + iodesc->d_id.b.domain, iodesc->d_id.b.area, + iodesc->d_id.b.al_pa, status, mb[0], mb[1], + mb[2], mb[6], mb[7])); + } + + /* Reissue Login with the same IO descriptor. */ + iodesc->signature = + qla2x00_iodesc_to_handle(iodesc); + iodesc->cb_idx = LOGIN_PORT_IOCB_CB; + iodesc->d_id.b24 = remote_fcport->d_id.b24; + remote_fcport->iodesc_idx_sent = iodesc->idx; + remote_fcport->login_retry--; + + DEBUG14(printk("scsi(%ld): Login IOCB -- retrying " + "login to [%x/%02x%02x%02x] (%d).\n", ha->host_no, + remote_fcport->loop_id, + remote_fcport->d_id.b.domain, + remote_fcport->d_id.b.area, + remote_fcport->d_id.b.al_pa, + remote_fcport->login_retry)); + + qla2x00_send_login_iocb(ha, iodesc, + &remote_fcport->d_id, 1); + + return (QLA_FUNCTION_FAILED); + } else { + /* No more logins, mark device dead. */ + DEBUG14(printk("scsi(%ld): Login IOCB -- failed " + "login [%x/%02x%02x%02x] after retries, status=%x " + "mb0=%x mb1=%x mb2=%x mb6=%x mb7=%x.\n", + ha->host_no, remote_fcport->loop_id, + iodesc->d_id.b.domain, iodesc->d_id.b.area, + iodesc->d_id.b.al_pa, status, mb[0], mb[1], + mb[2], mb[6], mb[7])); + + atomic_set(&remote_fcport->state, FCS_DEVICE_DEAD); + if (remote_fcport->port_type == FCT_RSCN) { + DEBUG14(printk("scsi(%ld): Login IOCB -- " + "Freeing dead RSCN fcport %p " + "[%x/%02x%02x%02x].\n", ha->host_no, + remote_fcport, remote_fcport->loop_id, + remote_fcport->d_id.b.domain, + remote_fcport->d_id.b.area, + remote_fcport->d_id.b.al_pa)); + + list_del(&remote_fcport->list); + kfree(remote_fcport); + } + } + } + + return (QLA_SUCCESS); +} + + +/** + * IO descriptor processing routines. + **/ + +/** + * qla2x00_alloc_rscn_fcport() - Allocate an RSCN type fcport. + * @ha: HA context + * @flags: allocation flags + * + * Returns a pointer to the allocated RSCN fcport, or NULL, if none available. + */ +fc_port_t * +qla2x00_alloc_rscn_fcport(scsi_qla_host_t *ha, int flags) +{ + fc_port_t *fcport; + + fcport = qla2x00_alloc_fcport(ha, flags); + if (fcport == NULL) + return (fcport); + + /* Setup RSCN fcport structure. */ + fcport->port_type = FCT_RSCN; + + return (fcport); +} + +/** + * qla2x00_handle_port_rscn() - Handle port RSCN. + * @ha: HA context + * @rscn_entry: RSCN entry + * @fcport: fcport entry to updated + * + * Returns QLA_SUCCESS if the port RSCN was handled. + */ +int +qla2x00_handle_port_rscn(scsi_qla_host_t *ha, uint32_t rscn_entry, + fc_port_t *known_fcport, int ha_locked) +{ + int rval; + port_id_t rscn_pid; + fc_port_t *fcport, *remote_fcport, *rscn_fcport; + struct io_descriptor *iodesc; + + remote_fcport = NULL; + rscn_fcport = NULL; + + /* Prepare port id based on incoming entries. */ + if (known_fcport) { + rscn_pid.b24 = known_fcport->d_id.b24; + remote_fcport = known_fcport; + + DEBUG14(printk("scsi(%ld): Handle RSCN -- process RSCN for " + "fcport [%02x%02x%02x].\n", ha->host_no, + remote_fcport->d_id.b.domain, remote_fcport->d_id.b.area, + remote_fcport->d_id.b.al_pa)); + } else { + rscn_pid.b.domain = LSB(MSW(rscn_entry)); + rscn_pid.b.area = MSB(LSW(rscn_entry)); + rscn_pid.b.al_pa = LSB(LSW(rscn_entry)); + + DEBUG14(printk("scsi(%ld): Handle RSCN -- process RSCN for " + "port id [%02x%02x%02x].\n", ha->host_no, + rscn_pid.b.domain, rscn_pid.b.area, rscn_pid.b.al_pa)); + + /* + * Search fcport lists for a known entry at the specified port + * ID. + */ + list_for_each_entry(fcport, &ha->fcports, list) { + if (rscn_pid.b24 == fcport->d_id.b24) { + remote_fcport = fcport; + break; + } + } + list_for_each_entry(fcport, &ha->rscn_fcports, list) { + if (rscn_pid.b24 == fcport->d_id.b24) { + rscn_fcport = fcport; + break; + } + } + if (remote_fcport == NULL) + remote_fcport = rscn_fcport; + } + + /* + * If the port is already in our fcport list and online, send an ADISC + * to see if it's still alive. Issue login if a new fcport or the known + * fcport is currently offline. + */ + if (remote_fcport) { + /* + * No need to send request if the remote fcport is currently + * waiting for an available io descriptor. + */ + if (known_fcport == NULL && + (remote_fcport->iodesc_idx_sent == IODESC_ADISC_NEEDED || + remote_fcport->iodesc_idx_sent == IODESC_LOGIN_NEEDED)) { + /* + * If previous waiting io descriptor is an ADISC, then + * the new RSCN may come from a new remote fcport being + * plugged into the same location. + */ + if (remote_fcport->port_type == FCT_RSCN) { + remote_fcport->iodesc_idx_sent = + IODESC_LOGIN_NEEDED; + } else if (remote_fcport->iodesc_idx_sent == + IODESC_ADISC_NEEDED) { + fc_port_t *new_fcport; + + remote_fcport->iodesc_idx_sent = + IODESC_INVALID_INDEX; + + /* Create new fcport for later login. */ + new_fcport = qla2x00_alloc_rscn_fcport(ha, + ha_locked ? GFP_ATOMIC: GFP_KERNEL); + if (new_fcport) { + DEBUG14(printk("scsi(%ld): Handle RSCN " + "-- creating RSCN fcport %p for " + "future login.\n", ha->host_no, + new_fcport)); + + new_fcport->d_id.b24 = + remote_fcport->d_id.b24; + new_fcport->iodesc_idx_sent = + IODESC_LOGIN_NEEDED; + + list_add_tail(&new_fcport->list, + &ha->rscn_fcports); + set_bit(IODESC_PROCESS_NEEDED, + &ha->dpc_flags); + } else { + DEBUG14(printk("scsi(%ld): Handle RSCN " + "-- unable to allocate RSCN fcport " + "for future login.\n", + ha->host_no)); + } + } + return (QLA_SUCCESS); + } + + /* Send ADISC if the fcport is online */ + if (atomic_read(&remote_fcport->state) == FCS_ONLINE || + remote_fcport->iodesc_idx_sent == IODESC_ADISC_NEEDED) { + + atomic_set(&remote_fcport->state, FCS_DEVICE_LOST); + + iodesc = qla2x00_alloc_iodesc(ha); + if (iodesc == NULL) { + /* Mark fcport for later adisc processing */ + DEBUG14(printk("scsi(%ld): Handle RSCN -- not " + "enough IO descriptors for Adisc, flag " + "for later processing.\n", ha->host_no)); + + remote_fcport->iodesc_idx_sent = + IODESC_ADISC_NEEDED; + set_bit(IODESC_PROCESS_NEEDED, &ha->dpc_flags); + + return (QLA_SUCCESS); + } + + iodesc->cb_idx = ADISC_PORT_IOCB_CB; + iodesc->d_id.b24 = rscn_pid.b24; + iodesc->remote_fcport = remote_fcport; + remote_fcport->iodesc_idx_sent = iodesc->idx; + qla2x00_send_adisc_iocb(ha, iodesc, ha_locked); + + return (QLA_SUCCESS); + } else if (remote_fcport->iodesc_idx_sent < + MAX_IO_DESCRIPTORS && + ha->io_descriptors[remote_fcport->iodesc_idx_sent].cb_idx == + ADISC_PORT_IOCB_CB) { + /* + * Receiving another RSCN while an ADISC is pending, + * abort the IOCB. Use the same descriptor for the + * abort. + */ + uint32_t handle_to_abort; + + iodesc = &ha->io_descriptors[ + remote_fcport->iodesc_idx_sent]; + qla2x00_remove_iodesc_timer(iodesc); + handle_to_abort = iodesc->signature; + iodesc->signature = qla2x00_iodesc_to_handle(iodesc); + iodesc->cb_idx = ABORT_IOCB_CB; + iodesc->d_id.b24 = remote_fcport->d_id.b24; + iodesc->remote_fcport = remote_fcport; + remote_fcport->iodesc_idx_sent = iodesc->idx; + + DEBUG14(printk("scsi(%ld): Handle RSCN -- issuing " + "abort to outstanding Adisc [%x/%02x%02x%02x].\n", + ha->host_no, remote_fcport->loop_id, + iodesc->d_id.b.domain, iodesc->d_id.b.area, + iodesc->d_id.b.al_pa)); + + qla2x00_send_abort_iocb(ha, iodesc, handle_to_abort, + ha_locked); + } + } + + /* We need to login to the remote port, find it. */ + if (known_fcport) { + remote_fcport = known_fcport; + } else if (rscn_fcport && rscn_fcport->d_id.b24 != INVALID_PORT_ID && + rscn_fcport->iodesc_idx_sent < MAX_IO_DESCRIPTORS && + ha->io_descriptors[rscn_fcport->iodesc_idx_sent].cb_idx == + LOGIN_PORT_IOCB_CB) { + /* + * Ignore duplicate RSCN on fcport which has already + * initiated a login IOCB. + */ + DEBUG14(printk("scsi(%ld): Handle RSCN -- ignoring, login " + "already sent to [%02x%02x%02x].\n", ha->host_no, + rscn_fcport->d_id.b.domain, rscn_fcport->d_id.b.area, + rscn_fcport->d_id.b.al_pa)); + + return (QLA_SUCCESS); + } else if (rscn_fcport && rscn_fcport->d_id.b24 != INVALID_PORT_ID && + rscn_fcport != remote_fcport) { + /* Reuse same rscn fcport. */ + DEBUG14(printk("scsi(%ld): Handle RSCN -- reusing RSCN fcport " + "[%02x%02x%02x].\n", ha->host_no, + rscn_fcport->d_id.b.domain, rscn_fcport->d_id.b.area, + rscn_fcport->d_id.b.al_pa)); + + remote_fcport = rscn_fcport; + } else { + /* Create new fcport for later login. */ + remote_fcport = qla2x00_alloc_rscn_fcport(ha, + ha_locked ? GFP_ATOMIC: GFP_KERNEL); + list_add_tail(&remote_fcport->list, &ha->rscn_fcports); + } + if (remote_fcport == NULL) + return (QLA_SUCCESS); + + /* Prepare fcport for login. */ + atomic_set(&remote_fcport->state, FCS_DEVICE_LOST); + remote_fcport->login_retry = 3; /* ha->login_retry_count; */ + remote_fcport->d_id.b24 = rscn_pid.b24; + + iodesc = qla2x00_alloc_iodesc(ha); + if (iodesc == NULL) { + /* Mark fcport for later adisc processing. */ + DEBUG14(printk("scsi(%ld): Handle RSCN -- not enough IO " + "descriptors for Login, flag for later processing.\n", + ha->host_no)); + + remote_fcport->iodesc_idx_sent = IODESC_LOGIN_NEEDED; + set_bit(IODESC_PROCESS_NEEDED, &ha->dpc_flags); + + return (QLA_SUCCESS); + } + + if (known_fcport == NULL || rscn_pid.b24 != INVALID_PORT_ID) { + remote_fcport->loop_id = ha->min_external_loopid; + + rval = qla2x00_find_new_loop_id(ha, remote_fcport); + if (rval == QLA_FUNCTION_FAILED) { + /* No more loop ids, failed. */ + DEBUG14(printk("scsi(%ld): Handle RSCN -- no available " + "loop id to perform Login, failed.\n", + ha->host_no)); + + return (rval); + } + } + + iodesc->cb_idx = LOGIN_PORT_IOCB_CB; + iodesc->d_id.b24 = rscn_pid.b24; + iodesc->remote_fcport = remote_fcport; + remote_fcport->iodesc_idx_sent = iodesc->idx; + + DEBUG14(printk("scsi(%ld): Handle RSCN -- attempting login to " + "[%x/%02x%02x%02x].\n", ha->host_no, remote_fcport->loop_id, + iodesc->d_id.b.domain, iodesc->d_id.b.area, iodesc->d_id.b.al_pa)); + + qla2x00_send_login_iocb(ha, iodesc, &rscn_pid, ha_locked); + + return (QLA_SUCCESS); +} + +/** + * qla2x00_process_iodesc() - Complete IO descriptor processing. + * @ha: HA context + * @mbxstat: Mailbox IOCB status + */ +void +qla2x00_process_iodesc(scsi_qla_host_t *ha, struct mbx_entry *mbxstat) +{ + int rval; + uint32_t signature; + fc_port_t *fcport; + struct io_descriptor *iodesc; + + signature = mbxstat->handle; + + DEBUG14(printk("scsi(%ld): Process IODesc -- processing %08x.\n", + ha->host_no, signature)); + + /* Retrieve proper IO descriptor. */ + iodesc = qla2x00_handle_to_iodesc(ha, signature); + if (iodesc == NULL) { + DEBUG14(printk("scsi(%ld): Process IODesc -- ignoring, " + "incorrect signature %08x.\n", ha->host_no, signature)); + + return; + } + + /* Stop IO descriptor timer. */ + qla2x00_remove_iodesc_timer(iodesc); + + /* Verify signature match. */ + if (iodesc->signature != signature) { + DEBUG14(printk("scsi(%ld): Process IODesc -- ignoring, " + "signature mismatch, sent %08x, received %08x.\n", + ha->host_no, iodesc->signature, signature)); + + return; + } + + /* Go with IOCB callback. */ + rval = iocb_function_cb_list[iodesc->cb_idx](ha, iodesc, mbxstat); + if (rval != QLA_SUCCESS) { + /* IO descriptor reused by callback. */ + return; + } + + qla2x00_free_iodesc(iodesc); + + if (test_bit(IODESC_PROCESS_NEEDED, &ha->dpc_flags)) { + /* Scan our fcports list for any RSCN requests. */ + list_for_each_entry(fcport, &ha->fcports, list) { + if (fcport->iodesc_idx_sent == IODESC_ADISC_NEEDED || + fcport->iodesc_idx_sent == IODESC_LOGIN_NEEDED) { + qla2x00_handle_port_rscn(ha, 0, fcport, 1); + return; + } + } + + /* Scan our RSCN fcports list for any RSCN requests. */ + list_for_each_entry(fcport, &ha->rscn_fcports, list) { + if (fcport->iodesc_idx_sent == IODESC_ADISC_NEEDED || + fcport->iodesc_idx_sent == IODESC_LOGIN_NEEDED) { + qla2x00_handle_port_rscn(ha, 0, fcport, 1); + return; + } + } + } + clear_bit(IODESC_PROCESS_NEEDED, &ha->dpc_flags); +} + +/** + * qla2x00_cancel_io_descriptors() - Cancel all outstanding io descriptors. + * @ha: HA context + * + * This routine will also delete any RSCN entries related to the outstanding + * IO descriptors. + */ +void +qla2x00_cancel_io_descriptors(scsi_qla_host_t *ha) +{ + fc_port_t *fcport, *fcptemp; + + clear_bit(IODESC_PROCESS_NEEDED, &ha->dpc_flags); + + /* Abort all IO descriptors. */ + qla2x00_init_io_descriptors(ha); + + /* Reset all pending IO descriptors in fcports list. */ + list_for_each_entry(fcport, &ha->fcports, list) { + fcport->iodesc_idx_sent = IODESC_INVALID_INDEX; + } + + /* Reset all pending IO descriptors in rscn fcports list. */ + list_for_each_entry_safe(fcport, fcptemp, &ha->rscn_fcports, list) { + DEBUG14(printk("scsi(%ld): Cancel IOs -- Freeing RSCN fcport " + "%p [%x/%02x%02x%02x].\n", ha->host_no, fcport, + fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, + fcport->d_id.b.al_pa)); + + list_del(&fcport->list); + kfree(fcport); + } +} diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qla_settings.h 830-ivtv/drivers/scsi/qla2xxx/qla_settings.h --- 000-virgin/drivers/scsi/qla2xxx/qla_settings.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qla_settings.h Thu Jan 8 10:22:00 2004 @@ -0,0 +1,66 @@ +/****************************************************************************** + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + ******************************************************************************/ +/* + * Compile time Options: + * 0 - Disable and 1 - Enable + */ +#define DEBUG_QLA2100 0 /* For Debug of qla2x00 */ + +#define MEMORY_MAPPED_IO 1 +#define STOP_ON_ERROR 0 /* Stop on aborts and resets */ +#define STOP_ON_RESET 0 +#define USE_ABORT_TGT 1 /* Use Abort Target mbx cmd */ + +#define VSA 0 /* Volume Set Addressing */ + +/* Failover options */ +#define MAX_RECOVERYTIME 10 /* + * Max suspend time for a lun recovery + * time + */ +#define MAX_FAILBACKTIME 5 /* Max suspend time before fail back */ + +#define QLA_CMD_TIMER_DELTA 3 + +/* + * When a lun is suspended for the "Not Ready" condition then it will suspend + * the lun for increments of 6 sec delays. SUSPEND_COUNT is that count. + */ +#define SUSPEND_COUNT 10 /* 6 secs * 10 retries = 60 secs */ + +/* + * Defines the time in seconds that the driver extends the command timeout to + * get around the problem where the mid-layer only allows 5 retries for + * commands that return BUS_BUSY + */ +#define EXTEND_CMD_TIMEOUT 60 + +#define MAX_RETRIES_OF_ISP_ABORT 5 + +/* Max time to wait for the loop to be in LOOP_READY state */ +#define MAX_LOOP_TIMEOUT (60 * 5) +#define EH_ACTIVE 1 /* Error handler active */ + +/* + * Some vendor subsystems do not recover properly after a device reset. Define + * the following to force a logout after a successful device reset. + */ +#undef LOGOUT_AFTER_DEVICE_RESET + +#include "qla_version.h" diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qla_sup.c 830-ivtv/drivers/scsi/qla2xxx/qla_sup.c --- 000-virgin/drivers/scsi/qla2xxx/qla_sup.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qla_sup.c Thu Jan 8 10:22:00 2004 @@ -0,0 +1,680 @@ +/****************************************************************************** + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + ******************************************************************************/ + +#include "qla_os.h" +#include "qla_def.h" + +static uint16_t qla2x00_nvram_request(scsi_qla_host_t *, uint32_t); +static void qla2x00_nv_deselect(scsi_qla_host_t *); +static void qla2x00_nv_write(scsi_qla_host_t *, uint16_t); + +uint8_t qla2x00_read_flash_byte(scsi_qla_host_t *, uint32_t); +static void qla2x00_write_flash_byte(scsi_qla_host_t *, uint32_t, uint8_t); +static uint8_t qla2x00_poll_flash(scsi_qla_host_t *ha, + uint32_t addr, uint8_t poll_data, uint8_t mid); +static uint8_t qla2x00_program_flash_address(scsi_qla_host_t *ha, + uint32_t addr, uint8_t data, uint8_t mid); +static uint8_t qla2x00_erase_flash_sector(scsi_qla_host_t *ha, + uint32_t addr, uint32_t sec_mask, uint8_t mid); + +uint8_t qla2x00_get_flash_manufacturer(scsi_qla_host_t *ha); +uint16_t qla2x00_get_flash_version(scsi_qla_host_t *); +uint16_t qla2x00_get_flash_image(scsi_qla_host_t *ha, uint8_t *image); +uint16_t qla2x00_set_flash_image(scsi_qla_host_t *ha, uint8_t *image); + + +/* + * NVRAM support routines + */ + +/** + * qla2x00_lock_nvram_access() - + * @ha: HA context + */ +void +qla2x00_lock_nvram_access(scsi_qla_host_t *ha) +{ + uint16_t data; + device_reg_t *reg; + + reg = ha->iobase; + + if (IS_QLA2312(ha) || IS_QLA2322(ha)) { + data = RD_REG_WORD(®->nvram); + while (data & NVR_BUSY) { + udelay(100); + data = RD_REG_WORD(®->nvram); + } + + /* Lock resource */ + WRT_REG_WORD(®->u.isp2300.host_semaphore, 0x1); + udelay(5); + data = RD_REG_WORD(®->u.isp2300.host_semaphore); + while ((data & BIT_0) == 0) { + /* Lock failed */ + udelay(100); + WRT_REG_WORD(®->u.isp2300.host_semaphore, 0x1); + udelay(5); + data = RD_REG_WORD(®->u.isp2300.host_semaphore); + } + } +} + +/** + * qla2x00_unlock_nvram_access() - + * @ha: HA context + */ +void +qla2x00_unlock_nvram_access(scsi_qla_host_t *ha) +{ + device_reg_t *reg; + + reg = ha->iobase; + + if (IS_QLA2312(ha) || IS_QLA2322(ha)) + WRT_REG_WORD(®->u.isp2300.host_semaphore, 0); +} + +/** + * qla2x00_get_nvram_word() - Calculates word position in NVRAM and calls the + * request routine to get the word from NVRAM. + * @ha: HA context + * @addr: Address in NVRAM to read + * + * Returns the word read from nvram @addr. + */ +uint16_t +qla2x00_get_nvram_word(scsi_qla_host_t *ha, uint32_t addr) +{ + uint16_t data; + uint32_t nv_cmd; + + nv_cmd = addr << 16; + nv_cmd |= NV_READ_OP; + data = qla2x00_nvram_request(ha, nv_cmd); + + return (data); +} + +/** + * qla2x00_write_nvram_word() - Write NVRAM data. + * @ha: HA context + * @addr: Address in NVRAM to write + * @data: word to program + */ +void +qla2x00_write_nvram_word(scsi_qla_host_t *ha, uint32_t addr, uint16_t data) +{ + int count; + uint16_t word; + uint32_t nv_cmd; + device_reg_t *reg = ha->iobase; + + qla2x00_nv_write(ha, NVR_DATA_OUT); + qla2x00_nv_write(ha, 0); + qla2x00_nv_write(ha, 0); + + for (word = 0; word < 8; word++) + qla2x00_nv_write(ha, NVR_DATA_OUT); + + qla2x00_nv_deselect(ha); + + /* Erase Location */ + nv_cmd = (addr << 16) | NV_ERASE_OP; + nv_cmd <<= 5; + for (count = 0; count < 11; count++) { + if (nv_cmd & BIT_31) + qla2x00_nv_write(ha, NVR_DATA_OUT); + else + qla2x00_nv_write(ha, 0); + + nv_cmd <<= 1; + } + + qla2x00_nv_deselect(ha); + + /* Wait for Erase to Finish */ + WRT_REG_WORD(®->nvram, NVR_SELECT); + do { + NVRAM_DELAY(); + word = RD_REG_WORD(®->nvram); + } while ((word & NVR_DATA_IN) == 0); + + qla2x00_nv_deselect(ha); + + /* Write data */ + nv_cmd = (addr << 16) | NV_WRITE_OP; + nv_cmd |= data; + nv_cmd <<= 5; + for (count = 0; count < 27; count++) { + if (nv_cmd & BIT_31) + qla2x00_nv_write(ha, NVR_DATA_OUT); + else + qla2x00_nv_write(ha, 0); + + nv_cmd <<= 1; + } + + qla2x00_nv_deselect(ha); + + /* Wait for NVRAM to become ready */ + WRT_REG_WORD(®->nvram, NVR_SELECT); + do { + NVRAM_DELAY(); + word = RD_REG_WORD(®->nvram); + } while ((word & NVR_DATA_IN) == 0); + + qla2x00_nv_deselect(ha); + + /* Disable writes */ + qla2x00_nv_write(ha, NVR_DATA_OUT); + for (count = 0; count < 10; count++) + qla2x00_nv_write(ha, 0); + + qla2x00_nv_deselect(ha); +} + +/** + * qla2x00_nvram_request() - Sends read command to NVRAM and gets data from + * NVRAM. + * @ha: HA context + * @nv_cmd: NVRAM command + * + * Bit definitions for NVRAM command: + * + * Bit 26 = start bit + * Bit 25, 24 = opcode + * Bit 23-16 = address + * Bit 15-0 = write data + * + * Returns the word read from nvram @addr. + */ +static uint16_t +qla2x00_nvram_request(scsi_qla_host_t *ha, uint32_t nv_cmd) +{ + uint8_t cnt; + device_reg_t *reg = ha->iobase; + uint16_t data = 0; + uint16_t reg_data; + + /* Send command to NVRAM. */ + nv_cmd <<= 5; + for (cnt = 0; cnt < 11; cnt++) { + if (nv_cmd & BIT_31) + qla2x00_nv_write(ha, NVR_DATA_OUT); + else + qla2x00_nv_write(ha, 0); + nv_cmd <<= 1; + } + + /* Read data from NVRAM. */ + for (cnt = 0; cnt < 16; cnt++) { + WRT_REG_WORD(®->nvram, NVR_SELECT | NVR_CLOCK); + NVRAM_DELAY(); + data <<= 1; + reg_data = RD_REG_WORD(®->nvram); + if (reg_data & NVR_DATA_IN) + data |= BIT_0; + WRT_REG_WORD(®->nvram, NVR_SELECT); + NVRAM_DELAY(); + RD_REG_WORD(®->nvram); /* PCI Posting. */ + } + + /* Deselect chip. */ + WRT_REG_WORD(®->nvram, NVR_DESELECT); + NVRAM_DELAY(); + RD_REG_WORD(®->nvram); /* PCI Posting. */ + + return (data); +} + +/** + * qla2x00_nv_write() - Clean NVRAM operations. + * @ha: HA context + */ +void +qla2x00_nv_deselect(scsi_qla_host_t *ha) +{ + device_reg_t *reg = ha->iobase; + + WRT_REG_WORD(®->nvram, NVR_DESELECT); + NVRAM_DELAY(); + RD_REG_WORD(®->nvram); /* PCI Posting. */ +} + +/** + * qla2x00_nv_write() - Prepare for NVRAM read/write operation. + * @ha: HA context + * @data: Serial interface selector + */ +void +qla2x00_nv_write(scsi_qla_host_t *ha, uint16_t data) +{ + device_reg_t *reg = ha->iobase; + + WRT_REG_WORD(®->nvram, data | NVR_SELECT); + NVRAM_DELAY(); + RD_REG_WORD(®->nvram); /* PCI Posting. */ + WRT_REG_WORD(®->nvram, data | NVR_SELECT | NVR_CLOCK); + NVRAM_DELAY(); + RD_REG_WORD(®->nvram); /* PCI Posting. */ + WRT_REG_WORD(®->nvram, data | NVR_SELECT); + NVRAM_DELAY(); + RD_REG_WORD(®->nvram); /* PCI Posting. */ +} + +/* + * Flash support routines + */ + +/** + * qla2x00_flash_enable() - Setup flash for reading and writing. + * @ha: HA context + */ +void +qla2x00_flash_enable(scsi_qla_host_t *ha) +{ + uint16_t data; + device_reg_t *reg = ha->iobase; + + data = RD_REG_WORD(®->ctrl_status); + data |= CSR_FLASH_ENABLE; + WRT_REG_WORD(®->ctrl_status, data); +} + +/** + * qla2x00_flash_disable() - Disable flash and allow RISC to run. + * @ha: HA context + */ +void +qla2x00_flash_disable(scsi_qla_host_t *ha) +{ + uint16_t data; + device_reg_t *reg = ha->iobase; + + data = RD_REG_WORD(®->ctrl_status); + data &= ~(CSR_FLASH_ENABLE); + WRT_REG_WORD(®->ctrl_status, data); +} + +/** + * qla2x00_read_flash_byte() - Reads a byte from flash + * @ha: HA context + * @addr: Address in flash to read + * + * A word is read from the chip, but, only the lower byte is valid. + * + * Returns the byte read from flash @addr. + */ +uint8_t +qla2x00_read_flash_byte(scsi_qla_host_t *ha, uint32_t addr) +{ + uint16_t data; + uint16_t bank_select; + device_reg_t *reg = ha->iobase; + + /* Setup bit 16 of flash address. */ + bank_select = RD_REG_WORD(®->ctrl_status); + if ((addr & BIT_16) && ((bank_select & CSR_FLASH_64K_BANK) == 0)) { + bank_select |= CSR_FLASH_64K_BANK; + WRT_REG_WORD(®->ctrl_status, bank_select); + } else if (((addr & BIT_16) == 0) && + (bank_select & CSR_FLASH_64K_BANK)) { + bank_select &= ~(CSR_FLASH_64K_BANK); + WRT_REG_WORD(®->ctrl_status, bank_select); + } + WRT_REG_WORD(®->flash_address, (uint16_t)addr); + data = qla2x00_debounce_register(®->flash_data); + + return ((uint8_t)data); +} + +/** + * qla2x00_write_flash_byte() - Write a byte to flash + * @ha: HA context + * @addr: Address in flash to write + * @data: Data to write + */ +static void +qla2x00_write_flash_byte(scsi_qla_host_t *ha, uint32_t addr, uint8_t data) +{ + uint16_t bank_select; + device_reg_t *reg = ha->iobase; + + /* Setup bit 16 of flash address. */ + bank_select = RD_REG_WORD(®->ctrl_status); + if ((addr & BIT_16) && ((bank_select & CSR_FLASH_64K_BANK) == 0)) { + bank_select |= CSR_FLASH_64K_BANK; + WRT_REG_WORD(®->ctrl_status, bank_select); + } else if (((addr & BIT_16) == 0) && + (bank_select & CSR_FLASH_64K_BANK)) { + bank_select &= ~(CSR_FLASH_64K_BANK); + WRT_REG_WORD(®->ctrl_status, bank_select); + } + WRT_REG_WORD(®->flash_address, (uint16_t)addr); + WRT_REG_WORD(®->flash_data, (uint16_t)data); +} + +/** + * qla2x00_poll_flash() - Polls flash for completion. + * @ha: HA context + * @addr: Address in flash to poll + * @poll_data: Data to be polled + * @mid: Flash manufacturer ID + * + * This function polls the device until bit 7 of what is read matches data + * bit 7 or until data bit 5 becomes a 1. If that hapens, the flash ROM timed + * out (a fatal error). The flash book recommeds reading bit 7 again after + * reading bit 5 as a 1. + * + * Returns 0 on success, else non-zero. + */ +static uint8_t +qla2x00_poll_flash(scsi_qla_host_t *ha, + uint32_t addr, uint8_t poll_data, uint8_t mid) +{ + uint8_t status; + uint8_t flash_data; + uint32_t cnt; + int failed_pass; + + status = 1; + failed_pass = 1; + + /* Wait for 30 seconds for command to finish. */ + poll_data &= BIT_7; + for (cnt = 3000000; cnt; cnt--) { + flash_data = qla2x00_read_flash_byte(ha, addr); + if ((flash_data & BIT_7) == poll_data) { + status = 0; + break; + } + + if (mid != 0x40 && mid != 0xda) { + if (flash_data & BIT_5) + failed_pass--; + if (failed_pass < 0) + break; + } + udelay(10); + barrier(); + } + return (status); +} + +/** + * qla2x00_program_flash_address() - Programs a flash address + * @ha: HA context + * @addr: Address in flash to program + * @data: Data to be written in flash + * @mid: Flash manufacturer ID + * + * Returns 0 on success, else non-zero. + */ +static uint8_t +qla2x00_program_flash_address(scsi_qla_host_t *ha, + uint32_t addr, uint8_t data, uint8_t mid) +{ + /* Write Program Command Sequence */ + qla2x00_write_flash_byte(ha, 0x5555, 0xaa); + qla2x00_write_flash_byte(ha, 0x2aaa, 0x55); + qla2x00_write_flash_byte(ha, 0x5555, 0xa0); + qla2x00_write_flash_byte(ha, addr, data); + + /* Wait for write to complete. */ + return (qla2x00_poll_flash(ha, addr, data, mid)); +} + +/** + * qla2x00_erase_flash_sector() - Erase a flash sector. + * @ha: HA context + * @addr: Flash sector to erase + * @sec_mask: Sector address mask + * @mid: Flash manufacturer ID + * + * Returns 0 on success, else non-zero. + */ +static uint8_t +qla2x00_erase_flash_sector(scsi_qla_host_t *ha, + uint32_t addr, uint32_t sec_mask, uint8_t mid) +{ + /* Individual Sector Erase Command Sequence */ + qla2x00_write_flash_byte(ha, 0x5555, 0xaa); + qla2x00_write_flash_byte(ha, 0x2aaa, 0x55); + qla2x00_write_flash_byte(ha, 0x5555, 0x80); + qla2x00_write_flash_byte(ha, 0x5555, 0xaa); + qla2x00_write_flash_byte(ha, 0x2aaa, 0x55); + + if (mid == 0xda) + qla2x00_write_flash_byte(ha, addr & sec_mask, 0x10); + else + qla2x00_write_flash_byte(ha, addr & sec_mask, 0x30); + + udelay(150); + + /* Wait for erase to complete. */ + return (qla2x00_poll_flash(ha, addr, 0x80, mid)); +} + +/** + * qla2x00_get_flash_manufacturer() - Read manufacturer ID from flash chip. + * @ha: HA context + * + * Returns the manufacturer's ID read from the flash chip. + */ +uint8_t +qla2x00_get_flash_manufacturer(scsi_qla_host_t *ha) +{ + uint8_t manuf_id; + + qla2x00_write_flash_byte(ha, 0x5555, 0xaa); + qla2x00_write_flash_byte(ha, 0x2aaa, 0x55); + qla2x00_write_flash_byte(ha, 0x5555, 0x90); + manuf_id = qla2x00_read_flash_byte(ha, 0x0001); + + return (manuf_id); +} + +/** + * qla2x00_get_flash_version() - Read version information from flash. + * @ha: HA context + * + * Returns QLA_SUCCESS on successful retrieval of flash version. + */ +uint16_t +qla2x00_get_flash_version(scsi_qla_host_t *ha) +{ + uint16_t ret = QLA_SUCCESS; + uint32_t loop_cnt = 1; /* this is for error exit only */ + uint32_t pcir_adr; + + ENTER(__func__); + + qla2x00_flash_enable(ha); + do { /* Loop once to provide quick error exit */ + /* Match signature */ + if (!(qla2x00_read_flash_byte(ha, 0) == 0x55 && + qla2x00_read_flash_byte(ha, 1) == 0xaa)) { + /* No signature */ + DEBUG2(printk("scsi(%ld): No matching FLASH " + "signature.\n", ha->host_no)); + ret = QLA_FUNCTION_FAILED; + break; + } + + pcir_adr = qla2x00_read_flash_byte(ha, 0x18) & 0xff; + + /* validate signature of PCI data structure */ + if ((qla2x00_read_flash_byte(ha, pcir_adr)) == 'P' && + (qla2x00_read_flash_byte(ha, pcir_adr + 1)) == 'C' && + (qla2x00_read_flash_byte(ha, pcir_adr + 2)) == 'I' && + (qla2x00_read_flash_byte(ha, pcir_adr + 3)) == 'R') { + + /* Read version */ + ha->optrom_minor = + qla2x00_read_flash_byte(ha, pcir_adr + 0x12); + ha->optrom_major = + qla2x00_read_flash_byte(ha, pcir_adr + 0x13); + DEBUG3(printk("%s(): got %d.%d.\n", + __func__, ha->optrom_major, ha->optrom_minor)); + } else { + /* error */ + DEBUG2(printk("%s(): PCI data struct not found. " + "pcir_adr=%x.\n", + __func__, pcir_adr)); + ret = QLA_FUNCTION_FAILED; + break; + } + + } while (--loop_cnt); + qla2x00_flash_disable(ha); + + LEAVE(__func__); + + return (ret); +} + +/** + * qla2x00_get_flash_image() - Read image from flash chip. + * @ha: HA context + * @image: Buffer to receive flash image + * + * Returns 0 on success, else non-zero. + */ +uint16_t +qla2x00_get_flash_image(scsi_qla_host_t *ha, uint8_t *image) +{ + uint32_t addr; + uint32_t midpoint; + uint8_t *data; + device_reg_t *reg = ha->iobase; + + midpoint = FLASH_IMAGE_SIZE / 2; + + qla2x00_flash_enable(ha); + WRT_REG_WORD(®->nvram, 0); + for (addr = 0, data = image; addr < FLASH_IMAGE_SIZE; addr++, data++) { + if (addr == midpoint) + WRT_REG_WORD(®->nvram, NVR_SELECT); + + *data = qla2x00_read_flash_byte(ha, addr); + } + qla2x00_flash_disable(ha); + + return (0); +} + +/** + * qla2x00_set_flash_image() - Write image to flash chip. + * @ha: HA context + * @image: Source image to write to flash + * + * Returns 0 on success, else non-zero. + */ +uint16_t +qla2x00_set_flash_image(scsi_qla_host_t *ha, uint8_t *image) +{ + uint16_t status; + uint32_t addr; + uint32_t midpoint; + uint32_t sec_mask; + uint32_t rest_addr; + uint8_t mid; + uint8_t sec_number; + uint8_t data; + device_reg_t *reg = ha->iobase; + + status = 0; + sec_number = 0; + + /* Reset ISP chip. */ + WRT_REG_WORD(®->ctrl_status, CSR_ISP_SOFT_RESET); + + qla2x00_flash_enable(ha); + do { /* Loop once to provide quick error exit */ + /* Structure of flash memory based on manufacturer */ + mid = qla2x00_get_flash_manufacturer(ha); + if (mid == 0x6d) { + // Am29LV001 part + rest_addr = 0x1fff; + sec_mask = 0x1e000; + } else if (mid == 0x40) { + // Mostel v29c51001 part + rest_addr = 0x1ff; + sec_mask = 0x1fe00; + } else if (mid == 0xbf) { + // SST39sf10 part + rest_addr = 0xfff; + sec_mask = 0x1f000; + } else if (mid == 0xda) { + // Winbond W29EE011 part + rest_addr = 0x7f; + sec_mask = 0x1ff80; + addr = 0; + if (qla2x00_erase_flash_sector(ha, addr, sec_mask, + mid)) { + status = 1; + break; + } + } else { + // Am29F010 part + rest_addr = 0x3fff; + sec_mask = 0x1c000; + } + + midpoint = FLASH_IMAGE_SIZE / 2; + for (addr = 0; addr < FLASH_IMAGE_SIZE; addr++) { + data = *image++; + /* Are we at the beginning of a sector? */ + if (!(addr & rest_addr)) { + if (addr == midpoint) + WRT_REG_WORD(®->nvram, NVR_SELECT); + + /* Then erase it */ + if (qla2x00_erase_flash_sector(ha, addr, + sec_mask, mid)) { + status = 1; + break; + } + + sec_number++; + } + if (mid == 0x6d) { + if (sec_number == 1 && + (addr == (rest_addr - 1))) { + rest_addr = 0x0fff; + sec_mask = 0x1f000; + } else if (sec_number == 3 && (addr & 0x7ffe)) { + rest_addr = 0x3fff; + sec_mask = 0x1c000; + } + } + + if (qla2x00_program_flash_address(ha, addr, data, + mid)) { + status = 1; + break; + } + } + } while (0); + + qla2x00_flash_disable(ha); + + return (status); +} diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qla_version.h 830-ivtv/drivers/scsi/qla2xxx/qla_version.h --- 000-virgin/drivers/scsi/qla2xxx/qla_version.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qla_version.h Thu Jan 8 10:22:00 2004 @@ -0,0 +1,27 @@ +/****************************************************************************** + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + ******************************************************************************/ +/* + * Driver version + */ +#define QLA2XXX_VERSION "8.00.00b8" + +#define QLA_DRIVER_MAJOR_VER 8 +#define QLA_DRIVER_MINOR_VER 0 +#define QLA_DRIVER_PATCH_VER 0 +#define QLA_DRIVER_BETA_VER 8 diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qla_xioct.c 830-ivtv/drivers/scsi/qla2xxx/qla_xioct.c --- 000-virgin/drivers/scsi/qla2xxx/qla_xioct.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qla_xioct.c Thu Jan 8 10:22:00 2004 @@ -0,0 +1,6393 @@ +/****************************************************************************** + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + ******************************************************************************/ + + +#include "qla_os.h" +#include "qla_def.h" + +#include "inioct.h" + +#define QLA_PT_CMD_TOV (60) /* firmware timeout */ +#define QLA_PT_CMD_DRV_TOV (QLA_PT_CMD_TOV + 1) /* drvr timeout */ +#define QLA_IOCTL_ACCESS_WAIT_TIME (QLA_PT_CMD_DRV_TOV + 2) /* wait_q tov */ +#define QLA_INITIAL_IOCTLMEM_SIZE (2 * PAGE_SIZE) +#define QLA_IOCTL_SCRAP_SIZE 2048 /* scrap memory for local use. */ + +/* ELS related defines */ +#define FC_HEADER_LEN 24 +#define ELS_RJT_LENGTH 0x08 /* 8 */ +#define ELS_RPS_ACC_LENGTH 0x40 /* 64 */ +#define ELS_RLS_ACC_LENGTH 0x1C /* 28 */ + +/* ELS cmd Reply Codes */ +#define ELS_STAT_LS_RJT 0x01 +#define ELS_STAT_LS_ACC 0x02 + +#define IOCTL_INVALID_STATUS 0xffff + + +int qla2x00_alloc_ioctl_mem(scsi_qla_host_t *); +void qla2x00_free_ioctl_mem(scsi_qla_host_t *); + +int qla2x00_get_ioctl_scrap_mem(scsi_qla_host_t *, void **, uint32_t); +void qla2x00_free_ioctl_scrap_mem(scsi_qla_host_t *); + +/* + * Local prototypes + */ +static int qla2x00_get_new_ioctl_dma_mem(scsi_qla_host_t *, uint32_t); + +static int qla2x00_find_curr_ha(uint16_t, scsi_qla_host_t **); + +static int qla2x00_get_driver_specifics(EXT_IOCTL *); + +static int qla2x00_aen_reg(scsi_qla_host_t *, EXT_IOCTL *, int); +static int qla2x00_aen_get(scsi_qla_host_t *, EXT_IOCTL *, int); + +static int qla2x00_query(scsi_qla_host_t *, EXT_IOCTL *, int); +static int qla2x00_query_hba_node(scsi_qla_host_t *, EXT_IOCTL *, int); +static int qla2x00_query_hba_port(scsi_qla_host_t *, EXT_IOCTL *, int); +static int qla2x00_query_disc_port(scsi_qla_host_t *, EXT_IOCTL *, int); +static int qla2x00_query_disc_tgt(scsi_qla_host_t *, EXT_IOCTL *, int); +static int qla2x00_query_chip(scsi_qla_host_t *, EXT_IOCTL *, int); + +static int qla2x00_get_data(scsi_qla_host_t *, EXT_IOCTL *, int); +static int qla2x00_get_statistics(scsi_qla_host_t *, EXT_IOCTL *, int); +static int qla2x00_get_fc_statistics(scsi_qla_host_t *, EXT_IOCTL *, int); +static int qla2x00_get_port_summary(scsi_qla_host_t *, EXT_IOCTL *, int); +static int qla2x00_get_fcport_summary(scsi_qla_host_t *, EXT_DEVICEDATAENTRY *, + void *, uint32_t, uint32_t *, uint32_t *); +#if 0 +static int qla2x00_std_missing_port_summary(scsi_qla_host_t *, + EXT_DEVICEDATAENTRY *, void *, uint32_t, uint32_t *, uint32_t *); +#endif + +static int qla2x00_query_driver(scsi_qla_host_t *, EXT_IOCTL *, int); +static int qla2x00_query_fw(scsi_qla_host_t *, EXT_IOCTL *, int); + +static int qla2x00_msiocb_passthru(scsi_qla_host_t *, EXT_IOCTL *, int, int); + +static int qla2x00_send_els_passthru(scsi_qla_host_t *, EXT_IOCTL *, + struct scsi_cmnd *, fc_port_t *, fc_lun_t *, int); +static int qla2x00_get_led_state(scsi_qla_host_t *, EXT_IOCTL *, int); +static int qla2x00_set_led_state(scsi_qla_host_t *, EXT_IOCTL *, int); +static int qla2x00_send_fcct(scsi_qla_host_t *, EXT_IOCTL *, + struct scsi_cmnd *, fc_port_t *, fc_lun_t *, int); +static int qla2x00_ioctl_ms_queuecommand(scsi_qla_host_t *, EXT_IOCTL *, + struct scsi_cmnd *, fc_port_t *, fc_lun_t *, EXT_ELS_PT_REQ *); + +static int qla2x00_start_ms_cmd(scsi_qla_host_t *, EXT_IOCTL *, srb_t *, + EXT_ELS_PT_REQ *); + +static int qla2x00_wwpn_to_scsiaddr(scsi_qla_host_t *, EXT_IOCTL *, int); +static int qla2x00_scsi_passthru(scsi_qla_host_t *, EXT_IOCTL *, int); +static int qla2x00_sc_scsi_passthru(scsi_qla_host_t *, EXT_IOCTL *, + struct scsi_cmnd *, struct scsi_device *, int); +static int qla2x00_sc_fc_scsi_passthru(scsi_qla_host_t *, EXT_IOCTL *, + struct scsi_cmnd *, struct scsi_device *, int); +static int qla2x00_sc_scsi3_passthru(scsi_qla_host_t *, EXT_IOCTL *, + struct scsi_cmnd *, struct scsi_device *, int); +static int qla2x00_ioctl_scsi_queuecommand(scsi_qla_host_t *, EXT_IOCTL *, + struct scsi_cmnd *, struct scsi_device *, fc_port_t *, fc_lun_t *); + +static int qla2x00_send_els_rnid(scsi_qla_host_t *, EXT_IOCTL *, int); +static int qla2x00_get_rnid_params(scsi_qla_host_t *, EXT_IOCTL *, int); +static int qla2x00_set_host_data(scsi_qla_host_t *, EXT_IOCTL *, int); +static int qla2x00_set_rnid_params(scsi_qla_host_t *, EXT_IOCTL *, int); + +static void qla2x00_waitq_sem_timeout(unsigned long); +static int qla2x00_get_ioctl_access(scsi_qla_host_t *, uint32_t); +static int qla2x00_release_ioctl_access(scsi_qla_host_t *); + +static void qla2x00_wait_q_memb_alloc(scsi_qla_host_t *, wait_q_t **); +static void qla2x00_wait_q_memb_free(scsi_qla_host_t *, wait_q_t *); +static int qla2x00_wait_q_add(scsi_qla_host_t *, wait_q_t **); +static void qla2x00_wait_q_get_next(scsi_qla_host_t *, wait_q_t **); +static void qla2x00_wait_q_remove(scsi_qla_host_t *, wait_q_t *); + +/* + * qla2x00_ioctl_sleep_done + * + * Description: + * This is the callback function to wakeup ioctl completion semaphore + * for the ioctl request that is waiting. + * + * Input: + * sem - pointer to the ioctl completion semaphore. + * + * Returns: + */ +static void +qla2x00_ioctl_sleep_done(struct semaphore * sem) +{ + DEBUG9(printk("%s: entered.\n", __func__);) + + if (sem != NULL){ + DEBUG9(printk("ioctl_sleep: wake up sem.\n");) + up(sem); + } + + DEBUG9(printk("%s: exiting.\n", __func__);) +} + +/* + * qla2x00_ioctl_sem_init + * + * Description: + * Initialize the ioctl timer and semaphore used to wait for passthru + * completion. + * + * Input: + * ha - pointer to scsi_qla_host_t structure used for initialization. + * + * Returns: + * None. + */ +static void +qla2x00_ioctl_sem_init(scsi_qla_host_t *ha) +{ + init_MUTEX_LOCKED(&ha->ioctl->cmpl_sem); + init_timer(&(ha->ioctl->cmpl_timer)); + ha->ioctl->cmpl_timer.data = (unsigned long)&ha->ioctl->cmpl_sem; + ha->ioctl->cmpl_timer.function = + (void (*)(unsigned long))qla2x00_ioctl_sleep_done; +} + +/* + * qla2x00_scsi_pt_done + * + * Description: + * Resets ioctl progress flag and wakes up the ioctl completion semaphore. + * + * Input: + * pscsi_cmd - pointer to the passthru Scsi cmd structure which has completed. + * + * Returns: + */ +static void +qla2x00_scsi_pt_done(struct scsi_cmnd *pscsi_cmd) +{ + struct Scsi_Host *host; + scsi_qla_host_t *ha; + + host = pscsi_cmd->device->host; + ha = (scsi_qla_host_t *) host->hostdata; + + DEBUG9(printk("%s post function called OK\n", __func__);) + + /* save detail status for IOCTL reporting */ + ha->ioctl->SCSIPT_InProgress = 0; + ha->ioctl->ioctl_tov = 0; + + up(&ha->ioctl->cmpl_sem); + + DEBUG9(printk("%s: exiting.\n", __func__);) + + return; +} + +/* + * qla2x00_msiocb_done + * + * Description: + * Resets MSIOCB ioctl progress flag and wakes up the ioctl completion + * semaphore. + * + * Input: + * cmd - pointer to the passthru Scsi cmd structure which has completed. + * + * Returns: + */ +static void +qla2x00_msiocb_done(struct scsi_cmnd *pscsi_cmd) +{ + struct Scsi_Host *host; + scsi_qla_host_t *ha; + + host = pscsi_cmd->device->host; + ha = (scsi_qla_host_t *) host->hostdata; + + DEBUG9(printk("%s post function called OK\n", __func__);) + + ha->ioctl->MSIOCB_InProgress = 0; + ha->ioctl->ioctl_tov = 0; + + up(&ha->ioctl->cmpl_sem); + + DEBUG9(printk("%s: exiting.\n", __func__);) + + return; +} + +/************************************************************************* + * qla2x00_ioctl + * + * Description: + * Performs additional ioctl requests not satisfied by the upper levels. + * + * Returns: + * ret = 0 Success + * ret != 0 Failed; detailed status copied to EXT_IOCTL structure + * if possible + *************************************************************************/ +int +qla2x00_ioctl(struct scsi_device *dev, int cmd, void *arg) +{ + int mode = 0; + int tmp_rval = 0; + int ret = -EINVAL; + + uint8_t *temp; + uint8_t tempbuf[8]; + uint32_t i; + uint32_t status; + + EXT_IOCTL *pext; + + scsi_qla_host_t *ha; + + + DEBUG9(printk("%s: entry to command (%x), arg (%p)\n", + __func__, cmd, arg);) + + /* Catch any non-exioct ioctls */ + if (_IOC_TYPE(cmd) != QLMULTIPATH_MAGIC) { + return (ret); + } + + ret = verify_area(VERIFY_READ, (void *)arg, sizeof(EXT_IOCTL)); + if (ret) { + DEBUG9_10(printk("%s: ERROR VERIFY_READ EXT_IOCTL " + "sturct. cmd=%x arg=%p.\n", __func__, cmd, arg);) + return (ret); + } + + /* Allocate ioctl structure buffer to support multiple concurrent + * entries. + */ + pext = KMEM_ZALLOC(sizeof(EXT_IOCTL), 16); + if (pext == NULL) { + /* error */ + printk(KERN_WARNING + "qla2x00: ERROR in main ioctl buffer allocation.\n"); + return (-ENOMEM); + } + + /* copy in application layer EXT_IOCTL */ + ret = copy_from_user(pext, arg, sizeof(EXT_IOCTL)); + if (ret) { + DEBUG9_10(printk("%s: ERROR COPY_FROM_USER " + "EXT_IOCTL sturct. cmd=%x arg=%p.\n", + __func__, cmd, arg);) + + KMEM_FREE(pext, sizeof(EXT_IOCTL)); + return (ret); + } + + /* Verify before update status fields in EXT_IOCTL struct. */ + ret = verify_area(VERIFY_WRITE, (void *)arg, sizeof(EXT_IOCTL)); + if (ret) { + DEBUG9_10(printk("%s: ERROR VERIFY_WRITE EXT_IOCTL " + "sturct. cmd=%x arg=%p.\n", __func__, cmd, arg);) + + KMEM_FREE(pext, sizeof(EXT_IOCTL)); + return (ret); + } + + /* check signature of this ioctl */ + temp = (uint8_t *) &pext->Signature; + + for (i = 0; i < 4; i++, temp++) + tempbuf[i] = *temp; + + if ((tempbuf[0] == 'Q') && (tempbuf[1] == 'L') && + (tempbuf[2] == 'O') && (tempbuf[3] == 'G')) + status = 0; + else + status = 1; + + if (status != 0) { + DEBUG9_10(printk("%s: signature did not match. " + "cmd=%x arg=%p.\n", __func__, cmd, arg);) + pext->Status = EXT_STATUS_INVALID_PARAM; + copy_to_user((void *)arg, (void *)pext, sizeof(EXT_IOCTL)); + + KMEM_FREE(pext, sizeof(EXT_IOCTL)); + return (-EINVAL); + } + + /* check version of this ioctl */ + if (pext->Version > EXT_VERSION) { + printk(KERN_WARNING + "qla2x00: ioctl interface version not supported = %d.\n", + pext->Version); + pext->Status = EXT_STATUS_UNSUPPORTED_VERSION; + copy_to_user((void *)arg, (void *)pext, sizeof(EXT_IOCTL)); + + KMEM_FREE(pext, sizeof(EXT_IOCTL)); + return (-EINVAL); + } + + /* check for special cmds used during application's setup time. */ + switch (cmd) { + case EXT_CC_STARTIOCTL: + DEBUG9(printk("%s: got startioctl command.\n", __func__);) + + pext->Instance = num_hosts; + pext->Status = EXT_STATUS_OK; + ret = copy_to_user((void *)arg, (void *)pext, + sizeof(EXT_IOCTL)); + + KMEM_FREE(pext, sizeof(EXT_IOCTL)); + return (ret); + + case EXT_CC_SETINSTANCE: + /* This call is used to return the HBA's host number to + * ioctl caller. All subsequent ioctl commands will put + * the host number in HbaSelect field to tell us which + * HBA is the destination. + */ + if (pext->Instance < num_hosts) { + if (!((ulong)pext->VendorSpecificData & + EXT_DEF_USE_HBASELECT)) { + DEBUG9(printk( + "%s: got setinstance cmd w/o HbaSelect.\n", + __func__);) + /* Backward compatible code. */ + apiHBAInstance = pext->Instance; + } + + /* + * Return host number via pext->HbaSelect for + * specified API instance number. + */ + if (qla2x00_find_curr_ha(pext->Instance, &ha) != 0) { + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + ret = copy_to_user(arg, pext, sizeof(EXT_IOCTL)); + DEBUG9_10(printk("%s: SETINSTANCE invalid inst " + "%d. num_hosts=%d ha=%p ret=%d.\n", + __func__, pext->Instance, num_hosts, ha, + ret);) + + KMEM_FREE(pext, sizeof(EXT_IOCTL)); + return (ret); /* ioctl completed ok */ + } + + pext->HbaSelect = ha->host_no; + pext->Status = EXT_STATUS_OK; + + DEBUG9(printk("%s: Matching instance %d to hba " + "%ld.\n", __func__, pext->Instance, ha->host_no);) + } else { + DEBUG9_10(printk("%s: ERROR EXT_SETINSTANCE." + " Instance=%d num_hosts=%d ha=%p.\n", + __func__, pext->Instance, num_hosts, ha);) + + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + } + ret = copy_to_user(arg, pext, sizeof(EXT_IOCTL)); + KMEM_FREE(pext, sizeof(EXT_IOCTL)); + + DEBUG9(printk("%s: SETINSTANCE exiting. ret=%d.\n", + __func__, ret);) + + return (ret); + + case EXT_CC_DRIVER_SPECIFIC: + ret = qla2x00_get_driver_specifics(pext); + tmp_rval = copy_to_user(arg, (void *)pext, sizeof(EXT_IOCTL)); + + if (ret == 0) + ret = tmp_rval; + + KMEM_FREE(pext, sizeof(EXT_IOCTL)); + return (ret); + + default: + break; + } + + if (!((ulong)pext->VendorSpecificData & EXT_DEF_USE_HBASELECT)) { + /* Backward compatible code. */ + /* Will phase out soon. */ + + /* Check for valid apiHBAInstance (set previously by + * EXT_SETINSTANCE or default 0) and set ha context + * for this IOCTL. + */ + DEBUG9(printk("%s: not using HbaSelect. apiHBAInstance=%d.\n", + __func__, apiHBAInstance);) + if (qla2x00_find_curr_ha(apiHBAInstance, &ha) != 0) { + + DEBUG9_10(printk("%s: ERROR matching apiHBAInstance " + "%d to an HBA Instance.\n", + __func__, apiHBAInstance);) + + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + copy_to_user(arg, pext, sizeof(EXT_IOCTL)); + + KMEM_FREE(pext, sizeof(EXT_IOCTL)); + return (-EINVAL); + } + + DEBUG9(printk("%s: active apiHBAInstance=%d host_no=%ld " + "CC=%x SC=%x.\n", + __func__, apiHBAInstance, ha->host_no, cmd, pext->SubCode);) + + } else { + /* Use HbaSelect value to get a matching ha instance + * for this ioctl command. + */ + if (qla2x00_find_curr_ha(pext->HbaSelect, &ha) != 0) { + + DEBUG9_10(printk("%s: ERROR matching pext->HbaSelect " + "%d to an HBA Instance.\n", + __func__, pext->HbaSelect);) + + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + copy_to_user(arg, pext, sizeof(EXT_IOCTL)); + + KMEM_FREE(pext, sizeof(EXT_IOCTL)); + return (-EINVAL); + } + + DEBUG9(printk("%s: active host_inst=%ld CC=%x SC=%x.\n", + __func__, ha->instance, cmd, pext->SubCode);) + } + + /* + * Get permission to process ioctl command. Only one will proceed + * at a time. + */ + if (qla2x00_get_ioctl_access(ha, QLA_IOCTL_ACCESS_WAIT_TIME) != 0) { + /* error timed out */ + DEBUG9_10(printk("%s: ERROR timeout getting ioctl " + "access. host no=%d.\n", __func__, pext->HbaSelect);) + + pext->Status = EXT_STATUS_BUSY; + copy_to_user(arg, pext, sizeof(EXT_IOCTL)); + + KMEM_FREE(pext, sizeof(EXT_IOCTL)); + return (-EBUSY); + } + + + while (test_bit(CFG_ACTIVE, &ha->cfg_flags) || ha->dpc_active) { + if( signal_pending(current) ) + break; /* get out */ + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ); + } + + switch (cmd) { /* switch on EXT IOCTL COMMAND CODE */ + + case EXT_CC_QUERY: + DEBUG9(printk("%s: got query command.\n", __func__);) + + ret = qla2x00_query(ha, pext, 0); + + break; + + case EXT_CC_GET_DATA: + DEBUG9(printk("%s: got get_data command.\n", __func__);) + + ret = qla2x00_get_data(ha, pext, 0); + + break; + + case EXT_CC_SEND_SCSI_PASSTHRU: + DEBUG9(printk("%s: got SCSI passthru cmd.\n", __func__)); + + ret = qla2x00_scsi_passthru(ha, pext, mode); + + break; + + case EXT_CC_REG_AEN: + ret = qla2x00_aen_reg(ha, pext, mode); + + break; + + case EXT_CC_GET_AEN: + ret = qla2x00_aen_get(ha, pext, mode); + + break; + + case EXT_CC_WWPN_TO_SCSIADDR: + ret = qla2x00_wwpn_to_scsiaddr(ha, pext, 0); + break; + + case EXT_CC_SEND_ELS_RNID: + DEBUG9(printk("%s: got ELS RNID cmd.\n", __func__)); + + ret = qla2x00_send_els_rnid(ha, pext, mode); + break; + + case EXT_CC_SET_DATA: + ret = qla2x00_set_host_data(ha, pext, mode); + break; + + case INT_CC_READ_NVRAM: + ret = qla2x00_read_nvram(ha, pext, mode); + + break; + + case INT_CC_UPDATE_NVRAM: + ret = qla2x00_update_nvram(ha, pext, mode); + + break; + + case INT_CC_LOOPBACK: + ret = qla2x00_send_loopback(ha, pext, mode); + + break; + + case INT_CC_READ_OPTION_ROM: + ret = qla2x00_read_option_rom(ha, pext, mode); + + break; + + case INT_CC_UPDATE_OPTION_ROM: + ret = qla2x00_update_option_rom(ha, pext, mode); + + break; + + + case EXT_CC_SEND_ELS_PASSTHRU: + if (!IS_QLA23XX(ha)) + goto fail; + /*FALLTHROUGH*/ + case EXT_CC_SEND_FCCT_PASSTHRU: + ret = qla2x00_msiocb_passthru(ha, pext, cmd, mode); + + break; + + /* all others go here */ + /* + case EXT_CC_PLATFORM_REG: + break; + */ + +#if defined(CONFIG_SCSI_QLA2XXX_FAILOVER_ENABLE) + /* Failover IOCTLs */ + case FO_CC_GET_PARAMS: + case FO_CC_SET_PARAMS: + case FO_CC_GET_PATHS: + case FO_CC_SET_CURRENT_PATH: + case FO_CC_RESET_HBA_STAT: + case FO_CC_GET_HBA_STAT: + case FO_CC_GET_LUN_DATA: + case FO_CC_SET_LUN_DATA: + case FO_CC_GET_TARGET_DATA: + case FO_CC_SET_TARGET_DATA: + DEBUG9(printk("%s: failover arg (%p):\n", __func__, arg);) + + qla2x00_fo_ioctl(ha, cmd, pext, mode); + + break; +#endif + + default: + fail: + pext->Status = EXT_STATUS_INVALID_REQUEST; + break; + + } /* end of CC decode switch */ + + /* Always try to copy values back regardless what happened before. */ + tmp_rval = copy_to_user(arg, (void *)pext, sizeof(EXT_IOCTL)); + + if (ret == 0) + ret = tmp_rval; + + DEBUG9(printk("%s: exiting. tmp_rval(%d) ret(%d)\n", + __func__, tmp_rval, ret);) + + qla2x00_release_ioctl_access(ha); + + KMEM_FREE(pext, sizeof(EXT_IOCTL)); + + return (ret); +} + +/* + * qla2x00_alloc_ioctl_mem + * Allocates memory needed by IOCTL code. + * + * Input: + * ha = adapter state pointer. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_alloc_ioctl_mem(scsi_qla_host_t *ha) +{ + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + if (qla2x00_get_new_ioctl_dma_mem(ha, QLA_INITIAL_IOCTLMEM_SIZE) != + QLA_SUCCESS) { + printk(KERN_WARNING + "qla2x00: ERROR in ioctl physical memory allocation\n"); + + return QLA_MEMORY_ALLOC_FAILED; + } + + /* Allocate context memory buffer */ + ha->ioctl = KMEM_ZALLOC(sizeof(hba_ioctl_context), 11); + if (ha->ioctl == NULL) { + /* error */ + printk(KERN_WARNING + "qla2x00: ERROR in ioctl context allocation.\n"); + return QLA_MEMORY_ALLOC_FAILED; + } + + /* Allocate AEN tracking buffer */ + ha->ioctl->aen_tracking_queue = + KMEM_ZALLOC(EXT_DEF_MAX_AEN_QUEUE * sizeof(EXT_ASYNC_EVENT), 12); + if (ha->ioctl->aen_tracking_queue == NULL) { + printk(KERN_WARNING + "qla2x00: ERROR in ioctl aen_queue allocation.\n"); + return QLA_MEMORY_ALLOC_FAILED; + } + + ha->ioctl->ioctl_tq = KMEM_ZALLOC(sizeof(os_tgt_t), 13); + if (ha->ioctl->ioctl_tq == NULL) { + printk(KERN_WARNING + "qla2x00: ERROR in ioctl tgt queue allocation.\n"); + return QLA_MEMORY_ALLOC_FAILED; + } + + ha->ioctl->ioctl_lq = KMEM_ZALLOC(sizeof(os_lun_t), 14); + if (ha->ioctl->ioctl_lq == NULL) { + printk(KERN_WARNING + "qla2x00: ERROR in ioctl lun queue allocation.\n"); + return QLA_MEMORY_ALLOC_FAILED; + } + /*INIT_LIST_HEAD(&(ha->ioctl->ioctl_lq->cmd));*/ + + /* Pick the largest size we'll need per ha of all ioctl cmds. + * Use this size when freeing. + */ + ha->ioctl->scrap_mem = KMEM_ZALLOC(QLA_IOCTL_SCRAP_SIZE, 15); + if (ha->ioctl->scrap_mem == NULL) { + printk(KERN_WARNING + "qla2x00: ERROR in ioctl scrap_mem allocation.\n"); + return QLA_MEMORY_ALLOC_FAILED; + } + ha->ioctl->scrap_mem_size = QLA_IOCTL_SCRAP_SIZE; + ha->ioctl->scrap_mem_used = 0; + DEBUG9(printk("%s(%ld): scrap_mem_size=%d.\n", + __func__, ha->host_no, ha->ioctl->scrap_mem_size);) + + ha->ioctl->ioctl_lq->q_state = LUN_STATE_READY; + ha->ioctl->ioctl_lq->q_lock = SPIN_LOCK_UNLOCKED; + + /* Init wait_q fields */ + ha->ioctl->wait_q_lock = SPIN_LOCK_UNLOCKED; + + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) + + return QLA_SUCCESS; +} + +/* + * qla2x00_get_new_ioctl_dma_mem + * Allocates dma memory of the specified size. + * This is done to replace any previously allocated ioctl dma buffer. + * + * Input: + * ha = adapter state pointer. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +static int +qla2x00_get_new_ioctl_dma_mem(scsi_qla_host_t *ha, uint32_t size) +{ + DEBUG9(printk("%s entered.\n", __func__);) + + if (ha->ioctl_mem) { + DEBUG9(printk("%s: ioctl_mem was previously allocated. " + "Dealloc old buffer.\n", __func__);) + + /* free the memory first */ + pci_free_consistent(ha->pdev, ha->ioctl_mem_size, ha->ioctl_mem, + ha->ioctl_mem_phys); + } + + /* Get consistent memory allocated for ioctl I/O operations. */ + ha->ioctl_mem = pci_alloc_consistent(ha->pdev, + size, &ha->ioctl_mem_phys); + + if (ha->ioctl_mem == NULL) { + printk(KERN_WARNING + "%s: ERROR in ioctl physical memory allocation. " + "Requested length=%x.\n", __func__, size); + + ha->ioctl_mem_size = 0; + return QLA_MEMORY_ALLOC_FAILED; + } + ha->ioctl_mem_size = size; + + DEBUG9(printk("%s exiting.\n", __func__);) + + return QLA_SUCCESS; +} + +/* + * qla2x00_free_ioctl_mem + * Frees memory used by IOCTL code for the specified ha. + * + * Input: + * ha = adapter state pointer. + * + * Context: + * Kernel context. + */ +void +qla2x00_free_ioctl_mem(scsi_qla_host_t *ha) +{ + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + if (ha->ioctl != NULL) { + + if (ha->ioctl->scrap_mem != NULL) { + /* The size here must match up to what we + * allocated before. + */ + KMEM_FREE(ha->ioctl->scrap_mem, + ha->ioctl->scrap_mem_size); + ha->ioctl->scrap_mem = NULL; + ha->ioctl->scrap_mem_size = 0; + } + + if (ha->ioctl->ioctl_tq != NULL) { + KMEM_FREE(ha->ioctl->ioctl_tq, sizeof(os_tgt_t)); + ha->ioctl->ioctl_tq = NULL; + } + + if (ha->ioctl->ioctl_lq != NULL) { + KMEM_FREE(ha->ioctl->ioctl_lq, sizeof(os_lun_t)); + ha->ioctl->ioctl_lq = NULL; + } + + if (ha->ioctl->aen_tracking_queue != NULL) { + KMEM_FREE(ha->ioctl->aen_tracking_queue, + EXT_DEF_MAX_AEN_QUEUE * sizeof(EXT_ASYNC_EVENT)); + ha->ioctl->aen_tracking_queue = NULL; + } + + KMEM_FREE(ha->ioctl, sizeof(hba_ioctl_context)); + ha->ioctl = NULL; + } + + /* free memory allocated for ioctl operations */ + pci_free_consistent(ha->pdev, ha->ioctl_mem_size, ha->ioctl_mem, + ha->ioctl_mem_phys); + ha->ioctl_mem = NULL; + + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) + +} + +/* + * qla2x00_get_ioctl_scrap_mem + * Returns pointer to memory of the specified size from the scrap buffer. + * This can be called multiple times before the free call as long + * as the memory is to be used by the same ioctl command and + * there's still memory left in the scrap buffer. + * + * Input: + * ha = adapter state pointer. + * ppmem = pointer to return a buffer pointer. + * size = size of buffer to return. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +int +qla2x00_get_ioctl_scrap_mem(scsi_qla_host_t *ha, void **ppmem, uint32_t size) +{ + int ret = QLA_SUCCESS; + uint32_t free_mem; + + DEBUG9(printk("%s(%ld): inst=%ld entered. size=%d.\n", + __func__, ha->host_no, ha->instance, size);) + + free_mem = ha->ioctl->scrap_mem_size - ha->ioctl->scrap_mem_used; + if (free_mem >= size) { + *ppmem = ha->ioctl->scrap_mem + ha->ioctl->scrap_mem_used; + ha->ioctl->scrap_mem_used += size; + } else { + DEBUG10(printk("%s(%ld): no more scrap memory.\n", + __func__, ha->host_no);) + + ret = QLA_FUNCTION_FAILED; + } + + DEBUG9(printk("%s(%ld): exiting. ret=%d.\n", + __func__, ha->host_no, ret);) + + return (ret); +} + +/* + * qla2x00_free_ioctl_scrap_mem + * Makes the entire scrap buffer free for use. + * + * Input: + * ha = adapter state pointer. + * + * Returns: + * qla2x00 local function return status code. + * + */ +void +qla2x00_free_ioctl_scrap_mem(scsi_qla_host_t *ha) +{ + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + memset(ha->ioctl->scrap_mem, 0, ha->ioctl->scrap_mem_size); + ha->ioctl->scrap_mem_used = 0; + + DEBUG9(printk("%s(%ld): exiting.\n", + __func__, ha->host_no);) +} + +/* + * qla2x00_find_curr_ha + * Searches and returns the pointer to the adapter host_no specified. + * + * Input: + * host_inst = driver internal adapter instance number to search. + * ha = adapter state pointer of the instance requested. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +static int +qla2x00_find_curr_ha(uint16_t host_inst, scsi_qla_host_t **ret_ha) +{ + int rval = QLA_SUCCESS; + int found; + struct list_head *hal; + scsi_qla_host_t *search_ha = NULL; + + /* + * Set ha context for this IOCTL by matching host_no. + */ + found = 0; + read_lock(&qla_hostlist_lock); + list_for_each(hal, &qla_hostlist) { + search_ha = list_entry(hal, scsi_qla_host_t, list); + + if (search_ha->instance == host_inst) { + found++; + break; + } + } + read_unlock(&qla_hostlist_lock); + + if (!found) { + DEBUG10(printk("%s: ERROR matching host_inst " + "%d to an HBA Instance.\n", __func__, host_inst);) + rval = QLA_FUNCTION_FAILED; + } else { + DEBUG9(printk("%s: found matching host_inst " + "%d to an HBA Instance.\n", __func__, host_inst);) + *ret_ha = search_ha; + } + + return rval; +} + +/* + * qla2x00_get_driver_specifics + * Returns driver specific data in the response buffer. + * + * Input: + * pext = pointer to EXT_IOCTL structure containing values from user. + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_get_driver_specifics(EXT_IOCTL *pext) +{ + int ret = 0; + EXT_LN_DRIVER_DATA data; + + DEBUG9(printk("%s: entered.\n", + __func__);) + + if (pext->ResponseLen < sizeof(EXT_LN_DRIVER_DATA)) { + pext->Status = EXT_STATUS_BUFFER_TOO_SMALL; + DEBUG9_10(printk("%s: ERROR ResponseLen too small.\n", + __func__);) + + return (ret); + } + + data.DrvVer.Major = QLA_DRIVER_MAJOR_VER; + data.DrvVer.Minor = QLA_DRIVER_MINOR_VER; + data.DrvVer.Patch = QLA_DRIVER_PATCH_VER; + data.DrvVer.Beta = QLA_DRIVER_BETA_VER; + + ret = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr, + sizeof(EXT_LN_DRIVER_DATA)); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s: ERROR verify write resp buf\n", + __func__);) + + return (ret); + } + + ret = copy_to_user(pext->ResponseAdr, &data, sizeof(EXT_LN_DRIVER_DATA)); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s: ERROR copy resp buf\n", + __func__);) + } + + DEBUG9(printk("%s: exiting. ret=%d.\n", + __func__, ret);) + + return (ret); +} + +/* + * qla2x00_aen_reg + * IOCTL management server Asynchronous Event Tracking Enable/Disable. + * + * Input: + * ha = pointer to the adapter struct of the adapter to register. + * cmd = pointer to EXT_IOCTL structure containing values from user. + * mode = flags. not used. + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_aen_reg(scsi_qla_host_t *ha, EXT_IOCTL *cmd, int mode) +{ + int rval = 0; + EXT_REG_AEN reg_struct; + + DEBUG9(printk("%s(%ld): inst %ld entered.\n", + __func__, ha->host_no, ha->instance);) + + rval = verify_area(VERIFY_READ, (void *)cmd->RequestAdr, + sizeof(EXT_REG_AEN)); + if (rval) { + cmd->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst %ld ERROR verify read req buf\n", + __func__, ha->host_no, ha->instance);) + + return (rval); + } + + rval = copy_from_user(®_struct, cmd->RequestAdr, sizeof(EXT_REG_AEN)); + if (rval == 0) { + cmd->Status = EXT_STATUS_OK; + if (reg_struct.Enable) { + ha->ioctl->flags |= IOCTL_AEN_TRACKING_ENABLE; + } else { + ha->ioctl->flags &= ~IOCTL_AEN_TRACKING_ENABLE; + } + } else { + cmd->Status = EXT_STATUS_COPY_ERR; + } + + DEBUG9(printk("%s(%ld): inst %ld reg_struct.Enable(%d) " + "ha->ioctl_flag(%x) cmd->Status(%d).", + __func__, ha->host_no, ha->instance, reg_struct.Enable, + ha->ioctl->flags, cmd->Status);) + + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) + + return (rval); +} + +/* + * qla2x00_aen_get + * Asynchronous Event Record Transfer to user. + * The entire queue will be emptied and transferred back. + * + * Input: + * ha = pointer to the adapter struct of the specified adapter. + * pext = pointer to EXT_IOCTL structure containing values from user. + * mode = flags. + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + * + * NOTE: Need to use hardware lock to protect the queues from updates + * via isr/enqueue_aen after we get rid of io_request_lock. + */ +static int +qla2x00_aen_get(scsi_qla_host_t *ha, EXT_IOCTL *cmd, int mode) +{ + int rval = 0; + EXT_ASYNC_EVENT *tmp_q; + EXT_ASYNC_EVENT *paen; + uint8_t i; + uint8_t queue_cnt; + uint8_t request_cnt; + uint32_t stat = EXT_STATUS_OK; + uint32_t ret_len = 0; + unsigned long cpu_flags = 0; + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + request_cnt = (uint8_t)(cmd->ResponseLen / sizeof(EXT_ASYNC_EVENT)); + + if (request_cnt < EXT_DEF_MAX_AEN_QUEUE) { + /* We require caller to alloc for the maximum request count */ + cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL; + DEBUG9_10(printk("%s(%ld): inst=%ld Buffer too small. " + "Exiting normally.", + __func__, ha->host_no, ha->instance);) + + return (rval); + } + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&paen, + sizeof(EXT_ASYNC_EVENT) * EXT_DEF_MAX_AEN_QUEUE)) { + /* not enough memory */ + cmd->Status = EXT_STATUS_NO_MEMORY; + DEBUG9_10(printk("%s(%ld): inst=%ld scrap not big enough. " + "size requested=%ld.\n", + __func__, ha->host_no, ha->instance, + (ulong)sizeof(EXT_ASYNC_EVENT)*EXT_DEF_MAX_AEN_QUEUE);) + return (rval); + } + + /* 1st: Make a local copy of the entire queue content. */ + tmp_q = (EXT_ASYNC_EVENT *)ha->ioctl->aen_tracking_queue; + queue_cnt = 0; + + spin_lock_irqsave(&ha->hardware_lock, cpu_flags); + i = ha->ioctl->aen_q_head; + + for (; queue_cnt < EXT_DEF_MAX_AEN_QUEUE;) { + if (tmp_q[i].AsyncEventCode != 0) { + memcpy(&paen[queue_cnt], &tmp_q[i], + sizeof(EXT_ASYNC_EVENT)); + queue_cnt++; + tmp_q[i].AsyncEventCode = 0; /* empty out the slot */ + } + + if (i == ha->ioctl->aen_q_tail) { + /* done. */ + break; + } + + i++; + + if (i == EXT_DEF_MAX_AEN_QUEUE) { + i = 0; + } + } + + /* Empty the queue. */ + ha->ioctl->aen_q_head = 0; + ha->ioctl->aen_q_tail = 0; + + spin_unlock_irqrestore(&ha->hardware_lock, cpu_flags); + + /* 2nd: Now transfer the queue content to user buffer */ + /* Copy the entire queue to user's buffer. */ + ret_len = (uint32_t)(queue_cnt * sizeof(EXT_ASYNC_EVENT)); + if (queue_cnt != 0) { + rval = verify_area(VERIFY_WRITE, (void *)cmd->ResponseAdr, + ret_len); + if (rval != 0) { + cmd->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk( + "%s(%ld): inst=%ld ERROR verify write resp buf.\n", + __func__, ha->host_no, ha->instance);) + + qla2x00_free_ioctl_scrap_mem(ha); + return (rval); + } + + rval = copy_to_user(cmd->ResponseAdr, paen, ret_len); + } + cmd->ResponseLen = ret_len; + + if (rval != 0) { + stat = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld FAILED. error = %d\n", + __func__, ha->host_no, ha->instance, stat);) + } else { + stat = EXT_STATUS_OK; + } + + cmd->Status = stat; + qla2x00_free_ioctl_scrap_mem(ha); + + DEBUG9(printk("%s(%ld): inst=%ld exiting. rval=%d.\n", + __func__, ha->host_no, ha->instance, rval);) + + return (rval); +} + +/* + * qla2x00_enqueue_aen + * + * Input: + * ha = adapter state pointer. + * event_code = async event code of the event to add to queue. + * payload = event payload for the queue. + * + * Context: + * Interrupt context. + * NOTE: Need to hold the hardware lock to protect the queues from + * aen_get after we get rid of the io_request_lock. + */ +void +qla2x00_enqueue_aen(scsi_qla_host_t *ha, uint16_t event_code, void *payload) +{ + uint8_t new_entry; /* index to current entry */ + uint16_t *mbx; + EXT_ASYNC_EVENT *aen_queue; + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + aen_queue = (EXT_ASYNC_EVENT *)ha->ioctl->aen_tracking_queue; + if (aen_queue[ha->ioctl->aen_q_tail].AsyncEventCode != 0) { + /* Need to change queue pointers to make room. */ + + /* Increment tail for adding new entry. */ + ha->ioctl->aen_q_tail++; + if (ha->ioctl->aen_q_tail == EXT_DEF_MAX_AEN_QUEUE) { + ha->ioctl->aen_q_tail = 0; + } + + if (ha->ioctl->aen_q_head == ha->ioctl->aen_q_tail) { + /* + * We're overwriting the oldest entry, so need to + * update the head pointer. + */ + ha->ioctl->aen_q_head++; + if (ha->ioctl->aen_q_head == EXT_DEF_MAX_AEN_QUEUE) { + ha->ioctl->aen_q_head = 0; + } + } + } + + DEBUG(printk("%s(%ld): inst=%ld Adding code 0x%x to aen_q %p @ %d\n", + __func__, ha->host_no, ha->instance, event_code, aen_queue, + ha->ioctl->aen_q_tail);) + + new_entry = ha->ioctl->aen_q_tail; + aen_queue[new_entry].AsyncEventCode = event_code; + + /* Update payload */ + switch (event_code) { + case MBA_LIP_OCCURRED: + case MBA_LOOP_UP: + case MBA_LOOP_DOWN: + case MBA_LIP_RESET: + case MBA_PORT_UPDATE: + /* empty */ + break; + + case MBA_RSCN_UPDATE: + mbx = (uint16_t *)payload; + aen_queue[new_entry].Payload.RSCN.AddrFormat = MSB(mbx[1]); + /* domain */ + aen_queue[new_entry].Payload.RSCN.RSCNInfo[0] = LSB(mbx[1]); + /* area */ + aen_queue[new_entry].Payload.RSCN.RSCNInfo[1] = MSB(mbx[2]); + /* al_pa */ + aen_queue[new_entry].Payload.RSCN.RSCNInfo[2] = LSB(mbx[2]); + + break; + + default: + /* Not supported */ + aen_queue[new_entry].AsyncEventCode = 0; + break; + } + + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) +} + +/* + * qla2x00_query + * Handles all subcommands of the EXT_CC_QUERY command. + * + * Input: + * ha = adapter state pointer. + * pext = EXT_IOCTL structure pointer. + * mode = not used. + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_query(scsi_qla_host_t *ha, EXT_IOCTL *pext, int mode) +{ + int rval = 0; + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + /* All Query type ioctls are done here */ + switch(pext->SubCode) { + + case EXT_SC_QUERY_HBA_NODE: + /* fill in HBA NODE Information */ + rval = qla2x00_query_hba_node(ha, pext, mode); + break; + + case EXT_SC_QUERY_HBA_PORT: + /* return HBA PORT related info */ + rval = qla2x00_query_hba_port(ha, pext, mode); + break; + + case EXT_SC_QUERY_DISC_PORT: + /* return discovered port information */ + rval = qla2x00_query_disc_port(ha, pext, mode); + break; + + case EXT_SC_QUERY_DISC_TGT: + /* return discovered target information */ + rval = qla2x00_query_disc_tgt(ha, pext, mode); + break; + + case EXT_SC_QUERY_CHIP: + rval = qla2x00_query_chip(ha, pext, mode); + break; + + case EXT_SC_QUERY_DISC_LUN: + pext->Status = EXT_STATUS_UNSUPPORTED_SUBCODE; + break; + + default: + DEBUG9_10(printk("%s(%ld): inst=%ld unknown SubCode %d.\n", + __func__, ha->host_no, ha->instance, pext->SubCode);) + pext->Status = EXT_STATUS_UNSUPPORTED_SUBCODE; + break; + } + + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) + return rval; +} + +/* + * qla2x00_query_hba_node + * Handles EXT_SC_QUERY_HBA_NODE subcommand. + * + * Input: + * ha = adapter state pointer. + * pext = EXT_IOCTL structure pointer. + * mode = not used. + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_query_hba_node(scsi_qla_host_t *ha, EXT_IOCTL *pext, int mode) +{ + int ret = 0; + uint32_t i, transfer_size; + EXT_HBA_NODE *ptmp_hba_node; + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&ptmp_hba_node, + sizeof(EXT_HBA_NODE))) { + /* not enough memory */ + pext->Status = EXT_STATUS_NO_MEMORY; + DEBUG9_10(printk("%s(%ld): inst=%ld scrap not big enough. " + "size requested=%ld.\n", + __func__, ha->host_no, ha->instance, + (ulong)sizeof(EXT_HBA_NODE));) + return (ret); + } + + /* fill all available HBA NODE Information */ + for (i = 0; i < 8 ; i++) + ptmp_hba_node->WWNN[i] = ha->node_name[i]; + + sprintf((char *)(ptmp_hba_node->Manufacturer),"Qlogic Corp."); + sprintf((char *)(ptmp_hba_node->Model), ha->model_number); + + ptmp_hba_node->SerialNum[0] = ha->serial0; + ptmp_hba_node->SerialNum[1] = ha->serial1; + ptmp_hba_node->SerialNum[2] = ha->serial2; + sprintf((char *)(ptmp_hba_node->DriverVersion), qla2x00_version_str); + sprintf((char *)(ptmp_hba_node->FWVersion),"%2d.%02d.%02d", + ha->fw_major_version, + ha->fw_minor_version, + ha->fw_subminor_version); + + sprintf((char *)(ptmp_hba_node->OptRomVersion),"%d.%d", + ha->optrom_major, ha->optrom_minor); + + ptmp_hba_node->InterfaceType = EXT_DEF_FC_INTF_TYPE; + ptmp_hba_node->PortCount = 1; + ptmp_hba_node->DriverAttr = 0; + +#if defined(CONFIG_SCSI_QLA2XXX_FAILOVER_ENABLE) + if (qla2x00_failover_enabled(ha)) + ptmp_hba_node->DriverAttr |= DRVR_FO_ENABLED; +#endif + + ret = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr, + sizeof(EXT_HBA_NODE)); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR verify wrt rsp buf\n", + __func__, ha->host_no, ha->instance);) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + /* now copy up the HBA_NODE to user */ + if (pext->ResponseLen < sizeof(EXT_HBA_NODE)) + transfer_size = pext->ResponseLen; + else + transfer_size = sizeof(EXT_HBA_NODE); + + ret = copy_to_user((uint8_t *)pext->ResponseAdr, + (uint8_t *)ptmp_hba_node, transfer_size); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR copy rsp buffer.\n", + __func__, ha->host_no, ha->instance);) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) + + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); +} + +/* + * qla2x00_query_hba_port + * Handles EXT_SC_QUERY_HBA_PORT subcommand. + * + * Input: + * ha = adapter state pointer. + * pext = EXT_IOCTL structure pointer. + * mode = not used. + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_query_hba_port(scsi_qla_host_t *ha, EXT_IOCTL *pext, int mode) +{ + int ret = 0; + uint32_t tgt_cnt, tgt, transfer_size; + uint32_t port_cnt; + fc_port_t *fcport; + EXT_HBA_PORT *ptmp_hba_port; + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&ptmp_hba_port, + sizeof(EXT_HBA_PORT))) { + /* not enough memory */ + pext->Status = EXT_STATUS_NO_MEMORY; + DEBUG9_10(printk("%s(%ld): inst=%ld scrap not big enough. " + "size requested=%ld.\n", + __func__, ha->host_no, ha->instance, + (ulong)sizeof(EXT_HBA_PORT));) + return (ret); + } + + /* reflect all HBA PORT related info */ + ptmp_hba_port->WWPN[7] = ha->init_cb->port_name[7]; + ptmp_hba_port->WWPN[6] = ha->init_cb->port_name[6]; + ptmp_hba_port->WWPN[5] = ha->init_cb->port_name[5]; + ptmp_hba_port->WWPN[4] = ha->init_cb->port_name[4]; + ptmp_hba_port->WWPN[3] = ha->init_cb->port_name[3]; + ptmp_hba_port->WWPN[2] = ha->init_cb->port_name[2]; + ptmp_hba_port->WWPN[1] = ha->init_cb->port_name[1]; + ptmp_hba_port->WWPN[0] = ha->init_cb->port_name[0]; + ptmp_hba_port->Id[0] = 0; + ptmp_hba_port->Id[1] = ha->d_id.r.d_id[2]; + ptmp_hba_port->Id[2] = ha->d_id.r.d_id[1]; + ptmp_hba_port->Id[3] = ha->d_id.r.d_id[0]; + ptmp_hba_port->Type = EXT_DEF_INITIATOR_DEV; + + switch (ha->current_topology) { + case ISP_CFG_NL: + case ISP_CFG_FL: + ptmp_hba_port->Mode = EXT_DEF_LOOP_MODE; + break; + + case ISP_CFG_N: + case ISP_CFG_F: + ptmp_hba_port->Mode = EXT_DEF_P2P_MODE; + break; + + default: + ptmp_hba_port->Mode = EXT_DEF_UNKNOWN_MODE; + break; + } + + port_cnt = 0; + list_for_each_entry(fcport, &ha->fcports, list) { + /* if removed or missing */ + if (atomic_read(&fcport->state) != FCS_ONLINE) { + DEBUG9_10(printk( + "%s(%ld): inst=%ld port " + "%02x%02x%02x%02x%02x%02x%02x%02x not online\n", + __func__, ha->host_no, ha->instance, + fcport->port_name[0], fcport->port_name[1], + fcport->port_name[2], fcport->port_name[3], + fcport->port_name[4], fcport->port_name[5], + fcport->port_name[6], fcport->port_name[7])); + continue; + } + port_cnt++; + } + + tgt_cnt = 0; + for (tgt = 0; tgt < MAX_TARGETS; tgt++) { + if (ha->otgt[tgt] == NULL) { + continue; + } + if (ha->otgt[tgt]->fcport == NULL) { + /* port doesn't exist */ + DEBUG9(printk("%s(%ld): tgt %d port not exist.\n", + __func__, ha->host_no, tgt);) + continue; + } + tgt_cnt++; + } + + DEBUG9_10(printk("%s(%ld): inst=%ld disc_port cnt=%d, tgt cnt=%d.\n", + __func__, ha->host_no, ha->instance, + port_cnt, tgt_cnt);) + ptmp_hba_port->DiscPortCount = port_cnt; + ptmp_hba_port->DiscTargetCount = tgt_cnt; + + if (atomic_read(&ha->loop_state) == LOOP_DOWN) { + ptmp_hba_port->State = EXT_DEF_HBA_LOOP_DOWN; + } else if (atomic_read(&ha->loop_state) != LOOP_READY || + test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) || + test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) || + test_bit(CFG_ACTIVE, &ha->cfg_flags)) { + + ptmp_hba_port->State = EXT_DEF_HBA_SUSPENDED; + } else { + ptmp_hba_port->State = EXT_DEF_HBA_OK; + } + + ptmp_hba_port->DiscPortNameType = EXT_DEF_USE_PORT_NAME; + + /* Return supported FC4 type depending on driver support. */ + ptmp_hba_port->PortSupportedFC4Types = EXT_DEF_FC4_TYPE_SCSI; + + ptmp_hba_port->PortActiveFC4Types = ha->active_fc4_types; + + /* Return supported speed depending on adapter type */ + if (IS_QLA2100(ha) || IS_QLA2200(ha)) + ptmp_hba_port->PortSupportedSpeed = EXT_DEF_PORTSPEED_1GBIT; + else + ptmp_hba_port->PortSupportedSpeed = EXT_DEF_PORTSPEED_2GBIT; + + ptmp_hba_port->PortSpeed = ha->current_speed; + + ret = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr , + sizeof(EXT_HBA_PORT)); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR verify wrt rsp buf\n", + __func__, ha->host_no, ha->instance);) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + /* now copy up the HBA_PORT to user */ + if (pext->ResponseLen < sizeof(EXT_HBA_PORT)) + transfer_size = pext->ResponseLen; + else + transfer_size = sizeof(EXT_HBA_PORT); + + ret = copy_to_user((uint8_t *)pext->ResponseAdr, + (uint8_t *)ptmp_hba_port, transfer_size); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR copy rsp buffer.\n", + __func__, ha->host_no, ha->instance);) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + qla2x00_free_ioctl_scrap_mem(ha); + + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) + + return ret; +} + +/* + * qla2x00_query_disc_port + * Handles EXT_SC_QUERY_DISC_PORT subcommand. + * + * Input: + * ha = adapter state pointer. + * pext = EXT_IOCTL structure pointer. + * mode = not used. + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_query_disc_port(scsi_qla_host_t *ha, EXT_IOCTL *pext, int mode) +{ + int ret = 0; + int found; + uint32_t tgt, transfer_size, inst; + fc_port_t *fcport; + os_tgt_t *tq; + EXT_DISC_PORT *ptmp_disc_port; + + DEBUG9(printk("%s(%ld): inst=%ld entered. Port inst=%02d.\n", + __func__, ha->host_no, ha->instance, pext->Instance);) + + inst = 0; + found = 0; + fcport = NULL; + list_for_each_entry(fcport, &ha->fcports, list) { + if (atomic_read(&fcport->state) != FCS_ONLINE) { + /* port does not exist anymore */ + DEBUG9(printk("%s(%ld): fcport marked lost. " + "port=%02x%02x%02x%02x%02x%02x%02x%02x " + "loop_id=%02x not online.\n", + __func__, ha->host_no, + fcport->port_name[0], fcport->port_name[1], + fcport->port_name[2], fcport->port_name[3], + fcport->port_name[4], fcport->port_name[5], + fcport->port_name[6], fcport->port_name[7], + fcport->loop_id);) + continue; + } + + if (inst != pext->Instance) { + DEBUG9(printk("%s(%ld): found fcport %02d " + "d_id=%02x%02x%02x. Skipping.\n", + __func__, ha->host_no, inst, + fcport->d_id.b.domain, + fcport->d_id.b.area, + fcport->d_id.b.al_pa)); + + inst++; + continue; + } + + DEBUG9(printk("%s(%ld): inst=%ld found matching fcport %02d " + "online. d_id=%02x%02x%02x loop_id=%02x online.\n", + __func__, ha->host_no, ha->instance, inst, + fcport->d_id.b.domain, + fcport->d_id.b.area, + fcport->d_id.b.al_pa, + fcport->loop_id);) + + /* Found the matching port still connected. */ + found++; + break; + } + + if (!found) { + DEBUG9_10(printk("%s(%ld): inst=%ld dev not found.\n", + __func__, ha->host_no, ha->instance);) + + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + return (ret); + } + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&ptmp_disc_port, + sizeof(EXT_DISC_PORT))) { + /* not enough memory */ + pext->Status = EXT_STATUS_NO_MEMORY; + DEBUG9_10(printk("%s(%ld): inst=%ld scrap not big enough. " + "size requested=%ld.\n", + __func__, ha->host_no, ha->instance, + (ulong)sizeof(EXT_DISC_PORT));) + return (ret); + } + + memcpy(ptmp_disc_port->WWNN, fcport->node_name, WWN_SIZE); + memcpy(ptmp_disc_port->WWPN, fcport->port_name, WWN_SIZE); + + ptmp_disc_port->Id[0] = 0; + ptmp_disc_port->Id[1] = fcport->d_id.r.d_id[2]; + ptmp_disc_port->Id[2] = fcport->d_id.r.d_id[1]; + ptmp_disc_port->Id[3] = fcport->d_id.r.d_id[0]; + + /* Currently all devices on fcport list are target capable devices */ + /* This default value may need to be changed after we add non target + * devices also to this list. + */ + ptmp_disc_port->Type = EXT_DEF_TARGET_DEV; + + if (fcport->flags & FCF_FABRIC_DEVICE) { + ptmp_disc_port->Type |= EXT_DEF_FABRIC_DEV; + } + if (fcport->flags & FCF_TAPE_PRESENT) { + ptmp_disc_port->Type |= EXT_DEF_TAPE_DEV; + } + if (fcport->port_type == FCT_INITIATOR) { + ptmp_disc_port->Type |= EXT_DEF_INITIATOR_DEV; + } + + ptmp_disc_port->LoopID = fcport->loop_id; + ptmp_disc_port->Status = 0; + ptmp_disc_port->Bus = 0; + + for (tgt = 0; tgt < MAX_TARGETS; tgt++) { + if ((tq = ha->otgt[tgt]) == NULL) { + continue; + } + + if (tq->fcport == NULL) /* dg 08/14/01 */ + continue; + + if (memcmp(fcport->port_name, tq->fcport->port_name, + EXT_DEF_WWN_NAME_SIZE) == 0) { + ptmp_disc_port->TargetId = tgt; + break; + } + } + + ret = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr , + sizeof(EXT_DISC_PORT)); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR verify wrt rsp buf\n", + __func__, ha->host_no, ha->instance);) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + /* now copy up the DISC_PORT to user */ + if (pext->ResponseLen < sizeof(EXT_DISC_PORT)) + transfer_size = pext->ResponseLen; + else + transfer_size = sizeof(EXT_DISC_PORT); + + ret = copy_to_user((uint8_t *)pext->ResponseAdr, + (uint8_t *)ptmp_disc_port, transfer_size); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR copy rsp buffer.\n", + __func__, ha->host_no, ha->instance);) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + qla2x00_free_ioctl_scrap_mem(ha); + + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); +} + +/* + * qla2x00_query_disc_tgt + * Handles EXT_SC_QUERY_DISC_TGT subcommand. + * + * Input: + * ha = adapter state pointer. + * pext = EXT_IOCTL structure pointer. + * mode = not used. + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_query_disc_tgt(scsi_qla_host_t *ha, EXT_IOCTL *pext, int mode) +{ + int ret = 0; + uint32_t tgt, transfer_size, inst; + uint32_t cnt, i; + fc_port_t *tgt_fcport; + os_tgt_t *tq; + EXT_DISC_TARGET *ptmp_disc_target; + + DEBUG9(printk("%s(%ld): inst=%ld entered for tgt inst %d.\n", + __func__, ha->host_no, ha->instance, pext->Instance);) + + tq = NULL; + for (tgt = 0, inst = 0; tgt < MAX_TARGETS; tgt++) { + if (ha->otgt[tgt] == NULL) { + continue; + } + /* if wrong target id then skip to next entry */ + if (inst != pext->Instance) { + inst++; + continue; + } + tq = ha->otgt[tgt]; + break; + } + + if (tq == NULL || tgt == MAX_TARGETS) { + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + DEBUG9_10(printk("%s(%ld): inst=%ld target dev not found. " + "tq=%p, tgt=%d.\n", + __func__, ha->host_no, ha->instance, tq, tgt);) + return (ret); + } + + if (tq->fcport == NULL) { /* dg 08/14/01 */ + pext->Status = EXT_STATUS_BUSY; + DEBUG9_10(printk("%s(%ld): inst=%ld target %d port not found. " + "tq=%p.\n", + __func__, ha->host_no, ha->instance, tgt, tq);) + return (ret); + } + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&ptmp_disc_target, + sizeof(EXT_DISC_TARGET))) { + /* not enough memory */ + pext->Status = EXT_STATUS_NO_MEMORY; + DEBUG9_10(printk("%s(%ld): inst=%ld scrap not big enough. " + "size requested=%ld.\n", + __func__, ha->host_no, ha->instance, + (ulong)sizeof(EXT_DISC_TARGET));) + return (ret); + } + + tgt_fcport = tq->fcport; + memcpy(ptmp_disc_target->WWNN, tgt_fcport->node_name, WWN_SIZE); + memcpy(ptmp_disc_target->WWPN, tgt_fcport->port_name, WWN_SIZE); + + ptmp_disc_target->Id[0] = 0; + ptmp_disc_target->Id[1] = tgt_fcport->d_id.r.d_id[2]; + ptmp_disc_target->Id[2] = tgt_fcport->d_id.r.d_id[1]; + ptmp_disc_target->Id[3] = tgt_fcport->d_id.r.d_id[0]; + + /* All devices on ha->otgt list are target capable devices. */ + ptmp_disc_target->Type = EXT_DEF_TARGET_DEV; + + if (tgt_fcport->flags & FCF_FABRIC_DEVICE) { + ptmp_disc_target->Type |= EXT_DEF_FABRIC_DEV; + } + if (tgt_fcport->flags & FCF_TAPE_PRESENT) { + ptmp_disc_target->Type |= EXT_DEF_TAPE_DEV; + } + if (tgt_fcport->port_type & FCT_INITIATOR) { + ptmp_disc_target->Type |= EXT_DEF_INITIATOR_DEV; + } + + ptmp_disc_target->LoopID = tgt_fcport->loop_id; + ptmp_disc_target->Status = 0; + if (atomic_read(&tq->fcport->state) != FCS_ONLINE) { + ptmp_disc_target->Status |= EXT_DEF_TGTSTAT_OFFLINE; + } + if (qla2x00_is_fcport_in_config(ha, tq->fcport)) { + ptmp_disc_target->Status |= EXT_DEF_TGTSTAT_IN_CFG; + } + + ptmp_disc_target->Bus = 0; + ptmp_disc_target->TargetId = tgt; + + cnt = 0; + /* enumerate available LUNs under this TGT (if any) */ + if (ha->otgt[tgt] != NULL) { + for (i = 0; i < MAX_LUNS ; i++) { + if ((ha->otgt[tgt])->olun[i] !=0) + cnt++; + } + } + + ptmp_disc_target->LunCount = cnt; + + DEBUG9(printk("%s(%ld): copying data for tgt id %d. ", + __func__, ha->host_no, tgt);) + DEBUG9(printk("port=%p:%02x%02x%02x%02x%02x%02x%02x%02x. " + "lun cnt=%d.\n", + tgt_fcport, + tgt_fcport->port_name[0], + tgt_fcport->port_name[1], + tgt_fcport->port_name[2], + tgt_fcport->port_name[3], + tgt_fcport->port_name[4], + tgt_fcport->port_name[5], + tgt_fcport->port_name[6], + tgt_fcport->port_name[7], + cnt);) + + ret = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr, + sizeof(EXT_DISC_TARGET)); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR verify wrt rsp buf\n", + __func__, ha->host_no, ha->instance);) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + /* now copy up the DISC_PORT to user */ + if (pext->ResponseLen < sizeof(EXT_DISC_PORT)) + transfer_size = pext->ResponseLen; + else + transfer_size = sizeof(EXT_DISC_TARGET); + + ret = copy_to_user((uint8_t *)pext->ResponseAdr, + (uint8_t *)ptmp_disc_target, transfer_size); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR copy rsp buffer.\n", + __func__, ha->host_no, ha->instance);) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + qla2x00_free_ioctl_scrap_mem(ha); + + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); +} + +/* + * qla2x00_query_chip + * Handles EXT_SC_QUERY_CHIP subcommand. + * + * Input: + * ha = adapter state pointer. + * pext = EXT_IOCTL structure pointer. + * mode = not used. + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_query_chip(scsi_qla_host_t *ha, EXT_IOCTL *pext, int mode) +{ + int ret = 0; + uint32_t transfer_size, i; + EXT_CHIP *ptmp_isp; + struct Scsi_Host *host; + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&ptmp_isp, + sizeof(EXT_CHIP))) { + /* not enough memory */ + pext->Status = EXT_STATUS_NO_MEMORY; + DEBUG9_10(printk("%s(%ld): inst=%ld scrap not big enough. " + "size requested=%ld.\n", + __func__, ha->host_no, ha->instance, + (ulong)sizeof(EXT_CHIP));) + return (ret); + } + + host = ha->host; + ptmp_isp->VendorId = ha->pdev->vendor; + ptmp_isp->DeviceId = ha->pdev->device; + ptmp_isp->SubVendorId = ha->pdev->subsystem_vendor; + ptmp_isp->SubSystemId = ha->pdev->subsystem_device; + ptmp_isp->PciBusNumber = ha->pdev->bus->number; + ptmp_isp->PciDevFunc = ha->pdev->devfn; + ptmp_isp->PciSlotNumber = PCI_SLOT(ha->pdev->devfn); + ptmp_isp->IoAddr = (UINT32)ha->pio_address; + ptmp_isp->IoAddrLen = (UINT32)ha->pio_length; + ptmp_isp->MemAddr = (UINT32)ha->mmio_address; + ptmp_isp->MemAddrLen = (UINT32)ha->mmio_length; + ptmp_isp->ChipType = 0; /* ? */ + ptmp_isp->InterruptLevel = host->irq; + + for (i = 0; i < 8; i++) + ptmp_isp->OutMbx[i] = 0; + + ret = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr, + sizeof(EXT_CHIP)); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR verify wrt rsp buf\n", + __func__, ha->host_no, ha->instance);) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + /* now copy up the ISP to user */ + if (pext->ResponseLen < sizeof(EXT_CHIP)) + transfer_size = pext->ResponseLen; + else + transfer_size = sizeof(EXT_CHIP); + + ret = copy_to_user((uint8_t *)pext->ResponseAdr, (uint8_t *)ptmp_isp, + transfer_size); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR copy rsp buffer.\n", + __func__, ha->host_no, ha->instance);) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + qla2x00_free_ioctl_scrap_mem(ha); + + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); +} + +/* + * qla2x00_get_data + * Handles all subcommands of the EXT_CC_GET_DATA command. + * + * Input: + * ha = adapter state pointer. + * pext = EXT_IOCTL structure pointer. + * mode = not used. + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_get_data(scsi_qla_host_t *ha, EXT_IOCTL *pext, int mode) +{ + int tmp_rval = 0; + + switch(pext->SubCode) { + case EXT_SC_GET_STATISTICS: + tmp_rval = qla2x00_get_statistics(ha, pext, mode); + break; + + case EXT_SC_GET_FC_STATISTICS: + tmp_rval = qla2x00_get_fc_statistics(ha, pext, mode); + break; + + case EXT_SC_GET_PORT_SUMMARY: + tmp_rval = qla2x00_get_port_summary(ha, pext, mode); + break; + + case EXT_SC_QUERY_DRIVER: + tmp_rval = qla2x00_query_driver(ha, pext, mode); + break; + + case EXT_SC_QUERY_FW: + tmp_rval = qla2x00_query_fw(ha, pext, mode); + break; + + case EXT_SC_GET_RNID: + tmp_rval = qla2x00_get_rnid_params(ha, pext, mode); + break; + + case EXT_SC_GET_BEACON_STATE: + if (IS_QLA23XX(ha)) { + tmp_rval = qla2x00_get_led_state(ha, pext, mode); + break; + } + /*FALLTHROUGH*/ + + default: + DEBUG10(printk("%s(%ld): inst=%ld unknown SubCode %d.\n", + __func__, ha->host_no, ha->instance, pext->SubCode);) + pext->Status = EXT_STATUS_UNSUPPORTED_SUBCODE; + break; + } + + return (tmp_rval); +} + +/* + * qla2x00_get_statistics + * Issues get_link_status mbx cmd and returns statistics + * relavent to the specified adapter. + * + * Input: + * ha = pointer to adapter struct of the specified adapter. + * pext = pointer to EXT_IOCTL structure containing values from user. + * mode = not used. + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_get_statistics(scsi_qla_host_t *ha, EXT_IOCTL *pext, int mode) +{ + EXT_HBA_PORT_STAT *ptmp_stat; + int ret = 0; + link_stat_t stat_buf; + uint8_t rval; + uint8_t *usr_temp, *kernel_tmp; + uint16_t mb_stat[1]; + uint32_t transfer_size; + + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + ret = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr, + sizeof(EXT_HBA_PORT_STAT)); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR VERIFY_WRITE " + "EXT_HBA_PORT_STAT.\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + + /* check on loop down */ + if (atomic_read(&ha->loop_state) != LOOP_READY || + test_bit(CFG_ACTIVE, &ha->cfg_flags) || + test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) || + test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) || + ha->dpc_active) { + + pext->Status = EXT_STATUS_BUSY; + DEBUG9_10(printk("%s(%ld): inst=%ld loop not ready.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); + } + + /* Send mailbox cmd to get more. */ + if ((rval = qla2x00_get_link_status(ha, ha->loop_id, &stat_buf, + mb_stat)) != QLA_SUCCESS) { + + if (rval == BIT_0) { + pext->Status = EXT_STATUS_NO_MEMORY; + } else if (rval == BIT_1) { + pext->Status = EXT_STATUS_MAILBOX; + pext->DetailStatus = EXT_DSTATUS_NOADNL_INFO; + } else { + pext->Status = EXT_STATUS_ERR; + } + + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR mailbox failed. " + "mb[0]=%x.\n", + __func__, ha->host_no, ha->instance, mb_stat[0]);) + printk(KERN_WARNING + "%s(%ld): inst=%ld ERROR mailbox failed. mb[0]=%x.\n", + __func__, ha->host_no, ha->instance, mb_stat[0]); + + return (ret); + } + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&ptmp_stat, + sizeof(EXT_HBA_PORT_STAT))) { + /* not enough memory */ + pext->Status = EXT_STATUS_NO_MEMORY; + DEBUG9_10(printk("%s(%ld): inst=%ld scrap not big enough. " + "size requested=%ld.\n", + __func__, ha->host_no, ha->instance, + (ulong)sizeof(EXT_HBA_PORT_STAT));) + return (ret); + } + + ptmp_stat->ControllerErrorCount = ha->total_isp_aborts; + ptmp_stat->DeviceErrorCount = ha->total_dev_errs; + ptmp_stat->TotalIoCount = ha->total_ios; + ptmp_stat->TotalMBytes = ha->total_bytes >> 20; + ptmp_stat->TotalLipResets = ha->total_lip_cnt; + /* + ptmp_stat->TotalInterrupts = ha->total_isr_cnt; + */ + + ptmp_stat->TotalLinkFailures = stat_buf.link_fail_cnt; + ptmp_stat->TotalLossOfSync = stat_buf.loss_sync_cnt; + ptmp_stat->TotalLossOfSignals = stat_buf.loss_sig_cnt; + ptmp_stat->PrimitiveSeqProtocolErrorCount = stat_buf.prim_seq_err_cnt; + ptmp_stat->InvalidTransmissionWordCount = stat_buf.inval_xmit_word_cnt; + ptmp_stat->InvalidCRCCount = stat_buf.inval_crc_cnt; + + /* now copy up the STATISTICS to user */ + if (pext->ResponseLen < sizeof(EXT_HBA_PORT_STAT)) + transfer_size = pext->ResponseLen; + else + transfer_size = sizeof(EXT_HBA_PORT_STAT); + + usr_temp = (uint8_t *)pext->ResponseAdr; + kernel_tmp = (uint8_t *)ptmp_stat; + ret = copy_to_user(usr_temp, kernel_tmp, transfer_size); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR copy rsp buffer.\n", + __func__, ha->host_no, ha->instance);) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + qla2x00_free_ioctl_scrap_mem(ha); + + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); +} + +/* + * qla2x00_get_fc_statistics + * Issues get_link_status mbx cmd to the target device with + * the specified WWN and returns statistics relavent to the + * device. + * + * Input: + * ha = pointer to adapter struct of the specified device. + * pext = pointer to EXT_IOCTL structure containing values from user. + * mode = not used. + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_get_fc_statistics(scsi_qla_host_t *ha, EXT_IOCTL *pext, int mode) +{ + EXT_HBA_PORT_STAT *ptmp_stat; + EXT_DEST_ADDR addr_struct; + fc_port_t *fcport; + int port_found; + link_stat_t stat_buf; + int ret = 0; + uint8_t rval; + uint8_t *usr_temp, *kernel_tmp; + uint8_t *req_name; + uint16_t mb_stat[1]; + uint32_t transfer_size; + + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + ret = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr, + sizeof(EXT_HBA_PORT_STAT)); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR VERIFY_WRITE.\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + + ret = copy_from_user(&addr_struct, pext->RequestAdr, pext->RequestLen); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR copy req buf.\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + + /* find the device's loop_id */ + port_found = 0; + fcport = NULL; + switch (addr_struct.DestType) { + case EXT_DEF_DESTTYPE_WWPN: + req_name = addr_struct.DestAddr.WWPN; + list_for_each_entry(fcport, &ha->fcports, list) { + if (memcmp(fcport->port_name, req_name, + EXT_DEF_WWN_NAME_SIZE) == 0) { + port_found = 1; + break; + } + } + break; + + case EXT_DEF_DESTTYPE_WWNN: + case EXT_DEF_DESTTYPE_PORTID: + case EXT_DEF_DESTTYPE_FABRIC: + case EXT_DEF_DESTTYPE_SCSI: + default: + pext->Status = EXT_STATUS_INVALID_PARAM; + pext->DetailStatus = EXT_DSTATUS_NOADNL_INFO; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR Unsupported subcode " + "address type.\n", __func__, ha->host_no, ha->instance);) + return (ret); + + break; + } + + if (!port_found) { + /* not found */ + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + pext->DetailStatus = EXT_DSTATUS_TARGET; + return (ret); + } + + /* check for suspended/lost device */ + /* + if (ha->fcport is suspended/lost) { + pext->Status = EXT_STATUS_SUSPENDED; + pext->DetailStatus = EXT_DSTATUS_TARGET; + return pext->Status; + } + */ + + /* check on loop down */ + if (atomic_read(&ha->loop_state) != LOOP_READY || + test_bit(CFG_ACTIVE, &ha->cfg_flags) || + test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) || + test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) || + ha->dpc_active) { + + pext->Status = EXT_STATUS_BUSY; + DEBUG9_10(printk("%s(%ld): inst=%ld loop not ready.\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + + /* Send mailbox cmd to get more. */ + if ((rval = qla2x00_get_link_status(ha, fcport->loop_id, + &stat_buf, mb_stat)) != QLA_SUCCESS) { + if (rval == BIT_0) { + pext->Status = EXT_STATUS_NO_MEMORY; + } else if (rval == BIT_1) { + pext->Status = EXT_STATUS_MAILBOX; + pext->DetailStatus = EXT_DSTATUS_NOADNL_INFO; + } else { + pext->Status = EXT_STATUS_ERR; + } + + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR mailbox failed. " + "mb[0]=%x.\n", + __func__, ha->host_no, ha->instance, mb_stat[0]);) + return (ret); + } + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&ptmp_stat, + sizeof(EXT_HBA_PORT_STAT))) { + /* not enough memory */ + pext->Status = EXT_STATUS_NO_MEMORY; + DEBUG9_10(printk("%s(%ld): inst=%ld scrap not big enough. " + "size requested=%ld.\n", + __func__, ha->host_no, ha->instance, + (ulong)sizeof(EXT_HBA_PORT_STAT));) + return (ret); + } + + ptmp_stat->ControllerErrorCount = ha->total_isp_aborts; + ptmp_stat->DeviceErrorCount = ha->total_dev_errs; + ptmp_stat->TotalIoCount = ha->total_ios; + ptmp_stat->TotalMBytes = ha->total_bytes >> 20; + ptmp_stat->TotalLipResets = ha->total_lip_cnt; + /* + ptmp_stat->TotalInterrupts = ha->total_isr_cnt; + */ + + ptmp_stat->TotalLinkFailures = stat_buf.link_fail_cnt; + ptmp_stat->TotalLossOfSync = stat_buf.loss_sync_cnt; + ptmp_stat->TotalLossOfSignals = stat_buf.loss_sig_cnt; + ptmp_stat->PrimitiveSeqProtocolErrorCount = stat_buf.prim_seq_err_cnt; + ptmp_stat->InvalidTransmissionWordCount = stat_buf.inval_xmit_word_cnt; + ptmp_stat->InvalidCRCCount = stat_buf.inval_crc_cnt; + + /* now copy up the STATISTICS to user */ + if (pext->ResponseLen < sizeof(EXT_HBA_PORT_STAT)) + transfer_size = pext->ResponseLen; + else + transfer_size = sizeof(EXT_HBA_PORT_STAT); + + usr_temp = (uint8_t *)pext->ResponseAdr; + kernel_tmp = (uint8_t *)ptmp_stat; + ret = copy_to_user(usr_temp, kernel_tmp, transfer_size); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR copy rsp buffer.\n", + __func__, ha->host_no, ha->instance);) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + qla2x00_free_ioctl_scrap_mem(ha); + + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); +} + +/* + * qla2x00_get_port_summary + * Handles EXT_SC_GET_PORT_SUMMARY subcommand. + * Returns values of devicedata and dd_entry list. + * + * Input: + * ha = adapter state pointer. + * pext = EXT_IOCTL structure pointer. + * mode = not used. + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_get_port_summary(scsi_qla_host_t *ha, EXT_IOCTL *pext, int mode) +{ + int ret = 0; + uint8_t *usr_temp, *kernel_tmp; + uint32_t entry_cnt = 0; + uint32_t port_cnt = 0; + uint32_t top_xfr_size; + uint32_t usr_no_of_entries = 0; + void *start_of_entry_list; + fc_port_t *fcport; + + EXT_DEVICEDATA *pdevicedata; + EXT_DEVICEDATAENTRY *pdd_entry; + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&pdevicedata, + sizeof(EXT_DEVICEDATA))) { + /* not enough memory */ + pext->Status = EXT_STATUS_NO_MEMORY; + DEBUG9_10(printk("%s(%ld): inst=%ld scrap not big enough. " + "pdevicedata requested=%d.\n", + __func__, ha->host_no, ha->instance, + sizeof(EXT_DEVICEDATA));) + return (ret); + } + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&pdd_entry, + sizeof(EXT_DEVICEDATAENTRY))) { + /* not enough memory */ + pext->Status = EXT_STATUS_NO_MEMORY; + DEBUG9_10(printk("%s(%ld): inst=%ld scrap not big enough. " + "pdd_entry requested=%d.\n", + __func__, ha->host_no, ha->instance, + sizeof(EXT_DEVICEDATAENTRY));) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + /* Get maximum number of entries allowed in response buf */ + usr_no_of_entries = pext->ResponseLen / sizeof(EXT_DEVICEDATAENTRY); + + /* reserve some spaces to be filled in later. */ + top_xfr_size = sizeof(pdevicedata->ReturnListEntryCount) + + sizeof(pdevicedata->TotalDevices); + + start_of_entry_list = (void *)(pext->ResponseAdr) + top_xfr_size; + + /* Start copying from devices that exist. */ + ret = qla2x00_get_fcport_summary(ha, pdd_entry, + start_of_entry_list, usr_no_of_entries, + &entry_cnt, &pext->Status); + + DEBUG9(printk("%s(%ld): after get_fcport_summary, entry_cnt=%d.\n", + __func__, ha->host_no, entry_cnt);) + + /* If there's still space in user buffer, return devices found + * in config file which don't actually exist (missing). + */ + if (ret == 0) { + if (!qla2x00_failover_enabled(ha)) { +#if 0 + ret = qla2x00_std_missing_port_summary(ha, pdd_entry, + start_of_entry_list, usr_no_of_entries, + &entry_cnt, &pext->Status); +#endif + } else { + ret = qla2x00_fo_missing_port_summary(ha, pdd_entry, + start_of_entry_list, usr_no_of_entries, + &entry_cnt, &pext->Status); + + } + } + + DEBUG9(printk( + "%s(%ld): after get_missing_port_summary. entry_cnt=%d.\n", + __func__, ha->host_no, entry_cnt);) + + if (ret) { + DEBUG9_10(printk("%s(%ld): failed getting port info.\n", + __func__, ha->host_no);) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + pdevicedata->ReturnListEntryCount = entry_cnt; + list_for_each_entry(fcport, &ha->fcports, list) { + port_cnt++; + } + if (port_cnt > entry_cnt) + pdevicedata->TotalDevices = port_cnt; + else + pdevicedata->TotalDevices = entry_cnt; + + DEBUG9(printk("%s(%ld): inst=%ld EXT_SC_GET_PORT_SUMMARY " + "return entry cnt=%d port_cnt=%d.\n", + __func__, ha->host_no, ha->instance, + entry_cnt, port_cnt);) + + /* copy top of devicedata, which is everything other than the + * actual entry list data. + */ + ret = verify_area(VERIFY_WRITE, (void *)(pext->ResponseAdr), + top_xfr_size); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR verify wrt rsp buf\n", + __func__, ha->host_no, ha->instance);) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + usr_temp = (uint8_t *)pext->ResponseAdr; + kernel_tmp = (uint8_t *)pdevicedata; + ret = copy_to_user(usr_temp, kernel_tmp, top_xfr_size); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR copy rsp " + "devicedata buffer.\n", + __func__, ha->host_no, ha->instance);) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + + qla2x00_free_ioctl_scrap_mem(ha); + + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); +} + +/* + * qla2x00_get_fcport_summary + * Returns port values in user's dd_entry list. + * + * Input: + * ha = adapter state pointer. + * pdd_entry = pointer to a temporary EXT_DEVICEDATAENTRY struct + * pstart_of_entry_list = start of user addr of buffer for dd_entry entries + * max_entries = max number of entries allowed by user buffer + * pentry_cnt = pointer to total number of entries so far + * ret_status = pointer to ioctl status field + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_get_fcport_summary(scsi_qla_host_t *ha, EXT_DEVICEDATAENTRY *pdd_entry, + void *pstart_of_entry_list, uint32_t max_entries, uint32_t *pentry_cnt, + uint32_t *ret_status) +{ + int ret = QLA_SUCCESS; + uint8_t *usr_temp, *kernel_tmp; + uint32_t b; + uint32_t current_offset; + uint32_t tgt; + uint32_t transfer_size; + fc_port_t *fcport; + os_tgt_t *tq; + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + list_for_each_entry(fcport, &ha->fcports, list) { + if (*pentry_cnt >= max_entries) + break; + + if ((atomic_read(&fcport->state) != FCS_ONLINE) && + !qla2x00_is_fcport_in_config(ha, fcport)) { + /* no need to report */ + DEBUG2_9_10(printk("%s(%ld): not reporting " + "fcport %02x%02x%02x%02x%02x%02x%02x%02x. " + "state=%i, flags=%02x.\n", + __func__, ha->host_no, fcport->port_name[0], + fcport->port_name[1], fcport->port_name[2], + fcport->port_name[3], fcport->port_name[4], + fcport->port_name[5], fcport->port_name[6], + fcport->port_name[7], atomic_read(&fcport->state), + fcport->flags)); + continue; + } + + /* copy from fcport to dd_entry */ + memcpy(pdd_entry->NodeWWN, fcport->node_name, WWN_SIZE); + memcpy(pdd_entry->PortWWN, fcport->port_name, WWN_SIZE); + + for (b = 0; b < 3 ; b++) + pdd_entry->PortID[b] = fcport->d_id.r.d_id[2-b]; + + if (fcport->flags & FCF_FABRIC_DEVICE) { + pdd_entry->ControlFlags = EXT_DEF_GET_FABRIC_DEVICE; + } else { + pdd_entry->ControlFlags = 0; + } + + pdd_entry->TargetAddress.Bus = 0; + /* Retrieve 'Target' number for port */ + for (tgt = 0; tgt < MAX_TARGETS; tgt++) { + if ((tq = ha->otgt[tgt]) == NULL) { + continue; + } + + if (tq->fcport == NULL) + continue; + + if (memcmp(fcport->port_name, tq->fcport->port_name, + EXT_DEF_WWN_NAME_SIZE) == 0) { + pdd_entry->TargetAddress.Target = tgt; + break; + } + } + pdd_entry->TargetAddress.Lun = 0; + pdd_entry->DeviceFlags = 0; + pdd_entry->LoopID = fcport->loop_id; + pdd_entry->BaseLunNumber = 0; + + DEBUG9_10(printk("%s(%ld): reporting " + "fcport %02x%02x%02x%02x%02x%02x%02x%02x.\n", + __func__, ha->host_no, fcport->port_name[0], + fcport->port_name[1], fcport->port_name[2], + fcport->port_name[3], fcport->port_name[4], + fcport->port_name[5], fcport->port_name[6], + fcport->port_name[7])); + + current_offset = *pentry_cnt * sizeof(EXT_DEVICEDATAENTRY); + + transfer_size = sizeof(EXT_DEVICEDATAENTRY); + ret = verify_area(VERIFY_WRITE, + (uint8_t *)pstart_of_entry_list + current_offset, + transfer_size); + + if (ret) { + *ret_status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR verify WRITE " + "rsp bufaddr=%p\n", + __func__, ha->host_no, ha->instance, + (uint8_t *)pstart_of_entry_list + current_offset);) + return (ret); + } + + /* now copy up this dd_entry to user */ + usr_temp = (uint8_t *)pstart_of_entry_list + current_offset; + kernel_tmp = (uint8_t *)pdd_entry; + ret = copy_to_user(usr_temp, kernel_tmp, transfer_size); + if (ret) { + *ret_status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR copy rsp " + "entry list buffer.\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + + *pentry_cnt += 1; + } + + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); +} + +/* + * qla2x00_fo_missing_port_summary is in qla_fo.c + */ + +//RUBY: Do we need this with the new consolidated fcports list? This will +// be handled transparently in qla2x00_get_fcport_summary(). +#if 0 +/* + * qla2x00_std_missing_port_summary + * Returns values of devices not connected but found in configuration + * file in user's dd_entry list. + * + * Input: + * ha = adapter state pointer. + * pdd_entry = pointer to a temporary EXT_DEVICEDATAENTRY struct + * pstart_of_entry_list = start of user addr of buffer for dd_entry entries + * max_entries = max number of entries allowed by user buffer + * pentry_cnt = pointer to total number of entries so far + * ret_status = pointer to ioctl status field + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_std_missing_port_summary(scsi_qla_host_t *ha, + EXT_DEVICEDATAENTRY *pdd_entry, void *pstart_of_entry_list, + uint32_t max_entries, uint32_t *pentry_cnt, uint32_t *ret_status) +{ + int ret = QLA_SUCCESS; + uint8_t *usr_temp, *kernel_tmp; + uint16_t idx; + uint32_t b; + uint32_t current_offset; + uint32_t transfer_size; + fcdev_t *pdev; + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + for (idx = 0; idx < MAX_FIBRE_DEVICES && *pentry_cnt < max_entries; + idx++) { + pdev = &ha->fc_db[idx]; + + if (pdev->loop_id == PORT_UNUSED) + continue; + + /* RLU: sanity check */ + /* + if (qla2x00_is_wwn_zero(pdev->wwn) && + qla2x00_is_wwn_zero(pdev->name) && pdev->d_id.b24 == 0) { + continue; + } + */ + + if (pdev->loop_id == PORT_AVAILABLE) { + DEBUG10(printk("%s: returning missing device " + "%02x%02x%02x%02x%02x%02x%02x%02x.\n", + __func__, + pdev->wwn[0], pdev->wwn[1], + pdev->wwn[2], pdev->wwn[3], + pdev->wwn[4], pdev->wwn[5], + pdev->wwn[6], pdev->wwn[7]);) + + /* This device was not found. Return + * as unconfigured. + */ + memcpy(pdd_entry->NodeWWN, pdev->name, WWN_SIZE); + memcpy(pdd_entry->PortWWN, pdev->wwn, WWN_SIZE); + + for (b = 0; b < 3 ; b++) + pdd_entry->PortID[b] = 0; + + /* assume fabric dev so api won't translate the portid from loopid */ + pdd_entry->ControlFlags = EXT_DEF_GET_FABRIC_DEVICE; + + pdd_entry->TargetAddress.Bus = 0; + pdd_entry->TargetAddress.Target = idx; + pdd_entry->TargetAddress.Lun = 0; + pdd_entry->DeviceFlags = 0; + pdd_entry->LoopID = 0; + pdd_entry->BaseLunNumber = 0; + + current_offset = *pentry_cnt * + sizeof(EXT_DEVICEDATAENTRY); + + transfer_size = sizeof(EXT_DEVICEDATAENTRY); + ret = verify_area(VERIFY_WRITE, + (uint8_t *)pstart_of_entry_list + current_offset, + transfer_size); + + if (ret == 0) { + + /* now copy up this dd_entry to user */ + usr_temp = (uint8_t *)pstart_of_entry_list + + current_offset; + kernel_tmp = (uint8_t *)pdd_entry; + ret = copy_to_user(usr_temp, kernel_tmp, + transfer_size); + if (ret) { + *ret_status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld " + "ERROR copy rsp list buffer.\n", + __func__, ha->host_no, + ha->instance);) + break; + } else { + *pentry_cnt+=1; + } + } else { + *ret_status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld " + "ERROR verify wrt rsp bufaddr=%p\n", + __func__, ha->host_no, ha->instance, + (uint8_t *)pstart_of_entry_list + + current_offset);) + break; + } + } + + if (ret || *ret_status) { + break; + } + } + + DEBUG9(printk("%s(%ld): inst=%ld exiting. ret=%d.\n", + __func__, ha->host_no, ha->instance, ret);) + + return (ret); +} +#endif + +/* + * qla2x00_query_driver + * Handles EXT_SC_QUERY_DRIVER subcommand. + * + * Input: + * ha = adapter state pointer. + * pext = EXT_IOCTL structure pointer. + * mode = not used. + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_query_driver(scsi_qla_host_t *ha, EXT_IOCTL *pext, int mode) +{ + int ret = 0; + uint8_t *usr_temp, *kernel_tmp; + uint32_t transfer_size; + EXT_DRIVER *pdriver_prop; + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&pdriver_prop, + sizeof(EXT_DRIVER))) { + /* not enough memory */ + pext->Status = EXT_STATUS_NO_MEMORY; + DEBUG9_10(printk("%s(%ld): inst=%ld scrap not big enough. " + "size requested=%ld.\n", + __func__, ha->host_no, ha->instance, + (ulong)sizeof(EXT_DRIVER));) + return (ret); + } + + sprintf(pdriver_prop->Version, qla2x00_version_str); + pdriver_prop->NumOfBus = MAX_BUSES; + pdriver_prop->TargetsPerBus = MAX_FIBRE_DEVICES; + pdriver_prop->LunsPerTarget = MAX_LUNS; + pdriver_prop->MaxTransferLen = 0xffffffff; + pdriver_prop->MaxDataSegments = 0xffffffff; + + if (ha->flags.enable_64bit_addressing == 1) + pdriver_prop->DmaBitAddresses = 64; + else + pdriver_prop->DmaBitAddresses = 32; + + if (pext->ResponseLen < sizeof(EXT_DRIVER)) + transfer_size = pext->ResponseLen; + else + transfer_size = sizeof(EXT_DRIVER); + + ret = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr , + transfer_size); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG10(printk("%s(%ld): inst=%ld ERROR verify wrt rsp buf.\n", + __func__, ha->host_no, ha->instance);) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + /* now copy up the ISP to user */ + usr_temp = (uint8_t *)pext->ResponseAdr; + kernel_tmp = (uint8_t *)pdriver_prop; + ret = copy_to_user(usr_temp, kernel_tmp, transfer_size); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR copy rsp buffer.\n", + __func__, ha->host_no, ha->instance);) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + qla2x00_free_ioctl_scrap_mem(ha); + + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); +} + +/* + * qla2x00_query_fw + * Handles EXT_SC_QUERY_FW subcommand. + * + * Input: + * ha = adapter state pointer. + * pext = EXT_IOCTL structure pointer. + * mode = not used. + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_query_fw(scsi_qla_host_t *ha, EXT_IOCTL *pext, int mode) +{ + int ret = 0; + uint8_t *usr_temp, *kernel_tmp; + uint32_t transfer_size; + EXT_FW *pfw_prop; + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&pfw_prop, + sizeof(EXT_FW))) { + /* not enough memory */ + pext->Status = EXT_STATUS_NO_MEMORY; + DEBUG9_10(printk("%s(%ld): inst=%ld scrap not big enough. " + "size requested=%ld.\n", + __func__, ha->host_no, ha->instance, + (ulong)sizeof(EXT_FW));) + return (ret); + } + + pfw_prop->Version[0] = ha->fw_major_version; + pfw_prop->Version[1] = ha->fw_minor_version; + pfw_prop->Version[2] = ha->fw_subminor_version; + + transfer_size = sizeof(EXT_FW); + + ret = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr , + transfer_size); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG10(printk("%s(%ld): inst=%ld ERROR verify wrt rsp buf.\n", + __func__, ha->host_no, ha->instance);) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + usr_temp = (uint8_t *)pext->ResponseAdr; + kernel_tmp = (uint8_t *)pfw_prop; + ret = copy_to_user(usr_temp, kernel_tmp, transfer_size); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR copy rsp buffer.\n", + __func__, ha->host_no, ha->instance);) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + qla2x00_free_ioctl_scrap_mem(ha); + + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); +} + +static int +qla2x00_msiocb_passthru(scsi_qla_host_t *ha, EXT_IOCTL *pext, int cmd, + int mode) +{ + int ret = 0; + fc_lun_t *ptemp_fclun = NULL; /* buf from scrap mem */ + fc_port_t *ptemp_fcport = NULL; /* buf from scrap mem */ + struct scsi_cmnd *pscsi_cmd = NULL; /* buf from scrap mem */ + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + /* check on current topology */ + if ((ha->current_topology != ISP_CFG_F) && + (ha->current_topology != ISP_CFG_FL)) { + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR not in F/FL mode\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + + if (ha->ioctl_mem_size <= 0) { + if (qla2x00_get_new_ioctl_dma_mem(ha, + QLA_INITIAL_IOCTLMEM_SIZE) != QLA_SUCCESS) { + + DEBUG9_10(printk("%s: ERROR cannot alloc DMA " + "buffer size=%lx.\n", + __func__, QLA_INITIAL_IOCTLMEM_SIZE);) + + pext->Status = EXT_STATUS_NO_MEMORY; + return (ret); + } + } + + if (pext->ResponseLen > ha->ioctl_mem_size) { + if (qla2x00_get_new_ioctl_dma_mem(ha, pext->ResponseLen) != + QLA_SUCCESS) { + + DEBUG9_10(printk("%s: ERROR cannot alloc requested" + "DMA buffer size %x.\n", + __func__, pext->ResponseLen);) + + pext->Status = EXT_STATUS_NO_MEMORY; + return (ret); + } + + DEBUG9(printk("%s(%ld): inst=%ld rsp buf length larger than " + "existing size. Additional mem alloc successful.\n", + __func__, ha->host_no, ha->instance);) + } + + ret = verify_area(VERIFY_READ, (void *)pext->RequestAdr, + pext->RequestLen); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk( + "%s(%ld): inst=%ld ERROR verify read req buf\n", + __func__, ha->host_no, ha->instance);) + + return (ret); + } + + DEBUG9(printk("%s(%ld): inst=%ld req buf verified.\n", + __func__, ha->host_no, ha->instance);) + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&pscsi_cmd, + sizeof(struct scsi_cmnd))) { + /* not enough memory */ + pext->Status = EXT_STATUS_NO_MEMORY; + DEBUG9_10(printk("%s(%ld): inst=%ld scrap not big enough. " + "cmd size requested=%ld.\n", + __func__, ha->host_no, ha->instance, + (ulong)sizeof(struct scsi_cmnd));) + return (ret); + } + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&ptemp_fcport, + sizeof(fc_port_t))) { + /* not enough memory */ + pext->Status = EXT_STATUS_NO_MEMORY; + DEBUG9_10(printk("%s(%ld): inst=%ld scrap not big enough. " + "fcport size requested=%ld.\n", + __func__, ha->host_no, ha->instance, + (ulong)sizeof(fc_port_t));) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&ptemp_fclun, + sizeof(fc_lun_t))) { + /* not enough memory */ + pext->Status = EXT_STATUS_NO_MEMORY; + DEBUG9_10(printk("%s(%ld): inst=%ld scrap not big enough. " + "fclun size requested=%ld.\n", + __func__, ha->host_no, ha->instance, + (ulong)sizeof(fc_lun_t));) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + /* initialize */ + memset(ha->ioctl_mem, 0, ha->ioctl_mem_size); + + switch (cmd) { + case EXT_CC_SEND_FCCT_PASSTHRU: + DEBUG9(printk("%s: got CT passthru cmd.\n", __func__)); + ret = qla2x00_send_fcct(ha, pext, pscsi_cmd, ptemp_fcport, + ptemp_fclun, mode); + break; + case EXT_CC_SEND_ELS_PASSTHRU: + DEBUG9(printk("%s: got ELS passthru cmd.\n", __func__)); + if (IS_QLA23XX(ha)) { + ret = qla2x00_send_els_passthru(ha, pext, pscsi_cmd, + ptemp_fcport, ptemp_fclun, mode); + break; + } + /*FALLTHROUGH */ + default: + DEBUG9_10(printk("%s: got invalid cmd.\n", __func__)); + break; + } + + qla2x00_free_ioctl_scrap_mem(ha); + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); +} + +/* + * qla2x00_send_els_passthru + * Passes the ELS command down to firmware as MSIOCB and + * copies the response back when it completes. + * + * Input: + * ha = adapter state pointer. + * pext = EXT_IOCTL structure pointer. + * mode = not used. + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_send_els_passthru(scsi_qla_host_t *ha, EXT_IOCTL *pext, + struct scsi_cmnd *pscsi_cmd, fc_port_t *ptmp_fcport, fc_lun_t *ptmp_fclun, + int mode) +{ + int ret = 0; + + uint8_t invalid_wwn = FALSE; + uint8_t *ptmp_stat; + uint8_t *pusr_req_buf; + uint8_t *presp_payload; + uint32_t payload_len; + uint32_t usr_req_len; + + int found; + uint16_t next_loop_id; + fc_port_t *fcport; + + EXT_ELS_PT_REQ *pels_pt_req; + + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + usr_req_len = pext->RequestLen - sizeof(EXT_ELS_PT_REQ); + if (usr_req_len > ha->ioctl_mem_size) { + pext->Status = EXT_STATUS_INVALID_PARAM; + + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR ReqLen too big=%x.\n", + __func__, ha->host_no, ha->instance, pext->RequestLen);) + + return (ret); + } + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&pels_pt_req, + sizeof(EXT_ELS_PT_REQ))) { + /* not enough memory */ + pext->Status = EXT_STATUS_NO_MEMORY; + DEBUG9_10(printk("%s(%ld): inst=%ld scrap not big enough. " + "els_pt_req size requested=%ld.\n", + __func__, ha->host_no, ha->instance, + (ulong)sizeof(EXT_ELS_PT_REQ));) + return (ret); + } + + /* copy request buffer */ + + ret = copy_from_user(pels_pt_req, pext->RequestAdr, + sizeof(EXT_ELS_PT_REQ)); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR" + "copy_from_user() of struct failed (%d).\n", + __func__, ha->host_no, ha->instance, ret);) + + return (ret); + } + + pusr_req_buf = (uint8_t *)pext->RequestAdr + sizeof(EXT_ELS_PT_REQ); + + ret = copy_from_user(ha->ioctl_mem, pusr_req_buf, usr_req_len); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR" + "copy_from_user() of request buf failed (%d).\n", + __func__, ha->host_no, ha->instance, ret);) + + return (ret); + } + + DEBUG9(printk("%s(%ld): inst=%ld after copy request.\n", + __func__, ha->host_no, ha->instance);) + + /* check on loop down (1) */ + if (atomic_read(&ha->loop_state) != LOOP_READY || + test_bit(CFG_ACTIVE, &ha->cfg_flags) || + test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) || + test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) { + + DEBUG9_10(printk( + "%s(%ld): inst=%ld before dest port validation- loop not " + "ready; cannot proceed.\n", + __func__, ha->host_no, ha->instance);) + + pext->Status = EXT_STATUS_BUSY; + + return (ret); + } + + /*********************************/ + /* Validate the destination port */ + /*********************************/ + + /* first: WWN cannot be zero if no PID is specified */ + invalid_wwn = qla2x00_is_wwn_zero(pels_pt_req->WWPN); + if (invalid_wwn && !(pels_pt_req->ValidMask & EXT_DEF_PID_VALID)) { + /* error: both are not set. */ + pext->Status = EXT_STATUS_INVALID_PARAM; + + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR no valid WWPN/PID\n", + __func__, ha->host_no, ha->instance);) + + return (ret); + } + + /* second: it cannot be the local/current HBA itself */ + if (!invalid_wwn) { + if (memcmp(ha->init_cb->port_name, pels_pt_req->WWPN, + EXT_DEF_WWN_NAME_SIZE) == 0) { + + /* local HBA specified. */ + + pext->Status = EXT_STATUS_INVALID_PARAM; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR local HBA's " + "WWPN found.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); + } + } else { /* using PID */ + if (pels_pt_req->Id[1] == ha->d_id.r.d_id[2] + && pels_pt_req->Id[2] == ha->d_id.r.d_id[1] + && pels_pt_req->Id[3] == ha->d_id.r.d_id[0]) { + + /* local HBA specified. */ + + pext->Status = EXT_STATUS_INVALID_PARAM; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR local HBA's " + "PID found.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); + } + } + + /************************/ + /* Now find the loop ID */ + /************************/ + + found = 0; + fcport = NULL; + list_for_each_entry(fcport, &ha->fcports, list) { + if (fcport->port_type != FCT_INITIATOR || + fcport->port_type != FCT_TARGET) + continue; + + if (!invalid_wwn) { + /* search with WWPN */ + if (memcmp(pels_pt_req->WWPN, fcport->port_name, + EXT_DEF_WWN_NAME_SIZE)) + continue; + } else { + /* search with PID */ + if (pels_pt_req->Id[1] != fcport->d_id.r.d_id[2] + || pels_pt_req->Id[2] != fcport->d_id.r.d_id[1] + || pels_pt_req->Id[3] != fcport->d_id.r.d_id[0]) + continue; + } + + found++; + } + + if (!found) { + /* invalid WWN or PID specified */ + pext->Status = EXT_STATUS_INVALID_PARAM; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR WWPN/PID invalid.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); + } + + /* If this is for a host device, check if we need to perform login */ + if (fcport->port_type == FCT_INITIATOR && + fcport->loop_id >= ha->last_loop_id) { + + next_loop_id = 0; + ret = qla2x00_fabric_login(ha, fcport, &next_loop_id); + if (ret != QLA_SUCCESS) { + /* login failed. */ + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR login to " + "host port failed. loop_id=%02x pid=%02x%02x%02x " + "ret=%d.\n", + __func__, ha->host_no, ha->instance, + fcport->loop_id, fcport->d_id.b.domain, + fcport->d_id.b.area, fcport->d_id.b.al_pa, ret);) + + return (ret); + } + } + + /* queue command */ + pels_pt_req->Lid = fcport->loop_id; + + if ((ret = qla2x00_ioctl_ms_queuecommand(ha, pext, pscsi_cmd, + ptmp_fcport, ptmp_fclun, pels_pt_req))) { + return (ret); + } + + /* check on data returned */ + ptmp_stat = (uint8_t *)ha->ioctl_mem + FC_HEADER_LEN; + + if (*ptmp_stat == ELS_STAT_LS_RJT) { + payload_len = FC_HEADER_LEN + ELS_RJT_LENGTH; + + } else if (*ptmp_stat == ELS_STAT_LS_ACC) { + payload_len = pext->ResponseLen - sizeof(EXT_ELS_PT_REQ); + + } else { + /* invalid. just copy the status word. */ + DEBUG9_10(printk("%s(%ld): inst=%ld invalid stat " + "returned =0x%x.\n", + __func__, ha->host_no, ha->instance, *ptmp_stat);) + + payload_len = FC_HEADER_LEN + 4; + } + + DEBUG9(printk("%s(%ld): inst=%ld data dump-\n", + __func__, ha->host_no, ha->instance);) + DEBUG9(qla2x00_dump_buffer((uint8_t *)ptmp_stat, + pext->ResponseLen - sizeof(EXT_ELS_PT_REQ) - FC_HEADER_LEN);) + + /* Verify response buffer to be written */ + /* The data returned include FC frame header */ + presp_payload = (uint8_t *)pext->ResponseAdr + sizeof(EXT_ELS_PT_REQ); + + ret = verify_area(VERIFY_WRITE, (void *)presp_payload, payload_len); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR verify wrt rsp " + "buffer. ha=%p.\n", + __func__, ha->host_no, ha->instance, ha);) + + return (ret); + } + + /* copy back data returned to response buffer */ + ret = copy_to_user(presp_payload, (uint8_t *)ha->ioctl_mem, + payload_len); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR copy rsp buffer.\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + + DEBUG9(printk("%s(%ld): inst=%ld exiting normally.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); +} + +/* + * qla2x00_send_fcct + * Passes the FC CT command down to firmware as MSIOCB and + * copies the response back when it completes. + * + * Input: + * ha = adapter state pointer. + * pext = EXT_IOCTL structure pointer. + * mode = not used. + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_send_fcct(scsi_qla_host_t *ha, EXT_IOCTL *pext, + struct scsi_cmnd *pscsi_cmd, fc_port_t *ptmp_fcport, fc_lun_t *ptmp_fclun, + int mode) +{ + int ret = 0; + int tmp_rval = 0; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + if (pext->RequestLen > ha->ioctl_mem_size) { + pext->Status = EXT_STATUS_INVALID_PARAM; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR ReqLen too big=%x.\n", + __func__, ha->host_no, ha->instance, pext->RequestLen);) + + return (ret); + } + + /* copy request buffer */ + ret = copy_from_user(ha->ioctl_mem, pext->RequestAdr, pext->RequestLen); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk( + "%s(%ld): inst=%ld ERROR copy req buf. ret=%d\n", + __func__, ha->host_no, ha->instance, ret);) + + + return (ret); + } + + DEBUG9(printk("%s(%ld): inst=%ld after copy request.\n", + __func__, ha->host_no, ha->instance);) + + /* check on management server login status */ + if (ha->flags.management_server_logged_in == 0) { + /* login to management server device */ + + tmp_rval = qla2x00_login_fabric(ha, MANAGEMENT_SERVER, + 0xff, 0xff, 0xfa, &mb[0], BIT_1); + + if (tmp_rval != 0 || mb[0] != 0x4000) { + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + + DEBUG9_10(printk( + "%s(%ld): inst=%ld ERROR login to MS.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); + } + + ha->flags.management_server_logged_in = 1; + } + + DEBUG9(printk("%s(%ld): success login to MS.\n", + __func__, ha->host_no);) + + /* queue command */ + if ((ret = qla2x00_ioctl_ms_queuecommand(ha, pext, pscsi_cmd, + ptmp_fcport, ptmp_fclun, NULL))) { + return (ret); + } + + if (CMD_COMPL_STATUS(pscsi_cmd) != 0 || + CMD_ENTRY_STATUS(pscsi_cmd) != 0) { + DEBUG9_10(printk("%s(%ld): inst=%ld cmd returned error=%x.\n", + __func__, ha->host_no, ha->instance, + CMD_COMPL_STATUS(pscsi_cmd));) + pext->Status = EXT_STATUS_ERR; + return (ret); + } + + /* getting device data and putting in pext->ResponseAdr */ + ret = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr , + pext->ResponseLen); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR verify wrt rsp " + "buffer. ha=%p.\n", + __func__, ha->host_no, ha->instance, ha);) + return (ret); + } + + /* sending back data returned from Management Server */ + ret = copy_to_user((uint8_t *)pext->ResponseAdr, + (uint8_t *)ha->ioctl_mem, pext->ResponseLen); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR copy rsp buffer.\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); +} + +static int +qla2x00_ioctl_ms_queuecommand(scsi_qla_host_t *ha, EXT_IOCTL *pext, + struct scsi_cmnd *pscsi_cmd, fc_port_t *pfcport, fc_lun_t *pfclun, + EXT_ELS_PT_REQ *pels_pt_req) +{ + int ret = 0; + int tmp_rval = 0; + os_lun_t *plq; + os_tgt_t *ptq; + + srb_t *sp = NULL; + + /* alloc sp */ + if ((sp = qla2x00_get_new_sp(ha)) == NULL) { + + pext->Status = EXT_STATUS_NO_MEMORY; + DEBUG9_10(printk("%s: ERROR cannot alloc sp %p.\n", + __func__, sp);) + + return (ret); + } + + DEBUG9(printk("%s(%ld): inst=%ld after alloc sp.\n", + __func__, ha->host_no, ha->instance);) + + /* setup sp for this command */ + ptq = ha->ioctl->ioctl_tq; + plq = ha->ioctl->ioctl_lq; + sp->cmd = pscsi_cmd; + sp->flags = SRB_IOCTL; + sp->lun_queue = plq; + sp->tgt_queue = ptq; + pfclun->fcport = pfcport; + pfclun->lun = 0; + plq->fclun = pfclun; + plq->fclun->fcport->ha = ha; + + /* init scsi_cmd */ + pscsi_cmd->device->host = ha->host; + pscsi_cmd->scsi_done = qla2x00_msiocb_done; + + /* check on loop down (2)- check again just before sending cmd out. */ + if (atomic_read(&ha->loop_state) != LOOP_READY || + test_bit(CFG_ACTIVE, &ha->cfg_flags) || + test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) || + test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) { + + DEBUG9_10(printk("%s(%ld): inst=%ld before issue cmd- loop " + "not ready.\n", + __func__, ha->host_no, ha->instance);) + + pext->Status = EXT_STATUS_BUSY; + + atomic_set(&sp->ref_count, 0); + add_to_free_queue (ha, sp); + + return (ret); + } + + DEBUG9(printk("%s(%ld): inst=%ld going to issue command.\n", + __func__, ha->host_no, ha->instance);) + + tmp_rval = qla2x00_start_ms_cmd(ha, pext, sp, pels_pt_req); + + DEBUG9(printk("%s(%ld): inst=%ld after issue command.\n", + __func__, ha->host_no, ha->instance);) + + if (tmp_rval != 0) { + /* We waited and post function did not get called */ + DEBUG9_10(printk("%s(%ld): inst=%ld command timed out.\n", + __func__, ha->host_no, ha->instance);) + + pext->Status = EXT_STATUS_MS_NO_RESPONSE; + + atomic_set(&sp->ref_count, 0); + add_to_free_queue (ha, sp); + + return (ret); + } + + return (ret); +} + + +/* + * qla2x00_start_ms_cmd + * Allocates an MSIOCB request pkt and sends out the passthru cmd. + * + * Input: + * ha = adapter state pointer. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +static int +qla2x00_start_ms_cmd(scsi_qla_host_t *ha, EXT_IOCTL *pext, srb_t *sp, + EXT_ELS_PT_REQ *pels_pt_req) +{ +#define ELS_REQUEST_RCTL 0x22 +#define ELS_REPLY_RCTL 0x23 + + uint32_t usr_req_len; + uint32_t usr_resp_len; + + ms_iocb_entry_t *pkt; + unsigned long cpu_flags = 0; + + + /* get spin lock for this operation */ + spin_lock_irqsave(&ha->hardware_lock, cpu_flags); + + /* Get MS request packet. */ + pkt = (ms_iocb_entry_t *)qla2x00_ms_req_pkt(ha, sp); + if (pkt == NULL) { + /* release spin lock and return error. */ + spin_unlock_irqrestore(&ha->hardware_lock, cpu_flags); + + pext->Status = EXT_STATUS_NO_MEMORY; + DEBUG9_10(printk("%s(%ld): inst=%ld MSIOCB PT - could not get " + "Request Packet.\n", __func__, ha->host_no, ha->instance);) + return (QLA_MEMORY_ALLOC_FAILED); + } + + pkt->entry_type = MS_IOCB_TYPE; + pkt->entry_count = 1; + + if (pels_pt_req != NULL) { + /* process ELS passthru command */ + usr_req_len = pext->RequestLen - sizeof(EXT_ELS_PT_REQ); + usr_resp_len = pext->ResponseLen - sizeof(EXT_ELS_PT_REQ); + /* ELS passthru enabled */ + pkt->control_flags = cpu_to_le16(BIT_15); + SET_TARGET_ID(ha, pkt->loop_id, pels_pt_req->Lid); + pkt->type = 1; /* ELS frame */ + + if (pext->ResponseLen != 0) { + pkt->r_ctl = ELS_REQUEST_RCTL; + pkt->rx_id = 0; + } else { + pkt->r_ctl = ELS_REPLY_RCTL; + pkt->rx_id = cpu_to_le16(pels_pt_req->Rxid); + } + } else { + usr_req_len = pext->RequestLen; + usr_resp_len = pext->ResponseLen; + SET_TARGET_ID(ha, pkt->loop_id, MANAGEMENT_SERVER); + } + + DEBUG9_10(printk("%s(%ld): inst=%ld using loop_id=%02x req_len=%d, " + "resp_len=%d. Initializing pkt.\n", + __func__, ha->host_no, ha->instance, + pkt->loop_id, usr_req_len, usr_resp_len);) + + pkt->timeout = __constant_cpu_to_le16(QLA_PT_CMD_TOV); + pkt->cmd_dsd_count = __constant_cpu_to_le16(1); + pkt->total_dsd_count = __constant_cpu_to_le16(2); /* no continuation */ + pkt->rsp_bytecount = cpu_to_le32(usr_resp_len); + pkt->req_bytecount = cpu_to_le32(usr_req_len); + + /* + * Loading command payload address. user request is assumed to have + * been copied to ioctl_mem. + */ + pkt->dseg_req_address[0] = cpu_to_le32(LSD(ha->ioctl_mem_phys)); + pkt->dseg_req_address[1] = cpu_to_le32(MSD(ha->ioctl_mem_phys)); + pkt->dseg_req_length = cpu_to_le32(usr_req_len); + + /* loading response payload address */ + pkt->dseg_rsp_address[0] = cpu_to_le32(LSD(ha->ioctl_mem_phys)); + pkt->dseg_rsp_address[1] = cpu_to_le32(MSD(ha->ioctl_mem_phys)); + pkt->dseg_rsp_length = cpu_to_le32(usr_resp_len); + + /* set flag to indicate IOCTL MSIOCB cmd in progress */ + ha->ioctl->MSIOCB_InProgress = 1; + ha->ioctl->ioctl_tov = pkt->timeout + 1; /* 1 second more */ + + /* prepare for receiving completion. */ + qla2x00_ioctl_sem_init(ha); + + /* Issue command to ISP */ + qla2x00_isp_cmd(ha); + + ha->ioctl->cmpl_timer.expires = jiffies + ha->ioctl->ioctl_tov * HZ; + add_timer(&ha->ioctl->cmpl_timer); + + DEBUG9(printk("%s(%ld): inst=%ld releasing hardware_lock.\n", + __func__, ha->host_no, ha->instance);) + spin_unlock_irqrestore(&ha->hardware_lock, cpu_flags); + + DEBUG9(printk("%s(%ld): inst=%ld sleep for completion.\n", + __func__, ha->host_no, ha->instance);) + + down(&ha->ioctl->cmpl_sem); + + del_timer(&ha->ioctl->cmpl_timer); + + if (ha->ioctl->MSIOCB_InProgress == 1) { + DEBUG9_10(printk("%s(%ld): inst=%ld timed out. exiting.\n", + __func__, ha->host_no, ha->instance);) + return QLA_FUNCTION_FAILED; + } + + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) + + return QLA_SUCCESS; +} + +/* + * qla2x00_wwpn_to_scsiaddr + * Handles the EXT_CC_WWPN_TO_SCSIADDR command. + * + * Input: + * ha = adapter state pointer. + * pext = EXT_IOCTL structure pointer. + * mode = not used. + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_wwpn_to_scsiaddr(scsi_qla_host_t *ha, EXT_IOCTL *pext, int mode) +{ + int ret = 0; + fc_port_t *tgt_fcport; + os_tgt_t *tq; + uint8_t tmp_wwpn[EXT_DEF_WWN_NAME_SIZE]; + uint32_t b, tgt, l; + EXT_SCSI_ADDR tmp_addr; + + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + if (pext->RequestLen != EXT_DEF_WWN_NAME_SIZE || + pext->ResponseLen < sizeof(EXT_SCSI_ADDR)) { + /* error */ + DEBUG9_10(printk("%s(%ld): inst=%ld invalid WWN buffer size %d " + "received.\n", + __func__, ha->host_no, ha->instance, pext->ResponseLen);) + pext->Status = EXT_STATUS_INVALID_PARAM; + + return (ret); + } + + ret = verify_area(VERIFY_READ, (void *)pext->RequestAdr, + pext->RequestLen); + if (ret) { + DEBUG9_10(printk( + "%s(%ld): inst=%ld ERROR VERIFY_READ req buf\n", + __func__, ha->host_no, ha->instance);) + pext->Status = EXT_STATUS_COPY_ERR; + return (ret); + } + + ret = copy_from_user(tmp_wwpn, pext->RequestAdr, pext->RequestLen); + if (ret) { + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR copy_from_user " + "failed(%d) on request buf.\n", + __func__, ha->host_no, ha->instance, ret);) + pext->Status = EXT_STATUS_COPY_ERR; + return (ret); + } + + tq = NULL; + for (tgt = 0; tgt < MAX_TARGETS; tgt++) { + if (ha->otgt[tgt] == NULL) { + continue; + } + + tq = ha->otgt[tgt]; + if (tq->fcport == NULL) { + break; + } + + tgt_fcport = tq->fcport; + if (memcmp(tmp_wwpn, tgt_fcport->port_name, + EXT_DEF_WWN_NAME_SIZE) == 0) { + break; + } + } + + if (tq == NULL || tgt >= MAX_TARGETS) { + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + DEBUG9_10(printk("%s(%ld): inst=%ld target dev not found. " + "tq=%p, tgt=%x.\n", __func__, ha->host_no, ha->instance, + tq, tgt);) + return (ret); + } + + if (tq->fcport == NULL) { /* dg 08/14/01 */ + pext->Status = EXT_STATUS_BUSY; + DEBUG9_10(printk("%s(%ld): inst=%ld target port not found. " + "tq=%p, tgt=%x.\n", + __func__, ha->host_no, ha->instance, tq, tgt);) + return (ret); + } + + /* Currently we only have bus 0 and no translation on LUN */ + b = 0; + l = 0; + + /* + * Return SCSI address. Currently no translation is done for + * LUN. + */ + tmp_addr.Bus = b; + tmp_addr.Target = tgt; + tmp_addr.Lun = l; + if (pext->ResponseLen > sizeof(EXT_SCSI_ADDR)) + pext->ResponseLen = sizeof(EXT_SCSI_ADDR); + + ret = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr, + pext->ResponseLen); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR VERIFY wrt rsp buf\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + + ret = copy_to_user((uint8_t *)pext->ResponseAdr, &tmp_addr, + pext->ResponseLen); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR copy rsp buffer.\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + + DEBUG9(printk(KERN_INFO + "%s(%ld): Found t%d l%d for %02x%02x%02x%02x%02x%02x%02x%02x.\n", + __func__, ha->host_no, + tmp_addr.Target, tmp_addr.Lun, + tmp_wwpn[0], tmp_wwpn[1], tmp_wwpn[2], tmp_wwpn[3], + tmp_wwpn[4], tmp_wwpn[5], tmp_wwpn[6], tmp_wwpn[7]);) + + pext->Status = EXT_STATUS_OK; + + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); +} + +/* + * qla2x00_scsi_passthru + * Handles all subcommands of the EXT_CC_SEND_SCSI_PASSTHRU command. + * + * Input: + * ha = adapter state pointer. + * pext = EXT_IOCTL structure pointer. + * mode = not used. + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_scsi_passthru(scsi_qla_host_t *ha, EXT_IOCTL *pext, int mode) +{ + int ret = 0; + struct scsi_cmnd *pscsi_cmd = NULL; + struct scsi_device *pscsi_device = NULL; + + DEBUG9(printk("%s(%ld): entered.\n", + __func__, ha->host_no);) + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&pscsi_cmd, + sizeof(struct scsi_cmnd))) { + /* not enough memory */ + pext->Status = EXT_STATUS_NO_MEMORY; + DEBUG9_10(printk("%s(%ld): inst=%ld scrap not big enough. " + "size requested=%ld.\n", + __func__, ha->host_no, ha->instance, + (ulong)sizeof(struct scsi_cmnd));) + return (ret); + } + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&pscsi_device, + sizeof(struct scsi_device))) { + /* not enough memory */ + pext->Status = EXT_STATUS_NO_MEMORY; + DEBUG9_10(printk("%s(%ld): inst=%ld scrap not big enough. " + "size requested=%ld.\n", + __func__, ha->host_no, ha->instance, + (ulong)sizeof(struct scsi_device));) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + switch(pext->SubCode) { + case EXT_SC_SEND_SCSI_PASSTHRU: + DEBUG9(printk("%s(%ld): got SCSI passthru cmd.\n", + __func__, ha->host_no);) + ret = qla2x00_sc_scsi_passthru(ha, pext, pscsi_cmd, + pscsi_device, mode); + break; + case EXT_SC_SEND_FC_SCSI_PASSTHRU: + DEBUG9(printk("%s(%ld): got FC SCSI passthru cmd.\n", + __func__, ha->host_no);) + ret = qla2x00_sc_fc_scsi_passthru(ha, pext, pscsi_cmd, + pscsi_device, mode); + break; + case EXT_SC_SCSI3_PASSTHRU: + DEBUG9(printk("%s(%ld): got SCSI3 passthru cmd.\n", + __func__, ha->host_no);) + ret = qla2x00_sc_scsi3_passthru(ha, pext, pscsi_cmd, + pscsi_device, mode); + break; + default: + DEBUG9_10(printk("%s: got invalid cmd.\n", __func__)); + break; + } + + qla2x00_free_ioctl_scrap_mem(ha); + DEBUG9(printk("%s(%ld): exiting.\n", + __func__, ha->host_no);) + + return (ret); +} + +static int +qla2x00_ioctl_scsi_queuecommand(scsi_qla_host_t *ha, EXT_IOCTL *pext, + struct scsi_cmnd *pscsi_cmd, struct scsi_device *pscsi_dev, + fc_port_t *pfcport, fc_lun_t *pfclun) +{ + int ret = 0; + int ret2 = 0; + uint8_t *usr_temp, *kernel_tmp; + uint32_t lun = 0, tgt = 0; +#if defined(QL_DEBUG_LEVEL_9) + uint32_t b, t, l; +#endif + os_lun_t *lq = NULL; + os_tgt_t *tq = NULL; + srb_t *sp = NULL; + + + DEBUG9(printk("%s(%ld): entered.\n", + __func__, ha->host_no);) + + if ((sp = qla2x00_get_new_sp(ha)) == NULL) { + + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR cannot alloc sp.\n", + __func__, ha->host_no, ha->instance);) + + pext->Status = EXT_STATUS_NO_MEMORY; + return (ret); + } + + switch(pext->SubCode) { + case EXT_SC_SEND_SCSI_PASSTHRU: + + tgt = pscsi_cmd->device->id; + lun = pscsi_cmd->device->lun; + + tq = (os_tgt_t *)TGT_Q(ha, tgt); + lq = (os_lun_t *)LUN_Q(ha, tgt, lun); + + break; + case EXT_SC_SEND_FC_SCSI_PASSTHRU: + if (pfcport == NULL || pfclun == NULL) { + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + DEBUG9_10(printk("%s(%ld): inst=%ld received invalid " + "pointers. fcport=%p fclun=%p.\n", + __func__, ha->host_no, ha->instance, pfcport, pfclun);) + atomic_set(&sp->ref_count, 0); + add_to_free_queue (ha, sp); + return (ret); + } + + if (pscsi_cmd->cmd_len != 6 && pscsi_cmd->cmd_len != 0x0A && + pscsi_cmd->cmd_len != 0x0C && pscsi_cmd->cmd_len != 0x10) { + DEBUG9_10(printk(KERN_WARNING + "%s(%ld): invalid Cdb Length 0x%x received.\n", + __func__, ha->host_no, + pscsi_cmd->cmd_len);) + pext->Status = EXT_STATUS_INVALID_PARAM; + atomic_set(&sp->ref_count, 0); + add_to_free_queue (ha, sp); + return (ret); + } + tq = ha->ioctl->ioctl_tq; + lq = ha->ioctl->ioctl_lq; + + break; + case EXT_SC_SCSI3_PASSTHRU: + if (pfcport == NULL || pfclun == NULL) { + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + DEBUG9_10(printk("%s(%ld): inst=%ld received invalid " + "pointers. fcport=%p fclun=%p.\n", + __func__, + ha->host_no, ha->instance, pfcport, pfclun);) + atomic_set(&sp->ref_count, 0); + add_to_free_queue (ha, sp); + return (ret); + } + + tq = ha->ioctl->ioctl_tq; + lq = ha->ioctl->ioctl_lq; + + break; + default: + break; + } + + sp->ha = ha; + sp->cmd = pscsi_cmd; + sp->flags = SRB_IOCTL; + + /* set local fc_scsi_cmd's sp pointer to sp */ + CMD_SP(pscsi_cmd) = (void *) sp; + + if (pscsi_cmd->sc_data_direction == DMA_TO_DEVICE) { + /* sending user data from pext->ResponseAdr to device */ + ret = verify_area(VERIFY_READ, (void *)pext->ResponseAdr, + pext->ResponseLen); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR verify read " + "ResponseAdr.\n", + __func__, ha->host_no, ha->instance);) + atomic_set(&sp->ref_count, 0); + add_to_free_queue (ha, sp); + + return (ret); + } + + usr_temp = (uint8_t *)pext->ResponseAdr; + kernel_tmp = (uint8_t *)ha->ioctl_mem; + ret = copy_from_user(kernel_tmp, usr_temp, pext->ResponseLen); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR copy " + "failed(%d) on rsp buf.\n", + __func__, ha->host_no, ha->instance, ret);) + atomic_set(&sp->ref_count, 0); + add_to_free_queue (ha, sp); + + return (ret); + } + } + + pscsi_cmd->device->host = ha->host; + + /* mark this as a special delivery and collection command */ + pscsi_cmd->scsi_done = qla2x00_scsi_pt_done; + + pscsi_cmd->device = pscsi_dev; + pscsi_cmd->device->tagged_supported = 0; + pscsi_cmd->use_sg = 0; /* no ScatterGather */ + pscsi_cmd->request_bufflen = pext->ResponseLen; + pscsi_cmd->request_buffer = ha->ioctl_mem; + pscsi_cmd->timeout_per_command = QLA_PT_CMD_TOV * HZ; + + if (tq && lq) { + if (pext->SubCode == EXT_SC_SEND_SCSI_PASSTHRU) { + pfcport = lq->fclun->fcport; + pfclun = lq->fclun; + + if (pfcport == NULL || pfclun == NULL) { + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + DEBUG9_10(printk("%s(%ld): inst=%ld scsi pt " + "rcvd invalid ptrs. fcport=%p fclun=%p.\n", + __func__, ha->host_no, ha->instance, + pfcport, pfclun);) + atomic_set(&sp->ref_count, 0); + add_to_free_queue (ha, sp); + return (ret); + } + + } else { + if (pext->SubCode == EXT_SC_SCSI3_PASSTHRU) + /* The LUN value is of FCP LUN format */ + tq->olun[pfclun->lun & 0xff] = lq; + else + tq->olun[pfclun->lun] = lq; + + tq->ha = ha; + lq->fclun = pfclun; + } + + sp->lun_queue = lq; + sp->tgt_queue = tq; + sp->fclun = pfclun; + } else { + /* cannot send command without a queue. force error. */ + pfcport = NULL; + DEBUG9_10(printk("%s(%ld): error dev q not found. tq=%p lq=%p.\n", + __func__, ha->host_no, tq, lq);) + } + + DEBUG9({ + b = pscsi_cmd->device->channel; + t = pscsi_cmd->device->id; + l = pscsi_cmd->device->lun; + }) + DEBUG9(printk("%s(%ld): ha instance=%ld tq=%p lq=%p " + "pfclun=%p pfcport=%p.\n", + __func__, ha->host_no, ha->instance, tq, lq, pfclun, + pfcport);) + DEBUG9(printk("\tCDB=%02x %02x %02x %02x; b=%x t=%x l=%x.\n", + pscsi_cmd->cmnd[0], pscsi_cmd->cmnd[1], pscsi_cmd->cmnd[2], + pscsi_cmd->cmnd[3], b, t, l);) + + /* + * Check the status of the port + */ + if (pext->SubCode == EXT_SC_SEND_SCSI_PASSTHRU) { + if (qla2x00_check_tgt_status(ha, pscsi_cmd)) { + DEBUG9_10(printk("%s(%ld): inst=%ld check_tgt_status " + "failed.\n", + __func__, ha->host_no, ha->instance);) + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + atomic_set(&sp->ref_count, 0); + add_to_free_queue (ha, sp); + return (ret); + } + } else { + ret2 = qla2x00_check_port_status(ha, pfcport); + if (ret2 != QLA_SUCCESS) { + DEBUG9_10(printk("%s(%ld): inst=%ld check_port_status " + "failed.\n", + __func__, ha->host_no, ha->instance);) + if (ret2 == QLA_BUSY) + pext->Status = EXT_STATUS_BUSY; + else + pext->Status = EXT_STATUS_ERR; + atomic_set(&sp->ref_count, 0); + add_to_free_queue (ha, sp); + return (ret); + } + } + + /* set flag to indicate IOCTL SCSI PassThru in progress */ + ha->ioctl->SCSIPT_InProgress = 1; + ha->ioctl->ioctl_tov = (int)QLA_PT_CMD_DRV_TOV; + + /* prepare for receiving completion. */ + qla2x00_ioctl_sem_init(ha); + CMD_COMPL_STATUS(pscsi_cmd) = (int) IOCTL_INVALID_STATUS; + + /* send command to adapter */ + DEBUG9(printk("%s(%ld): inst=%ld sending command.\n", + __func__, ha->host_no, ha->instance);) + + add_to_pending_queue(ha, sp); + + qla2x00_next(ha); + + DEBUG9(printk("%s(%ld): exiting.\n", + __func__, ha->host_no);) + return (ret); +} + +/* + * qla2x00_sc_scsi_passthru + * Handles EXT_SC_SEND_SCSI_PASSTHRU subcommand. + * + * Input: + * ha = adapter state pointer. + * pext = EXT_IOCTL structure pointer. + * mode = not used. + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_sc_scsi_passthru(scsi_qla_host_t *ha, EXT_IOCTL *pext, + struct scsi_cmnd *pscsi_cmd, struct scsi_device *pscsi_device, int mode) +{ + int ret = 0; + uint8_t *usr_temp, *kernel_tmp; + uint32_t i; + + uint32_t transfer_len; + + EXT_SCSI_PASSTHRU *pscsi_pass; + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + ret = verify_area(VERIFY_READ, (void *)pext->RequestAdr, + sizeof(EXT_SCSI_PASSTHRU)); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR verify READ " + "req buf.\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + + if (pext->ResponseLen > ha->ioctl_mem_size) { + if (qla2x00_get_new_ioctl_dma_mem(ha, pext->ResponseLen) != + QLA_SUCCESS) { + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR cannot alloc " + "requested DMA buffer size %x.\n", + __func__, ha->host_no, ha->instance, + pext->ResponseLen);) + pext->Status = EXT_STATUS_NO_MEMORY; + return (ret); + } + } + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&pscsi_pass, + sizeof(EXT_SCSI_PASSTHRU))) { + /* not enough memory */ + pext->Status = EXT_STATUS_NO_MEMORY; + DEBUG9_10(printk("%s(%ld): inst=%ld scrap not big enough. " + "size requested=%ld.\n", + __func__, ha->host_no, ha->instance, + (ulong)sizeof(EXT_SCSI_PASSTHRU));) + return (ret); + } + + /* clear ioctl_mem to be used */ + memset(ha->ioctl_mem, 0, ha->ioctl_mem_size); + + /* Copy request buffer */ + usr_temp = (uint8_t *)pext->RequestAdr; + kernel_tmp = (uint8_t *)pscsi_pass; + ret = copy_from_user(kernel_tmp, usr_temp, sizeof(EXT_SCSI_PASSTHRU)); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk( + "%s(%ld): inst=%ld ERROR copy req buf ret=%d\n", + __func__, ha->host_no, ha->instance, ret);) + return (ret); + } + + /* set target coordinates */ + pscsi_cmd->device->id = pscsi_pass->TargetAddr.Target; + pscsi_cmd->device->lun = pscsi_pass->TargetAddr.Lun; + + /* Verify target exists */ + if (TGT_Q(ha, pscsi_cmd->device->id) == NULL) { + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR tgt %d not found.\n", + __func__, + ha->host_no, ha->instance, pscsi_cmd->device->id)); + return (ret); + } + + /* Copy over cdb */ + + if (pscsi_pass->CdbLength == 6) { + pscsi_cmd->cmd_len = 6; + + } else if (pscsi_pass->CdbLength == 10) { + pscsi_cmd->cmd_len = 0x0A; + + } else if (pscsi_pass->CdbLength == 12) { + pscsi_cmd->cmd_len = 0x0C; + + } else { + printk(KERN_WARNING + "%s: Unsupported Cdb Length=%x.\n", + __func__, pscsi_pass->CdbLength); + + pext->Status = EXT_STATUS_INVALID_PARAM; + + return (ret); + } + + memcpy(pscsi_cmd->data_cmnd, pscsi_pass->Cdb, pscsi_cmd->cmd_len); + memcpy(pscsi_cmd->cmnd, pscsi_pass->Cdb, pscsi_cmd->cmd_len); + + DEBUG9(printk("%s Dump of cdb buffer:\n", __func__);) + DEBUG9(qla2x00_dump_buffer((uint8_t *)&pscsi_cmd->data_cmnd[0], + pscsi_cmd->cmd_len);) + + if (pscsi_pass->Direction == EXT_DEF_SCSI_PASSTHRU_DATA_OUT) { + pscsi_cmd->sc_data_direction = DMA_TO_DEVICE; + } else { + pscsi_cmd->sc_data_direction = DMA_FROM_DEVICE; + } + + /* send command to adapter */ + DEBUG9(printk("%s(%ld): inst=%ld sending command.\n", + __func__, ha->host_no, ha->instance);) + + if ((ret = qla2x00_ioctl_scsi_queuecommand(ha, pext, pscsi_cmd, + pscsi_device, NULL, NULL))) { + return (ret); + } + + ha->ioctl->cmpl_timer.expires = jiffies + ha->ioctl->ioctl_tov * HZ; + add_timer(&ha->ioctl->cmpl_timer); + + DEBUG9(printk("%s(%ld): inst=%ld waiting for completion.\n", + __func__, ha->host_no, ha->instance);) + + down(&ha->ioctl->cmpl_sem); + + del_timer(&ha->ioctl->cmpl_timer); + + DEBUG9(printk("%s(%ld): inst=%ld completed.\n", + __func__, ha->host_no, ha->instance);) + + if (ha->ioctl->SCSIPT_InProgress == 1) { + + printk(KERN_WARNING + "qla2x00: scsi%ld ERROR passthru command timeout.\n", + ha->host_no); + + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + return (ret); + } + + if (CMD_COMPL_STATUS(pscsi_cmd) == (int)IOCTL_INVALID_STATUS) { + + DEBUG9(printk("%s(%ld): inst=%ld ERROR - cmd not completed.\n", + __func__, ha->host_no, ha->instance);) + + pext->Status = EXT_STATUS_ERR; + return (ret); + } + + switch (CMD_COMPL_STATUS(pscsi_cmd)) { + case CS_INCOMPLETE: + case CS_ABORTED: + case CS_PORT_UNAVAILABLE: + case CS_PORT_LOGGED_OUT: + case CS_PORT_CONFIG_CHG: + case CS_PORT_BUSY: + DEBUG9_10(printk("%s(%ld): inst=%ld cs err = %x.\n", + __func__, ha->host_no, ha->instance, + CMD_COMPL_STATUS(pscsi_cmd));) + pext->Status = EXT_STATUS_BUSY; + + return (ret); + } + + if ((CMD_SCSI_STATUS(pscsi_cmd) & 0xff) != 0) { + + /* have done the post function */ + pext->Status = EXT_STATUS_SCSI_STATUS; + pext->DetailStatus = CMD_SCSI_STATUS(pscsi_cmd) & 0xff; + + DEBUG9_10(printk(KERN_INFO "%s(%ld): inst=%ld scsi err. " + "host status =0x%x, scsi status = 0x%x.\n", + __func__, ha->host_no, ha->instance, + CMD_COMPL_STATUS(pscsi_cmd), CMD_SCSI_STATUS(pscsi_cmd));) + } else { + if (CMD_COMPL_STATUS(pscsi_cmd) == CS_DATA_OVERRUN) { + pext->Status = EXT_STATUS_DATA_OVERRUN; + + DEBUG9_10(printk(KERN_INFO + "%s(%ld): inst=%ld return overrun.\n", + __func__, ha->host_no, ha->instance);) + + } else if (CMD_COMPL_STATUS(pscsi_cmd) == CS_DATA_UNDERRUN && + (CMD_SCSI_STATUS(pscsi_cmd) & SS_RESIDUAL_UNDER)) { + pext->Status = EXT_STATUS_DATA_UNDERRUN; + + DEBUG9_10(printk(KERN_INFO + "%s(%ld): inst=%ld return underrun.\n", + __func__, ha->host_no, ha->instance);) + + } else if (CMD_COMPL_STATUS(pscsi_cmd) != 0 || + CMD_SCSI_STATUS(pscsi_cmd) != 0) { + pext->Status = EXT_STATUS_ERR; + + DEBUG9_10(printk(KERN_INFO + "%s(%ld): inst=%ld, cs err=%x, scsi err=%x.\n", + __func__, ha->host_no, ha->instance, + CMD_COMPL_STATUS(pscsi_cmd), + CMD_SCSI_STATUS(pscsi_cmd));) + + return (ret); + } + } + + /* copy up structure to make sense data available to user */ + pscsi_pass->SenseLength = CMD_ACTUAL_SNSLEN(pscsi_cmd); + if (CMD_ACTUAL_SNSLEN(pscsi_cmd)) { + for (i = 0; i < CMD_ACTUAL_SNSLEN(pscsi_cmd); i++) + pscsi_pass->SenseData[i] = pscsi_cmd->sense_buffer[i]; + + DEBUG10(printk("%s Dump of sense buffer:\n", __func__);) + DEBUG10(qla2x00_dump_buffer( + (uint8_t *)&pscsi_pass->SenseData[0], + CMD_ACTUAL_SNSLEN(pscsi_cmd));) + + ret = verify_area(VERIFY_WRITE, (void *)pext->RequestAdr, + sizeof(EXT_SCSI_PASSTHRU)); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR verify WRITE " + "req buf.\n", __func__, ha->host_no, ha->instance);) + return (ret); + } + + usr_temp = (uint8_t *)pext->RequestAdr; + kernel_tmp = (uint8_t *)pscsi_pass; + ret = copy_to_user(usr_temp, kernel_tmp, + sizeof(EXT_SCSI_PASSTHRU)); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR copy sense " + "buffer.\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + } + + if (pscsi_pass->Direction == EXT_DEF_SCSI_PASSTHRU_DATA_IN) { + DEBUG9(printk("%s(%ld): inst=%ld copying data.\n", + __func__, ha->host_no, ha->instance);) + + /* getting device data and putting in pext->ResponseAdr */ + ret = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr , + pext->ResponseLen); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR verify write " + "ResponseAdr.\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + + /* now copy up the READ data to user */ + if ((CMD_COMPL_STATUS(pscsi_cmd) == CS_DATA_UNDERRUN) && + (CMD_RESID_LEN(pscsi_cmd))) { + + transfer_len = pext->ResponseLen - + CMD_RESID_LEN(pscsi_cmd); + + pext->ResponseLen = transfer_len; + } else { + transfer_len = pext->ResponseLen; + } + + DEBUG9_10(printk(KERN_INFO + "%s(%ld): final transferlen=%d.\n", + __func__, ha->host_no, transfer_len);) + + usr_temp = (uint8_t *)pext->ResponseAdr; + kernel_tmp = (uint8_t *)ha->ioctl_mem; + ret = copy_to_user(usr_temp, kernel_tmp, transfer_len); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk( + "%s(%ld): inst=%ld ERROR copy rsp buf\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + } + + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); +} + +/* + * qla2x00_sc_fc_scsi_passthru + * Handles EXT_SC_SEND_FC_SCSI_PASSTHRU subcommand. + * + * Input: + * ha = adapter state pointer. + * pext = EXT_IOCTL structure pointer. + * mode = not used. + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_sc_fc_scsi_passthru(scsi_qla_host_t *ha, EXT_IOCTL *pext, + struct scsi_cmnd *pfc_scsi_cmd, struct scsi_device *pfc_scsi_device, + int mode) +{ + int ret = 0; + int port_found, lun_found; + fc_lun_t temp_fclun; + struct list_head *fcpl; + fc_port_t *fcport; + struct list_head *fcll; + fc_lun_t *fclun; + uint8_t *usr_temp, *kernel_tmp; + uint32_t i; + + uint32_t transfer_len; + + EXT_FC_SCSI_PASSTHRU *pfc_scsi_pass; + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + DEBUG9_10( + if (!pfc_scsi_cmd || !pfc_scsi_device) { + printk("%s(%ld): invalid pointer received. " + "pfc_scsi_cmd=%p, pfc_scsi_device=%p.\n", + __func__, ha->host_no, pfc_scsi_cmd, + pfc_scsi_device); + return (ret); + } + ) + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&pfc_scsi_pass, + sizeof(EXT_FC_SCSI_PASSTHRU))) { + /* not enough memory */ + pext->Status = EXT_STATUS_NO_MEMORY; + DEBUG9_10(printk("%s(%ld): inst=%ld scrap not big enough. " + "size requested=%ld.\n", + __func__, ha->host_no, ha->instance, + (ulong)sizeof(EXT_FC_SCSI_PASSTHRU));) + return (ret); + } + + /* clear ioctl_mem to be used */ + memset(ha->ioctl_mem, 0, ha->ioctl_mem_size); + + ret = verify_area(VERIFY_READ, (void *)pext->RequestAdr, + sizeof(EXT_FC_SCSI_PASSTHRU)); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk( + "%s(%ld): inst=%ld ERROR verify READ req buf.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); + } + + if (pext->ResponseLen > ha->ioctl_mem_size) { + if (qla2x00_get_new_ioctl_dma_mem(ha, pext->ResponseLen) != + QLA_SUCCESS) { + + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR cannot alloc " + "requested DMA buffer size %x.\n", + __func__, ha->host_no, ha->instance, + pext->ResponseLen);) + + pext->Status = EXT_STATUS_NO_MEMORY; + return (ret); + } + } + + /* Copy request buffer */ + usr_temp = (uint8_t *)pext->RequestAdr; + kernel_tmp = (uint8_t *)pfc_scsi_pass; + ret = copy_from_user(kernel_tmp, usr_temp, + sizeof(EXT_FC_SCSI_PASSTHRU)); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk( + "%s(%ld): inst=%ld ERROR copy req buf ret=%d\n", + __func__, ha->host_no, ha->instance, ret);) + + return (ret); + } + + if (pfc_scsi_pass->FCScsiAddr.DestType != EXT_DEF_DESTTYPE_WWPN) { + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR -wrong Dest type. \n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + + fcport = NULL; + fclun = NULL; + port_found = lun_found = 0; + list_for_each(fcpl, &ha->fcports) { + fcport = list_entry(fcpl, fc_port_t, list); + + if (memcmp(fcport->port_name, + pfc_scsi_pass->FCScsiAddr.DestAddr.WWPN, 8) != 0) { + continue; + + } + port_found++; + + list_for_each(fcll, &fcport->fcluns) { + fclun = list_entry(fcll, fc_lun_t, list); + + if (fclun->lun == pfc_scsi_pass->FCScsiAddr.Lun) { + /* Found the right LUN */ + lun_found++; + break; + } + } + break; + } + + if (!port_found) { + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + DEBUG9_10(printk("%s(%ld): inst=%ld FC AddrFormat - DID NOT " + "FIND Port matching WWPN.\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + + /* v5.21b9 - use a temporary fclun */ + if (!lun_found) { + fclun = &temp_fclun; + fclun->fcport = fcport; + fclun->lun = pfc_scsi_pass->FCScsiAddr.Lun; + } + + /* set target coordinates */ + pfc_scsi_cmd->device->id = 0xff; /* not used. just put something there. */ + pfc_scsi_cmd->device->lun = pfc_scsi_pass->FCScsiAddr.Lun; + + DEBUG9(printk("%s(%ld): inst=%ld cmd for loopid=%04x L=%04x " + "WWPN=%02x%02x%02x%02x%02x%02x%02x%02x.\n", + __func__, ha->host_no, ha->instance, fclun->fcport->loop_id, + pfc_scsi_cmd->device->lun, + pfc_scsi_pass->FCScsiAddr.DestAddr.WWPN[0], + pfc_scsi_pass->FCScsiAddr.DestAddr.WWPN[1], + pfc_scsi_pass->FCScsiAddr.DestAddr.WWPN[2], + pfc_scsi_pass->FCScsiAddr.DestAddr.WWPN[3], + pfc_scsi_pass->FCScsiAddr.DestAddr.WWPN[4], + pfc_scsi_pass->FCScsiAddr.DestAddr.WWPN[5], + pfc_scsi_pass->FCScsiAddr.DestAddr.WWPN[6], + pfc_scsi_pass->FCScsiAddr.DestAddr.WWPN[7]);) + + if (pfc_scsi_pass->CdbLength == 6) { + pfc_scsi_cmd->cmd_len = 6; + + } else if (pfc_scsi_pass->CdbLength == 0x0A) { + pfc_scsi_cmd->cmd_len = 0x0A; + + } else if (pfc_scsi_pass->CdbLength == 0x0C) { + pfc_scsi_cmd->cmd_len = 0x0C; + + } else if (pfc_scsi_pass->CdbLength == 0x10) { + pfc_scsi_cmd->cmd_len = 0x10; + } else { + printk(KERN_WARNING + "qla2x00_ioctl: FC_SCSI_PASSTHRU Unknown Cdb Length=%x.\n", + pfc_scsi_pass->CdbLength); + pext->Status = EXT_STATUS_INVALID_PARAM; + + return (ret); + } + + memcpy(pfc_scsi_cmd->data_cmnd, pfc_scsi_pass->Cdb, + pfc_scsi_cmd->cmd_len); + memcpy(pfc_scsi_cmd->cmnd, pfc_scsi_pass->Cdb, + pfc_scsi_cmd->cmd_len); + + DEBUG9(printk("%s Dump of cdb buffer:\n", __func__);) + DEBUG9(qla2x00_dump_buffer((uint8_t *)&pfc_scsi_cmd->data_cmnd[0], 16);) + + if (pfc_scsi_pass->Direction == EXT_DEF_SCSI_PASSTHRU_DATA_OUT) { + pfc_scsi_cmd->sc_data_direction = DMA_TO_DEVICE; + } else { + pfc_scsi_cmd->sc_data_direction = DMA_FROM_DEVICE; + } + + /* send command to adapter */ + DEBUG9(printk("%s(%ld): inst=%ld queuing command.\n", + __func__, ha->host_no, ha->instance);) + + if ((ret = qla2x00_ioctl_scsi_queuecommand(ha, pext, pfc_scsi_cmd, + pfc_scsi_device, fcport, fclun))) { + return (ret); + } + + /* Wait for comletion */ + ha->ioctl->cmpl_timer.expires = jiffies + ha->ioctl->ioctl_tov * HZ; + add_timer(&ha->ioctl->cmpl_timer); + + down(&ha->ioctl->cmpl_sem); + + del_timer(&ha->ioctl->cmpl_timer); + + if (ha->ioctl->SCSIPT_InProgress == 1) { + + printk(KERN_WARNING + "qla2x00: scsi%ld ERROR passthru command timeout.\n", + ha->host_no); + + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + return (ret); + } + + if (CMD_COMPL_STATUS(pfc_scsi_cmd) == (int)IOCTL_INVALID_STATUS) { + + DEBUG9(printk("%s(%ld): inst=%ld ERROR. cmd not completed.\n", + __func__, ha->host_no, ha->instance);) + + pext->Status = EXT_STATUS_ERR; + return (ret); + } + + switch (CMD_COMPL_STATUS(pfc_scsi_cmd)) { + case CS_INCOMPLETE: + case CS_ABORTED: + case CS_PORT_UNAVAILABLE: + case CS_PORT_LOGGED_OUT: + case CS_PORT_CONFIG_CHG: + case CS_PORT_BUSY: + DEBUG9_10(printk("%s(%ld): inst=%ld cs err = %x.\n", + __func__, ha->host_no, ha->instance, + CMD_COMPL_STATUS(pfc_scsi_cmd));) + pext->Status = EXT_STATUS_BUSY; + + return (ret); + } + + if ((CMD_COMPL_STATUS(pfc_scsi_cmd) == CS_DATA_UNDERRUN) || + (CMD_SCSI_STATUS(pfc_scsi_cmd) != 0)) { + + /* have done the post function */ + pext->Status = EXT_STATUS_SCSI_STATUS; + /* The SDMAPI is only concerned with the low-order byte */ + pext->DetailStatus = CMD_SCSI_STATUS(pfc_scsi_cmd) & 0xff; + + DEBUG9_10(printk("%s(%ld): inst=%ld data underrun or scsi err. " + "host status =0x%x, scsi status = 0x%x.\n", + __func__, ha->host_no, ha->instance, + CMD_COMPL_STATUS(pfc_scsi_cmd), + CMD_SCSI_STATUS(pfc_scsi_cmd));) + + } else if (CMD_COMPL_STATUS(pfc_scsi_cmd) != 0) { + DEBUG9_10(printk("%s(%ld): inst=%ld cs err=%x.\n", + __func__, ha->host_no, ha->instance, + CMD_COMPL_STATUS(pfc_scsi_cmd));) + pext->Status = EXT_STATUS_ERR; + + return (ret); + } + + /* Process completed command */ + DEBUG9(printk("%s(%ld): inst=%ld done. host status=0x%x, " + "scsi status=0x%x.\n", + __func__, ha->host_no, ha->instance, CMD_COMPL_STATUS(pfc_scsi_cmd), + CMD_SCSI_STATUS(pfc_scsi_cmd));) + + /* copy up structure to make sense data available to user */ + pfc_scsi_pass->SenseLength = CMD_ACTUAL_SNSLEN(pfc_scsi_cmd); + if (CMD_ACTUAL_SNSLEN(pfc_scsi_cmd)) { + DEBUG9_10(printk("%s(%ld): inst=%ld sense[0]=%x sense[2]=%x.\n", + __func__, ha->host_no, ha->instance, + pfc_scsi_cmd->sense_buffer[0], + pfc_scsi_cmd->sense_buffer[2]);) + + for (i = 0; i < CMD_ACTUAL_SNSLEN(pfc_scsi_cmd); i++) { + pfc_scsi_pass->SenseData[i] = + pfc_scsi_cmd->sense_buffer[i]; + } + + ret = verify_area(VERIFY_WRITE, (void *)pext->RequestAdr, + sizeof(EXT_FC_SCSI_PASSTHRU)); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR verify WRITE " + "RequestAdr.\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + + usr_temp = (uint8_t *)pext->RequestAdr; + kernel_tmp = (uint8_t *)pfc_scsi_pass; + ret = copy_to_user(usr_temp, kernel_tmp, + sizeof(EXT_FC_SCSI_PASSTHRU)); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR copy sense " + "buffer.\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + } + + if (pfc_scsi_pass->Direction == EXT_DEF_SCSI_PASSTHRU_DATA_IN) { + + DEBUG9(printk("%s(%ld): inst=%ld copying data.\n", + __func__, ha->host_no, ha->instance);) + + /* getting device data and putting in pext->ResponseAdr */ + ret = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr, + pext->ResponseLen); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR verify write " + "ResponseAdr.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); + } + + /* now copy up the READ data to user */ + if ((CMD_COMPL_STATUS(pfc_scsi_cmd) == CS_DATA_UNDERRUN) && + (CMD_RESID_LEN(pfc_scsi_cmd))) { + + transfer_len = pext->ResponseLen - + CMD_RESID_LEN(pfc_scsi_cmd); + + pext->ResponseLen = transfer_len; + } else { + transfer_len = pext->ResponseLen; + } + + usr_temp = (uint8_t *)pext->ResponseAdr; + kernel_tmp = (uint8_t *)ha->ioctl_mem; + ret = copy_to_user(usr_temp, kernel_tmp, transfer_len); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk( + "%s(%ld): inst=%ld ERROR copy rsp buf\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + } + + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); +} + +/* + * qla2x00_sc_scsi3_passthru + * Handles EXT_SC_SCSI3_PASSTHRU subcommand. + * + * Input: + * ha = adapter state pointer. + * pext = EXT_IOCTL structure pointer. + * mode = not used. + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_sc_scsi3_passthru(scsi_qla_host_t *ha, EXT_IOCTL *pext, + struct scsi_cmnd *pscsi3_cmd, struct scsi_device *pscsi3_device, int mode) +{ +#define MAX_SCSI3_CDB_LEN 16 + + int ret = 0; + int found; + fc_lun_t temp_fclun; + fc_lun_t *fclun = NULL; + struct list_head *fcpl; + fc_port_t *fcport; + uint8_t *usr_temp, *kernel_tmp; + uint32_t transfer_len; + uint32_t i; + + EXT_FC_SCSI_PASSTHRU *pscsi3_pass; + + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + DEBUG9_10( + if (!pscsi3_cmd || !pscsi3_device) { + printk("%s(%ld): invalid pointer received. " + "pfc_scsi_cmd=%p, pfc_scsi_device=%p.\n", + __func__, ha->host_no, pscsi3_cmd, + pscsi3_device); + return (ret); + } + ) + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&pscsi3_pass, + sizeof(EXT_FC_SCSI_PASSTHRU))) { + /* not enough memory */ + pext->Status = EXT_STATUS_NO_MEMORY; + DEBUG9_10(printk("%s(%ld): inst=%ld scrap not big enough. " + "size requested=%ld.\n", + __func__, ha->host_no, ha->instance, + (ulong)sizeof(EXT_FC_SCSI_PASSTHRU));) + return (ret); + } + + + /* clear ioctl_mem to be used */ + memset(ha->ioctl_mem, 0, ha->ioctl_mem_size); + + ret = verify_area(VERIFY_READ, (void *)pext->RequestAdr, + sizeof(EXT_FC_SCSI_PASSTHRU)); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR verify READ " + "req buf.\n", __func__, ha->host_no, ha->instance);) + return (ret); + } + + if (pext->ResponseLen > ha->ioctl_mem_size) { + if (qla2x00_get_new_ioctl_dma_mem(ha, pext->ResponseLen) != + QLA_SUCCESS) { + + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR cannot " + "alloc requested DMA buffer size=%x.\n", + __func__, ha->host_no, ha->instance, + pext->ResponseLen);) + + pext->Status = EXT_STATUS_NO_MEMORY; + return (ret); + } + } + + /* Copy request buffer */ + usr_temp = (uint8_t *)pext->RequestAdr; + kernel_tmp = (uint8_t *)pscsi3_pass; + ret = copy_from_user(kernel_tmp, usr_temp, + sizeof(EXT_FC_SCSI_PASSTHRU)); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk( + "%s(%ld): inst=%ld ERROR copy req buf ret=%d\n", + __func__, ha->host_no, ha->instance, ret);) + return (ret); + } + + if (pscsi3_pass->FCScsiAddr.DestType != EXT_DEF_DESTTYPE_WWPN) { + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR - wrong Dest type.\n", + __func__, ha->host_no, ha->instance);) + ret = EXT_STATUS_ERR; + + return (ret); + } + + /* + * For this ioctl command we always assume all 16 bytes are + * initialized. + */ + if (pscsi3_pass->CdbLength != MAX_SCSI3_CDB_LEN) { + pext->Status = EXT_STATUS_INVALID_PARAM; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR -wrong Cdb Len %d.\n", + __func__, ha->host_no, ha->instance, + pscsi3_pass->CdbLength);) + return (ret); + } + + fcport = NULL; + found = 0; + list_for_each(fcpl, &ha->fcports) { + fcport = list_entry(fcpl, fc_port_t, list); + + if (memcmp(fcport->port_name, + pscsi3_pass->FCScsiAddr.DestAddr.WWPN, 8) == 0) { + found++; + break; + } + } + if (!found) { + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + + DEBUG9_10(printk("%s(%ld): inst=%ld DID NOT FIND Port for WWPN " + "%02x%02x%02x%02x%02x%02x%02x%02x.\n", + __func__, ha->host_no, ha->instance, + pscsi3_pass->FCScsiAddr.DestAddr.WWPN[0], + pscsi3_pass->FCScsiAddr.DestAddr.WWPN[1], + pscsi3_pass->FCScsiAddr.DestAddr.WWPN[2], + pscsi3_pass->FCScsiAddr.DestAddr.WWPN[3], + pscsi3_pass->FCScsiAddr.DestAddr.WWPN[4], + pscsi3_pass->FCScsiAddr.DestAddr.WWPN[5], + pscsi3_pass->FCScsiAddr.DestAddr.WWPN[6], + pscsi3_pass->FCScsiAddr.DestAddr.WWPN[7]);) + + return (ret); + } + + /* Use a temporary fclun to send out the command. */ + fclun = &temp_fclun; + fclun->fcport = fcport; + fclun->lun = pscsi3_pass->FCScsiAddr.Lun; + + /* set target coordinates */ + pscsi3_cmd->device->id = 0xff; /* not used. just put something there. */ + pscsi3_cmd->device->lun = pscsi3_pass->FCScsiAddr.Lun; + + DEBUG9(printk("%s(%ld): inst=%ld cmd for loopid=%04x L=%04x " + "WWPN=%02x%02x%02x%02x%02x%02x%02x%02x.\n", + __func__, ha->host_no, ha->instance, + fclun->fcport->loop_id, pscsi3_cmd->device->lun, + pscsi3_pass->FCScsiAddr.DestAddr.WWPN[0], + pscsi3_pass->FCScsiAddr.DestAddr.WWPN[1], + pscsi3_pass->FCScsiAddr.DestAddr.WWPN[2], + pscsi3_pass->FCScsiAddr.DestAddr.WWPN[3], + pscsi3_pass->FCScsiAddr.DestAddr.WWPN[4], + pscsi3_pass->FCScsiAddr.DestAddr.WWPN[5], + pscsi3_pass->FCScsiAddr.DestAddr.WWPN[6], + pscsi3_pass->FCScsiAddr.DestAddr.WWPN[7]);) + + pscsi3_cmd->cmd_len = MAX_SCSI3_CDB_LEN; + memcpy(pscsi3_cmd->data_cmnd, pscsi3_pass->Cdb, pscsi3_cmd->cmd_len); + memcpy(pscsi3_cmd->cmnd, pscsi3_pass->Cdb, pscsi3_cmd->cmd_len); + + DEBUG9(printk("%s(%ld): inst=%ld cdb buffer dump:\n", + __func__, ha->host_no, ha->instance);) + DEBUG9(qla2x00_dump_buffer((uint8_t *)&pscsi3_cmd->data_cmnd[0], 16);) + + if ((ret = qla2x00_ioctl_scsi_queuecommand(ha, pext, pscsi3_cmd, + pscsi3_device, fcport, fclun))) { + return (ret); + } + + /* Wait for comletion */ + ha->ioctl->cmpl_timer.expires = jiffies + ha->ioctl->ioctl_tov * HZ; + add_timer(&ha->ioctl->cmpl_timer); + + down(&ha->ioctl->cmpl_sem); + + del_timer(&ha->ioctl->cmpl_timer); + + if (ha->ioctl->SCSIPT_InProgress == 1) { + + printk(KERN_WARNING + "qla2x00: inst=%ld scsi%ld ERROR PT command timeout.\n", + ha->host_no, ha->instance); + + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + return (ret); + + } + if (CMD_COMPL_STATUS(pscsi3_cmd) == (int)IOCTL_INVALID_STATUS) { + + DEBUG9(printk("%s(%ld): inst=%ld ERROR - cmd not completed.\n", + __func__, ha->host_no, ha->instance);) + + pext->Status = EXT_STATUS_ERR; + return (ret); + } + + if ((CMD_SCSI_STATUS(pscsi3_cmd) & 0xff) != 0) { + + /* have done the post function */ + pext->Status = EXT_STATUS_SCSI_STATUS; + pext->DetailStatus = CMD_SCSI_STATUS(pscsi3_cmd) & 0xff; + + DEBUG9_10(printk(KERN_INFO "%s(%ld): inst=%ld scsi err. " + "host status =0x%x, scsi status = 0x%x.\n", + __func__, ha->host_no, ha->instance, + CMD_COMPL_STATUS(pscsi3_cmd), CMD_SCSI_STATUS(pscsi3_cmd));) + + } else { + if (CMD_COMPL_STATUS(pscsi3_cmd) == CS_DATA_OVERRUN) { + pext->Status = EXT_STATUS_DATA_OVERRUN; + + DEBUG9_10(printk(KERN_INFO + "%s(%ld): inst=%ld return overrun.\n", + __func__, ha->host_no, ha->instance);) + + } else if (CMD_COMPL_STATUS(pscsi3_cmd) == CS_DATA_UNDERRUN && + (CMD_SCSI_STATUS(pscsi3_cmd) & SS_RESIDUAL_UNDER)) { + pext->Status = EXT_STATUS_DATA_UNDERRUN; + + DEBUG9_10(printk(KERN_INFO + "%s(%ld): inst=%ld return underrun.\n", + __func__, ha->host_no, ha->instance);) + + } else if (CMD_COMPL_STATUS(pscsi3_cmd) != 0 || + CMD_SCSI_STATUS(pscsi3_cmd) != 0) { + pext->Status = EXT_STATUS_ERR; + + DEBUG9_10(printk(KERN_INFO + "%s(%ld): inst=%ld, cs err=%x, scsi err=%x.\n", + __func__, ha->host_no, ha->instance, + CMD_COMPL_STATUS(pscsi3_cmd), + CMD_SCSI_STATUS(pscsi3_cmd));) + + return (ret); + } + } + + /* Process completed command */ + DEBUG9(printk("%s(%ld): inst=%ld done. host status=0x%x, " + "scsi status=0x%x.\n", + __func__, ha->host_no, ha->instance, CMD_COMPL_STATUS(pscsi3_cmd), + CMD_SCSI_STATUS(pscsi3_cmd));) + + /* copy up structure to make sense data available to user */ + pscsi3_pass->SenseLength = CMD_ACTUAL_SNSLEN(pscsi3_cmd); + if (CMD_ACTUAL_SNSLEN(pscsi3_cmd)) { + DEBUG9_10(printk("%s(%ld): inst=%ld sense[0]=%x sense[2]=%x.\n", + __func__, ha->host_no, ha->instance, + pscsi3_cmd->sense_buffer[0], + pscsi3_cmd->sense_buffer[2]);) + + for (i = 0; i < CMD_ACTUAL_SNSLEN(pscsi3_cmd); i++) { + pscsi3_pass->SenseData[i] = + pscsi3_cmd->sense_buffer[i]; + } + + ret = verify_area(VERIFY_WRITE, (void *)pext->RequestAdr, + sizeof(EXT_FC_SCSI_PASSTHRU)); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR verify WRITE " + "RequestAdr.\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + + usr_temp = (uint8_t *)pext->RequestAdr; + kernel_tmp = (uint8_t *)pscsi3_pass; + ret = copy_to_user(usr_temp, kernel_tmp, + sizeof(EXT_FC_SCSI_PASSTHRU)); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR copy sense " + "buffer.\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + } + + if (pscsi3_pass->Direction == EXT_DEF_SCSI_PASSTHRU_DATA_IN) { + + DEBUG9(printk("%s(%ld): inst=%ld copying data.\n", + __func__, ha->host_no, ha->instance);) + + /* getting device data and putting in pext->ResponseAdr */ + ret = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr, + pext->ResponseLen); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR verify write " + "ResponseAdr.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); + } + + /* now copy up the READ data to user */ + if ((CMD_COMPL_STATUS(pscsi3_cmd) == CS_DATA_UNDERRUN) && + (CMD_RESID_LEN(pscsi3_cmd))) { + + transfer_len = pext->ResponseLen - + CMD_RESID_LEN(pscsi3_cmd); + + pext->ResponseLen = transfer_len; + } else { + transfer_len = pext->ResponseLen; + } + + DEBUG9_10(printk(KERN_INFO + "%s(%ld): final transferlen=%d.\n", + __func__, ha->host_no, transfer_len);) + + usr_temp = (uint8_t *)pext->ResponseAdr; + kernel_tmp = (uint8_t *)ha->ioctl_mem; + ret = copy_to_user(usr_temp, kernel_tmp, transfer_len); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk( + "%s(%ld): inst=%ld ERROR copy rsp buf\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + } + + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); +} + +/* + * qla2x00_send_els_rnid + * IOCTL to send extended link service RNID command to a target. + * + * Input: + * ha = adapter state pointer. + * pext = User space CT arguments pointer. + * mode = flags. + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_send_els_rnid(scsi_qla_host_t *ha, EXT_IOCTL *pext, int mode) +{ + EXT_RNID_REQ *tmp_rnid; + int ret = 0; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + uint32_t copy_len; + int found; + uint16_t next_loop_id; + fc_port_t *fcport; + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + if (ha->ioctl_mem_size < SEND_RNID_RSP_SIZE) { + if (qla2x00_get_new_ioctl_dma_mem(ha, + SEND_RNID_RSP_SIZE) != QLA_SUCCESS) { + + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR cannot alloc " + "DMA buffer. size=%x.\n", + __func__, ha->host_no, ha->instance, + SEND_RNID_RSP_SIZE);) + + pext->Status = EXT_STATUS_NO_MEMORY; + return (ret); + } + } + + if (pext->RequestLen != sizeof(EXT_RNID_REQ)) { + /* parameter error */ + DEBUG9_10(printk("%s(%ld): inst=%ld invalid req length %d.\n", + __func__, ha->host_no, ha->instance, pext->RequestLen);) + pext->Status = EXT_STATUS_INVALID_PARAM; + return (ret); + } + + ret = verify_area(VERIFY_READ, (void *)pext->RequestAdr, + pext->RequestLen); + + if (ret != 0) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk( + "%s(%ld): inst=%ld req buf verify READ FAILED\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + + DEBUG9(printk("%s(%ld): inst=%ld req buf verified. Copying req data.\n", + __func__, ha->host_no, ha->instance);) + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&tmp_rnid, + sizeof(EXT_RNID_REQ))) { + /* not enough memory */ + pext->Status = EXT_STATUS_NO_MEMORY; + DEBUG9_10(printk("%s(%ld): inst=%ld scrap not big enough. " + "size requested=%ld.\n", + __func__, ha->host_no, ha->instance, + (ulong)sizeof(EXT_RNID_REQ));) + return (ret); + } + + ret = copy_from_user(tmp_rnid, pext->RequestAdr, pext->RequestLen); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk( + "%s(%ld): inst=%ld ERROR copy req buf ret=%d\n", + __func__, ha->host_no, ha->instance, ret);) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + /* Find loop ID of the device */ + found = 0; + fcport = NULL; + switch (tmp_rnid->Addr.Type) { + case EXT_DEF_TYPE_WWNN: + DEBUG9(printk("%s(%ld): inst=%ld got node name.\n", + __func__, ha->host_no, ha->instance);) + + list_for_each_entry(fcport, &ha->fcports, list) { + if (fcport->port_type != FCT_INITIATOR || + fcport->port_type != FCT_TARGET) + continue; + + if (memcmp(tmp_rnid->Addr.FcAddr.WWNN, + fcport->node_name, EXT_DEF_WWN_NAME_SIZE)) + continue; + + if (fcport->port_type == FCT_TARGET) { + if (atomic_read(&fcport->state) != FCS_ONLINE) + continue; + } else { /* FCT_INITIATOR */ + if (!fcport->d_id.b24) + continue; + } + + found++; + } + break; + + case EXT_DEF_TYPE_WWPN: + DEBUG9(printk("%s(%ld): inst=%ld got port name.\n", + __func__, ha->host_no, ha->instance);) + + list_for_each_entry(fcport, &ha->fcports, list) { + if (fcport->port_type != FCT_INITIATOR || + fcport->port_type != FCT_TARGET) + continue; + + if (memcmp(tmp_rnid->Addr.FcAddr.WWPN, + fcport->port_name, EXT_DEF_WWN_NAME_SIZE)) + continue; + + if (fcport->port_type == FCT_TARGET) { + if (atomic_read(&fcport->state) != FCS_ONLINE) + continue; + } else { /* FCT_INITIATOR */ + if (!fcport->d_id.b24) + continue; + } + + found++; + } + break; + + case EXT_DEF_TYPE_PORTID: + DEBUG9(printk("%s(%ld): inst=%ld got port ID.\n", + __func__, ha->host_no, ha->instance);) + + list_for_each_entry(fcport, &ha->fcports, list) { + if (fcport->port_type != FCT_INITIATOR || + fcport->port_type != FCT_TARGET) + continue; + + /* PORTID bytes entered must already be big endian */ + if (memcmp(&tmp_rnid->Addr.FcAddr.Id[1], + &fcport->d_id, EXT_DEF_PORTID_SIZE_ACTUAL)) + continue; + + if (fcport->port_type == FCT_TARGET) { + if (atomic_read(&fcport->state) != FCS_ONLINE) + continue; + } + + found++; + } + break; + default: + /* parameter error */ + pext->Status = EXT_STATUS_INVALID_PARAM; + DEBUG9_10(printk("%s(%ld): inst=%ld invalid addressing type.\n", + __func__, ha->host_no, ha->instance);) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + if (!found || (fcport->port_type == FCT_TARGET && + fcport->loop_id > ha->last_loop_id)) { + /* + * No matching device or the target device is not configured; + * just return error. + */ + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + /* check on loop down */ + if (atomic_read(&ha->loop_state) != LOOP_READY || + test_bit(CFG_ACTIVE, &ha->cfg_flags) || + test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) || + test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) || ha->dpc_active) { + + pext->Status = EXT_STATUS_BUSY; + DEBUG9_10(printk("%s(%ld): inst=%ld loop not ready.\n", + __func__, ha->host_no, ha->instance);) + + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + /* If this is for a host device, check if we need to perform login */ + if (fcport->port_type == FCT_INITIATOR && + fcport->loop_id >= ha->last_loop_id) { + next_loop_id = 0; + ret = qla2x00_fabric_login(ha, fcport, &next_loop_id); + if (ret != QLA_SUCCESS) { + /* login failed. */ + pext->Status = EXT_STATUS_DEV_NOT_FOUND; + + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR login to " + "host port failed. loop_id=%02x pid=%02x%02x%02x " + "ret=%d.\n", + __func__, ha->host_no, ha->instance, + fcport->loop_id, fcport->d_id.b.domain, + fcport->d_id.b.area, fcport->d_id.b.al_pa, ret);) + + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + } + + /* Send command */ + DEBUG9(printk("%s(%ld): inst=%ld sending rnid cmd.\n", + __func__, ha->host_no, ha->instance);) + + ret = qla2x00_send_rnid_mbx(ha, fcport->loop_id, + (uint8_t)tmp_rnid->DataFormat, ha->ioctl_mem_phys, + SEND_RNID_RSP_SIZE, &mb[0]); + + if (ret != QLA_SUCCESS) { + /* error */ + pext->Status = EXT_STATUS_ERR; + + DEBUG9_10(printk("%s(%ld): inst=%ld FAILED. rval = %x.\n", + __func__, ha->host_no, ha->instance, mb[0]);) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + DEBUG9(printk("%s(%ld): inst=%ld rnid cmd sent ok.\n", + __func__, ha->host_no, ha->instance);) + + /* Copy the response */ + copy_len = (pext->ResponseLen > SEND_RNID_RSP_SIZE) ? + SEND_RNID_RSP_SIZE : pext->ResponseLen; + + ret = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr, + copy_len); + + if (ret != 0) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk( + "%s(%ld): inst=%ld rsp buf verify WRITE error\n", + __func__, ha->host_no, ha->instance);) + } else { + ret = copy_to_user((uint8_t *)pext->ResponseAdr, + (uint8_t *)ha->ioctl_mem, copy_len); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk( + "%s(%ld): inst=%ld ERROR copy rsp buf\n", + __func__, ha->host_no, ha->instance);) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + if (SEND_RNID_RSP_SIZE > pext->ResponseLen) { + pext->Status = EXT_STATUS_DATA_OVERRUN; + DEBUG9(printk("%s(%ld): inst=%ld data overrun. " + "exiting normally.\n", + __func__, ha->host_no, ha->instance);) + } else { + pext->Status = EXT_STATUS_OK; + DEBUG9(printk("%s(%ld): inst=%ld exiting normally.\n", + __func__, ha->host_no, ha->instance);) + } + pext->ResponseLen = copy_len; + } + + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); +} + +/* + * qla2x00_get_rnid_params + * IOCTL to get RNID parameters of the adapter. + * + * Input: + * ha = adapter state pointer. + * pext = User space CT arguments pointer. + * mode = flags. + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_get_rnid_params(scsi_qla_host_t *ha, EXT_IOCTL *pext, int mode) +{ + int ret = 0; + int tmp_rval = 0; + uint32_t copy_len; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + /* check on loop down */ + if (atomic_read(&ha->loop_state) != LOOP_READY || + test_bit(CFG_ACTIVE, &ha->cfg_flags) || + test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) || + test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) || ha->dpc_active) { + + pext->Status = EXT_STATUS_BUSY; + DEBUG9_10(printk("%s(%ld): inst=%ld loop not ready.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); + } + + /* Send command */ + tmp_rval = qla2x00_get_rnid_params_mbx(ha, ha->ioctl_mem_phys, + sizeof(EXT_RNID_DATA), &mb[0]); + + if (tmp_rval != QLA_SUCCESS) { + /* error */ + pext->Status = EXT_STATUS_ERR; + + DEBUG9_10(printk("%s(%ld): inst=%ld cmd FAILED=%x.\n", + __func__, ha->host_no, ha->instance, mb[0]);) + return (ret); + } + + /* Copy the response */ + copy_len = (pext->ResponseLen > sizeof(EXT_RNID_DATA)) ? + (uint32_t)sizeof(EXT_RNID_DATA) : pext->ResponseLen; + ret = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr, + copy_len); + + if (ret != 0) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld verify WRITE rsp buf error\n", + __func__, ha->host_no, ha->instance);) + } else { + ret = copy_to_user((void *)pext->ResponseAdr, + (void *)ha->ioctl_mem, copy_len); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR copy rsp buf\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + + pext->ResponseLen = copy_len; + if (copy_len < sizeof(EXT_RNID_DATA)) { + pext->Status = EXT_STATUS_DATA_OVERRUN; + DEBUG9_10(printk("%s(%ld): inst=%ld data overrun. " + "exiting normally.\n", + __func__, ha->host_no, ha->instance);) + } else if (pext->ResponseLen > sizeof(EXT_RNID_DATA)) { + pext->Status = EXT_STATUS_DATA_UNDERRUN; + DEBUG9_10(printk("%s(%ld): inst=%ld data underrun. " + "exiting normally.\n", + __func__, ha->host_no, ha->instance);) + } else { + pext->Status = EXT_STATUS_OK; + DEBUG9(printk("%s(%ld): inst=%ld exiting normally.\n", + __func__, ha->host_no, ha->instance);) + } + } + + return (ret); +} + +/* + *qla2x00_get_led_state + * IOCTL to get QLA2XXX HBA LED state + * + * Input: + * ha = adapter state pointer. + * pext = User space CT arguments pointer. + * mode = flags. + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_get_led_state(scsi_qla_host_t *ha, EXT_IOCTL *pext, int mode) +{ + int ret = 0; + EXT_BEACON_CONTROL ptmp_led_state; + + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + ret = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr, + sizeof(EXT_BEACON_CONTROL)); + + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR VERIFY_WRITE " + "EXT_HBA_PORT_STAT.\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + + if (test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags)) { + pext->Status = EXT_STATUS_BUSY; + DEBUG9_10(printk("%s(%ld): inst=%ld loop not ready.\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + + if (ha->beacon_blink_led) { + ptmp_led_state.State = EXT_DEF_GRN_BLINK_ON; + } else { + ptmp_led_state.State = EXT_DEF_GRN_BLINK_OFF; + + } + + ret = copy_to_user(pext->ResponseAdr, + &ptmp_led_state, sizeof(EXT_BEACON_CONTROL)); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR copy rsp buffer.\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); + +} + +/* + * qla2x00_set_host_data + * IOCTL command to set host/adapter related data. + * + * Input: + * ha = adapter state pointer. + * pext = User space CT arguments pointer. + * mode = flags. + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_set_host_data(scsi_qla_host_t *ha, EXT_IOCTL *pext, int mode) +{ + int ret = 0; + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + /* switch on command subcode */ + switch (pext->SubCode) { + case EXT_SC_SET_RNID: + ret = qla2x00_set_rnid_params(ha, pext, mode); + break; + case EXT_SC_SET_BEACON_STATE: + if (IS_QLA23XX(ha)) { + ret = qla2x00_set_led_state(ha, pext, mode); + break; + } + /*FALLTHROUGH*/ + default: + /* function not supported. */ + pext->Status = EXT_STATUS_UNSUPPORTED_SUBCODE; + break; + } + + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); +} + +/* + * qla2x00_set_rnid_params + * IOCTL to set RNID parameters of the adapter. + * + * Input: + * ha = adapter state pointer. + * pext = User space CT arguments pointer. + * mode = flags. + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_set_rnid_params(scsi_qla_host_t *ha, EXT_IOCTL *pext, int mode) +{ + EXT_SET_RNID_REQ *tmp_set; + EXT_RNID_DATA *tmp_buf; + int ret = 0; + int tmp_rval = 0; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + /* check on loop down */ + if (atomic_read(&ha->loop_state) != LOOP_READY || + test_bit(CFG_ACTIVE, &ha->cfg_flags) || + test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) || + test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) || ha->dpc_active) { + + pext->Status = EXT_STATUS_BUSY; + DEBUG9_10(printk("%s(%ld): inst=%ld loop not ready.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); + } + + if (pext->RequestLen != sizeof(EXT_SET_RNID_REQ)) { + /* parameter error */ + pext->Status = EXT_STATUS_INVALID_PARAM; + DEBUG9_10(printk("%s(%ld): inst=%ld invalid request length.\n", + __func__, ha->host_no, ha->instance);) + return(ret); + } + + ret = verify_area(VERIFY_READ, (void *)pext->RequestAdr, + pext->RequestLen); + + if (ret != 0) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld verify READ request buf.\n", + __func__, ha->host_no, ha->instance);) + return(ret); + } + + if (qla2x00_get_ioctl_scrap_mem(ha, (void **)&tmp_set, + sizeof(EXT_SET_RNID_REQ))) { + /* not enough memory */ + pext->Status = EXT_STATUS_NO_MEMORY; + DEBUG9_10(printk("%s(%ld): inst=%ld scrap not big enough. " + "size requested=%ld.\n", + __func__, ha->host_no, ha->instance, + (ulong)sizeof(EXT_SET_RNID_REQ));) + return (ret); + } + + ret = copy_from_user(tmp_set, pext->RequestAdr, pext->RequestLen); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk( + "%s(%ld): inst=%ld ERROR copy req buf ret=%d\n", + __func__, ha->host_no, ha->instance, ret);) + qla2x00_free_ioctl_scrap_mem(ha); + return(ret); + } + + tmp_rval = qla2x00_get_rnid_params_mbx(ha, ha->ioctl_mem_phys, + sizeof(EXT_RNID_DATA), &mb[0]); + if (tmp_rval != QLA_SUCCESS) { + /* error */ + pext->Status = EXT_STATUS_ERR; + + DEBUG9_10(printk("%s(%ld): inst=%ld read cmd FAILED=%x.\n", + __func__, ha->host_no, ha->instance, mb[0]);) + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); + } + + tmp_buf = (EXT_RNID_DATA *)ha->ioctl_mem; + /* Now set the params. */ + memcpy(tmp_buf->IPVersion, tmp_set->IPVersion, 2); + memcpy(tmp_buf->UDPPortNumber, tmp_set->UDPPortNumber, 2); + memcpy(tmp_buf->IPAddress, tmp_set->IPAddress, 16); + tmp_rval = qla2x00_set_rnid_params_mbx(ha, ha->ioctl_mem_phys, + sizeof(EXT_RNID_DATA), &mb[0]); + + if (tmp_rval != QLA_SUCCESS) { + /* error */ + pext->Status = EXT_STATUS_ERR; + + DEBUG9_10(printk("%s(%ld): inst=%ld set cmd FAILED=%x.\n", + __func__, ha->host_no, ha->instance, mb[0]);) + } else { + pext->Status = EXT_STATUS_OK; + DEBUG9(printk("%s(%ld): inst=%ld exiting normally.\n", + __func__, ha->host_no, ha->instance);) + } + + qla2x00_free_ioctl_scrap_mem(ha); + return (ret); +} + +/* + *qla2x00_set_led_state + * IOCTL to set QLA2XXX HBA LED state + * + * Input: + * ha = adapter state pointer. + * pext = User space CT arguments pointer. + * mode = flags. + * + * Returns: + * 0 = success + * others = errno value + * + * Context: + * Kernel context. + */ +static int +qla2x00_set_led_state(scsi_qla_host_t *ha, EXT_IOCTL *pext, int mode) +{ + int ret = 0; + EXT_BEACON_CONTROL ptmp_led_state; + device_reg_t *reg = ha->iobase; + uint8_t gpio_enable, gpio_data; + unsigned long cpu_flags = 0; + + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + ret = verify_area(VERIFY_READ, (void *)pext->RequestAdr, + sizeof(EXT_BEACON_CONTROL)); + + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR VERIFY_WRITE " + "EXT_HBA_PORT_STAT.\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + + if (test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags)) { + pext->Status = EXT_STATUS_BUSY; + DEBUG9_10(printk("%s(%ld): inst=%ld abort isp active.\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + + ret = copy_from_user(&ptmp_led_state, + pext->RequestAdr, pext->RequestLen); + if (ret) { + pext->Status = EXT_STATUS_COPY_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR copy req buf.\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + + if (ptmp_led_state.State != EXT_DEF_GRN_BLINK_ON && + ptmp_led_state.State != EXT_DEF_GRN_BLINK_OFF) { + pext->Status = EXT_STATUS_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld Unknown Led State set " + "operation.\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + + if (ptmp_led_state.State == EXT_DEF_GRN_BLINK_ON) { + + DEBUG9_10(printk("%s(%ld): inst=%ld start blinking led \n", + __func__, ha->host_no, ha->instance);) + + DEBUG9_10(printk("%s(%ld): inst=%ld firmware options " + "fw_options1=0x%x fw_options2=0x%x fw_options3=0x%x.\n", + __func__, ha->host_no, ha->instance, ha->fw_options[1], + ha->fw_options[2], ha->fw_options[3]);) + + ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING; + ha->fw_options[1] |= FO1_DISABLE_GPIO6_7; + + if (qla2x00_set_fw_options(ha, ha->fw_options) != QLA_SUCCESS) { + pext->Status = EXT_STATUS_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld set" + "firmware options failed.\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + + /* Turn of both LEDs */ + spin_lock_irqsave(&ha->hardware_lock, cpu_flags); + gpio_enable = RD_REG_WORD(®->gpioe); + gpio_data = RD_REG_WORD(®->gpiod); + gpio_enable |= GPIO_LED_MASK; + + /* Set the modified gpio_enable values */ + WRT_REG_WORD(®->gpioe,gpio_enable); + + /* Clear out previously set LED colour */ + gpio_data &= ~GPIO_LED_MASK; + WRT_REG_WORD(®->gpiod,gpio_data); + spin_unlock_irqrestore(&ha->hardware_lock, cpu_flags); + + /* Let the per HBA timer kick off the blinking process*/ + ha->beacon_blink_led = 1; + ha->beacon_green_on = 0; + } /* end of if(ptmp_led_state.State == EXT_DEF_GRN_BLINK_ON) ) */ + + if (ptmp_led_state.State == EXT_DEF_GRN_BLINK_OFF) { + DEBUG9_10(printk("%s(%ld): inst=%ld stop blinking led \n", + __func__, ha->host_no, ha->instance);) + ha->beacon_blink_led = 0; + ha->beacon_green_on = 1; /* Turn green led on */ + qla2x00_blink_led(ha); + + DEBUG9_10(printk("%s(%ld): inst=%ld firmware" + " options fw_options1=0x%x fw_options2=0x%x " + "fw_options3=0x%x.\n", + __func__, ha->host_no, ha->instance, ha->fw_options[1], + ha->fw_options[2], ha->fw_options[3]);) + + ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING; + ha->fw_options[1] &= ~FO1_DISABLE_GPIO6_7; + + if (qla2x00_set_fw_options(ha, ha->fw_options) != QLA_SUCCESS) { + pext->Status = EXT_STATUS_ERR; + DEBUG9_10(printk("%s(%ld): inst=%ld set" + "firmware options failed.\n", + __func__, ha->host_no, ha->instance);) + return (ret); + } + } /* end of if(ptmp_led_state.State == EXT_DEF_GRN_BLINK_OFF) */ + + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) + + return (ret); +} + +/* + * qla2x00_waitq_sem_timeout + * Timeout function to be called when a thread on the wait_q + * queue timed out. + * + * Input: + * data = data pointer for timeout function. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +static void +qla2x00_waitq_sem_timeout(unsigned long data) +{ + wait_q_t *tmp_ptr = (wait_q_t *)data; + + DEBUG9(printk("%s: entered.\n", __func__);) + + if (tmp_ptr != NULL) { + DEBUG9(printk("%s: wait_q thread=%p.\n", __func__, tmp_ptr);) + up(&tmp_ptr->wait_q_sem); + } + + DEBUG9(printk("%s: exiting.\n", __func__);) + +} + +/* + * qla2x00_get_ioctl_access + * Serialization routine for the ioctl commands. + * When succeeded the exiting thread gains "access" and + * proceeds, otherwise it gives up and returns error. + * Each thread would wait tov seconds before giving up. + * + * Input: + * ha = adapter state pointer. + * tov = timeout value in seconds + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +static int +qla2x00_get_ioctl_access(scsi_qla_host_t *ha, uint32_t tov) +{ + int rval; + int prev_val = 1; + unsigned long cpu_flags; + struct timer_list tmp_access_timer; + wait_q_t *ptmp_wq = NULL; + + rval = QLA_SUCCESS; + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + while (1) { + if (test_bit(IOCTL_WANT, (void *)&(ha->ioctl->access_bits)) == + 0) { + + DEBUG9(printk("%s(%ld): going to test access_bits.\n", + __func__, ha->host_no);) + + /* No one else is waiting. Go ahead and try to + * get access. + */ + if ((prev_val = test_and_set_bit(IOCTL_ACTIVE, + (void *)&ha->ioctl->access_bits)) == 0) { + break; + } + } + + /* wait for previous command to finish */ + DEBUG9(printk("%s(%ld): inst=%ld access_bits=%x. busy. " + "Waiting for access. curr time=0x%lx.\n", + __func__, ha->host_no, ha->instance, + ha->ioctl->access_bits, jiffies);) + + /* + * Init timer and get semaphore from wait_q. if we got valid + * semaphore pointer the IOCTL_WANT flag would also had + * been set. + */ + qla2x00_wait_q_add(ha, &ptmp_wq); + + if (ptmp_wq == NULL) { + /* queue full? problem? can't proceed. */ + DEBUG9_10(printk("%s(%ld): ERROR no more wait_q " + "allowed. exiting.\n", __func__, ha->host_no);) + + break; + } + + init_timer(&tmp_access_timer); + + tmp_access_timer.data = (unsigned long)ptmp_wq; + tmp_access_timer.function = + (void (*)(unsigned long))qla2x00_waitq_sem_timeout; + tmp_access_timer.expires = jiffies + tov * HZ; + + DEBUG9(printk("%s(%ld): adding timer. " + "curr time=0x%lx timeoutval=0x%lx.\n", + __func__, ha->host_no, jiffies, tmp_access_timer.expires);) + + /* wait. */ + add_timer(&tmp_access_timer); + + DEBUG9(printk("%s(%ld): inst=%ld wait_q %p going to sleep. " + "current time=0x%lx.\n", + __func__, ha->host_no, ha->instance, ptmp_wq, jiffies);) + + if (down_interruptible(&ptmp_wq->wait_q_sem)) { + DEBUG9_10(printk("%s(%ld): inst=%ld signal received " + "while spleeping.\n", __func__, ha->host_no, + ha->instance);) + del_timer(&tmp_access_timer); + prev_val = 1; + break; + } + + DEBUG9(printk("%s(%ld): inst=%ld wait_q %p woke up. current " + "time=0x%lx.\n", + __func__, ha->host_no, ha->instance, ptmp_wq, jiffies);) + + del_timer(&tmp_access_timer); + + /* try to get lock again. we'll test later to see + * if we actually got the lock. + */ + prev_val = test_and_set_bit(IOCTL_ACTIVE, + (void *)&(ha->ioctl->access_bits)); + + /* + * After we tried to get access then we check to see + * if we need to clear the IOCTL_WANT flag. Don't clear + * this flag before trying to get access or another + * new thread might grab it before we did. + */ + spin_lock_irqsave(&ha->ioctl->wait_q_lock, cpu_flags); + if (prev_val != 0) { + /* We'll return with error. + * Make sure we remove ourselves from wait_q. + */ + qla2x00_wait_q_remove(ha, ptmp_wq); + } + if (ha->ioctl->wait_q_head == NULL) { + /* We're the last thread in wait_q queue. */ + clear_bit(IOCTL_WANT, (void *)&ha->ioctl->access_bits); + } + qla2x00_wait_q_memb_free(ha, ptmp_wq); + spin_unlock_irqrestore(&ha->ioctl->wait_q_lock, cpu_flags); + + break; + } + + if (prev_val == 0) { + /* We got the lock */ + DEBUG9(printk("%s(%ld): inst=%ld got access.\n", + __func__, ha->host_no, ha->instance);) + + } else { + /* Timeout or resource error. */ + DEBUG9_10(printk("%s(%ld): inst=%ld timed out " + "or wait_q error.\n", __func__, ha->host_no, ha->instance);) + + rval = QLA_FUNCTION_TIMEOUT; + } + + return (rval); +} + +/* + * qla2x00_release_ioctl_access + * Serialization routine for the ioctl commands. + * This releases "access" and checks on wai_q queue. If there's + * another thread waiting then wakes it up. + * + * Input: + * ha = adapter state pointer. + * tov = timeout value in seconds + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +static int +qla2x00_release_ioctl_access(scsi_qla_host_t *ha) +{ + wait_q_t *next_thread = NULL; + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + clear_bit(IOCTL_ACTIVE, (void *)&(ha->ioctl->access_bits)); + + /* Wake up one pending ioctl thread in wait_q */ + qla2x00_wait_q_get_next(ha, &next_thread); + if (next_thread) { + DEBUG9(printk( + "%s(%ld): inst=%ld found wait_q. Wake up waitq %p\n", + __func__, ha->host_no, ha->instance, &next_thread);) + up(&next_thread->wait_q_sem); + } + + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) + + return QLA_SUCCESS; +} + +/* + * qla2x00_wait_q_memb_alloc + * Finds a free wait_q member from the array. Must already got the + * wait_q_lock spinlock. + * + * Input: + * ha = adapter state pointer. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +static void +qla2x00_wait_q_memb_alloc(scsi_qla_host_t *ha, wait_q_t **ret_wait_q_memb) +{ + uint8_t i; + wait_q_t *ptmp = NULL; + + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + for (i = 0; i < MAX_IOCTL_WAIT_THREADS; i++) { + if (!(ha->ioctl->wait_q_arr[i].flags & WQ_IN_USE)) { + ha->ioctl->wait_q_arr[i].flags |= WQ_IN_USE; + ptmp = &ha->ioctl->wait_q_arr[i]; + break; + } + } + + *ret_wait_q_memb = ptmp; + + DEBUG9(printk("%s(%ld): inst=%ld return waitq_memb=%p.\n", + __func__, ha->host_no, ha->instance, *ret_wait_q_memb);) +} + +/* + * qla2x00_wait_q_memb_free + * Frees the specified wait_q member. Must already got the wait_q_lock + * spinlock. + * + * Input: + * ha = adapter state pointer. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +static void +qla2x00_wait_q_memb_free(scsi_qla_host_t *ha, wait_q_t *pfree_wait_q_memb) +{ + DEBUG9(printk("%s(%ld): inst=%ld entered.\n", + __func__, ha->host_no, ha->instance);) + + if (pfree_wait_q_memb != NULL) { + DEBUG9(printk("%s(%ld): freeing %p.\n", + __func__, ha->host_no, pfree_wait_q_memb);) + pfree_wait_q_memb->flags &= ~WQ_IN_USE; + } + + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) +} + +/* + * qla2x00_wait_q_add + * Allocates a wait_q_t struct and add to the wait_q list. + * + * Input: + * ha = adapter state pointer. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +static int +qla2x00_wait_q_add(scsi_qla_host_t *ha, wait_q_t **ret_wq) +{ + int rval; + unsigned long cpu_flags; + wait_q_t *ptmp = NULL; + + rval = QLA_SUCCESS; + + spin_lock_irqsave(&ha->ioctl->wait_q_lock, cpu_flags); + + DEBUG9(printk("%s(%ld): inst=%ld got wait_q spinlock.\n", + __func__, ha->host_no, ha->instance);) + + qla2x00_wait_q_memb_alloc(ha, &ptmp); + if (ptmp == NULL) { + /* can't add any more threads */ + DEBUG9_10(printk("%s(%ld): inst=%ld ERROR no more ioctl " + "threads allowed.\n", + __func__, ha->host_no, ha->instance);) + + rval = QLA_MEMORY_ALLOC_FAILED; + } else { + if (ha->ioctl->wait_q_tail == NULL) { + /* First thread to queue. */ + set_bit(IOCTL_WANT, (void *)&ha->ioctl->access_bits); + + ha->ioctl->wait_q_head = ptmp; + } else { + ha->ioctl->wait_q_tail->pnext = ptmp; + } + ha->ioctl->wait_q_tail = ptmp; + + *ret_wq = ptmp; + + /* Now init the semaphore */ + + init_MUTEX_LOCKED(&ptmp->wait_q_sem); + + rval = QLA_SUCCESS; + } + + DEBUG9(printk("%s(%ld): inst=%ld going to release spinlock. " + "ret_wq=%p, rval=%d.\n", + __func__, ha->host_no, ha->instance, *ret_wq, rval);) + + spin_unlock_irqrestore(&ha->ioctl->wait_q_lock, cpu_flags); + + return rval; +} + +/* + * qla2x00_wait_q_get_next + * This just removes one member from head of wait_q. + * + * Input: + * ha = adapter state pointer. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +static void +qla2x00_wait_q_get_next(scsi_qla_host_t *ha, wait_q_t **ret_wq) +{ + unsigned long cpu_flags; + + if (test_bit(IOCTL_ACTIVE, (void *)&(ha->ioctl->access_bits)) != 0) { + /* Another thread just became active. Exit. */ + *ret_wq = NULL; + return; + } + + /* Find the next thread to wake up */ + spin_lock_irqsave(&ha->ioctl->wait_q_lock, cpu_flags); + + DEBUG9(printk("%s(%ld): inst=%ld got wait_q spinlock.\n", + __func__, ha->host_no, ha->instance);) + + /* Remove from head */ + *ret_wq = ha->ioctl->wait_q_head; + if (ha->ioctl->wait_q_head != NULL) { + + ha->ioctl->wait_q_head = ha->ioctl->wait_q_head->pnext; + + if (ha->ioctl->wait_q_head == NULL) { + /* That's the last one in queue. */ + ha->ioctl->wait_q_tail = NULL; + } + + (*ret_wq)->pnext = NULL; + } + + DEBUG9(printk("%s(%ld): inst=%ld return ret_wq=%p. Going to release " + "spinlock.\n", + __func__, ha->host_no, ha->instance, *ret_wq);) + spin_unlock_irqrestore(&ha->ioctl->wait_q_lock, cpu_flags); +} + +/* + * qla2x00_wait_q_remove + * Removes the specified member from wait_q. + * Must already got the wait_q_lock spin lock. + * + * Input: + * ha = adapter state pointer. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +static void +qla2x00_wait_q_remove(scsi_qla_host_t *ha, wait_q_t *rem_wq) +{ + wait_q_t *ptmp_wq; + wait_q_t *ptmp_prev; + + DEBUG9(printk("%s(%ld): inst=%ld rem_wq=%p.\n", + __func__, ha->host_no, ha->instance, rem_wq);) + + /* Search then remove */ + ptmp_prev = NULL; + for (ptmp_wq = ha->ioctl->wait_q_head; ptmp_wq != NULL; + ptmp_wq = ptmp_wq->pnext) { + + if (ptmp_wq == rem_wq) { + /* Found it in wait_q. Remove. */ + + DEBUG9(printk("%s(%ld): inst=%ld removing.\n", + __func__, ha->host_no, ha->instance);) + + if (ha->ioctl->wait_q_head == ptmp_wq) { + ha->ioctl->wait_q_head = ptmp_wq->pnext; + } else { + ptmp_prev->pnext = ptmp_wq->pnext; + } + + if (ha->ioctl->wait_q_tail == ptmp_wq) { + ha->ioctl->wait_q_tail = ptmp_prev; + } + + ptmp_wq->pnext = NULL; + + break; + } + ptmp_prev = ptmp_wq; + } + + DEBUG9(printk("%s(%ld): inst=%ld exiting.\n", + __func__, ha->host_no, ha->instance);) +} diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qlfo.h 830-ivtv/drivers/scsi/qla2xxx/qlfo.h --- 000-virgin/drivers/scsi/qla2xxx/qlfo.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qlfo.h Thu Jan 8 10:22:00 2004 @@ -0,0 +1,415 @@ +/****************************************************************************** + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + ******************************************************************************/ + +/* + * San/Device Management Failover Ioctl Header + * File is created to adhere to Solaris requirement using 8-space tabs. + * + * !!!!! PLEASE DO NOT REMOVE THE TABS !!!!! + * !!!!! PLEASE NO SINGLE LINE COMMENTS: // !!!!! + * !!!!! PLEASE NO MORE THAN 80 CHARS PER LINE !!!!! + * + * Revision History: + * + * Rev. 0.00 August 8, 2000 + * WTR - Created. + * + * Rev. 0.01 August 8, 2000 + * WTR - Made size of HbaInstance fields consistant as UINT8. + * Made command codes as 300 upward to be consistant with definitions + * in ExIoct.h. + * Rev. 0.01 October 3, 2000 + * TLE - Exclusion of ExIoct.h + * + * Rev. 0.01 October 6, 2000 + * TLE - Made size of HbaInstance fields UINT8 + * + * Rev. 0.01 October 10, 2000 + * TLE - Add _FO_DRIVER_VERSION data structure + */ + + + +#ifndef _FO_H +#define _FO_H + +/* + * *********************************************************************** + * X OS type definitions + * *********************************************************************** + */ +#ifdef _MSC_VER /* NT */ + +#pragma pack(1) +#include "qlfont.h" + +#elif defined(linux) /* Linux */ + +#include "qlfoln.h" + +#elif defined(sun) || defined(__sun) /* Solaris */ + +#include "qlfoso.h" + +#endif + +#define SDM_DEF_MAX_DEVICES 16 +#define SDM_DEF_MAX_PATHS_PER_TARGET 4 +#define SDM_DEF_MAX_TARGETS_PER_DEVICE 4 +#define SDM_DEF_MAX_PATHS_PER_DEVICE (SDM_DEF_MAX_PATHS_PER_TARGET * SDM_DEF_MAX_TARGETS_PER_DEVICE) + +#define FO_MAX_LUNS_PER_DEVICE MAX_LUNS_OS +#define FO_MAX_PATHS (SDM_DEF_MAX_PATHS_PER_DEVICE * SDM_DEF_MAX_DEVICES) +#define FO_MAX_ADAPTERS 32 +#define FO_ADAPTER_ALL 0xFF +#define FO_DEF_WWN_SIZE 8 +#define FO_MAX_GEN_INFO_STRING_LEN 32 + +#if 0 /* defined in qlfolimits.h */ +#define FO_NOTIFY_TYPE_NONE 0 +#define FO_NOTIFY_TYPE_LUN_RESET 1 +#define FO_NOTIFY_TYPE_CDB 2 +#define FO_NOTIFY_TYPE_LOGOUT_OR_LUN_RESET 3 +#define FO_NOTIFY_TYPE_LOGOUT_OR_CDB 4 +#define FO_NOTIFY_TYPE_SPINUP 5 + +#define FO_NOTIFY_TYPE_MIN FO_NOTIFY_TYPE_NONE +#define FO_NOTIFY_TYPE_MAX FO_NOTIFY_TYPE_LOGOUT_OR_CDB +#define FO_NOTIFY_TYPE_DEF FO_NOTIFY_TYPE_SPINUP + +#define FO_NOTIFY_CDB_LENGTH_MIN 6 +#define FO_NOTIFY_CDB_LENGTH_MAX 16 +#endif + +/* + * IOCTL Commands + */ + +#define FO_CC_GET_PARAMS FO_CC_GET_PARAMS_OS +#define FO_CC_SET_PARAMS FO_CC_SET_PARAMS_OS +#define FO_CC_GET_PATHS FO_CC_GET_PATHS_OS +#define FO_CC_SET_CURRENT_PATH FO_CC_SET_CURRENT_PATH_OS +#define FO_CC_GET_HBA_STAT FO_CC_GET_HBA_STAT_OS +#define FO_CC_RESET_HBA_STAT FO_CC_RESET_HBA_STAT_OS +#define FO_CC_GET_LUN_DATA FO_CC_GET_LUN_DATA_OS +#define FO_CC_SET_LUN_DATA FO_CC_SET_LUN_DATA_OS +#define FO_CC_GET_TARGET_DATA FO_CC_GET_TARGET_DATA_OS +#define FO_CC_SET_TARGET_DATA FO_CC_SET_TARGET_DATA_OS +#define FO_CC_GET_FO_DRIVER_VERSION FO_CC_GET_FO_DRIVER_VERSION_OS + + +/* Systemwide failover parameters. */ + +typedef struct _FO_PARAMS +{ + UINT32 InspectionInterval; /* Timer interval to check for failover.*/ + UINT8 MaxPathsPerDevice; /* Max paths to any single device. */ + UINT8 MaxRetriesPerPath; /* Max retries on a path before */ + + /* Failover. */ + UINT8 MaxRetriesPerIo; /* Max retries per i/o request. */ + UINT8 Reserved1; + UINT32 Flags; /* Control flags. */ + UINT8 DeviceErrorThreshold; /* Max device errors. */ + UINT8 DeviceTimeoutThreshold; /* Max device timeouts.*/ + UINT8 FrameErrorThreshold; /* Max frame errors.*/ + UINT8 LinkErrorThreshold; /* Max link errors.*/ + UINT32 Reserved2[4]; /* Spares.*/ + + /* Load balancing parameters.*/ + + UINT8 RollingAverageIntervals;/* Intervals to sum for rolling average.*/ + UINT8 MaxDevicesToMigrate; /* Max devices to migrate in any interval.*/ + UINT8 BalanceMethod; /* Method to use for load balancing.*/ + UINT8 Reserved3; /* Memory alignment.*/ + + UINT16 LoadShareMinPercentage; /* Load balancing parameter.*/ + UINT16 LoadShareMaxPercentage; /* Load balancing parameter.*/ + + /* Failover notify parameters. */ + + UINT8 FailoverNotifyType; /* Type of notification. */ + UINT8 FailoverNotifyCdbLength;/* Length of notification CDB. */ + UINT16 Reserved4; + UINT8 FailoverNotifyCdb[16]; /* CDB if notification by CDB. */ + UINT32 Reserved5; + +} +FO_PARAMS, *PFO_PARAMS, SysFoParams_t, *SysFoParams_p; + +extern SysFoParams_t qla_fo_params; + +typedef struct _FO_GET_PATHS +{ + UINT8 HbaInstance; + EXT_DEST_ADDR HbaAddr; /* Lun field is ignored */ + UINT32 Reserved[5]; + +} +FO_GET_PATHS, *PFO_GET_PATHS; + + +typedef struct _FO_PATH_ENTRY +{ + UINT8 Reserved1; + UINT8 Visible; /* Path is visible path. */ + UINT8 Priority; + UINT8 Reserved2; + UINT8 HbaInstance; + UINT8 PortName[EXT_DEF_WWN_NAME_SIZE]; + UINT16 Reserved3; + UINT32 Reserved[3]; + +} +FO_PATH_ENTRY, *PFO_PATH_ENTRY; + + +typedef struct _FO_PATHS_INFO +{ + /* These first fields in the output buffer are specifically the + * same as the fields in the input buffer. This is because the + * same system buffer holds both, and this allows us to reference + * the input buffer parameters while filling the output buffer. */ + + UINT8 HbaInstance; + EXT_DEST_ADDR HbaAddr; + UINT32 Reserved[5]; + UINT8 PathCount; /* Number of Paths in PathEntry array */ + UINT8 Reserved3; + UINT8 VisiblePathIndex; /* Which index has BOOLEAN "visible" flag set */ + UINT8 Reserved4; + + UINT8 CurrentPathIndex[FO_MAX_LUNS_PER_DEVICE]; /* Current Path Index for each Lun */ + + FO_PATH_ENTRY PathEntry[FO_MAX_PATHS]; + + UINT32 Reserved5[4]; + +} +FO_PATHS_INFO, *PFO_PATHS_INFO; + +typedef struct _FO_SET_CURRENT_PATH +{ + UINT8 HbaInstance; + EXT_DEST_ADDR HbaAddr; + UINT8 NewCurrentPathIndex; /* Path index to make current path. */ + UINT8 FailoverType; /* Reason for failover. */ + UINT32 Reserved[3]; + +} +FO_SET_CURRENT_PATH, *PFO_SET_CURRENT_PATH; + +typedef union _FO_PATHS { + FO_GET_PATHS input; + FO_SET_CURRENT_PATH set + ; + FO_PATHS_INFO info; +} FO_PATHS; + + +typedef struct _FO_HBA_STAT_INPUT +{ + /* The first field in the input buffer is specifically the + * same as the field in the output buffer. This is because the + * same system buffer holds both, and this allows us to reference + * the input buffer parameters while filling the output buffer. */ + + UINT8 HbaInstance; /* Port number or ADAPTER_ALL. */ + UINT8 Reserved1[3]; + UINT32 Reserved2[7]; + +} +FO_HBA_STAT_INPUT, *PFO_HBA_STAT_INPUT; + + +typedef struct _FO_HBA_STAT_ENTRY +{ + UINT8 HbaInstance; + UINT8 Reserved1[3]; + UINT32 Reserved2; + UINT64 IosRequested; /* IOs requested on this adapter. */ + UINT64 BytesRequested; /* Bytes requested on this adapter. */ + UINT64 IosExecuted; /* IOs executed on this adapter. */ + UINT64 BytesExecuted; /* Bytes executed on this adapter. */ + UINT32 Reserved3[22]; + +} +FO_HBA_STAT_ENTRY, *PFO_HBA_STAT_ENTRY; + + +typedef struct _FO_HBA_STAT_INFO +{ + /* The first fields in the output buffer is specifically the + * same as the field in the input buffer. This is because the + * same system buffer holds both, and this allows us to reference + * the input buffer parameters while filling the output buffer. */ + + UINT8 HbaInstance; /* Port number or ADAPTER_ALL. */ + UINT8 HbaCount; /* Count of adapters returned. */ + UINT8 Reserved1[2]; + UINT32 Reserved2[7]; + + FO_HBA_STAT_ENTRY StatEntry[FO_MAX_ADAPTERS]; + +} +FO_HBA_STAT_INFO, *PFO_HBA_STAT_INFO; + + + +/* The "external" LUN data refers to the LUNs as represented in our + configuration utility, where one physical target can support up to + 2048 LUNs, which are mapped around internally. This is in comparison + to an "internal" LUN data, which is 256 LUNs, after being mapped + inside the driver to multiple target slots. */ + +#define EXTERNAL_LUN_COUNT 2048 + +/* Structure as used in the IOCTL.*/ + +typedef struct _FO_EXTERNAL_LUN_DATA_ENTRY +{ + UINT8 NodeName[EXT_DEF_WWN_NAME_SIZE]; + UINT8 PortName[EXT_DEF_WWP_NAME_SIZE]; //sri + + UINT16 LunCount; /* Entries in Lun Data array. */ + UINT8 TargetId; + UINT8 Dev_No; + UINT32 Reserved3; + UINT32 Reserved4; + UINT32 Reserved5; /* Pad to 32-byte header.*/ + + UINT8 Data[EXTERNAL_LUN_COUNT]; +} +FO_EXTERNAL_LUN_DATA_ENTRY, *PFO_EXTERNAL_LUN_DATA_ENTRY; + +// Structure as it is stored in the NT registry. + +typedef struct _FO_LUN_DATA_LIST +{ + UINT16 Version; /* Should be LUN_DATA_REGISTRY_VERSION.*/ + UINT16 EntryCount; /* Count of variable entries following.*/ + UINT32 Reserved1; + UINT32 Reserved2; + UINT32 Reserved3; + UINT32 Reserved4; + UINT32 Reserved5; + UINT32 Reserved6; + UINT32 Reserved7; /* Pad to 32-byte header.*/ + + FO_EXTERNAL_LUN_DATA_ENTRY DataEntry[1]; /* Variable-length data.*/ + +} +FO_LUN_DATA_LIST, *PFO_LUN_DATA_LIST; + +typedef struct _FO_LUN_DATA_INPUT +{ + /* The first field in the input buffer is specifically the + * same as the field in the output buffer. This is because the + * same system buffer holds both, and this allows us to reference + * the input buffer parameters while filling the output buffer. */ + + UINT8 HbaInstance; /* Port number */ + UINT8 Reserved1[3]; + UINT32 Reserved2[7]; + +} +FO_LUN_DATA_INPUT, *PFO_LUN_DATA_INPUT; + +typedef struct _FO_REQUEST_ADDR +{ + UINT8 HbaInstance; + EXT_DEST_ADDR TargetAddr; + UINT32 Reserved[5]; + +} +FO_REQUEST_ADDR, *PFO_REQUEST_ADDR; + +typedef struct _FO_TARGET_DATA_INPUT +{ + UINT8 HbaInstance; /* Port number */ + UINT8 Reserved1[3]; + UINT32 Reserved2[7]; + +} +FO_TARGET_DATA_INPUT, *PFO_TARGET_DATA_INPUT; + +#define FO_INTERNAL_LUN_COUNT 256 +#define FO_INTERNAL_LUN_BITMASK_BYTES (FO_INTERNAL_LUN_COUNT / 8) + +typedef struct _FO_INTERNAL_LUN_BITMASK +{ + UINT8 Bitmask[FO_INTERNAL_LUN_BITMASK_BYTES]; +} +FO_INTERNAL_LUN_BITMASK, *PFO_INTERNAL_LUN_BITMASK; + +typedef struct _FO_DEVICE_DATA +{ + UINT32 DeviceFlags; /* Device flags */ + UINT16 LoopId; /* Current loop ID */ + UINT16 BaseLunNumber; /* Base LUN number */ + UINT8 WorldWideName[8]; /* World Wide Name for device */ + UINT8 PortId[3]; /* Port ID */ + UINT8 MultipathControl; /* Multipath control byte. */ + UINT16 DeviceState; /* Device state */ + UINT16 LoginRetryCount; /* Number of login retries */ + UINT8 PortName[8]; /* Port name for device */ + UINT16 TimeoutCount; /* Command timeout count */ + UINT8 TargetId; + UINT8 Dev_No; + FO_INTERNAL_LUN_BITMASK LunBitmask; /* LUN bitmask */ +} +FO_DEVICE_DATA, *PFO_DEVICE_DATA; + +typedef struct _FO_DEVICE_DATABASE +{ + FO_DEVICE_DATA DeviceData[256]; +} +FO_DEVICE_DATABASE, *PFO_DEVICE_DATABASE; + +typedef struct _FO_DRIVER_VERSION +{ + // Numeric version. + UINT8 Version; // Major version number. + UINT8 Revision; // Minor version number. + UINT8 Subrevision; // Subminor version number. + UINT8 Reserved1; // Memory alignment. + + // String version. + UINT8 VersionStr[FO_MAX_GEN_INFO_STRING_LEN]; + + // Reserved fields. + UINT32 Reserved2[16]; + +} +FO_DRIVER_VERSION, *PFO_DRIVER_VERSION; + + +#define FO_LUN_DATA_LIST_MIN_ENTRIES 1 +#define FO_LUN_DATA_LIST_MAX_ENTRIES 256 +#ifdef _WIN64 +#define FO_LUN_DATA_LIST_HEADER_SIZE 32 +#else +#define FO_LUN_DATA_LIST_HEADER_SIZE offsetof(FO_LUN_DATA_LIST, DataEntry) +#endif + +#define FO_LUN_DATA_LIST_MIN_SIZE (FO_LUN_DATA_LIST_HEADER_SIZE + (sizeof(FO_EXTERNAL_LUN_DATA_ENTRY) * FO_LUN_DATA_LIST_MIN_ENTRIES)) +#define FO_LUN_DATA_LIST_MAX_SIZE (FO_LUN_DATA_LIST_HEADER_SIZE + (sizeof(FO_EXTERNAL_LUN_DATA_ENTRY) * FO_LUN_DATA_LIST_MAX_ENTRIES)) + + +#endif /* ifndef _FO_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qlfolimits.h 830-ivtv/drivers/scsi/qla2xxx/qlfolimits.h --- 000-virgin/drivers/scsi/qla2xxx/qlfolimits.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qlfolimits.h Thu Jan 8 10:22:00 2004 @@ -0,0 +1,93 @@ +/****************************************************************************** + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + ******************************************************************************/ + +/* + * Minimums, maximums, defaults, and other definitions for MC_PARAMS. + */ + +#define FO_INSPECTION_INTERVAL_MIN 0 +#define FO_INSPECTION_INTERVAL_MAX 1000000 +#define FO_INSPECTION_INTERVAL_DEF 600 + +#define FO_MAX_PATHS_PER_DEVICE_MIN 1 +#define FO_MAX_PATHS_PER_DEVICE_MAX 8 +#define FO_MAX_PATHS_PER_DEVICE_DEF 8 + +#define FO_MAX_RETRIES_PER_PATH_MIN 1 +#define FO_MAX_RETRIES_PER_PATH_MAX 8 +#define FO_MAX_RETRIES_PER_PATH_DEF 3 + +#define FO_MAX_RETRIES_PER_IO_MIN ((FO_MAX_PATHS_PER_DEVICE_MIN * FO_MAX_RETRIES_PER_PATH_MIN) + 1) +#define FO_MAX_RETRIES_PER_IO_MAX ((FO_MAX_PATHS_PER_DEVICE_MAX * FO_MAX_RETRIES_PER_PATH_MAX) + 1) +#define FO_MAX_RETRIES_PER_IO_DEF ((FO_MAX_PATHS_PER_DEVICE_DEF * FO_MAX_RETRIES_PER_PATH_DEF) + 1) + +#define FO_DEVICE_ERROR_THRESHOLD_MIN 1 +#define FO_DEVICE_ERROR_THRESHOLD_MAX 255 +#define FO_DEVICE_ERROR_THRESHOLD_DEF 4 + +#define FO_DEVICE_TIMEOUT_THRESHOLD_MIN 1 +#define FO_DEVICE_TIMEOUT_THRESHOLD_MAX 255 +#define FO_DEVICE_TIMEOUT_THRESHOLD_DEF 4 + +#define FO_FRAME_ERROR_THRESHOLD_MIN 1 +#define FO_FRAME_ERROR_THRESHOLD_MAX 255 +#define FO_FRAME_ERROR_THRESHOLD_DEF 4 + +#define FO_LINK_ERROR_THRESHOLD_MIN 1 +#define FO_LINK_ERROR_THRESHOLD_MAX 255 +#define FO_LINK_ERROR_THRESHOLD_DEF 4 + +#define FO_ROLLING_AVERAGE_INTERVALS_MIN 1 +#define FO_ROLLING_AVERAGE_INTERVALS_MAX 10 +#define FO_ROLLING_AVERAGE_INTERVALS_DEF 1 + +#define FO_MAX_DEVICES_TO_MIGRATE_MIN 0 +#define FO_MAX_DEVICES_TO_MIGRATE_MAX 255 +#define FO_MAX_DEVICES_TO_MIGRATE_DEF 4 + +#define FO_BALANCE_METHOD_NONE 0 +#define FO_BALANCE_METHOD_IOS 1 +#define FO_BALANCE_METHOD_MBS 2 + +#define FO_BALANCE_METHOD_MIN FO_BALANCE_METHOD_NONE +#define FO_BALANCE_METHOD_MAX FO_BALANCE_METHOD_MBS +#define FO_BALANCE_METHOD_DEF FO_BALANCE_METHOD_IOS + +#define FO_LOAD_SHARE_MIN_PERCENTAGE_MIN 25 +#define FO_LOAD_SHARE_MIN_PERCENTAGE_MAX 99 +#define FO_LOAD_SHARE_MIN_PERCENTAGE_DEF 75 + +#define FO_LOAD_SHARE_MAX_PERCENTAGE_MIN 101 +#define FO_LOAD_SHARE_MAX_PERCENTAGE_MAX 500 +#define FO_LOAD_SHARE_MAX_PERCENTAGE_DEF 150 + +#define FO_NOTIFY_TYPE_NONE 0 +#define FO_NOTIFY_TYPE_LUN_RESET 1 +#define FO_NOTIFY_TYPE_CDB 2 +#define FO_NOTIFY_TYPE_LOGOUT_OR_LUN_RESET 3 +#define FO_NOTIFY_TYPE_LOGOUT_OR_CDB 4 +#define FO_NOTIFY_TYPE_SPINUP 5 + +#define FO_NOTIFY_TYPE_MIN FO_NOTIFY_TYPE_NONE +#define FO_NOTIFY_TYPE_MAX FO_NOTIFY_TYPE_LOGOUT_OR_CDB +#define FO_NOTIFY_TYPE_DEF FO_NOTIFY_TYPE_NONE + +#define FO_NOTIFY_CDB_LENGTH_MIN 6 +#define FO_NOTIFY_CDB_LENGTH_MAX 16 + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/qlfoln.h 830-ivtv/drivers/scsi/qla2xxx/qlfoln.h --- 000-virgin/drivers/scsi/qla2xxx/qlfoln.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/qlfoln.h Thu Jan 8 10:22:00 2004 @@ -0,0 +1,76 @@ +/****************************************************************************** + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP2x00 device driver for Linux 2.6.x + * Copyright (C) 2003 QLogic Corporation + * (www.qlogic.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + ******************************************************************************/ + + +#define QLMULTIPATH_MAGIC 'y' +/********************************************************/ +/* Failover ioctl command codes range from 0xc0 to 0xdf */ +/********************************************************/ + + +#define FO_CC_GET_PARAMS_OS \ + _IOWR_BAD(QLMULTIPATH_MAGIC, 200, sizeof(EXT_IOCTL)) /* 0xc8 */ +#define FO_CC_SET_PARAMS_OS \ + _IOWR_BAD(QLMULTIPATH_MAGIC, 201, sizeof(EXT_IOCTL)) /* 0xc9 */ +#define FO_CC_GET_PATHS_OS \ + _IOWR_BAD(QLMULTIPATH_MAGIC, 202, sizeof(EXT_IOCTL)) /* 0xca */ +#define FO_CC_SET_CURRENT_PATH_OS \ + _IOWR_BAD(QLMULTIPATH_MAGIC, 203, sizeof(EXT_IOCTL)) /* 0xcb */ +#define FO_CC_GET_HBA_STAT_OS \ + _IOWR_BAD(QLMULTIPATH_MAGIC, 204, sizeof(EXT_IOCTL)) /* 0xcc */ +#define FO_CC_RESET_HBA_STAT_OS \ + _IOWR_BAD(QLMULTIPATH_MAGIC, 205, sizeof(EXT_IOCTL)) /* 0xcd */ +#define FO_CC_GET_LUN_DATA_OS \ + _IOWR_BAD(QLMULTIPATH_MAGIC, 206, sizeof(EXT_IOCTL)) /* 0xce */ +#define FO_CC_SET_LUN_DATA_OS \ + _IOWR_BAD(QLMULTIPATH_MAGIC, 207, sizeof(EXT_IOCTL)) /* 0xcf */ +#define FO_CC_GET_TARGET_DATA_OS \ + _IOWR_BAD(QLMULTIPATH_MAGIC, 208, sizeof(EXT_IOCTL)) /* 0xd0 */ +#define FO_CC_SET_TARGET_DATA_OS \ + _IOWR_BAD(QLMULTIPATH_MAGIC, 209, sizeof(EXT_IOCTL)) /* 0xd1 */ +#define FO_CC_GET_FO_DRIVER_VERSION_OS \ + _IOWR_BAD(QLMULTIPATH_MAGIC, 210, sizeof(EXT_IOCTL)) /* 0xd2 */ + + +#define BOOLEAN uint8_t +#define MAX_LUNS_OS 256 + +/* Driver attributes bits */ +#define DRVR_FO_ENABLED 0x1 /* bit 0 */ + + +/* + * Overrides for Emacs so that we almost follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 2 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -2 + * c-argdecl-indent: 2 + * c-label-offset: -2 + * c-continued-statement-offset: 2 + * c-continued-brace-offset: 0 + * indent-tabs-mode: nil + * tab-width: 8 + * End: + */ + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/qla2xxx/revision.notes 830-ivtv/drivers/scsi/qla2xxx/revision.notes --- 000-virgin/drivers/scsi/qla2xxx/revision.notes Wed Dec 31 16:00:00 1969 +++ 830-ivtv/drivers/scsi/qla2xxx/revision.notes Thu Jan 8 10:22:00 2004 @@ -0,0 +1,457 @@ +/* + * QLogic ISP2200 and ISP2300 Linux Driver Revision List File. + * + ******************************************************************** + * + * Revision History + * + * Rev 8.00.00b8 December 5, 2003 AV + * - Instruct mid-layer to perform initial scan. + * + * Rev 8.00.00b7 December 5, 2003 AV + * - Resync with Linux Kernel 2.6.0-test11. + * - Add basic NVRAM parser (extras/qla_nvr). + * + * Rev 8.00.00b7-pre11 December 3, 2003 AV + * - Sanitize the scsi_qla_host structure: + * - Purge unused elements. + * - Reorganize high-priority members (cache coherency). + * - Add support for NVRAM access via a sysfs binary attribute: + * - Consolidate semaphore locking access. + * - Fix more PCI posting issues. + * - Add extras directory for dump/NVRAM tools. + * - Remove unused qla_vendor.c file. + * + * Rev 8.00.00b7-pre11 November 26, 2003 DG/AV + * - Merge several patches from Christoph Hellwig [hch@lst.de]: + * - in Linux 2.6 both pci and the scsi layer use the generic + * dma direction bits, use them directly instead of the scsi + * and pci variants and the (noop) conversion routines. + * - Fix _IOXX_BAD() usage for external IOCTL interface. + * - Use atomic construct for HA loop_state member. + * - Add generic model description text for HBA types. + * + * Rev 8.00.00b7-pre5 November 17, 2003 AV + * - Merge several patches from Christoph Hellwig [hch@lst.de]: + * - patch to split the driver into a common qla2xxx.ko and a + * qla2?00.ko for each HBA type - the latter modules are + * only very small wrappers, mostly for the firmware + * images, all the meat is in the common qla2xxx.ko. + * - make the failover code optional. + * - kill useless lock_kernel in dpc thread startup. + * - no need for modversions hacks in 2.6 (or 2.4). + * - kill qla2x00_register_with_Linux. + * - simplify EH code, cmd or it's hostdata can't be NULL, no + * need to search whether the host it's ours, the midlayer + * makes sure it won't call into a driver for some else + * host. + * - Merge several patches from Jes Sorensen + * [jes@wildopensource.com]: + * - Call qla2x00_config_dma_addressing() before performing + * any consistent allocations. This is required since the + * dma mask settings will affect the memory + * pci_alloc_consistent() will return. + * - Call pci_set_consistent_dma_mask() to allow for 64 bit + * consistent allocations, required on some platforms such + * as the SN2. + * - Wait 20 usecs (not sure how long is really necessary, + * but this seems safe) after setting CSR_ISP_SOFT_RESET in + * the ctrl_status register as the card doesn't respond to + * PCI reads while in reset state. This causes a machine + * check on some architectures. + * - Flush PCI writes before calling udelay() to ensure the + * write is not sitting idle in-flight for a while before + * hitting the hardware. + * - Include linux/vmalloc.h in qla_os.c since it uses + * vmalloc(). + * - Use auto-negotiate link speed when using default + * parameters rather than NVRAM settings. Disable NVRAM + * reading on SN2 since it's not possible to execute the + * HBA's BIOS on an SN2. I suggest doing something similar + * for all architectures that do not provide x86 BIOS + * emulation. + * - Clean-up slab-cache allocations: + * - locking. + * - mempool allocations in case of low-memory situations. + * - Fallback to GA_NXT scan if GID_PT call returns more than + * MAX_FIBRE_DEVICES. + * - Preserve iterating port ID across GA_NXT calls in + * qla2x00_find_all_fabric_devs(). + * - Pre-calculate ASCII firmware dump length as to not incur the + * cost-to-calculate at each invocation of a read(). + * + * Rev 8.00.00b6 November 4, 2003 AV + * - Add new 2300 TPX firmware (3.02.18). + * + * Rev 8.00.00b6-pre25 October 20, 2003 RA/AV + * - Resync with Linux Kernel 2.6.0-test9. + * - Rework firmware dump process: + * - Use binary attribute within sysfs tree. + * - Add user-space tool (gdump.sh) to retrieve formatted + * buffer. + * - Add ISP2100 support. + * - Use a slab cache for SRB allocations to reduce memory + * pressure. + * - Initial conversion of driver logging methods to a new + * qla_printk() function which uses dev_printk (Daniel + * Stekloff, IBM). + * - Further reduce stack usage in qla2x00_configure_local_loop() + * and qla2x00_find_all_fabric_devs(). + * - Separate port state used for routing of I/O's from port + * mgmt-login retry etc. + * + * Rev 8.00.00b6-pre19 October 13, 2003 AV + * - Resync with Linux Kernel 2.6.0-test7-bk5. + * - Add intelligent RSCN event handling: + * - reduce scan time during 'port' RSCN events by only + * querying specified port ids. + * - Available on ISP23xx cards only. + * - Increase maximum number of recognizable targets from 256 + * to 512. + * - Backend changes were previously added to support TPX + * (2K logins) firmware. Mid-layer can now scan for targets + * (H, B, T, L) where 512 < T >= 0. + * - Remove IP support from driver. + * - Switch firmware types from IP->TP for ISP22xx and + * IPX->TPX for ISP23xx cards. + * - Remove files qla_ip.[ch]. + * - Remove type designations from firmware filenames. + * + * Rev 8.00.00b6-pre11 September 15, 2003 DG/AV + * - Resync with 6.06.00. + * - Resync with Linux Kernel 2.6.0-test5-bk3. + * - Add new 2300 IPX firmware (3.02.15). + * + * Rev 8.00.00b5 July 31, 2003 AV + * - Always create an fc_lun_t entry for lun 0 - as the mid- + * layer requires access to this lun for discovery to occur. + * - General sanitizing: + * - Add generic firmware option definitions. + * - Generalize retrieval/update of firmware options. + * - Fix compile errors which occur with extended debug. + * - Handle failure cases for scsi_add_host() and + * down_interruptible(). + * - Host template updates: + * - Use standard bios_param callback function. + * - Disable clustering. + * - Remove unchecked_is_dma entry. + * + * Rev 8.00.00b5-pre5 July 29, 2003 DG/AV + * - Resync with 6.06.00b13. + * - Resync with Linux Kernel 2.6.0-test2. + * - Pass the complete loop_id, not the masked (0xff) value + * while issuing mailbox commands (qla_mbx.c/qla_fo.c/ + * qla_iocb.c/qla_init.c). + * - Properly handle zero-length return status for an RLC CDB. + * - Create an fclun_t structure for 'disconnected' luns, + * peripheral-qualifier of 001b. + * - Remove unused LIP-sequence register access during AE 8010. + * - Generalize qla2x00_mark_device_lost() to handle forced + * login request -- modify all direct/indirect invocations + * with proper flag. + * - Save RSCN notification (AE 8015h) data in a proper and + * consistent format (domain, area, al_pa). + * - General sanitizing: + * - scsi_qla_host structure member reordering for cache-line + * coherency. + * - Remove unused SCSI opcodes, endian-swap definitions. + * - Remove CMD_* pre-processor defines. + * - Remove unused SCSIFCHOTSWAP/GAMAP/MULTIHOST codes. + * - Backout patch which added a per-scsi_qla_host scsi host + * spinlock, since mid-layer already defines one. + * - Add new 2300 IPX firmware (3.02.15). + * + * Rev 8.00.00b4 July 14, 2003 RA/DG/AV + * - Resync with 6.06.00b12. + * - Resync with Linux Kernel 2.6.0-test1. + * - Remove IOCB throttling code -- originally #if'd. + * - Remove apidev_*() routines since proc_mknod() has been + * removed -- need alternate IOCTL interface. + * - Merge several performance/fix patches from Arjan van de + * Ven: + * - Undefined operation >> 32. + * - No need to acquire mid-layer lock during command + * callback. + * - Use a per-HBA mid-layer lock. + * - Use a non-locked cycle for setting the count of the + * newly allocated sp (qla2x00_get_new_sp()). + * - Modify semantic behavior of qla2x00_queuecommand(): + * - Reduce cacheline bouncing by having I/Os submitted + * by the IRQ handler. + * - Remove extraneous calls to qla2x00_next() during I/O + * queuing. + * - Use list_splice_init() during qla2x00_done() handling + * of commands to reduce list_lock contention. + * - RIO mode support for ISP2200: + * - Implementation differs slightly from original patch. + * - Do not use bottom-half handler (tasklet/work queue) + * for qla2x00_done() processing. + * + * Rev 8.00.00b4-pre22 July 12, 2003 AV + * - Check for 'Process Response Queue' requests early during + * the Host Status check. + * - General sanitizing: + * - srb_t structure rewrite, removal of unused members. + * - Remove unused fcdev array, fabricid, and PORT_* + * definitions. + * - Remove unused config_reg_t PCI definitions. + * - Add new 2200 IP firmware (2.02.06). + * - Add new 2300 IPX firmware (3.02.14). + * + * Rev 8.00.00b4-pre19 June 30, 2003 AV + * - Resync with Linux Kernel 2.5.73-bk8. + * - Rework IOCB command queuing methods: + * - Upper-layer driver *MUST* properly set the direction + * bit of SCSI commands. + * - Generalize 32bit/64bit queuing path functions. + * - Remove costly page-boundary cross check when using + * 64bit address capable IOCBs. + * + * Rev 8.00.00b4-pre15 June 19, 2003 AV + * - Resync with 6.06.00b11. + * - Continue fcport list consolidation work: + * - Updated IOCTL implementations to use new fcports + * list. + * - Modified product ID check to not verify ISP chip + * revision -- ISP2312 v3 (qla2x00_chip_diag()). + * - Add new 2300 IPX firmware (3.02.13): + * + * Rev 8.00.00b4-pre13 June 19, 2003 AV + * - Fix build process for qla2100 driver -- no support + * for IP. + * - SCSI host template modifications: + * - Set sg_tablesize based on the derived DMA mask. + * - Increase max_sectors since only limit within RISC + * is transfer of (((2^32) - 1) >> 9) sectors. + * + * Rev 8.00.00b4-pre12 June 18, 2003 RA, DG, RL, AV + * - Resync with 6.06.00b10. + * - Resync with Linux Kernel 2.5.72. + * - Initial fcport list consolidation work: + * - fcports/fcinitiators/fcdev/fc_ip --> ha->fcports + * list. + * + * Rev 8.00.00b4-pre7 June 05, 2003 AV + * - Properly release PCI resouces in init-failure case. + * - Reconcile disparite function return code definitions. + * + * Rev 8.00.00b4-pre4 June 03, 2003 AV + * - Resync with Linux Kernel 2.5.70-bk8: + * - SHT proc_info() changes. + * - Restructure SNS Generic Services routines: + * - Add qla_gs.c file to driver distribution. + * - Configure PCI latency timer for ISP23xx. + * + * Rev 8.00.00b4-pre3 June 02, 2003 RA, DG, RL, AV + * - Resync with 6.06.00b5. + * - Rework (again) PCI I/O space configuration + * (Anton Blanchard): + * - Use pci_set_mwi() routine; + * - Remove uneeded qla2x00_set_cache_line() function. + * - Remove extraneous modification of PCI_COMMAND word. + * + * Rev 8.00.00b3 May 29, 2003 AV + * - Resync with Linux Kernel 2.5.70. + * - Move RISC paused check from ISR fast-path. + * + * Rev 8.00.00b3-pre8 May 26, 2003 AV + * - Add new 2300 IPX firmware (3.02.12): + * - Rework PCI I/O space configuration. + * + * Rev 8.00.00b3-pre6 May 22, 2003 RA, DG, RL, AV + * - Resync with 6.06.00b3. + * + * Rev 8.00.00b3-pre4 May 21 2003 AV + * - Add new 2300 IPX firmware (3.02.11): + * - Remove 2300 TPX firmware from distribution. + * + * Rev 8.00.00b3-pre3 May 21 2003 AV + * - Properly setup PCI configuation space during + * initialization: + * - Properly configure Memory-Mapped I/O during early + * configuration stage. + * - Rework IP functionality to support 2k logins. + * - Add new 2300 IPX firmware (3.02.11): + * - Remove 2300 TPX firmware from distribution. + * + * Rev 8.00.00b3-pre2 May ??, 2003 RA, DG, RL, AV + * - Resync with 6.06.00b1. + * + * Rev 8.00.00b3-pre1 May ??, 2003 RA, DG, RL, AV + * - Resync with 6.05.00. + * + * Rev 8.00.00b2 May 19, 2003 AV + * - Simplify dma_addr_t handling during command queuing given + * new block-layer defined restrictions: + * - Physical addresses not spanning 4GB boundaries. + * - Firmware versions: 2100 TP (1.19.24), 2200 IP (2.02.05), + * 2300 TPX (3.02.10). + * + * Rev 8.00.00b2-pre1 May 13, 2003 AV + * - Add support for new 'Hotplug initialization' model. + * - Simplify host template by removing unused callbacks. + * - Use scsicam facilities to determine geometry. + * - Fix compilation issues for non-ISP23xx builds: + * - Correct register references in qla_dbg.c. + * - Correct Makefile build process. + * + * Rev 8.00.00b1 May 05, 2003 AV + * - Resync with Linux Kernel 2.5.69. + * - Firmware versions: 2100 TP (1.19.24), 2200 TP (2.02.05), + * 2300 TPX (3.02.10). + * + * Rev 8.00.00b1-pre45 April ??, 2003 AV + * - Resync with Linux Kernel 2.5.68-bk11: + * - Fix improper return-code assignment during fabric + * discovery. + * - Remove additional extraneous #defines from + * qla_settings.h. + * - USE_PORTNAME -- FO will always use portname. + * - Default queue depth size set to 64. + * + * Rev 8.00.00b1-pre42 April ??, 2003 AV + * - Convert bottom-half tasklet to a work_queue. + * - Initial basic coding of dynamic queue depth handling + * during QUEUE FULL statuses. + * - Fix mailbox interface problem with + * qla2x00_get_retry_cnt(). + * + * Rev 8.00.00b1-pre41 April ??, 2003 AV + * - Convert build defines qla2[1|2|3]00 macros to + * qla2[1|2|3]xx due to module name stringification clashes. + * - Add additional ISP2322 checks during board configuration. + * + * Rev 8.00.00b1-pre40 April ??, 2003 AV + * - Resync with Linux Kernel 2.5.68-bk8: + * - Updated IRQ handler interface. + * - Add ISP dump code (stub) in case of SYSTEM_ERROR on + * ISP2100. + * - Add new 2200 IP firmware (2.02.05). + * + * Rev 8.00.00b1-pre39 April ??, 2003 AV + * - Resync with Linux Kernel 2.5.68. + * - Add simple build.sh script to aid in external compilation. + * - Clean-break with Kernel 2.4 compatibility. + * - Rework DPC routine -- completion routines for signaling. + * - Re-add HBAAPI character device node for IOCTL support. + * - Remove residual QLA2X_PERFORMANCE defines. + * - Allocate SP pool via __get_free_pages() rather than + * individual kmalloc()'s. + * - Inform SCSI mid-layer of 16-byte CDB support + * (host->max_cmd_len): + * - Remove unecessary 'more_cdb' handling code from + * qla_iocb.c and qla_xioct.c. + * - Reduce duplicate code in fabric scanning logic (MS IOCB + * preparation). + * - Add ISP dump code in case of SYSTEM_ERROR. + * - Remove 2300 VIX firmware from distribution: + * - Add initial code for IPX support. + * - Add new 2300 TPX firmware (3.02.10). + * + * Rev 8.00.00b1-pre34 April ??, 2003 AV + * - Resync with Linux Kernel 2.5.67. + * - Use domain/area/al_pa fields when displaying PortID + * values -- addresses endianess issues. + * - Rework large case statement to check 'common' CDB commands + * early in qla2x00_get_cmd_direction(). + * + * Rev 8.00.00b1-pre31 April ??, 2003 AV + * - Update makefile to support PPC64 build. + * - Retool NVRAM configuration routine and structures: + * - Consoldate ISP21xx/ISP22xx/ISP23xx configuration + * (struct nvram_t). + * - Remove big/little endian support structures in favor of + * simplified bit-operations within byte fields. + * - Fix long-standing 'static' buffer sharing problem in + * qla2x00_configure_fabric(). + * + * Rev 8.00.00b1-pre30 April ??, 2003 AV + * - Complete implementation of GID_PT scan. + * - Use consistent MS IOCB invocation method to query SNS: + * - Add RNN_ID and RSNN_NN registrations in a fabric. + * - Remove unused Mailbox Command 6Eh (Send SNS) support + * structures. + * - Use 64bit safe IOCBs while issuing INQUIRY and RLC during + * topology scan. + * - Until reimplementation of fcdev_t/fcport list + * consolidation, valid loop_id ranges are still limited from + * 0x00 through 0xFF -- enforce this within the code. + * + * Rev 8.00.00b1-pre27 March ??, 2003 AV + * - Resync with 6.05.00b9. + * - Retool HBA PCI configuration -- qla2x00_pci_config(). + * - Remove inconsistent use of delay routines (UDELAY/SYS*). + * - Continue to teardown/clean/add comments and debug + * routines. + * - Properly swap bytes of the device's nodename in + * qla2x00_configure_local_loop(). + * + * Rev 8.00.00b1-pre25 March ??, 2003 AV + * - Resync with 6.05.00b8. + * + * Rev 8.00.00b1-pre23 March ??, 2003 AV + * - Remove (#define) IOCB usage throttling. + * - Abstract interrupt polling with qla2x00_poll(). + * - Modify lun scanning logic: + * - If the device does not support the SCSI Report Luns + * command, the driver will now only scan from 0 to the + * max#-luns as defined in the NVRAM (BIOS), rather than + * blindly scanning from 0 to 255 -- which could result in + * an increase in startup time when running against slow + * (JBOD) devices. + * - Rework reset logic in qla2x00_reset_chip() (spec). + * + * Rev 8.00.00b1-pre22 March ??, 2003 AV + * - Resync with 6.05.00b7. + * - Cleanup (rewrite) ISR handler. + * - Rename kmem_zalloc --> qla2x00_kmem_zalloc(): + * - This function will eventually be removed. + * - Add new 2300 VIX firmware (3.02.09): + * - Support for Tape, Fabric, 2K logins, IP, and VI. + * + * Rev 8.00.00b1-pre18 March ??, 2003 AV + * - Support 232x type ISPs. + * - Support single firmware for each ISP type: + * - Restructure brd_info/fw_info methods. + * - Streamline firmware load process. + * - Properly query firmware for version information. + * - Remove extraneous scsi_qla_host members: + * - device_id ==> pdev->device + * - Fix fc4 features (RFF_ID) registration. + * - Convert kmem_zalloc --> qla2x00_kmem_zalloc(). + * - Remove unused/extraneous #defines (USE_PORTNAME). + * + * Rev 8.00.00b1-pre14 March ??, 2003 AV + * - Resync with 6.05.00b6. + * - Initial source-code restructuring effort. + * - Build procedure. + * - Source file layout -- intuitive component layout. + * - Remove unused #defines (*PERFORMANCE, WORD_FW_LOAD, etc). + * - Add support for 2K logins (TPX -- firmware). + * - Add module parameter ql2xsuspendcount. + * - Add new 2200 IP/TP firmware (2.02.04). + * + * Rev 8.00.00b1-pre9 March ??, 2003 RL/DG/RA/AV + * - Use kernel struct list_head for fcport and fclun lists. + * - Remove extraneous (L|M)S_64BITS() and QL21_64*() defines. + * + * Rev 8.00.00b1-pre8 February 28, 2003 RL/DG/RA/AV + * - Resync with 6.05.00b3. + * + * Rev 8.00.00b1-pre7 February 23, 2003 RL/DG/RA/AV + * - Add alternate fabric scanning logic (GID_PT/GNN_ID/GPN_ID). + * - Remove use of deprecated function check_region(). + * - Add new 2300 IP/TP firmware (3.02.08). + * + * Rev 8.00.00b1-pre5 January 28, 2003 RL/DG/RA/AV + * - Resync with 6.05.00b3. + * - Consolidate device_reg structure definitions for ISP types. + * - Add support for new queue-depth selection. + * - Add new 2300 IP/TP firmware (3.02.07). + * + * Rev 8.00.00b1-pre1 January 17, 2003 AV + * - Initial branch from 6.04.00b8 driver. + * - Remove VMWARE specific code. + * - Add support for pci_driver interface. + * + ********************************************************************/ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/scsi/sd.c 830-ivtv/drivers/scsi/sd.c --- 000-virgin/drivers/scsi/sd.c Mon Nov 17 18:29:48 2003 +++ 830-ivtv/drivers/scsi/sd.c Thu Jan 8 09:31:06 2004 @@ -62,6 +62,7 @@ */ #define SD_MAJORS 16 #define SD_DISKS (SD_MAJORS << 4) +#define TOTAL_SD_DISKS CONFIG_MAX_SD_DISKS /* * Time out in seconds for disks and Magneto-opticals (which are slower). @@ -95,7 +96,7 @@ struct scsi_disk { }; -static unsigned long sd_index_bits[SD_DISKS / BITS_PER_LONG]; +static unsigned long sd_index_bits[TOTAL_SD_DISKS / BITS_PER_LONG]; static spinlock_t sd_index_lock = SPIN_LOCK_UNLOCKED; static int sd_revalidate_disk(struct gendisk *disk); @@ -130,6 +131,9 @@ static int sd_major(int major_idx) return SCSI_DISK1_MAJOR + major_idx - 1; case 8 ... 15: return SCSI_DISK8_MAJOR + major_idx - 8; +#define MAX_IDX (TOTAL_SD_DISKS >> 4) + case 16 ... MAX_IDX: + return SCSI_DISK15_MAJOR; default: BUG(); return 0; /* shut up gcc */ @@ -1320,8 +1324,8 @@ static int sd_probe(struct device *dev) goto out_free; spin_lock(&sd_index_lock); - index = find_first_zero_bit(sd_index_bits, SD_DISKS); - if (index == SD_DISKS) { + index = find_first_zero_bit(sd_index_bits, TOTAL_SD_DISKS); + if (index == TOTAL_SD_DISKS) { spin_unlock(&sd_index_lock); error = -EBUSY; goto out_put; @@ -1336,15 +1340,24 @@ static int sd_probe(struct device *dev) sdkp->openers = 0; gd->major = sd_major(index >> 4); - gd->first_minor = (index & 15) << 4; + if (index > SD_DISKS) + gd->first_minor = ((index - SD_DISKS) & 15) << 4; + else + gd->first_minor = (index & 15) << 4; gd->minors = 16; gd->fops = &sd_fops; - if (index >= 26) { + if (index < 26) { + sprintf(gd->disk_name, "sd%c", 'a' + index % 26); + } else if (index < (26*27)) { sprintf(gd->disk_name, "sd%c%c", 'a' + index/26-1,'a' + index % 26); } else { - sprintf(gd->disk_name, "sd%c", 'a' + index % 26); + const unsigned int m1 = (index/ 26 - 1) / 26 - 1; + const unsigned int m2 = (index / 26 - 1) % 26; + const unsigned int m3 = index % 26; + sprintf(gd->disk_name, "sd%c%c%c", + 'a' + m1, 'a' + m2, 'a' + m3); } strcpy(gd->devfs_name, sdp->devfs_name); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/serial/8250.c 830-ivtv/drivers/serial/8250.c --- 000-virgin/drivers/serial/8250.c Thu Jan 8 08:35:45 2004 +++ 830-ivtv/drivers/serial/8250.c Thu Jan 8 09:30:15 2004 @@ -837,7 +837,7 @@ receive_chars(struct uart_8250_port *up, if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) { tty->flip.work.func((void *)tty); if (tty->flip.count >= TTY_FLIPBUF_SIZE) - return; // if TTY_DONT_FLIP is set + return; /* if TTY_DONT_FLIP is set */ } ch = serial_inp(up, UART_RX); *tty->flip.char_buf_ptr = ch; @@ -1198,12 +1198,21 @@ static void serial8250_break_ctl(struct spin_unlock_irqrestore(&up->port.lock, flags); } +#ifdef CONFIG_KGDB +static int kgdb_irq = -1; +#endif + static int serial8250_startup(struct uart_port *port) { struct uart_8250_port *up = (struct uart_8250_port *)port; unsigned long flags; int retval; +#ifdef CONFIG_KGDB + if (up->port.irq == kgdb_irq) + return -EBUSY; +#endif + up->capabilities = uart_config[up->port.type].flags; if (up->port.type == PORT_16C950) { @@ -1869,6 +1878,10 @@ static void __init serial8250_register_p for (i = 0; i < UART_NR; i++) { struct uart_8250_port *up = &serial8250_ports[i]; +#ifdef CONFIG_KGDB + if (up->port.irq == kgdb_irq) + up->port.kgdb = 1; +#endif up->port.line = i; up->port.ops = &serial8250_pops; init_timer(&up->timer); @@ -2137,6 +2150,31 @@ void serial8250_resume_port(int line) { uart_resume_port(&serial8250_reg, &serial8250_ports[line].port); } + +#ifdef CONFIG_KGDB +/* + * Find all the ports using the given irq and shut them down. + * Result should be that the irq will be released. + */ +void shutdown_for_kgdb(struct async_struct * info) +{ + int irq = info->state->irq; + struct uart_8250_port *up; + int ttyS; + + kgdb_irq = irq; /* save for later init */ + for (ttyS = 0; ttyS < UART_NR; ttyS++){ + up = &serial8250_ports[ttyS]; + if (up->port.irq == irq && (irq_lists + irq)->head) { +#ifdef CONFIG_DEBUG_SPINLOCK /* ugly business... */ + if(up->port.lock.magic != SPINLOCK_MAGIC) + spin_lock_init(&up->port.lock); +#endif + serial8250_shutdown(&up->port); + } + } +} +#endif /* CONFIG_KGDB */ static int __init serial8250_init(void) { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/serial/serial_core.c 830-ivtv/drivers/serial/serial_core.c --- 000-virgin/drivers/serial/serial_core.c Thu Jan 8 08:35:45 2004 +++ 830-ivtv/drivers/serial/serial_core.c Thu Jan 8 09:30:15 2004 @@ -1978,6 +1978,11 @@ uart_configure_port(struct uart_driver * { unsigned int flags; +#ifdef CONFIG_KGDB + if (port->kgdb) + return; +#endif + /* * If there isn't a port here, don't do anything further. */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/drivers/usb/gadget/ether.c 830-ivtv/drivers/usb/gadget/ether.c --- 000-virgin/drivers/usb/gadget/ether.c Thu Jan 8 08:35:45 2004 +++ 830-ivtv/drivers/usb/gadget/ether.c Thu Jan 8 08:54:31 2004 @@ -1782,9 +1782,7 @@ eth_bind (struct usb_gadget *gadget) /* network device setup */ dev->net = net; SET_MODULE_OWNER (net); - net->priv = dev; strcpy (net->name, "usb%d"); - ether_setup (net); /* one random address for the gadget device ... both of these could * reasonably come from an id prom or a module parameter. diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/fs/aio.c 830-ivtv/fs/aio.c --- 000-virgin/fs/aio.c Mon Dec 8 09:55:52 2003 +++ 830-ivtv/fs/aio.c Thu Jan 8 10:26:46 2004 @@ -203,6 +203,7 @@ static struct kioctx *ioctx_alloc(unsign { struct mm_struct *mm; struct kioctx *ctx; + int ret = 0; /* Prevent overflows */ if ((nr_events > (0x10000000U / sizeof(struct io_event))) || @@ -232,7 +233,8 @@ static struct kioctx *ioctx_alloc(unsign INIT_LIST_HEAD(&ctx->run_list); INIT_WORK(&ctx->wq, aio_kick_handler, ctx); - if (aio_setup_ring(ctx) < 0) + ret = aio_setup_ring(ctx); + if (unlikely(ret < 0)) goto out_freectx; /* limit the number of system wide aios */ @@ -259,7 +261,7 @@ out_cleanup: out_freectx: mmdrop(mm); kmem_cache_free(kioctx_cachep, ctx); - ctx = ERR_PTR(-ENOMEM); + ctx = ERR_PTR(ret); dprintk("aio: error allocating ioctx %p\n", ctx); return ctx; @@ -541,7 +543,7 @@ struct kioctx *lookup_ioctx(unsigned lon return ioctx; } -static void use_mm(struct mm_struct *mm) +void use_mm(struct mm_struct *mm) { struct mm_struct *active_mm = current->active_mm; atomic_inc(&mm->mm_count); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/fs/binfmt_aout.c 830-ivtv/fs/binfmt_aout.c --- 000-virgin/fs/binfmt_aout.c Mon Nov 17 18:28:55 2003 +++ 830-ivtv/fs/binfmt_aout.c Thu Jan 8 10:21:12 2004 @@ -309,7 +309,7 @@ static int load_aout_binary(struct linux (current->mm->start_brk = N_BSSADDR(ex)); current->mm->free_area_cache = TASK_UNMAPPED_BASE; - current->mm->rss = 0; + zero_rss(current->mm); current->mm->mmap = NULL; compute_creds(bprm); current->flags &= ~PF_FORKNOEXEC; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/fs/binfmt_elf.c 830-ivtv/fs/binfmt_elf.c --- 000-virgin/fs/binfmt_elf.c Thu Jan 8 08:35:48 2004 +++ 830-ivtv/fs/binfmt_elf.c Thu Jan 8 10:22:24 2004 @@ -7,6 +7,7 @@ * Tools". * * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com). + * Top-down vma allocation support, William Irwin, IBM, 2003 */ #include @@ -333,8 +334,13 @@ static unsigned long load_elf_interp(str if (retval < 0) goto out_close; +#ifndef CONFIG_MMAP_TOPDOWN eppnt = elf_phdata; for (i=0; ie_phnum; i++, eppnt++) { +#else + eppnt = &elf_phdata[interp_elf_ex->e_phnum - 1]; + for (i = interp_elf_ex->e_phnum - 1; i >= 0; --i, --eppnt) { +#endif if (eppnt->p_type == PT_LOAD) { int elf_type = MAP_PRIVATE | MAP_DENYWRITE; int elf_prot = 0; @@ -348,7 +354,8 @@ static unsigned long load_elf_interp(str if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) elf_type |= MAP_FIXED; - map_addr = elf_map(interpreter, load_addr + vaddr, eppnt, elf_prot, elf_type); + map_addr = load_addr_set ? load_addr + vaddr : 0; + map_addr = elf_map(interpreter, map_addr, eppnt, elf_prot, elf_type); if (BAD_ADDR(map_addr)) goto out_close; @@ -670,7 +677,7 @@ static int load_elf_binary(struct linux_ /* Do this so that we can load the interpreter, if need be. We will change some of these later */ - current->mm->rss = 0; + zero_rss(current->mm); current->mm->free_area_cache = TASK_UNMAPPED_BASE; retval = setup_arg_pages(bprm); if (retval < 0) { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/fs/binfmt_flat.c 830-ivtv/fs/binfmt_flat.c --- 000-virgin/fs/binfmt_flat.c Wed Aug 13 20:24:28 2003 +++ 830-ivtv/fs/binfmt_flat.c Thu Jan 8 10:21:12 2004 @@ -643,7 +643,7 @@ static int load_flat_file(struct linux_b current->mm->start_brk = datapos + data_len + bss_len; current->mm->brk = (current->mm->start_brk + 3) & ~3; current->mm->context.end_brk = memp + ksize((void *) memp) - stack_len; - current->mm->rss = 0; + zero_rss(current->mm); } if (flags & FLAT_FLAG_KTRACE) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/fs/binfmt_som.c 830-ivtv/fs/binfmt_som.c --- 000-virgin/fs/binfmt_som.c Thu Jan 8 08:35:48 2004 +++ 830-ivtv/fs/binfmt_som.c Thu Jan 8 10:21:12 2004 @@ -259,7 +259,7 @@ load_som_binary(struct linux_binprm * bp create_som_tables(bprm); current->mm->start_stack = bprm->p; - current->mm->rss = 0; + zero_rss(current->mm); #if 0 printk("(start_brk) %08lx\n" , (unsigned long) current->mm->start_brk); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/fs/exec.c 830-ivtv/fs/exec.c --- 000-virgin/fs/exec.c Thu Jan 8 08:35:48 2004 +++ 830-ivtv/fs/exec.c Thu Jan 8 10:21:12 2004 @@ -323,10 +323,11 @@ void put_dirty_page(struct task_struct * } lru_cache_add_active(page); flush_dcache_page(page); + SetPageAnon(page); set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(page, prot)))); pte_chain = page_add_rmap(page, pte, pte_chain); pte_unmap(pte); - tsk->mm->rss++; + inc_rss(tsk->mm, page); spin_unlock(&tsk->mm->page_table_lock); /* no need for flush_tlb */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/fs/fcntl.c 830-ivtv/fs/fcntl.c --- 000-virgin/fs/fcntl.c Mon Nov 17 18:29:32 2003 +++ 830-ivtv/fs/fcntl.c Thu Jan 8 10:26:32 2004 @@ -537,9 +537,19 @@ int send_sigurg(struct fown_struct *fown return ret; } -static rwlock_t fasync_lock = RW_LOCK_UNLOCKED; +static spinlock_t fasync_lock = SPIN_LOCK_UNLOCKED; static kmem_cache_t *fasync_cache; +struct fasync_rcu_struct { + struct fasync_struct data; + struct rcu_head rcu; +}; + +static void fasync_free(void *data) +{ + kmem_cache_free(fasync_cache, data); +} + /* * fasync_helper() is used by some character device drivers (mainly mice) * to set up the fasync queue. It returns negative on error, 0 if it did @@ -548,7 +558,7 @@ static kmem_cache_t *fasync_cache; int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp) { struct fasync_struct *fa, **fp; - struct fasync_struct *new = NULL; + struct fasync_rcu_struct *new = NULL; int result = 0; if (on) { @@ -556,15 +566,23 @@ int fasync_helper(int fd, struct file * if (!new) return -ENOMEM; } - write_lock_irq(&fasync_lock); + spin_lock(&fasync_lock); for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) { if (fa->fa_file == filp) { if(on) { + /* RCU violation: + * We are modifying a struct that's visible by + * readers. If there is a fasync notification + * right now, then it could go to either the + * old or the new fd. Shouldn't matter. + * Manfred + */ fa->fa_fd = fd; kmem_cache_free(fasync_cache, new); } else { *fp = fa->fa_next; - kmem_cache_free(fasync_cache, fa); + new = container_of(fa, struct fasync_rcu_struct, data); + call_rcu(&new->rcu, fasync_free, new); result = 1; } goto out; @@ -572,15 +590,16 @@ int fasync_helper(int fd, struct file * } if (on) { - new->magic = FASYNC_MAGIC; - new->fa_file = filp; - new->fa_fd = fd; - new->fa_next = *fapp; - *fapp = new; + new->data.magic = FASYNC_MAGIC; + new->data.fa_file = filp; + new->data.fa_fd = fd; + new->data.fa_next = *fapp; + smp_wmb(); + *fapp = &new->data; result = 1; } out: - write_unlock_irq(&fasync_lock); + spin_unlock(&fasync_lock); return result; } @@ -590,7 +609,8 @@ void __kill_fasync(struct fasync_struct { while (fa) { struct fown_struct * fown; - if (fa->magic != FASYNC_MAGIC) { + read_barrier_depends(); + if (unlikely(fa->magic != FASYNC_MAGIC)) { printk(KERN_ERR "kill_fasync: bad magic number in " "fasync_struct!\n"); return; @@ -609,9 +629,9 @@ EXPORT_SYMBOL(__kill_fasync); void kill_fasync(struct fasync_struct **fp, int sig, int band) { - read_lock(&fasync_lock); + rcu_read_lock(); __kill_fasync(*fp, sig, band); - read_unlock(&fasync_lock); + rcu_read_unlock(); } EXPORT_SYMBOL(kill_fasync); @@ -619,7 +639,7 @@ EXPORT_SYMBOL(kill_fasync); static int __init fasync_init(void) { fasync_cache = kmem_cache_create("fasync_cache", - sizeof(struct fasync_struct), 0, 0, NULL, NULL); + sizeof(struct fasync_rcu_struct), 0, 0, NULL, NULL); if (!fasync_cache) panic("cannot create fasync slab cache"); return 0; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/fs/hugetlbfs/inode.c 830-ivtv/fs/hugetlbfs/inode.c --- 000-virgin/fs/hugetlbfs/inode.c Mon Nov 17 18:29:49 2003 +++ 830-ivtv/fs/hugetlbfs/inode.c Thu Jan 8 10:22:37 2004 @@ -26,12 +26,17 @@ #include #include #include +#include #include +#include /* some random number */ #define HUGETLBFS_MAGIC 0x958458f6 +extern int mmap_use_hugepages; +extern int mmap_hugepages_map_sz; + static struct super_operations hugetlbfs_ops; static struct address_space_operations hugetlbfs_aops; struct file_operations hugetlbfs_file_operations; @@ -82,7 +87,7 @@ static int hugetlbfs_file_mmap(struct fi unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags); #else -static unsigned long +unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { @@ -114,6 +119,65 @@ hugetlb_get_unmapped_area(struct file *f } } #endif + +int mmap_hugetlb_implicit(unsigned long len) +{ + /* Are we enabled? */ + if (!mmap_use_hugepages) + return 0; + /* Must be HPAGE aligned */ + if (len & ~HPAGE_MASK) + return 0; + /* Are we under the minimum size? */ + if (mmap_hugepages_map_sz + && len < (mmap_hugepages_map_sz << 20)) + return 0; + /* Do we have enough free huge pages? */ + if (!is_hugepage_mem_enough(len)) + return 0; + + return 1; +} + +unsigned long +try_hugetlb_get_unmapped_area(struct file *file, unsigned long addr, + unsigned long len, unsigned long pgoff, unsigned long *flags) +{ + long pre_error = 0; + + /* Check some prerequisites */ + if (!capable(CAP_IPC_LOCK)) + pre_error = -EPERM; + else if (file) + pre_error = -EINVAL; + + /* Explicit requests for huge pages are allowed to return errors */ + if (*flags & MAP_HUGETLB) { + if (pre_error) + return pre_error; + return hugetlb_get_unmapped_area(NULL, addr, len, pgoff, *flags); + } + + /* + * When implicit request fails, return 0 so we can + * retry later with regular pages. + */ + if (mmap_hugetlb_implicit(len)) { + if (pre_error) + goto out; + addr = hugetlb_get_unmapped_area(NULL, addr, len, pgoff, *flags); + if (IS_ERR((void *)addr)) + goto out; + else { + *flags |= MAP_HUGETLB; + return addr; + } + } + +out: + *flags &= ~MAP_HUGETLB; + return 0; +} /* * Read a page. Again trivial. If it didn't already exist diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/fs/inode.c 830-ivtv/fs/inode.c --- 000-virgin/fs/inode.c Mon Nov 17 18:29:42 2003 +++ 830-ivtv/fs/inode.c Thu Jan 8 10:21:50 2004 @@ -147,6 +147,9 @@ static struct inode *alloc_inode(struct mapping->dirtied_when = 0; mapping->assoc_mapping = NULL; mapping->backing_dev_info = &default_backing_dev_info; +#ifdef CONFIG_NUMA + mapping->binding = NULL; +#endif if (sb->s_bdev) mapping->backing_dev_info = sb->s_bdev->bd_inode->i_mapping->backing_dev_info; memset(&inode->u, 0, sizeof(inode->u)); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/fs/proc/array.c 830-ivtv/fs/proc/array.c --- 000-virgin/fs/proc/array.c Mon Nov 17 18:29:42 2003 +++ 830-ivtv/fs/proc/array.c Thu Jan 8 10:21:33 2004 @@ -345,7 +345,7 @@ int proc_pid_stat(struct task_struct *ta read_unlock(&tasklist_lock); res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ %lu %lu %lu %lu %lu %ld %ld %ld %ld %d %ld %llu %lu %ld %lu %lu %lu %lu %lu \ -%lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu\n", +%lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu %lu %lu %lu\n", task->pid, task->comm, state, @@ -391,7 +391,14 @@ int proc_pid_stat(struct task_struct *ta task->exit_signal, task_cpu(task), task->rt_priority, +#ifdef CONFIG_SCHEDSTATS + task->policy, + task->sched_info.cpu_time, + task->sched_info.run_delay, + task->sched_info.pcnt); +#else task->policy); +#endif /* CONFIG_SCHEDSTATS */ if(mm) mmput(mm); return res; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/fs/proc/proc_misc.c 830-ivtv/fs/proc/proc_misc.c --- 000-virgin/fs/proc/proc_misc.c Thu Jan 8 08:35:48 2004 +++ 830-ivtv/fs/proc/proc_misc.c Thu Jan 8 10:21:33 2004 @@ -51,6 +51,10 @@ #include #include +#ifdef CONFIG_MCOUNT +#include +#endif + #define LOAD_INT(x) ((x) >> FSHIFT) #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) /* @@ -134,6 +138,41 @@ static struct vmalloc_info get_vmalloc_i return vmi; } +static int real_loadavg_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int a, b, c, cpu; + int len; + + a = tasks_running[0] + (FIXED_1/200); + b = tasks_running[1] + (FIXED_1/200); + c = tasks_running[2] + (FIXED_1/200); + len = sprintf(page,"Domain load1 load2 load3 nr_run/nr_thrd\n"); + len += sprintf(page+len,"SYSTEM %5d.%02d %5d.%02d %5d.%02d %7ld/%7d\n", + LOAD_INT(a), LOAD_FRAC(a), + LOAD_INT(b), LOAD_FRAC(b), + LOAD_INT(c), LOAD_FRAC(c), + nr_running(), nr_threads); + for (cpu = 0; cpu < NR_CPUS; ++cpu) { + unsigned long nr_running; + if (!cpu_online(cpu)) + continue; + preempt_disable(); + a = per_cpu(cpu_tasks_running,cpu)[0] + (FIXED_1/200); + b = per_cpu(cpu_tasks_running,cpu)[1] + (FIXED_1/200); + c = per_cpu(cpu_tasks_running,cpu)[2] + (FIXED_1/200); + nr_running = nr_running_cpu(cpu); + preempt_enable(); + len += sprintf(page+len, "%5d %5d.%02d %5d.%02d %5d.%02d %7ld/%7d\n", + cpu, + LOAD_INT(a), LOAD_FRAC(a), + LOAD_INT(b), LOAD_FRAC(b), + LOAD_INT(c), LOAD_FRAC(c), + nr_running, nr_threads); + } + return proc_calc_metrics(page, start, off, count, eof, len); +} + static int uptime_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -286,6 +325,10 @@ static struct file_operations proc_vmsta .release = seq_release, }; +#ifdef CONFIG_SCHEDSTATS +extern struct file_operations proc_schedstat_operations; +#endif + #ifdef CONFIG_PROC_HARDWARE static int hardware_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) @@ -342,6 +385,71 @@ static struct file_operations proc_modul }; #endif +#ifdef CONFIG_NUMA +#define K(x) ((x) << (PAGE_SHIFT - 10)) +static int show_meminfo_numa (struct seq_file *m, void *v) +{ + int *d = v; + int nid = *d; + struct sysinfo i; + si_meminfo_node(&i, nid); + seq_printf(m, "\n" + "Node %d MemTotal: %8lu kB\n" + "Node %d MemFree: %8lu kB\n" + "Node %d MemUsed: %8lu kB\n" + "Node %d HighTotal: %8lu kB\n" + "Node %d HighFree: %8lu kB\n" + "Node %d LowTotal: %8lu kB\n" + "Node %d LowFree: %8lu kB\n", + nid, K(i.totalram), + nid, K(i.freeram), + nid, K(i.totalram-i.freeram), + nid, K(i.totalhigh), + nid, K(i.freehigh), + nid, K(i.totalram-i.totalhigh), + nid, K(i.freeram-i.freehigh)); + + return 0; +} +#undef K + +extern struct seq_operations meminfo_numa_op; +static int meminfo_numa_open(struct inode *inode, struct file *file) +{ + return seq_open(file,&meminfo_numa_op); +} + +static struct file_operations proc_meminfo_numa_operations = { + open: meminfo_numa_open, + read: seq_read, + llseek: seq_lseek, + release: seq_release, +}; + +static void *meminfo_numa_start(struct seq_file *m, loff_t *pos) +{ + return *pos < numnodes ? pos : NULL; +} + +static void *meminfo_numa_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return meminfo_numa_start(m, pos); +} + +static void meminfo_numa_stop(struct seq_file *m, void *v) +{ +} + +struct seq_operations meminfo_numa_op = { + .start = meminfo_numa_start, + .next = meminfo_numa_next, + .stop = meminfo_numa_stop, + .show = show_meminfo_numa, +}; + +#endif + extern struct seq_operations slabinfo_op; extern ssize_t slabinfo_write(struct file *, const char __user *, size_t, loff_t *); static int slabinfo_open(struct inode *inode, struct file *file) @@ -654,6 +762,36 @@ static void create_seq_entry(char *name, entry->proc_fops = f; } +#ifdef CONFIG_LOCKMETER +extern ssize_t get_lockmeter_info(char *, size_t, loff_t *); +extern ssize_t put_lockmeter_info(const char *, size_t); +extern int get_lockmeter_info_size(void); + +/* + * This function accesses lock metering information. + */ +static ssize_t read_lockmeter(struct file *file, char *buf, + size_t count, loff_t *ppos) +{ + return get_lockmeter_info(buf, count, ppos); +} + +/* + * Writing to /proc/lockmeter resets the counters + */ +static ssize_t write_lockmeter(struct file * file, const char * buf, + size_t count, loff_t *ppos) +{ + return put_lockmeter_info(buf, count); +} + +static struct file_operations proc_lockmeter_operations = { + NULL, /* lseek */ + read: read_lockmeter, + write: write_lockmeter, +}; +#endif /* CONFIG_LOCKMETER */ + void __init proc_misc_init(void) { struct proc_dir_entry *entry; @@ -662,6 +800,7 @@ void __init proc_misc_init(void) int (*read_proc)(char*,char**,off_t,int,int*,void*); } *p, simple_ones[] = { {"loadavg", loadavg_read_proc}, + {"real_loadavg",real_loadavg_read_proc}, {"uptime", uptime_read_proc}, {"meminfo", meminfo_read_proc}, {"version", version_read_proc}, @@ -701,6 +840,12 @@ void __init proc_misc_init(void) #ifdef CONFIG_MODULES create_seq_entry("modules", 0, &proc_modules_operations); #endif +#ifdef CONFIG_SCHEDSTATS + create_seq_entry("schedstat", 0, &proc_schedstat_operations); +#endif +#ifdef CONFIG_NUMA + create_seq_entry("meminfo.numa",0,&proc_meminfo_numa_operations); +#endif #ifdef CONFIG_PROC_KCORE proc_root_kcore = create_proc_entry("kcore", S_IRUSR, NULL); if (proc_root_kcore) { @@ -721,12 +866,28 @@ void __init proc_misc_init(void) if (entry) entry->proc_fops = &proc_sysrq_trigger_operations; #endif +#ifdef CONFIG_LOCKMETER + entry = create_proc_entry("lockmeter", S_IWUSR | S_IRUGO, NULL); + if (entry) { + entry->proc_fops = &proc_lockmeter_operations; + entry->size = get_lockmeter_info_size(); + } +#endif #ifdef CONFIG_PPC32 { extern struct file_operations ppc_htab_operations; entry = create_proc_entry("ppc_htab", S_IRUGO|S_IWUSR, NULL); if (entry) entry->proc_fops = &ppc_htab_operations; + } +#endif +#ifdef CONFIG_MCOUNT + { + extern struct file_operations mcount_operations; + extern struct proc_dir_entry *mcount_pde; + mcount_pde = create_proc_entry("mcount", S_IRUGO|S_IWUSR, NULL); + if (mcount_pde) + mcount_pde->proc_fops = &mcount_operations; } #endif } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/fs/proc/task_mmu.c 830-ivtv/fs/proc/task_mmu.c --- 000-virgin/fs/proc/task_mmu.c Thu Jan 8 08:35:48 2004 +++ 830-ivtv/fs/proc/task_mmu.c Thu Jan 8 10:21:12 2004 @@ -4,6 +4,22 @@ #include #include +#ifdef CONFIG_NUMA +char *task_mem_pernode(struct mm_struct *mm, char *buffer) +{ + int nid; + + for (nid = 0; nid < MAX_NUMNODES; nid++){ + buffer += sprintf(buffer, "VmRSS-node_%d:\t%8lu kb\n", + nid, mm->pernode_rss[nid] << (PAGE_SHIFT-10)); + } + + return buffer; +} +#else /* !CONFIG_NUMA */ +#define task_mem_pernode(mm, buffer) (buffer) +#endif /* CONFIG_NUMA */ + char *task_mem(struct mm_struct *mm, char *buffer) { unsigned long data = 0, stack = 0, exec = 0, lib = 0; @@ -40,6 +56,7 @@ char *task_mem(struct mm_struct *mm, cha mm->rss << (PAGE_SHIFT-10), data - stack, stack, exec - lib, lib); + buffer = task_mem_pernode(mm, buffer); up_read(&mm->mmap_sem); return buffer; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/fs/sysfs/bin.c 830-ivtv/fs/sysfs/bin.c --- 000-virgin/fs/sysfs/bin.c Mon Nov 17 18:28:19 2003 +++ 830-ivtv/fs/sysfs/bin.c Thu Jan 8 11:16:25 2004 @@ -17,8 +17,10 @@ static int fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count) { - struct bin_attribute * attr = dentry->d_fsdata; - struct kobject * kobj = dentry->d_parent->d_fsdata; + struct sysfs_dirent * sd_attr = dentry->d_fsdata; + struct bin_attribute * attr = sd_attr->s_element; + struct sysfs_dirent * sd_kobj = dentry->d_parent->d_fsdata; + struct kobject * kobj = sd_kobj->s_element; return attr->read(kobj, buffer, off, count); } @@ -60,8 +62,10 @@ read(struct file * file, char __user * u static int flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count) { - struct bin_attribute *attr = dentry->d_fsdata; - struct kobject *kobj = dentry->d_parent->d_fsdata; + struct sysfs_dirent * sd_attr = dentry->d_fsdata; + struct bin_attribute * attr = sd_attr->s_element; + struct sysfs_dirent * sd_kobj = dentry->d_parent->d_fsdata; + struct kobject * kobj = sd_kobj->s_element; return attr->write(kobj, buffer, offset, count); } @@ -94,8 +98,10 @@ static ssize_t write(struct file * file, static int open(struct inode * inode, struct file * file) { - struct kobject * kobj = kobject_get(file->f_dentry->d_parent->d_fsdata); - struct bin_attribute * attr = file->f_dentry->d_fsdata; + struct sysfs_dirent * sd_kobj = file->f_dentry->d_parent->d_fsdata; + struct kobject * kobj = kobject_get(sd_kobj->s_element); + struct sysfs_dirent * sd_attr = file->f_dentry->d_fsdata; + struct bin_attribute * attr = sd_attr->s_element; int error = -EINVAL; if (!kobj || !attr) @@ -122,7 +128,9 @@ static int open(struct inode * inode, st static int release(struct inode * inode, struct file * file) { - struct kobject * kobj = file->f_dentry->d_parent->d_fsdata; + struct sysfs_dirent * sd = file->f_dentry->d_parent->d_fsdata; + struct kobject * kobj = sd->s_element; + u8 * buffer = file->private_data; if (kobj) @@ -131,7 +139,7 @@ static int release(struct inode * inode, return 0; } -static struct file_operations bin_fops = { +struct file_operations bin_fops = { .read = read, .write = write, .llseek = generic_file_llseek, @@ -148,31 +156,10 @@ static struct file_operations bin_fops = int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr) { - struct dentry * dentry; - struct dentry * parent; - int error = 0; - - if (!kobj || !attr) - return -EINVAL; - - parent = kobj->dentry; - - down(&parent->d_inode->i_sem); - dentry = sysfs_get_dentry(parent,attr->attr.name); - if (!IS_ERR(dentry)) { - dentry->d_fsdata = (void *)attr; - error = sysfs_create(dentry, - (attr->attr.mode & S_IALLUGO) | S_IFREG, - NULL); - if (!error) { - dentry->d_inode->i_size = attr->size; - dentry->d_inode->i_fop = &bin_fops; - } - dput(dentry); - } else - error = PTR_ERR(dentry); - up(&parent->d_inode->i_sem); - return error; + if (kobj && kobj->dentry && attr) + return sysfs_add_file(kobj->dentry, SYSFS_KOBJ_BIN_ATTR, + &attr->attr); + return -EINVAL; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/fs/sysfs/dir.c 830-ivtv/fs/sysfs/dir.c --- 000-virgin/fs/sysfs/dir.c Thu Jan 8 08:35:48 2004 +++ 830-ivtv/fs/sysfs/dir.c Wed Jan 7 21:24:52 2004 @@ -10,10 +10,54 @@ #include #include "sysfs.h" +struct inode_operations sysfs_dir_inode_operations = { + .lookup = sysfs_lookup, +}; + +struct file_operations sysfs_dir_operations = { + .open = dcache_dir_open, + .release = dcache_dir_close, + .llseek = sysfs_dir_lseek, + .read = generic_read_dir, + .readdir = sysfs_readdir, +}; + +/* dentry iput only for sysfs leaf dentries */ +static void sysfs_d_iput(struct dentry * dentry, struct inode * inode) +{ + struct sysfs_dirent * sd = dentry->d_fsdata; + + if (sd) + sysfs_put(sd); + iput(inode); +} + + +static struct dentry_operations sysfs_dentry_ops = { + .d_iput = sysfs_d_iput, +}; + +char * sysfs_get_name(struct sysfs_dirent *sd) +{ + if (!sd || !sd->s_element) + BUG(); + + return (sd->s_type & SYSFS_KOBJ_ATTR) ? + ((struct attribute *)(sd->s_element))->name : + ((struct bin_attribute *)(sd->s_element))->attr.name; +} + +static int init_file(struct inode * inode) +{ + inode->i_size = PAGE_SIZE; + inode->i_fop = &sysfs_file_operations; + return 0; +} + static int init_dir(struct inode * inode) { - inode->i_op = &simple_dir_inode_operations; - inode->i_fop = &simple_dir_operations; + inode->i_op = &sysfs_dir_inode_operations; + inode->i_fop = &sysfs_dir_operations; /* directory inodes start off with i_nlink == 2 (for "." entry) */ inode->i_nlink++; @@ -21,6 +65,61 @@ static int init_dir(struct inode * inode } +/* attaches attribute's sysfs_dirent to the dentry corresponding to the + * attribute file + */ +int sysfs_attach_attr(struct sysfs_dirent * sd, struct dentry * dentry) +{ + struct attribute * attr = NULL; + struct bin_attribute * bin_attr = NULL; + int (* init) (struct inode *) = NULL; + int error = 0; + + if (sd->s_type & SYSFS_KOBJ_BIN_ATTR) { + bin_attr = sd->s_element; + attr = &bin_attr->attr; + } else { + attr = sd->s_element; + init = init_file; + } + + error = sysfs_create(dentry, (attr->mode & S_IALLUGO) | S_IFREG, init); + if (error) + return error; + + if (bin_attr) { + dentry->d_inode->i_size = bin_attr->size; + dentry->d_inode->i_fop = &bin_fops; + } + dentry->d_op = &sysfs_dentry_ops; + dentry->d_fsdata = sysfs_get(sd); + sd->s_dentry = dentry; + d_rehash(dentry); + + return 0; +} + +struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, + struct nameidata *nd) +{ + struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata; + struct sysfs_dirent * sd; + int err = 0; + + list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { + if ((sd->s_type == SYSFS_KOBJ_ATTR) + || (sd->s_type == SYSFS_KOBJ_BIN_ATTR)) { + char * name = sysfs_get_name(sd); + if (strcmp(name, dentry->d_name.name)) + continue; + err = sysfs_attach_attr(sd, dentry); + break; + } + } + + return ERR_PTR(err); +} + static int create_dir(struct kobject * k, struct dentry * p, const char * n, struct dentry ** d) { @@ -29,12 +128,23 @@ static int create_dir(struct kobject * k down(&p->d_inode->i_sem); *d = sysfs_get_dentry(p,n); if (!IS_ERR(*d)) { - error = sysfs_create(*d, + error = sysfs_create(*d, S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO, init_dir); if (!error) { - (*d)->d_fsdata = k; - p->d_inode->i_nlink++; + struct sysfs_dirent * sd, * parent_sd; + parent_sd = p->d_fsdata; + sd = sysfs_new_dirent(parent_sd, k, + (parent_sd->s_element == k) ? + SYSFS_KOBJ_ATTR_GROUP : + SYSFS_KOBJECT); + if (sd) { + (*d)->d_fsdata = sysfs_get(sd); + (*d)->d_op = &sysfs_dentry_ops; + p->d_inode->i_nlink++; + d_rehash(*d); + } else + error = -ENOMEM; } dput(*d); } else @@ -81,8 +191,13 @@ int sysfs_create_dir(struct kobject * ko static void remove_dir(struct dentry * d) { struct dentry * parent = dget(d->d_parent); + struct sysfs_dirent * sd; + down(&parent->d_inode->i_sem); d_delete(d); + sd = d->d_fsdata; + list_del_init(&sd->s_sibling); + sysfs_put(d->d_fsdata); if (d->d_inode) simple_rmdir(parent->d_inode,d); @@ -123,8 +238,8 @@ void sysfs_remove_dir(struct kobject * k node = dentry->d_subdirs.next; while (node != &dentry->d_subdirs) { struct dentry * d = list_entry(node,struct dentry,d_child); - list_del_init(node); + node = node->next; pr_debug(" o %s (%d): ",d->d_name.name,atomic_read(&d->d_count)); if (d->d_inode) { d = dget_locked(d); @@ -134,15 +249,22 @@ void sysfs_remove_dir(struct kobject * k * Unlink and unhash. */ spin_unlock(&dcache_lock); - d_delete(d); - simple_unlink(dentry->d_inode,d); - dput(d); + if (S_ISREG(d->d_inode->i_mode)) { + struct sysfs_dirent * sd = d->d_fsdata; + + list_del_init(&sd->s_sibling); + sysfs_put(sd); + d_drop(d); + simple_unlink(dentry->d_inode,d); + } else { + d_delete(d); + simple_unlink(dentry->d_inode,d); + dput(d); + } spin_lock(&dcache_lock); } pr_debug(" done\n"); - node = dentry->d_subdirs.next; } - list_del_init(&dentry->d_child); spin_unlock(&dcache_lock); up(&dentry->d_inode->i_sem); @@ -173,6 +295,164 @@ void sysfs_rename_dir(struct kobject * k up(&parent->d_inode->i_sem); } +/* called under parent inode's i_sem (taken in vfs_readdir */ +static void sysfs_close_attr_files(struct dentry * parent) +{ + struct sysfs_dirent * parent_sd = parent->d_fsdata; + struct sysfs_dirent * sd; + + list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { + if ((sd->s_type == SYSFS_KOBJ_ATTR) || + (sd->s_type == SYSFS_KOBJ_BIN_ATTR)) { + struct dentry * dentry = sd->s_dentry; + if (dentry && dentry->d_inode) + dput(dentry); + } + } +} + +/* called under parent inode's i_sem (taken in vfs_readdir */ +static int sysfs_open_attr_files(struct dentry * parent) +{ + struct sysfs_dirent * parent_sd = parent->d_fsdata; + struct sysfs_dirent * sd; + struct dentry * dentry; + int error = 0; + + list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { + if ((sd->s_type == SYSFS_KOBJ_ATTR) || + (sd->s_type == SYSFS_KOBJ_BIN_ATTR)) { + char * name = sysfs_get_name(sd); + dentry = sysfs_get_dentry(parent, name); + if (IS_ERR(dentry)) + error = PTR_ERR(dentry); + if (!dentry->d_inode) + error = sysfs_attach_attr(sd, dentry); + if (error) + break; + } + } + if (error) { + /* release all successfully opened entires so far*/ + sysfs_close_attr_files(parent); + } + + return error; +} + +/* Relationship between i_mode and the DT_xxx types */ +static inline unsigned char dt_type(struct inode *inode) +{ + return (inode->i_mode >> 12) & 15; +} + +/* + * Directory is locked and all positive dentries in it are safe, since + * for ramfs-type trees they can't go away without unlink() or rmdir(), + * both impossible due to the lock on directory. + */ + +int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) +{ + struct dentry *dentry = filp->f_dentry; + struct dentry *cursor = filp->private_data; + struct list_head *p, *q = &cursor->d_child; + ino_t ino; + int i = filp->f_pos; + int err = 0; + + switch (i) { + case 0: + ino = dentry->d_inode->i_ino; + if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) + break; + filp->f_pos++; + i++; + /* fallthrough */ + case 1: + ino = parent_ino(dentry); + if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0) + break; + filp->f_pos++; + i++; + /* fallthrough */ + default: + if ((err = sysfs_open_attr_files(dentry))) + return err; + + spin_lock(&dcache_lock); + if (filp->f_pos == 2) { + list_del(q); + list_add(q, &dentry->d_subdirs); + } + for (p=q->next; p != &dentry->d_subdirs; p=p->next) { + struct dentry *next; + next = list_entry(p, struct dentry, d_child); + if (d_unhashed(next) || !next->d_inode) + continue; + + spin_unlock(&dcache_lock); + if (filldir(dirent, next->d_name.name, next->d_name.len, filp->f_pos, next->d_inode->i_ino, dt_type(next->d_inode)) < 0) + return 0; + spin_lock(&dcache_lock); + /* next is still alive */ + list_del(q); + list_add(q, p); + p = q; + filp->f_pos++; + } + spin_unlock(&dcache_lock); + sysfs_close_attr_files(dentry); + } + return 0; +} + +loff_t sysfs_dir_lseek(struct file *file, loff_t offset, int origin) +{ + int err = 0; + + down(&file->f_dentry->d_inode->i_sem); + switch (origin) { + case 1: + offset += file->f_pos; + case 0: + if (offset >= 0) + break; + default: + up(&file->f_dentry->d_inode->i_sem); + return -EINVAL; + } + if (offset != file->f_pos) { + file->f_pos = offset; + if (file->f_pos >= 2) { + struct list_head *p; + struct dentry *cursor = file->private_data; + loff_t n = file->f_pos - 2; + + if ((err = sysfs_open_attr_files(file->f_dentry))) { + offset = err; + goto exit; + } + + spin_lock(&dcache_lock); + list_del(&cursor->d_child); + p = file->f_dentry->d_subdirs.next; + while (n && p != &file->f_dentry->d_subdirs) { + struct dentry *next; + next = list_entry(p, struct dentry, d_child); + if (!d_unhashed(next) && next->d_inode) + n--; + p = p->next; + } + list_add_tail(&cursor->d_child, p); + spin_unlock(&dcache_lock); + sysfs_close_attr_files(file->f_dentry); + } + } +exit: + up(&file->f_dentry->d_inode->i_sem); + return offset; +} EXPORT_SYMBOL(sysfs_create_dir); EXPORT_SYMBOL(sysfs_remove_dir); EXPORT_SYMBOL(sysfs_rename_dir); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/fs/sysfs/file.c 830-ivtv/fs/sysfs/file.c --- 000-virgin/fs/sysfs/file.c Mon Nov 17 18:28:56 2003 +++ 830-ivtv/fs/sysfs/file.c Thu Jan 8 11:16:22 2004 @@ -9,14 +9,6 @@ #include "sysfs.h" -static struct file_operations sysfs_file_operations; - -static int init_file(struct inode * inode) -{ - inode->i_size = PAGE_SIZE; - inode->i_fop = &sysfs_file_operations; - return 0; -} #define to_subsys(k) container_of(k,struct subsystem,kset.kobj) #define to_sattr(a) container_of(a,struct subsys_attribute,attr) @@ -77,8 +69,10 @@ struct sysfs_buffer { */ static int fill_read_buffer(struct file * file, struct sysfs_buffer * buffer) { - struct attribute * attr = file->f_dentry->d_fsdata; - struct kobject * kobj = file->f_dentry->d_parent->d_fsdata; + struct sysfs_dirent * sd_attr = file->f_dentry->d_fsdata; + struct attribute * attr = sd_attr->s_element; + struct sysfs_dirent * sd_kobj = file->f_dentry->d_parent->d_fsdata; + struct kobject * kobj = sd_kobj->s_element; struct sysfs_ops * ops = buffer->ops; int ret = 0; ssize_t count; @@ -198,8 +192,10 @@ fill_write_buffer(struct sysfs_buffer * static int flush_write_buffer(struct file * file, struct sysfs_buffer * buffer, size_t count) { - struct attribute * attr = file->f_dentry->d_fsdata; - struct kobject * kobj = file->f_dentry->d_parent->d_fsdata; + struct sysfs_dirent * sd_attr = file->f_dentry->d_fsdata; + struct attribute * attr = sd_attr->s_element; + struct sysfs_dirent * sd_kobj = file->f_dentry->d_parent->d_fsdata; + struct kobject * kobj = sd_kobj->s_element; struct sysfs_ops * ops = buffer->ops; return ops->store(kobj,attr,buffer->page,count); @@ -238,8 +234,10 @@ sysfs_write_file(struct file *file, cons static int check_perm(struct inode * inode, struct file * file) { - struct kobject * kobj = kobject_get(file->f_dentry->d_parent->d_fsdata); - struct attribute * attr = file->f_dentry->d_fsdata; + struct sysfs_dirent * sd_attr = file->f_dentry->d_fsdata; + struct attribute * attr = sd_attr->s_element; + struct sysfs_dirent * sd_kobj = file->f_dentry->d_parent->d_fsdata; + struct kobject * kobj = kobject_get(sd_kobj->s_element); struct sysfs_buffer * buffer; struct sysfs_ops * ops = NULL; int error = 0; @@ -320,8 +318,10 @@ static int sysfs_open_file(struct inode static int sysfs_release(struct inode * inode, struct file * filp) { - struct kobject * kobj = filp->f_dentry->d_parent->d_fsdata; - struct attribute * attr = filp->f_dentry->d_fsdata; + struct sysfs_dirent * sd_attr = filp->f_dentry->d_fsdata; + struct attribute * attr = sd_attr->s_element; + struct sysfs_dirent * sd_kobj = filp->f_dentry->d_parent->d_fsdata; + struct kobject * kobj = kobject_get(sd_kobj->s_element); struct sysfs_buffer * buffer = filp->private_data; if (kobj) @@ -336,7 +336,7 @@ static int sysfs_release(struct inode * return 0; } -static struct file_operations sysfs_file_operations = { +struct file_operations sysfs_file_operations = { .read = sysfs_read_file, .write = sysfs_write_file, .llseek = generic_file_llseek, @@ -345,23 +345,18 @@ static struct file_operations sysfs_file }; -int sysfs_add_file(struct dentry * dir, const struct attribute * attr) +int sysfs_add_file(struct dentry * parent, int t, const struct attribute * attr) { - struct dentry * dentry; - int error; + struct sysfs_dirent * sd; + struct sysfs_dirent * parent_sd = parent->d_fsdata; + int error = 0; - down(&dir->d_inode->i_sem); - dentry = sysfs_get_dentry(dir,attr->name); - if (!IS_ERR(dentry)) { - error = sysfs_create(dentry, - (attr->mode & S_IALLUGO) | S_IFREG, - init_file); - if (!error) - dentry->d_fsdata = (void *)attr; - dput(dentry); - } else - error = PTR_ERR(dentry); - up(&dir->d_inode->i_sem); + down(&parent->d_inode->i_sem); + sd = sysfs_new_dirent(parent_sd, (void *) attr, t); + if (!sd) + error = -ENOMEM; + up(&parent->d_inode->i_sem); + return error; } @@ -374,8 +369,8 @@ int sysfs_add_file(struct dentry * dir, int sysfs_create_file(struct kobject * kobj, const struct attribute * attr) { - if (kobj && attr) - return sysfs_add_file(kobj->dentry,attr); + if (kobj && kobj->dentry && attr) + return sysfs_add_file(kobj->dentry, SYSFS_KOBJ_ATTR, attr); return -EINVAL; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/fs/sysfs/group.c 830-ivtv/fs/sysfs/group.c --- 000-virgin/fs/sysfs/group.c Mon Nov 17 18:28:56 2003 +++ 830-ivtv/fs/sysfs/group.c Thu Jan 8 11:16:28 2004 @@ -31,7 +31,7 @@ static int create_files(struct dentry * int error = 0; for (attr = grp->attrs; *attr && !error; attr++) { - error = sysfs_add_file(dir,*attr); + error = sysfs_add_file(dir, SYSFS_KOBJ_ATTR, * attr); } if (error) remove_files(dir,grp); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/fs/sysfs/inode.c 830-ivtv/fs/sysfs/inode.c --- 000-virgin/fs/sysfs/inode.c Mon Nov 17 18:28:19 2003 +++ 830-ivtv/fs/sysfs/inode.c Thu Jan 8 11:16:22 2004 @@ -11,6 +11,8 @@ #include #include #include +#include "sysfs.h" + extern struct super_block * sysfs_sb; static struct address_space_operations sysfs_aops = { @@ -61,7 +63,8 @@ int sysfs_create(struct dentry * dentry, error = init(inode); if (!error) { d_instantiate(dentry, inode); - dget(dentry); /* Extra count - pin the dentry in core */ + if (!S_ISREG(inode->i_mode)) + dget(dentry); /* pin non-leaf dentry in core */ } else iput(inode); Done: @@ -96,14 +99,24 @@ void sysfs_hash_and_remove(struct dentry pr_debug("sysfs: Removing %s (%d)\n", victim->d_name.name, atomic_read(&victim->d_count)); - d_delete(victim); - simple_unlink(dir->d_inode,victim); + if (S_ISREG(victim->d_inode->i_mode)) { + spin_lock(&dcache_lock); + spin_lock(&victim->d_lock); + __d_drop(victim); + spin_unlock(&dcache_lock); + spin_unlock(&victim->d_lock); + } + else { + d_delete(victim); + simple_unlink(dir->d_inode,victim); + } } /* * Drop reference from sysfs_get_dentry() above. */ dput(victim); } + sysfs_remove_attr_dirent(dir->d_fsdata, name); up(&dir->d_inode->i_sem); } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/fs/sysfs/mount.c 830-ivtv/fs/sysfs/mount.c --- 000-virgin/fs/sysfs/mount.c Fri May 30 19:02:19 2003 +++ 830-ivtv/fs/sysfs/mount.c Thu Jan 8 10:27:08 2004 @@ -20,6 +20,14 @@ struct super_block * sysfs_sb = NULL; static struct super_operations sysfs_ops = { .statfs = simple_statfs, .drop_inode = generic_delete_inode, + .umount_begin = sysfs_umount_begin, +}; + +struct sysfs_dirent sysfs_root = { + .s_sibling = LIST_HEAD_INIT(sysfs_root.s_sibling), + .s_children = LIST_HEAD_INIT(sysfs_root.s_children), + .s_element = NULL, + .s_type = SYSFS_ROOT, }; static int sysfs_fill_super(struct super_block *sb, void *data, int silent) @@ -35,8 +43,8 @@ static int sysfs_fill_super(struct super inode = sysfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO); if (inode) { - inode->i_op = &simple_dir_inode_operations; - inode->i_fop = &simple_dir_operations; + inode->i_op = &sysfs_dir_inode_operations; + inode->i_fop = &sysfs_dir_operations; /* directory inodes start off with i_nlink == 2 (for "." entry) */ inode->i_nlink++; } else { @@ -50,6 +58,7 @@ static int sysfs_fill_super(struct super iput(inode); return -ENOMEM; } + root->d_fsdata = &sysfs_root; sb->s_root = root; return 0; } @@ -58,6 +67,14 @@ static struct super_block *sysfs_get_sb( int flags, const char *dev_name, void *data) { return get_sb_single(fs_type, flags, data, sysfs_fill_super); +} + +void sysfs_umount_begin(struct super_block * sb) +{ + lock_super(sb); + if (sb->s_root) + shrink_dcache_parent(sb->s_root); + unlock_super(sb); } static struct file_system_type sysfs_fs_type = { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/fs/sysfs/symlink.c 830-ivtv/fs/sysfs/symlink.c --- 000-virgin/fs/sysfs/symlink.c Mon Nov 17 18:28:19 2003 +++ 830-ivtv/fs/sysfs/symlink.c Thu Jan 8 11:16:28 2004 @@ -25,6 +25,8 @@ static int sysfs_symlink(struct inode * error = page_symlink(dentry->d_inode, symname, l); if (error) iput(dentry->d_inode); + else + d_rehash(dentry); } return error; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/fs/sysfs/sysfs.h 830-ivtv/fs/sysfs/sysfs.h --- 000-virgin/fs/sysfs/sysfs.h Mon Nov 17 18:28:56 2003 +++ 830-ivtv/fs/sysfs/sysfs.h Thu Jan 8 11:16:28 2004 @@ -1,4 +1,5 @@ +#include extern struct vfsmount * sysfs_mount; extern struct inode * sysfs_new_inode(mode_t mode); @@ -6,8 +7,75 @@ extern int sysfs_create(struct dentry *, extern struct dentry * sysfs_get_dentry(struct dentry *, const char *); -extern int sysfs_add_file(struct dentry * dir, const struct attribute * attr); +extern int sysfs_add_file(struct dentry *, int, const struct attribute *); extern void sysfs_hash_and_remove(struct dentry * dir, const char * name); extern int sysfs_create_subdir(struct kobject *, const char *, struct dentry **); extern void sysfs_remove_subdir(struct dentry *); + +extern loff_t sysfs_dir_lseek(struct file *, loff_t, int); +extern int sysfs_readdir(struct file *, void *, filldir_t); +extern void sysfs_umount_begin(struct super_block *); +extern char * sysfs_get_name(struct sysfs_dirent *); +extern struct dentry * sysfs_lookup(struct inode *, struct dentry *, struct nameidata *); + +extern struct file_operations sysfs_file_operations; +extern struct file_operations bin_fops; +extern struct inode_operations sysfs_dir_inode_operations; +extern struct file_operations sysfs_dir_operations; + + +static inline +struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * p, void * e, int t) +{ + struct sysfs_dirent * sd; + + sd = kmalloc(sizeof(*sd), GFP_KERNEL); + if (!sd) + return NULL; + memset(sd, 0, sizeof(*sd)); + atomic_set(&sd->s_count, 1); + sd->s_element = e; + sd->s_type = t; + sd->s_dentry = NULL; + INIT_LIST_HEAD(&sd->s_children); + list_add(&sd->s_sibling, &p->s_children); + + return sd; +} + +static inline struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd) +{ + if (sd) { + WARN_ON(!atomic_read(&sd->s_count)); + atomic_inc(&sd->s_count); + } + return sd; +} + +static inline void sysfs_put(struct sysfs_dirent * sd) +{ + if (atomic_dec_and_test(&sd->s_count)) + kfree(sd); +} + +static inline +void sysfs_remove_attr_dirent(struct sysfs_dirent * sd, const char * name) +{ + struct list_head * tmp; + + tmp = sd->s_children.next; + while (tmp != & sd->s_children) { + struct sysfs_dirent * tmp_sd; + tmp_sd = list_entry(tmp, struct sysfs_dirent, s_sibling); + tmp = tmp->next; + if ((tmp_sd->s_type == SYSFS_KOBJ_ATTR) || + (tmp_sd->s_type == SYSFS_KOBJ_BIN_ATTR)) { + if (!strcmp(sysfs_get_name(tmp_sd), name)) { + list_del_init(&tmp_sd->s_sibling); + sysfs_put(tmp_sd); + } + } + } +} + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-alpha/ioctls.h 830-ivtv/include/asm-alpha/ioctls.h --- 000-virgin/include/asm-alpha/ioctls.h Tue Apr 8 14:38:20 2003 +++ 830-ivtv/include/asm-alpha/ioctls.h Thu Jan 8 11:17:33 2004 @@ -91,6 +91,7 @@ #define TIOCGSID 0x5429 /* Return the session ID of FD */ #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ #define TIOCSERCONFIG 0x5453 #define TIOCSERGWILD 0x5454 diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-alpha/lockmeter.h 830-ivtv/include/asm-alpha/lockmeter.h --- 000-virgin/include/asm-alpha/lockmeter.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/include/asm-alpha/lockmeter.h Thu Jan 8 09:30:50 2004 @@ -0,0 +1,90 @@ +/* + * Written by John Hawkes (hawkes@sgi.com) + * Based on klstat.h by Jack Steiner (steiner@sgi.com) + * + * Modified by Peter Rival (frival@zk3.dec.com) + */ + +#ifndef _ALPHA_LOCKMETER_H +#define _ALPHA_LOCKMETER_H + +#include +#define CPU_CYCLE_FREQUENCY hwrpb->cycle_freq + +#define get_cycles64() get_cycles() + +#define THIS_CPU_NUMBER smp_processor_id() + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) +#define local_irq_save(x) \ + __save_and_cli(x) +#define local_irq_restore(x) \ + __restore_flags(x) +#endif /* Linux version 2.2.x */ + +#define SPINLOCK_MAGIC_INIT /**/ + +/* + * Macros to cache and retrieve an index value inside of a lock + * these macros assume that there are less than 65536 simultaneous + * (read mode) holders of a rwlock. + * We also assume that the hash table has less than 32767 entries. + * the high order bit is used for write locking a rw_lock + * Note: although these defines and macros are the same as what is being used + * in include/asm-i386/lockmeter.h, they are present here to easily + * allow an alternate Alpha implementation. + */ +/* + * instrumented spinlock structure -- never used to allocate storage + * only used in macros below to overlay a spinlock_t + */ +typedef struct inst_spinlock_s { + /* remember, Alpha is little endian */ + unsigned short lock; + unsigned short index; +} inst_spinlock_t; +#define PUT_INDEX(lock_ptr,indexv) ((inst_spinlock_t *)(lock_ptr))->index = indexv +#define GET_INDEX(lock_ptr) ((inst_spinlock_t *)(lock_ptr))->index + +/* + * macros to cache and retrieve an index value in a read/write lock + * as well as the cpu where a reader busy period started + * we use the 2nd word (the debug word) for this, so require the + * debug word to be present + */ +/* + * instrumented rwlock structure -- never used to allocate storage + * only used in macros below to overlay a rwlock_t + */ +typedef struct inst_rwlock_s { + volatile int lock; + unsigned short index; + unsigned short cpu; +} inst_rwlock_t; +#define PUT_RWINDEX(rwlock_ptr,indexv) ((inst_rwlock_t *)(rwlock_ptr))->index = indexv +#define GET_RWINDEX(rwlock_ptr) ((inst_rwlock_t *)(rwlock_ptr))->index +#define PUT_RW_CPU(rwlock_ptr,cpuv) ((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv +#define GET_RW_CPU(rwlock_ptr) ((inst_rwlock_t *)(rwlock_ptr))->cpu + +/* + * return true if rwlock is write locked + * (note that other lock attempts can cause the lock value to be negative) + */ +#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) (((inst_rwlock_t *)rwlock_ptr)->lock & 1) +#define IABS(x) ((x) > 0 ? (x) : -(x)) + +#define RWLOCK_READERS(rwlock_ptr) rwlock_readers(rwlock_ptr) +extern inline int rwlock_readers(rwlock_t *rwlock_ptr) +{ + int tmp = (int) ((inst_rwlock_t *)rwlock_ptr)->lock; + /* readers subtract 2, so we have to: */ + /* - andnot off a possible writer (bit 0) */ + /* - get the absolute value */ + /* - divide by 2 (right shift by one) */ + /* to find the number of readers */ + if (tmp == 0) return(0); + else return(IABS(tmp & ~1)>>1); +} + +#endif /* _ALPHA_LOCKMETER_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-alpha/spinlock.h 830-ivtv/include/asm-alpha/spinlock.h --- 000-virgin/include/asm-alpha/spinlock.h Fri May 30 19:02:20 2003 +++ 830-ivtv/include/asm-alpha/spinlock.h Thu Jan 8 09:30:50 2004 @@ -6,6 +6,10 @@ #include #include +#ifdef CONFIG_LOCKMETER +#undef DEBUG_SPINLOCK +#undef DEBUG_RWLOCK +#endif /* * Simple spin lock operations. There are two variants, one clears IRQ's @@ -95,9 +99,18 @@ static inline int _raw_spin_trylock(spin typedef struct { volatile int write_lock:1, read_counter:31; +#ifdef CONFIG_LOCKMETER + /* required for LOCKMETER since all bits in lock are used */ + /* need this storage for CPU and lock INDEX ............. */ + unsigned magic; +#endif } /*__attribute__((aligned(32)))*/ rwlock_t; +#ifdef CONFIG_LOCKMETER +#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0, 0 } +#else #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 } +#endif #define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) #define rwlock_is_locked(x) (*(volatile int *)(x) != 0) @@ -168,5 +181,42 @@ static inline void _raw_read_unlock(rwlo : "=m" (*lock), "=&r" (regx) : "m" (*lock) : "memory"); } + +#ifdef CONFIG_LOCKMETER +static inline int _raw_write_trylock(rwlock_t *lock) +{ + long temp,result; + + __asm__ __volatile__( + " ldl_l %1,%0\n" + " mov $31,%2\n" + " bne %1,1f\n" + " or $31,1,%2\n" + " stl_c %2,%0\n" + "1: mb\n" + : "=m" (*(volatile int *)lock), "=&r" (temp), "=&r" (result) + : "m" (*(volatile int *)lock) + ); + + return (result); +} + +static inline int _raw_read_trylock(rwlock_t *lock) +{ + unsigned long temp,result; + + __asm__ __volatile__( + " ldl_l %1,%0\n" + " mov $31,%2\n" + " blbs %1,1f\n" + " subl %1,2,%2\n" + " stl_c %2,%0\n" + "1: mb\n" + : "=m" (*(volatile int *)lock), "=&r" (temp), "=&r" (result) + : "m" (*(volatile int *)lock) + ); + return (result); +} +#endif /* CONFIG_LOCKMETER */ #endif /* _ALPHA_SPINLOCK_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-arm/ioctls.h 830-ivtv/include/asm-arm/ioctls.h --- 000-virgin/include/asm-arm/ioctls.h Tue Apr 8 14:38:20 2003 +++ 830-ivtv/include/asm-arm/ioctls.h Thu Jan 8 11:17:33 2004 @@ -48,6 +48,7 @@ #define TIOCGSID 0x5429 /* Return the session ID of FD */ #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ #define FIOCLEX 0x5451 diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-generic/tlb.h 830-ivtv/include/asm-generic/tlb.h --- 000-virgin/include/asm-generic/tlb.h Tue Sep 2 09:55:52 2003 +++ 830-ivtv/include/asm-generic/tlb.h Thu Jan 8 10:21:12 2004 @@ -39,7 +39,6 @@ struct mmu_gather { unsigned int nr; /* set to ~0U means fast mode */ unsigned int need_flush;/* Really unmapped some ptes? */ unsigned int fullmm; /* non-zero means full mm flush */ - unsigned long freed; struct page * pages[FREE_PTE_NR]; }; @@ -60,7 +59,6 @@ tlb_gather_mmu(struct mm_struct *mm, uns tlb->nr = num_online_cpus() > 1 ? 0U : ~0U; tlb->fullmm = full_mm_flush; - tlb->freed = 0; return tlb; } @@ -85,13 +83,6 @@ tlb_flush_mmu(struct mmu_gather *tlb, un static inline void tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end) { - int freed = tlb->freed; - struct mm_struct *mm = tlb->mm; - int rss = mm->rss; - - if (rss < freed) - freed = rss; - mm->rss = rss - freed; tlb_flush_mmu(tlb, start, end); /* keep the page table cache within bounds */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/a.out.h 830-ivtv/include/asm-i386/a.out.h --- 000-virgin/include/asm-i386/a.out.h Sun Nov 17 20:29:32 2002 +++ 830-ivtv/include/asm-i386/a.out.h Thu Jan 8 10:22:24 2004 @@ -19,7 +19,16 @@ struct exec #ifdef __KERNEL__ +/* + * Typical ELF load address is 0x8048000, which is 128MB + 288KB. + * Shoving the stack very close to it lets smaller programs fit in + * a single pagetable page's worth of virtualspace. + */ +#ifdef CONFIG_MMAP_TOPDOWN +#define STACK_TOP ((128 << 20) + (256 << 10)) +#else #define STACK_TOP TASK_SIZE +#endif #endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/apic.h 830-ivtv/include/asm-i386/apic.h --- 000-virgin/include/asm-i386/apic.h Mon Nov 17 18:28:19 2003 +++ 830-ivtv/include/asm-i386/apic.h Thu Jan 8 10:26:46 2004 @@ -99,6 +99,9 @@ extern unsigned int nmi_watchdog; #define NMI_LOCAL_APIC 2 #define NMI_INVALID 3 +extern void stop_apics(void); +#else +static inline void stop_apics(void) { } #endif /* CONFIG_X86_LOCAL_APIC */ #endif /* __ASM_APIC_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/apicdef.h 830-ivtv/include/asm-i386/apicdef.h --- 000-virgin/include/asm-i386/apicdef.h Fri May 30 19:02:20 2003 +++ 830-ivtv/include/asm-i386/apicdef.h Thu Jan 8 10:26:46 2004 @@ -86,6 +86,7 @@ #define APIC_LVT_REMOTE_IRR (1<<14) #define APIC_INPUT_POLARITY (1<<13) #define APIC_SEND_PENDING (1<<12) +#define APIC_MODE_MASK 0x700 #define GET_APIC_DELIVERY_MODE(x) (((x)>>8)&0x7) #define SET_APIC_DELIVERY_MODE(x,y) (((x)&~0x700)|((y)<<8)) #define APIC_MODE_FIXED 0x0 diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/atomic.h 830-ivtv/include/asm-i386/atomic.h --- 000-virgin/include/asm-i386/atomic.h Tue Sep 2 09:55:53 2003 +++ 830-ivtv/include/asm-i386/atomic.h Thu Jan 8 10:21:27 2004 @@ -58,6 +58,17 @@ static __inline__ void atomic_add(int i, :"ir" (i), "m" (v->counter)); } +/* Like the above but also returns the result */ +static __inline__ int atomic_add_return(int i, atomic_t *v) +{ + register int oldval; + __asm__ __volatile__( + LOCK "xaddl %2,%0" + :"=m" (v->counter), "=r" (oldval) + :"1" (i), "m" (v->counter) : "memory"); + return oldval + i; +} + /** * atomic_sub - subtract the atomic variable * @i: integer value to subtract diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/atomic_kmap.h 830-ivtv/include/asm-i386/atomic_kmap.h --- 000-virgin/include/asm-i386/atomic_kmap.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/include/asm-i386/atomic_kmap.h Thu Jan 8 09:30:59 2004 @@ -0,0 +1,95 @@ +/* + * atomic_kmap.h: temporary virtual kernel memory mappings + * + * Copyright (C) 2003 Ingo Molnar + */ + +#ifndef _ASM_ATOMIC_KMAP_H +#define _ASM_ATOMIC_KMAP_H + +#ifdef __KERNEL__ + +#include +#include + +#ifdef CONFIG_DEBUG_HIGHMEM +#define HIGHMEM_DEBUG 1 +#else +#define HIGHMEM_DEBUG 0 +#endif + +extern pte_t *kmap_pte; +#define kmap_prot PAGE_KERNEL + +#define PKMAP_BASE (0xff000000UL) +#define NR_SHARED_PMDS ((0xffffffff-PKMAP_BASE+1)/PMD_SIZE) + +static inline unsigned long __kmap_atomic_vaddr(enum km_type type) +{ + enum fixed_addresses idx; + + idx = type + KM_TYPE_NR*smp_processor_id(); + return __fix_to_virt(FIX_KMAP_BEGIN + idx); +} + +static inline void *__kmap_atomic_noflush(struct page *page, enum km_type type) +{ + enum fixed_addresses idx; + unsigned long vaddr; + + idx = type + KM_TYPE_NR*smp_processor_id(); + vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); + /* + * NOTE: entries that rely on some secondary TLB-flush + * effect must not be global: + */ + set_pte(kmap_pte-idx, mk_pte(page, PAGE_KERNEL)); + + return (void*) vaddr; +} + +static inline void *__kmap_atomic(struct page *page, enum km_type type) +{ + enum fixed_addresses idx; + unsigned long vaddr; + + idx = type + KM_TYPE_NR*smp_processor_id(); + vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); +#if HIGHMEM_DEBUG + BUG_ON(!pte_none(*(kmap_pte-idx))); +#else + /* + * Performance optimization - do not flush if the new + * pte is the same as the old one: + */ + if (pte_val(*(kmap_pte-idx)) == pte_val(mk_pte(page, kmap_prot))) + return (void *) vaddr; +#endif + set_pte(kmap_pte-idx, mk_pte(page, kmap_prot)); + __flush_tlb_one(vaddr); + + return (void*) vaddr; +} + +static inline void __kunmap_atomic(void *kvaddr, enum km_type type) +{ +#if HIGHMEM_DEBUG + unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; + enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id(); + + BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN+idx)); + /* + * force other mappings to Oops if they'll try to access + * this pte without first remap it + */ + pte_clear(kmap_pte-idx); + __flush_tlb_one(vaddr); +#endif +} + +#define __kunmap_atomic_type(type) \ + __kunmap_atomic((void *)__kmap_atomic_vaddr(type), (type)) + +#endif /* __KERNEL__ */ + +#endif /* _ASM_ATOMIC_KMAP_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/bugs.h 830-ivtv/include/asm-i386/bugs.h --- 000-virgin/include/asm-i386/bugs.h Mon Nov 17 18:28:19 2003 +++ 830-ivtv/include/asm-i386/bugs.h Thu Jan 8 09:30:15 2004 @@ -1,11 +1,11 @@ /* * include/asm-i386/bugs.h * - * Copyright (C) 1994 Linus Torvalds + * Copyright (C) 1994 Linus Torvalds * * Cyrix stuff, June 1998 by: * - Rafael R. Reilova (moved everything from head.S), - * + * * - Channing Corn (tests & fixes), * - Andrew D. Balsa (code cleanup). * @@ -25,7 +25,20 @@ #include #include #include - +#ifdef CONFIG_KGDB +/* + * Provied the command line "gdb" initial break + */ +int __init kgdb_initial_break(char * str) +{ + if (*str == '\0'){ + breakpoint(); + return 1; + } + return 0; +} +__setup("gdb",kgdb_initial_break); +#endif static int __init no_halt(char *s) { boot_cpu_data.hlt_works_ok = 0; @@ -140,7 +153,7 @@ static void __init check_popad(void) : "ecx", "edi" ); /* If this fails, it means that any user program may lock the CPU hard. Too bad. */ if (res != 12345678) printk( "Buggy.\n" ); - else printk( "OK.\n" ); + else printk( "OK.\n" ); #endif } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/checksum.h 830-ivtv/include/asm-i386/checksum.h --- 000-virgin/include/asm-i386/checksum.h Mon Dec 8 09:55:52 2003 +++ 830-ivtv/include/asm-i386/checksum.h Thu Jan 8 09:30:59 2004 @@ -25,7 +25,7 @@ asmlinkage unsigned int csum_partial(con * better 64-bit) boundary */ -asmlinkage unsigned int csum_partial_copy_generic( const char *src, char *dst, int len, int sum, +asmlinkage unsigned int direct_csum_partial_copy_generic( const char *src, char *dst, int len, int sum, int *src_err_ptr, int *dst_err_ptr); /* @@ -39,14 +39,19 @@ static __inline__ unsigned int csum_partial_copy_nocheck ( const char *src, char *dst, int len, int sum) { - return csum_partial_copy_generic ( src, dst, len, sum, NULL, NULL); + /* + * The direct function is OK for kernel-space => kernel-space copies: + */ + return direct_csum_partial_copy_generic ( src, dst, len, sum, NULL, NULL); } static __inline__ unsigned int csum_partial_copy_from_user ( const char *src, char *dst, int len, int sum, int *err_ptr) { - return csum_partial_copy_generic ( src, dst, len, sum, err_ptr, NULL); + if (copy_from_user(dst, src, len)) + *err_ptr = -EFAULT; + return csum_partial(dst, len, sum); } /* @@ -172,11 +177,26 @@ static __inline__ unsigned short int csu * Copy and checksum to user */ #define HAVE_CSUM_COPY_USER -static __inline__ unsigned int csum_and_copy_to_user(const char *src, char *dst, +static __inline__ unsigned int direct_csum_and_copy_to_user(const char *src, char *dst, int len, int sum, int *err_ptr) { if (access_ok(VERIFY_WRITE, dst, len)) - return csum_partial_copy_generic(src, dst, len, sum, NULL, err_ptr); + return direct_csum_partial_copy_generic(src, dst, len, sum, NULL, err_ptr); + + if (len) + *err_ptr = -EFAULT; + + return -1; /* invalid checksum */ +} + +static __inline__ unsigned int csum_and_copy_to_user(const char *src, char *dst, + int len, int sum, int *err_ptr) +{ + if (access_ok(VERIFY_WRITE, dst, len)) { + if (copy_to_user(dst, src, len)) + *err_ptr = -EFAULT; + return csum_partial(src, len, sum); + } if (len) *err_ptr = -EFAULT; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/desc.h 830-ivtv/include/asm-i386/desc.h --- 000-virgin/include/asm-i386/desc.h Tue Feb 25 23:03:50 2003 +++ 830-ivtv/include/asm-i386/desc.h Thu Jan 8 09:30:59 2004 @@ -21,6 +21,13 @@ struct Xgt_desc_struct { extern struct Xgt_desc_struct idt_descr, cpu_gdt_descr[NR_CPUS]; +extern void trap_init_virtual_IDT(void); +extern void trap_init_virtual_GDT(void); + +asmlinkage int system_call(void); +asmlinkage void lcall7(void); +asmlinkage void lcall27(void); + #define load_TR_desc() __asm__ __volatile__("ltr %%ax"::"a" (GDT_ENTRY_TSS*8)) #define load_LDT_desc() __asm__ __volatile__("lldt %%ax"::"a" (GDT_ENTRY_LDT*8)) @@ -30,6 +37,7 @@ extern struct Xgt_desc_struct idt_descr, */ extern struct desc_struct default_ldt[]; extern void set_intr_gate(unsigned int irq, void * addr); +extern void set_trap_gate(unsigned int n, void *addr); #define _set_tssldt_desc(n,addr,limit,type) \ __asm__ __volatile__ ("movw %w3,0(%2)\n\t" \ @@ -90,31 +98,8 @@ static inline void load_TLS(struct threa #undef C } -static inline void clear_LDT(void) -{ - int cpu = get_cpu(); - - set_ldt_desc(cpu, &default_ldt[0], 5); - load_LDT_desc(); - put_cpu(); -} - -/* - * load one particular LDT into the current CPU - */ -static inline void load_LDT_nolock(mm_context_t *pc, int cpu) -{ - void *segments = pc->ldt; - int count = pc->size; - - if (likely(!count)) { - segments = &default_ldt[0]; - count = 5; - } - - set_ldt_desc(cpu, segments, count); - load_LDT_desc(); -} +extern struct page *default_ldt_page; +extern void load_LDT_nolock(mm_context_t *pc, int cpu); static inline void load_LDT(mm_context_t *pc) { @@ -123,6 +108,6 @@ static inline void load_LDT(mm_context_t put_cpu(); } -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLY__ */ #endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/early_printk.h 830-ivtv/include/asm-i386/early_printk.h --- 000-virgin/include/asm-i386/early_printk.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/include/asm-i386/early_printk.h Thu Jan 8 10:20:31 2004 @@ -0,0 +1,8 @@ +#ifndef __X86_EARLY_PRINTK_H_I386_ +#define __X86_EARLY_PRINTK_H_I386_ + +#define VGABASE 0xB8000 +#define SERIAL_BASES { 0x3f8, 0x2f8 } +#define SERIAL_BASES_LEN 2 + +#endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/fixmap.h 830-ivtv/include/asm-i386/fixmap.h --- 000-virgin/include/asm-i386/fixmap.h Sat Jun 14 18:37:35 2003 +++ 830-ivtv/include/asm-i386/fixmap.h Thu Jan 8 09:30:59 2004 @@ -18,17 +18,15 @@ #include #include #include -#ifdef CONFIG_HIGHMEM #include #include -#endif /* * Here we define all the compile-time 'special' virtual * addresses. The point is to have a constant address at * compile time, but to set the physical address only - * in the boot process. We allocate these special addresses - * from the end of virtual memory (0xfffff000) backwards. + * in the boot process. We allocate these special addresses + * from the end of virtual memory (0xffffe000) backwards. * Also this lets us do fail-safe vmalloc(), we * can guarantee that these special addresses and * vmalloc()-ed addresses never overlap. @@ -41,11 +39,20 @@ * TLB entries of such buffers will not be flushed across * task switches. */ + +/* + * on UP currently we will have no trace of the fixmap mechanizm, + * no page table allocations, etc. This might change in the + * future, say framebuffers for the console driver(s) could be + * fix-mapped? + */ enum fixed_addresses { FIX_HOLE, FIX_VSYSCALL, #ifdef CONFIG_X86_LOCAL_APIC FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */ +#else + FIX_VSTACK_HOLE_1, #endif #ifdef CONFIG_X86_IO_APIC FIX_IO_APIC_BASE_0, @@ -57,16 +64,21 @@ enum fixed_addresses { FIX_LI_PCIA, /* Lithium PCI Bridge A */ FIX_LI_PCIB, /* Lithium PCI Bridge B */ #endif -#ifdef CONFIG_X86_F00F_BUG - FIX_F00F_IDT, /* Virtual mapping for IDT */ -#endif + FIX_IDT, + FIX_GDT_1, + FIX_GDT_0, + FIX_TSS_3, + FIX_TSS_2, + FIX_TSS_1, + FIX_TSS_0, + FIX_ENTRY_TRAMPOLINE_1, + FIX_ENTRY_TRAMPOLINE_0, #ifdef CONFIG_X86_CYCLONE_TIMER FIX_CYCLONE_TIMER, /*cyclone timer register*/ + FIX_VSTACK_HOLE_2, #endif -#ifdef CONFIG_HIGHMEM FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */ FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1, -#endif #ifdef CONFIG_ACPI_BOOT FIX_ACPI_BEGIN, FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1, @@ -95,12 +107,15 @@ extern void __set_fixmap (enum fixed_add __set_fixmap(idx, 0, __pgprot(0)) /* - * used by vmalloc.c. + * used by vmalloc.c and various other places. * * Leave one empty page between vmalloc'ed areas and * the start of the fixmap. + * + * IMPORTANT: dont change FIXADDR_TOP without adjusting KM_VSTACK0 + * and KM_VSTACK1 so that the virtual stack is 8K aligned. */ -#define FIXADDR_TOP (0xfffff000UL) +#define FIXADDR_TOP (0xffffe000UL) #define __FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT) #define FIXADDR_START (FIXADDR_TOP - __FIXADDR_SIZE) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/highmem.h 830-ivtv/include/asm-i386/highmem.h --- 000-virgin/include/asm-i386/highmem.h Mon Nov 17 18:29:33 2003 +++ 830-ivtv/include/asm-i386/highmem.h Thu Jan 8 09:30:59 2004 @@ -25,26 +25,19 @@ #include #include #include +#include /* declarations for highmem.c */ extern unsigned long highstart_pfn, highend_pfn; -extern pte_t *kmap_pte; -extern pgprot_t kmap_prot; extern pte_t *pkmap_page_table; - -extern void kmap_init(void); +extern void kmap_init(void) __init; /* * Right now we initialize only a single pte table. It can be extended * easily, subsequent pte tables have to be allocated in one physical * chunk of RAM. */ -#if NR_CPUS <= 32 -#define PKMAP_BASE (0xff800000UL) -#else -#define PKMAP_BASE (0xff600000UL) -#endif #ifdef CONFIG_X86_PAE #define LAST_PKMAP 512 #else diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/ioctls.h 830-ivtv/include/asm-i386/ioctls.h --- 000-virgin/include/asm-i386/ioctls.h Tue Apr 8 14:38:20 2003 +++ 830-ivtv/include/asm-i386/ioctls.h Thu Jan 8 11:17:33 2004 @@ -49,6 +49,7 @@ #define TIOCGSID 0x5429 /* Return the session ID of FD */ #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ #define FIONCLEX 0x5450 #define FIOCLEX 0x5451 diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/kexec.h 830-ivtv/include/asm-i386/kexec.h --- 000-virgin/include/asm-i386/kexec.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/include/asm-i386/kexec.h Thu Jan 8 10:26:46 2004 @@ -0,0 +1,23 @@ +#ifndef _I386_KEXEC_H +#define _I386_KEXEC_H + +#include + +/* + * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return. + * I.e. Maximum page that is mapped directly into kernel memory, + * and kmap is not required. + * + * Someone correct me if FIXADDR_START - PAGEOFFSET is not the correct + * calculation for the amount of memory directly mappable into the + * kernel memory space. + */ + +/* Maximum physical address we can use pages from */ +#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL) +/* Maximum address we can reach in physical address mode */ +#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL) + +#define KEXEC_REBOOT_CODE_SIZE 4096 + +#endif /* _I386_KEXEC_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/kgdb.h 830-ivtv/include/asm-i386/kgdb.h --- 000-virgin/include/asm-i386/kgdb.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/include/asm-i386/kgdb.h Thu Jan 8 09:30:18 2004 @@ -0,0 +1,69 @@ +#ifndef __KGDB +#define __KGDB + +/* + * This file should not include ANY others. This makes it usable + * most anywhere without the fear of include order or inclusion. + * Make it so! + * + * This file may be included all the time. It is only active if + * CONFIG_KGDB is defined, otherwise it stubs out all the macros + * and entry points. + */ +#if defined(CONFIG_KGDB) && !defined(__ASSEMBLY__) + +extern void breakpoint(void); +#define INIT_KGDB_INTS kgdb_enable_ints() + +#ifndef BREAKPOINT +#define BREAKPOINT asm(" int $3") +#endif + +extern void kgdb_schedule_breakpoint(void); +extern void kgdb_process_breakpoint(void); + +extern int kgdb_tty_hook(void); +extern int kgdb_eth_hook(void); +extern int kgdboe; + +/* + * GDB debug stub (or any debug stub) can point the 'linux_debug_hook' + * pointer to its routine and it will be entered as the first thing + * when a trap occurs. + * + * Return values are, at present, undefined. + * + * The debug hook routine does not necessarily return to its caller. + * It has the register image and thus may choose to resume execution + * anywhere it pleases. + */ +struct pt_regs; + +extern int kgdb_handle_exception(int trapno, + int signo, int err_code, struct pt_regs *regs); +extern int in_kgdb(struct pt_regs *regs); + +#ifdef CONFIG_KGDB_TS +void kgdb_tstamp(int line, char *source, int data0, int data1); +/* + * This is the time stamp function. The macro adds the source info and + * does a cast on the data to allow most any 32-bit value. + */ + +#define kgdb_ts(data0,data1) kgdb_tstamp(__LINE__,__FILE__,(int)data0,(int)data1) +#else +#define kgdb_ts(data0,data1) +#endif +#else /* CONFIG_KGDB && ! __ASSEMBLY__ ,stubs follow... */ +#ifndef BREAKPOINT +#define BREAKPOINT +#endif +#define kgdb_ts(data0,data1) +#define in_kgdb +#define kgdb_handle_exception +#define breakpoint +#define INIT_KGDB_INTS +#define kgdb_process_breakpoint() do {} while(0) + +#endif +#endif /* __KGDB */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/kgdb_local.h 830-ivtv/include/asm-i386/kgdb_local.h --- 000-virgin/include/asm-i386/kgdb_local.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/include/asm-i386/kgdb_local.h Thu Jan 8 09:30:15 2004 @@ -0,0 +1,102 @@ +#ifndef __KGDB_LOCAL +#define ___KGDB_LOCAL +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT 0x3f8 +#ifdef CONFIG_KGDB_PORT +#undef PORT +#define PORT CONFIG_KGDB_PORT +#endif +#define IRQ 4 +#ifdef CONFIG_KGDB_IRQ +#undef IRQ +#define IRQ CONFIG_KGDB_IRQ +#endif +#define SB_CLOCK 1843200 +#define SB_BASE (SB_CLOCK/16) +#define SB_BAUD9600 SB_BASE/9600 +#define SB_BAUD192 SB_BASE/19200 +#define SB_BAUD384 SB_BASE/38400 +#define SB_BAUD576 SB_BASE/57600 +#define SB_BAUD1152 SB_BASE/115200 +#ifdef CONFIG_KGDB_9600BAUD +#define SB_BAUD SB_BAUD9600 +#endif +#ifdef CONFIG_KGDB_19200BAUD +#define SB_BAUD SB_BAUD192 +#endif +#ifdef CONFIG_KGDB_38400BAUD +#define SB_BAUD SB_BAUD384 +#endif +#ifdef CONFIG_KGDB_57600BAUD +#define SB_BAUD SB_BAUD576 +#endif +#ifdef CONFIG_KGDB_115200BAUD +#define SB_BAUD SB_BAUD1152 +#endif +#ifndef SB_BAUD +#define SB_BAUD SB_BAUD1152 /* Start with this if not given */ +#endif + +#ifndef CONFIG_X86_TSC +#undef rdtsc +#define rdtsc(a,b) if (a++ > 10000){a = 0; b++;} +#undef rdtscll +#define rdtscll(s) s++ +#endif + +#ifdef _raw_read_unlock /* must use a name that is "define"ed, not an inline */ +#undef spin_lock +#undef spin_trylock +#undef spin_unlock +#define spin_lock _raw_spin_lock +#define spin_trylock _raw_spin_trylock +#define spin_unlock _raw_spin_unlock +#else +#endif +#undef spin_unlock_wait +#define spin_unlock_wait(x) do { cpu_relax(); barrier();} \ + while(spin_is_locked(x)) + +#define SB_IER 1 +#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS + +#define FLAGS 0 +#define SB_STATE { \ + magic: SSTATE_MAGIC, \ + baud_base: SB_BASE, \ + port: PORT, \ + irq: IRQ, \ + flags: FLAGS, \ + custom_divisor:SB_BAUD} +#define SB_INFO { \ + magic: SERIAL_MAGIC, \ + port: PORT,0,FLAGS, \ + state: &state, \ + tty: (struct tty_struct *)&state, \ + IER: SB_IER, \ + MCR: SB_MCR} +extern void putDebugChar(int); +/* RTAI support needs us to really stop/start interrupts */ + +#define kgdb_sti() __asm__ __volatile__("sti": : :"memory") +#define kgdb_cli() __asm__ __volatile__("cli": : :"memory") +#define kgdb_local_save_flags(x) __asm__ __volatile__(\ + "pushfl ; popl %0":"=g" (x): /* no input */) +#define kgdb_local_irq_restore(x) __asm__ __volatile__(\ + "pushl %0 ; popfl": \ + /* no output */ :"g" (x):"memory", "cc") +#define kgdb_local_irq_save(x) kgdb_local_save_flags(x); kgdb_cli() + +#ifdef CONFIG_SERIAL +extern void shutdown_for_kgdb(struct async_struct *info); +#endif +#define INIT_KDEBUG putDebugChar("+"); +#endif /* __KGDB_LOCAL */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/kmap_types.h 830-ivtv/include/asm-i386/kmap_types.h --- 000-virgin/include/asm-i386/kmap_types.h Fri May 30 19:02:20 2003 +++ 830-ivtv/include/asm-i386/kmap_types.h Thu Jan 8 09:30:59 2004 @@ -3,30 +3,36 @@ #include -#ifdef CONFIG_DEBUG_HIGHMEM -# define D(n) __KM_FENCE_##n , -#else -# define D(n) -#endif - enum km_type { -D(0) KM_BOUNCE_READ, -D(1) KM_SKB_SUNRPC_DATA, -D(2) KM_SKB_DATA_SOFTIRQ, -D(3) KM_USER0, -D(4) KM_USER1, -D(5) KM_BIO_SRC_IRQ, -D(6) KM_BIO_DST_IRQ, -D(7) KM_PTE0, -D(8) KM_PTE1, -D(9) KM_PTE2, -D(10) KM_IRQ0, -D(11) KM_IRQ1, -D(12) KM_SOFTIRQ0, -D(13) KM_SOFTIRQ1, -D(14) KM_TYPE_NR -}; - -#undef D + /* + * IMPORTANT: don't move these 3 entries, and only add entries in + * pairs: the 4G/4G virtual stack must be 8K aligned on each cpu. + */ + KM_BOUNCE_READ, + KM_VSTACK1, + KM_VSTACK0, + KM_LDT_PAGE15, + KM_LDT_PAGE0 = KM_LDT_PAGE15 + 16-1, + KM_USER_COPY, + KM_VSTACK_HOLE, + KM_SKB_SUNRPC_DATA, + KM_SKB_DATA_SOFTIRQ, + KM_USER0, + KM_USER1, + KM_BIO_SRC_IRQ, + KM_BIO_DST_IRQ, + KM_PTE0, + KM_PTE1, + KM_PTE2, + KM_IRQ0, + KM_IRQ1, + KM_SOFTIRQ0, + KM_SOFTIRQ1, + /* + * Add new entries in pairs: + * the 4G/4G virtual stack must be 8K aligned on each cpu. + */ + KM_TYPE_NR +}; #endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/lockmeter.h 830-ivtv/include/asm-i386/lockmeter.h --- 000-virgin/include/asm-i386/lockmeter.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/include/asm-i386/lockmeter.h Thu Jan 8 10:27:02 2004 @@ -0,0 +1,123 @@ +/* + * Copyright (C) 1999,2000 Silicon Graphics, Inc. + * + * Written by John Hawkes (hawkes@sgi.com) + * Based on klstat.h by Jack Steiner (steiner@sgi.com) + * + * Modified by Ray Bryant (raybry@us.ibm.com) + * Changes Copyright (C) 2000 IBM, Inc. + * Added save of index in spinlock_t to improve efficiency + * of "hold" time reporting for spinlocks. + * Added support for hold time statistics for read and write + * locks. + * Moved machine dependent code here from include/lockmeter.h. + * + */ + +#ifndef _I386_LOCKMETER_H +#define _I386_LOCKMETER_H + +#include +#include + +#include + +#ifdef __KERNEL__ +extern unsigned long cpu_khz; +#define CPU_CYCLE_FREQUENCY (cpu_khz * 1000) +#else +#define CPU_CYCLE_FREQUENCY 450000000 +#endif + +#define THIS_CPU_NUMBER smp_processor_id() + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) +#define local_irq_save(x) \ + __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory") + +#define local_irq_restore(x) \ + __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory") +#endif /* Linux version 2.2.x */ + +/* + * macros to cache and retrieve an index value inside of a spin lock + * these macros assume that there are less than 65536 simultaneous + * (read mode) holders of a rwlock. Not normally a problem!! + * we also assume that the hash table has less than 65535 entries. + */ +/* + * instrumented spinlock structure -- never used to allocate storage + * only used in macros below to overlay a spinlock_t + */ +typedef struct inst_spinlock_s { + /* remember, Intel is little endian */ + unsigned short lock; + unsigned short index; +} inst_spinlock_t; +#define PUT_INDEX(lock_ptr,indexv) ((inst_spinlock_t *)(lock_ptr))->index = indexv +#define GET_INDEX(lock_ptr) ((inst_spinlock_t *)(lock_ptr))->index + +/* + * macros to cache and retrieve an index value in a read/write lock + * as well as the cpu where a reader busy period started + * we use the 2nd word (the debug word) for this, so require the + * debug word to be present + */ +/* + * instrumented rwlock structure -- never used to allocate storage + * only used in macros below to overlay a rwlock_t + */ +typedef struct inst_rwlock_s { + volatile int lock; + unsigned short index; + unsigned short cpu; +} inst_rwlock_t; +#define PUT_RWINDEX(rwlock_ptr,indexv) ((inst_rwlock_t *)(rwlock_ptr))->index = indexv +#define GET_RWINDEX(rwlock_ptr) ((inst_rwlock_t *)(rwlock_ptr))->index +#define PUT_RW_CPU(rwlock_ptr,cpuv) ((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv +#define GET_RW_CPU(rwlock_ptr) ((inst_rwlock_t *)(rwlock_ptr))->cpu + +/* + * return the number of readers for a rwlock_t + */ +#define RWLOCK_READERS(rwlock_ptr) rwlock_readers(rwlock_ptr) + +extern inline int rwlock_readers(rwlock_t *rwlock_ptr) +{ + int tmp = (int) rwlock_ptr->lock; + /* read and write lock attempts may cause the lock value to temporarily */ + /* be negative. Until it is >= 0 we know nothing (i. e. can't tell if */ + /* is -1 because it was write locked and somebody tried to read lock it */ + /* or if it is -1 because it was read locked and somebody tried to write*/ + /* lock it. ........................................................... */ + do { + tmp = (int) rwlock_ptr->lock; + } while (tmp < 0); + if (tmp == 0) return(0); + else return(RW_LOCK_BIAS-tmp); +} + +/* + * return true if rwlock is write locked + * (note that other lock attempts can cause the lock value to be negative) + */ +#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) ((rwlock_ptr)->lock <= 0) +#define IABS(x) ((x) > 0 ? (x) : -(x)) +#define RWLOCK_IS_READ_LOCKED(rwlock_ptr) ((IABS((rwlock_ptr)->lock) % RW_LOCK_BIAS) != 0) + +/* this is a lot of typing just to get gcc to emit "rdtsc" */ +static inline long long get_cycles64 (void) +{ + union longlong_u { + long long intlong; + struct intint_s { + uint32_t eax; + uint32_t edx; + } intint; + } longlong; + + rdtsc(longlong.intint.eax,longlong.intint.edx); + return longlong.intlong; +} + +#endif /* _I386_LOCKMETER_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/mman.h 830-ivtv/include/asm-i386/mman.h --- 000-virgin/include/asm-i386/mman.h Mon Nov 17 18:29:33 2003 +++ 830-ivtv/include/asm-i386/mman.h Thu Jan 8 10:22:37 2004 @@ -11,6 +11,11 @@ #define MAP_SHARED 0x01 /* Share changes */ #define MAP_PRIVATE 0x02 /* Changes are private */ +#ifdef CONFIG_HUGETLB_PAGE +#define MAP_HUGETLB 0x04 /* Use huge pages */ +#else +#define MAP_HUGETLB 0x00 +#endif #define MAP_TYPE 0x0f /* Mask for type of mapping */ #define MAP_FIXED 0x10 /* Interpret addr exactly */ #define MAP_ANONYMOUS 0x20 /* don't use a file */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/mmu.h 830-ivtv/include/asm-i386/mmu.h --- 000-virgin/include/asm-i386/mmu.h Fri Dec 13 23:18:12 2002 +++ 830-ivtv/include/asm-i386/mmu.h Thu Jan 8 09:30:59 2004 @@ -8,10 +8,13 @@ * * cpu_vm_mask is used to optimize ldt flushing. */ + +#define MAX_LDT_PAGES 16 + typedef struct { int size; struct semaphore sem; - void *ldt; + struct page *ldt_pages[MAX_LDT_PAGES]; } mm_context_t; #endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/mmu_context.h 830-ivtv/include/asm-i386/mmu_context.h --- 000-virgin/include/asm-i386/mmu_context.h Tue Sep 2 09:55:53 2003 +++ 830-ivtv/include/asm-i386/mmu_context.h Thu Jan 8 09:30:59 2004 @@ -29,6 +29,10 @@ static inline void switch_mm(struct mm_s { int cpu = smp_processor_id(); +#ifdef CONFIG_X86_SWITCH_PAGETABLES + if (tsk->mm) + tsk->thread_info->user_pgd = (void *)__pa(tsk->mm->pgd); +#endif if (likely(prev != next)) { /* stop flush ipis for the previous mm */ cpu_clear(cpu, prev->cpu_vm_mask); @@ -39,12 +43,14 @@ static inline void switch_mm(struct mm_s cpu_set(cpu, next->cpu_vm_mask); /* Re-load page tables */ +#if !defined(CONFIG_X86_SWITCH_PAGETABLES) load_cr3(next->pgd); +#endif /* * load the LDT, if the LDT is different: */ - if (unlikely(prev->context.ldt != next->context.ldt)) + if (unlikely(prev->context.size + next->context.size)) load_LDT_nolock(&next->context, cpu); } #ifdef CONFIG_SMP @@ -56,7 +62,9 @@ static inline void switch_mm(struct mm_s /* We were in lazy tlb mode and leave_mm disabled * tlb flush IPI delivery. We must reload %cr3. */ +#if !defined(CONFIG_X86_SWITCH_PAGETABLES) load_cr3(next->pgd); +#endif load_LDT_nolock(&next->context, cpu); } } @@ -67,6 +75,6 @@ static inline void switch_mm(struct mm_s asm("movl %0,%%fs ; movl %0,%%gs": :"r" (0)) #define activate_mm(prev, next) \ - switch_mm((prev),(next),NULL) + switch_mm((prev),(next),current) #endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/mmzone.h 830-ivtv/include/asm-i386/mmzone.h --- 000-virgin/include/asm-i386/mmzone.h Mon Nov 17 18:28:57 2003 +++ 830-ivtv/include/asm-i386/mmzone.h Thu Jan 8 10:21:14 2004 @@ -10,7 +10,49 @@ #ifdef CONFIG_DISCONTIGMEM +#ifdef CONFIG_NUMA + #ifdef CONFIG_X86_NUMAQ + #include + #else /* summit or generic arch */ + #include + #endif +#else /* !CONFIG_NUMA */ + #define get_memcfg_numa get_memcfg_numa_flat + #define get_zholes_size(n) (0) +#endif /* CONFIG_NUMA */ + extern struct pglist_data *node_data[]; +#define NODE_DATA(nid) (node_data[nid]) + +/* + * generic node memory support, the following assumptions apply: + * + * 1) memory comes in 256Mb contigious chunks which are either present or not + * 2) we will not have more than 64Gb in total + * + * for now assume that 64Gb is max amount of RAM for whole system + * 64Gb / 4096bytes/page = 16777216 pages + */ +#define MAX_NR_PAGES 16777216 +#define MAX_ELEMENTS 256 +#define PAGES_PER_ELEMENT (MAX_NR_PAGES/MAX_ELEMENTS) + +extern u8 physnode_map[]; + +static inline int pfn_to_nid(unsigned long pfn) +{ +#ifdef CONFIG_NUMA + return(physnode_map[(pfn) / PAGES_PER_ELEMENT]); +#else + return 0; +#endif +} + +static inline struct pglist_data *pfn_to_pgdat(unsigned long pfn) +{ + return(NODE_DATA(pfn_to_nid(pfn))); +} + /* * Following are macros that are specific to this numa platform. @@ -43,11 +85,6 @@ extern struct pglist_data *node_data[]; */ #define kvaddr_to_nid(kaddr) pfn_to_nid(__pa(kaddr) >> PAGE_SHIFT) -/* - * Return a pointer to the node data for node n. - */ -#define NODE_DATA(nid) (node_data[nid]) - #define node_mem_map(nid) (NODE_DATA(nid)->node_mem_map) #define node_start_pfn(nid) (NODE_DATA(nid)->node_start_pfn) #define node_end_pfn(nid) \ @@ -92,40 +129,6 @@ extern struct pglist_data *node_data[]; * ( pfn_to_pgdat(pfn) && ((pfn) < node_end_pfn(pfn_to_nid(pfn))) ) */ #define pfn_valid(pfn) ((pfn) < num_physpages) - -/* - * generic node memory support, the following assumptions apply: - * - * 1) memory comes in 256Mb contigious chunks which are either present or not - * 2) we will not have more than 64Gb in total - * - * for now assume that 64Gb is max amount of RAM for whole system - * 64Gb / 4096bytes/page = 16777216 pages - */ -#define MAX_NR_PAGES 16777216 -#define MAX_ELEMENTS 256 -#define PAGES_PER_ELEMENT (MAX_NR_PAGES/MAX_ELEMENTS) - -extern u8 physnode_map[]; - -static inline int pfn_to_nid(unsigned long pfn) -{ - return(physnode_map[(pfn) / PAGES_PER_ELEMENT]); -} -static inline struct pglist_data *pfn_to_pgdat(unsigned long pfn) -{ - return(NODE_DATA(pfn_to_nid(pfn))); -} - -#ifdef CONFIG_X86_NUMAQ -#include -#elif CONFIG_ACPI_SRAT -#include -#elif CONFIG_X86_PC -#define get_zholes_size(n) (0) -#else -#define pfn_to_nid(pfn) (0) -#endif /* CONFIG_X86_NUMAQ */ extern int get_memcfg_numa_flat(void ); /* diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/page.h 830-ivtv/include/asm-i386/page.h --- 000-virgin/include/asm-i386/page.h Tue Apr 8 14:38:20 2003 +++ 830-ivtv/include/asm-i386/page.h Thu Jan 8 10:20:38 2004 @@ -1,6 +1,8 @@ #ifndef _I386_PAGE_H #define _I386_PAGE_H +#include + /* PAGE_SHIFT determines the page size */ #define PAGE_SHIFT 12 #define PAGE_SIZE (1UL << PAGE_SHIFT) @@ -9,11 +11,10 @@ #define LARGE_PAGE_MASK (~(LARGE_PAGE_SIZE-1)) #define LARGE_PAGE_SIZE (1UL << PMD_SHIFT) -#ifdef __KERNEL__ -#ifndef __ASSEMBLY__ - #include +#ifdef __KERNEL__ +#ifndef __ASSEMBLY__ #ifdef CONFIG_X86_USE_3DNOW #include @@ -88,8 +89,30 @@ typedef struct { unsigned long pgprot; } * * If you want more physical memory than this then see the CONFIG_HIGHMEM4G * and CONFIG_HIGHMEM64G options in the kernel configuration. + * + * Note: on PAE the kernel must never go below 32 MB, we use the + * first 8 entries of the 2-level boot pgd for PAE magic. */ +#ifdef CONFIG_X86_4G_VM_LAYOUT +#define __PAGE_OFFSET (0x02000000) +#define TASK_SIZE (0xff000000) +#elif defined(CONFIG_05GB) +#define __PAGE_OFFSET (0xe0000000) +#define TASK_SIZE (0xe0000000) +#elif defined(CONFIG_1GB) +#define __PAGE_OFFSET (0xc0000000) +#define TASK_SIZE (0xc0000000) +#elif defined(CONFIG_2GB) +#define __PAGE_OFFSET (0x80000000) +#define TASK_SIZE (0x80000000) +#elif defined(CONFIG_3GB) +#define __PAGE_OFFSET (0x40000000) +#define TASK_SIZE (0x40000000) +#else +#error I have no idea what VM layout to use +#endif + /* * This much address space is reserved for vmalloc() and iomap() * as well as fixmap mappings. @@ -114,16 +137,10 @@ static __inline__ int get_order(unsigned #endif /* __ASSEMBLY__ */ -#ifdef __ASSEMBLY__ -#define __PAGE_OFFSET (0xC0000000) -#else -#define __PAGE_OFFSET (0xC0000000UL) -#endif - - #define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET) #define VMALLOC_RESERVE ((unsigned long)__VMALLOC_RESERVE) -#define MAXMEM (-__PAGE_OFFSET-__VMALLOC_RESERVE) +#define __MAXMEM (-__PAGE_OFFSET-__VMALLOC_RESERVE) +#define MAXMEM ((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE)) #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/param.h 830-ivtv/include/asm-i386/param.h --- 000-virgin/include/asm-i386/param.h Sun Nov 17 20:29:26 2002 +++ 830-ivtv/include/asm-i386/param.h Thu Jan 8 10:20:35 2004 @@ -2,10 +2,18 @@ #define _ASMi386_PARAM_H #ifdef __KERNEL__ -# define HZ 1000 /* Internal kernel timer frequency */ -# define USER_HZ 100 /* .. some user interfaces are in "ticks" */ -# define CLOCKS_PER_SEC (USER_HZ) /* like times() */ +#include + +#ifdef CONFIG_1000HZ +# define HZ 1000 /* Internal kernel timer frequency */ +#else +# define HZ 100 #endif + +#define USER_HZ 100 /* .. some user interfaces are in "ticks" */ +#define CLOCKS_PER_SEC (USER_HZ) /* like times() */ + +#endif /* __KERNEL__ */ #ifndef HZ #define HZ 100 diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/pgtable.h 830-ivtv/include/asm-i386/pgtable.h --- 000-virgin/include/asm-i386/pgtable.h Mon Nov 17 18:29:33 2003 +++ 830-ivtv/include/asm-i386/pgtable.h Thu Jan 8 10:22:24 2004 @@ -25,6 +25,10 @@ #include #include +#ifdef CONFIG_MMAP_TOPDOWN +#define HAVE_ARCH_UNMAPPED_AREA +#endif + /* * ZERO_PAGE is a global shared page that is always zero: used * for zero-mapped memory areas etc.. @@ -32,16 +36,17 @@ #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) extern unsigned long empty_zero_page[1024]; extern pgd_t swapper_pg_dir[1024]; -extern kmem_cache_t *pgd_cache; -extern kmem_cache_t *pmd_cache; +extern kmem_cache_t *pgd_cache, *pmd_cache, *kpmd_cache; extern spinlock_t pgd_lock; extern struct list_head pgd_list; void pmd_ctor(void *, kmem_cache_t *, unsigned long); +void kpmd_ctor(void *, kmem_cache_t *, unsigned long); void pgd_ctor(void *, kmem_cache_t *, unsigned long); void pgd_dtor(void *, kmem_cache_t *, unsigned long); void pgtable_cache_init(void); void paging_init(void); +void setup_identity_mappings(pgd_t *pgd_base, unsigned long start, unsigned long end); #endif /* !__ASSEMBLY__ */ @@ -51,6 +56,11 @@ void paging_init(void); * newer 3-level PAE-mode page tables. */ #ifndef __ASSEMBLY__ + +extern void set_system_gate(unsigned int n, void *addr); +extern void init_entry_mappings(void); +extern void entry_trampoline_setup(void); + #ifdef CONFIG_X86_PAE # include #else @@ -63,7 +73,12 @@ void paging_init(void); #define PGDIR_SIZE (1UL << PGDIR_SHIFT) #define PGDIR_MASK (~(PGDIR_SIZE-1)) -#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) +#if defined(CONFIG_X86_PAE) && defined(CONFIG_X86_4G_VM_LAYOUT) +# define USER_PTRS_PER_PGD 4 +#else +# define USER_PTRS_PER_PGD ((TASK_SIZE/PGDIR_SIZE) + ((TASK_SIZE % PGDIR_SIZE) + PGDIR_SIZE-1)/PGDIR_SIZE) +#endif + #define FIRST_USER_PGD_NR 0 #define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT) @@ -233,6 +248,7 @@ static inline void ptep_mkdirty(pte_t *p #define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot)) #define mk_pte_huge(entry) ((entry).pte_low |= _PAGE_PRESENT | _PAGE_PSE) +#define mk_pte_phys(physpage, pgprot) pfn_pte((physpage) >> PAGE_SHIFT, pgprot) static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/processor.h 830-ivtv/include/asm-i386/processor.h --- 000-virgin/include/asm-i386/processor.h Thu Jan 8 08:35:49 2004 +++ 830-ivtv/include/asm-i386/processor.h Thu Jan 8 10:26:40 2004 @@ -291,15 +291,14 @@ extern unsigned int machine_submodel_id; extern unsigned int BIOS_revision; extern unsigned int mca_pentium_flag; -/* - * User space process size: 3GB (default). - */ -#define TASK_SIZE (PAGE_OFFSET) - /* This decides where the kernel will search for a free chunk of vm * space during mmap's. */ +#ifdef CONFIG_05GB +#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 16)) +#else #define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3)) +#endif /* * Size of io_bitmap, covering ports 0 to 0x3ff. @@ -406,6 +405,7 @@ struct tss_struct { struct thread_struct { /* cached TLS descriptors. */ struct desc_struct tls_array[GDT_ENTRY_TLS_ENTRIES]; + void *stack_page0, *stack_page1; unsigned long esp0; unsigned long sysenter_cs; unsigned long eip; @@ -449,7 +449,8 @@ struct thread_struct { .io_bitmap = { [ 0 ... IO_BITMAP_LONGS] = ~0 }, \ } -static inline void load_esp0(struct tss_struct *tss, struct thread_struct *thread) +static inline void +load_esp0(struct tss_struct *tss, struct thread_struct *thread) { tss->esp0 = thread->esp0; /* This can only happen when SEP is enabled, no need to test "SEP"arately */ @@ -484,6 +485,23 @@ extern void prepare_to_copy(struct task_ * create a kernel thread without removing it from tasklists */ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); + +#ifdef CONFIG_X86_HIGH_ENTRY +#define virtual_esp0(tsk) \ + ((unsigned long)(tsk)->thread_info->virtual_stack + ((tsk)->thread.esp0 - (unsigned long)(tsk)->thread_info->real_stack)) +#else +# define virtual_esp0(tsk) ((tsk)->thread.esp0) +#endif + +#define load_virtual_esp0(tss, task) \ + do { \ + tss->esp0 = virtual_esp0(task); \ + if (likely(cpu_has_sep) && unlikely(tss->ss1 != task->thread.sysenter_cs)) { \ + tss->ss1 = task->thread.sysenter_cs; \ + wrmsr(MSR_IA32_SYSENTER_CS, \ + task->thread.sysenter_cs, 0); \ + } \ + } while (0) extern unsigned long thread_saved_pc(struct task_struct *tsk); void show_trace(struct task_struct *task, unsigned long *stack); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/rwlock.h 830-ivtv/include/asm-i386/rwlock.h --- 000-virgin/include/asm-i386/rwlock.h Sun Nov 17 20:29:57 2002 +++ 830-ivtv/include/asm-i386/rwlock.h Thu Jan 8 09:30:47 2004 @@ -20,28 +20,52 @@ #define RW_LOCK_BIAS 0x01000000 #define RW_LOCK_BIAS_STR "0x01000000" -#define __build_read_lock_ptr(rw, helper) \ - asm volatile(LOCK "subl $1,(%0)\n\t" \ - "js 2f\n" \ - "1:\n" \ - LOCK_SECTION_START("") \ - "2:\tcall " helper "\n\t" \ - "jmp 1b\n" \ - LOCK_SECTION_END \ - ::"a" (rw) : "memory") - -#define __build_read_lock_const(rw, helper) \ - asm volatile(LOCK "subl $1,%0\n\t" \ - "js 2f\n" \ - "1:\n" \ - LOCK_SECTION_START("") \ - "2:\tpushl %%eax\n\t" \ - "leal %0,%%eax\n\t" \ - "call " helper "\n\t" \ - "popl %%eax\n\t" \ - "jmp 1b\n" \ - LOCK_SECTION_END \ - :"=m" (*(volatile int *)rw) : : "memory") +#ifdef CONFIG_SPINLINE + + #define __build_read_lock_ptr(rw, helper) \ + asm volatile(LOCK "subl $1,(%0)\n\t" \ + "jns 1f\n\t" \ + "call " helper "\n\t" \ + "1:\t" \ + ::"a" (rw) : "memory") + + #define __build_read_lock_const(rw, helper) \ + asm volatile(LOCK "subl $1,%0\n\t" \ + "jns 1f\n\t" \ + "pushl %%eax\n\t" \ + "leal %0,%%eax\n\t" \ + "call " helper "\n\t" \ + "popl %%eax\n\t" \ + "1:\t" \ + :"=m" (*(volatile int *)rw) : : "memory") + +#else /* !CONFIG_SPINLINE */ + + #define __build_read_lock_ptr(rw, helper) \ + asm volatile(LOCK "subl $1,(%0)\n\t" \ + "js 2f\n" \ + "1:\n" \ + LOCK_SECTION_START("") \ + "2:\tcall " helper "\n\t" \ + "jmp 1b\n" \ + LOCK_SECTION_END \ + ::"a" (rw) : "memory") + + #define __build_read_lock_const(rw, helper) \ + asm volatile(LOCK "subl $1,%0\n\t" \ + "js 2f\n" \ + "1:\n" \ + LOCK_SECTION_START("") \ + "2:\tpushl %%eax\n\t" \ + "leal %0,%%eax\n\t" \ + "call " helper "\n\t" \ + "popl %%eax\n\t" \ + "jmp 1b\n" \ + LOCK_SECTION_END \ + :"=m" (*(volatile int *)rw) : : "memory") + +#endif /* CONFIG_SPINLINE */ + #define __build_read_lock(rw, helper) do { \ if (__builtin_constant_p(rw)) \ @@ -50,28 +74,51 @@ __build_read_lock_ptr(rw, helper); \ } while (0) -#define __build_write_lock_ptr(rw, helper) \ - asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \ - "jnz 2f\n" \ - "1:\n" \ - LOCK_SECTION_START("") \ - "2:\tcall " helper "\n\t" \ - "jmp 1b\n" \ - LOCK_SECTION_END \ - ::"a" (rw) : "memory") - -#define __build_write_lock_const(rw, helper) \ - asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",%0\n\t" \ - "jnz 2f\n" \ - "1:\n" \ - LOCK_SECTION_START("") \ - "2:\tpushl %%eax\n\t" \ - "leal %0,%%eax\n\t" \ - "call " helper "\n\t" \ - "popl %%eax\n\t" \ - "jmp 1b\n" \ - LOCK_SECTION_END \ - :"=m" (*(volatile int *)rw) : : "memory") +#ifdef CONFIG_SPINLINE + + #define __build_write_lock_ptr(rw, helper) \ + asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \ + "jz 1f\n\t" \ + "call " helper "\n\t" \ + "1:\n" \ + ::"a" (rw) : "memory") + + #define __build_write_lock_const(rw, helper) \ + asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",%0\n\t" \ + "jz 1f\n\t" \ + "pushl %%eax\n\t" \ + "leal %0,%%eax\n\t" \ + "call " helper "\n\t" \ + "popl %%eax\n\t" \ + "1:\n" \ + :"=m" (*(volatile int *)rw) : : "memory") + +#else /* !CONFIG_SPINLINE */ + + #define __build_write_lock_ptr(rw, helper) \ + asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \ + "jnz 2f\n" \ + "1:\n" \ + LOCK_SECTION_START("") \ + "2:\tcall " helper "\n\t" \ + "jmp 1b\n" \ + LOCK_SECTION_END \ + ::"a" (rw) : "memory") + + #define __build_write_lock_const(rw, helper) \ + asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",%0\n\t" \ + "jnz 2f\n" \ + "1:\n" \ + LOCK_SECTION_START("") \ + "2:\tpushl %%eax\n\t" \ + "leal %0,%%eax\n\t" \ + "call " helper "\n\t" \ + "popl %%eax\n\t" \ + "jmp 1b\n" \ + LOCK_SECTION_END \ + :"=m" (*(volatile int *)rw) : : "memory") + +#endif /* CONFIG_SPINLINE */ #define __build_write_lock(rw, helper) do { \ if (__builtin_constant_p(rw)) \ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/spinlock.h 830-ivtv/include/asm-i386/spinlock.h --- 000-virgin/include/asm-i386/spinlock.h Fri May 30 19:02:20 2003 +++ 830-ivtv/include/asm-i386/spinlock.h Thu Jan 8 09:30:50 2004 @@ -43,18 +43,35 @@ typedef struct { #define spin_is_locked(x) (*(volatile signed char *)(&(x)->lock) <= 0) #define spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x)) -#define spin_lock_string \ - "\n1:\t" \ - "lock ; decb %0\n\t" \ - "js 2f\n" \ - LOCK_SECTION_START("") \ - "2:\t" \ - "rep;nop\n\t" \ - "cmpb $0,%0\n\t" \ - "jle 2b\n\t" \ - "jmp 1b\n" \ - LOCK_SECTION_END +#ifdef CONFIG_SPINLINE + #define spin_lock_string \ + "\n1:\t" \ + "lock ; decb %0\n\t" \ + "js 2f\n" \ + "jmp 3f\n" \ + "2:\t" \ + "rep;nop\n\t" \ + "cmpb $0,%0\n\t" \ + "jle 2b\n\t" \ + "jmp 1b\n" \ + "3:\t" + +#else /* !CONFIG_SPINLINE */ + + #define spin_lock_string \ + "\n1:\t" \ + "lock ; decb %0\n\t" \ + "js 2f\n" \ + LOCK_SECTION_START("") \ + "2:\t" \ + "rep;nop\n\t" \ + "cmpb $0,%0\n\t" \ + "jle 2b\n\t" \ + "jmp 1b\n" \ + LOCK_SECTION_END + +#endif /* CONFIG_SPINLINE */ /* * This works. Despite all the confusion. * (except on PPro SMP or if we are using OOSTORE) @@ -138,6 +155,11 @@ here: */ typedef struct { volatile unsigned int lock; +#ifdef CONFIG_LOCKMETER + /* required for LOCKMETER since all bits in lock are used */ + /* and we need this storage for CPU and lock INDEX */ + unsigned lockmeter_magic; +#endif #ifdef CONFIG_DEBUG_SPINLOCK unsigned magic; #endif @@ -145,11 +167,19 @@ typedef struct { #define RWLOCK_MAGIC 0xdeaf1eed +#ifdef CONFIG_LOCKMETER +#ifdef CONFIG_DEBUG_SPINLOCK +#define RWLOCK_MAGIC_INIT , 0, RWLOCK_MAGIC +#else +#define RWLOCK_MAGIC_INIT , 0 +#endif +#else /* !CONFIG_LOCKMETER */ #ifdef CONFIG_DEBUG_SPINLOCK #define RWLOCK_MAGIC_INIT , RWLOCK_MAGIC #else #define RWLOCK_MAGIC_INIT /* */ #endif +#endif /* !CONFIG_LOCKMETER */ #define RW_LOCK_UNLOCKED (rwlock_t) { RW_LOCK_BIAS RWLOCK_MAGIC_INIT } @@ -195,5 +225,61 @@ static inline int _raw_write_trylock(rwl atomic_add(RW_LOCK_BIAS, count); return 0; } + +#ifdef CONFIG_LOCKMETER +static inline int _raw_read_trylock(rwlock_t *lock) +{ +/* FIXME -- replace with assembler */ + atomic_t *count = (atomic_t *)lock; + atomic_dec(count); + if (count->counter > 0) + return 1; + atomic_inc(count); + return 0; +} +#endif + +#if defined(CONFIG_LOCKMETER) && defined(CONFIG_HAVE_DEC_LOCK) +extern void _metered_spin_lock (spinlock_t *lock); +extern void _metered_spin_unlock(spinlock_t *lock); + +/* + * Matches what is in arch/i386/lib/dec_and_lock.c, except this one is + * "static inline" so that the spin_lock(), if actually invoked, is charged + * against the real caller, not against the catch-all atomic_dec_and_lock + */ +static inline int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) +{ + int counter; + int newcount; + +repeat: + counter = atomic_read(atomic); + newcount = counter-1; + + if (!newcount) + goto slow_path; + + asm volatile("lock; cmpxchgl %1,%2" + :"=a" (newcount) + :"r" (newcount), "m" (atomic->counter), "0" (counter)); + + /* If the above failed, "eax" will have changed */ + if (newcount != counter) + goto repeat; + return 0; + +slow_path: + preempt_disable(); + _metered_spin_lock(lock); + if (atomic_dec_and_test(atomic)) + return 1; + _metered_spin_unlock(lock); + preempt_enable(); + return 0; +} + +#define ATOMIC_DEC_AND_LOCK +#endif #endif /* __ASM_SPINLOCK_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/string.h 830-ivtv/include/asm-i386/string.h --- 000-virgin/include/asm-i386/string.h Thu Jan 8 08:35:49 2004 +++ 830-ivtv/include/asm-i386/string.h Thu Jan 8 09:30:59 2004 @@ -56,6 +56,29 @@ __asm__ __volatile__( return dest; } +/* + * This is a more generic variant of strncpy_count() suitable for + * implementing string-access routines with all sorts of return + * code semantics. It's used by mm/usercopy.c. + */ +static inline size_t strncpy_count(char * dest,const char *src,size_t count) +{ + __asm__ __volatile__( + + "1:\tdecl %0\n\t" + "js 2f\n\t" + "lodsb\n\t" + "stosb\n\t" + "testb %%al,%%al\n\t" + "jne 1b\n\t" + "2:" + "incl %0" + : "=c" (count) + :"S" (src),"D" (dest),"0" (count) : "memory"); + + return count; +} + #define __HAVE_ARCH_STRCAT static inline char * strcat(char * dest,const char * src) { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/thread_info.h 830-ivtv/include/asm-i386/thread_info.h --- 000-virgin/include/asm-i386/thread_info.h Tue Aug 5 20:01:54 2003 +++ 830-ivtv/include/asm-i386/thread_info.h Thu Jan 8 09:30:59 2004 @@ -33,23 +33,12 @@ struct thread_info { 0-0xBFFFFFFF for user-thead 0-0xFFFFFFFF for kernel-thread */ - struct restart_block restart_block; + void *real_stack, *virtual_stack, *user_pgd; + struct restart_block restart_block; __u8 supervisor_stack[0]; }; -#else /* !__ASSEMBLY__ */ - -/* offsets into the thread_info struct for assembly code access */ -#define TI_TASK 0x00000000 -#define TI_EXEC_DOMAIN 0x00000004 -#define TI_FLAGS 0x00000008 -#define TI_STATUS 0x0000000C -#define TI_CPU 0x00000010 -#define TI_PRE_COUNT 0x00000014 -#define TI_ADDR_LIMIT 0x00000018 -#define TI_RESTART_BLOCK 0x000001C - #endif #define PREEMPT_ACTIVE 0x4000000 @@ -61,7 +50,7 @@ struct thread_info { */ #ifndef __ASSEMBLY__ -#define INIT_THREAD_INFO(tsk) \ +#define INIT_THREAD_INFO(tsk, thread_info) \ { \ .task = &tsk, \ .exec_domain = &default_exec_domain, \ @@ -72,6 +61,7 @@ struct thread_info { .restart_block = { \ .fn = do_no_restart_syscall, \ }, \ + .real_stack = &thread_info, \ } #define init_thread_info (init_thread_union.thread_info) @@ -113,6 +103,7 @@ static inline struct thread_info *curren #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ #define TIF_SINGLESTEP 4 /* restore singlestep on return to user mode */ #define TIF_IRET 5 /* return with iret */ +#define TIF_DB7 6 /* has debug registers */ #define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */ #define _TIF_SYSCALL_TRACE (1<active_mm) __flush_tlb(); +#endif } static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) { +#ifndef CONFIG_X86_SWITCH_PAGETABLES if (vma->vm_mm == current->active_mm) __flush_tlb_one(addr); +#endif } static inline void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { +#ifndef CONFIG_X86_SWITCH_PAGETABLES if (vma->vm_mm == current->active_mm) __flush_tlb(); +#endif } #else @@ -111,11 +117,10 @@ static inline void flush_tlb_range(struc __flush_tlb() extern void flush_tlb_all(void); -extern void flush_tlb_current_task(void); extern void flush_tlb_mm(struct mm_struct *); extern void flush_tlb_page(struct vm_area_struct *, unsigned long); -#define flush_tlb() flush_tlb_current_task() +#define flush_tlb() flush_tlb_all() static inline void flush_tlb_range(struct vm_area_struct * vma, unsigned long start, unsigned long end) { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/uaccess.h 830-ivtv/include/asm-i386/uaccess.h --- 000-virgin/include/asm-i386/uaccess.h Mon Nov 17 18:28:57 2003 +++ 830-ivtv/include/asm-i386/uaccess.h Thu Jan 8 09:30:59 2004 @@ -26,7 +26,7 @@ #define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFFUL) -#define USER_DS MAKE_MM_SEG(PAGE_OFFSET) +#define USER_DS MAKE_MM_SEG(TASK_SIZE) #define get_ds() (KERNEL_DS) #define get_fs() (current_thread_info()->addr_limit) @@ -149,6 +149,45 @@ extern void __get_user_4(void); :"=a" (ret),"=d" (x) \ :"0" (ptr)) +extern int get_user_size(unsigned int size, void *val, const void *ptr); +extern int put_user_size(unsigned int size, const void *val, void *ptr); +extern int zero_user_size(unsigned int size, void *ptr); +extern int copy_str_fromuser_size(unsigned int size, void *val, const void *ptr); +extern int strlen_fromuser_size(unsigned int size, const void *ptr); + + +# define indirect_get_user(x,ptr) \ +({ int __ret_gu,__val_gu; \ + __typeof__(ptr) __ptr_gu = (ptr); \ + __ret_gu = get_user_size(sizeof(*__ptr_gu), &__val_gu,__ptr_gu) ? -EFAULT : 0;\ + (x) = (__typeof__(*__ptr_gu))__val_gu; \ + __ret_gu; \ +}) +#define indirect_put_user(x,ptr) \ +({ \ + __typeof__(*(ptr)) *__ptr_pu = (ptr), __x_pu = (x); \ + put_user_size(sizeof(*__ptr_pu), &__x_pu, __ptr_pu) ? -EFAULT : 0; \ +}) +#define __indirect_put_user indirect_put_user +#define __indirect_get_user indirect_get_user + +#define indirect_copy_from_user(to,from,n) get_user_size(n,to,from) +#define indirect_copy_to_user(to,from,n) put_user_size(n,from,to) + +#define __indirect_copy_from_user indirect_copy_from_user +#define __indirect_copy_to_user indirect_copy_to_user + +#define indirect_strncpy_from_user(dst, src, count) \ + copy_str_fromuser_size(count, dst, src) + +extern int strlen_fromuser_size(unsigned int size, const void *ptr); +#define indirect_strnlen_user(str, n) strlen_fromuser_size(n, str) +#define indirect_strlen_user(str) indirect_strnlen_user(str, ~0UL >> 1) + +extern int zero_user_size(unsigned int size, void *ptr); + +#define indirect_clear_user(mem, len) zero_user_size(len, mem) +#define __indirect_clear_user clear_user /* Careful: we have to cast the result to the type of the pointer for sign reasons */ /** @@ -168,7 +207,7 @@ extern void __get_user_4(void); * Returns zero on success, or -EFAULT on error. * On error, the variable @x is set to zero. */ -#define get_user(x,ptr) \ +#define direct_get_user(x,ptr) \ ({ int __ret_gu,__val_gu; \ switch(sizeof (*(ptr))) { \ case 1: __get_user_x(1,__ret_gu,__val_gu,ptr); break; \ @@ -198,7 +237,7 @@ extern void __put_user_bad(void); * * Returns zero on success, or -EFAULT on error. */ -#define put_user(x,ptr) \ +#define direct_put_user(x,ptr) \ __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) @@ -222,7 +261,7 @@ extern void __put_user_bad(void); * Returns zero on success, or -EFAULT on error. * On error, the variable @x is set to zero. */ -#define __get_user(x,ptr) \ +#define __direct_get_user(x,ptr) \ __get_user_nocheck((x),(ptr),sizeof(*(ptr))) @@ -245,7 +284,7 @@ extern void __put_user_bad(void); * * Returns zero on success, or -EFAULT on error. */ -#define __put_user(x,ptr) \ +#define __direct_put_user(x,ptr) \ __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) #define __put_user_nocheck(x,ptr,size) \ @@ -396,7 +435,7 @@ unsigned long __copy_from_user_ll(void * * On success, this will be zero. */ static inline unsigned long -__copy_to_user(void __user *to, const void *from, unsigned long n) +__direct_copy_to_user(void __user *to, const void *from, unsigned long n) { if (__builtin_constant_p(n)) { unsigned long ret; @@ -434,7 +473,7 @@ __copy_to_user(void __user *to, const vo * data to the requested size using zero bytes. */ static inline unsigned long -__copy_from_user(void *to, const void __user *from, unsigned long n) +__direct_copy_from_user(void *to, const void __user *from, unsigned long n) { if (__builtin_constant_p(n)) { unsigned long ret; @@ -468,11 +507,11 @@ __copy_from_user(void *to, const void __ * On success, this will be zero. */ static inline unsigned long -copy_to_user(void __user *to, const void *from, unsigned long n) +direct_copy_to_user(void __user *to, const void *from, unsigned long n) { might_sleep(); if (access_ok(VERIFY_WRITE, to, n)) - n = __copy_to_user(to, from, n); + n = __direct_copy_to_user(to, from, n); return n; } @@ -493,11 +532,11 @@ copy_to_user(void __user *to, const void * data to the requested size using zero bytes. */ static inline unsigned long -copy_from_user(void *to, const void __user *from, unsigned long n) +direct_copy_from_user(void *to, const void __user *from, unsigned long n) { might_sleep(); if (access_ok(VERIFY_READ, from, n)) - n = __copy_from_user(to, from, n); + n = __direct_copy_from_user(to, from, n); else memset(to, 0, n); return n; @@ -520,10 +559,68 @@ long __strncpy_from_user(char *dst, cons * If there is a limit on the length of a valid string, you may wish to * consider using strnlen_user() instead. */ -#define strlen_user(str) strnlen_user(str, ~0UL >> 1) -long strnlen_user(const char __user *str, long n); -unsigned long clear_user(void __user *mem, unsigned long len); -unsigned long __clear_user(void __user *mem, unsigned long len); +long direct_strncpy_from_user(char *dst, const char *src, long count); +long __direct_strncpy_from_user(char *dst, const char *src, long count); +#define direct_strlen_user(str) direct_strnlen_user(str, ~0UL >> 1) +long direct_strnlen_user(const char *str, long n); +unsigned long direct_clear_user(void *mem, unsigned long len); +unsigned long __direct_clear_user(void *mem, unsigned long len); + +extern int indirect_uaccess; + +#ifdef CONFIG_X86_UACCESS_INDIRECT + +/* + * Return code and zeroing semantics: + + __clear_user 0 <-> bytes not done + clear_user 0 <-> bytes not done + __copy_to_user 0 <-> bytes not done + copy_to_user 0 <-> bytes not done + __copy_from_user 0 <-> bytes not done, zero rest + copy_from_user 0 <-> bytes not done, zero rest + __get_user 0 <-> -EFAULT + get_user 0 <-> -EFAULT + __put_user 0 <-> -EFAULT + put_user 0 <-> -EFAULT + strlen_user strlen + 1 <-> 0 + strnlen_user strlen + 1 (or n+1) <-> 0 + strncpy_from_user strlen (or n) <-> -EFAULT + + */ + +#define __clear_user(mem,len) __indirect_clear_user(mem,len) +#define clear_user(mem,len) indirect_clear_user(mem,len) +#define __copy_to_user(to,from,n) __indirect_copy_to_user(to,from,n) +#define copy_to_user(to,from,n) indirect_copy_to_user(to,from,n) +#define __copy_from_user(to,from,n) __indirect_copy_from_user(to,from,n) +#define copy_from_user(to,from,n) indirect_copy_from_user(to,from,n) +#define __get_user(val,ptr) __indirect_get_user(val,ptr) +#define get_user(val,ptr) indirect_get_user(val,ptr) +#define __put_user(val,ptr) __indirect_put_user(val,ptr) +#define put_user(val,ptr) indirect_put_user(val,ptr) +#define strlen_user(str) indirect_strlen_user(str) +#define strnlen_user(src,count) indirect_strnlen_user(src,count) +#define strncpy_from_user(dst,src,count) \ + indirect_strncpy_from_user(dst,src,count) + +#else + +#define __clear_user __direct_clear_user +#define clear_user direct_clear_user +#define __copy_to_user __direct_copy_to_user +#define copy_to_user direct_copy_to_user +#define __copy_from_user __direct_copy_from_user +#define copy_from_user direct_copy_from_user +#define __get_user __direct_get_user +#define get_user direct_get_user +#define __put_user __direct_put_user +#define put_user direct_put_user +#define strlen_user direct_strlen_user +#define strnlen_user direct_strnlen_user +#define strncpy_from_user direct_strncpy_from_user + +#endif /* CONFIG_X86_UACCESS_INDIRECT */ #endif /* __i386_UACCESS_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-i386/unistd.h 830-ivtv/include/asm-i386/unistd.h --- 000-virgin/include/asm-i386/unistd.h Mon Nov 17 18:29:33 2003 +++ 830-ivtv/include/asm-i386/unistd.h Thu Jan 8 10:26:46 2004 @@ -228,7 +228,7 @@ #define __NR_madvise1 219 /* delete when C lib stub is removed */ #define __NR_getdents64 220 #define __NR_fcntl64 221 -/* 223 is unused */ +#define __NR_mbind 223 #define __NR_gettid 224 #define __NR_readahead 225 #define __NR_setxattr 226 @@ -279,8 +279,9 @@ #define __NR_utimes 271 #define __NR_fadvise64_64 272 #define __NR_vserver 273 - -#define NR_syscalls 274 +#define __NR_sys_kexec_load 274 + +#define NR_syscalls 275 /* user-visible error numbers are in the range -1 - -124: see */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-ia64/ioctls.h 830-ivtv/include/asm-ia64/ioctls.h --- 000-virgin/include/asm-ia64/ioctls.h Tue Apr 8 14:38:20 2003 +++ 830-ivtv/include/asm-ia64/ioctls.h Thu Jan 8 11:17:33 2004 @@ -53,6 +53,7 @@ #define TIOCGSID 0x5429 /* Return the session ID of FD */ #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ #define FIOCLEX 0x5451 diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-ia64/lockmeter.h 830-ivtv/include/asm-ia64/lockmeter.h --- 000-virgin/include/asm-ia64/lockmeter.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/include/asm-ia64/lockmeter.h Thu Jan 8 09:30:50 2004 @@ -0,0 +1,72 @@ +/* + * Copyright (C) 1999,2000 Silicon Graphics, Inc. + * + * Written by John Hawkes (hawkes@sgi.com) + * Based on klstat.h by Jack Steiner (steiner@sgi.com) + */ + +#ifndef _IA64_LOCKMETER_H +#define _IA64_LOCKMETER_H + +#ifdef local_cpu_data +#define CPU_CYCLE_FREQUENCY local_cpu_data->itc_freq +#else +#define CPU_CYCLE_FREQUENCY my_cpu_data.itc_freq +#endif +#define get_cycles64() get_cycles() + +#define THIS_CPU_NUMBER smp_processor_id() + +/* + * macros to cache and retrieve an index value inside of a lock + * these macros assume that there are less than 65536 simultaneous + * (read mode) holders of a rwlock. + * we also assume that the hash table has less than 32767 entries. + */ +/* + * instrumented spinlock structure -- never used to allocate storage + * only used in macros below to overlay a spinlock_t + */ +typedef struct inst_spinlock_s { + /* remember, Intel is little endian */ + volatile unsigned short lock; + volatile unsigned short index; +} inst_spinlock_t; +#define PUT_INDEX(lock_ptr,indexv) ((inst_spinlock_t *)(lock_ptr))->index = indexv +#define GET_INDEX(lock_ptr) ((inst_spinlock_t *)(lock_ptr))->index + +/* + * macros to cache and retrieve an index value in a read/write lock + * as well as the cpu where a reader busy period started + * we use the 2nd word (the debug word) for this, so require the + * debug word to be present + */ +/* + * instrumented rwlock structure -- never used to allocate storage + * only used in macros below to overlay a rwlock_t + */ +typedef struct inst_rwlock_s { + volatile int read_counter:31; + volatile int write_lock:1; + volatile unsigned short index; + volatile unsigned short cpu; +} inst_rwlock_t; +#define PUT_RWINDEX(rwlock_ptr,indexv) ((inst_rwlock_t *)(rwlock_ptr))->index = indexv +#define GET_RWINDEX(rwlock_ptr) ((inst_rwlock_t *)(rwlock_ptr))->index +#define PUT_RW_CPU(rwlock_ptr,cpuv) ((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv +#define GET_RW_CPU(rwlock_ptr) ((inst_rwlock_t *)(rwlock_ptr))->cpu + +/* + * return the number of readers for a rwlock_t + */ +#define RWLOCK_READERS(rwlock_ptr) ((rwlock_ptr)->read_counter) + +/* + * return true if rwlock is write locked + * (note that other lock attempts can cause the lock value to be negative) + */ +#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) ((rwlock_ptr)->write_lock) +#define RWLOCK_IS_READ_LOCKED(rwlock_ptr) ((rwlock_ptr)->read_counter) + +#endif /* _IA64_LOCKMETER_H */ + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-ia64/spinlock.h 830-ivtv/include/asm-ia64/spinlock.h --- 000-virgin/include/asm-ia64/spinlock.h Thu Jan 8 08:35:49 2004 +++ 830-ivtv/include/asm-ia64/spinlock.h Thu Jan 8 09:30:50 2004 @@ -110,8 +110,18 @@ do { \ typedef struct { volatile int read_counter : 31; volatile int write_lock : 1; +#ifdef CONFIG_LOCKMETER + /* required for LOCKMETER since all bits in lock are used */ + /* and we need this storage for CPU and lock INDEX */ + unsigned lockmeter_magic; +#endif } rwlock_t; + +#ifdef CONFIG_LOCKMETER +#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0, 0 } +#else #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 } +#endif #define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) #define rwlock_is_locked(x) (*(volatile int *) (x) != 0) @@ -127,6 +137,48 @@ do { \ } \ } while (0) +#ifdef CONFIG_LOCKMETER +/* + * HACK: This works, but still have a timing window that affects performance: + * we see that no one owns the Write lock, then someone * else grabs for Write + * lock before we do a read_lock(). + * This means that on rare occasions our read_lock() will stall and spin-wait + * until we acquire for Read, instead of simply returning a trylock failure. + */ +static inline int _raw_read_trylock(rwlock_t *rw) +{ + if (rw->write_lock) { + return 0; + } else { + _raw_read_lock(rw); + return 1; + } +} + +static inline int _raw_write_trylock(rwlock_t *rw) +{ + if (!(rw->write_lock)) { + /* isn't currently write-locked... that looks promising... */ + if (test_and_set_bit(31, rw) == 0) { + /* now it is write-locked by me... */ + if (rw->read_counter) { + /* really read-locked, so release write-lock and fail */ + clear_bit(31, rw); + } else { + /* we've the the write-lock, no read-lockers... success! */ + barrier(); + return 1; + } + + } + } + + /* falls through ... fails to write-lock */ + barrier(); + return 0; +} +#endif + #define _raw_read_unlock(rw) \ do { \ rwlock_t *__read_lock_ptr = (rw); \ @@ -189,5 +241,26 @@ do { \ smp_mb__before_clear_bit(); /* need barrier before releasing lock... */ \ clear_bit(31, (x)); \ }) + +#ifdef CONFIG_LOCKMETER +extern void _metered_spin_lock (spinlock_t *lock); +extern void _metered_spin_unlock(spinlock_t *lock); + +/* + * Use a less efficient, and inline, atomic_dec_and_lock() if lockmetering + * so we can see the callerPC of who is actually doing the spin_lock(). + * Otherwise, all we see is the generic rollup of all locks done by + * atomic_dec_and_lock(). + */ +static inline int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) +{ + _metered_spin_lock(lock); + if (atomic_dec_and_test(atomic)) + return 1; + _metered_spin_unlock(lock); + return 0; +} +#define ATOMIC_DEC_AND_LOCK +#endif #endif /* _ASM_IA64_SPINLOCK_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-m68k/ioctls.h 830-ivtv/include/asm-m68k/ioctls.h --- 000-virgin/include/asm-m68k/ioctls.h Tue Apr 8 14:38:20 2003 +++ 830-ivtv/include/asm-m68k/ioctls.h Thu Jan 8 11:17:33 2004 @@ -48,6 +48,7 @@ #define TIOCGSID 0x5429 /* Return the session ID of FD */ #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ #define FIOCLEX 0x5451 diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-mips/ioctls.h 830-ivtv/include/asm-mips/ioctls.h --- 000-virgin/include/asm-mips/ioctls.h Wed Jul 2 21:59:13 2003 +++ 830-ivtv/include/asm-mips/ioctls.h Thu Jan 8 11:17:33 2004 @@ -79,6 +79,7 @@ #define TIOCGSID 0x7416 /* Return the session ID of FD */ #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ /* I hope the range from 0x5480 on is free ... */ #define TIOCSCTTY 0x5480 /* become controlling tty */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-mips/lockmeter.h 830-ivtv/include/asm-mips/lockmeter.h --- 000-virgin/include/asm-mips/lockmeter.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/include/asm-mips/lockmeter.h Thu Jan 8 09:30:50 2004 @@ -0,0 +1,126 @@ +/* + * Copyright (C) 1999,2000 Silicon Graphics, Inc. + * + * Written by John Hawkes (hawkes@sgi.com) + * Based on klstat.h by Jack Steiner (steiner@sgi.com) + * Ported to mips32 for Asita Technologies + * by D.J. Barrow ( dj.barrow@asitatechnologies.com ) + */ +#ifndef _ASM_LOCKMETER_H +#define _ASM_LOCKMETER_H + +/* do_gettimeoffset is a function pointer on mips */ +/* & it is not included by */ +#include +#include +#include + +#define SPINLOCK_MAGIC_INIT /* */ + +#define CPU_CYCLE_FREQUENCY get_cpu_cycle_frequency() + +#define THIS_CPU_NUMBER smp_processor_id() + +static uint32_t cpu_cycle_frequency = 0; + +static uint32_t get_cpu_cycle_frequency(void) +{ + /* a total hack, slow and invasive, but ... it works */ + int sec; + uint32_t start_cycles; + struct timeval tv; + + if (cpu_cycle_frequency == 0) { /* uninitialized */ + do_gettimeofday(&tv); + sec = tv.tv_sec; /* set up to catch the tv_sec rollover */ + while (sec == tv.tv_sec) { do_gettimeofday(&tv); } + sec = tv.tv_sec; /* rolled over to a new sec value */ + start_cycles = get_cycles(); + while (sec == tv.tv_sec) { do_gettimeofday(&tv); } + cpu_cycle_frequency = get_cycles() - start_cycles; + } + + return cpu_cycle_frequency; +} + +extern struct timeval xtime; + +static uint64_t get_cycles64(void) +{ + static uint64_t last_get_cycles64 = 0; + uint64_t ret; + unsigned long sec; + unsigned long usec, usec_offset; + +again: + sec = xtime.tv_sec; + usec = xtime.tv_usec; + usec_offset = do_gettimeoffset(); + if ((xtime.tv_sec != sec) || + (xtime.tv_usec != usec)|| + (usec_offset >= 20000)) + goto again; + + ret = ((uint64_t)(usec + usec_offset) * cpu_cycle_frequency); + /* We can't do a normal 64 bit division on mips without libgcc.a */ + do_div(ret,1000000); + ret += ((uint64_t)sec * cpu_cycle_frequency); + + /* XXX why does time go backwards? do_gettimeoffset? general time adj? */ + if (ret <= last_get_cycles64) + ret = last_get_cycles64+1; + last_get_cycles64 = ret; + + return ret; +} + +/* + * macros to cache and retrieve an index value inside of a lock + * these macros assume that there are less than 65536 simultaneous + * (read mode) holders of a rwlock. + * we also assume that the hash table has less than 32767 entries. + * the high order bit is used for write locking a rw_lock + */ +#define INDEX_MASK 0x7FFF0000 +#define READERS_MASK 0x0000FFFF +#define INDEX_SHIFT 16 +#define PUT_INDEX(lockp,index) \ + lockp->lock = (((lockp->lock) & ~INDEX_MASK) | (index) << INDEX_SHIFT) +#define GET_INDEX(lockp) \ + (((lockp->lock) & INDEX_MASK) >> INDEX_SHIFT) + +/* + * macros to cache and retrieve an index value in a read/write lock + * as well as the cpu where a reader busy period started + * we use the 2nd word (the debug word) for this, so require the + * debug word to be present + */ +/* + * instrumented rwlock structure -- never used to allocate storage + * only used in macros below to overlay a rwlock_t + */ +typedef struct inst_rwlock_s { + volatile int lock; + unsigned short index; + unsigned short cpu; +} inst_rwlock_t; +#define PUT_RWINDEX(rwlock_ptr,indexv) ((inst_rwlock_t *)(rwlock_ptr))->index = indexv +#define GET_RWINDEX(rwlock_ptr) ((inst_rwlock_t *)(rwlock_ptr))->index +#define PUT_RW_CPU(rwlock_ptr,cpuv) ((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv +#define GET_RW_CPU(rwlock_ptr) ((inst_rwlock_t *)(rwlock_ptr))->cpu + +/* + * return the number of readers for a rwlock_t + */ +#define RWLOCK_READERS(rwlock_ptr) rwlock_readers(rwlock_ptr) + +extern inline int rwlock_readers(rwlock_t *rwlock_ptr) +{ + int tmp = (int) rwlock_ptr->lock; + return (tmp >= 0) ? tmp : 0; +} + +#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) ((rwlock_ptr)->lock < 0) +#define RWLOCK_IS_READ_LOCKED(rwlock_ptr) ((rwlock_ptr)->lock > 0) + +#endif /* _ASM_LOCKMETER_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-mips/spinlock.h 830-ivtv/include/asm-mips/spinlock.h --- 000-virgin/include/asm-mips/spinlock.h Wed Jul 2 21:59:13 2003 +++ 830-ivtv/include/asm-mips/spinlock.h Thu Jan 8 09:30:50 2004 @@ -91,9 +91,18 @@ static inline unsigned int _raw_spin_try typedef struct { volatile unsigned int lock; +#ifdef CONFIG_LOCKMETER + /* required for LOCKMETER since all bits in lock are used */ + /* and we need this storage for CPU and lock INDEX */ + unsigned lockmeter_magic; +#endif } rwlock_t; +#ifdef CONFIG_LOCKMETER +#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 } +#else #define RW_LOCK_UNLOCKED (rwlock_t) { 0 } +#endif #define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-ppc/ioctls.h 830-ivtv/include/asm-ppc/ioctls.h --- 000-virgin/include/asm-ppc/ioctls.h Tue Apr 8 14:38:20 2003 +++ 830-ivtv/include/asm-ppc/ioctls.h Thu Jan 8 11:17:33 2004 @@ -88,6 +88,7 @@ #define TIOCGSID 0x5429 /* Return the session ID of FD */ #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ #define TIOCSERCONFIG 0x5453 #define TIOCSERGWILD 0x5454 diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-ppc64/ioctls.h 830-ivtv/include/asm-ppc64/ioctls.h --- 000-virgin/include/asm-ppc64/ioctls.h Tue Apr 8 14:38:20 2003 +++ 830-ivtv/include/asm-ppc64/ioctls.h Thu Jan 8 11:17:33 2004 @@ -95,6 +95,7 @@ #define TIOCGSID 0x5429 /* Return the session ID of FD */ #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ #define TIOCSERCONFIG 0x5453 #define TIOCSERGWILD 0x5454 diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-ppc64/mman.h 830-ivtv/include/asm-ppc64/mman.h --- 000-virgin/include/asm-ppc64/mman.h Mon Nov 17 18:28:58 2003 +++ 830-ivtv/include/asm-ppc64/mman.h Thu Jan 8 10:22:37 2004 @@ -18,6 +18,11 @@ #define MAP_SHARED 0x01 /* Share changes */ #define MAP_PRIVATE 0x02 /* Changes are private */ +#ifdef CONFIG_HUGETLB_PAGE +#define MAP_HUGETLB 0x04 +#else +#define MAP_HUGETLB 0x0 +#endif #define MAP_TYPE 0x0f /* Mask for type of mapping */ #define MAP_FIXED 0x10 /* Interpret addr exactly */ #define MAP_ANONYMOUS 0x20 /* don't use a file */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-s390/ioctls.h 830-ivtv/include/asm-s390/ioctls.h --- 000-virgin/include/asm-s390/ioctls.h Tue Apr 8 14:38:20 2003 +++ 830-ivtv/include/asm-s390/ioctls.h Thu Jan 8 11:17:33 2004 @@ -56,6 +56,7 @@ #define TIOCGSID 0x5429 /* Return the session ID of FD */ #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ #define FIOCLEX 0x5451 diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-sh/ioctls.h 830-ivtv/include/asm-sh/ioctls.h --- 000-virgin/include/asm-sh/ioctls.h Tue Apr 8 14:38:20 2003 +++ 830-ivtv/include/asm-sh/ioctls.h Thu Jan 8 11:17:33 2004 @@ -80,6 +80,7 @@ #define TIOCGSID _IOR('T', 41, pid_t) /* 0x5429 */ /* Return the session ID of FD */ #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ #define TIOCSERCONFIG _IO('T', 83) /* 0x5453 */ #define TIOCSERGWILD _IOR('T', 84, int) /* 0x5454 */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-sparc/ioctls.h 830-ivtv/include/asm-sparc/ioctls.h --- 000-virgin/include/asm-sparc/ioctls.h Tue Apr 8 14:38:20 2003 +++ 830-ivtv/include/asm-sparc/ioctls.h Thu Jan 8 11:17:33 2004 @@ -15,6 +15,7 @@ #define TCSETS _IOW('T', 9, struct termios) #define TCSETSW _IOW('T', 10, struct termios) #define TCSETSF _IOW('T', 11, struct termios) +#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ /* Note that all the ioctls that are not available in Linux have a * double underscore on the front to: a) avoid some programs to diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-sparc64/ioctls.h 830-ivtv/include/asm-sparc64/ioctls.h --- 000-virgin/include/asm-sparc64/ioctls.h Tue Apr 8 14:38:20 2003 +++ 830-ivtv/include/asm-sparc64/ioctls.h Thu Jan 8 11:17:33 2004 @@ -16,6 +16,7 @@ #define TCSETS _IOW('T', 9, struct termios) #define TCSETSW _IOW('T', 10, struct termios) #define TCSETSF _IOW('T', 11, struct termios) +#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ /* Note that all the ioctls that are not available in Linux have a * double underscore on the front to: a) avoid some programs to diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-sparc64/lockmeter.h 830-ivtv/include/asm-sparc64/lockmeter.h --- 000-virgin/include/asm-sparc64/lockmeter.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/include/asm-sparc64/lockmeter.h Thu Jan 8 09:30:50 2004 @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com) + * Copyright (C) 2003 David S. Miller (davem@redhat.com) + */ + +#ifndef _SPARC64_LOCKMETER_H +#define _SPARC64_LOCKMETER_H + +#include +#include +#include +#include + +/* Actually, this is not the CPU frequency by the system tick + * frequency which is good enough for lock metering. + */ +#define CPU_CYCLE_FREQUENCY (timer_tick_offset * HZ) +#define THIS_CPU_NUMBER smp_processor_id() + +#define PUT_INDEX(lock_ptr,indexv) (lock_ptr)->index = (indexv) +#define GET_INDEX(lock_ptr) (lock_ptr)->index + +#define PUT_RWINDEX(rwlock_ptr,indexv) (rwlock_ptr)->index = (indexv) +#define GET_RWINDEX(rwlock_ptr) (rwlock_ptr)->index +#define PUT_RW_CPU(rwlock_ptr,cpuv) (rwlock_ptr)->cpu = (cpuv) +#define GET_RW_CPU(rwlock_ptr) (rwlock_ptr)->cpu + +#define RWLOCK_READERS(rwlock_ptr) rwlock_readers(rwlock_ptr) + +extern inline int rwlock_readers(rwlock_t *rwlock_ptr) +{ + signed int tmp = rwlock_ptr->lock; + + if (tmp > 0) + return tmp; + else + return 0; +} + +#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) ((signed int)((rwlock_ptr)->lock) < 0) +#define RWLOCK_IS_READ_LOCKED(rwlock_ptr) ((signed int)((rwlock_ptr)->lock) > 0) + +#define get_cycles64() get_cycles() + +#endif /* _SPARC64_LOCKMETER_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-sparc64/spinlock.h 830-ivtv/include/asm-sparc64/spinlock.h --- 000-virgin/include/asm-sparc64/spinlock.h Mon Dec 8 09:55:53 2003 +++ 830-ivtv/include/asm-sparc64/spinlock.h Thu Jan 8 09:30:50 2004 @@ -30,15 +30,23 @@ #ifndef CONFIG_DEBUG_SPINLOCK -typedef unsigned char spinlock_t; -#define SPIN_LOCK_UNLOCKED 0 +typedef struct { + unsigned char lock; + unsigned int index; +} spinlock_t; -#define spin_lock_init(lock) (*((unsigned char *)(lock)) = 0) -#define spin_is_locked(lock) (*((volatile unsigned char *)(lock)) != 0) +#ifdef CONFIG_LOCKMETER +#define SPIN_LOCK_UNLOCKED (spinlock_t) {0, 0} +#else +#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } +#endif + +#define spin_lock_init(__lock) do { *(__lock) = SPIN_LOCK_UNLOCKED; } while(0) +#define spin_is_locked(__lock) (*((volatile unsigned char *)(&((__lock)->lock))) != 0) -#define spin_unlock_wait(lock) \ +#define spin_unlock_wait(__lock) \ do { membar("#LoadLoad"); \ -} while(*((volatile unsigned char *)lock)) +} while(*((volatile unsigned char *)(&(((spinlock_t *)__lock)->lock)))) static __inline__ void _raw_spin_lock(spinlock_t *lock) { @@ -109,17 +117,31 @@ extern int _spin_trylock (spinlock_t *lo #ifndef CONFIG_DEBUG_SPINLOCK -typedef unsigned int rwlock_t; -#define RW_LOCK_UNLOCKED 0 -#define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0) -#define rwlock_is_locked(x) (*(x) != RW_LOCK_UNLOCKED) +#ifdef CONFIG_LOCKMETER +typedef struct { + unsigned int lock; + unsigned int index; + unsigned int cpu; +} rwlock_t; +#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0, 0xff } +#else +typedef struct { + unsigned int lock; +} rwlock_t; +#define RW_LOCK_UNLOCKED (rwlock_t) { 0 } +#endif + +#define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0) +#define rwlock_is_locked(x) ((x)->lock != 0) +extern int __read_trylock(rwlock_t *); extern void __read_lock(rwlock_t *); extern void __read_unlock(rwlock_t *); extern void __write_lock(rwlock_t *); extern void __write_unlock(rwlock_t *); extern int __write_trylock(rwlock_t *); +#define _raw_read_trylock(p) __read_trylock(p) #define _raw_read_lock(p) __read_lock(p) #define _raw_read_unlock(p) __read_unlock(p) #define _raw_write_lock(p) __write_lock(p) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-x86_64/early_printk.h 830-ivtv/include/asm-x86_64/early_printk.h --- 000-virgin/include/asm-x86_64/early_printk.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/include/asm-x86_64/early_printk.h Thu Jan 8 10:20:31 2004 @@ -0,0 +1,8 @@ +#ifndef __X86_EARLY_PRINTK_H_X86_64_ +#define __X86_EARLY_PRINTK_H_X86_64_ + +#define VGABASE 0xffffffff800b8000UL +#define SERIAL_BASES { 0x3f8, 0x2f8 } +#define SERIAL_BASES_LEN 2 + +#endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-x86_64/hpet.h 830-ivtv/include/asm-x86_64/hpet.h --- 000-virgin/include/asm-x86_64/hpet.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/include/asm-x86_64/hpet.h Thu Jan 8 10:20:07 2004 @@ -0,0 +1,59 @@ +#ifndef _ASM_X8664_HPET_H +#define _ASM_X8664_HPET_H 1 + +#include + +/* + * Documentation on HPET can be found at: + * http://www.intel.com/ial/home/sp/pcmmspec.htm + * ftp://download.intel.com/ial/home/sp/mmts098.pdf + */ + +#define HPET_MMAP_SIZE 1024 + +#define HPET_ID 0x000 +#define HPET_PERIOD 0x004 +#define HPET_CFG 0x010 +#define HPET_STATUS 0x020 +#define HPET_COUNTER 0x0f0 +#define HPET_T0_CFG 0x100 +#define HPET_T0_CMP 0x108 +#define HPET_T0_ROUTE 0x110 +#define HPET_T1_CFG 0x120 +#define HPET_T1_CMP 0x128 +#define HPET_T1_ROUTE 0x130 +#define HPET_T2_CFG 0x140 +#define HPET_T2_CMP 0x148 +#define HPET_T2_ROUTE 0x150 + +#define HPET_ID_VENDOR 0xffff0000 +#define HPET_ID_LEGSUP 0x00008000 +#define HPET_ID_NUMBER 0x00001f00 +#define HPET_ID_REV 0x000000ff + +#define HPET_ID_VENDOR_SHIFT 16 +#define HPET_ID_VENDOR_8086 0x8086 + +#define HPET_CFG_ENABLE 0x001 +#define HPET_CFG_LEGACY 0x002 + +#define HPET_TN_ENABLE 0x004 +#define HPET_TN_PERIODIC 0x008 +#define HPET_TN_PERIODIC_CAP 0x010 +#define HPET_TN_SETVAL 0x040 +#define HPET_TN_32BIT 0x100 + +extern int is_hpet_enabled(void); +extern int hpet_rtc_timer_init(void); + +#ifdef CONFIG_HPET_EMULATE_RTC +extern int hpet_mask_rtc_irq_bit(unsigned long bit_mask); +extern int hpet_set_rtc_irq_bit(unsigned long bit_mask); +extern int hpet_set_alarm_time(unsigned char hrs, unsigned char min, unsigned char sec); +extern int hpet_set_periodic_freq(unsigned long freq); +extern int hpet_rtc_dropped_irq(void); +extern int hpet_rtc_timer_init(void); +extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs); +#endif /* CONFIG_HPET_EMULATE_RTC */ + +#endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-x86_64/hw_irq.h 830-ivtv/include/asm-x86_64/hw_irq.h --- 000-virgin/include/asm-x86_64/hw_irq.h Thu Jan 8 08:35:50 2004 +++ 830-ivtv/include/asm-x86_64/hw_irq.h Thu Jan 8 10:20:07 2004 @@ -106,8 +106,6 @@ extern unsigned long io_apic_irqs; extern atomic_t irq_err_count; extern atomic_t irq_mis_count; -extern char _stext, _etext; - #define IO_APIC_IRQ(x) (((x) >= 16) || ((1<<(x)) & io_apic_irqs)) #define __STR(x) #x diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-x86_64/ia32.h 830-ivtv/include/asm-x86_64/ia32.h --- 000-virgin/include/asm-x86_64/ia32.h Mon Nov 17 18:28:20 2003 +++ 830-ivtv/include/asm-x86_64/ia32.h Thu Jan 8 10:20:07 2004 @@ -100,8 +100,11 @@ typedef struct siginfo32 { /* POSIX.1b timers */ struct { - unsigned int _timer1; - unsigned int _timer2; + int _tid; /* timer id */ + int _overrun; /* overrun count */ + sigval_t32 _sigval; /* same as below */ + int _sys_private; /* not to be passed to user */ + int _overrun_incr; /* amount to add to overrun */ } _timer; /* POSIX.1b signals */ @@ -164,9 +167,12 @@ struct ustat32 { #ifdef __KERNEL__ struct user_desc; +struct siginfo_t; int do_get_thread_area(struct thread_struct *t, struct user_desc *u_info); int do_set_thread_area(struct thread_struct *t, struct user_desc *u_info); int ia32_child_tls(struct task_struct *p, struct pt_regs *childregs); +int ia32_copy_siginfo_from_user(siginfo_t *to, siginfo_t32 __user *from); +int ia32_copy_siginfo_to_user(siginfo_t32 __user *to, siginfo_t *from); #endif #endif /* !CONFIG_IA32_SUPPORT */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-x86_64/ioctls.h 830-ivtv/include/asm-x86_64/ioctls.h --- 000-virgin/include/asm-x86_64/ioctls.h Tue Apr 8 14:38:21 2003 +++ 830-ivtv/include/asm-x86_64/ioctls.h Thu Jan 8 11:17:33 2004 @@ -48,6 +48,7 @@ #define TIOCGSID 0x5429 /* Return the session ID of FD */ #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ #define FIOCLEX 0x5451 diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-x86_64/mc146818rtc.h 830-ivtv/include/asm-x86_64/mc146818rtc.h --- 000-virgin/include/asm-x86_64/mc146818rtc.h Sat Jun 14 18:37:37 2003 +++ 830-ivtv/include/asm-x86_64/mc146818rtc.h Thu Jan 8 10:20:07 2004 @@ -24,11 +24,6 @@ outb_p((addr),RTC_PORT(0)); \ outb_p((val),RTC_PORT(1)); \ }) -#ifndef CONFIG_HPET_TIMER #define RTC_IRQ 8 -#else -/* Temporary workaround due to IRQ routing problem. */ -#define RTC_IRQ 0 -#endif #endif /* _ASM_MC146818RTC_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-x86_64/scatterlist.h 830-ivtv/include/asm-x86_64/scatterlist.h --- 000-virgin/include/asm-x86_64/scatterlist.h Wed Jul 2 21:59:15 2003 +++ 830-ivtv/include/asm-x86_64/scatterlist.h Thu Jan 8 10:20:07 2004 @@ -6,6 +6,7 @@ struct scatterlist { unsigned int offset; unsigned int length; dma_addr_t dma_address; + unsigned int dma_length; }; #define ISA_DMA_THRESHOLD (0x00ffffff) @@ -16,6 +17,6 @@ struct scatterlist { * returns. */ #define sg_dma_address(sg) ((sg)->dma_address) -#define sg_dma_len(sg) ((sg)->length) +#define sg_dma_len(sg) ((sg)->dma_length) #endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/asm-x86_64/timex.h 830-ivtv/include/asm-x86_64/timex.h --- 000-virgin/include/asm-x86_64/timex.h Tue Jun 17 20:58:53 2003 +++ 830-ivtv/include/asm-x86_64/timex.h Thu Jan 8 10:20:07 2004 @@ -9,6 +9,7 @@ #include #include #include +#include #define CLOCK_TICK_RATE 1193182 /* Underlying HZ */ #define CLOCK_TICK_FACTOR 20 /* Factor of both 1000000 and CLOCK_TICK_RATE */ @@ -29,34 +30,6 @@ static inline cycles_t get_cycles (void) } extern unsigned int cpu_khz; - -/* - * Documentation on HPET can be found at: - * http://www.intel.com/ial/home/sp/pcmmspec.htm - * ftp://download.intel.com/ial/home/sp/mmts098.pdf - */ - -#define HPET_ID 0x000 -#define HPET_PERIOD 0x004 -#define HPET_CFG 0x010 -#define HPET_STATUS 0x020 -#define HPET_COUNTER 0x0f0 -#define HPET_T0_CFG 0x100 -#define HPET_T0_CMP 0x108 -#define HPET_T0_ROUTE 0x110 - -#define HPET_ID_VENDOR 0xffff0000 -#define HPET_ID_LEGSUP 0x00008000 -#define HPET_ID_NUMBER 0x00000f00 -#define HPET_ID_REV 0x000000ff - -#define HPET_CFG_ENABLE 0x001 -#define HPET_CFG_LEGACY 0x002 - -#define HPET_T0_ENABLE 0x004 -#define HPET_T0_PERIODIC 0x008 -#define HPET_T0_SETVAL 0x040 -#define HPET_T0_32BIT 0x100 extern struct vxtime_data vxtime; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/arcdevice.h 830-ivtv/include/linux/arcdevice.h --- 000-virgin/include/linux/arcdevice.h Tue Aug 5 20:01:55 2003 +++ 830-ivtv/include/linux/arcdevice.h Thu Jan 8 08:54:31 2004 @@ -331,6 +331,7 @@ void arcnet_dump_packet(struct net_devic void arcnet_unregister_proto(struct ArcProto *proto); irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs); void arcdev_setup(struct net_device *dev); +struct net_device *alloc_arcdev(char *name); void arcnet_rx(struct net_device *dev, int bufnum); #endif /* __KERNEL__ */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/chio.h 830-ivtv/include/linux/chio.h --- 000-virgin/include/linux/chio.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/include/linux/chio.h Thu Jan 8 11:16:54 2004 @@ -0,0 +1,168 @@ +/* + * ioctl interface for the scsi media changer driver + */ + +/* changer element types */ +#define CHET_MT 0 /* media transport element (robot) */ +#define CHET_ST 1 /* storage element (media slots) */ +#define CHET_IE 2 /* import/export element */ +#define CHET_DT 3 /* data transfer element (tape/cdrom/whatever) */ +#define CHET_V1 4 /* vendor specific #1 */ +#define CHET_V2 5 /* vendor specific #2 */ +#define CHET_V3 6 /* vendor specific #3 */ +#define CHET_V4 7 /* vendor specific #4 */ + + +/* + * CHIOGPARAMS + * query changer properties + * + * CHIOVGPARAMS + * query vendor-specific element types + * + * accessing elements works by specifing type and unit of the element. + * for eample, storage elements are addressed with type = CHET_ST and + * unit = 0 .. cp_nslots-1 + * + */ +struct changer_params { + int cp_curpicker; /* current transport element */ + int cp_npickers; /* number of transport elements (CHET_MT) */ + int cp_nslots; /* number of storage elements (CHET_ST) */ + int cp_nportals; /* number of import/export elements (CHET_IE) */ + int cp_ndrives; /* number of data transfer elements (CHET_DT) */ +}; +struct changer_vendor_params { + int cvp_n1; /* number of vendor specific elems (CHET_V1) */ + char cvp_label1[16]; + int cvp_n2; /* number of vendor specific elems (CHET_V2) */ + char cvp_label2[16]; + int cvp_n3; /* number of vendor specific elems (CHET_V3) */ + char cvp_label3[16]; + int cvp_n4; /* number of vendor specific elems (CHET_V4) */ + char cvp_label4[16]; + int reserved[8]; +}; + + +/* + * CHIOMOVE + * move a medium from one element to another + */ +struct changer_move { + int cm_fromtype; /* type/unit of source element */ + int cm_fromunit; + int cm_totype; /* type/unit of destination element */ + int cm_tounit; + int cm_flags; +}; +#define CM_INVERT 1 /* flag: rotate media (for double-sided like MOD) */ + + +/* + * CHIOEXCHANGE + * move one medium from element #1 to element #2, + * and another one from element #2 to element #3. + * element #1 and #3 are allowed to be identical. + */ +struct changer_exchange { + int ce_srctype; /* type/unit of element #1 */ + int ce_srcunit; + int ce_fdsttype; /* type/unit of element #2 */ + int ce_fdstunit; + int ce_sdsttype; /* type/unit of element #3 */ + int ce_sdstunit; + int ce_flags; +}; +#define CE_INVERT1 1 +#define CE_INVERT2 2 + + +/* + * CHIOPOSITION + * move the transport element (robot arm) to a specific element. + */ +struct changer_position { + int cp_type; + int cp_unit; + int cp_flags; +}; +#define CP_INVERT 1 + + +/* + * CHIOGSTATUS + * get element status for all elements of a specific type + */ +struct changer_element_status { + int ces_type; + unsigned char *ces_data; +}; +#define CESTATUS_FULL 0x01 /* full */ +#define CESTATUS_IMPEXP 0x02 /* media was imported (inserted by sysop) */ +#define CESTATUS_EXCEPT 0x04 /* error condition */ +#define CESTATUS_ACCESS 0x08 /* access allowed */ +#define CESTATUS_EXENAB 0x10 /* element can export media */ +#define CESTATUS_INENAB 0x20 /* element can import media */ + + +/* + * CHIOGELEM + * get more detailed status informtion for a single element + */ +struct changer_get_element { + int cge_type; /* type/unit */ + int cge_unit; + int cge_status; /* status */ + int cge_errno; /* errno */ + int cge_srctype; /* source element of the last move/exchange */ + int cge_srcunit; + int cge_id; /* scsi id (for data transfer elements) */ + int cge_lun; /* scsi lun (for data transfer elements) */ + char cge_pvoltag[36]; /* primary volume tag */ + char cge_avoltag[36]; /* alternate volume tag */ + int cge_flags; +}; +/* flags */ +#define CGE_ERRNO 0x01 /* errno available */ +#define CGE_INVERT 0x02 /* media inverted */ +#define CGE_SRC 0x04 /* media src available */ +#define CGE_IDLUN 0x08 /* ID+LUN available */ +#define CGE_PVOLTAG 0x10 /* primary volume tag available */ +#define CGE_AVOLTAG 0x20 /* alternate volume tag available */ + + +/* + * CHIOSVOLTAG + * set volume tag + */ +struct changer_set_voltag { + int csv_type; /* type/unit */ + int csv_unit; + char csv_voltag[36]; /* volume tag */ + int csv_flags; +}; +#define CSV_PVOLTAG 0x01 /* primary volume tag */ +#define CSV_AVOLTAG 0x02 /* alternate volume tag */ +#define CSV_CLEARTAG 0x04 /* clear volume tag */ + +/* ioctls */ +#define CHIOMOVE _IOW('c', 1,struct changer_move) +#define CHIOEXCHANGE _IOW('c', 2,struct changer_exchange) +#define CHIOPOSITION _IOW('c', 3,struct changer_position) +#define CHIOGPICKER _IOR('c', 4,int) /* not impl. */ +#define CHIOSPICKER _IOW('c', 5,int) /* not impl. */ +#define CHIOGPARAMS _IOR('c', 6,struct changer_params) +#define CHIOGSTATUS _IOW('c', 8,struct changer_element_status) +#define CHIOGELEM _IOW('c',16,struct changer_get_element) +#define CHIOINITELEM _IO('c',17) +#define CHIOSVOLTAG _IOW('c',18,struct changer_set_voltag) +#define CHIOGVPARAMS _IOR('c',19,struct changer_vendor_params) + +/* ---------------------------------------------------------------------- */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/com20020.h 830-ivtv/include/linux/com20020.h --- 000-virgin/include/linux/com20020.h Fri Feb 21 23:40:48 2003 +++ 830-ivtv/include/linux/com20020.h Thu Jan 8 08:54:31 2004 @@ -29,7 +29,6 @@ int com20020_check(struct net_device *dev); int com20020_found(struct net_device *dev, int shared); -void com20020_remove(struct net_device *dev); /* The number of low I/O ports used by the card. */ #define ARCNET_TOTAL_SIZE 8 diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/compat_ioctl.h 830-ivtv/include/linux/compat_ioctl.h --- 000-virgin/include/linux/compat_ioctl.h Thu Jan 8 08:35:50 2004 +++ 830-ivtv/include/linux/compat_ioctl.h Thu Jan 8 10:20:07 2004 @@ -260,6 +260,7 @@ COMPATIBLE_IOCTL(SIOCATMARK) COMPATIBLE_IOCTL(SIOCSIFLINK) COMPATIBLE_IOCTL(SIOCSIFENCAP) COMPATIBLE_IOCTL(SIOCGIFENCAP) +COMPATIBLE_IOCTL(SIOCSIFNAME) COMPATIBLE_IOCTL(SIOCSIFBR) COMPATIBLE_IOCTL(SIOCGIFBR) COMPATIBLE_IOCTL(SIOCSARP) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/compiler-gcc.h 830-ivtv/include/linux/compiler-gcc.h --- 000-virgin/include/linux/compiler-gcc.h Mon Nov 17 18:28:59 2003 +++ 830-ivtv/include/linux/compiler-gcc.h Thu Jan 8 09:30:30 2004 @@ -13,5 +13,5 @@ shouldn't recognize the original var, and make assumptions about it */ #define RELOC_HIDE(ptr, off) \ ({ unsigned long __ptr; \ - __asm__ ("" : "=g"(__ptr) : "0"(ptr)); \ + __asm__ ("" : "=r"(__ptr) : "0"(ptr)); \ (typeof(ptr)) (__ptr + (off)); }) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/config.h 830-ivtv/include/linux/config.h --- 000-virgin/include/linux/config.h Sun Nov 17 20:29:56 2002 +++ 830-ivtv/include/linux/config.h Thu Jan 8 09:30:15 2004 @@ -2,5 +2,8 @@ #define _LINUX_CONFIG_H #include +#if defined(__i386__) && !defined(IN_BOOTLOADER) +#include +#endif #endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/dwarf2-lang.h 830-ivtv/include/linux/dwarf2-lang.h --- 000-virgin/include/linux/dwarf2-lang.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/include/linux/dwarf2-lang.h Thu Jan 8 09:30:15 2004 @@ -0,0 +1,132 @@ +#ifndef DWARF2_LANG +#define DWARF2_LANG +#include + +/* + * This is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2, or (at your option) any later + * version. + */ +/* + * This file defines macros that allow generation of DWARF debug records + * for asm files. This file is platform independent. Register numbers + * (which are about the only thing that is platform dependent) are to be + * supplied by a platform defined file. + */ +#define DWARF_preamble() .section .debug_frame,"",@progbits +/* + * This macro starts a debug frame section. The debug_frame describes + * where to find the registers that the enclosing function saved on + * entry. + * + * ORD is use by the label generator and should be the same as what is + * passed to CFI_postamble. + * + * pc, pc register gdb ordinal. + * + * code_align this is the factor used to define locations or regions + * where the given definitions apply. If you use labels to define these + * this should be 1. + * + * data_align this is the factor used to define register offsets. If + * you use struct offset, this should be the size of the register in + * bytes or the negative of that. This is how it is used: you will + * define a register as the reference register, say the stack pointer, + * then you will say where a register is located relative to this + * reference registers value, say 40 for register 3 (the gdb register + * number). The <40> will be multiplied by to define the + * byte offset of the given register (3, in this example). So if your + * <40> is the byte offset and the reference register points at the + * begining, you would want 1 for the data_offset. If <40> was the 40th + * 4-byte element in that structure you would want 4. And if your + * reference register points at the end of the structure you would want + * a negative data_align value(and you would have to do other math as + * well). + */ + +#define CFI_preamble(ORD, pc, code_align, data_align) \ +.section .debug_frame,"",@progbits ; \ +frame/**/_/**/ORD: \ + .long end/**/_/**/ORD-start/**/_/**/ORD; \ +start/**/_/**/ORD: \ + .long DW_CIE_ID; \ + .byte DW_CIE_VERSION; \ + .byte 0 ; \ + .uleb128 code_align; \ + .sleb128 data_align; \ + .byte pc; + +/* + * After the above macro and prior to the CFI_postamble, you need to + * define the initial state. This starts with defining the reference + * register and, usually the pc. Here are some helper macros: + */ + +#define CFA_define_reference(reg, offset) \ + .byte DW_CFA_def_cfa; \ + .uleb128 reg; \ + .uleb128 (offset); + +#define CFA_define_offset(reg, offset) \ + .byte (DW_CFA_offset + reg); \ + .uleb128 (offset); + +#define CFI_postamble(ORD) \ + .align 4; \ +end/**/_/**/ORD: +/* + * So now your code pushs stuff on the stack, you need a new location + * and the rules for what to do. This starts a running description of + * the call frame. You need to describe what changes with respect to + * the call registers as the location of the pc moves through the code. + * The following builds an FDE (fram descriptor entry?). Like the + * above, it has a preamble and a postamble. It also is tied to the CFI + * above. + * The first entry after the preamble must be the location in the code + * that the call frame is being described for. + */ +#define FDE_preamble(ORD, fde_no, initial_address, length) \ + .long FDE_end/**/_/**/fde_no-FDE_start/**/_/**/fde_no; \ +FDE_start/**/_/**/fde_no: \ + .long frame/**/_/**/ORD; \ + .long initial_address; \ + .long length; + +#define FDE_postamble(fde_no) \ + .align 4; \ +FDE_end/**/_/**/fde_no: +/* + * That done, you can now add registers, subtract registers, move the + * reference and even change the reference. You can also define a new + * area of code the info applies to. For discontinuous bits you should + * start a new FDE. You may have as many as you like. + */ + +/* + * To advance the address by + */ + +#define FDE_advance(bytes) \ + .byte DW_CFA_advance_loc4 \ + .long bytes + + + +/* + * With the above you can define all the register locations. But + * suppose the reference register moves... Takes the new offset NOT an + * increment. This is how esp is tracked if it is not saved. + */ + +#define CFA_define_cfa_offset(offset) \ + .byte $DW_CFA_def_cfa_offset; \ + .uleb128 (offset); +/* + * Or suppose you want to use a different reference register... + */ +#define CFA_define_cfa_register(reg) \ + .byte DW_CFA_def_cfa_register; \ + .uleb128 reg; + +#endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/dwarf2.h 830-ivtv/include/linux/dwarf2.h --- 000-virgin/include/linux/dwarf2.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/include/linux/dwarf2.h Thu Jan 8 09:30:15 2004 @@ -0,0 +1,738 @@ +/* Declarations and definitions of codes relating to the DWARF2 symbolic + debugging information format. + Copyright (C) 1992, 1993, 1995, 1996, 1997, 1999, 2000, 2001, 2002 + Free Software Foundation, Inc. + + Written by Gary Funck (gary@intrepid.com) The Ada Joint Program + Office (AJPO), Florida State Unviversity and Silicon Graphics Inc. + provided support for this effort -- June 21, 1995. + + Derived from the DWARF 1 implementation written by Ron Guilmette + (rfg@netcom.com), November 1990. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2, or (at your option) any later + version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* This file is derived from the DWARF specification (a public document) + Revision 2.0.0 (July 27, 1993) developed by the UNIX International + Programming Languages Special Interest Group (UI/PLSIG) and distributed + by UNIX International. Copies of this specification are available from + UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054. + + This file also now contains definitions from the DWARF 3 specification. */ + +/* This file is shared between GCC and GDB, and should not contain + prototypes. */ + +#ifndef _ELF_DWARF2_H +#define _ELF_DWARF2_H + +/* Structure found in the .debug_line section. */ +#ifndef __ASSEMBLY__ +typedef struct +{ + unsigned char li_length [4]; + unsigned char li_version [2]; + unsigned char li_prologue_length [4]; + unsigned char li_min_insn_length [1]; + unsigned char li_default_is_stmt [1]; + unsigned char li_line_base [1]; + unsigned char li_line_range [1]; + unsigned char li_opcode_base [1]; +} +DWARF2_External_LineInfo; + +typedef struct +{ + unsigned long li_length; + unsigned short li_version; + unsigned int li_prologue_length; + unsigned char li_min_insn_length; + unsigned char li_default_is_stmt; + int li_line_base; + unsigned char li_line_range; + unsigned char li_opcode_base; +} +DWARF2_Internal_LineInfo; + +/* Structure found in .debug_pubnames section. */ +typedef struct +{ + unsigned char pn_length [4]; + unsigned char pn_version [2]; + unsigned char pn_offset [4]; + unsigned char pn_size [4]; +} +DWARF2_External_PubNames; + +typedef struct +{ + unsigned long pn_length; + unsigned short pn_version; + unsigned long pn_offset; + unsigned long pn_size; +} +DWARF2_Internal_PubNames; + +/* Structure found in .debug_info section. */ +typedef struct +{ + unsigned char cu_length [4]; + unsigned char cu_version [2]; + unsigned char cu_abbrev_offset [4]; + unsigned char cu_pointer_size [1]; +} +DWARF2_External_CompUnit; + +typedef struct +{ + unsigned long cu_length; + unsigned short cu_version; + unsigned long cu_abbrev_offset; + unsigned char cu_pointer_size; +} +DWARF2_Internal_CompUnit; + +typedef struct +{ + unsigned char ar_length [4]; + unsigned char ar_version [2]; + unsigned char ar_info_offset [4]; + unsigned char ar_pointer_size [1]; + unsigned char ar_segment_size [1]; +} +DWARF2_External_ARange; + +typedef struct +{ + unsigned long ar_length; + unsigned short ar_version; + unsigned long ar_info_offset; + unsigned char ar_pointer_size; + unsigned char ar_segment_size; +} +DWARF2_Internal_ARange; + +#define ENUM(name) enum name { +#define IF_NOT_ASM(a) a +#define COMMA , +#else +#define ENUM(name) +#define IF_NOT_ASM(a) +#define COMMA + +#endif + +/* Tag names and codes. */ +ENUM(dwarf_tag) + + DW_TAG_padding = 0x00 COMMA + DW_TAG_array_type = 0x01 COMMA + DW_TAG_class_type = 0x02 COMMA + DW_TAG_entry_point = 0x03 COMMA + DW_TAG_enumeration_type = 0x04 COMMA + DW_TAG_formal_parameter = 0x05 COMMA + DW_TAG_imported_declaration = 0x08 COMMA + DW_TAG_label = 0x0a COMMA + DW_TAG_lexical_block = 0x0b COMMA + DW_TAG_member = 0x0d COMMA + DW_TAG_pointer_type = 0x0f COMMA + DW_TAG_reference_type = 0x10 COMMA + DW_TAG_compile_unit = 0x11 COMMA + DW_TAG_string_type = 0x12 COMMA + DW_TAG_structure_type = 0x13 COMMA + DW_TAG_subroutine_type = 0x15 COMMA + DW_TAG_typedef = 0x16 COMMA + DW_TAG_union_type = 0x17 COMMA + DW_TAG_unspecified_parameters = 0x18 COMMA + DW_TAG_variant = 0x19 COMMA + DW_TAG_common_block = 0x1a COMMA + DW_TAG_common_inclusion = 0x1b COMMA + DW_TAG_inheritance = 0x1c COMMA + DW_TAG_inlined_subroutine = 0x1d COMMA + DW_TAG_module = 0x1e COMMA + DW_TAG_ptr_to_member_type = 0x1f COMMA + DW_TAG_set_type = 0x20 COMMA + DW_TAG_subrange_type = 0x21 COMMA + DW_TAG_with_stmt = 0x22 COMMA + DW_TAG_access_declaration = 0x23 COMMA + DW_TAG_base_type = 0x24 COMMA + DW_TAG_catch_block = 0x25 COMMA + DW_TAG_const_type = 0x26 COMMA + DW_TAG_constant = 0x27 COMMA + DW_TAG_enumerator = 0x28 COMMA + DW_TAG_file_type = 0x29 COMMA + DW_TAG_friend = 0x2a COMMA + DW_TAG_namelist = 0x2b COMMA + DW_TAG_namelist_item = 0x2c COMMA + DW_TAG_packed_type = 0x2d COMMA + DW_TAG_subprogram = 0x2e COMMA + DW_TAG_template_type_param = 0x2f COMMA + DW_TAG_template_value_param = 0x30 COMMA + DW_TAG_thrown_type = 0x31 COMMA + DW_TAG_try_block = 0x32 COMMA + DW_TAG_variant_part = 0x33 COMMA + DW_TAG_variable = 0x34 COMMA + DW_TAG_volatile_type = 0x35 COMMA + /* DWARF 3. */ + DW_TAG_dwarf_procedure = 0x36 COMMA + DW_TAG_restrict_type = 0x37 COMMA + DW_TAG_interface_type = 0x38 COMMA + DW_TAG_namespace = 0x39 COMMA + DW_TAG_imported_module = 0x3a COMMA + DW_TAG_unspecified_type = 0x3b COMMA + DW_TAG_partial_unit = 0x3c COMMA + DW_TAG_imported_unit = 0x3d COMMA + /* SGI/MIPS Extensions. */ + DW_TAG_MIPS_loop = 0x4081 COMMA + /* GNU extensions. */ + DW_TAG_format_label = 0x4101 COMMA /* For FORTRAN 77 and Fortran 90. */ + DW_TAG_function_template = 0x4102 COMMA /* For C++. */ + DW_TAG_class_template = 0x4103 COMMA /* For C++. */ + DW_TAG_GNU_BINCL = 0x4104 COMMA + DW_TAG_GNU_EINCL = 0x4105 COMMA + /* Extensions for UPC. See: http://upc.gwu.edu/~upc. */ + DW_TAG_upc_shared_type = 0x8765 COMMA + DW_TAG_upc_strict_type = 0x8766 COMMA + DW_TAG_upc_relaxed_type = 0x8767 +IF_NOT_ASM(};) + +#define DW_TAG_lo_user 0x4080 +#define DW_TAG_hi_user 0xffff + +/* Flag that tells whether entry has a child or not. */ +#define DW_children_no 0 +#define DW_children_yes 1 + +/* Form names and codes. */ +ENUM(dwarf_form) + + DW_FORM_addr = 0x01 COMMA + DW_FORM_block2 = 0x03 COMMA + DW_FORM_block4 = 0x04 COMMA + DW_FORM_data2 = 0x05 COMMA + DW_FORM_data4 = 0x06 COMMA + DW_FORM_data8 = 0x07 COMMA + DW_FORM_string = 0x08 COMMA + DW_FORM_block = 0x09 COMMA + DW_FORM_block1 = 0x0a COMMA + DW_FORM_data1 = 0x0b COMMA + DW_FORM_flag = 0x0c COMMA + DW_FORM_sdata = 0x0d COMMA + DW_FORM_strp = 0x0e COMMA + DW_FORM_udata = 0x0f COMMA + DW_FORM_ref_addr = 0x10 COMMA + DW_FORM_ref1 = 0x11 COMMA + DW_FORM_ref2 = 0x12 COMMA + DW_FORM_ref4 = 0x13 COMMA + DW_FORM_ref8 = 0x14 COMMA + DW_FORM_ref_udata = 0x15 COMMA + DW_FORM_indirect = 0x16 +IF_NOT_ASM(};) + +/* Attribute names and codes. */ + +ENUM(dwarf_attribute) + + DW_AT_sibling = 0x01 COMMA + DW_AT_location = 0x02 COMMA + DW_AT_name = 0x03 COMMA + DW_AT_ordering = 0x09 COMMA + DW_AT_subscr_data = 0x0a COMMA + DW_AT_byte_size = 0x0b COMMA + DW_AT_bit_offset = 0x0c COMMA + DW_AT_bit_size = 0x0d COMMA + DW_AT_element_list = 0x0f COMMA + DW_AT_stmt_list = 0x10 COMMA + DW_AT_low_pc = 0x11 COMMA + DW_AT_high_pc = 0x12 COMMA + DW_AT_language = 0x13 COMMA + DW_AT_member = 0x14 COMMA + DW_AT_discr = 0x15 COMMA + DW_AT_discr_value = 0x16 COMMA + DW_AT_visibility = 0x17 COMMA + DW_AT_import = 0x18 COMMA + DW_AT_string_length = 0x19 COMMA + DW_AT_common_reference = 0x1a COMMA + DW_AT_comp_dir = 0x1b COMMA + DW_AT_const_value = 0x1c COMMA + DW_AT_containing_type = 0x1d COMMA + DW_AT_default_value = 0x1e COMMA + DW_AT_inline = 0x20 COMMA + DW_AT_is_optional = 0x21 COMMA + DW_AT_lower_bound = 0x22 COMMA + DW_AT_producer = 0x25 COMMA + DW_AT_prototyped = 0x27 COMMA + DW_AT_return_addr = 0x2a COMMA + DW_AT_start_scope = 0x2c COMMA + DW_AT_stride_size = 0x2e COMMA + DW_AT_upper_bound = 0x2f COMMA + DW_AT_abstract_origin = 0x31 COMMA + DW_AT_accessibility = 0x32 COMMA + DW_AT_address_class = 0x33 COMMA + DW_AT_artificial = 0x34 COMMA + DW_AT_base_types = 0x35 COMMA + DW_AT_calling_convention = 0x36 COMMA + DW_AT_count = 0x37 COMMA + DW_AT_data_member_location = 0x38 COMMA + DW_AT_decl_column = 0x39 COMMA + DW_AT_decl_file = 0x3a COMMA + DW_AT_decl_line = 0x3b COMMA + DW_AT_declaration = 0x3c COMMA + DW_AT_discr_list = 0x3d COMMA + DW_AT_encoding = 0x3e COMMA + DW_AT_external = 0x3f COMMA + DW_AT_frame_base = 0x40 COMMA + DW_AT_friend = 0x41 COMMA + DW_AT_identifier_case = 0x42 COMMA + DW_AT_macro_info = 0x43 COMMA + DW_AT_namelist_items = 0x44 COMMA + DW_AT_priority = 0x45 COMMA + DW_AT_segment = 0x46 COMMA + DW_AT_specification = 0x47 COMMA + DW_AT_static_link = 0x48 COMMA + DW_AT_type = 0x49 COMMA + DW_AT_use_location = 0x4a COMMA + DW_AT_variable_parameter = 0x4b COMMA + DW_AT_virtuality = 0x4c COMMA + DW_AT_vtable_elem_location = 0x4d COMMA + /* DWARF 3 values. */ + DW_AT_allocated = 0x4e COMMA + DW_AT_associated = 0x4f COMMA + DW_AT_data_location = 0x50 COMMA + DW_AT_stride = 0x51 COMMA + DW_AT_entry_pc = 0x52 COMMA + DW_AT_use_UTF8 = 0x53 COMMA + DW_AT_extension = 0x54 COMMA + DW_AT_ranges = 0x55 COMMA + DW_AT_trampoline = 0x56 COMMA + DW_AT_call_column = 0x57 COMMA + DW_AT_call_file = 0x58 COMMA + DW_AT_call_line = 0x59 COMMA + /* SGI/MIPS extensions. */ + DW_AT_MIPS_fde = 0x2001 COMMA + DW_AT_MIPS_loop_begin = 0x2002 COMMA + DW_AT_MIPS_tail_loop_begin = 0x2003 COMMA + DW_AT_MIPS_epilog_begin = 0x2004 COMMA + DW_AT_MIPS_loop_unroll_factor = 0x2005 COMMA + DW_AT_MIPS_software_pipeline_depth = 0x2006 COMMA + DW_AT_MIPS_linkage_name = 0x2007 COMMA + DW_AT_MIPS_stride = 0x2008 COMMA + DW_AT_MIPS_abstract_name = 0x2009 COMMA + DW_AT_MIPS_clone_origin = 0x200a COMMA + DW_AT_MIPS_has_inlines = 0x200b COMMA + /* GNU extensions. */ + DW_AT_sf_names = 0x2101 COMMA + DW_AT_src_info = 0x2102 COMMA + DW_AT_mac_info = 0x2103 COMMA + DW_AT_src_coords = 0x2104 COMMA + DW_AT_body_begin = 0x2105 COMMA + DW_AT_body_end = 0x2106 COMMA + DW_AT_GNU_vector = 0x2107 COMMA + /* VMS extensions. */ + DW_AT_VMS_rtnbeg_pd_address = 0x2201 COMMA + /* UPC extension. */ + DW_AT_upc_threads_scaled = 0x3210 +IF_NOT_ASM(};) + +#define DW_AT_lo_user 0x2000 /* Implementation-defined range start. */ +#define DW_AT_hi_user 0x3ff0 /* Implementation-defined range end. */ + +/* Location atom names and codes. */ +ENUM(dwarf_location_atom) + + DW_OP_addr = 0x03 COMMA + DW_OP_deref = 0x06 COMMA + DW_OP_const1u = 0x08 COMMA + DW_OP_const1s = 0x09 COMMA + DW_OP_const2u = 0x0a COMMA + DW_OP_const2s = 0x0b COMMA + DW_OP_const4u = 0x0c COMMA + DW_OP_const4s = 0x0d COMMA + DW_OP_const8u = 0x0e COMMA + DW_OP_const8s = 0x0f COMMA + DW_OP_constu = 0x10 COMMA + DW_OP_consts = 0x11 COMMA + DW_OP_dup = 0x12 COMMA + DW_OP_drop = 0x13 COMMA + DW_OP_over = 0x14 COMMA + DW_OP_pick = 0x15 COMMA + DW_OP_swap = 0x16 COMMA + DW_OP_rot = 0x17 COMMA + DW_OP_xderef = 0x18 COMMA + DW_OP_abs = 0x19 COMMA + DW_OP_and = 0x1a COMMA + DW_OP_div = 0x1b COMMA + DW_OP_minus = 0x1c COMMA + DW_OP_mod = 0x1d COMMA + DW_OP_mul = 0x1e COMMA + DW_OP_neg = 0x1f COMMA + DW_OP_not = 0x20 COMMA + DW_OP_or = 0x21 COMMA + DW_OP_plus = 0x22 COMMA + DW_OP_plus_uconst = 0x23 COMMA + DW_OP_shl = 0x24 COMMA + DW_OP_shr = 0x25 COMMA + DW_OP_shra = 0x26 COMMA + DW_OP_xor = 0x27 COMMA + DW_OP_bra = 0x28 COMMA + DW_OP_eq = 0x29 COMMA + DW_OP_ge = 0x2a COMMA + DW_OP_gt = 0x2b COMMA + DW_OP_le = 0x2c COMMA + DW_OP_lt = 0x2d COMMA + DW_OP_ne = 0x2e COMMA + DW_OP_skip = 0x2f COMMA + DW_OP_lit0 = 0x30 COMMA + DW_OP_lit1 = 0x31 COMMA + DW_OP_lit2 = 0x32 COMMA + DW_OP_lit3 = 0x33 COMMA + DW_OP_lit4 = 0x34 COMMA + DW_OP_lit5 = 0x35 COMMA + DW_OP_lit6 = 0x36 COMMA + DW_OP_lit7 = 0x37 COMMA + DW_OP_lit8 = 0x38 COMMA + DW_OP_lit9 = 0x39 COMMA + DW_OP_lit10 = 0x3a COMMA + DW_OP_lit11 = 0x3b COMMA + DW_OP_lit12 = 0x3c COMMA + DW_OP_lit13 = 0x3d COMMA + DW_OP_lit14 = 0x3e COMMA + DW_OP_lit15 = 0x3f COMMA + DW_OP_lit16 = 0x40 COMMA + DW_OP_lit17 = 0x41 COMMA + DW_OP_lit18 = 0x42 COMMA + DW_OP_lit19 = 0x43 COMMA + DW_OP_lit20 = 0x44 COMMA + DW_OP_lit21 = 0x45 COMMA + DW_OP_lit22 = 0x46 COMMA + DW_OP_lit23 = 0x47 COMMA + DW_OP_lit24 = 0x48 COMMA + DW_OP_lit25 = 0x49 COMMA + DW_OP_lit26 = 0x4a COMMA + DW_OP_lit27 = 0x4b COMMA + DW_OP_lit28 = 0x4c COMMA + DW_OP_lit29 = 0x4d COMMA + DW_OP_lit30 = 0x4e COMMA + DW_OP_lit31 = 0x4f COMMA + DW_OP_reg0 = 0x50 COMMA + DW_OP_reg1 = 0x51 COMMA + DW_OP_reg2 = 0x52 COMMA + DW_OP_reg3 = 0x53 COMMA + DW_OP_reg4 = 0x54 COMMA + DW_OP_reg5 = 0x55 COMMA + DW_OP_reg6 = 0x56 COMMA + DW_OP_reg7 = 0x57 COMMA + DW_OP_reg8 = 0x58 COMMA + DW_OP_reg9 = 0x59 COMMA + DW_OP_reg10 = 0x5a COMMA + DW_OP_reg11 = 0x5b COMMA + DW_OP_reg12 = 0x5c COMMA + DW_OP_reg13 = 0x5d COMMA + DW_OP_reg14 = 0x5e COMMA + DW_OP_reg15 = 0x5f COMMA + DW_OP_reg16 = 0x60 COMMA + DW_OP_reg17 = 0x61 COMMA + DW_OP_reg18 = 0x62 COMMA + DW_OP_reg19 = 0x63 COMMA + DW_OP_reg20 = 0x64 COMMA + DW_OP_reg21 = 0x65 COMMA + DW_OP_reg22 = 0x66 COMMA + DW_OP_reg23 = 0x67 COMMA + DW_OP_reg24 = 0x68 COMMA + DW_OP_reg25 = 0x69 COMMA + DW_OP_reg26 = 0x6a COMMA + DW_OP_reg27 = 0x6b COMMA + DW_OP_reg28 = 0x6c COMMA + DW_OP_reg29 = 0x6d COMMA + DW_OP_reg30 = 0x6e COMMA + DW_OP_reg31 = 0x6f COMMA + DW_OP_breg0 = 0x70 COMMA + DW_OP_breg1 = 0x71 COMMA + DW_OP_breg2 = 0x72 COMMA + DW_OP_breg3 = 0x73 COMMA + DW_OP_breg4 = 0x74 COMMA + DW_OP_breg5 = 0x75 COMMA + DW_OP_breg6 = 0x76 COMMA + DW_OP_breg7 = 0x77 COMMA + DW_OP_breg8 = 0x78 COMMA + DW_OP_breg9 = 0x79 COMMA + DW_OP_breg10 = 0x7a COMMA + DW_OP_breg11 = 0x7b COMMA + DW_OP_breg12 = 0x7c COMMA + DW_OP_breg13 = 0x7d COMMA + DW_OP_breg14 = 0x7e COMMA + DW_OP_breg15 = 0x7f COMMA + DW_OP_breg16 = 0x80 COMMA + DW_OP_breg17 = 0x81 COMMA + DW_OP_breg18 = 0x82 COMMA + DW_OP_breg19 = 0x83 COMMA + DW_OP_breg20 = 0x84 COMMA + DW_OP_breg21 = 0x85 COMMA + DW_OP_breg22 = 0x86 COMMA + DW_OP_breg23 = 0x87 COMMA + DW_OP_breg24 = 0x88 COMMA + DW_OP_breg25 = 0x89 COMMA + DW_OP_breg26 = 0x8a COMMA + DW_OP_breg27 = 0x8b COMMA + DW_OP_breg28 = 0x8c COMMA + DW_OP_breg29 = 0x8d COMMA + DW_OP_breg30 = 0x8e COMMA + DW_OP_breg31 = 0x8f COMMA + DW_OP_regx = 0x90 COMMA + DW_OP_fbreg = 0x91 COMMA + DW_OP_bregx = 0x92 COMMA + DW_OP_piece = 0x93 COMMA + DW_OP_deref_size = 0x94 COMMA + DW_OP_xderef_size = 0x95 COMMA + DW_OP_nop = 0x96 COMMA + /* DWARF 3 extensions. */ + DW_OP_push_object_address = 0x97 COMMA + DW_OP_call2 = 0x98 COMMA + DW_OP_call4 = 0x99 COMMA + DW_OP_call_ref = 0x9a COMMA + /* GNU extensions. */ + DW_OP_GNU_push_tls_address = 0xe0 +IF_NOT_ASM(};) + +#define DW_OP_lo_user 0xe0 /* Implementation-defined range start. */ +#define DW_OP_hi_user 0xff /* Implementation-defined range end. */ + +/* Type encodings. */ +ENUM(dwarf_type) + + DW_ATE_void = 0x0 COMMA + DW_ATE_address = 0x1 COMMA + DW_ATE_boolean = 0x2 COMMA + DW_ATE_complex_float = 0x3 COMMA + DW_ATE_float = 0x4 COMMA + DW_ATE_signed = 0x5 COMMA + DW_ATE_signed_char = 0x6 COMMA + DW_ATE_unsigned = 0x7 COMMA + DW_ATE_unsigned_char = 0x8 COMMA + /* DWARF 3. */ + DW_ATE_imaginary_float = 0x9 +IF_NOT_ASM(};) + +#define DW_ATE_lo_user 0x80 +#define DW_ATE_hi_user 0xff + +/* Array ordering names and codes. */ +ENUM(dwarf_array_dim_ordering) + + DW_ORD_row_major = 0 COMMA + DW_ORD_col_major = 1 +IF_NOT_ASM(};) + +/* Access attribute. */ +ENUM(dwarf_access_attribute) + + DW_ACCESS_public = 1 COMMA + DW_ACCESS_protected = 2 COMMA + DW_ACCESS_private = 3 +IF_NOT_ASM(};) + +/* Visibility. */ +ENUM(dwarf_visibility_attribute) + + DW_VIS_local = 1 COMMA + DW_VIS_exported = 2 COMMA + DW_VIS_qualified = 3 +IF_NOT_ASM(};) + +/* Virtuality. */ +ENUM(dwarf_virtuality_attribute) + + DW_VIRTUALITY_none = 0 COMMA + DW_VIRTUALITY_virtual = 1 COMMA + DW_VIRTUALITY_pure_virtual = 2 +IF_NOT_ASM(};) + +/* Case sensitivity. */ +ENUM(dwarf_id_case) + + DW_ID_case_sensitive = 0 COMMA + DW_ID_up_case = 1 COMMA + DW_ID_down_case = 2 COMMA + DW_ID_case_insensitive = 3 +IF_NOT_ASM(};) + +/* Calling convention. */ +ENUM(dwarf_calling_convention) + + DW_CC_normal = 0x1 COMMA + DW_CC_program = 0x2 COMMA + DW_CC_nocall = 0x3 +IF_NOT_ASM(};) + +#define DW_CC_lo_user 0x40 +#define DW_CC_hi_user 0xff + +/* Inline attribute. */ +ENUM(dwarf_inline_attribute) + + DW_INL_not_inlined = 0 COMMA + DW_INL_inlined = 1 COMMA + DW_INL_declared_not_inlined = 2 COMMA + DW_INL_declared_inlined = 3 +IF_NOT_ASM(};) + +/* Discriminant lists. */ +ENUM(dwarf_discrim_list) + + DW_DSC_label = 0 COMMA + DW_DSC_range = 1 +IF_NOT_ASM(};) + +/* Line number opcodes. */ +ENUM(dwarf_line_number_ops) + + DW_LNS_extended_op = 0 COMMA + DW_LNS_copy = 1 COMMA + DW_LNS_advance_pc = 2 COMMA + DW_LNS_advance_line = 3 COMMA + DW_LNS_set_file = 4 COMMA + DW_LNS_set_column = 5 COMMA + DW_LNS_negate_stmt = 6 COMMA + DW_LNS_set_basic_block = 7 COMMA + DW_LNS_const_add_pc = 8 COMMA + DW_LNS_fixed_advance_pc = 9 COMMA + /* DWARF 3. */ + DW_LNS_set_prologue_end = 10 COMMA + DW_LNS_set_epilogue_begin = 11 COMMA + DW_LNS_set_isa = 12 +IF_NOT_ASM(};) + +/* Line number extended opcodes. */ +ENUM(dwarf_line_number_x_ops) + + DW_LNE_end_sequence = 1 COMMA + DW_LNE_set_address = 2 COMMA + DW_LNE_define_file = 3 +IF_NOT_ASM(};) + +/* Call frame information. */ +ENUM(dwarf_call_frame_info) + + DW_CFA_advance_loc = 0x40 COMMA + DW_CFA_offset = 0x80 COMMA + DW_CFA_restore = 0xc0 COMMA + DW_CFA_nop = 0x00 COMMA + DW_CFA_set_loc = 0x01 COMMA + DW_CFA_advance_loc1 = 0x02 COMMA + DW_CFA_advance_loc2 = 0x03 COMMA + DW_CFA_advance_loc4 = 0x04 COMMA + DW_CFA_offset_extended = 0x05 COMMA + DW_CFA_restore_extended = 0x06 COMMA + DW_CFA_undefined = 0x07 COMMA + DW_CFA_same_value = 0x08 COMMA + DW_CFA_register = 0x09 COMMA + DW_CFA_remember_state = 0x0a COMMA + DW_CFA_restore_state = 0x0b COMMA + DW_CFA_def_cfa = 0x0c COMMA + DW_CFA_def_cfa_register = 0x0d COMMA + DW_CFA_def_cfa_offset = 0x0e COMMA + + /* DWARF 3. */ + DW_CFA_def_cfa_expression = 0x0f COMMA + DW_CFA_expression = 0x10 COMMA + DW_CFA_offset_extended_sf = 0x11 COMMA + DW_CFA_def_cfa_sf = 0x12 COMMA + DW_CFA_def_cfa_offset_sf = 0x13 COMMA + + /* SGI/MIPS specific. */ + DW_CFA_MIPS_advance_loc8 = 0x1d COMMA + + /* GNU extensions. */ + DW_CFA_GNU_window_save = 0x2d COMMA + DW_CFA_GNU_args_size = 0x2e COMMA + DW_CFA_GNU_negative_offset_extended = 0x2f +IF_NOT_ASM(};) + +#define DW_CIE_ID 0xffffffff +#define DW_CIE_VERSION 1 + +#define DW_CFA_extended 0 +#define DW_CFA_lo_user 0x1c +#define DW_CFA_hi_user 0x3f + +#define DW_CHILDREN_no 0x00 +#define DW_CHILDREN_yes 0x01 + +#define DW_ADDR_none 0 + +/* Source language names and codes. */ +ENUM(dwarf_source_language) + + DW_LANG_C89 = 0x0001 COMMA + DW_LANG_C = 0x0002 COMMA + DW_LANG_Ada83 = 0x0003 COMMA + DW_LANG_C_plus_plus = 0x0004 COMMA + DW_LANG_Cobol74 = 0x0005 COMMA + DW_LANG_Cobol85 = 0x0006 COMMA + DW_LANG_Fortran77 = 0x0007 COMMA + DW_LANG_Fortran90 = 0x0008 COMMA + DW_LANG_Pascal83 = 0x0009 COMMA + DW_LANG_Modula2 = 0x000a COMMA + DW_LANG_Java = 0x000b COMMA + /* DWARF 3. */ + DW_LANG_C99 = 0x000c COMMA + DW_LANG_Ada95 = 0x000d COMMA + DW_LANG_Fortran95 = 0x000e COMMA + /* MIPS. */ + DW_LANG_Mips_Assembler = 0x8001 COMMA + /* UPC. */ + DW_LANG_Upc = 0x8765 +IF_NOT_ASM(};) + +#define DW_LANG_lo_user 0x8000 /* Implementation-defined range start. */ +#define DW_LANG_hi_user 0xffff /* Implementation-defined range start. */ + +/* Names and codes for macro information. */ +ENUM(dwarf_macinfo_record_type) + + DW_MACINFO_define = 1 COMMA + DW_MACINFO_undef = 2 COMMA + DW_MACINFO_start_file = 3 COMMA + DW_MACINFO_end_file = 4 COMMA + DW_MACINFO_vendor_ext = 255 +IF_NOT_ASM(};) + +/* @@@ For use with GNU frame unwind information. */ + +#define DW_EH_PE_absptr 0x00 +#define DW_EH_PE_omit 0xff + +#define DW_EH_PE_uleb128 0x01 +#define DW_EH_PE_udata2 0x02 +#define DW_EH_PE_udata4 0x03 +#define DW_EH_PE_udata8 0x04 +#define DW_EH_PE_sleb128 0x09 +#define DW_EH_PE_sdata2 0x0A +#define DW_EH_PE_sdata4 0x0B +#define DW_EH_PE_sdata8 0x0C +#define DW_EH_PE_signed 0x08 + +#define DW_EH_PE_pcrel 0x10 +#define DW_EH_PE_textrel 0x20 +#define DW_EH_PE_datarel 0x30 +#define DW_EH_PE_funcrel 0x40 +#define DW_EH_PE_aligned 0x50 + +#define DW_EH_PE_indirect 0x80 + +#endif /* _ELF_DWARF2_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/early_printk.h 830-ivtv/include/linux/early_printk.h --- 000-virgin/include/linux/early_printk.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/include/linux/early_printk.h Thu Jan 8 10:20:31 2004 @@ -0,0 +1,47 @@ +#ifndef __X86_EARLY_PRINTK_H_ +#define __X86_EARLY_PRINTK_H_ + +#ifdef CONFIG_X86_EARLY_PRINTK +#include +#include +#include +#include +#include +#include + +/* Simple VGA output */ + +#define MAX_YPOS 25 +#define MAX_XPOS 80 + +/* Simple serial port output */ + +#define DEFAULT_BAUD 57600 +#define XMTRDY 0x20 + +#define DLAB 0x80 + +#define TXR 0 /* Transmit register (WRITE) */ +#define RXR 0 /* Receive register (READ) */ +#define IER 1 /* Interrupt Enable */ +#define IIR 2 /* Interrupt ID */ +#define FCR 2 /* FIFO control */ +#define LCR 3 /* Line control */ +#define MCR 4 /* Modem control */ +#define LSR 5 /* Line Status */ +#define MSR 6 /* Modem Status */ +#define DLL 0 /* Divisor Latch Low */ +#define DLH 1 /* Divisor latch High */ + + +void early_printk(const char *fmt, ...); +int __init setup_early_printk(); + +#else + +#define early_printk(...) do {} while(0) +#define setup_early_printk() do {} while(0) + +#endif + +#endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/fs.h 830-ivtv/include/linux/fs.h --- 000-virgin/include/linux/fs.h Thu Jan 8 08:35:50 2004 +++ 830-ivtv/include/linux/fs.h Thu Jan 8 10:21:50 2004 @@ -336,6 +336,9 @@ struct address_space { spinlock_t private_lock; /* for use by the address_space */ struct list_head private_list; /* ditto */ struct address_space *assoc_mapping; /* ditto */ +#ifdef CONFIG_NUMA + struct binding *binding; /* for memory bindings */ +#endif }; struct block_device { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/gfp.h 830-ivtv/include/linux/gfp.h --- 000-virgin/include/linux/gfp.h Tue Sep 2 09:55:55 2003 +++ 830-ivtv/include/linux/gfp.h Thu Jan 8 10:21:46 2004 @@ -32,6 +32,7 @@ #define __GFP_NOFAIL 0x800 /* Retry for ever. Cannot fail */ #define __GFP_NORETRY 0x1000 /* Do not retry. Might fail */ #define __GFP_NO_GROW 0x2000 /* Slab internal usage */ +#define __GFP_NODE_STRICT 0x4000 /* Do not fall back to other nodes */ #define __GFP_BITS_SHIFT 16 /* Room for 16 __GFP_FOO bits */ #define __GFP_BITS_MASK ((1 << __GFP_BITS_SHIFT) - 1) @@ -69,7 +70,7 @@ static inline struct page * alloc_pages_ if (unlikely(order >= MAX_ORDER)) return NULL; - return __alloc_pages(gfp_mask, order, NODE_DATA(nid)->node_zonelists + (gfp_mask & GFP_ZONEMASK)); + return __alloc_pages(gfp_mask, order, get_node_zonelist(nid, gfp_mask)); } #define alloc_pages(gfp_mask, order) \ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/hugetlb.h 830-ivtv/include/linux/hugetlb.h --- 000-virgin/include/linux/hugetlb.h Thu Jan 8 08:35:50 2004 +++ 830-ivtv/include/linux/hugetlb.h Thu Jan 8 10:22:37 2004 @@ -120,4 +120,9 @@ static inline void set_file_hugepages(st #endif /* !CONFIG_HUGETLBFS */ +unsigned long +hugetlb_get_unmapped_area(struct file *, unsigned long, unsigned long, + unsigned long, unsigned long); + + #endif /* _LINUX_HUGETLB_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/if_bonding.h 830-ivtv/include/linux/if_bonding.h --- 000-virgin/include/linux/if_bonding.h Fri May 30 19:02:22 2003 +++ 830-ivtv/include/linux/if_bonding.h Thu Jan 8 08:54:31 2004 @@ -1,7 +1,7 @@ /* * Bond several ethernet interfaces into a Cisco, running 'Etherchannel'. * - * + * * Portions are (c) Copyright 1995 Simon "Guru Aleph-Null" Janes * NCM: Network and Communications Management, Inc. * @@ -10,11 +10,11 @@ * * This software may be used and distributed according to the terms * of the GNU Public License, incorporated herein by reference. - * + * * 2003/03/18 - Amir Noam * - Added support for getting slave's speed and duplex via ethtool. * Needed for 802.3ad and other future modes. - * + * * 2003/03/18 - Tsippy Mendelson and * Shmulik Hen * - Enable support of modes that need to use the unique mac address of @@ -42,7 +42,7 @@ #include /* userland - kernel ABI version (2003/05/08) */ -#define BOND_ABI_VERSION 1 +#define BOND_ABI_VERSION 2 /* * We can remove these ioctl definitions in 2.5. People should use the @@ -77,10 +77,6 @@ #define BOND_DEFAULT_MAX_BONDS 1 /* Default maximum number of devices to support */ -#define BOND_MULTICAST_DISABLED 0 -#define BOND_MULTICAST_ACTIVE 1 -#define BOND_MULTICAST_ALL 2 - typedef struct ifbond { __s32 bond_mode; __s32 num_slaves; @@ -90,9 +86,9 @@ typedef struct ifbond { typedef struct ifslave { __s32 slave_id; /* Used as an IN param to the BOND_SLAVE_INFO_QUERY ioctl */ - char slave_name[IFNAMSIZ]; - char link; - char state; + __s8 slave_name[IFNAMSIZ]; + __s8 link; + __s8 state; __u32 link_failure_count; } ifslave; @@ -115,3 +111,4 @@ struct ad_info { * tab-width: 8 * End: */ + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/kexec.h 830-ivtv/include/linux/kexec.h --- 000-virgin/include/linux/kexec.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/include/linux/kexec.h Thu Jan 8 10:26:46 2004 @@ -0,0 +1,53 @@ +#ifndef LINUX_KEXEC_H +#define LINUX_KEXEC_H + +#if CONFIG_KEXEC +#include +#include +#include + +/* + * This structure is used to hold the arguments that are used when loading + * kernel binaries. + */ + +typedef unsigned long kimage_entry_t; +#define IND_DESTINATION 0x1 +#define IND_INDIRECTION 0x2 +#define IND_DONE 0x4 +#define IND_SOURCE 0x8 + +#define KEXEC_SEGMENT_MAX 8 +struct kexec_segment { + void *buf; + size_t bufsz; + void *mem; + size_t memsz; +}; + +struct kimage { + kimage_entry_t head; + kimage_entry_t *entry; + kimage_entry_t *last_entry; + + unsigned long destination; + unsigned long offset; + + unsigned long start; + struct page *reboot_code_pages; + + unsigned long nr_segments; + struct kexec_segment segment[KEXEC_SEGMENT_MAX+1]; + + struct list_head dest_pages; + struct list_head unuseable_pages; +}; + + +/* kexec interface functions */ +extern void machine_kexec(struct kimage *image); +extern asmlinkage long sys_kexec(unsigned long entry, long nr_segments, + struct kexec_segment *segments); +extern struct kimage *kexec_image; +#endif +#endif /* LINUX_KEXEC_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/lockmeter.h 830-ivtv/include/linux/lockmeter.h --- 000-virgin/include/linux/lockmeter.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/include/linux/lockmeter.h Thu Jan 8 09:30:50 2004 @@ -0,0 +1,320 @@ +/* + * Copyright (C) 1999-2002 Silicon Graphics, Inc. + * + * Written by John Hawkes (hawkes@sgi.com) + * Based on klstat.h by Jack Steiner (steiner@sgi.com) + * + * Modified by Ray Bryant (raybry@us.ibm.com) Feb-Apr 2000 + * Changes Copyright (C) 2000 IBM, Inc. + * Added save of index in spinlock_t to improve efficiency + * of "hold" time reporting for spinlocks + * Added support for hold time statistics for read and write + * locks. + * Moved machine dependent code to include/asm/lockmeter.h. + * + */ + +#ifndef _LINUX_LOCKMETER_H +#define _LINUX_LOCKMETER_H + + +/*--------------------------------------------------- + * architecture-independent lockmeter.h + *-------------------------------------------------*/ + +/* + * raybry -- version 2: added efficient hold time statistics + * requires lstat recompile, so flagged as new version + * raybry -- version 3: added global reader lock data + * hawkes -- version 4: removed some unnecessary fields to simplify mips64 port + */ +#define LSTAT_VERSION 5 + +int lstat_update(void*, void*, int); +int lstat_update_time(void*, void*, int, uint32_t); + +/* + * Currently, the mips64 and sparc64 kernels talk to a 32-bit lockstat, so we + * need to force compatibility in the inter-communication data structure. + */ + +#if defined(CONFIG_MIPS32_COMPAT) +#define TIME_T uint32_t +#elif defined(CONFIG_SPARC) || defined(CONFIG_SPARC64) +#define TIME_T uint64_t +#else +#define TIME_T time_t +#endif + +#if defined(__KERNEL__) || (!defined(CONFIG_MIPS32_COMPAT) && !defined(CONFIG_SPARC) && !defined(CONFIG_SPARC64)) || (_MIPS_SZLONG==32) +#define POINTER void * +#else +#define POINTER int64_t +#endif + +/* + * Values for the "action" parameter passed to lstat_update. + * ZZZ - do we want a try-success status here??? + */ +#define LSTAT_ACT_NO_WAIT 0 +#define LSTAT_ACT_SPIN 1 +#define LSTAT_ACT_REJECT 2 +#define LSTAT_ACT_WW_SPIN 3 +#define LSTAT_ACT_SLEPT 4 /* UNUSED */ + +#define LSTAT_ACT_MAX_VALUES 4 /* NOTE: Increase to 5 if use ACT_SLEPT */ + +/* + * Special values for the low 2 bits of an RA passed to + * lstat_update. + */ +/* we use these values to figure out what kind of lock data */ +/* is stored in the statistics table entry at index ....... */ +#define LSTAT_RA_SPIN 0 /* spin lock data */ +#define LSTAT_RA_READ 1 /* read lock statistics */ +#define LSTAT_RA_SEMA 2 /* RESERVED */ +#define LSTAT_RA_WRITE 3 /* write lock statistics*/ + +#define LSTAT_RA(n) \ + ((void*)( ((unsigned long)__builtin_return_address(0) & ~3) | n) ) + +/* + * Constants used for lock addresses in the lstat_directory + * to indicate special values of the lock address. + */ +#define LSTAT_MULTI_LOCK_ADDRESS NULL + +/* + * Maximum size of the lockstats tables. Increase this value + * if its not big enough. (Nothing bad happens if its not + * big enough although some locks will not be monitored.) + * We record overflows of this quantity in lstat_control.dir_overflows + * + * Note: The max value here must fit into the field set + * and obtained by the macro's PUT_INDEX() and GET_INDEX(). + * This value depends on how many bits are available in the + * lock word in the particular machine implementation we are on. + */ +#define LSTAT_MAX_STAT_INDEX 2000 + +/* + * Size and mask for the hash table into the directory. + */ +#define LSTAT_HASH_TABLE_SIZE 4096 /* must be 2**N */ +#define LSTAT_HASH_TABLE_MASK (LSTAT_HASH_TABLE_SIZE-1) + +#define DIRHASH(ra) ((unsigned long)(ra)>>2 & LSTAT_HASH_TABLE_MASK) + +/* + * This defines an entry in the lockstat directory. It contains + * information about a lock being monitored. + * A directory entry only contains the lock identification - + * counts on usage of the lock are kept elsewhere in a per-cpu + * data structure to minimize cache line pinging. + */ +typedef struct { + POINTER caller_ra; /* RA of code that set lock */ + POINTER lock_ptr; /* lock address */ + ushort next_stat_index; /* Used to link multiple locks that have the same hash table value */ +} lstat_directory_entry_t; + +/* + * A multi-dimensioned array used to contain counts for lock accesses. + * The array is 3-dimensional: + * - CPU number. Keep from thrashing cache lines between CPUs + * - Directory entry index. Identifies the lock + * - Action. Indicates what kind of contention occurred on an + * access to the lock. + * + * The index of an entry in the directory is the same as the 2nd index + * of the entry in the counts array. + */ +/* + * This table contains data for spin_locks, write locks, and read locks + * Not all data is used for all cases. In particular, the hold time + * information is not stored here for read locks since that is a global + * (e. g. cannot be separated out by return address) quantity. + * See the lstat_read_lock_counts_t structure for the global read lock + * hold time. + */ +typedef struct { + uint64_t cum_wait_ticks; /* sum of wait times */ + /* for write locks, sum of time a */ + /* writer is waiting for a reader */ + int64_t cum_hold_ticks; /* cumulative sum of holds */ + /* not used for read mode locks */ + /* must be signed. ............... */ + uint32_t max_wait_ticks; /* max waiting time */ + uint32_t max_hold_ticks; /* max holding time */ + uint64_t cum_wait_ww_ticks; /* sum times writer waits on writer*/ + uint32_t max_wait_ww_ticks; /* max wait time writer vs writer */ + /* prev 2 only used for write locks*/ + uint32_t acquire_time; /* time lock acquired this CPU */ + uint32_t count[LSTAT_ACT_MAX_VALUES]; +} lstat_lock_counts_t; + +typedef lstat_lock_counts_t lstat_cpu_counts_t[LSTAT_MAX_STAT_INDEX]; + +/* + * User request to: + * - turn statistic collection on/off, or to reset + */ +#define LSTAT_OFF 0 +#define LSTAT_ON 1 +#define LSTAT_RESET 2 +#define LSTAT_RELEASE 3 + +#define LSTAT_MAX_READ_LOCK_INDEX 1000 +typedef struct { + POINTER lock_ptr; /* address of lock for output stats */ + uint32_t read_lock_count; + int64_t cum_hold_ticks; /* sum of read lock hold times over */ + /* all callers. ....................*/ + uint32_t write_index; /* last write lock hash table index */ + uint32_t busy_periods; /* count of busy periods ended this */ + uint64_t start_busy; /* time this busy period started. ..*/ + uint64_t busy_ticks; /* sum of busy periods this lock. ..*/ + uint64_t max_busy; /* longest busy period for this lock*/ + uint32_t max_readers; /* maximum number of readers ...... */ +#ifdef USER_MODE_TESTING + rwlock_t entry_lock; /* lock for this read lock entry... */ + /* avoid having more than one rdr at*/ + /* needed for user space testing... */ + /* not needed for kernel 'cause it */ + /* is non-preemptive. ............. */ +#endif +} lstat_read_lock_counts_t; +typedef lstat_read_lock_counts_t lstat_read_lock_cpu_counts_t[LSTAT_MAX_READ_LOCK_INDEX]; + +#if defined(__KERNEL__) || defined(USER_MODE_TESTING) + +#ifndef USER_MODE_TESTING +#include +#else +#include "asm_newlockmeter.h" +#endif + +/* + * Size and mask for the hash table into the directory. + */ +#define LSTAT_HASH_TABLE_SIZE 4096 /* must be 2**N */ +#define LSTAT_HASH_TABLE_MASK (LSTAT_HASH_TABLE_SIZE-1) + +#define DIRHASH(ra) ((unsigned long)(ra)>>2 & LSTAT_HASH_TABLE_MASK) + +/* + * This version eliminates the per processor lock stack. What we do is to + * store the index of the lock hash structure in unused bits in the lock + * itself. Then on unlock we can find the statistics record without doing + * any additional hash or lock stack lookup. This works for spin_locks. + * Hold time reporting is now basically as cheap as wait time reporting + * so we ignore the difference between LSTAT_ON_HOLD and LSTAT_ON_WAIT + * as in version 1.1.* of lockmeter. + * + * For rw_locks, we store the index of a global reader stats structure in + * the lock and the writer index is stored in the latter structure. + * For read mode locks we hash at the time of the lock to find an entry + * in the directory for reader wait time and the like. + * At unlock time for read mode locks, we update just the global structure + * so we don't need to know the reader directory index value at unlock time. + * + */ + +/* + * Protocol to change lstat_control.state + * This is complicated because we don't want the cum_hold_time for + * a rw_lock to be decremented in _read_lock_ without making sure it + * is incremented in _read_lock_ and vice versa. So here is the + * way we change the state of lstat_control.state: + * I. To Turn Statistics On + * After allocating storage, set lstat_control.state non-zero. + * This works because we don't start updating statistics for in use + * locks until the reader lock count goes to zero. + * II. To Turn Statistics Off: + * (0) Disable interrupts on this CPU + * (1) Seize the lstat_control.directory_lock + * (2) Obtain the current value of lstat_control.next_free_read_lock_index + * (3) Store a zero in lstat_control.state. + * (4) Release the lstat_control.directory_lock + * (5) For each lock in the read lock list up to the saved value + * (well, -1) of the next_free_read_lock_index, do the following: + * (a) Check validity of the stored lock address + * by making sure that the word at the saved addr + * has an index that matches this entry. If not + * valid, then skip this entry. + * (b) If there is a write lock already set on this lock, + * skip to (d) below. + * (c) Set a non-metered write lock on the lock + * (d) set the cached INDEX in the lock to zero + * (e) Release the non-metered write lock. + * (6) Re-enable interrupts + * + * These rules ensure that a read lock will not have its statistics + * partially updated even though the global lock recording state has + * changed. See put_lockmeter_info() for implementation. + * + * The reason for (b) is that there may be write locks set on the + * syscall path to put_lockmeter_info() from user space. If we do + * not do this check, then we can deadlock. A similar problem would + * occur if the lock was read locked by the current CPU. At the + * moment this does not appear to happen. + */ + +/* + * Main control structure for lockstat. Used to turn statistics on/off + * and to maintain directory info. + */ +typedef struct { + int state; + spinlock_t control_lock; /* used to serialize turning statistics on/off */ + spinlock_t directory_lock; /* for serialize adding entries to directory */ + volatile int next_free_dir_index;/* next free entry in the directory */ + /* FIXME not all of these fields are used / needed .............. */ + /* the following fields represent data since */ + /* first "lstat on" or most recent "lstat reset" */ + TIME_T first_started_time; /* time when measurement first enabled */ + TIME_T started_time; /* time when measurement last started */ + TIME_T ending_time; /* time when measurement last disabled */ + uint64_t started_cycles64; /* cycles when measurement last started */ + uint64_t ending_cycles64; /* cycles when measurement last disabled */ + uint64_t enabled_cycles64; /* total cycles with measurement enabled */ + int intervals; /* number of measurement intervals recorded */ + /* i. e. number of times did lstat on;lstat off */ + lstat_directory_entry_t *dir; /* directory */ + int dir_overflow; /* count of times ran out of space in directory */ + int rwlock_overflow; /* count of times we couldn't allocate a rw block*/ + ushort *hashtab; /* hash table for quick dir scans */ + lstat_cpu_counts_t *counts[NR_CPUS]; /* Array of pointers to per-cpu stats */ + int next_free_read_lock_index; /* next rwlock reader (global) stats block */ + lstat_read_lock_cpu_counts_t *read_lock_counts[NR_CPUS]; /* per cpu read lock stats */ +} lstat_control_t; + +#endif /* defined(__KERNEL__) || defined(USER_MODE_TESTING) */ + +typedef struct { + short lstat_version; /* version of the data */ + short state; /* the current state is returned */ + int maxcpus; /* Number of cpus present */ + int next_free_dir_index; /* index of the next free directory entry */ + TIME_T first_started_time; /* when measurement enabled for first time */ + TIME_T started_time; /* time in secs since 1969 when stats last turned on */ + TIME_T ending_time; /* time in secs since 1969 when stats last turned off */ + uint32_t cycleval; /* cycles per second */ +#ifdef notyet + void *kernel_magic_addr; /* address of kernel_magic */ + void *kernel_end_addr; /* contents of kernel magic (points to "end") */ +#endif + int next_free_read_lock_index; /* index of next (global) read lock stats struct */ + uint64_t started_cycles64; /* cycles when measurement last started */ + uint64_t ending_cycles64; /* cycles when stats last turned off */ + uint64_t enabled_cycles64; /* total cycles with measurement enabled */ + int intervals; /* number of measurement intervals recorded */ + /* i.e. number of times we did lstat on;lstat off*/ + int dir_overflow; /* number of times we wanted more space in directory */ + int rwlock_overflow; /* # of times we wanted more space in read_locks_count */ + struct new_utsname uts; /* info about machine where stats are measured */ + /* -T option of lockstat allows data to be */ + /* moved to another machine. ................. */ +} lstat_user_request_t; + +#endif /* _LINUX_LOCKMETER_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/major.h 830-ivtv/include/linux/major.h --- 000-virgin/include/linux/major.h Mon Nov 17 18:28:59 2003 +++ 830-ivtv/include/linux/major.h Thu Jan 8 11:16:54 2004 @@ -101,6 +101,7 @@ #define I2O_MAJOR 80 /* 80->87 */ #define SHMIQ_MAJOR 85 /* Linux/mips, SGI /dev/shmiq */ +#define SCSI_CHANGER_MAJOR 86 #define IDE6_MAJOR 88 #define IDE7_MAJOR 89 diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/mcount.h 830-ivtv/include/linux/mcount.h --- 000-virgin/include/linux/mcount.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/include/linux/mcount.h Thu Jan 8 10:21:27 2004 @@ -0,0 +1,63 @@ +/* + * include/linux/mcount.h + * + * Implementation of kernel mcount handler and supporting functions. + * + * Code based on kernprof http://oss.sgi.com/projects/kernprof/ + * Copyright (C) SGI 1999, 2000, 2001 + * Written by Dimitris Michailidis (dimitris@engr.sgi.com) + * Modified by John Hawkes (hawkes@engr.sgi.com) + * Contributions from Niels Christiansen (nchr@us.ibm.com) + * Adapted for stand-alone call graphing by Adam Litke (agl@us.ibm.com) + */ + +#ifndef __MCOUNT_H +#define __MCOUNT_H + +#include +#include +#include + +#define DFL_PC_RES 4 /* default PC resolution for this platform */ +#define CG_MAX_ARCS (1 << (8 * sizeof(short))) +#define FUNCTIONPC(func) (*(unsigned long *)&(func)) + +#define pc_out_of_range(pc) \ + ((pc) < (unsigned long) &_stext || (pc) >= (unsigned long) &_etext) + +struct prof_mem_map +{ + unsigned long kernel_buckets; /* number of kernel buckets */ + unsigned long nr_cpus; /* number of processors whether profiled or not */ + unsigned long cg_from_size; /* size of one cg_from array */ + unsigned long cg_to_size; /* size of one cg_to array */ + unsigned long cg_to_offset; /* offset of cg_to array */ + unsigned long kernel_start; /* lowest text address in kernel */ + unsigned long kernel_end; /* highest text address in kernel */ +}; + +struct cg_arc_dest { + unsigned long address; + atomic_t count; + unsigned short link; + unsigned short pad; +}; + +#ifdef CONFIG_X86 +void cg_record_arc(unsigned long frompc, unsigned long selfpc) __attribute__((regparm(2))); +#endif + +int mcount_init(void); + +ssize_t mcount_write(struct file * file, const char * buf, + size_t count, loff_t *ppos); + +ssize_t mcount_read(struct file * file, char * buf, + size_t count, loff_t *ppos); + +static struct file_operations mcount_operations = { + write: mcount_write, + read: mcount_read, +}; + +#endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/mm.h 830-ivtv/include/linux/mm.h --- 000-virgin/include/linux/mm.h Thu Jan 8 08:35:50 2004 +++ 830-ivtv/include/linux/mm.h Thu Jan 8 10:21:12 2004 @@ -180,6 +180,7 @@ struct page { struct pte_chain *chain;/* Reverse pte mapping pointer. * protected by PG_chainlock */ pte_addr_t direct; + int mapcount; } pte; unsigned long private; /* mapping-private opaque data */ @@ -616,6 +617,39 @@ extern struct page * follow_page(struct int write); extern int remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long to, unsigned long size, pgprot_t prot); + +/* + * Given a struct page, determine which node's memory it is from. + * TODO: There's probably a more efficient way to do this... + */ +static inline int page_to_nid(struct page *page) +{ + return pfn_to_nid(page_to_pfn(page)); +} + +#ifdef CONFIG_NUMA +static inline void zero_rss(struct mm_struct *mm) +{ + mm->rss = 0; + memset(mm->pernode_rss, 0, MAX_NUMNODES * sizeof(*mm->pernode_rss)); +} + +static inline void inc_rss(struct mm_struct *mm, struct page *page) +{ + mm->rss++; + mm->pernode_rss[page_to_nid(page)]++; +} + +static inline void dec_rss(struct mm_struct *mm, struct page *page) +{ + mm->rss--; + mm->pernode_rss[page_to_nid(page)]--; +} +#else /* !CONFIG_NUMA */ +#define zero_rss(mm) ((mm)->rss = 0) +#define inc_rss(mm, page) ((mm)->rss++) +#define dec_rss(mm, page) ((mm)->rss--) +#endif /* CONFIG_NUMA */ #ifndef CONFIG_DEBUG_PAGEALLOC static inline void diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/mman.h 830-ivtv/include/linux/mman.h --- 000-virgin/include/linux/mman.h Mon Nov 17 18:29:34 2003 +++ 830-ivtv/include/linux/mman.h Thu Jan 8 10:22:37 2004 @@ -58,6 +58,9 @@ calc_vm_flag_bits(unsigned long flags) return _calc_vm_trans(flags, MAP_GROWSDOWN, VM_GROWSDOWN ) | _calc_vm_trans(flags, MAP_DENYWRITE, VM_DENYWRITE ) | _calc_vm_trans(flags, MAP_EXECUTABLE, VM_EXECUTABLE) | +#ifdef CONFIG_HUGETLB_PAGE + _calc_vm_trans(flags, MAP_HUGETLB, VM_HUGETLB ) | +#endif _calc_vm_trans(flags, MAP_LOCKED, VM_LOCKED ); } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/mmzone.h 830-ivtv/include/linux/mmzone.h --- 000-virgin/include/linux/mmzone.h Thu Jan 8 08:35:50 2004 +++ 830-ivtv/include/linux/mmzone.h Thu Jan 8 10:21:50 2004 @@ -304,7 +304,7 @@ extern struct pglist_data contig_page_da #define NODE_DATA(nid) (&contig_page_data) #define NODE_MEM_MAP(nid) mem_map #define MAX_NODES_SHIFT 0 - +#define pfn_to_nid(pfn) (0) #else /* CONFIG_DISCONTIGMEM */ #include @@ -380,6 +380,19 @@ static inline unsigned int num_online_me #define num_online_memblks() 1 #endif /* CONFIG_DISCONTIGMEM || CONFIG_NUMA */ + +static inline struct zonelist *get_node_zonelist(int nid, int gfp_mask) +{ + return NODE_DATA(nid)->node_zonelists + (gfp_mask & GFP_ZONEMASK); +} + +#define get_zonelist(gfp_mask) get_node_zonelist(numa_node_id(), gfp_mask) + +/* Structure to keep track of memory segment (VMA) bindings */ +struct binding { + struct zonelist zonelist; +}; + #endif /* !__ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif /* _LINUX_MMZONE_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/module.h 830-ivtv/include/linux/module.h --- 000-virgin/include/linux/module.h Tue Aug 5 20:01:55 2003 +++ 830-ivtv/include/linux/module.h Thu Jan 8 10:21:18 2004 @@ -257,6 +257,11 @@ struct module /* The command line arguments (may be mangled). People like keeping pointers to this stuff */ char *args; + +#ifdef CONFIG_GCOV_PROFILE + const char *ctors_start; /* Pointer to start of .ctors-section */ + const char *ctors_end; /* Pointer to end of .ctors-section */ +#endif }; /* FIXME: It'd be nice to isolate modules during init, too, so they diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/netdevice.h 830-ivtv/include/linux/netdevice.h --- 000-virgin/include/linux/netdevice.h Thu Jan 8 08:35:50 2004 +++ 830-ivtv/include/linux/netdevice.h Thu Jan 8 08:54:31 2004 @@ -452,6 +452,12 @@ struct net_device unsigned char *haddr); int (*neigh_setup)(struct net_device *dev, struct neigh_parms *); int (*accept_fastpath)(struct net_device *, struct dst_entry*); +#ifdef CONFIG_NETPOLL_RX + int netpoll_rx; +#endif +#ifdef CONFIG_NET_POLL_CONTROLLER + void (*poll_controller)(struct net_device *dev); +#endif /* bridge stuff */ struct net_bridge_port *br_port; @@ -470,8 +476,15 @@ struct net_device /* class/net/name entry */ struct class_device class_dev; struct net_device_stats* (*last_stats)(struct net_device *); + /* how much padding had been added by alloc_netdev() */ + int padded; }; +static inline void *netdev_priv(struct net_device *dev) +{ + return (char *)dev + ((sizeof(struct net_device) + 31) & ~31); +} + #define SET_MODULE_OWNER(dev) do { } while (0) /* Set the sysfs physical device reference for the network logical device * if set prior to registration will cause a symlink during initialization. @@ -496,6 +509,7 @@ extern rwlock_t dev_base_lock; /* De extern int netdev_boot_setup_add(char *name, struct ifmap *map); extern int netdev_boot_setup_check(struct net_device *dev); +extern unsigned long netdev_boot_base(const char *prefix, int unit); extern struct net_device *dev_getbyhwaddr(unsigned short type, char *hwaddr); extern struct net_device *__dev_getfirstbyhwtype(unsigned short type); extern struct net_device *dev_getfirstbyhwtype(unsigned short type); @@ -533,6 +547,9 @@ extern int dev_new_index(void); extern struct net_device *dev_get_by_index(int ifindex); extern struct net_device *__dev_get_by_index(int ifindex); extern int dev_restart(struct net_device *dev); +#ifdef CONFIG_NETPOLL_TRAP +extern int netpoll_trap(void); +#endif typedef int gifconf_func_t(struct net_device * dev, char * bufptr, int len); extern int register_gifconf(unsigned int family, gifconf_func_t * gifconf); @@ -591,12 +608,20 @@ static inline void netif_start_queue(str static inline void netif_wake_queue(struct net_device *dev) { +#ifdef CONFIG_NETPOLL_TRAP + if (netpoll_trap()) + return; +#endif if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state)) __netif_schedule(dev); } static inline void netif_stop_queue(struct net_device *dev) { +#ifdef CONFIG_NETPOLL_TRAP + if (netpoll_trap()) + return; +#endif set_bit(__LINK_STATE_XOFF, &dev->state); } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/netpoll.h 830-ivtv/include/linux/netpoll.h --- 000-virgin/include/linux/netpoll.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/include/linux/netpoll.h Thu Jan 8 08:54:31 2004 @@ -0,0 +1,38 @@ +/* + * Common code for low-level network console, dump, and debugger code + * + * Derived from netconsole, kgdb-over-ethernet, and netdump patches + */ + +#ifndef _LINUX_NETPOLL_H +#define _LINUX_NETPOLL_H + +#include +#include +#include +#include + +struct netpoll; + +struct netpoll { + struct net_device *dev; + char dev_name[16], *name; + void (*rx_hook)(struct netpoll *, int, char *, int); + u32 local_ip, remote_ip; + u16 local_port, remote_port; + unsigned char local_mac[6], remote_mac[6]; + struct list_head rx_list; +}; + +void netpoll_poll(struct netpoll *np); +void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb); +void netpoll_send_udp(struct netpoll *np, const char *msg, int len); +int netpoll_parse_options(struct netpoll *np, char *opt); +int netpoll_setup(struct netpoll *np); +int netpoll_trap(void); +void netpoll_set_trap(int trap); +void netpoll_cleanup(struct netpoll *np); +int netpoll_rx(struct sk_buff *skb); + + +#endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/page-flags.h 830-ivtv/include/linux/page-flags.h --- 000-virgin/include/linux/page-flags.h Thu Jan 8 08:35:50 2004 +++ 830-ivtv/include/linux/page-flags.h Thu Jan 8 10:20:47 2004 @@ -75,6 +75,7 @@ #define PG_mappedtodisk 17 /* Has blocks allocated on-disk */ #define PG_reclaim 18 /* To be reclaimed asap */ #define PG_compound 19 /* Part of a compound page */ +#define PG_anon 20 /* Anonymous page */ /* @@ -269,6 +270,10 @@ extern void get_full_page_state(struct p #define PageCompound(page) test_bit(PG_compound, &(page)->flags) #define SetPageCompound(page) set_bit(PG_compound, &(page)->flags) #define ClearPageCompound(page) clear_bit(PG_compound, &(page)->flags) + +#define PageAnon(page) test_bit(PG_anon, &(page)->flags) +#define SetPageAnon(page) set_bit(PG_anon, &(page)->flags) +#define ClearPageAnon(page) clear_bit(PG_anon, &(page)->flags) /* * The PageSwapCache predicate doesn't use a PG_flag at this time, diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/pagemap.h 830-ivtv/include/linux/pagemap.h --- 000-virgin/include/linux/pagemap.h Thu Jan 8 08:35:50 2004 +++ 830-ivtv/include/linux/pagemap.h Thu Jan 8 10:21:50 2004 @@ -49,14 +49,37 @@ static inline void mapping_set_gfp_mask( #define page_cache_release(page) put_page(page) void release_pages(struct page **pages, int nr, int cold); +#ifndef CONFIG_NUMA + +static inline struct page *__page_cache_alloc(struct address_space *x, int gfp_mask) +{ + return alloc_pages(gfp_mask, 0); +} + +#else /* CONFIG_NUMA */ + +static inline struct page *__page_cache_alloc(struct address_space *x, int gfp_mask) +{ + struct zonelist *zonelist; + + if (!x->binding) + zonelist = get_zonelist(gfp_mask); + else + zonelist = &x->binding->zonelist; + + return __alloc_pages(gfp_mask, 0, zonelist); +} + +#endif /* !CONFIG_NUMA */ + static inline struct page *page_cache_alloc(struct address_space *x) { - return alloc_pages(mapping_gfp_mask(x), 0); + return __page_cache_alloc(x, mapping_gfp_mask(x)); } static inline struct page *page_cache_alloc_cold(struct address_space *x) { - return alloc_pages(mapping_gfp_mask(x)|__GFP_COLD, 0); + return __page_cache_alloc(x, mapping_gfp_mask(x)|__GFP_COLD); } typedef int filler_t(void *, struct page *); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/pci.h 830-ivtv/include/linux/pci.h --- 000-virgin/include/linux/pci.h Thu Jan 8 08:35:50 2004 +++ 830-ivtv/include/linux/pci.h Thu Jan 8 10:22:31 2004 @@ -473,10 +473,12 @@ struct pci_bus { char name[48]; - struct device * dev; + struct device *bridge; + struct class_device class_dev; }; -#define pci_bus_b(n) list_entry(n, struct pci_bus, node) +#define pci_bus_b(n) list_entry(n, struct pci_bus, node) +#define to_pci_bus(n) container_of(n, struct pci_bus, class_dev) /* * Error values that may be returned by PCI functions. diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/pci_ids.h 830-ivtv/include/linux/pci_ids.h --- 000-virgin/include/linux/pci_ids.h Thu Jan 8 08:35:50 2004 +++ 830-ivtv/include/linux/pci_ids.h Thu Jan 8 10:20:07 2004 @@ -631,6 +631,8 @@ #define PCI_DEVICE_ID_HP_TACHLITE 0x1029 #define PCI_DEVICE_ID_HP_J2585A 0x1030 #define PCI_DEVICE_ID_HP_J2585B 0x1031 +#define PCI_DEVICE_ID_HP_J2973A 0x1040 +#define PCI_DEVICE_ID_HP_J2970A 0x1042 #define PCI_DEVICE_ID_HP_DIVA 0x1048 #define PCI_DEVICE_ID_HP_DIVA_TOSCA1 0x1049 #define PCI_DEVICE_ID_HP_DIVA_TOSCA2 0x104A @@ -1032,6 +1034,8 @@ #define PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE 0x0085 #define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA 0x008e #define PCI_DEVICE_ID_NVIDIA_ITNT2 0x00A0 +#define PCI_DEVICE_ID_NVIDIA_NFORCE3 0x00d1 +#define PCI_DEVICE_ID_NVIDIA_NFORCE3S 0x00e1 #define PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE 0x00d5 #define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA 0x00e3 #define PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE 0x00e5 diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/reboot.h 830-ivtv/include/linux/reboot.h --- 000-virgin/include/linux/reboot.h Tue Sep 2 09:55:56 2003 +++ 830-ivtv/include/linux/reboot.h Thu Jan 8 10:26:46 2004 @@ -22,6 +22,7 @@ * POWER_OFF Stop OS and remove all power from system, if possible. * RESTART2 Restart system using given command string. * SW_SUSPEND Suspend system using software suspend if compiled in. + * KEXEC Restart the system using a different kernel. */ #define LINUX_REBOOT_CMD_RESTART 0x01234567 @@ -31,6 +32,7 @@ #define LINUX_REBOOT_CMD_POWER_OFF 0x4321FEDC #define LINUX_REBOOT_CMD_RESTART2 0xA1B2C3D4 #define LINUX_REBOOT_CMD_SW_SUSPEND 0xD000FCE2 +#define LINUX_REBOOT_CMD_KEXEC 0x45584543 #ifdef __KERNEL__ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/sched.h 830-ivtv/include/linux/sched.h --- 000-virgin/include/linux/sched.h Thu Jan 8 08:35:50 2004 +++ 830-ivtv/include/linux/sched.h Thu Jan 8 10:21:33 2004 @@ -71,7 +71,11 @@ struct exec_domain; * the EXP_n values would be 1981, 2034 and 2043 if still using only * 11 bit fractions. */ -extern unsigned long avenrun[]; /* Load averages */ +extern unsigned long avenrun[]; /* Load averages */ +extern unsigned long tasks_running[3]; /* Real load averages */ +DECLARE_PER_CPU(unsigned long[3],cpu_tasks_running); /* Real load averages per cpu */ + +extern unsigned long tasks_running[]; /* Real load averages */ #define FSHIFT 11 /* nr of bits of precision */ #define FIXED_1 (1< #include #include @@ -192,7 +207,7 @@ struct mm_struct { atomic_t mm_count; /* How many references to "struct mm_struct" (users count as 1) */ int map_count; /* number of VMAs */ struct rw_semaphore mmap_sem; - spinlock_t page_table_lock; /* Protects task page tables and mm->rss */ + spinlock_t page_table_lock; /* Protects task page tables and RSS data */ struct list_head mmlist; /* List of all active mm's. These are globally strung * together off init_mm.mmlist, and are protected @@ -202,7 +217,11 @@ struct mm_struct { unsigned long start_code, end_code, start_data, end_data; unsigned long start_brk, brk, start_stack; unsigned long arg_start, arg_end, env_start, env_end; - unsigned long rss, total_vm, locked_vm; + unsigned long total_vm, locked_vm; + unsigned long rss; +#ifdef CONFIG_NUMA + unsigned long pernode_rss[MAX_NUMNODES]; +#endif unsigned long def_flags; cpumask_t cpu_vm_mask; @@ -325,6 +344,18 @@ struct k_itimer { struct sigqueue *sigq; /* signal queue entry. */ }; +#ifdef CONFIG_SCHEDSTATS +struct sched_info { + /* cumulative counters */ + unsigned long cpu_time, /* time spent on the cpu */ + run_delay, /* time spent waiting on a runqueue */ + pcnt; /* # of timeslices run on this cpu */ + + /* timestamps */ + unsigned long last_arrival, /* when we last ran on a cpu */ + last_queued; /* when we were last queued to run */ +}; +#endif /* CONFIG_SCHEDSTATS */ struct io_context; /* See blkdev.h */ void exit_io_context(void); @@ -350,6 +381,10 @@ struct task_struct { unsigned long policy; cpumask_t cpus_allowed; unsigned int time_slice, first_time_slice; + +#ifdef CONFIG_SCHEDSTATS + struct sched_info sched_info; +#endif /* CONFIG_SCHEDSTATS */ struct list_head tasks; struct list_head ptrace_children; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/serial_core.h 830-ivtv/include/linux/serial_core.h --- 000-virgin/include/linux/serial_core.h Mon Nov 17 18:28:59 2003 +++ 830-ivtv/include/linux/serial_core.h Thu Jan 8 09:30:15 2004 @@ -158,7 +158,9 @@ struct uart_port { unsigned char x_char; /* xon/xoff char */ unsigned char regshift; /* reg offset shift */ unsigned char iotype; /* io access style */ - +#ifdef CONFIG_KGDB + int kgdb; /* in use by kgdb */ +#endif #define UPIO_PORT (0) #define UPIO_HUB6 (1) #define UPIO_MEM (2) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/spinlock.h 830-ivtv/include/linux/spinlock.h --- 000-virgin/include/linux/spinlock.h Wed Jul 2 21:59:15 2003 +++ 830-ivtv/include/linux/spinlock.h Thu Jan 8 09:30:50 2004 @@ -15,6 +15,12 @@ #include /* for cpu relax */ #include +#ifdef CONFIG_KGDB +#include +#define SET_WHO(x, him) (x)->who = him; +#else +#define SET_WHO(x, him) +#endif /* * Must define these before including other files, inline functions need them @@ -55,6 +61,9 @@ typedef struct { const char *module; char *owner; int oline; +#ifdef CONFIG_KGDB + struct task_struct *who; +#endif } spinlock_t; #define SPIN_LOCK_UNLOCKED (spinlock_t) { SPINLOCK_MAGIC, 0, 10, __FILE__ , NULL, 0} @@ -66,6 +75,7 @@ typedef struct { (x)->module = __FILE__; \ (x)->owner = NULL; \ (x)->oline = 0; \ + SET_WHO(x, NULL) \ } while (0) #define CHECK_LOCK(x) \ @@ -88,6 +98,7 @@ typedef struct { (x)->lock = 1; \ (x)->owner = __FILE__; \ (x)->oline = __LINE__; \ + SET_WHO(x, current) \ } while (0) /* without debugging, spin_is_locked on UP always says @@ -118,6 +129,7 @@ typedef struct { (x)->lock = 1; \ (x)->owner = __FILE__; \ (x)->oline = __LINE__; \ + SET_WHO(x, current) \ 1; \ }) @@ -184,6 +196,17 @@ typedef struct { #endif /* !SMP */ +#ifdef CONFIG_LOCKMETER +extern void _metered_spin_lock (spinlock_t *lock); +extern void _metered_spin_unlock (spinlock_t *lock); +extern int _metered_spin_trylock(spinlock_t *lock); +extern void _metered_read_lock (rwlock_t *lock); +extern void _metered_read_unlock (rwlock_t *lock); +extern void _metered_write_lock (rwlock_t *lock); +extern void _metered_write_unlock (rwlock_t *lock); +extern int _metered_write_trylock(rwlock_t *lock); +#endif + /* * Define the various spin_lock and rw_lock methods. Note we define these * regardless of whether CONFIG_SMP or CONFIG_PREEMPT are set. The various @@ -388,6 +411,141 @@ do { \ #define spin_trylock_bh(lock) ({ local_bh_disable(); preempt_disable(); \ _raw_spin_trylock(lock) ? 1 : \ ({preempt_enable(); local_bh_enable(); 0;});}) + +#ifdef CONFIG_LOCKMETER +#undef spin_lock +#undef spin_trylock +#undef spin_unlock +#undef spin_lock_irqsave +#undef spin_lock_irq +#undef spin_lock_bh +#undef read_lock +#undef read_unlock +#undef write_lock +#undef write_unlock +#undef write_trylock +#undef spin_unlock_bh +#undef read_lock_irqsave +#undef read_lock_irq +#undef read_lock_bh +#undef read_unlock_bh +#undef write_lock_irqsave +#undef write_lock_irq +#undef write_lock_bh +#undef write_unlock_bh + +#define spin_lock(lock) \ +do { \ + preempt_disable(); \ + _metered_spin_lock(lock); \ +} while(0) + +#define spin_trylock(lock) ({preempt_disable(); _metered_spin_trylock(lock) ? \ + 1 : ({preempt_enable(); 0;});}) +#define spin_unlock(lock) \ +do { \ + _metered_spin_unlock(lock); \ + preempt_enable(); \ +} while (0) + +#define spin_lock_irqsave(lock, flags) \ +do { \ + local_irq_save(flags); \ + preempt_disable(); \ + _metered_spin_lock(lock); \ +} while (0) + +#define spin_lock_irq(lock) \ +do { \ + local_irq_disable(); \ + preempt_disable(); \ + _metered_spin_lock(lock); \ +} while (0) + +#define spin_lock_bh(lock) \ +do { \ + local_bh_disable(); \ + preempt_disable(); \ + _metered_spin_lock(lock); \ +} while (0) + +#define spin_unlock_bh(lock) \ +do { \ + _metered_spin_unlock(lock); \ + preempt_enable(); \ + local_bh_enable(); \ +} while (0) + + +#define read_lock(lock) ({preempt_disable(); _metered_read_lock(lock);}) +#define read_unlock(lock) ({_metered_read_unlock(lock); preempt_enable();}) +#define write_lock(lock) ({preempt_disable(); _metered_write_lock(lock);}) +#define write_unlock(lock) ({_metered_write_unlock(lock); preempt_enable();}) +#define write_trylock(lock) ({preempt_disable();_metered_write_trylock(lock) ? \ + 1 : ({preempt_enable(); 0;});}) +#define spin_unlock_no_resched(lock) \ +do { \ + _metered_spin_unlock(lock); \ + preempt_enable_no_resched(); \ +} while (0) + +#define read_lock_irqsave(lock, flags) \ +do { \ + local_irq_save(flags); \ + preempt_disable(); \ + _metered_read_lock(lock); \ +} while (0) + +#define read_lock_irq(lock) \ +do { \ + local_irq_disable(); \ + preempt_disable(); \ + _metered_read_lock(lock); \ +} while (0) + +#define read_lock_bh(lock) \ +do { \ + local_bh_disable(); \ + preempt_disable(); \ + _metered_read_lock(lock); \ +} while (0) + +#define read_unlock_bh(lock) \ +do { \ + _metered_read_unlock(lock); \ + preempt_enable(); \ + local_bh_enable(); \ +} while (0) + +#define write_lock_irqsave(lock, flags) \ +do { \ + local_irq_save(flags); \ + preempt_disable(); \ + _metered_write_lock(lock); \ +} while (0) + +#define write_lock_irq(lock) \ +do { \ + local_irq_disable(); \ + preempt_disable(); \ + _metered_write_lock(lock); \ +} while (0) + +#define write_lock_bh(lock) \ +do { \ + local_bh_disable(); \ + preempt_disable(); \ + _metered_write_lock(lock); \ +} while (0) + +#define write_unlock_bh(lock) \ +do { \ + _metered_write_unlock(lock); \ + preempt_enable(); \ + local_bh_enable(); \ +} while (0) + +#endif /* !CONFIG_LOCKMETER */ /* "lock on reference count zero" */ #ifndef ATOMIC_DEC_AND_LOCK diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/swap.h 830-ivtv/include/linux/swap.h --- 000-virgin/include/linux/swap.h Mon Nov 17 18:29:34 2003 +++ 830-ivtv/include/linux/swap.h Thu Jan 8 10:20:47 2004 @@ -185,6 +185,8 @@ struct pte_chain *FASTCALL(page_add_rmap void FASTCALL(page_remove_rmap(struct page *, pte_t *)); int FASTCALL(try_to_unmap(struct page *)); +int page_convert_anon(struct page *); + /* linux/mm/shmem.c */ extern int shmem_unuse(swp_entry_t entry, struct page *page); #else diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/sysctl.h 830-ivtv/include/linux/sysctl.h --- 000-virgin/include/linux/sysctl.h Thu Jan 8 08:35:50 2004 +++ 830-ivtv/include/linux/sysctl.h Thu Jan 8 10:22:37 2004 @@ -61,7 +61,8 @@ enum CTL_DEV=7, /* Devices */ CTL_BUS=8, /* Busses */ CTL_ABI=9, /* Binary emulation */ - CTL_CPU=10 /* CPU stuff (speed scaling, etc) */ + CTL_CPU=10, /* CPU stuff (speed scaling, etc) */ + CTL_SCHED=11, /* scheduler tunables */ }; /* CTL_BUS names: */ @@ -127,6 +128,10 @@ enum KERN_PANIC_ON_OOPS=57, /* int: whether we will panic on an oops */ KERN_HPPA_PWRSW=58, /* int: hppa soft-power enable */ KERN_HPPA_UNALIGNED=59, /* int: hppa unaligned-trap enable */ + KERN_SHMUSEHUGEPAGES=60, /* int: back shm with huge pages */ + KERN_MMAPUSEHUGEPAGES=61, /* int: back anon mmap with huge pages */ + KERN_HPAGES_PER_FILE=62, /* int: max bigpages per file */ + KERN_HPAGES_MAP_SZ=63, /* int: min size (MB) of mapping */ }; @@ -156,6 +161,21 @@ enum VM_MIN_FREE_KBYTES=21, /* Minimum free kilobytes to maintain */ }; +/* Tunable scheduler parameters in /proc/sys/sched/ */ +enum { + SCHED_MIN_TIMESLICE=1, /* minimum process timeslice */ + SCHED_MAX_TIMESLICE=2, /* maximum process timeslice */ + SCHED_CHILD_PENALTY=3, /* penalty on fork to child */ + SCHED_PARENT_PENALTY=4, /* penalty on fork to parent */ + SCHED_EXIT_WEIGHT=5, /* penalty to parent of CPU hog child */ + SCHED_PRIO_BONUS_RATIO=6, /* percent of max prio given as bonus */ + SCHED_INTERACTIVE_DELTA=7, /* delta used to scale interactivity */ + SCHED_MAX_SLEEP_AVG=8, /* maximum sleep avg attainable */ + SCHED_STARVATION_LIMIT=9, /* no re-active if expired is starved */ + SCHED_NODE_THRESHOLD=10, /* NUMA node rebalance threshold */ + SCHED_IDLE_NODE_REBALANCE_RATIO=11, /* how often to global balance */ + SCHED_BUSY_NODE_REBALANCE_RATIO=12, /* how often to global balance */ +}; /* CTL_NET names: */ enum diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/sysfs.h 830-ivtv/include/linux/sysfs.h --- 000-virgin/include/linux/sysfs.h Tue Sep 2 09:55:56 2003 +++ 830-ivtv/include/linux/sysfs.h Thu Jan 8 10:27:08 2004 @@ -9,6 +9,8 @@ #ifndef _SYSFS_H_ #define _SYSFS_H_ +#include + struct kobject; struct module; @@ -32,6 +34,21 @@ struct sysfs_ops { ssize_t (*show)(struct kobject *, struct attribute *,char *); ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t); }; + +struct sysfs_dirent { + atomic_t s_count; + struct list_head s_sibling; + struct list_head s_children; + void * s_element; + int s_type; + struct dentry * s_dentry; +}; + +#define SYSFS_ROOT 0x0001 +#define SYSFS_KOBJECT 0x0002 +#define SYSFS_KOBJ_ATTR 0x0004 +#define SYSFS_KOBJ_BIN_ATTR 0x0008 +#define SYSFS_KOBJ_ATTR_GROUP 0x0010 extern int sysfs_create_dir(struct kobject *); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/timex.h 830-ivtv/include/linux/timex.h --- 000-virgin/include/linux/timex.h Mon Nov 17 18:29:49 2003 +++ 830-ivtv/include/linux/timex.h Thu Jan 8 10:20:35 2004 @@ -78,7 +78,7 @@ #elif HZ >= 768 && HZ < 1536 # define SHIFT_HZ 10 #else -# error You lose. +# error Please use a HZ value which is between 12 and 1536 #endif /* diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/videodev.h 830-ivtv/include/linux/videodev.h --- 000-virgin/include/linux/videodev.h Thu Jan 8 08:35:50 2004 +++ 830-ivtv/include/linux/videodev.h Thu Jan 8 11:17:04 2004 @@ -3,7 +3,6 @@ #include #include -#include #define HAVE_V4L2 1 #include @@ -12,6 +11,7 @@ #include #include +#include struct video_device { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/linux/videodev2.h 830-ivtv/include/linux/videodev2.h --- 000-virgin/include/linux/videodev2.h Wed Aug 13 20:24:33 2003 +++ 830-ivtv/include/linux/videodev2.h Thu Jan 8 11:17:04 2004 @@ -13,7 +13,9 @@ * Justin Schoeman * et al. */ +#ifdef __KERNEL__ #include /* need struct timeval */ +#endif /* * M I S C E L L A N E O U S @@ -111,6 +113,14 @@ enum v4l2_colorspace { V4L2_COLORSPACE_SRGB = 8, }; +enum v4l2_priority { + V4L2_PRIORITY_UNSET = 0, /* not initialized */ + V4L2_PRIORITY_BACKGROUND = 1, + V4L2_PRIORITY_INTERACTIVE = 2, + V4L2_PRIORITY_RECORD = 3, + V4L2_PRIORITY_DEFAULT = V4L2_PRIORITY_INTERACTIVE, +}; + struct v4l2_rect { __s32 left; __s32 top; @@ -144,8 +154,9 @@ struct v4l2_capability #define V4L2_CAP_VBI_OUTPUT 0x00000020 /* Is a VBI output device */ #define V4L2_CAP_RDS_CAPTURE 0x00000100 /* RDS data capture */ -#define V4L2_CAP_TUNER 0x00010000 /* Has a tuner */ +#define V4L2_CAP_TUNER 0x00010000 /* has a tuner */ #define V4L2_CAP_AUDIO 0x00020000 /* has audio support */ +#define V4L2_CAP_RADIO 0x00040000 /* is a radio device */ #define V4L2_CAP_READWRITE 0x01000000 /* read/write systemcalls */ #define V4L2_CAP_ASYNCIO 0x02000000 /* async I/O */ @@ -203,7 +214,7 @@ struct v4l2_pix_format #define V4L2_PIX_FMT_MPEG v4l2_fourcc('M','P','E','G') /* MPEG */ /* Vendor-specific formats */ -#define V4L2_PIX_FMT_WNVA v4l2_fourcc('W','N','V','A') /* Winnov hw compres */ +#define V4L2_PIX_FMT_WNVA v4l2_fourcc('W','N','V','A') /* Winnov hw compress */ /* * F O R M A T E N U M E R A T I O N @@ -264,6 +275,51 @@ struct v4l2_compression __u32 keyframerate; __u32 pframerate; __u32 reserved[5]; + +/* what we'll need for MPEG, extracted from some postings on + the v4l list (Gert Vervoort, PlasmaJohn). + +system stream: + - type: elementary stream(ES), packatised elementary stream(s) (PES) + program stream(PS), transport stream(TS) + - system bitrate + - PS packet size (DVD: 2048 bytes, VCD: 2324 bytes) + - TS video PID + - TS audio PID + - TS PCR PID + - TS system information tables (PAT, PMT, CAT, NIT and SIT) + - (MPEG-1 systems stream vs. MPEG-2 program stream (TS not supported + by MPEG-1 systems) + +audio: + - type: MPEG (+Layer I,II,III), AC-3, LPCM + - bitrate + - sampling frequency (DVD: 48 Khz, VCD: 44.1 KHz, 32 kHz) + - Trick Modes? (ff, rew) + - Copyright + - Inverse Telecine + +video: + - picturesize (SIF, 1/2 D1, 2/3 D1, D1) and PAL/NTSC norm can be set + through excisting V4L2 controls + - noise reduction, parameters encoder specific? + - MPEG video version: MPEG-1, MPEG-2 + - GOP (Group Of Pictures) definition: + - N: number of frames per GOP + - M: distance between reference (I,P) frames + - open/closed GOP + - quantiser matrix: inter Q matrix (64 bytes) and intra Q matrix (64 bytes) + - quantiser scale: linear or logarithmic + - scanning: alternate or zigzag + - bitrate mode: CBR (constant bitrate) or VBR (variable bitrate). + - target video bitrate for CBR + - target video bitrate for VBR + - maximum video bitrate for VBR - min. quantiser value for VBR + - max. quantiser value for VBR + - adaptive quantisation value + - return the number of bytes per GOP or bitrate for bitrate monitoring + +*/ }; #endif @@ -783,22 +839,22 @@ struct v4l2_streamparm #define VIDIOC_QUERYBUF _IOWR ('V', 9, struct v4l2_buffer) #define VIDIOC_G_FBUF _IOR ('V', 10, struct v4l2_framebuffer) #define VIDIOC_S_FBUF _IOW ('V', 11, struct v4l2_framebuffer) -#define VIDIOC_OVERLAY _IOWR ('V', 14, int) +#define VIDIOC_OVERLAY _IOW ('V', 14, int) #define VIDIOC_QBUF _IOWR ('V', 15, struct v4l2_buffer) #define VIDIOC_DQBUF _IOWR ('V', 17, struct v4l2_buffer) #define VIDIOC_STREAMON _IOW ('V', 18, int) #define VIDIOC_STREAMOFF _IOW ('V', 19, int) #define VIDIOC_G_PARM _IOWR ('V', 21, struct v4l2_streamparm) -#define VIDIOC_S_PARM _IOW ('V', 22, struct v4l2_streamparm) +#define VIDIOC_S_PARM _IOWR ('V', 22, struct v4l2_streamparm) #define VIDIOC_G_STD _IOR ('V', 23, v4l2_std_id) #define VIDIOC_S_STD _IOW ('V', 24, v4l2_std_id) #define VIDIOC_ENUMSTD _IOWR ('V', 25, struct v4l2_standard) #define VIDIOC_ENUMINPUT _IOWR ('V', 26, struct v4l2_input) #define VIDIOC_G_CTRL _IOWR ('V', 27, struct v4l2_control) -#define VIDIOC_S_CTRL _IOW ('V', 28, struct v4l2_control) +#define VIDIOC_S_CTRL _IOWR ('V', 28, struct v4l2_control) #define VIDIOC_G_TUNER _IOWR ('V', 29, struct v4l2_tuner) #define VIDIOC_S_TUNER _IOW ('V', 30, struct v4l2_tuner) -#define VIDIOC_G_AUDIO _IOWR ('V', 33, struct v4l2_audio) +#define VIDIOC_G_AUDIO _IOR ('V', 33, struct v4l2_audio) #define VIDIOC_S_AUDIO _IOW ('V', 34, struct v4l2_audio) #define VIDIOC_QUERYCTRL _IOWR ('V', 36, struct v4l2_queryctrl) #define VIDIOC_QUERYMENU _IOWR ('V', 37, struct v4l2_querymenu) @@ -807,7 +863,7 @@ struct v4l2_streamparm #define VIDIOC_G_OUTPUT _IOR ('V', 46, int) #define VIDIOC_S_OUTPUT _IOWR ('V', 47, int) #define VIDIOC_ENUMOUTPUT _IOWR ('V', 48, struct v4l2_output) -#define VIDIOC_G_AUDOUT _IOWR ('V', 49, struct v4l2_audioout) +#define VIDIOC_G_AUDOUT _IOR ('V', 49, struct v4l2_audioout) #define VIDIOC_S_AUDOUT _IOW ('V', 50, struct v4l2_audioout) #define VIDIOC_G_MODULATOR _IOWR ('V', 54, struct v4l2_modulator) #define VIDIOC_S_MODULATOR _IOW ('V', 55, struct v4l2_modulator) @@ -820,6 +876,17 @@ struct v4l2_streamparm #define VIDIOC_S_JPEGCOMP _IOW ('V', 62, struct v4l2_jpegcompression) #define VIDIOC_QUERYSTD _IOR ('V', 63, v4l2_std_id) #define VIDIOC_TRY_FMT _IOWR ('V', 64, struct v4l2_format) +#define VIDIOC_ENUMAUDIO _IOWR ('V', 65, struct v4l2_audio) +#define VIDIOC_ENUMAUDOUT _IOWR ('V', 66, struct v4l2_audioout) +#define VIDIOC_G_PRIORITY _IOR ('V', 67, enum v4l2_priority) +#define VIDIOC_S_PRIORITY _IOW ('V', 68, enum v4l2_priority) + +/* for compatibility, will go away some day */ +#define VIDIOC_OVERLAY_OLD _IOWR ('V', 14, int) +#define VIDIOC_S_PARM_OLD _IOW ('V', 22, struct v4l2_streamparm) +#define VIDIOC_S_CTRL_OLD _IOW ('V', 28, struct v4l2_control) +#define VIDIOC_G_AUDIO_OLD _IOWR ('V', 33, struct v4l2_audio) +#define VIDIOC_G_AUDOUT_OLD _IOWR ('V', 49, struct v4l2_audioout) #define BASE_VIDIOC_PRIVATE 192 /* 192-255 are private */ @@ -838,16 +905,28 @@ extern unsigned int v4l2_video_std_fps(s extern int v4l2_video_std_construct(struct v4l2_standard *vs, int id, char *name); -/* Compatibility layer interface */ -typedef int (*v4l2_kioctl)(struct inode *inode, struct file *file, - unsigned int cmd, void *arg); -int v4l_compat_translate_ioctl(struct inode *inode, struct file *file, - int cmd, void *arg, v4l2_kioctl driver_ioctl); +/* prority handling */ +struct v4l2_prio_state { + atomic_t prios[4]; +}; +int v4l2_prio_init(struct v4l2_prio_state *global); +int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local, + enum v4l2_priority new); +int v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local); +int v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority *local); +enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global); +int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local); /* names for fancy debug output */ extern char *v4l2_field_names[]; extern char *v4l2_type_names[]; extern char *v4l2_ioctl_names[]; + +/* Compatibility layer interface -- v4l1-compat module */ +typedef int (*v4l2_kioctl)(struct inode *inode, struct file *file, + unsigned int cmd, void *arg); +int v4l_compat_translate_ioctl(struct inode *inode, struct file *file, + int cmd, void *arg, v4l2_kioctl driver_ioctl); #endif /* __KERNEL__ */ #endif /* __LINUX_VIDEODEV2_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/media/id.h 830-ivtv/include/media/id.h --- 000-virgin/include/media/id.h Mon Mar 17 21:43:50 2003 +++ 830-ivtv/include/media/id.h Thu Jan 8 11:17:12 2004 @@ -27,6 +27,9 @@ #ifndef I2C_DRIVERID_TDA9874 # define I2C_DRIVERID_TDA9874 I2C_DRIVERID_EXP0+7 #endif +#ifndef I2C_DRIVERID_SAA6752HS +# define I2C_DRIVERID_SAA6752HS I2C_DRIVERID_EXP0+8 +#endif /* algorithms */ #ifndef I2C_ALGO_SAA7134 diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/media/ir-common.h 830-ivtv/include/media/ir-common.h --- 000-virgin/include/media/ir-common.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/include/media/ir-common.h Thu Jan 8 11:17:15 2004 @@ -0,0 +1,61 @@ +/* + * some common structs and functions to handle infrared remotes via + * input layer ... + * + * (c) 2003 Gerd Knorr [SuSE Labs] + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + + +#define IR_TYPE_RC5 1 +#define IR_TYPE_OTHER 99 + +#define IR_KEYTAB_TYPE u32 +#define IR_KEYTAB_SIZE 64 // enougth for rc5, probably need more some day ... + +#define IR_KEYCODE(tab,code) (((unsigned)code < IR_KEYTAB_SIZE) \ + ? tab[code] : KEY_RESERVED) + +struct ir_input_state { + /* configuration */ + int ir_type; + IR_KEYTAB_TYPE ir_codes[IR_KEYTAB_SIZE]; + + /* key info */ + u32 ir_raw; /* raw data */ + u32 ir_key; /* ir key code */ + u32 keycode; /* linux key code */ + int keypressed; /* current state */ +}; + +extern IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE]; +extern IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE]; + +void ir_input_init(struct input_dev *dev, struct ir_input_state *ir, + int ir_type, IR_KEYTAB_TYPE *ir_codes); +void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir); +void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir, + u32 ir_key, u32 ir_raw); +u32 ir_extract_bits(u32 data, u32 mask); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/media/tuner.h 830-ivtv/include/media/tuner.h --- 000-virgin/include/media/tuner.h Fri May 30 19:02:23 2003 +++ 830-ivtv/include/media/tuner.h Thu Jan 8 11:17:18 2004 @@ -65,14 +65,16 @@ #define TUNER_PHILIPS_FM1216ME_MK3 38 #define TUNER_LG_NTSC_NEW_TAPC 39 #define TUNER_HITACHI_NTSC 40 - - +#define TUNER_PHILIPS_PAL_MK 41 +#define TUNER_PHILIPS_ATSC 42 +#define TUNER_PHILIPS_FM1236_MK3 43 #define NOTUNER 0 #define PAL 1 /* PAL_BG */ #define PAL_I 2 #define NTSC 3 #define SECAM 4 +#define ATSC 5 #define NoTuner 0 #define Philips 1 diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/net/atmclip.h 830-ivtv/include/net/atmclip.h --- 000-virgin/include/net/atmclip.h Mon Nov 17 18:28:59 2003 +++ 830-ivtv/include/net/atmclip.h Thu Jan 8 08:54:31 2004 @@ -44,7 +44,7 @@ struct atmarp_entry { }; -#define PRIV(dev) ((struct clip_priv *) ((struct net_device *) (dev)+1)) +#define PRIV(dev) ((struct clip_priv *) netdev_priv(dev)) struct clip_priv { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/scsi/scsi.h 830-ivtv/include/scsi/scsi.h --- 000-virgin/include/scsi/scsi.h Thu Jan 8 08:35:53 2004 +++ 830-ivtv/include/scsi/scsi.h Thu Jan 8 11:16:54 2004 @@ -28,6 +28,7 @@ extern const unsigned char scsi_command_ #define FORMAT_UNIT 0x04 #define READ_BLOCK_LIMITS 0x05 #define REASSIGN_BLOCKS 0x07 +#define INITIALIZE_ELEMENT_STATUS 0x07 #define READ_6 0x08 #define WRITE_6 0x0a #define SEEK_6 0x0b @@ -52,6 +53,7 @@ extern const unsigned char scsi_command_ #define READ_10 0x28 #define WRITE_10 0x2a #define SEEK_10 0x2b +#define POSITION_TO_ELEMENT 0x2b #define WRITE_VERIFY 0x2e #define VERIFY 0x2f #define SEARCH_HIGH 0x30 @@ -84,6 +86,7 @@ extern const unsigned char scsi_command_ #define PERSISTENT_RESERVE_OUT 0x5f #define REPORT_LUNS 0xa0 #define MOVE_MEDIUM 0xa5 +#define EXCHANGE_MEDIUM 0xa6 #define READ_12 0xa8 #define WRITE_12 0xaa #define WRITE_VERIFY_12 0xae diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/sound/ac97_codec.h 830-ivtv/include/sound/ac97_codec.h --- 000-virgin/include/sound/ac97_codec.h Mon Nov 17 18:28:59 2003 +++ 830-ivtv/include/sound/ac97_codec.h Thu Jan 8 10:26:49 2004 @@ -83,6 +83,33 @@ #define AC97_VENDOR_ID1 0x7c /* Vendor ID1 */ #define AC97_VENDOR_ID2 0x7e /* Vendor ID2 / revision */ +/* slot allocation */ +#define AC97_SLOT_TAG 0 +#define AC97_SLOT_CMD_ADDR 1 +#define AC97_SLOT_CMD_DATA 2 +#define AC97_SLOT_PCM_LEFT 3 +#define AC97_SLOT_PCM_RIGHT 4 +#define AC97_SLOT_MODEM_LINE1 5 +#define AC97_SLOT_PCM_CENTER 6 +#define AC97_SLOT_MIC 6 /* input */ +#define AC97_SLOT_SPDIF_LEFT1 6 +#define AC97_SLOT_PCM_SLEFT 7 /* surround left */ +#define AC97_SLOT_PCM_LEFT_0 7 /* double rate operation */ +#define AC97_SLOT_SPDIF_LEFT 7 +#define AC97_SLOT_PCM_SRIGHT 8 /* surround right */ +#define AC97_SLOT_PCM_RIGHT_0 8 /* double rate operation */ +#define AC97_SLOT_SPDIF_RIGHT 8 +#define AC97_SLOT_LFE 9 +#define AC97_SLOT_SPDIF_RIGHT1 9 +#define AC97_SLOT_MODEM_LINE2 10 +#define AC97_SLOT_PCM_LEFT_1 10 /* double rate operation */ +#define AC97_SLOT_SPDIF_LEFT2 10 +#define AC97_SLOT_HANDSET 11 /* output */ +#define AC97_SLOT_PCM_RIGHT_1 11 /* double rate operation */ +#define AC97_SLOT_SPDIF_RIGHT2 11 +#define AC97_SLOT_MODEM_GPIO 12 /* modem GPIO */ +#define AC97_SLOT_PCM_CENTER_1 12 /* double rate operation */ + /* basic capabilities (reset register) */ #define AC97_BC_DEDICATED_MIC 0x0001 /* Dedicated Mic PCM In Channel */ #define AC97_BC_RESERVED1 0x0002 /* Reserved (was Modem Line Codec support) */ @@ -274,10 +301,13 @@ /* ac97->scaps */ -#define AC97_SCAP_AUDIO (1<<0) /* audio AC'97 codec */ -#define AC97_SCAP_MODEM (1<<1) /* modem AC'97 codec */ +#define AC97_SCAP_AUDIO (1<<0) /* audio codec 97 */ +#define AC97_SCAP_MODEM (1<<1) /* modem codec 97 */ #define AC97_SCAP_SURROUND_DAC (1<<2) /* surround L&R DACs are present */ #define AC97_SCAP_CENTER_LFE_DAC (1<<3) /* center and LFE DACs are present */ +#define AC97_SCAP_SKIP_AUDIO (1<<4) /* skip audio part of codec */ +#define AC97_SCAP_SKIP_MODEM (1<<5) /* skip modem part of codec */ +#define AC97_SCAP_INDEP_SDIN (1<<6) /* independent SDIN */ /* ac97->flags */ #define AC97_HAS_PC_BEEP (1<<0) /* force PC Speaker usage */ @@ -298,8 +328,36 @@ * */ +typedef struct _snd_ac97_bus ac97_bus_t; typedef struct _snd_ac97 ac97_t; +enum ac97_pcm_cfg { + AC97_PCM_CFG_FRONT = 2, + AC97_PCM_CFG_REAR = 10, /* alias surround */ + AC97_PCM_CFG_LFE = 11, /* center + lfe */ + AC97_PCM_CFG_40 = 4, /* front + rear */ + AC97_PCM_CFG_51 = 6, /* front + rear + center/lfe */ + AC97_PCM_CFG_SPDIF = 20 +}; + +/* PCM allocation */ +struct ac97_pcm { + ac97_bus_t *bus; + unsigned int stream: 1, /* stream type: 1 = capture */ + exclusive: 1, /* exclusive mode, don't override with other pcms */ + copy_flag: 1, /* lowlevel driver must fill all entries */ + spdif: 1; /* spdif pcm */ + unsigned short aslots; /* active slots */ + unsigned int rates; /* available rates */ + struct { + unsigned short slots; /* driver input: requested AC97 slot numbers */ + unsigned short rslots[4]; /* allocated slots per codecs */ + unsigned char rate_table[4]; + ac97_t *codec[4]; /* allocated codecs */ + } r[2]; /* 0 = standard rates, 1 = double rates */ + unsigned long private_value; /* used by the hardware driver */ +}; + struct snd_ac97_build_ops { int (*build_3d) (ac97_t *ac97); int (*build_specific) (ac97_t *ac97); @@ -307,18 +365,39 @@ struct snd_ac97_build_ops { int (*build_post_spdif) (ac97_t *ac97); }; -struct _snd_ac97 { +struct _snd_ac97_bus { + /* -- lowlevel (hardware) driver specific -- */ void (*reset) (ac97_t *ac97); void (*write) (ac97_t *ac97, unsigned short reg, unsigned short val); unsigned short (*read) (ac97_t *ac97, unsigned short reg); void (*wait) (ac97_t *ac97); void (*init) (ac97_t *ac97); + void *private_data; + void (*private_free) (ac97_bus_t *bus); + /* --- */ + snd_card_t *card; + unsigned short num; /* bus number */ + unsigned short vra: 1, /* bridge supports VRA */ + isdin: 1;/* independent SDIN */ + unsigned int clock; /* AC'97 base clock (usually 48000Hz) */ + spinlock_t bus_lock; /* used mainly for slot allocation */ + unsigned short used_slots[2][4]; /* actually used PCM slots */ + unsigned short pcms_count; /* count of PCMs */ + struct ac97_pcm *pcms; + ac97_t *codec[4]; + snd_info_entry_t *proc; +}; + +struct _snd_ac97 { + /* -- lowlevel (hardware) driver specific -- */ struct snd_ac97_build_ops * build_ops; void *private_data; void (*private_free) (ac97_t *ac97); /* --- */ - snd_card_t *card; + ac97_bus_t *bus; struct pci_dev *pci; /* assigned PCI device - used for quirks */ + snd_info_entry_t *proc; + snd_info_entry_t *proc_regs; unsigned short subsystem_vendor; unsigned short subsystem_device; spinlock_t reg_lock; @@ -330,7 +409,6 @@ struct _snd_ac97 { unsigned short ext_mid; /* extended modem ID (register 3C) */ unsigned int scaps; /* driver capabilities */ unsigned int flags; /* specific code */ - unsigned int clock; /* AC'97 clock (usually 48000Hz) */ unsigned int rates[6]; /* see AC97_RATES_* defines */ unsigned int spdif_status; unsigned short regs[0x80]; /* register cache */ @@ -368,15 +446,14 @@ static inline int ac97_can_amap(ac97_t * } /* functions */ -int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97); /* create mixer controls */ -int snd_ac97_modem(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97); /* create modem controls */ +int snd_ac97_bus(snd_card_t * card, ac97_bus_t * _bus, ac97_bus_t ** rbus); /* create new AC97 bus */ +int snd_ac97_mixer(ac97_bus_t * bus, ac97_t * _ac97, ac97_t ** rac97); /* create mixer controls */ void snd_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short value); unsigned short snd_ac97_read(ac97_t *ac97, unsigned short reg); void snd_ac97_write_cache(ac97_t *ac97, unsigned short reg, unsigned short value); int snd_ac97_update(ac97_t *ac97, unsigned short reg, unsigned short value); int snd_ac97_update_bits(ac97_t *ac97, unsigned short reg, unsigned short mask, unsigned short value); -int snd_ac97_set_rate(ac97_t *ac97, int reg, unsigned short rate); #ifdef CONFIG_PM void snd_ac97_suspend(ac97_t *ac97); void snd_ac97_resume(ac97_t *ac97); @@ -399,5 +476,13 @@ struct ac97_quirk { }; int snd_ac97_tune_hardware(ac97_t *ac97, struct ac97_quirk *quirk); +int snd_ac97_set_rate(ac97_t *ac97, int reg, unsigned short rate); + +int snd_ac97_pcm_assign(ac97_bus_t *ac97, + unsigned short pcms_count, + const struct ac97_pcm *pcms); +int snd_ac97_pcm_open(struct ac97_pcm *pcm, unsigned int rate, + enum ac97_pcm_cfg cfg, unsigned short slots); +int snd_ac97_pcm_close(struct ac97_pcm *pcm); #endif /* __SOUND_AC97_CODEC_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/sound/asound.h 830-ivtv/include/sound/asound.h --- 000-virgin/include/sound/asound.h Mon Nov 17 18:28:59 2003 +++ 830-ivtv/include/sound/asound.h Thu Jan 8 10:26:49 2004 @@ -272,6 +272,7 @@ enum sndrv_pcm_subformat { #define SNDRV_PCM_INFO_HALF_DUPLEX 0x00100000 /* only half duplex */ #define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000 /* playback and capture stream are somewhat correlated */ #define SNDRV_PCM_INFO_SYNC_START 0x00400000 /* pcm support some kind of sync go */ +#define SNDRV_PCM_INFO_NONATOMIC_OPS 0x00800000 /* non-atomic prepare callback */ enum sndrv_pcm_state { SNDRV_PCM_STATE_OPEN = 0, /* stream is open */ @@ -683,7 +684,7 @@ struct sndrv_timer_tread { * * ****************************************************************************/ -#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 2) +#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 3) struct sndrv_ctl_card_info { int card; /* card number */ @@ -728,6 +729,7 @@ enum sndrv_ctl_elem_iface { #define SNDRV_CTL_ELEM_ACCESS_INACTIVE (1<<8) /* control does actually nothing, but may be updated */ #define SNDRV_CTL_ELEM_ACCESS_LOCK (1<<9) /* write lock */ #define SNDRV_CTL_ELEM_ACCESS_OWNER (1<<10) /* write lock owner */ +#define SNDRV_CTL_ELEM_ACCESS_USER (1<<29) /* user space element */ #define SNDRV_CTL_ELEM_ACCESS_DINDIRECT (1<<30) /* indirect access for matrix dimensions in the info structure */ #define SNDRV_CTL_ELEM_ACCESS_INDIRECT (1<<31) /* indirect access for element value in the value structure */ @@ -824,6 +826,9 @@ enum { SNDRV_CTL_IOCTL_ELEM_LOCK = _IOW('U', 0x14, struct sndrv_ctl_elem_id), SNDRV_CTL_IOCTL_ELEM_UNLOCK = _IOW('U', 0x15, struct sndrv_ctl_elem_id), SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS = _IOWR('U', 0x16, int), + SNDRV_CTL_IOCTL_ELEM_ADD = _IOWR('U', 0x17, struct sndrv_ctl_elem_info), + SNDRV_CTL_IOCTL_ELEM_REPLACE = _IOWR('U', 0x18, struct sndrv_ctl_elem_info), + SNDRV_CTL_IOCTL_ELEM_REMOVE = _IOWR('U', 0x19, struct sndrv_ctl_elem_id), SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE = _IOWR('U', 0x20, int), SNDRV_CTL_IOCTL_HWDEP_INFO = _IOR('U', 0x21, struct sndrv_hwdep_info), SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE = _IOR('U', 0x30, int), diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/sound/asound_fm.h 830-ivtv/include/sound/asound_fm.h --- 000-virgin/include/sound/asound_fm.h Sun Nov 17 20:29:54 2002 +++ 830-ivtv/include/sound/asound_fm.h Thu Jan 8 10:26:49 2004 @@ -105,15 +105,11 @@ typedef struct snd_dm_fm_params { /* for OPL3 only */ #define SNDRV_DM_FM_IOCTL_SET_CONNECTION _IOW('H', 0x26, int) -#ifdef __SND_OSS_COMPAT__ - #define SNDRV_DM_FM_OSS_IOCTL_RESET 0x20 #define SNDRV_DM_FM_OSS_IOCTL_PLAY_NOTE 0x21 #define SNDRV_DM_FM_OSS_IOCTL_SET_VOICE 0x22 #define SNDRV_DM_FM_OSS_IOCTL_SET_PARAMS 0x23 #define SNDRV_DM_FM_OSS_IOCTL_SET_MODE 0x24 #define SNDRV_DM_FM_OSS_IOCTL_SET_OPL 0x25 - -#endif #endif /* __SOUND_ASOUND_FM_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/sound/cs46xx.h 830-ivtv/include/sound/cs46xx.h --- 000-virgin/include/sound/cs46xx.h Sun Apr 20 19:35:08 2003 +++ 830-ivtv/include/sound/cs46xx.h Thu Jan 8 10:26:49 2004 @@ -1712,6 +1712,7 @@ struct _snd_cs46xx { int nr_ac97_codecs; + ac97_bus_t *ac97_bus; ac97_t *ac97[MAX_NR_AC97]; struct pci_dev *pci; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/sound/emu10k1.h 830-ivtv/include/sound/emu10k1.h --- 000-virgin/include/sound/emu10k1.h Mon Nov 17 18:28:59 2003 +++ 830-ivtv/include/sound/emu10k1.h Thu Jan 8 10:26:49 2004 @@ -679,6 +679,9 @@ #define A_ADCIDX 0x63 #define A_ADCIDX_IDX 0x10000063 +#define A_MICIDX 0x64 +#define A_MICIDX_IDX 0x10000064 + #define FXIDX 0x65 /* FX recording buffer index register */ #define FXIDX_MASK 0x0000ffff /* 16-bit value */ #define FXIDX_IDX 0x10000065 @@ -1152,10 +1155,12 @@ int snd_emu10k1_proc_init(emu10k1_t * em #define FXBUS_MIDI_RIGHT 0x05 #define FXBUS_PCM_CENTER 0x06 #define FXBUS_PCM_LFE 0x07 -#define FXBUS_PT_LEFT 20 -#define FXBUS_PT_RIGHT 21 +#define FXBUS_PCM_LEFT_FRONT 0x08 +#define FXBUS_PCM_RIGHT_FRONT 0x09 #define FXBUS_MIDI_REVERB 0x0c #define FXBUS_MIDI_CHORUS 0x0d +#define FXBUS_PT_LEFT 0x14 +#define FXBUS_PT_RIGHT 0x15 /* Inputs */ #define EXTIN_AC97_L 0x00 /* AC'97 capture channel - left */ @@ -1199,8 +1204,8 @@ int snd_emu10k1_proc_init(emu10k1_t * em #define A_EXTIN_OPT_SPDIF_R 0x05 /* right */ #define A_EXTIN_LINE2_L 0x08 /* audigy drive line2/mic2 - left */ #define A_EXTIN_LINE2_R 0x09 /* right */ -#define A_EXTIN_RCA_SPDIF_L 0x0a /* audigy drive RCA SPDIF - left */ -#define A_EXTIN_RCA_SPDIF_R 0x0b /* right */ +#define A_EXTIN_ADC_L 0x0a /* Philips ADC - left */ +#define A_EXTIN_ADC_R 0x0b /* right */ #define A_EXTIN_AUX2_L 0x0c /* audigy drive aux2 - left */ #define A_EXTIN_AUX2_R 0x0d /* - right */ @@ -1225,6 +1230,7 @@ int snd_emu10k1_proc_init(emu10k1_t * em #define A_EXTOUT_AC97_R 0x11 /* right */ #define A_EXTOUT_ADC_CAP_L 0x16 /* ADC capture buffer left */ #define A_EXTOUT_ADC_CAP_R 0x17 /* right */ +#define A_EXTOUT_MIC_CAP 0x18 /* Mic capture buffer */ /* Audigy constants */ #define A_C_00000000 0xc0 @@ -1249,8 +1255,8 @@ int snd_emu10k1_proc_init(emu10k1_t * em #define A_C_4f1bbcdc 0xd3 #define A_C_5a7ef9db 0xd4 #define A_C_00100000 0xd5 -/* 0xd6 = 0x7fffffff (?) ACCUM? */ -/* 0xd7 = 0x0000000 CCR */ +#define A_GPR_ACCU 0xd6 /* ACCUM, accumulator */ +#define A_GPR_COND 0xd7 /* CCR, condition register */ /* 0xd8 = noise1 */ /* 0xd9 = noise2 */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/sound/hdsp.h 830-ivtv/include/sound/hdsp.h --- 000-virgin/include/sound/hdsp.h Mon Nov 17 18:28:59 2003 +++ 830-ivtv/include/sound/hdsp.h Thu Jan 8 10:26:49 2004 @@ -25,17 +25,20 @@ typedef enum { Digiface, Multiface, H9652, + H9632, Undefined, } HDSP_IO_Type; typedef struct _snd_hdsp_peak_rms hdsp_peak_rms_t; struct _snd_hdsp_peak_rms { - unsigned int playback_peaks[26]; unsigned int input_peaks[26]; + unsigned int playback_peaks[26]; unsigned int output_peaks[28]; - unsigned long long playback_rms[26]; unsigned long long input_rms[26]; + unsigned long long playback_rms[26]; + /* These are only used for H96xx cards */ + unsigned long long output_rms[26]; }; #define SNDRV_HDSP_IOCTL_GET_PEAK_RMS _IOR('H', 0x40, hdsp_peak_rms_t) @@ -61,6 +64,11 @@ struct _snd_hdsp_config_info { unsigned char autosync_ref; unsigned char line_out; unsigned char passthru; + unsigned char da_gain; + unsigned char ad_gain; + unsigned char phone_gain; + unsigned char xlr_breakout_cable; + unsigned char analog_extension_board; }; #define SNDRV_HDSP_IOCTL_GET_CONFIG_INFO _IOR('H', 0x41, hdsp_config_info_t) @@ -89,5 +97,14 @@ struct _snd_hdsp_mixer { }; #define SNDRV_HDSP_IOCTL_GET_MIXER _IOR('H', 0x44, hdsp_mixer_t) + +typedef struct _snd_hdsp_9632_aeb hdsp_9632_aeb_t; + +struct _snd_hdsp_9632_aeb { + int aebi; + int aebo; +}; + +#define SNDRV_HDSP_IOCTL_GET_9632_AEB _IOR('H', 0x45, hdsp_9632_aeb_t) #endif /* __SOUND_HDSP_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/sound/i2c.h 830-ivtv/include/sound/i2c.h --- 000-virgin/include/sound/i2c.h Sun Nov 17 20:29:27 2002 +++ 830-ivtv/include/sound/i2c.h Thu Jan 8 10:26:49 2004 @@ -58,7 +58,7 @@ struct _snd_i2c_bus { snd_card_t *card; /* card which I2C belongs to */ char name[32]; /* some useful label */ - spinlock_t lock; + struct semaphore lock_mutex; snd_i2c_bus_t *master; /* master bus when SCK/SCL is shared */ struct list_head buses; /* master: slave buses sharing SCK/SCL, slave: link list */ @@ -84,15 +84,15 @@ int snd_i2c_device_free(snd_i2c_device_t static inline void snd_i2c_lock(snd_i2c_bus_t *bus) { if (bus->master) - spin_lock(&bus->master->lock); + down(&bus->master->lock_mutex); else - spin_lock(&bus->lock); + down(&bus->lock_mutex); } static inline void snd_i2c_unlock(snd_i2c_bus_t *bus) { if (bus->master) - spin_unlock(&bus->master->lock); + up(&bus->master->lock_mutex); else - spin_unlock(&bus->lock); + up(&bus->lock_mutex); } int snd_i2c_sendbytes(snd_i2c_device_t *device, unsigned char *bytes, int count); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/sound/info.h 830-ivtv/include/sound/info.h --- 000-virgin/include/sound/info.h Wed Aug 13 20:24:33 2003 +++ 830-ivtv/include/sound/info.h Thu Jan 8 10:26:49 2004 @@ -134,12 +134,13 @@ void snd_remove_proc_entry(struct proc_d /* for card drivers */ int snd_card_proc_new(snd_card_t *card, const char *name, snd_info_entry_t **entryp); -inline static void snd_info_set_text_ops(snd_info_entry_t *entry, +static inline void snd_info_set_text_ops(snd_info_entry_t *entry, void *private_data, + long read_size, void (*read)(snd_info_entry_t *, snd_info_buffer_t *)) { entry->private_data = private_data; - entry->c.text.read_size = 1024; + entry->c.text.read_size = read_size; entry->c.text.read = read; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/sound/initval.h 830-ivtv/include/sound/initval.h --- 000-virgin/include/sound/initval.h Sat Jun 14 18:37:38 2003 +++ 830-ivtv/include/sound/initval.h Thu Jan 8 10:26:49 2004 @@ -35,7 +35,7 @@ static const char __module_generic_strin #define MODULE_DEVICES(val) MODULE_GENERIC_STRING(info_devices, val) #define MODULE_PARM_SYNTAX(id, val) MODULE_GENERIC_STRING(info_parm_##id, val) -#define SNDRV_AUTO_PORT 0xffff +#define SNDRV_AUTO_PORT 1 #define SNDRV_AUTO_IRQ 0xffff #define SNDRV_AUTO_DMA 0xffff #define SNDRV_AUTO_DMA_SIZE (0x7fffffff) @@ -58,7 +58,7 @@ static const char __module_generic_strin #else #define SNDRV_DEFAULT_ENABLE_ISAPNP SNDRV_DEFAULT_ENABLE #endif -#define SNDRV_DEFAULT_PORT { SNDRV_AUTO_PORT, [1 ... (SNDRV_CARDS-1)] = -1 } +#define SNDRV_DEFAULT_PORT { [0 ... (SNDRV_CARDS-1)] = SNDRV_AUTO_PORT } #define SNDRV_DEFAULT_IRQ { [0 ... (SNDRV_CARDS-1)] = SNDRV_AUTO_IRQ } #define SNDRV_DEFAULT_DMA { [0 ... (SNDRV_CARDS-1)] = SNDRV_AUTO_DMA } #define SNDRV_DEFAULT_DMA_SIZE { [0 ... (SNDRV_CARDS-1)] = SNDRV_AUTO_DMA_SIZE } @@ -162,5 +162,17 @@ static int __init get_id(char **str, cha return 1; } #endif + +/* simple wrapper for long variable. + * the value more than 32bit won't work! + */ +inline static int get_option_long(char **str, long *valp) +{ + int val, ret; + ret = get_option(str, &val); + if (ret) + *valp = val; + return ret; +} #endif /* __SOUND_INITVAL_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/sound/minors.h 830-ivtv/include/sound/minors.h --- 000-virgin/include/sound/minors.h Sun Nov 17 20:29:21 2002 +++ 830-ivtv/include/sound/minors.h Thu Jan 8 10:26:49 2004 @@ -81,6 +81,9 @@ #define SNDRV_OSS_DEVICE_TYPE_SNDSTAT 5 #define SNDRV_OSS_DEVICE_TYPE_MUSIC 6 +#define MODULE_ALIAS_SNDRV_MINOR(type) \ + MODULE_ALIAS("sound-service-?-" __stringify(type)) + #endif #endif /* __SOUND_MINORS_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/sound/pcm.h 830-ivtv/include/sound/pcm.h --- 000-virgin/include/sound/pcm.h Sat Jun 14 18:37:38 2003 +++ 830-ivtv/include/sound/pcm.h Thu Jan 8 10:26:49 2004 @@ -461,8 +461,6 @@ typedef struct _snd_pcm_notify { extern snd_pcm_t *snd_pcm_devices[]; extern snd_minor_t snd_pcm_reg[2]; -void snd_pcm_lock(int unlock); - int snd_pcm_new(snd_card_t * card, char *id, int device, int playback_count, int capture_count, snd_pcm_t **rpcm); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/sound/pcm_oss.h 830-ivtv/include/sound/pcm_oss.h --- 000-virgin/include/sound/pcm_oss.h Mon Nov 17 18:29:43 2003 +++ 830-ivtv/include/sound/pcm_oss.h Thu Jan 8 10:26:59 2004 @@ -31,7 +31,6 @@ struct _snd_pcm_oss_setup { direct:1, block:1, nonblock:1, - wholefrag:1, nosilence:1; unsigned int periods; unsigned int period_size; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/sound/sb.h 830-ivtv/include/sound/sb.h --- 000-virgin/include/sound/sb.h Sat Jun 14 18:37:38 2003 +++ 830-ivtv/include/sound/sb.h Thu Jan 8 10:26:49 2004 @@ -63,8 +63,6 @@ enum sb_hw_type { struct _snd_sb { unsigned long port; /* base port of DSP chip */ struct resource *res_port; - unsigned long alt_port; /* alternate port (ALS4000) */ - struct resource *res_alt_port; unsigned long mpu_port; /* MPU port for SB DSP 4.0+ */ int irq; /* IRQ number of DSP chip */ int dma8; /* 8-bit DMA */ @@ -72,6 +70,7 @@ struct _snd_sb { unsigned short version; /* version of DSP chip */ enum sb_hw_type hardware; /* see to SB_HW_XXXX */ + unsigned long alt_port; /* alternate port (ALS4000) */ struct pci_dev *pci; /* ALS4000 */ unsigned int open; /* see to SB_OPEN_XXXX for sb8 */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/sound/sndmagic.h 830-ivtv/include/sound/sndmagic.h --- 000-virgin/include/sound/sndmagic.h Mon Nov 17 18:29:34 2003 +++ 830-ivtv/include/sound/sndmagic.h Thu Jan 8 10:26:49 2004 @@ -133,6 +133,7 @@ static inline int _snd_magic_bad(void *o #define mpu401_t_magic 0xa15a1701 #define fm801_t_magic 0xa15a1801 #define ac97_t_magic 0xa15a1901 +#define ac97_bus_t_magic 0xa15a1902 #define ak4531_t_magic 0xa15a1a01 #define snd_uart16550_t_magic 0xa15a1b01 #define emu10k1_t_magic 0xa15a1c01 diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/sound/sscape_ioctl.h 830-ivtv/include/sound/sscape_ioctl.h --- 000-virgin/include/sound/sscape_ioctl.h Mon Nov 17 18:28:59 2003 +++ 830-ivtv/include/sound/sscape_ioctl.h Thu Jan 8 10:26:49 2004 @@ -8,9 +8,11 @@ struct sscape_bootblock unsigned version; }; +#define SSCAPE_MICROCODE_SIZE 65536 + struct sscape_microcode { - unsigned char *code; /* 65536 chars */ + unsigned char *code; }; #define SND_SSCAPE_LOAD_BOOTB _IOWR('P', 100, struct sscape_bootblock) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/sound/trident.h 830-ivtv/include/sound/trident.h --- 000-virgin/include/sound/trident.h Fri May 30 19:02:23 2003 +++ 830-ivtv/include/sound/trident.h Thu Jan 8 10:26:49 2004 @@ -443,6 +443,7 @@ struct _snd_trident { snd_rawmidi_t *rmidi; snd_seq_device_t *seq_dev; + ac97_bus_t *ac97_bus; ac97_t *ac97; ac97_t *ac97_sec; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/sound/version.h 830-ivtv/include/sound/version.h --- 000-virgin/include/sound/version.h Mon Nov 17 18:28:59 2003 +++ 830-ivtv/include/sound/version.h Thu Jan 8 10:26:49 2004 @@ -1,3 +1,3 @@ /* include/version.h. Generated automatically by configure. */ -#define CONFIG_SND_VERSION "0.9.7" -#define CONFIG_SND_DATE " (Thu Sep 25 19:16:36 2003 UTC)" +#define CONFIG_SND_VERSION "1.0.0rc2" +#define CONFIG_SND_DATE " (Fri Dec 05 13:57:15 2003 UTC)" diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/include/sound/ymfpci.h 830-ivtv/include/sound/ymfpci.h --- 000-virgin/include/sound/ymfpci.h Wed Aug 13 20:24:33 2003 +++ 830-ivtv/include/sound/ymfpci.h Thu Jan 8 10:26:49 2004 @@ -25,6 +25,7 @@ #include "pcm.h" #include "rawmidi.h" #include "ac97_codec.h" +#include "timer.h" #include #ifndef PCI_VENDOR_ID_YAMAHA @@ -311,8 +312,6 @@ struct _snd_ymfpci { unsigned short old_legacy_ctrl; #if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE) - unsigned int joystick_port; - struct semaphore joystick_mutex; struct resource *joystick_res; struct gameport gameport; #endif @@ -347,8 +346,10 @@ struct _snd_ymfpci { u32 active_bank; ymfpci_voice_t voices[64]; + ac97_bus_t *ac97_bus; ac97_t *ac97; snd_rawmidi_t *rawmidi; + snd_timer_t *timer; struct pci_dev *pci; snd_card_t *card; @@ -389,9 +390,7 @@ int snd_ymfpci_pcm2(ymfpci_t *chip, int int snd_ymfpci_pcm_spdif(ymfpci_t *chip, int device, snd_pcm_t **rpcm); int snd_ymfpci_pcm_4ch(ymfpci_t *chip, int device, snd_pcm_t **rpcm); int snd_ymfpci_mixer(ymfpci_t *chip, int rear_switch); -#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE) -int snd_ymfpci_joystick(ymfpci_t *chip); -#endif +int snd_ymfpci_timer(ymfpci_t *chip, int device); int snd_ymfpci_voice_alloc(ymfpci_t *chip, ymfpci_voice_type_t type, int pair, ymfpci_voice_t **rvoice); int snd_ymfpci_voice_free(ymfpci_t *chip, ymfpci_voice_t *pvoice); @@ -399,6 +398,10 @@ int snd_ymfpci_voice_free(ymfpci_t *chip #ifdef CONFIG_PM void snd_ymfpci_suspend(ymfpci_t *chip); void snd_ymfpci_resume(ymfpci_t *chip); +#endif + +#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#define SUPPORT_JOYSTICK #endif #endif /* __SOUND_YMFPCI_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/init/main.c 830-ivtv/init/main.c --- 000-virgin/init/main.c Thu Jan 8 08:35:54 2004 +++ 830-ivtv/init/main.c Thu Jan 8 10:21:18 2004 @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -113,6 +114,10 @@ static char *execute_command; /* Setup configured maximum number of CPUs to activate */ static unsigned int max_cpus = NR_CPUS; +#if defined(CONFIG_GCOV_PROFILE) && (defined(CONFIG_PPC32) || defined(CONFIG_PPC64)) +void __bb_fork_func (void) { } +#endif + /* * Setup routine for controlling SMP activation * @@ -393,6 +398,8 @@ asmlinkage void __init start_kernel(void */ lock_kernel(); printk(linux_banner); + setup_early_printk(); + setup_arch(&command_line); setup_per_cpu_areas(); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/ipc/shm.c 830-ivtv/ipc/shm.c --- 000-virgin/ipc/shm.c Mon Nov 17 18:28:20 2003 +++ 830-ivtv/ipc/shm.c Thu Jan 8 10:22:37 2004 @@ -32,6 +32,9 @@ #define shm_flags shm_perm.mode +extern int shm_use_hugepages; +extern int shm_hugepages_per_file; + static struct file_operations shm_file_operations; static struct vm_operations_struct shm_vm_ops; @@ -165,6 +168,31 @@ static struct vm_operations_struct shm_v .nopage = shmem_nopage, }; +#ifdef CONFIG_HUGETLBFS +int shm_with_hugepages(int shmflag, size_t size) +{ + /* flag specified explicitly */ + if (shmflag & SHM_HUGETLB) + return 1; + /* Are we disabled? */ + if (!shm_use_hugepages) + return 0; + /* Must be HPAGE aligned */ + if (size & ~HPAGE_MASK) + return 0; + /* Are we under the max per file? */ + if ((size >> HPAGE_SHIFT) > shm_hugepages_per_file) + return 0; + /* Do we have enough free huge pages? */ + if (!is_hugepage_mem_enough(size)) + return 0; + + return 1; +} +#else +int shm_with_hugepages(int shmflag, size_t size) { return 0; } +#endif + static int newseg (key_t key, int shmflg, size_t size) { int error; @@ -194,8 +222,10 @@ static int newseg (key_t key, int shmflg return error; } - if (shmflg & SHM_HUGETLB) + if (shm_with_hugepages(shmflg, size)) { + shmflg |= SHM_HUGETLB; file = hugetlb_zero_setup(size); + } else { sprintf (name, "SYSV%08x", key); file = shmem_file_setup(name, size, VM_ACCOUNT); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/kernel/Makefile 830-ivtv/kernel/Makefile --- 000-virgin/kernel/Makefile Mon Nov 17 18:29:35 2003 +++ 830-ivtv/kernel/Makefile Thu Jan 8 11:16:34 2004 @@ -8,17 +8,37 @@ obj-y = sched.o fork.o exec_domain.o signal.o sys.o kmod.o workqueue.o pid.o \ rcupdate.o intermodule.o extable.o params.o posix-timers.o +ifdef CONFIG_GCOV_PROFILE +obj-y += gcov.o +CFLAGS_gcov.o := -DGCOV_PATH='"$(TOPDIR)"' +endif + obj-$(CONFIG_FUTEX) += futex.o obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o obj-$(CONFIG_SMP) += cpu.o +obj-$(CONFIG_LOCKMETER) += lockmeter.o obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_KALLSYMS) += kallsyms.o obj-$(CONFIG_PM) += power/ obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o +obj-$(CONFIG_KEXEC) += kexec.o obj-$(CONFIG_COMPAT) += compat.o obj-$(CONFIG_IKCONFIG) += configs.o obj-$(CONFIG_IKCONFIG_PROC) += configs.o +obj-$(CONFIG_X86_EARLY_PRINTK) += early_printk.o +obj-$(CONFIG_MCOUNT) += mcount.o + +ifeq ($(CONFIG_MCOUNT),y) +quiet_cmd_nopg = CC $@ + cmd_nopg = $(CC) $(subst -pg,,$(CFLAGS)) -c $(src)/$(*F).c -o $@ + +$(obj)/mcount.o: alwayscc + $(call cmd,nopg) +alwayscc: + $(Q)rm -f $(obj)/mcount.o +endif + ifneq ($(CONFIG_IA64),y) # According to Alan Modra , the -fno-omit-frame-pointer is diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/kernel/early_printk.c 830-ivtv/kernel/early_printk.c --- 000-virgin/kernel/early_printk.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/kernel/early_printk.c Thu Jan 8 10:20:32 2004 @@ -0,0 +1,218 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +/* Simple VGA output */ + +#define MAX_YPOS 25 +#define MAX_XPOS 80 + +static int current_ypos = 1, current_xpos = 0; + +static void early_vga_write(struct console *con, const char *str, unsigned n) +{ + char c; + int i, k, j; + + while ((c = *str++) != '\0' && n-- > 0) { + if (current_ypos >= MAX_YPOS) { + /* scroll 1 line up */ + for(k = 1, j = 0; k < MAX_YPOS; k++, j++) { + for(i = 0; i < MAX_XPOS; i++) { + writew(readw(VGABASE + 2*(MAX_XPOS*k + i)), + VGABASE + 2*(MAX_XPOS*j + i)); + } + } + for(i = 0; i < MAX_XPOS; i++) { + writew(0x720, VGABASE + 2*(MAX_XPOS*j + i)); + } + current_ypos = MAX_YPOS-1; + } + if (c == '\n') { + current_xpos = 0; + current_ypos++; + } else if (c != '\r') { + writew(((0x7 << 8) | (unsigned short) c), + VGABASE + 2*(MAX_XPOS*current_ypos + current_xpos++)); + if (current_xpos >= MAX_XPOS) { + current_xpos = 0; + current_ypos++; + } + } + } +} + +static struct console early_vga_console = { + .name = "earlyvga", + .write = early_vga_write, + .flags = CON_PRINTBUFFER, + .index = -1, +}; + +/* Serial functions losely based on a similar package from Klaus P. Gerlicher */ + +int early_serial_base; /* ttyS0 */ + +static int early_serial_putc(unsigned char ch) +{ + unsigned timeout = 0xffff; + while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout) + rep_nop(); + outb(ch, early_serial_base + TXR); + return timeout ? 0 : -1; +} + +static void early_serial_write(struct console *con, const char *s, unsigned n) +{ + while (*s && n-- > 0) { + early_serial_putc(*s); + if (*s == '\n') + early_serial_putc('\r'); + s++; + } +} + +static __init void early_serial_init(char *opt) +{ + unsigned char c; + unsigned divisor, baud = DEFAULT_BAUD; + static int bases[] = SERIAL_BASES; + char *s, *e; + + early_serial_base = bases[0]; + + if (*opt == ',') + ++opt; + + s = strsep(&opt, ","); + if (s != NULL) { + unsigned port; + if (!strncmp(s,"0x",2)) + early_serial_base = simple_strtoul(s, &e, 16); + else { + if (!strncmp(s,"ttyS",4)) + s+=4; + port = simple_strtoul(s, &e, 10); + if (port > (SERIAL_BASES_LEN-1) || s == e) + port = 0; + early_serial_base = bases[port]; + } + } + + outb(0x3, early_serial_base + LCR); /* 8n1 */ + outb(0, early_serial_base + IER); /* no interrupt */ + outb(0, early_serial_base + FCR); /* no fifo */ + outb(0x3, early_serial_base + MCR); /* DTR + RTS */ + + s = strsep(&opt, ","); + if (s != NULL) { + baud = simple_strtoul(s, &e, 0); + if (baud == 0 || s == e) + baud = DEFAULT_BAUD; + } + + divisor = 115200 / baud; + c = inb(early_serial_base + LCR); + outb(c | DLAB, early_serial_base + LCR); + outb(divisor & 0xff, early_serial_base + DLL); + outb((divisor >> 8) & 0xff, early_serial_base + DLH); + outb(c & ~DLAB, early_serial_base + LCR); +} + +static struct console early_serial_console = { + .name = "earlyser", + .write = early_serial_write, + .flags = CON_PRINTBUFFER, + .index = -1, +}; + +/* Direct interface for emergencies */ +struct console *early_console = &early_vga_console; +static int early_console_initialized = 0; + +void early_printk(const char *fmt, ...) +{ + char buf[512]; + int n; + va_list ap; + va_start(ap,fmt); + n = vsnprintf(buf,512,fmt,ap); + early_console->write(early_console,buf,n); + va_end(ap); +} + +static int keep_early; + +int __init setup_early_printk(void) +{ + char *space, *s; + char buf[256]; + char cmd[COMMAND_LINE_SIZE]; + char *opt; + + /* Get our own copy of the cmd line */ + memcpy(cmd, COMMAND_LINE, COMMAND_LINE_SIZE); + cmd[COMMAND_LINE_SIZE-1] = '\0'; + opt = cmd; + + s = strstr(opt, "earlyprintk="); + if (s == NULL) + return -1; + opt = s+12; + + if (early_console_initialized) + return -1; + + strncpy(buf,opt,256); + buf[255] = 0; + space = strchr(buf, ' '); + if (space) + *space = 0; + + if (strstr(buf,"keep")) + keep_early = 1; + + if (!strncmp(buf, "serial", 6)) { + early_serial_init(buf + 6); + early_console = &early_serial_console; + } else if (!strncmp(buf, "ttyS", 4)) { + early_serial_init(buf); + early_console = &early_serial_console; + } else if (!strncmp(buf, "vga", 3)) { + early_console = &early_vga_console; + } else { + early_console = NULL; + return -1; + } + early_console_initialized = 1; + register_console(early_console); + printk("early printk console registered\n"); + return 0; +} + +void __init disable_early_printk(void) +{ + if (!early_console_initialized || !early_console) + return; + if (!keep_early) { + printk("disabling early console...\n"); + unregister_console(early_console); + early_console_initialized = 0; + } else { + printk("keeping early console.\n"); + } +} + +/* syntax: earlyprintk=vga + earlyprintk=serial[,ttySn[,baudrate]] + Append ,keep to not disable it when the real console takes over. + Only vga or serial at a time, not both. + Currently only ttyS0 and ttyS1 are supported. + Interaction with the standard serial driver is not very good. + The VGA output is eventually overwritten by the real console. */ +__setup("earlyprintk=", setup_early_printk); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/kernel/fork.c 830-ivtv/kernel/fork.c --- 000-virgin/kernel/fork.c Thu Jan 8 08:35:54 2004 +++ 830-ivtv/kernel/fork.c Thu Jan 8 10:21:33 2004 @@ -274,7 +274,7 @@ static inline int dup_mmap(struct mm_str mm->mmap_cache = NULL; mm->free_area_cache = TASK_UNMAPPED_BASE; mm->map_count = 0; - mm->rss = 0; + zero_rss(mm); cpus_clear(mm->cpu_vm_mask); pprev = &mm->mmap; @@ -963,6 +963,9 @@ struct task_struct *copy_process(unsigne p->start_time = get_jiffies_64(); p->security = NULL; p->io_context = NULL; + #ifdef CONFIG_SCHEDSTATS + memset(&p->sched_info, 0, sizeof(p->sched_info)); + #endif /* CONFIG_SCHEDSTATS */ retval = -ENOMEM; if ((retval = security_task_alloc(p))) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/kernel/gcov.c 830-ivtv/kernel/gcov.c --- 000-virgin/kernel/gcov.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/kernel/gcov.c Thu Jan 8 10:21:18 2004 @@ -0,0 +1,158 @@ +/* + * Coverage support under Linux + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (c) International Business Machines Corp., 2002 + * + * Author: Hubertus Franke + * Rajan Ravindran + * + * Modified by + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +struct bb +{ + long zero_word; + const char *filename; + long *counts; + long ncounts; + struct bb *next; + const unsigned long *addresses; + + /* Older GCC's did not emit these fields. */ + long nwords; + const char **functions; + const long *line_nums; + const char **filenames; + char *flags; +}; + +struct bb *bb_head; +struct module *bb_context_address; +void (*gcov_callback)(int cmd, struct bb *bbptr) = NULL; + +#ifdef GCOV_PATH +char *gcov_kernelpath = GCOV_PATH; +#else +char *gcov_kernelpath = __FILE__; +#endif + + +void +__bb_init_func (struct bb *blocks) +{ + if (blocks->zero_word) + return; + + /* Set up linked list. */ + blocks->zero_word = 1; + + /* Store the address of the module of which this object-file is a part + of (set in do_global_ctors). */ + blocks->addresses = (unsigned long *) bb_context_address; + + blocks->next = bb_head; + bb_head = blocks; + + if (gcov_callback && bb_context_address) + (*gcov_callback)(1,blocks); +} + +/* Call constructors for all kernel objects and dynamic modules. This function + * is called both during module initialization and when the gcov kernel + * module is insmod'ed. The list of constructors is compiled into the + * kernel at &__CTOR_LIST__ to &__DTOR_LIST__ (labels are defined in + * head.S). In the case of a dynamic module the list is located at + * ctors_start to ctors_end. + * + * The constructors in turn call __bb_init_func, reporting the respective + * struct bb for each object file. + */ + +void +do_global_ctors (char *ctors_start, char *ctors_end, struct module *addr, int mod_flag) +{ + extern char __CTOR_LIST__; + extern char __DTOR_LIST__; + typedef void (*func_ptr)(void) ; + func_ptr *constructor_ptr=NULL; + + if (!mod_flag) { + /* Set start and end ptr from global kernel constructor list. */ + ctors_start = &__CTOR_LIST__; + ctors_end = &__DTOR_LIST__; + bb_context_address = NULL; + } else { + /* Set context to current module address. */ + bb_context_address = addr; + } + + if (!ctors_start) + return; + + /* Call all constructor functions until either the end of the + list is reached or until a NULL is encountered. */ + for (constructor_ptr = (func_ptr *) ctors_start; + (constructor_ptr != (func_ptr *) ctors_end) && + (*constructor_ptr != NULL); + constructor_ptr++) { + (*constructor_ptr) (); + } +} + + +/* When a module is unloaded, this function is called to remove + * the respective bb entries from our list. context specifies + * the address of the module that is unloaded. */ + +void +remove_bb_link (struct module *context) +{ + struct bb *bbptr; + struct bb *prev = NULL; + + /* search for all the module's bbptrs */ + for (bbptr = bb_head; bbptr ; bbptr = bbptr->next) { + if (bbptr->addresses == (unsigned long *) context) { + if (gcov_callback) + (*gcov_callback)(0,bbptr); + if (prev == NULL) + bb_head = bbptr->next; + else + prev->next = bbptr->next; + } + else + prev = bbptr; + } +} + +EXPORT_SYMBOL(bb_head); +EXPORT_SYMBOL(__bb_init_func); +EXPORT_SYMBOL(do_global_ctors); +EXPORT_SYMBOL(gcov_kernelpath); +EXPORT_SYMBOL(gcov_callback); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/kernel/kexec.c 830-ivtv/kernel/kexec.c --- 000-virgin/kernel/kexec.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/kernel/kexec.c Thu Jan 8 10:26:46 2004 @@ -0,0 +1,639 @@ +/* + * kexec.c - kexec system call + * Copyright (C) 2002-2003 Eric Biederman + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* When kexec transitions to the new kernel there is a one to one + * mapping between physical and virtual addresses. On processors + * where you can disable the MMU this is trivial, and easy. For + * others it is still a simple predictable page table to setup. + * + * In that environment kexec copies the new kernel to it's final + * resting place. This means I can only support memory whose + * physical address can fit in an unsigned long. In particular + * addresses where (pfn << PAGE_SHIFT) > ULONG_MAX cannot be handled. + * If the assembly stub has more restrictive requirements + * KEXEC_SOURCE_MEMORY_LIMIT and KEXEC_DEST_MEMORY_LIMIT can be + * defined more restrictively in . + * + * The code for the transition from the current kernel to the + * the new kernel is placed in the reboot_code_buffer, whose size + * is given by KEXEC_REBOOT_CODE_SIZE. In the best case only a single + * page of memory is necessary, but some architectures require more. + * Because this memory must be identity mapped in the transition from + * virtual to physical addresses it must live in the range + * 0 - TASK_SIZE, as only the user space mappings are arbitrarily + * modifyable. + * + * The assembly stub in the reboot code buffer is passed a linked list + * of descriptor pages detailing the source pages of the new kernel, + * and the destination addresses of those source pages. As this data + * structure is not used in the context of the current OS, it must + * be self contained. + * + * The code has been made to work with highmem pages and will use a + * destination page in it's final resting place (if it happens + * to allocate it). The end product of this is that most of the + * physical address space, and most of ram can be used. + * + * Future directions include: + * - allocating a page table with the reboot code buffer identity + * mapped, to simplify machine_kexec and make kexec_on_panic, more + * reliable. + * - allocating the pages for a page table for machines that cannot + * disable their MMUs. (Hammer, Alpha...) + */ + +/* KIMAGE_NO_DEST is an impossible destination address..., for + * allocating pages whose destination address we do not care about. + */ +#define KIMAGE_NO_DEST (-1UL) + +static int kimage_is_destination_range( + struct kimage *image, unsigned long start, unsigned long end); +static struct page *kimage_alloc_reboot_code_pages(struct kimage *image); +static struct page *kimage_alloc_page(struct kimage *image, unsigned int gfp_mask, unsigned long dest); + + +static int kimage_alloc(struct kimage **rimage, + unsigned long nr_segments, struct kexec_segment *segments) +{ + int result; + struct kimage *image; + size_t segment_bytes; + struct page *reboot_pages; + unsigned long i; + + /* Allocate a controlling structure */ + result = -ENOMEM; + image = kmalloc(sizeof(*image), GFP_KERNEL); + if (!image) { + goto out; + } + memset(image, 0, sizeof(*image)); + image->head = 0; + image->entry = &image->head; + image->last_entry = &image->head; + + /* Initialize the list of destination pages */ + INIT_LIST_HEAD(&image->dest_pages); + + /* Initialize the list of unuseable pages */ + INIT_LIST_HEAD(&image->unuseable_pages); + + /* Read in the segments */ + image->nr_segments = nr_segments; + segment_bytes = nr_segments * sizeof*segments; + result = copy_from_user(image->segment, segments, segment_bytes); + if (result) + goto out; + + /* Verify we have good destination addresses. The caller is + * responsible for making certain we don't attempt to load + * the new image into invalid or reserved areas of RAM. This + * just verifies it is an address we can use. + */ + result = -EADDRNOTAVAIL; + for(i = 0; i < nr_segments; i++) { + unsigned long mend; + mend = ((unsigned long)(image->segment[i].mem)) + + image->segment[i].memsz; + if (mend >= KEXEC_DESTINATION_MEMORY_LIMIT) + goto out; + } + + /* Find a location for the reboot code buffer, and add it + * the vector of segments so that it's pages will also be + * counted as destination pages. + */ + result = -ENOMEM; + reboot_pages = kimage_alloc_reboot_code_pages(image); + if (!reboot_pages) { + printk(KERN_ERR "Could not allocate reboot_code_buffer\n"); + goto out; + } + image->reboot_code_pages = reboot_pages; + image->segment[nr_segments].buf = 0; + image->segment[nr_segments].bufsz = 0; + image->segment[nr_segments].mem = (void *)(page_to_pfn(reboot_pages) << PAGE_SHIFT); + image->segment[nr_segments].memsz = KEXEC_REBOOT_CODE_SIZE; + image->nr_segments++; + + result = 0; + out: + if (result == 0) { + *rimage = image; + } else { + kfree(image); + } + return result; +} + +static int kimage_is_destination_range( + struct kimage *image, unsigned long start, unsigned long end) +{ + unsigned long i; + for(i = 0; i < image->nr_segments; i++) { + unsigned long mstart, mend; + mstart = (unsigned long)image->segment[i].mem; + mend = mstart + image->segment[i].memsz; + if ((end > mstart) && (start < mend)) { + return 1; + } + } + return 0; +} + +#ifdef CONFIG_MMU +static int identity_map_pages(struct page *pages, int order) +{ + struct mm_struct *mm; + struct vm_area_struct *vma; + int error; + mm = &init_mm; + vma = 0; + + down_write(&mm->mmap_sem); + error = -ENOMEM; + vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + if (!vma) { + goto out; + } + + memset(vma, 0, sizeof(*vma)); + vma->vm_mm = mm; + vma->vm_start = page_to_pfn(pages) << PAGE_SHIFT; + vma->vm_end = vma->vm_start + (1 << (order + PAGE_SHIFT)); + vma->vm_ops = 0; + vma->vm_flags = VM_SHARED \ + | VM_READ | VM_WRITE | VM_EXEC \ + | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC \ + | VM_DONTCOPY | VM_RESERVED; + vma->vm_page_prot = protection_map[vma->vm_flags & 0xf]; + vma->vm_file = NULL; + vma->vm_private_data = NULL; + INIT_LIST_HEAD(&vma->shared); + insert_vm_struct(mm, vma); + + error = remap_page_range(vma, vma->vm_start, vma->vm_start, + vma->vm_end - vma->vm_start, vma->vm_page_prot); + if (error) { + goto out; + } + + error = 0; + out: + if (error && vma) { + kmem_cache_free(vm_area_cachep, vma); + vma = 0; + } + up_write(&mm->mmap_sem); + + return error; +} +#else +#define identity_map_pages(pages, order) 0 +#endif + +struct page *kimage_alloc_reboot_code_pages(struct kimage *image) +{ + /* The reboot code buffer is special. It is the only set of + * pages that must be allocated in their final resting place, + * and the only set of pages whose final resting place we can + * pick. + * + * At worst this runs in O(N) of the image size. + */ + struct list_head extra_pages, *pos, *next; + struct page *pages; + unsigned long addr; + int order, count; + order = get_order(KEXEC_REBOOT_CODE_SIZE); + count = 1 << order; + INIT_LIST_HEAD(&extra_pages); + do { + int i; + pages = alloc_pages(GFP_KERNEL, order); + if (!pages) + break; + for(i = 0; i < count; i++) { + SetPageReserved(pages +i); + } + addr = page_to_pfn(pages) << PAGE_SHIFT; + if ((page_to_pfn(pages) >= (TASK_SIZE >> PAGE_SHIFT)) || + kimage_is_destination_range(image, addr, addr + KEXEC_REBOOT_CODE_SIZE)) { + list_add(&pages->list, &extra_pages); + pages = 0; + } + } while(!pages); + if (pages) { + int result; + result = identity_map_pages(pages, order); + if (result < 0) { + list_add(&pages->list, &extra_pages); + pages = 0; + } + } + /* If I could convert a multi page allocation into a buch of + * single page allocations I could add these pages to + * image->dest_pages. For now it is simpler to just free the + * pages again. + */ + list_for_each_safe(pos, next, &extra_pages) { + struct page *page; + int i; + page = list_entry(pos, struct page, list); + for(i = 0; i < count; i++) { + ClearPageReserved(pages +i); + } + list_del(&extra_pages); + __free_pages(page, order); + } + return pages; +} + +static int kimage_add_entry(struct kimage *image, kimage_entry_t entry) +{ + if (image->offset != 0) { + image->entry++; + } + if (image->entry == image->last_entry) { + kimage_entry_t *ind_page; + struct page *page; + page = kimage_alloc_page(image, GFP_KERNEL, KIMAGE_NO_DEST); + if (!page) { + return -ENOMEM; + } + ind_page = page_address(page); + *image->entry = virt_to_phys(ind_page) | IND_INDIRECTION; + image->entry = ind_page; + image->last_entry = + ind_page + ((PAGE_SIZE/sizeof(kimage_entry_t)) - 1); + } + *image->entry = entry; + image->entry++; + image->offset = 0; + return 0; +} + +static int kimage_set_destination( + struct kimage *image, unsigned long destination) +{ + int result; + destination &= PAGE_MASK; + result = kimage_add_entry(image, destination | IND_DESTINATION); + if (result == 0) { + image->destination = destination; + } + return result; +} + + +static int kimage_add_page(struct kimage *image, unsigned long page) +{ + int result; + page &= PAGE_MASK; + result = kimage_add_entry(image, page | IND_SOURCE); + if (result == 0) { + image->destination += PAGE_SIZE; + } + return result; +} + + +static void kimage_free_extra_pages(struct kimage *image) +{ + /* Walk through and free any extra destination pages I may have */ + struct list_head *pos, *next; + list_for_each_safe(pos, next, &image->dest_pages) { + struct page *page; + page = list_entry(pos, struct page, list); + list_del(&page->list); + ClearPageReserved(page); + __free_page(page); + } + /* Walk through and free any unuseable pages I have cached */ + list_for_each_safe(pos, next, &image->unuseable_pages) { + struct page *page; + page = list_entry(pos, struct page, list); + list_del(&page->list); + ClearPageReserved(page); + __free_page(page); + } + +} +static int kimage_terminate(struct kimage *image) +{ + int result; + result = kimage_add_entry(image, IND_DONE); + if (result == 0) { + /* Point at the terminating element */ + image->entry--; + kimage_free_extra_pages(image); + } + return result; +} + +#define for_each_kimage_entry(image, ptr, entry) \ + for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE); \ + ptr = (entry & IND_INDIRECTION)? \ + phys_to_virt((entry & PAGE_MASK)): ptr +1) + +static void kimage_free(struct kimage *image) +{ + kimage_entry_t *ptr, entry; + kimage_entry_t ind = 0; + int i, count, order; + if (!image) + return; + kimage_free_extra_pages(image); + for_each_kimage_entry(image, ptr, entry) { + if (entry & IND_INDIRECTION) { + /* Free the previous indirection page */ + if (ind & IND_INDIRECTION) { + free_page((unsigned long)phys_to_virt(ind & PAGE_MASK)); + } + /* Save this indirection page until we are + * done with it. + */ + ind = entry; + } + else if (entry & IND_SOURCE) { + free_page((unsigned long)phys_to_virt(entry & PAGE_MASK)); + } + } + order = get_order(KEXEC_REBOOT_CODE_SIZE); + count = 1 << order; + do_munmap(&init_mm, + page_to_pfn(image->reboot_code_pages) << PAGE_SHIFT, + count << PAGE_SHIFT); + for(i = 0; i < count; i++) { + ClearPageReserved(image->reboot_code_pages + i); + } + __free_pages(image->reboot_code_pages, order); + kfree(image); +} + +static kimage_entry_t *kimage_dst_used(struct kimage *image, unsigned long page) +{ + kimage_entry_t *ptr, entry; + unsigned long destination = 0; + for_each_kimage_entry(image, ptr, entry) { + if (entry & IND_DESTINATION) { + destination = entry & PAGE_MASK; + } + else if (entry & IND_SOURCE) { + if (page == destination) { + return ptr; + } + destination += PAGE_SIZE; + } + } + return 0; +} + +static struct page *kimage_alloc_page(struct kimage *image, unsigned int gfp_mask, unsigned long destination) +{ + /* Here we implment safe guards to ensure that a source page + * is not copied to it's destination page before the data on + * the destination page is no longer useful. + * + * To do this we maintain the invariant that a source page is + * either it's own destination page, or it is not a + * destination page at all. + * + * That is slightly stronger than required, but the proof + * that no problems will not occur is trivial, and the + * implemenation is simply to verify. + * + * When allocating all pages normally this algorithm will run + * in O(N) time, but in the worst case it will run in O(N^2) + * time. If the runtime is a problem the data structures can + * be fixed. + */ + struct page *page; + unsigned long addr; + + /* Walk through the list of destination pages, and see if I + * have a match. + */ + list_for_each_entry(page, &image->dest_pages, list) { + addr = page_to_pfn(page) << PAGE_SHIFT; + if (addr == destination) { + list_del(&page->list); + return page; + } + } + page = 0; + while(1) { + kimage_entry_t *old; + /* Allocate a page, if we run out of memory give up */ + page = alloc_page(gfp_mask); + if (!page) { + return 0; + } + SetPageReserved(page); + /* If the page cannot be used file it away */ + if (page_to_pfn(page) > (KEXEC_SOURCE_MEMORY_LIMIT >> PAGE_SHIFT)) { + list_add(&page->list, &image->unuseable_pages); + continue; + } + addr = page_to_pfn(page) << PAGE_SHIFT; + + /* If it is the destination page we want use it */ + if (addr == destination) + break; + + /* If the page is not a destination page use it */ + if (!kimage_is_destination_range(image, addr, addr + PAGE_SIZE)) + break; + + /* I know that the page is someones destination page. + * See if there is already a source page for this + * destination page. And if so swap the source pages. + */ + old = kimage_dst_used(image, addr); + if (old) { + /* If so move it */ + unsigned long old_addr; + struct page *old_page; + + old_addr = *old & PAGE_MASK; + old_page = pfn_to_page(old_addr >> PAGE_SHIFT); + copy_highpage(page, old_page); + *old = addr | (*old & ~PAGE_MASK); + + /* The old page I have found cannot be a + * destination page, so return it. + */ + addr = old_addr; + page = old_page; + break; + } + else { + /* Place the page on the destination list I + * will use it later. + */ + list_add(&page->list, &image->dest_pages); + } + } + return page; +} + +static int kimage_load_segment(struct kimage *image, + struct kexec_segment *segment) +{ + unsigned long mstart; + int result; + unsigned long offset; + unsigned long offset_end; + unsigned char *buf; + + result = 0; + buf = segment->buf; + mstart = (unsigned long)segment->mem; + + offset_end = segment->memsz; + + result = kimage_set_destination(image, mstart); + if (result < 0) { + goto out; + } + for(offset = 0; offset < segment->memsz; offset += PAGE_SIZE) { + struct page *page; + char *ptr; + size_t size, leader; + page = kimage_alloc_page(image, GFP_HIGHUSER, mstart + offset); + if (page == 0) { + result = -ENOMEM; + goto out; + } + result = kimage_add_page(image, page_to_pfn(page) << PAGE_SHIFT); + if (result < 0) { + goto out; + } + ptr = kmap(page); + if (segment->bufsz < offset) { + /* We are past the end zero the whole page */ + memset(ptr, 0, PAGE_SIZE); + kunmap(page); + continue; + } + size = PAGE_SIZE; + leader = 0; + if ((offset == 0)) { + leader = mstart & ~PAGE_MASK; + } + if (leader) { + /* We are on the first page zero the unused portion */ + memset(ptr, 0, leader); + size -= leader; + ptr += leader; + } + if (size > (segment->bufsz - offset)) { + size = segment->bufsz - offset; + } + if (size < (PAGE_SIZE - leader)) { + /* zero the trailing part of the page */ + memset(ptr + size, 0, (PAGE_SIZE - leader) - size); + } + result = copy_from_user(ptr, buf + offset, size); + kunmap(page); + if (result) { + result = (result < 0)?result : -EIO; + goto out; + } + } + out: + return result; +} + +/* + * Exec Kernel system call: for obvious reasons only root may call it. + * + * This call breaks up into three pieces. + * - A generic part which loads the new kernel from the current + * address space, and very carefully places the data in the + * allocated pages. + * + * - A generic part that interacts with the kernel and tells all of + * the devices to shut down. Preventing on-going dmas, and placing + * the devices in a consistent state so a later kernel can + * reinitialize them. + * + * - A machine specific part that includes the syscall number + * and the copies the image to it's final destination. And + * jumps into the image at entry. + * + * kexec does not sync, or unmount filesystems so if you need + * that to happen you need to do that yourself. + */ +struct kimage *kexec_image = 0; + +asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments, + struct kexec_segment *segments, unsigned long flags) +{ + struct kimage *image; + int result; + + /* We only trust the superuser with rebooting the system. */ + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + /* In case we need just a little bit of special behavior for + * reboot on panic + */ + if (flags != 0) + return -EINVAL; + + if (nr_segments > KEXEC_SEGMENT_MAX) + return -EINVAL; + + image = 0; + result = 0; + + if (nr_segments > 0) { + unsigned long i; + result = kimage_alloc(&image, nr_segments, segments); + if (result) { + goto out; + } + image->start = entry; + for (i = 0; i < nr_segments; i++) { + ///result = kimage_load_segment(image, &segments[i]); + result = kimage_load_segment(image, &image->segment[i]); + if (result) { + goto out; + } + } + result = kimage_terminate(image); + if (result) { + goto out; + } + } + + image = xchg(&kexec_image, image); + + out: + kimage_free(image); + return result; +} diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/kernel/lockmeter.c 830-ivtv/kernel/lockmeter.c --- 000-virgin/kernel/lockmeter.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/kernel/lockmeter.c Thu Jan 8 09:30:50 2004 @@ -0,0 +1,1178 @@ +/* + * Copyright (C) 1999,2000 Silicon Graphics, Inc. + * + * Written by John Hawkes (hawkes@sgi.com) + * Based on klstat.c by Jack Steiner (steiner@sgi.com) + * + * Modified by Ray Bryant (raybry@us.ibm.com) + * Changes Copyright (C) 2000 IBM, Inc. + * Added save of index in spinlock_t to improve efficiency + * of "hold" time reporting for spinlocks + * Added support for hold time statistics for read and write + * locks. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define ASSERT(cond) +#define bzero(loc,size) memset(loc,0,size) + +/*<---------------------------------------------------*/ +/* lockmeter.c */ +/*>---------------------------------------------------*/ + +static lstat_control_t lstat_control __cacheline_aligned = + { LSTAT_OFF, SPIN_LOCK_UNLOCKED, SPIN_LOCK_UNLOCKED, + 19 * 0, NR_CPUS * 0, 0, NR_CPUS * 0 }; + +static ushort lstat_make_dir_entry(void *, void *); + +/* + * lstat_lookup + * + * Given a RA, locate the directory entry for the lock. + */ +static ushort +lstat_lookup(void *lock_ptr, void *caller_ra) +{ + ushort index; + lstat_directory_entry_t *dirp; + + dirp = lstat_control.dir; + + index = lstat_control.hashtab[DIRHASH(caller_ra)]; + while (dirp[index].caller_ra != caller_ra) { + if (index == 0) { + return lstat_make_dir_entry(lock_ptr, caller_ra); + } + index = dirp[index].next_stat_index; + } + + if (dirp[index].lock_ptr != NULL && dirp[index].lock_ptr != lock_ptr) { + dirp[index].lock_ptr = NULL; + } + + return index; +} + +/* + * lstat_make_dir_entry + * Called to add a new lock to the lock directory. + */ +static ushort +lstat_make_dir_entry(void *lock_ptr, void *caller_ra) +{ + lstat_directory_entry_t *dirp; + ushort index, hindex; + unsigned long flags; + + /* lock the table without recursively reentering this metering code */ + local_irq_save(flags); + _raw_spin_lock(&lstat_control.directory_lock); + + hindex = DIRHASH(caller_ra); + index = lstat_control.hashtab[hindex]; + dirp = lstat_control.dir; + while (index && dirp[index].caller_ra != caller_ra) + index = dirp[index].next_stat_index; + + if (index == 0) { + if (lstat_control.next_free_dir_index < LSTAT_MAX_STAT_INDEX) { + index = lstat_control.next_free_dir_index++; + lstat_control.dir[index].caller_ra = caller_ra; + lstat_control.dir[index].lock_ptr = lock_ptr; + lstat_control.dir[index].next_stat_index = + lstat_control.hashtab[hindex]; + lstat_control.hashtab[hindex] = index; + } else { + lstat_control.dir_overflow++; + } + } + _raw_spin_unlock(&lstat_control.directory_lock); + local_irq_restore(flags); + return index; +} + +int +lstat_update(void *lock_ptr, void *caller_ra, int action) +{ + int index; + int cpu; + + ASSERT(action < LSTAT_ACT_MAX_VALUES); + + if (lstat_control.state == LSTAT_OFF) + return 0; + + index = lstat_lookup(lock_ptr, caller_ra); + cpu = THIS_CPU_NUMBER; + (*lstat_control.counts[cpu])[index].count[action]++; + (*lstat_control.counts[cpu])[index].acquire_time = get_cycles(); + + return index; +} + +int +lstat_update_time(void *lock_ptr, void *caller_ra, int action, uint32_t ticks) +{ + ushort index; + int cpu; + + ASSERT(action < LSTAT_ACT_MAX_VALUES); + + if (lstat_control.state == LSTAT_OFF) + return 0; + + index = lstat_lookup(lock_ptr, caller_ra); + cpu = THIS_CPU_NUMBER; + (*lstat_control.counts[cpu])[index].count[action]++; + (*lstat_control.counts[cpu])[index].cum_wait_ticks += (uint64_t) ticks; + if ((*lstat_control.counts[cpu])[index].max_wait_ticks < ticks) + (*lstat_control.counts[cpu])[index].max_wait_ticks = ticks; + + (*lstat_control.counts[cpu])[index].acquire_time = get_cycles(); + + return index; +} + +void +_metered_spin_lock(spinlock_t * lock_ptr) +{ + if (lstat_control.state == LSTAT_OFF) { + _raw_spin_lock(lock_ptr); /* do the real lock */ + PUT_INDEX(lock_ptr, 0); /* clean index in case lockmetering */ + /* gets turned on before unlock */ + } else { + void *this_pc = LSTAT_RA(LSTAT_RA_SPIN); + int index; + + if (_raw_spin_trylock(lock_ptr)) { + index = lstat_update(lock_ptr, this_pc, + LSTAT_ACT_NO_WAIT); + } else { + uint32_t start_cycles = get_cycles(); + _raw_spin_lock(lock_ptr); /* do the real lock */ + index = lstat_update_time(lock_ptr, this_pc, + LSTAT_ACT_SPIN, get_cycles() - start_cycles); + } + /* save the index in the lock itself for use in spin unlock */ + PUT_INDEX(lock_ptr, index); + } +} + +int +_metered_spin_trylock(spinlock_t * lock_ptr) +{ + if (lstat_control.state == LSTAT_OFF) { + return _raw_spin_trylock(lock_ptr); + } else { + int retval; + void *this_pc = LSTAT_RA(LSTAT_RA_SPIN); + + if ((retval = _raw_spin_trylock(lock_ptr))) { + int index = lstat_update(lock_ptr, this_pc, + LSTAT_ACT_NO_WAIT); + /* + * save the index in the lock itself for use in spin + * unlock + */ + PUT_INDEX(lock_ptr, index); + } else { + lstat_update(lock_ptr, this_pc, LSTAT_ACT_REJECT); + } + + return retval; + } +} + +void +_metered_spin_unlock(spinlock_t * lock_ptr) +{ + int index = -1; + + if (lstat_control.state != LSTAT_OFF) { + index = GET_INDEX(lock_ptr); + /* + * If statistics were turned off when we set the lock, + * then the index can be zero. If that is the case, + * then collect no stats on this call. + */ + if (index > 0) { + uint32_t hold_time; + int cpu = THIS_CPU_NUMBER; + hold_time = get_cycles() - + (*lstat_control.counts[cpu])[index].acquire_time; + (*lstat_control.counts[cpu])[index].cum_hold_ticks += + (uint64_t) hold_time; + if ((*lstat_control.counts[cpu])[index].max_hold_ticks < + hold_time) + (*lstat_control.counts[cpu])[index]. + max_hold_ticks = hold_time; + } + } + + /* make sure we don't have a stale index value saved */ + PUT_INDEX(lock_ptr, 0); + _raw_spin_unlock(lock_ptr); /* do the real unlock */ +} + +/* + * allocate the next global read lock structure and store its index + * in the rwlock at "lock_ptr". + */ +uint32_t +alloc_rwlock_struct(rwlock_t * rwlock_ptr) +{ + int index; + unsigned long flags; + int cpu = THIS_CPU_NUMBER; + + /* If we've already overflowed, then do a quick exit */ + if (lstat_control.next_free_read_lock_index > + LSTAT_MAX_READ_LOCK_INDEX) { + lstat_control.rwlock_overflow++; + return 0; + } + + local_irq_save(flags); + _raw_spin_lock(&lstat_control.directory_lock); + + /* It is possible this changed while we were waiting for the directory_lock */ + if (lstat_control.state == LSTAT_OFF) { + index = 0; + goto unlock; + } + + /* It is possible someone else got here first and set the index */ + if ((index = GET_RWINDEX(rwlock_ptr)) == 0) { + /* + * we can't turn on read stats for this lock while there are + * readers (this would mess up the running hold time sum at + * unlock time) + */ + if (RWLOCK_READERS(rwlock_ptr) != 0) { + index = 0; + goto unlock; + } + + /* + * if stats are turned on after being off, we may need to + * return an old index from when the statistics were on last + * time. + */ + for (index = 1; index < lstat_control.next_free_read_lock_index; + index++) + if ((*lstat_control.read_lock_counts[cpu])[index]. + lock_ptr == rwlock_ptr) + goto put_index_and_unlock; + + /* allocate the next global read lock structure */ + if (lstat_control.next_free_read_lock_index >= + LSTAT_MAX_READ_LOCK_INDEX) { + lstat_control.rwlock_overflow++; + index = 0; + goto unlock; + } + index = lstat_control.next_free_read_lock_index++; + + /* + * initialize the global read stats data structure for each + * cpu + */ + for (cpu = 0; cpu < num_online_cpus(); cpu++) { + (*lstat_control.read_lock_counts[cpu])[index].lock_ptr = + rwlock_ptr; + } +put_index_and_unlock: + /* store the index for the read lock structure into the lock */ + PUT_RWINDEX(rwlock_ptr, index); + } + +unlock: + _raw_spin_unlock(&lstat_control.directory_lock); + local_irq_restore(flags); + return index; +} + +void +_metered_read_lock(rwlock_t * rwlock_ptr) +{ + void *this_pc; + uint32_t start_cycles; + int index; + int cpu; + unsigned long flags; + int readers_before, readers_after; + uint64_t cycles64; + + if (lstat_control.state == LSTAT_OFF) { + _raw_read_lock(rwlock_ptr); + /* clean index in case lockmetering turns on before an unlock */ + PUT_RWINDEX(rwlock_ptr, 0); + return; + } + + this_pc = LSTAT_RA(LSTAT_RA_READ); + cpu = THIS_CPU_NUMBER; + index = GET_RWINDEX(rwlock_ptr); + + /* allocate the global stats entry for this lock, if needed */ + if (index == 0) + index = alloc_rwlock_struct(rwlock_ptr); + + readers_before = RWLOCK_READERS(rwlock_ptr); + if (_raw_read_trylock(rwlock_ptr)) { + /* + * We have decremented the lock to count a new reader, + * and have confirmed that no writer has it locked. + */ + /* update statistics if enabled */ + if (index > 0) { + local_irq_save(flags); + lstat_update((void *) rwlock_ptr, this_pc, + LSTAT_ACT_NO_WAIT); + /* preserve value of TSC so cum_hold_ticks and start_busy use same value */ + cycles64 = get_cycles64(); + (*lstat_control.read_lock_counts[cpu])[index]. + cum_hold_ticks -= cycles64; + + /* record time and cpu of start of busy period */ + /* this is not perfect (some race conditions are possible) */ + if (readers_before == 0) { + (*lstat_control.read_lock_counts[cpu])[index]. + start_busy = cycles64; + PUT_RW_CPU(rwlock_ptr, cpu); + } + readers_after = RWLOCK_READERS(rwlock_ptr); + if (readers_after > + (*lstat_control.read_lock_counts[cpu])[index]. + max_readers) + (*lstat_control.read_lock_counts[cpu])[index]. + max_readers = readers_after; + local_irq_restore(flags); + } + + return; + } + /* If we get here, then we could not quickly grab the read lock */ + + start_cycles = get_cycles(); /* start counting the wait time */ + + /* Now spin until read_lock is successful */ + _raw_read_lock(rwlock_ptr); + + lstat_update_time((void *) rwlock_ptr, this_pc, LSTAT_ACT_SPIN, + get_cycles() - start_cycles); + + /* update statistics if they are enabled for this lock */ + if (index > 0) { + local_irq_save(flags); + cycles64 = get_cycles64(); + (*lstat_control.read_lock_counts[cpu])[index].cum_hold_ticks -= + cycles64; + + /* this is not perfect (some race conditions are possible) */ + if (readers_before == 0) { + (*lstat_control.read_lock_counts[cpu])[index]. + start_busy = cycles64; + PUT_RW_CPU(rwlock_ptr, cpu); + } + readers_after = RWLOCK_READERS(rwlock_ptr); + if (readers_after > + (*lstat_control.read_lock_counts[cpu])[index].max_readers) + (*lstat_control.read_lock_counts[cpu])[index]. + max_readers = readers_after; + local_irq_restore(flags); + } +} + +void +_metered_read_unlock(rwlock_t * rwlock_ptr) +{ + int index; + int cpu; + unsigned long flags; + uint64_t busy_length; + uint64_t cycles64; + + if (lstat_control.state == LSTAT_OFF) { + _raw_read_unlock(rwlock_ptr); + return; + } + + index = GET_RWINDEX(rwlock_ptr); + cpu = THIS_CPU_NUMBER; + + if (index > 0) { + local_irq_save(flags); + /* + * preserve value of TSC so cum_hold_ticks and busy_ticks are + * consistent. + */ + cycles64 = get_cycles64(); + (*lstat_control.read_lock_counts[cpu])[index].cum_hold_ticks += + cycles64; + (*lstat_control.read_lock_counts[cpu])[index].read_lock_count++; + + /* + * once again, this is not perfect (some race conditions are + * possible) + */ + if (RWLOCK_READERS(rwlock_ptr) == 1) { + int cpu1 = GET_RW_CPU(rwlock_ptr); + uint64_t last_start_busy = + (*lstat_control.read_lock_counts[cpu1])[index]. + start_busy; + (*lstat_control.read_lock_counts[cpu])[index]. + busy_periods++; + if (cycles64 > last_start_busy) { + busy_length = cycles64 - last_start_busy; + (*lstat_control.read_lock_counts[cpu])[index]. + busy_ticks += busy_length; + if (busy_length > + (*lstat_control. + read_lock_counts[cpu])[index]. + max_busy) + (*lstat_control. + read_lock_counts[cpu])[index]. + max_busy = busy_length; + } + } + local_irq_restore(flags); + } + _raw_read_unlock(rwlock_ptr); +} + +void +_metered_write_lock(rwlock_t * rwlock_ptr) +{ + uint32_t start_cycles; + void *this_pc; + uint32_t spin_ticks = 0; /* in anticipation of a potential wait */ + int index; + int write_index = 0; + int cpu; + enum { + writer_writer_conflict, + writer_reader_conflict + } why_wait = writer_writer_conflict; + + if (lstat_control.state == LSTAT_OFF) { + _raw_write_lock(rwlock_ptr); + /* clean index in case lockmetering turns on before an unlock */ + PUT_RWINDEX(rwlock_ptr, 0); + return; + } + + this_pc = LSTAT_RA(LSTAT_RA_WRITE); + cpu = THIS_CPU_NUMBER; + index = GET_RWINDEX(rwlock_ptr); + + /* allocate the global stats entry for this lock, if needed */ + if (index == 0) { + index = alloc_rwlock_struct(rwlock_ptr); + } + + if (_raw_write_trylock(rwlock_ptr)) { + /* We acquired the lock on the first try */ + write_index = lstat_update((void *) rwlock_ptr, this_pc, + LSTAT_ACT_NO_WAIT); + /* save the write_index for use in unlock if stats enabled */ + if (index > 0) + (*lstat_control.read_lock_counts[cpu])[index]. + write_index = write_index; + return; + } + + /* If we get here, then we could not quickly grab the write lock */ + start_cycles = get_cycles(); /* start counting the wait time */ + + why_wait = RWLOCK_READERS(rwlock_ptr) ? + writer_reader_conflict : writer_writer_conflict; + + /* Now set the lock and wait for conflicts to disappear */ + _raw_write_lock(rwlock_ptr); + + spin_ticks = get_cycles() - start_cycles; + + /* update stats -- if enabled */ + if (index > 0 && spin_ticks) { + if (why_wait == writer_reader_conflict) { + /* waited due to a reader holding the lock */ + write_index = lstat_update_time((void *)rwlock_ptr, + this_pc, LSTAT_ACT_SPIN, spin_ticks); + } else { + /* + * waited due to another writer holding the lock + */ + write_index = lstat_update_time((void *)rwlock_ptr, + this_pc, LSTAT_ACT_WW_SPIN, spin_ticks); + (*lstat_control.counts[cpu])[write_index]. + cum_wait_ww_ticks += spin_ticks; + if (spin_ticks > + (*lstat_control.counts[cpu])[write_index]. + max_wait_ww_ticks) { + (*lstat_control.counts[cpu])[write_index]. + max_wait_ww_ticks = spin_ticks; + } + } + + /* save the directory index for use on write_unlock */ + (*lstat_control.read_lock_counts[cpu])[index]. + write_index = write_index; + } +} + +void +_metered_write_unlock(rwlock_t * rwlock_ptr) +{ + int index; + int cpu; + int write_index; + uint32_t hold_time; + + if (lstat_control.state == LSTAT_OFF) { + _raw_write_unlock(rwlock_ptr); + return; + } + + cpu = THIS_CPU_NUMBER; + index = GET_RWINDEX(rwlock_ptr); + + /* update statistics if stats enabled for this lock */ + if (index > 0) { + write_index = + (*lstat_control.read_lock_counts[cpu])[index].write_index; + + hold_time = get_cycles() - + (*lstat_control.counts[cpu])[write_index].acquire_time; + (*lstat_control.counts[cpu])[write_index].cum_hold_ticks += + (uint64_t) hold_time; + if ((*lstat_control.counts[cpu])[write_index].max_hold_ticks < + hold_time) + (*lstat_control.counts[cpu])[write_index]. + max_hold_ticks = hold_time; + } + _raw_write_unlock(rwlock_ptr); +} + +int +_metered_write_trylock(rwlock_t * rwlock_ptr) +{ + int retval; + void *this_pc = LSTAT_RA(LSTAT_RA_WRITE); + + if ((retval = _raw_write_trylock(rwlock_ptr))) { + lstat_update(rwlock_ptr, this_pc, LSTAT_ACT_NO_WAIT); + } else { + lstat_update(rwlock_ptr, this_pc, LSTAT_ACT_REJECT); + } + + return retval; +} + +static void +init_control_space(void) +{ + /* Set all control space pointers to null and indices to "empty" */ + int cpu; + + /* + * Access CPU_CYCLE_FREQUENCY at the outset, which in some + * architectures may trigger a runtime calculation that uses a + * spinlock. Let's do this before lockmetering is turned on. + */ + if (CPU_CYCLE_FREQUENCY == 0) + BUG(); + + lstat_control.hashtab = NULL; + lstat_control.dir = NULL; + for (cpu = 0; cpu < NR_CPUS; cpu++) { + lstat_control.counts[cpu] = NULL; + lstat_control.read_lock_counts[cpu] = NULL; + } +} + +static int +reset_lstat_data(void) +{ + int cpu, flags; + + flags = 0; + lstat_control.next_free_dir_index = 1; /* 0 is for overflows */ + lstat_control.next_free_read_lock_index = 1; + lstat_control.dir_overflow = 0; + lstat_control.rwlock_overflow = 0; + + lstat_control.started_cycles64 = 0; + lstat_control.ending_cycles64 = 0; + lstat_control.enabled_cycles64 = 0; + lstat_control.first_started_time = 0; + lstat_control.started_time = 0; + lstat_control.ending_time = 0; + lstat_control.intervals = 0; + + /* + * paranoia -- in case someone does a "lockstat reset" before + * "lockstat on" + */ + if (lstat_control.hashtab) { + bzero(lstat_control.hashtab, + LSTAT_HASH_TABLE_SIZE * sizeof (short)); + bzero(lstat_control.dir, LSTAT_MAX_STAT_INDEX * + sizeof (lstat_directory_entry_t)); + + for (cpu = 0; cpu < num_online_cpus(); cpu++) { + bzero(lstat_control.counts[cpu], + sizeof (lstat_cpu_counts_t)); + bzero(lstat_control.read_lock_counts[cpu], + sizeof (lstat_read_lock_cpu_counts_t)); + } + } +#ifdef NOTDEF + _raw_spin_unlock(&lstat_control.directory_lock); + local_irq_restore(flags); +#endif + return 1; +} + +static void +release_control_space(void) +{ + /* + * Called when either (1) allocation of kmem + * or (2) when user writes LSTAT_RELEASE to /pro/lockmeter. + * Assume that all pointers have been initialized to zero, + * i.e., nonzero pointers are valid addresses. + */ + int cpu; + + if (lstat_control.hashtab) { + kfree(lstat_control.hashtab); + lstat_control.hashtab = NULL; + } + + if (lstat_control.dir) { + vfree(lstat_control.dir); + lstat_control.dir = NULL; + } + + for (cpu = 0; cpu < NR_CPUS; cpu++) { + if (lstat_control.counts[cpu]) { + vfree(lstat_control.counts[cpu]); + lstat_control.counts[cpu] = NULL; + } + if (lstat_control.read_lock_counts[cpu]) { + kfree(lstat_control.read_lock_counts[cpu]); + lstat_control.read_lock_counts[cpu] = NULL; + } + } +} + +int +get_lockmeter_info_size(void) +{ + return sizeof (lstat_user_request_t) + + num_online_cpus() * sizeof (lstat_cpu_counts_t) + + num_online_cpus() * sizeof (lstat_read_lock_cpu_counts_t) + + (LSTAT_MAX_STAT_INDEX * sizeof (lstat_directory_entry_t)); +} + +ssize_t +get_lockmeter_info(char *buffer, size_t max_len, loff_t * last_index) +{ + lstat_user_request_t req; + struct timeval tv; + ssize_t next_ret_bcount; + ssize_t actual_ret_bcount = 0; + int cpu; + + *last_index = 0; /* a one-shot read */ + + req.lstat_version = LSTAT_VERSION; + req.state = lstat_control.state; + req.maxcpus = num_online_cpus(); + req.cycleval = CPU_CYCLE_FREQUENCY; +#ifdef notyet + req.kernel_magic_addr = (void *) &_etext; + req.kernel_end_addr = (void *) &_etext; +#endif + req.uts = system_utsname; + req.intervals = lstat_control.intervals; + + req.first_started_time = lstat_control.first_started_time; + req.started_time = lstat_control.started_time; + req.started_cycles64 = lstat_control.started_cycles64; + + req.next_free_dir_index = lstat_control.next_free_dir_index; + req.next_free_read_lock_index = lstat_control.next_free_read_lock_index; + req.dir_overflow = lstat_control.dir_overflow; + req.rwlock_overflow = lstat_control.rwlock_overflow; + + if (lstat_control.state == LSTAT_OFF) { + if (req.intervals == 0) { + /* mesasurement is off and no valid data present */ + next_ret_bcount = sizeof (lstat_user_request_t); + req.enabled_cycles64 = 0; + + if ((actual_ret_bcount + next_ret_bcount) > max_len) + return actual_ret_bcount; + + copy_to_user(buffer, (void *) &req, next_ret_bcount); + actual_ret_bcount += next_ret_bcount; + return actual_ret_bcount; + } else { + /* + * measurement is off but valid data present + * fetch time info from lstat_control + */ + req.ending_time = lstat_control.ending_time; + req.ending_cycles64 = lstat_control.ending_cycles64; + req.enabled_cycles64 = lstat_control.enabled_cycles64; + } + } else { + /* + * this must be a read while data active--use current time, + * etc + */ + do_gettimeofday(&tv); + req.ending_time = tv.tv_sec; + req.ending_cycles64 = get_cycles64(); + req.enabled_cycles64 = req.ending_cycles64 - + req.started_cycles64 + lstat_control.enabled_cycles64; + } + + next_ret_bcount = sizeof (lstat_user_request_t); + if ((actual_ret_bcount + next_ret_bcount) > max_len) + return actual_ret_bcount; + + copy_to_user(buffer, (void *) &req, next_ret_bcount); + actual_ret_bcount += next_ret_bcount; + + if (!lstat_control.counts[0]) /* not initialized? */ + return actual_ret_bcount; + + next_ret_bcount = sizeof (lstat_cpu_counts_t); + for (cpu = 0; cpu < num_online_cpus(); cpu++) { + if ((actual_ret_bcount + next_ret_bcount) > max_len) + return actual_ret_bcount; /* leave early */ + copy_to_user(buffer + actual_ret_bcount, + lstat_control.counts[cpu], next_ret_bcount); + actual_ret_bcount += next_ret_bcount; + } + + next_ret_bcount = LSTAT_MAX_STAT_INDEX * + sizeof (lstat_directory_entry_t); + if (((actual_ret_bcount + next_ret_bcount) > max_len) + || !lstat_control.dir) + return actual_ret_bcount; /* leave early */ + + copy_to_user(buffer + actual_ret_bcount, lstat_control.dir, + next_ret_bcount); + actual_ret_bcount += next_ret_bcount; + + next_ret_bcount = sizeof (lstat_read_lock_cpu_counts_t); + for (cpu = 0; cpu < num_online_cpus(); cpu++) { + if (actual_ret_bcount + next_ret_bcount > max_len) + return actual_ret_bcount; + copy_to_user(buffer + actual_ret_bcount, + lstat_control.read_lock_counts[cpu], + next_ret_bcount); + actual_ret_bcount += next_ret_bcount; + } + + return actual_ret_bcount; +} + +/* + * Writing to the /proc lockmeter node enables or disables metering. + * based upon the first byte of the "written" data. + * The following values are defined: + * LSTAT_ON: 1st call: allocates storage, intializes and turns on measurement + * subsequent calls just turn on measurement + * LSTAT_OFF: turns off measurement + * LSTAT_RESET: resets statistics + * LSTAT_RELEASE: releases statistics storage + * + * This allows one to accumulate statistics over several lockstat runs: + * + * lockstat on + * lockstat off + * ...repeat above as desired... + * lockstat get + * ...now start a new set of measurements... + * lockstat reset + * lockstat on + * ... + * + */ +ssize_t +put_lockmeter_info(const char *buffer, size_t len) +{ + int error = 0; + int dirsize, countsize, read_lock_countsize, hashsize; + int cpu; + char put_char; + int i, read_lock_blocks; + unsigned long flags; + rwlock_t *lock_ptr; + struct timeval tv; + + if (len <= 0) + return -EINVAL; + + _raw_spin_lock(&lstat_control.control_lock); + + get_user(put_char, buffer); + switch (put_char) { + + case LSTAT_OFF: + if (lstat_control.state != LSTAT_OFF) { + /* + * To avoid seeing read lock hold times in an + * inconsisent state, we have to follow this protocol + * to turn off statistics + */ + local_irq_save(flags); + /* + * getting this lock will stop any read lock block + * allocations + */ + _raw_spin_lock(&lstat_control.directory_lock); + /* + * keep any more read lock blocks from being + * allocated + */ + lstat_control.state = LSTAT_OFF; + /* record how may read lock blocks there are */ + read_lock_blocks = + lstat_control.next_free_read_lock_index; + _raw_spin_unlock(&lstat_control.directory_lock); + /* now go through the list of read locks */ + cpu = THIS_CPU_NUMBER; + for (i = 1; i < read_lock_blocks; i++) { + lock_ptr = + (*lstat_control.read_lock_counts[cpu])[i]. + lock_ptr; + /* is this saved lock address still valid? */ + if (GET_RWINDEX(lock_ptr) == i) { + /* + * lock address appears to still be + * valid because we only hold one lock + * at a time, this can't cause a + * deadlock unless this is a lock held + * as part of the current system call + * path. At the moment there + * are no READ mode locks held to get + * here from user space, so we solve + * this by skipping locks held in + * write mode. + */ + if (RWLOCK_IS_WRITE_LOCKED(lock_ptr)) { + PUT_RWINDEX(lock_ptr, 0); + continue; + } + /* + * now we know there are no read + * holders of this lock! stop + * statistics collection for this + * lock + */ + _raw_write_lock(lock_ptr); + PUT_RWINDEX(lock_ptr, 0); + _raw_write_unlock(lock_ptr); + } + /* + * it may still be possible for the hold time + * sum to be negative e.g. if a lock is + * reallocated while "busy" we will have to fix + * this up in the data reduction program. + */ + } + local_irq_restore(flags); + lstat_control.intervals++; + lstat_control.ending_cycles64 = get_cycles64(); + lstat_control.enabled_cycles64 += + lstat_control.ending_cycles64 - + lstat_control.started_cycles64; + do_gettimeofday(&tv); + lstat_control.ending_time = tv.tv_sec; + /* + * don't deallocate the structures -- we may do a + * lockstat on to add to the data that is already + * there. Use LSTAT_RELEASE to release storage + */ + } else { + error = -EBUSY; /* already OFF */ + } + break; + + case LSTAT_ON: + if (lstat_control.state == LSTAT_OFF) { +#ifdef DEBUG_LOCKMETER + printk("put_lockmeter_info(cpu=%d): LSTAT_ON\n", + THIS_CPU_NUMBER); +#endif + lstat_control.next_free_dir_index = 1; /* 0 is for overflows */ + + dirsize = LSTAT_MAX_STAT_INDEX * + sizeof (lstat_directory_entry_t); + hashsize = + (1 + LSTAT_HASH_TABLE_SIZE) * sizeof (ushort); + countsize = sizeof (lstat_cpu_counts_t); + read_lock_countsize = + sizeof (lstat_read_lock_cpu_counts_t); +#ifdef DEBUG_LOCKMETER + printk(" dirsize:%d", dirsize); + printk(" hashsize:%d", hashsize); + printk(" countsize:%d", countsize); + printk(" read_lock_countsize:%d\n", + read_lock_countsize); +#endif +#ifdef DEBUG_LOCKMETER + { + int secs; + unsigned long cycles; + uint64_t cycles64; + + do_gettimeofday(&tv); + secs = tv.tv_sec; + do { + do_gettimeofday(&tv); + } while (secs == tv.tv_sec); + cycles = get_cycles(); + cycles64 = get_cycles64(); + secs = tv.tv_sec; + do { + do_gettimeofday(&tv); + } while (secs == tv.tv_sec); + cycles = get_cycles() - cycles; + cycles64 = get_cycles64() - cycles; + printk("lockmeter: cycleFrequency:%d " + "cycles:%d cycles64:%d\n", + CPU_CYCLE_FREQUENCY, cycles, cycles64); + } +#endif + + /* + * if this is the first call, allocate storage and + * initialize + */ + if (!lstat_control.hashtab) { + + spin_lock_init(&lstat_control.directory_lock); + + /* guarantee all pointers at zero */ + init_control_space(); + + lstat_control.hashtab = + kmalloc(hashsize, GFP_KERNEL); + if (!lstat_control.hashtab) { + error = -ENOSPC; +#ifdef DEBUG_LOCKMETER + printk("!!error kmalloc of hashtab\n"); +#endif + } + lstat_control.dir = vmalloc(dirsize); + if (!lstat_control.dir) { + error = -ENOSPC; +#ifdef DEBUG_LOCKMETER + printk("!!error kmalloc of dir\n"); +#endif + } + + for (cpu = 0; cpu < num_online_cpus(); cpu++) { + lstat_control.counts[cpu] = + vmalloc(countsize); + if (!lstat_control.counts[cpu]) { + error = -ENOSPC; +#ifdef DEBUG_LOCKMETER + printk("!!error vmalloc of " + "counts[%d]\n", cpu); +#endif + } + lstat_control.read_lock_counts[cpu] = + (lstat_read_lock_cpu_counts_t *) + kmalloc(read_lock_countsize, + GFP_KERNEL); + if (!lstat_control. + read_lock_counts[cpu]) { + error = -ENOSPC; +#ifdef DEBUG_LOCKMETER + printk("!!error kmalloc of " + "read_lock_counts[%d]\n", + cpu); +#endif + } + } + } + + if (error) { + /* + * One or more kmalloc failures -- free + * everything + */ + release_control_space(); + } else { + + if (!reset_lstat_data()) { + error = -EINVAL; + break; + }; + + /* + * record starting and ending times and the + * like + */ + if (lstat_control.intervals == 0) { + do_gettimeofday(&tv); + lstat_control.first_started_time = + tv.tv_sec; + } + lstat_control.started_cycles64 = get_cycles64(); + do_gettimeofday(&tv); + lstat_control.started_time = tv.tv_sec; + + lstat_control.state = LSTAT_ON; + } + } else { + error = -EBUSY; /* already ON */ + } + break; + + case LSTAT_RESET: + if (lstat_control.state == LSTAT_OFF) { + if (!reset_lstat_data()) + error = -EINVAL; + } else { + error = -EBUSY; /* still on; can't reset */ + } + break; + + case LSTAT_RELEASE: + if (lstat_control.state == LSTAT_OFF) { + release_control_space(); + lstat_control.intervals = 0; + lstat_control.enabled_cycles64 = 0; + } else { + error = -EBUSY; + } + break; + + default: + error = -EINVAL; + } /* switch */ + + _raw_spin_unlock(&lstat_control.control_lock); + return error ? error : len; +} + +#ifdef USER_MODE_TESTING +/* following used for user mode testing */ +void +lockmeter_init() +{ + int dirsize, hashsize, countsize, read_lock_countsize, cpu; + + printf("lstat_control is at %x size=%d\n", &lstat_control, + sizeof (lstat_control)); + printf("sizeof(spinlock_t)=%d\n", sizeof (spinlock_t)); + lstat_control.state = LSTAT_ON; + + lstat_control.directory_lock = SPIN_LOCK_UNLOCKED; + lstat_control.next_free_dir_index = 1; /* 0 is for overflows */ + lstat_control.next_free_read_lock_index = 1; + + dirsize = LSTAT_MAX_STAT_INDEX * sizeof (lstat_directory_entry_t); + hashsize = (1 + LSTAT_HASH_TABLE_SIZE) * sizeof (ushort); + countsize = sizeof (lstat_cpu_counts_t); + read_lock_countsize = sizeof (lstat_read_lock_cpu_counts_t); + + lstat_control.hashtab = (ushort *) malloc(hashsize); + + if (lstat_control.hashtab == 0) { + printf("malloc failure for at line %d in lockmeter.c\n", + __LINE__); + exit(0); + } + + lstat_control.dir = (lstat_directory_entry_t *) malloc(dirsize); + + if (lstat_control.dir == 0) { + printf("malloc failure for at line %d in lockmeter.c\n", cpu, + __LINE__); + exit(0); + } + + for (cpu = 0; cpu < num_online_cpus(); cpu++) { + int j, k; + j = (int) (lstat_control.counts[cpu] = + (lstat_cpu_counts_t *) malloc(countsize)); + k = (int) (lstat_control.read_lock_counts[cpu] = + (lstat_read_lock_cpu_counts_t *) + malloc(read_lock_countsize)); + if (j * k == 0) { + printf("malloc failure for cpu=%d at line %d in " + "lockmeter.c\n", cpu, __LINE__); + exit(0); + } + } + + memset(lstat_control.hashtab, 0, hashsize); + memset(lstat_control.dir, 0, dirsize); + + for (cpu = 0; cpu < num_online_cpus(); cpu++) { + memset(lstat_control.counts[cpu], 0, countsize); + memset(lstat_control.read_lock_counts[cpu], 0, + read_lock_countsize); + } +} + +asm(" \ +.align 4 \ +.globl __write_lock_failed \ +__write_lock_failed: \ + " LOCK "addl $" RW_LOCK_BIAS_STR ",(%eax) \ +1: cmpl $" RW_LOCK_BIAS_STR ",(%eax) \ + jne 1b \ +\ + " LOCK "subl $" RW_LOCK_BIAS_STR ",(%eax) \ + jnz __write_lock_failed \ + ret \ +\ +\ +.align 4 \ +.globl __read_lock_failed \ +__read_lock_failed: \ + lock ; incl (%eax) \ +1: cmpl $1,(%eax) \ + js 1b \ +\ + lock ; decl (%eax) \ + js __read_lock_failed \ + ret \ +"); +#endif + +EXPORT_SYMBOL(_metered_spin_lock); +EXPORT_SYMBOL(_metered_spin_unlock); +EXPORT_SYMBOL(_metered_spin_trylock); +EXPORT_SYMBOL(_metered_read_lock); +EXPORT_SYMBOL(_metered_read_unlock); +EXPORT_SYMBOL(_metered_write_lock); +EXPORT_SYMBOL(_metered_write_unlock); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/kernel/mcount.c 830-ivtv/kernel/mcount.c --- 000-virgin/kernel/mcount.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/kernel/mcount.c Thu Jan 8 10:21:27 2004 @@ -0,0 +1,203 @@ +/* + * kernel/mcount.c + * + * Implementation of kernel mcount handler and supporting functions. + * + * Code based on kernprof http://oss.sgi.com/projects/kernprof/ + * Copyright (C) SGI 1999, 2000, 2001 + * Written by Dimitris Michailidis (dimitris@engr.sgi.com) + * Modified by John Hawkes (hawkes@engr.sgi.com) + * Contributions from Niels Christiansen (nchr@us.ibm.com) + * Adapted for stand-alone call graphing by Adam Litke (agl@us.ibm.com) + */ + +#include +#include +#include +#include +#include +#include + +void UNKNOWN_KERNEL(void) {} /* Dummy functions to make profiles more */ +void UNKNOWN_MODULE(void) {} /* descriptive */ + +unsigned int mcount_shift, PC_resolution = DFL_PC_RES; + +char* memory_start = NULL; +unsigned short *cg_from_base = NULL; +struct cg_arc_dest *cg_to_base = NULL; +int cg_arc_overflow = 0; /* set when no new arcs can be added to the call graph */ +int n_buckets = 0; +size_t mem_needed; /* space needed for the call graph and the PC samples */ +extern char _stext, _etext, _sinittext, _einittext; + +void (*mcount_hook)(unsigned long, unsigned long) = NULL; +struct proc_dir_entry *mcount_pde; + +static int mcount_alloc_mem(void) +{ + unsigned long cg_from_size, cg_to_size; + size_t text_size = (unsigned long) &_etext - (unsigned long) &_stext; + struct prof_mem_map *memory_map; + + for (mcount_shift = 0; (1 << mcount_shift) < PC_resolution; mcount_shift++); + n_buckets = text_size >> mcount_shift; + cg_from_size = n_buckets * sizeof(short); + cg_to_size = CG_MAX_ARCS * sizeof(struct cg_arc_dest); + mem_needed = sizeof(struct prof_mem_map) + + ((cg_from_size + cg_to_size) * num_online_cpus()); + if ((memory_start = vmalloc(mem_needed)) == NULL) { + return -ENOMEM; + } + memset(memory_start, 0, mem_needed); + + cg_from_base = (unsigned short *) (memory_start + sizeof(struct prof_mem_map)); + cg_to_base = (struct cg_arc_dest *) (memory_start + sizeof(struct prof_mem_map) + + (cg_from_size * num_online_cpus())); + + memory_map = (struct prof_mem_map*) memory_start; + memory_map->kernel_buckets = n_buckets; + memory_map->nr_cpus = num_online_cpus(); + memory_map->cg_from_size = cg_from_size; + memory_map->cg_to_size = cg_to_size; + memory_map->cg_to_offset = cg_from_size * num_online_cpus(); + memory_map->kernel_start = (unsigned long)&_stext; + memory_map->kernel_end = (unsigned long)&_etext; + return 0; +} + +static void mcount_free_mem(void) +{ + vfree(memory_start); + memory_start = NULL; +} + +void mcount_entry(void) +{ + unsigned long frompc, selfpc; + + if(mcount_hook) { + frompc = (unsigned long)__builtin_return_address(2); + selfpc = (unsigned long)__builtin_return_address(1); + mcount_hook(frompc, selfpc); + } + return; +} + +/* Record an arc traversal in the call graph. Called by mcount(). SMP safe */ +void cg_record_arc(unsigned long frompc, unsigned long selfpc) +{ + static spinlock_t cg_record_lock = SPIN_LOCK_UNLOCKED; + unsigned long flags; + int toindex, fromindex, cpu; + unsigned short *q, *cg_from; + struct cg_arc_dest *p, *cg_to; + + cpu = smp_processor_id(); + + cg_from = &cg_from_base[n_buckets * cpu]; + cg_to = &cg_to_base[CG_MAX_ARCS * cpu]; + + if (pc_out_of_range(frompc)) + fromindex = (FUNCTIONPC(UNKNOWN_KERNEL) - (unsigned long) &_stext) + >> mcount_shift; + else + fromindex = (frompc - (unsigned long) &_stext) >> mcount_shift; + q = &cg_from[fromindex]; + + /* Easy case: the arc is already in the call graph */ + for (toindex = *q; toindex != 0; ) { + p = &cg_to[toindex]; + if (p->address == selfpc) { + atomic_inc(&p->count); + return; + } + toindex = p->link; + } + /* + * No luck. We need to add a new arc. Since cg_to[0] is unused, + * we use cg_to[0].count to keep track of the next available arc. + */ + if (cg_arc_overflow) { + return; + } + toindex = atomic_add_return(1, &cg_to->count); + if (toindex >= CG_MAX_ARCS) { + /* + * We have run out of space for arcs. We'll keep incrementing + * the existing ones but we won't try to add any more. + */ + cg_arc_overflow = 1; + atomic_set(&cg_to->count, CG_MAX_ARCS - 1); + return; + } + /* + * We have a secured slot for a new arc and all we need to do is + * initialize it and add it to a hash bucket. We use compare&swap, if + * possible, to avoid any spinlocks whatsoever. + */ + p = &cg_to[toindex]; + p->address = selfpc; + atomic_set(&p->count, 1); + + spin_lock_irqsave(&cg_record_lock, flags); + p->link = *q; + *q = toindex; + spin_unlock_irqrestore(&cg_record_lock, flags); + return; +} + +int mcount_start(void) +{ + if (!memory_start) { + if(mcount_alloc_mem()) + return -ENOMEM; + mcount_pde->size = mem_needed; + } + mcount_hook = cg_record_arc; + return 0; +} + +int mcount_stop(void) +{ + mcount_hook = NULL; + return 0; +} + +int mcount_cleanup(void) +{ + mcount_stop(); + mcount_pde->size = 0; + mcount_free_mem(); + return 0; +} + +ssize_t mcount_read(struct file * file, char * buf, + size_t count, loff_t *ppos) +{ + count = (count + *ppos >= mcount_pde->size) ? + mcount_pde->size - *ppos : count; + copy_to_user(buf, memory_start + *ppos, count); + *ppos += count; + return count; +} + +ssize_t mcount_write(struct file * file, const char * buf, + size_t count, loff_t *ppos) +{ + int ret; + + switch (buf[0]) { + case '0': + ret = mcount_cleanup(); + break; + case '1': + ret = mcount_stop(); + break; + case '2': + ret = mcount_start(); + default: + ret = -EINVAL; + } + return (ret == 0) ? count : ret; +} diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/kernel/module.c 830-ivtv/kernel/module.c --- 000-virgin/kernel/module.c Thu Jan 8 08:35:54 2004 +++ 830-ivtv/kernel/module.c Thu Jan 8 10:21:18 2004 @@ -83,6 +83,11 @@ int unregister_module_notifier(struct no } EXPORT_SYMBOL(unregister_module_notifier); +#ifdef CONFIG_GCOV_PROFILE +extern void remove_bb_link (struct module *); +extern void do_global_ctors (char *, char *, struct module *, int); +#endif + /* We require a truly strong try_module_get() */ static inline int strong_try_module_get(struct module *mod) { @@ -1087,6 +1092,11 @@ static void free_module(struct module *m /* Arch-specific cleanup. */ module_arch_cleanup(mod); +#ifdef CONFIG_GCOV_PROFILE + if (mod->ctors_start && mod->ctors_end) + remove_bb_link(mod); +#endif + /* Module unload stuff */ module_unload_free(mod); @@ -1580,6 +1590,13 @@ static struct module *load_module(void _ /* Module has been moved. */ mod = (void *)sechdrs[modindex].sh_addr; +#ifdef CONFIG_GCOV_PROFILE + modindex = find_sec(hdr, sechdrs, secstrings, ".ctors"); + mod->ctors_start = (char *)sechdrs[modindex].sh_addr; + mod->ctors_end = (char *)(mod->ctors_start + + sechdrs[modindex].sh_size); +#endif + /* Now we've moved module, initialize linked lists, etc. */ module_unload_init(mod); @@ -1741,6 +1758,12 @@ sys_init_module(void __user *umod, /* Start the module */ ret = mod->init(); + +#ifdef CONFIG_GCOV_PROFILE + if (mod->ctors_start && mod->ctors_end) { + do_global_ctors(mod->ctors_start, mod->ctors_end, mod, 1); + } +#endif if (ret < 0) { /* Init routine failed: abort. Try to protect us from buggy refcounters. */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/kernel/pid.c 830-ivtv/kernel/pid.c --- 000-virgin/kernel/pid.c Mon Nov 17 18:29:43 2003 +++ 830-ivtv/kernel/pid.c Thu Jan 8 09:30:15 2004 @@ -268,6 +268,9 @@ void switch_exec_pids(task_t *leader, ta * machine. From a minimum of 16 slots up to 4096 slots at one gigabyte or * more. */ +#ifdef CONFIG_KGDB +int kgdb_pid_init_done; /* so we don't call prior to... */ +#endif void __init pidhash_init(void) { int i, j, pidhash_size; @@ -289,6 +292,9 @@ void __init pidhash_init(void) for (j = 0; j < pidhash_size; j++) INIT_LIST_HEAD(&pid_hash[i][j]); } +#ifdef CONFIG_KGDB + kgdb_pid_init_done++; +#endif } void __init pidmap_init(void) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/kernel/sched.c 830-ivtv/kernel/sched.c --- 000-virgin/kernel/sched.c Thu Jan 8 08:35:54 2004 +++ 830-ivtv/kernel/sched.c Thu Jan 8 10:22:10 2004 @@ -37,6 +37,8 @@ #include #include #include +#include +#include #ifdef CONFIG_NUMA #define cpu_to_node_mask(cpu) node_to_cpumask(cpu_to_node(cpu)) @@ -77,19 +79,28 @@ * maximum timeslice is 200 msecs. Timeslices get refilled after * they expire. */ -#define MIN_TIMESLICE ( 10 * HZ / 1000) -#define MAX_TIMESLICE (200 * HZ / 1000) + +int min_timeslice = (10 * HZ) / 1000; +#define MIN_TIMESLICE (min_timeslice) +int max_timeslice = (200 * HZ) / 1000; +#define MAX_TIMESLICE (max_timeslice) #define ON_RUNQUEUE_WEIGHT 30 -#define CHILD_PENALTY 95 -#define PARENT_PENALTY 100 -#define EXIT_WEIGHT 3 -#define PRIO_BONUS_RATIO 25 +int child_penalty = 95; +#define CHILD_PENALTY (child_penalty) +int parent_penalty = 100; +#define PARENT_PENALTY (parent_penalty) +int exit_weight = 3; +#define EXIT_WEIGHT (exit_weight) +int prio_bonus_ratio = 25; +#define PRIO_BONUS_RATIO (prio_bonus_ratio) #define MAX_BONUS (MAX_USER_PRIO * PRIO_BONUS_RATIO / 100) -#define INTERACTIVE_DELTA 2 +int interactive_delta = 2; +#define INTERACTIVE_DELTA (interactive_delta) #define MAX_SLEEP_AVG (AVG_TIMESLICE * MAX_BONUS) #define STARVATION_LIMIT (MAX_SLEEP_AVG) #define NS_MAX_SLEEP_AVG (JIFFIES_TO_NS(MAX_SLEEP_AVG)) -#define NODE_THRESHOLD 125 +int node_threshold = 125; +#define NODE_THRESHOLD (node_threshold) #define CREDIT_LIMIT 100 /* @@ -201,6 +212,9 @@ struct runqueue { unsigned long nr_running, nr_switches, expired_timestamp, nr_uninterruptible; task_t *curr, *idle; +#ifdef CONFIG_SCHEDSTATS + int cpu; /* to make easy reverse-lookups with per-cpu runqueues */ +#endif struct mm_struct *prev_mm; prio_array_t *active, *expired, arrays[2]; int prev_cpu_load[NR_CPUS]; @@ -212,6 +226,10 @@ struct runqueue { struct list_head migration_queue; atomic_t nr_iowait; + +#ifdef CONFIG_SCHEDSTATS + struct sched_info info; +#endif }; static DEFINE_PER_CPU(struct runqueue, runqueues); @@ -275,6 +293,140 @@ __init void node_nr_running_init(void) #endif /* CONFIG_NUMA */ + +#ifdef CONFIG_SCHEDSTATS +struct schedstat { + /* sys_sched_yield stats */ + unsigned long yld_exp_empty; + unsigned long yld_act_empty; + unsigned long yld_both_empty; + unsigned long yld_cnt; + + /* schedule stats */ + unsigned long sched_noswitch; + unsigned long sched_switch; + unsigned long sched_cnt; + + /* load_balance stats */ + unsigned long lb_imbalance; + unsigned long lb_idle; + unsigned long lb_busy; + unsigned long lb_resched; + unsigned long lb_cnt; + unsigned long lb_nobusy; + unsigned long lb_bnode; + + /* pull_task stats */ + unsigned long pt_gained; + unsigned long pt_lost; + unsigned long pt_node_gained; + unsigned long pt_node_lost; + + /* balance_node stats */ + unsigned long bn_cnt; + unsigned long bn_idle; +} ____cacheline_aligned; + +/* + * bump this up when changing the output format or the meaning of an existing + * format, so that tools can adapt (or abort) + */ +#define SCHEDSTAT_VERSION 4 + +struct schedstat schedstats[NR_CPUS]; + +static int show_schedstat(struct seq_file *seq, void *v) +{ + struct schedstat sums; + int i; + + memset(&sums, 0, sizeof(sums)); + seq_printf(seq, "version %d\n", SCHEDSTAT_VERSION); + seq_printf(seq, "timestamp %lu\n", jiffies); + for (i = 0; i < NR_CPUS; i++) { + + struct sched_info info; + + if (!cpu_online(i)) continue; + + cpu_sched_info(&info, i); + + sums.yld_exp_empty += schedstats[i].yld_exp_empty; + sums.yld_act_empty += schedstats[i].yld_act_empty; + sums.yld_both_empty += schedstats[i].yld_both_empty; + sums.yld_cnt += schedstats[i].yld_cnt; + sums.sched_noswitch += schedstats[i].sched_noswitch; + sums.sched_switch += schedstats[i].sched_switch; + sums.sched_cnt += schedstats[i].sched_cnt; + sums.lb_idle += schedstats[i].lb_idle; + sums.lb_busy += schedstats[i].lb_busy; + sums.lb_resched += schedstats[i].lb_resched; + sums.lb_cnt += schedstats[i].lb_cnt; + sums.lb_imbalance += schedstats[i].lb_imbalance; + sums.lb_nobusy += schedstats[i].lb_nobusy; + sums.lb_bnode += schedstats[i].lb_bnode; + sums.pt_node_gained += schedstats[i].pt_node_gained; + sums.pt_node_lost += schedstats[i].pt_node_lost; + sums.pt_gained += schedstats[i].pt_gained; + sums.pt_lost += schedstats[i].pt_lost; + sums.bn_cnt += schedstats[i].bn_cnt; + sums.bn_idle += schedstats[i].bn_idle; + seq_printf(seq, + "cpu%d %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu " + "%lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", + i, schedstats[i].yld_both_empty, + schedstats[i].yld_act_empty, schedstats[i].yld_exp_empty, + schedstats[i].yld_cnt, schedstats[i].sched_noswitch, + schedstats[i].sched_switch, schedstats[i].sched_cnt, + schedstats[i].lb_idle, schedstats[i].lb_busy, + schedstats[i].lb_resched, + schedstats[i].lb_cnt, schedstats[i].lb_imbalance, + schedstats[i].lb_nobusy, schedstats[i].lb_bnode, + schedstats[i].pt_gained, schedstats[i].pt_lost, + schedstats[i].pt_node_gained, schedstats[i].pt_node_lost, + schedstats[i].bn_cnt, schedstats[i].bn_idle, + info.cpu_time, info.run_delay, info.pcnt); + } + seq_printf(seq, + "totals %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu " + "%lu %lu %lu %lu %lu %lu %lu\n", + sums.yld_both_empty, sums.yld_act_empty, sums.yld_exp_empty, + sums.yld_cnt, sums.sched_noswitch, sums.sched_switch, + sums.sched_cnt, sums.lb_idle, sums.lb_busy, sums.lb_resched, + sums.lb_cnt, sums.lb_imbalance, sums.lb_nobusy, sums.lb_bnode, + sums.pt_gained, sums.pt_lost, sums.pt_node_gained, + sums.pt_node_lost, sums.bn_cnt, sums.bn_idle); + + return 0; +} + +static int schedstat_open(struct inode *inode, struct file *file) +{ + unsigned size = 4096 * (1 + num_online_cpus() / 32); + char *buf = kmalloc(size, GFP_KERNEL); + struct seq_file *m; + int res; + + if (!buf) + return -ENOMEM; + res = single_open(file, show_schedstat, NULL); + if (!res) { + m = file->private_data; + m->buf = buf; + m->size = size; + } else + kfree(buf); + return res; +} + +struct file_operations proc_schedstat_operations = { + .open = schedstat_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif + /* * task_rq_lock - lock the runqueue a given task resides on and disable * interrupts. Note the ordering: we can safely lookup the task_rq without @@ -319,6 +471,113 @@ static inline void rq_unlock(runqueue_t spin_unlock_irq(&rq->lock); } +#ifdef CONFIG_SCHEDSTATS +/* + * Called when a process is dequeued from the active array and given + * the cpu. We should note that with the exception of interactive + * tasks, the expired queue will become the active queue after the active + * queue is empty, without explicitly dequeuing and requeuing tasks in the + * expired queue. (Interactive tasks may be requeued directly to the + * active queue, thus delaying tasks in the expired queue from running; + * see scheduler_tick()). + * + * This function is only called from sched_info_arrive(), rather than + * dequeue_task(). Even though a task may be queued and dequeued multiple + * times as it is shuffled about, we're really interested in knowing how + * long it was from the *first* time it was queued to the time that it + * finally hit a cpu. + */ +static inline void sched_info_dequeued(task_t *t) +{ + t->sched_info.last_queued = 0; +} + +/* + * Called when a task finally hits the cpu. We can now calculate how + * long it was waiting to run. We also note when it began so that we + * can keep stats on how long its timeslice is. + */ +static inline void sched_info_arrive(task_t *t) +{ + unsigned long now = jiffies; + unsigned long diff = 0; + struct runqueue *rq = task_rq(t); + + if (t->sched_info.last_queued) + diff = now - t->sched_info.last_queued; + sched_info_dequeued(t); + t->sched_info.run_delay += diff; + t->sched_info.last_arrival = now; + t->sched_info.pcnt++; + + if (!rq) + return; + + rq->info.run_delay += diff; + rq->info.pcnt++; +} + +/* + * Called when a process is queued into either the active or expired + * array. The time is noted and later used to determine how long we + * had to wait for us to reach the cpu. Since the expired queue will + * become the active queue after active queue is empty, without dequeuing + * and requeuing any tasks, we are interested in queuing to either. It + * is unusual but not impossible for tasks to be dequeued and immediately + * requeued in the same or another array: this can happen in sched_yield(), + * set_user_nice(), and even load_balance() as it moves tasks from runqueue + * to runqueue. + * + * This function is only called from enqueue_task(), but also only updates + * the timestamp if it is already not set. It's assumed that + * sched_info_dequeued() will clear that stamp when appropriate. + */ +static inline void sched_info_queued(task_t *t) +{ + if (!t->sched_info.last_queued) + t->sched_info.last_queued = jiffies; +} + +/* + * Called when a process ceases being the active-running process, either + * voluntarily or involuntarily. Now we can calculate how long we ran. + */ +static inline void sched_info_depart(task_t *t) +{ + struct runqueue *rq = task_rq(t); + unsigned long diff = jiffies - t->sched_info.last_arrival; + + t->sched_info.cpu_time += diff; + + if (rq) + rq->info.cpu_time += diff; +} + +/* + * Called when tasks are switched involuntarily due, typically, to expiring + * their time slice. (This may also be called when switching to or from + * the idle task.) We are only called when prev != next. + */ +static inline void sched_info_switch(task_t *prev, task_t *next) +{ + struct runqueue *rq = task_rq(prev); + + /* + * prev now departs the cpu. It's not interesting to record + * stats about how efficient we were at scheduling the idle + * process, however. + */ + if (prev != rq->idle) + sched_info_depart(prev); + + if (next != rq->idle) + sched_info_arrive(next); +} +#else +#define sched_info_queued(t) {} +#define sched_info_switch(t, next) {} +#endif /* CONFIG_SCHEDSTATS */ + /* * Adding/removing a task to/from a priority array: */ @@ -332,6 +591,7 @@ static inline void dequeue_task(struct t static inline void enqueue_task(struct task_struct *p, prio_array_t *array) { + sched_info_queued(p); list_add_tail(&p->run_list, array->queue + p->prio); __set_bit(p->prio, array->bitmap); array->nr_active++; @@ -840,6 +1100,11 @@ unsigned long nr_running(void) return sum; } +unsigned long nr_running_cpu(int cpu) +{ + return cpu_rq(cpu)->nr_running; +} + unsigned long nr_uninterruptible(void) { unsigned long i, sum = 0; @@ -876,6 +1141,13 @@ unsigned long nr_iowait(void) return sum; } +#ifdef CONFIG_SCHEDSTATS +void cpu_sched_info(struct sched_info *info, int cpu) +{ + memcpy(info, &cpu_rq(cpu)->info, sizeof(struct sched_info)); +} +#endif /* CONFIG_SCHEDSTATS */ + /* * double_rq_lock - safely lock two runqueues * @@ -937,36 +1209,72 @@ static void sched_migrate_task(task_t *p */ static int sched_best_cpu(struct task_struct *p) { - int i, minload, load, best_cpu, node = 0; + int cpu, node, minload, load, best_cpu, best_node; + int this_cpu, this_node, this_node_load; cpumask_t cpumask; - best_cpu = task_cpu(p); - if (cpu_rq(best_cpu)->nr_running <= 2) - return best_cpu; + this_cpu = best_cpu = task_cpu(p); + if (cpu_rq(this_cpu)->nr_running <= 2) + return this_cpu; + this_node = best_node = cpu_to_node(this_cpu); + + /* + * First look for any node-local idle queue and use that. + * This improves performance under light loads (mbligh). + * In case this node turns out to be the lightest node, store the best + * cpu that we find, so we don't go sniffing the same runqueues again. + */ + minload = 10000000; + cpumask = node_to_cpumask(this_node); + for (cpu = 0; cpu < NR_CPUS; ++cpu) { + if (!cpu_isset(cpu, cpumask)) + continue; + load = cpu_rq(cpu)->nr_running; + if (load == 0) + return cpu; + if (load < minload) { + minload = load; + best_cpu = cpu; + } + } + /* + * Now find the lightest loaded node, and put it in best_node + * + * Node load is always divided by nr_cpus_node to normalise load + * values in case cpu count differs from node to node. We first + * multiply node_nr_running by 16 to get a little better resolution. + */ minload = 10000000; - for_each_node_with_cpus(i) { - /* - * Node load is always divided by nr_cpus_node to normalise - * load values in case cpu count differs from node to node. - * We first multiply node_nr_running by 10 to get a little - * better resolution. - */ - load = 10 * atomic_read(&node_nr_running[i]) / nr_cpus_node(i); + this_node_load = 16 * atomic_read(&node_nr_running[this_node]) + / nr_cpus_node(this_node); + for_each_node_with_cpus(node) { + if (node == this_node) + load = this_node_load; + else + load = 16 * atomic_read(&node_nr_running[node]) + / nr_cpus_node(node); if (load < minload) { minload = load; - node = i; + best_node = node; } } + /* If we chose this node, we already did the legwork earlier */ + if (best_node == this_node) + return best_cpu; + + /* Now find the lightest loaded cpu on best_node, and use that */ minload = 10000000; - cpumask = node_to_cpumask(node); - for (i = 0; i < NR_CPUS; ++i) { - if (!cpu_isset(i, cpumask)) + best_cpu = this_cpu; + cpumask = node_to_cpumask(best_node); + for (cpu = 0; cpu < NR_CPUS; ++cpu) { + if (!cpu_isset(cpu, cpumask)) continue; - if (cpu_rq(i)->nr_running < minload) { - best_cpu = i; - minload = cpu_rq(i)->nr_running; + load = cpu_rq(cpu)->nr_running; + if (load < minload) { + minload = load; + best_cpu = cpu; } } return best_cpu; @@ -1019,6 +1327,9 @@ static int find_busiest_node(int this_no #endif /* CONFIG_NUMA */ +int idle_node_rebalance_ratio = 10; +int busy_node_rebalance_ratio = 2; + #ifdef CONFIG_SMP /* @@ -1131,6 +1442,16 @@ out: */ static inline void pull_task(runqueue_t *src_rq, prio_array_t *src_array, task_t *p, runqueue_t *this_rq, int this_cpu) { +#ifdef CONFIG_SCHEDSTATS +#ifdef CONFIG_NUMA + if (cpu_to_node(this_cpu) != cpu_to_node(src_rq->cpu)) { + SCHEDSTAT_INC(this_cpu, pt_node_gained); + SCHEDSTAT_INC(src_rq->cpu, pt_node_lost); + } +#endif + SCHEDSTAT_INC(this_cpu, pt_gained); + SCHEDSTAT_INC(src_rq->cpu, pt_lost); +#endif dequeue_task(p, src_array); nr_running_dec(src_rq); set_task_cpu(p, this_cpu); @@ -1154,11 +1475,16 @@ static inline void pull_task(runqueue_t */ static inline int -can_migrate_task(task_t *tsk, runqueue_t *rq, int this_cpu, int idle) +can_migrate_task(task_t *tsk, runqueue_t *rq, int this_cpu, int idle, int crossnode) { unsigned long delta = sched_clock() - tsk->timestamp; + int task_is_warm = (delta <= JIFFIES_TO_NS(cache_decay_ticks)) ? 1 : 0; - if (!idle && (delta <= JIFFIES_TO_NS(cache_decay_ticks))) + /* only idle processors may steal warm tasks ... */ + if (!idle && task_is_warm) + return 0; + /* ... but no stealing warm tasks cross node on NUMA systems */ + if (crossnode && task_is_warm) return 0; if (task_running(rq, tsk)) return 0; @@ -1175,7 +1501,7 @@ can_migrate_task(task_t *tsk, runqueue_t * We call this with the current runqueue locked, * irqs disabled. */ -static void load_balance(runqueue_t *this_rq, int idle, cpumask_t cpumask) +static void load_balance(runqueue_t *this_rq, int idle, int crossnode, cpumask_t cpumask) { int imbalance, idx, this_cpu = smp_processor_id(); runqueue_t *busiest; @@ -1183,9 +1509,14 @@ static void load_balance(runqueue_t *thi struct list_head *head, *curr; task_t *tmp; + SCHEDSTAT_INC(this_cpu, lb_cnt); busiest = find_busiest_queue(this_rq, this_cpu, idle, &imbalance, cpumask); - if (!busiest) - goto out; + if (!busiest) { + SCHEDSTAT_INC(this_cpu, lb_nobusy); + goto out; + } + + SCHEDSTAT_ADD(this_cpu, lb_imbalance, imbalance); /* * We only want to steal a number of tasks equal to 1/2 the imbalance, @@ -1234,7 +1565,7 @@ skip_queue: curr = curr->prev; - if (!can_migrate_task(tmp, busiest, this_cpu, idle)) { + if (!can_migrate_task(tmp, busiest, this_cpu, idle, crossnode)) { if (curr != head) goto skip_queue; idx++; @@ -1266,19 +1597,21 @@ out: */ #define IDLE_REBALANCE_TICK (HZ/1000 ?: 1) #define BUSY_REBALANCE_TICK (HZ/5 ?: 1) -#define IDLE_NODE_REBALANCE_TICK (IDLE_REBALANCE_TICK * 5) -#define BUSY_NODE_REBALANCE_TICK (BUSY_REBALANCE_TICK * 2) +#define IDLE_NODE_REBALANCE_TICK (IDLE_REBALANCE_TICK * idle_node_rebalance_ratio) +#define BUSY_NODE_REBALANCE_TICK (BUSY_REBALANCE_TICK * busy_node_rebalance_ratio) #ifdef CONFIG_NUMA static void balance_node(runqueue_t *this_rq, int idle, int this_cpu) { int node = find_busiest_node(cpu_to_node(this_cpu)); + SCHEDSTAT_INC(this_cpu, bn_cnt); if (node >= 0) { cpumask_t cpumask = node_to_cpumask(node); + SCHEDSTAT_INC(this_cpu, lb_bnode); cpu_set(this_cpu, cpumask); spin_lock(&this_rq->lock); - load_balance(this_rq, idle, cpumask); + load_balance(this_rq, idle, 1, cpumask); spin_unlock(&this_rq->lock); } } @@ -1286,9 +1619,7 @@ static void balance_node(runqueue_t *thi static void rebalance_tick(runqueue_t *this_rq, int idle) { -#ifdef CONFIG_NUMA int this_cpu = smp_processor_id(); -#endif unsigned long j = jiffies; /* @@ -1301,12 +1632,15 @@ static void rebalance_tick(runqueue_t *t */ if (idle) { #ifdef CONFIG_NUMA - if (!(j % IDLE_NODE_REBALANCE_TICK)) + if (!(j % IDLE_NODE_REBALANCE_TICK)) { + SCHEDSTAT_INC(this_cpu, bn_idle); balance_node(this_rq, idle, this_cpu); + } #endif if (!(j % IDLE_REBALANCE_TICK)) { spin_lock(&this_rq->lock); - load_balance(this_rq, idle, cpu_to_node_mask(this_cpu)); + SCHEDSTAT_INC(this_cpu, lb_idle); + load_balance(this_rq, idle, 0, cpu_to_node_mask(this_cpu)); spin_unlock(&this_rq->lock); } return; @@ -1317,7 +1651,8 @@ static void rebalance_tick(runqueue_t *t #endif if (!(j % BUSY_REBALANCE_TICK)) { spin_lock(&this_rq->lock); - load_balance(this_rq, idle, cpu_to_node_mask(this_cpu)); + SCHEDSTAT_INC(this_cpu, lb_busy); + load_balance(this_rq, idle, 0, cpu_to_node_mask(this_cpu)); spin_unlock(&this_rq->lock); } } @@ -1478,13 +1813,14 @@ asmlinkage void schedule(void) struct list_head *queue; unsigned long long now; unsigned long run_time; - int idx; + int idx, this_cpu = smp_processor_id(); /* * Test if we are atomic. Since do_exit() needs to call into * schedule() atomically, we ignore that path for now. * Otherwise, whine if we are scheduling when we should not be. */ + SCHEDSTAT_INC(this_cpu, sched_cnt); if (likely(!(current->state & (TASK_DEAD | TASK_ZOMBIE)))) { if (unlikely(in_atomic())) { printk(KERN_ERR "bad: scheduling while atomic!\n"); @@ -1530,7 +1866,8 @@ need_resched: if (unlikely(!rq->nr_running)) { #ifdef CONFIG_SMP - load_balance(rq, 1, cpu_to_node_mask(smp_processor_id())); + SCHEDSTAT_INC(this_cpu, lb_resched); + load_balance(rq, 1, 0, cpu_to_node_mask(smp_processor_id())); #endif if (!rq->nr_running) { next = rq->idle; @@ -1544,11 +1881,13 @@ need_resched: /* * Switch the active and expired arrays. */ + SCHEDSTAT_INC(this_cpu, sched_switch); rq->active = rq->expired; rq->expired = array; array = rq->active; rq->expired_timestamp = 0; } + SCHEDSTAT_INC(this_cpu, sched_noswitch); idx = sched_find_first_bit(array->bitmap); queue = array->queue + idx; @@ -1579,6 +1918,7 @@ switch_tasks: } prev->timestamp = now; + sched_info_switch(prev, next); if (likely(prev != next)) { next->timestamp = now; rq->nr_switches++; @@ -1887,6 +2227,13 @@ out_unlock: EXPORT_SYMBOL(set_user_nice); +#if defined( CONFIG_KGDB) +struct task_struct * kgdb_get_idle(int this_cpu) +{ + return cpu_rq(this_cpu)->idle; +} +#endif + #ifndef __alpha__ /* @@ -2260,6 +2607,9 @@ asmlinkage long sys_sched_yield(void) { runqueue_t *rq = this_rq_lock(); prio_array_t *array = current->array; +#ifdef CONFIG_SCHEDSTATS + int this_cpu = smp_processor_id(); +#endif /* CONFIG_SCHEDSTATS */ /* * We implement yielding by moving the task into the expired @@ -2268,7 +2618,16 @@ asmlinkage long sys_sched_yield(void) * (special rule: RT tasks will just roundrobin in the active * array.) */ + SCHEDSTAT_INC(this_cpu, yld_cnt); if (likely(!rt_task(current))) { + if (current->array->nr_active == 1) { + SCHEDSTAT_INC(this_cpu, yld_act_empty); + if (!rq->expired->nr_active) { + SCHEDSTAT_INC(this_cpu, yld_both_empty); + } + } else if (!rq->expired->nr_active) { + SCHEDSTAT_INC(this_cpu, yld_exp_empty); + } dequeue_task(current, array); enqueue_task(current, rq->expired); } else { @@ -2810,6 +3169,9 @@ void __init sched_init(void) rq = cpu_rq(i); rq->active = rq->arrays; rq->expired = rq->arrays + 1; +#ifdef CONFIG_SCHEDSTATS + rq->cpu = i; +#endif /* CONFIG_SCHEDSTATS */ spin_lock_init(&rq->lock); INIT_LIST_HEAD(&rq->migration_queue); atomic_set(&rq->nr_iowait, 0); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/kernel/sys.c 830-ivtv/kernel/sys.c --- 000-virgin/kernel/sys.c Thu Jan 8 08:35:54 2004 +++ 830-ivtv/kernel/sys.c Thu Jan 8 10:26:46 2004 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -224,6 +225,7 @@ cond_syscall(sys_acct) cond_syscall(sys_lookup_dcookie) cond_syscall(sys_swapon) cond_syscall(sys_swapoff) +cond_syscall(sys_kexec_load) cond_syscall(sys_init_module) cond_syscall(sys_delete_module) cond_syscall(sys_socketpair) @@ -251,6 +253,7 @@ cond_syscall(sys_epoll_ctl) cond_syscall(sys_epoll_wait) cond_syscall(sys_pciconfig_read) cond_syscall(sys_pciconfig_write) +cond_syscall(sys_mbind) static int set_one_prio(struct task_struct *p, int niceval, int error) { @@ -470,6 +473,27 @@ asmlinkage long sys_reboot(int magic1, i machine_restart(buffer); break; +#ifdef CONFIG_KEXEC + case LINUX_REBOOT_CMD_KEXEC: + { + struct kimage *image; + if (arg) { + unlock_kernel(); + return -EINVAL; + } + image = xchg(&kexec_image, 0); + if (!image) { + unlock_kernel(); + return -EINVAL; + } + notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL); + system_running = 0; + device_shutdown(); + printk(KERN_EMERG "Starting new kernel\n"); + machine_kexec(image); + break; + } +#endif #ifdef CONFIG_SOFTWARE_SUSPEND case LINUX_REBOOT_CMD_SW_SUSPEND: if (!software_suspend_enabled) { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/kernel/sysctl.c 830-ivtv/kernel/sysctl.c --- 000-virgin/kernel/sysctl.c Mon Nov 17 18:29:35 2003 +++ 830-ivtv/kernel/sysctl.c Thu Jan 8 10:22:37 2004 @@ -60,6 +60,18 @@ extern int cad_pid; extern int pid_max; extern int sysctl_lower_zone_protection; extern int min_free_kbytes; +extern int shm_use_hugepages, shm_hugepages_per_file; +extern int mmap_use_hugepages, mmap_hugepages_map_sz; +extern int min_timeslice; +extern int max_timeslice; +extern int child_penalty; +extern int parent_penalty; +extern int exit_weight; +extern int prio_bonus_ratio; +extern int interactive_delta; +extern int node_threshold; +extern int idle_node_rebalance_ratio; +extern int busy_node_rebalance_ratio; /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */ static int maxolduid = 65535; @@ -122,6 +134,7 @@ static struct ctl_table_header root_tabl static ctl_table kern_table[]; static ctl_table vm_table[]; +static ctl_table sched_table[]; #ifdef CONFIG_NET extern ctl_table net_table[]; #endif @@ -198,6 +211,12 @@ static ctl_table root_table[] = { .mode = 0555, .child = dev_table, }, + { + .ctl_name = CTL_SCHED, + .procname = "sched", + .mode = 0555, + .child = sched_table, + }, { .ctl_name = 0 } }; @@ -579,12 +598,47 @@ static ctl_table kern_table[] = { .mode = 0644, .proc_handler = &proc_dointvec, }, +#ifdef CONFIG_HUGETLBFS + { + .ctl_name = KERN_SHMUSEHUGEPAGES, + .procname = "shm-use-hugepages", + .data = &shm_use_hugepages, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = KERN_MMAPUSEHUGEPAGES, + .procname = "mmap-use-hugepages", + .data = &mmap_use_hugepages, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = KERN_HPAGES_PER_FILE, + .procname = "shm-hugepages-per-file", + .data = &shm_hugepages_per_file, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = KERN_HPAGES_MAP_SZ, + .procname = "mmap-hugepages-min-mapping", + .data = &mmap_hugepages_map_sz, + .maxlen = sizeof(int), + .mode 0644, + .proc_handler = &proc_dointvec, + }, +#endif { .ctl_name = 0 } }; /* Constants for minimum and maximum testing in vm_table. We use these as one-element integer vectors. */ static int zero; +static int one = 1; static int one_hundred = 100; @@ -664,11 +718,8 @@ static ctl_table vm_table[] = { .procname = "swappiness", .data = &vm_swappiness, .maxlen = sizeof(vm_swappiness), - .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, - .extra1 = &zero, - .extra2 = &one_hundred, + .mode = 0444 /* read-only*/, + .proc_handler = &proc_dointvec, }, #ifdef CONFIG_HUGETLB_PAGE { @@ -804,6 +855,42 @@ static ctl_table debug_table[] = { static ctl_table dev_table[] = { { .ctl_name = 0 } }; + +static ctl_table sched_table[] = { + {SCHED_MAX_TIMESLICE, "max_timeslice", &max_timeslice, + sizeof(int), 0644, NULL, &proc_dointvec_minmax, + &sysctl_intvec, NULL, &one, NULL}, + {SCHED_MIN_TIMESLICE, "min_timeslice", &min_timeslice, + sizeof(int), 0644, NULL, &proc_dointvec_minmax, + &sysctl_intvec, NULL, &one, NULL}, + {SCHED_CHILD_PENALTY, "child_penalty", &child_penalty, + sizeof(int), 0644, NULL, &proc_dointvec_minmax, + &sysctl_intvec, NULL, &zero, NULL}, + {SCHED_PARENT_PENALTY, "parent_penalty", &parent_penalty, + sizeof(int), 0644, NULL, &proc_dointvec_minmax, + &sysctl_intvec, NULL, &zero, NULL}, + {SCHED_EXIT_WEIGHT, "exit_weight", &exit_weight, + sizeof(int), 0644, NULL, &proc_dointvec_minmax, + &sysctl_intvec, NULL, &zero, NULL}, + {SCHED_PRIO_BONUS_RATIO, "prio_bonus_ratio", &prio_bonus_ratio, + sizeof(int), 0644, NULL, &proc_dointvec_minmax, + &sysctl_intvec, NULL, &zero, NULL}, + {SCHED_INTERACTIVE_DELTA, "interactive_delta", &interactive_delta, + sizeof(int), 0644, NULL, &proc_dointvec_minmax, + &sysctl_intvec, NULL, &zero, NULL}, + {SCHED_NODE_THRESHOLD, "node_threshold", &node_threshold, + sizeof(int), 0644, NULL, &proc_dointvec_minmax, + sysctl_intvec, NULL, &one, NULL}, + {SCHED_IDLE_NODE_REBALANCE_RATIO, "idle_node_rebalance_ratio", + &idle_node_rebalance_ratio, + sizeof(int), 0644, NULL, &proc_dointvec_minmax, + &sysctl_intvec, NULL, &zero, NULL}, + {SCHED_BUSY_NODE_REBALANCE_RATIO, "busy_node_rebalance_ratio", + &busy_node_rebalance_ratio, + sizeof(int), 0644, NULL, &proc_dointvec_minmax, + &sysctl_intvec, NULL, &zero, NULL}, + {0} +}; extern void init_irq_proc (void); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/kernel/timer.c 830-ivtv/kernel/timer.c --- 000-virgin/kernel/timer.c Mon Dec 8 09:55:53 2003 +++ 830-ivtv/kernel/timer.c Thu Jan 8 10:21:09 2004 @@ -768,6 +768,8 @@ static unsigned long count_active_tasks( * Requires xtime_lock to access. */ unsigned long avenrun[3]; +unsigned long tasks_running[3]; +DEFINE_PER_CPU(unsigned long[3],cpu_tasks_running); /* * calc_load - given tick count, update the avenrun load estimates. @@ -775,7 +777,7 @@ unsigned long avenrun[3]; */ static inline void calc_load(unsigned long ticks) { - unsigned long active_tasks; /* fixed-point */ + unsigned long active_tasks, running_tasks; /* fixed-point */ static int count = LOAD_FREQ; count -= ticks; @@ -785,7 +787,37 @@ static inline void calc_load(unsigned lo CALC_LOAD(avenrun[0], EXP_1, active_tasks); CALC_LOAD(avenrun[1], EXP_5, active_tasks); CALC_LOAD(avenrun[2], EXP_15, active_tasks); + running_tasks = nr_running() * FIXED_1; + CALC_LOAD(tasks_running[0], EXP_1, running_tasks); + CALC_LOAD(tasks_running[1], EXP_5, running_tasks); + CALC_LOAD(tasks_running[2], EXP_15, running_tasks); } +} + +/* + * This does the frequency calculation a little bit different from the + * global version above. It doesn't ever look at the kernel's concept + * of time, it just updates that stats every LOAD_FREQ times into the + * function. + * + * Using jiffies is more accurate, but there _are_ just statistics, so + * they're not worth messing with xtime_lock and company. If we miss + * an interrupt or two, big deal. + */ +void calc_load_cpu(int cpu) +{ + unsigned long running_tasks; + static DEFINE_PER_CPU(int, count) = { LOAD_FREQ }; + + per_cpu(count, cpu)--; + if (per_cpu(count, cpu) != 0) + return; + + per_cpu(count, cpu) += LOAD_FREQ; + running_tasks = nr_running_cpu(cpu) * FIXED_1; + CALC_LOAD(per_cpu(cpu_tasks_running, cpu)[0], EXP_1, running_tasks); + CALC_LOAD(per_cpu(cpu_tasks_running, cpu)[1], EXP_5, running_tasks); + CALC_LOAD(per_cpu(cpu_tasks_running, cpu)[2], EXP_15, running_tasks); } /* jiffies at the most recent update of wall time */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/mm/Makefile 830-ivtv/mm/Makefile --- 000-virgin/mm/Makefile Mon Nov 17 18:28:20 2003 +++ 830-ivtv/mm/Makefile Thu Jan 8 10:21:50 2004 @@ -7,8 +7,13 @@ mmu-$(CONFIG_MMU) := fremap.o highmem.o mlock.o mmap.o mprotect.o mremap.o msync.o rmap.o \ shmem.o vmalloc.o -obj-y := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \ +obj-y := bootmem.o fadvise.o filemap.o mempool.o oom_kill.o \ page_alloc.o page-writeback.o pdflush.o readahead.o \ slab.o swap.o truncate.o vmscan.o $(mmu-y) obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o + +obj-$(CONFIG_NUMA) += mbind.o + +obj-$(CONFIG_X86_4G) += usercopy.o + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/mm/filemap.c 830-ivtv/mm/filemap.c --- 000-virgin/mm/filemap.c Thu Jan 8 08:35:54 2004 +++ 830-ivtv/mm/filemap.c Thu Jan 8 10:20:47 2004 @@ -73,6 +73,9 @@ * ->mmap_sem * ->i_sem (msync) * + * ->lock_page + * ->i_shared_sem (page_convert_anon) + * * ->inode_lock * ->sb_lock (fs/fs-writeback.c) * ->mapping->page_lock (__sync_single_inode) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/mm/fremap.c 830-ivtv/mm/fremap.c --- 000-virgin/mm/fremap.c Mon Nov 17 18:28:59 2003 +++ 830-ivtv/mm/fremap.c Thu Jan 8 10:21:12 2004 @@ -38,7 +38,7 @@ static inline int zap_pte(struct mm_stru set_page_dirty(page); page_remove_rmap(page, ptep); page_cache_release(page); - mm->rss--; + dec_rss(mm, page); } } return 1; @@ -63,10 +63,26 @@ int install_page(struct mm_struct *mm, s pmd_t *pmd; pte_t pte_val; struct pte_chain *pte_chain; + unsigned long pgidx; pte_chain = pte_chain_alloc(GFP_KERNEL); if (!pte_chain) goto err; + + /* + * Convert this page to anon for objrmap if it's nonlinear + */ + pgidx = (addr - vma->vm_start) >> PAGE_SHIFT; + pgidx += vma->vm_pgoff; + pgidx >>= PAGE_CACHE_SHIFT - PAGE_SHIFT; + if (!PageAnon(page) && (page->index != pgidx)) { + lock_page(page); + err = page_convert_anon(page); + unlock_page(page); + if (err < 0) + goto err_free; + } + pgd = pgd_offset(mm, addr); spin_lock(&mm->page_table_lock); @@ -80,7 +96,7 @@ int install_page(struct mm_struct *mm, s flush = zap_pte(mm, vma, addr, pte); - mm->rss++; + inc_rss(mm, page); flush_icache_page(vma, page); set_pte(pte, mk_pte(page, prot)); pte_chain = page_add_rmap(page, pte, pte_chain); @@ -89,12 +105,11 @@ int install_page(struct mm_struct *mm, s if (flush) flush_tlb_page(vma, addr); update_mmu_cache(vma, addr, pte_val); - spin_unlock(&mm->page_table_lock); - pte_chain_free(pte_chain); - return 0; + err = 0; err_unlock: spin_unlock(&mm->page_table_lock); +err_free: pte_chain_free(pte_chain); err: return err; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/mm/mbind.c 830-ivtv/mm/mbind.c --- 000-virgin/mm/mbind.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/mm/mbind.c Thu Jan 8 10:21:50 2004 @@ -0,0 +1,147 @@ +/* + * mm/mbind.c + * + * Written by: Matthew Dobson, IBM Corporation + * + * Copyright (C) 2003, IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + */ +#include +#include +#include +#include +#include + +/* Translate a cpumask to a nodemask */ +static inline void cpumask_to_nodemask(unsigned long * cpumask, unsigned long * nodemask) +{ + int i; + + for (i = 0; i < NR_CPUS; i++) + if (test_bit(i, cpumask)) + set_bit(cpu_to_node(i), nodemask); +} + +/* + * Adds the zones belonging to @pgdat to @zonelist. Returns the next + * index in @zonelist. + */ +static inline int add_node(pg_data_t *pgdat, struct zonelist *zonelist, int zone_num) +{ + int i; + struct zone *zone; + + for (i = MAX_NR_ZONES-1; i >=0 ; i--) { + zone = pgdat->node_zones + i; + if (zone->present_pages) + zonelist->zones[zone_num++] = zone; + } + return zone_num; +} + +/* Builds a binding for a region of memory, based on a bitmask of nodes. */ +static inline int build_binding(unsigned long * nodemask, struct binding *binding) +{ + int node, zone_num; + + memset(binding, 0, sizeof(struct binding)); + + /* Build binding zonelist */ + for (node = 0, zone_num = 0; node < MAX_NUMNODES; node++) + if (test_bit(node, nodemask) && node_online(node)) + zone_num = add_node(NODE_DATA(node), + &binding->zonelist, zone_num); + binding->zonelist.zones[zone_num] = NULL; + + if (zone_num == 0) + /* No zones were added to the zonelist. Let the caller know. */ + return -EINVAL; + + return 0; +} + + +/* + * mbind - Bind a range of a process' VM space to a set of memory blocks according to + * a predefined policy. + * @start: beginning address of memory region to bind + * @len: length of memory region to bind + * @mask_ptr: pointer to bitmask of cpus + * @mask_len: length of the bitmask + * @policy: flag specifying the policy to use for the segment + */ +asmlinkage unsigned long sys_mbind(unsigned long start, unsigned long len, + unsigned long *mask_ptr, unsigned int mask_len, unsigned long policy) +{ + DECLARE_BITMAP(cpu_mask, NR_CPUS); + DECLARE_BITMAP(node_mask, MAX_NUMNODES); + struct vm_area_struct *vma = NULL; + struct address_space *mapping; + int copy_len, error = 0; + + /* Deal with getting cpu_mask from userspace & translating to node_mask */ + CLEAR_BITMAP(cpu_mask, NR_CPUS); + CLEAR_BITMAP(node_mask, MAX_NUMNODES); + copy_len = min(mask_len, (unsigned int)NR_CPUS); + if (copy_from_user(cpu_mask, mask_ptr, (copy_len+7)/8)) { + error = -EFAULT; + goto out; + } + cpumask_to_nodemask(cpu_mask, node_mask); + + down_read(¤t->mm->mmap_sem); + vma = find_vma(current->mm, start); + up_read(¤t->mm->mmap_sem); + /* This is an ugly, gross hack. This is purely because I've hurt my + * brain trying to come up with a brilliant way of implementing this + * for VMA's in general. Shared Memory VMA's lend themselves to binding + * both because of how they're implemented, and their actual uses. + * If anyone has a great place to squirrel-away some data about the + * requested binding, and a way to easily force the allocator to respect + * these bindings, then send a patch, or let me know. Otherwise, this + * will have to wait for a stroke of insight. + */ + if (!(vma && vma->vm_file && vma->vm_ops && + vma->vm_ops->nopage == shmem_nopage)) { + /* This isn't a shm segment. For now, we bail. */ + error = -EINVAL; + goto out; + } + + mapping = vma->vm_file->f_dentry->d_inode->i_mapping; + if (mapping->binding) { + kfree(mapping->binding); + mapping->binding = NULL; + } + mapping->binding = kmalloc(sizeof(struct binding), GFP_KERNEL); + if (!mapping->binding) { + error = -ENOMEM; + goto out; + } + error = build_binding(node_mask, mapping->binding); + if (error) { + kfree(mapping->binding); + mapping->binding = NULL; + } + +out: + return error; +} diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/mm/memory.c 830-ivtv/mm/memory.c --- 000-virgin/mm/memory.c Thu Jan 8 08:35:54 2004 +++ 830-ivtv/mm/memory.c Thu Jan 8 10:21:12 2004 @@ -107,10 +107,11 @@ static inline void free_one_pmd(struct m pte_free_tlb(tlb, page); } -static inline void free_one_pgd(struct mmu_gather *tlb, pgd_t * dir) +static inline void free_one_pgd(struct mmu_gather *tlb, pgd_t * dir, + int pgd_idx) { - int j; pmd_t * pmd; + int j; if (pgd_none(*dir)) return; @@ -121,8 +122,12 @@ static inline void free_one_pgd(struct m } pmd = pmd_offset(dir, 0); pgd_clear(dir); - for (j = 0; j < PTRS_PER_PMD ; j++) + + for (j = 0; j < PTRS_PER_PMD ; j++) { + if (pgd_idx * PGDIR_SIZE + j * PMD_SIZE >= TASK_SIZE) + break; free_one_pmd(tlb, pmd+j); + } pmd_free_tlb(tlb, pmd); } @@ -135,11 +140,13 @@ static inline void free_one_pgd(struct m void clear_page_tables(struct mmu_gather *tlb, unsigned long first, int nr) { pgd_t * page_dir = tlb->mm->pgd; + int pgd_idx = first; page_dir += first; do { - free_one_pgd(tlb, page_dir); + free_one_pgd(tlb, page_dir, pgd_idx); page_dir++; + pgd_idx++; } while (--nr); } @@ -326,7 +333,7 @@ skip_copy_pte_range: pte = pte_mkclean(pte); pte = pte_mkold(pte); get_page(page); - dst->rss++; + inc_rss(dst, page); set_pte(dst_pte, pte); pte_chain = page_add_rmap(page, dst_pte, @@ -418,7 +425,14 @@ zap_pte_range(struct mmu_gather *tlb, pm if (page->mapping && pte_young(pte) && !PageSwapCache(page)) mark_page_accessed(page); - tlb->freed++; + /* + * While we have the page that is being + * freed handy, make sure we decrement + * the mm's RSS accordingly. This is + * only important for NUMA per-node + * RSS accounting. + */ + dec_rss(tlb->mm, page); page_remove_rmap(page, ptep); tlb_remove_page(tlb, page); } @@ -437,7 +451,7 @@ zap_pmd_range(struct mmu_gather *tlb, pg unsigned long address, unsigned long size) { pmd_t * pmd; - unsigned long end; + unsigned long end, pgd_boundary; if (pgd_none(*dir)) return; @@ -448,8 +462,9 @@ zap_pmd_range(struct mmu_gather *tlb, pg } pmd = pmd_offset(dir, address); end = address + size; - if (end > ((address + PGDIR_SIZE) & PGDIR_MASK)) - end = ((address + PGDIR_SIZE) & PGDIR_MASK); + pgd_boundary = ((address + PGDIR_SIZE) & PGDIR_MASK); + if (pgd_boundary && (end > pgd_boundary)) + end = pgd_boundary; do { zap_pte_range(tlb, pmd, address, end - address); address = (address + PMD_SIZE) & PMD_MASK; @@ -1052,9 +1067,10 @@ static int do_wp_page(struct mm_struct * page_table = pte_offset_map(pmd, address); if (pte_same(*page_table, pte)) { if (PageReserved(old_page)) - ++mm->rss; + inc_rss(mm, new_page); page_remove_rmap(old_page, page_table); break_cow(vma, new_page, address, page_table); + SetPageAnon(new_page); pte_chain = page_add_rmap(new_page, page_table, pte_chain); lru_cache_add_active(new_page); @@ -1286,7 +1302,7 @@ static int do_swap_page(struct mm_struct if (vm_swap_full()) remove_exclusive_swap_page(page); - mm->rss++; + inc_rss(mm, page); pte = mk_pte(page, vma->vm_page_prot); if (write_access && can_share_swap_page(page)) pte = pte_mkdirty(pte_mkwrite(pte)); @@ -1294,6 +1310,7 @@ static int do_swap_page(struct mm_struct flush_icache_page(vma, page); set_pte(page_table, pte); + SetPageAnon(page); pte_chain = page_add_rmap(page, page_table, pte_chain); /* No need to invalidate - it was non-present before */ @@ -1355,10 +1372,11 @@ do_anonymous_page(struct mm_struct *mm, ret = VM_FAULT_MINOR; goto out; } - mm->rss++; + inc_rss(mm, page); entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))); lru_cache_add_active(page); mark_page_accessed(page); + SetPageAnon(page); } set_pte(page_table, entry); @@ -1426,6 +1444,10 @@ retry: if (!pte_chain) goto oom; + /* See if nopage returned an anon page */ + if (!new_page->mapping || PageSwapCache(new_page)) + SetPageAnon(new_page); + /* * Should we do an early C-O-W break? */ @@ -1438,6 +1460,7 @@ retry: copy_user_highpage(page, new_page, address); page_cache_release(new_page); lru_cache_add_active(page); + SetPageAnon(page); new_page = page; } @@ -1470,7 +1493,7 @@ retry: /* Only go through if we didn't race with anybody else... */ if (pte_none(*page_table)) { if (!PageReserved(new_page)) - ++mm->rss; + inc_rss(mm, new_page); flush_icache_page(vma, new_page); entry = mk_pte(new_page, vma->vm_page_prot); if (write_access) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/mm/mmap.c 830-ivtv/mm/mmap.c --- 000-virgin/mm/mmap.c Thu Jan 8 08:35:54 2004 +++ 830-ivtv/mm/mmap.c Thu Jan 8 10:22:37 2004 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -59,6 +60,9 @@ EXPORT_SYMBOL(sysctl_overcommit_memory); EXPORT_SYMBOL(sysctl_overcommit_ratio); EXPORT_SYMBOL(vm_committed_space); +int mmap_use_hugepages = 0; +int mmap_hugepages_map_sz = 256; + /* * Requires inode->i_mapping->i_shared_sem */ @@ -269,9 +273,7 @@ static void vma_link(struct mm_struct *m if (mapping) down(&mapping->i_shared_sem); - spin_lock(&mm->page_table_lock); __vma_link(mm, vma, prev, rb_link, rb_parent); - spin_unlock(&mm->page_table_lock); if (mapping) up(&mapping->i_shared_sem); @@ -320,6 +322,22 @@ static inline int is_mergeable_vma(struc return 1; } +/* requires that the relevant i_shared_sem be held by the caller */ +static void move_vma_start(struct vm_area_struct *vma, unsigned long addr) +{ + struct inode *inode = NULL; + + if (vma->vm_file) + inode = vma->vm_file->f_dentry->d_inode; + if (inode) + __remove_shared_vm_struct(vma, inode); + /* If no vm_file, perhaps we should always keep vm_pgoff at 0?? */ + vma->vm_pgoff += (long)(addr - vma->vm_start) >> PAGE_SHIFT; + vma->vm_start = addr; + if (inode) + __vma_link_file(vma); +} + /* * Return true if we can merge this (vm_flags,file,vm_pgoff,size) * in front of (at a lower virtual address and file offset than) the vma. @@ -372,7 +390,6 @@ static int vma_merge(struct mm_struct *m unsigned long end, unsigned long vm_flags, struct file *file, unsigned long pgoff) { - spinlock_t *lock = &mm->page_table_lock; struct inode *inode = file ? file->f_dentry->d_inode : NULL; struct semaphore *i_shared_sem; @@ -404,7 +421,6 @@ static int vma_merge(struct mm_struct *m down(i_shared_sem); need_up = 1; } - spin_lock(lock); prev->vm_end = end; /* @@ -417,7 +433,6 @@ static int vma_merge(struct mm_struct *m prev->vm_end = next->vm_end; __vma_unlink(mm, next, prev); __remove_shared_vm_struct(next, inode); - spin_unlock(lock); if (need_up) up(i_shared_sem); if (file) @@ -427,7 +442,6 @@ static int vma_merge(struct mm_struct *m kmem_cache_free(vm_area_cachep, next); return 1; } - spin_unlock(lock); if (need_up) up(i_shared_sem); return 1; @@ -445,10 +459,7 @@ static int vma_merge(struct mm_struct *m if (end == prev->vm_start) { if (file) down(i_shared_sem); - spin_lock(lock); - prev->vm_start = addr; - prev->vm_pgoff -= (end - addr) >> PAGE_SHIFT; - spin_unlock(lock); + move_vma_start(prev, addr); if (file) up(i_shared_sem); return 1; @@ -473,7 +484,7 @@ unsigned long do_mmap_pgoff(struct file int correct_wcount = 0; int error; struct rb_node ** rb_link, * rb_parent; - unsigned long charged = 0; + unsigned long charged = 0, addr_save = addr; if (file) { if (!file->f_op || !file->f_op->mmap) @@ -501,8 +512,17 @@ unsigned long do_mmap_pgoff(struct file /* Obtain the address to map to. we verify (or select) it and ensure * that it represents a valid section of the address space. + * VM_HUGETLB will never appear in vm_flags when CONFIG_HUGETLB is + * unset. */ - addr = get_unmapped_area(file, addr, len, pgoff, flags); +#ifdef CONFIG_HUGETLBFS + addr = try_hugetlb_get_unmapped_area(NULL, addr, len, pgoff, &flags); + if (IS_ERR((void *)addr)) + return addr; + else if (addr == 0) +#endif + addr = get_unmapped_area(file, addr_save, len, pgoff, flags); + if (addr & ~PAGE_MASK) return addr; @@ -566,6 +586,9 @@ unsigned long do_mmap_pgoff(struct file default: return -EINVAL; case MAP_PRIVATE: +#ifdef CONFIG_HUGETLBFS + case (MAP_PRIVATE|MAP_HUGETLB): +#endif vm_flags &= ~(VM_SHARED | VM_MAYSHARE); /* fall through */ case MAP_SHARED: @@ -650,10 +673,31 @@ munmap_back: error = file->f_op->mmap(file, vma); if (error) goto unmap_and_free_vma; - } else if (vm_flags & VM_SHARED) { - error = shmem_zero_setup(vma); - if (error) - goto free_vma; + } else if ((vm_flags & VM_SHARED) || (vm_flags & VM_HUGETLB)) { + if (!is_vm_hugetlb_page(vma)) { + error = shmem_zero_setup(vma); + if (error) + goto free_vma; + } else { + /* + * Presumably hugetlb_zero_setup() acquires a + * reference count for us. The difference + * between this and the shmem_zero_setup() + * case is that we can encounter an error + * _after_ allocating the file. The error + * path was adjusted slightly to fput() for us. + */ + struct file *new_file = hugetlb_zero_setup(len); + if (IS_ERR(new_file)) { + error = PTR_ERR(new_file); + goto free_vma; + } else { + vma->vm_file = new_file; + error = new_file->f_op->mmap(new_file, vma); + if (error) + goto unmap_and_free_vma; + } + } } /* We set VM_ACCOUNT in a shared mapping's vm_flags, to inform @@ -701,11 +745,21 @@ out: unmap_and_free_vma: if (correct_wcount) atomic_inc(&inode->i_writecount); - vma->vm_file = NULL; - fput(file); - /* Undo any partial mapping done by a device driver. */ + /* + * Undo any partial mapping done by a device driver. + * hugetlb wants to know the vma's file etc. so nuke + * the file afterward. + */ zap_page_range(vma, vma->vm_start, vma->vm_end - vma->vm_start); + + /* + * vma->vm_file may be different from file in the hugetlb case. + */ + if (vma->vm_file) + fput(vma->vm_file); + vma->vm_file = NULL; + free_vma: kmem_cache_free(vm_area_cachep, vma); unacct_error: @@ -907,19 +961,16 @@ int expand_stack(struct vm_area_struct * */ address += 4 + PAGE_SIZE - 1; address &= PAGE_MASK; - spin_lock(&vma->vm_mm->page_table_lock); grow = (address - vma->vm_end) >> PAGE_SHIFT; /* Overcommit.. */ if (security_vm_enough_memory(grow)) { - spin_unlock(&vma->vm_mm->page_table_lock); return -ENOMEM; } if (address - vma->vm_start > current->rlim[RLIMIT_STACK].rlim_cur || ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur) { - spin_unlock(&vma->vm_mm->page_table_lock); vm_unacct_memory(grow); return -ENOMEM; } @@ -927,7 +978,6 @@ int expand_stack(struct vm_area_struct * vma->vm_mm->total_vm += grow; if (vma->vm_flags & VM_LOCKED) vma->vm_mm->locked_vm += grow; - spin_unlock(&vma->vm_mm->page_table_lock); return 0; } @@ -961,19 +1011,16 @@ int expand_stack(struct vm_area_struct * * the spinlock only before relocating the vma range ourself. */ address &= PAGE_MASK; - spin_lock(&vma->vm_mm->page_table_lock); grow = (vma->vm_start - address) >> PAGE_SHIFT; /* Overcommit.. */ if (security_vm_enough_memory(grow)) { - spin_unlock(&vma->vm_mm->page_table_lock); return -ENOMEM; } if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur || ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur) { - spin_unlock(&vma->vm_mm->page_table_lock); vm_unacct_memory(grow); return -ENOMEM; } @@ -982,7 +1029,6 @@ int expand_stack(struct vm_area_struct * vma->vm_mm->total_vm += grow; if (vma->vm_flags & VM_LOCKED) vma->vm_mm->locked_vm += grow; - spin_unlock(&vma->vm_mm->page_table_lock); return 0; } @@ -1149,8 +1195,6 @@ static void unmap_region(struct mm_struc /* * Create a list of vma's touched by the unmap, removing them from the mm's * vma list as we go.. - * - * Called with the page_table_lock held. */ static void detach_vmas_to_be_unmapped(struct mm_struct *mm, struct vm_area_struct *vma, @@ -1213,10 +1257,9 @@ int split_vma(struct mm_struct * mm, str down(&mapping->i_shared_sem); spin_lock(&mm->page_table_lock); - if (new_below) { - vma->vm_start = addr; - vma->vm_pgoff += ((addr - new->vm_start) >> PAGE_SHIFT); - } else + if (new_below) + move_vma_start(vma, addr); + else vma->vm_end = addr; __insert_vm_struct(mm, new); @@ -1290,8 +1333,8 @@ int do_munmap(struct mm_struct *mm, unsi /* * Remove the vma's, and unmap the actual pages */ - spin_lock(&mm->page_table_lock); detach_vmas_to_be_unmapped(mm, mpnt, prev, end); + spin_lock(&mm->page_table_lock); unmap_region(mm, mpnt, prev, start, end); spin_unlock(&mm->page_table_lock); @@ -1447,7 +1490,7 @@ void exit_mmap(struct mm_struct *mm) vma = mm->mmap; mm->mmap = mm->mmap_cache = NULL; mm->mm_rb = RB_ROOT; - mm->rss = 0; + zero_rss(mm); mm->total_vm = 0; mm->locked_vm = 0; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/mm/page_alloc.c 830-ivtv/mm/page_alloc.c --- 000-virgin/mm/page_alloc.c Thu Jan 8 08:35:54 2004 +++ 830-ivtv/mm/page_alloc.c Thu Jan 8 10:21:21 2004 @@ -225,6 +225,8 @@ static inline void free_pages_check(cons bad_page(function, page); if (PageDirty(page)) ClearPageDirty(page); + if (PageAnon(page)) + ClearPageAnon(page); } /* @@ -563,6 +565,10 @@ __alloc_pages(unsigned int gfp_mask, uns for (i = 0; zones[i] != NULL; i++) { struct zone *z = zones[i]; unsigned long local_low; + + if ((__GFP_NODE_STRICT & gfp_mask) && + (pfn_to_nid(z->zone_start_pfn) != numa_node_id())) + continue; /* * This is the fabled 'incremental min'. We let real-time tasks diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/mm/rmap.c 830-ivtv/mm/rmap.c --- 000-virgin/mm/rmap.c Mon Nov 17 18:28:20 2003 +++ 830-ivtv/mm/rmap.c Thu Jan 8 10:21:12 2004 @@ -102,6 +102,136 @@ pte_chain_encode(struct pte_chain *pte_c **/ /** + * find_pte - Find a pte pointer given a vma and a struct page. + * @vma: the vma to search + * @page: the page to find + * + * Determine if this page is mapped in this vma. If it is, map and rethrn + * the pte pointer associated with it. Return null if the page is not + * mapped in this vma for any reason. + * + * This is strictly an internal helper function for the object-based rmap + * functions. + * + * It is the caller's responsibility to unmap the pte if it is returned. + */ +static inline pte_t * +find_pte(struct vm_area_struct *vma, struct page *page, unsigned long *addr) +{ + struct mm_struct *mm = vma->vm_mm; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + unsigned long loffset; + unsigned long address; + + loffset = (page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT)); + address = vma->vm_start + ((loffset - vma->vm_pgoff) << PAGE_SHIFT); + if (address < vma->vm_start || address >= vma->vm_end) + goto out; + + pgd = pgd_offset(mm, address); + if (!pgd_present(*pgd)) + goto out; + + pmd = pmd_offset(pgd, address); + if (!pmd_present(*pmd)) + goto out; + + pte = pte_offset_map(pmd, address); + if (!pte_present(*pte)) + goto out_unmap; + + if (page_to_pfn(page) != pte_pfn(*pte)) + goto out_unmap; + + if (addr) + *addr = address; + + return pte; + +out_unmap: + pte_unmap(pte); +out: + return NULL; +} + +/** + * page_referenced_obj_one - referenced check for object-based rmap + * @vma: the vma to look in. + * @page: the page we're working on. + * + * Find a pte entry for a page/vma pair, then check and clear the referenced + * bit. + * + * This is strictly a helper function for page_referenced_obj. + */ +static int +page_referenced_obj_one(struct vm_area_struct *vma, struct page *page) +{ + struct mm_struct *mm = vma->vm_mm; + pte_t *pte; + int referenced = 0; + + if (!spin_trylock(&mm->page_table_lock)) + return 1; + + pte = find_pte(vma, page, NULL); + if (pte) { + if (ptep_test_and_clear_young(pte)) + referenced++; + pte_unmap(pte); + } + + spin_unlock(&mm->page_table_lock); + return referenced; +} + +/** + * page_referenced_obj_one - referenced check for object-based rmap + * @page: the page we're checking references on. + * + * For an object-based mapped page, find all the places it is mapped and + * check/clear the referenced flag. This is done by following the page->mapping + * pointer, then walking the chain of vmas it holds. It returns the number + * of references it found. + * + * This function is only called from page_referenced for object-based pages. + * + * The semaphore address_space->i_shared_sem is tried. If it can't be gotten, + * assume a reference count of 1. + */ +static int +page_referenced_obj(struct page *page) +{ + struct address_space *mapping = page->mapping; + struct vm_area_struct *vma; + int referenced = 0; + + if (!page->pte.mapcount) + return 0; + + if (!mapping) + BUG(); + + if (PageSwapCache(page)) + BUG(); + + if (down_trylock(&mapping->i_shared_sem)) + return 1; + + list_for_each_entry(vma, &mapping->i_mmap, shared) + referenced += page_referenced_obj_one(vma, page); + + list_for_each_entry(vma, &mapping->i_mmap_shared, shared) + referenced += page_referenced_obj_one(vma, page); + + up(&mapping->i_shared_sem); + + return referenced; +} + +/** * page_referenced - test if the page was referenced * @page: the page to test * @@ -120,6 +250,10 @@ int page_referenced(struct page * page) if (TestClearPageReferenced(page)) referenced++; + if (!PageAnon(page)) { + referenced += page_referenced_obj(page); + goto out; + } if (PageDirect(page)) { pte_t *pte = rmap_ptep_map(page->pte.direct); if (ptep_test_and_clear_young(pte)) @@ -153,6 +287,7 @@ int page_referenced(struct page * page) __pte_chain_free(pc); } } +out: return referenced; } @@ -175,6 +310,21 @@ page_add_rmap(struct page *page, pte_t * pte_chain_lock(page); + /* + * If this is an object-based page, just count it. We can + * find the mappings by walking the object vma chain for that object. + */ + if (!PageAnon(page)) { + if (!page->mapping) + BUG(); + if (PageSwapCache(page)) + BUG(); + if (!page->pte.mapcount) + inc_page_state(nr_mapped); + page->pte.mapcount++; + goto out; + } + if (page->pte.direct == 0) { page->pte.direct = pte_paddr; SetPageDirect(page); @@ -231,8 +381,25 @@ void page_remove_rmap(struct page *page, pte_chain_lock(page); if (!page_mapped(page)) - goto out_unlock; /* remap_page_range() from a driver? */ + goto out_unlock; + /* + * If this is an object-based page, just uncount it. We can + * find the mappings by walking the object vma chain for that object. + */ + if (!PageAnon(page)) { + if (!page->mapping) + BUG(); + if (PageSwapCache(page)) + BUG(); + if (!page->pte.mapcount) + BUG(); + page->pte.mapcount--; + if (!page->pte.mapcount) + dec_page_state(nr_mapped); + goto out_unlock; + } + if (PageDirect(page)) { if (page->pte.direct == pte_paddr) { page->pte.direct = 0; @@ -279,6 +446,102 @@ out_unlock: } /** + * try_to_unmap_obj - unmap a page using the object-based rmap method + * @page: the page to unmap + * + * Determine whether a page is mapped in a given vma and unmap it if it's found. + * + * This function is strictly a helper function for try_to_unmap_obj. + */ +static inline int +try_to_unmap_obj_one(struct vm_area_struct *vma, struct page *page) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long address; + pte_t *pte; + pte_t pteval; + int ret = SWAP_AGAIN; + + if (!spin_trylock(&mm->page_table_lock)) + return ret; + + pte = find_pte(vma, page, &address); + if (!pte) + goto out; + + if (vma->vm_flags & VM_LOCKED) { + ret = SWAP_FAIL; + goto out_unmap; + } + + flush_cache_page(vma, address); + pteval = ptep_get_and_clear(pte); + flush_tlb_page(vma, address); + + if (pte_dirty(pteval)) + set_page_dirty(page); + + if (!page->pte.mapcount) + BUG(); + + mm->rss--; + page->pte.mapcount--; + page_cache_release(page); + +out_unmap: + pte_unmap(pte); + +out: + spin_unlock(&mm->page_table_lock); + return ret; +} + +/** + * try_to_unmap_obj - unmap a page using the object-based rmap method + * @page: the page to unmap + * + * Find all the mappings of a page using the mapping pointer and the vma chains + * contained in the address_space struct it points to. + * + * This function is only called from try_to_unmap for object-based pages. + * + * The semaphore address_space->i_shared_sem is tried. If it can't be gotten, + * return a temporary error. + */ +static int +try_to_unmap_obj(struct page *page) +{ + struct address_space *mapping = page->mapping; + struct vm_area_struct *vma; + int ret = SWAP_AGAIN; + + if (!mapping) + BUG(); + + if (PageSwapCache(page)) + BUG(); + + if (down_trylock(&mapping->i_shared_sem)) + return ret; + + list_for_each_entry(vma, &mapping->i_mmap, shared) { + ret = try_to_unmap_obj_one(vma, page); + if (ret == SWAP_FAIL || !page->pte.mapcount) + goto out; + } + + list_for_each_entry(vma, &mapping->i_mmap_shared, shared) { + ret = try_to_unmap_obj_one(vma, page); + if (ret == SWAP_FAIL || !page->pte.mapcount) + goto out; + } + +out: + up(&mapping->i_shared_sem); + return ret; +} + +/** * try_to_unmap_one - worker function for try_to_unmap * @page: page to unmap * @ptep: page table entry to unmap from page @@ -360,7 +623,7 @@ static int try_to_unmap_one(struct page if (pte_dirty(pte)) set_page_dirty(page); - mm->rss--; + dec_rss(mm, page); page_cache_release(page); ret = SWAP_SUCCESS; @@ -397,6 +660,15 @@ int try_to_unmap(struct page * page) if (!page->mapping) BUG(); + /* + * If it's an object-based page, use the object vma chain to find all + * the mappings. + */ + if (!PageAnon(page)) { + ret = try_to_unmap_obj(page); + goto out; + } + if (PageDirect(page)) { ret = try_to_unmap_one(page, page->pte.direct); if (ret == SWAP_SUCCESS) { @@ -452,9 +724,112 @@ int try_to_unmap(struct page * page) } } out: - if (!page_mapped(page)) + if (!page_mapped(page)) { dec_page_state(nr_mapped); + ret = SWAP_SUCCESS; + } return ret; +} + +/** + * page_convert_anon - Convert an object-based mapped page to pte_chain-based. + * @page: the page to convert + * + * Find all the mappings for an object-based page and convert them + * to 'anonymous', ie create a pte_chain and store all the pte pointers there. + * + * This function takes the address_space->i_shared_sem, sets the PageAnon flag, + * then sets the mm->page_table_lock for each vma and calls page_add_rmap. This + * means there is a period when PageAnon is set, but still has some mappings + * with no pte_chain entry. This is in fact safe, since page_remove_rmap will + * simply not find it. try_to_unmap might erroneously return success, but it + * will never be called because the page_convert_anon() caller has locked the + * page. + * + * page_referenced() may fail to scan all the appropriate pte's and may return + * an inaccurate result. This is so rare that it does not matter. + */ +int page_convert_anon(struct page *page) +{ + struct address_space *mapping; + struct vm_area_struct *vma; + struct pte_chain *pte_chain = NULL; + pte_t *pte; + int err = 0; + + mapping = page->mapping; + if (mapping == NULL) + goto out; /* truncate won the lock_page() race */ + + down(&mapping->i_shared_sem); + pte_chain_lock(page); + + /* + * Has someone else done it for us before we got the lock? + * If so, pte.direct or pte.chain has replaced pte.mapcount. + */ + if (PageAnon(page)) { + pte_chain_unlock(page); + goto out_unlock; + } + + SetPageAnon(page); + if (page->pte.mapcount == 0) { + pte_chain_unlock(page); + goto out_unlock; + } + /* This is gonna get incremented by page_add_rmap */ + dec_page_state(nr_mapped); + page->pte.mapcount = 0; + + /* + * Now that the page is marked as anon, unlock it. page_add_rmap will + * lock it as necessary. + */ + pte_chain_unlock(page); + + list_for_each_entry(vma, &mapping->i_mmap, shared) { + if (!pte_chain) { + pte_chain = pte_chain_alloc(GFP_KERNEL); + if (!pte_chain) { + err = -ENOMEM; + goto out_unlock; + } + } + spin_lock(&vma->vm_mm->page_table_lock); + pte = find_pte(vma, page, NULL); + if (pte) { + /* Make sure this isn't a duplicate */ + page_remove_rmap(page, pte); + pte_chain = page_add_rmap(page, pte, pte_chain); + pte_unmap(pte); + } + spin_unlock(&vma->vm_mm->page_table_lock); + } + list_for_each_entry(vma, &mapping->i_mmap_shared, shared) { + if (!pte_chain) { + pte_chain = pte_chain_alloc(GFP_KERNEL); + if (!pte_chain) { + err = -ENOMEM; + goto out_unlock; + } + } + spin_lock(&vma->vm_mm->page_table_lock); + pte = find_pte(vma, page, NULL); + if (pte) { + /* Make sure this isn't a duplicate */ + page_remove_rmap(page, pte); + pte_chain = page_add_rmap(page, pte, pte_chain); + pte_unmap(pte); + } + spin_unlock(&vma->vm_mm->page_table_lock); + } + +out_unlock: + pte_chain_free(pte_chain); + up(&mapping->i_shared_sem); +out: + return err; } /** diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/mm/shmem.c 830-ivtv/mm/shmem.c --- 000-virgin/mm/shmem.c Thu Jan 8 08:35:55 2004 +++ 830-ivtv/mm/shmem.c Thu Jan 8 10:22:37 2004 @@ -40,6 +40,29 @@ #include #include +int shm_use_hugepages; + +/* + * On 64bit archs the vmalloc area is very large, + * so we allocate the array in vmalloc on 64bit archs. + * + * Assuming 2M pages (x86 and x86-64) those default setting + * will allow up to 128G of bigpages in a single file on + * 64bit archs and 64G on 32bit archs using the max + * kmalloc size of 128k. So tweaking in practice is needed + * only to go past 128G of bigpages per file on 64bit archs. + * + * This sysctl is in page units (each page large BIGPAGE_SIZE). + */ +#ifdef CONFIG_HUGETLBFS +#if BITS_PER_LONG == 64 +int shm_hugepages_per_file = 128UL << (30 - HPAGE_SHIFT); +#else +int shm_hugepages_per_file = 131072 / sizeof(struct page *); +#endif +#endif + + /* This magic number is used in glibc for posix shared memory */ #define TMPFS_MAGIC 0x01021994 diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/mm/slab.c 830-ivtv/mm/slab.c --- 000-virgin/mm/slab.c Thu Jan 8 08:35:55 2004 +++ 830-ivtv/mm/slab.c Thu Jan 8 10:22:07 2004 @@ -479,6 +479,19 @@ static struct cache_names { #undef CACHE }; +/* Adjustments to cache size limit based on memory size */ +static int cache_limit_multiplier_norm; +static int cache_limit_multiplier_dma; + +struct cache_multipliers { + int memsize; + int mult; +} cache_multipliers[] = { + {0x40000, 4}, + {0x10000, 2}, + {0x0, 1} +}; + struct arraycache_init initarray_cache __initdata = { { 0, BOOT_CPUCACHE_ENTRIES, 1, 0} }; struct arraycache_init initarray_generic __initdata = { { 0, BOOT_CPUCACHE_ENTRIES, 1, 0} }; @@ -661,6 +674,9 @@ void __init kmem_cache_init(void) size_t left_over; struct cache_sizes *sizes; struct cache_names *names; + unsigned long dmasize, normsize; + pg_data_t *pgdat; + int i; /* * Fragmentation resistance on low memory - only use bigger @@ -669,7 +685,21 @@ void __init kmem_cache_init(void) if (num_physpages > (32 << 20) >> PAGE_SHIFT) slab_break_gfp_order = BREAK_GFP_ORDER_HI; - + /* + * Increase cache limits based on the amount of memory in various + * zones. + */ + dmasize = normsize = 0; + for_each_pgdat(pgdat) { + dmasize += pgdat->node_zones[ZONE_DMA].present_pages; + normsize += pgdat->node_zones[ZONE_NORMAL].present_pages; + } + for (i = 0; dmasize < cache_multipliers[i].memsize; i++); + cache_limit_multiplier_dma = cache_multipliers[i].mult; + normsize += dmasize; + for (i = 0; normsize < cache_multipliers[i].memsize; i++); + cache_limit_multiplier_norm = cache_multipliers[i].mult; + /* Bootstrap is tricky, because several objects are allocated * from caches that do not exist yet: * 1) initialize the cache_cache cache: it contains the kmem_cache_t @@ -1181,7 +1211,8 @@ next: cachep = NULL; goto opps; } - slab_size = L1_CACHE_ALIGN(cachep->num*sizeof(kmem_bufctl_t)+sizeof(struct slab)); + slab_size = L1_CACHE_ALIGN(cachep->num*sizeof(kmem_bufctl_t) + + sizeof(struct slab)); /* * If the slab has been placed off-slab, and we have enough space then @@ -1225,10 +1256,13 @@ next: * the cache that's used by kmalloc(24), otherwise * the creation of further caches will BUG(). */ - cachep->array[smp_processor_id()] = &initarray_generic.cache; + cachep->array[smp_processor_id()] = + &initarray_generic.cache; g_cpucache_up = PARTIAL; } else { - cachep->array[smp_processor_id()] = kmalloc(sizeof(struct arraycache_init),GFP_KERNEL); + cachep->array[smp_processor_id()] = + kmalloc(sizeof(struct arraycache_init), + GFP_KERNEL); } BUG_ON(!ac_data(cachep)); ac_data(cachep)->avail = 0; @@ -1242,7 +1276,7 @@ next: } cachep->lists.next_reap = jiffies + REAPTIMEOUT_LIST3 + - ((unsigned long)cachep)%REAPTIMEOUT_LIST3; + ((unsigned long)cachep)%REAPTIMEOUT_LIST3; /* Need the semaphore to access the chain. */ down(&cache_chain_sem); @@ -1255,16 +1289,24 @@ next: list_for_each(p, &cache_chain) { kmem_cache_t *pc = list_entry(p, kmem_cache_t, next); char tmp; - /* This happens when the module gets unloaded and doesn't - destroy its slab cache and noone else reuses the vmalloc - area of the module. Print a warning. */ - if (__get_user(tmp,pc->name)) { - printk("SLAB: cache with size %d has lost its name\n", - pc->objsize); + + /* + * This happens when the module gets unloaded and + * doesn't destroy its slab cache and noone else reuses + * the vmalloc area of the module. Print a warning. + */ +#ifdef CONFIG_X86_UACCESS_INDIRECT + if (__direct_get_user(tmp,pc->name)) { +#else + if (__get_user(tmp,pc->name)) { +#endif + printk("SLAB: cache with size %d has lost its " + "name\n", pc->objsize); continue; } if (!strcmp(pc->name,name)) { - printk("kmem_cache_create: duplicate cache %s\n",name); + printk("kmem_cache_create: duplicate " + "cache %s\n",name); up(&cache_chain_sem); BUG(); } @@ -2356,6 +2398,11 @@ static void enable_cpucache (kmem_cache_ else limit = 120; + if (cachep->gfpflags & GFP_DMA) + limit *= cache_limit_multiplier_dma; + else + limit *= cache_limit_multiplier_norm; + /* Cpu bound tasks (e.g. network routing) can exhibit cpu bound * allocation behaviour: Most allocs on one cpu, most free operations * on another cpu. For these cases, an efficient object passing between @@ -2544,7 +2591,7 @@ static void *s_start(struct seq_file *m, seq_puts(m, "slabinfo - version: 2.0\n"); #endif seq_puts(m, "# name "); - seq_puts(m, " : tunables "); + seq_puts(m, " : tunables "); seq_puts(m, " : slabdata "); #if STATS seq_puts(m, " : globalstat "); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/mm/swapfile.c 830-ivtv/mm/swapfile.c --- 000-virgin/mm/swapfile.c Mon Nov 17 18:29:43 2003 +++ 830-ivtv/mm/swapfile.c Thu Jan 8 10:21:12 2004 @@ -387,9 +387,10 @@ static void unuse_pte(struct vm_area_struct *vma, unsigned long address, pte_t *dir, swp_entry_t entry, struct page *page, struct pte_chain **pte_chainp) { - vma->vm_mm->rss++; + inc_rss(vma->vm_mm, page); get_page(page); set_pte(dir, pte_mkold(mk_pte(page, vma->vm_page_prot))); + SetPageAnon(page); *pte_chainp = page_add_rmap(page, dir, *pte_chainp); swap_free(entry); } @@ -498,6 +499,7 @@ static int unuse_process(struct mm_struc /* * Go through process' page directory. */ + down_read(&mm->mmap_sem); spin_lock(&mm->page_table_lock); for (vma = mm->mmap; vma; vma = vma->vm_next) { pgd_t * pgd = pgd_offset(mm, vma->vm_start); @@ -505,6 +507,7 @@ static int unuse_process(struct mm_struc break; } spin_unlock(&mm->page_table_lock); + up_read(&mm->mmap_sem); pte_chain_free(pte_chain); return 0; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/mm/usercopy.c 830-ivtv/mm/usercopy.c --- 000-virgin/mm/usercopy.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/mm/usercopy.c Thu Jan 8 10:26:43 2004 @@ -0,0 +1,291 @@ +/* + * linux/mm/usercopy.c + * + * (C) Copyright 2003 Ingo Molnar + * + * Generic implementation of all the user-VM access functions, without + * relying on being able to access the VM directly. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * Get kernel address of the user page and pin it. + */ +static inline struct page *pin_page(unsigned long addr, int write) +{ + struct mm_struct *mm = current->mm ? : &init_mm; + struct page *page = NULL; + int ret; + + /* + * Do a quick atomic lookup first - this is the fastpath. + */ +retry: + page = follow_page(mm, addr, write); + if (likely(page != NULL)) { + if (!PageReserved(page)) + get_page(page); + return page; + } + + /* + * No luck - bad address or need to fault in the page: + */ + + /* Release the lock so get_user_pages can sleep */ + spin_unlock(&mm->page_table_lock); + + /* + * In the context of filemap_copy_from_user(), we are not allowed + * to sleep. We must fail this usercopy attempt and allow + * filemap_copy_from_user() to recover: drop its atomic kmap and use + * a sleeping kmap instead. + */ + if (in_atomic()) { + spin_lock(&mm->page_table_lock); + return NULL; + } + + down_read(&mm->mmap_sem); + ret = get_user_pages(current, mm, addr, 1, write, 0, NULL, NULL); + up_read(&mm->mmap_sem); + spin_lock(&mm->page_table_lock); + + if (ret <= 0) + return NULL; + + /* + * Go try the follow_page again. + */ + goto retry; +} + +static inline void unpin_page(struct page *page) +{ + put_page(page); +} + +/* + * Access another process' address space. + * Source/target buffer must be kernel space, + * Do not walk the page table directly, use get_user_pages + */ +static int rw_vm(unsigned long addr, void *buf, int len, int write) +{ + struct mm_struct *mm = current->mm ? : &init_mm; + + if (!len) + return 0; + + spin_lock(&mm->page_table_lock); + + /* ignore errors, just check how much was sucessfully transfered */ + while (len) { + struct page *page = NULL; + int bytes, offset; + void *maddr; + + page = pin_page(addr, write); + if (!page) + break; + + bytes = len; + offset = addr & (PAGE_SIZE-1); + if (bytes > PAGE_SIZE-offset) + bytes = PAGE_SIZE-offset; + + maddr = kmap_atomic(page, KM_USER_COPY); + +#define HANDLE_TYPE(type) \ + case sizeof(type): *(type *)(maddr+offset) = *(type *)(buf); break; + + if (write) { + switch (bytes) { + HANDLE_TYPE(char); + HANDLE_TYPE(int); + HANDLE_TYPE(long long); + default: + memcpy(maddr + offset, buf, bytes); + } + } else { +#undef HANDLE_TYPE +#define HANDLE_TYPE(type) \ + case sizeof(type): *(type *)(buf) = *(type *)(maddr+offset); break; + switch (bytes) { + HANDLE_TYPE(char); + HANDLE_TYPE(int); + HANDLE_TYPE(long long); + default: + memcpy(buf, maddr + offset, bytes); + } +#undef HANDLE_TYPE + } + kunmap_atomic(maddr, KM_USER_COPY); + unpin_page(page); + len -= bytes; + buf += bytes; + addr += bytes; + } + spin_unlock(&mm->page_table_lock); + + return len; +} + +static int str_vm(unsigned long addr, void *buf0, int len, int copy) +{ + struct mm_struct *mm = current->mm ? : &init_mm; + struct page *page; + void *buf = buf0; + + if (!len) + return len; + + spin_lock(&mm->page_table_lock); + + /* ignore errors, just check how much was sucessfully transfered */ + while (len) { + int bytes, offset, left, copied; + char *maddr; + + page = pin_page(addr, copy == 2); + if (!page) { + spin_unlock(&mm->page_table_lock); + return -EFAULT; + } + bytes = len; + offset = addr & (PAGE_SIZE-1); + if (bytes > PAGE_SIZE-offset) + bytes = PAGE_SIZE-offset; + + maddr = kmap_atomic(page, KM_USER_COPY); + if (copy == 2) { + memset(maddr + offset, 0, bytes); + copied = bytes; + left = 0; + } else if (copy == 1) { + left = strncpy_count(buf, maddr + offset, bytes); + copied = bytes - left; + } else { + copied = strnlen(maddr + offset, bytes); + left = bytes - copied; + } + BUG_ON(bytes < 0 || copied < 0); + kunmap_atomic(maddr, KM_USER_COPY); + unpin_page(page); + len -= copied; + buf += copied; + addr += copied; + if (left) + break; + } + spin_unlock(&mm->page_table_lock); + + return len; +} + +/* + * Copies memory from userspace (ptr) into kernelspace (val). + * + * returns # of bytes not copied. + */ +int get_user_size(unsigned int size, void *val, const void *ptr) +{ + int ret; + + if (unlikely(segment_eq(get_fs(), KERNEL_DS))) + ret = __direct_copy_from_user(val, ptr, size); + else + ret = rw_vm((unsigned long)ptr, val, size, 0); + if (ret) + /* + * Zero the rest: + */ + memset(val + size - ret, 0, ret); + return ret; +} + +/* + * Copies memory from kernelspace (val) into userspace (ptr). + * + * returns # of bytes not copied. + */ +int put_user_size(unsigned int size, const void *val, void *ptr) +{ + if (unlikely(segment_eq(get_fs(), KERNEL_DS))) + return __direct_copy_to_user(ptr, val, size); + else + return rw_vm((unsigned long)ptr, (void *)val, size, 1); +} + +int copy_str_fromuser_size(unsigned int size, void *val, const void *ptr) +{ + int copied, left; + + if (unlikely(segment_eq(get_fs(), KERNEL_DS))) { + left = strncpy_count(val, ptr, size); + copied = size - left; + BUG_ON(copied < 0); + + return copied; + } + left = str_vm((unsigned long)ptr, val, size, 1); + if (left < 0) + return left; + copied = size - left; + BUG_ON(copied < 0); + + return copied; +} + +int strlen_fromuser_size(unsigned int size, const void *ptr) +{ + int copied, left; + + if (unlikely(segment_eq(get_fs(), KERNEL_DS))) { + copied = strnlen(ptr, size) + 1; + BUG_ON(copied < 0); + + return copied; + } + left = str_vm((unsigned long)ptr, NULL, size, 0); + if (left < 0) + return 0; + copied = size - left + 1; + BUG_ON(copied < 0); + + return copied; +} + +int zero_user_size(unsigned int size, void *ptr) +{ + int left; + + if (unlikely(segment_eq(get_fs(), KERNEL_DS))) { + memset(ptr, 0, size); + return 0; + } + left = str_vm((unsigned long)ptr, NULL, size, 2); + if (left < 0) + return size; + return left; +} + +EXPORT_SYMBOL(get_user_size); +EXPORT_SYMBOL(put_user_size); +EXPORT_SYMBOL(zero_user_size); +EXPORT_SYMBOL(copy_str_fromuser_size); +EXPORT_SYMBOL(strlen_fromuser_size); + diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/mm/vmscan.c 830-ivtv/mm/vmscan.c --- 000-virgin/mm/vmscan.c Thu Jan 8 08:35:55 2004 +++ 830-ivtv/mm/vmscan.c Thu Jan 8 10:21:43 2004 @@ -47,7 +47,7 @@ /* * From 0 .. 100. Higher means more swappy. */ -int vm_swappiness = 60; +int vm_swappiness = 0; static long total_memory; #ifdef ARCH_HAS_PREFETCH @@ -600,6 +600,7 @@ refill_inactive_zone(struct zone *zone, LIST_HEAD(l_active); /* Pages to go onto the active_list */ struct page *page; struct pagevec pvec; + struct sysinfo i; int reclaim_mapped = 0; long mapped_ratio; long distress; @@ -640,6 +641,14 @@ refill_inactive_zone(struct zone *zone, * is mapped. */ mapped_ratio = (ps->nr_mapped * 100) / total_memory; + + /* + * Autoregulate vm_swappiness to be equal to the percentage of + * pages in physical ram that are application pages. -ck + */ + si_meminfo(&i); + vm_swappiness = 100 - (((i.freeram + get_page_cache_size() - + swapper_space.nrpages) * 100) / i.totalram); /* * Now decide how much we really want to unmap some pages. The mapped diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/net/Kconfig 830-ivtv/net/Kconfig --- 000-virgin/net/Kconfig Mon Dec 8 09:55:53 2003 +++ 830-ivtv/net/Kconfig Thu Jan 8 09:30:18 2004 @@ -664,4 +664,19 @@ source "net/irda/Kconfig" source "net/bluetooth/Kconfig" +config KGDBOE + def_bool X86 && KGDB + +config NETPOLL + def_bool NETCONSOLE || KGDBOE + +config NETPOLL_RX + def_bool KGDBOE + +config NETPOLL_TRAP + def_bool KGDBOE + +config NET_POLL_CONTROLLER + def_bool NETPOLL + endmenu diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/net/atm/clip.c 830-ivtv/net/atm/clip.c --- 000-virgin/net/atm/clip.c Mon Nov 17 18:29:43 2003 +++ 830-ivtv/net/atm/clip.c Thu Jan 8 08:54:31 2004 @@ -563,32 +563,20 @@ static int clip_setentry(struct atm_vcc } -static int clip_init(struct net_device *dev) +static void clip_setup(struct net_device *dev) { - DPRINTK("clip_init %s\n",dev->name); dev->hard_start_xmit = clip_start_xmit; /* sg_xmit ... */ - dev->hard_header = NULL; - dev->rebuild_header = NULL; - dev->set_mac_address = NULL; - dev->hard_header_parse = NULL; - dev->hard_header_cache = NULL; - dev->header_cache_update = NULL; - dev->change_mtu = NULL; - dev->do_ioctl = NULL; dev->get_stats = clip_get_stats; dev->type = ARPHRD_ATM; dev->hard_header_len = RFC1483LLC_LEN; dev->mtu = RFC1626_MTU; - dev->addr_len = 0; dev->tx_queue_len = 100; /* "normal" queue (packets) */ /* When using a "real" qdisc, the qdisc determines the queue */ /* length. tx_queue_len is only used for the default case, */ /* without any more elaborate queuing. 100 is a reasonable */ /* compromise between decent burst-tolerance and protection */ /* against memory hogs. */ - dev->flags = 0; - return 0; } @@ -608,18 +596,16 @@ static int clip_create(int number) if (PRIV(dev)->number >= number) number = PRIV(dev)->number+1; } - dev = kmalloc(sizeof(struct net_device)+sizeof(struct clip_priv), - GFP_KERNEL); - if (!dev) return -ENOMEM; - memset(dev,0,sizeof(struct net_device)+sizeof(struct clip_priv)); + dev = alloc_netdev(sizeof(struct clip_priv), "", clip_setup); + if (!dev) + return -ENOMEM; clip_priv = PRIV(dev); sprintf(dev->name,"atm%d",number); - dev->init = clip_init; spin_lock_init(&clip_priv->xoff_lock); clip_priv->number = number; error = register_netdev(dev); if (error) { - kfree(dev); + free_netdev(dev); return error; } clip_priv->next = clip_devs; @@ -634,7 +620,7 @@ static int clip_device_event(struct noti { /* ignore non-CLIP devices */ if (((struct net_device *) dev)->type != ARPHRD_ATM || - ((struct net_device *) dev)->init != clip_init) + ((struct net_device *) dev)->hard_start_xmit != clip_start_xmit) return NOTIFY_DONE; switch (event) { case NETDEV_UP: diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/net/bridge/br_if.c 830-ivtv/net/bridge/br_if.c --- 000-virgin/net/bridge/br_if.c Tue Aug 5 20:01:56 2003 +++ 830-ivtv/net/bridge/br_if.c Thu Jan 8 08:54:31 2004 @@ -172,7 +172,7 @@ int br_add_bridge(const char *name) ret = register_netdev(br->dev); if (ret) - kfree(br->dev); + free_netdev(br->dev); return ret; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/net/core/Makefile 830-ivtv/net/core/Makefile --- 000-virgin/net/core/Makefile Mon Nov 17 18:28:20 2003 +++ 830-ivtv/net/core/Makefile Thu Jan 8 08:54:31 2004 @@ -13,3 +13,4 @@ obj-$(CONFIG_NETFILTER) += netfilter.o obj-$(CONFIG_NET_DIVERT) += dv.o obj-$(CONFIG_NET_PKTGEN) += pktgen.o obj-$(CONFIG_NET_RADIO) += wireless.o +obj-$(CONFIG_NETPOLL) += netpoll.o diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/net/core/dev.c 830-ivtv/net/core/dev.c --- 000-virgin/net/core/dev.c Thu Jan 8 08:35:55 2004 +++ 830-ivtv/net/core/dev.c Thu Jan 8 09:30:18 2004 @@ -105,6 +105,7 @@ #include #include #include +#include #ifdef CONFIG_NET_RADIO #include /* Note : will define WIRELESS_EXT */ #include @@ -371,6 +372,30 @@ int netdev_boot_setup_check(struct net_d return 0; } + +/** + * netdev_boot_base - get address from boot time settings + * @prefix: prefix for network device + * @unit: id for network device + * + * Check boot time settings for the base address of device. + * The found settings are set for the device to be used + * later in the device probing. + * Returns 0 if no settings found. + */ +unsigned long netdev_boot_base(const char *prefix, int unit) +{ + const struct netdev_boot_setup *s = dev_boot_setup; + char name[IFNAMSIZ]; + int i; + + sprintf(name, "%s%d", prefix, unit); + for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) + if (!strcmp(name, s[i].name)) + return s[i].map.base_addr; + return 0; +} + /* * Saves at boot time configured settings for any netdevice. */ @@ -1380,7 +1405,6 @@ static void sample_queue(unsigned long d } #endif - /** * netif_rx - post buffer to the network code * @skb: buffer to post @@ -1405,6 +1429,13 @@ int netif_rx(struct sk_buff *skb) struct softnet_data *queue; unsigned long flags; +#ifdef CONFIG_NETPOLL_RX + if (skb->dev->netpoll_rx && netpoll_rx(skb)) { + kfree_skb(skb); + return NET_RX_DROP; + } +#endif + if (!skb->stamp.tv_sec) do_gettimeofday(&skb->stamp); @@ -1560,6 +1591,13 @@ int netif_receive_skb(struct sk_buff *sk int ret = NET_RX_DROP; unsigned short type = skb->protocol; +#ifdef CONFIG_NETPOLL_RX + if (skb->dev->netpoll_rx && skb->dev->poll && netpoll_rx(skb)) { + kfree_skb(skb); + return NET_RX_DROP; + } +#endif + if (!skb->stamp.tv_sec) do_gettimeofday(&skb->stamp); @@ -1684,7 +1722,6 @@ static void net_rx_action(struct softirq unsigned long start_time = jiffies; int budget = netdev_max_backlog; - preempt_disable(); local_irq_disable(); @@ -1711,6 +1748,8 @@ static void net_rx_action(struct softirq dev_put(dev); local_irq_disable(); } + + kgdb_process_breakpoint(); } out: local_irq_enable(); @@ -2875,7 +2914,7 @@ void free_netdev(struct net_device *dev) { /* Compatiablity with error handling in drivers */ if (dev->reg_state == NETREG_UNINITIALIZED) { - kfree(dev); + kfree((char *)dev - dev->padded); return; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/net/core/net-sysfs.c 830-ivtv/net/core/net-sysfs.c --- 000-virgin/net/core/net-sysfs.c Mon Nov 17 18:29:49 2003 +++ 830-ivtv/net/core/net-sysfs.c Thu Jan 8 08:54:31 2004 @@ -372,7 +372,7 @@ static void netdev_release(struct class_ BUG_ON(dev->reg_state != NETREG_RELEASED); - kfree(dev); + kfree((char *)dev - dev->padded); } static struct class net_class = { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/net/core/netpoll.c 830-ivtv/net/core/netpoll.c --- 000-virgin/net/core/netpoll.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/net/core/netpoll.c Thu Jan 8 08:54:31 2004 @@ -0,0 +1,642 @@ +/* + * Common framework for low-level network console, dump, and debugger code + * + * Sep 8 2003 Matt Mackall + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * We maintain a small pool of fully-sized skbs, to make sure the + * message gets out even in extreme OOM situations. + */ + +#define MAX_SKBS 32 +#define MAX_UDP_CHUNK 1460 + +static spinlock_t skb_list_lock = SPIN_LOCK_UNLOCKED; +static int nr_skbs; +static struct sk_buff *skbs; + +static spinlock_t rx_list_lock = SPIN_LOCK_UNLOCKED; +static LIST_HEAD(rx_list); + +static int trapped; + +#define MAX_SKB_SIZE \ + (MAX_UDP_CHUNK + sizeof(struct udphdr) + \ + sizeof(struct iphdr) + sizeof(struct ethhdr)) + +static void zap_completion_queue(void); + +static int checksum_udp(struct sk_buff *skb, struct udphdr *uh, + unsigned short ulen, u32 saddr, u32 daddr) +{ + if (uh->check == 0) + return 0; + + if (skb->ip_summed == CHECKSUM_HW) + return csum_tcpudp_magic( + saddr, daddr, ulen, IPPROTO_UDP, skb->csum); + + skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0); + + return csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)); +} + +void netpoll_poll(struct netpoll *np) +{ + int budget = 1; + + if(!np->dev || !netif_running(np->dev) || !np->dev->poll_controller) + return; + + /* Process pending work on NIC */ + np->dev->poll_controller(np->dev); + + /* If scheduling is stopped, tickle NAPI bits */ + if(trapped && np->dev->poll && + test_bit(__LINK_STATE_RX_SCHED, &np->dev->state)) + np->dev->poll(np->dev, &budget); + zap_completion_queue(); +} + +static void refill_skbs(void) +{ + struct sk_buff *skb; + unsigned long flags; + + spin_lock_irqsave(&skb_list_lock, flags); + while (nr_skbs < MAX_SKBS) { + skb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC); + if (!skb) + break; + + skb->next = skbs; + skbs = skb; + nr_skbs++; + } + spin_unlock_irqrestore(&skb_list_lock, flags); +} + +static void zap_completion_queue(void) +{ + unsigned long flags; + struct softnet_data *sd = &get_cpu_var(softnet_data); + + if (sd->completion_queue) { + struct sk_buff *clist; + + local_irq_save(flags); + clist = sd->completion_queue; + sd->completion_queue = NULL; + local_irq_restore(flags); + + while (clist != NULL) { + struct sk_buff *skb = clist; + clist = clist->next; + __kfree_skb(skb); + } + } + + put_cpu_var(softnet_data); +} + +static struct sk_buff * find_skb(struct netpoll *np, int len, int reserve) +{ + int once = 1, count = 0; + unsigned long flags; + struct sk_buff *skb = NULL; + + zap_completion_queue(); +repeat: + if (nr_skbs < MAX_SKBS) + refill_skbs(); + + skb = alloc_skb(len, GFP_ATOMIC); + + if (!skb) { + spin_lock_irqsave(&skb_list_lock, flags); + skb = skbs; + if (skb) + skbs = skb->next; + skb->next = NULL; + nr_skbs--; + spin_unlock_irqrestore(&skb_list_lock, flags); + } + + if(!skb) { + count++; + if (once && (count == 1000000)) { + printk("out of netpoll skbs!\n"); + once = 0; + } + netpoll_poll(np); + goto repeat; + } + + atomic_set(&skb->users, 1); + skb_reserve(skb, reserve); + return skb; +} + +void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) +{ + int status; + +repeat: + if(!np || !np->dev || !netif_running(np->dev)) { + __kfree_skb(skb); + return; + } + + spin_lock(&np->dev->xmit_lock); + np->dev->xmit_lock_owner = smp_processor_id(); + + if (netif_queue_stopped(np->dev)) { + np->dev->xmit_lock_owner = -1; + spin_unlock(&np->dev->xmit_lock); + + netpoll_poll(np); + goto repeat; + } + + status = np->dev->hard_start_xmit(skb, np->dev); + np->dev->xmit_lock_owner = -1; + spin_unlock(&np->dev->xmit_lock); + + /* transmit busy */ + if(status) + goto repeat; +} + +void netpoll_send_udp(struct netpoll *np, const char *msg, int len) +{ + int total_len, eth_len, ip_len, udp_len; + struct sk_buff *skb; + struct udphdr *udph; + struct iphdr *iph; + struct ethhdr *eth; + + udp_len = len + sizeof(*udph); + ip_len = eth_len = udp_len + sizeof(*iph); + total_len = eth_len + ETH_HLEN; + + skb = find_skb(np, total_len, total_len - len); + if (!skb) + return; + + memcpy(skb->data, msg, len); + skb->len += len; + + udph = (struct udphdr *) skb_push(skb, sizeof(*udph)); + udph->source = htons(np->local_port); + udph->dest = htons(np->remote_port); + udph->len = htons(udp_len); + udph->check = 0; + + iph = (struct iphdr *)skb_push(skb, sizeof(*iph)); + + iph->version = 4; + iph->ihl = 5; + iph->tos = 0; + iph->tot_len = htons(ip_len); + iph->id = 0; + iph->frag_off = 0; + iph->ttl = 64; + iph->protocol = IPPROTO_UDP; + iph->check = 0; + iph->saddr = htonl(np->local_ip); + iph->daddr = htonl(np->remote_ip); + iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); + + eth = (struct ethhdr *) skb_push(skb, ETH_HLEN); + + eth->h_proto = htons(ETH_P_IP); + memcpy(eth->h_source, np->local_mac, 6); + memcpy(eth->h_dest, np->remote_mac, 6); + + netpoll_send_skb(np, skb); +} + +static void arp_reply(struct sk_buff *skb) +{ + struct in_device *in_dev = (struct in_device *) skb->dev->ip_ptr; + struct arphdr *arp; + unsigned char *arp_ptr, *sha, *tha; + int size, type = ARPOP_REPLY, ptype = ETH_P_ARP; + u32 sip, tip; + struct sk_buff *send_skb; + unsigned long flags; + struct list_head *p; + struct netpoll *np = 0; + + spin_lock_irqsave(&rx_list_lock, flags); + list_for_each(p, &rx_list) { + np = list_entry(p, struct netpoll, rx_list); + if ( np->dev == skb->dev ) + break; + np = 0; + } + spin_unlock_irqrestore(&rx_list_lock, flags); + + if (!np) return; + + /* No arp on this interface */ + if (!in_dev || skb->dev->flags & IFF_NOARP) + return; + + if (!pskb_may_pull(skb, (sizeof(struct arphdr) + + (2 * skb->dev->addr_len) + + (2 * sizeof(u32))))) + return; + + skb->h.raw = skb->nh.raw = skb->data; + arp = skb->nh.arph; + + if ((arp->ar_hrd != htons(ARPHRD_ETHER) && + arp->ar_hrd != htons(ARPHRD_IEEE802)) || + arp->ar_pro != htons(ETH_P_IP) || + arp->ar_op != htons(ARPOP_REQUEST)) + return; + + arp_ptr= (unsigned char *)(arp+1); + sha = arp_ptr; + arp_ptr += skb->dev->addr_len; + memcpy(&sip, arp_ptr, 4); + arp_ptr += 4; + tha = arp_ptr; + arp_ptr += skb->dev->addr_len; + memcpy(&tip, arp_ptr, 4); + + /* Should we ignore arp? */ + if (tip != in_dev->ifa_list->ifa_address || + LOOPBACK(tip) || MULTICAST(tip)) + return; + + + size = sizeof(struct arphdr) + 2 * (skb->dev->addr_len + 4); + send_skb = find_skb(np, size + LL_RESERVED_SPACE(np->dev), + LL_RESERVED_SPACE(np->dev)); + + if (!send_skb) + return; + + send_skb->nh.raw = send_skb->data; + arp = (struct arphdr *) skb_put(send_skb, size); + send_skb->dev = skb->dev; + send_skb->protocol = htons(ETH_P_ARP); + + /* Fill the device header for the ARP frame */ + + if (np->dev->hard_header && + np->dev->hard_header(send_skb, skb->dev, ptype, + np->remote_mac, np->local_mac, + send_skb->len) < 0) { + kfree_skb(send_skb); + return; + } + + /* + * Fill out the arp protocol part. + * + * we only support ethernet device type, + * which (according to RFC 1390) should always equal 1 (Ethernet). + */ + + arp->ar_hrd = htons(np->dev->type); + arp->ar_pro = htons(ETH_P_IP); + arp->ar_hln = np->dev->addr_len; + arp->ar_pln = 4; + arp->ar_op = htons(type); + + arp_ptr=(unsigned char *)(arp + 1); + memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len); + arp_ptr += np->dev->addr_len; + memcpy(arp_ptr, &tip, 4); + arp_ptr += 4; + memcpy(arp_ptr, np->local_mac, np->dev->addr_len); + arp_ptr += np->dev->addr_len; + memcpy(arp_ptr, &sip, 4); + + netpoll_send_skb(np, send_skb); +} + +int netpoll_rx(struct sk_buff *skb) +{ + int proto, len, ulen; + struct iphdr *iph; + struct udphdr *uh; + struct netpoll *np; + struct list_head *p; + unsigned long flags; + + if (skb->dev->type != ARPHRD_ETHER) + goto out; + + /* check if netpoll clients need ARP */ + if (skb->protocol == __constant_htons(ETH_P_ARP) && trapped) { + arp_reply(skb); + return 1; + } + + proto = ntohs(skb->mac.ethernet->h_proto); + if (proto != ETH_P_IP) + goto out; + if (skb->pkt_type == PACKET_OTHERHOST) + goto out; + if (skb_shared(skb)) + goto out; + + iph = (struct iphdr *)skb->data; + if (!pskb_may_pull(skb, sizeof(struct iphdr))) + goto out; + if (iph->ihl < 5 || iph->version != 4) + goto out; + if (!pskb_may_pull(skb, iph->ihl*4)) + goto out; + if (ip_fast_csum((u8 *)iph, iph->ihl) != 0) + goto out; + + len = ntohs(iph->tot_len); + if (skb->len < len || len < iph->ihl*4) + goto out; + + if (iph->protocol != IPPROTO_UDP) + goto out; + + len -= iph->ihl*4; + uh = (struct udphdr *)(((char *)iph) + iph->ihl*4); + ulen = ntohs(uh->len); + + if (ulen != len) + goto out; + if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr) < 0) + goto out; + + spin_lock_irqsave(&rx_list_lock, flags); + list_for_each(p, &rx_list) { + np = list_entry(p, struct netpoll, rx_list); + if (np->dev && np->dev != skb->dev) + continue; + if (np->local_ip && np->local_ip != ntohl(iph->daddr)) + continue; + if (np->remote_ip && np->remote_ip != ntohl(iph->saddr)) + continue; + if (np->local_port && np->local_port != ntohs(uh->dest)) + continue; + + spin_unlock_irqrestore(&rx_list_lock, flags); + + if (np->rx_hook) + np->rx_hook(np, ntohs(uh->source), + (char *)(uh+1), ulen-sizeof(uh)-4); + + return 1; + } + spin_unlock_irqrestore(&rx_list_lock, flags); + +out: + return trapped; +} + +int netpoll_parse_options(struct netpoll *np, char *opt) +{ + char *cur=opt, *delim; + + if(*cur != '@') { + if ((delim = strchr(cur, '@')) == NULL) + goto parse_failed; + *delim=0; + np->local_port=simple_strtol(cur, 0, 10); + cur=delim; + } + cur++; + printk(KERN_INFO "%s: local port %d\n", np->name, np->local_port); + + if(*cur != '/') { + if ((delim = strchr(cur, '/')) == NULL) + goto parse_failed; + *delim=0; + np->local_ip=ntohl(in_aton(cur)); + cur=delim; + + printk(KERN_INFO "%s: local IP %d.%d.%d.%d\n", + np->name, HIPQUAD(np->local_ip)); + } + cur++; + + if ( *cur != ',') { + /* parse out dev name */ + if ((delim = strchr(cur, ',')) == NULL) + goto parse_failed; + *delim=0; + strlcpy(np->dev_name, cur, sizeof(np->dev_name)); + cur=delim; + } + cur++; + + printk(KERN_INFO "%s: interface %s\n", np->name, np->dev_name); + + if ( *cur != '@' ) { + /* dst port */ + if ((delim = strchr(cur, '@')) == NULL) + goto parse_failed; + *delim=0; + np->remote_port=simple_strtol(cur, 0, 10); + cur=delim; + } + cur++; + printk(KERN_INFO "%s: remote port %d\n", np->name, np->remote_port); + + /* dst ip */ + if ((delim = strchr(cur, '/')) == NULL) + goto parse_failed; + *delim=0; + np->remote_ip=ntohl(in_aton(cur)); + cur=delim+1; + + printk(KERN_INFO "%s: remote IP %d.%d.%d.%d\n", + np->name, HIPQUAD(np->remote_ip)); + + if( *cur != 0 ) + { + /* MAC address */ + if ((delim = strchr(cur, ':')) == NULL) + goto parse_failed; + *delim=0; + np->remote_mac[0]=simple_strtol(cur, 0, 16); + cur=delim+1; + if ((delim = strchr(cur, ':')) == NULL) + goto parse_failed; + *delim=0; + np->remote_mac[1]=simple_strtol(cur, 0, 16); + cur=delim+1; + if ((delim = strchr(cur, ':')) == NULL) + goto parse_failed; + *delim=0; + np->remote_mac[2]=simple_strtol(cur, 0, 16); + cur=delim+1; + if ((delim = strchr(cur, ':')) == NULL) + goto parse_failed; + *delim=0; + np->remote_mac[3]=simple_strtol(cur, 0, 16); + cur=delim+1; + if ((delim = strchr(cur, ':')) == NULL) + goto parse_failed; + *delim=0; + np->remote_mac[4]=simple_strtol(cur, 0, 16); + cur=delim+1; + np->remote_mac[5]=simple_strtol(cur, 0, 16); + } + + printk(KERN_INFO "%s: remote ethernet address " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + np->name, + np->remote_mac[0], + np->remote_mac[1], + np->remote_mac[2], + np->remote_mac[3], + np->remote_mac[4], + np->remote_mac[5]); + + return 0; + + parse_failed: + printk(KERN_INFO "%s: couldn't parse config at %s!\n", + np->name, cur); + return -1; +} + +int netpoll_setup(struct netpoll *np) +{ + struct net_device *ndev = NULL; + struct in_device *in_dev; + + if (np->dev_name) + ndev = dev_get_by_name(np->dev_name); + if (!ndev) { + printk(KERN_ERR "%s: %s doesn't exist, aborting.\n", + np->name, np->dev_name); + goto release; + } + if (!ndev->poll_controller) { + printk(KERN_ERR "%s: %s doesn't support polling, aborting.\n", + np->name, np->dev_name); + goto release; + } + + if (!(ndev->flags & IFF_UP)) { + unsigned short oflags; + unsigned long jiff; + + printk(KERN_INFO "%s: device %s not up yet, forcing it\n", + np->name, np->dev_name); + + oflags = ndev->flags; + + rtnl_shlock(); + if (dev_change_flags(ndev, oflags | IFF_UP) < 0) { + printk(KERN_ERR "%s: failed to open %s\n", + np->name, np->dev_name); + rtnl_shunlock(); + goto release; + } + rtnl_shunlock(); + + jiff = jiffies + 6*HZ; + while(!netif_carrier_ok(ndev)) { + if (!time_before(jiffies, jiff)) { + printk(KERN_NOTICE + "%s: timeout waiting for carrier\n", + np->name); + break; + } + cond_resched(); + } + + } + + if (!memcmp(np->local_mac, "\0\0\0\0\0\0", 6) && ndev->dev_addr) + memcpy(np->local_mac, ndev->dev_addr, 6); + + if (!np->local_ip) { + in_dev = in_dev_get(ndev); + + if (!in_dev) { + printk(KERN_ERR "%s: no IP address for %s, aborting\n", + np->name, np->dev_name); + goto release; + } + + np->local_ip = ntohl(in_dev->ifa_list->ifa_local); + in_dev_put(in_dev); + printk(KERN_INFO "%s: local IP %d.%d.%d.%d\n", + np->name, HIPQUAD(np->local_ip)); + } + + np->dev = ndev; + + if(np->rx_hook) { + unsigned long flags; + +#ifdef CONFIG_NETPOLL_RX + np->dev->netpoll_rx = 1; +#endif + + spin_lock_irqsave(&rx_list_lock, flags); + list_add(&np->rx_list, &rx_list); + spin_unlock_irqrestore(&rx_list_lock, flags); + } + + return 0; + release: + dev_put(ndev); + return -1; +} + +void netpoll_cleanup(struct netpoll *np) +{ + if(np->rx_hook) { + unsigned long flags; + + spin_lock_irqsave(&rx_list_lock, flags); + list_del(&np->rx_list); +#ifdef CONFIG_NETPOLL_RX + np->dev->netpoll_rx = 0; +#endif + spin_unlock_irqrestore(&rx_list_lock, flags); + } + + dev_put(np->dev); + np->dev = 0; +} + +int netpoll_trap() +{ + return trapped; +} + +void netpoll_set_trap(int trap) +{ + trapped = trap; +} + +EXPORT_SYMBOL(netpoll_set_trap); +EXPORT_SYMBOL(netpoll_trap); +EXPORT_SYMBOL(netpoll_parse_options); +EXPORT_SYMBOL(netpoll_setup); +EXPORT_SYMBOL(netpoll_cleanup); +EXPORT_SYMBOL(netpoll_send_skb); +EXPORT_SYMBOL(netpoll_send_udp); +EXPORT_SYMBOL(netpoll_poll); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/net/ipv4/esp4.c 830-ivtv/net/ipv4/esp4.c --- 000-virgin/net/ipv4/esp4.c Tue Sep 2 09:55:59 2003 +++ 830-ivtv/net/ipv4/esp4.c Thu Jan 8 10:22:04 2004 @@ -10,6 +10,7 @@ #include #include #include +#include #define MAX_SG_ONSTACK 4 @@ -325,7 +326,15 @@ int esp_input(struct xfrm_state *x, stru skb->h.raw = skb_pull(skb, sizeof(struct ip_esp_hdr) + esp->conf.ivlen); skb->nh.raw += encap_len + sizeof(struct ip_esp_hdr) + esp->conf.ivlen; memcpy(skb->nh.raw, workbuf, iph->ihl*4); - skb->nh.iph->tot_len = htons(skb->len); + iph = skb->nh.iph; + iph->tot_len = htons(skb->len + (skb->data - skb->nh.raw)); + iph->check = 0; + iph->check = ip_fast_csum(skb->nh.raw, iph->ihl); + { + unsigned char *oldmac = skb->mac.raw; + skb->mac.raw += encap_len + sizeof(struct ip_esp_hdr) + esp -> conf.ivlen; + memmove(skb->mac.raw, oldmac, skb->nh.raw - skb->mac.raw); + } } return 0; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/net/ipv4/xfrm4_input.c 830-ivtv/net/ipv4/xfrm4_input.c --- 000-virgin/net/ipv4/xfrm4_input.c Tue Sep 2 09:55:59 2003 +++ 830-ivtv/net/ipv4/xfrm4_input.c Thu Jan 8 10:22:04 2004 @@ -93,6 +93,19 @@ int xfrm4_rcv_encap(struct sk_buff *skb, iph = skb->nh.iph; if (x->props.mode) { + if (iph->protocol == 0xfe) { + skb_push(skb, skb->data - skb->nh.raw); + if (!(skb->dev->flags&IFF_LOOPBACK)){ + dst_release(skb->dst); + skb->dst = NULL; + } + if (skb->sp) { + secpath_put(skb->sp); + skb->sp = NULL; + } + netif_rx(skb); + return 0; + } if (iph->protocol != IPPROTO_IPIP) goto drop; skb->nh.raw = skb->data; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/net/wanrouter/wanmain.c 830-ivtv/net/wanrouter/wanmain.c --- 000-virgin/net/wanrouter/wanmain.c Mon Nov 17 18:29:01 2003 +++ 830-ivtv/net/wanrouter/wanmain.c Thu Jan 8 08:54:31 2004 @@ -726,8 +726,6 @@ static int wanrouter_device_new_if(struc if (dev->name == NULL) { err = -EINVAL; - } else if (dev_get(dev->name)) { - err = -EEXIST; /* name already exists */ } else { #ifdef WANDEBUG diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/scripts/Makefile.build 830-ivtv/scripts/Makefile.build --- 000-virgin/scripts/Makefile.build Mon Nov 17 18:29:36 2003 +++ 830-ivtv/scripts/Makefile.build Thu Jan 8 10:21:18 2004 @@ -128,7 +128,16 @@ cmd_cc_i_c = $(CPP) $(c_flags) - quiet_cmd_cc_o_c = CC $(quiet_modtag) $@ ifndef CONFIG_MODVERSIONS -cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< +new1_c_flags = $(c_flags:-I%=-I$(TOPDIR)/%) +new2_c_flags = $(new1_c_flags:-Wp%=) +PWD = $(TOPDIR) + +quiet_cmd_cc_o_c = CC $(quiet_modtag) $@ +cmd_cc_o_c = $(CC) $(c_flags) -E -o $@ $< \ + && cd $(dir $<) \ + && $(CC) $(new2_c_flags) -c -o $(notdir $@) $(notdir $<) \ + && cd $(TOPDIR) +#cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< else # When module versioning is enabled the following steps are executed: @@ -143,12 +152,21 @@ else # replace the unresolved symbols __crc_exported_symbol with # the actual value of the checksum generated by genksyms -cmd_cc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $< +new1_c_flags = $(c_flags:-I%=-I$(TOPDIR)/%) +new2_c_flags = $(new1_c_flags:-Wp%=) +PWD = $(TOPDIR) + +quiet_cmd_cc_o_c = CC $(quiet_modtag) $@ +cmd_cc_o_c = $(CC) $(c_flags) -E -o $@ $< \ + && cd $(dir $<) \ + && $(CC) $(new2_c_flags) -c -o .tmp_$(@F) $(notdir $<) \ + && cd $(TOPDIR) +#cmd_cc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $< cmd_modversions = \ if ! $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \ mv $(@D)/.tmp_$(@F) $@; \ else \ - $(CPP) -D__GENKSYMS__ $(c_flags) $< \ + $(CPP) -D__GENKSYMS__ $(new2_c_flags) $< \ | $(GENKSYMS) \ > $(@D)/.tmp_$(@F:.o=.ver); \ \ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/core/control.c 830-ivtv/sound/core/control.c --- 000-virgin/sound/core/control.c Mon Nov 17 18:29:43 2003 +++ 830-ivtv/sound/core/control.c Thu Jan 8 10:26:49 2004 @@ -37,6 +37,9 @@ typedef struct _snd_kctl_ioctl { #define snd_kctl_ioctl(n) list_entry(n, snd_kctl_ioctl_t, list) +/* find id without lock */ +static snd_kcontrol_t *_ctl_find_id(snd_card_t * card, snd_ctl_elem_id_t *id); + static DECLARE_RWSEM(snd_ioctl_rwsem); static LIST_HEAD(snd_control_ioctls); @@ -262,6 +265,8 @@ void snd_ctl_free_one(snd_kcontrol_t * k * snd_ctl_new1() to the given card. * * Returns zero if successful, or a negative error code on failure. + * + * It frees automatically the control which cannot be added. */ int snd_ctl_add(snd_card_t * card, snd_kcontrol_t * kcontrol) { @@ -270,13 +275,23 @@ int snd_ctl_add(snd_card_t * card, snd_k snd_runtime_check(card != NULL && kcontrol != NULL, return -EINVAL); snd_assert(kcontrol->info != NULL, return -EINVAL); + id = kcontrol->id; down_write(&card->controls_rwsem); + if (_ctl_find_id(card, &id)) { + up_write(&card->controls_rwsem); + snd_ctl_free_one(kcontrol); + return -EBUSY; + } + if (card->last_numid > 0x80000000 && card->last_numid + kcontrol->count < 0x80000000) { + up_write(&card->controls_rwsem); + snd_ctl_free_one(kcontrol); + return -ENOMEM; /* FIXME: find a hole */ + } list_add_tail(&kcontrol->list, &card->controls); card->controls_count += kcontrol->count; kcontrol->id.numid = card->last_numid + 1; card->last_numid += kcontrol->count; up_write(&card->controls_rwsem); - id = kcontrol->id; for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); return 0; @@ -288,7 +303,8 @@ int snd_ctl_add(snd_card_t * card, snd_k * @kcontrol: the control instance to remove * * Removes the control from the card and then releases the instance. - * You don't need to call snd_ctl_free_one(). + * You don't need to call snd_ctl_free_one(). You must be in + * the write lock - down_write(&card->controls_rwsem). * * Returns 0 if successful, or a negative error code on failure. */ @@ -298,10 +314,8 @@ int snd_ctl_remove(snd_card_t * card, sn unsigned int idx; snd_runtime_check(card != NULL && kcontrol != NULL, return -EINVAL); - down_write(&card->controls_rwsem); list_del(&kcontrol->list); card->controls_count -= kcontrol->count; - up_write(&card->controls_rwsem); id = kcontrol->id; for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_REMOVE, &id); @@ -322,15 +336,50 @@ int snd_ctl_remove(snd_card_t * card, sn int snd_ctl_remove_id(snd_card_t * card, snd_ctl_elem_id_t *id) { snd_kcontrol_t *kctl; + int ret; - kctl = snd_ctl_find_id(card, id); - if (kctl == NULL) + down_write(&card->controls_rwsem); + kctl = _ctl_find_id(card, id); + if (kctl == NULL) { + up_write(&card->controls_rwsem); return -ENOENT; - return snd_ctl_remove(card, kctl); + } + ret = snd_ctl_remove(card, kctl); + up_write(&card->controls_rwsem); + return ret; } -static snd_kcontrol_t *_ctl_find_id -(snd_card_t * card, snd_ctl_elem_id_t *id); /* w/o lock */ +/** + * snd_ctl_remove_unlocked_id - remove the unlocked control of the given id and release it + * @file: active control handle + * @id: the control id to remove + * + * Finds the control instance with the given id, removes it from the + * card list and releases it. + * + * Returns 0 if successful, or a negative error code on failure. + */ +static int snd_ctl_remove_unlocked_id(snd_ctl_file_t * file, snd_ctl_elem_id_t *id) +{ + snd_card_t *card = file->card; + snd_kcontrol_t *kctl; + int idx, ret; + + down_write(&card->controls_rwsem); + kctl = _ctl_find_id(card, id); + if (kctl == NULL) { + up_write(&card->controls_rwsem); + return -ENOENT; + } + for (idx = 0; idx < kctl->count; idx++) + if (kctl->vd[idx].owner != NULL && kctl->vd[idx].owner != file) { + up_write(&card->controls_rwsem); + return -EBUSY; + } + ret = snd_ctl_remove(card, kctl); + up_write(&card->controls_rwsem); + return ret; +} /** * snd_ctl_rename_id - replace the id of a control on the card @@ -564,7 +613,6 @@ static int snd_ctl_elem_info(snd_ctl_fil static int snd_ctl_elem_read(snd_card_t *card, snd_ctl_elem_value_t *_control) { - snd_ctl_elem_value_t *control; snd_kcontrol_t *kctl; snd_kcontrol_volatile_t *vd; @@ -711,6 +759,196 @@ static int snd_ctl_elem_unlock(snd_ctl_f return result; } +struct user_element { + enum sndrv_ctl_elem_type type; /* element type */ + unsigned int elem_count; /* count of elements */ + union { + struct { + unsigned int items; + } enumerated; + } u; + void *elem_data; /* element data */ + unsigned long elem_data_size; /* size of element data in bytes */ + void *priv_data; /* private data (like strings for enumerated type) */ + unsigned long priv_data_size; /* size of private data in bytes */ + unsigned short dimen_count; /* count of dimensions */ + unsigned short dimen[0]; /* array of dimensions */ +}; + +static int snd_ctl_elem_user_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + struct user_element *ue = kcontrol->private_data; + + uinfo->type = ue->type; + uinfo->count = ue->elem_count; + if (ue->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) { + uinfo->value.enumerated.items = ue->u.enumerated.items; + if (uinfo->value.enumerated.item >= ue->u.enumerated.items) + uinfo->value.enumerated.item = 0; + strlcpy(uinfo->value.enumerated.name, + (char *)ue->priv_data + uinfo->value.enumerated.item * 64, + 64); + } + return 0; +} + +static int snd_ctl_elem_user_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + struct user_element *ue = kcontrol->private_data; + + memcpy(&ucontrol->value, ue->elem_data, ue->elem_data_size); + return 0; +} + +static int snd_ctl_elem_user_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + int change; + struct user_element *ue = kcontrol->private_data; + + change = memcmp(&ucontrol->value, ue->elem_data, ue->elem_data_size); + memcpy(ue->elem_data, &ucontrol->value, ue->elem_data_size); + return !!change; +} + +static void snd_ctl_elem_user_free(snd_kcontrol_t * kcontrol) +{ + kfree(kcontrol->private_data); +} + +static int snd_ctl_elem_add(snd_ctl_file_t *file, snd_ctl_elem_info_t *_info, int replace) +{ + snd_card_t *card = file->card; + snd_ctl_elem_info_t info; + snd_kcontrol_t kctl, *_kctl; + unsigned int access; + long private_size, dimen_size, extra_size; + struct user_element *ue; + int idx, err; + + if (copy_from_user(&info, _info, sizeof(info))) + return -EFAULT; + if (info.count > 1024) + return -EINVAL; + access = info.access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : + (info.access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|SNDRV_CTL_ELEM_ACCESS_INACTIVE| + SNDRV_CTL_ELEM_ACCESS_DINDIRECT|SNDRV_CTL_ELEM_ACCESS_INDIRECT)); + if (access & (SNDRV_CTL_ELEM_ACCESS_DINDIRECT | SNDRV_CTL_ELEM_ACCESS_INDIRECT)) + return -EINVAL; + info.id.numid = 0; + memset(&kctl, 0, sizeof(kctl)); + down_write(&card->controls_rwsem); + if (!!((_kctl = _ctl_find_id(card, &info.id)) != NULL) ^ replace) { + up_write(&card->controls_rwsem); + return !replace ? -EBUSY : -ENOENT; + } + if (replace) { + err = snd_ctl_remove(card, _kctl); + if (err < 0) { + up_write(&card->controls_rwsem); + return err; + } + } + up_write(&card->controls_rwsem); + memcpy(&kctl.id, &info.id, sizeof(info.id)); + kctl.count = info.owner ? info.owner : 1; + access |= SNDRV_CTL_ELEM_ACCESS_USER; + kctl.info = snd_ctl_elem_user_info; + if (access & SNDRV_CTL_ELEM_ACCESS_READ) + kctl.get = snd_ctl_elem_user_get; + if (access & SNDRV_CTL_ELEM_ACCESS_WRITE) + kctl.put = snd_ctl_elem_user_put; + extra_size = 0; + switch (info.type) { + case SNDRV_CTL_ELEM_TYPE_BOOLEAN: + private_size = sizeof(char); + if (info.count > 128) + return -EINVAL; + break; + case SNDRV_CTL_ELEM_TYPE_INTEGER: + private_size = sizeof(long); + if (info.count > 128) + return -EINVAL; + break; + case SNDRV_CTL_ELEM_TYPE_INTEGER64: + private_size = sizeof(long long); + if (info.count > 64) + return -EINVAL; + break; + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: + private_size = sizeof(unsigned int); + if (info.count > 128) + return -EINVAL; + if (info.value.enumerated.items > 1024) + return -EINVAL; + extra_size = info.value.enumerated.items * 64; + break; + case SNDRV_CTL_ELEM_TYPE_BYTES: + private_size = sizeof(unsigned char); + if (info.count > 512) + return -EINVAL; + break; + case SNDRV_CTL_ELEM_TYPE_IEC958: + private_size = sizeof(struct sndrv_aes_iec958); + if (info.count != 1) + return -EINVAL; + break; + default: + return -EINVAL; + } + private_size *= info.count; + if (private_size > 1024 * 1024) + return -EINVAL; + dimen_size = 0; + if (!(info.access & SNDRV_CTL_ELEM_ACCESS_DINDIRECT)) + for (idx = 0; idx < 4 && info.dimen.d[idx]; idx++) + dimen_size += sizeof(unsigned short); + ue = snd_kcalloc(sizeof(struct user_element) + dimen_size + private_size + extra_size, GFP_KERNEL); + if (ue == NULL) + return -ENOMEM; + ue->type = info.type; + ue->elem_count = info.count; + if (!(info.access & SNDRV_CTL_ELEM_ACCESS_DINDIRECT)) { + for (idx = 0; idx < 4 && info.dimen.d[idx]; idx++) + ue->dimen[idx] = info.dimen.d[idx]; + ue->dimen_count = dimen_size / sizeof(unsigned short); + } + ue->elem_data = (char *)ue + sizeof(ue) + dimen_size; + ue->elem_data_size = private_size; + if (extra_size) { + ue->priv_data = (char *)ue + sizeof(ue) + dimen_size + private_size; + ue->priv_data_size = extra_size; + if (ue->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) { + if (copy_from_user(ue->priv_data, *(char **)info.value.enumerated.name, extra_size)) + return -EFAULT; + ue->u.enumerated.items = info.value.enumerated.items; + } + } + kctl.private_free = snd_ctl_elem_user_free; + _kctl = snd_ctl_new(&kctl, access); + if (_kctl == NULL) { + kfree(_kctl->private_data); + return -ENOMEM; + } + _kctl->private_data = ue; + for (idx = 0; idx < _kctl->count; idx++) + _kctl->vd[idx].owner = file; + err = snd_ctl_add(card, _kctl); + if (err < 0) { + snd_ctl_free_one(_kctl); + return err; + } + return 0; +} + +static int snd_ctl_elem_remove(snd_ctl_file_t *file, snd_ctl_elem_id_t *_id) +{ + snd_ctl_elem_id_t id; + + if (copy_from_user(&id, _id, sizeof(id))) + return -EFAULT; + return snd_ctl_remove_unlocked_id(file, &id); +} + static int snd_ctl_subscribe_events(snd_ctl_file_t *file, int *ptr) { int subscribe; @@ -761,6 +999,12 @@ static int snd_ctl_ioctl(struct inode *i return snd_ctl_elem_lock(ctl, (snd_ctl_elem_id_t *) arg); case SNDRV_CTL_IOCTL_ELEM_UNLOCK: return snd_ctl_elem_unlock(ctl, (snd_ctl_elem_id_t *) arg); + case SNDRV_CTL_IOCTL_ELEM_ADD: + return snd_ctl_elem_add(ctl, (snd_ctl_elem_info_t *) arg, 0); + case SNDRV_CTL_IOCTL_ELEM_REPLACE: + return snd_ctl_elem_add(ctl, (snd_ctl_elem_info_t *) arg, 1); + case SNDRV_CTL_IOCTL_ELEM_REMOVE: + return snd_ctl_elem_remove(ctl, (snd_ctl_elem_id_t *) arg); case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS: return snd_ctl_subscribe_events(ctl, (int *) arg); case SNDRV_CTL_IOCTL_POWER: @@ -995,9 +1239,11 @@ int snd_ctl_unregister(snd_card_t *card) snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO); if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL, card, 0)) < 0) return err; + down_write(&card->controls_rwsem); while (!list_empty(&card->controls)) { control = snd_kcontrol(card->controls.next); snd_ctl_remove(card, control); } + up_write(&card->controls_rwsem); return 0; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/core/hwdep.c 830-ivtv/sound/core/hwdep.c --- 000-virgin/sound/core/hwdep.c Mon Nov 17 18:29:43 2003 +++ 830-ivtv/sound/core/hwdep.c Thu Jan 8 10:26:49 2004 @@ -214,7 +214,7 @@ static int snd_hwdep_dsp_load(snd_hwdep_ snd_hwdep_dsp_image_t info; int err; - if (! hw->ops.dsp_load || ! hw->ops.dsp_status) + if (! hw->ops.dsp_load) return -ENXIO; memset(&info, 0, sizeof(info)); if (copy_from_user(&info, _info, sizeof(info))) @@ -487,7 +487,6 @@ static int __init alsa_hwdep_init(void) memset(snd_hwdep_devices, 0, sizeof(snd_hwdep_devices)); if ((entry = snd_info_create_module_entry(THIS_MODULE, "hwdep", NULL)) != NULL) { - entry->content = SNDRV_INFO_CONTENT_TEXT; entry->c.text.read_size = 512; entry->c.text.read = snd_hwdep_proc_read; if (snd_info_register(entry) < 0) { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/core/info_oss.c 830-ivtv/sound/core/info_oss.c --- 000-virgin/sound/core/info_oss.c Sun Nov 17 20:29:26 2002 +++ 830-ivtv/sound/core/info_oss.c Thu Jan 8 10:26:49 2004 @@ -114,7 +114,6 @@ int snd_info_minor_register(void) memset(snd_sndstat_strings, 0, sizeof(snd_sndstat_strings)); if ((entry = snd_info_create_module_entry(THIS_MODULE, "sndstat", snd_oss_root)) != NULL) { - entry->content = SNDRV_INFO_CONTENT_TEXT; entry->c.text.read_size = 2048; entry->c.text.read = snd_sndstat_proc_read; if (snd_info_register(entry) < 0) { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/core/init.c 830-ivtv/sound/core/init.c --- 000-virgin/sound/core/init.c Mon Nov 17 18:29:43 2003 +++ 830-ivtv/sound/core/init.c Thu Jan 8 10:26:49 2004 @@ -442,7 +442,6 @@ int snd_card_register(snd_card_t * card) snd_printd("unable to create card entry\n"); goto __skip_info; } - entry->content = SNDRV_INFO_CONTENT_TEXT; entry->c.text.read_size = PAGE_SIZE; entry->c.text.read = snd_card_id_read; if (snd_info_register(entry) < 0) { @@ -527,7 +526,6 @@ int __init snd_card_info_init(void) entry = snd_info_create_module_entry(THIS_MODULE, "cards", NULL); snd_runtime_check(entry != NULL, return -ENOMEM); - entry->content = SNDRV_INFO_CONTENT_TEXT; entry->c.text.read_size = PAGE_SIZE; entry->c.text.read = snd_card_info_read; if (snd_info_register(entry) < 0) { @@ -539,7 +537,6 @@ int __init snd_card_info_init(void) #ifdef MODULE entry = snd_info_create_module_entry(THIS_MODULE, "modules", NULL); if (entry) { - entry->content = SNDRV_INFO_CONTENT_TEXT; entry->c.text.read_size = PAGE_SIZE; entry->c.text.read = snd_card_module_info_read; if (snd_info_register(entry) < 0) @@ -682,6 +679,7 @@ int snd_card_file_remove(snd_card_t *car int snd_power_wait(snd_card_t *card, unsigned int power_state, struct file *file) { wait_queue_t wait; + int result = 0; /* fastpath */ if (snd_power_get_state(card) == power_state) @@ -689,18 +687,24 @@ int snd_power_wait(snd_card_t *card, uns init_waitqueue_entry(&wait, current); add_wait_queue(&card->power_sleep, &wait); while (1) { - if (card->shutdown) - return -ENODEV; - if (snd_power_get_state(card) == power_state) { - remove_wait_queue(&card->power_sleep, &wait); - return 0; + if (card->shutdown) { + result = -ENODEV; + break; } - if (file && (file->f_flags & O_NONBLOCK)) - return -EAGAIN; + if (snd_power_get_state(card) == power_state) + break; +#if 0 /* block all devices */ + if (file && (file->f_flags & O_NONBLOCK)) { + result = -EAGAIN; + break; + } +#endif set_current_state(TASK_UNINTERRUPTIBLE); snd_power_unlock(card); schedule_timeout(30 * HZ); snd_power_lock(card); } + remove_wait_queue(&card->power_sleep, &wait); + return result; } #endif /* CONFIG_PM */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/core/memalloc.c 830-ivtv/sound/core/memalloc.c --- 000-virgin/sound/core/memalloc.c Mon Nov 17 18:29:01 2003 +++ 830-ivtv/sound/core/memalloc.c Thu Jan 8 10:26:49 2004 @@ -39,7 +39,7 @@ MODULE_LICENSE("GPL"); #ifndef SNDRV_CARDS #define SNDRV_CARDS 8 #endif -static int enable[8] = {[0 ... (SNDRV_CARDS-1)] = 1}; +static int enable[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1}; MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(enable, "Enable cards to allocate buffers."); @@ -95,25 +95,25 @@ static void *snd_pci_hack_alloc_consiste { void *ret; u64 dma_mask; - unsigned long rmask; + unsigned long mask; if (hwdev == NULL) return pci_alloc_consistent(hwdev, size, dma_handle); - dma_mask = hwdev->dma_mask; - rmask = ~((unsigned long)dma_mask); - hwdev->dma_mask = 0xffffffff; /* do without masking */ + dma_mask = hwdev->consistent_dma_mask; + mask = (unsigned long)dma_mask; + hwdev->consistent_dma_mask = 0xffffffff; /* do without masking */ ret = pci_alloc_consistent(hwdev, size, dma_handle); - hwdev->dma_mask = dma_mask; /* restore */ + hwdev->consistent_dma_mask = dma_mask; /* restore */ if (ret) { /* obtained address is out of range? */ - if (((unsigned long)*dma_handle + size - 1) & rmask) { + if (((unsigned long)*dma_handle + size - 1) & ~mask) { /* reallocate with the proper mask */ pci_free_consistent(hwdev, size, ret, *dma_handle); ret = pci_alloc_consistent(hwdev, size, dma_handle); } } else { /* wish to success now with the proper mask... */ - if (dma_mask != 0xffffffff) + if (mask != 0xffffffffUL) ret = pci_alloc_consistent(hwdev, size, dma_handle); } return ret; @@ -640,13 +640,13 @@ void *snd_malloc_pci_page(struct pci_dev { void *ptr; dma_addr_t addr; - unsigned long rmask; + unsigned long mask; - rmask = ~(unsigned long)(pci ? pci->dma_mask : 0x00ffffff); + mask = pci ? (unsigned long)pci->consistent_dma_mask : 0x00ffffffUL; ptr = (void *)__get_free_page(GFP_KERNEL); if (ptr) { addr = virt_to_phys(ptr); - if (((unsigned long)addr + PAGE_SIZE - 1) & rmask) { + if (((unsigned long)addr + PAGE_SIZE - 1) & ~mask) { /* try to reallocate with the GFP_DMA */ free_page((unsigned long)ptr); /* use GFP_ATOMIC for the DMA zone to avoid stall */ @@ -783,6 +783,7 @@ void snd_free_sbus_pages(struct sbus_dev * allocation of buffers for pre-defined devices */ +#ifdef CONFIG_PCI /* FIXME: for pci only - other bus? */ struct prealloc_dev { unsigned short vendor; @@ -832,7 +833,7 @@ static void __init preallocate_cards(voi if (! enable[card++]) continue; - if (pci_set_dma_mask(pci, dev->dma_mask) < 0) { + if (pci_set_consistent_dma_mask(pci, dev->dma_mask) < 0) { printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", dev->dma_mask, dev->vendor, dev->device); continue; } @@ -854,6 +855,9 @@ static void __init preallocate_cards(voi } } } +#else +#define preallocate_cards() /* NOP */ +#endif #ifdef CONFIG_PROC_FS diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/core/memory.c 830-ivtv/sound/core/memory.c --- 000-virgin/sound/core/memory.c Wed Mar 26 22:54:39 2003 +++ 830-ivtv/sound/core/memory.c Thu Jan 8 10:26:49 2004 @@ -231,7 +231,6 @@ int __init snd_memory_info_init(void) entry = snd_info_create_module_entry(THIS_MODULE, "meminfo", NULL); if (entry) { - entry->content = SNDRV_INFO_CONTENT_TEXT; entry->c.text.read_size = 256; entry->c.text.read = snd_memory_info_read; if (snd_info_register(entry) < 0) { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/core/oss/mixer_oss.c 830-ivtv/sound/core/oss/mixer_oss.c --- 000-virgin/sound/core/oss/mixer_oss.c Mon Nov 17 18:28:22 2003 +++ 830-ivtv/sound/core/oss/mixer_oss.c Thu Jan 8 10:26:49 2004 @@ -33,6 +33,7 @@ MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("Mixer OSS emulation for ALSA."); MODULE_LICENSE("GPL"); +MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_MIXER); static int snd_mixer_oss_open(struct inode *inode, struct file *file) { @@ -872,7 +873,12 @@ static void mixer_slot_clear(snd_mixer_o rslot->number = idx; } -static int snd_mixer_oss_build_input(snd_mixer_oss_t *mixer, struct snd_mixer_oss_assign_table *ptr, int ptr_allocated) +/* + * build an OSS mixer element. + * ptr_allocated means the entry is dynamically allocated (change via proc file). + * when replace_old = 1, the old entry is replaced with the new one. + */ +static int snd_mixer_oss_build_input(snd_mixer_oss_t *mixer, struct snd_mixer_oss_assign_table *ptr, int ptr_allocated, int replace_old) { struct slot slot; struct slot *pslot; @@ -880,6 +886,10 @@ static int snd_mixer_oss_build_input(snd snd_mixer_oss_slot_t *rslot; char str[64]; + /* check if already assigned */ + if (mixer->slots[ptr->oss_id].get_volume && ! replace_old) + return 0; + memset(&slot, 0, sizeof(slot)); if (snd_mixer_oss_build_test(mixer, &slot, ptr->name, ptr->index, SNDRV_MIXER_OSS_ITEM_GLOBAL)) @@ -1084,7 +1094,7 @@ static void snd_mixer_oss_proc_write(snd goto __unlock; } tbl->index = idx; - if (snd_mixer_oss_build_input(mixer, tbl, 1) <= 0) { + if (snd_mixer_oss_build_input(mixer, tbl, 1, 1) <= 0) { kfree(tbl->name); kfree(tbl); } @@ -1127,9 +1137,11 @@ static void snd_mixer_oss_build(snd_mixe { static struct snd_mixer_oss_assign_table table[] = { { SOUND_MIXER_VOLUME, "Master", 0 }, + { SOUND_MIXER_VOLUME, "Front", 0 }, /* fallback */ { SOUND_MIXER_BASS, "Tone Control - Bass", 0 }, { SOUND_MIXER_TREBLE, "Tone Control - Treble", 0 }, { SOUND_MIXER_SYNTH, "Synth", 0 }, + { SOUND_MIXER_SYNTH, "FM", 0 }, /* fallback */ { SOUND_MIXER_PCM, "PCM", 0 }, { SOUND_MIXER_SPEAKER, "PC Speaker", 0 }, { SOUND_MIXER_LINE, "Line", 0 }, @@ -1137,6 +1149,7 @@ static void snd_mixer_oss_build(snd_mixe { SOUND_MIXER_CD, "CD", 0 }, { SOUND_MIXER_IMIX, "Monitor Mix", 0 }, { SOUND_MIXER_ALTPCM, "PCM", 1 }, + { SOUND_MIXER_ALTPCM, "Wave", 0 }, /* fallback */ { SOUND_MIXER_RECLEV, "-- nothing --", 0 }, { SOUND_MIXER_IGAIN, "Capture", 0 }, { SOUND_MIXER_OGAIN, "Playback", 0 }, @@ -1152,15 +1165,10 @@ static void snd_mixer_oss_build(snd_mixe { SOUND_MIXER_RADIO, "Radio", 0 }, { SOUND_MIXER_MONITOR, "Monitor", 0 } }; - static struct snd_mixer_oss_assign_table fm_table = { - SOUND_MIXER_SYNTH, "FM", 0 - }; unsigned int idx; for (idx = 0; idx < sizeof(table) / sizeof(struct snd_mixer_oss_assign_table); idx++) - snd_mixer_oss_build_input(mixer, &table[idx], 0); - if (mixer->slots[SOUND_MIXER_SYNTH].get_volume == NULL) - snd_mixer_oss_build_input(mixer, &fm_table, 0); + snd_mixer_oss_build_input(mixer, &table[idx], 0, 0); if (mixer->mask_recsrc) { mixer->get_recsrc = snd_mixer_oss_get_recsrc2; mixer->put_recsrc = snd_mixer_oss_put_recsrc2; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/core/oss/pcm_oss.c 830-ivtv/sound/core/oss/pcm_oss.c --- 000-virgin/sound/core/oss/pcm_oss.c Mon Nov 17 18:29:43 2003 +++ 830-ivtv/sound/core/oss/pcm_oss.c Thu Jan 8 10:26:59 2004 @@ -56,6 +56,8 @@ MODULE_PARM_SYNTAX(adsp_map, "default:1, MODULE_PARM(nonblock_open, "i"); MODULE_PARM_DESC(nonblock_open, "Don't block opening busy PCM devices."); MODULE_PARM_SYNTAX(nonblock_open, "default:0,skill:advanced"); +MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_PCM); +MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_PCM1); extern int snd_mixer_oss_ioctl_card(snd_card_t *card, unsigned int cmd, unsigned long arg); static int snd_pcm_oss_get_rate(snd_pcm_oss_file_t *pcm_oss_file); @@ -122,11 +124,11 @@ int snd_pcm_plugin_append(snd_pcm_plugin static long snd_pcm_oss_bytes(snd_pcm_substream_t *substream, long frames) { snd_pcm_runtime_t *runtime = substream->runtime; - if (runtime->period_size == runtime->oss.period_bytes) + snd_pcm_uframes_t buffer_size = snd_pcm_lib_buffer_bytes(substream); + frames = frames_to_bytes(runtime, frames); + if (buffer_size == runtime->oss.buffer_bytes) return frames; - if (runtime->period_size < runtime->oss.period_bytes) - return frames * (runtime->oss.period_bytes / runtime->period_size); - return frames / (runtime->period_size / runtime->oss.period_bytes); + return (runtime->oss.buffer_bytes * frames) / buffer_size; } static int snd_pcm_oss_format_from(int format) @@ -451,7 +453,7 @@ static int snd_pcm_oss_change_params(snd sw_params->tstamp_mode = SNDRV_PCM_TSTAMP_NONE; sw_params->period_step = 1; sw_params->sleep_min = 0; - sw_params->avail_min = runtime->period_size; + sw_params->avail_min = 1; sw_params->xfer_align = 1; if (atomic_read(&runtime->mmap_count) || (substream->oss.setup && substream->oss.setup->nosilence)) { @@ -470,7 +472,6 @@ static int snd_pcm_oss_change_params(snd snd_printd("SW_PARAMS failed: %i\n", err); goto failure; } - runtime->control->avail_min = runtime->period_size; runtime->oss.periods = params_periods(sparams); oss_period_size = snd_pcm_plug_client_size(substream, params_period_size(sparams)); @@ -555,6 +556,7 @@ static int snd_pcm_oss_prepare(snd_pcm_s runtime->oss.prepare = 0; runtime->oss.prev_hw_ptr_interrupt = 0; runtime->oss.period_ptr = 0; + runtime->oss.buffer_used = 0; return 0; } @@ -812,9 +814,8 @@ static ssize_t snd_pcm_oss_write1(snd_pc buf += tmp; bytes -= tmp; xfer += tmp; - if (substream->oss.setup == NULL || !substream->oss.setup->wholefrag || - runtime->oss.buffer_used == runtime->oss.period_bytes) { - tmp = snd_pcm_oss_write2(substream, runtime->oss.buffer, runtime->oss.buffer_used, 1); + if (runtime->oss.buffer_used == runtime->oss.period_bytes) { + tmp = snd_pcm_oss_write2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1); if (tmp <= 0) return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; runtime->oss.bytes += tmp; @@ -883,12 +884,13 @@ static ssize_t snd_pcm_oss_read1(snd_pcm if (tmp <= 0) return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; runtime->oss.bytes += tmp; - runtime->oss.buffer_used = runtime->oss.period_bytes; + runtime->oss.period_ptr = tmp; + runtime->oss.buffer_used = tmp; } tmp = bytes; if ((size_t) tmp > runtime->oss.buffer_used) tmp = runtime->oss.buffer_used; - if (copy_to_user(buf, runtime->oss.buffer + (runtime->oss.period_bytes - runtime->oss.buffer_used), tmp)) + if (copy_to_user(buf, runtime->oss.buffer + (runtime->oss.period_ptr - runtime->oss.buffer_used), tmp)) return xfer > 0 ? (snd_pcm_sframes_t)xfer : -EFAULT; buf += tmp; bytes -= tmp; @@ -1425,6 +1427,7 @@ static int snd_pcm_oss_get_ptr(snd_pcm_o snd_pcm_substream_t *substream; snd_pcm_runtime_t *runtime; snd_pcm_sframes_t delay; + int fixup; struct count_info info; int err; @@ -1444,20 +1447,19 @@ static int snd_pcm_oss_get_ptr(snd_pcm_o } if (stream == SNDRV_PCM_STREAM_PLAYBACK) { err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &delay); - if (err == -EPIPE || err == -ESTRPIPE) { + if (err == -EPIPE || err == -ESTRPIPE || (! err && delay < 0)) { err = 0; delay = 0; + fixup = 0; + } else { + fixup = runtime->oss.buffer_used; } } else { err = snd_pcm_oss_capture_position_fixup(substream, &delay); + fixup = -runtime->oss.buffer_used; } if (err < 0) return err; - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - info.bytes = runtime->oss.bytes - snd_pcm_oss_bytes(substream, delay); - } else { - info.bytes = runtime->oss.bytes + snd_pcm_oss_bytes(substream, delay); - } info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size); if (atomic_read(&runtime->mmap_count)) { snd_pcm_sframes_t n; @@ -1468,8 +1470,14 @@ static int snd_pcm_oss_get_ptr(snd_pcm_o runtime->oss.prev_hw_ptr_interrupt = runtime->hw_ptr_interrupt; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) snd_pcm_oss_simulate_fill(substream); + info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr); } else { - info.blocks = delay / runtime->period_size; + delay = snd_pcm_oss_bytes(substream, delay) + fixup; + info.blocks = delay / runtime->oss.period_bytes; + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + info.bytes = runtime->oss.bytes - snd_pcm_oss_bytes(substream, delay); + else + info.bytes = runtime->oss.bytes + snd_pcm_oss_bytes(substream, delay); } if (copy_to_user(_info, &info, sizeof(info))) return -EFAULT; @@ -1481,6 +1489,7 @@ static int snd_pcm_oss_get_space(snd_pcm snd_pcm_substream_t *substream; snd_pcm_runtime_t *runtime; snd_pcm_sframes_t avail; + int fixup; struct audio_buf_info info; int err; @@ -1499,8 +1508,8 @@ static int snd_pcm_oss_get_space(snd_pcm info.fragstotal = runtime->periods; if (runtime->oss.prepare) { if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - info.bytes = runtime->oss.period_bytes * runtime->periods; - info.fragments = runtime->periods; + info.bytes = runtime->oss.period_bytes * runtime->oss.periods; + info.fragments = runtime->oss.periods; } else { info.bytes = 0; info.fragments = 0; @@ -1508,19 +1517,22 @@ static int snd_pcm_oss_get_space(snd_pcm } else { if (stream == SNDRV_PCM_STREAM_PLAYBACK) { err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &avail); - if (err == -EPIPE || err == -ESTRPIPE) { + if (err == -EPIPE || err == -ESTRPIPE || (! err && avail < 0)) { avail = runtime->buffer_size; err = 0; + fixup = 0; } else { avail = runtime->buffer_size - avail; + fixup = -runtime->oss.buffer_used; } } else { err = snd_pcm_oss_capture_position_fixup(substream, &avail); + fixup = runtime->oss.buffer_used; } if (err < 0) return err; - info.bytes = snd_pcm_oss_bytes(substream, avail); - info.fragments = avail / runtime->period_size; + info.bytes = snd_pcm_oss_bytes(substream, avail) + fixup; + info.fragments = info.bytes / runtime->oss.period_bytes; } #ifdef OSS_DEBUG @@ -2160,6 +2172,8 @@ static int snd_pcm_oss_mmap(struct file if (err < 0) return err; runtime->oss.mmap_bytes = area->vm_end - area->vm_start; + runtime->silence_threshold = 0; + runtime->silence_size = 0; #ifdef OSS_DEBUG printk("pcm_oss: mmap ok, bytes = 0x%x\n", runtime->oss.mmap_bytes); #endif @@ -2180,7 +2194,7 @@ static void snd_pcm_oss_proc_read(snd_in snd_pcm_oss_setup_t *setup = pstr->oss.setup_list; down(&pstr->oss.setup_mutex); while (setup) { - snd_iprintf(buffer, "%s %u %u%s%s%s%s%s%s\n", + snd_iprintf(buffer, "%s %u %u%s%s%s%s%s\n", setup->task_name, setup->periods, setup->period_size, @@ -2188,7 +2202,6 @@ static void snd_pcm_oss_proc_read(snd_in setup->direct ? " direct" : "", setup->block ? " block" : "", setup->nonblock ? " non-block" : "", - setup->wholefrag ? " whole-frag" : "", setup->nosilence ? " no-silence" : ""); setup = setup->next; } @@ -2255,8 +2268,6 @@ static void snd_pcm_oss_proc_write(snd_i template.block = 1; } else if (!strcmp(str, "non-block")) { template.nonblock = 1; - } else if (!strcmp(str, "whole-frag")) { - template.wholefrag = 1; } else if (!strcmp(str, "no-silence")) { template.nosilence = 1; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/core/pcm.c 830-ivtv/sound/core/pcm.c --- 000-virgin/sound/core/pcm.c Sat Jun 14 18:37:42 2003 +++ 830-ivtv/sound/core/pcm.c Thu Jan 8 10:26:49 2004 @@ -43,15 +43,6 @@ static int snd_pcm_dev_register(snd_devi static int snd_pcm_dev_disconnect(snd_device_t *device); static int snd_pcm_dev_unregister(snd_device_t *device); -void snd_pcm_lock(int xup) -{ - if (!xup) { - down(®ister_mutex); - } else { - up(®ister_mutex); - } -} - static int snd_pcm_control_ioctl(snd_card_t * card, snd_ctl_file_t * control, unsigned int cmd, unsigned long arg) @@ -380,6 +371,7 @@ static void snd_pcm_substream_proc_statu snd_iprintf(buffer, "closed\n"); return; } + memset(&status, 0, sizeof(status)); err = snd_pcm_status(substream, &status); if (err < 0) { snd_iprintf(buffer, "error %d\n", err); @@ -416,11 +408,7 @@ static int snd_pcm_stream_proc_init(snd_ pstr->proc_root = entry; if ((entry = snd_info_create_card_entry(pcm->card, "info", pstr->proc_root)) != NULL) { - entry->content = SNDRV_INFO_CONTENT_TEXT; - entry->mode = S_IFREG | S_IRUGO; - entry->c.text.read_size = 256; - entry->c.text.read = snd_pcm_stream_proc_info_read; - entry->private_data = pstr; + snd_info_set_text_ops(entry, pstr, 256, snd_pcm_stream_proc_info_read); if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); entry = NULL; @@ -463,11 +451,7 @@ static int snd_pcm_substream_proc_init(s substream->proc_root = entry; if ((entry = snd_info_create_card_entry(card, "info", substream->proc_root)) != NULL) { - entry->content = SNDRV_INFO_CONTENT_TEXT; - entry->mode = S_IFREG | S_IRUGO; - entry->c.text.read_size = 256; - entry->c.text.read = snd_pcm_substream_proc_info_read; - entry->private_data = substream; + snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_info_read); if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); entry = NULL; @@ -476,11 +460,7 @@ static int snd_pcm_substream_proc_init(s substream->proc_info_entry = entry; if ((entry = snd_info_create_card_entry(card, "hw_params", substream->proc_root)) != NULL) { - entry->content = SNDRV_INFO_CONTENT_TEXT; - entry->mode = S_IFREG | S_IRUGO; - entry->c.text.read_size = 256; - entry->c.text.read = snd_pcm_substream_proc_hw_params_read; - entry->private_data = substream; + snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_hw_params_read); if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); entry = NULL; @@ -489,11 +469,7 @@ static int snd_pcm_substream_proc_init(s substream->proc_hw_params_entry = entry; if ((entry = snd_info_create_card_entry(card, "sw_params", substream->proc_root)) != NULL) { - entry->content = SNDRV_INFO_CONTENT_TEXT; - entry->mode = S_IFREG | S_IRUGO; - entry->c.text.read_size = 256; - entry->c.text.read = snd_pcm_substream_proc_sw_params_read; - entry->private_data = substream; + snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_sw_params_read); if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); entry = NULL; @@ -502,11 +478,7 @@ static int snd_pcm_substream_proc_init(s substream->proc_sw_params_entry = entry; if ((entry = snd_info_create_card_entry(card, "status", substream->proc_root)) != NULL) { - entry->content = SNDRV_INFO_CONTENT_TEXT; - entry->mode = S_IFREG | S_IRUGO; - entry->c.text.read_size = 256; - entry->c.text.read = snd_pcm_substream_proc_status_read; - entry->private_data = substream; + snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_status_read); if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); entry = NULL; @@ -521,23 +493,23 @@ static int snd_pcm_substream_proc_done(s { if (substream->proc_info_entry) { snd_info_unregister(substream->proc_info_entry); - substream->proc_info_entry = 0; + substream->proc_info_entry = NULL; } if (substream->proc_hw_params_entry) { snd_info_unregister(substream->proc_hw_params_entry); - substream->proc_hw_params_entry = 0; + substream->proc_hw_params_entry = NULL; } if (substream->proc_sw_params_entry) { snd_info_unregister(substream->proc_sw_params_entry); - substream->proc_sw_params_entry = 0; + substream->proc_sw_params_entry = NULL; } if (substream->proc_status_entry) { snd_info_unregister(substream->proc_status_entry); - substream->proc_status_entry = 0; + substream->proc_status_entry = NULL; } if (substream->proc_root) { snd_info_unregister(substream->proc_root); - substream->proc_root = 0; + substream->proc_root = NULL; } return 0; } @@ -819,7 +791,8 @@ void snd_pcm_release_substream(snd_pcm_s runtime->private_free(runtime); snd_free_pages((void*)runtime->status, PAGE_ALIGN(sizeof(snd_pcm_mmap_status_t))); snd_free_pages((void*)runtime->control, PAGE_ALIGN(sizeof(snd_pcm_mmap_control_t))); - kfree(runtime->hw_constraints.rules); + if (runtime->hw_constraints.rules) + kfree(runtime->hw_constraints.rules); kfree(runtime); substream->runtime = NULL; substream->pstr->substream_opened--; @@ -835,10 +808,10 @@ static int snd_pcm_dev_register(snd_devi snd_pcm_t *pcm = snd_magic_cast(snd_pcm_t, device->device_data, return -ENXIO); snd_assert(pcm != NULL && device != NULL, return -ENXIO); - snd_pcm_lock(0); + down(®ister_mutex); idx = (pcm->card->number * SNDRV_PCM_DEVICES) + pcm->device; if (snd_pcm_devices[idx]) { - snd_pcm_lock(1); + up(®ister_mutex); return -EBUSY; } snd_pcm_devices[idx] = pcm; @@ -860,7 +833,7 @@ static int snd_pcm_dev_register(snd_devi } if ((err = snd_register_device(devtype, pcm->card, pcm->device, pcm->streams[cidx].reg, str)) < 0) { snd_pcm_devices[idx] = NULL; - snd_pcm_lock(1); + up(®ister_mutex); return err; } for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) @@ -871,7 +844,7 @@ static int snd_pcm_dev_register(snd_devi notify = list_entry(list, snd_pcm_notify_t, list); notify->n_register(pcm); } - snd_pcm_lock(1); + up(®ister_mutex); return 0; } @@ -881,7 +854,7 @@ static int snd_pcm_dev_disconnect(snd_de struct list_head *list; int idx; - snd_pcm_lock(0); + down(®ister_mutex); idx = (pcm->card->number * SNDRV_PCM_DEVICES) + pcm->device; snd_pcm_devices[idx] = NULL; list_for_each(list, &snd_pcm_notify_list) { @@ -889,7 +862,7 @@ static int snd_pcm_dev_disconnect(snd_de notify = list_entry(list, snd_pcm_notify_t, list); notify->n_disconnect(pcm); } - snd_pcm_lock(1); + up(®ister_mutex); return 0; } @@ -901,7 +874,7 @@ static int snd_pcm_dev_unregister(snd_de snd_pcm_t *pcm = snd_magic_cast(snd_pcm_t, device->device_data, return -ENXIO); snd_assert(pcm != NULL, return -ENXIO); - snd_pcm_lock(0); + down(®ister_mutex); idx = (pcm->card->number * SNDRV_PCM_DEVICES) + pcm->device; snd_pcm_devices[idx] = NULL; for (cidx = 0; cidx < 2; cidx++) { @@ -923,7 +896,7 @@ static int snd_pcm_dev_unregister(snd_de notify = list_entry(list, snd_pcm_notify_t, list); notify->n_unregister(pcm); } - snd_pcm_lock(1); + up(®ister_mutex); return snd_pcm_free(pcm); } @@ -932,7 +905,7 @@ int snd_pcm_notify(snd_pcm_notify_t *not int idx; snd_assert(notify != NULL && notify->n_register != NULL && notify->n_unregister != NULL, return -EINVAL); - snd_pcm_lock(0); + down(®ister_mutex); if (nfree) { list_del(¬ify->list); for (idx = 0; idx < SNDRV_CARDS * SNDRV_PCM_DEVICES; idx++) { @@ -948,7 +921,7 @@ int snd_pcm_notify(snd_pcm_notify_t *not notify->n_register(snd_pcm_devices[idx]); } } - snd_pcm_lock(1); + up(®ister_mutex); return 0; } @@ -989,9 +962,7 @@ static int __init alsa_pcm_init(void) snd_ctl_register_ioctl(snd_pcm_control_ioctl); if ((entry = snd_info_create_module_entry(THIS_MODULE, "pcm", NULL)) != NULL) { - entry->content = SNDRV_INFO_CONTENT_TEXT; - entry->c.text.read_size = SNDRV_CARDS * SNDRV_PCM_DEVICES * 128; - entry->c.text.read = snd_pcm_proc_read; + snd_info_set_text_ops(entry, NULL, SNDRV_CARDS * SNDRV_PCM_DEVICES * 128, snd_pcm_proc_read); if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); entry = NULL; @@ -1013,7 +984,6 @@ static void __exit alsa_pcm_exit(void) module_init(alsa_pcm_init) module_exit(alsa_pcm_exit) -EXPORT_SYMBOL(snd_pcm_lock); EXPORT_SYMBOL(snd_pcm_devices); EXPORT_SYMBOL(snd_pcm_new); EXPORT_SYMBOL(snd_pcm_new_stream); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/core/pcm_lib.c 830-ivtv/sound/core/pcm_lib.c --- 000-virgin/sound/core/pcm_lib.c Mon Nov 17 18:29:43 2003 +++ 830-ivtv/sound/core/pcm_lib.c Thu Jan 8 10:26:49 2004 @@ -125,15 +125,11 @@ void snd_pcm_playback_silence(snd_pcm_su } } -static inline int snd_pcm_update_hw_ptr_interrupt(snd_pcm_substream_t *substream) +static inline snd_pcm_uframes_t snd_pcm_update_hw_ptr_pos(snd_pcm_substream_t *substream, + snd_pcm_runtime_t *runtime) { - snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_uframes_t pos; - snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_ptr_interrupt; - snd_pcm_uframes_t avail; - snd_pcm_sframes_t delta; - old_hw_ptr = runtime->status->hw_ptr; pos = substream->ops->pointer(substream); if (runtime->tstamp_mode & SNDRV_PCM_TSTAMP_MMAP) snd_timestamp_now((snd_timestamp_t*)&runtime->status->tstamp, runtime->tstamp_timespec); @@ -143,18 +139,55 @@ static inline int snd_pcm_update_hw_ptr_ } else #endif snd_runtime_check(pos < runtime->buffer_size, return 0); - pos -= pos % runtime->min_align; - new_hw_ptr = runtime->hw_ptr_base + pos; + return pos; +} + +static inline int snd_pcm_update_hw_ptr_post(snd_pcm_substream_t *substream, + snd_pcm_runtime_t *runtime) +{ + snd_pcm_uframes_t avail; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + avail = snd_pcm_playback_avail(runtime); + else + avail = snd_pcm_capture_avail(runtime); + if (avail > runtime->avail_max) + runtime->avail_max = avail; + if (avail >= runtime->stop_threshold) { + snd_pcm_stop(substream, + runtime->status->state == SNDRV_PCM_STATE_DRAINING ? + SNDRV_PCM_STATE_SETUP : SNDRV_PCM_STATE_XRUN); + return -EPIPE; + } + if (avail >= runtime->control->avail_min) + wake_up(&runtime->sleep); + return 0; +} + +static inline int snd_pcm_update_hw_ptr_interrupt(snd_pcm_substream_t *substream) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + snd_pcm_uframes_t pos; + snd_pcm_uframes_t new_hw_ptr, hw_ptr_interrupt; + snd_pcm_sframes_t delta; + + pos = snd_pcm_update_hw_ptr_pos(substream, runtime); + if (runtime->period_size == runtime->buffer_size) + goto __next_buf; + new_hw_ptr = runtime->hw_ptr_base + pos; hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size; delta = hw_ptr_interrupt - new_hw_ptr; if (delta > 0) { if ((snd_pcm_uframes_t)delta < runtime->buffer_size / 2) { - snd_printd("Unexpected hw_pointer value (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2); +#ifdef CONFIG_SND_DEBUG + if (runtime->periods > 1) + snd_printd(KERN_ERR "Unexpected hw_pointer value [1] (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2); +#endif return 0; } + __next_buf: runtime->hw_ptr_base += runtime->buffer_size; if (runtime->hw_ptr_base == runtime->boundary) runtime->hw_ptr_base = 0; @@ -168,21 +201,7 @@ static inline int snd_pcm_update_hw_ptr_ runtime->status->hw_ptr = new_hw_ptr; runtime->hw_ptr_interrupt = new_hw_ptr - new_hw_ptr % runtime->period_size; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - avail = snd_pcm_playback_avail(runtime); - else - avail = snd_pcm_capture_avail(runtime); - if (avail > runtime->avail_max) - runtime->avail_max = avail; - if (avail >= runtime->stop_threshold) { - snd_pcm_stop(substream, - runtime->status->state == SNDRV_PCM_STATE_DRAINING ? - SNDRV_PCM_STATE_SETUP : SNDRV_PCM_STATE_XRUN); - return -EPIPE; - } - if (avail >= runtime->control->avail_min) - wake_up(&runtime->sleep); - return 0; + return snd_pcm_update_hw_ptr_post(substream, runtime); } /* CAUTION: call it with irq disabled */ @@ -191,27 +210,19 @@ int snd_pcm_update_hw_ptr(snd_pcm_substr snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_uframes_t pos; snd_pcm_uframes_t old_hw_ptr, new_hw_ptr; - snd_pcm_uframes_t avail; snd_pcm_sframes_t delta; old_hw_ptr = runtime->status->hw_ptr; - pos = substream->ops->pointer(substream); - if (runtime->tstamp_mode & SNDRV_PCM_TSTAMP_MMAP) - snd_timestamp_now((snd_timestamp_t*)&runtime->status->tstamp, runtime->tstamp_timespec); -#ifdef CONFIG_SND_DEBUG - if (pos >= runtime->buffer_size) { - snd_printk(KERN_ERR "BUG: stream = %i, pos = 0x%lx, buffer size = 0x%lx, period size = 0x%lx\n", substream->stream, pos, runtime->buffer_size, runtime->period_size); - } else -#endif - snd_runtime_check(pos < runtime->buffer_size, return 0); - - pos -= pos % runtime->min_align; + pos = snd_pcm_update_hw_ptr_pos(substream, runtime); new_hw_ptr = runtime->hw_ptr_base + pos; delta = old_hw_ptr - new_hw_ptr; if (delta > 0) { if ((snd_pcm_uframes_t)delta < runtime->buffer_size / 2) { - snd_printd("Unexpected hw_pointer value (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2); +#ifdef CONFIG_SND_DEBUG + if (runtime->periods > 2) + snd_printd(KERN_ERR "Unexpected hw_pointer value [2] (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2); +#endif return 0; } runtime->hw_ptr_base += runtime->buffer_size; @@ -222,23 +233,10 @@ int snd_pcm_update_hw_ptr(snd_pcm_substr if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) snd_pcm_playback_silence(substream, new_hw_ptr); + runtime->status->hw_ptr = new_hw_ptr; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - avail = snd_pcm_playback_avail(runtime); - else - avail = snd_pcm_capture_avail(runtime); - if (avail > runtime->avail_max) - runtime->avail_max = avail; - if (avail >= runtime->stop_threshold) { - snd_pcm_stop(substream, - runtime->status->state == SNDRV_PCM_STATE_DRAINING ? - SNDRV_PCM_STATE_SETUP : SNDRV_PCM_STATE_XRUN); - return -EPIPE; - } - if (avail >= runtime->control->avail_min) - wake_up(&runtime->sleep); - return 0; + return snd_pcm_update_hw_ptr_post(substream, runtime); } /** diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/core/pcm_native.c 830-ivtv/sound/core/pcm_native.c --- 000-virgin/sound/core/pcm_native.c Thu Jan 8 08:35:58 2004 +++ 830-ivtv/sound/core/pcm_native.c Thu Jan 8 10:26:49 2004 @@ -620,7 +620,7 @@ struct action_ops { */ static int snd_pcm_action_group(struct action_ops *ops, snd_pcm_substream_t *substream, - int state) + int state, int atomic_only) { struct list_head *pos; snd_pcm_substream_t *s = NULL; @@ -628,6 +628,8 @@ static int snd_pcm_action_group(struct a snd_pcm_group_for_each(pos, substream) { s = snd_pcm_group_substream_entry(pos); + if (atomic_only && (s->pcm->info_flags & SNDRV_PCM_INFO_NONATOMIC_OPS)) + continue; if (s != substream) spin_lock(&s->self_group.lock); res = ops->pre_action(s, state); @@ -637,6 +639,8 @@ static int snd_pcm_action_group(struct a if (res >= 0) { snd_pcm_group_for_each(pos, substream) { s = snd_pcm_group_substream_entry(pos); + if (atomic_only && (s->pcm->info_flags & SNDRV_PCM_INFO_NONATOMIC_OPS)) + continue; err = ops->do_action(s, state); if (err < 0) { if (res == 0) @@ -652,7 +656,9 @@ static int snd_pcm_action_group(struct a /* unlock all streams */ snd_pcm_group_for_each(pos, substream) { s1 = snd_pcm_group_substream_entry(pos); - if (s1 != substream) + if (atomic_only && (s1->pcm->info_flags & SNDRV_PCM_INFO_NONATOMIC_OPS)) + ; + else if (s1 != substream) spin_unlock(&s1->self_group.lock); if (s1 == s) /* end */ break; @@ -682,6 +688,8 @@ static int snd_pcm_action_single(struct /* * Note: call with stream lock + * + * NB2: this won't handle the non-atomic callbacks */ static int snd_pcm_action(struct action_ops *ops, snd_pcm_substream_t *substream, @@ -695,7 +703,7 @@ static int snd_pcm_action(struct action_ spin_lock(&substream->group->lock); spin_lock(&substream->self_group.lock); } - res = snd_pcm_action_group(ops, substream, state); + res = snd_pcm_action_group(ops, substream, state, 0); spin_unlock(&substream->group->lock); } else { res = snd_pcm_action_single(ops, substream, state); @@ -705,10 +713,14 @@ static int snd_pcm_action(struct action_ /* * Note: don't use any locks before + * + * NB2: this can handle the non-atomic callbacks if allow_nonatomic = 1 + * when the pcm->info_flags has NONATOMIC_OPS bit, it's handled + * ouside the lock to allow sleep in the callback. */ static int snd_pcm_action_lock_irq(struct action_ops *ops, snd_pcm_substream_t *substream, - int state) + int state, int allow_nonatomic) { int res; @@ -716,10 +728,43 @@ static int snd_pcm_action_lock_irq(struc if (snd_pcm_stream_linked(substream)) { spin_lock(&substream->group->lock); spin_lock(&substream->self_group.lock); - res = snd_pcm_action_group(ops, substream, state); + res = snd_pcm_action_group(ops, substream, state, allow_nonatomic); spin_unlock(&substream->self_group.lock); spin_unlock(&substream->group->lock); + if (res >= 0 && allow_nonatomic) { + /* now process the non-atomic substreams separately + * outside the lock + */ +#define MAX_LINKED_STREAMS 16 /* FIXME: should be variable */ + + struct list_head *pos; + int i, num_s = 0; + snd_pcm_substream_t *s; + snd_pcm_substream_t *subs[MAX_LINKED_STREAMS]; + snd_pcm_group_for_each(pos, substream) { + if (num_s >= MAX_LINKED_STREAMS) { + res = -ENOMEM; + num_s = 0; /* don't proceed */ + break; + } + s = snd_pcm_group_substream_entry(pos); + if (s->pcm->info_flags & SNDRV_PCM_INFO_NONATOMIC_OPS) + subs[num_s++] = s; + } + if (num_s > 0) { + read_unlock_irq(&snd_pcm_link_rwlock); + for (i = 0; i < num_s && res >= 0; i++) + res = snd_pcm_action_single(ops, subs[i], state); + return res; + } + } } else { + if (allow_nonatomic && + (substream->pcm->info_flags & SNDRV_PCM_INFO_NONATOMIC_OPS)) { + read_unlock_irq(&snd_pcm_link_rwlock); + /* process outside the lock */ + return snd_pcm_action_single(ops, substream, state); + } spin_lock(&substream->self_group.lock); res = snd_pcm_action_single(ops, substream, state); spin_unlock(&substream->self_group.lock); @@ -888,7 +933,8 @@ static int snd_pcm_do_suspend(snd_pcm_su snd_pcm_runtime_t *runtime = substream->runtime; if (runtime->trigger_master != substream) return 0; - if (runtime->status->suspended_state != SNDRV_PCM_STATE_RUNNING) + if (runtime->status->suspended_state != SNDRV_PCM_STATE_RUNNING && + runtime->status->suspended_state != SNDRV_PCM_STATE_DRAINING) return 0; return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_SUSPEND); } @@ -962,7 +1008,8 @@ static int snd_pcm_do_resume(snd_pcm_sub snd_pcm_runtime_t *runtime = substream->runtime; if (runtime->trigger_master != substream) return 0; - if (runtime->status->suspended_state != SNDRV_PCM_STATE_RUNNING) + if (runtime->status->suspended_state != SNDRV_PCM_STATE_RUNNING && + runtime->status->suspended_state != SNDRV_PCM_STATE_DRAINING) return 0; return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_RESUME); } @@ -991,7 +1038,7 @@ static int snd_pcm_resume(snd_pcm_substr snd_power_lock(card); if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile)) >= 0) - return snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0); + return snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0, 0); snd_power_unlock(card); return res; } @@ -1081,7 +1128,7 @@ static struct action_ops snd_pcm_action_ static int snd_pcm_reset(snd_pcm_substream_t *substream) { - return snd_pcm_action_lock_irq(&snd_pcm_action_reset, substream, 0); + return snd_pcm_action_lock_irq(&snd_pcm_action_reset, substream, 0, 0); } static int snd_pcm_pre_prepare(snd_pcm_substream_t * substream, int state) @@ -1129,7 +1176,7 @@ int snd_pcm_prepare(snd_pcm_substream_t snd_power_lock(card); if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile)) >= 0) - res = snd_pcm_action_lock_irq(&snd_pcm_action_prepare, substream, 0); + res = snd_pcm_action_lock_irq(&snd_pcm_action_prepare, substream, 0, 1); /* allow sleep if specified */ snd_power_unlock(card); return res; } @@ -1243,7 +1290,9 @@ static int snd_pcm_playback_drain(snd_pc } set_current_state(TASK_INTERRUPTIBLE); snd_pcm_stream_unlock_irq(substream); + snd_power_unlock(card); tout = schedule_timeout(10 * HZ); + snd_power_lock(card); snd_pcm_stream_lock_irq(substream); if (tout == 0) { state = runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ? SUSPENDED : EXPIRED; @@ -2326,7 +2375,7 @@ static int snd_pcm_common_ioctl1(snd_pcm case SNDRV_PCM_IOCTL_RESET: return snd_pcm_reset(substream); case SNDRV_PCM_IOCTL_START: - return snd_pcm_action(&snd_pcm_action_start, substream, 0); + return snd_pcm_action_lock_irq(&snd_pcm_action_start, substream, 0, 0); case SNDRV_PCM_IOCTL_LINK: return snd_pcm_link(substream, (long) arg); case SNDRV_PCM_IOCTL_UNLINK: diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/core/rawmidi.c 830-ivtv/sound/core/rawmidi.c --- 000-virgin/sound/core/rawmidi.c Mon Nov 17 18:29:43 2003 +++ 830-ivtv/sound/core/rawmidi.c Thu Jan 8 10:26:49 2004 @@ -1507,7 +1507,6 @@ static int snd_rawmidi_dev_register(snd_ sprintf(name, "midi%d", rmidi->device); entry = snd_info_create_card_entry(rmidi->card, name, rmidi->card->proc_root); if (entry) { - entry->content = SNDRV_INFO_CONTENT_TEXT; entry->private_data = rmidi; entry->c.text.read_size = 1024; entry->c.text.read = snd_rawmidi_proc_info_read; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/core/seq/oss/seq_oss.c 830-ivtv/sound/core/seq/oss/seq_oss.c --- 000-virgin/sound/core/seq/oss/seq_oss.c Mon Nov 17 18:28:22 2003 +++ 830-ivtv/sound/core/seq/oss/seq_oss.c Thu Jan 8 10:26:49 2004 @@ -35,6 +35,9 @@ MODULE_AUTHOR("Takashi Iwai fs->root) { client_requested[clientid] = 1; for (idx = 0; idx < 64; idx++) { if (seq_client_load[idx] < 0) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/core/seq/seq_device.c 830-ivtv/sound/core/seq/seq_device.c --- 000-virgin/sound/core/seq/seq_device.c Fri May 30 19:02:28 2003 +++ 830-ivtv/sound/core/seq/seq_device.c Thu Jan 8 10:26:49 2004 @@ -132,6 +132,9 @@ void snd_seq_device_load_drivers(void) #ifdef CONFIG_KMOD struct list_head *head; + if (! current->fs->root) + return; + down(&ops_mutex); list_for_each(head, &opslist) { ops_list_t *ops = list_entry(head, ops_list_t, list); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/core/seq/seq_timer.c 830-ivtv/sound/core/seq/seq_timer.c --- 000-virgin/sound/core/seq/seq_timer.c Wed Mar 26 22:54:40 2003 +++ 830-ivtv/sound/core/seq/seq_timer.c Thu Jan 8 10:26:50 2004 @@ -335,7 +335,7 @@ static int initialize_timer(seq_timer_t if (! r && t->hw.c_resolution) r = t->hw.c_resolution(t); if (r) { - tmr->ticks = (unsigned int)(tmr->preferred_resolution / r); + tmr->ticks = (unsigned int)(1000000000uL / (r * tmr->preferred_resolution)); if (! tmr->ticks) tmr->ticks = 1; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/core/seq/seq_timer.h 830-ivtv/sound/core/seq/seq_timer.h --- 000-virgin/sound/core/seq/seq_timer.h Thu Feb 13 11:08:16 2003 +++ 830-ivtv/sound/core/seq/seq_timer.h Thu Jan 8 10:26:50 2004 @@ -47,7 +47,7 @@ typedef struct { snd_timer_id_t alsa_id; /* ALSA's timer ID */ snd_timer_instance_t *timeri; /* timer instance */ unsigned int ticks; - unsigned long preferred_resolution; /* timer resolution */ + unsigned long preferred_resolution; /* timer resolution, ticks/sec */ unsigned int skew; unsigned int skew_base; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/core/sound.c 830-ivtv/sound/core/sound.c --- 000-virgin/sound/core/sound.c Thu Jan 8 08:35:58 2004 +++ 830-ivtv/sound/core/sound.c Thu Jan 8 10:26:50 2004 @@ -37,7 +37,7 @@ static int major = CONFIG_SND_MAJOR; int snd_major; -static int cards_limit = SNDRV_CARDS; +static int cards_limit = 1; #ifdef CONFIG_DEVFS_FS static int device_mode = S_IFCHR | S_IRUGO | S_IWUGO; #endif @@ -51,7 +51,7 @@ MODULE_PARM(major, "i"); MODULE_PARM_DESC(major, "Major # for sound driver."); MODULE_PARM_SYNTAX(major, "default:116,skill:devel"); MODULE_PARM(cards_limit, "i"); -MODULE_PARM_DESC(cards_limit, "Count of soundcards installed in the system."); +MODULE_PARM_DESC(cards_limit, "Count of auto-loadable soundcards."); MODULE_PARM_SYNTAX(cards_limit, "default:8,skill:advanced"); MODULE_ALIAS_CHARDEV_MAJOR(CONFIG_SND_MAJOR); #ifdef CONFIG_DEVFS_FS @@ -59,7 +59,12 @@ MODULE_PARM(device_mode, "i"); MODULE_PARM_DESC(device_mode, "Device file permission mask for devfs."); MODULE_PARM_SYNTAX(device_mode, "default:0666,base:8"); #endif +MODULE_ALIAS_CHARDEV_MAJOR(CONFIG_SND_MAJOR); +/* this one holds the actual max. card number currently available. + * as default, it's identical with cards_limit option. when more + * modules are loaded manually, this limit number increases, too. + */ int snd_ecards_limit; static struct list_head snd_minors_hash[SNDRV_CARDS]; @@ -79,6 +84,8 @@ void snd_request_card(int card) { int locked; + if (! current->fs->root) + return; read_lock(&snd_card_rwlock); locked = snd_cards_lock & (1 << card); read_unlock(&snd_card_rwlock); @@ -93,6 +100,8 @@ static void snd_request_other(int minor) { char *str; + if (! current->fs->root) + return; switch (minor) { case SNDRV_MINOR_SEQUENCER: str = "snd-seq"; break; case SNDRV_MINOR_TIMER: str = "snd-timer"; break; @@ -222,7 +231,7 @@ int snd_register_device(int type, snd_ca } list_add_tail(&preg->list, &snd_minors_hash[SNDRV_MINOR_CARD(minor)]); #ifdef CONFIG_DEVFS_FS - if (strncmp(name, "controlC", 8)) /* created in sound.c */ + if (strncmp(name, "controlC", 8) || card->number >= cards_limit) devfs_mk_cdev(MKDEV(major, minor), S_IFCHR | device_mode, "snd/%s", name); #endif up(&sound_mutex); @@ -255,6 +264,8 @@ int snd_unregister_device(int type, snd_ #ifdef CONFIG_DEVFS_FS if (strncmp(mptr->name, "controlC", 8)) /* created in sound.c */ devfs_remove("snd/%s", mptr->name); + else if (card->number >= cards_limit) + devfs_remove("snd/%s", mptr->name); /* manualy created */ #endif list_del(&mptr->list); up(&sound_mutex); @@ -297,7 +308,6 @@ int __init snd_minor_info_init(void) entry = snd_info_create_module_entry(THIS_MODULE, "devices", NULL); if (entry) { - entry->content = SNDRV_INFO_CONTENT_TEXT; entry->c.text.read_size = PAGE_SIZE; entry->c.text.read = snd_minor_info_read; if (snd_info_register(entry) < 0) { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/core/sound_oss.c 830-ivtv/sound/core/sound_oss.c --- 000-virgin/sound/core/sound_oss.c Wed Aug 13 20:24:36 2003 +++ 830-ivtv/sound/core/sound_oss.c Thu Jan 8 10:26:50 2004 @@ -217,7 +217,6 @@ int __init snd_minor_info_oss_init(void) entry = snd_info_create_module_entry(THIS_MODULE, "devices", snd_oss_root); if (entry) { - entry->content = SNDRV_INFO_CONTENT_TEXT; entry->c.text.read_size = PAGE_SIZE; entry->c.text.read = snd_minor_info_oss_read; if (snd_info_register(entry) < 0) { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/core/timer.c 830-ivtv/sound/core/timer.c --- 000-virgin/sound/core/timer.c Mon Nov 17 18:29:43 2003 +++ 830-ivtv/sound/core/timer.c Thu Jan 8 10:26:50 2004 @@ -148,6 +148,8 @@ static snd_timer_t *snd_timer_find(snd_t static void snd_timer_request(snd_timer_id_t *tid) { + if (! current->fs->root) + return; switch (tid->dev_class) { case SNDRV_TIMER_CLASS_GLOBAL: if (tid->device < timer_limit) @@ -304,14 +306,31 @@ int snd_timer_close(snd_timer_instance_t snd_assert(timeri != NULL, return -ENXIO); - snd_timer_stop(timeri); /* force to stop the timer */ + /* force to stop the timer */ + snd_timer_stop(timeri); if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { + /* wait, until the active callback is finished */ + spin_lock_irq(&slave_active_lock); + while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) { + spin_unlock_irq(&slave_active_lock); + udelay(10); + spin_lock_irq(&slave_active_lock); + } + spin_unlock_irq(&slave_active_lock); down(®ister_mutex); list_del(&timeri->open_list); up(®ister_mutex); } else { timer = timeri->timer; + /* wait, until the active callback is finished */ + spin_lock_irq(&timer->lock); + while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) { + spin_unlock_irq(&timer->lock); + udelay(10); + spin_lock_irq(&timer->lock); + } + spin_unlock_irq(&timer->lock); down(®ister_mutex); list_del(&timeri->open_list); if (timer && list_empty(&timer->open_list_head) && timer->hw.close) @@ -389,12 +408,15 @@ static int snd_timer_start1(snd_timer_t list_del(&timeri->active_list); list_add_tail(&timeri->active_list, &timer->active_list_head); if (timer->running) { + if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) + goto __start_now; timer->flags |= SNDRV_TIMER_FLG_RESCHED; timeri->flags |= SNDRV_TIMER_IFLG_START; return 1; /* delayed start */ } else { timer->sticks = sticks; timer->hw.start(timer); + __start_now: timer->running++; timeri->flags |= SNDRV_TIMER_IFLG_RUNNING; return 0; @@ -448,22 +470,21 @@ static int _snd_timer_stop(snd_timer_ins snd_assert(timeri != NULL, return -ENXIO); + if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { + if (!keep_flag) { + spin_lock_irqsave(&slave_active_lock, flags); + timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; + spin_unlock_irqrestore(&slave_active_lock, flags); + } + goto __end; + } timer = timeri->timer; - if (! timer) + if (!timer) return -EINVAL; spin_lock_irqsave(&timer->lock, flags); list_del_init(&timeri->ack_list); -#if 0 /* FIXME: this causes dead lock with the sequencer timer */ - /* wait until the callback is finished */ - while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) { - spin_unlock_irqrestore(&timer->lock, flags); - udelay(10); - spin_lock_irqsave(&timer->lock, flags); - } -#endif list_del_init(&timeri->active_list); if ((timeri->flags & SNDRV_TIMER_IFLG_RUNNING) && - !(timeri->flags & SNDRV_TIMER_IFLG_SLAVE) && !(--timer->running)) { timer->hw.stop(timer); if (timer->flags & SNDRV_TIMER_FLG_RESCHED) { @@ -478,6 +499,7 @@ static int _snd_timer_stop(snd_timer_ins if (!keep_flag) timeri->flags &= ~(SNDRV_TIMER_IFLG_RUNNING|SNDRV_TIMER_IFLG_START); spin_unlock_irqrestore(&timer->lock, flags); + __end: if (event != SNDRV_TIMER_EVENT_RESOLUTION) snd_timer_notify1(timeri, event); return 0; @@ -1381,8 +1403,8 @@ static int snd_timer_user_gstatus(struct if (t->hw.precise_resolution) { t->hw.precise_resolution(t, &gstatus.resolution_num, &gstatus.resolution_den); } else { - gstatus.resolution_num = 1; - gstatus.resolution_den = gstatus.resolution; + gstatus.resolution_num = gstatus.resolution; + gstatus.resolution_den = 1000000000uL; } } else { err = -ENODEV; @@ -1684,20 +1706,20 @@ static ssize_t snd_timer_user_read(struc break; } } - if (err < 0) - break; spin_unlock_irq(&tu->qlock); + if (err < 0) + goto _error; if (tu->tread) { if (copy_to_user(buffer, &tu->tqueue[tu->qhead++], sizeof(snd_timer_tread_t))) { err = -EFAULT; - break; + goto _error; } } else { if (copy_to_user(buffer, &tu->queue[tu->qhead++], sizeof(snd_timer_read_t))) { err = -EFAULT; - break; + goto _error; } } @@ -1710,6 +1732,7 @@ static ssize_t snd_timer_user_read(struc tu->qused--; } spin_unlock_irq(&tu->qlock); + _error: return result > 0 ? result : err; } @@ -1761,7 +1784,6 @@ static int __init alsa_timer_init(void) snd_oss_info_register(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1, "system timer"); #endif if ((entry = snd_info_create_module_entry(THIS_MODULE, "timers", NULL)) != NULL) { - entry->content = SNDRV_INFO_CONTENT_TEXT; entry->c.text.read_size = SNDRV_TIMER_DEVICES * 128; entry->c.text.read = snd_timer_proc_read; if (snd_info_register(entry) < 0) { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/drivers/mpu401/mpu401.c 830-ivtv/sound/drivers/mpu401/mpu401.c --- 000-virgin/sound/drivers/mpu401/mpu401.c Thu Feb 13 11:08:16 2003 +++ 830-ivtv/sound/drivers/mpu401/mpu401.c Thu Jan 8 10:26:50 2004 @@ -157,7 +157,7 @@ static int __init alsa_card_mpu401_setup #ifdef CONFIG_X86_PC9800 get_option(&str,&pc98ii[nr_dev]) == 2 && #endif - get_option(&str,(int *)&port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2); nr_dev++; return 1; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/drivers/mtpav.c 830-ivtv/sound/drivers/mtpav.c --- 000-virgin/sound/drivers/mtpav.c Sat May 10 18:35:07 2003 +++ 830-ivtv/sound/drivers/mtpav.c Thu Jan 8 10:26:50 2004 @@ -813,7 +813,7 @@ static int __init alsa_card_mtpav_setup( (void)(get_option(&str,&enable) == 2 && get_option(&str,&index) == 2 && get_id(&str,&id) == 2 && - get_option(&str,(int *)&port) == 2 && + get_option_long(&str,&port) == 2 && get_option(&str,&irq) == 2 && get_option(&str,&hwports) == 2); return 1; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/drivers/opl3/opl3_synth.c 830-ivtv/sound/drivers/opl3/opl3_synth.c --- 000-virgin/sound/drivers/opl3/opl3_synth.c Sun Apr 20 19:35:09 2003 +++ 830-ivtv/sound/drivers/opl3/opl3_synth.c Thu Jan 8 10:26:50 2004 @@ -20,7 +20,6 @@ */ #include -#define __SND_OSS_COMPAT__ #include /* diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/drivers/opl4/opl4_proc.c 830-ivtv/sound/drivers/opl4/opl4_proc.c --- 000-virgin/sound/drivers/opl4/opl4_proc.c Sat Jun 14 18:37:42 2003 +++ 830-ivtv/sound/drivers/opl4/opl4_proc.c Thu Jan 8 10:26:50 2004 @@ -18,6 +18,7 @@ */ #include "opl4_local.h" +#include #include #ifdef CONFIG_PROC_FS @@ -59,15 +60,15 @@ static long snd_opl4_mem_proc_read(snd_i if (file->f_pos + size > entry->size) size = entry->size - file->f_pos; if (size > 0) { - buf = kmalloc(size, GFP_KERNEL); + buf = vmalloc(size); if (!buf) return -ENOMEM; snd_opl4_read_memory(opl4, buf, file->f_pos, size); if (copy_to_user(_buf, buf, size)) { - kfree(buf); + vfree(buf); return -EFAULT; } - kfree(buf); + vfree(buf); file->f_pos += size; return size; } @@ -85,15 +86,15 @@ static long snd_opl4_mem_proc_write(snd_ if (file->f_pos + size > entry->size) size = entry->size - file->f_pos; if (size > 0) { - buf = kmalloc(size, GFP_KERNEL); + buf = vmalloc(size); if (!buf) return -ENOMEM; if (copy_from_user(buf, _buf, size)) { - kfree(buf); + vfree(buf); return -EFAULT; } snd_opl4_write_memory(opl4, buf, file->f_pos, size); - kfree(buf); + vfree(buf); file->f_pos += size; return size; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/drivers/serial-u16550.c 830-ivtv/sound/drivers/serial-u16550.c --- 000-virgin/sound/drivers/serial-u16550.c Sat May 10 18:35:07 2003 +++ 830-ivtv/sound/drivers/serial-u16550.c Thu Jan 8 10:26:50 2004 @@ -63,6 +63,9 @@ static char *adaptor_names[] = { "Generic" }; +#define SNDRV_SERIAL_NORMALBUFF 0 /* Normal blocking buffer operation */ +#define SNDRV_SERIAL_DROPBUFF 1 /* Non-blocking discard operation */ + static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ @@ -73,6 +76,7 @@ static int base[SNDRV_CARDS] = {[0 ... ( static int outs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; /* 1 to 16 */ static int ins[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; /* 1 to 16 */ static int adaptor[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = SNDRV_SERIAL_SOUNDCANVAS}; +static int droponfull[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS -1)] = SNDRV_SERIAL_NORMALBUFF }; MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(index, "Index value for Serial MIDI."); @@ -99,6 +103,9 @@ MODULE_PARM(outs, "1-" __MODULE_STRING(S MODULE_PARM_DESC(outs, "Number of MIDI outputs."); MODULE_PARM(ins, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(ins, "Number of MIDI inputs."); +MODULE_PARM(droponfull, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(droponfull, "Flag to enable drop-on-full buffer mode"); +MODULE_PARM_SYNTAX(droponfull, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); MODULE_PARM_SYNTAX(outs, SNDRV_ENABLED ",allows:{{1,16}},dialog:list"); MODULE_PARM_SYNTAX(ins, SNDRV_ENABLED ",allows:{{1,16}},dialog:list"); @@ -163,6 +170,7 @@ typedef struct _snd_uart16550 { int buff_in_count; int buff_in; int buff_out; + int drop_on_full; // wait timer unsigned int timer_running:1; @@ -194,12 +202,14 @@ inline static void snd_uart16550_del_tim inline static void snd_uart16550_buffer_output(snd_uart16550_t *uart) { unsigned short buff_out = uart->buff_out; - outb(uart->tx_buff[buff_out], uart->base + UART_TX); - uart->fifo_count++; - buff_out++; - buff_out &= TX_BUFF_MASK; - uart->buff_out = buff_out; - uart->buff_in_count--; + if( uart->buff_in_count > 0 ) { + outb(uart->tx_buff[buff_out], uart->base + UART_TX); + uart->fifo_count++; + buff_out++; + buff_out &= TX_BUFF_MASK; + uart->buff_out = buff_out; + uart->buff_in_count--; + } } /* This loop should be called with interrupts disabled @@ -257,9 +267,11 @@ static void snd_uart16550_io_loop(snd_ua || uart->adaptor == SNDRV_SERIAL_GENERIC) { /* Can't use FIFO, must send only when CTS is true */ status = inb(uart->base + UART_MSR); - if (uart->fifo_count == 0 && (status & UART_MSR_CTS) - && uart->buff_in_count > 0) - snd_uart16550_buffer_output(uart); + while( (uart->fifo_count == 0) && (status & UART_MSR_CTS) && + (uart->buff_in_count > 0) ) { + snd_uart16550_buffer_output(uart); + status = inb( uart->base + UART_MSR ); + } } else { /* Write loop */ while (uart->fifo_count < uart->fifo_limit /* Can we write ? */ @@ -576,19 +588,31 @@ static int snd_uart16550_output_close(sn return 0; }; -inline static void snd_uart16550_write_buffer(snd_uart16550_t *uart, unsigned char byte) +inline static int snd_uart16550_buffer_can_write( snd_uart16550_t *uart, int Num ) +{ + if( uart->buff_in_count + Num < TX_BUFF_SIZE ) + return 1; + else + return 0; +} + +inline static int snd_uart16550_write_buffer(snd_uart16550_t *uart, unsigned char byte) { unsigned short buff_in = uart->buff_in; - uart->tx_buff[buff_in] = byte; - buff_in++; - buff_in &= TX_BUFF_MASK; - uart->buff_in = buff_in; - uart->buff_in_count++; - if (uart->irq < 0) /* polling mode */ - snd_uart16550_add_timer(uart); + if( uart->buff_in_count < TX_BUFF_SIZE ) { + uart->tx_buff[buff_in] = byte; + buff_in++; + buff_in &= TX_BUFF_MASK; + uart->buff_in = buff_in; + uart->buff_in_count++; + if (uart->irq < 0) /* polling mode */ + snd_uart16550_add_timer(uart); + return 1; + } else + return 0; } -static void snd_uart16550_output_byte(snd_uart16550_t *uart, snd_rawmidi_substream_t * substream, unsigned char midi_byte) +static int snd_uart16550_output_byte(snd_uart16550_t *uart, snd_rawmidi_substream_t * substream, unsigned char midi_byte) { if (uart->buff_in_count == 0 /* Buffer empty? */ && ((uart->adaptor != SNDRV_SERIAL_MS124W_SA && @@ -611,13 +635,14 @@ static void snd_uart16550_output_byte(sn } } } else { - if (uart->buff_in_count >= TX_BUFF_SIZE) { + if( !snd_uart16550_write_buffer(uart, midi_byte) ) { snd_printk("%s: Buffer overrun on device at 0x%lx\n", uart->rmidi->name, uart->base); - return; + return 0; } - snd_uart16550_write_buffer(uart, midi_byte); } + + return 1; } static void snd_uart16550_output_write(snd_rawmidi_substream_t * substream) @@ -661,40 +686,38 @@ static void snd_uart16550_output_write(s } } else { first = 0; - while (1) { - if (snd_rawmidi_transmit(substream, &midi_byte, 1) != 1) - break; + while( 1 == snd_rawmidi_transmit_peek(substream, &midi_byte, 1) ) { /* Also send F5 after 3 seconds with no data to handle device disconnect */ if (first == 0 && (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS || uart->adaptor == SNDRV_SERIAL_GENERIC) && (uart->prev_out != substream->number || jiffies-lasttime > 3*HZ)) { - /* We will need three bytes of data here (worst case). */ - if (uart->buff_in_count >= TX_BUFF_SIZE - 3) + if( snd_uart16550_buffer_can_write( uart, 3 ) ) { + /* Roland Soundcanvas part selection */ + /* If this substream of the data is different previous + substream in this uart, send the change part event */ + uart->prev_out = substream->number; + /* change part */ + snd_uart16550_output_byte(uart, substream, 0xf5); + /* data */ + snd_uart16550_output_byte(uart, substream, uart->prev_out + 1); + /* If midi_byte is a data byte, send the previous status byte */ + if ((midi_byte < 0x80) && (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS)) + snd_uart16550_output_byte(uart, substream, uart->prev_status[uart->prev_out]); + } else if( !uart->drop_on_full ) break; - /* Roland Soundcanvas part selection */ - /* If this substream of the data is different previous - substream in this uart, send the change part event */ - uart->prev_out = substream->number; - /* change part */ - snd_uart16550_output_byte(uart, substream, 0xf5); - /* data */ - snd_uart16550_output_byte(uart, substream, uart->prev_out + 1); - /* If midi_byte is a data byte, send the previous status byte */ - if ((midi_byte < 0x80) && (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS)) - snd_uart16550_output_byte(uart, substream, uart->prev_status[uart->prev_out]); } - /* buffer full? */ - if (uart->buff_in_count >= TX_BUFF_SIZE) + /* send midi byte */ + if( !snd_uart16550_output_byte(uart, substream, midi_byte) && !uart->drop_on_full ) break; - /* send midi byte */ - snd_uart16550_output_byte(uart, substream, midi_byte); if (midi_byte >= 0x80 && midi_byte < 0xf0) uart->prev_status[uart->prev_out] = midi_byte; first = 1; + + snd_rawmidi_transmit_ack( substream, 1 ); } lasttime = jiffies; } @@ -755,6 +778,7 @@ static int __init snd_uart16550_create(s unsigned int speed, unsigned int base, int adaptor, + int droponfull, snd_uart16550_t **ruart) { static snd_device_ops_t ops = { @@ -771,6 +795,7 @@ static int __init snd_uart16550_create(s spin_lock_init(&uart->open_lock); uart->irq = -1; uart->base = iobase; + uart->drop_on_full = droponfull; if ((err = snd_uart16550_detect(uart)) <= 0) { printk(KERN_ERR "no UART detected at 0x%lx\n", iobase); @@ -900,6 +925,7 @@ static int __init snd_serial_probe(int d speed[dev], base[dev], adaptor[dev], + droponfull[dev], &uart)) < 0) { snd_card_free(card); return err; @@ -910,7 +936,7 @@ static int __init snd_serial_probe(int d return err; } - sprintf(card->longname, "%s at 0x%lx, irq %d speed %d div %d outs %d ins %d adaptor %s", + sprintf(card->longname, "%s at 0x%lx, irq %d speed %d div %d outs %d ins %d adaptor %s droponfull %d", card->shortname, uart->base, uart->irq, @@ -918,7 +944,8 @@ static int __init snd_serial_probe(int d (int)uart->divisor, outs[dev], ins[dev], - adaptor_names[uart->adaptor]); + adaptor_names[uart->adaptor], + uart->drop_on_full); if ((err = snd_card_register(card)) < 0) { snd_card_free(card); @@ -964,7 +991,7 @@ module_exit(alsa_card_serial_exit) /* format is: snd-serial=enable,index,id, port,irq,speed,base,outs, - ins,adaptor */ + ins,adaptor,droponfull */ static int __init alsa_card_serial_setup(char *str) { @@ -975,13 +1002,14 @@ static int __init alsa_card_serial_setup (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&speed[nr_dev]) == 2 && get_option(&str,&base[nr_dev]) == 2 && get_option(&str,&outs[nr_dev]) == 2 && get_option(&str,&ins[nr_dev]) == 2 && - get_option(&str,&adaptor[nr_dev]) == 2); + get_option(&str,&adaptor[nr_dev]) == 2 && + get_option(&str,&droponfull[nr_dev]) == 2 ); nr_dev++; return 1; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/drivers/vx/vx_core.c 830-ivtv/sound/drivers/vx/vx_core.c --- 000-virgin/sound/drivers/vx/vx_core.c Wed Aug 13 20:24:36 2003 +++ 830-ivtv/sound/drivers/vx/vx_core.c Thu Jan 8 10:26:50 2004 @@ -641,7 +641,7 @@ static void vx_proc_init(vx_core_t *chip snd_info_entry_t *entry; if (! snd_card_proc_new(chip->card, "vx-status", &entry)) - snd_info_set_text_ops(entry, chip, vx_proc_read); + snd_info_set_text_ops(entry, chip, 1024, vx_proc_read); } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/drivers/vx/vx_pcm.c 830-ivtv/sound/drivers/vx/vx_pcm.c --- 000-virgin/sound/drivers/vx/vx_pcm.c Sat Jun 14 18:37:42 2003 +++ 830-ivtv/sound/drivers/vx/vx_pcm.c Thu Jan 8 10:26:50 2004 @@ -611,6 +611,10 @@ static int vx_pcm_playback_open(snd_pcm_ runtime->hw.period_bytes_min = chip->ibl.size; runtime->private_data = pipe; + /* align to 4 bytes (otherwise will be problematic when 24bit is used) */ + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 4); + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4); + return 0; } @@ -1014,6 +1018,10 @@ static int vx_pcm_capture_open(snd_pcm_s runtime->hw = vx_pcm_capture_hw; runtime->hw.period_bytes_min = chip->ibl.size; runtime->private_data = pipe; + + /* align to 4 bytes (otherwise will be problematic when 24bit is used) */ + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 4); + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4); return 0; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/i2c/i2c.c 830-ivtv/sound/i2c/i2c.c --- 000-virgin/sound/i2c/i2c.c Fri May 30 19:02:28 2003 +++ 830-ivtv/sound/i2c/i2c.c Thu Jan 8 10:26:50 2004 @@ -84,7 +84,7 @@ int snd_i2c_bus_create(snd_card_t *card, bus = (snd_i2c_bus_t *)snd_magic_kcalloc(snd_i2c_bus_t, 0, GFP_KERNEL); if (bus == NULL) return -ENOMEM; - spin_lock_init(&bus->lock); + init_MUTEX(&bus->lock_mutex); INIT_LIST_HEAD(&bus->devices); INIT_LIST_HEAD(&bus->buses); bus->card = card; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/i2c/l3/uda1341.c 830-ivtv/sound/i2c/l3/uda1341.c --- 000-virgin/sound/i2c/l3/uda1341.c Sat Jun 14 18:37:42 2003 +++ 830-ivtv/sound/i2c/l3/uda1341.c Thu Jan 8 10:26:50 2004 @@ -17,7 +17,7 @@ * 2002-05-12 Tomas Kasparek another code cleanup */ -/* $Id: uda1341.c,v 1.9 2003/04/19 13:34:33 perex Exp $ */ +/* $Id: uda1341.c,v 1.10 2003/10/23 14:34:52 perex Exp $ */ #include #include @@ -421,9 +421,9 @@ static void __devinit snd_uda1341_proc_i snd_info_entry_t *entry; if (! snd_card_proc_new(card, "uda1341", &entry)) - snd_info_set_text_ops(entry, clnt, snd_uda1341_proc_read); + snd_info_set_text_ops(entry, clnt, 1024, snd_uda1341_proc_read); if (! snd_card_proc_new(card, "uda1341-regs", &entry)) - snd_info_set_text_ops(entry, clnt, snd_uda1341_proc_regs_read); + snd_info_set_text_ops(entry, clnt, 1024, snd_uda1341_proc_regs_read); } /* }}} */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/ad1816a/ad1816a.c 830-ivtv/sound/isa/ad1816a/ad1816a.c --- 000-virgin/sound/isa/ad1816a/ad1816a.c Wed Aug 13 20:24:36 2003 +++ 830-ivtv/sound/isa/ad1816a/ad1816a.c Thu Jan 8 10:26:50 2004 @@ -338,9 +338,9 @@ static int __init alsa_card_ad1816a_setu (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && - get_option(&str,(int *)&mpu_port[nr_dev]) == 2 && - get_option(&str,(int *)&fm_port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && + get_option_long(&str,&mpu_port[nr_dev]) == 2 && + get_option_long(&str,&fm_port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&mpu_irq[nr_dev]) == 2 && get_option(&str,&dma1[nr_dev]) == 2 && diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/ad1848/ad1848.c 830-ivtv/sound/isa/ad1848/ad1848.c --- 000-virgin/sound/isa/ad1848/ad1848.c Wed Aug 13 20:24:36 2003 +++ 830-ivtv/sound/isa/ad1848/ad1848.c Thu Jan 8 10:26:50 2004 @@ -174,7 +174,7 @@ static int __init alsa_card_ad1848_setup (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&dma1[nr_dev]) == 2 && get_option(&str,&thinkpad[nr_dev]) == 2); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/ad1848/ad1848_lib.c 830-ivtv/sound/isa/ad1848/ad1848_lib.c --- 000-virgin/sound/isa/ad1848/ad1848_lib.c Wed Aug 13 20:24:36 2003 +++ 830-ivtv/sound/isa/ad1848/ad1848_lib.c Thu Jan 8 10:26:50 2004 @@ -736,11 +736,13 @@ static int snd_ad1848_probe(ad1848_t * c snd_ad1848_out(chip, AD1848_RIGHT_INPUT, 0x45); rev = snd_ad1848_in(chip, AD1848_RIGHT_INPUT); if (rev == 0x65) { + spin_unlock_irqrestore(&chip->reg_lock, flags); id = 1; ad1847 = 1; break; } if (snd_ad1848_in(chip, AD1848_LEFT_INPUT) == 0xaa && rev == 0x45) { + spin_unlock_irqrestore(&chip->reg_lock, flags); id = 1; break; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/als100.c 830-ivtv/sound/isa/als100.c --- 000-virgin/sound/isa/als100.c Wed Aug 13 20:24:36 2003 +++ 830-ivtv/sound/isa/als100.c Thu Jan 8 10:26:50 2004 @@ -249,7 +249,7 @@ static int __init snd_card_als100_probe( return error; } - if (mpu_port[dev] > 0) { + if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { if (snd_mpu401_uart_new(card, 0, MPU401_HW_ALS100, mpu_port[dev], 0, mpu_irq[dev], SA_INTERRUPT, @@ -257,7 +257,7 @@ static int __init snd_card_als100_probe( snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]); } - if (fm_port[dev] > 0) { + if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) { if (snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2, OPL3_HW_AUTO, 0, &opl3) < 0) { @@ -359,9 +359,9 @@ static int __init alsa_card_als100_setup (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && - get_option(&str,(int *)&mpu_port[nr_dev]) == 2 && - get_option(&str,(int *)&fm_port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && + get_option_long(&str,&mpu_port[nr_dev]) == 2 && + get_option_long(&str,&fm_port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&mpu_irq[nr_dev]) == 2 && get_option(&str,&dma8[nr_dev]) == 2 && diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/azt2320.c 830-ivtv/sound/isa/azt2320.c --- 000-virgin/sound/isa/azt2320.c Wed Aug 13 20:24:36 2003 +++ 830-ivtv/sound/isa/azt2320.c Thu Jan 8 10:26:50 2004 @@ -283,7 +283,7 @@ static int __devinit snd_card_azt2320_pr return error; } - if (mpu_port[dev] > 0) { + if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { if (snd_mpu401_uart_new(card, 0, MPU401_HW_AZT2320, mpu_port[dev], 0, mpu_irq[dev], SA_INTERRUPT, @@ -291,7 +291,7 @@ static int __devinit snd_card_azt2320_pr snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]); } - if (fm_port[dev] > 0) { + if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) { if (snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2, OPL3_HW_AUTO, 0, &opl3) < 0) { @@ -393,9 +393,9 @@ static int __init alsa_card_azt2320_setu (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && - get_option(&str,(int *)&wss_port[nr_dev]) == 2 && - get_option(&str,(int *)&mpu_port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && + get_option_long(&str,&wss_port[nr_dev]) == 2 && + get_option_long(&str,&mpu_port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&mpu_irq[nr_dev]) == 2 && get_option(&str,&dma1[nr_dev]) == 2 && diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/cmi8330.c 830-ivtv/sound/isa/cmi8330.c --- 000-virgin/sound/isa/cmi8330.c Wed Aug 13 20:24:36 2003 +++ 830-ivtv/sound/isa/cmi8330.c Thu Jan 8 10:26:50 2004 @@ -658,11 +658,11 @@ static int __init alsa_card_cmi8330_setu get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && get_option(&str,&pnp) == 2 && - get_option(&str,(int *)&sbport[nr_dev]) == 2 && + get_option_long(&str,&sbport[nr_dev]) == 2 && get_option(&str,&sbirq[nr_dev]) == 2 && get_option(&str,&sbdma8[nr_dev]) == 2 && get_option(&str,&sbdma16[nr_dev]) == 2 && - get_option(&str,(int *)&wssport[nr_dev]) == 2 && + get_option_long(&str,&wssport[nr_dev]) == 2 && get_option(&str,&wssirq[nr_dev]) == 2 && get_option(&str,&wssdma[nr_dev]) == 2); #ifdef CONFIG_PNP diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/cs423x/cs4231.c 830-ivtv/sound/isa/cs423x/cs4231.c --- 000-virgin/sound/isa/cs423x/cs4231.c Sun Nov 17 20:29:20 2002 +++ 830-ivtv/sound/isa/cs423x/cs4231.c Thu Jan 8 10:26:50 2004 @@ -103,8 +103,6 @@ static int __init snd_card_cs4231_probe( if (card == NULL) return -ENOMEM; acard = (struct snd_card_cs4231 *)card->private_data; - if (mpu_port[dev] < 0) - mpu_port[dev] = SNDRV_AUTO_PORT; if ((err = snd_cs4231_create(card, port[dev], -1, irq[dev], dma1[dev], @@ -128,10 +126,13 @@ static int __init snd_card_cs4231_probe( return err; } - if (mpu_irq[dev] >= 0 && mpu_irq[dev] != SNDRV_AUTO_IRQ) { + if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { + if (mpu_irq[dev] == SNDRV_AUTO_IRQ) + mpu_irq[dev] = -1; if (snd_mpu401_uart_new(card, 0, MPU401_HW_CS4232, mpu_port[dev], 0, - mpu_irq[dev], SA_INTERRUPT, + mpu_irq[dev], + mpu_irq[dev] >= 0 ? SA_INTERRUPT : 0, NULL) < 0) printk(KERN_ERR "cs4231: MPU401 not detected\n"); } @@ -194,8 +195,8 @@ static int __init alsa_card_cs4231_setup get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && get_option(&str,&pnp) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && - get_option(&str,(int *)&mpu_port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && + get_option_long(&str,&mpu_port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&mpu_irq[nr_dev]) == 2 && get_option(&str,&dma1[nr_dev]) == 2 && diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/cs423x/cs4236.c 830-ivtv/sound/isa/cs423x/cs4236.c --- 000-virgin/sound/isa/cs423x/cs4236.c Mon Nov 17 18:29:01 2003 +++ 830-ivtv/sound/isa/cs423x/cs4236.c Thu Jan 8 10:26:50 2004 @@ -307,7 +307,7 @@ static int __devinit snd_card_cs4236_pnp pnp_init_resource_table(cfg); if (port[dev] != SNDRV_AUTO_PORT) pnp_resource_change(&cfg->port_resource[0], port[dev], 4); - if (fm_port[dev] != SNDRV_AUTO_PORT && fm_port[dev] >= 0) + if (fm_port[dev] != SNDRV_AUTO_PORT && fm_port[dev] > 0) pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4); if (sb_port[dev] != SNDRV_AUTO_PORT) pnp_resource_change(&cfg->port_resource[2], sb_port[dev], 16); @@ -327,7 +327,7 @@ static int __devinit snd_card_cs4236_pnp return -EBUSY; } port[dev] = pnp_port_start(pdev, 0); - if (fm_port[dev] >= 0) + if (fm_port[dev] > 0) fm_port[dev] = pnp_port_start(pdev, 1); sb_port[dev] = pnp_port_start(pdev, 2); irq[dev] = pnp_irq(pdev, 0); @@ -338,7 +338,7 @@ static int __devinit snd_card_cs4236_pnp snd_printdd("isapnp WSS: irq=%i, dma1=%i, dma2=%i\n", irq[dev], dma1[dev], dma2[dev]); /* CTRL initialization */ - if (acard->ctrl && cport[dev] >= 0) { + if (acard->ctrl && cport[dev] > 0) { pdev = acard->ctrl; pnp_init_resource_table(cfg); if (cport[dev] != SNDRV_AUTO_PORT) @@ -356,12 +356,13 @@ static int __devinit snd_card_cs4236_pnp snd_printdd("isapnp CTRL: control port=0x%lx\n", cport[dev]); } /* MPU initialization */ - if (acard->mpu && mpu_port[dev] >= 0) { + if (acard->mpu && mpu_port[dev] > 0) { pdev = acard->mpu; pnp_init_resource_table(cfg); if (mpu_port[dev] != SNDRV_AUTO_PORT) pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2); - if (mpu_irq[dev] != SNDRV_AUTO_IRQ && mpu_irq[dev] >= 0) + if (mpu_irq[dev] != SNDRV_AUTO_IRQ && mpu_irq[dev] >= 0 && + pnp_irq_valid(pdev, 0)) pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1); err = pnp_manual_config_dev(pdev, cfg, 0); if (err < 0) @@ -373,7 +374,8 @@ static int __devinit snd_card_cs4236_pnp mpu_irq[dev] = SNDRV_AUTO_IRQ; } else { mpu_port[dev] = pnp_port_start(pdev, 0); - if (pnp_irq_valid(pdev, 0) && pnp_irq(pdev, 0) >= 0) { + if (mpu_irq[dev] >= 0 && + pnp_irq_valid(pdev, 0) && pnp_irq(pdev, 0) >= 0) { mpu_irq[dev] = pnp_irq(pdev, 0); } else { mpu_irq[dev] = -1; /* disable interrupt */ @@ -435,13 +437,7 @@ static int __devinit snd_card_cs423x_pro return -ENXIO; } #endif - if (mpu_port[dev] < 0) - mpu_port[dev] = SNDRV_AUTO_PORT; - if (fm_port[dev] < 0) - fm_port[dev] = SNDRV_AUTO_PORT; - if (sb_port[dev] < 0) - sb_port[dev] = SNDRV_AUTO_PORT; - if (sb_port[dev] != SNDRV_AUTO_PORT) + if (sb_port[dev] > 0 && sb_port[dev] != SNDRV_AUTO_PORT) if ((acard->res_sb_port = request_region(sb_port[dev], 16, IDENT " SB")) == NULL) { printk(KERN_ERR IDENT ": unable to register SB port at 0x%lx\n", sb_port[dev]); snd_card_free(card); @@ -498,7 +494,7 @@ static int __devinit snd_card_cs423x_pro return err; } - if (fm_port[dev] != SNDRV_AUTO_PORT) { + if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) { if (snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2, OPL3_HW_OPL3_CS, 0, &opl3) < 0) { @@ -511,7 +507,9 @@ static int __devinit snd_card_cs423x_pro } } - if (mpu_port[dev] != SNDRV_AUTO_PORT) { + if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { + if (mpu_irq[dev] == SNDRV_AUTO_IRQ) + mpu_irq[dev] = -1; if (snd_mpu401_uart_new(card, 0, MPU401_HW_CS4232, mpu_port[dev], 0, mpu_irq[dev], @@ -546,7 +544,7 @@ static int __devinit snd_cs423x_pnp_dete int res; for ( ; dev < SNDRV_CARDS; dev++) { - if (!enable[dev]) + if (!enable[dev] || !isapnp[dev]) continue; res = snd_card_cs423x_probe(dev, card, id); if (res < 0) @@ -638,11 +636,11 @@ static int __init alsa_card_cs423x_setup get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && get_option(&str,&pnp) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && - get_option(&str,(int *)&cport[nr_dev]) == 2 && - get_option(&str,(int *)&mpu_port[nr_dev]) == 2 && - get_option(&str,(int *)&fm_port[nr_dev]) == 2 && - get_option(&str,(int *)&sb_port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && + get_option_long(&str,&cport[nr_dev]) == 2 && + get_option_long(&str,&mpu_port[nr_dev]) == 2 && + get_option_long(&str,&fm_port[nr_dev]) == 2 && + get_option_long(&str,&sb_port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&mpu_irq[nr_dev]) == 2 && get_option(&str,&dma1[nr_dev]) == 2 && diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/cs423x/pc98.c 830-ivtv/sound/isa/cs423x/pc98.c --- 000-virgin/sound/isa/cs423x/pc98.c Mon Nov 17 18:29:01 2003 +++ 830-ivtv/sound/isa/cs423x/pc98.c Thu Jan 8 10:26:50 2004 @@ -327,10 +327,6 @@ static int __init snd_card_pc98_probe(in card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); if (card == NULL) return -ENOMEM; - if (mpu_port[dev] < 0 || mpu_irq[dev] < 0) - mpu_port[dev] = SNDRV_AUTO_PORT; - if (fm_port[dev] < 0) - fm_port[dev] = SNDRV_AUTO_PORT; if ((err = pc98_cs4231_chip_init(dev)) < 0) { snd_card_free(card); @@ -363,7 +359,7 @@ static int __init snd_card_pc98_probe(in return err; } - if (fm_port[dev] != SNDRV_AUTO_PORT) { + if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) { /* ??? */ outb(0x00, fm_port[dev] + 6); inb(fm_port[dev] + 7); @@ -381,7 +377,7 @@ static int __init snd_card_pc98_probe(in } } - if (mpu_port[dev] != SNDRV_AUTO_PORT) { + if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { err = pc98_mpu401_init(mpu_irq[dev]); if (! err) { err = snd_mpu401_uart_new(card, 0, @@ -455,9 +451,9 @@ static int __init alsa_card_pc98_setup(c (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && - get_option(&str,(int *)&mpu_port[nr_dev]) == 2 && - get_option(&str,(int *)&fm_port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && + get_option_long(&str,&mpu_port[nr_dev]) == 2 && + get_option_long(&str,&fm_port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&mpu_irq[nr_dev]) == 2 && get_option(&str,&dma1[nr_dev]) == 2 && diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/dt019x.c 830-ivtv/sound/isa/dt019x.c --- 000-virgin/sound/isa/dt019x.c Wed Aug 13 20:24:36 2003 +++ 830-ivtv/sound/isa/dt019x.c Thu Jan 8 10:26:50 2004 @@ -235,18 +235,20 @@ static int __devinit snd_card_dt019x_pro return error; } - if (mpu_port[dev] > 0) { + if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { + if (mpu_irq[dev] == SNDRV_AUTO_IRQ) + mpu_irq[dev] = -1; if (snd_mpu401_uart_new(card, 0, /* MPU401_HW_SB,*/ MPU401_HW_MPU401, mpu_port[dev], 0, mpu_irq[dev], - SA_INTERRUPT, + mpu_irq[dev] >= 0 ? SA_INTERRUPT : 0, NULL) < 0) snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx ?\n", mpu_port[dev]); } - if (fm_port[dev] > 0) { + if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) { if (snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2, @@ -347,9 +349,9 @@ static int __init alsa_card_dt019x_setup (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && - get_option(&str,(int *)&mpu_port[nr_dev]) == 2 && - get_option(&str,(int *)&fm_port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && + get_option_long(&str,&mpu_port[nr_dev]) == 2 && + get_option_long(&str,&fm_port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&mpu_irq[nr_dev]) == 2 && get_option(&str,&dma8[nr_dev]) == 2); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/es1688/es1688.c 830-ivtv/sound/isa/es1688/es1688.c --- 000-virgin/sound/isa/es1688/es1688.c Sun Nov 17 20:29:30 2002 +++ 830-ivtv/sound/isa/es1688/es1688.c Thu Jan 8 10:26:50 2004 @@ -226,8 +226,8 @@ static int __init alsa_card_es1688_setup (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && - get_option(&str,(int *)&mpu_port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && + get_option_long(&str,&mpu_port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&mpu_irq[nr_dev]) == 2 && get_option(&str,&dma8[nr_dev]) == 2); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/es18xx.c 830-ivtv/sound/isa/es18xx.c --- 000-virgin/sound/isa/es18xx.c Wed Aug 13 20:24:36 2003 +++ 830-ivtv/sound/isa/es18xx.c Thu Jan 8 10:26:50 2004 @@ -2286,9 +2286,9 @@ static int __init alsa_card_es18xx_setup get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && get_option(&str,&pnp) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && - get_option(&str,(int *)&mpu_port[nr_dev]) == 2 && - get_option(&str,(int *)&fm_port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && + get_option_long(&str,&mpu_port[nr_dev]) == 2 && + get_option_long(&str,&fm_port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&dma1[nr_dev]) == 2 && get_option(&str,&dma2[nr_dev]) == 2); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/gus/gus_irq.c 830-ivtv/sound/isa/gus/gus_irq.c --- 000-virgin/sound/isa/gus/gus_irq.c Sat Jun 14 18:37:43 2003 +++ 830-ivtv/sound/isa/gus/gus_irq.c Thu Jan 8 10:26:50 2004 @@ -136,7 +136,7 @@ void snd_gus_irq_profile_init(snd_gus_ca snd_info_entry_t *entry; if (! snd_card_proc_new(gus->card, "gusirq", &entry)) - snd_info_set_text_ops(entry, gus, snd_gus_irq_info_read); + snd_info_set_text_ops(entry, gus, 1024, snd_gus_irq_info_read); } #endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/gus/gus_mem.c 830-ivtv/sound/isa/gus/gus_mem.c --- 000-virgin/sound/isa/gus/gus_mem.c Thu Feb 13 11:08:17 2003 +++ 830-ivtv/sound/isa/gus/gus_mem.c Thu Jan 8 10:26:50 2004 @@ -265,7 +265,7 @@ int snd_gf1_mem_init(snd_gus_card_t * gu return -ENOMEM; #ifdef CONFIG_SND_DEBUG if (! snd_card_proc_new(gus->card, "gusmem", &entry)) { - snd_info_set_text_ops(entry, gus, snd_gf1_mem_info_read); + snd_info_set_text_ops(entry, gus, 1024, snd_gf1_mem_info_read); entry->c.text.read_size = 256 * 1024; } #endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/gus/gus_pcm.c 830-ivtv/sound/isa/gus/gus_pcm.c --- 000-virgin/sound/isa/gus/gus_pcm.c Wed Mar 26 22:54:40 2003 +++ 830-ivtv/sound/isa/gus/gus_pcm.c Thu Jan 8 10:26:50 2004 @@ -813,6 +813,15 @@ static snd_kcontrol_new_t snd_gf1_pcm_vo .put = snd_gf1_pcm_volume_put }; +static snd_kcontrol_new_t snd_gf1_pcm_volume_control1 = +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "GPCM Playback Volume", + .info = snd_gf1_pcm_volume_info, + .get = snd_gf1_pcm_volume_get, + .put = snd_gf1_pcm_volume_put +}; + static snd_pcm_ops_t snd_gf1_pcm_playback_ops = { .open = snd_gf1_pcm_playback_open, .close = snd_gf1_pcm_playback_close, @@ -880,7 +889,11 @@ int snd_gf1_pcm_new(snd_gus_card_t * gus strcat(pcm->name, " (synth)"); gus->pcm = pcm; - if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_gf1_pcm_volume_control, gus))) < 0) + if (gus->codec_flag) + kctl = snd_ctl_new1(&snd_gf1_pcm_volume_control1, gus); + else + kctl = snd_ctl_new1(&snd_gf1_pcm_volume_control, gus); + if ((err = snd_ctl_add(card, kctl)) < 0) return err; kctl->id.index = control_index; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/gus/gusclassic.c 830-ivtv/sound/isa/gus/gusclassic.c --- 000-virgin/sound/isa/gus/gusclassic.c Tue Sep 2 09:56:01 2003 +++ 830-ivtv/sound/isa/gus/gusclassic.c Thu Jan 8 10:26:50 2004 @@ -284,7 +284,7 @@ static int __init alsa_card_gusclassic_s (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&dma1[nr_dev]) == 2 && get_option(&str,&dma2[nr_dev]) == 2 && diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/gus/gusextreme.c 830-ivtv/sound/isa/gus/gusextreme.c --- 000-virgin/sound/isa/gus/gusextreme.c Tue Sep 2 09:56:01 2003 +++ 830-ivtv/sound/isa/gus/gusextreme.c Thu Jan 8 10:26:50 2004 @@ -417,9 +417,9 @@ static int __init alsa_card_gusextreme_s (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && - get_option(&str,(int *)&gf1_port[nr_dev]) == 2 && - get_option(&str,(int *)&mpu_port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && + get_option_long(&str,&gf1_port[nr_dev]) == 2 && + get_option_long(&str,&mpu_port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&gf1_irq[nr_dev]) == 2 && get_option(&str,&mpu_irq[nr_dev]) == 2 && diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/gus/gusmax.c 830-ivtv/sound/isa/gus/gusmax.c --- 000-virgin/sound/isa/gus/gusmax.c Tue Sep 2 09:56:01 2003 +++ 830-ivtv/sound/isa/gus/gusmax.c Thu Jan 8 10:26:50 2004 @@ -424,7 +424,7 @@ static int __init alsa_card_gusmax_setup (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&dma1[nr_dev]) == 2 && get_option(&str,&dma2[nr_dev]) == 2 && diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/gus/interwave.c 830-ivtv/sound/isa/gus/interwave.c --- 000-virgin/sound/isa/gus/interwave.c Wed Aug 13 20:24:36 2003 +++ 830-ivtv/sound/isa/gus/interwave.c Thu Jan 8 10:26:50 2004 @@ -229,12 +229,12 @@ static int __devinit snd_interwave_detec break; port += 0x10; } - if (port > 0x380) - return -ENODEV; } else { - if ((iwcard->i2c_res = request_region(port, 1, "InterWave (I2C bus)")) != NULL) - return -ENODEV; + iwcard->i2c_res = request_region(port, 1, "InterWave (I2C bus)"); } + if (iwcard->i2c_res == NULL) + return -ENODEV; + sprintf(name, "InterWave-%i", card->number); if ((err = snd_i2c_bus_create(card, name, NULL, &bus)) < 0) return err; @@ -994,9 +994,9 @@ static int __init alsa_card_interwave_se get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && get_option(&str,&pnp) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && #ifdef SNDRV_STB - get_option(&str,(int *)&port_tc[nr_dev]) == 2 && + get_option_long(&str,&port_tc[nr_dev]) == 2 && #endif get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&dma1[nr_dev]) == 2 && diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/opl3sa2.c 830-ivtv/sound/isa/opl3sa2.c --- 000-virgin/sound/isa/opl3sa2.c Tue Sep 2 09:56:01 2003 +++ 830-ivtv/sound/isa/opl3sa2.c Thu Jan 8 10:26:50 2004 @@ -945,11 +945,11 @@ static int __init alsa_card_opl3sa2_setu get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && get_option(&str,&pnp) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && - get_option(&str,(int *)&sb_port[nr_dev]) == 2 && - get_option(&str,(int *)&wss_port[nr_dev]) == 2 && - get_option(&str,(int *)&fm_port[nr_dev]) == 2 && - get_option(&str,(int *)&midi_port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && + get_option_long(&str,&sb_port[nr_dev]) == 2 && + get_option_long(&str,&wss_port[nr_dev]) == 2 && + get_option_long(&str,&fm_port[nr_dev]) == 2 && + get_option_long(&str,&midi_port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&dma1[nr_dev]) == 2 && get_option(&str,&dma2[nr_dev]) == 2 && diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/opti9xx/opti92x-ad1848.c 830-ivtv/sound/isa/opti9xx/opti92x-ad1848.c --- 000-virgin/sound/isa/opti9xx/opti92x-ad1848.c Sat Jun 14 18:37:43 2003 +++ 830-ivtv/sound/isa/opti9xx/opti92x-ad1848.c Thu Jan 8 10:26:50 2004 @@ -543,11 +543,11 @@ static int __devinit snd_opti9xx_configu __skip_base: switch (chip->irq) { -#ifdef OPTi93X +//#ifdef OPTi93X case 5: irq_bits = 0x05; break; -#endif /* OPTi93X */ +//#endif /* OPTi93X */ case 7: irq_bits = 0x01; break; @@ -604,6 +604,7 @@ __skip_base: __skip_resources: if (chip->hardware > OPTi9XX_HW_82C928) { switch (chip->mpu_port) { + case 0: case -1: break; case 0x300: @@ -644,7 +645,7 @@ __skip_resources: } snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), - (chip->mpu_port == -1) ? 0x00 : + (chip->mpu_port <= 0) ? 0x00 : 0x80 | mpu_port_bits << 5 | mpu_irq_bits << 3, 0xf8); } @@ -1734,15 +1735,23 @@ static int __devinit snd_card_opti9xx_pn #if defined(CS4231) || defined(OPTi93X) if (dma2 != SNDRV_AUTO_DMA) pnp_resource_change(&cfg->dma_resource[1], dma2, 1); +#else +#ifdef snd_opti9xx_fixup_dma2 + snd_opti9xx_fixup_dma2(pdev); +#endif #endif /* CS4231 || OPTi93X */ - if (fm_port != SNDRV_AUTO_PORT) +#ifdef OPTi93X + if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) pnp_resource_change(&cfg->port_resource[1], fm_port, 4); - +#else + if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) + pnp_resource_change(&cfg->port_resource[2], fm_port, 4); +#endif if (pnp_manual_config_dev(pdev, cfg, 0) < 0) snd_printk(KERN_ERR "AUDIO the requested resources are invalid, using auto config\n"); err = pnp_activate_dev(pdev); if (err < 0) { - snd_printk(KERN_ERR "AUDIO pnp configure failure\n"); + snd_printk(KERN_ERR "AUDIO pnp configure failure: %d\n", err); kfree(cfg); return err; } @@ -1762,7 +1771,7 @@ static int __devinit snd_card_opti9xx_pn #endif /* CS4231 || OPTi93X */ pdev = chip->devmpu; - if (pdev) { + if (pdev && mpu_port > 0) { pnp_init_resource_table(cfg); if (mpu_port != SNDRV_AUTO_PORT) @@ -1985,9 +1994,6 @@ static int __devinit snd_card_opti9xx_pr chip->dma2 = dma2; #endif -#ifdef CONFIG_PNP - if (!isapnp) { -#endif if (chip->wss_base == SNDRV_AUTO_PORT) { if ((chip->wss_base = snd_legacy_find_free_ioport(possible_ports, 4)) < 0) { snd_card_free(card); @@ -1995,6 +2001,9 @@ static int __devinit snd_card_opti9xx_pr return -EBUSY; } } +#ifdef CONFIG_PNP + if (!isapnp) { +#endif if (chip->mpu_port == SNDRV_AUTO_PORT) { if ((chip->mpu_port = snd_legacy_find_free_ioport(possible_mpu_ports, 2)) < 0) { snd_card_free(card); @@ -2093,7 +2102,7 @@ static int __devinit snd_card_opti9xx_pr } #endif - if (chip->mpu_port <= 0) + if (chip->mpu_port <= 0 || chip->mpu_port == SNDRV_AUTO_PORT) rmidi = NULL; else if ((error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, @@ -2101,7 +2110,7 @@ static int __devinit snd_card_opti9xx_pr &rmidi))) snd_printk("no MPU-401 device at 0x%lx?\n", chip->mpu_port); - if (chip->fm_port > 0) { + if (chip->fm_port > 0 && chip->fm_port != SNDRV_AUTO_PORT) { opl3_t *opl3 = NULL; #ifndef OPTi93X if (chip->hardware == OPTi9XX_HW_82C928 || @@ -2240,9 +2249,9 @@ static int __init alsa_card_opti9xx_setu get_option(&str,&index) == 2 && get_id(&str,&id) == 2 && get_option(&str,&pnp) == 2 && - get_option(&str,(int *)&port) == 2 && - get_option(&str,(int *)&mpu_port) == 2 && - get_option(&str,(int *)&fm_port) == 2 && + get_option_long(&str,&port) == 2 && + get_option_long(&str,&mpu_port) == 2 && + get_option_long(&str,&fm_port) == 2 && get_option(&str,&irq) == 2 && get_option(&str,&mpu_irq) == 2 && get_option(&str,&dma1) == 2 diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/sb/emu8000.c 830-ivtv/sound/isa/sb/emu8000.c --- 000-virgin/sound/isa/sb/emu8000.c Wed Aug 13 20:24:36 2003 +++ 830-ivtv/sound/isa/sb/emu8000.c Thu Jan 8 10:26:50 2004 @@ -1044,8 +1044,10 @@ snd_emu8000_create_mixer(snd_card_t *car __error: for (i = 0; i < EMU8000_NUM_CONTROLS; i++) { + down_write(&card->controls_rwsem); if (emu->controls[i]) snd_ctl_remove(card, emu->controls[i]); + up_write(&card->controls_rwsem); } return err; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/sb/es968.c 830-ivtv/sound/isa/sb/es968.c --- 000-virgin/sound/isa/sb/es968.c Wed Aug 13 20:24:36 2003 +++ 830-ivtv/sound/isa/sb/es968.c Thu Jan 8 10:26:50 2004 @@ -257,7 +257,7 @@ static int __init alsa_card_es968_setup( (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&dma8[nr_dev]) == 2); nr_dev++; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/sb/sb16.c 830-ivtv/sound/isa/sb/sb16.c --- 000-virgin/sound/isa/sb/sb16.c Wed Aug 13 20:24:36 2003 +++ 830-ivtv/sound/isa/sb/sb16.c Thu Jan 8 10:26:50 2004 @@ -465,7 +465,7 @@ static int __init snd_sb16_probe(int dev return -ENXIO; } - if (chip->mpu_port) { + if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) { if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_SB, chip->mpu_port, 0, xirq, 0, &chip->rmidi)) < 0) { @@ -475,7 +475,12 @@ static int __init snd_sb16_probe(int dev chip->rmidi_callback = snd_mpu401_uart_interrupt; } - if (fm_port[dev] > 0) { +#ifdef SNDRV_SBAWE_EMU8000 + if (awe_port[dev] == SNDRV_AUTO_PORT) + awe_port[dev] = 0; /* disable */ +#endif + + if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) { if (snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2, OPL3_HW_OPL3, fm_port[dev] == port[dev] || fm_port[dev] == 0x388, @@ -696,9 +701,9 @@ static int __init alsa_card_sb16_setup(c get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && get_option(&str,&pnp) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && - get_option(&str,(int *)&mpu_port[nr_dev]) == 2 && - get_option(&str,(int *)&fm_port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && + get_option_long(&str,&mpu_port[nr_dev]) == 2 && + get_option_long(&str,&fm_port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&dma8[nr_dev]) == 2 && get_option(&str,&dma16[nr_dev]) == 2 && @@ -709,7 +714,7 @@ static int __init alsa_card_sb16_setup(c #endif #ifdef SNDRV_SBAWE_EMU8000 && - get_option(&str,(int *)&awe_port[nr_dev]) == 2 && + get_option_long(&str,&awe_port[nr_dev]) == 2 && get_option(&str,&seq_ports[nr_dev]) == 2 #endif ); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/sb/sb16_csp.c 830-ivtv/sound/isa/sb/sb16_csp.c --- 000-virgin/sound/isa/sb/sb16_csp.c Fri May 30 19:02:28 2003 +++ 830-ivtv/sound/isa/sb/sb16_csp.c Thu Jan 8 10:26:50 2004 @@ -1059,10 +1059,12 @@ static void snd_sb_qsound_destroy(snd_sb card = p->chip->card; + down_write(&card->controls_rwsem); if (p->qsound_switch) snd_ctl_remove(card, p->qsound_switch); if (p->qsound_space) snd_ctl_remove(card, p->qsound_space); + up_write(&card->controls_rwsem); /* cancel pending transfer of QSound parameters */ spin_lock_irqsave (&p->q_lock, flags); @@ -1105,7 +1107,7 @@ static int init_proc_entry(snd_sb_csp_t snd_info_entry_t *entry; sprintf(name, "cspD%d", device); if (! snd_card_proc_new(p->chip->card, name, &entry)) - snd_info_set_text_ops(entry, p, info_read); + snd_info_set_text_ops(entry, p, 1024, info_read); return 0; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/sb/sb8.c 830-ivtv/sound/isa/sb/sb8.c --- 000-virgin/sound/isa/sb/sb8.c Sat Jun 14 18:37:43 2003 +++ 830-ivtv/sound/isa/sb/sb8.c Thu Jan 8 10:26:50 2004 @@ -242,7 +242,7 @@ static int __init alsa_card_sb8_setup(ch (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&dma8[nr_dev]) == 2); nr_dev++; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/sb/sb_common.c 830-ivtv/sound/isa/sb/sb_common.c --- 000-virgin/sound/isa/sb/sb_common.c Sat May 10 18:35:07 2003 +++ 830-ivtv/sound/isa/sb/sb_common.c Thu Jan 8 10:26:50 2004 @@ -185,10 +185,6 @@ static int snd_sbdsp_free(sb_t *chip) release_resource(chip->res_port); kfree_nocheck(chip->res_port); } - if (chip->res_alt_port) { - release_resource(chip->res_alt_port); - kfree_nocheck(chip->res_alt_port); - } if (chip->irq >= 0) free_irq(chip->irq, (void *) chip); #ifdef CONFIG_ISA diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/sgalaxy.c 830-ivtv/sound/isa/sgalaxy.c --- 000-virgin/sound/isa/sgalaxy.c Sat May 10 18:35:07 2003 +++ 830-ivtv/sound/isa/sgalaxy.c Thu Jan 8 10:26:50 2004 @@ -341,10 +341,10 @@ static int __init alsa_card_sgalaxy_setu (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&sbport[nr_dev]) == 2 && - get_option(&str,(int *)&wssport[nr_dev]) == 2 && - get_option(&str,(int *)&irq[nr_dev]) == 2 && - get_option(&str,(int *)&dma1[nr_dev]) == 2); + get_option_long(&str,&sbport[nr_dev]) == 2 && + get_option_long(&str,&wssport[nr_dev]) == 2 && + get_option(&str,&irq[nr_dev]) == 2 && + get_option(&str,&dma1[nr_dev]) == 2); nr_dev++; return 1; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/sscape.c 830-ivtv/sound/isa/sscape.c --- 000-virgin/sound/isa/sscape.c Mon Nov 17 18:29:01 2003 +++ 830-ivtv/sound/isa/sscape.c Thu Jan 8 10:26:50 2004 @@ -31,6 +31,7 @@ #include #include #include +#define SNDRV_GET_ID #include #include @@ -616,10 +617,10 @@ static int sscape_upload_microcode(struc */ if (get_user(code, &mc->code)) return -EFAULT; - if ((err = verify_area(VERIFY_READ, code, 65536)) != 0) + if ((err = verify_area(VERIFY_READ, code, SSCAPE_MICROCODE_SIZE)) != 0) return err; - if ((ret = upload_dma_data(sscape, code, 65536)) == 0) { + if ((ret = upload_dma_data(sscape, code, SSCAPE_MICROCODE_SIZE)) == 0) { snd_printk(KERN_INFO "sscape: MIDI firmware loaded\n"); } @@ -1538,8 +1539,8 @@ static int __init builtin_sscape_setup(c return 0; (void)((get_option(&str, &index[nr_dev]) == 2) && - (get_option(&str, (int*)&id[nr_dev]) == 2) && - (get_option(&str, (int*)&port[nr_dev]) == 2) && + (get_id(&str, &id[nr_dev]) == 2) && + (get_option_long(&str, &port[nr_dev]) == 2) && (get_option(&str, &irq[nr_dev]) == 2) && (get_option(&str, &mpu_irq[nr_dev]) == 2) && (get_option(&str, &dma[nr_dev]) == 2)); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/isa/wavefront/wavefront.c 830-ivtv/sound/isa/wavefront/wavefront.c --- 000-virgin/sound/isa/wavefront/wavefront.c Wed Aug 13 20:24:36 2003 +++ 830-ivtv/sound/isa/wavefront/wavefront.c Thu Jan 8 10:26:50 2004 @@ -418,13 +418,6 @@ snd_wavefront_probe (int dev, struct pnp snd_hwdep_t *fx_processor; int hw_dev = 0, midi_dev = 0, err; - if (cs4232_mpu_port[dev] < 0) - cs4232_mpu_port[dev] = SNDRV_AUTO_PORT; - if (fm_port[dev] < 0) - fm_port[dev] = SNDRV_AUTO_PORT; - if (ics2115_port[dev] < 0) - ics2115_port[dev] = SNDRV_AUTO_PORT; - #ifdef CONFIG_PNP if (!isapnp[dev]) { #endif @@ -490,7 +483,7 @@ snd_wavefront_probe (int dev, struct pnp /* ---------- OPL3 synth --------- */ - if (fm_port[dev] != SNDRV_AUTO_PORT) { + if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) { opl3_t *opl3; if ((err = snd_opl3_create(card, @@ -561,7 +554,7 @@ snd_wavefront_probe (int dev, struct pnp /* ------ ICS2115 internal MIDI ------------ */ - if (ics2115_port[dev] >= 0 && ics2115_port[dev] != SNDRV_AUTO_PORT) { + if (ics2115_port[dev] > 0 && ics2115_port[dev] != SNDRV_AUTO_PORT) { ics2115_internal_rmidi = snd_wavefront_new_midi (card, midi_dev, @@ -578,7 +571,7 @@ snd_wavefront_probe (int dev, struct pnp /* ------ ICS2115 external MIDI ------------ */ - if (ics2115_port[dev] >= 0 && ics2115_port[dev] != SNDRV_AUTO_PORT) { + if (ics2115_port[dev] > 0 && ics2115_port[dev] != SNDRV_AUTO_PORT) { ics2115_external_rmidi = snd_wavefront_new_midi (card, midi_dev, @@ -631,7 +624,7 @@ snd_wavefront_probe (int dev, struct pnp if (dma2[dev] >= 0 && dma2[dev] < 8) sprintf(card->longname + strlen(card->longname), "&%d", dma2[dev]); - if (cs4232_mpu_port[dev] != SNDRV_AUTO_PORT) { + if (cs4232_mpu_port[dev] > 0 && cs4232_mpu_port[dev] != SNDRV_AUTO_PORT) { sprintf (card->longname + strlen (card->longname), " MPU-401 0x%lx irq %d", cs4232_mpu_port[dev], @@ -756,13 +749,13 @@ static int __init alsa_card_wavefront_se get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && get_option(&str,&isapnp[nr_dev]) == 2 && - get_option(&str,(int *)&cs4232_pcm_port[nr_dev]) == 2 && + get_option_long(&str,&cs4232_pcm_port[nr_dev]) == 2 && get_option(&str,&cs4232_pcm_irq[nr_dev]) == 2 && - get_option(&str,(int *)&cs4232_mpu_port[nr_dev]) == 2 && + get_option_long(&str,&cs4232_mpu_port[nr_dev]) == 2 && get_option(&str,&cs4232_mpu_irq[nr_dev]) == 2 && - get_option(&str,(int *)&ics2115_port[nr_dev]) == 2 && + get_option_long(&str,&ics2115_port[nr_dev]) == 2 && get_option(&str,&ics2115_irq[nr_dev]) == 2 && - get_option(&str,(int *)&fm_port[nr_dev]) == 2 && + get_option_long(&str,&fm_port[nr_dev]) == 2 && get_option(&str,&dma1[nr_dev]) == 2 && get_option(&str,&dma2[nr_dev]) == 2 && get_option(&str,&use_cs4232_midi[nr_dev]) == 2); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/ac97/Makefile 830-ivtv/sound/pci/ac97/Makefile --- 000-virgin/sound/pci/ac97/Makefile Wed Aug 13 20:24:37 2003 +++ 830-ivtv/sound/pci/ac97/Makefile Thu Jan 8 10:26:50 2004 @@ -3,7 +3,7 @@ # Copyright (c) 2001 by Jaroslav Kysela # -snd-ac97-codec-objs := ac97_codec.o ac97_proc.o ac97_patch.o +snd-ac97-codec-objs := ac97_codec.o ac97_pcm.o ac97_proc.o ac97_patch.o snd-ak4531-codec-objs := ak4531_codec.o # Toplevel Module Dependency diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/ac97/ac97_codec.c 830-ivtv/sound/pci/ac97/ac97_codec.c --- 000-virgin/sound/pci/ac97/ac97_codec.c Mon Nov 17 18:29:01 2003 +++ 830-ivtv/sound/pci/ac97/ac97_codec.c Thu Jan 8 10:26:50 2004 @@ -101,8 +101,8 @@ static const ac97_codec_id_t snd_ac97_co { 0x41445362, 0xffffffff, "AD1887", patch_ad1881, NULL }, { 0x41445363, 0xffffffff, "AD1886A", patch_ad1881, NULL }, { 0x41445370, 0xffffffff, "AD1980", patch_ad1980, NULL }, -{ 0x41445372, 0xffffffff, "AD1981A", patch_ad1881, NULL }, -{ 0x41445374, 0xffffffff, "AD1981B", patch_ad1881, NULL }, +{ 0x41445372, 0xffffffff, "AD1981A", patch_ad1981a, NULL }, +{ 0x41445374, 0xffffffff, "AD1981B", patch_ad1981b, NULL }, { 0x41445375, 0xffffffff, "AD1985", patch_ad1985, NULL }, { 0x414c4300, 0xfffffff0, "RL5306", NULL, NULL }, { 0x414c4310, 0xfffffff0, "RL5382", NULL, NULL }, @@ -112,6 +112,8 @@ static const ac97_codec_id_t snd_ac97_co { 0x414c4721, 0xfffffff0, "ALC650D", patch_alc650, NULL }, { 0x414c4722, 0xfffffff0, "ALC650E", patch_alc650, NULL }, { 0x414c4723, 0xfffffff0, "ALC650F", patch_alc650, NULL }, +{ 0x414c4760, 0xfffffff0, "ALC655", patch_alc655, NULL }, +{ 0x414c4780, 0xfffffff0, "ALC658", patch_alc655, NULL }, { 0x414c4730, 0xffffffff, "ALC101", NULL, NULL }, { 0x414c4740, 0xfffffff0, "ALC202", NULL, NULL }, { 0x414c4750, 0xfffffff0, "ALC250", NULL, NULL }, @@ -139,6 +141,7 @@ static const ac97_codec_id_t snd_ac97_co { 0x49434551, 0xffffffff, "VT1616", patch_vt1616, NULL }, { 0x49434552, 0xffffffff, "VT1616i", patch_vt1616, NULL }, // VT1616 compatible (chipset integrated) { 0x49544520, 0xffffffff, "IT2226E", NULL, NULL }, +{ 0x49544561, 0xffffffff, "IT2646E", patch_it2646, NULL }, { 0x4e534300, 0xffffffff, "LM4540/43/45/46/48", NULL, NULL }, // only guess --jk { 0x4e534331, 0xffffffff, "LM4549", NULL, NULL }, { 0x4e534350, 0xffffffff, "LM4550", NULL, NULL }, @@ -202,7 +205,7 @@ const char *snd_ac97_stereo_enhancements /* 24 */ "Wolfson Microelectronics 3D Enhancement", /* 25 */ "Delta Integration 3D Enhancement", /* 26 */ "SigmaTel 3D Enhancement", - /* 27 */ "Reserved 27", + /* 27 */ "IC Ensemble/KS Waves", /* 28 */ "Rockwell 3D Stereo Enhancement", /* 29 */ "Reserved 29", /* 30 */ "Reserved 30", @@ -270,7 +273,7 @@ void snd_ac97_write(ac97_t *ac97, unsign { if (!snd_ac97_valid_reg(ac97, reg)) return; - ac97->write(ac97, reg, value); + ac97->bus->write(ac97, reg, value); } /** @@ -288,7 +291,7 @@ unsigned short snd_ac97_read(ac97_t *ac9 { if (!snd_ac97_valid_reg(ac97, reg)) return 0; - return ac97->read(ac97, reg); + return ac97->bus->read(ac97, reg); } /** @@ -308,7 +311,7 @@ void snd_ac97_write_cache(ac97_t *ac97, spin_lock(&ac97->reg_lock); ac97->regs[reg] = value; spin_unlock(&ac97->reg_lock); - ac97->write(ac97, reg, value); + ac97->bus->write(ac97, reg, value); set_bit(reg, ac97->reg_accessed); } @@ -335,7 +338,7 @@ int snd_ac97_update(ac97_t *ac97, unsign if (change) { ac97->regs[reg] = value; spin_unlock(&ac97->reg_lock); - ac97->write(ac97, reg, value); + ac97->bus->write(ac97, reg, value); } else spin_unlock(&ac97->reg_lock); return change; @@ -368,7 +371,7 @@ int snd_ac97_update_bits(ac97_t *ac97, u if (change) { ac97->regs[reg] = new; spin_unlock(&ac97->reg_lock); - ac97->write(ac97, reg, new); + ac97->bus->write(ac97, reg, new); } else spin_unlock(&ac97->reg_lock); return change; @@ -388,11 +391,11 @@ static int snd_ac97_ad18xx_update_pcm_bi ac97->spec.ad18xx.pcmreg[codec] = new; spin_unlock(&ac97->reg_lock); /* select single codec */ - ac97->write(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]); + ac97->bus->write(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]); /* update PCM bits */ - ac97->write(ac97, AC97_PCM, new); + ac97->bus->write(ac97, AC97_PCM, new); /* select all codecs */ - ac97->write(ac97, AC97_AD_SERIAL_CFG, 0x7000); + ac97->bus->write(ac97, AC97_AD_SERIAL_CFG, 0x7000); } else spin_unlock(&ac97->reg_lock); up(&ac97->spec.ad18xx.mutex); @@ -976,9 +979,31 @@ AD18XX_PCM_BITS("LFE Playback Volume", 2 * */ +static int snd_ac97_bus_free(ac97_bus_t *bus) +{ + if (bus) { + snd_ac97_bus_proc_done(bus); + if (bus->pcms) + kfree(bus->pcms); + if (bus->private_free) + bus->private_free(bus); + snd_magic_kfree(bus); + } + return 0; +} + +static int snd_ac97_bus_dev_free(snd_device_t *device) +{ + ac97_bus_t *bus = snd_magic_cast(ac97_bus_t, device->device_data, return -ENXIO); + return snd_ac97_bus_free(bus); +} + static int snd_ac97_free(ac97_t *ac97) { if (ac97) { + snd_ac97_proc_done(ac97); + if (ac97->bus) + ac97->bus->codec[ac97->num] = NULL; if (ac97->private_free) ac97->private_free(ac97); snd_magic_kfree(ac97); @@ -1014,17 +1039,17 @@ static int snd_ac97_try_volume_mix(ac97_ } return 0; case AC97_CENTER_LFE_MASTER: /* center */ - if ((ac97->ext_id & 0x40) == 0) + if ((ac97->ext_id & AC97_EI_CDAC) == 0) return 0; break; case AC97_CENTER_LFE_MASTER+1: /* lfe */ - if ((ac97->ext_id & 0x100) == 0) + if ((ac97->ext_id & AC97_EI_LDAC) == 0) return 0; reg = AC97_CENTER_LFE_MASTER; mask = 0x0080; break; case AC97_SURROUND_MASTER: - if ((ac97->ext_id & 0x80) == 0) + if ((ac97->ext_id & AC97_EI_SDAC) == 0) return 0; break; } @@ -1193,7 +1218,7 @@ static int snd_ac97_cmix_new(snd_card_t static int snd_ac97_mixer_build(ac97_t * ac97) { - snd_card_t *card = ac97->card; + snd_card_t *card = ac97->bus->card; snd_kcontrol_t *kctl; int err; unsigned int idx; @@ -1500,7 +1525,7 @@ static int snd_ac97_test_rate(ac97_t *ac unsigned short val; unsigned int tmp; - tmp = ((unsigned int)rate * ac97->clock) / 48000; + tmp = ((unsigned int)rate * ac97->bus->clock) / 48000; snd_ac97_write_cache(ac97, reg, tmp & 0xffff); val = snd_ac97_read(ac97, reg); return val == (tmp & 0xffff); @@ -1605,13 +1630,62 @@ static int ac97_reset_wait(ac97_t *ac97, } /** - * snd_ac97_mixer - create an AC97 codec component + * snd_ac97_bus - create an AC97 bus component * @card: the card instance + * @_bus: the template of AC97 bus, callbacks and + * the private data. + * @rbus: the pointer to store the new AC97 bus instance. + * + * Creates an AC97 bus component. An ac97_bus_t instance is newly + * allocated and initialized from the template (_bus). + * + * The template must include the valid callbacks (at least read and + * write), the bus number (num), and the private data (private_data). + * The other callbacks, wait and reset, are not mandatory. + * + * The clock is set to 48000. If another clock is needed, set + * bus->clock manually. + * + * The AC97 bus instance is registered as a low-level device, so you don't + * have to release it manually. + * + * Returns zero if successful, or a negative error code on failure. + */ +int snd_ac97_bus(snd_card_t * card, ac97_bus_t * _bus, ac97_bus_t ** rbus) +{ + int err; + ac97_bus_t *bus; + static snd_device_ops_t ops = { + .dev_free = snd_ac97_bus_dev_free, + }; + + snd_assert(card != NULL, return -EINVAL); + snd_assert(_bus != NULL && rbus != NULL, return -EINVAL); + bus = snd_magic_kmalloc(ac97_bus_t, 0, GFP_KERNEL); + if (bus == NULL) + return -ENOMEM; + *bus = *_bus; + bus->card = card; + if (bus->clock == 0) + bus->clock = 48000; + spin_lock_init(&bus->bus_lock); + snd_ac97_bus_proc_init(bus); + if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, bus, &ops)) < 0) { + snd_ac97_bus_free(bus); + return err; + } + *rbus = bus; + return 0; +} + +/** + * snd_ac97_mixer - create an Codec97 component + * @bus: the AC97 bus which codec is attached to * @_ac97: the template of ac97, including index, callbacks and * the private data. * @rac97: the pointer to store the new ac97 instance. * - * Creates an AC97 codec component. An ac97_t instance is newly + * Creates an Codec97 component. An ac97_t instance is newly * allocated and initialized from the template (_ac97). The codec * is then initialized by the standard procedure. * @@ -1620,21 +1694,16 @@ static int ac97_reset_wait(ac97_t *ac97, * data (private_data). The other callbacks, wait and reset, are not * mandatory. * - * The clock is set to 48000. If another clock is needed, reset - * ac97->clock manually afterwards. - * * The ac97 instance is registered as a low-level device, so you don't * have to release it manually. * - * The MCs (Modem Codecs only) are only detected but valid. The PCM driver - * have to check for MCs using the !ac97_is_audio() function. - * * Returns zero if successful, or a negative error code on failure. */ -int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97) +int snd_ac97_mixer(ac97_bus_t * bus, ac97_t * _ac97, ac97_t ** rac97) { int err; ac97_t *ac97; + snd_card_t *card; char name[64]; unsigned long end_time; unsigned int reg; @@ -1644,40 +1713,42 @@ int snd_ac97_mixer(snd_card_t * card, ac snd_assert(rac97 != NULL, return -EINVAL); *rac97 = NULL; - snd_assert(card != NULL && _ac97 != NULL, return -EINVAL); + snd_assert(bus != NULL && _ac97 != NULL, return -EINVAL); + snd_assert(_ac97->num < 4 && bus->codec[_ac97->num] == NULL, return -EINVAL); + card = bus->card; ac97 = snd_magic_kmalloc(ac97_t, 0, GFP_KERNEL); if (ac97 == NULL) return -ENOMEM; *ac97 = *_ac97; - ac97->card = card; + ac97->bus = bus; + bus->codec[ac97->num] = ac97; spin_lock_init(&ac97->reg_lock); if (ac97->pci) { pci_read_config_word(ac97->pci, PCI_SUBSYSTEM_VENDOR_ID, &ac97->subsystem_vendor); pci_read_config_word(ac97->pci, PCI_SUBSYSTEM_ID, &ac97->subsystem_device); } - if (ac97->reset) { - ac97->reset(ac97); + if (bus->reset) { + bus->reset(ac97); goto __access_ok; } snd_ac97_write(ac97, AC97_RESET, 0); /* reset to defaults */ - if (ac97->wait) - ac97->wait(ac97); + if (bus->wait) + bus->wait(ac97); else { udelay(50); if (ac97_reset_wait(ac97, HZ/2, 0) < 0 && ac97_reset_wait(ac97, HZ/2, 1) < 0) { - snd_printk("AC'97 %d:%d does not respond - RESET\n", ac97->num, ac97->addr); - snd_ac97_free(ac97); - return -ENXIO; + snd_printk(KERN_WARNING "AC'97 %d does not respond - RESET\n", ac97->num); + /* proceed anyway - it's often non-critical */ } } __access_ok: ac97->id = snd_ac97_read(ac97, AC97_VENDOR_ID1) << 16; ac97->id |= snd_ac97_read(ac97, AC97_VENDOR_ID2); if (ac97->id == 0x00000000 || ac97->id == 0xffffffff) { - snd_printk("AC'97 %d:%d access is not valid [0x%x], removing mixer.\n", ac97->num, ac97->addr, ac97->id); + snd_printk(KERN_ERR "AC'97 %d access is not valid [0x%x], removing mixer.\n", ac97->num, ac97->id); snd_ac97_free(ac97); return -EIO; } @@ -1697,7 +1768,7 @@ int snd_ac97_mixer(snd_card_t * card, ac } /* test for AC'97 */ - if (! (ac97->scaps & AC97_SCAP_AUDIO)) { + if (!(ac97->scaps & AC97_SCAP_SKIP_AUDIO) && !(ac97->scaps & AC97_SCAP_AUDIO)) { /* test if we can write to the record gain volume register */ snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x8a06); if ((err = snd_ac97_read(ac97, AC97_REC_GAIN)) == 0x8a06) @@ -1711,13 +1782,22 @@ int snd_ac97_mixer(snd_card_t * card, ac } /* test for MC'97 */ - ac97->ext_mid = snd_ac97_read(ac97, AC97_EXTENDED_MID); - if (ac97->ext_mid == 0xffff) /* invalid combination */ - ac97->ext_mid = 0; - if (ac97->ext_mid & 1) - ac97->scaps |= AC97_SCAP_MODEM; + if (!(ac97->scaps & AC97_SCAP_SKIP_MODEM) && !(ac97->scaps & AC97_SCAP_MODEM)) { + ac97->ext_mid = snd_ac97_read(ac97, AC97_EXTENDED_MID); + if (ac97->ext_mid == 0xffff) /* invalid combination */ + ac97->ext_mid = 0; + if (ac97->ext_mid & 1) + ac97->scaps |= AC97_SCAP_MODEM; + } + + if (!ac97_is_audio(ac97) && !ac97_is_modem(ac97)) { + if (!(ac97->scaps & (AC97_SCAP_SKIP_AUDIO|AC97_SCAP_SKIP_MODEM))) + snd_printk(KERN_ERR "AC'97 %d access error (not audio or modem codec)\n", ac97->num); + snd_ac97_free(ac97); + return -EACCES; + } - if (ac97->reset) // FIXME: always skipping? + if (bus->reset) // FIXME: always skipping? goto __ready_ok; /* FIXME: add powerdown control */ @@ -1736,12 +1816,43 @@ int snd_ac97_mixer(snd_card_t * card, ac set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/10); } while (time_after_eq(end_time, jiffies)); - snd_printk("AC'97 %d:%d analog subsections not ready\n", ac97->num, ac97->addr); + snd_printk(KERN_ERR "AC'97 %d analog subsections not ready\n", ac97->num); } + /* FIXME: add powerdown control */ + if (ac97_is_modem(ac97)) { + unsigned char tmp; + + /* nothing should be in powerdown mode */ + /* note: it's important to set the rate at first */ + tmp = AC97_MEA_GPIO; + if (ac97->ext_mid & AC97_MEI_LINE1) { + snd_ac97_write_cache(ac97, AC97_LINE1_RATE, 12000); + tmp |= AC97_MEA_ADC1 | AC97_MEA_DAC1; + } + if (ac97->ext_mid & AC97_MEI_LINE2) { + snd_ac97_write_cache(ac97, AC97_LINE2_RATE, 12000); + tmp |= AC97_MEA_ADC2 | AC97_MEA_DAC2; + } + if (ac97->ext_mid & AC97_MEI_HANDSET) { + snd_ac97_write_cache(ac97, AC97_HANDSET_RATE, 12000); + tmp |= AC97_MEA_HADC | AC97_MEA_HDAC; + } + snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8)); + udelay(100); + /* nothing should be in powerdown mode */ + snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8)); + end_time = jiffies + (HZ / 10); + do { + if ((snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS) & tmp) == tmp) + goto __ready_ok; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ/10); + } while (time_after_eq(end_time, jiffies)); + snd_printk(KERN_ERR "MC'97 %d converters and GPIO not ready (0x%x)\n", ac97->num, snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS)); + } + __ready_ok: - if (ac97->clock == 0) - ac97->clock = 48000; /* standard value */ if (ac97_is_audio(ac97)) ac97->addr = (ac97->ext_id & AC97_EI_ADDR_MASK) >> AC97_EI_ADDR_SHIFT; else @@ -1780,8 +1891,8 @@ int snd_ac97_mixer(snd_card_t * card, ac ac97->scaps |= AC97_SCAP_CENTER_LFE_DAC; } /* additional initializations */ - if (ac97->init) - ac97->init(ac97); + if (bus->init) + bus->init(ac97); snd_ac97_get_name(ac97, ac97->id, name, 0); snd_ac97_get_name(NULL, ac97->id, name, 0); // ac97->id might be changed in the special setup code if (ac97_is_audio(ac97)) { @@ -1802,183 +1913,6 @@ int snd_ac97_mixer(snd_card_t * card, ac return -ENOMEM; } } - snd_ac97_proc_init(card, ac97, "ac97"); - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ac97, &ops)) < 0) { - snd_ac97_free(ac97); - return err; - } - *rac97 = ac97; - return 0; -} - -/* wait for a while until registers are accessible after RESET - * return 0 if ok, negative not ready - */ -static int ac97_modem_reset_wait(ac97_t *ac97, int timeout) -{ - unsigned long end_time; - end_time = jiffies + timeout; - do { - unsigned short ext_mid; - - /* use preliminary reads to settle the communication */ - snd_ac97_read(ac97, AC97_EXTENDED_MID); - snd_ac97_read(ac97, AC97_VENDOR_ID1); - snd_ac97_read(ac97, AC97_VENDOR_ID2); - ext_mid = snd_ac97_read(ac97, AC97_EXTENDED_MID); - if (ext_mid != 0xffff && (ext_mid & 1) != 0) - return 0; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/100); - } while (time_after_eq(end_time, jiffies)); - return -ENODEV; -} - -/** - * snd_ac97_modem - create an MC97 codec component - * @card: the card instance - * @_ac97: the template of ac97, including index, callbacks and - * the private data. - * @rac97: the pointer to store the new ac97 instance. - * - * Creates an MC97 codec component. An ac97_t instance is newly - * allocated and initialized from the template (_ac97). The codec - * is then initialized by the standard procedure. - * - * The template must include the valid callbacks (at least read and - * write), the codec number (num) and address (addr), and the private - * data (private_data). The other callbacks, wait and reset, are not - * mandatory. - * - * The clock is set to 48000. If another clock is needed, reset - * ac97->clock manually afterwards. - * - * The ac97 instance is registered as a low-level device, so you don't - * have to release it manually. - * - * The ACs (Audio Codecs only) are only detected but valid. The PCM driver - * have to check for ACs using the !ac97_is_modem() function. - * - * Returns zero if successful, or a negative error code on failure. - */ -int snd_ac97_modem(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97) -{ - int err; - ac97_t *ac97; - char name[64]; - unsigned long end_time; - unsigned short tmp; - static snd_device_ops_t ops = { - .dev_free = snd_ac97_dev_free, - }; - - snd_assert(rac97 != NULL, return -EINVAL); - *rac97 = NULL; - snd_assert(card != NULL && _ac97 != NULL, return -EINVAL); - ac97 = snd_magic_kcalloc(ac97_t, 0, GFP_KERNEL); - if (ac97 == NULL) - return -ENOMEM; - *ac97 = *_ac97; - ac97->card = card; - spin_lock_init(&ac97->reg_lock); - - ac97->pci = _ac97->pci; - if (ac97->pci) { - pci_read_config_word(ac97->pci, PCI_SUBSYSTEM_VENDOR_ID, &ac97->subsystem_vendor); - pci_read_config_word(ac97->pci, PCI_SUBSYSTEM_ID, &ac97->subsystem_device); - } - - if (ac97->reset) { - ac97->reset(ac97); - goto __access_ok; - } - - snd_ac97_write(ac97, AC97_EXTENDED_MID, 0); /* reset to defaults */ - if (ac97->wait) - ac97->wait(ac97); - else { - udelay(50); - if (ac97_modem_reset_wait(ac97, HZ/2) < 0) { - snd_printk("MC'97 %d:%d does not respond - MODEM RESET\n", ac97->num, ac97->addr); - snd_ac97_free(ac97); - return -ENXIO; - } - } - __access_ok: - ac97->id = snd_ac97_read(ac97, AC97_VENDOR_ID1) << 16; - ac97->id |= snd_ac97_read(ac97, AC97_VENDOR_ID2); - if (ac97->id == 0x00000000 || ac97->id == 0xffffffff) { - snd_printk("MC'97 %d:%d access is not valid [0x%x], removing modem controls.\n", ac97->num, ac97->addr, ac97->id); - snd_ac97_free(ac97); - return -EIO; - } - - /* test for MC'97 */ - ac97->ext_mid = snd_ac97_read(ac97, AC97_EXTENDED_MID); - if (ac97->ext_mid == 0xffff) /* invalid combination */ - ac97->ext_mid = 0; - if (ac97->ext_mid & 1) - ac97->scaps |= AC97_SCAP_MODEM; - - /* non-destructive test for AC'97 */ - tmp = snd_ac97_read(ac97, AC97_RESET); - if (tmp == 0 || tmp == 0xffff) { - tmp = snd_ac97_read(ac97, AC97_EXTENDED_ID); - if (tmp == 0 || tmp == 0xffff) { - tmp = snd_ac97_read(ac97, AC97_REC_GAIN); - if (tmp == 0 || tmp == 0xffff) - tmp = snd_ac97_read(ac97, AC97_POWERDOWN); - } - } - if ((tmp != 0 && tmp != 0xffff) || !(ac97->scaps & AC97_SCAP_MODEM)) - ac97->scaps |= AC97_SCAP_AUDIO; - - if (ac97->reset) // FIXME: always skipping? - goto __ready_ok; - - /* FIXME: add powerdown control */ - if (ac97->scaps & AC97_SCAP_MODEM) { - /* nothing should be in powerdown mode */ - /* note: it's important to set the rate at first */ - tmp = AC97_MEA_GPIO; - if (ac97->ext_mid & AC97_MEI_LINE1) { - snd_ac97_write_cache(ac97, AC97_LINE1_RATE, 12000); - tmp |= AC97_MEA_ADC1 | AC97_MEA_DAC1; - } - if (ac97->ext_mid & AC97_MEI_LINE2) { - snd_ac97_write_cache(ac97, AC97_LINE2_RATE, 12000); - tmp |= AC97_MEA_ADC2 | AC97_MEA_DAC2; - } - if (ac97->ext_mid & AC97_MEI_HANDSET) { - snd_ac97_write_cache(ac97, AC97_HANDSET_RATE, 12000); - tmp |= AC97_MEA_HADC | AC97_MEA_HDAC; - } - snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8)); - udelay(100); - /* nothing should be in powerdown mode */ - snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8)); - end_time = jiffies + (HZ / 10); - do { - if ((snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS) & tmp) == tmp) - goto __ready_ok; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/10); - } while (time_after_eq(end_time, jiffies)); - snd_printk("MC'97 %d:%d converters and GPIO not ready (0x%x)\n", ac97->num, ac97->addr, snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS)); - } - - __ready_ok: - /* additional initializations */ - /* FIXME: ADD MODEM INITALIZATION */ - if (ac97_is_modem(ac97)) - ac97->addr = (ac97->ext_mid & AC97_MEI_ADDR_MASK) >> AC97_MEI_ADDR_SHIFT; - else - ac97->addr = (ac97->ext_id & AC97_EI_ADDR_MASK) >> AC97_EI_ADDR_SHIFT; - - if (ac97->init) - ac97->init(ac97); - snd_ac97_get_name(ac97, ac97->id, name, 1); - snd_ac97_get_name(NULL, ac97->id, name, 1); // ac97->id might be changed in the special setup code if (ac97_is_modem(ac97)) { if (card->mixername[0] == '\0') { strcpy(card->mixername, name); @@ -1992,12 +1926,12 @@ int snd_ac97_modem(snd_card_t * card, ac snd_ac97_free(ac97); return err; } + if (snd_ac97_modem_build(card, ac97) < 0) { + snd_ac97_free(ac97); + return -ENOMEM; + } } - if (ac97_is_modem(ac97) && snd_ac97_modem_build(card, ac97) < 0) { - snd_ac97_free(ac97); - return -ENOMEM; - } - snd_ac97_proc_init(card, ac97, "mc97"); + snd_ac97_proc_init(ac97); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ac97, &ops)) < 0) { snd_ac97_free(ac97); return err; @@ -2006,110 +1940,6 @@ int snd_ac97_modem(snd_card_t * card, ac return 0; } -/* - * PCM support - */ - -static int set_spdif_rate(ac97_t *ac97, unsigned short rate) -{ - unsigned short old, bits, reg, mask; - - if (! (ac97->ext_id & AC97_EI_SPDIF)) - return -ENODEV; - - if (ac97->flags & AC97_CS_SPDIF) { - switch (rate) { - case 48000: bits = 0; break; - case 44100: bits = 1 << AC97_SC_SPSR_SHIFT; break; - default: /* invalid - disable output */ - snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); - return -EINVAL; - } - reg = AC97_CSR_SPDIF; - mask = 1 << AC97_SC_SPSR_SHIFT; - } else { - if (ac97->id == AC97_ID_CM9739 && rate != 48000) { - snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); - return -EINVAL; - } - switch (rate) { - case 44100: bits = AC97_SC_SPSR_44K; break; - case 48000: bits = AC97_SC_SPSR_48K; break; - case 32000: bits = AC97_SC_SPSR_32K; break; - default: /* invalid - disable output */ - snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); - return -EINVAL; - } - reg = AC97_SPDIF; - mask = AC97_SC_SPSR_MASK; - } - - spin_lock(&ac97->reg_lock); - old = ac97->regs[reg] & mask; - spin_unlock(&ac97->reg_lock); - if (old != bits) { - snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); - snd_ac97_update_bits(ac97, reg, mask, bits); - } - snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF); - return 0; -} - -/** - * snd_ac97_set_rate - change the rate of the given input/output. - * @ac97: the ac97 instance - * @reg: the register to change - * @rate: the sample rate to set - * - * Changes the rate of the given input/output on the codec. - * If the codec doesn't support VAR, the rate must be 48000 (except - * for SPDIF). - * - * The valid registers are AC97_PMC_MIC_ADC_RATE, - * AC97_PCM_FRONT_DAC_RATE, AC97_PCM_LR_ADC_RATE and AC97_SPDIF. - * The SPDIF register is a pseudo-register to change the rate of SPDIF - * (only if supported). - * - * Returns zero if successful, or a negative error code on failure. - */ -int snd_ac97_set_rate(ac97_t *ac97, int reg, unsigned short rate) -{ - unsigned short mask; - unsigned int tmp; - - switch (reg) { - case AC97_PCM_MIC_ADC_RATE: - mask = 0x0000; - if ((ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_VRM) == 0) /* MIC VRA */ - if (rate != 48000) - return -EINVAL; - break; - case AC97_PCM_FRONT_DAC_RATE: - mask = 0x0200; - if ((ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_VRA) == 0) /* VRA */ - if (rate != 48000) - return -EINVAL; - break; - case AC97_PCM_LR_ADC_RATE: - mask = 0x0100; - if ((ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_VRA) == 0) /* VRA */ - if (rate != 48000) - return -EINVAL; - break; - case AC97_SPDIF: - return set_spdif_rate(ac97, rate); - default: - return -EINVAL; - } - tmp = ((unsigned int)rate * ac97->clock) / 48000; - if (tmp > 65535) - return -EINVAL; - snd_ac97_update(ac97, reg, tmp & 0xffff); - snd_ac97_read(ac97, reg); - return 0; -} - - #ifdef CONFIG_PM /** * snd_ac97_suspend - General suspend function for AC97 codec @@ -2143,8 +1973,8 @@ void snd_ac97_resume(ac97_t *ac97) { int i, is_ad18xx, codec; - if (ac97->reset) { - ac97->reset(ac97); + if (ac97->bus->reset) { + ac97->bus->reset(ac97); goto __reset_ready; } @@ -2155,29 +1985,29 @@ void snd_ac97_resume(ac97_t *ac97) snd_ac97_write(ac97, AC97_GENERAL_PURPOSE, 0); snd_ac97_write(ac97, AC97_POWERDOWN, ac97->regs[AC97_POWERDOWN]); - snd_ac97_write(ac97, AC97_MASTER, 0x8000); + snd_ac97_write(ac97, AC97_MASTER, 0x8101); for (i = 0; i < 10; i++) { - if (snd_ac97_read(ac97, AC97_MASTER) == 0x8000) + if (snd_ac97_read(ac97, AC97_MASTER) == 0x8101) break; mdelay(1); } __reset_ready: - if (ac97->init) - ac97->init(ac97); + if (ac97->bus->init) + ac97->bus->init(ac97); - is_ad18xx = (ac97->id & 0xffffff40) == AC97_ID_AD1881; + is_ad18xx = (ac97->flags & AC97_AD_MULTI); if (is_ad18xx) { /* restore the AD18xx codec configurations */ for (codec = 0; codec < 3; codec++) { if (! ac97->spec.ad18xx.id[codec]) continue; /* select single codec */ - ac97->write(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]); - ac97->write(ac97, AC97_AD_CODEC_CFG, ac97->spec.ad18xx.codec_cfg[codec]); + ac97->bus->write(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]); + ac97->bus->write(ac97, AC97_AD_CODEC_CFG, ac97->spec.ad18xx.codec_cfg[codec]); } /* select all codecs */ - ac97->write(ac97, AC97_AD_SERIAL_CFG, 0x7000); + ac97->bus->write(ac97, AC97_AD_SERIAL_CFG, 0x7000); } /* restore ac97 status */ @@ -2196,12 +2026,12 @@ __reset_ready: if (! ac97->spec.ad18xx.id[codec]) continue; /* select single codec */ - ac97->write(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]); + ac97->bus->write(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]); /* update PCM bits */ - ac97->write(ac97, AC97_PCM, ac97->spec.ad18xx.pcmreg[codec]); + ac97->bus->write(ac97, AC97_PCM, ac97->spec.ad18xx.pcmreg[codec]); } /* select all codecs */ - ac97->write(ac97, AC97_AD_SERIAL_CFG, 0x7000); + ac97->bus->write(ac97, AC97_AD_SERIAL_CFG, 0x7000); continue; } else if (i == AC97_AD_TEST || i == AC97_AD_CODEC_CFG || @@ -2231,13 +2061,13 @@ __reset_ready: /* */ -static int remove_ctl(ac97_t *ac97, const char *name) +int snd_ac97_remove_ctl(ac97_t *ac97, const char *name) { snd_ctl_elem_id_t id; memset(&id, 0, sizeof(id)); strcpy(id.name, name); id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - return snd_ctl_remove_id(ac97->card, &id); + return snd_ctl_remove_id(ac97->bus->card, &id); } static snd_kcontrol_t *ctl_find(ac97_t *ac97, const char *name) @@ -2246,10 +2076,10 @@ static snd_kcontrol_t *ctl_find(ac97_t * memset(&sid, 0, sizeof(sid)); strcpy(sid.name, name); sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - return snd_ctl_find_id(ac97->card, &sid); + return snd_ctl_find_id(ac97->bus->card, &sid); } -static int rename_ctl(ac97_t *ac97, const char *src, const char *dst) +int snd_ac97_rename_ctl(ac97_t *ac97, const char *src, const char *dst) { snd_kcontrol_t *kctl = ctl_find(ac97, src); if (kctl) { @@ -2259,7 +2089,7 @@ static int rename_ctl(ac97_t *ac97, cons return -ENOENT; } -static int swap_ctl(ac97_t *ac97, const char *s1, const char *s2) +int snd_ac97_swap_ctl(ac97_t *ac97, const char *s1, const char *s2) { snd_kcontrol_t *kctl1, *kctl2; kctl1 = ctl_find(ac97, s1); @@ -2276,22 +2106,22 @@ static int swap_headphone(ac97_t *ac97, { /* FIXME: error checks.. */ if (remove_master) { - remove_ctl(ac97, "Master Playback Switch"); - remove_ctl(ac97, "Master Playback Volume"); + snd_ac97_remove_ctl(ac97, "Master Playback Switch"); + snd_ac97_remove_ctl(ac97, "Master Playback Volume"); } else { - rename_ctl(ac97, "Master Playback Switch", "Line-Out Playback Switch"); - rename_ctl(ac97, "Master Playback Volume", "Line-Out Playback Volume"); + snd_ac97_rename_ctl(ac97, "Master Playback Switch", "Line-Out Playback Switch"); + snd_ac97_rename_ctl(ac97, "Master Playback Volume", "Line-Out Playback Volume"); } - rename_ctl(ac97, "Headphone Playback Switch", "Master Playback Switch"); - rename_ctl(ac97, "Headphone Playback Volume", "Master Playback Volume"); + snd_ac97_rename_ctl(ac97, "Headphone Playback Switch", "Master Playback Switch"); + snd_ac97_rename_ctl(ac97, "Headphone Playback Volume", "Master Playback Volume"); return 0; } static int swap_surround(ac97_t *ac97) { /* FIXME: error checks.. */ - swap_ctl(ac97, "Master Playback Switch", "Surround Playback Switch"); - swap_ctl(ac97, "Master Playback Volume", "Surround Playback Volume"); + snd_ac97_swap_ctl(ac97, "Master Playback Switch", "Surround Playback Switch"); + snd_ac97_swap_ctl(ac97, "Master Playback Volume", "Surround Playback Volume"); return 0; } @@ -2301,7 +2131,7 @@ static int tune_ad_sharing(ac97_t *ac97) /* Turn on OMS bit to route microphone to back panel */ scfg = snd_ac97_read(ac97, AC97_AD_SERIAL_CFG); snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, scfg | 0x0200); - return swap_headphone(ac97, 1); + return 0; } /** @@ -2353,10 +2183,13 @@ EXPORT_SYMBOL(snd_ac97_read); EXPORT_SYMBOL(snd_ac97_write_cache); EXPORT_SYMBOL(snd_ac97_update); EXPORT_SYMBOL(snd_ac97_update_bits); +EXPORT_SYMBOL(snd_ac97_bus); EXPORT_SYMBOL(snd_ac97_mixer); -EXPORT_SYMBOL(snd_ac97_modem); -EXPORT_SYMBOL(snd_ac97_set_rate); +EXPORT_SYMBOL(snd_ac97_pcm_assign); +EXPORT_SYMBOL(snd_ac97_pcm_open); +EXPORT_SYMBOL(snd_ac97_pcm_close); EXPORT_SYMBOL(snd_ac97_tune_hardware); +EXPORT_SYMBOL(snd_ac97_set_rate); #ifdef CONFIG_PM EXPORT_SYMBOL(snd_ac97_resume); #endif diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/ac97/ac97_local.h 830-ivtv/sound/pci/ac97/ac97_local.h --- 000-virgin/sound/pci/ac97/ac97_local.h Mon Nov 17 18:29:01 2003 +++ 830-ivtv/sound/pci/ac97/ac97_local.h Thu Jan 8 10:26:50 2004 @@ -37,6 +37,12 @@ int snd_ac97_info_single(snd_kcontrol_t int snd_ac97_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol); int snd_ac97_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol); int snd_ac97_try_bit(ac97_t * ac97, int reg, int bit); +int snd_ac97_remove_ctl(ac97_t *ac97, const char *name); +int snd_ac97_rename_ctl(ac97_t *ac97, const char *src, const char *dst); +int snd_ac97_swap_ctl(ac97_t *ac97, const char *s1, const char *s2); /* ac97_proc.c */ -void snd_ac97_proc_init(snd_card_t * card, ac97_t * ac97, const char *prefix); +void snd_ac97_bus_proc_init(ac97_bus_t * ac97); +void snd_ac97_bus_proc_done(ac97_bus_t * ac97); +void snd_ac97_proc_init(ac97_t * ac97); +void snd_ac97_proc_done(ac97_t * ac97); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/ac97/ac97_patch.c 830-ivtv/sound/pci/ac97/ac97_patch.c --- 000-virgin/sound/pci/ac97/ac97_patch.c Mon Nov 17 18:29:01 2003 +++ 830-ivtv/sound/pci/ac97/ac97_patch.c Thu Jan 8 10:26:50 2004 @@ -46,7 +46,7 @@ static int patch_build_controls(ac97_t * int idx, err; for (idx = 0; idx < count; idx++) - if ((err = snd_ctl_add(ac97->card, snd_ac97_cnew(&controls[idx], ac97))) < 0) + if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&controls[idx], ac97))) < 0) return err; return 0; } @@ -201,12 +201,12 @@ static int patch_yamaha_ymf753_3d(ac97_t snd_kcontrol_t *kctl; int err; - if ((err = snd_ctl_add(ac97->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) + if ((err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) return err; strcpy(kctl->id.name, "3D Control - Wide"); kctl->private_value = AC97_3D_CONTROL | (9 << 8) | (7 << 16); snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); - if ((err = snd_ctl_add(ac97->card, snd_ac97_cnew(&snd_ac97_ymf753_controls_speaker, ac97))) < 0) + if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&snd_ac97_ymf753_controls_speaker, ac97))) < 0) return err; snd_ac97_write_cache(ac97, AC97_YMF753_3D_MODE_SEL, 0x0c00); return 0; @@ -306,7 +306,7 @@ static int patch_sigmatel_stac9700_3d(ac snd_kcontrol_t *kctl; int err; - if ((err = snd_ctl_add(ac97->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) + if ((err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) return err; strcpy(kctl->id.name, "3D Control Sigmatel - Depth"); kctl->private_value = AC97_3D_CONTROL | (3 << 16); @@ -319,11 +319,11 @@ static int patch_sigmatel_stac9708_3d(ac snd_kcontrol_t *kctl; int err; - if ((err = snd_ctl_add(ac97->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) + if ((err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) return err; strcpy(kctl->id.name, "3D Control Sigmatel - Depth"); kctl->private_value = AC97_3D_CONTROL | (3 << 16); - if ((err = snd_ctl_add(ac97->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) + if ((err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) return err; strcpy(kctl->id.name, "3D Control Sigmatel - Rear Depth"); kctl->private_value = AC97_3D_CONTROL | (2 << 8) | (3 << 16); @@ -708,7 +708,7 @@ int patch_ad1886(ac97_t * ac97) #define AC97_AD198X_2MIC 0x0040 /* 2-channel mic select */ #define AC97_AD198X_SPRD 0x0080 /* SPREAD enable */ #define AC97_AD198X_DMIX0 0x0100 /* downmix mode: 0 = 6-to-4, 1 = 6-to-2 downmix */ -#define AC97_AD198X_DMIX1 0x0300 /* downmix mode: 1 = enabled */ +#define AC97_AD198X_DMIX1 0x0200 /* downmix mode: 1 = enabled */ #define AC97_AD198X_HPSEL 0x0400 /* headphone amplifier input select */ #define AC97_AD198X_CLDIS 0x0800 /* center/lfe disable */ #define AC97_AD198X_LODIS 0x1000 /* LINE_OUT disable */ @@ -717,7 +717,7 @@ int patch_ad1886(ac97_t * ac97) #define AC97_AD198X_DACZ 0x8000 /* DAC zero-fill mode */ -static int snd_ac97_ad1980_spdif_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +static int snd_ac97_ad198x_spdif_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { static char *texts[2] = { "AC-Link", "A/D Converter" }; @@ -730,7 +730,7 @@ static int snd_ac97_ad1980_spdif_source_ return 0; } -static int snd_ac97_ad1980_spdif_source_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +static int snd_ac97_ad198x_spdif_source_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { ac97_t *ac97 = snd_kcontrol_chip(kcontrol); unsigned short val; @@ -740,7 +740,7 @@ static int snd_ac97_ad1980_spdif_source_ return 0; } -static int snd_ac97_ad1980_spdif_source_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +static int snd_ac97_ad198x_spdif_source_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { ac97_t *ac97 = snd_kcontrol_chip(kcontrol); unsigned short val; @@ -751,21 +751,163 @@ static int snd_ac97_ad1980_spdif_source_ return snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x0004, val); } -static const snd_kcontrol_new_t snd_ac97_ad1980_spdif_source = { +static const snd_kcontrol_new_t snd_ac97_ad198x_spdif_source = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", - .info = snd_ac97_ad1980_spdif_source_info, - .get = snd_ac97_ad1980_spdif_source_get, - .put = snd_ac97_ad1980_spdif_source_put, + .info = snd_ac97_ad198x_spdif_source_info, + .get = snd_ac97_ad198x_spdif_source_get, + .put = snd_ac97_ad198x_spdif_source_put, }; -static int patch_ad1980_post_spdif(ac97_t * ac97) +static int patch_ad198x_post_spdif(ac97_t * ac97) { - return patch_build_controls(ac97, &snd_ac97_ad1980_spdif_source, 1); + return patch_build_controls(ac97, &snd_ac97_ad198x_spdif_source, 1); +} + +static struct snd_ac97_build_ops patch_ad1981a_build_ops = { + .build_post_spdif = patch_ad198x_post_spdif +}; + +int patch_ad1981a(ac97_t *ac97) +{ + patch_ad1881(ac97); + ac97->build_ops = &patch_ad1981a_build_ops; + snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD198X_MSPLT, AC97_AD198X_MSPLT); + ac97->flags |= AC97_STEREO_MUTES; + return 0; +} + +static const snd_kcontrol_new_t snd_ac97_ad198x_2cmic = +AC97_SINGLE("Stereo Mic", AC97_AD_MISC, 6, 1, 0); + +static int patch_ad1981b_specific(ac97_t *ac97) +{ + return patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1); +} + +static struct snd_ac97_build_ops patch_ad1981b_build_ops = { + .build_post_spdif = patch_ad198x_post_spdif, + .build_specific = patch_ad1981b_specific +}; + +int patch_ad1981b(ac97_t *ac97) +{ + patch_ad1881(ac97); + ac97->build_ops = &patch_ad1981b_build_ops; + snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD198X_MSPLT, AC97_AD198X_MSPLT); + ac97->flags |= AC97_STEREO_MUTES; + return 0; +} + +static int snd_ac97_ad1980_lohpsel_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_ac97_ad1980_lohpsel_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t* ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + + val = ac97->regs[AC97_AD_MISC]; + ucontrol->value.integer.value[0] = !(val & AC97_AD198X_LOSEL); + return 0; +} + +static int snd_ac97_ad1980_lohpsel_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + + val = !ucontrol->value.integer.value[0] + ? (AC97_AD198X_LOSEL | AC97_AD198X_HPSEL) : 0; + return snd_ac97_update_bits(ac97, AC97_AD_MISC, + AC97_AD198X_LOSEL | AC97_AD198X_HPSEL, val); +} + +static int snd_ac97_ad1980_downmix_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + static char *texts[3] = {"Off", "6 -> 4", "6 -> 2"}; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 3; + if (uinfo->value.enumerated.item > 2) + uinfo->value.enumerated.item = 2; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_ac97_ad1980_downmix_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t* ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + + val = ac97->regs[AC97_AD_MISC]; + if (!(val & AC97_AD198X_DMIX1)) + ucontrol->value.enumerated.item[0] = 0; + else + ucontrol->value.enumerated.item[0] = 1 + ((val >> 8) & 1); + return 0; +} + +static int snd_ac97_ad1980_downmix_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + + if (ucontrol->value.enumerated.item[0] > 2) + return -EINVAL; + if (ucontrol->value.enumerated.item[0] == 0) + val = 0; + else + val = AC97_AD198X_DMIX1 | + ((ucontrol->value.enumerated.item[0] - 1) << 8); + return snd_ac97_update_bits(ac97, AC97_AD_MISC, + AC97_AD198X_DMIX0 | AC97_AD198X_DMIX1, val); +} + +static const snd_kcontrol_new_t snd_ac97_ad1980_controls[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Exchange Front/Surround", + .info = snd_ac97_ad1980_lohpsel_info, + .get = snd_ac97_ad1980_lohpsel_get, + .put = snd_ac97_ad1980_lohpsel_put + }, + AC97_SINGLE("Spread Front to Surround and Center/LFE", AC97_AD_MISC, 7, 1, 0), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Downmix", + .info = snd_ac97_ad1980_downmix_info, + .get = snd_ac97_ad1980_downmix_get, + .put = snd_ac97_ad1980_downmix_put + }, + AC97_SINGLE("Surround Jack as Input", AC97_AD_MISC, 12, 1, 0), + AC97_SINGLE("Center/LFE Jack as Input", AC97_AD_MISC, 11, 1, 0), +}; + +static int patch_ad1980_specific(ac97_t *ac97) +{ + int err; + + /* rename 0x04 as "Master" and 0x02 as "Master Surround" */ + snd_ac97_rename_ctl(ac97, "Master Playback Switch", "Master Surround Playback Switch"); + snd_ac97_rename_ctl(ac97, "Master Playback Volume", "Master Surround Playback Volume"); + snd_ac97_rename_ctl(ac97, "Headphone Playback Switch", "Master Playback Switch"); + snd_ac97_rename_ctl(ac97, "Headphone Playback Volume", "Master Playback Volume"); + if ((err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1)) < 0) + return err; + return patch_build_controls(ac97, snd_ac97_ad1980_controls, ARRAY_SIZE(snd_ac97_ad1980_controls)); } static struct snd_ac97_build_ops patch_ad1980_build_ops = { - .build_post_spdif = &patch_ad1980_post_spdif + .build_post_spdif = patch_ad198x_post_spdif, + .build_specific = patch_ad1980_specific }; int patch_ad1980(ac97_t * ac97) @@ -776,22 +918,43 @@ int patch_ad1980(ac97_t * ac97) ac97->build_ops = &patch_ad1980_build_ops; /* Switch FRONT/SURROUND LINE-OUT/HP-OUT default connection */ /* it seems that most vendors connect line-out connector to headphone out of AC'97 */ + /* AD-compatible mode */ /* Stereo mutes enabled */ misc = snd_ac97_read(ac97, AC97_AD_MISC); snd_ac97_write_cache(ac97, AC97_AD_MISC, misc | AC97_AD198X_LOSEL | AC97_AD198X_HPSEL | - AC97_AD198X_MSPLT); + AC97_AD198X_MSPLT | + AC97_AD198X_AC97NC); ac97->flags |= AC97_STEREO_MUTES; return 0; } +static const snd_kcontrol_new_t snd_ac97_ad1985_controls[] = { + AC97_SINGLE("Center/LFE Jack as Mic", AC97_AD_SERIAL_CFG, 9, 1, 0), + AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0) +}; + +static int patch_ad1985_specific(ac97_t *ac97) +{ + int err; + + if ((err = patch_ad1980_specific(ac97)) < 0) + return err; + return patch_build_controls(ac97, snd_ac97_ad1985_controls, ARRAY_SIZE(snd_ac97_ad1985_controls)); +} + +static struct snd_ac97_build_ops patch_ad1985_build_ops = { + .build_post_spdif = patch_ad198x_post_spdif, + .build_specific = patch_ad1985_specific +}; + int patch_ad1985(ac97_t * ac97) { unsigned short misc; patch_ad1881(ac97); - ac97->build_ops = &patch_ad1980_build_ops; + ac97->build_ops = &patch_ad1985_build_ops; misc = snd_ac97_read(ac97, AC97_AD_MISC); /* switch front/surround line-out/hp-out */ /* center/LFE, surround in High-Z mode */ @@ -820,6 +983,8 @@ static const snd_kcontrol_new_t snd_ac97 /* 7: Independent Master Volume Left */ /* 8: reserved */ AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0), + /* 10: mic, see below */ + /* 11-13: in IEC958 controls */ AC97_SINGLE("Swap Surround Slot", AC97_ALC650_MULTICH, 14, 1, 0), #if 0 /* always set in patch_alc650 */ AC97_SINGLE("IEC958 Input Clock Enable", AC97_ALC650_CLOCK, 0, 1, 0), @@ -898,7 +1063,6 @@ static struct snd_ac97_build_ops patch_a int patch_alc650(ac97_t * ac97) { unsigned short val; - int spdif = 0; ac97->build_ops = &patch_alc650_ops; @@ -907,22 +1071,16 @@ int patch_alc650(ac97_t * ac97) ac97->spec.dev_flags = (ac97->id == 0x414c4722 || ac97->id == 0x414c4723); - /* check spdif (should be only on rev.E) */ - if (ac97->spec.dev_flags) { - val = snd_ac97_read(ac97, AC97_EXTENDED_STATUS); - if (val & AC97_EA_SPCV) - spdif = 1; - } + /* enable AC97_ALC650_GPIO_SETUP, AC97_ALC650_CLOCK for R/W */ + snd_ac97_write_cache(ac97, AC97_ALC650_GPIO_STATUS, + snd_ac97_read(ac97, AC97_ALC650_GPIO_STATUS) | 0x8000); - if (spdif) { - /* enable AC97_ALC650_GPIO_SETUP, AC97_ALC650_CLOCK for R/W */ - snd_ac97_write_cache(ac97, AC97_ALC650_GPIO_STATUS, - snd_ac97_read(ac97, AC97_ALC650_GPIO_STATUS) | 0x8000); + /* Enable SPDIF-IN only on Rev.E and above */ + if (ac97->spec.dev_flags) { /* enable spdif in */ snd_ac97_write_cache(ac97, AC97_ALC650_CLOCK, snd_ac97_read(ac97, AC97_ALC650_CLOCK) | 0x03); - } else - ac97->ext_id &= ~AC97_EI_SPDIF; /* disable extended-id */ + } val = snd_ac97_read(ac97, AC97_ALC650_MULTICH); val &= ~0xc000; /* slot: 3,4,7,8,6,9 */ @@ -953,6 +1111,98 @@ int patch_alc650(ac97_t * ac97) return 0; } +static const snd_kcontrol_new_t snd_ac97_controls_alc655[] = { + AC97_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0), + AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0), + AC97_SINGLE("Mic As Center/LFE", AC97_ALC650_MULTICH, 10, 1, 0), +}; + +static int alc655_iec958_route_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + static char *texts_655[3] = { "PCM", "Analog In", "IEC958 In" }; + static char *texts_658[4] = { "PCM", "Analog1 In", "Analog2 In", "IEC958 In" }; + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = ac97->spec.dev_flags ? 4 : 3; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + ac97->spec.dev_flags ? + texts_658[uinfo->value.enumerated.item] : + texts_655[uinfo->value.enumerated.item]); + return 0; + +} + +static int alc655_iec958_route_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + + val = ac97->regs[AC97_ALC650_MULTICH]; + val = (val >> 12) & 3; + if (ac97->spec.dev_flags && val == 3) + val = 0; + ucontrol->value.enumerated.item[0] = val; + return 0; +} + +static int alc655_iec958_route_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + return snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 3 << 12, + (unsigned short)ucontrol->value.enumerated.item[0]); +} + +static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc655[] = { + AC97_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0), + AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 14, 1, 0), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "IEC958 Playback Route", + .info = alc655_iec958_route_info, + .get = alc655_iec958_route_get, + .put = alc655_iec958_route_put, + }, +}; + +static int patch_alc655_specific(ac97_t * ac97) +{ + int err; + + if ((err = patch_build_controls(ac97, snd_ac97_controls_alc655, ARRAY_SIZE(snd_ac97_controls_alc655))) < 0) + return err; + if (ac97->ext_id & AC97_EI_SPDIF) { + if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc655, ARRAY_SIZE(snd_ac97_spdif_controls_alc655))) < 0) + return err; + } + return 0; +} + +static struct snd_ac97_build_ops patch_alc655_ops = { + .build_specific = patch_alc655_specific +}; + +int patch_alc655(ac97_t * ac97) +{ + ac97->spec.dev_flags = (ac97->id == 0x414c4780); /* ALC658 */ + + ac97->build_ops = &patch_alc655_ops; + + /* enable spdif in */ + snd_ac97_write_cache(ac97, AC97_ALC650_CLOCK, + snd_ac97_read(ac97, AC97_ALC650_MULTICH) | 0x8000); + snd_ac97_write_cache(ac97, AC97_ALC650_CLOCK, + snd_ac97_read(ac97, AC97_ALC650_CLOCK) | 0x02); + + /* full DAC volume */ + snd_ac97_write_cache(ac97, AC97_ALC650_SURR_DAC_VOL, 0x0808); + snd_ac97_write_cache(ac97, AC97_ALC650_LFE_DAC_VOL, 0x0808); + return 0; +} + static const snd_kcontrol_new_t snd_ac97_cm9738_controls[] = { AC97_SINGLE("Line-In As Surround", AC97_CM9738_VENDOR_CTRL, 10, 1, 0), AC97_SINGLE("Duplicate Front", AC97_CM9738_VENDOR_CTRL, 13, 1, 0), @@ -1097,5 +1347,39 @@ static struct snd_ac97_build_ops patch_v int patch_vt1616(ac97_t * ac97) { ac97->build_ops = &patch_vt1616_ops; + return 0; +} + +static const snd_kcontrol_new_t snd_ac97_controls_it2646[] = { + AC97_SINGLE("Line-In As Surround", 0x76, 9, 1, 0), + AC97_SINGLE("Mic As Center/LFE", 0x76, 10, 1, 0), +}; + +static const snd_kcontrol_new_t snd_ac97_spdif_controls_it2646[] = { + AC97_SINGLE("IEC958 Capture Switch", 0x76, 11, 1, 0), + AC97_SINGLE("Analog to IEC958 Output", 0x76, 12, 1, 0), + AC97_SINGLE("IEC958 Input Monitor", 0x76, 13, 1, 0), +}; + +static int patch_it2646_specific(ac97_t * ac97) +{ + int err; + if ((err = patch_build_controls(ac97, snd_ac97_controls_it2646, ARRAY_SIZE(snd_ac97_controls_it2646))) < 0) + return err; + if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_it2646, ARRAY_SIZE(snd_ac97_spdif_controls_it2646))) < 0) + return err; + return 0; +} + +static struct snd_ac97_build_ops patch_it2646_ops = { + .build_specific = patch_it2646_specific +}; + +int patch_it2646(ac97_t * ac97) +{ + ac97->build_ops = &patch_it2646_ops; + /* full DAC volume */ + snd_ac97_write_cache(ac97, 0x5E, 0x0808); + snd_ac97_write_cache(ac97, 0x7A, 0x0808); return 0; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/ac97/ac97_patch.h 830-ivtv/sound/pci/ac97/ac97_patch.h --- 000-virgin/sound/pci/ac97/ac97_patch.h Tue Sep 2 09:56:04 2003 +++ 830-ivtv/sound/pci/ac97/ac97_patch.h Thu Jan 8 10:26:50 2004 @@ -42,8 +42,12 @@ int patch_ad1881(ac97_t * ac97); int patch_ad1885(ac97_t * ac97); int patch_ad1886(ac97_t * ac97); int patch_ad1980(ac97_t * ac97); +int patch_ad1981a(ac97_t * ac97); +int patch_ad1981b(ac97_t * ac97); int patch_ad1985(ac97_t * ac97); int patch_alc650(ac97_t * ac97); +int patch_alc655(ac97_t * ac97); int patch_cm9738(ac97_t * ac97); int patch_cm9739(ac97_t * ac97); int patch_vt1616(ac97_t * ac97); +int patch_it2646(ac97_t * ac97); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/ac97/ac97_pcm.c 830-ivtv/sound/pci/ac97/ac97_pcm.c --- 000-virgin/sound/pci/ac97/ac97_pcm.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/sound/pci/ac97/ac97_pcm.c Thu Jan 8 10:26:50 2004 @@ -0,0 +1,593 @@ +/* + * Copyright (c) by Jaroslav Kysela + * Universal interface for Audio Codec '97 + * + * For more details look to AC '97 component specification revision 2.2 + * by Intel Corporation (http://developer.intel.com) and to datasheets + * for specific codecs. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "ac97_patch.h" +#include "ac97_id.h" +#include "ac97_local.h" + +#define chip_t ac97_t + +/* + * PCM support + */ + +static unsigned char rate_reg_tables[2][4][9] = { +{ + /* standard rates */ + { + /* 3&4 front, 7&8 rear, 6&9 center/lfe */ + AC97_PCM_FRONT_DAC_RATE, /* slot 3 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 4 */ + 0xff, /* slot 5 */ + AC97_PCM_LFE_DAC_RATE, /* slot 6 */ + AC97_PCM_SURR_DAC_RATE, /* slot 7 */ + AC97_PCM_SURR_DAC_RATE, /* slot 8 */ + AC97_PCM_LFE_DAC_RATE, /* slot 9 */ + 0xff, /* slot 10 */ + 0xff, /* slot 11 */ + }, + { + /* 7&8 front, 6&9 rear, 10&11 center/lfe */ + 0xff, /* slot 3 */ + 0xff, /* slot 4 */ + 0xff, /* slot 5 */ + AC97_PCM_SURR_DAC_RATE, /* slot 6 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 7 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 8 */ + AC97_PCM_SURR_DAC_RATE, /* slot 9 */ + AC97_PCM_LFE_DAC_RATE, /* slot 10 */ + AC97_PCM_LFE_DAC_RATE, /* slot 11 */ + }, + { + /* 6&9 front, 10&11 rear, 3&4 center/lfe */ + AC97_PCM_LFE_DAC_RATE, /* slot 3 */ + AC97_PCM_LFE_DAC_RATE, /* slot 4 */ + 0xff, /* slot 5 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 6 */ + 0xff, /* slot 7 */ + 0xff, /* slot 8 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 9 */ + AC97_PCM_SURR_DAC_RATE, /* slot 10 */ + AC97_PCM_SURR_DAC_RATE, /* slot 11 */ + }, + { + /* 10&11 front, 3&4 rear, 7&8 center/lfe */ + AC97_PCM_SURR_DAC_RATE, /* slot 3 */ + AC97_PCM_SURR_DAC_RATE, /* slot 4 */ + 0xff, /* slot 5 */ + 0xff, /* slot 6 */ + AC97_PCM_LFE_DAC_RATE, /* slot 7 */ + AC97_PCM_LFE_DAC_RATE, /* slot 8 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 9 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 10 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 11 */ + }, +}, +{ + /* FIXME: double rates */ + { + /* 3&4 front, 7&8 rear, 6&9 center/lfe */ + AC97_PCM_FRONT_DAC_RATE, /* slot 3 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 4 */ + 0xff, /* slot 5 */ + AC97_PCM_LFE_DAC_RATE, /* slot 6 */ + AC97_PCM_SURR_DAC_RATE, /* slot 7 */ + AC97_PCM_SURR_DAC_RATE, /* slot 8 */ + AC97_PCM_LFE_DAC_RATE, /* slot 9 */ + 0xff, /* slot 10 */ + 0xff, /* slot 11 */ + }, + { + /* 7&8 front, 6&9 rear, 10&11 center/lfe */ + 0xff, /* slot 3 */ + 0xff, /* slot 4 */ + 0xff, /* slot 5 */ + AC97_PCM_SURR_DAC_RATE, /* slot 6 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 7 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 8 */ + AC97_PCM_SURR_DAC_RATE, /* slot 9 */ + AC97_PCM_LFE_DAC_RATE, /* slot 10 */ + AC97_PCM_LFE_DAC_RATE, /* slot 11 */ + }, + { + /* 6&9 front, 10&11 rear, 3&4 center/lfe */ + AC97_PCM_LFE_DAC_RATE, /* slot 3 */ + AC97_PCM_LFE_DAC_RATE, /* slot 4 */ + 0xff, /* slot 5 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 6 */ + 0xff, /* slot 7 */ + 0xff, /* slot 8 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 9 */ + AC97_PCM_SURR_DAC_RATE, /* slot 10 */ + AC97_PCM_SURR_DAC_RATE, /* slot 11 */ + }, + { + /* 10&11 front, 3&4 rear, 7&8 center/lfe */ + AC97_PCM_SURR_DAC_RATE, /* slot 3 */ + AC97_PCM_SURR_DAC_RATE, /* slot 4 */ + 0xff, /* slot 5 */ + 0xff, /* slot 6 */ + AC97_PCM_LFE_DAC_RATE, /* slot 7 */ + AC97_PCM_LFE_DAC_RATE, /* slot 8 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 9 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 10 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 11 */ + } +}}; + +/* FIXME: more various mappings for ADC? */ +static unsigned char rate_cregs[9] = { + AC97_PCM_LR_ADC_RATE, /* 3 */ + AC97_PCM_LR_ADC_RATE, /* 4 */ + 0xff, /* 5 */ + AC97_PCM_MIC_ADC_RATE, /* 6 */ + 0xff, /* 7 */ + 0xff, /* 8 */ + 0xff, /* 9 */ + 0xff, /* 10 */ + 0xff, /* 11 */ +}; + +static unsigned char get_slot_reg(struct ac97_pcm *pcm, unsigned short cidx, + unsigned short slot, int dbl) +{ + if (slot < 3) + return 0xff; + if (slot > 11) + return 0xff; + if (pcm->spdif) + return AC97_SPDIF; /* pseudo register */ + if (pcm->stream == SNDRV_PCM_STREAM_PLAYBACK) + return rate_reg_tables[dbl][pcm->r[dbl].rate_table[cidx]][slot - 3]; + else + return rate_cregs[slot - 3]; +} + +static int set_spdif_rate(ac97_t *ac97, unsigned short rate) +{ + unsigned short old, bits, reg, mask; + + if (! (ac97->ext_id & AC97_EI_SPDIF)) + return -ENODEV; + + if (ac97->flags & AC97_CS_SPDIF) { + switch (rate) { + case 48000: bits = 0; break; + case 44100: bits = 1 << AC97_SC_SPSR_SHIFT; break; + default: /* invalid - disable output */ + snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); + return -EINVAL; + } + reg = AC97_CSR_SPDIF; + mask = 1 << AC97_SC_SPSR_SHIFT; + } else { + if (ac97->id == AC97_ID_CM9739 && rate != 48000) { + snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); + return -EINVAL; + } + switch (rate) { + case 44100: bits = AC97_SC_SPSR_44K; break; + case 48000: bits = AC97_SC_SPSR_48K; break; + case 32000: bits = AC97_SC_SPSR_32K; break; + default: /* invalid - disable output */ + snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); + return -EINVAL; + } + reg = AC97_SPDIF; + mask = AC97_SC_SPSR_MASK; + } + + spin_lock(&ac97->reg_lock); + old = ac97->regs[reg] & mask; + spin_unlock(&ac97->reg_lock); + if (old != bits) { + snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); + snd_ac97_update_bits(ac97, reg, mask, bits); + } + snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF); + return 0; +} + +/** + * snd_ac97_set_rate - change the rate of the given input/output. + * @ac97: the ac97 instance + * @reg: the register to change + * @rate: the sample rate to set + * + * Changes the rate of the given input/output on the codec. + * If the codec doesn't support VAR, the rate must be 48000 (except + * for SPDIF). + * + * The valid registers are AC97_PMC_MIC_ADC_RATE, + * AC97_PCM_FRONT_DAC_RATE, AC97_PCM_LR_ADC_RATE. + * AC97_PCM_SURR_DAC_RATE and AC97_PCM_LFE_DAC_RATE are accepted + * if the codec supports them. + * AC97_SPDIF is accepted as a pseudo register to modify the SPDIF + * status bits. + * + * Returns zero if successful, or a negative error code on failure. + */ +int snd_ac97_set_rate(ac97_t *ac97, int reg, unsigned short rate) +{ + unsigned int tmp; + + switch (reg) { + case AC97_PCM_MIC_ADC_RATE: + if ((ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_VRM) == 0) /* MIC VRA */ + if (rate != 48000) + return -EINVAL; + break; + case AC97_PCM_FRONT_DAC_RATE: + case AC97_PCM_LR_ADC_RATE: + if ((ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_VRA) == 0) /* VRA */ + if (rate != 48000) + return -EINVAL; + break; + case AC97_PCM_SURR_DAC_RATE: + if (! (ac97->scaps & AC97_SCAP_SURROUND_DAC)) + return -EINVAL; + break; + case AC97_PCM_LFE_DAC_RATE: + if (! (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC)) + return -EINVAL; + break; + case AC97_SPDIF: + /* special case */ + return set_spdif_rate(ac97, rate); + default: + return -EINVAL; + } + tmp = ((unsigned int)rate * ac97->bus->clock) / 48000; + if (tmp > 65535) + return -EINVAL; + snd_ac97_update(ac97, reg, tmp & 0xffff); + snd_ac97_read(ac97, reg); + return 0; +} + +static unsigned short get_pslots(ac97_t *ac97, unsigned char *rate_table, unsigned short *spdif_slots) +{ + if (!ac97_is_audio(ac97)) + return 0; + if (ac97_is_rev22(ac97) || ac97_can_amap(ac97)) { + unsigned short slots = 0; + if (ac97_is_rev22(ac97)) { + /* Note: it's simply emulation of AMAP behaviour */ + u16 es; + es = ac97->regs[AC97_EXTENDED_STATUS] &= ~AC97_EI_DACS_SLOT_MASK; + switch (ac97->addr) { + case 1: + case 2: es |= (1<addr) { + case 0: + slots |= (1<scaps & AC97_SCAP_SURROUND_DAC) + slots |= (1<scaps & AC97_SCAP_CENTER_LFE_DAC) + slots |= (1<ext_id & AC97_EI_SPDIF) { + if (!(ac97->scaps & AC97_SCAP_SURROUND_DAC)) + *spdif_slots = (1<scaps & AC97_SCAP_CENTER_LFE_DAC)) + *spdif_slots = (1<scaps & AC97_SCAP_SURROUND_DAC) + slots |= (1<ext_id & AC97_EI_SPDIF) { + if (!(ac97->scaps & AC97_SCAP_SURROUND_DAC)) + *spdif_slots = (1<ext_id & AC97_EI_SPDIF) + *spdif_slots = (1<scaps & AC97_SCAP_SURROUND_DAC) + slots |= (1<scaps & AC97_SCAP_CENTER_LFE_DAC) + slots |= (1<ext_id & AC97_EI_SPDIF) { + if (!(ac97->scaps & AC97_SCAP_SURROUND_DAC)) + *spdif_slots = (1<scaps & AC97_SCAP_CENTER_LFE_DAC)) + *spdif_slots = (1<r[dbl].codec[cidx]->rates[idx]; + } + return rates; +} + +/** + * snd_ac97_pcm_assign - assign AC97 slots to given PCM streams + * @bus: the ac97 bus instance + * @pcms_count: count of PCMs to be assigned + * @pcms: PCMs to be assigned + * + * It assigns available AC97 slots for given PCMs. If none or only + * some slots are available, pcm->xxx.slots and pcm->xxx.rslots[] members + * are reduced and might be zero. + */ +int snd_ac97_pcm_assign(ac97_bus_t *bus, + unsigned short pcms_count, + const struct ac97_pcm *pcms) +{ + int i, j, k; + const struct ac97_pcm *pcm; + struct ac97_pcm *rpcms, *rpcm; + unsigned short avail_slots[2][4]; + unsigned char rate_table[2][4]; + unsigned short tmp, slots; + unsigned short spdif_slots[4]; + unsigned int rates; + ac97_t *codec; + + rpcms = snd_kcalloc(sizeof(struct ac97_pcm) * pcms_count, GFP_KERNEL); + if (rpcms == NULL) + return -ENOMEM; + memset(avail_slots, 0, sizeof(avail_slots)); + memset(rate_table, 0, sizeof(rate_table)); + memset(spdif_slots, 0, sizeof(spdif_slots)); + for (i = 0; i < 4; i++) { + codec = bus->codec[i]; + if (!codec) + continue; + avail_slots[0][i] = get_pslots(codec, &rate_table[0][i], &spdif_slots[i]); + avail_slots[1][i] = get_cslots(codec); + if (!(codec->scaps & AC97_SCAP_INDEP_SDIN)) { + for (j = 0; j < i; j++) { + if (bus->codec[j]) + avail_slots[1][i] &= ~avail_slots[1][j]; + } + } + } + /* FIXME: add double rate allocation */ + /* first step - exclusive devices */ + for (i = 0; i < pcms_count; i++) { + pcm = &pcms[i]; + rpcm = &rpcms[i]; + /* low-level driver thinks that it's more clever */ + if (pcm->copy_flag) { + *rpcm = *pcm; + continue; + } + rpcm->stream = pcm->stream; + rpcm->exclusive = pcm->exclusive; + rpcm->spdif = pcm->spdif; + rpcm->private_value = pcm->private_value; + rpcm->bus = bus; + rpcm->rates = ~0; + slots = pcm->r[0].slots; + for (j = 0; j < 4 && slots; j++) { + if (!bus->codec[j]) + continue; + rates = ~0; + if (pcm->spdif && pcm->stream == 0) + tmp = spdif_slots[j]; + else + tmp = avail_slots[pcm->stream][j]; + if (pcm->exclusive) { + /* exclusive access */ + tmp &= slots; + for (k = 0; k < i; k++) { + if (rpcm->stream == rpcms[k].stream) + tmp &= ~rpcms[k].r[0].rslots[j]; + } + } else { + /* non-exclusive access */ + tmp &= pcm->r[0].slots; + } + if (tmp) { + rpcm->r[0].rslots[j] = tmp; + rpcm->r[0].codec[j] = bus->codec[j]; + rpcm->r[0].rate_table[j] = rate_table[pcm->stream][j]; + rates = get_rates(rpcm, j, tmp, 0); + if (pcm->exclusive) + avail_slots[pcm->stream][j] &= ~tmp; + } + slots &= ~tmp; + rpcm->r[0].slots |= tmp; + rpcm->rates &= rates; + } + if (rpcm->rates == ~0) + rpcm->rates = 0; /* not used */ + } + bus->pcms_count = pcms_count; + bus->pcms = rpcms; + return 0; +} + +/** + * snd_ac97_pcm_open - opens the given AC97 pcm + * @pcm: the ac97 pcm instance + * @rate: rate in Hz, if codec does not support VRA, this value must be 48000Hz + * @cfg: output stream characteristics + * @slots: a subset of allocated slots (snd_ac97_pcm_assign) for this pcm + * + * It locks the specified slots and sets the given rate to AC97 registers. + */ +int snd_ac97_pcm_open(struct ac97_pcm *pcm, unsigned int rate, + enum ac97_pcm_cfg cfg, unsigned short slots) +{ + ac97_bus_t *bus; + int i, cidx, r = 0, ok_flag; + unsigned int reg_ok = 0; + unsigned char reg; + int err = 0; + + if (rate > 48000) /* FIXME: add support for double rate */ + return -EINVAL; + bus = pcm->bus; + if (cfg == AC97_PCM_CFG_SPDIF) { + int err; + for (cidx = 0; cidx < 4; cidx++) + if (bus->codec[cidx] && (bus->codec[cidx]->ext_id & AC97_EI_SPDIF)) { + err = set_spdif_rate(bus->codec[cidx], rate); + if (err < 0) + return err; + } + } + spin_lock_irq(&pcm->bus->bus_lock); + for (i = 3; i < 12; i++) { + if (!(slots & (1 << i))) + continue; + ok_flag = 0; + for (cidx = 0; cidx < 4; cidx++) { + if (bus->used_slots[pcm->stream][cidx] & (1 << i)) { + spin_unlock_irq(&pcm->bus->bus_lock); + err = -EBUSY; + goto error; + } + if (pcm->r[r].rslots[cidx] & (1 << i)) { + bus->used_slots[pcm->stream][cidx] |= (1 << i); + ok_flag++; + } + } + if (!ok_flag) { + spin_unlock_irq(&pcm->bus->bus_lock); + snd_printk(KERN_ERR "cannot find configuration for AC97 slot %i\n", i); + err = -EAGAIN; + goto error; + } + } + spin_unlock_irq(&pcm->bus->bus_lock); + for (i = 3; i < 12; i++) { + if (!(slots & (1 << i))) + continue; + for (cidx = 0; cidx < 4; cidx++) { + if (pcm->r[r].rslots[cidx] & (1 << i)) { + reg = get_slot_reg(pcm, cidx, i, r); + if (reg == 0xff) { + snd_printk(KERN_ERR "invalid AC97 slot %i?\n", i); + continue; + } + if (reg_ok & (1 << (reg - AC97_PCM_FRONT_DAC_RATE))) + continue; + //printk(KERN_DEBUG "setting ac97 reg 0x%x to rate %d\n", reg, rate); + err = snd_ac97_set_rate(pcm->r[r].codec[cidx], reg, rate); + if (err < 0) + snd_printk(KERN_ERR "error in snd_ac97_set_rate: cidx=%d, reg=0x%x, rate=%d, err=%d\n", cidx, reg, rate, err); + else + reg_ok |= (1 << (reg - AC97_PCM_FRONT_DAC_RATE)); + } + } + } + pcm->aslots = slots; + return 0; + + error: + pcm->aslots = slots; + snd_ac97_pcm_close(pcm); + return err; +} + +/** + * snd_ac97_pcm_close - closes the given AC97 pcm + * @pcm: the ac97 pcm instance + * + * It frees the locked AC97 slots. + */ +int snd_ac97_pcm_close(struct ac97_pcm *pcm) +{ + ac97_bus_t *bus; + unsigned short slots = pcm->aslots; + int i, cidx; + + bus = pcm->bus; + spin_lock_irq(&pcm->bus->bus_lock); + for (i = 3; i < 12; i++) { + if (!(slots & (1 << i))) + continue; + for (cidx = 0; cidx < 4; cidx++) + bus->used_slots[pcm->stream][cidx] &= ~(1 << i); + } + pcm->aslots = 0; + spin_unlock_irq(&pcm->bus->bus_lock); + return 0; +} diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/ac97/ac97_proc.c 830-ivtv/sound/pci/ac97/ac97_proc.c --- 000-virgin/sound/pci/ac97/ac97_proc.c Mon Nov 17 18:29:01 2003 +++ 830-ivtv/sound/pci/ac97/ac97_proc.c Thu Jan 8 10:26:50 2004 @@ -37,15 +37,12 @@ static void snd_ac97_proc_read_main(ac97_t *ac97, snd_info_buffer_t * buffer, int subidx) { char name[64]; - unsigned int id; unsigned short val, tmp, ext, mext; static const char *spdif_slots[4] = { " SPDIF=3/4", " SPDIF=7/8", " SPDIF=6/9", " SPDIF=res" }; static const char *spdif_rates[4] = { " Rate=44.1kHz", " Rate=res", " Rate=48kHz", " Rate=32kHz" }; static const char *spdif_rates_cs4205[4] = { " Rate=48kHz", " Rate=44.1kHz", " Rate=res", " Rate=res" }; - id = snd_ac97_read(ac97, AC97_VENDOR_ID1) << 16; - id |= snd_ac97_read(ac97, AC97_VENDOR_ID2); - snd_ac97_get_name(NULL, id, name, 0); + snd_ac97_get_name(NULL, ac97->id, name, 0); snd_iprintf(buffer, "%d-%d/%d: %s\n\n", ac97->addr, ac97->num, subidx, name); if ((ac97->scaps & AC97_SCAP_AUDIO) == 0) goto __modem; @@ -299,21 +296,67 @@ static void snd_ac97_proc_regs_read(snd_ } } -void snd_ac97_proc_init(snd_card_t * card, ac97_t * ac97, const char *prefix) +void snd_ac97_proc_init(ac97_t * ac97) { snd_info_entry_t *entry; char name[32]; + const char *prefix; - if (ac97->num) - sprintf(name, "%s#%d-%d", prefix, ac97->addr, ac97->num); - else - sprintf(name, "%s#%d", prefix, ac97->addr); - if (! snd_card_proc_new(card, name, &entry)) - snd_info_set_text_ops(entry, ac97, snd_ac97_proc_read); - if (ac97->num) - sprintf(name, "%s#%d-%dregs", prefix, ac97->addr, ac97->num); - else - sprintf(name, "%s#%dregs", prefix, ac97->addr); - if (! snd_card_proc_new(card, name, &entry)) - snd_info_set_text_ops(entry, ac97, snd_ac97_proc_regs_read); + if (ac97->bus->proc == NULL) + return; + prefix = ac97_is_audio(ac97) ? "ac97" : "mc97"; + sprintf(name, "%s#%d-%d", prefix, ac97->addr, ac97->num); + if ((entry = snd_info_create_card_entry(ac97->bus->card, name, ac97->bus->proc)) != NULL) { + snd_info_set_text_ops(entry, ac97, 1024, snd_ac97_proc_read); + if (snd_info_register(entry) < 0) { + snd_info_free_entry(entry); + entry = NULL; + } + } + ac97->proc = entry; + sprintf(name, "%s#%d-%d+regs", prefix, ac97->addr, ac97->num); + if ((entry = snd_info_create_card_entry(ac97->bus->card, name, ac97->bus->proc)) != NULL) { + snd_info_set_text_ops(entry, ac97, 1024, snd_ac97_proc_regs_read); + if (snd_info_register(entry) < 0) { + snd_info_free_entry(entry); + entry = NULL; + } + } + ac97->proc_regs = entry; +} + +void snd_ac97_proc_done(ac97_t * ac97) +{ + if (ac97->proc_regs) { + snd_info_unregister(ac97->proc_regs); + ac97->proc_regs = NULL; + } + if (ac97->proc) { + snd_info_unregister(ac97->proc); + ac97->proc = NULL; + } +} + +void snd_ac97_bus_proc_init(ac97_bus_t * bus) +{ + snd_info_entry_t *entry; + char name[32]; + + sprintf(name, "codec97#%d", bus->num); + if ((entry = snd_info_create_card_entry(bus->card, name, bus->card->proc_root)) != NULL) { + entry->mode = S_IFDIR | S_IRUGO | S_IXUGO; + if (snd_info_register(entry) < 0) { + snd_info_free_entry(entry); + entry = NULL; + } + } + bus->proc = entry; +} + +void snd_ac97_bus_proc_done(ac97_bus_t * bus) +{ + if (bus->proc) { + snd_info_unregister(bus->proc); + bus->proc = NULL; + } } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/ac97/ak4531_codec.c 830-ivtv/sound/pci/ac97/ak4531_codec.c --- 000-virgin/sound/pci/ac97/ak4531_codec.c Thu Feb 13 11:08:17 2003 +++ 830-ivtv/sound/pci/ac97/ak4531_codec.c Thu Jan 8 10:26:50 2004 @@ -425,7 +425,7 @@ static void snd_ak4531_proc_init(snd_car snd_info_entry_t *entry; if (! snd_card_proc_new(card, "ak4531", &entry)) - snd_info_set_text_ops(entry, ak4531, snd_ak4531_proc_read); + snd_info_set_text_ops(entry, ak4531, 1024, snd_ak4531_proc_read); } EXPORT_SYMBOL(snd_ak4531_mixer); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/ali5451/ali5451.c 830-ivtv/sound/pci/ali5451/ali5451.c --- 000-virgin/sound/pci/ali5451/ali5451.c Wed Aug 13 20:24:37 2003 +++ 830-ivtv/sound/pci/ali5451/ali5451.c Thu Jan 8 10:26:50 2004 @@ -265,6 +265,7 @@ struct snd_stru_ali { unsigned int spurious_irq_count; unsigned int spurious_irq_max_delta; + ac97_bus_t *ac97_bus; ac97_t *ac97; unsigned short ac97_ext_id; unsigned short ac97_ext_status; @@ -1860,6 +1861,12 @@ static snd_kcontrol_new_t snd_ali5451_mi ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), 0, 2) }; +static void snd_ali_mixer_free_ac97_bus(ac97_bus_t *bus) +{ + ali_t *codec = snd_magic_cast(ali_t, bus->private_data, return); + codec->ac97_bus = NULL; +} + static void snd_ali_mixer_free_ac97(ac97_t *ac97) { ali_t *codec = snd_magic_cast(ali_t, ac97->private_data, return); @@ -1868,16 +1875,23 @@ static void snd_ali_mixer_free_ac97(ac97 static int __devinit snd_ali_mixer(ali_t * codec) { + ac97_bus_t bus; ac97_t ac97; unsigned int idx; int err; + memset(&bus, 0, sizeof(bus)); + bus.write = snd_ali_codec_write; + bus.read = snd_ali_codec_read; + bus.private_data = codec; + bus.private_free = snd_ali_mixer_free_ac97_bus; + if ((err = snd_ac97_bus(codec->card, &bus, &codec->ac97_bus)) < 0) + return err; + memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_ali_codec_write; - ac97.read = snd_ali_codec_read; ac97.private_data = codec; ac97.private_free = snd_ali_mixer_free_ac97; - if ((err = snd_ac97_mixer(codec->card, &ac97, &codec->ac97)) < 0) { + if ((err = snd_ac97_mixer(codec->ac97_bus, &ac97, &codec->ac97)) < 0) { snd_printk("ali mixer creating error.\n"); return err; } @@ -2096,7 +2110,7 @@ static int __devinit snd_ali_create(snd_ snd_printk("architecture does not support 31bit PCI busmaster DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x7fffffff); + pci_set_consistent_dma_mask(pci, 0x7fffffff); if ((codec = snd_magic_kcalloc(ali_t, 0, GFP_KERNEL)) == NULL) return -ENOMEM; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/als4000.c 830-ivtv/sound/pci/als4000.c --- 000-virgin/sound/pci/als4000.c Wed Aug 13 20:24:37 2003 +++ 830-ivtv/sound/pci/als4000.c Thu Jan 8 10:26:50 2004 @@ -63,6 +63,7 @@ #include #include #include +#include #include #include #include @@ -78,14 +79,15 @@ MODULE_LICENSE("GPL"); MODULE_CLASSES("{sound}"); MODULE_DEVICES("{{Avance Logic,ALS4000}}"); +#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#define SUPPORT_JOYSTICK 1 +#endif + static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ -static int joystick_port[SNDRV_CARDS] = -#ifdef CONFIG_ISA - {0x200}; /* enable as default */ -#else - {0}; /* disabled */ +#ifdef SUPPORT_JOYSTICK +static int joystick_port[SNDRV_CARDS]; #endif MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); @@ -105,6 +107,11 @@ MODULE_PARM_SYNTAX(joystick_port, SNDRV_ typedef struct { unsigned long gcr; + struct resource *res_gcr; +#ifdef SUPPORT_JOYSTICK + struct gameport gameport; + struct resource *res_joystick; +#endif } snd_card_als4000_t; static struct pci_device_id snd_als4000_ids[] = { @@ -523,7 +530,7 @@ static int __devinit snd_als4000_pcm(sb_ /******************************************************************/ -static void __devinit snd_als4000_set_addr(unsigned long gcr, +static void snd_als4000_set_addr(unsigned long gcr, unsigned int sb, unsigned int mpu, unsigned int opl, @@ -574,6 +581,18 @@ static void snd_card_als4000_free( snd_c snd_card_als4000_t * acard = (snd_card_als4000_t *)card->private_data; /* make sure that interrupts are disabled */ snd_als4000_gcr_write_addr( acard->gcr, 0x8c, 0); + /* free resources */ +#ifdef SUPPORT_JOYSTICK + if (acard->res_joystick) { + if (acard->gameport.io) + gameport_unregister_port(&acard->gameport); + snd_als4000_set_addr(acard->gcr, 0, 0, 0, 0); /* disable joystick */ + release_resource(acard->res_joystick); + kfree_nocheck(acard->res_joystick); + } +#endif + release_resource(acard->res_gcr); + kfree_nocheck(acard->res_gcr); } static int __devinit snd_card_als4000_probe(struct pci_dev *pci, @@ -588,6 +607,7 @@ static int __devinit snd_card_als4000_pr opl3_t *opl3; unsigned short word; int err; + int joystick = 0; if (dev >= SNDRV_CARDS) return -ENODEV; @@ -605,7 +625,7 @@ static int __devinit snd_card_als4000_pr snd_printk("architecture does not support 24bit PCI busmaster DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x00ffffff); + pci_set_consistent_dma_mask(pci, 0x00ffffff); gcr = pci_resource_start(pci, 0); if ((res_gcr_port = request_region(gcr, 0x40, "ALS4000")) == NULL) { @@ -617,9 +637,6 @@ static int __devinit snd_card_als4000_pr pci_write_config_word(pci, PCI_COMMAND, word | PCI_COMMAND_IO); pci_set_master(pci); - /* disable all legacy ISA stuff except for joystick */ - snd_als4000_set_addr(gcr, 0, 0, 0, joystick_port[dev]); - card = snd_card_new(index[dev], id[dev], THIS_MODULE, sizeof( snd_card_als4000_t ) ); if (card == NULL) { @@ -630,8 +647,29 @@ static int __devinit snd_card_als4000_pr acard = (snd_card_als4000_t *)card->private_data; acard->gcr = gcr; + acard->res_gcr = res_gcr_port; card->private_free = snd_card_als4000_free; + /* disable all legacy ISA stuff except for joystick */ +#ifdef SUPPORT_JOYSTICK + if (joystick_port[dev] == 1) { + /* auto-detect */ + long p; + for (p = 0x200; p <= 0x218; p += 8) { + if ((acard->res_joystick = request_region(p, 8, "ALS4000 gameport")) != NULL) { + joystick_port[dev] = p; + break; + } + } + } else if (joystick_port[dev] > 0) + acard->res_joystick = request_region(joystick_port[dev], 8, "ALS4000 gameport"); + if (acard->res_joystick) + joystick = joystick_port[dev]; + else + joystick = 0; +#endif + snd_als4000_set_addr(gcr, 0, 0, 0, joystick); + if ((err = snd_sbdsp_create(card, gcr + 0x10, pci->irq, @@ -640,15 +678,12 @@ static int __devinit snd_card_als4000_pr -1, SB_HW_ALS4000, &chip)) < 0) { - release_resource(res_gcr_port); - kfree_nocheck(res_gcr_port); snd_card_free(card); return err; } chip->pci = pci; chip->alt_port = gcr; - chip->res_alt_port = res_gcr_port; snd_als4000_configure(chip); @@ -680,6 +715,12 @@ static int __devinit snd_card_als4000_pr } } +#ifdef SUPPORT_JOYSTICK + if (acard->res_joystick) { + acard->gameport.io = joystick; + gameport_register_port(&acard->gameport); + } +#endif strcpy(card->driver, "ALS4000"); strcpy(card->shortname, "Avance Logic ALS4000"); sprintf(card->longname, "%s at 0x%lx, irq %i", @@ -730,7 +771,7 @@ module_exit(alsa_card_als4000_exit) #ifndef MODULE -/* format is: snd-als4000=enable,index,id */ +/* format is: snd-als4000=enable,index,id,joystick_port */ static int __init alsa_card_als4000_setup(char *str) { @@ -740,7 +781,11 @@ static int __init alsa_card_als4000_setu return 0; (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && - get_id(&str,&id[nr_dev]) == 2); + get_id(&str,&id[nr_dev]) == 2 +#ifdef SUPPORT_JOYSTICK + && get_option(&str,&joystick_port[nr_dev]) == 2 +#endif + ); nr_dev++; return 1; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/azt3328.c 830-ivtv/sound/pci/azt3328.c --- 000-virgin/sound/pci/azt3328.c Tue Sep 2 09:56:04 2003 +++ 830-ivtv/sound/pci/azt3328.c Thu Jan 8 10:26:50 2004 @@ -97,6 +97,7 @@ #include #include #include +#include #include #include #include @@ -113,6 +114,10 @@ MODULE_LICENSE("GPL"); MODULE_CLASSES("{sound}"); MODULE_DEVICES("{{Aztech,AZF3328}}"); +#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#define SUPPORT_JOYSTICK 1 +#endif + #define DEBUG_MISC 0 #define DEBUG_CALLS 0 #define DEBUG_MIXER 0 @@ -158,8 +163,9 @@ MODULE_DEVICES("{{Aztech,AZF3328}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ -static int joystick[SNDRV_CARDS] = - {-1}; /* "unset" as default */ +#ifdef SUPPORT_JOYSTICK +static int joystick[SNDRV_CARDS]; +#endif MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(index, "Index value for AZF3328 soundcard."); @@ -170,9 +176,11 @@ MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(enable, "Enable AZF3328 soundcard."); MODULE_PARM_SYNTAX(enable, SNDRV_INDEX_DESC); +#ifdef SUPPORT_JOYSTICK MODULE_PARM(joystick, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); -MODULE_PARM_DESC(joystick, "Forced joystick port enable for AZF3328 soundcard. (0 = force disable)"); -MODULE_PARM_SYNTAX(joystick, SNDRV_ENABLED); +MODULE_PARM_DESC(joystick, "Enable joystick for AZF3328 soundcard."); +MODULE_PARM_SYNTAX(joystick, SNDRV_BOOLEAN_FALSE_DESC); +#endif typedef struct _snd_azf3328 azf3328_t; #define chip_t azf3328_t @@ -190,7 +198,11 @@ struct _snd_azf3328 { struct resource *res_synth_port; unsigned long mixer_port; struct resource *res_mixer_port; - unsigned long game_port; + +#ifdef SUPPORT_JOYSTICK + struct gameport gameport; + struct resource *res_joystick; +#endif struct pci_dev *pci; snd_card_t *card; @@ -1259,6 +1271,16 @@ static int snd_azf3328_free(azf3328_t *c synchronize_irq(chip->irq); __end_hw: +#ifdef SUPPORT_JOYSTICK + if (chip->res_joystick) { + gameport_unregister_port(&chip->gameport); + /* disable gameport */ + snd_azf3328_io2_write(chip, IDX_IO2_LEGACY_ADDR, + snd_azf3328_io2_read(chip, IDX_IO2_LEGACY_ADDR) & ~LEGACY_JOY); + release_resource(chip->res_joystick); + kfree_nocheck(chip->res_joystick); + } +#endif if (chip->res_codec_port) { release_resource(chip->res_codec_port); kfree_nocheck(chip->res_codec_port); @@ -1343,7 +1365,7 @@ static int __devinit snd_azf3328_create( snd_printk("architecture does not support 24bit PCI busmaster DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x00ffffff); + pci_set_consistent_dma_mask(pci, 0x00ffffff); chip->codec_port = pci_resource_start(pci, 0); if ((chip->res_codec_port = request_region(chip->codec_port, 0x80, "Aztech AZF3328 I/O")) == NULL) { @@ -1419,53 +1441,27 @@ static int __devinit snd_azf3328_create( return 0; } +#ifdef SUPPORT_JOYSTICK static void __devinit snd_azf3328_config_joystick(azf3328_t *chip, int joystick) { - int i, detected = 0, activate = 0; - char *msg = NULL; unsigned char val; - if (joystick == -1) /* auto detection/activation */ - { - for (i=0x200; i <= 0x207; i++) - if (inb(i) != 0xff) - detected = 1; /* other joy found, don't activate */ + if (joystick == 1) { + if ((chip->res_joystick = request_region(0x200, 8, "AZF3328 gameport")) != NULL) + chip->gameport.io = 0x200; } - if ((joystick == -1) && (detected == 1)) - { - activate = 0; - msg = "DISABLED (address occupied by another joystick port)"; - } - else - if ((joystick == -1) && (detected == 0)) - { - activate = 1; - msg = "ENABLED (via autodetect)"; - } - else - if (joystick == 0) - { - activate = 0; - msg = "DISABLED (forced)"; - } - else - if (joystick == 1) - { - activate = 1; - msg = "ENABLED (Warning: forced!)"; - } val = inb(chip->io2_port + IDX_IO2_LEGACY_ADDR); - if (activate) - val |= LEGACY_JOY; + if (chip->res_joystick) + val |= LEGACY_JOY; else - val &= ~LEGACY_JOY; + val &= ~LEGACY_JOY; outb(val, chip->io2_port + IDX_IO2_LEGACY_ADDR); -#ifdef MODULE - printk("azt3328: Joystick port: %s.\n", msg); -#endif + if (chip->res_joystick) + gameport_register_port(&chip->gameport); } +#endif static int __devinit snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) @@ -1537,7 +1533,9 @@ static int __devinit snd_azf3328_probe(s "azt3328: Feel free to contact hw7oshyuv3001@sneakemail.com for bug reports etc.!\n"); #endif +#ifdef SUPPORT_JOYSTICK snd_azf3328_config_joystick(chip, joystick[dev]); +#endif pci_set_drvdata(pci, chip); dev++; @@ -1598,7 +1596,7 @@ module_exit(alsa_card_azf3328_exit) #ifndef MODULE -/* format is: snd-azf3328=enable,index,id */ +/* format is: snd-azf3328=enable,index,id,joystick */ static int __init alsa_card_azf3328_setup(char *str) { @@ -1610,12 +1608,16 @@ static int __init alsa_card_azf3328_setu return 0; (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && - get_id(&str,&id[nr_dev]) == 2); + get_id(&str,&id[nr_dev]) == 2 +#ifdef SUPPORT_JOYSTICK + && get_option(&str,&joystick[nr_dev]) == 2 +#endif + ); nr_dev++; snd_azf3328_dbgcallleave(); return 1; } -__setup("snd-azf3328=", alsa_card_azf3328_setup); +__setup("snd-azt3328=", alsa_card_azf3328_setup); #endif /* ifndef MODULE */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/cmipci.c 830-ivtv/sound/pci/cmipci.c --- 000-virgin/sound/pci/cmipci.c Mon Nov 17 18:29:36 2003 +++ 830-ivtv/sound/pci/cmipci.c Thu Jan 8 10:26:50 2004 @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -52,14 +53,21 @@ MODULE_DEVICES("{{C-Media,CMI8738}," "{C-Media,CMI8338A}," "{C-Media,CMI8338B}}"); +#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#define SUPPORT_JOYSTICK 1 +#endif + static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable switches */ -static long mpu_port[SNDRV_CARDS] = {0x330, [1 ... (SNDRV_CARDS-1)]=-1}; -static long fm_port[SNDRV_CARDS] = {0x388, [1 ... (SNDRV_CARDS-1)]=-1}; +static long mpu_port[SNDRV_CARDS]; +static long fm_port[SNDRV_CARDS]; #ifdef DO_SOFT_AC3 static int soft_ac3[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)]=1}; #endif +#ifdef SUPPORT_JOYSTICK +static int joystick[SNDRV_CARDS]; +#endif MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(index, "Index value for C-Media PCI soundcard."); @@ -72,15 +80,20 @@ MODULE_PARM_DESC(enable, "Enable C-Media MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); MODULE_PARM(mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l"); MODULE_PARM_DESC(mpu_port, "MPU-401 port."); -MODULE_PARM_SYNTAX(mpu_port, SNDRV_ENABLED ",allows:{{-1},{0x330},{0x320},{0x310},{0x300}},dialog:list"); +MODULE_PARM_SYNTAX(mpu_port, SNDRV_ENABLED ",allows:{{0},{0x330},{0x320},{0x310},{0x300}},dialog:list"); MODULE_PARM(fm_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l"); MODULE_PARM_DESC(fm_port, "FM port."); -MODULE_PARM_SYNTAX(fm_port, SNDRV_ENABLED ",allows:{{-1},{0x388},{0x3c8},{0x3e0},{0x3e8}},dialog:list"); +MODULE_PARM_SYNTAX(fm_port, SNDRV_ENABLED ",allows:{{0},{0x388},{0x3c8},{0x3e0},{0x3e8}},dialog:list"); #ifdef DO_SOFT_AC3 MODULE_PARM(soft_ac3, "1-" __MODULE_STRING(SNDRV_CARDS) "l"); MODULE_PARM_DESC(soft_ac3, "Sofware-conversion of raw SPDIF packets (model 033 only)."); MODULE_PARM_SYNTAX(soft_ac3, SNDRV_ENABLED "," SNDRV_BOOLEAN_TRUE_DESC); #endif +#ifdef SUPPORT_JOYSTICK +MODULE_PARM(joystick, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(joystick, "Enable joystick."); +MODULE_PARM_SYNTAX(joystick, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); +#endif #ifndef PCI_DEVICE_ID_CMEDIA_CM8738 #define PCI_DEVICE_ID_CMEDIA_CM8738 0x0111 @@ -339,6 +352,10 @@ MODULE_PARM_SYNTAX(soft_ac3, SNDRV_ENABL #define CM_EXTENT_MIDI 0x2 #define CM_EXTENT_SYNTH 0x4 +/* fixed legacy joystick address */ +#define CM_JOYSTICK_ADDR 0x200 + + /* * pci ids */ @@ -480,6 +497,11 @@ struct snd_stru_cmipci { /* external MIDI */ snd_rawmidi_t *rmidi; +#ifdef SUPPORT_JOYSTICK + struct gameport gameport; + struct resource *res_joystick; +#endif + spinlock_t reg_lock; }; @@ -703,6 +725,7 @@ static int set_dac_channels(cmipci_t *cm spin_lock_irqsave(&cm->reg_lock, flags); snd_cmipci_set_bit(cm, CM_REG_LEGACY_CTRL, CM_NXCHG); + snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_XCHGDAC); if (channels > 4) { snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_CHB3D); snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_CHB3D5C); @@ -727,6 +750,7 @@ static int set_dac_channels(cmipci_t *cm snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_CHB3D5C); snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_CHB3D6C); snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_ENCENTER); + snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_XCHGDAC); spin_unlock_irqrestore(&cm->reg_lock, flags); } } @@ -2599,7 +2623,7 @@ DEFINE_SWITCH_ARG(exchange_dac, CM_REG_M DEFINE_BIT_SWITCH_ARG(fourch, CM_REG_MISC_CTRL, CM_N4SPK3D, 0, 0); DEFINE_BIT_SWITCH_ARG(line_rear, CM_REG_MIXER1, CM_SPK4, 1, 0); DEFINE_BIT_SWITCH_ARG(line_bass, CM_REG_LEGACY_CTRL, CM_LINE_AS_BASS, 0, 0); -DEFINE_BIT_SWITCH_ARG(joystick, CM_REG_FUNCTRL1, CM_JYSTK_EN, 0, 0); +// DEFINE_BIT_SWITCH_ARG(joystick, CM_REG_FUNCTRL1, CM_JYSTK_EN, 0, 0); /* now module option */ DEFINE_SWITCH_ARG(modem, CM_REG_MISC_CTRL, CM_FLINKON|CM_FLINKOFF, CM_FLINKON, 0, 0); #define DEFINE_SWITCH(sname, stype, sarg) \ @@ -2649,11 +2673,14 @@ static int snd_cmipci_spdout_enable_put( /* both for CM8338/8738 */ static snd_kcontrol_new_t snd_cmipci_mixer_switches[] __devinitdata = { - DEFINE_MIXER_SWITCH("Exchange DAC", exchange_dac), DEFINE_MIXER_SWITCH("Four Channel Mode", fourch), DEFINE_MIXER_SWITCH("Line-In As Rear", line_rear), }; +/* for non-multichannel chips */ +static snd_kcontrol_new_t snd_cmipci_nomulti_switch __devinitdata = +DEFINE_MIXER_SWITCH("Exchange DAC", exchange_dac); + /* only for CM8738 */ static snd_kcontrol_new_t snd_cmipci_8738_mixer_switches[] __devinitdata = { #if 0 /* controlled in pcm device */ @@ -2693,7 +2720,7 @@ static snd_kcontrol_new_t snd_cmipci_ext /* card control switches */ static snd_kcontrol_new_t snd_cmipci_control_switches[] __devinitdata = { - DEFINE_CARD_SWITCH("Joystick", joystick), + // DEFINE_CARD_SWITCH("Joystick", joystick), /* now module option */ DEFINE_CARD_SWITCH("Modem", modem), }; @@ -2729,6 +2756,11 @@ static int __devinit snd_cmipci_mixer_ne if (err < 0) return err; } + if (! cm->can_multi_ch) { + err = snd_ctl_add(cm->card, snd_ctl_new1(&snd_cmipci_nomulti_switch, cm)); + if (err < 0) + return err; + } if (cm->device == PCI_DEVICE_ID_CMEDIA_CM8738 || cm->device == PCI_DEVICE_ID_CMEDIA_CM8738B) { sw = snd_cmipci_8738_mixer_switches; @@ -2816,7 +2848,7 @@ static void __devinit snd_cmipci_proc_in snd_info_entry_t *entry; if (! snd_card_proc_new(cm->card, "cmipci", &entry)) - snd_info_set_text_ops(entry, cm, snd_cmipci_proc_read); + snd_info_set_text_ops(entry, cm, 1024, snd_cmipci_proc_read); } #else /* !CONFIG_PROC_FS */ static inline void snd_cmipci_proc_init(cmipci_t *cm) {} @@ -2905,6 +2937,14 @@ static int snd_cmipci_free(cmipci_t *cm) free_irq(cm->irq, (void *)cm); } +#ifdef SUPPORT_JOYSTICK + if (cm->res_joystick) { + gameport_unregister_port(&cm->gameport); + snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_JYSTK_EN); + release_resource(cm->res_joystick); + kfree_nocheck(cm->res_joystick); + } +#endif if (cm->res_iobase) { release_resource(cm->res_iobase); kfree_nocheck(cm->res_iobase); @@ -2928,8 +2968,8 @@ static int __devinit snd_cmipci_create(s .dev_free = snd_cmipci_dev_free, }; unsigned int val = 0; - unsigned long iomidi = mpu_port[dev]; - unsigned long iosynth = fm_port[dev]; + long iomidi = mpu_port[dev]; + long iosynth = fm_port[dev]; int pcm_index, pcm_spdif_index; *rcmipci = NULL; @@ -3110,6 +3150,15 @@ static int __devinit snd_cmipci_create(s snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_SPDIF48K|CM_SPDF_AC97); #endif /* USE_VAR48KRATE */ +#ifdef SUPPORT_JOYSTICK + if (joystick[dev] && + (cm->res_joystick = request_region(CM_JOYSTICK_ADDR, 8, "CMIPCI gameport")) != NULL) { + cm->gameport.io = CM_JOYSTICK_ADDR; + snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_JYSTK_EN); + gameport_register_port(&cm->gameport); + } else + snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_JYSTK_EN); +#endif *rcmipci = cm; return 0; @@ -3218,7 +3267,7 @@ module_exit(alsa_card_cmipci_exit) #ifndef MODULE /* format is: snd-cmipci=enable,index,id, - mpu_port,fm_port */ + mpu_port,fm_port,soft_ac3,joystick */ static int __init alsa_card_cmipci_setup(char *str) { @@ -3229,8 +3278,15 @@ static int __init alsa_card_cmipci_setup (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&mpu_port[nr_dev]) == 2 && - get_option(&str,(int *)&fm_port[nr_dev]) == 2); + get_option_long(&str,&mpu_port[nr_dev]) == 2 && + get_option_long(&str,&fm_port[nr_dev]) == 2 +#ifdef DO_SOFT_AC3 + && get_option(&str,&soft_ac3[nr_dev]) == 2 +#endif +#ifdef SUPPORT_JOYSTICK + && get_option(&str,&joystick[nr_dev]) == 2 +#endif + ); nr_dev++; return 1; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/cs4281.c 830-ivtv/sound/pci/cs4281.c --- 000-virgin/sound/pci/cs4281.c Tue Sep 2 09:56:04 2003 +++ 830-ivtv/sound/pci/cs4281.c Thu Jan 8 10:26:50 2004 @@ -479,6 +479,7 @@ struct snd_cs4281 { int dual_codec; + ac97_bus_t *ac97_bus; ac97_t *ac97; ac97_t *ac97_secondary; @@ -564,7 +565,7 @@ static inline unsigned int snd_cs4281_pe } static void snd_cs4281_ac97_write(ac97_t *ac97, - unsigned short reg, unsigned short val) + unsigned short reg, unsigned short val) { /* * 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address @@ -609,7 +610,7 @@ static void snd_cs4281_ac97_write(ac97_t } static unsigned short snd_cs4281_ac97_read(ac97_t *ac97, - unsigned short reg) + unsigned short reg) { cs4281_t *chip = snd_magic_cast(cs4281_t, ac97->private_data, return -ENXIO); int count; @@ -1119,6 +1120,12 @@ static snd_kcontrol_new_t snd_cs4281_pcm .private_value = ((BA0_PPLVC << 16) | BA0_PPRVC), }; +static void snd_cs4281_mixer_free_ac97_bus(ac97_bus_t *bus) +{ + cs4281_t *chip = snd_magic_cast(cs4281_t, bus->private_data, return); + chip->ac97_bus = NULL; +} + static void snd_cs4281_mixer_free_ac97(ac97_t *ac97) { cs4281_t *chip = snd_magic_cast(cs4281_t, ac97->private_data, return); @@ -1131,19 +1138,26 @@ static void snd_cs4281_mixer_free_ac97(a static int __devinit snd_cs4281_mixer(cs4281_t * chip) { snd_card_t *card = chip->card; + ac97_bus_t bus; ac97_t ac97; int err; + memset(&bus, 0, sizeof(bus)); + bus.write = snd_cs4281_ac97_write; + bus.read = snd_cs4281_ac97_read; + bus.private_data = chip; + bus.private_free = snd_cs4281_mixer_free_ac97_bus; + if ((err = snd_ac97_bus(card, &bus, &chip->ac97_bus)) < 0) + return err; + memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_cs4281_ac97_write; - ac97.read = snd_cs4281_ac97_read; ac97.private_data = chip; ac97.private_free = snd_cs4281_mixer_free_ac97; - if ((err = snd_ac97_mixer(card, &ac97, &chip->ac97)) < 0) + if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0) return err; if (chip->dual_codec) { ac97.num = 1; - if ((err = snd_ac97_mixer(card, &ac97, &chip->ac97_secondary)) < 0) + if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97_secondary)) < 0) return err; } if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4281_fm_vol, chip))) < 0) @@ -1178,23 +1192,11 @@ static long snd_cs4281_BA0_read(snd_info if (file->f_pos + size > CS4281_BA0_SIZE) size = (long)CS4281_BA0_SIZE - file->f_pos; if (size > 0) { - char *tmp; - long res; - unsigned long virt; - if ((tmp = kmalloc(size, GFP_KERNEL)) == NULL) - return -ENOMEM; - virt = chip->ba0 + file->f_pos; - memcpy_fromio(tmp, virt, size); - if (copy_to_user(buf, tmp, size)) - res = -EFAULT; - else { - res = size; - file->f_pos += size; - } - kfree(tmp); - return res; + if (copy_to_user_fromio(buf, chip->ba0 + file->f_pos, size)) + return -EFAULT; + file->f_pos += size; } - return 0; + return size; } static long snd_cs4281_BA1_read(snd_info_entry_t *entry, void *file_private_data, @@ -1207,23 +1209,11 @@ static long snd_cs4281_BA1_read(snd_info if (file->f_pos + size > CS4281_BA1_SIZE) size = (long)CS4281_BA1_SIZE - file->f_pos; if (size > 0) { - char *tmp; - long res; - unsigned long virt; - if ((tmp = kmalloc(size, GFP_KERNEL)) == NULL) - return -ENOMEM; - virt = chip->ba1 + file->f_pos; - memcpy_fromio(tmp, virt, size); - if (copy_to_user(buf, tmp, size)) - res = -EFAULT; - else { - res = size; - file->f_pos += size; - } - kfree(tmp); - return res; + if (copy_to_user_fromio(buf, chip->ba1 + file->f_pos, size)) + return -EFAULT; + file->f_pos += size; } - return 0; + return size; } static struct snd_info_entry_ops snd_cs4281_proc_ops_BA0 = { @@ -1239,7 +1229,7 @@ static void __devinit snd_cs4281_proc_in snd_info_entry_t *entry; if (! snd_card_proc_new(chip->card, "cs4281", &entry)) - snd_info_set_text_ops(entry, chip, snd_cs4281_proc_read); + snd_info_set_text_ops(entry, chip, 1024, snd_cs4281_proc_read); if (! snd_card_proc_new(chip->card, "cs4281_BA0", &entry)) { entry->content = SNDRV_INFO_CONTENT_DATA; entry->private_data = chip; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/cs46xx/cs46xx_lib.c 830-ivtv/sound/pci/cs46xx/cs46xx_lib.c --- 000-virgin/sound/pci/cs46xx/cs46xx_lib.c Mon Nov 17 18:29:01 2003 +++ 830-ivtv/sound/pci/cs46xx/cs46xx_lib.c Thu Jan 8 10:26:50 2004 @@ -1804,6 +1804,13 @@ int __devinit snd_cs46xx_pcm_iec958(cs46 /* * Mixer routines */ +static void snd_cs46xx_mixer_free_ac97_bus(ac97_bus_t *bus) +{ + cs46xx_t *chip = snd_magic_cast(cs46xx_t, bus->private_data, return); + + chip->ac97_bus = NULL; +} + static void snd_cs46xx_mixer_free_ac97(ac97_t *ac97) { cs46xx_t *chip = snd_magic_cast(cs46xx_t, ac97->private_data, return); @@ -2445,6 +2452,7 @@ static void snd_cs46xx_codec_reset (ac97 int __devinit snd_cs46xx_mixer(cs46xx_t *chip) { snd_card_t *card = chip->card; + ac97_bus_t bus; ac97_t ac97; snd_ctl_elem_id_t id; int err; @@ -2453,14 +2461,20 @@ int __devinit snd_cs46xx_mixer(cs46xx_t /* detect primary codec */ chip->nr_ac97_codecs = 0; snd_printdd("snd_cs46xx: detecting primary codec\n"); + memset(&bus, 0, sizeof(bus)); + bus.write = snd_cs46xx_ac97_write; + bus.read = snd_cs46xx_ac97_read; +#ifdef CONFIG_SND_CS46XX_NEW_DSP + bus.reset = snd_cs46xx_codec_reset; +#endif + bus.private_data = chip; + bus.private_free = snd_cs46xx_mixer_free_ac97_bus; + if ((err = snd_ac97_bus(card, &bus, &chip->ac97_bus)) < 0) + return err; + memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_cs46xx_ac97_write; - ac97.read = snd_cs46xx_ac97_read; ac97.private_data = chip; ac97.private_free = snd_cs46xx_mixer_free_ac97; -#ifdef CONFIG_SND_CS46XX_NEW_DSP - ac97.reset = snd_cs46xx_codec_reset; -#endif chip->ac97[CS46XX_PRIMARY_CODEC_INDEX] = &ac97; snd_cs46xx_ac97_write(&ac97, AC97_MASTER, 0x8000); @@ -2474,7 +2488,7 @@ int __devinit snd_cs46xx_mixer(cs46xx_t return -ENXIO; _ok: - if ((err = snd_ac97_mixer(card, &ac97, &chip->ac97[CS46XX_PRIMARY_CODEC_INDEX])) < 0) + if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97[CS46XX_PRIMARY_CODEC_INDEX])) < 0) return err; snd_printdd("snd_cs46xx: primary codec phase one\n"); chip->nr_ac97_codecs = 1; @@ -2483,8 +2497,6 @@ int __devinit snd_cs46xx_mixer(cs46xx_t snd_printdd("snd_cs46xx: detecting seconadry codec\n"); /* try detect a secondary codec */ memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_cs46xx_ac97_write; - ac97.read = snd_cs46xx_ac97_read; ac97.private_data = chip; ac97.private_free = snd_cs46xx_mixer_free_ac97; ac97.num = CS46XX_SECONDARY_CODEC_INDEX; @@ -2516,13 +2528,7 @@ int __devinit snd_cs46xx_mixer(cs46xx_t /* well, one codec only ... */ goto _end; _ok2: - /* set secondary codec in extended mode */ - - /* use custom reset to set secondary codec in - extended mode */ - ac97.reset = snd_cs46xx_codec_reset; - - if ((err = snd_ac97_mixer(card, &ac97, &chip->ac97[CS46XX_SECONDARY_CODEC_INDEX])) < 0) + if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97[CS46XX_SECONDARY_CODEC_INDEX])) < 0) return err; chip->nr_ac97_codecs = 2; @@ -2546,8 +2552,10 @@ int __devinit snd_cs46xx_mixer(cs46xx_t #ifdef CONFIG_SND_CS46XX_NEW_DSP if (chip->nr_ac97_codecs == 1 && - snd_cs46xx_codec_read(chip, AC97_VENDOR_ID2, - CS46XX_PRIMARY_CODEC_INDEX) == 0x592d) { + (snd_cs46xx_codec_read(chip, AC97_VENDOR_ID2, + CS46XX_PRIMARY_CODEC_INDEX) == 0x592b || + snd_cs46xx_codec_read(chip, AC97_VENDOR_ID2, + CS46XX_PRIMARY_CODEC_INDEX) == 0x592d)) { /* set primary cs4294 codec into Extended Audio Mode */ snd_printdd("setting EAM bit on cs4294 CODEC\n"); snd_cs46xx_codec_write(chip, AC97_CSR_ACMODE, 0x200, @@ -2849,23 +2857,11 @@ static long snd_cs46xx_io_read(snd_info_ if (file->f_pos + (size_t)size > region->size) size = region->size - file->f_pos; if (size > 0) { - char *tmp; - long res; - unsigned long virt; - if ((tmp = kmalloc(size, GFP_KERNEL)) == NULL) - return -ENOMEM; - virt = region->remap_addr + file->f_pos; - memcpy_fromio(tmp, virt, size); - if (copy_to_user(buf, tmp, size)) - res = -EFAULT; - else { - res = size; - file->f_pos += size; - } - kfree(tmp); - return res; + if (copy_to_user_fromio(buf, region->remap_addr + file->f_pos, size)) + return -EFAULT; + file->f_pos += size; } - return 0; + return size; } static struct snd_info_entry_ops snd_cs46xx_proc_io_ops = { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/emu10k1/emu10k1_main.c 830-ivtv/sound/pci/emu10k1/emu10k1_main.c --- 000-virgin/sound/pci/emu10k1/emu10k1_main.c Wed Aug 13 20:24:37 2003 +++ 830-ivtv/sound/pci/emu10k1/emu10k1_main.c Thu Jan 8 10:26:50 2004 @@ -269,6 +269,9 @@ static int __devinit snd_emu10k1_init(em * This has to be done after init ALice3 I2SOut beyond 48KHz. * So, sequence is important. */ outl(inl(emu->port + A_IOCFG) | 0x0040, emu->port + A_IOCFG); + } else { + /* Disable routing from AC97 line out to Front speakers */ + outl(inl(emu->port + A_IOCFG) | 0x0080, emu->port + A_IOCFG); } } @@ -601,7 +604,7 @@ int __devinit snd_emu10k1_create(snd_car return -ENOMEM; /* set the DMA transfer mask */ emu->dma_mask = is_audigy ? AUDIGY_DMA_MASK : EMU10K1_DMA_MASK; - if (pci_set_dma_mask(pci, emu->dma_mask) < 0) { + if (pci_set_consistent_dma_mask(pci, emu->dma_mask) < 0) { snd_printk(KERN_ERR "architecture does not support PCI busmaster DMA with mask 0x%lx\n", emu->dma_mask); snd_magic_kfree(emu); return -ENXIO; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/emu10k1/emufx.c 830-ivtv/sound/pci/emu10k1/emufx.c --- 000-virgin/sound/pci/emu10k1/emufx.c Mon Nov 17 18:29:01 2003 +++ 830-ivtv/sound/pci/emu10k1/emufx.c Thu Jan 8 10:26:50 2004 @@ -1009,13 +1009,16 @@ static void snd_emu10k1_del_controls(emu unsigned int i; snd_ctl_elem_id_t *_id, id; snd_emu10k1_fx8010_ctl_t *ctl; + snd_card_t *card = emu->card; for (i = 0, _id = icode->gpr_del_controls; i < icode->gpr_del_control_count; i++, _id++) { snd_runtime_check(copy_from_user(&id, _id, sizeof(id)) == 0, continue); + down_write(&card->controls_rwsem); ctl = snd_emu10k1_look_for_ctl(emu, &id); - snd_runtime_check(ctl == NULL, continue); - snd_ctl_remove(emu->card, ctl->kcontrol); + if (ctl) + snd_ctl_remove(card, ctl->kcontrol); + up_write(&card->controls_rwsem); } } @@ -1234,14 +1237,12 @@ static void __devinit snd_emu10k1_init_s * initial DSP configuration for Audigy */ -#define A_GPR_ACCU 0xd6 -#define A_GPR_COND 0xd7 - static int __devinit _snd_emu10k1_audigy_init_efx(emu10k1_t *emu) { int err, i, z, gpr, nctl; const int playback = 10; const int capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */ + const int stereo_mix = capture + 2; const int tmp = 0x88; u32 ptr; emu10k1_fx8010_code_t *icode; @@ -1265,45 +1266,52 @@ static int __devinit _snd_emu10k1_audigy strcpy(icode->name, "Audigy DSP code for ALSA"); ptr = 0; nctl = 0; - gpr = capture + 10; + gpr = stereo_mix + 10; /* stop FX processor */ snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP); - /* Wave Playback Volume */ - A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT)); - snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Playback Volume", gpr, 100); + /* PCM front Playback Volume (independent from stereo mix) */ + A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT)); + snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Front Playback Volume", gpr, 100); gpr += 2; - - /* Wave Surround Playback */ - A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT)); - snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Surround Playback Volume", gpr, 0); + + /* PCM Surround Playback (independent from stereo mix) */ + A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_REAR)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_REAR)); + snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Surround Playback Volume", gpr, 100); gpr += 2; - /* Wave Center Playback */ - /* Center = sub = Left/2 + Right/2 */ - A_OP(icode, &ptr, iINTERP, A_GPR(tmp), A_FXBUS(FXBUS_PCM_LEFT), 0xcd, A_FXBUS(FXBUS_PCM_RIGHT)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_C_00000000, A_GPR(gpr), A_GPR(tmp)); - snd_emu10k1_init_mono_control(&controls[nctl++], "Wave Center Playback Volume", gpr, 0); + /* PCM Center Playback (independent from stereo mix) */ + A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_CENTER)); + snd_emu10k1_init_mono_control(&controls[nctl++], "PCM Center Playback Volume", gpr, 100); gpr++; - /* Wave LFE Playback */ - A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_C_00000000, A_GPR(gpr), A_GPR(tmp)); - snd_emu10k1_init_mono_control(&controls[nctl++], "Wave LFE Playback Volume", gpr, 0); + /* PCM LFE Playback (independent from stereo mix) */ + A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LFE)); + snd_emu10k1_init_mono_control(&controls[nctl++], "PCM LFE Playback Volume", gpr, 100); gpr++; + + /* + * Stereo Mix + */ + /* Wave (PCM) Playback Volume (will be renamed later) */ + A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT)); + A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT)); + snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Playback Volume", gpr, 100); + gpr += 2; /* Music Playback */ - A_OP(icode, &ptr, iMAC0, A_GPR(playback+0), A_GPR(playback+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_GPR(playback+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT)); + A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+0), A_GPR(stereo_mix+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT)); + A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_GPR(stereo_mix+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT)); snd_emu10k1_init_stereo_control(&controls[nctl++], "Music Playback Volume", gpr, 100); gpr += 2; - /* Wave Capture */ + /* Wave (PCM) Capture */ A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT)); A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT)); - snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Capture Volume", gpr, 0); + snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Capture Volume", gpr, 0); gpr += 2; /* Music Capture */ @@ -1312,42 +1320,29 @@ static int __devinit _snd_emu10k1_audigy snd_emu10k1_init_stereo_control(&controls[nctl++], "Music Capture Volume", gpr, 0); gpr += 2; - /* Surround Playback */ - A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_GPR(playback+2), A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_REAR)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_GPR(playback+3), A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_REAR)); - snd_emu10k1_init_stereo_control(&controls[nctl++], "Surround Playback Volume", gpr, 80); - gpr += 2; - - /* Center Playback */ - A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_GPR(playback+4), A_GPR(gpr), A_FXBUS(FXBUS_PCM_CENTER)); - snd_emu10k1_init_mono_control(&controls[nctl++], "Center Playback Volume", gpr, 80); - gpr++; - - /* LFE Playback */ - A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_GPR(playback+5), A_GPR(gpr), A_FXBUS(FXBUS_PCM_LFE)); - snd_emu10k1_init_mono_control(&controls[nctl++], "LFE Playback Volume", gpr, 80); - gpr++; - /* * inputs */ #define A_ADD_VOLUME_IN(var,vol,input) \ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) - /* AC'97 Playback Volume */ - A_ADD_VOLUME_IN(playback, gpr, A_EXTIN_AC97_L); - A_ADD_VOLUME_IN(playback+1, gpr+1, A_EXTIN_AC97_R); - snd_emu10k1_init_stereo_control(&controls[nctl++], "AC97 Playback Volume", gpr, 0); + /* AC'97 Playback Volume - used only for mic */ + A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AC97_L); + A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AC97_R); + snd_emu10k1_init_stereo_control(&controls[nctl++], "AMic Playback Volume", gpr, 0); gpr += 2; - /* AC'97 Capture Volume */ + /* AC'97 Capture Volume - used only for mic */ A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AC97_L); A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AC97_R); - snd_emu10k1_init_stereo_control(&controls[nctl++], "AC97 Capture Volume", gpr, 100); + snd_emu10k1_init_stereo_control(&controls[nctl++], "Mic Capture Volume", gpr, 0); gpr += 2; + /* mic capture buffer */ + A_OP(icode, &ptr, iINTERP, A_EXTOUT(A_EXTOUT_MIC_CAP), A_EXTIN(A_EXTIN_AC97_L), 0xcd, A_EXTIN(A_EXTIN_AC97_R)); + /* Audigy CD Playback Volume */ - A_ADD_VOLUME_IN(playback, gpr, A_EXTIN_SPDIF_CD_L); - A_ADD_VOLUME_IN(playback+1, gpr+1, A_EXTIN_SPDIF_CD_R); + A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_SPDIF_CD_L); + A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_SPDIF_CD_R); snd_emu10k1_init_stereo_control(&controls[nctl++], "Audigy CD Playback Volume", gpr, 0); gpr += 2; /* Audigy CD Capture Volume */ @@ -1357,19 +1352,19 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_G gpr += 2; /* Optical SPDIF Playback Volume */ - A_ADD_VOLUME_IN(playback, gpr, A_EXTIN_OPT_SPDIF_L); - A_ADD_VOLUME_IN(playback+1, gpr+1, A_EXTIN_OPT_SPDIF_R); - snd_emu10k1_init_stereo_control(&controls[nctl++], "Optical IEC958 Playback Volume", gpr, 0); + A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_OPT_SPDIF_L); + A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_OPT_SPDIF_R); + snd_emu10k1_init_stereo_control(&controls[nctl++], "IEC958 Optical Playback Volume", gpr, 0); gpr += 2; /* Optical SPDIF Capture Volume */ A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_OPT_SPDIF_L); A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_OPT_SPDIF_R); - snd_emu10k1_init_stereo_control(&controls[nctl++], "Optical IEC958 Capture Volume", gpr, 0); + snd_emu10k1_init_stereo_control(&controls[nctl++], "IEC958 Optical Capture Volume", gpr, 0); gpr += 2; /* Line2 Playback Volume */ - A_ADD_VOLUME_IN(playback, gpr, A_EXTIN_LINE2_L); - A_ADD_VOLUME_IN(playback+1, gpr+1, A_EXTIN_LINE2_R); + A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_LINE2_L); + A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_LINE2_R); snd_emu10k1_init_stereo_control(&controls[nctl++], "Line2 Playback Volume", gpr, 0); gpr += 2; /* Line2 Capture Volume */ @@ -1378,20 +1373,20 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_G snd_emu10k1_init_stereo_control(&controls[nctl++], "Line2 Capture Volume", gpr, 0); gpr += 2; - /* RCA SPDIF Playback Volume */ - A_ADD_VOLUME_IN(playback, gpr, A_EXTIN_RCA_SPDIF_L); - A_ADD_VOLUME_IN(playback+1, gpr+1, A_EXTIN_RCA_SPDIF_R); - snd_emu10k1_init_stereo_control(&controls[nctl++], "RCA SPDIF Playback Volume", gpr, 0); - gpr += 2; - /* RCA SPDIF Capture Volume */ - A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_RCA_SPDIF_L); - A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_RCA_SPDIF_R); - snd_emu10k1_init_stereo_control(&controls[nctl++], "RCA SPDIF Capture Volume", gpr, 0); + /* Philips ADC Playback Volume */ + A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_ADC_L); + A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_ADC_R); + snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Playback Volume", gpr, 0); + gpr += 2; + /* Philips ADC Capture Volume */ + A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_ADC_L); + A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_ADC_R); + snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Capture Volume", gpr, 0); gpr += 2; /* Aux2 Playback Volume */ - A_ADD_VOLUME_IN(playback, gpr, A_EXTIN_AUX2_L); - A_ADD_VOLUME_IN(playback+1, gpr+1, A_EXTIN_AUX2_R); + A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AUX2_L); + A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AUX2_R); snd_emu10k1_init_stereo_control(&controls[nctl++], "Aux2 Playback Volume", gpr, 0); gpr += 2; /* Aux2 Capture Volume */ @@ -1399,6 +1394,30 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_G A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AUX2_R); snd_emu10k1_init_stereo_control(&controls[nctl++], "Aux2 Capture Volume", gpr, 0); gpr += 2; + + /* Stereo Mix Front Playback Volume */ + A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_GPR(playback), A_GPR(gpr), A_GPR(stereo_mix)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_GPR(playback+1), A_GPR(gpr+1), A_GPR(stereo_mix+1)); + snd_emu10k1_init_stereo_control(&controls[nctl++], "Front Playback Volume", gpr, 100); + gpr += 2; + + /* Stereo Mix Surround Playback */ + A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_GPR(playback+2), A_GPR(gpr), A_GPR(stereo_mix)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_GPR(playback+3), A_GPR(gpr+1), A_GPR(stereo_mix+1)); + snd_emu10k1_init_stereo_control(&controls[nctl++], "Surround Playback Volume", gpr, 0); + gpr += 2; + + /* Stereo Mix Center Playback */ + /* Center = sub = Left/2 + Right/2 */ + A_OP(icode, &ptr, iINTERP, A_GPR(tmp), A_GPR(stereo_mix), 0xcd, A_GPR(stereo_mix+1)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_GPR(playback+4), A_GPR(gpr), A_GPR(tmp)); + snd_emu10k1_init_mono_control(&controls[nctl++], "Center Playback Volume", gpr, 0); + gpr++; + + /* Stereo Mix LFE Playback */ + A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_GPR(playback+5), A_GPR(gpr), A_GPR(tmp)); + snd_emu10k1_init_mono_control(&controls[nctl++], "LFE Playback Volume", gpr, 0); + gpr++; /* * outputs @@ -1497,20 +1516,18 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_G snd_emu10k1_init_stereo_onoff_control(controls + nctl++, "Tone Control - Switch", gpr, 0); gpr += 2; - /* Master volume for audigy2 */ - if (emu->revision == 4) { - A_OP(icode, &ptr, iMAC0, A_GPR(playback+0+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+0+SND_EMU10K1_PLAYBACK_CHANNELS)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+1+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr+1), A_GPR(playback+1+SND_EMU10K1_PLAYBACK_CHANNELS)); - snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Master Playback Volume", gpr, 0); - gpr += 2; - } + /* Master volume (will be renamed later) */ + A_OP(icode, &ptr, iMAC0, A_GPR(playback+0+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+0+SND_EMU10K1_PLAYBACK_CHANNELS)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+1+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr+1), A_GPR(playback+1+SND_EMU10K1_PLAYBACK_CHANNELS)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+2+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr+1), A_GPR(playback+2+SND_EMU10K1_PLAYBACK_CHANNELS)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+3+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr+1), A_GPR(playback+3+SND_EMU10K1_PLAYBACK_CHANNELS)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+4+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr+1), A_GPR(playback+4+SND_EMU10K1_PLAYBACK_CHANNELS)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+5+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr+1), A_GPR(playback+5+SND_EMU10K1_PLAYBACK_CHANNELS)); + snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Master Playback Volume", gpr, 0); + gpr += 2; /* analog speakers */ - if (emu->revision == 4) { /* audigy2 */ - A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); - } else { - A_PUT_STEREO_OUTPUT(A_EXTOUT_AC97_L, A_EXTOUT_AC97_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); - } + A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS); A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS); A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS); @@ -1519,7 +1536,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_G A_PUT_STEREO_OUTPUT(A_EXTOUT_HEADPHONE_L, A_EXTOUT_HEADPHONE_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); /* digital outputs */ -// A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); + /* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */ /* IEC958 Optical Raw Playback Switch */ icode->gpr_map[gpr++] = 0x1008; @@ -1931,7 +1948,7 @@ static int __devinit _snd_emu10k1_init_e /* Line LiveDrive Playback Volume */ for (z = 0; z < 2; z++) VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_LINE2_L + z, gpr + z); - snd_emu10k1_init_stereo_control(controls + i++, "Line LiveDrive Playback Volume", gpr, 0); + snd_emu10k1_init_stereo_control(controls + i++, "Line2 LiveDrive Playback Volume", gpr, 0); controls[i-1].id.index = 1; gpr += 2; @@ -1940,8 +1957,8 @@ static int __devinit _snd_emu10k1_init_e SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_LINE2_L + z, gpr + 2 + z); VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z); } - snd_emu10k1_init_stereo_control(controls + i++, "Line LiveDrive Capture Volume", gpr, 0); - snd_emu10k1_init_stereo_onoff_control(controls + i++, "Line LiveDrive Capture Switch", gpr + 2, 0); + snd_emu10k1_init_stereo_control(controls + i++, "Line2 LiveDrive Capture Volume", gpr, 0); + snd_emu10k1_init_stereo_onoff_control(controls + i++, "Line2 LiveDrive Capture Switch", gpr + 2, 0); controls[i-1].id.index = 1; gpr += 4; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/emu10k1/emumixer.c 830-ivtv/sound/pci/emu10k1/emumixer.c --- 000-virgin/sound/pci/emu10k1/emumixer.c Wed Aug 13 20:24:37 2003 +++ 830-ivtv/sound/pci/emu10k1/emumixer.c Thu Jan 8 10:26:50 2004 @@ -455,30 +455,51 @@ static int rename_ctl(snd_card_t *card, int __devinit snd_emu10k1_mixer(emu10k1_t *emu) { - ac97_t ac97; int err, pcm; snd_kcontrol_t *kctl; snd_card_t *card = emu->card; if (!emu->no_ac97) { + ac97_bus_t bus, *pbus; + ac97_t ac97; + + memset(&bus, 0, sizeof(bus)); + bus.write = snd_emu10k1_ac97_write; + bus.read = snd_emu10k1_ac97_read; + if ((err = snd_ac97_bus(emu->card, &bus, &pbus)) < 0) + return err; + memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_emu10k1_ac97_write; - ac97.read = snd_emu10k1_ac97_read; ac97.private_data = emu; ac97.private_free = snd_emu10k1_mixer_free_ac97; - if ((err = snd_ac97_mixer(emu->card, &ac97, &emu->ac97)) < 0) + if ((err = snd_ac97_mixer(pbus, &ac97, &emu->ac97)) < 0) return err; - if (emu->audigy && emu->revision == 4) { - /* Master/PCM controls on ac97 of Audigy2 has no effect */ - /* FIXME: keep master volume/switch to be sure. - * once after we check that they play really no roles, - * they shall be removed. - */ - rename_ctl(card, "Master Playback Switch", "AC97 Master Playback Switch"); - rename_ctl(card, "Master Playback Volume", "AC97 Master Playback Volume"); + if (emu->audigy) { + /* Master/PCM controls on ac97 of Audigy has no effect */ /* pcm controls are removed */ remove_ctl(card, "PCM Playback Switch"); remove_ctl(card, "PCM Playback Volume"); + remove_ctl(card, "Master Mono Playback Switch"); + remove_ctl(card, "Master Mono Playback Volume"); + remove_ctl(card, "Master Playback Switch"); + remove_ctl(card, "Master Playback Volume"); + remove_ctl(card, "PCM Out Path & Mute"); + remove_ctl(card, "Mono Output Select"); + + /* set master volume to 0 dB */ + snd_ac97_write(emu->ac97, AC97_MASTER, 0x0202); + /* set capture source to mic */ + snd_ac97_write(emu->ac97, AC97_REC_SEL, 0x0000); + + /* remove unused AC97 capture controls */ + remove_ctl(card, "Capture Source"); + remove_ctl(card, "Capture Switch"); + remove_ctl(card, "Capture Volume"); + remove_ctl(card, "Mic Select"); + remove_ctl(card, "Video Playback Switch"); + remove_ctl(card, "Video Playback Volume"); + remove_ctl(card, "Mic Playback Switch"); + remove_ctl(card, "Mic Playback Volume"); } } else { if (emu->APS) @@ -489,12 +510,12 @@ int __devinit snd_emu10k1_mixer(emu10k1_ strcpy(emu->card->mixername, "Emu10k1"); } - if (emu->audigy && emu->revision == 4) { - /* Audigy2 and Audigy2 EX */ + if (emu->audigy) { /* use the conventional names */ rename_ctl(card, "Wave Playback Volume", "PCM Playback Volume"); - rename_ctl(card, "Wave Playback Volume", "PCM Capture Volume"); + /* rename_ctl(card, "Wave Capture Volume", "PCM Capture Volume"); */ rename_ctl(card, "Wave Master Playback Volume", "Master Playback Volume"); + rename_ctl(card, "AMic Playback Volume", "Mic Playback Volume"); } if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL) @@ -536,6 +557,11 @@ int __devinit snd_emu10k1_mixer(emu10k1_ return -ENOMEM; if ((err = snd_ctl_add(card, kctl))) return err; + if ((kctl = ctl_find(card, SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT))) != NULL) { + /* already defined by ac97, remove it */ + /* FIXME: or do we need both controls? */ + remove_ctl(card, SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT)); + } if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL) return -ENOMEM; if ((err = snd_ctl_add(card, kctl))) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/emu10k1/emupcm.c 830-ivtv/sound/pci/emu10k1/emupcm.c --- 000-virgin/sound/pci/emu10k1/emupcm.c Mon Nov 17 18:29:01 2003 +++ 830-ivtv/sound/pci/emu10k1/emupcm.c Thu Jan 8 10:26:50 2004 @@ -871,7 +871,7 @@ static int snd_emu10k1_capture_mic_open( epcm->capture_inte = INTE_MICBUFENABLE; epcm->capture_ba_reg = MICBA; epcm->capture_bs_reg = MICBS; - epcm->capture_idx_reg = MICIDX; + epcm->capture_idx_reg = emu->audigy ? A_MICIDX : MICIDX; substream->runtime->private_data = epcm; substream->runtime->private_free = snd_emu10k1_pcm_free_substream; runtime->hw = snd_emu10k1_capture; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/emu10k1/emuproc.c 830-ivtv/sound/pci/emu10k1/emuproc.c --- 000-virgin/sound/pci/emu10k1/emuproc.c Wed Mar 26 22:54:40 2003 +++ 830-ivtv/sound/pci/emu10k1/emuproc.c Thu Jan 8 10:26:50 2004 @@ -240,7 +240,7 @@ int __devinit snd_emu10k1_proc_init(emu1 snd_info_entry_t *entry; if (! snd_card_proc_new(emu->card, "emu10k1", &entry)) - snd_info_set_text_ops(entry, emu, snd_emu10k1_proc_read); + snd_info_set_text_ops(entry, emu, 1024, snd_emu10k1_proc_read); if (! snd_card_proc_new(emu->card, "fx8010_gpr", &entry)) { entry->content = SNDRV_INFO_CONTENT_DATA; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/ens1370.c 830-ivtv/sound/pci/ens1370.c --- 000-virgin/sound/pci/ens1370.c Mon Nov 17 18:29:01 2003 +++ 830-ivtv/sound/pci/ens1370.c Thu Jan 8 10:26:50 2004 @@ -72,9 +72,20 @@ MODULE_DEVICES("{{Ensoniq,AudioPCI ES137 "{Ectiva,EV1938}}"); #endif +#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#define SUPPORT_JOYSTICK +#endif + static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable switches */ +#ifdef SUPPORT_JOYSTICK +#ifdef CHIP1371 +static int joystick_port[SNDRV_CARDS]; +#else +static int joystick[SNDRV_CARDS]; +#endif +#endif MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(index, "Index value for Ensoniq AudioPCI soundcard."); @@ -85,6 +96,17 @@ MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(enable, "Enable Ensoniq AudioPCI soundcard."); MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); +#ifdef SUPPORT_JOYSTICK +#ifdef CHIP1371 +MODULE_PARM(joystick_port, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(joystick_port, "Joystick port address."); +MODULE_PARM_SYNTAX(joystick_port, SNDRV_ENABLED ",allows:{{0},{1},{0x200},{0x208},{0x210},{0x218}},dialog:list"); +#else +MODULE_PARM(joystick, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(joystick, "Enable joystick."); +MODULE_PARM_SYNTAX(joystick, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); +#endif +#endif /* SUPPORT_JOYSTICK */ #ifndef PCI_DEVICE_ID_ENSONIQ_CT5880 #define PCI_DEVICE_ID_ENSONIQ_CT5880 0x5880 @@ -416,9 +438,8 @@ struct _snd_ensoniq { dma_addr_t bugbuf_addr; #endif -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#ifdef SUPPORT_JOYSTICK struct gameport gameport; - struct semaphore joy_sem; // gameport configuration semaphore #endif }; @@ -1513,16 +1534,21 @@ static struct { static int snd_ensoniq_1371_mixer(ensoniq_t * ensoniq) { snd_card_t *card = ensoniq->card; + ac97_bus_t bus, *pbus; ac97_t ac97; int err, idx; + memset(&bus, 0, sizeof(bus)); + bus.write = snd_es1371_codec_write; + bus.read = snd_es1371_codec_read; + if ((err = snd_ac97_bus(card, &bus, &pbus)) < 0) + return err; + memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_es1371_codec_write; - ac97.read = snd_es1371_codec_read; ac97.private_data = ensoniq; ac97.private_free = snd_ensoniq_mixer_free_ac97; ac97.scaps = AC97_SCAP_AUDIO; - if ((err = snd_ac97_mixer(card, &ac97, &ensoniq->u.es1371.ac97)) < 0) + if ((err = snd_ac97_mixer(pbus, &ac97, &ensoniq->u.es1371.ac97)) < 0) return err; for (idx = 0; es1371_spdif_present[idx].vid != (unsigned short)PCI_ANY_ID; idx++) if (ensoniq->pci->vendor == es1371_spdif_present[idx].vid && @@ -1565,8 +1591,8 @@ static int snd_ensoniq_1371_mixer(ensoni #endif /* CHIP1371 */ -/* generic control callbacks for ens1370 and for joystick */ -#if defined(CHIP1370) || defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +/* generic control callbacks for ens1370 */ +#ifdef CHIP1370 #define ENSONIQ_CONTROL(xname, mask) \ { .iface = SNDRV_CTL_ELEM_IFACE_CARD, .name = xname, .info = snd_ensoniq_control_info, \ .get = snd_ensoniq_control_get, .put = snd_ensoniq_control_put, \ @@ -1593,7 +1619,6 @@ static int snd_ensoniq_control_get(snd_k return 0; } -#ifdef CHIP1370 static int snd_ensoniq_control_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol); @@ -1611,14 +1636,11 @@ static int snd_ensoniq_control_put(snd_k spin_unlock_irqrestore(&ensoniq->reg_lock, flags); return change; } -#endif /* CHIP1370 */ -#endif /* CHIP1370 || GAMEPORT */ /* * ENS1370 mixer */ -#ifdef CHIP1370 static snd_kcontrol_new_t snd_es1370_controls[2] __devinitdata = { ENSONIQ_CONTROL("PCM 0 Output also on Line-In Jack", ES_1370_XCTL0), ENSONIQ_CONTROL("Mic +5V bias", ES_1370_XCTL1) @@ -1660,129 +1682,45 @@ static int __devinit snd_ensoniq_1370_mi #endif /* CHIP1370 */ -/* - * General Switches... - */ - -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) -/* MQ: gameport driver connectivity */ -#define ENSONIQ_JOY_CONTROL(xname, mask) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_CARD, .name = xname, .info = snd_ensoniq_control_info, \ - .get = snd_ensoniq_control_get, .put = snd_ensoniq_joy_control_put, \ - .private_value = mask } - -static int snd_ensoniq_joy_enable(ensoniq_t *ensoniq) +#ifdef SUPPORT_JOYSTICK +static int snd_ensoniq_joystick(ensoniq_t *ensoniq, long port) { - static unsigned long last_jiffies = 0; - unsigned long flags; - - if (!request_region(ensoniq->gameport.io, 8, "ens137x: gameport")) { -#define ES___GAMEPORT_LOG_DELAY (30*HZ) - // avoid log pollution: limit to 2 infos per minute - if (time_after(jiffies, last_jiffies + ES___GAMEPORT_LOG_DELAY)) { - last_jiffies = jiffies; +#ifdef CHIP1371 + if (port == 1) { /* auto-detect */ + for (port = 0x200; port <= 0x218; port += 8) + if (request_region(port, 8, "ens137x: gameport")) + break; + if (port > 0x218) { + snd_printk("no gameport available\n"); + return -EBUSY; + } + } else +#endif + { + if (!request_region(port, 8, "ens137x: gameport")) { snd_printk("gameport io port 0x%03x in use", ensoniq->gameport.io); + return -EBUSY; } - return 0; } - spin_lock_irqsave(&ensoniq->reg_lock, flags); + ensoniq->gameport.io = port; ensoniq->ctrl |= ES_JYSTK_EN; +#ifdef CHIP1371 + ensoniq->ctrl &= ~ES_1371_JOY_ASELM; + ensoniq->ctrl |= ES_1371_JOY_ASEL((ensoniq->gameport.io - 0x200) / 8); +#endif outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); - spin_unlock_irqrestore(&ensoniq->reg_lock, flags); gameport_register_port(&ensoniq->gameport); - return 1; + return 0; } -static int snd_ensoniq_joy_disable(ensoniq_t *ensoniq) +static void snd_ensoniq_joystick_free(ensoniq_t *ensoniq) { - unsigned long flags; - gameport_unregister_port(&ensoniq->gameport); - spin_lock_irqsave(&ensoniq->reg_lock, flags); ensoniq->ctrl &= ~ES_JYSTK_EN; outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); - spin_unlock_irqrestore(&ensoniq->reg_lock, flags); release_region(ensoniq->gameport.io, 8); - return 1; -} - -static int snd_ensoniq_joy_control_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol); - unsigned int nval; - int change; - - down(&ensoniq->joy_sem); - nval = ucontrol->value.integer.value[0] ? ES_JYSTK_EN : 0; - change = (ensoniq->ctrl & ES_JYSTK_EN) != nval; // spinlock shouldn't be needed because of joy_sem - if (change) { - if (nval) // enable - change = snd_ensoniq_joy_enable(ensoniq); - else change = snd_ensoniq_joy_disable(ensoniq); - } - up(&ensoniq->joy_sem); - return change; -} - -static snd_kcontrol_new_t snd_ensoniq_control_joystick __devinitdata = -ENSONIQ_JOY_CONTROL("Joystick Enable", ES_JYSTK_EN); - -#ifdef CHIP1371 - -#define ES1371_JOYSTICK_ADDR(xname) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_CARD, .name = xname, .info = snd_es1371_joystick_addr_info, \ - .get = snd_es1371_joystick_addr_get, .put = snd_es1371_joystick_addr_put } - -static int snd_es1371_joystick_addr_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 4; - if (uinfo->value.enumerated.item >= 4) - uinfo->value.enumerated.item = 3; - sprintf(uinfo->value.enumerated.name, "port 0x%x", (uinfo->value.enumerated.item * 8) + 0x200); - return 0; -} - -static int snd_es1371_joystick_addr_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol); - unsigned long flags; - - spin_lock_irqsave(&ensoniq->reg_lock, flags); - ucontrol->value.enumerated.item[0] = ES_1371_JOY_ASELI(ensoniq->ctrl); - spin_unlock_irqrestore(&ensoniq->reg_lock, flags); - return 0; -} - -static int snd_es1371_joystick_addr_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol); - unsigned long flags; - unsigned int nval; - int change; - - down(&ensoniq->joy_sem); - nval = ES_1371_JOY_ASEL(ucontrol->value.integer.value[0]); - spin_lock_irqsave(&ensoniq->reg_lock, flags); - if (!(change = !(ensoniq->ctrl & ES_JYSTK_EN))) - goto no_change; // FIXME: now we allow change only when joystick is disabled - change = (ensoniq->ctrl & ES_1371_JOY_ASELM) != nval; - ensoniq->ctrl &= ~ES_1371_JOY_ASELM; - ensoniq->ctrl |= nval; - outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); - ensoniq->gameport.io = 0x200 + ES_1371_JOY_ASELI(nval) * 8; -no_change: - spin_unlock_irqrestore(&ensoniq->reg_lock, flags); - up(&ensoniq->joy_sem); - return change; } - -static snd_kcontrol_new_t snd_es1371_joystick_addr __devinitdata = -ES1371_JOYSTICK_ADDR("Joystick Address"); - -#endif /* CHIP1371 */ -#endif /* CONFIG_GAMEPORT */ +#endif /* SUPPORT_JOYSTICK */ /* @@ -1812,7 +1750,7 @@ static void __devinit snd_ensoniq_proc_i snd_info_entry_t *entry; if (! snd_card_proc_new(ensoniq->card, "audiopci", &entry)) - snd_info_set_text_ops(entry, ensoniq, snd_ensoniq_proc_read); + snd_info_set_text_ops(entry, ensoniq, 1024, snd_ensoniq_proc_read); } /* @@ -1821,9 +1759,9 @@ static void __devinit snd_ensoniq_proc_i static int snd_ensoniq_free(ensoniq_t *ensoniq) { -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#ifdef SUPPORT_JOYSTICK if (ensoniq->ctrl & ES_JYSTK_EN) - snd_ensoniq_joy_disable(ensoniq); + snd_ensoniq_joystick_free(ensoniq); #endif if (ensoniq->irq < 0) goto __hw_end; @@ -2019,14 +1957,6 @@ static int __devinit snd_ensoniq_create( outb(ensoniq->uartc = 0x00, ES_REG(ensoniq, UART_CONTROL)); outb(0x00, ES_REG(ensoniq, UART_RES)); outl(ensoniq->cssr, ES_REG(ensoniq, STATUS)); -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) - init_MUTEX(&ensoniq->joy_sem); -#ifdef CHIP1371 - snd_ctl_add(card, snd_ctl_new1(&snd_es1371_joystick_addr, ensoniq)); -#endif - snd_ctl_add(card, snd_ctl_new1(&snd_ensoniq_control_joystick, ensoniq)); - ensoniq->gameport.io = 0x200; // FIXME: is ES1371 configured like this above ? -#endif synchronize_irq(ensoniq->irq); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ensoniq, &ops)) < 0) { @@ -2331,6 +2261,22 @@ static int __devinit snd_audiopci_probe( snd_card_free(card); return err; } +#ifdef SUPPORT_JOYSTICK +#ifdef CHIP1371 + switch (joystick_port[dev]) { + case 1: /* auto-detect */ + case 0x200: + case 0x208: + case 0x210: + case 0x218: + snd_ensoniq_joystick(ensoniq, joystick_port[dev]); + break; + } +#else + if (joystick[dev]) + snd_ensoniq_joystick(ensoniq, 0x200); +#endif +#endif /* SUPPORT_JOYSTICK */ strcpy(card->driver, DRIVER_NAME); strcpy(card->shortname, "Ensoniq AudioPCI"); @@ -2386,7 +2332,7 @@ module_exit(alsa_card_ens137x_exit) #ifndef MODULE -/* format is: snd-ens1370=enable,index,id */ +/* format is: snd-ens1370=enable,index,id,joystick */ static int __init alsa_card_ens137x_setup(char *str) { @@ -2396,7 +2342,15 @@ static int __init alsa_card_ens137x_setu return 0; (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && - get_id(&str,&id[nr_dev]) == 2); + get_id(&str,&id[nr_dev]) == 2 +#ifdef SUPPORT_JOYSTICK +#ifdef CHIP1371 + && get_option(&str,&joystick_port[nr_dev]) == 2 +#else + && get_option(&str,&joystick[nr_dev]) == 2 +#endif +#endif + ); nr_dev++; return 1; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/es1938.c 830-ivtv/sound/pci/es1938.c --- 000-virgin/sound/pci/es1938.c Tue Sep 2 09:56:04 2003 +++ 830-ivtv/sound/pci/es1938.c Thu Jan 8 10:26:50 2004 @@ -1402,7 +1402,7 @@ static int __devinit snd_es1938_create(s snd_printk("architecture does not support 24bit PCI busmaster DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x00ffffff); + pci_set_consistent_dma_mask(pci, 0x00ffffff); chip = snd_magic_kcalloc(es1938_t, 0, GFP_KERNEL); if (chip == NULL) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/es1968.c 830-ivtv/sound/pci/es1968.c --- 000-virgin/sound/pci/es1968.c Mon Nov 17 18:29:01 2003 +++ 830-ivtv/sound/pci/es1968.c Thu Jan 8 10:26:50 2004 @@ -94,7 +94,6 @@ * places. */ -#define __SND_OSS_COMPAT__ #include #include #include @@ -102,6 +101,7 @@ #include #include #include +#include #include #include #include @@ -122,6 +122,10 @@ MODULE_DEVICES("{{ESS,Maestro 2e}," "{ESS,Maestro 1}," "{TerraTec,DMX}}"); +#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#define SUPPORT_JOYSTICK 1 +#endif + static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 1-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ @@ -131,6 +135,9 @@ static int pcm_substreams_c[SNDRV_CARDS] static int clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; static int use_pm[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2}; static int enable_mpu[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2}; +#ifdef SUPPORT_JOYSTICK +static int joystick[SNDRV_CARDS]; +#endif MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); @@ -159,6 +166,11 @@ MODULE_PARM_SYNTAX(use_pm, SNDRV_ENABLED MODULE_PARM(enable_mpu, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(enable_mpu, "Enable MPU401. (0 = off, 1 = on, 2 = auto)"); MODULE_PARM_SYNTAX(enable_mpu, SNDRV_ENABLED "," SNDRV_BOOLEAN_TRUE_DESC); +#ifdef SUPPORT_JOYSTICK +MODULE_PARM(joystick, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(joystick, "Enable joystick."); +MODULE_PARM_SYNTAX(joystick, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); +#endif /* PCI Dev ID's */ @@ -602,6 +614,11 @@ struct snd_es1968 { #ifdef CONFIG_PM u16 apu_map[NR_APUS][NR_APU_REGS]; #endif + +#ifdef SUPPORT_JOYSTICK + struct gameport gameport; + struct resource *res_joystick; +#endif }; static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id, struct pt_regs *regs); @@ -2020,15 +2037,20 @@ static irqreturn_t snd_es1968_interrupt( static int __devinit snd_es1968_mixer(es1968_t *chip) { + ac97_bus_t bus, *pbus; ac97_t ac97; snd_ctl_elem_id_t id; int err; + memset(&bus, 0, sizeof(bus)); + bus.write = snd_es1968_ac97_write; + bus.read = snd_es1968_ac97_read; + if ((err = snd_ac97_bus(chip->card, &bus, &pbus)) < 0) + return err; + memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_es1968_ac97_write; - ac97.read = snd_es1968_ac97_read; ac97.private_data = chip; - if ((err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97)) < 0) + if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97)) < 0) return err; /* attach master switch / volumes for h/w volume control */ @@ -2478,6 +2500,13 @@ static int snd_es1968_free(es1968_t *chi if (chip->res_io_port) snd_es1968_reset(chip); +#ifdef SUPPORT_JOYSTICK + if (chip->res_joystick) { + gameport_unregister_port(&chip->gameport); + release_resource(chip->res_joystick); + kfree_nocheck(chip->res_joystick); + } +#endif snd_es1968_set_acpi(chip, ACPI_D3); chip->master_switch = NULL; chip->master_volume = NULL; @@ -2538,7 +2567,7 @@ static int __devinit snd_es1968_create(s snd_printk("architecture does not support 28bit PCI busmaster DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x0fffffff); + pci_set_consistent_dma_mask(pci, 0x0fffffff); chip = (es1968_t *) snd_magic_kcalloc(es1968_t, 0, GFP_KERNEL); if (! chip) @@ -2624,57 +2653,6 @@ static int __devinit snd_es1968_create(s /* - * joystick - */ - -static int snd_es1968_joystick_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} - -static int snd_es1968_joystick_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - es1968_t *chip = snd_kcontrol_chip(kcontrol); - u16 val; - - pci_read_config_word(chip->pci, ESM_LEGACY_AUDIO_CONTROL, &val); - ucontrol->value.integer.value[0] = (val & 0x04) ? 1 : 0; - return 0; -} - -static int snd_es1968_joystick_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - es1968_t *chip = snd_kcontrol_chip(kcontrol); - u16 val, oval; - - pci_read_config_word(chip->pci, ESM_LEGACY_AUDIO_CONTROL, &oval); - val = oval & ~0x04; - if (ucontrol->value.integer.value[0]) - val |= 0x04; - if (val != oval) { - pci_write_config_word(chip->pci, ESM_LEGACY_AUDIO_CONTROL, val); - return 1; - } - return 0; -} - -#define num_controls(ary) (sizeof(ary) / sizeof(snd_kcontrol_new_t)) - -static snd_kcontrol_new_t snd_es1968_control_switches[] __devinitdata = { - { - .name = "Joystick", - .iface = SNDRV_CTL_ELEM_IFACE_CARD, - .info = snd_es1968_joystick_info, - .get = snd_es1968_joystick_get, - .put = snd_es1968_joystick_put, - } -}; - -/* */ static int __devinit snd_es1968_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) @@ -2756,14 +2734,17 @@ static int __devinit snd_es1968_probe(st } } - /* card switches */ - for (i = 0; i < num_controls(snd_es1968_control_switches); i++) { - err = snd_ctl_add(card, snd_ctl_new1(&snd_es1968_control_switches[i], chip)); - if (err < 0) { - snd_card_free(card); - return err; - } +#ifdef SUPPORT_JOYSTICK +#define JOYSTICK_ADDR 0x200 + if (joystick[dev] && + (chip->res_joystick = request_region(JOYSTICK_ADDR, 8, "ES1968 gameport")) != NULL) { + u16 val; + pci_read_config_word(pci, ESM_LEGACY_AUDIO_CONTROL, &val); + pci_write_config_word(pci, ESM_LEGACY_AUDIO_CONTROL, val | 0x04); + chip->gameport.io = JOYSTICK_ADDR; + gameport_register_port(&chip->gameport); } +#endif snd_es1968_start_irq(chip); @@ -2834,7 +2815,8 @@ module_exit(alsa_card_es1968_exit) pcm_substreams_c, clock, use_pm, - enable_mpu + enable_mpu, + joystick */ static int __init alsa_card_es1968_setup(char *str) @@ -2851,7 +2833,11 @@ static int __init alsa_card_es1968_setup get_option(&str,&pcm_substreams_c[nr_dev]) == 2 && get_option(&str,&clock[nr_dev]) == 2 && get_option(&str,&use_pm[nr_dev]) == 2 && - get_option(&str,&enable_mpu[nr_dev]) == 2); + get_option(&str,&enable_mpu[nr_dev]) == 2 +#ifdef SUPPORT_JOYSTICK + && get_option(&str,&joystick[nr_dev]) == 2 +#endif + ); nr_dev++; return 1; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/fm801.c 830-ivtv/sound/pci/fm801.c --- 000-virgin/sound/pci/fm801.c Wed Aug 13 20:24:37 2003 +++ 830-ivtv/sound/pci/fm801.c Thu Jan 8 10:26:51 2004 @@ -147,6 +147,7 @@ struct _snd_fm801 { unsigned int cap_size; unsigned int cap_pos; + ac97_bus_t *ac97_bus; ac97_t *ac97; ac97_t *ac97_sec; @@ -844,6 +845,12 @@ FM801_SINGLE("IEC958 Raw Data Capture Sw FM801_SINGLE("IEC958 Playback Switch", FM801_GEN_CTRL, 2, 1, 0), }; +static void snd_fm801_mixer_free_ac97_bus(ac97_bus_t *bus) +{ + fm801_t *chip = snd_magic_cast(fm801_t, bus->private_data, return); + chip->ac97_bus = NULL; +} + static void snd_fm801_mixer_free_ac97(ac97_t *ac97) { fm801_t *chip = snd_magic_cast(fm801_t, ac97->private_data, return); @@ -856,21 +863,28 @@ static void snd_fm801_mixer_free_ac97(ac static int __devinit snd_fm801_mixer(fm801_t *chip) { + ac97_bus_t bus; ac97_t ac97; unsigned int i; int err; + memset(&bus, 0, sizeof(bus)); + bus.write = snd_fm801_codec_write; + bus.read = snd_fm801_codec_read; + bus.private_data = chip; + bus.private_free = snd_fm801_mixer_free_ac97_bus; + if ((err = snd_ac97_bus(chip->card, &bus, &chip->ac97_bus)) < 0) + return err; + memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_fm801_codec_write; - ac97.read = snd_fm801_codec_read; ac97.private_data = chip; ac97.private_free = snd_fm801_mixer_free_ac97; - if ((err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97)) < 0) + if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0) return err; if (chip->secondary) { ac97.num = 1; ac97.addr = chip->secondary_addr; - if ((err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97_sec)) < 0) + if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97_sec)) < 0) return err; } for (i = 0; i < FM801_CONTROLS; i++) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/ice1712/Makefile 830-ivtv/sound/pci/ice1712/Makefile --- 000-virgin/sound/pci/ice1712/Makefile Sat Jun 14 18:37:44 2003 +++ 830-ivtv/sound/pci/ice1712/Makefile Thu Jan 8 10:26:51 2004 @@ -5,7 +5,7 @@ snd-ice17xx-ak4xxx-objs := ak4xxx.o snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o -snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o +snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o prodigy.o # Toplevel Module Dependency obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/ice1712/aureon.c 830-ivtv/sound/pci/ice1712/aureon.c --- 000-virgin/sound/pci/ice1712/aureon.c Mon Nov 17 18:29:01 2003 +++ 830-ivtv/sound/pci/ice1712/aureon.c Thu Jan 8 10:26:51 2004 @@ -185,7 +185,7 @@ static int wm_dac_vol_put(snd_kcontrol_t if (nvol <= 0x1a && ovol <= 0x1a) change = 0; else - wm_put(ice, idx, nvol | 0x100); + wm_put(ice, idx, nvol | 0x180); /* update on zero detect */ } snd_ice1712_restore_gpio_status(ice); return change; @@ -366,9 +366,15 @@ static int __devinit aureon_add_controls static int __devinit aureon_init(ice1712_t *ice) { static unsigned short wm_inits[] = { + /* These come first to reduce init pop noise */ + 0x1b, 0x000, /* ADC Mux */ + 0x1c, 0x009, /* Out Mux1 */ + 0x1d, 0x009, /* Out Mux2 */ + + 0x18, 0x000, /* All power-up */ + 0x16, 0x122, /* I2S, normal polarity, 24bit */ 0x17, 0x022, /* 256fs, slave mode */ - 0x18, 0x000, /* All power-up */ 0x00, 0, /* DAC1 analog mute */ 0x01, 0, /* DAC2 analog mute */ 0x02, 0, /* DAC3 analog mute */ @@ -393,9 +399,6 @@ static int __devinit aureon_init(ice1712 0x15, 0x000, /* no deemphasis, no ZFLG */ 0x19, 0x000, /* -12dB ADC/L */ 0x1a, 0x000, /* -12dB ADC/R */ - 0x1b, 0x000, /* ADC Mux */ - 0x1c, 0x009, /* Out Mux1 */ - 0x1d, 0x009, /* Out Mux2 */ }; static unsigned short cs_inits[] = { 0x0441, /* RUN */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/ice1712/ice1712.c 830-ivtv/sound/pci/ice1712/ice1712.c --- 000-virgin/sound/pci/ice1712/ice1712.c Tue Sep 2 09:56:05 2003 +++ 830-ivtv/sound/pci/ice1712/ice1712.c Thu Jan 8 10:26:51 2004 @@ -1040,6 +1040,7 @@ static void snd_ice1712_set_pro_rate(ice default: snd_BUG(); val = 0; + rate = 48000; break; } outb(val, ICEMT(ice, RATE)); @@ -1050,6 +1051,8 @@ static void snd_ice1712_set_pro_rate(ice if (ice->akm[i].ops.set_rate_val) ice->akm[i].ops.set_rate_val(&ice->akm[i], rate); } + if (ice->spdif.ops.setup_rate) + ice->spdif.ops.setup_rate(ice, rate); } static int snd_ice1712_playback_pro_prepare(snd_pcm_substream_t * substream) @@ -1072,8 +1075,6 @@ static int snd_ice1712_playback_pro_hw_p ice1712_t *ice = snd_pcm_substream_chip(substream); snd_ice1712_set_pro_rate(ice, params_rate(hw_params), 0); - if (ice->spdif.ops.setup_rate) - ice->spdif.ops.setup_rate(ice, params_rate(hw_params)); return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); } @@ -1449,13 +1450,17 @@ static int __devinit snd_ice1712_ac97_mi int err; if (ice_has_con_ac97(ice)) { + ac97_bus_t bus, *pbus; ac97_t ac97; + memset(&bus, 0, sizeof(bus)); + bus.write = snd_ice1712_ac97_write; + bus.read = snd_ice1712_ac97_read; + if ((err = snd_ac97_bus(ice->card, &bus, &pbus)) < 0) + return err; memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_ice1712_ac97_write; - ac97.read = snd_ice1712_ac97_read; ac97.private_data = ice; ac97.private_free = snd_ice1712_mixer_free_ac97; - if ((err = snd_ac97_mixer(ice->card, &ac97, &ice->ac97)) < 0) + if ((err = snd_ac97_mixer(pbus, &ac97, &ice->ac97)) < 0) printk(KERN_WARNING "ice1712: cannot initialize ac97 for consumer, skipped\n"); else { if ((err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_digmix_route_ac97, ice))) < 0) @@ -1465,13 +1470,17 @@ static int __devinit snd_ice1712_ac97_mi } if (! (ice->eeprom.data[ICE_EEP1_ACLINK] & ICE1712_CFG_PRO_I2S)) { + ac97_bus_t bus, *pbus; ac97_t ac97; + memset(&bus, 0, sizeof(bus)); + bus.write = snd_ice1712_pro_ac97_write; + bus.read = snd_ice1712_pro_ac97_read; + if ((err = snd_ac97_bus(ice->card, &bus, &pbus)) < 0) + return err; memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_ice1712_pro_ac97_write; - ac97.read = snd_ice1712_pro_ac97_read; ac97.private_data = ice; ac97.private_free = snd_ice1712_mixer_free_ac97; - if ((err = snd_ac97_mixer(ice->card, &ac97, &ice->ac97)) < 0) + if ((err = snd_ac97_mixer(pbus, &ac97, &ice->ac97)) < 0) printk(KERN_WARNING "ice1712: cannot initialize pro ac97, skipped\n"); else return 0; @@ -1532,7 +1541,7 @@ static void __devinit snd_ice1712_proc_i snd_info_entry_t *entry; if (! snd_card_proc_new(ice->card, "ice1712", &entry)) - snd_info_set_text_ops(entry, ice, snd_ice1712_proc_read); + snd_info_set_text_ops(entry, ice, 1024, snd_ice1712_proc_read); } /* @@ -2356,7 +2365,7 @@ static int __devinit snd_ice1712_create( snd_printk("architecture does not support 28bit PCI busmaster DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x0fffffff); + pci_set_consistent_dma_mask(pci, 0x0fffffff); ice = snd_magic_kcalloc(ice1712_t, 0, GFP_KERNEL); if (ice == NULL) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/ice1712/ice1724.c 830-ivtv/sound/pci/ice1712/ice1724.c --- 000-virgin/sound/pci/ice1712/ice1724.c Mon Nov 17 18:29:01 2003 +++ 830-ivtv/sound/pci/ice1712/ice1724.c Thu Jan 8 10:26:51 2004 @@ -43,6 +43,8 @@ #include "amp.h" #include "revo.h" #include "aureon.h" +#include "prodigy.h" + MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("ICEnsemble ICE1724 (Envy24HT)"); @@ -52,6 +54,7 @@ MODULE_DEVICES("{" REVO_DEVICE_DESC AMP_AUDIO2000_DEVICE_DESC AUREON_DEVICE_DESC + PRODIGY_DEVICE_DESC "{VIA,VT1724}," "{ICEnsemble,Generic ICE1724}," "{ICEnsemble,Generic Envy24HT}}"); @@ -908,17 +911,21 @@ static int __devinit snd_vt1724_ac97_mix int err; if (! (ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S)) { + ac97_bus_t bus, *pbus; ac97_t ac97; /* cold reset */ outb(inb(ICEMT1724(ice, AC97_CMD)) | 0x80, ICEMT1724(ice, AC97_CMD)); mdelay(5); /* FIXME */ outb(inb(ICEMT1724(ice, AC97_CMD)) & ~0x80, ICEMT1724(ice, AC97_CMD)); + memset(&bus, 0, sizeof(bus)); + bus.write = snd_vt1724_ac97_write; + bus.read = snd_vt1724_ac97_read; + if ((err = snd_ac97_bus(ice->card, &bus, &pbus)) < 0) + return err; memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_vt1724_ac97_write; - ac97.read = snd_vt1724_ac97_read; ac97.private_data = ice; - if ((err = snd_ac97_mixer(ice->card, &ac97, &ice->ac97)) < 0) + if ((err = snd_ac97_mixer(pbus, &ac97, &ice->ac97)) < 0) printk(KERN_WARNING "ice1712: cannot initialize pro ac97, skipped\n"); else return 0; @@ -975,7 +982,7 @@ static void __devinit snd_vt1724_proc_in snd_info_entry_t *entry; if (! snd_card_proc_new(ice->card, "ice1724", &entry)) - snd_info_set_text_ops(entry, ice, snd_vt1724_proc_read); + snd_info_set_text_ops(entry, ice, 1024, snd_vt1724_proc_read); } /* @@ -1576,6 +1583,7 @@ static struct snd_ice1712_card_info *car snd_vt1724_revo_cards, snd_vt1724_amp_cards, snd_vt1724_aureon_cards, + snd_vt1724_prodigy_cards, 0, }; @@ -1793,7 +1801,7 @@ static int __devinit snd_vt1724_create(s /* enable PCI device */ if ((err = pci_enable_device(pci)) < 0) return err; - pci_set_dma_mask(pci, 0xffffffff); + pci_set_consistent_dma_mask(pci, 0xffffffff); ice = snd_magic_kcalloc(ice1712_t, 0, GFP_KERNEL); if (ice == NULL) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/ice1712/prodigy.c 830-ivtv/sound/pci/ice1712/prodigy.c --- 000-virgin/sound/pci/ice1712/prodigy.c Wed Dec 31 16:00:00 1969 +++ 830-ivtv/sound/pci/ice1712/prodigy.c Thu Jan 8 10:26:51 2004 @@ -0,0 +1,662 @@ +/* + * ALSA driver for ICEnsemble VT1724 (Envy24HT) + * + * Lowlevel functions for AudioTrak Prodigy 7.1 (and possibly 192) cards + * Copyright (c) 2003 Dimitromanolakis Apostolos + * based on the aureon.c code (c) 2003 by Takashi Iwai + * + * version 0.82: Stable / not all features work yet (no communication with AC97 secondary) + * added 64x/128x oversampling switch (should be 64x only for 96khz) + * fixed some recording labels (still need to check the rest) + * recording is working probably thanks to correct wm8770 initialization + * + * version 0.5: Initial release: + * working: analog output, mixer, headphone amplifier switch + * not working: prety much everything else, at least i could verify that + * we have no digital output, no capture, pretty bad clicks and poops + * on mixer switch and other coll stuff. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * NOTES: + * + * + * + * - we reuse the akm4xxx_t record for storing the wm8770 codec data. + * both wm and akm codecs are pretty similar, so we can integrate + * both controls in the future, once if wm codecs are reused in + * many boards. + * + * - writing over SPI is implemented but reading is not yet. + * the SPDIF-in channel status, etc. can be read from CS chip. + * + * - DAC digital volumes are not implemented in the mixer. + * if they show better response than DAC analog volumes, we can use them + * instead. + * + * - Prodigy boards are equipped with AC97 STAC9744 chip , too. it's used to do + * the analog mixing but not easily controllable (it's not connected + * directly from envy24ht chip). so let's leave it as it is. + * + */ + +#define REVISION 0.82b + +#include +#include +#include +#include +#include +#include +#include + +#include "ice1712.h" +#include "envy24ht.h" +#include "prodigy.h" + + +static int prodigy_set_headphone_amp(ice1712_t *ice, int enable) +{ + unsigned int tmp, tmp2; + + tmp2 = tmp = snd_ice1712_gpio_read(ice); + if (enable) + tmp |= PRODIGY_HP_AMP_EN; + else + tmp &= ~ PRODIGY_HP_AMP_EN; + if (tmp != tmp2) { + snd_ice1712_gpio_write(ice, tmp); + return 1; + } + return 0; +} + + +static int prodigy_get_headphone_amp(ice1712_t *ice) +{ + unsigned int tmp = snd_ice1712_gpio_read(ice); + + return ( tmp & PRODIGY_HP_AMP_EN )!= 0; +} + + +/* + * write data in the SPI mode + */ +static void prodigy_spi_write(ice1712_t *ice, unsigned int cs, unsigned int data, int bits) +{ + unsigned int tmp; + int i; + + tmp = snd_ice1712_gpio_read(ice); + + snd_ice1712_gpio_set_mask(ice, ~(PRODIGY_WM_RW|PRODIGY_WM_DATA|PRODIGY_WM_CLK| + PRODIGY_WM_CS|PRODIGY_CS8415_CS|PRODIGY_HP_AMP_EN)); + tmp |= PRODIGY_WM_RW; + tmp &= ~cs; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + + for (i = bits - 1; i >= 0; i--) { + tmp &= ~PRODIGY_WM_CLK; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + if (data & (1 << i)) + tmp |= PRODIGY_WM_DATA; + else + tmp &= ~PRODIGY_WM_DATA; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + tmp |= PRODIGY_WM_CLK; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + } + + tmp &= ~PRODIGY_WM_CLK; + tmp |= cs; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + tmp |= PRODIGY_WM_CLK; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); +} + + +/* + * get the current register value of WM codec + */ +static unsigned short wm_get(ice1712_t *ice, int reg) +{ + reg <<= 1; + return ((unsigned short)ice->akm[0].images[reg] << 8) | + ice->akm[0].images[reg + 1]; +} + +/* + * set the register value of WM codec and remember it + */ +static void wm_put(ice1712_t *ice, int reg, unsigned short val) +{ + prodigy_spi_write(ice, PRODIGY_WM_CS, (reg << 9) | (val & 0x1ff), 16); + reg <<= 1; + ice->akm[0].images[reg] = val >> 8; + ice->akm[0].images[reg + 1] = val; +} + + +/********************************* + ********* Controls section ****** + *********************************/ + +#define PRODIGY_CON_HPAMP \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Headphone Amplifier", \ + .info = prodigy_hpamp_info, \ + .get = prodigy_hpamp_get, \ + .put = prodigy_hpamp_put \ + } + +static int prodigy_hpamp_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo) +{ + static char *texts[2] = { + "Off", "On" + }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + + return 0; +} + + +static int prodigy_hpamp_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = prodigy_get_headphone_amp(ice); + return 0; +} + + +static int prodigy_hpamp_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + + return prodigy_set_headphone_amp(ice,ucontrol->value.integer.value[0]); +} + + + +#define PRODIGY_CON_DEEMP \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "DAC De-emphasis", \ + .info = prodigy_deemp_info, \ + .get = prodigy_deemp_get, \ + .put = prodigy_deemp_put \ + } + +static int prodigy_deemp_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo) +{ + static char *texts[2] = { "Off", "On" }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + + return 0; +} + +static int prodigy_deemp_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + ucontrol->value.integer.value[0] = (wm_get(ice, 0x15) & 0xf) == 0xf; + return 0; +} + +static int prodigy_deemp_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int temp, temp2; + temp2 = temp = wm_get(ice, 0x15); + temp = (temp & ~0xf) | ((ucontrol->value.integer.value[0])*0xf); + if (temp != temp2) { + wm_put(ice,0x15,temp); + return 1; + } + return 0; +} + + +#define PRODIGY_CON_OVERSAMPLING \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "ADC Oversampling", \ + .info = prodigy_oversampling_info, \ + .get = prodigy_oversampling_get, \ + .put = prodigy_oversampling_put \ + } + +static int prodigy_oversampling_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo) +{ + static char *texts[2] = { "128x", "64x" }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + + return 0; +} + +static int prodigy_oversampling_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + ucontrol->value.integer.value[0] = (wm_get(ice, 0x17) & 0x8) == 0x8; + return 0; +} + +static int prodigy_oversampling_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + int temp, temp2; + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + + temp2 = temp = wm_get(ice, 0x17); + + if( ucontrol->value.integer.value[0] ) { + temp |= 0x8; + } else { + temp &= ~0x8; + } + + if (temp != temp2) { + wm_put(ice,0x17,temp); + return 1; + } + return 0; +} + + + + +/* + * DAC volume attenuation mixer control + */ +static int wm_dac_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; /* mute */ + uinfo->value.integer.max = 101; /* 0dB */ + return 0; +} + +static int wm_dac_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int idx; + unsigned short vol; + + down(&ice->gpio_mutex); + if (kcontrol->private_value) + idx = WM_DAC_MASTER_ATTEN; + else + idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_DAC_ATTEN; + vol = wm_get(ice, idx) & 0x7f; + if (vol <= 0x1a) + ucontrol->value.integer.value[0] = 0; + else + ucontrol->value.integer.value[0] = vol - 0x1a; + up(&ice->gpio_mutex); + + return 0; +} + +static int wm_dac_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int idx; + unsigned short ovol, nvol; + int change; + + snd_ice1712_save_gpio_status(ice); + if (kcontrol->private_value) + idx = WM_DAC_MASTER_ATTEN; + else + idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_DAC_ATTEN; + nvol = ucontrol->value.integer.value[0] + 0x1a; + ovol = wm_get(ice, idx) & 0x7f; + change = (ovol != nvol); + if (change) { + if (nvol <= 0x1a && ovol <= 0x1a) + change = 0; + else + wm_put(ice, idx, nvol | 0x180); /* update on zero detect */ + } + snd_ice1712_restore_gpio_status(ice); + return change; +} + +/* + * ADC gain mixer control + */ +static int wm_adc_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; /* -12dB */ + uinfo->value.integer.max = 0x1f; /* 19dB */ + return 0; +} + +static int wm_adc_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int idx; + unsigned short vol; + + down(&ice->gpio_mutex); + idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_ADC_GAIN; + vol = wm_get(ice, idx) & 0x1f; + ucontrol->value.integer.value[0] = vol; + up(&ice->gpio_mutex); + return 0; +} + +static int wm_adc_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int idx; + unsigned short ovol, nvol; + int change; + + snd_ice1712_save_gpio_status(ice); + idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_ADC_GAIN; + nvol = ucontrol->value.integer.value[0]; + ovol = wm_get(ice, idx) & 0x1f; + change = (ovol != nvol); + if (change) + wm_put(ice, idx, nvol); + snd_ice1712_restore_gpio_status(ice); + return change; +} + +/* + * ADC input mux mixer control + */ +static int wm_adc_mux_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + static char *texts[] = { + "CD Left", + "CD Right", + "Line Left", + "Line Right", + "Aux Left", + "Aux Right", + "Mic Left", + "Mic Right", + }; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 2; + uinfo->value.enumerated.items = 8; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int wm_adc_mux_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + unsigned short val; + + down(&ice->gpio_mutex); + val = wm_get(ice, WM_ADC_MUX); + ucontrol->value.integer.value[0] = val & 7; + ucontrol->value.integer.value[1] = (val >> 4) & 7; + up(&ice->gpio_mutex); + return 0; +} + +static int wm_adc_mux_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + unsigned short oval, nval; + int change; + + snd_ice1712_save_gpio_status(ice); + oval = wm_get(ice, WM_ADC_MUX); + nval = oval & ~0x77; + nval |= ucontrol->value.integer.value[0] & 7; + nval |= (ucontrol->value.integer.value[1] & 7) << 4; + change = (oval != nval); + if (change) + wm_put(ice, WM_ADC_MUX, nval); + snd_ice1712_restore_gpio_status(ice); + return 0; +} + +/* + * mixers + */ + +static snd_kcontrol_new_t prodigy71_dac_control __devinitdata = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "DAC Volume", + .count = 8, + .info = wm_dac_vol_info, + .get = wm_dac_vol_get, + .put = wm_dac_vol_put, +}; + +static snd_kcontrol_new_t wm_controls[] __devinitdata = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Volume", + .info = wm_dac_vol_info, + .get = wm_dac_vol_get, + .put = wm_dac_vol_put, + .private_value = 1, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "ADC Volume", + .count = 2, + .info = wm_adc_vol_info, + .get = wm_adc_vol_get, + .put = wm_adc_vol_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Route", + .info = wm_adc_mux_info, + .get = wm_adc_mux_get, + .put = wm_adc_mux_put, + }, + PRODIGY_CON_HPAMP , + PRODIGY_CON_DEEMP , + PRODIGY_CON_OVERSAMPLING +}; + + +static int __devinit prodigy_add_controls(ice1712_t *ice) +{ + unsigned int i; + int err; + + err = snd_ctl_add(ice->card, snd_ctl_new1(&prodigy71_dac_control, ice)); + if (err < 0) + return err; + + for (i = 0; i < ARRAY_SIZE(wm_controls); i++) { + err = snd_ctl_add(ice->card, snd_ctl_new1(&wm_controls[i], ice)); + if (err < 0) + return err; + } + return 0; +} + + +/* + * initialize the chip + */ +static int __devinit prodigy_init(ice1712_t *ice) +{ + static unsigned short wm_inits[] = { + + /* These come first to reduce init pop noise */ + 0x1b, 0x000, /* ADC Mux */ + 0x1c, 0x009, /* Out Mux1 */ + 0x1d, 0x009, /* Out Mux2 */ + + 0x18, 0x000, /* All power-up */ + + 0x16, 0x022, /* I2S, normal polarity, 24bit, high-pass on */ + 0x17, 0x006, /* 128fs, slave mode */ + + 0x00, 0, /* DAC1 analog mute */ + 0x01, 0, /* DAC2 analog mute */ + 0x02, 0, /* DAC3 analog mute */ + 0x03, 0, /* DAC4 analog mute */ + 0x04, 0, /* DAC5 analog mute */ + 0x05, 0, /* DAC6 analog mute */ + 0x06, 0, /* DAC7 analog mute */ + 0x07, 0, /* DAC8 analog mute */ + 0x08, 0x100, /* master analog mute */ + + 0x09, 0x7f, /* DAC1 digital full */ + 0x0a, 0x7f, /* DAC2 digital full */ + 0x0b, 0x7f, /* DAC3 digital full */ + 0x0c, 0x7f, /* DAC4 digital full */ + 0x0d, 0x7f, /* DAC5 digital full */ + 0x0e, 0x7f, /* DAC6 digital full */ + 0x0f, 0x7f, /* DAC7 digital full */ + 0x10, 0x7f, /* DAC8 digital full */ + 0x11, 0x1FF, /* master digital full */ + + 0x12, 0x000, /* phase normal */ + 0x13, 0x090, /* unmute DAC L/R */ + 0x14, 0x000, /* all unmute */ + 0x15, 0x000, /* no deemphasis, no ZFLG */ + + 0x19, 0x000, /* -12dB ADC/L */ + 0x1a, 0x000 /* -12dB ADC/R */ + + }; + + static unsigned short cs_inits[] = { + 0x0441, /* RUN */ + 0x0100, /* no mute */ + 0x0200, /* */ + 0x0600, /* slave, 24bit */ + }; + + unsigned int tmp; + unsigned int i; + + printk(KERN_INFO "ice1724: AudioTrak Prodigy 7.1 driver rev. 0.82b\n"); + printk(KERN_INFO "ice1724: This driver is in beta stage. Forsuccess/failure reporting contact\n"); + printk(KERN_INFO "ice1724: Apostolos Dimitromanolakis \n"); + + ice->num_total_dacs = 8; + + /* to remeber the register values */ + ice->akm = snd_kcalloc(sizeof(akm4xxx_t), GFP_KERNEL); + if (! ice->akm) + return -ENOMEM; + ice->akm_codecs = 1; + + snd_ice1712_gpio_set_dir(ice, 0xbfffff); /* fix this for the time being */ + + /* reset the wm codec as the SPI mode */ + snd_ice1712_save_gpio_status(ice); + snd_ice1712_gpio_set_mask(ice,~( PRODIGY_WM_RESET|PRODIGY_WM_CS| + PRODIGY_CS8415_CS|PRODIGY_HP_AMP_EN )); + + tmp = snd_ice1712_gpio_read(ice); + tmp &= ~PRODIGY_WM_RESET; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + tmp |= PRODIGY_WM_CS | PRODIGY_CS8415_CS; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + tmp |= PRODIGY_WM_RESET; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + + /* initialize WM8770 codec */ + for (i = 0; i < ARRAY_SIZE(wm_inits); i += 2) + wm_put(ice, wm_inits[i], wm_inits[i+1]); + + /* initialize CS8415A codec */ + for (i = 0; i < ARRAY_SIZE(cs_inits); i++) + prodigy_spi_write(ice, PRODIGY_CS8415_CS, + cs_inits[i] | 0x200000, 24); + + + prodigy_set_headphone_amp(ice, 1); + + snd_ice1712_restore_gpio_status(ice); + + return 0; +} + +/* + * Prodigy boards don't provide the EEPROM data except for the vendor IDs. + * hence the driver needs to sets up it properly. + */ + +static unsigned char prodigy71_eeprom[] __devinitdata = { + 0x2b, /* SYSCONF: clock 512, mpu401, spdif-in/ADC, 4DACs */ + 0x80, /* ACLINK: I2S */ + 0xf8, /* I2S: vol, 96k, 24bit, 192k */ + 0xc3, /* SPDIF: out-en, out-int, spdif-in */ + 0xff, /* GPIO_DIR */ + 0xff, /* GPIO_DIR1 */ + 0xbf, /* GPIO_DIR2 */ + 0x00, /* GPIO_MASK */ + 0x00, /* GPIO_MASK1 */ + 0x00, /* GPIO_MASK2 */ + 0x00, /* GPIO_STATE */ + 0x00, /* GPIO_STATE1 */ + 0x00, /* GPIO_STATE2 */ +}; + +/* entry point */ +struct snd_ice1712_card_info snd_vt1724_prodigy_cards[] __devinitdata = { + { + .subvendor = VT1724_SUBDEVICE_PRODIGY71, + .name = "Audiotrak Prodigy 7.1", + .chip_init = prodigy_init, + .build_controls = prodigy_add_controls, + .eeprom_size = sizeof(prodigy71_eeprom), + .eeprom_data = prodigy71_eeprom, + }, + { } /* terminator */ +}; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/ice1712/prodigy.h 830-ivtv/sound/pci/ice1712/prodigy.h --- 000-virgin/sound/pci/ice1712/prodigy.h Wed Dec 31 16:00:00 1969 +++ 830-ivtv/sound/pci/ice1712/prodigy.h Thu Jan 8 10:26:51 2004 @@ -0,0 +1,67 @@ +#ifndef __SOUND_PRODIGY_H +#define __SOUND_PRODIGY_H + +/* + * ALSA driver for VIA VT1724 (Envy24HT) + * + * Lowlevel functions for Terratec PRODIGY cards + * + * Copyright (c) 2003 Takashi Iwai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define PRODIGY_DEVICE_DESC "{AudioTrak,Prodigy 7.1}," + +#define VT1724_SUBDEVICE_PRODIGY71 0x33495345 /* PRODIGY 7.1 */ + +extern struct snd_ice1712_card_info snd_vt1724_prodigy_cards[]; + +/* GPIO bits */ +#define PRODIGY_CS8415_CS (1 << 23) +#define PRODIGY_CS8415_CDTO (1 << 22) +#define PRODIGY_WM_RESET (1 << 20) +#define PRODIGY_WM_CLK (1 << 19) +#define PRODIGY_WM_DATA (1 << 18) +#define PRODIGY_WM_RW (1 << 17) +#define PRODIGY_AC97_RESET (1 << 16) +#define PRODIGY_DIGITAL_SEL1 (1 << 15) +// #define PRODIGY_HP_SEL (1 << 14) +#define PRODIGY_WM_CS (1 << 12) + +#define PRODIGY_HP_AMP_EN (1 << 14) + + +/* WM8770 registers */ +#define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */ +#define WM_DAC_MASTER_ATTEN 0x08 /* DAC master analog attenuation */ +#define WM_DAC_DIG_ATTEN 0x09 /* DAC1-8 digital attenuation */ +#define WM_DAC_DIG_MATER_ATTEN 0x11 /* DAC master digital attenuation */ +#define WM_PHASE_SWAP 0x12 /* DAC phase */ +#define WM_DAC_CTRL1 0x13 /* DAC control bits */ +#define WM_MUTE 0x14 /* mute controls */ +#define WM_DAC_CTRL2 0x15 /* de-emphasis and zefo-flag */ +#define WM_INT_CTRL 0x16 /* interface control */ +#define WM_MASTER 0x17 /* master clock and mode */ +#define WM_POWERDOWN 0x18 /* power-down controls */ +#define WM_ADC_GAIN 0x19 /* ADC gain L(19)/R(1a) */ +#define WM_ADC_MUX 0x1b /* input MUX */ +#define WM_OUT_MUX1 0x1c /* output MUX */ +#define WM_OUT_MUX2 0x1e /* output MUX */ +#define WM_RESET 0x1f /* software reset */ + + +#endif /* __SOUND_PRODIGY_H */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/intel8x0.c 830-ivtv/sound/pci/intel8x0.c --- 000-virgin/sound/pci/intel8x0.c Mon Nov 17 18:29:01 2003 +++ 830-ivtv/sound/pci/intel8x0.c Thu Jan 8 10:26:51 2004 @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -59,7 +60,9 @@ MODULE_DEVICES("{{Intel,82801AA-ICH}," "{AMD,AMD8111}," "{ALI,M5455}}"); +#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) #define SUPPORT_JOYSTICK 1 +#endif #define SUPPORT_MIDI 1 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ @@ -67,12 +70,7 @@ static char *id[SNDRV_CARDS] = SNDRV_DEF static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; #ifdef SUPPORT_JOYSTICK -static int joystick_port[SNDRV_CARDS] = -#ifdef CONFIG_ISA - {0x200}; /* enable as default */ -#else - {0}; /* disabled */ -#endif +static int joystick[SNDRV_CARDS]; #endif #ifdef SUPPORT_MIDI static int mpu_port[SNDRV_CARDS]; /* disabled */ @@ -91,9 +89,9 @@ MODULE_PARM(ac97_clock, "1-" __MODULE_ST MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (0 = auto-detect)."); MODULE_PARM_SYNTAX(ac97_clock, SNDRV_ENABLED ",default:0"); #ifdef SUPPORT_JOYSTICK -MODULE_PARM(joystick_port, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); -MODULE_PARM_DESC(joystick_port, "Joystick port address for Intel i8x0 soundcard. (0 = disabled)"); -MODULE_PARM_SYNTAX(joystick_port, SNDRV_ENABLED ",allows:{{0},{0x200}},dialog:list"); +MODULE_PARM(joystick, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(joystick, "Enable joystick for Intel i8x0 soundcard."); +MODULE_PARM_SYNTAX(joystick, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); #endif #ifdef SUPPORT_MIDI MODULE_PARM(mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); @@ -368,9 +366,8 @@ typedef struct { unsigned int roff_picb; unsigned int int_sta_mask; /* interrupt status mask */ unsigned int ali_slot; /* ALI DMA slot */ - ac97_t *ac97; - unsigned short ac97_rate_regs[3]; - int ac97_rates_idx; + struct ac97_pcm *pcm; + int pcm_open_flag; } ichdev_t; typedef struct _snd_intel8x0 intel8x0_t; @@ -405,6 +402,7 @@ struct _snd_intel8x0 { int in_ac97_init: 1, in_sdin_init: 1; + ac97_bus_t *ac97_bus; ac97_t *ac97[3]; unsigned int ac97_sdin[3]; @@ -888,11 +886,37 @@ static int snd_intel8x0_ali_trigger(snd_ static int snd_intel8x0_hw_params(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params) { - return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); + intel8x0_t *chip = snd_pcm_substream_chip(substream); + ichdev_t *ichdev = get_ichdev(substream); + int err; + + err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); + if (err < 0) + return err; + if (ichdev->pcm_open_flag) { + snd_ac97_pcm_close(ichdev->pcm); + ichdev->pcm_open_flag = 0; + } + err = snd_ac97_pcm_open(ichdev->pcm, params_rate(hw_params), + params_channels(hw_params), + ichdev->pcm->r[0].slots); + if (err >= 0) { + ichdev->pcm_open_flag = 1; + /* FIXME: hack to enable spdif support */ + if (ichdev->ichd == ICHD_PCMOUT && chip->device_type == DEVICE_SIS) + snd_ac97_set_rate(ichdev->pcm->r[0].codec[0], AC97_SPDIF, params_rate(hw_params)); + } + return err; } static int snd_intel8x0_hw_free(snd_pcm_substream_t * substream) { + ichdev_t *ichdev = get_ichdev(substream); + + if (ichdev->pcm_open_flag) { + snd_ac97_pcm_close(ichdev->pcm); + ichdev->pcm_open_flag = 0; + } return snd_pcm_lib_free_pages(substream); } @@ -935,7 +959,6 @@ static int snd_intel8x0_pcm_prepare(snd_ intel8x0_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; ichdev_t *ichdev = get_ichdev(substream); - int i; ichdev->physbuf = runtime->dma_addr; ichdev->size = snd_pcm_lib_buffer_bytes(substream); @@ -945,14 +968,6 @@ static int snd_intel8x0_pcm_prepare(snd_ snd_intel8x0_setup_multi_channels(chip, runtime->channels); spin_unlock(&chip->reg_lock); } - if (ichdev->ac97) { - for (i = 0; i < 3; i++) - if (ichdev->ac97_rate_regs[i]) - snd_ac97_set_rate(ichdev->ac97, ichdev->ac97_rate_regs[i], runtime->rate); - /* FIXME: hack to enable spdif support */ - if (ichdev->ichd == ICHD_PCMOUT && chip->device_type == DEVICE_SIS) - snd_ac97_set_rate(ichdev->ac97, AC97_SPDIF, runtime->rate); - } snd_intel8x0_setup_periods(chip, ichdev); return 0; } @@ -1031,13 +1046,11 @@ static int snd_intel8x0_pcm_open(snd_pcm ichdev->substream = substream; runtime->hw = snd_intel8x0_stream; - if (ichdev->ac97 && ichdev->ac97_rates_idx >= 0) { - runtime->hw.rates = ichdev->ac97->rates[ichdev->ac97_rates_idx]; - for (i = 0; i < ARRAY_SIZE(rates); i++) { - if (runtime->hw.rates & (1 << i)) { - runtime->hw.rate_min = rates[i]; - break; - } + runtime->hw.rates = ichdev->pcm->rates; + for (i = 0; i < ARRAY_SIZE(rates); i++) { + if (runtime->hw.rates & (1 << i)) { + runtime->hw.rate_min = rates[i]; + break; } } if (chip->device_type == DEVICE_SIS) { @@ -1513,7 +1526,7 @@ static int __devinit snd_intel8x0_pcm(in rec = tbl + i; if (i > 0 && rec->ac97_idx) { /* activate PCM only when associated AC'97 codec */ - if (! chip->ichd[rec->ac97_idx].ac97) + if (! chip->ichd[rec->ac97_idx].pcm) continue; } err = snd_intel8x0_pcm1(chip, device, rec); @@ -1531,77 +1544,95 @@ static int __devinit snd_intel8x0_pcm(in * Mixer part */ +static void snd_intel8x0_mixer_free_ac97_bus(ac97_bus_t *bus) +{ + intel8x0_t *chip = snd_magic_cast(intel8x0_t, bus->private_data, return); + chip->ac97_bus = NULL; +} + static void snd_intel8x0_mixer_free_ac97(ac97_t *ac97) { intel8x0_t *chip = snd_magic_cast(intel8x0_t, ac97->private_data, return); chip->ac97[ac97->num] = NULL; } -struct _ac97_rate_regs { - unsigned int ichd; - unsigned short regs[3]; - short rates_idx; -}; - -static struct _ac97_rate_regs intel_ac97_rate_regs[] __devinitdata = { - { ICHD_PCMOUT, { AC97_PCM_FRONT_DAC_RATE, AC97_PCM_SURR_DAC_RATE, AC97_PCM_LFE_DAC_RATE }, AC97_RATES_FRONT_DAC }, - { ICHD_PCMIN, { AC97_PCM_LR_ADC_RATE, 0, 0 }, AC97_RATES_ADC }, - { ICHD_MIC, { AC97_PCM_MIC_ADC_RATE, 0, 0 }, AC97_RATES_MIC_ADC }, - { ICHD_MIC2, { AC97_PCM_MIC_ADC_RATE, 0, 0 }, AC97_RATES_MIC_ADC }, - { ICHD_PCM2IN, { AC97_PCM_LR_ADC_RATE, 0, 0 }, AC97_RATES_ADC }, - { ICHD_SPBAR, { AC97_SPDIF, 0, 0 }, AC97_RATES_SPDIF }, -}; - -static struct _ac97_rate_regs nforce_ac97_rate_regs[] __devinitdata = { - { NVD_PCMOUT, { AC97_PCM_FRONT_DAC_RATE, AC97_PCM_SURR_DAC_RATE, AC97_PCM_LFE_DAC_RATE }, AC97_RATES_FRONT_DAC }, - { NVD_PCMIN, { AC97_PCM_LR_ADC_RATE, 0, 0 }, AC97_RATES_ADC }, - { NVD_MIC, { AC97_PCM_MIC_ADC_RATE, 0, 0 }, AC97_RATES_MIC_ADC }, - { NVD_SPBAR, { AC97_SPDIF, AC97_PCM_FRONT_DAC_RATE, 0 }, -1 }, /* spdif is 48k only */ -}; - -static struct _ac97_rate_regs ali_ac97_rate_regs[] __devinitdata = { -#if 0 /* FIXME: my test board doens't work well with VRA... */ - { ALID_PCMOUT, { AC97_PCM_FRONT_DAC_RATE, AC97_PCM_SURR_DAC_RATE, AC97_PCM_LFE_DAC_RATE }, AC97_RATES_FRONT_DAC }, - { ALID_PCMIN, { AC97_PCM_LR_ADC_RATE, 0, 0 }, AC97_RATES_ADC }, - { ALID_MIC, { AC97_PCM_MIC_ADC_RATE, 0, 0 }, AC97_RATES_MIC_ADC }, - { ALID_AC97SPDIFOUT, { AC97_SPDIF, 0, 0 }, AC97_RATES_SPDIF }, - { ALID_SPDIFOUT, { 0, 0, 0 }, -1 }, - { ALID_SPDIFIN, { 0, 0, 0 }, -1 }, -#else - { ALID_PCMOUT, { AC97_PCM_FRONT_DAC_RATE }, -1 }, - { ALID_PCMIN, { AC97_PCM_LR_ADC_RATE }, -1 }, - { ALID_MIC, { AC97_PCM_MIC_ADC_RATE }, -1 }, - { ALID_AC97SPDIFOUT, { AC97_SPDIF }, -1 }, - { ALID_SPDIFOUT, { }, -1 }, - { ALID_SPDIFIN, { }, -1 }, -#endif +static struct ac97_pcm ac97_pcm_defs[] __devinitdata = { + /* front PCM */ + { + .exclusive = 1, + .r = { { + .slots = (1 << AC97_SLOT_PCM_LEFT) | + (1 << AC97_SLOT_PCM_RIGHT) | + (1 << AC97_SLOT_PCM_CENTER) | + (1 << AC97_SLOT_PCM_SLEFT) | + (1 << AC97_SLOT_PCM_SRIGHT) | + (1 << AC97_SLOT_LFE) + } + } + }, + /* PCM IN #1 */ + { + .stream = 1, + .exclusive = 1, + .r = { { + .slots = (1 << AC97_SLOT_PCM_LEFT) | + (1 << AC97_SLOT_PCM_RIGHT) + } + } + }, + /* MIC IN #1 */ + { + .stream = 1, + .exclusive = 1, + .r = { { + .slots = (1 << AC97_SLOT_MIC) + } + } + }, + /* S/PDIF PCM */ + { + .exclusive = 1, + .spdif = 1, + .r = { { + .slots = (1 << AC97_SLOT_SPDIF_LEFT2) | + (1 << AC97_SLOT_SPDIF_RIGHT2) + } + } + }, + /* PCM IN #2 */ + { + .stream = 1, + .exclusive = 1, + .r = { { + .slots = (1 << AC97_SLOT_PCM_LEFT) | + (1 << AC97_SLOT_PCM_RIGHT) + } + } + }, + /* MIC IN #2 */ + { + .stream = 1, + .exclusive = 1, + .r = { { + .slots = (1 << AC97_SLOT_MIC) + } + } + }, }; static struct ac97_quirk ac97_quirks[] __devinitdata = { { .vendor = 0x1028, .device = 0x00d8, - .name = "Dell Precision 530", + .name = "Dell Precision 530", /* AD1885 */ .type = AC97_TUNE_HP_ONLY }, { .vendor = 0x1028, .device = 0x0126, - .name = "Dell Optiplex GX260", + .name = "Dell Optiplex GX260", /* AD1981A */ .type = AC97_TUNE_HP_ONLY }, - { - .vendor = 0x1028, - .device = 0x0157, - .name = "Dell Dimension 8300", - .type = AC97_TUNE_SWAP_SURROUND - }, - { - .vendor = 0x1043, - .device =0x80b0, - .name = "ASUS P4PE Mobo", - .type = AC97_TUNE_SWAP_SURROUND - }, { .vendor = 0x1043, .device = 0x80f3, @@ -1611,41 +1642,19 @@ static struct ac97_quirk ac97_quirks[] _ { .vendor = 0x10f1, .device = 0x2665, - .name = "Fujitsu-Siemens Celcius", + .name = "Fujitsu-Siemens Celsius", /* AD1981? */ .type = AC97_TUNE_HP_ONLY }, { .vendor = 0x110a, .device = 0x0056, - .name = "Fujitsu-Siemens Scenic", - .type = AC97_TUNE_HP_ONLY - }, - { - .vendor = 0x11d4, - .device = 0x5375, - .name = "ADI AD1985 (discrete)", + .name = "Fujitsu-Siemens Scenic", /* AD1981? */ .type = AC97_TUNE_HP_ONLY }, { .vendor = 0x1734, .device = 0x0088, - .name = "Fujitsu-Siemens D1522", - .type = AC97_TUNE_HP_ONLY - }, -#if 0 - /* FIXME: this seems invalid */ - { - .vendor = 0x4144, - .device = 0x5360, - .type = "AMD64 Motherboard", - .name = AC97_TUNE_HP_ONLY - }, -#endif - { - .vendor = 0x8086, - .device = 0x2000, - .mask = 0xfff0, - .name = "Intel ICH5/AD1985 (discrete)", + .name = "Fujitsu-Siemens D1522", /* AD1981 */ .type = AC97_TUNE_HP_ONLY }, { @@ -1658,7 +1667,7 @@ static struct ac97_quirk ac97_quirks[] _ { .vendor = 0x8086, .device = 0x4d44, - .name = "Intel D850EMV2", + .name = "Intel D850EMV2", /* AD1885 */ .type = AC97_TUNE_HP_ONLY }, { @@ -1675,14 +1684,7 @@ static struct ac97_quirk ac97_quirks[] _ .name = "Intel ICH5/AD1985", .type = AC97_TUNE_AD_SHARING }, - { - .vendor = 0x8086, - .device = 0xa000, - .mask = 0xfff0, - .name = "Intel ICH5/AD1985 (discrete)", - .type = AC97_TUNE_HP_ONLY - }, - { + { /* FIXME: which codec? */ .vendor = 0x103c, .device = 0x00c3, .name = "Hewlett-Packard onboard", @@ -1693,50 +1695,42 @@ static struct ac97_quirk ac97_quirks[] _ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock) { + ac97_bus_t bus, *pbus; ac97_t ac97, *x97; - ichdev_t *ichdev; int err; - unsigned int i, num, codecs, _codecs; + unsigned int i, codecs; unsigned int glob_sta = 0; - struct _ac97_rate_regs *tbl; int spdif_idx = -1; /* disabled */ switch (chip->device_type) { case DEVICE_NFORCE: - tbl = nforce_ac97_rate_regs; spdif_idx = NVD_SPBAR; break; case DEVICE_ALI: - tbl = ali_ac97_rate_regs; spdif_idx = ALID_AC97SPDIFOUT; break; default: - tbl = intel_ac97_rate_regs; if (chip->device_type == DEVICE_INTEL_ICH4) spdif_idx = ICHD_SPBAR; break; }; - for (i = 0; i < chip->bdbars_count; i++) { - struct _ac97_rate_regs *aregs = tbl + i; - ichdev = &chip->ichd[aregs->ichd]; - ichdev->ac97_rate_regs[0] = aregs->regs[0]; - ichdev->ac97_rate_regs[1] = aregs->regs[1]; - ichdev->ac97_rate_regs[2] = aregs->regs[2]; - ichdev->ac97_rates_idx = aregs->rates_idx; - } chip->in_ac97_init = 1; + memset(&bus, 0, sizeof(bus)); + bus.private_data = chip; + bus.private_free = snd_intel8x0_mixer_free_ac97_bus; + if (ac97_clock >= 8000 && ac97_clock <= 48000) + bus.clock = ac97_clock; + else + bus.clock = 48000; + memset(&ac97, 0, sizeof(ac97)); ac97.private_data = chip; ac97.private_free = snd_intel8x0_mixer_free_ac97; - if (ac97_clock >= 8000 && ac97_clock <= 48000) - ac97.clock = ac97_clock; - else - ac97.clock = 48000; if (chip->device_type != DEVICE_ALI) { glob_sta = igetdword(chip, ICHREG(GLOB_STA)); - ac97.write = snd_intel8x0_codec_write; - ac97.read = snd_intel8x0_codec_read; + bus.write = snd_intel8x0_codec_write; + bus.read = snd_intel8x0_codec_read; if (chip->device_type == DEVICE_INTEL_ICH4) { codecs = 0; if (glob_sta & ICH_PCR) @@ -1756,9 +1750,10 @@ static int __devinit snd_intel8x0_mixer( } else { codecs = glob_sta & ICH_SCR ? 2 : 1; } + bus.vra = 1; } else { - ac97.write = snd_intel8x0_ali_codec_write; - ac97.read = snd_intel8x0_ali_codec_read; + bus.write = snd_intel8x0_ali_codec_write; + bus.read = snd_intel8x0_ali_codec_read; codecs = 1; /* detect the secondary codec */ for (i = 0; i < 100; i++) { @@ -1770,144 +1765,82 @@ static int __devinit snd_intel8x0_mixer( iputdword(chip, ICHREG(ALI_RTSR), reg | 0x40); udelay(1); } + /* FIXME: my test board doens't work well with VRA... */ + bus.vra = 0; } + if ((err = snd_ac97_bus(chip->card, &bus, &pbus)) < 0) + goto __err; + chip->ac97_bus = pbus; ac97.pci = chip->pci; - if ((err = snd_ac97_mixer(chip->card, &ac97, &x97)) < 0) { - /* clear the cold-reset bit for the next chance */ - if (chip->device_type != DEVICE_ALI) - iputdword(chip, ICHREG(GLOB_CNT), igetdword(chip, ICHREG(GLOB_CNT)) & ~ICH_AC97COLD); - return err; + for (i = 0; i < codecs; i++) { + ac97.num = i; + if ((err = snd_ac97_mixer(pbus, &ac97, &x97)) < 0) { + snd_printk(KERN_ERR "Unable to initialize codec #%d\n", i); + if (i == 0) + goto __err; + continue; + } + chip->ac97[i] = x97; } - chip->ac97[0] = x97; /* tune up the primary codec */ snd_ac97_tune_hardware(chip->ac97[0], ac97_quirks); - /* the following three entries are common among all devices */ - chip->ichd[ICHD_PCMOUT].ac97 = x97; - chip->ichd[ICHD_PCMIN].ac97 = x97; - if (x97->ext_id & AC97_EI_VRM) - chip->ichd[ICHD_MIC].ac97 = x97; - /* spdif */ - if ((x97->ext_id & AC97_EI_SPDIF) && spdif_idx >= 0) - chip->ichd[spdif_idx].ac97 = x97; - /* make sure, that we have DACs at right slot for rev2.2 */ - if (ac97_is_rev22(x97)) - snd_ac97_update_bits(x97, AC97_EXTENDED_ID, AC97_EI_DACS_SLOT_MASK, 0); - /* AnalogDevices CNR boards uses special codec chaining */ - /* skip standard test method for secondary codecs in this case */ - if (x97->flags & AC97_AD_MULTI) - codecs = 1; - if (codecs < 2) - goto __skip_secondary; - for (i = 1, num = 1, _codecs = codecs; num < _codecs; num++) { - ac97.num = num; - if ((err = snd_ac97_mixer(chip->card, &ac97, &x97)) < 0) { - snd_printk("Unable to initialize codec #%i [device = %i, GLOB_STA = 0x%x]\n", i, chip->device_type, glob_sta); - codecs--; - continue; - } - chip->ac97[i++] = x97; - if (!ac97_is_audio(x97)) - continue; - switch (chip->device_type) { - case DEVICE_INTEL_ICH4: - if (chip->ichd[ICHD_PCM2IN].ac97 == NULL) - chip->ichd[ICHD_PCM2IN].ac97 = x97; - if (x97->ext_id & AC97_EI_VRM) { - if (chip->ichd[ICHD_MIC].ac97 == NULL) - chip->ichd[ICHD_MIC].ac97 = x97; - else if (chip->ichd[ICHD_MIC2].ac97 == NULL && - chip->ichd[ICHD_PCM2IN].ac97 == x97) - chip->ichd[ICHD_MIC2].ac97 = x97; - } - break; - default: - if (x97->ext_id & AC97_EI_VRM) { - if (chip->ichd[ICHD_MIC].ac97 == NULL) - chip->ichd[ICHD_MIC].ac97 = x97; - } - break; - } - if ((x97->ext_id & AC97_EI_SPDIF) && spdif_idx >= 0) { - if (chip->ichd[spdif_idx].ac97 == NULL) - chip->ichd[spdif_idx].ac97 = x97; - } + /* enable separate SDINs for ICH4 */ + if (chip->device_type == DEVICE_INTEL_ICH4) + pbus->isdin = 1; + /* find the available PCM streams */ + i = ARRAY_SIZE(ac97_pcm_defs); + if (chip->device_type != DEVICE_INTEL_ICH4) + i -= 2; /* do not allocate PCM2IN and MIC2 */ + if (spdif_idx < 0) + i--; /* do not allocate S/PDIF */ + err = snd_ac97_pcm_assign(pbus, i, ac97_pcm_defs); + if (err < 0) + goto __err; + chip->ichd[ICHD_PCMOUT].pcm = &pbus->pcms[0]; + chip->ichd[ICHD_PCMIN].pcm = &pbus->pcms[1]; + chip->ichd[ICHD_MIC].pcm = &pbus->pcms[2]; + if (spdif_idx >= 0) + chip->ichd[spdif_idx].pcm = &pbus->pcms[3]; + if (chip->device_type == DEVICE_INTEL_ICH4) { + chip->ichd[ICHD_PCM2IN].pcm = &pbus->pcms[4]; + chip->ichd[ICHD_MIC2].pcm = &pbus->pcms[5]; } - - __skip_secondary: + /* enable separate SDINs for ICH4 */ if (chip->device_type == DEVICE_INTEL_ICH4) { + struct ac97_pcm *pcm = chip->ichd[ICHD_PCM2IN].pcm; u8 tmp = igetbyte(chip, ICHREG(SDM)); tmp &= ~(ICH_DI2L_MASK|ICH_DI1L_MASK); - if (chip->ichd[ICHD_PCM2IN].ac97) { + if (pcm) { tmp |= ICH_SE; /* steer enable for multiple SDINs */ tmp |= chip->ac97_sdin[0] << ICH_DI1L_SHIFT; - tmp |= chip->ac97_sdin[chip->ichd[ICHD_PCM2IN].ac97->num] << ICH_DI2L_SHIFT; + for (i = 1; i < 4; i++) { + if (pcm->r[0].codec[i]) { + tmp |= chip->ac97_sdin[pcm->r[0].codec[1]->num] << ICH_DI2L_SHIFT; + break; + } + } } else { - tmp &= ~ICH_SE; + tmp &= ~ICH_SE; /* steer disable */ } iputbyte(chip, ICHREG(SDM), tmp); } - for (i = 0; i < codecs; i++) { - x97 = chip->ac97[i]; - if (!ac97_is_audio(x97)) - continue; - if (x97->scaps & AC97_SCAP_SURROUND_DAC) - chip->multi4 = 1; - } - for (i = 0; i < codecs && chip->multi4; i++) { - x97 = chip->ac97[i]; - if (!ac97_is_audio(x97)) - continue; - if (x97->scaps & AC97_SCAP_CENTER_LFE_DAC) + if (pbus->pcms[0].r[0].slots & (1 << AC97_SLOT_PCM_SLEFT)) { + chip->multi4 = 1; + if (pbus->pcms[0].r[0].slots & (1 << AC97_SLOT_LFE)) chip->multi6 = 1; } - if (chip->device_type == DEVICE_ALI && chip->ac97[1]) { - /* set secondary codec id */ - iputdword(chip, ICHREG(ALI_SSR), - (igetdword(chip, ICHREG(ALI_SSR)) & ~ICH_ALI_SS_SEC_ID) | - (chip->ac97[1]->addr << 5)); - } - if (codecs > 1 && !chip->multi6) { - /* assign right slots for rev2.2 codecs */ - i = 1; - for ( ; i < codecs && !chip->multi4; i++) { - x97 = chip->ac97[i]; - if (!ac97_is_audio(x97)) - continue; - if (ac97_is_rev22(x97)) { - snd_ac97_update_bits(x97, AC97_EXTENDED_ID, AC97_EI_DACS_SLOT_MASK, 1); - chip->multi4 = 1; - } - } - for ( ; i < codecs && chip->multi4; i++) { - x97 = chip->ac97[i]; - if (!ac97_is_audio(x97)) - continue; - if (ac97_is_rev22(x97)) { - snd_ac97_update_bits(x97, AC97_EXTENDED_ID, AC97_EI_DACS_SLOT_MASK, 2); - chip->multi6 = 1; - break; - } - } - /* ok, some older codecs might support only AMAP */ - if (!chip->multi4) { - int cnums = 0; - for (i = 1; i < codecs; i++) { - x97 = chip->ac97[i]; - if (!ac97_is_audio(x97)) - continue; - if (ac97_can_amap(x97)) { - if (x97->addr > 0) - cnums++; - } - } - if (cnums >= 2) - chip->multi6 = 1; - if (cnums >= 1) - chip->multi4 = 1; - } + if (chip->device_type == DEVICE_NFORCE) { + /* 48kHz only */ + chip->ichd[spdif_idx].pcm->rates = SNDRV_PCM_RATE_48000; } chip->in_ac97_init = 0; return 0; + + __err: + /* clear the cold-reset bit for the next chance */ + if (chip->device_type != DEVICE_ALI) + iputdword(chip, ICHREG(GLOB_CNT), igetdword(chip, ICHREG(GLOB_CNT)) & ~ICH_AC97COLD); + return err; } @@ -2212,7 +2145,7 @@ static void __devinit intel8x0_measure_a unsigned long flags; struct timeval start_time, stop_time; - if (chip->ac97[0]->clock != 48000) + if (chip->ac97_bus->clock != 48000) return; /* specified in module option */ subs = chip->pcm[0]->streams[0].substream; @@ -2227,7 +2160,7 @@ static void __devinit intel8x0_measure_a /* set rate */ if (snd_ac97_set_rate(chip->ac97[0], AC97_PCM_FRONT_DAC_RATE, 48000) < 0) { - snd_printk(KERN_ERR "cannot set ac97 rate: clock = %d\n", chip->ac97[0]->clock); + snd_printk(KERN_ERR "cannot set ac97 rate: clock = %d\n", chip->ac97_bus->clock); return; } snd_intel8x0_setup_periods(chip, ichdev); @@ -2286,8 +2219,8 @@ static void __devinit intel8x0_measure_a printk(KERN_INFO "intel8x0: measured clock %ld rejected\n", pos); else if (pos < 47500 || pos > 48500) /* not 48000Hz, tuning the clock.. */ - chip->ac97[0]->clock = (chip->ac97[0]->clock * 48000) / pos; - printk(KERN_INFO "intel8x0: clocking to %d\n", chip->ac97[0]->clock); + chip->ac97_bus->clock = (chip->ac97_bus->clock * 48000) / pos; + printk(KERN_INFO "intel8x0: clocking to %d\n", chip->ac97_bus->clock); } static void snd_intel8x0_proc_read(snd_info_entry_t * entry, @@ -2321,7 +2254,7 @@ static void __devinit snd_intel8x0_proc_ snd_info_entry_t *entry; if (! snd_card_proc_new(chip->card, "intel8x0", &entry)) - snd_info_set_text_ops(entry, chip, snd_intel8x0_proc_read); + snd_info_set_text_ops(entry, chip, 1024, snd_intel8x0_proc_read); } static int snd_intel8x0_dev_free(snd_device_t *device) @@ -2656,9 +2589,16 @@ static struct pci_driver driver = { * initialize joystick/midi addresses */ +#ifdef SUPPORT_JOYSTICK +/* there is only one available device, so we keep it here */ +static struct pci_dev *ich_gameport_pci; +static struct gameport ich_gameport = { .io = 0x200 }; +#endif + static int __devinit snd_intel8x0_joystick_probe(struct pci_dev *pci, const struct pci_device_id *id) { + u16 val; static int dev; if (dev >= SNDRV_CARDS) return -ENODEV; @@ -2667,17 +2607,24 @@ static int __devinit snd_intel8x0_joysti return -ENOENT; } - if (joystick_port[dev] > 0 || mpu_port[dev] > 0) { - u16 val; - pci_read_config_word(pci, 0xe6, &val); - if (joystick_port[dev] > 0) + pci_read_config_word(pci, 0xe6, &val); +#ifdef SUPPORT_JOYSTICK + if (joystick[dev]) { + if (! request_region(ich_gameport.io, 8, "ICH gameport")) { + printk(KERN_WARNING "intel8x0: cannot grab gameport 0x%x\n", ich_gameport.io); + joystick[dev] = 0; + } else { + ich_gameport_pci = pci; + gameport_register_port(&ich_gameport); val |= 0x100; - if (mpu_port[dev] == 0x300 || mpu_port[dev] == 0x330) - val |= 0x20; - pci_write_config_word(pci, 0xe6, val | 0x100); - + } + } +#endif +#ifdef SUPPORT_MIDI + if (mpu_port[dev] > 0) { if (mpu_port[dev] == 0x300 || mpu_port[dev] == 0x330) { u8 b; + val |= 0x20; pci_read_config_byte(pci, 0xe2, &b); if (mpu_port[dev] == 0x300) b |= 0x08; @@ -2686,9 +2633,27 @@ static int __devinit snd_intel8x0_joysti pci_write_config_byte(pci, 0xe2, b); } } +#endif + pci_write_config_word(pci, 0xe6, val); return 0; } +static void __devexit snd_intel8x0_joystick_remove(struct pci_dev *pci) +{ + u16 val; +#ifdef SUPPORT_JOYSTICK + if (ich_gameport_pci == pci) { + gameport_unregister_port(&ich_gameport); + release_region(ich_gameport.io, 8); + ich_gameport_pci = NULL; + } +#endif + /* disable joystick and MIDI */ + pci_read_config_word(pci, 0xe6, &val); + val &= ~0x120; + pci_write_config_word(pci, 0xe6, val); +} + static struct pci_device_id snd_intel8x0_joystick_ids[] = { { 0x8086, 0x2410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* 82801AA */ { 0x8086, 0x2420, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* 82901AB */ @@ -2707,6 +2672,7 @@ static struct pci_driver joystick_driver .name = "Intel ICH Joystick", .id_table = snd_intel8x0_joystick_ids, .probe = snd_intel8x0_joystick_probe, + .remove = __devexit_p(snd_intel8x0_joystick_remove), }; static int have_joystick; @@ -2749,7 +2715,7 @@ module_exit(alsa_card_intel8x0_exit) #ifndef MODULE -/* format is: snd-intel8x0=enable,index,id,ac97_clock */ +/* format is: snd-intel8x0=enable,index,id,ac97_clock,mpu_port,joystick */ static int __init alsa_card_intel8x0_setup(char *str) { @@ -2760,7 +2726,14 @@ static int __init alsa_card_intel8x0_set (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,&ac97_clock[nr_dev]) == 2); + get_option(&str,&ac97_clock[nr_dev]) == 2 +#ifdef SUPPORT_MIDI + && get_option(&str,&mpu_port[nr_dev]) == 2 +#endif +#ifdef SUPPORT_JOYSTICK + && get_option(&str,&joystick[nr_dev]) == 2 +#endif + ); nr_dev++; return 1; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/korg1212/korg1212.c 830-ivtv/sound/pci/korg1212/korg1212.c --- 000-virgin/sound/pci/korg1212/korg1212.c Wed Aug 13 20:24:37 2003 +++ 830-ivtv/sound/pci/korg1212/korg1212.c Thu Jan 8 10:26:51 2004 @@ -2093,7 +2093,7 @@ static void __devinit snd_korg1212_proc_ snd_info_entry_t *entry; if (! snd_card_proc_new(korg1212->card, "korg1212", &entry)) - snd_info_set_text_ops(entry, korg1212, snd_korg1212_proc_read); + snd_info_set_text_ops(entry, korg1212, 1024, snd_korg1212_proc_read); } static int diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/maestro3.c 830-ivtv/sound/pci/maestro3.c --- 000-virgin/sound/pci/maestro3.c Wed Aug 13 20:24:37 2003 +++ 830-ivtv/sound/pci/maestro3.c Thu Jan 8 10:26:51 2004 @@ -1981,14 +1981,19 @@ static void snd_m3_ac97_reset(m3_t *chip static int __devinit snd_m3_mixer(m3_t *chip) { + ac97_bus_t bus, *pbus; ac97_t ac97; int err; + memset(&bus, 0, sizeof(bus)); + bus.write = snd_m3_ac97_write; + bus.read = snd_m3_ac97_read; + if ((err = snd_ac97_bus(chip->card, &bus, &pbus)) < 0) + return err; + memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_m3_ac97_write; - ac97.read = snd_m3_ac97_read; ac97.private_data = chip; - if ((err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97)) < 0) + if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97)) < 0) return err; /* seems ac97 PCM needs initialization.. hack hack.. */ @@ -2349,7 +2354,8 @@ snd_m3_enable_ints(m3_t *chip) { unsigned long io = chip->iobase; - outw(ASSP_INT_ENABLE | MPU401_INT_ENABLE, io + HOST_INT_CTRL); + /* TODO: MPU401 not supported yet */ + outw(ASSP_INT_ENABLE /*| MPU401_INT_ENABLE*/, io + HOST_INT_CTRL); outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE, io + ASSP_CONTROL_C); } @@ -2545,7 +2551,7 @@ snd_m3_create(snd_card_t *card, struct p snd_printk("architecture does not support 28bit PCI busmaster DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x0fffffff); + pci_set_consistent_dma_mask(pci, 0x0fffffff); chip = snd_magic_kcalloc(m3_t, 0, GFP_KERNEL); if (chip == NULL) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/nm256/nm256.c 830-ivtv/sound/pci/nm256/nm256.c --- 000-virgin/sound/pci/nm256/nm256.c Wed Aug 13 20:24:37 2003 +++ 830-ivtv/sound/pci/nm256/nm256.c Thu Jan 8 10:26:51 2004 @@ -335,7 +335,7 @@ snd_nm256_write_buffer(nm256_t *chip, vo return; } #endif - memcpy_toio(chip->buffer + offset, src, size); + memcpy_toio((void *)chip->buffer + offset, src, size); } /* @@ -1195,6 +1195,7 @@ snd_nm256_ac97_reset(ac97_t *ac97) static int __devinit snd_nm256_mixer(nm256_t *chip) { + ac97_bus_t bus, *pbus; ac97_t ac97; int i, err; /* looks like nm256 hangs up when unexpected registers are touched... */ @@ -1208,16 +1209,20 @@ snd_nm256_mixer(nm256_t *chip) -1 }; + memset(&bus, 0, sizeof(bus)); + bus.reset = snd_nm256_ac97_reset; + bus.write = snd_nm256_ac97_write; + bus.read = snd_nm256_ac97_read; + if ((err = snd_ac97_bus(chip->card, &bus, &pbus)) < 0) + return err; + memset(&ac97, 0, sizeof(ac97)); - ac97.reset = snd_nm256_ac97_reset; - ac97.write = snd_nm256_ac97_write; - ac97.read = snd_nm256_ac97_read; ac97.scaps = AC97_SCAP_AUDIO; /* we support audio! */ ac97.limited_regs = 1; for (i = 0; mixer_regs[i] >= 0; i++) set_bit(mixer_regs[i], ac97.reg_accessed); ac97.private_data = chip; - err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97); + err = snd_ac97_mixer(pbus, &ac97, &chip->ac97); if (err < 0) return err; if (! (chip->ac97->id & (0xf0000000))) { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/rme32.c 830-ivtv/sound/pci/rme32.c --- 000-virgin/sound/pci/rme32.c Tue Sep 2 09:56:05 2003 +++ 830-ivtv/sound/pci/rme32.c Thu Jan 8 10:26:51 2004 @@ -1191,18 +1191,18 @@ snd_rme32_playback_pointer(snd_pcm_subst } bytes = diff << rme32->playback_frlog; if (bytes > RME32_BUFFER_SIZE - rme32->playback_ptr) { - memcpy_toio(rme32->iobase + RME32_IO_DATA_BUFFER + rme32->playback_ptr, + memcpy_toio((void *)(rme32->iobase + RME32_IO_DATA_BUFFER + rme32->playback_ptr), runtime->dma_area + rme32->playback_ptr, RME32_BUFFER_SIZE - rme32->playback_ptr); bytes -= RME32_BUFFER_SIZE - rme32->playback_ptr; if (bytes > RME32_BUFFER_SIZE) { bytes = RME32_BUFFER_SIZE; } - memcpy_toio(rme32->iobase + RME32_IO_DATA_BUFFER, + memcpy_toio((void *)(rme32->iobase + RME32_IO_DATA_BUFFER), runtime->dma_area, bytes); rme32->playback_ptr = bytes; } else if (bytes != 0) { - memcpy_toio(rme32->iobase + RME32_IO_DATA_BUFFER + rme32->playback_ptr, + memcpy_toio((void *)(rme32->iobase + RME32_IO_DATA_BUFFER + rme32->playback_ptr), runtime->dma_area + rme32->playback_ptr, bytes); rme32->playback_ptr += bytes; } @@ -1223,17 +1223,17 @@ snd_rme32_capture_pointer(snd_pcm_substr ptr = frameptr << rme32->capture_frlog; if (ptr > rme32->capture_ptr) { memcpy_fromio(runtime->dma_area + rme32->capture_ptr, - rme32->iobase + RME32_IO_DATA_BUFFER + - rme32->capture_ptr, + (void *)(rme32->iobase + RME32_IO_DATA_BUFFER + + rme32->capture_ptr), ptr - rme32->capture_ptr); rme32->capture_ptr += ptr - rme32->capture_ptr; } else if (ptr < rme32->capture_ptr) { memcpy_fromio(runtime->dma_area + rme32->capture_ptr, - rme32->iobase + RME32_IO_DATA_BUFFER + - rme32->capture_ptr, + (void *)(rme32->iobase + RME32_IO_DATA_BUFFER + + rme32->capture_ptr), RME32_BUFFER_SIZE - rme32->capture_ptr); memcpy_fromio(runtime->dma_area, - rme32->iobase + RME32_IO_DATA_BUFFER, + (void *)(rme32->iobase + RME32_IO_DATA_BUFFER), ptr); rme32->capture_ptr = ptr; } @@ -1545,7 +1545,7 @@ static void __devinit snd_rme32_proc_ini snd_info_entry_t *entry; if (! snd_card_proc_new(rme32->card, "rme32", &entry)) - snd_info_set_text_ops(entry, rme32, snd_rme32_proc_read); + snd_info_set_text_ops(entry, rme32, 1024, snd_rme32_proc_read); } /* diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/rme96.c 830-ivtv/sound/pci/rme96.c --- 000-virgin/sound/pci/rme96.c Wed Aug 13 20:24:37 2003 +++ 830-ivtv/sound/pci/rme96.c Thu Jan 8 10:26:51 2004 @@ -1524,21 +1524,21 @@ snd_rme96_playback_pointer(snd_pcm_subst bytes = diff << rme96->playback_frlog; if (bytes > RME96_BUFFER_SIZE - rme96->playback_ptr) { - memcpy_toio(rme96->iobase + RME96_IO_PLAY_BUFFER + - rme96->playback_ptr, + memcpy_toio((void *)(rme96->iobase + RME96_IO_PLAY_BUFFER + + rme96->playback_ptr), runtime->dma_area + rme96->playback_ptr, RME96_BUFFER_SIZE - rme96->playback_ptr); bytes -= RME96_BUFFER_SIZE - rme96->playback_ptr; if (bytes > RME96_BUFFER_SIZE) { bytes = RME96_BUFFER_SIZE; } - memcpy_toio(rme96->iobase + RME96_IO_PLAY_BUFFER, + memcpy_toio((void *)(rme96->iobase + RME96_IO_PLAY_BUFFER), runtime->dma_area, bytes); rme96->playback_ptr = bytes; } else if (bytes != 0) { - memcpy_toio(rme96->iobase + RME96_IO_PLAY_BUFFER + - rme96->playback_ptr, + memcpy_toio((void *)(rme96->iobase + RME96_IO_PLAY_BUFFER + + rme96->playback_ptr), runtime->dma_area + rme96->playback_ptr, bytes); rme96->playback_ptr += bytes; @@ -1560,17 +1560,17 @@ snd_rme96_capture_pointer(snd_pcm_substr ptr = frameptr << rme96->capture_frlog; if (ptr > rme96->capture_ptr) { memcpy_fromio(runtime->dma_area + rme96->capture_ptr, - rme96->iobase + RME96_IO_REC_BUFFER + - rme96->capture_ptr, + (void *)(rme96->iobase + RME96_IO_REC_BUFFER + + rme96->capture_ptr), ptr - rme96->capture_ptr); rme96->capture_ptr += ptr - rme96->capture_ptr; } else if (ptr < rme96->capture_ptr) { memcpy_fromio(runtime->dma_area + rme96->capture_ptr, - rme96->iobase + RME96_IO_REC_BUFFER + - rme96->capture_ptr, + (void *)(rme96->iobase + RME96_IO_REC_BUFFER + + rme96->capture_ptr), RME96_BUFFER_SIZE - rme96->capture_ptr); memcpy_fromio(runtime->dma_area, - rme96->iobase + RME96_IO_REC_BUFFER, + (void *)(rme96->iobase + RME96_IO_REC_BUFFER), ptr); rme96->capture_ptr = ptr; } @@ -1930,7 +1930,7 @@ snd_rme96_proc_init(rme96_t *rme96) snd_info_entry_t *entry; if (! snd_card_proc_new(rme96->card, "rme96", &entry)) - snd_info_set_text_ops(entry, rme96, snd_rme96_proc_read); + snd_info_set_text_ops(entry, rme96, 1024, snd_rme96_proc_read); } /* diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/rme9652/hdsp.c 830-ivtv/sound/pci/rme9652/hdsp.c --- 000-virgin/sound/pci/rme9652/hdsp.c Mon Nov 17 18:29:01 2003 +++ 830-ivtv/sound/pci/rme9652/hdsp.c Thu Jan 8 10:26:51 2004 @@ -69,15 +69,24 @@ MODULE_DESCRIPTION("RME Hammerfall DSP") MODULE_LICENSE("GPL"); MODULE_CLASSES("{sound}"); MODULE_DEVICES("{{RME Hammerfall-DSP}," - "{RME HDSP-9652}}"); + "{RME HDSP-9652}," + "{RME HDSP-9632}}"); #define HDSP_MAX_CHANNELS 26 +#define HDSP_MAX_DS_CHANNELS 14 +#define HDSP_MAX_QS_CHANNELS 8 #define DIGIFACE_SS_CHANNELS 26 #define DIGIFACE_DS_CHANNELS 14 #define MULTIFACE_SS_CHANNELS 18 #define MULTIFACE_DS_CHANNELS 14 #define H9652_SS_CHANNELS 26 #define H9652_DS_CHANNELS 14 +/* This does not include possible Analog Extension Boards + AEBs are detected at card initialization +*/ +#define H9632_SS_CHANNELS 12 +#define H9632_DS_CHANNELS 8 +#define H9632_QS_CHANNELS 4 /* Write registers. These are defined as byte-offsets from the iobase value. */ @@ -121,7 +130,21 @@ MODULE_DEVICES("{{RME Hammerfall-DSP}," #define HDSP_playbackRmsLevel 4612 /* 26 * 64 bit values */ #define HDSP_inputRmsLevel 4868 /* 26 * 64 bit values */ -#define HDSP_IO_EXTENT 5192 + +/* This is for H9652 cards + Peak values are read downward from the base + Rms values are read upward + There are rms values for the outputs too + 26*3 values are read in ss mode + 14*3 in ds mode, with no gap between values +*/ +#define HDSP_9652_peakBase 7164 +#define HDSP_9652_rmsBase 4096 + +/* c.f. the hdsp_9632_meters_t struct */ +#define HDSP_9632_metersBase 4096 + +#define HDSP_IO_EXTENT 7168 /* control2 register bits */ @@ -137,6 +160,7 @@ MODULE_DEVICES("{{RME Hammerfall-DSP}," #define HDSP_BIGENDIAN_MODE 0x200 #define HDSP_RD_MULTIPLE 0x400 #define HDSP_9652_ENABLE_MIXER 0x800 +#define HDSP_TDO 0x10000000 #define HDSP_S_PROGRAM (HDSP_PROGRAM|HDSP_CONFIG_MODE_0) #define HDSP_S_LOAD (HDSP_PROGRAM|HDSP_CONFIG_MODE_1) @@ -146,11 +170,11 @@ MODULE_DEVICES("{{RME Hammerfall-DSP}," #define HDSP_Start (1<<0) /* start engine */ #define HDSP_Latency0 (1<<1) /* buffer size = 2^n where n is defined by Latency{2,1,0} */ #define HDSP_Latency1 (1<<2) /* [ see above ] */ -#define HDSP_Latency2 (1<<3) /* ] see above ] */ +#define HDSP_Latency2 (1<<3) /* [ see above ] */ #define HDSP_ClockModeMaster (1<<4) /* 1=Master, 0=Slave/Autosync */ #define HDSP_AudioInterruptEnable (1<<5) /* what do you think ? */ -#define HDSP_Frequency0 (1<<6) /* 0=44.1kHz/88.2kHz 1=48kHz/96kHz */ -#define HDSP_Frequency1 (1<<7) /* 0=32kHz/64kHz */ +#define HDSP_Frequency0 (1<<6) /* 0=44.1kHz/88.2kHz/176.4kHz 1=48kHz/96kHz/192kHz */ +#define HDSP_Frequency1 (1<<7) /* 0=32kHz/64kHz/128kHz */ #define HDSP_DoubleSpeed (1<<8) /* 0=normal speed, 1=double speed */ #define HDSP_SPDIFProfessional (1<<9) /* 0=consumer, 1=professional */ #define HDSP_SPDIFEmphasis (1<<10) /* 0=none, 1=on */ @@ -160,21 +184,46 @@ MODULE_DEVICES("{{RME Hammerfall-DSP}," #define HDSP_SPDIFInputSelect0 (1<<14) #define HDSP_SPDIFInputSelect1 (1<<15) #define HDSP_SyncRef0 (1<<16) -#define HDSP_SyncRef1 (1<<17) +#define HDSP_SyncRef1 (1<<17) +#define HDSP_AnalogExtensionBoard (1<<18) /* For H9632 cards */ +#define HDSP_XLRBreakoutCable (1<<20) /* For H9632 cards */ #define HDSP_Midi0InterruptEnable (1<<22) #define HDSP_Midi1InterruptEnable (1<<23) #define HDSP_LineOut (1<<24) +#define HDSP_ADGain0 (1<<25) /* From here : H9632 specific */ +#define HDSP_ADGain1 (1<<26) +#define HDSP_DAGain0 (1<<27) +#define HDSP_DAGain1 (1<<28) +#define HDSP_PhoneGain0 (1<<29) +#define HDSP_PhoneGain1 (1<<30) +#define HDSP_QuadSpeed (1<<31) + +#define HDSP_ADGainMask (HDSP_ADGain0|HDSP_ADGain1) +#define HDSP_ADGainMinus10dBV HDSP_ADGainMask +#define HDSP_ADGainPlus4dBu (HDSP_ADGain0) +#define HDSP_ADGainLowGain 0 + +#define HDSP_DAGainMask (HDSP_DAGain0|HDSP_DAGain1) +#define HDSP_DAGainHighGain HDSP_DAGainMask +#define HDSP_DAGainPlus4dBu (HDSP_DAGain0) +#define HDSP_DAGainMinus10dBV 0 + +#define HDSP_PhoneGainMask (HDSP_PhoneGain0|HDSP_PhoneGain1) +#define HDSP_PhoneGain0dB HDSP_PhoneGainMask +#define HDSP_PhoneGainMinus6dB (HDSP_PhoneGain0) +#define HDSP_PhoneGainMinus12dB 0 #define HDSP_LatencyMask (HDSP_Latency0|HDSP_Latency1|HDSP_Latency2) -#define HDSP_FrequencyMask (HDSP_Frequency0|HDSP_Frequency1|HDSP_DoubleSpeed) +#define HDSP_FrequencyMask (HDSP_Frequency0|HDSP_Frequency1|HDSP_DoubleSpeed|HDSP_QuadSpeed) #define HDSP_SPDIFInputMask (HDSP_SPDIFInputSelect0|HDSP_SPDIFInputSelect1) #define HDSP_SPDIFInputADAT1 0 -#define HDSP_SPDIFInputCoaxial (HDSP_SPDIFInputSelect1) -#define HDSP_SPDIFInputCDROM (HDSP_SPDIFInputSelect0|HDSP_SPDIFInputSelect1) +#define HDSP_SPDIFInputCoaxial (HDSP_SPDIFInputSelect0) +#define HDSP_SPDIFInputCdrom (HDSP_SPDIFInputSelect1) +#define HDSP_SPDIFInputAES (HDSP_SPDIFInputSelect0|HDSP_SPDIFInputSelect1) #define HDSP_SyncRefMask (HDSP_SyncRef0|HDSP_SyncRef1|HDSP_SyncRef2) -#define HDSP_SyncRef_ADAT1 0 +#define HDSP_SyncRef_ADAT1 0 #define HDSP_SyncRef_ADAT2 (HDSP_SyncRef0) #define HDSP_SyncRef_ADAT3 (HDSP_SyncRef1) #define HDSP_SyncRef_SPDIF (HDSP_SyncRef0|HDSP_SyncRef1) @@ -183,20 +232,23 @@ MODULE_DEVICES("{{RME Hammerfall-DSP}," /* Sample Clock Sources */ -#define HDSP_CLOCK_SOURCE_AUTOSYNC 0 -#define HDSP_CLOCK_SOURCE_INTERNAL_32KHZ 1 -#define HDSP_CLOCK_SOURCE_INTERNAL_44_1KHZ 2 -#define HDSP_CLOCK_SOURCE_INTERNAL_48KHZ 3 -#define HDSP_CLOCK_SOURCE_INTERNAL_64KHZ 4 -#define HDSP_CLOCK_SOURCE_INTERNAL_88_2KHZ 5 -#define HDSP_CLOCK_SOURCE_INTERNAL_96KHZ 6 +#define HDSP_CLOCK_SOURCE_AUTOSYNC 0 +#define HDSP_CLOCK_SOURCE_INTERNAL_32KHZ 1 +#define HDSP_CLOCK_SOURCE_INTERNAL_44_1KHZ 2 +#define HDSP_CLOCK_SOURCE_INTERNAL_48KHZ 3 +#define HDSP_CLOCK_SOURCE_INTERNAL_64KHZ 4 +#define HDSP_CLOCK_SOURCE_INTERNAL_88_2KHZ 5 +#define HDSP_CLOCK_SOURCE_INTERNAL_96KHZ 6 +#define HDSP_CLOCK_SOURCE_INTERNAL_128KHZ 7 +#define HDSP_CLOCK_SOURCE_INTERNAL_176_4KHZ 8 +#define HDSP_CLOCK_SOURCE_INTERNAL_192KHZ 9 /* Preferred sync reference choices - used by "pref_sync_ref" control switch */ #define HDSP_SYNC_FROM_WORD 0 -#define HDSP_SYNC_FROM_ADAT_SYNC 1 -#define HDSP_SYNC_FROM_SPDIF 2 -#define HDSP_SYNC_FROM_ADAT1 3 +#define HDSP_SYNC_FROM_SPDIF 1 +#define HDSP_SYNC_FROM_ADAT1 2 +#define HDSP_SYNC_FROM_ADAT_SYNC 3 #define HDSP_SYNC_FROM_ADAT2 4 #define HDSP_SYNC_FROM_ADAT3 5 @@ -218,16 +270,21 @@ MODULE_DEVICES("{{RME Hammerfall-DSP}," /* Possible sources of S/PDIF input */ -#define HDSP_SPDIFIN_OPTICAL 0 /* optical (ADAT1) */ -#define HDSP_SPDIFIN_COAXIAL 1 /* coaxial (RCA) */ -#define HDSP_SPDIFIN_INTERN 2 /* internal (CDROM) */ +#define HDSP_SPDIFIN_OPTICAL 0 /* optical (ADAT1) */ +#define HDSP_SPDIFIN_COAXIAL 1 /* coaxial (RCA) */ +#define HDSP_SPDIFIN_INTERNAL 2 /* internal (CDROM) */ +#define HDSP_SPDIFIN_AES 3 /* xlr for H9632 (AES)*/ #define HDSP_Frequency32KHz HDSP_Frequency0 #define HDSP_Frequency44_1KHz HDSP_Frequency1 -#define HDSP_Frequency48KHz (HDSP_Frequency1|HDSP_Frequency0) -#define HDSP_Frequency64KHz (HDSP_DoubleSpeed|HDSP_Frequency0) -#define HDSP_Frequency88_2KHz (HDSP_DoubleSpeed|HDSP_Frequency1) -#define HDSP_Frequency96KHz (HDSP_DoubleSpeed|HDSP_Frequency1|HDSP_Frequency0) +#define HDSP_Frequency48KHz (HDSP_Frequency1|HDSP_Frequency0) +#define HDSP_Frequency64KHz (HDSP_DoubleSpeed|HDSP_Frequency0) +#define HDSP_Frequency88_2KHz (HDSP_DoubleSpeed|HDSP_Frequency1) +#define HDSP_Frequency96KHz (HDSP_DoubleSpeed|HDSP_Frequency1|HDSP_Frequency0) +/* For H9632 cards */ +#define HDSP_Frequency128KHz (HDSP_QuadSpeed|HDSP_DoubleSpeed|HDSP_Frequency0) +#define HDSP_Frequency176_4KHz (HDSP_QuadSpeed|HDSP_DoubleSpeed|HDSP_Frequency1) +#define HDSP_Frequency192KHz (HDSP_QuadSpeed|HDSP_DoubleSpeed|HDSP_Frequency1|HDSP_Frequency0) #define hdsp_encode_latency(x) (((x)<<1) & HDSP_LatencyMask) #define hdsp_decode_latency(x) (((x) & HDSP_LatencyMask)>>1) @@ -238,7 +295,8 @@ MODULE_DEVICES("{{RME Hammerfall-DSP}," /* Status Register bits */ #define HDSP_audioIRQPending (1<<0) -#define HDSP_Lock2 (1<<1) +#define HDSP_Lock2 (1<<1) /* this is for Digiface and H9652 */ +#define HDSP_spdifFrequency3 HDSP_Lock2 /* this is for H9632 only */ #define HDSP_Lock1 (1<<2) #define HDSP_Lock0 (1<<3) #define HDSP_SPDIFSync (1<<4) @@ -256,8 +314,9 @@ MODULE_DEVICES("{{RME Hammerfall-DSP}," #define HDSP_SPDIFErrorFlag (1<<25) #define HDSP_BufferID (1<<26) #define HDSP_TimecodeSync (1<<27) -#define HDSP_CIN (1<<28) -#define HDSP_midi0IRQPending (1<<30) /* notice the gap at bit 29 */ +#define HDSP_AEBO (1<<28) /* H9632 specific Analog Extension Boards */ +#define HDSP_AEBI (1<<29) /* 0 = present, 1 = absent */ +#define HDSP_midi0IRQPending (1<<30) #define HDSP_midi1IRQPending (1<<31) #define HDSP_spdifFrequencyMask (HDSP_spdifFrequency0|HDSP_spdifFrequency1|HDSP_spdifFrequency2) @@ -270,6 +329,11 @@ MODULE_DEVICES("{{RME Hammerfall-DSP}," #define HDSP_spdifFrequency88_2KHz (HDSP_spdifFrequency0|HDSP_spdifFrequency2) #define HDSP_spdifFrequency96KHz (HDSP_spdifFrequency2|HDSP_spdifFrequency1) +/* This is for H9632 cards */ +#define HDSP_spdifFrequency128KHz HDSP_spdifFrequencyMask +#define HDSP_spdifFrequency176_4KHz HDSP_spdifFrequency3 +#define HDSP_spdifFrequency192KHz (HDSP_spdifFrequency3|HDSP_spdifFrequency0) + /* Status2 Register bits */ #define HDSP_version0 (1<<0) @@ -293,6 +357,7 @@ MODULE_DEVICES("{{RME Hammerfall-DSP}," #define HDSP_systemFrequency64 (HDSP_inp_freq2) #define HDSP_systemFrequency88_2 (HDSP_inp_freq0|HDSP_inp_freq2) #define HDSP_systemFrequency96 (HDSP_inp_freq1|HDSP_inp_freq2) +/* FIXME : more values for 9632 cards ? */ #define HDSP_SelSyncRefMask (HDSP_SelSyncRef0|HDSP_SelSyncRef1|HDSP_SelSyncRef2) #define HDSP_SelSyncRef_ADAT1 0 @@ -340,8 +405,25 @@ MODULE_DEVICES("{{RME Hammerfall-DSP}," #define HDSP_DMA_AREA_BYTES ((HDSP_MAX_CHANNELS+1) * HDSP_CHANNEL_BUFFER_BYTES) #define HDSP_DMA_AREA_KILOBYTES (HDSP_DMA_AREA_BYTES/1024) -typedef struct _hdsp hdsp_t; -typedef struct _hdsp_midi hdsp_midi_t; +typedef struct _hdsp hdsp_t; +typedef struct _hdsp_midi hdsp_midi_t; +typedef struct _hdsp_9632_meters hdsp_9632_meters_t; + +struct _hdsp_9632_meters { + u32 input_peak[16]; + u32 playback_peak[16]; + u32 output_peak[16]; + u32 xxx_peak[16]; + u32 padding[64]; + u32 input_rms_low[16]; + u32 playback_rms_low[16]; + u32 output_rms_low[16]; + u32 xxx_rms_low[16]; + u32 input_rms_high[16]; + u32 playback_rms_high[16]; + u32 output_rms_high[16]; + u32 xxx_rms_high[16]; +}; struct _hdsp_midi { hdsp_t *hdsp; @@ -372,8 +454,13 @@ struct _hdsp { unsigned short state; /* stores state bits */ u32 firmware_cache[24413]; /* this helps recover from accidental iobox power failure */ size_t period_bytes; /* guess what this is */ - unsigned char ds_channels; - unsigned char ss_channels; /* different for multiface/digiface */ + unsigned char max_channels; + unsigned char qs_in_channels; /* quad speed mode for H9632 */ + unsigned char ds_in_channels; + unsigned char ss_in_channels; /* different for multiface/digiface */ + unsigned char qs_out_channels; + unsigned char ds_out_channels; + unsigned char ss_out_channels; void *capture_buffer_unaligned; /* original buffer addresses */ void *playback_buffer_unaligned; /* original buffer addresses */ unsigned char *capture_buffer; /* suitably aligned address */ @@ -384,9 +471,6 @@ struct _hdsp { pid_t playback_pid; int running; int passthru; /* non-zero if doing pass-thru */ - int last_spdif_sample_rate;/* for information reporting */ - int last_external_sample_rate; - int last_internal_sample_rate; int system_sample_rate; char *channel_map; int dev; @@ -399,7 +483,6 @@ struct _hdsp { snd_hwdep_t *hwdep; struct pci_dev *pci; snd_kcontrol_t *spdif_ctl; - snd_kcontrol_t *playback_mixer_ctls[HDSP_MAX_CHANNELS]; unsigned short mixer_matrix[HDSP_MATRIX_MIXER_SIZE]; }; @@ -423,7 +506,7 @@ static char channel_map_mf_ss[HDSP_MAX_C 16, 17, 18, 19, 20, 21, 22, 23, /* SPDIF */ 24, 25, - -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; static char channel_map_ds[HDSP_MAX_CHANNELS] = { @@ -432,7 +515,49 @@ static char channel_map_ds[HDSP_MAX_CHAN /* channels 12 and 13 are S/PDIF */ 24, 25, /* others don't exist */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + +static char channel_map_H9632_ss[HDSP_MAX_CHANNELS] = { + /* ADAT channels */ + 0, 1, 2, 3, 4, 5, 6, 7, + /* SPDIF */ + 8, 9, + /* Analog */ + 10, 11, + /* AO4S-192 and AI4S-192 extension boards */ + 12, 13, 14, 15, + /* others don't exist */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1 +}; + +static char channel_map_H9632_ds[HDSP_MAX_CHANNELS] = { + /* ADAT */ + 1, 3, 5, 7, + /* SPDIF */ + 8, 9, + /* Analog */ + 10, 11, + /* AO4S-192 and AI4S-192 extension boards */ + 12, 13, 14, 15, + /* others don't exist */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1 +}; + +static char channel_map_H9632_qs[HDSP_MAX_CHANNELS] = { + /* ADAT is disabled in this mode */ + /* SPDIF */ + 8, 9, + /* Analog */ + 10, 11, + /* AO4S-192 and AI4S-192 extension boards */ + 12, 13, 14, 15, + /* others don't exist */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1 }; #define HDSP_PREALLOCATE_MEMORY /* via module snd-hdsp_mem */ @@ -492,15 +617,17 @@ static inline int snd_hdsp_enable_io (hd static inline void snd_hdsp_initialize_midi_flush (hdsp_t *hdsp); static inline void snd_hdsp_initialize_channels (hdsp_t *hdsp); static inline int hdsp_fifo_wait(hdsp_t *hdsp, int count, int timeout); -static int hdsp_update_simple_mixer_controls(hdsp_t *hdsp); static int hdsp_autosync_ref(hdsp_t *hdsp); static int snd_hdsp_set_defaults(hdsp_t *hdsp); +static inline void snd_hdsp_9652_enable_mixer (hdsp_t *hdsp); static inline int hdsp_playback_to_output_key (hdsp_t *hdsp, int in, int out) { switch (hdsp->firmware_rev) { case 0xa: return (64 * out) + (32 + (in)); + case 0x96: + return (32 * out) + (16 + (in)); default: return (52 * out) + (26 + (in)); } @@ -511,6 +638,8 @@ static inline int hdsp_input_to_output_k switch (hdsp->firmware_rev) { case 0xa: return (64 * out) + in; + case 0x96: + return (32 * out) + in; default: return (52 * out) + in; } @@ -529,7 +658,7 @@ static inline unsigned int hdsp_read(hds static inline int hdsp_check_for_iobox (hdsp_t *hdsp) { - if (hdsp->io_type == H9652) return 0; + if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return 0; if (hdsp_read (hdsp, HDSP_statusRegister) & HDSP_ConfigError) { snd_printk ("Hammerfall-DSP: no Digiface or Multiface connected!\n"); hdsp->state &= ~HDSP_FirmwareLoaded; @@ -565,6 +694,13 @@ static int snd_hdsp_load_firmware_from_c return -EIO; } } + + if ((1000 / HZ) < 3000) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((3000 * HZ + 999) / 1000); + } else { + mdelay(3000); + } if (hdsp_fifo_wait (hdsp, 0, HDSP_LONG_WAIT)) { snd_printk ("timeout at end of firmware loading\n"); @@ -579,12 +715,6 @@ static int snd_hdsp_load_firmware_from_c hdsp_write (hdsp, HDSP_control2Reg, hdsp->control2_register); snd_printk ("finished firmware loading\n"); - if ((1000 / HZ) < 3000) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((3000 * HZ + 999) / 1000); - } else { - mdelay(3000); - } } if (hdsp->state & HDSP_InitializationComplete) { snd_printk("firmware loaded from cache, restoring defaults\n"); @@ -643,7 +773,7 @@ static inline int hdsp_get_iobox_version static inline int hdsp_check_for_firmware (hdsp_t *hdsp) { - if (hdsp->io_type == H9652) return 0; + if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return 0; if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) { snd_printk("firmware not present.\n"); hdsp->state &= ~HDSP_FirmwareLoaded; @@ -692,8 +822,8 @@ static inline int hdsp_write_gain(hdsp_t if (addr >= HDSP_MATRIX_MIXER_SIZE) return -1; - - if (hdsp->io_type == H9652) { + + if (hdsp->io_type == H9652 || hdsp->io_type == H9632) { /* from martin björnsen: @@ -707,8 +837,17 @@ static inline int hdsp_write_gain(hdsp_t memory." */ + if (hdsp->io_type == H9632 && addr >= 512) { + return 0; + } + + if (hdsp->io_type == H9652 && addr >= 1352) { + return 0; + } + hdsp->mixer_matrix[addr] = data; + /* `addr' addresses a 16-bit wide address, but the address space accessed via hdsp_write uses byte offsets. put another way, addr @@ -716,8 +855,9 @@ static inline int hdsp_write_gain(hdsp_t corresponding memory location, we need to access 0 to 2703 ... */ - - hdsp_write (hdsp, 4096 + (addr*2), + ad = addr/2; + + hdsp_write (hdsp, 4096 + (ad*4), (hdsp->mixer_matrix[(addr&0x7fe)+1] << 16) + hdsp->mixer_matrix[addr&0x7fe]); @@ -786,10 +926,20 @@ static inline int hdsp_spdif_sample_rate case HDSP_spdifFrequency64KHz: return 64000; case HDSP_spdifFrequency88_2KHz: return 88200; case HDSP_spdifFrequency96KHz: return 96000; + case HDSP_spdifFrequency128KHz: + if (hdsp->io_type == H9632) return 128000; + break; + case HDSP_spdifFrequency176_4KHz: + if (hdsp->io_type == H9632) return 176400; + break; + case HDSP_spdifFrequency192KHz: + if (hdsp->io_type == H9632) return 192000; + break; default: - snd_printk ("unknown spdif frequency status; bits = 0x%x, status = 0x%x\n", rate_bits, status); - return 0; + break; } + snd_printk ("unknown spdif frequency status; bits = 0x%x, status = 0x%x\n", rate_bits, status); + return 0; } static inline void hdsp_compute_period_size(hdsp_t *hdsp) @@ -867,7 +1017,7 @@ static int hdsp_set_rate(hdsp_t *hdsp, i int current_rate; int rate_bits; - /* ASSUMPTION: hdsp->lock is either help, or + /* ASSUMPTION: hdsp->lock is either held, or there is no need for it (e.g. during module initialization). */ @@ -884,6 +1034,8 @@ static int hdsp_set_rate(hdsp_t *hdsp, i if ((spdif_freq == external_freq*2) && (hdsp_autosync_ref(hdsp) >= HDSP_AUTOSYNC_FROM_ADAT1)) { snd_printk("Detected ADAT in double speed mode\n"); + } else if (hdsp->io_type == H9632 && (spdif_freq == external_freq*4) && (hdsp_autosync_ref(hdsp) >= HDSP_AUTOSYNC_FROM_ADAT1)) { + snd_printk("Detected ADAT in quad speed mode\n"); } else if (rate != external_freq) { snd_printk("No AutoSync source for requested rate\n"); return -1; @@ -903,6 +1055,10 @@ static int hdsp_set_rate(hdsp_t *hdsp, i exists for externally-driven rate changes. All we can do is to flag rate changes in the read/write routines. */ + if (rate > 96000 && hdsp->io_type != H9632) { + return -EINVAL; + } + switch (rate) { case 32000: if (current_rate > 48000) { @@ -923,29 +1079,47 @@ static int hdsp_set_rate(hdsp_t *hdsp, i rate_bits = HDSP_Frequency48KHz; break; case 64000: - if (current_rate <= 48000) { + if (current_rate <= 48000 || current_rate > 96000) { reject_if_open = 1; } rate_bits = HDSP_Frequency64KHz; break; case 88200: - if (current_rate <= 48000) { + if (current_rate <= 48000 || current_rate > 96000) { reject_if_open = 1; } rate_bits = HDSP_Frequency88_2KHz; break; case 96000: - if (current_rate <= 48000) { + if (current_rate <= 48000 || current_rate > 96000) { reject_if_open = 1; } rate_bits = HDSP_Frequency96KHz; break; + case 128000: + if (current_rate < 128000) { + reject_if_open = 1; + } + rate_bits = HDSP_Frequency128KHz; + break; + case 176400: + if (current_rate < 128000) { + reject_if_open = 1; + } + rate_bits = HDSP_Frequency176_4KHz; + break; + case 192000: + if (current_rate < 128000) { + reject_if_open = 1; + } + rate_bits = HDSP_Frequency192KHz; + break; default: return -EINVAL; } if (reject_if_open && (hdsp->capture_pid >= 0 || hdsp->playback_pid >= 0)) { - snd_printk ("cannot change between single- and double-speed mode (capture PID = %d, playback PID = %d)\n", + snd_printk ("cannot change speed mode (capture PID = %d, playback PID = %d)\n", hdsp->capture_pid, hdsp->playback_pid); return -EBUSY; @@ -955,8 +1129,14 @@ static int hdsp_set_rate(hdsp_t *hdsp, i hdsp->control_register |= rate_bits; hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); - if (rate > 48000) { - hdsp->channel_map = channel_map_ds; + if (rate >= 128000) { + hdsp->channel_map = channel_map_H9632_qs; + } else if (rate > 48000) { + if (hdsp->io_type == H9632) { + hdsp->channel_map = channel_map_H9632_ds; + } else { + hdsp->channel_map = channel_map_ds; + } } else { switch (hdsp->io_type) { case Multiface: @@ -966,6 +1146,9 @@ static int hdsp_set_rate(hdsp_t *hdsp, i case H9652: hdsp->channel_map = channel_map_df_ss; break; + case H9632: + hdsp->channel_map = channel_map_H9632_ss; + break; default: /* should never happen */ break; @@ -973,10 +1156,6 @@ static int hdsp_set_rate(hdsp_t *hdsp, i } hdsp->system_sample_rate = rate; - - if (reject_if_open) { - hdsp_update_simple_mixer_controls (hdsp); - } return 0; } @@ -993,11 +1172,11 @@ static void hdsp_set_thru(hdsp_t *hdsp, /* set thru for all channels */ if (enable) { - for (i = 0; i < 26; i++) { + for (i = 0; i < hdsp->max_channels; i++) { hdsp_write_gain (hdsp, hdsp_input_to_output_key(hdsp,i,i), UNITY_GAIN); } } else { - for (i = 0; i < 26; i++) { + for (i = 0; i < hdsp->max_channels; i++) { hdsp_write_gain (hdsp, hdsp_input_to_output_key(hdsp,i,i), MINUS_INFINITY_GAIN); } } @@ -1005,7 +1184,7 @@ static void hdsp_set_thru(hdsp_t *hdsp, } else { int mapped_channel; - snd_assert(channel < HDSP_MAX_CHANNELS, return); + snd_assert(channel < hdsp->max_channels, return); mapped_channel = hdsp->channel_map[channel]; @@ -1463,13 +1642,14 @@ static int hdsp_set_spdif_input(hdsp_t * static int snd_hdsp_info_spdif_in(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { - static char *texts[3] = {"ADAT1", "Coaxial", "Internal"}; + static char *texts[4] = {"Optical", "Coaxial", "Internal", "AES"}; + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; - uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item > 2) - uinfo->value.enumerated.item = 2; + uinfo->value.enumerated.items = ((hdsp->io_type == H9632) ? 4 : 3); + if (uinfo->value.enumerated.item > ((hdsp->io_type == H9632) ? 3 : 2)) + uinfo->value.enumerated.item = ((hdsp->io_type == H9632) ? 3 : 2); strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); return 0; } @@ -1491,7 +1671,7 @@ static int snd_hdsp_put_spdif_in(snd_kco if (!snd_hdsp_use_is_exclusive(hdsp)) return -EBUSY; - val = ucontrol->value.enumerated.item[0] % 3; + val = ucontrol->value.enumerated.item[0] % ((hdsp->io_type == H9632) ? 4 : 3); spin_lock_irqsave(&hdsp->lock, flags); change = val != hdsp_spdif_in(hdsp); if (change) @@ -1704,10 +1884,12 @@ static int snd_hdsp_put_spdif_nonaudio(s static int snd_hdsp_info_spdif_sample_rate(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { - static char *texts[] = {"32000", "44100", "48000", "64000", "88200", "96000", "None"}; + static char *texts[] = {"32000", "44100", "48000", "64000", "88200", "96000", "None", "128000", "176400", "192000"}; + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; - uinfo->value.enumerated.items = 7 ; + uinfo->value.enumerated.items = (hdsp->io_type == H9632) ? 10 : 7; if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); @@ -1737,6 +1919,15 @@ static int snd_hdsp_get_spdif_sample_rat case 96000: ucontrol->value.enumerated.item[0] = 5; break; + case 128000: + ucontrol->value.enumerated.item[0] = 7; + break; + case 176400: + ucontrol->value.enumerated.item[0] = 8; + break; + case 192000: + ucontrol->value.enumerated.item[0] = 9; + break; default: ucontrol->value.enumerated.item[0] = 6; } @@ -1778,10 +1969,11 @@ static int snd_hdsp_get_system_sample_ra static int snd_hdsp_info_autosync_sample_rate(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { - static char *texts[] = {"32000", "44100", "48000", "64000", "88200", "96000", "None"}; + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + static char *texts[] = {"32000", "44100", "48000", "64000", "88200", "96000", "None", "128000", "176400", "192000"}; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; - uinfo->value.enumerated.items = 7 ; + uinfo->value.enumerated.items = (hdsp->io_type == H9632) ? 10 : 7 ; if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); @@ -1811,6 +2003,15 @@ static int snd_hdsp_get_autosync_sample_ case 96000: ucontrol->value.enumerated.item[0] = 5; break; + case 128000: + ucontrol->value.enumerated.item[0] = 7; + break; + case 176400: + ucontrol->value.enumerated.item[0] = 8; + break; + case 192000: + ucontrol->value.enumerated.item[0] = 9; + break; default: ucontrol->value.enumerated.item[0] = 6; } @@ -1882,6 +2083,12 @@ static int hdsp_clock_source(hdsp_t *hds return 5; case 96000: return 6; + case 128000: + return 7; + case 176400: + return 8; + case 192000: + return 9; default: return 3; } @@ -1896,9 +2103,11 @@ static int hdsp_set_clock_source(hdsp_t switch (mode) { case HDSP_CLOCK_SOURCE_AUTOSYNC: if (hdsp_external_sample_rate(hdsp) != 0) { - hdsp->control_register &= ~HDSP_ClockModeMaster; - hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); - return 0; + if (!hdsp_set_rate(hdsp, hdsp_external_sample_rate(hdsp), 1)) { + hdsp->control_register &= ~HDSP_ClockModeMaster; + hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); + return 0; + } } return -1; case HDSP_CLOCK_SOURCE_INTERNAL_32KHZ: @@ -1919,6 +2128,15 @@ static int hdsp_set_clock_source(hdsp_t case HDSP_CLOCK_SOURCE_INTERNAL_96KHZ: rate = 96000; break; + case HDSP_CLOCK_SOURCE_INTERNAL_128KHZ: + rate = 128000; + break; + case HDSP_CLOCK_SOURCE_INTERNAL_176_4KHZ: + rate = 176400; + break; + case HDSP_CLOCK_SOURCE_INTERNAL_192KHZ: + rate = 192000; + break; default: rate = 48000; } @@ -1930,11 +2148,15 @@ static int hdsp_set_clock_source(hdsp_t static int snd_hdsp_info_clock_source(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { - static char *texts[] = {"AutoSync", "Internal 32.0 kHz", "Internal 44.1 kHz", "Internal 48.0 kHz", "Internal 64.0 kHz", "Internal 88.2 kHz", "Internal 96.0 kHz" }; + static char *texts[] = {"AutoSync", "Internal 32.0 kHz", "Internal 44.1 kHz", "Internal 48.0 kHz", "Internal 64.0 kHz", "Internal 88.2 kHz", "Internal 96.0 kHz", "Internal 128 kHz", "Internal 176.4 kHz", "Internal 192.0 KHz" }; + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; - uinfo->value.enumerated.items = 7; + if (hdsp->io_type == H9632) + uinfo->value.enumerated.items = 10; + else + uinfo->value.enumerated.items = 7; if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); @@ -1960,7 +2182,11 @@ static int snd_hdsp_put_clock_source(snd return -EBUSY; val = ucontrol->value.enumerated.item[0]; if (val < 0) val = 0; - if (val > 6) val = 6; + if (hdsp->io_type == H9632) { + if (val > 9) val = 9; + } else { + if (val > 6) val = 6; + } spin_lock_irqsave(&hdsp->lock, flags); if (val != hdsp_clock_source(hdsp)) { change = (hdsp_set_clock_source(hdsp, val) == 0) ? 1 : 0; @@ -1971,264 +2197,362 @@ static int snd_hdsp_put_clock_source(snd return change; } -#define HDSP_PREF_SYNC_REF(xname, xindex) \ +#define HDSP_DA_GAIN(xname, xindex) \ { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ .name = xname, \ .index = xindex, \ - .info = snd_hdsp_info_pref_sync_ref, \ - .get = snd_hdsp_get_pref_sync_ref, \ - .put = snd_hdsp_put_pref_sync_ref \ + .info = snd_hdsp_info_da_gain, \ + .get = snd_hdsp_get_da_gain, \ + .put = snd_hdsp_put_da_gain \ } -static int hdsp_pref_sync_ref(hdsp_t *hdsp) +static int hdsp_da_gain(hdsp_t *hdsp) { - /* Notice that this looks at the requested sync source, - not the one actually in use. - */ - - switch (hdsp->control_register & HDSP_SyncRefMask) { - case HDSP_SyncRef_ADAT1: - return HDSP_SYNC_FROM_ADAT1; - case HDSP_SyncRef_ADAT2: - return HDSP_SYNC_FROM_ADAT2; - case HDSP_SyncRef_ADAT3: - return HDSP_SYNC_FROM_ADAT3; - case HDSP_SyncRef_SPDIF: - return HDSP_SYNC_FROM_SPDIF; - case HDSP_SyncRef_WORD: - return HDSP_SYNC_FROM_WORD; - case HDSP_SyncRef_ADAT_SYNC: - return HDSP_SYNC_FROM_ADAT_SYNC; + switch (hdsp->control_register & HDSP_DAGainMask) { + case HDSP_DAGainHighGain: + return 0; + case HDSP_DAGainPlus4dBu: + return 1; + case HDSP_DAGainMinus10dBV: + return 2; default: - return HDSP_SYNC_FROM_WORD; + return 1; } - return 0; } -static int hdsp_set_pref_sync_ref(hdsp_t *hdsp, int pref) +static int hdsp_set_da_gain(hdsp_t *hdsp, int mode) { - hdsp->control_register &= ~HDSP_SyncRefMask; - switch (pref) { - case HDSP_SYNC_FROM_ADAT1: - hdsp->control_register &= ~HDSP_SyncRefMask; /* clear SyncRef bits */ - break; - case HDSP_SYNC_FROM_ADAT2: - hdsp->control_register |= HDSP_SyncRef_ADAT2; - break; - case HDSP_SYNC_FROM_ADAT3: - hdsp->control_register |= HDSP_SyncRef_ADAT3; - break; - case HDSP_SYNC_FROM_SPDIF: - hdsp->control_register |= HDSP_SyncRef_SPDIF; - break; - case HDSP_SYNC_FROM_WORD: - hdsp->control_register |= HDSP_SyncRef_WORD; + hdsp->control_register &= ~HDSP_DAGainMask; + switch (mode) { + case 0: + hdsp->control_register |= HDSP_DAGainHighGain; break; - case HDSP_SYNC_FROM_ADAT_SYNC: - hdsp->control_register |= HDSP_SyncRef_ADAT_SYNC; + case 1: + hdsp->control_register |= HDSP_DAGainPlus4dBu; break; + case 2: + hdsp->control_register |= HDSP_DAGainMinus10dBV; + break; default: return -1; + } hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); return 0; } -static int snd_hdsp_info_pref_sync_ref(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +static int snd_hdsp_info_da_gain(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { - static char *texts[] = {"Word", "ADAT Sync", "IEC958", "ADAT1", "ADAT2", "ADAT3" }; - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + static char *texts[] = {"Hi Gain", "+4 dBu", "-10 dbV"}; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; - - switch (hdsp->io_type) { - case Digiface: - case H9652: - uinfo->value.enumerated.items = 6; - break; - case Multiface: - uinfo->value.enumerated.items = 4; - default: - uinfo->value.enumerated.items = 0; - break; - } - + uinfo->value.enumerated.items = 3; if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); return 0; } -static int snd_hdsp_get_pref_sync_ref(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +static int snd_hdsp_get_da_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); - ucontrol->value.enumerated.item[0] = hdsp_pref_sync_ref(hdsp); + ucontrol->value.enumerated.item[0] = hdsp_da_gain(hdsp); return 0; } -static int snd_hdsp_put_pref_sync_ref(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +static int snd_hdsp_put_da_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); unsigned long flags; - int change, max; - unsigned int val; + int change; + int val; if (!snd_hdsp_use_is_exclusive(hdsp)) return -EBUSY; - - switch (hdsp->io_type) { - case Digiface: - case H9652: - max = 6; - break; - case Multiface: - max = 4; - break; - default: - return -EIO; - } - - val = ucontrol->value.enumerated.item[0] % max; + val = ucontrol->value.enumerated.item[0]; + if (val < 0) val = 0; + if (val > 2) val = 2; spin_lock_irqsave(&hdsp->lock, flags); - change = (int)val != hdsp_pref_sync_ref(hdsp); - hdsp_set_pref_sync_ref(hdsp, val); + if (val != hdsp_da_gain(hdsp)) { + change = (hdsp_set_da_gain(hdsp, val) == 0) ? 1 : 0; + } else { + change = 0; + } spin_unlock_irqrestore(&hdsp->lock, flags); return change; } -#define HDSP_AUTOSYNC_REF(xname, xindex) \ +#define HDSP_AD_GAIN(xname, xindex) \ { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ .name = xname, \ .index = xindex, \ - .access = SNDRV_CTL_ELEM_ACCESS_READ, \ - .info = snd_hdsp_info_autosync_ref, \ - .get = snd_hdsp_get_autosync_ref, \ + .info = snd_hdsp_info_ad_gain, \ + .get = snd_hdsp_get_ad_gain, \ + .put = snd_hdsp_put_ad_gain \ } -static int hdsp_autosync_ref(hdsp_t *hdsp) +static int hdsp_ad_gain(hdsp_t *hdsp) { - /* This looks at the autosync selected sync reference */ - unsigned int status2 = hdsp_read(hdsp, HDSP_status2Register); + switch (hdsp->control_register & HDSP_ADGainMask) { + case HDSP_ADGainMinus10dBV: + return 0; + case HDSP_ADGainPlus4dBu: + return 1; + case HDSP_ADGainLowGain: + return 2; + default: + return 1; + } +} - switch (status2 & HDSP_SelSyncRefMask) { - case HDSP_SelSyncRef_WORD: - return HDSP_AUTOSYNC_FROM_WORD; - case HDSP_SelSyncRef_ADAT_SYNC: - return HDSP_AUTOSYNC_FROM_ADAT_SYNC; - case HDSP_SelSyncRef_SPDIF: - return HDSP_AUTOSYNC_FROM_SPDIF; - case HDSP_SelSyncRefMask: - return HDSP_AUTOSYNC_FROM_NONE; - case HDSP_SelSyncRef_ADAT1: - return HDSP_AUTOSYNC_FROM_ADAT1; - case HDSP_SelSyncRef_ADAT2: - return HDSP_AUTOSYNC_FROM_ADAT2; - case HDSP_SelSyncRef_ADAT3: - return HDSP_AUTOSYNC_FROM_ADAT3; +static int hdsp_set_ad_gain(hdsp_t *hdsp, int mode) +{ + hdsp->control_register &= ~HDSP_ADGainMask; + switch (mode) { + case 0: + hdsp->control_register |= HDSP_ADGainMinus10dBV; + break; + case 1: + hdsp->control_register |= HDSP_ADGainPlus4dBu; + break; + case 2: + hdsp->control_register |= HDSP_ADGainLowGain; + break; default: - return HDSP_AUTOSYNC_FROM_WORD; + return -1; + } + hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); return 0; } -static int snd_hdsp_info_autosync_ref(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +static int snd_hdsp_info_ad_gain(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { - static char *texts[] = {"Word", "ADAT Sync", "IEC958", "None", "ADAT1", "ADAT2", "ADAT3" }; + static char *texts[] = {"-10 dBV", "+4 dBu", "Lo Gain"}; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; - uinfo->value.enumerated.items = 7; + uinfo->value.enumerated.items = 3; if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); return 0; } -static int snd_hdsp_get_autosync_ref(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +static int snd_hdsp_get_ad_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); - ucontrol->value.enumerated.item[0] = hdsp_pref_sync_ref(hdsp); + ucontrol->value.enumerated.item[0] = hdsp_ad_gain(hdsp); return 0; } -#define HDSP_PASSTHRU(xname, xindex) \ +static int snd_hdsp_put_ad_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + unsigned long flags; + int change; + int val; + + if (!snd_hdsp_use_is_exclusive(hdsp)) + return -EBUSY; + val = ucontrol->value.enumerated.item[0]; + if (val < 0) val = 0; + if (val > 2) val = 2; + spin_lock_irqsave(&hdsp->lock, flags); + if (val != hdsp_ad_gain(hdsp)) { + change = (hdsp_set_ad_gain(hdsp, val) == 0) ? 1 : 0; + } else { + change = 0; + } + spin_unlock_irqrestore(&hdsp->lock, flags); + return change; +} + +#define HDSP_PHONE_GAIN(xname, xindex) \ { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ .name = xname, \ .index = xindex, \ - .info = snd_hdsp_info_passthru, \ - .put = snd_hdsp_put_passthru, \ - .get = snd_hdsp_get_passthru \ + .info = snd_hdsp_info_phone_gain, \ + .get = snd_hdsp_get_phone_gain, \ + .put = snd_hdsp_put_phone_gain \ } -static int snd_hdsp_info_passthru(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo) +static int hdsp_phone_gain(hdsp_t *hdsp) { - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; + switch (hdsp->control_register & HDSP_PhoneGainMask) { + case HDSP_PhoneGain0dB: + return 0; + case HDSP_PhoneGainMinus6dB: + return 1; + case HDSP_PhoneGainMinus12dB: + return 2; + default: + return 0; + } } -static int snd_hdsp_get_passthru(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +static int hdsp_set_phone_gain(hdsp_t *hdsp, int mode) +{ + hdsp->control_register &= ~HDSP_PhoneGainMask; + switch (mode) { + case 0: + hdsp->control_register |= HDSP_PhoneGain0dB; + break; + case 1: + hdsp->control_register |= HDSP_PhoneGainMinus6dB; + break; + case 2: + hdsp->control_register |= HDSP_PhoneGainMinus12dB; + break; + default: + return -1; + + } + hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); + return 0; +} + +static int snd_hdsp_info_phone_gain(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + static char *texts[] = {"0 dB", "-6 dB", "-12 dB"}; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 3; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_hdsp_get_phone_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); - unsigned long flags; + + ucontrol->value.enumerated.item[0] = hdsp_phone_gain(hdsp); + return 0; +} +static int snd_hdsp_put_phone_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + unsigned long flags; + int change; + int val; + + if (!snd_hdsp_use_is_exclusive(hdsp)) + return -EBUSY; + val = ucontrol->value.enumerated.item[0]; + if (val < 0) val = 0; + if (val > 2) val = 2; spin_lock_irqsave(&hdsp->lock, flags); - ucontrol->value.integer.value[0] = hdsp->passthru; + if (val != hdsp_phone_gain(hdsp)) { + change = (hdsp_set_phone_gain(hdsp, val) == 0) ? 1 : 0; + } else { + change = 0; + } spin_unlock_irqrestore(&hdsp->lock, flags); + return change; +} + +#define HDSP_XLR_BREAKOUT_CABLE(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdsp_info_xlr_breakout_cable, \ + .get = snd_hdsp_get_xlr_breakout_cable, \ + .put = snd_hdsp_put_xlr_breakout_cable \ +} + +static int hdsp_xlr_breakout_cable(hdsp_t *hdsp) +{ + if (hdsp->control_register & HDSP_XLRBreakoutCable) { + return 1; + } return 0; } -static int snd_hdsp_put_passthru(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +static int hdsp_set_xlr_breakout_cable(hdsp_t *hdsp, int mode) +{ + if (mode) { + hdsp->control_register |= HDSP_XLRBreakoutCable; + } else { + hdsp->control_register &= ~HDSP_XLRBreakoutCable; + } + hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); + return 0; +} + +static int snd_hdsp_info_xlr_breakout_cable(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_hdsp_get_xlr_breakout_cable(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = hdsp_xlr_breakout_cable(hdsp); + return 0; +} + +static int snd_hdsp_put_xlr_breakout_cable(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); unsigned long flags; int change; - unsigned int val; - int err = 0; - + int val; + if (!snd_hdsp_use_is_exclusive(hdsp)) return -EBUSY; - val = ucontrol->value.integer.value[0] & 1; spin_lock_irqsave(&hdsp->lock, flags); - change = (ucontrol->value.integer.value[0] != hdsp->passthru); - if (change) - err = hdsp_set_passthru(hdsp, val); + change = (int)val != hdsp_xlr_breakout_cable(hdsp); + hdsp_set_xlr_breakout_cable(hdsp, val); spin_unlock_irqrestore(&hdsp->lock, flags); - return err ? err : change; + return change; } -#define HDSP_LINE_OUT(xname, xindex) \ +/* (De)activates old RME Analog Extension Board + These are connected to the internal ADAT connector + Switching this on desactivates external ADAT +*/ +#define HDSP_AEB(xname, xindex) \ { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ .name = xname, \ .index = xindex, \ - .info = snd_hdsp_info_line_out, \ - .get = snd_hdsp_get_line_out, \ - .put = snd_hdsp_put_line_out \ + .info = snd_hdsp_info_aeb, \ + .get = snd_hdsp_get_aeb, \ + .put = snd_hdsp_put_aeb \ } -static int hdsp_line_out(hdsp_t *hdsp) +static int hdsp_aeb(hdsp_t *hdsp) { - return (hdsp->control_register & HDSP_LineOut) ? 1 : 0; + if (hdsp->control_register & HDSP_AnalogExtensionBoard) { + return 1; + } + return 0; } -static int hdsp_set_line_output(hdsp_t *hdsp, int out) +static int hdsp_set_aeb(hdsp_t *hdsp, int mode) { - if (out) { - hdsp->control_register |= HDSP_LineOut; + if (mode) { + hdsp->control_register |= HDSP_AnalogExtensionBoard; } else { - hdsp->control_register &= ~HDSP_LineOut; + hdsp->control_register &= ~HDSP_AnalogExtensionBoard; } hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); return 0; } -static int snd_hdsp_info_line_out(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +static int snd_hdsp_info_aeb(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 1; @@ -2237,182 +2561,399 @@ static int snd_hdsp_info_line_out(snd_kc return 0; } -static int snd_hdsp_get_line_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +static int snd_hdsp_get_aeb(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); - unsigned long flags; - spin_lock_irqsave(&hdsp->lock, flags); - ucontrol->value.integer.value[0] = hdsp_line_out(hdsp); - spin_unlock_irqrestore(&hdsp->lock, flags); + ucontrol->value.enumerated.item[0] = hdsp_aeb(hdsp); return 0; } -static int snd_hdsp_put_line_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +static int snd_hdsp_put_aeb(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); unsigned long flags; int change; - unsigned int val; + int val; if (!snd_hdsp_use_is_exclusive(hdsp)) return -EBUSY; val = ucontrol->value.integer.value[0] & 1; spin_lock_irqsave(&hdsp->lock, flags); - change = (int)val != hdsp_line_out(hdsp); - hdsp_set_line_output(hdsp, val); + change = (int)val != hdsp_aeb(hdsp); + hdsp_set_aeb(hdsp, val); spin_unlock_irqrestore(&hdsp->lock, flags); return change; } -#define HDSP_MIXER(xname, xindex) \ +#define HDSP_PREF_SYNC_REF(xname, xindex) \ { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ .name = xname, \ .index = xindex, \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ - SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ - .info = snd_hdsp_info_mixer, \ - .get = snd_hdsp_get_mixer, \ - .put = snd_hdsp_put_mixer \ + .info = snd_hdsp_info_pref_sync_ref, \ + .get = snd_hdsp_get_pref_sync_ref, \ + .put = snd_hdsp_put_pref_sync_ref \ } -static int snd_hdsp_info_mixer(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +static int hdsp_pref_sync_ref(hdsp_t *hdsp) { - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 3; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 65536; - uinfo->value.integer.step = 1; + /* Notice that this looks at the requested sync source, + not the one actually in use. + */ + + switch (hdsp->control_register & HDSP_SyncRefMask) { + case HDSP_SyncRef_ADAT1: + return HDSP_SYNC_FROM_ADAT1; + case HDSP_SyncRef_ADAT2: + return HDSP_SYNC_FROM_ADAT2; + case HDSP_SyncRef_ADAT3: + return HDSP_SYNC_FROM_ADAT3; + case HDSP_SyncRef_SPDIF: + return HDSP_SYNC_FROM_SPDIF; + case HDSP_SyncRef_WORD: + return HDSP_SYNC_FROM_WORD; + case HDSP_SyncRef_ADAT_SYNC: + return HDSP_SYNC_FROM_ADAT_SYNC; + default: + return HDSP_SYNC_FROM_WORD; + } return 0; } -static int snd_hdsp_get_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +static int hdsp_set_pref_sync_ref(hdsp_t *hdsp, int pref) +{ + hdsp->control_register &= ~HDSP_SyncRefMask; + switch (pref) { + case HDSP_SYNC_FROM_ADAT1: + hdsp->control_register &= ~HDSP_SyncRefMask; /* clear SyncRef bits */ + break; + case HDSP_SYNC_FROM_ADAT2: + hdsp->control_register |= HDSP_SyncRef_ADAT2; + break; + case HDSP_SYNC_FROM_ADAT3: + hdsp->control_register |= HDSP_SyncRef_ADAT3; + break; + case HDSP_SYNC_FROM_SPDIF: + hdsp->control_register |= HDSP_SyncRef_SPDIF; + break; + case HDSP_SYNC_FROM_WORD: + hdsp->control_register |= HDSP_SyncRef_WORD; + break; + case HDSP_SYNC_FROM_ADAT_SYNC: + hdsp->control_register |= HDSP_SyncRef_ADAT_SYNC; + break; + default: + return -1; + } + hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); + return 0; +} + +static int snd_hdsp_info_pref_sync_ref(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + static char *texts[] = {"Word", "IEC958", "ADAT1", "ADAT Sync", "ADAT2", "ADAT3" }; + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + + switch (hdsp->io_type) { + case Digiface: + case H9652: + uinfo->value.enumerated.items = 6; + break; + case Multiface: + uinfo->value.enumerated.items = 4; + break; + case H9632: + uinfo->value.enumerated.items = 3; + break; + default: + uinfo->value.enumerated.items = 0; + break; + } + + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_hdsp_get_pref_sync_ref(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = hdsp_pref_sync_ref(hdsp); + return 0; +} + +static int snd_hdsp_put_pref_sync_ref(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); unsigned long flags; - int source; - int destination; - int addr; + int change, max; + unsigned int val; + + if (!snd_hdsp_use_is_exclusive(hdsp)) + return -EBUSY; - source = ucontrol->value.integer.value[0]; - destination = ucontrol->value.integer.value[1]; + switch (hdsp->io_type) { + case Digiface: + case H9652: + max = 6; + break; + case Multiface: + max = 4; + break; + case H9632: + max = 3; + break; + default: + return -EIO; + } - if (source > 25) { - addr = hdsp_playback_to_output_key(hdsp,source-26,destination); - } else { - addr = hdsp_input_to_output_key(hdsp,source, destination); + val = ucontrol->value.enumerated.item[0] % max; + spin_lock_irqsave(&hdsp->lock, flags); + change = (int)val != hdsp_pref_sync_ref(hdsp); + hdsp_set_pref_sync_ref(hdsp, val); + spin_unlock_irqrestore(&hdsp->lock, flags); + return change; +} + +#define HDSP_AUTOSYNC_REF(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ, \ + .info = snd_hdsp_info_autosync_ref, \ + .get = snd_hdsp_get_autosync_ref, \ +} + +static int hdsp_autosync_ref(hdsp_t *hdsp) +{ + /* This looks at the autosync selected sync reference */ + unsigned int status2 = hdsp_read(hdsp, HDSP_status2Register); + + switch (status2 & HDSP_SelSyncRefMask) { + case HDSP_SelSyncRef_WORD: + return HDSP_AUTOSYNC_FROM_WORD; + case HDSP_SelSyncRef_ADAT_SYNC: + return HDSP_AUTOSYNC_FROM_ADAT_SYNC; + case HDSP_SelSyncRef_SPDIF: + return HDSP_AUTOSYNC_FROM_SPDIF; + case HDSP_SelSyncRefMask: + return HDSP_AUTOSYNC_FROM_NONE; + case HDSP_SelSyncRef_ADAT1: + return HDSP_AUTOSYNC_FROM_ADAT1; + case HDSP_SelSyncRef_ADAT2: + return HDSP_AUTOSYNC_FROM_ADAT2; + case HDSP_SelSyncRef_ADAT3: + return HDSP_AUTOSYNC_FROM_ADAT3; + default: + return HDSP_AUTOSYNC_FROM_WORD; } + return 0; +} + +static int snd_hdsp_info_autosync_ref(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + static char *texts[] = {"Word", "ADAT Sync", "IEC958", "None", "ADAT1", "ADAT2", "ADAT3" }; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 7; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_hdsp_get_autosync_ref(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = hdsp_pref_sync_ref(hdsp); + return 0; +} + +#define HDSP_PASSTHRU(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdsp_info_passthru, \ + .put = snd_hdsp_put_passthru, \ + .get = snd_hdsp_get_passthru \ +} + +static int snd_hdsp_info_passthru(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_hdsp_get_passthru(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + unsigned long flags; + spin_lock_irqsave(&hdsp->lock, flags); - ucontrol->value.integer.value[2] = hdsp_read_gain (hdsp, addr); + ucontrol->value.integer.value[0] = hdsp->passthru; spin_unlock_irqrestore(&hdsp->lock, flags); return 0; } -static int snd_hdsp_put_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +static int snd_hdsp_put_passthru(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); unsigned long flags; int change; - int source; - int destination; - int gain; - int addr; + unsigned int val; + int err = 0; if (!snd_hdsp_use_is_exclusive(hdsp)) return -EBUSY; - source = ucontrol->value.integer.value[0]; - destination = ucontrol->value.integer.value[1]; + val = ucontrol->value.integer.value[0] & 1; + spin_lock_irqsave(&hdsp->lock, flags); + change = (ucontrol->value.integer.value[0] != hdsp->passthru); + if (change) + err = hdsp_set_passthru(hdsp, val); + spin_unlock_irqrestore(&hdsp->lock, flags); + return err ? err : change; +} + +#define HDSP_LINE_OUT(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdsp_info_line_out, \ + .get = snd_hdsp_get_line_out, \ + .put = snd_hdsp_put_line_out \ +} - if (source > 25) { - addr = hdsp_playback_to_output_key(hdsp,source-26, destination); +static int hdsp_line_out(hdsp_t *hdsp) +{ + return (hdsp->control_register & HDSP_LineOut) ? 1 : 0; +} + +static int hdsp_set_line_output(hdsp_t *hdsp, int out) +{ + if (out) { + hdsp->control_register |= HDSP_LineOut; } else { - addr = hdsp_input_to_output_key(hdsp,source, destination); + hdsp->control_register &= ~HDSP_LineOut; } + hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); + return 0; +} - gain = ucontrol->value.integer.value[2]; +static int snd_hdsp_info_line_out(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_hdsp_get_line_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + unsigned long flags; + + spin_lock_irqsave(&hdsp->lock, flags); + ucontrol->value.integer.value[0] = hdsp_line_out(hdsp); + spin_unlock_irqrestore(&hdsp->lock, flags); + return 0; +} +static int snd_hdsp_put_line_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + unsigned long flags; + int change; + unsigned int val; + + if (!snd_hdsp_use_is_exclusive(hdsp)) + return -EBUSY; + val = ucontrol->value.integer.value[0] & 1; spin_lock_irqsave(&hdsp->lock, flags); - change = gain != hdsp_read_gain(hdsp, addr); - if (change) - hdsp_write_gain(hdsp, addr, gain); + change = (int)val != hdsp_line_out(hdsp); + hdsp_set_line_output(hdsp, val); spin_unlock_irqrestore(&hdsp->lock, flags); return change; } -/* The simple mixer control(s) provide gain control for the - basic 1:1 mappings of playback streams to output - streams. -*/ - -#define HDSP_PLAYBACK_MIXER \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE | \ +#define HDSP_MIXER(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ - .info = snd_hdsp_info_playback_mixer, \ - .get = snd_hdsp_get_playback_mixer, \ - .put = snd_hdsp_put_playback_mixer \ + .info = snd_hdsp_info_mixer, \ + .get = snd_hdsp_get_mixer, \ + .put = snd_hdsp_put_mixer \ } -static int snd_hdsp_info_playback_mixer(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +static int snd_hdsp_info_mixer(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; + uinfo->count = 3; uinfo->value.integer.min = 0; uinfo->value.integer.max = 65536; uinfo->value.integer.step = 1; return 0; } -static int snd_hdsp_get_playback_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +static int snd_hdsp_get_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); unsigned long flags; + int source; + int destination; int addr; - int channel; - int mapped_channel; - - channel = ucontrol->id.index - 1; - snd_assert(channel >= 0 || channel < HDSP_MAX_CHANNELS, return -EINVAL); - - if ((mapped_channel = hdsp->channel_map[channel]) < 0) { - return -EINVAL; + source = ucontrol->value.integer.value[0]; + destination = ucontrol->value.integer.value[1]; + + if (source >= hdsp->max_channels) { + addr = hdsp_playback_to_output_key(hdsp,source-hdsp->max_channels,destination); + } else { + addr = hdsp_input_to_output_key(hdsp,source, destination); } - - addr = hdsp_playback_to_output_key(hdsp,mapped_channel, mapped_channel); - + spin_lock_irqsave(&hdsp->lock, flags); - ucontrol->value.integer.value[0] = hdsp_read_gain (hdsp, addr); + ucontrol->value.integer.value[2] = hdsp_read_gain (hdsp, addr); spin_unlock_irqrestore(&hdsp->lock, flags); return 0; } -static int snd_hdsp_put_playback_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +static int snd_hdsp_put_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); unsigned long flags; int change; - int addr; - int channel; - int mapped_channel; + int source; + int destination; int gain; + int addr; if (!snd_hdsp_use_is_exclusive(hdsp)) return -EBUSY; - - channel = ucontrol->id.index - 1; - snd_assert(channel >= 0 || channel < HDSP_MAX_CHANNELS, return -EINVAL); - - if ((mapped_channel = hdsp->channel_map[channel]) < 0) { - return -EINVAL; - } + source = ucontrol->value.integer.value[0]; + destination = ucontrol->value.integer.value[1]; - addr = hdsp_playback_to_output_key(hdsp,mapped_channel, mapped_channel); - gain = ucontrol->value.integer.value[0]; + if (source >= hdsp->max_channels) { + addr = hdsp_playback_to_output_key(hdsp,source-hdsp->max_channels, destination); + } else { + addr = hdsp_input_to_output_key(hdsp,source, destination); + } + gain = ucontrol->value.integer.value[2]; spin_lock_irqsave(&hdsp->lock, flags); change = gain != hdsp_read_gain(hdsp, addr); @@ -2566,6 +3107,7 @@ static int snd_hdsp_get_adat_sync_check( return -EINVAL; break; case Multiface: + case H9632: if (offset >= 1) return -EINVAL; break; @@ -2577,6 +3119,13 @@ static int snd_hdsp_get_adat_sync_check( return 0; } +static snd_kcontrol_new_t snd_hdsp_9632_controls[] = { +HDSP_DA_GAIN("DA Gain", 0), +HDSP_AD_GAIN("AD Gain", 0), +HDSP_PHONE_GAIN("Phones Gain", 0), +HDSP_XLR_BREAKOUT_CABLE("XLR Breakout Cable", 0) +}; + static snd_kcontrol_new_t snd_hdsp_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -2637,34 +3186,14 @@ HDSP_LINE_OUT("Line Out", 0), #define HDSP_CONTROLS (sizeof(snd_hdsp_controls)/sizeof(snd_kcontrol_new_t)) -static snd_kcontrol_new_t snd_hdsp_playback_mixer = HDSP_PLAYBACK_MIXER; -static snd_kcontrol_new_t snd_hdsp_adat_sync_check = HDSP_ADAT_SYNC_CHECK; - - -static int hdsp_update_simple_mixer_controls(hdsp_t *hdsp) -{ - int i; - - for (i = hdsp->ds_channels; i < hdsp->ss_channels; ++i) { - if (hdsp->system_sample_rate > 48000) { - hdsp->playback_mixer_ctls[i]->vd[0].access = SNDRV_CTL_ELEM_ACCESS_INACTIVE | - SNDRV_CTL_ELEM_ACCESS_READ | - SNDRV_CTL_ELEM_ACCESS_VOLATILE; - } else { - hdsp->playback_mixer_ctls[i]->vd[0].access = SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_VOLATILE; - } - snd_ctl_notify(hdsp->card, SNDRV_CTL_EVENT_MASK_VALUE | - SNDRV_CTL_EVENT_MASK_INFO, &hdsp->playback_mixer_ctls[i]->id); - } - - return 0; -} +#define HDSP_9632_CONTROLS (sizeof(snd_hdsp_9632_controls)/sizeof(snd_kcontrol_new_t)) +static snd_kcontrol_new_t snd_hdsp_96xx_aeb = HDSP_AEB("Analog Extension Board", 0); +static snd_kcontrol_new_t snd_hdsp_adat_sync_check = HDSP_ADAT_SYNC_CHECK; int snd_hdsp_create_controls(snd_card_t *card, hdsp_t *hdsp) { - unsigned int idx, limit; + unsigned int idx; int err; snd_kcontrol_t *kctl; @@ -2676,38 +3205,8 @@ int snd_hdsp_create_controls(snd_card_t hdsp->spdif_ctl = kctl; } - snd_hdsp_playback_mixer.name = "Chn"; - snd_hdsp_adat_sync_check.name = "ADAT Lock Status"; - - switch (hdsp->io_type) { - case Digiface: - limit = DIGIFACE_SS_CHANNELS; - break; - case H9652: - limit = H9652_SS_CHANNELS; - break; - case Multiface: - limit = MULTIFACE_SS_CHANNELS; - break; - default: - return -EIO; - } - - /* The index values are one greater than the channel ID so that alsamixer - will display them correctly. We want to use the index for fast lookup - of the relevant channel, but if we use it at all, most ALSA software - does the wrong thing with it ... - */ - - for (idx = 0; idx < limit; ++idx) { - snd_hdsp_playback_mixer.index = idx+1; - if ((err = snd_ctl_add (card, kctl = snd_ctl_new1(&snd_hdsp_playback_mixer, hdsp)))) { - return err; - } - hdsp->playback_mixer_ctls[idx] = kctl; - } - /* ADAT SyncCheck status */ + snd_hdsp_adat_sync_check.name = "ADAT Lock Status"; snd_hdsp_adat_sync_check.index = 1; if ((err = snd_ctl_add (card, kctl = snd_ctl_new1(&snd_hdsp_adat_sync_check, hdsp)))) { return err; @@ -2720,6 +3219,22 @@ int snd_hdsp_create_controls(snd_card_t } } } + + /* DA, AD and Phone gain and XLR breakout cable controls for H9632 cards */ + if (hdsp->io_type == H9632) { + for (idx = 0; idx < HDSP_9632_CONTROLS; idx++) { + if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_9632_controls[idx], hdsp))) < 0) { + return err; + } + } + } + + /* AEB control for H96xx card */ + if (hdsp->io_type == H9632 || hdsp->io_type == H9652) { + if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_96xx_aeb, hdsp))) < 0) { + return err; + } + } return 0; } @@ -2812,6 +3327,15 @@ snd_hdsp_proc_read(snd_info_entry_t *ent case HDSP_CLOCK_SOURCE_INTERNAL_96KHZ: clock_source = "Internal 96 kHz"; break; + case HDSP_CLOCK_SOURCE_INTERNAL_128KHZ: + clock_source = "Internal 128 kHz"; + break; + case HDSP_CLOCK_SOURCE_INTERNAL_176_4KHZ: + clock_source = "Internal 176.4 kHz"; + break; + case HDSP_CLOCK_SOURCE_INTERNAL_192KHZ: + clock_source = "Internal 192 kHz"; + break; default: clock_source = "Error"; } @@ -2884,16 +3408,19 @@ snd_hdsp_proc_read(snd_info_entry_t *ent snd_iprintf(buffer, "\n"); - switch ((hdsp->control_register & HDSP_SPDIFInputMask) >> 14) { + switch (hdsp_spdif_in(hdsp)) { case HDSP_SPDIFIN_OPTICAL: - snd_iprintf(buffer, "IEC958 input: ADAT1\n"); + snd_iprintf(buffer, "IEC958 input: Optical\n"); break; case HDSP_SPDIFIN_COAXIAL: snd_iprintf(buffer, "IEC958 input: Coaxial\n"); break; - case HDSP_SPDIFIN_INTERN: + case HDSP_SPDIFIN_INTERNAL: snd_iprintf(buffer, "IEC958 input: Internal\n"); break; + case HDSP_SPDIFIN_AES: + snd_iprintf(buffer, "IEC958 input: AES\n"); + break; default: snd_iprintf(buffer, "IEC958 input: ???\n"); break; @@ -2980,13 +3507,60 @@ snd_hdsp_proc_read(snd_info_entry_t *ent } snd_iprintf(buffer, "\n"); + + /* Informations about H9632 specific controls */ + if (hdsp->io_type == H9632) { + char *tmp; + + switch (hdsp_ad_gain(hdsp)) { + case 0: + tmp = "-10 dBV"; + break; + case 1: + tmp = "+4 dBu"; + break; + default: + tmp = "Lo Gain"; + break; + } + snd_iprintf(buffer, "AD Gain : %s\n", tmp); -#if 0 - for (x = 0; x < 26; x++) { - unsigned int val = hdsp_read (hdsp, HDSP_inputPeakLevel + (4 * x)); - snd_iprintf (buffer, "%d: input peak = %d overs = %d\n", x, val&0xffffff00, val&0xf); + switch (hdsp_da_gain(hdsp)) { + case 0: + tmp = "Hi Gain"; + break; + case 1: + tmp = "+4 dBu"; + break; + default: + tmp = "-10 dBV"; + break; + } + snd_iprintf(buffer, "DA Gain : %s\n", tmp); + + switch (hdsp_phone_gain(hdsp)) { + case 0: + tmp = "0 dB"; + break; + case 1: + tmp = "-6 dB"; + break; + default: + tmp = "-12 dB"; + break; + } + snd_iprintf(buffer, "Phones Gain : %s\n", tmp); + + snd_iprintf(buffer, "XLR Breakout Cable : %s\n", hdsp_xlr_breakout_cable(hdsp) ? "yes" : "no"); + + if (hdsp->control_register & HDSP_AnalogExtensionBoard) { + snd_iprintf(buffer, "AEB : on (ADAT1 internal)\n"); + } else { + snd_iprintf(buffer, "AEB : off (ADAT1 external)\n"); + } + snd_iprintf(buffer, "\n"); } -#endif + } static void __devinit snd_hdsp_proc_init(hdsp_t *hdsp) @@ -2994,7 +3568,7 @@ static void __devinit snd_hdsp_proc_init snd_info_entry_t *entry; if (! snd_card_proc_new(hdsp->card, "hdsp", &entry)) - snd_info_set_text_ops(entry, hdsp, snd_hdsp_proc_read); + snd_info_set_text_ops(entry, hdsp, 1024, snd_hdsp_proc_read); } static void snd_hdsp_free_buffers(hdsp_t *hdsp) @@ -3078,8 +3652,21 @@ static int snd_hdsp_set_defaults(hdsp_t HDSP_SPDIFInputCoaxial | hdsp_encode_latency(7) | HDSP_LineOut; + hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); + +#ifdef SNDRV_BIG_ENDIAN + hdsp->control2_register = HDSP_BIGENDIAN_MODE; +#else + hdsp->control2_register = 0; +#endif + if (hdsp->io_type == H9652) { + snd_hdsp_9652_enable_mixer (hdsp); + } else { + hdsp_write (hdsp, HDSP_control2Reg, hdsp->control2_register); + } + hdsp_reset_hw_pointer(hdsp); hdsp_compute_period_size(hdsp); @@ -3089,7 +3676,7 @@ static int snd_hdsp_set_defaults(hdsp_t hdsp->mixer_matrix[i] = MINUS_INFINITY_GAIN; } - for (i = 0; i < (hdsp->io_type == H9652 ? 1352 : HDSP_MATRIX_MIXER_SIZE); i++) { + for (i = 0; i < ((hdsp->io_type == H9652 || hdsp->io_type == H9632) ? 1352 : HDSP_MATRIX_MIXER_SIZE); ++i) { if (hdsp_write_gain (hdsp, i, MINUS_INFINITY_GAIN)) { return -EIO; } @@ -3097,21 +3684,30 @@ static int snd_hdsp_set_defaults(hdsp_t if ((hdsp->io_type != H9652) && line_outs_monitor[hdsp->dev]) { + int lineouts_base; + snd_printk ("sending all inputs and playback streams to line outs.\n"); /* route all inputs to the line outs for easy monitoring. send odd numbered channels to right, even to left. */ + if (hdsp->io_type == H9632) { + /* this is the phones/analog output */ + lineouts_base = 10; + } else { + lineouts_base = 26; + } - for (i = 0; i < HDSP_MAX_CHANNELS; i++) { + for (i = 0; i < hdsp->max_channels; i++) { if (i & 1) { - if (hdsp_write_gain (hdsp, hdsp_input_to_output_key (hdsp, i, 26), UNITY_GAIN) || - hdsp_write_gain (hdsp, hdsp_playback_to_output_key (hdsp, i, 26), UNITY_GAIN)) { + if (hdsp_write_gain (hdsp, hdsp_input_to_output_key (hdsp, i, lineouts_base), UNITY_GAIN) || + hdsp_write_gain (hdsp, hdsp_playback_to_output_key (hdsp, i, lineouts_base), UNITY_GAIN)) { return -EIO; } } else { - if (hdsp_write_gain (hdsp, hdsp_input_to_output_key (hdsp, i, 27), UNITY_GAIN) || - hdsp_write_gain (hdsp, hdsp_playback_to_output_key (hdsp, i, 27), UNITY_GAIN)) { + if (hdsp_write_gain (hdsp, hdsp_input_to_output_key (hdsp, i, lineouts_base+1), UNITY_GAIN) || + hdsp_write_gain (hdsp, hdsp_playback_to_output_key (hdsp, i, lineouts_base+1), UNITY_GAIN)) { + return -EIO; } } @@ -3120,6 +3716,12 @@ static int snd_hdsp_set_defaults(hdsp_t hdsp->passthru = 0; + /* H9632 specific defaults */ + if (hdsp->io_type == H9632) { + hdsp->control_register |= (HDSP_DAGainPlus4dBu | HDSP_ADGainPlus4dBu | HDSP_PhoneGain0dB); + hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); + } + /* set a default rate so that the channel map is set up. */ @@ -3208,7 +3810,7 @@ static char *hdsp_channel_buffer_locatio { int mapped_channel; - snd_assert(channel >= 0 || channel < HDSP_MAX_CHANNELS, return NULL); + snd_assert(channel >= 0 || channel < hdsp->max_channels, return NULL); if ((mapped_channel = hdsp->channel_map[channel]) < 0) { return NULL; @@ -3378,7 +3980,7 @@ static int snd_hdsp_channel_info(snd_pcm hdsp_t *hdsp = _snd_pcm_substream_chip(substream); int mapped_channel; - snd_assert(info->channel < HDSP_MAX_CHANNELS, return -EINVAL); + snd_assert(info->channel < hdsp->max_channels, return -EINVAL); if ((mapped_channel = hdsp->channel_map[info->channel]) < 0) { return -EINVAL; @@ -3567,42 +4169,118 @@ static snd_pcm_hardware_t snd_hdsp_captu .fifo_size = 0 }; -static unsigned int period_sizes[] = { 64, 128, 256, 512, 1024, 2048, 4096, 8192 }; +static unsigned int hdsp_period_sizes[] = { 64, 128, 256, 512, 1024, 2048, 4096, 8192 }; + +#define HDSP_PERIOD_SIZES sizeof(hdsp_period_sizes) / sizeof(hdsp_period_sizes[0]) + +static snd_pcm_hw_constraint_list_t hdsp_hw_constraints_period_sizes = { + .count = HDSP_PERIOD_SIZES, + .list = hdsp_period_sizes, + .mask = 0 +}; + +static unsigned int hdsp_9632_sample_rates[] = { 32000, 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000 }; -#define PERIOD_SIZES sizeof(period_sizes) / sizeof(period_sizes[0]) +#define HDSP_9632_SAMPLE_RATES sizeof(hdsp_9632_sample_rates) / sizeof(hdsp_9632_sample_rates[0]) -static snd_pcm_hw_constraint_list_t hw_constraints_period_sizes = { - .count = PERIOD_SIZES, - .list = period_sizes, +static snd_pcm_hw_constraint_list_t hdsp_hw_constraints_9632_sample_rates = { + .count = HDSP_9632_SAMPLE_RATES, + .list = hdsp_9632_sample_rates, .mask = 0 }; -static int snd_hdsp_hw_rule_channels(snd_pcm_hw_params_t *params, +static int snd_hdsp_hw_rule_in_channels(snd_pcm_hw_params_t *params, + snd_pcm_hw_rule_t *rule) +{ + hdsp_t *hdsp = rule->private; + snd_interval_t *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + if (hdsp->io_type == H9632) { + unsigned int list[3]; + list[0] = hdsp->qs_in_channels; + list[1] = hdsp->ds_in_channels; + list[2] = hdsp->ss_in_channels; + return snd_interval_list(c, 3, list, 0); + } else { + unsigned int list[2]; + list[0] = hdsp->ds_in_channels; + list[1] = hdsp->ss_in_channels; + return snd_interval_list(c, 2, list, 0); + } +} + +static int snd_hdsp_hw_rule_out_channels(snd_pcm_hw_params_t *params, snd_pcm_hw_rule_t *rule) { + unsigned int list[3]; hdsp_t *hdsp = rule->private; snd_interval_t *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - unsigned int list[2] = { hdsp->ds_channels, hdsp->ss_channels }; + if (hdsp->io_type == H9632) { + list[0] = hdsp->qs_out_channels; + list[1] = hdsp->ds_out_channels; + list[2] = hdsp->ss_out_channels; + return snd_interval_list(c, 3, list, 0); + } else { + list[0] = hdsp->ds_out_channels; + list[1] = hdsp->ss_out_channels; + } return snd_interval_list(c, 2, list, 0); } -static int snd_hdsp_hw_rule_channels_rate(snd_pcm_hw_params_t *params, +static int snd_hdsp_hw_rule_in_channels_rate(snd_pcm_hw_params_t *params, + snd_pcm_hw_rule_t *rule) +{ + hdsp_t *hdsp = rule->private; + snd_interval_t *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + snd_interval_t *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + if (r->min > 96000 && hdsp->io_type == H9632) { + snd_interval_t t = { + .min = hdsp->qs_in_channels, + .max = hdsp->qs_in_channels, + .integer = 1, + }; + return snd_interval_refine(c, &t); + } else if (r->min > 48000 && r->max <= 96000) { + snd_interval_t t = { + .min = hdsp->ds_in_channels, + .max = hdsp->ds_in_channels, + .integer = 1, + }; + return snd_interval_refine(c, &t); + } else if (r->max < 64000) { + snd_interval_t t = { + .min = hdsp->ss_in_channels, + .max = hdsp->ss_in_channels, + .integer = 1, + }; + return snd_interval_refine(c, &t); + } + return 0; +} + +static int snd_hdsp_hw_rule_out_channels_rate(snd_pcm_hw_params_t *params, snd_pcm_hw_rule_t *rule) { hdsp_t *hdsp = rule->private; snd_interval_t *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); snd_interval_t *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); - if (r->min > 48000) { + if (r->min > 96000 && hdsp->io_type == H9632) { + snd_interval_t t = { + .min = hdsp->qs_out_channels, + .max = hdsp->qs_out_channels, + .integer = 1, + }; + return snd_interval_refine(c, &t); + } else if (r->min > 48000 && r->max <= 96000) { snd_interval_t t = { - .min = hdsp->ds_channels, - .max = hdsp->ds_channels, + .min = hdsp->ds_out_channels, + .max = hdsp->ds_out_channels, .integer = 1, }; return snd_interval_refine(c, &t); } else if (r->max < 64000) { snd_interval_t t = { - .min = hdsp->ss_channels, - .max = hdsp->ss_channels, + .min = hdsp->ss_out_channels, + .max = hdsp->ss_out_channels, .integer = 1, }; return snd_interval_refine(c, &t); @@ -3610,20 +4288,58 @@ static int snd_hdsp_hw_rule_channels_rat return 0; } -static int snd_hdsp_hw_rule_rate_channels(snd_pcm_hw_params_t *params, +static int snd_hdsp_hw_rule_rate_out_channels(snd_pcm_hw_params_t *params, + snd_pcm_hw_rule_t *rule) +{ + hdsp_t *hdsp = rule->private; + snd_interval_t *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + snd_interval_t *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + if (c->min >= hdsp->ss_out_channels) { + snd_interval_t t = { + .min = 32000, + .max = 48000, + .integer = 1, + }; + return snd_interval_refine(r, &t); + } else if (c->max <= hdsp->qs_out_channels && hdsp->io_type == H9632) { + snd_interval_t t = { + .min = 128000, + .max = 192000, + .integer = 1, + }; + return snd_interval_refine(r, &t); + } else if (c->max <= hdsp->ds_out_channels) { + snd_interval_t t = { + .min = 64000, + .max = 96000, + .integer = 1, + }; + return snd_interval_refine(r, &t); + } + return 0; +} + +static int snd_hdsp_hw_rule_rate_in_channels(snd_pcm_hw_params_t *params, snd_pcm_hw_rule_t *rule) { hdsp_t *hdsp = rule->private; snd_interval_t *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); snd_interval_t *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); - if (c->min >= hdsp->ss_channels) { + if (c->min >= hdsp->ss_in_channels) { snd_interval_t t = { .min = 32000, .max = 48000, .integer = 1, }; return snd_interval_refine(r, &t); - } else if (c->max <= hdsp->ds_channels) { + } else if (c->max <= hdsp->qs_in_channels && hdsp->io_type == H9632) { + snd_interval_t t = { + .min = 128000, + .max = 192000, + .integer = 1, + }; + return snd_interval_refine(r, &t); + } else if (c->max <= hdsp->ds_in_channels) { snd_interval_t t = { .min = 64000, .max = 96000, @@ -3674,15 +4390,23 @@ static int snd_hdsp_playback_open(snd_pc spin_unlock_irqrestore(&hdsp->lock, flags); snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hw_constraints_period_sizes); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hdsp_hw_constraints_period_sizes); + if (hdsp->io_type == H9632) { + runtime->hw.channels_min = hdsp->qs_out_channels; + runtime->hw.channels_max = hdsp->ss_out_channels; + runtime->hw.rate_max = 192000; + runtime->hw.rates = SNDRV_PCM_RATE_KNOT; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hdsp_hw_constraints_9632_sample_rates); + } + snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - snd_hdsp_hw_rule_channels, hdsp, + snd_hdsp_hw_rule_out_channels, hdsp, SNDRV_PCM_HW_PARAM_CHANNELS, -1); snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - snd_hdsp_hw_rule_channels_rate, hdsp, + snd_hdsp_hw_rule_out_channels_rate, hdsp, SNDRV_PCM_HW_PARAM_RATE, -1); snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - snd_hdsp_hw_rule_rate_channels, hdsp, + snd_hdsp_hw_rule_rate_out_channels, hdsp, SNDRV_PCM_HW_PARAM_CHANNELS, -1); hdsp->creg_spdif_stream = hdsp->creg_spdif; @@ -3751,15 +4475,22 @@ static int snd_hdsp_capture_open(snd_pcm spin_unlock_irqrestore(&hdsp->lock, flags); snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hw_constraints_period_sizes); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hdsp_hw_constraints_period_sizes); + if (hdsp->io_type == H9632) { + runtime->hw.channels_min = hdsp->qs_in_channels; + runtime->hw.channels_max = hdsp->ss_in_channels; + runtime->hw.rate_max = 192000; + runtime->hw.rates = SNDRV_PCM_RATE_KNOT; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hdsp_hw_constraints_9632_sample_rates); + } snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - snd_hdsp_hw_rule_channels, hdsp, + snd_hdsp_hw_rule_in_channels, hdsp, SNDRV_PCM_HW_PARAM_CHANNELS, -1); snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - snd_hdsp_hw_rule_channels_rate, hdsp, + snd_hdsp_hw_rule_in_channels_rate, hdsp, SNDRV_PCM_HW_PARAM_RATE, -1); snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - snd_hdsp_hw_rule_rate_channels, hdsp, + snd_hdsp_hw_rule_rate_in_channels, hdsp, SNDRV_PCM_HW_PARAM_CHANNELS, -1); return 0; } @@ -3780,42 +4511,117 @@ static int snd_hdsp_capture_release(snd_ static int snd_hdsp_hwdep_dummy_op(snd_hwdep_t *hw, struct file *file) { - /* we have nothing to initialize but the call is required */ - return 0; + /* we have nothing to initialize but the call is required */ + return 0; } static int snd_hdsp_hwdep_ioctl(snd_hwdep_t *hw, struct file *file, unsigned int cmd, unsigned long arg) { hdsp_t *hdsp = (hdsp_t *)hw->private_data; - + switch (cmd) { case SNDRV_HDSP_IOCTL_GET_PEAK_RMS: { hdsp_peak_rms_t *peak_rms; - + int i; + if (hdsp->io_type == H9652) { - snd_printk("hardware metering isn't supported yet for hdsp9652 cards\n"); - return -EINVAL; + unsigned long rms_low, rms_high; + int doublespeed = 0; + if (hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DoubleSpeedStatus) + doublespeed = 1; + peak_rms = (hdsp_peak_rms_t *)arg; + for (i = 0; i < 26; ++i) { + if (!(doublespeed && (i & 4))) { + if (copy_to_user_fromio((void *)peak_rms->input_peaks+i*4, hdsp->iobase+HDSP_9652_peakBase-i*4, 4) != 0) + return -EFAULT; + if (copy_to_user_fromio((void *)peak_rms->playback_peaks+i*4, hdsp->iobase+HDSP_9652_peakBase-(doublespeed ? 14 : 26)*4-i*4, 4) != 0) + return -EFAULT; + if (copy_to_user_fromio((void *)peak_rms->output_peaks+i*4, hdsp->iobase+HDSP_9652_peakBase-2*(doublespeed ? 14 : 26)*4-i*4, 4) != 0) + return -EFAULT; + rms_low = *(u32 *)(hdsp->iobase+HDSP_9652_rmsBase+i*8) & 0xFFFFFF00; + rms_high = *(u32 *)(hdsp->iobase+HDSP_9652_rmsBase+i*8+4) & 0xFFFFFF00; + rms_high += (rms_low >> 24); + rms_low <<= 8; + if (copy_to_user((void *)peak_rms->input_rms+i*8, &rms_low, 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->input_rms+i*8+4, &rms_high, 4) != 0) + return -EFAULT; + rms_low = *(u32 *)(hdsp->iobase+HDSP_9652_rmsBase+(doublespeed ? 14 : 26)*8+i*8) & 0xFFFFFF00; + rms_high = *(u32 *)(hdsp->iobase+HDSP_9652_rmsBase+(doublespeed ? 14 : 26)*8+i*8+4) & 0xFFFFFF00; + rms_high += (rms_low >> 24); + rms_low <<= 8; + if (copy_to_user((void *)peak_rms->playback_rms+i*8, &rms_low, 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->playback_rms+i*8+4, &rms_high, 4) != 0) + return -EFAULT; + rms_low = *(u32 *)(hdsp->iobase+HDSP_9652_rmsBase+2*(doublespeed ? 14 : 26)*8+i*8) & 0xFFFFFF00; + rms_high = *(u32 *)(hdsp->iobase+HDSP_9652_rmsBase+2*(doublespeed ? 14 : 26)*8+i*8+4) & 0xFFFFFF00; + rms_high += (rms_low >> 24); + rms_low <<= 8; + if (copy_to_user((void *)peak_rms->output_rms+i*8, &rms_low, 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->output_rms+i*8+4, &rms_high, 4) != 0) + return -EFAULT; + } + } + return 0; + } + if (hdsp->io_type == H9632) { + int j; + hdsp_9632_meters_t *m; + int doublespeed = 0; + if (hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DoubleSpeedStatus) + doublespeed = 1; + m = (hdsp_9632_meters_t *)(hdsp->iobase+HDSP_9632_metersBase); + peak_rms = (hdsp_peak_rms_t *)arg; + for (i = 0, j = 0; i < 16; ++i, ++j) { + if (copy_to_user((void *)peak_rms->input_peaks+i*4, &(m->input_peak[j]), 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->playback_peaks+i*4, &(m->playback_peak[j]), 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->output_peaks+i*4, &(m->output_peak[j]), 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->input_rms+i*8, &(m->input_rms_low[j]), 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->playback_rms+i*8, &(m->playback_rms_low[j]), 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->output_rms+i*8, &(m->output_rms_low[j]), 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->input_rms+i*8+4, &(m->input_rms_high[j]), 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->playback_rms+i*8+4, &(m->playback_rms_high[j]), 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->output_rms+i*8+4, &(m->output_rms_high[j]), 4) != 0) + return -EFAULT; + if (doublespeed && i == 3) i += 4; + } + return 0; } if (!(hdsp->state & HDSP_FirmwareLoaded)) { snd_printk("firmware needs to be uploaded to the card.\n"); return -EINVAL; } peak_rms = (hdsp_peak_rms_t *)arg; - if (copy_to_user_fromio((void *)peak_rms->playback_peaks, hdsp->iobase+HDSP_playbackPeakLevel, 26*4) != 0) { - return -EFAULT; - } - if (copy_to_user_fromio((void *)peak_rms->input_peaks, hdsp->iobase+HDSP_inputPeakLevel, 26*4) != 0) { - return -EFAULT; - } - if (copy_to_user_fromio((void *)peak_rms->output_peaks, hdsp->iobase+HDSP_outputPeakLevel, 28*4) != 0) { - return -EFAULT; - } - if (copy_to_user_fromio((void *)peak_rms->playback_rms, hdsp->iobase+HDSP_playbackRmsLevel, 26*8) != 0) { - return -EFAULT; - } - if (copy_to_user_fromio((void *)peak_rms->input_rms, hdsp->iobase+HDSP_inputRmsLevel, 26*8) != 0) { - return -EFAULT; + for (i = 0; i < 26; ++i) { + if (copy_to_user((void *)peak_rms->playback_peaks+i*4, (void *)hdsp->iobase+HDSP_playbackPeakLevel+i*4, 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->input_peaks+i*4, (void *)hdsp->iobase+HDSP_inputPeakLevel+i*4, 4) != 0) + return -EFAULT; + } + for (i = 0; i < 26; ++i) { + if (copy_to_user((void *)peak_rms->playback_rms+i*8+4, (void *)hdsp->iobase+HDSP_playbackRmsLevel+i*8, 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->playback_rms+i*8, (void *)hdsp->iobase+HDSP_playbackRmsLevel+i*8+4, 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->input_rms+i*8+4, (void *)hdsp->iobase+HDSP_inputRmsLevel+i*8, 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->input_rms+i*8, (void *)hdsp->iobase+HDSP_inputRmsLevel+i*8+4, 4) != 0) + return -EFAULT; + } + for (i = 0; i < 28; ++i) { + if (copy_to_user((void *)peak_rms->output_peaks+i*4, (void *)hdsp->iobase+HDSP_outputPeakLevel+i*4, 4) != 0) + return -EFAULT; } break; } @@ -3823,7 +4629,7 @@ static int snd_hdsp_hwdep_ioctl(snd_hwde hdsp_config_info_t info; unsigned long flags; int i; - + if (!(hdsp->state & HDSP_FirmwareLoaded)) { snd_printk("Firmware needs to be uploaded to the card.\n"); return -EINVAL; @@ -3831,9 +4637,11 @@ static int snd_hdsp_hwdep_ioctl(snd_hwde spin_lock_irqsave(&hdsp->lock, flags); info.pref_sync_ref = (unsigned char)hdsp_pref_sync_ref(hdsp); info.wordclock_sync_check = (unsigned char)hdsp_wc_sync_check(hdsp); - info.adatsync_sync_check = (unsigned char)hdsp_adatsync_sync_check(hdsp); + if (hdsp->io_type != H9632) { + info.adatsync_sync_check = (unsigned char)hdsp_adatsync_sync_check(hdsp); + } info.spdif_sync_check = (unsigned char)hdsp_spdif_sync_check(hdsp); - for (i = 0; i < ((hdsp->io_type != Multiface) ? 3 : 1); ++i) { + for (i = 0; i < ((hdsp->io_type != Multiface && hdsp->io_type != H9632) ? 3 : 1); ++i) { info.adat_sync_check[i] = (unsigned char)hdsp_adat_sync_check(hdsp, i); } info.spdif_in = (unsigned char)hdsp_spdif_in(hdsp); @@ -3849,16 +4657,36 @@ static int snd_hdsp_hwdep_ioctl(snd_hwde info.autosync_ref = (unsigned char)hdsp_autosync_ref(hdsp); info.line_out = (unsigned char)hdsp_line_out(hdsp); info.passthru = (unsigned char)hdsp->passthru; + if (hdsp->io_type == H9632) { + info.da_gain = (unsigned char)hdsp_da_gain(hdsp); + info.ad_gain = (unsigned char)hdsp_ad_gain(hdsp); + info.phone_gain = (unsigned char)hdsp_phone_gain(hdsp); + info.xlr_breakout_cable = (unsigned char)hdsp_xlr_breakout_cable(hdsp); + + } + if (hdsp->io_type == H9632 || hdsp->io_type == H9652) { + info.analog_extension_board = (unsigned char)hdsp_aeb(hdsp); + } spin_unlock_irqrestore(&hdsp->lock, flags); if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; break; } + case SNDRV_HDSP_IOCTL_GET_9632_AEB: { + hdsp_9632_aeb_t h9632_aeb; + + if (hdsp->io_type != H9632) return -EINVAL; + h9632_aeb.aebi = hdsp->ss_in_channels - H9632_SS_CHANNELS; + h9632_aeb.aebo = hdsp->ss_out_channels - H9632_SS_CHANNELS; + if (copy_to_user((void *)arg, &h9632_aeb, sizeof(h9632_aeb))) + return -EFAULT; + break; + } case SNDRV_HDSP_IOCTL_GET_VERSION: { hdsp_version_t hdsp_version; int err; - - if (hdsp->io_type == H9652) return -EINVAL; + + if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return -EINVAL; if (hdsp->io_type == Undefined) { if ((err = hdsp_get_iobox_version(hdsp)) < 0) { return err; @@ -3875,17 +4703,18 @@ static int snd_hdsp_hwdep_ioctl(snd_hwde hdsp_firmware_t *firmware; unsigned long *firmware_data; int err; - - if (hdsp->io_type == H9652) return -EINVAL; + + if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return -EINVAL; /* SNDRV_HDSP_IOCTL_GET_VERSION must have been called */ if (hdsp->io_type == Undefined) return -EINVAL; snd_printk("initializing firmware upload\n"); firmware = (hdsp_firmware_t *)arg; + if (get_user(firmware_data, &firmware->firmware_data)) { return -EFAULT; } - + if (hdsp_check_for_iobox (hdsp)) { return -EIO; } @@ -3900,7 +4729,6 @@ static int snd_hdsp_hwdep_ioctl(snd_hwde return err; } - if (!(hdsp->state & HDSP_InitializationComplete)) { snd_hdsp_initialize_channels(hdsp); @@ -3914,8 +4742,8 @@ static int snd_hdsp_hwdep_ioctl(snd_hwde break; } case SNDRV_HDSP_IOCTL_GET_MIXER: { - hdsp_mixer_t *mixer; - + hdsp_mixer_t *mixer; + mixer = (hdsp_mixer_t *)arg; if (copy_to_user(mixer->matrix, hdsp->mixer_matrix, sizeof(unsigned short)*HDSP_MATRIX_MIXER_SIZE)) return -EFAULT; @@ -4011,7 +4839,7 @@ static inline int snd_hdsp_enable_io (hd return -EIO; } - for (i = 0; i < HDSP_MAX_CHANNELS; ++i) { + for (i = 0; i < hdsp->max_channels; ++i) { hdsp_write (hdsp, HDSP_inputEnable + (4 * i), 1); hdsp_write (hdsp, HDSP_outputEnable + (4 * i), 1); } @@ -4021,24 +4849,41 @@ static inline int snd_hdsp_enable_io (hd static inline void snd_hdsp_initialize_channels(hdsp_t *hdsp) { + int status, aebi_channels, aebo_channels; + switch (hdsp->io_type) { case Digiface: hdsp->card_name = "RME Hammerfall DSP + Digiface"; - hdsp->ss_channels = DIGIFACE_SS_CHANNELS; - hdsp->ds_channels = DIGIFACE_DS_CHANNELS; + hdsp->ss_in_channels = hdsp->ss_out_channels = DIGIFACE_SS_CHANNELS; + hdsp->ds_in_channels = hdsp->ds_out_channels = DIGIFACE_DS_CHANNELS; break; case H9652: hdsp->card_name = "RME Hammerfall HDSP 9652"; - hdsp->ss_channels = H9652_SS_CHANNELS; - hdsp->ds_channels = H9652_DS_CHANNELS; + hdsp->ss_in_channels = hdsp->ss_out_channels = H9652_SS_CHANNELS; + hdsp->ds_in_channels = hdsp->ds_out_channels = H9652_DS_CHANNELS; + break; + + case H9632: + status = hdsp_read(hdsp, HDSP_statusRegister); + /* HDSP_AEBx bits are low when AEB are connected */ + aebi_channels = (status & HDSP_AEBI) ? 0 : 4; + aebo_channels = (status & HDSP_AEBO) ? 0 : 4; + hdsp->card_name = "RME Hammerfall HDSP 9632"; + hdsp->ss_in_channels = H9632_SS_CHANNELS+aebi_channels; + hdsp->ds_in_channels = H9632_DS_CHANNELS+aebi_channels; + hdsp->qs_in_channels = H9632_QS_CHANNELS+aebi_channels; + hdsp->ss_out_channels = H9632_SS_CHANNELS+aebo_channels; + hdsp->ds_out_channels = H9632_DS_CHANNELS+aebo_channels; + hdsp->qs_out_channels = H9632_QS_CHANNELS+aebo_channels; break; case Multiface: hdsp->card_name = "RME Hammerfall DSP + Multiface"; - hdsp->ss_channels = MULTIFACE_SS_CHANNELS; - hdsp->ds_channels = MULTIFACE_DS_CHANNELS; - + hdsp->ss_in_channels = hdsp->ss_out_channels = MULTIFACE_SS_CHANNELS; + hdsp->ds_in_channels = hdsp->ds_out_channels = MULTIFACE_DS_CHANNELS; + break; + default: /* should never get here */ break; @@ -4056,38 +4901,40 @@ static int __devinit snd_hdsp_create_als int err; if ((err = snd_hdsp_create_pcm(card, hdsp)) < 0) { + snd_printk("Error creating pcm interface\n"); return err; } + if ((err = snd_hdsp_create_midi(card, hdsp, 0)) < 0) { + snd_printk("Error creating first midi interface\n"); return err; } + if ((err = snd_hdsp_create_midi(card, hdsp, 1)) < 0) { + snd_printk("Error creating second midi interface\n"); return err; } if ((err = snd_hdsp_create_controls(card, hdsp)) < 0) { + snd_printk("Error creating ctl interface\n"); return err; } snd_hdsp_proc_init(hdsp); - hdsp->last_spdif_sample_rate = -1; hdsp->system_sample_rate = -1; - hdsp->last_external_sample_rate = -1; - hdsp->last_internal_sample_rate = -1; hdsp->playback_pid = -1; hdsp->capture_pid = -1; hdsp->capture_substream = NULL; hdsp->playback_substream = NULL; if ((err = snd_hdsp_set_defaults(hdsp)) < 0) { + snd_printk("Error setting default values\n"); return err; } - hdsp_update_simple_mixer_controls(hdsp); - if (!(hdsp->state & HDSP_InitializationComplete)) { sprintf(card->longname, "%s at 0x%lx, irq %d", hdsp->card_name, hdsp->port, hdsp->irq); @@ -4108,8 +4955,8 @@ static int __devinit snd_hdsp_create(snd { struct pci_dev *pci = hdsp->pci; int err; - int i; int is_9652 = 0; + int is_9632 = 0; hdsp->irq = -1; hdsp->state = 0; @@ -4123,9 +4970,10 @@ static int __devinit snd_hdsp_create(snd spin_lock_init(&hdsp->midi[1].lock); hdsp->iobase = 0; hdsp->res_port = 0; + hdsp->control_register = 0; + hdsp->control2_register = 0; hdsp->io_type = Undefined; - for (i = 0; i < HDSP_MAX_CHANNELS; ++i) - hdsp->playback_mixer_ctls[i] = 0; + hdsp->max_channels = 26; hdsp->card = card; @@ -4150,7 +4998,11 @@ static int __devinit snd_hdsp_create(snd hdsp->card_name = "RME HDSP 9652"; is_9652 = 1; break; - + case 0x96: + hdsp->card_name = "RME HDSP 9632"; + hdsp->max_channels = 16; + is_9632 = 1; + break; default: return -ENODEV; } @@ -4185,7 +5037,7 @@ static int __devinit snd_hdsp_create(snd return err; } - if (!is_9652 && hdsp_check_for_iobox (hdsp)) { + if (!is_9652 && !is_9632 && hdsp_check_for_iobox (hdsp)) { /* no iobox connected, we defer initialization */ snd_printk("card initialization pending : waiting for firmware\n"); if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0) { @@ -4216,7 +5068,10 @@ static int __devinit snd_hdsp_create(snd if (is_9652) { hdsp->io_type = H9652; - snd_hdsp_9652_enable_mixer (hdsp); + } + + if (is_9632) { + hdsp->io_type = H9632; } if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0) { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/rme9652/rme9652.c 830-ivtv/sound/pci/rme9652/rme9652.c --- 000-virgin/sound/pci/rme9652/rme9652.c Wed Aug 13 20:24:37 2003 +++ 830-ivtv/sound/pci/rme9652/rme9652.c Thu Jan 8 10:26:51 2004 @@ -1835,7 +1835,7 @@ static void __devinit snd_rme9652_proc_i snd_info_entry_t *entry; if (! snd_card_proc_new(rme9652->card, "rme9652", &entry)) - snd_info_set_text_ops(entry, rme9652, snd_rme9652_proc_read); + snd_info_set_text_ops(entry, rme9652, 1024, snd_rme9652_proc_read); } static void snd_rme9652_free_buffers(rme9652_t *rme9652) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/sonicvibes.c 830-ivtv/sound/pci/sonicvibes.c --- 000-virgin/sound/pci/sonicvibes.c Tue Sep 2 09:56:05 2003 +++ 830-ivtv/sound/pci/sonicvibes.c Thu Jan 8 10:26:51 2004 @@ -1177,7 +1177,7 @@ static void __devinit snd_sonicvibes_pro snd_info_entry_t *entry; if (! snd_card_proc_new(sonic->card, "sonicvibes", &entry)) - snd_info_set_text_ops(entry, sonic, snd_sonicvibes_proc_read); + snd_info_set_text_ops(entry, sonic, 1024, snd_sonicvibes_proc_read); } /* @@ -1253,7 +1253,7 @@ static int __devinit snd_sonicvibes_crea snd_printk("architecture does not support 24bit PCI busmaster DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x00ffffff); + pci_set_consistent_dma_mask(pci, 0x00ffffff); sonic = snd_magic_kcalloc(sonicvibes_t, 0, GFP_KERNEL); if (sonic == NULL) diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/trident/trident_main.c 830-ivtv/sound/pci/trident/trident_main.c --- 000-virgin/sound/pci/trident/trident_main.c Mon Nov 17 18:29:01 2003 +++ 830-ivtv/sound/pci/trident/trident_main.c Thu Jan 8 10:26:51 2004 @@ -2955,6 +2955,7 @@ static int snd_trident_pcm_mixer_free(tr static int __devinit snd_trident_mixer(trident_t * trident, int pcm_spdif_device) { + ac97_bus_t _bus; ac97_t _ac97; snd_card_t * card = trident->card; snd_kcontrol_t *kctl; @@ -2965,14 +2966,18 @@ static int __devinit snd_trident_mixer(t if (!uctl) return -ENOMEM; + memset(&_bus, 0, sizeof(_bus)); + _bus.write = snd_trident_codec_write; + _bus.read = snd_trident_codec_read; + if ((err = snd_ac97_bus(trident->card, &_bus, &trident->ac97_bus)) < 0) + goto __out; + memset(&_ac97, 0, sizeof(_ac97)); - _ac97.write = snd_trident_codec_write; - _ac97.read = snd_trident_codec_read; _ac97.private_data = trident; trident->ac97_detect = 1; __again: - if ((err = snd_ac97_mixer(trident->card, &_ac97, &trident->ac97)) < 0) { + if ((err = snd_ac97_mixer(trident->ac97_bus, &_ac97, &trident->ac97)) < 0) { if (trident->device == TRIDENT_DEVICE_ID_SI7018) { if ((err = snd_trident_sis_reset(trident)) < 0) goto __out; @@ -2987,7 +2992,7 @@ static int __devinit snd_trident_mixer(t if (trident->device == TRIDENT_DEVICE_ID_SI7018 && (inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)) & SI_AC97_PRIMARY_READY) != 0) { _ac97.num = 1; - err = snd_ac97_mixer(trident->card, &_ac97, &trident->ac97_sec); + err = snd_ac97_mixer(trident->ac97_bus, &_ac97, &trident->ac97_sec); if (err < 0) snd_printk("SI7018: the secondary codec - invalid access\n"); #if 0 // only for my testing purpose --jk @@ -3295,7 +3300,7 @@ static void __devinit snd_trident_proc_i if (trident->device == TRIDENT_DEVICE_ID_SI7018) s = "sis7018"; if (! snd_card_proc_new(trident->card, s, &entry)) - snd_info_set_text_ops(entry, trident, snd_trident_proc_read); + snd_info_set_text_ops(entry, trident, 1024, snd_trident_proc_read); } static int snd_trident_dev_free(snd_device_t *device) @@ -3522,7 +3527,7 @@ int __devinit snd_trident_create(snd_car snd_printk("architecture does not support 30bit PCI busmaster DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x3fffffff); + pci_set_consistent_dma_mask(pci, 0x3fffffff); trident = snd_magic_kcalloc(trident_t, 0, GFP_KERNEL); if (trident == NULL) @@ -3947,7 +3952,7 @@ void snd_trident_resume(trident_t *tride return; pci_enable_device(trident->pci); - pci_set_dma_mask(trident->pci, 0x3fffffff); /* to be sure */ + pci_set_consistent_dma_mask(trident->pci, 0x3fffffff); /* FIXME: correct? */ pci_set_master(trident->pci); /* to be sure */ switch (trident->device) { diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/via82xx.c 830-ivtv/sound/pci/via82xx.c --- 000-virgin/sound/pci/via82xx.c Mon Nov 17 18:29:43 2003 +++ 830-ivtv/sound/pci/via82xx.c Thu Jan 8 10:26:51 2004 @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -69,10 +70,17 @@ MODULE_LICENSE("GPL"); MODULE_CLASSES("{sound}"); MODULE_DEVICES("{{VIA,VT82C686A/B/C,pci},{VIA,VT8233A/C,8235}}"); +#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#define SUPPORT_JOYSTICK 1 +#endif + static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ -static long mpu_port[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1}; +static long mpu_port[SNDRV_CARDS]; +#ifdef SUPPORT_JOYSTICK +static int joystick[SNDRV_CARDS]; +#endif static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 48000}; static int dxs_support[SNDRV_CARDS]; @@ -86,14 +94,19 @@ MODULE_PARM(enable, "1-" __MODULE_STRING MODULE_PARM_DESC(enable, "Enable audio part of VIA 82xx bridge."); MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); MODULE_PARM(mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l"); -MODULE_PARM_DESC(mpu_port, "MPU-401 port."); +MODULE_PARM_DESC(mpu_port, "MPU-401 port. (VT82C686x only)"); MODULE_PARM_SYNTAX(mpu_port, SNDRV_PORT_DESC); +#ifdef SUPPORT_JOYSTICK +MODULE_PARM(joystick, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(joystick, "Enable joystick. (VT82C686x only)"); +MODULE_PARM_SYNTAX(joystick, SNDRV_ENABLE_DESC "," SNDRV_BOOLEAN_FALSE_DESC); +#endif MODULE_PARM(ac97_clock, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz)."); MODULE_PARM_SYNTAX(ac97_clock, SNDRV_ENABLED ",default:48000"); MODULE_PARM(dxs_support, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); -MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only)"); -MODULE_PARM_SYNTAX(dxs_support, SNDRV_ENABLED ",allows:{{0,3}},dialog:list"); +MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only, 4 = no VRA)"); +MODULE_PARM_SYNTAX(dxs_support, SNDRV_ENABLED ",allows:{{0,4}},dialog:list"); /* pci ids */ @@ -290,6 +303,7 @@ DEFINE_VIA_REGSET(CAPTURE_8233, 0x60); #define VIA_DXS_ENABLE 1 #define VIA_DXS_DISABLE 2 #define VIA_DXS_48K 3 +#define VIA_DXS_NO_VRA 4 /* @@ -449,9 +463,11 @@ struct _snd_via82xx { viadev_t devs[VIA_MAX_DEVS]; struct via_rate_lock rates[2]; /* playback and capture */ unsigned int dxs_fixed: 1; /* DXS channel accepts only 48kHz */ + unsigned int no_vra: 1; /* no need to set VRA on DXS channels */ snd_rawmidi_t *rmidi; + ac97_bus_t *ac97_bus; ac97_t *ac97; unsigned int ac97_clock; unsigned int ac97_secondary; /* secondary AC'97 codec is present */ @@ -459,6 +475,11 @@ struct _snd_via82xx { spinlock_t reg_lock; spinlock_t ac97_lock; snd_info_entry_t *proc_entry; + +#ifdef SUPPORT_JOYSTICK + struct gameport gameport; + struct resource *res_joystick; +#endif }; static struct pci_device_id snd_via82xx_ids[] = { @@ -509,7 +530,6 @@ static int snd_via82xx_codec_valid(via82 if ((val = snd_via82xx_codec_xread(chip)) & stat) return val & 0xffff; } - snd_printk(KERN_ERR "codec_valid: codec %i is not valid [0x%x]\n", secondary, snd_via82xx_codec_xread(chip)); return -EIO; } @@ -554,6 +574,7 @@ static unsigned short snd_via82xx_codec_ while (1) { if (again++ > 3) { spin_unlock(&chip->ac97_lock); + snd_printk(KERN_ERR "codec_read: codec %i is not valid [0x%x]\n", ac97->num, snd_via82xx_codec_xread(chip)); return 0xffff; } snd_via82xx_codec_xwrite(chip, xval); @@ -865,12 +886,12 @@ static int via_lock_rate(struct via_rate spin_lock(&rec->lock); if (rec->rate != rate) { - if (rec->rate && rec->used > 1) { /* already set */ - spin_unlock(&rec->lock); - return -EINVAL; + if (rec->rate && rec->used > 1) /* already set */ + changed = -EINVAL; + else { + rec->rate = rate; + changed = 1; } - rec->rate = rate; - changed = 1; } spin_unlock(&rec->lock); return changed; @@ -890,9 +911,8 @@ static int snd_via8233_playback_prepare( if ((rate_changed = via_lock_rate(&chip->rates[0], runtime->rate)) < 0) return rate_changed; if (rate_changed) { - snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate); - snd_ac97_set_rate(chip->ac97, AC97_PCM_SURR_DAC_RATE, runtime->rate); - snd_ac97_set_rate(chip->ac97, AC97_PCM_LFE_DAC_RATE, runtime->rate); + snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, + chip->no_vra ? 48000 : runtime->rate); snd_ac97_set_rate(chip->ac97, AC97_SPDIF, runtime->rate); } #if 0 @@ -1382,7 +1402,7 @@ static int snd_via8233_capture_source_in static int snd_via8233_capture_source_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { via82xx_t *chip = snd_kcontrol_chip(kcontrol); - unsigned long port = chip->port + kcontrol->id.index ? (VIA_REG_CAPTURE_CHANNEL + 0x10) : VIA_REG_CAPTURE_CHANNEL; + unsigned long port = chip->port + (kcontrol->id.index ? (VIA_REG_CAPTURE_CHANNEL + 0x10) : VIA_REG_CAPTURE_CHANNEL); ucontrol->value.enumerated.item[0] = inb(port) & VIA_REG_CAPTURE_CHANNEL_MIC ? 1 : 0; return 0; } @@ -1390,7 +1410,7 @@ static int snd_via8233_capture_source_ge static int snd_via8233_capture_source_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { via82xx_t *chip = snd_kcontrol_chip(kcontrol); - unsigned long port = chip->port + kcontrol->id.index ? (VIA_REG_CAPTURE_CHANNEL + 0x10) : VIA_REG_CAPTURE_CHANNEL; + unsigned long port = chip->port + (kcontrol->id.index ? (VIA_REG_CAPTURE_CHANNEL + 0x10) : VIA_REG_CAPTURE_CHANNEL); unsigned long flags; u8 val, oval; @@ -1509,6 +1529,12 @@ static snd_kcontrol_new_t snd_via8233_dx /* */ +static void snd_via82xx_mixer_free_ac97_bus(ac97_bus_t *bus) +{ + via82xx_t *chip = snd_magic_cast(via82xx_t, bus->private_data, return); + chip->ac97_bus = NULL; +} + static void snd_via82xx_mixer_free_ac97(ac97_t *ac97) { via82xx_t *chip = snd_magic_cast(via82xx_t, ac97->private_data, return); @@ -1516,29 +1542,42 @@ static void snd_via82xx_mixer_free_ac97( } static struct ac97_quirk ac97_quirks[] = { - { + { /* FIXME: which codec? */ .vendor = 0x1106, .device = 0x4161, .name = "ASRock K7VT2", .type = AC97_TUNE_HP_ONLY }, + { + .vendor = 0x1849, + .device = 0x3059, + .name = "ASRock K7VM2", + .type = AC97_TUNE_HP_ONLY /* VT1616 */ + }, { } /* terminator */ }; static int __devinit snd_via82xx_mixer_new(via82xx_t *chip) { + ac97_bus_t bus; ac97_t ac97; int err; + memset(&bus, 0, sizeof(bus)); + bus.write = snd_via82xx_codec_write; + bus.read = snd_via82xx_codec_read; + bus.wait = snd_via82xx_codec_wait; + bus.private_data = chip; + bus.private_free = snd_via82xx_mixer_free_ac97_bus; + bus.clock = chip->ac97_clock; + if ((err = snd_ac97_bus(chip->card, &bus, &chip->ac97_bus)) < 0) + return err; + memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_via82xx_codec_write; - ac97.read = snd_via82xx_codec_read; - ac97.wait = snd_via82xx_codec_wait; ac97.private_data = chip; ac97.private_free = snd_via82xx_mixer_free_ac97; - ac97.clock = chip->ac97_clock; ac97.pci = chip->pci; - if ((err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97)) < 0) + if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0) return err; snd_ac97_tune_hardware(chip->ac97, ac97_quirks); @@ -1552,53 +1591,6 @@ static int __devinit snd_via82xx_mixer_n } /* - * joystick - */ - -static int snd_via82xx_joystick_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} - -static int snd_via82xx_joystick_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - via82xx_t *chip = snd_kcontrol_chip(kcontrol); - u16 val; - - pci_read_config_word(chip->pci, VIA_FUNC_ENABLE, &val); - ucontrol->value.integer.value[0] = (val & VIA_FUNC_ENABLE_GAME) ? 1 : 0; - return 0; -} - -static int snd_via82xx_joystick_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - via82xx_t *chip = snd_kcontrol_chip(kcontrol); - u16 val, oval; - - pci_read_config_word(chip->pci, VIA_FUNC_ENABLE, &oval); - val = oval & ~VIA_FUNC_ENABLE_GAME; - if (ucontrol->value.integer.value[0]) - val |= VIA_FUNC_ENABLE_GAME; - if (val != oval) { - pci_write_config_word(chip->pci, VIA_FUNC_ENABLE, val); - return 1; - } - return 0; -} - -static snd_kcontrol_new_t snd_via82xx_joystick_control __devinitdata = { - .name = "Joystick", - .iface = SNDRV_CTL_ELEM_IFACE_CARD, - .info = snd_via82xx_joystick_info, - .get = snd_via82xx_joystick_get, - .put = snd_via82xx_joystick_put, -}; - -/* * */ @@ -1653,7 +1645,7 @@ static int snd_via686_init_misc(via82xx_ "VIA82xx MPU401")) != NULL) { legacy |= VIA_FUNC_ENABLE_MIDI; } else { - mpu_port[dev] = -1; + mpu_port[dev] = 0; legacy &= ~VIA_FUNC_ENABLE_MIDI; } } else { @@ -1680,8 +1672,18 @@ static int snd_via686_init_misc(via82xx_ if (rev_h) legacy &= ~VIA_FUNC_MIDI_PNP; /* disable PCI I/O 2 */ legacy &= ~VIA_FUNC_ENABLE_MIDI; - mpu_port[dev] = -1; + mpu_port[dev] = 0; + } + +#ifdef SUPPORT_JOYSTICK +#define JOYSTICK_ADDR 0x200 + if (joystick[dev] && + (chip->res_joystick = request_region(JOYSTICK_ADDR, 8, "VIA686 gameport")) != NULL) { + legacy |= VIA_FUNC_ENABLE_GAME; + chip->gameport.io = JOYSTICK_ADDR; } +#endif + pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE, legacy); pci_write_config_byte(chip->pci, VIA_PNP_CONTROL, legacy_cfg); if (chip->mpu_res) { @@ -1695,9 +1697,13 @@ static int snd_via686_init_misc(via82xx_ } pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE, legacy); } - - /* card switches */ - return snd_ctl_add(chip->card, snd_ctl_new1(&snd_via82xx_joystick_control, chip)); + +#ifdef SUPPORT_JOYSTICK + if (chip->res_joystick) + gameport_register_port(&chip->gameport); +#endif + + return 0; } @@ -1711,7 +1717,7 @@ static void snd_via82xx_proc_read(snd_in snd_iprintf(buffer, "%s\n\n", chip->card->longname); for (i = 0; i < 0xa0; i += 4) { - snd_iprintf(buffer, "%02x: %08x", i, inl(chip->port + i)); + snd_iprintf(buffer, "%02x: %08x\n", i, inl(chip->port + i)); } } @@ -1720,7 +1726,7 @@ static void __devinit snd_via82xx_proc_i snd_info_entry_t *entry; if (! snd_card_proc_new(chip->card, "via82xx", &entry)) - snd_info_set_text_ops(entry, chip, snd_via82xx_proc_read); + snd_info_set_text_ops(entry, chip, 1024, snd_via82xx_proc_read); } /* @@ -1859,6 +1865,13 @@ static int snd_via82xx_free(via82xx_t *c if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); if (chip->chip_type == TYPE_VIA686) { +#ifdef SUPPORT_JOYSTICK + if (chip->res_joystick) { + gameport_unregister_port(&chip->gameport); + release_resource(chip->res_joystick); + kfree_nocheck(chip->res_joystick); + } +#endif pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE, chip->old_legacy); pci_write_config_byte(chip->pci, VIA_PNP_CONTROL, chip->old_legacy_cfg); } @@ -1968,7 +1981,16 @@ static int __devinit check_dxs_list(stru { static struct dxs_whitelist whitelist[] = { { .vendor = 0x1019, .device = 0x0996, .action = VIA_DXS_48K }, + { .vendor = 0x1043, .device = 0x8095, .action = VIA_DXS_ENABLE }, /* ASUS A7V8X */ + { .vendor = 0x1043, .device = 0x80a1, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8-X */ + { .vendor = 0x1043, .device = 0x80b0, .action = VIA_DXS_ENABLE }, /* ASUS A7V600 */ + { .vendor = 0x10cf, .device = 0x118e, .action = VIA_DXS_ENABLE }, /* FSC laptop */ { .vendor = 0x1297, .device = 0xc160, .action = VIA_DXS_ENABLE }, /* Shuttle SK41G */ + { .vendor = 0x1458, .device = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */ + { .vendor = 0x14ff, .device = 0x0403, .action = VIA_DXS_ENABLE }, /* Twinhead mobo */ + { .vendor = 0x1462, .device = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */ + { .vendor = 0x1695, .device = 0x3005, .action = VIA_DXS_ENABLE }, /* EPoX EP-8K9A */ + { .vendor = 0x1849, .device = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */ { } /* terminator */ }; struct dxs_whitelist *w; @@ -1994,7 +2016,8 @@ static int __devinit check_dxs_list(stru * not detected, try 48k rate only to be sure. */ printk(KERN_INFO "via82xx: Assuming DXS channels with 48k fixed sample rate.\n"); - printk(KERN_INFO " Please try dxs_support=1 option and report if it works on your machine.\n"); + printk(KERN_INFO " Please try dxs_support=1 or dxs_support=4 option\n"); + printk(KERN_INFO " and report if it works on your machine.\n"); return VIA_DXS_48K; }; @@ -2073,12 +2096,14 @@ static int __devinit snd_via82xx_probe(s if (chip_type == TYPE_VIA8233A) { if ((err = snd_via8233a_pcm_new(chip)) < 0) goto __error; - chip->dxs_fixed = 1; /* use 48k for DXS #3 */ + // chip->dxs_fixed = 1; /* FIXME: use 48k for DXS #3? */ } else { if ((err = snd_via8233_pcm_new(chip)) < 0) goto __error; if (dxs_support[dev] == VIA_DXS_48K) chip->dxs_fixed = 1; + else if (dxs_support[dev] == VIA_DXS_NO_VRA) + chip->no_vra = 1; } if ((err = snd_via8233_init_misc(chip, dev)) < 0) goto __error; @@ -2142,7 +2167,7 @@ module_exit(alsa_card_via82xx_exit) #ifndef MODULE /* format is: snd-via82xx=enable,index,id, - mpu_port,ac97_clock,dxs_support */ + mpu_port,joystick,ac97_clock,dxs_support */ static int __init alsa_card_via82xx_setup(char *str) { @@ -2153,7 +2178,10 @@ static int __init alsa_card_via82xx_setu (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&mpu_port[nr_dev]) == 2 && + get_option_long(&str,&mpu_port[nr_dev]) == 2 && +#ifdef SUPPORT_JOYSTICK + get_option(&str,&joystick[nr_dev]) == 2 && +#endif get_option(&str,&ac97_clock[nr_dev]) == 2 && get_option(&str,&dxs_support[nr_dev]) == 2); nr_dev++; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/ymfpci/ymfpci.c 830-ivtv/sound/pci/ymfpci/ymfpci.c --- 000-virgin/sound/pci/ymfpci/ymfpci.c Wed Aug 13 20:24:38 2003 +++ 830-ivtv/sound/pci/ymfpci/ymfpci.c Thu Jan 8 10:26:51 2004 @@ -44,8 +44,11 @@ MODULE_DEVICES("{{Yamaha,YMF724}," static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ -static long fm_port[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1}; -static long mpu_port[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1}; +static long fm_port[SNDRV_CARDS]; +static long mpu_port[SNDRV_CARDS]; +#ifdef SUPPORT_JOYSTICK +static long joystick_port[SNDRV_CARDS]; +#endif static int rear_switch[SNDRV_CARDS]; MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); @@ -63,6 +66,11 @@ MODULE_PARM_SYNTAX(mpu_port, SNDRV_ENABL MODULE_PARM(fm_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l"); MODULE_PARM_DESC(fm_port, "FM OPL-3 Port."); MODULE_PARM_SYNTAX(fm_port, SNDRV_ENABLED); +#ifdef SUPPORT_JOYSTICK +MODULE_PARM(joystick_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l"); +MODULE_PARM_DESC(joystick_port, "Joystick port address"); +MODULE_PARM_SYNTAX(joystick_port, SNDRV_ENABLED); +#endif MODULE_PARM(rear_switch, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(rear_switch, "Enable shared rear/line-in switch"); MODULE_PARM_SYNTAX(rear_switch, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); @@ -86,6 +94,9 @@ static int __devinit snd_card_ymfpci_pro snd_card_t *card; struct resource *fm_res = NULL; struct resource *mpu_res = NULL; +#ifdef SUPPORT_JOYSTICK + struct resource *joystick_res = NULL; +#endif ymfpci_t *chip; opl3_t *opl3; char *str; @@ -117,51 +128,92 @@ static int __devinit snd_card_ymfpci_pro legacy_ctrl2 = 0x0800; /* SBEN = 0, SMOD = 01, LAD = 0 */ if (pci_id->device >= 0x0010) { /* YMF 744/754 */ - if (fm_port[dev] < 0) { + if (fm_port[dev] == 1) { + /* auto-detect */ fm_port[dev] = pci_resource_start(pci, 1); } - if (fm_port[dev] >= 0 && + if (fm_port[dev] > 0 && (fm_res = request_region(fm_port[dev], 4, "YMFPCI OPL3")) != NULL) { legacy_ctrl |= YMFPCI_LEGACY_FMEN; pci_write_config_word(pci, PCIR_DSXG_FMBASE, fm_port[dev]); } - if (mpu_port[dev] < 0) { + if (mpu_port[dev] == 1) { + /* auto-detect */ mpu_port[dev] = pci_resource_start(pci, 1) + 0x20; } - if (mpu_port[dev] >= 0 && + if (mpu_port[dev] > 0 && (mpu_res = request_region(mpu_port[dev], 2, "YMFPCI MPU401")) != NULL) { legacy_ctrl |= YMFPCI_LEGACY_MEN; pci_write_config_word(pci, PCIR_DSXG_MPU401BASE, mpu_port[dev]); } +#ifdef SUPPORT_JOYSTICK + if (joystick_port[dev] == 1) { + /* auto-detect */ + joystick_port[dev] = pci_resource_start(pci, 2); + } + if (joystick_port[dev] > 0 && + (joystick_res = request_region(joystick_port[dev], 1, "YMFPCI gameport")) != NULL) { + legacy_ctrl |= YMFPCI_LEGACY_JPEN; + pci_write_config_word(pci, PCIR_DSXG_JOYBASE, joystick_port[dev]); + } +#endif } else { switch (fm_port[dev]) { case 0x388: legacy_ctrl2 |= 0; break; case 0x398: legacy_ctrl2 |= 1; break; case 0x3a0: legacy_ctrl2 |= 2; break; case 0x3a8: legacy_ctrl2 |= 3; break; - default: fm_port[dev] = -1; break; + default: fm_port[dev] = 0; break; } if (fm_port[dev] > 0 && (fm_res = request_region(fm_port[dev], 4, "YMFPCI OPL3")) != NULL) { legacy_ctrl |= YMFPCI_LEGACY_FMEN; } else { legacy_ctrl2 &= ~YMFPCI_LEGACY2_FMIO; - fm_port[dev] = -1; + fm_port[dev] = 0; } switch (mpu_port[dev]) { case 0x330: legacy_ctrl2 |= 0 << 4; break; case 0x300: legacy_ctrl2 |= 1 << 4; break; case 0x332: legacy_ctrl2 |= 2 << 4; break; case 0x334: legacy_ctrl2 |= 3 << 4; break; - default: mpu_port[dev] = -1; break; + default: mpu_port[dev] = 0; break; } if (mpu_port[dev] > 0 && (mpu_res = request_region(mpu_port[dev], 2, "YMFPCI MPU401")) != NULL) { legacy_ctrl |= YMFPCI_LEGACY_MEN; } else { legacy_ctrl2 &= ~YMFPCI_LEGACY2_MPUIO; - mpu_port[dev] = -1; + mpu_port[dev] = 0; + } +#ifdef SUPPORT_JOYSTICK + if (joystick_port[dev] == 1) { + /* auto-detect */ + long p; + for (p = 0x201; p <= 0x205; p++) { + if (p == 0x203) continue; + if ((joystick_res = request_region(p, 1, "YMFPCI gameport")) != NULL) + break; + } + if (joystick_res) + joystick_port[dev] = p; + } + switch (joystick_port[dev]) { + case 0x201: legacy_ctrl2 |= 0 << 6; break; + case 0x202: legacy_ctrl2 |= 1 << 6; break; + case 0x204: legacy_ctrl2 |= 2 << 6; break; + case 0x205: legacy_ctrl2 |= 3 << 6; break; + default: joystick_port[dev] = 0; break; + } + if (! joystick_res && joystick_port[dev] > 0) + joystick_res = request_region(joystick_port[dev], 1, "YMFPCI gameport"); + if (joystick_res) { + legacy_ctrl |= YMFPCI_LEGACY_JPEN; + } else { + legacy_ctrl2 &= ~YMFPCI_LEGACY2_JSIO; + joystick_port[dev] = 0; } +#endif } if (mpu_res) { legacy_ctrl |= YMFPCI_LEGACY_MIEN; @@ -182,10 +234,19 @@ static int __devinit snd_card_ymfpci_pro release_resource(fm_res); kfree_nocheck(fm_res); } +#ifdef SUPPORT_JOYSTICK + if (joystick_res) { + release_resource(joystick_res); + kfree_nocheck(joystick_res); + } +#endif return err; } chip->fm_res = fm_res; chip->mpu_res = mpu_res; +#ifdef SUPPORT_JOYSTICK + chip->joystick_res = joystick_res; +#endif if ((err = snd_ymfpci_pcm(chip, 0, NULL)) < 0) { snd_card_free(card); return err; @@ -206,6 +267,10 @@ static int __devinit snd_card_ymfpci_pro snd_card_free(card); return err; } + if ((err = snd_ymfpci_timer(chip, 0)) < 0) { + snd_card_free(card); + return err; + } if (chip->mpu_res) { if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_YMFPCI, mpu_port[dev], 1, @@ -229,9 +294,10 @@ static int __devinit snd_card_ymfpci_pro return err; } } -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) - if ((err = snd_ymfpci_joystick(chip)) < 0) { - printk(KERN_WARNING "ymfpci: cannot initialize joystick, skipping...\n"); +#ifdef SUPPORT_JOYSTICK + if (chip->joystick_res) { + chip->gameport.io = joystick_port[dev]; + gameport_register_port(&chip->gameport); } #endif strcpy(card->driver, str); @@ -319,8 +385,8 @@ static int __init alsa_card_ymfpci_setup (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&fm_port[nr_dev]) == 2 && - get_option(&str,(int *)&mpu_port[nr_dev]) == 2); + get_option_long(&str,&fm_port[nr_dev]) == 2 && + get_option_long(&str,&mpu_port[nr_dev]) == 2); nr_dev++; return 1; } diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pci/ymfpci/ymfpci_main.c 830-ivtv/sound/pci/ymfpci/ymfpci_main.c --- 000-virgin/sound/pci/ymfpci/ymfpci_main.c Tue Sep 2 09:56:05 2003 +++ 830-ivtv/sound/pci/ymfpci/ymfpci_main.c Thu Jan 8 10:26:51 2004 @@ -779,7 +779,8 @@ static irqreturn_t snd_ymfpci_interrupt( status = snd_ymfpci_readw(chip, YDSXGR_INTFLAG); if (status & 1) { - /* timer handler */ + if (chip->timer) + snd_timer_interrupt(chip->timer, chip->timer->sticks); } snd_ymfpci_writew(chip, YDSXGR_INTFLAG, status); @@ -1135,7 +1136,7 @@ int __devinit snd_ymfpci_pcm2(ymfpci_t * if (rpcm) *rpcm = NULL; - if ((err = snd_pcm_new(chip->card, "YMFPCI - AC'97", device, 0, 1, &pcm)) < 0) + if ((err = snd_pcm_new(chip->card, "YMFPCI - PCM2", device, 0, 1, &pcm)) < 0) return err; pcm->private_data = chip; pcm->private_free = snd_ymfpci_pcm2_free; @@ -1144,7 +1145,8 @@ int __devinit snd_ymfpci_pcm2(ymfpci_t * /* global setup */ pcm->info_flags = 0; - strcpy(pcm->name, "YMFPCI - AC'97"); + sprintf(pcm->name, "YMFPCI - %s", + chip->device_id == PCI_DEVICE_ID_YAMAHA_754 ? "Direct Recording" : "AC'97"); chip->pcm2 = pcm; snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 256*1024); @@ -1368,6 +1370,61 @@ static snd_kcontrol_new_t snd_ymfpci_spd .put = snd_ymfpci_spdif_stream_put }; +static int snd_ymfpci_drec_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *info) +{ + static char *texts[3] = {"AC'97", "IEC958", "ZV Port"}; + + info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + info->count = 1; + info->value.enumerated.items = 3; + if (info->value.enumerated.item > 2) + info->value.enumerated.item = 2; + strcpy(info->value.enumerated.name, texts[info->value.enumerated.item]); + return 0; +} + +static int snd_ymfpci_drec_source_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value) +{ + ymfpci_t *chip = snd_kcontrol_chip(kcontrol); + unsigned long flags; + u16 reg; + + spin_lock_irqsave(&chip->reg_lock, flags); + reg = snd_ymfpci_readw(chip, YDSXGR_GLOBALCTRL); + spin_unlock_irqrestore(&chip->reg_lock, flags); + if (!(reg & 0x100)) + value->value.enumerated.item[0] = 0; + else + value->value.enumerated.item[0] = 1 + ((reg & 0x200) != 0); + return 0; +} + +static int snd_ymfpci_drec_source_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value) +{ + ymfpci_t *chip = snd_kcontrol_chip(kcontrol); + unsigned long flags; + u16 reg, old_reg; + + spin_lock_irqsave(&chip->reg_lock, flags); + old_reg = snd_ymfpci_readw(chip, YDSXGR_GLOBALCTRL); + if (value->value.enumerated.item[0] == 0) + reg = old_reg & ~0x100; + else + reg = (old_reg & ~0x300) | 0x100 | ((value->value.enumerated.item[0] == 2) << 9); + snd_ymfpci_writew(chip, YDSXGR_GLOBALCTRL, reg); + spin_unlock_irqrestore(&chip->reg_lock, flags); + return reg != old_reg; +} + +static snd_kcontrol_new_t snd_ymfpci_drec_source __devinitdata = { + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Direct Recording Source", + .info = snd_ymfpci_drec_source_info, + .get = snd_ymfpci_drec_source_get, + .put = snd_ymfpci_drec_source_put +}; + /* * Mixer controls */ @@ -1651,6 +1708,12 @@ static snd_kcontrol_new_t snd_ymfpci_rea * Mixer routines */ +static void snd_ymfpci_mixer_free_ac97_bus(ac97_bus_t *bus) +{ + ymfpci_t *chip = snd_magic_cast(ymfpci_t, bus->private_data, return); + chip->ac97_bus = NULL; +} + static void snd_ymfpci_mixer_free_ac97(ac97_t *ac97) { ymfpci_t *chip = snd_magic_cast(ymfpci_t, ac97->private_data, return); @@ -1659,17 +1722,24 @@ static void snd_ymfpci_mixer_free_ac97(a int __devinit snd_ymfpci_mixer(ymfpci_t *chip, int rear_switch) { + ac97_bus_t bus; ac97_t ac97; snd_kcontrol_t *kctl; unsigned int idx; int err; + memset(&bus, 0, sizeof(bus)); + bus.write = snd_ymfpci_codec_write; + bus.read = snd_ymfpci_codec_read; + bus.private_data = chip; + bus.private_free = snd_ymfpci_mixer_free_ac97_bus; + if ((err = snd_ac97_bus(chip->card, &bus, &chip->ac97_bus)) < 0) + return err; + memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_ymfpci_codec_write; - ac97.read = snd_ymfpci_codec_read; ac97.private_data = chip; ac97.private_free = snd_ymfpci_mixer_free_ac97; - if ((err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97)) < 0) + if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0) return err; for (idx = 0; idx < YMFPCI_CONTROLS; idx++) { @@ -1690,6 +1760,11 @@ int __devinit snd_ymfpci_mixer(ymfpci_t kctl->id.device = chip->pcm_spdif->device; chip->spdif_pcm_ctl = kctl; + /* direct recording source */ + if (chip->device_id == PCI_DEVICE_ID_YAMAHA_754 && + (err = snd_ctl_add(chip->card, kctl = snd_ctl_new1(&snd_ymfpci_drec_source, chip))) < 0) + return err; + /* * shared rear/line-in */ @@ -1703,174 +1778,74 @@ int __devinit snd_ymfpci_mixer(ymfpci_t /* - * joystick support + * timer */ -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) -static int ymfpci_joystick_ports[4] = { - 0x201, 0x202, 0x204, 0x205 -}; - -static int snd_ymfpci_get_joystick_port(ymfpci_t *chip, int index) +static int snd_ymfpci_timer_start(snd_timer_t *timer) { - if (index < 4) - return ymfpci_joystick_ports[index]; - else - return pci_resource_start(chip->pci, 2); -} - -static void setup_joystick_base(ymfpci_t *chip) -{ - if (chip->device_id >= 0x0010) /* YMF 744/754 */ - pci_write_config_word(chip->pci, PCIR_DSXG_JOYBASE, - snd_ymfpci_get_joystick_port(chip, chip->joystick_port)); - else { - u16 legacy_ctrl2; - pci_read_config_word(chip->pci, PCIR_DSXG_ELEGACY, &legacy_ctrl2); - legacy_ctrl2 &= ~YMFPCI_LEGACY2_JSIO; - legacy_ctrl2 |= chip->joystick_port << 6; - pci_write_config_word(chip->pci, PCIR_DSXG_ELEGACY, legacy_ctrl2); - } -} - -static int snd_ymfpci_enable_joystick(ymfpci_t *chip) -{ - u16 val; - - chip->gameport.io = snd_ymfpci_get_joystick_port(chip, chip->joystick_port); - chip->joystick_res = request_region(chip->gameport.io, 1, "YMFPCI gameport"); - if (!chip->joystick_res) { - snd_printk(KERN_WARNING "gameport port %#x in use\n", chip->gameport.io); - return 0; - } - setup_joystick_base(chip); - pci_read_config_word(chip->pci, PCIR_DSXG_LEGACY, &val); - val |= YMFPCI_LEGACY_JPEN; - pci_write_config_word(chip->pci, PCIR_DSXG_LEGACY, val); - gameport_register_port(&chip->gameport); - return 1; -} - -static int snd_ymfpci_disable_joystick(ymfpci_t *chip) -{ - u16 val; - - gameport_unregister_port(&chip->gameport); - pci_read_config_word(chip->pci, PCIR_DSXG_LEGACY, &val); - val &= ~YMFPCI_LEGACY_JPEN; - pci_write_config_word(chip->pci, PCIR_DSXG_LEGACY, val); - release_resource(chip->joystick_res); - kfree_nocheck(chip->joystick_res); - chip->joystick_res = NULL; - return 1; -} - -static int snd_ymfpci_joystick_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} - -static int snd_ymfpci_joystick_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - ymfpci_t *chip = snd_kcontrol_chip(kcontrol); - u16 val; + ymfpci_t *chip; + unsigned long flags; + unsigned int count; - pci_read_config_word(chip->pci, PCIR_DSXG_LEGACY, &val); - ucontrol->value.integer.value[0] = (val & YMFPCI_LEGACY_JPEN) ? 1 : 0; + chip = snd_timer_chip(timer); + count = timer->sticks - 1; + if (count == 0) /* minimum time is 20.8 us */ + count = 1; + spin_lock_irqsave(&chip->reg_lock, flags); + snd_ymfpci_writew(chip, YDSXGR_TIMERCOUNT, count); + snd_ymfpci_writeb(chip, YDSXGR_TIMERCTRL, 0x03); + spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } -static int snd_ymfpci_joystick_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +static int snd_ymfpci_timer_stop(snd_timer_t *timer) { - ymfpci_t *chip = snd_kcontrol_chip(kcontrol); - int enabled, change; - - down(&chip->joystick_mutex); - enabled = chip->joystick_res != NULL; - change = enabled != !! ucontrol->value.integer.value[0]; - if (change) { - if (!enabled) - change = snd_ymfpci_enable_joystick(chip); - else - change = snd_ymfpci_disable_joystick(chip); - } - up(&chip->joystick_mutex); - return change; -} - -static int snd_ymfpci_joystick_addr_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) -{ - ymfpci_t *chip = snd_kcontrol_chip(kcontrol); - int ports = chip->device_id >= 0x0010 ? 5 : 4; + ymfpci_t *chip; + unsigned long flags; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = ports; - if (uinfo->value.enumerated.item >= ports) - uinfo->value.enumerated.item = ports - 1; - sprintf(uinfo->value.enumerated.name, "port 0x%x", - snd_ymfpci_get_joystick_port(chip, uinfo->value.enumerated.item)); + chip = snd_timer_chip(timer); + spin_lock_irqsave(&chip->reg_lock, flags); + snd_ymfpci_writeb(chip, YDSXGR_TIMERCTRL, 0x00); + spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } -static int snd_ymfpci_joystick_addr_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +static int snd_ymfpci_timer_precise_resolution(snd_timer_t *timer, + unsigned long *num, unsigned long *den) { - ymfpci_t *chip = snd_kcontrol_chip(kcontrol); - ucontrol->value.enumerated.item[0] = chip->joystick_port; + *num = 1; + *den = 96000; return 0; } -static int snd_ymfpci_joystick_addr_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - ymfpci_t *chip = snd_kcontrol_chip(kcontrol); - int change, enabled; - - down(&chip->joystick_mutex); - change = ucontrol->value.enumerated.item[0] != chip->joystick_port; - if (change) { - enabled = chip->joystick_res != NULL; - if (enabled) - snd_ymfpci_disable_joystick(chip); - chip->joystick_port = ucontrol->value.enumerated.item[0]; - if (enabled) - snd_ymfpci_enable_joystick(chip); - } - up(&chip->joystick_mutex); - return change; -} - -static snd_kcontrol_new_t snd_ymfpci_control_joystick __devinitdata = { - .name = "Joystick", - .iface = SNDRV_CTL_ELEM_IFACE_CARD, - .info = snd_ymfpci_joystick_info, - .get = snd_ymfpci_joystick_get, - .put = snd_ymfpci_joystick_put, +static struct _snd_timer_hardware snd_ymfpci_timer_hw = { + .flags = SNDRV_TIMER_HW_AUTO, + .resolution = 10417, /* 1/2fs = 10.41666...us */ + .ticks = 65536, + .start = snd_ymfpci_timer_start, + .stop = snd_ymfpci_timer_stop, + .precise_resolution = snd_ymfpci_timer_precise_resolution, }; -static snd_kcontrol_new_t snd_ymfpci_control_joystick_addr __devinitdata = { - .name = "Joystick Address", - .iface = SNDRV_CTL_ELEM_IFACE_CARD, - .info = snd_ymfpci_joystick_addr_info, - .get = snd_ymfpci_joystick_addr_get, - .put = snd_ymfpci_joystick_addr_put, -}; - -int __devinit snd_ymfpci_joystick(ymfpci_t *chip) +int __devinit snd_ymfpci_timer(ymfpci_t *chip, int device) { + snd_timer_t *timer = NULL; + snd_timer_id_t tid; int err; - chip->joystick_port = 0; /* default */ - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_ymfpci_control_joystick, chip))) < 0) - return err; - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_ymfpci_control_joystick_addr, chip))) < 0) - return err; - return 0; + tid.dev_class = SNDRV_TIMER_CLASS_CARD; + tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE; + tid.card = chip->card->number; + tid.device = device; + tid.subdevice = 0; + if ((err = snd_timer_new(chip->card, "YMFPCI", &tid, &timer)) >= 0) { + strcpy(timer->name, "YMFPCI timer"); + timer->private_data = chip; + timer->hw = snd_ymfpci_timer_hw; + } + chip->timer = timer; + return err; } -#endif /* CONFIG_GAMEPORT */ /* @@ -1893,7 +1868,7 @@ static int __devinit snd_ymfpci_proc_ini snd_info_entry_t *entry; if (! snd_card_proc_new(card, "ymfpci", &entry)) - snd_info_set_text_ops(entry, chip, snd_ymfpci_proc_read); + snd_info_set_text_ops(entry, chip, 1024, snd_ymfpci_proc_read); return 0; } @@ -2122,9 +2097,13 @@ static int snd_ymfpci_free(ymfpci_t *chi release_resource(chip->fm_res); kfree_nocheck(chip->fm_res); } -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) - if (chip->joystick_res) - snd_ymfpci_disable_joystick(chip); +#ifdef SUPPORT_JOYSTICK + if (chip->joystick_res) { + if (chip->gameport.io) + gameport_unregister_port(&chip->gameport); + release_resource(chip->joystick_res); + kfree_nocheck(chip->joystick_res); + } #endif if (chip->reg_area_virt) iounmap((void *)chip->reg_area_virt); @@ -2221,10 +2200,11 @@ void snd_ymfpci_resume(ymfpci_t *chip) /* start hw again */ if (chip->start_count > 0) { - spin_lock(&chip->reg_lock); + unsigned long flags; + spin_lock_irqsave(&chip->reg_lock, flags); snd_ymfpci_writel(chip, YDSXGR_MODE, chip->saved_ydsxgr_mode); chip->active_bank = snd_ymfpci_readl(chip, YDSXGR_CTRLSELECT); - spin_unlock(&chip->reg_lock); + spin_unlock_irqrestore(&chip->reg_lock, flags); } snd_power_change_state(card, SNDRV_CTL_POWER_D0); } @@ -2275,9 +2255,6 @@ int __devinit snd_ymfpci_create(snd_card spin_lock_init(&chip->voice_lock); init_waitqueue_head(&chip->interrupt_sleep); atomic_set(&chip->interrupt_sleep_count, 0); -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) - init_MUTEX(&chip->joystick_mutex); -#endif chip->card = card; chip->pci = pci; chip->irq = -1; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pcmcia/Kconfig 830-ivtv/sound/pcmcia/Kconfig --- 000-virgin/sound/pcmcia/Kconfig Sat Jun 14 18:37:44 2003 +++ 830-ivtv/sound/pcmcia/Kconfig Thu Jan 8 10:26:51 2004 @@ -5,13 +5,13 @@ menu "PCMCIA devices" config SND_VXPOCKET tristate "Digigram VXpocket" - depends on SND && PCMCIA + depends on SND && PCMCIA && ISA help Say 'Y' or 'M' to include support for Digigram VXpocket soundcard. config SND_VXP440 tristate "Digigram VXpocket 440" - depends on SND && PCMCIA + depends on SND && PCMCIA && ISA help Say 'Y' or 'M' to include support for Digigram VXpocket 440 soundcard. diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/pcmcia/vx/vx_entry.c 830-ivtv/sound/pcmcia/vx/vx_entry.c --- 000-virgin/sound/pcmcia/vx/vx_entry.c Mon Nov 17 18:29:01 2003 +++ 830-ivtv/sound/pcmcia/vx/vx_entry.c Thu Jan 8 10:26:51 2004 @@ -27,6 +27,10 @@ #include +MODULE_AUTHOR("Takashi Iwai "); +MODULE_DESCRIPTION("Common routines for Digigram PCMCIA VX drivers"); +MODULE_LICENSE("GPL"); + /* * prototypes */ diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/ppc/daca.c 830-ivtv/sound/ppc/daca.c --- 000-virgin/sound/ppc/daca.c Mon Nov 17 18:29:01 2003 +++ 830-ivtv/sound/ppc/daca.c Thu Jan 8 10:26:51 2004 @@ -249,7 +249,8 @@ int __init snd_pmac_daca_init(pmac_t *ch pmac_daca_t *mix; #ifdef CONFIG_KMOD - request_module("i2c-keywest"); + if (current->fs->root) + request_module("i2c-keywest"); #endif /* CONFIG_KMOD */ mix = kmalloc(sizeof(*mix), GFP_KERNEL); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/ppc/tumbler.c 830-ivtv/sound/ppc/tumbler.c --- 000-virgin/sound/ppc/tumbler.c Mon Nov 17 18:29:01 2003 +++ 830-ivtv/sound/ppc/tumbler.c Thu Jan 8 10:26:51 2004 @@ -993,7 +993,8 @@ int __init snd_pmac_tumbler_init(pmac_t char *chipname; #ifdef CONFIG_KMOD - request_module("i2c-keywest"); + if (current->fs->root) + request_module("i2c-keywest"); #endif /* CONFIG_KMOD */ mix = kmalloc(sizeof(*mix), GFP_KERNEL); diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/usb/usbaudio.c 830-ivtv/sound/usb/usbaudio.c --- 000-virgin/sound/usb/usbaudio.c Mon Nov 17 18:29:36 2003 +++ 830-ivtv/sound/usb/usbaudio.c Thu Jan 8 10:26:51 2004 @@ -23,6 +23,18 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * NOTES: + * + * - async unlink should be used for avoiding the sleep inside lock. + * 2.4.22 usb-uhci seems buggy for async unlinking and results in + * oops. in such a cse, pass async_unlink=0 option. + * - the linked URBs would be preferred but not used so far because of + * the instability of unlinking. + * - type II is not supported properly. there is no device which supports + * this type *correctly*. SB extigy looks as if it supports, but it's + * indeed an AC3 stream packed in SPDIF frames (i.e. no real AC3 stream). */ @@ -56,6 +68,7 @@ static int enable[SNDRV_CARDS] = SNDRV_D static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Vendor ID for this card */ static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Product ID for this card */ static int nrpacks = 4; /* max. number of packets per urb */ +static int async_unlink = 1; MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(index, "Index value for the USB audio adapter."); @@ -75,21 +88,9 @@ MODULE_PARM_SYNTAX(pid, SNDRV_ENABLED ", MODULE_PARM(nrpacks, "i"); MODULE_PARM_DESC(nrpacks, "Max. number of packets per URB."); MODULE_PARM_SYNTAX(nrpacks, SNDRV_ENABLED ",allows:{{2,10}}"); - - -/* - * for using ASYNC unlink mode, define the following. - * this will make the driver quicker response for request to STOP-trigger, - * but it may cause oops by some unknown reason (bug of usb driver?), - * so turning off might be sure. - */ -/* #define SND_USE_ASYNC_UNLINK */ - -#ifdef SND_USB_ASYNC_UNLINK -#define UNLINK_FLAGS URB_ASYNC_UNLINK -#else -#define UNLINK_FLAGS 0 -#endif +MODULE_PARM(async_unlink, "i"); +MODULE_PARM_DESC(async_unlink, "Use async unlink mode."); +MODULE_PARM_SYNTAX(async_unlink, SNDRV_BOOLEAN_TRUE_DESC); /* @@ -571,20 +572,18 @@ static void snd_complete_urb(struct urb snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; snd_usb_substream_t *subs = ctx->subs; snd_pcm_substream_t *substream = ctx->subs->pcm_substream; - int err; + int err = 0; - clear_bit(ctx->index, &subs->active_mask); - if (subs->running && subs->ops.retire(subs, substream->runtime, urb)) - return; - if (! subs->running) /* can be stopped during retire callback */ - return; - if ((err = subs->ops.prepare(subs, substream->runtime, urb)) < 0 || + if ((subs->running && subs->ops.retire(subs, substream->runtime, urb)) || + ! subs->running || /* can be stopped during retire callback */ + (err = subs->ops.prepare(subs, substream->runtime, urb)) < 0 || (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { - snd_printd(KERN_ERR "cannot submit urb (err = %d)\n", err); - snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); - return; + clear_bit(ctx->index, &subs->active_mask); + if (err < 0) { + snd_printd(KERN_ERR "cannot submit urb (err = %d)\n", err); + snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); + } } - set_bit(ctx->index, &subs->active_mask); } @@ -596,20 +595,18 @@ static void snd_complete_sync_urb(struct snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; snd_usb_substream_t *subs = ctx->subs; snd_pcm_substream_t *substream = ctx->subs->pcm_substream; - int err; + int err = 0; - clear_bit(ctx->index + 16, &subs->active_mask); - if (subs->running && subs->ops.retire_sync(subs, substream->runtime, urb)) - return; - if (! subs->running) /* can be stopped during retire callback */ - return; - if ((err = subs->ops.prepare_sync(subs, substream->runtime, urb)) < 0 || + if ((subs->running && subs->ops.retire_sync(subs, substream->runtime, urb)) || + ! subs->running || /* can be stopped during retire callback */ + (err = subs->ops.prepare_sync(subs, substream->runtime, urb)) < 0 || (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { - snd_printd(KERN_ERR "cannot submit sync urb (err = %d)\n", err); - snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); - return; + clear_bit(ctx->index + 16, &subs->active_mask); + if (err < 0) { + snd_printd(KERN_ERR "cannot submit sync urb (err = %d)\n", err); + snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); + } } - set_bit(ctx->index + 16, &subs->active_mask); } @@ -617,42 +614,51 @@ static void snd_complete_sync_urb(struct * unlink active urbs. * return the number of active urbs. */ -static int deactivate_urbs(snd_usb_substream_t *subs, int force) +static int deactivate_urbs(snd_usb_substream_t *subs, int force, int can_sleep) { unsigned int i; - int alive; + int alive, async; subs->running = 0; if (!force && subs->stream->chip->shutdown) /* to be sure... */ return 0; -#ifndef SND_USB_ASYNC_UNLINK - if (in_interrupt()) + async = !can_sleep && async_unlink; + + if (! async && in_interrupt()) return 0; -#endif + alive = 0; for (i = 0; i < subs->nurbs; i++) { if (test_bit(i, &subs->active_mask)) { alive++; - if (! test_and_set_bit(i, &subs->unlink_mask)) - usb_unlink_urb(subs->dataurb[i].urb); + if (! test_and_set_bit(i, &subs->unlink_mask)) { + struct urb *u = subs->dataurb[i].urb; + if (async) + u->transfer_flags |= URB_ASYNC_UNLINK; + else + u->transfer_flags &= ~URB_ASYNC_UNLINK; + usb_unlink_urb(u); + } } } if (subs->syncpipe) { for (i = 0; i < SYNC_URBS; i++) { if (test_bit(i+16, &subs->active_mask)) { alive++; - if (! test_and_set_bit(i+16, &subs->unlink_mask)) - usb_unlink_urb(subs->syncurb[i].urb); + if (! test_and_set_bit(i+16, &subs->unlink_mask)) { + struct urb *u = subs->syncurb[i].urb; + if (async) + u->transfer_flags |= URB_ASYNC_UNLINK; + else + u->transfer_flags &= ~URB_ASYNC_UNLINK; + usb_unlink_urb(u); + } } } } -#ifdef SND_USB_ASYNC_UNLINK - return alive; -#else - return 0; -#endif + return async ? alive : 0; } @@ -681,9 +687,11 @@ static int start_urbs(snd_usb_substream_ } } + subs->active_mask = 0; + subs->unlink_mask = 0; subs->running = 1; for (i = 0; i < subs->nurbs; i++) { - if ((err = usb_submit_urb(subs->dataurb[i].urb, GFP_KERNEL)) < 0) { + if ((err = usb_submit_urb(subs->dataurb[i].urb, GFP_ATOMIC)) < 0) { snd_printk(KERN_ERR "cannot submit datapipe for urb %d, err = %d\n", i, err); goto __error; } @@ -691,7 +699,7 @@ static int start_urbs(snd_usb_substream_ } if (subs->syncpipe) { for (i = 0; i < SYNC_URBS; i++) { - if ((err = usb_submit_urb(subs->syncurb[i].urb, GFP_KERNEL)) < 0) { + if ((err = usb_submit_urb(subs->syncurb[i].urb, GFP_ATOMIC)) < 0) { snd_printk(KERN_ERR "cannot submit syncpipe for urb %d, err = %d\n", i, err); goto __error; } @@ -702,7 +710,7 @@ static int start_urbs(snd_usb_substream_ __error: // snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN); - deactivate_urbs(subs, 0); + deactivate_urbs(subs, 0, 0); return -EPIPE; } @@ -762,7 +770,7 @@ static int snd_usb_pcm_trigger(snd_pcm_s err = start_urbs(subs, substream->runtime); break; case SNDRV_PCM_TRIGGER_STOP: - err = deactivate_urbs(subs, 0); + err = deactivate_urbs(subs, 0, 0); break; default: err = -EINVAL; @@ -795,7 +803,7 @@ static void release_substream_urbs(snd_u int i; /* stop urbs (to be sure) */ - if (deactivate_urbs(subs, force) > 0) + if (deactivate_urbs(subs, force, 1) > 0) wait_clear_urbs(subs); for (i = 0; i < MAX_URBS; i++) @@ -824,14 +832,6 @@ static int init_substream_urbs(snd_usb_s subs->freqmax = subs->freqn + (subs->freqn >> 2); /* max. allowed frequency */ subs->phase = 0; - /* reset the pointer */ - subs->hwptr = 0; - subs->hwptr_done = 0; - subs->transfer_sched = 0; - subs->transfer_done = 0; - subs->active_mask = 0; - subs->unlink_mask = 0; - /* calculate the max. size of packet */ maxsize = ((subs->freqmax + 0x3fff) * (frame_bits >> 3)) >> 14; if (subs->maxpacksize && maxsize > subs->maxpacksize) { @@ -914,7 +914,7 @@ static int init_substream_urbs(snd_usb_s } u->urb->dev = subs->dev; u->urb->pipe = subs->datapipe; - u->urb->transfer_flags = URB_ISO_ASAP | UNLINK_FLAGS; + u->urb->transfer_flags = URB_ISO_ASAP; u->urb->number_of_packets = u->packets; u->urb->context = u; u->urb->complete = snd_usb_complete_callback(snd_complete_urb); @@ -936,7 +936,7 @@ static int init_substream_urbs(snd_usb_s u->urb->transfer_buffer_length = nrpacks * 3; u->urb->dev = subs->dev; u->urb->pipe = subs->syncpipe; - u->urb->transfer_flags = URB_ISO_ASAP | UNLINK_FLAGS; + u->urb->transfer_flags = URB_ISO_ASAP; u->urb->number_of_packets = u->packets; u->urb->context = u; u->urb->complete = snd_usb_complete_callback(snd_complete_sync_urb); @@ -954,6 +954,7 @@ static struct audioformat *find_format(s { struct list_head *p; struct audioformat *found = NULL; + int cur_attr = 0, attr; list_for_each(p, &subs->fmt_list) { struct audioformat *fp; @@ -970,9 +971,37 @@ static struct audioformat *find_format(s if (i >= fp->nr_rates) continue; } + attr = fp->ep_attr & EP_ATTR_MASK; + if (! found) { + found = fp; + cur_attr = attr; + continue; + } + /* avoid async out and adaptive in if the other method + * supports the same format. + * this is a workaround for the case like + * M-audio audiophile USB. + */ + if (attr != cur_attr) { + if ((attr == EP_ATTR_ASYNC && + subs->direction == SNDRV_PCM_STREAM_PLAYBACK) || + (attr == EP_ATTR_ADAPTIVE && + subs->direction == SNDRV_PCM_STREAM_CAPTURE)) + continue; + if ((cur_attr == EP_ATTR_ASYNC && + subs->direction == SNDRV_PCM_STREAM_PLAYBACK) || + (cur_attr == EP_ATTR_ADAPTIVE && + subs->direction == SNDRV_PCM_STREAM_CAPTURE)) { + found = fp; + cur_attr = attr; + continue; + } + } /* find the format with the largest max. packet size */ - if (! found || fp->maxpacksize > found->maxpacksize) + if (fp->maxpacksize > found->maxpacksize) { found = fp; + cur_attr = attr; + } } return found; } @@ -1240,6 +1269,17 @@ static int snd_usb_pcm_prepare(snd_pcm_s subs->maxframesize = bytes_to_frames(runtime, subs->maxpacksize); subs->curframesize = bytes_to_frames(runtime, subs->curpacksize); + /* reset the pointer */ + subs->hwptr = 0; + subs->hwptr_done = 0; + subs->transfer_sched = 0; + subs->transfer_done = 0; + subs->phase = 0; + + /* clear urbs (to be sure) */ + if (deactivate_urbs(subs, 0, 0) > 0) + wait_clear_urbs(subs); + return 0; } @@ -1429,7 +1469,7 @@ static int hw_rule_format(snd_pcm_hw_par fp = list_entry(p, struct audioformat, list); if (! hw_check_valid_format(params, fp)) continue; - fbits |= (1UL << fp->format); + fbits |= (1ULL << fp->format); } oldbits[0] = fmt->bits[0]; @@ -1454,6 +1494,7 @@ static int check_hw_params_convention(sn u32 channels[64]; u32 rates[64]; u32 cmaster, rmaster; + u32 rate_min = 0, rate_max = 0; struct list_head *p; memset(channels, 0, sizeof(channels)); @@ -1465,6 +1506,15 @@ static int check_hw_params_convention(sn /* unconventional channels? */ if (f->channels > 32) return 1; + /* continuous rate min/max matches? */ + if (f->rates & SNDRV_PCM_RATE_CONTINUOUS) { + if (rate_min && f->rate_min != rate_min) + return 1; + if (rate_max && f->rate_max != rate_max) + return 1; + rate_min = f->rate_min; + rate_max = f->rate_max; + } /* combination of continuous rates and fixed rates? */ if (rates[f->format] & SNDRV_PCM_RATE_CONTINUOUS) { if (f->rates != rates[f->format]) @@ -1819,7 +1869,7 @@ static void proc_pcm_format_add(snd_usb_ sprintf(name, "stream%d", stream->pcm_index); if (! snd_card_proc_new(card, name, &entry)) - snd_info_set_text_ops(entry, stream, proc_pcm_format_read); + snd_info_set_text_ops(entry, stream, 1024, proc_pcm_format_read); } @@ -1955,7 +2005,7 @@ static int add_audio_endpoint(snd_usb_au as->pcm = pcm; pcm->private_data = as; pcm->private_free = snd_usb_audio_pcm_free; - pcm->info_flags = 0; + pcm->info_flags = SNDRV_PCM_INFO_NONATOMIC_OPS; if (chip->pcm_devs > 0) sprintf(pcm->name, "USB Audio #%d", chip->pcm_devs); else @@ -2008,10 +2058,20 @@ static int parse_audio_format_i_type(str pcm_format = SNDRV_PCM_FORMAT_S8; break; case 2: - pcm_format = SNDRV_PCM_FORMAT_S16_LE; + /* M-Audio audiophile USB workaround */ + if (dev->descriptor.idVendor == 0x0763 && + dev->descriptor.idProduct == 0x2003) + pcm_format = SNDRV_PCM_FORMAT_S16_BE; /* grrr, big endian!! */ + else + pcm_format = SNDRV_PCM_FORMAT_S16_LE; break; case 3: - pcm_format = SNDRV_PCM_FORMAT_S24_3LE; + /* M-Audio audiophile USB workaround */ + if (dev->descriptor.idVendor == 0x0763 && + dev->descriptor.idProduct == 0x2003) + pcm_format = SNDRV_PCM_FORMAT_S24_3BE; /* grrr, big endian!! */ + else + pcm_format = SNDRV_PCM_FORMAT_S24_3LE; break; case 4: pcm_format = SNDRV_PCM_FORMAT_S32_LE; @@ -2604,6 +2664,32 @@ static int snd_usb_create_quirk(snd_usb_ /* + * common proc files to show the usb device info + */ +static void proc_audio_usbbus_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer) +{ + snd_usb_audio_t *chip = snd_magic_cast(snd_usb_audio_t, entry->private_data, return); + if (! chip->shutdown) + snd_iprintf(buffer, "%03d/%03d\n", chip->dev->bus->busnum, chip->dev->devnum); +} + +static void proc_audio_usbid_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer) +{ + snd_usb_audio_t *chip = snd_magic_cast(snd_usb_audio_t, entry->private_data, return); + if (! chip->shutdown) + snd_iprintf(buffer, "%04x:%04x\n", chip->dev->descriptor.idVendor, chip->dev->descriptor.idProduct); +} + +static void snd_usb_audio_create_proc(snd_usb_audio_t *chip) +{ + snd_info_entry_t *entry; + if (! snd_card_proc_new(chip->card, "usbbus", &entry)) + snd_info_set_text_ops(entry, chip, 1024, proc_audio_usbbus_read); + if (! snd_card_proc_new(chip->card, "usbid", &entry)) + snd_info_set_text_ops(entry, chip, 1024, proc_audio_usbid_read); +} + +/* * free the chip instance * * here we have to do not much, since pcm and controls are already freed @@ -2700,6 +2786,8 @@ static int snd_usb_audio_create(snd_card if (len < sizeof(card->longname)) usb_make_path(dev, card->longname + len, sizeof(card->longname) - len); + + snd_usb_audio_create_proc(chip); *rchip = chip; return 0; diff -aurpN -X /home/fletch/.diff.exclude 000-virgin/sound/usb/usbquirks.h 830-ivtv/sound/usb/usbquirks.h --- 000-virgin/sound/usb/usbquirks.h Mon Nov 17 18:29:01 2003 +++ 830-ivtv/sound/usb/usbquirks.h Thu Jan 8 10:26:51 2004 @@ -39,202 +39,72 @@ .idProduct = prod, \ .bInterfaceClass = USB_CLASS_VENDOR_SPEC -/* Yamaha devices */ -{ - USB_DEVICE(0x0499, 0x1000), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "UX256", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x1001), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "MU1000", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x1002), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "MU2000", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x1003), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "MU500", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE_VENDOR_SPEC(0x0499, 0x1004), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "UW500", - .ifnum = 3, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x1005), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "MOTIF6", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x1006), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "MOTIF7", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x1007), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "MOTIF8", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x1008), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "UX96", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x1009), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "UX16", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE_VENDOR_SPEC(0x0499, 0x100a), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "EOS BX", - .ifnum = 3, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x100e), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "S08", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x100f), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "CLP-150", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x1010), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "CLP-170", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x1011), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "P-250", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x1012), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "TYROS", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x1013), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "PF-500", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x1014), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "S90", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x5002), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "DME32", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x5003), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "DM2000", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x5004), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "02R96", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, +/* + * Yamaha devices + */ + +#define YAMAHA_DEVICE(id, name) { \ + USB_DEVICE(0x0499, id), \ + .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { \ + .vendor_name = "Yamaha", \ + .product_name = name, \ + .ifnum = QUIRK_ANY_INTERFACE, \ + .type = QUIRK_MIDI_YAMAHA \ + } \ +} +#define YAMAHA_INTERFACE(id, intf, name) { \ + USB_DEVICE_VENDOR_SPEC(0x0499, id), \ + .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { \ + .vendor_name = "Yamaha", \ + .product_name = name, \ + .ifnum = intf, \ + .type = QUIRK_MIDI_YAMAHA \ + } \ +} +YAMAHA_DEVICE(0x1000, "UX256"), +YAMAHA_DEVICE(0x1001, "MU1000"), +YAMAHA_DEVICE(0x1002, "MU2000"), +YAMAHA_DEVICE(0x1003, "MU500"), +YAMAHA_INTERFACE(0x1004, 3, "UW500"), +YAMAHA_DEVICE(0x1005, "MOTIF6"), +YAMAHA_DEVICE(0x1006, "MOTIF7"), +YAMAHA_DEVICE(0x1007, "MOTIF8"), +YAMAHA_DEVICE(0x1008, "UX96"), +YAMAHA_DEVICE(0x1009, "UX16"), +YAMAHA_INTERFACE(0x100a, 3, "EOS BX"), +YAMAHA_DEVICE(0x100e, "S08"), +YAMAHA_DEVICE(0x100f, "CLP-150"), +YAMAHA_DEVICE(0x1010, "CLP-170"), +YAMAHA_DEVICE(0x1011, "P-250"), +YAMAHA_DEVICE(0x1012, "TYROS"), +YAMAHA_DEVICE(0x1013, "PF-500"), +YAMAHA_DEVICE(0x1014, "S90"), +YAMAHA_DEVICE(0x1015, "MOTIF-R"), +YAMAHA_DEVICE(0x1017, "CVP-204"), +YAMAHA_DEVICE(0x1018, "CVP-206"), +YAMAHA_DEVICE(0x1019, "CVP-208"), +YAMAHA_DEVICE(0x101a, "CVP-210"), +YAMAHA_DEVICE(0x101b, "PSR-1100"), +YAMAHA_DEVICE(0x101c, "PSR-2100"), +YAMAHA_DEVICE(0x101e, "PSR-K1"), +YAMAHA_DEVICE(0x1020, "EZ-250i"), +YAMAHA_DEVICE(0x1021, "MOTIF ES 6"), +YAMAHA_DEVICE(0x1022, "MOTIF ES 7"), +YAMAHA_DEVICE(0x1023, "MOTIF ES 8"), +YAMAHA_DEVICE(0x5000, "CS1D"), +YAMAHA_DEVICE(0x5001, "DSP1D"), +YAMAHA_DEVICE(0x5002, "DME32"), +YAMAHA_DEVICE(0x5003, "DM2000"), +YAMAHA_DEVICE(0x5004, "02R96"), +YAMAHA_DEVICE(0x5005, "ACU16-C"), +YAMAHA_DEVICE(0x5006, "NHB32-C"), +YAMAHA_DEVICE(0x5007, "DM1000"), +YAMAHA_DEVICE(0x5008, "01V96"), +#undef YAMAHA_DEVICE +#undef YAMAHA_INTERFACE /* * Roland/RolandED/Edirol devices - * - * The USB MIDI Specification has been written by Roland, - * but a 100% conforming Roland device has yet to be found. */ { USB_DEVICE(0x0582, 0x0000), @@ -761,6 +631,19 @@ .vendor_name = "M-Audio", .product_name = "Ozone", .ifnum = 3, + .type = QUIRK_MIDI_MIDIMAN, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + } +}, +{ + USB_DEVICE_VENDOR_SPEC(0x0763, 0x200d), + .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { + .vendor_name = "M-Audio", + .product_name = "OmniStudio", + .ifnum = 9, .type = QUIRK_MIDI_MIDIMAN, .data = & (const snd_usb_midi_endpoint_info_t) { .out_cables = 0x0001,